mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
36
Commits
continious
...
fo1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4bb81a919 | ||
|
|
7ea5265a01 | ||
|
|
649d255ca2 | ||
|
|
64af575bdf | ||
|
|
03d703b734 | ||
|
|
19dfece38e | ||
|
|
7c361af576 | ||
|
|
0dc93bab88 | ||
|
|
64bb2af1fd | ||
|
|
cf56c0ecef | ||
|
|
161d114306 | ||
|
|
4823bd328f | ||
|
|
62f4dae07e | ||
|
|
f05831648b | ||
|
|
692cef5c98 | ||
|
|
d68790a096 | ||
|
|
97cd20d21e | ||
|
|
f4bb72b9e8 | ||
|
|
f56a96ec9c | ||
|
|
2504c64735 | ||
|
|
8a14b2b3ed | ||
|
|
bdf5d253ba | ||
|
|
9d2462ef44 | ||
|
|
be9169b234 | ||
|
|
aa54707d60 | ||
|
|
61947f5fb9 | ||
|
|
cead52bbd1 | ||
|
|
f80a61d359 | ||
|
|
34b3232422 | ||
|
|
a323a1292c | ||
|
|
cf6b3e75f3 | ||
|
|
a1dafba37a | ||
|
|
f264827cd6 | ||
|
|
544eb92d8e | ||
|
|
1e9b81dd17 | ||
|
|
b5c420274f |
@@ -98,6 +98,12 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/file_find.h"
|
||||
"src/file_utils.cc"
|
||||
"src/file_utils.h"
|
||||
"src/fo1db/fo1_assoc.cc"
|
||||
"src/fo1db/fo1_assoc.h"
|
||||
"src/fo1db/fo1_db.cc"
|
||||
"src/fo1db/fo1_db.h"
|
||||
"src/fo1db/fo1_lzss.cc"
|
||||
"src/fo1db/fo1_lzss.h"
|
||||
"src/font_manager.cc"
|
||||
"src/font_manager.h"
|
||||
"src/game_config.cc"
|
||||
@@ -114,6 +120,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/game_movie.h"
|
||||
"src/game_sound.cc"
|
||||
"src/game_sound.h"
|
||||
"src/game_variant.cc"
|
||||
"src/game_variant.h"
|
||||
"src/game_vars.h"
|
||||
"src/game.cc"
|
||||
"src/game.h"
|
||||
@@ -322,6 +330,10 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(${EXECUTABLE_NAME} PRIVATE /EHsc)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${EXECUTABLE_NAME}
|
||||
winmm
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#
|
||||
# enddeath.txt
|
||||
#
|
||||
# format of each line is:
|
||||
#
|
||||
# gvar, value, worldAreaKnown, worldAreaNotKnown, minLevel, %, narrator file
|
||||
#
|
||||
# Where:
|
||||
#
|
||||
# gvar is the GVAR_* number for the variable controlling the slide.
|
||||
#
|
||||
# value is the value that the gvar must be >= to for this slide
|
||||
# to be shown
|
||||
#
|
||||
# worldAreaKnown is the # of a worldmap area that has to be known
|
||||
# in order to get this one as an option
|
||||
#
|
||||
# worldAreaNotKnown is the # of a worldmap area that has to be *not*
|
||||
# known in order to get this one as an option
|
||||
#
|
||||
# minLevel is the minimum player level in order to get this one as
|
||||
# an option
|
||||
#
|
||||
# % is the % chance of a given line to occur
|
||||
#
|
||||
# narrator file is the base filename (no path path or extension) used
|
||||
# for the narrator voice-over and subtitles. Maximum of 8 characters.
|
||||
#
|
||||
|
||||
|
||||
#####
|
||||
# Generic Deaths
|
||||
#####
|
||||
-1, 0, -1, -1, 0, 20, NAR_3
|
||||
-1, 0, -1, -1, 0, 20, NAR_4
|
||||
-1, 0, -1, -1, 0, 20, NAR_5
|
||||
-1, 0, -1, -1, 0, 20, NAR_6
|
||||
-1, 0, 8, -1, 0, 20, NAR_8
|
||||
|
||||
#####
|
||||
# Specific Deaths
|
||||
#####
|
||||
-1, 0, -1, 0, 200, 0, nar_dth3
|
||||
-1, 0, -1, 0, 200, 0, nar_dth4
|
||||
-1, 0, -1, 0, 200, 0, nar_dth5
|
||||
-1, 0, -1, 0, 200, 0, nar_dth6
|
||||
-1, 0, -1, 0, 200, 0, nar_dth7
|
||||
-1, 0, -1, 0, 200, 0, nar_dth8
|
||||
-1, 0, -1, 0, 200, 0, nar_dth9
|
||||
|
||||
# Special Radiation Death
|
||||
491, 999, 3, -1, 150, 0, NAR_7
|
||||
|
||||
#####
|
||||
# Joke Deaths
|
||||
#####
|
||||
-1, 0, -1, -1, 10, 1, nar_jdd1
|
||||
-1, 0, -1, -1, 10, 1, nar_jdd3
|
||||
-1, 0, -1, -1, 10, 1, nar_jdd4
|
||||
-1, 0, -1, -1, 10, 1, nar_jdd5
|
||||
-1, 0, -1, -1, 10, 1, nar_jdd6
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
|
||||
;
|
||||
; Party Member valid option data
|
||||
;
|
||||
|
||||
;
|
||||
; Warning: Adding a party member here means you must also add it to party.h!
|
||||
;
|
||||
|
||||
;
|
||||
; Note: Party Member level-up float messages are found in game\misc.msg!
|
||||
;
|
||||
|
||||
|
||||
[Party Member 0] ; Player -- Not actually used!
|
||||
party_member_pid=16777216
|
||||
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=no_pref, melee, melee_over_ranged, ranged_over_melee, ranged, unarmed, unarmed_over_thrown, random
|
||||
chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime, always
|
||||
distance=stay_close, charge, snipe, on_your_own, stay
|
||||
run_away_mode=none, coward, finger_hurts, bleeding, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, coward, defensive, aggressive, berserk
|
||||
level_minimum=0
|
||||
level_up_every=0
|
||||
level_pids=-1
|
||||
|
||||
[Party Member 1] ; pMIan_PID
|
||||
party_member_pid=16777292
|
||||
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=no_pref, melee, ranged_over_melee, ranged
|
||||
chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime
|
||||
distance=stay_close, charge, snipe, on_your_own, stay
|
||||
run_away_mode=none, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, defensive, aggressive, berserk
|
||||
level_minimum=3
|
||||
level_up_every=3
|
||||
level_pids=16777530,16777531,16777532,16777533
|
||||
|
||||
[Party Member 2] ; pMDog_PID
|
||||
party_member_pid=16777338
|
||||
area_attack_mode=
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=unarmed
|
||||
chem_use=clean
|
||||
distance=stay_close, charge, on_your_own, stay
|
||||
run_away_mode=none, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, aggressive, berserk
|
||||
level_minimum=4
|
||||
level_up_every=3
|
||||
level_pids=16777542,16777543,16777544,16777545
|
||||
|
||||
[Party Member 3] ; pMTycho_PID
|
||||
party_member_pid=16777426
|
||||
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=no_pref, ranged_over_melee, ranged, unarmed
|
||||
chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime
|
||||
distance=stay_close, charge, snipe, on_your_own, stay
|
||||
run_away_mode=none, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, defensive, aggressive, berserk
|
||||
level_minimum=4
|
||||
level_up_every=3
|
||||
level_pids=16777534,16777535,16777536,16777537
|
||||
|
||||
[Party Member 4] ; pMKatja_PID
|
||||
party_member_pid=16777518
|
||||
area_attack_mode=sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, weakest, whomever, closest
|
||||
best_weapon=no_pref, melee, melee_over_ranged, ranged_over_melee, ranged, unarmed
|
||||
chem_use=stims_when_hurt_little, stims_when_hurt_lots
|
||||
distance=stay_close, charge, on_your_own, stay
|
||||
run_away_mode=none, coward, finger_hurts, bleeding, not_feeling_good
|
||||
disposition=none, custom, defensive, aggressive, coward
|
||||
level_minimum=4
|
||||
level_up_every=2
|
||||
level_pids=16777538,16777539,16777540,16777541
|
||||
|
||||
[Party Member 5] ; pMTandi_PID
|
||||
party_member_pid=16777279
|
||||
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=no_pref, melee, melee_over_ranged, ranged_over_melee, ranged, unarmed
|
||||
chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime, always
|
||||
distance=stay_close, charge, snipe, on_your_own, stay
|
||||
run_away_mode=none, coward, finger_hurts, bleeding, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, coward, defensive, aggressive, berserk
|
||||
level_minimum=0
|
||||
level_up_every=0
|
||||
level_pids=-1
|
||||
|
||||
[Party Member 6] ; pMMrHandyC_PID
|
||||
party_member_pid=16777529
|
||||
area_attack_mode=always, sometimes, be_sure, be_careful, be_absolutely_sure
|
||||
attack_who=whomever_attacking_me, strongest, weakest, whomever, closest
|
||||
best_weapon=no_pref, melee, melee_over_ranged, ranged_over_melee, ranged, unarmed
|
||||
chem_use=clean
|
||||
distance=stay_close, charge, snipe, on_your_own, stay
|
||||
run_away_mode=none, coward, finger_hurts, bleeding, not_feeling_good, tourniquet, never
|
||||
disposition=none, custom, coward, defensive, aggressive, berserk
|
||||
level_minimum=0
|
||||
level_up_every=0
|
||||
level_pids=-1
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
||||
;
|
||||
; Fallout team quotes
|
||||
;
|
||||
; The fonts used to display this file are the reverse of the
|
||||
; credits.txt file. In other words, the font used to display
|
||||
; titles in credits.txt (the lines with the '@') is the font
|
||||
; used to display these quotes. Putting an '@' at the start of
|
||||
; a line in this file will use the font used to display the
|
||||
; names in the credits.txt file (currently 104).
|
||||
;
|
||||
; Max line length with the current font (103) is about 63.
|
||||
; Anything longer than that won't be displayed, as it won't fit
|
||||
; on the screen.
|
||||
;
|
||||
; All lines are automatically centered on the display.
|
||||
;
|
||||
; See top of credits.txt for additional info.
|
||||
;
|
||||
@Quotes from the Fallout team:
|
||||
(Press ESC if you don't want to see some raw language)
|
||||
|
||||
|
||||
I asked for anatomically correct, but not naked!
|
||||
- Tim C.
|
||||
|
||||
I appreciate the fact that ?? is only speaking to us when spoken to.
|
||||
- Leonard
|
||||
|
||||
So now that you are past the learning curve,
|
||||
you can blow up people much faster, right?
|
||||
- Tim C.
|
||||
|
||||
So how fast can _you_ draw a bunny?
|
||||
- JT
|
||||
|
||||
I didn't do it yet today because I was waiting for Leonard's head.
|
||||
- Scott C.
|
||||
|
||||
|
||||
|
||||
Did you see Steven Spielberg go by?
|
||||
- Tim C.
|
||||
No, I was taking a piss.
|
||||
- Mark Harrison
|
||||
|
||||
|
||||
|
||||
Blueberry muffins are one of Man's crowning achievements.
|
||||
- JT
|
||||
|
||||
Out of my way. I'm a fucking genius.
|
||||
- Jason
|
||||
|
||||
Dismemberment is just inherently funny.
|
||||
- JT
|
||||
|
||||
I had a wooden one, but Spence broke it.
|
||||
- Jesse
|
||||
|
||||
You can say penis, but you can't say cocksucker.
|
||||
- Leonard
|
||||
|
||||
It's fun to make fun of people who are stupid.
|
||||
- JT
|
||||
|
||||
Crap is the hardest stuff to make.
|
||||
- Michael
|
||||
|
||||
No, I haven't shot anyone today.
|
||||
- JT
|
||||
|
||||
|
||||
|
||||
But 15 _is_ an even number!
|
||||
- Leonard
|
||||
But 15 isn't divisible by 2.
|
||||
- Tim.
|
||||
You know what I mean. I meant 15 is prime.
|
||||
- Leonard
|
||||
|
||||
|
||||
|
||||
I'll be going on to death at the end of the day.
|
||||
- Michael
|
||||
|
||||
I'm tired of looking at that peanut.
|
||||
- Tim C.
|
||||
|
||||
I only wash my nose. It's the only thing that gets dirty.
|
||||
- Fred
|
||||
|
||||
I'm going to jiujitsu his ass.
|
||||
- Leonard
|
||||
|
||||
I'll have to remember or else I'll forget.
|
||||
- Jesse
|
||||
|
||||
You never know what wacky things I'm going to do with my hand.
|
||||
- Tim C.
|
||||
|
||||
Sorry I'm late, but Mary needed marbles and I had lost mine.
|
||||
- Chris T.
|
||||
|
||||
It's fun hitting other people's balls.
|
||||
- Tim C.
|
||||
|
||||
I'm going to kill this game.
|
||||
- Mark Morgan
|
||||
|
||||
Do you want help putting on your bikini?
|
||||
- Fred to Tim C.
|
||||
|
||||
I like to get them in the butt.
|
||||
- Tim C.
|
||||
|
||||
I need more peasants!
|
||||
- Fred
|
||||
|
||||
If I hadn't had sex, I would have called Tom or Jesse.
|
||||
- Scotty
|
||||
|
||||
Did you know you can talk to people who don't have heads?
|
||||
- Jesse
|
||||
|
||||
We'll have a little bowl hair-cut kid so you
|
||||
can't tell if it's a boy or a girl when you're killing it.
|
||||
- Leonard
|
||||
|
||||
It's just a flag!
|
||||
- Scotty
|
||||
|
||||
I'll tell them to give me more exploding peasants.
|
||||
- Fred
|
||||
|
||||
Do you need help changing his pants?
|
||||
- Leonard
|
||||
|
||||
I was getting home and getting ready to get some,
|
||||
and I remembered it was a holiday.
|
||||
- Scotty
|
||||
|
||||
I'd rather drink a bottle of urine than THAT!
|
||||
- Scotty
|
||||
|
||||
Rusty wants any body he can have.
|
||||
- Gus
|
||||
|
||||
Nick's are worn and falling apart and orange.
|
||||
- Jesse
|
||||
|
||||
I never let work interfere with my cooking.
|
||||
- Tim C.
|
||||
|
||||
I don't want you to stop making them,
|
||||
because it's the only time I get any.
|
||||
- Scotty
|
||||
|
||||
I vote for Hate.
|
||||
- Jason
|
||||
|
||||
That reminds me of Toxic Avenger, the unrated version.
|
||||
- Scotty
|
||||
|
||||
You know, we should lock down sex.
|
||||
- Chris T.
|
||||
|
||||
How do I kill people? I need some dead bodies.
|
||||
- Robert H.
|
||||
|
||||
Don't quote me on that.
|
||||
- Leonard
|
||||
|
||||
|
||||
|
||||
I had a weird dream involving Scotty,
|
||||
and I don't even want to remember it.
|
||||
- Jesse
|
||||
What?!
|
||||
- Scotty
|
||||
|
||||
|
||||
|
||||
I don't know what we're going to do about it.
|
||||
I guess we're going to have to start cutting heads.
|
||||
- Tim C.
|
||||
|
||||
Well, that's true and that's untrue.
|
||||
- Gus
|
||||
|
||||
But I like being a woman!
|
||||
- Scotty
|
||||
|
||||
I'm used to playing with myself.
|
||||
- Scotty
|
||||
|
||||
That's the essence of art -- making it all work together.
|
||||
- Leonard
|
||||
|
||||
Did I tell you I broke my thingy?
|
||||
- Dave
|
||||
|
||||
I want more randomness in my randomology.
|
||||
- Robert H.
|
||||
|
||||
I can't finish the AI without drugs.
|
||||
- Tim C.
|
||||
|
||||
Please do not make fun of my poop.
|
||||
- Tim C.
|
||||
|
||||
I know how to tell males from females now.
|
||||
- Tim C.
|
||||
|
||||
Excuse me, my butt did that.
|
||||
- Jesse
|
||||
|
||||
|
||||
|
||||
I'm going to kick you in the butt.
|
||||
- Robert H. to Tim C.
|
||||
Because it's soft as a baby's behind.
|
||||
- Jesse.
|
||||
How do you know?
|
||||
- Scotty
|
||||
|
||||
|
||||
|
||||
I can do Troy. I used to be his monkey.
|
||||
- Chris T.
|
||||
|
||||
I had one once, but I pumped it too hard and I broke it.
|
||||
- Scotty
|
||||
|
||||
I stripped and wiped.
|
||||
- Scotty
|
||||
|
||||
Why can't I be a lesbian?
|
||||
- Shanna
|
||||
|
||||
I wonder what that thing hanging there is.
|
||||
- Shanna
|
||||
|
||||
I need more intelligence.
|
||||
- Nick
|
||||
|
||||
At the same time, I want to make sure that
|
||||
I don't have dead people stand up.
|
||||
- Tim C.
|
||||
|
||||
I'd model dust, if I could.
|
||||
- Jason
|
||||
|
||||
I'm on top now.
|
||||
- Evan
|
||||
|
||||
I do a good cow.
|
||||
- Greg B.
|
||||
|
||||
If he's on top of me, I'm gonna be pissed!
|
||||
- Shanna
|
||||
|
||||
If I was a girl, I'd do him.
|
||||
- Evan
|
||||
|
||||
You won't be here when I get off.
|
||||
- Mike Krueger
|
||||
|
||||
Well, I was playing with it last night but I
|
||||
couldn't get anything to come out!
|
||||
- Mike Krueger
|
||||
|
||||
Stop shaking my monkey!
|
||||
- Matt Murakami
|
||||
|
||||
I like people who say poop.
|
||||
- Savina
|
||||
|
||||
It's not unstable, it's just buggy.
|
||||
There's a difference.
|
||||
- Chris J.
|
||||
|
||||
Instead of sexual urges, they get
|
||||
sucking blood urges.
|
||||
- Scotty
|
||||
|
||||
I like little boys who wear skirts.
|
||||
- Mike Krueger
|
||||
|
||||
His iguana-stick is way too long.
|
||||
- Leonard
|
||||
|
||||
Fallout is "By Americans, For Americans" and
|
||||
the rest of the world can just get stuffed.
|
||||
- Scotty
|
||||
|
||||
All the Brotherhood do it. They know how.
|
||||
- Nick
|
||||
|
||||
I'm going to teach you to script,
|
||||
that'll be torture.
|
||||
- Nick
|
||||
|
||||
His little thing looks better anyway.
|
||||
- Evan
|
||||
|
||||
He TOLD me to touch it!
|
||||
- Nick
|
||||
|
||||
I'm really scared of the people on the Internet.
|
||||
They're all dumb. Except for that one guy.
|
||||
- Scotty
|
||||
|
||||
|
||||
|
||||
I haven't touched it for two months.
|
||||
- Nick
|
||||
Well, you better start touching it.
|
||||
- Evan
|
||||
|
||||
|
||||
|
||||
You can never be paranoid enough.
|
||||
- Scotty
|
||||
|
||||
You should be 14-18 when you blow the Master.
|
||||
- Jess
|
||||
|
||||
Oh, wait a minute, talk to Jesse.
|
||||
Jesse usually has lots of drugs.
|
||||
- Scotty
|
||||
|
||||
I burnt my part, for one thing.
|
||||
- Mark H.
|
||||
|
||||
I'm usually a lot happier about the
|
||||
game when I'm not playing it.
|
||||
- Scotty
|
||||
|
||||
You gotta take it easy, this is my first time.
|
||||
- Dave Hendee
|
||||
|
||||
It's really quick to get it up.
|
||||
- Mark H.
|
||||
|
||||
I can find the hole without looking now.
|
||||
- Ed H.
|
||||
|
||||
I've actually had it both ways, but I'm not sure why...
|
||||
- Dan S.
|
||||
|
||||
I can touch it everywhere and it seems to work.
|
||||
- Scotty
|
||||
|
||||
OK, I was sleeping with Ian...
|
||||
- Gus
|
||||
|
||||
What is the sound of one man working on another?
|
||||
- Dan S.
|
||||
|
||||
I hate being fucked.
|
||||
- Gus
|
||||
|
||||
I think our game has a high potential
|
||||
for being very violent.
|
||||
- Jason A.
|
||||
|
||||
I'm not going to be beaten by cheesecake.
|
||||
- Tim C.
|
||||
|
||||
I have new respect for crowbars.
|
||||
(pause)
|
||||
Well, at least it isn't about sex.
|
||||
- Scotty
|
||||
|
||||
That thing is a little too
|
||||
big to stick right there.
|
||||
- Matt G.
|
||||
|
||||
|
||||
|
||||
I'm not going to do the cows.
|
||||
- Dan S.
|
||||
The cows are glad to hear that.
|
||||
- Robert H.
|
||||
|
||||
|
||||
|
||||
But I love faggot pizza.
|
||||
- Scotty
|
||||
|
||||
It won't crash any more. In theory.
|
||||
- Mark H.
|
||||
|
||||
I wasn't wearing anything
|
||||
the first time I won the game.
|
||||
- Tim C.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@FIN
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_variant.h"
|
||||
#include "memory.h"
|
||||
#include "object.h"
|
||||
#include "proto.h"
|
||||
@@ -231,6 +232,13 @@ int artInit()
|
||||
critterFileNames += 13;
|
||||
}
|
||||
|
||||
// FO1 does not have a tribal look; use jumpsuit as the default player art.
|
||||
if (gameVariantIsFallout1() && _art_vault_guy_num == 0) {
|
||||
_art_vault_guy_num = _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE];
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE];
|
||||
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE];
|
||||
}
|
||||
|
||||
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
||||
if (!fileReadString(string, sizeof(string), stream)) {
|
||||
break;
|
||||
|
||||
@@ -6988,7 +6988,7 @@ static int karmaInit()
|
||||
|
||||
File* stream = fileOpen("data\\karmavar.txt", "rt");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char string[256];
|
||||
@@ -7087,7 +7087,7 @@ static int genericReputationInit()
|
||||
|
||||
File* stream = fileOpen("data\\genrep.txt", "rt");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char string[256];
|
||||
|
||||
@@ -610,6 +610,8 @@ static bool characterSelectorWindowRenderFace()
|
||||
// 0x4A7EA8
|
||||
static bool characterSelectorWindowRenderStats()
|
||||
{
|
||||
static char emptyString[] = "";
|
||||
|
||||
char* str;
|
||||
char text[260];
|
||||
int length;
|
||||
@@ -828,6 +830,9 @@ static bool characterSelectorWindowRenderStats()
|
||||
y += vh;
|
||||
|
||||
str = skillGetName(skills[index]);
|
||||
if (str == nullptr) {
|
||||
str = emptyString;
|
||||
}
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
|
||||
+39
-14
@@ -420,29 +420,50 @@ int aiInit()
|
||||
if (!configGetInt(&config, sectionEntry->key, "outline_color", &(ai->outline_color))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "chance", &(ai->chance))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "run_start", &(ai->run.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "run_end", &(ai->run.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "move_start", &(ai->move.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "move_end", &(ai->move.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "attack_start", &(ai->attack.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "attack_end", &(ai->attack.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "miss_start", &(ai->miss.start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "miss_end", &(ai->miss.end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_head_start", &(ai->hit[HIT_LOCATION_HEAD].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_head_end", &(ai->hit[HIT_LOCATION_HEAD].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_arm_start", &(ai->hit[HIT_LOCATION_LEFT_ARM].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_arm_end", &(ai->hit[HIT_LOCATION_LEFT_ARM].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_arm_start", &(ai->hit[HIT_LOCATION_RIGHT_ARM].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_arm_end", &(ai->hit[HIT_LOCATION_RIGHT_ARM].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_torso_start", &(ai->hit[HIT_LOCATION_TORSO].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_torso_end", &(ai->hit[HIT_LOCATION_TORSO].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_leg_start", &(ai->hit[HIT_LOCATION_RIGHT_LEG].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_leg_end", &(ai->hit[HIT_LOCATION_RIGHT_LEG].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_leg_start", &(ai->hit[HIT_LOCATION_LEFT_LEG].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_leg_end", &(ai->hit[HIT_LOCATION_LEFT_LEG].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_eyes_start", &(ai->hit[HIT_LOCATION_EYES].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_eyes_end", &(ai->hit[HIT_LOCATION_EYES].end))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_groin_start", &(ai->hit[HIT_LOCATION_GROIN].start))) goto err;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_groin_end", &(ai->hit[HIT_LOCATION_GROIN].end))) goto err;
|
||||
|
||||
// *_end fields are optional: FO1's ai.txt omits them and uses each *_start as
|
||||
// the inclusive upper bound of the preceding range (FO1-CE convention).
|
||||
// FO2's ai.txt always supplies explicit *_end values.
|
||||
if (!configGetInt(&config, sectionEntry->key, "run_end", &(ai->run.end)))
|
||||
ai->run.end = ai->move.start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "move_end", &(ai->move.end)))
|
||||
ai->move.end = ai->attack.start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "attack_end", &(ai->attack.end)))
|
||||
ai->attack.end = ai->miss.start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "miss_end", &(ai->miss.end)))
|
||||
ai->miss.end = ai->hit[HIT_LOCATION_HEAD].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_head_end", &(ai->hit[HIT_LOCATION_HEAD].end)))
|
||||
ai->hit[HIT_LOCATION_HEAD].end = ai->hit[HIT_LOCATION_LEFT_ARM].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_arm_end", &(ai->hit[HIT_LOCATION_LEFT_ARM].end)))
|
||||
ai->hit[HIT_LOCATION_LEFT_ARM].end = ai->hit[HIT_LOCATION_RIGHT_ARM].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_arm_end", &(ai->hit[HIT_LOCATION_RIGHT_ARM].end)))
|
||||
ai->hit[HIT_LOCATION_RIGHT_ARM].end = ai->hit[HIT_LOCATION_TORSO].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_torso_end", &(ai->hit[HIT_LOCATION_TORSO].end)))
|
||||
ai->hit[HIT_LOCATION_TORSO].end = ai->hit[HIT_LOCATION_RIGHT_LEG].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_right_leg_end", &(ai->hit[HIT_LOCATION_RIGHT_LEG].end)))
|
||||
ai->hit[HIT_LOCATION_RIGHT_LEG].end = ai->hit[HIT_LOCATION_LEFT_LEG].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_left_leg_end", &(ai->hit[HIT_LOCATION_LEFT_LEG].end)))
|
||||
ai->hit[HIT_LOCATION_LEFT_LEG].end = ai->hit[HIT_LOCATION_EYES].start;
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_eyes_end", &(ai->hit[HIT_LOCATION_EYES].end)))
|
||||
ai->hit[HIT_LOCATION_EYES].end = ai->hit[HIT_LOCATION_GROIN].start;
|
||||
// groin: FO1 uses last_msg as the inclusive end; CE expects the value before
|
||||
// the ++ below, so store last_msg - 1 so that ++ yields last_msg.
|
||||
if (!configGetInt(&config, sectionEntry->key, "hit_groin_end", &(ai->hit[HIT_LOCATION_GROIN].end))) {
|
||||
int lastMsg;
|
||||
if (!configGetInt(&config, sectionEntry->key, "last_msg", &lastMsg)) goto err;
|
||||
ai->hit[HIT_LOCATION_GROIN].end = lastMsg - 1;
|
||||
}
|
||||
|
||||
ai->hit[HIT_LOCATION_GROIN].end++;
|
||||
|
||||
@@ -577,8 +598,11 @@ int aiLoad(File* stream)
|
||||
int pid = gPartyMemberPids[index];
|
||||
if (pid != -1 && PID_TYPE(pid) == OBJ_TYPE_CRITTER) {
|
||||
Proto* proto;
|
||||
// TODO: fo1_shims party.txt contains FO2 pids with no valid proto
|
||||
// in FO1. Skip them rather than abort; fix by supplying a minimal
|
||||
// FO1-only party.txt.
|
||||
if (protoGetProto(pid, &proto) == -1) {
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
AiPacket* ai = aiGetPacketByNum(proto->critter.aiPacket);
|
||||
@@ -598,8 +622,9 @@ int aiSave(File* stream)
|
||||
int pid = gPartyMemberPids[index];
|
||||
if (pid != -1 && PID_TYPE(pid) == OBJ_TYPE_CRITTER) {
|
||||
Proto* proto;
|
||||
// TODO: same FO1 party.txt issue as aiLoad — skip invalid pids.
|
||||
if (protoGetProto(pid, &proto) == -1) {
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
AiPacket* ai = aiGetPacketByNum(proto->critter.aiPacket);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "game_variant.h"
|
||||
#include "platform_compat.h"
|
||||
#include "xfile.h"
|
||||
|
||||
@@ -37,6 +39,22 @@ static int gFileReadProgressChunkSize;
|
||||
// 0x673044
|
||||
static FileList* gFileListHead;
|
||||
|
||||
static bool dbShouldUseFo1Fallback(const char* path)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* baseName = strrchr(path, '/');
|
||||
if (baseName == nullptr) {
|
||||
baseName = strrchr(path, '\\');
|
||||
}
|
||||
|
||||
baseName = baseName != nullptr ? baseName + 1 : path;
|
||||
|
||||
return compat_stricmp(baseName, "master.dat") == 0 || compat_stricmp(baseName, "critter.dat") == 0;
|
||||
}
|
||||
|
||||
// Opens file database.
|
||||
//
|
||||
// Returns -1 if [filePath1] was specified, but could not be opened by the
|
||||
@@ -48,6 +66,17 @@ int dbOpen(const char* filePath1, const char* filePath2)
|
||||
{
|
||||
if (filePath1 != nullptr) {
|
||||
if (!xbaseOpen(filePath1)) {
|
||||
if (dbShouldUseFo1Fallback(filePath1)) {
|
||||
gameVariantForceFallout1();
|
||||
debugPrint("dbOpen: retrying %s with Fallout 1 backend.\n", filePath1);
|
||||
if (xbaseOpen(filePath1)) {
|
||||
if (filePath2 != nullptr) {
|
||||
xbaseOpen(filePath2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
+215
-5
@@ -7,8 +7,11 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "fpattern_windows.h"
|
||||
#include <fpattern/fpattern.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "fo1db/fo1_db.h"
|
||||
#include "game_variant.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -38,6 +41,8 @@ namespace fallout {
|
||||
#define DFILE_HAS_COMPRESSED_UNGETC (0x10)
|
||||
|
||||
static int dbaseFindEntryByFilePath(const void* file, const void* entryName);
|
||||
static DBase* dbaseOpenFo1(const char* filePath);
|
||||
static bool dbaseShouldUseFo1Backend(const char* filePath);
|
||||
static DFile* dfileOpenInternal(DBase* dbase, const char* filename, const char* mode, DFile* dfile);
|
||||
static int dfileReadCharInternal(DFile* stream);
|
||||
static bool dfileReadCompressed(DFile* stream, void* ptr, size_t size);
|
||||
@@ -52,6 +57,11 @@ DBase* dbaseOpen(const char* filePath)
|
||||
|
||||
FILE* stream = compat_fopen(filePath, "rb");
|
||||
if (stream == nullptr) {
|
||||
if (dbaseShouldUseFo1Backend(filePath)) {
|
||||
gameVariantForceFallout1();
|
||||
return dbaseOpenFo1(filePath);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -153,11 +163,15 @@ DBase* dbaseOpen(const char* filePath)
|
||||
return dbase;
|
||||
|
||||
err:
|
||||
|
||||
dbaseClose(dbase);
|
||||
|
||||
fclose(stream);
|
||||
|
||||
if (dbaseShouldUseFo1Backend(filePath)) {
|
||||
gameVariantForceFallout1();
|
||||
return dbaseOpenFo1(filePath);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -176,6 +190,20 @@ bool dbaseClose(DBase* dbase)
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if (dbase->backend == DBASE_BACKEND_FO1) {
|
||||
if (dbase->fo1Database != INVALID_DATABASE_HANDLE && dbase->fo1Database != nullptr) {
|
||||
db_close(dbase->fo1Database);
|
||||
}
|
||||
|
||||
if (dbase->path != nullptr) {
|
||||
free(dbase->path);
|
||||
}
|
||||
|
||||
memset(dbase, 0, sizeof(*dbase));
|
||||
free(dbase);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dbase->entries != nullptr) {
|
||||
for (int index = 0; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
@@ -201,10 +229,25 @@ bool dbaseClose(DBase* dbase)
|
||||
// 0x4E5308
|
||||
bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern)
|
||||
{
|
||||
// .dat files always have windows style paths
|
||||
findFileData->backend = dbase->backend;
|
||||
|
||||
if (dbase->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(dbase->fo1Database);
|
||||
findFileData->fo1FileNames = nullptr;
|
||||
findFileData->fo1FileNamesLength = db_get_file_list(pattern, &findFileData->fo1FileNames, nullptr, 0);
|
||||
if (findFileData->fo1FileNamesLength <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(findFileData->fileName, findFileData->fo1FileNames[0]);
|
||||
strcpy(findFileData->pattern, pattern);
|
||||
findFileData->index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int index = 0; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
if (fpattern_windows_match(pattern, entry->path)) {
|
||||
if (fpattern_match(pattern, entry->path)) {
|
||||
strcpy(findFileData->fileName, entry->path);
|
||||
strcpy(findFileData->pattern, pattern);
|
||||
findFileData->index = index;
|
||||
@@ -218,9 +261,20 @@ bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char*
|
||||
// 0x4E53A0
|
||||
bool dbaseFindNextEntry(DBase* dbase, DFileFindData* findFileData)
|
||||
{
|
||||
if (dbase->backend == DBASE_BACKEND_FO1) {
|
||||
int index = findFileData->index + 1;
|
||||
if (index >= findFileData->fo1FileNamesLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(findFileData->fileName, findFileData->fo1FileNames[index]);
|
||||
findFileData->index = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int index = findFileData->index + 1; index < dbase->entriesLength; index++) {
|
||||
DBaseEntry* entry = &(dbase->entries[index]);
|
||||
if (fpattern_windows_match(findFileData->pattern, entry->path)) {
|
||||
if (fpattern_match(findFileData->pattern, entry->path)) {
|
||||
strcpy(findFileData->fileName, entry->path);
|
||||
findFileData->index = index;
|
||||
return true;
|
||||
@@ -233,6 +287,12 @@ bool dbaseFindNextEntry(DBase* dbase, DFileFindData* findFileData)
|
||||
// 0x4E541C
|
||||
bool dbaseFindClose(DBase* dbase, DFileFindData* findFileData)
|
||||
{
|
||||
if (dbase->backend == DBASE_BACKEND_FO1 && findFileData->fo1FileNames != nullptr) {
|
||||
db_free_file_list(&findFileData->fo1FileNames, nullptr);
|
||||
findFileData->fo1FileNames = nullptr;
|
||||
findFileData->fo1FileNamesLength = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -241,6 +301,11 @@ bool dbaseFindClose(DBase* dbase, DFileFindData* findFileData)
|
||||
// 0x4E5424
|
||||
long dfileGetSize(DFile* stream)
|
||||
{
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_filelength(stream->fo1File);
|
||||
}
|
||||
|
||||
return stream->entry->uncompressedSize;
|
||||
}
|
||||
|
||||
@@ -253,6 +318,34 @@ int dfileClose(DFile* stream)
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
rc = db_fclose(stream->fo1File);
|
||||
|
||||
DFile* curr = stream->dbase->dfileHead;
|
||||
DFile* prev = nullptr;
|
||||
while (curr != nullptr) {
|
||||
if (curr == stream) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if (curr != nullptr) {
|
||||
if (prev == nullptr) {
|
||||
stream->dbase->dfileHead = stream->next;
|
||||
} else {
|
||||
prev->next = stream->next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
free(stream);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (stream->entry->compressed == 1) {
|
||||
if (inflateEnd(stream->decompressionStream) != Z_OK) {
|
||||
rc = -1;
|
||||
@@ -310,6 +403,32 @@ DFile* dfileOpen(DBase* dbase, const char* filePath, const char* mode)
|
||||
assert(filePath); // dfile.c, 296
|
||||
assert(mode); // dfile.c, 297
|
||||
|
||||
if (dbase->backend == DBASE_BACKEND_FO1) {
|
||||
if (mode[0] != 'r') {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
db_select(dbase->fo1Database);
|
||||
DB_FILE* fo1File = db_fopen(filePath, mode);
|
||||
if (fo1File == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DFile* dfile = (DFile*)malloc(sizeof(*dfile));
|
||||
if (dfile == nullptr) {
|
||||
db_fclose(fo1File);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(dfile, 0, sizeof(*dfile));
|
||||
dfile->backend = DBASE_BACKEND_FO1;
|
||||
dfile->dbase = dbase;
|
||||
dfile->fo1File = fo1File;
|
||||
dfile->next = dbase->dfileHead;
|
||||
dbase->dfileHead = dfile;
|
||||
return dfile;
|
||||
}
|
||||
|
||||
return dfileOpenInternal(dbase, filePath, mode, nullptr);
|
||||
}
|
||||
|
||||
@@ -321,6 +440,10 @@ int dfilePrintFormattedArgs(DFile* stream, const char* format, va_list args)
|
||||
assert(stream); // "stream", "dfile.c", 368
|
||||
assert(format); // "format", "dfile.c", 369
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -334,6 +457,11 @@ int dfileReadChar(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 384
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fgetc(stream->fo1File);
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -363,6 +491,11 @@ char* dfileReadString(char* string, int size, DFile* stream)
|
||||
assert(size); // "n", "dfile.c", 408
|
||||
assert(stream); // "stream", "dfile.c", 409
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fgets(string, size, stream->fo1File);
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -407,6 +540,11 @@ int dfileWriteChar(int ch, DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 437
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fputc(ch, stream->fo1File);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -418,6 +556,11 @@ int dfileWriteString(const char* string, DFile* stream)
|
||||
assert(string); // "s", "dfile.c", 448
|
||||
assert(stream); // "stream", "dfile.c", 449
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fputs(string, stream->fo1File);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -429,6 +572,11 @@ size_t dfileRead(void* ptr, size_t size, size_t count, DFile* stream)
|
||||
assert(ptr); // "ptr", "dfile.c", 499
|
||||
assert(stream); // "stream", dfile.c, 500
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fread(ptr, size, count, stream->fo1File);
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_EOF) != 0 || (stream->flags & DFILE_ERROR) != 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -480,6 +628,11 @@ size_t dfileWrite(const void* ptr, size_t size, size_t count, DFile* stream)
|
||||
assert(ptr); // "ptr", "dfile.c", 538
|
||||
assert(stream); // "stream", "dfile.c", 539
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fwrite(ptr, size, count, stream->fo1File);
|
||||
}
|
||||
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
@@ -490,6 +643,11 @@ int dfileSeek(DFile* stream, long offset, int origin)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 569
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_fseek(stream->fo1File, offset, origin);
|
||||
}
|
||||
|
||||
if ((stream->flags & DFILE_ERROR) != 0) {
|
||||
return 1;
|
||||
}
|
||||
@@ -599,6 +757,11 @@ long dfileTell(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 654
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_ftell(stream->fo1File);
|
||||
}
|
||||
|
||||
return stream->position;
|
||||
}
|
||||
|
||||
@@ -609,6 +772,12 @@ void dfileRewind(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 664
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
db_rewind(stream->fo1File);
|
||||
return;
|
||||
}
|
||||
|
||||
dfileSeek(stream, 0, SEEK_SET);
|
||||
|
||||
stream->flags &= ~DFILE_ERROR;
|
||||
@@ -621,9 +790,34 @@ int dfileEof(DFile* stream)
|
||||
{
|
||||
assert(stream); // "stream", "dfile.c", 685
|
||||
|
||||
if (stream->backend == DBASE_BACKEND_FO1) {
|
||||
db_select(stream->dbase->fo1Database);
|
||||
return db_feof(stream->fo1File);
|
||||
}
|
||||
|
||||
return stream->flags & DFILE_EOF;
|
||||
}
|
||||
|
||||
static DBase* dbaseOpenFo1(const char* filePath)
|
||||
{
|
||||
DB_DATABASE* fo1Database = db_init(filePath, nullptr, nullptr, 0);
|
||||
if (fo1Database == INVALID_DATABASE_HANDLE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DBase* dbase = (DBase*)malloc(sizeof(*dbase));
|
||||
if (dbase == nullptr) {
|
||||
db_close(fo1Database);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(dbase, 0, sizeof(*dbase));
|
||||
dbase->backend = DBASE_BACKEND_FO1;
|
||||
dbase->path = compat_strdup(filePath);
|
||||
dbase->fo1Database = fo1Database;
|
||||
return dbase;
|
||||
}
|
||||
|
||||
// The [bsearch] comparison callback, which is used to find [DBaseEntry] for
|
||||
// specified [filePath].
|
||||
//
|
||||
@@ -636,6 +830,22 @@ static int dbaseFindEntryByFilePath(const void* file, const void* entryName)
|
||||
return compat_stricmp(filePath, entry->path);
|
||||
}
|
||||
|
||||
static bool dbaseShouldUseFo1Backend(const char* filePath)
|
||||
{
|
||||
if (filePath == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* baseName = strrchr(filePath, '/');
|
||||
if (baseName == nullptr) {
|
||||
baseName = strrchr(filePath, '\\');
|
||||
}
|
||||
|
||||
baseName = baseName != nullptr ? baseName + 1 : filePath;
|
||||
|
||||
return compat_stricmp(baseName, "master.dat") == 0 || compat_stricmp(baseName, "critter.dat") == 0;
|
||||
}
|
||||
|
||||
// 0x4E5D9C
|
||||
static DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, DFile* dfile)
|
||||
{
|
||||
|
||||
+18
@@ -12,9 +12,18 @@ namespace fallout {
|
||||
typedef struct DBase DBase;
|
||||
typedef struct DBaseEntry DBaseEntry;
|
||||
typedef struct DFile DFile;
|
||||
typedef struct DB_DATABASE DB_DATABASE;
|
||||
typedef struct DB_FILE DB_FILE;
|
||||
|
||||
typedef enum DBaseBackend {
|
||||
DBASE_BACKEND_FO2,
|
||||
DBASE_BACKEND_FO1,
|
||||
} DBaseBackend;
|
||||
|
||||
// A representation of .DAT file.
|
||||
typedef struct DBase {
|
||||
DBaseBackend backend;
|
||||
|
||||
// The path of .DAT file that this structure represents.
|
||||
char* path;
|
||||
|
||||
@@ -29,6 +38,8 @@ typedef struct DBase {
|
||||
|
||||
// The head of linked list of open file handles.
|
||||
DFile* dfileHead;
|
||||
|
||||
DB_DATABASE* fo1Database;
|
||||
} DBase;
|
||||
|
||||
typedef struct DBaseEntry {
|
||||
@@ -41,6 +52,7 @@ typedef struct DBaseEntry {
|
||||
|
||||
// A handle to open entry in .DAT file.
|
||||
typedef struct DFile {
|
||||
DBaseBackend backend;
|
||||
DBase* dbase;
|
||||
DBaseEntry* entry;
|
||||
int flags;
|
||||
@@ -90,6 +102,8 @@ typedef struct DFile {
|
||||
// [DFile]s are stored in [DBase] in reverse order, so it's actually a
|
||||
// previous opened file, not next.
|
||||
DFile* next;
|
||||
|
||||
DB_FILE* fo1File;
|
||||
} DFile;
|
||||
|
||||
typedef struct DFileFindData {
|
||||
@@ -108,6 +122,10 @@ typedef struct DFileFindData {
|
||||
// [dbaseFindNextEntry] succeed so that subsequent calls to [dbaseFindNextEntry]
|
||||
// knows where to start search from.
|
||||
int index;
|
||||
|
||||
char** fo1FileNames;
|
||||
int fo1FileNamesLength;
|
||||
DBaseBackend backend;
|
||||
} DFileFindData;
|
||||
|
||||
DBase* dbaseOpen(const char* filename);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "game_mouse.h"
|
||||
#include "game_movie.h"
|
||||
#include "game_sound.h"
|
||||
#include "game_variant.h"
|
||||
#include "input.h"
|
||||
#include "map.h"
|
||||
#include "memory.h"
|
||||
@@ -1013,6 +1014,10 @@ int endgameDeathEndingInit()
|
||||
|
||||
stream = fileOpen("data\\enddeath.txt", "rt");
|
||||
if (stream == nullptr) {
|
||||
if (gameVariantIsFallout1()) {
|
||||
debugPrint("\nendgameDeathEndingInit: data\\enddeath.txt is missing in FO1 mode, continuing without death-ending table.");
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
#ifndef FALLOUT_FO1DB_ASSOC_H_
|
||||
#define FALLOUT_FO1DB_ASSOC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fo1_db.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef void*(assoc_malloc_func)(size_t size);
|
||||
typedef void*(assoc_realloc_func)(void* ptr, size_t newSize);
|
||||
typedef void(assoc_free_func)(void* ptr);
|
||||
typedef int(assoc_load_func)(FILE* stream, void* buffer, size_t size, int flags);
|
||||
typedef int(assoc_save_func)(FILE* stream, void* buffer, size_t size, int flags);
|
||||
typedef int(assoc_load_func_db)(DB_FILE* stream, void* buffer, size_t size, int flags);
|
||||
typedef int(assoc_save_func_db)(DB_FILE* stream, void* buffer, size_t size, int flags);
|
||||
|
||||
typedef struct assoc_func_list {
|
||||
assoc_load_func* loadFunc;
|
||||
assoc_save_func* saveFunc;
|
||||
assoc_load_func_db* loadFuncDB;
|
||||
assoc_save_func_db* saveFuncDB;
|
||||
assoc_load_func* newLoadFunc;
|
||||
} assoc_func_list;
|
||||
|
||||
// A tuple containing individual key-value pair of an assoc array.
|
||||
typedef struct assoc_pair {
|
||||
char* name;
|
||||
void* data;
|
||||
} assoc_pair;
|
||||
|
||||
// A collection of key/value pairs.
|
||||
//
|
||||
// The keys in assoc array are always strings. Internally pairs are kept sorted
|
||||
// by the key. Both keys and values are copied when new entry is added to
|
||||
// assoc array. For this reason the size of the value's type is provided during
|
||||
// assoc array initialization.
|
||||
typedef struct assoc_array {
|
||||
int init_flag;
|
||||
|
||||
// The number of key/value pairs in the array.
|
||||
int size;
|
||||
|
||||
// The capacity of key/value pairs in [entries] array.
|
||||
int max;
|
||||
|
||||
// The size of the values in bytes.
|
||||
size_t datasize;
|
||||
|
||||
// IO callbacks.
|
||||
assoc_func_list load_save_funcs;
|
||||
|
||||
// The array of key-value pairs.
|
||||
assoc_pair* list;
|
||||
} assoc_array;
|
||||
|
||||
int assoc_init(assoc_array* a, int n, size_t datasize, assoc_func_list* assoc_funcs);
|
||||
int assoc_resize(assoc_array* a, int n);
|
||||
int assoc_free(assoc_array* a);
|
||||
int assoc_search(assoc_array* a, const char* name);
|
||||
int assoc_insert(assoc_array* a, const char* name, const void* data);
|
||||
int assoc_delete(assoc_array* a, const char* name);
|
||||
int assoc_copy(assoc_array* dst, assoc_array* src);
|
||||
int assoc_load(FILE* fp, assoc_array* a, int flags);
|
||||
int assoc_save(FILE* fp, assoc_array* a, int flags);
|
||||
void assoc_register_mem(assoc_malloc_func* malloc_func, assoc_realloc_func* realloc_func, assoc_free_func* free_func);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_FO1DB_ASSOC_H_ */
|
||||
+3020
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
#ifndef FALLOUT_FO1DB_DB_H_
|
||||
#define FALLOUT_FO1DB_DB_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define INVALID_DATABASE_HANDLE ((DB_DATABASE*)-1)
|
||||
|
||||
#define db_init fo1db_init
|
||||
#define db_select fo1db_select
|
||||
#define db_current fo1db_current
|
||||
#define db_total fo1db_total
|
||||
#define db_close fo1db_close
|
||||
#define db_dir_entry fo1db_dir_entry
|
||||
#define db_read_to_buf fo1db_read_to_buf
|
||||
#define db_fopen fo1db_fopen
|
||||
#define db_fclose fo1db_fclose
|
||||
#define db_fread fo1db_fread
|
||||
#define db_fgetc fo1db_fgetc
|
||||
#define db_fgets fo1db_fgets
|
||||
#define db_fwrite fo1db_fwrite
|
||||
#define db_fputc fo1db_fputc
|
||||
#define db_fputs fo1db_fputs
|
||||
#define db_fseek fo1db_fseek
|
||||
#define db_ftell fo1db_ftell
|
||||
#define db_rewind fo1db_rewind
|
||||
#define db_feof fo1db_feof
|
||||
#define db_get_file_list fo1db_get_file_list
|
||||
#define db_free_file_list fo1db_free_file_list
|
||||
#define db_filelength fo1db_filelength
|
||||
|
||||
typedef struct DB_FILE DB_FILE;
|
||||
typedef struct DB_DATABASE DB_DATABASE;
|
||||
|
||||
typedef struct dir_entry_s {
|
||||
int flags;
|
||||
int offset;
|
||||
int length;
|
||||
int field_C;
|
||||
} dir_entry;
|
||||
|
||||
typedef void db_read_callback();
|
||||
typedef void*(db_malloc_func)(size_t size);
|
||||
typedef char*(db_strdup_func)(const char* string);
|
||||
typedef void(db_free_func)(void* ptr);
|
||||
|
||||
DB_DATABASE* db_init(const char* datafile, const char* datafile_path, const char* patches_path, int show_cursor);
|
||||
int db_select(DB_DATABASE* db_handle);
|
||||
DB_DATABASE* db_current();
|
||||
int db_total();
|
||||
int db_close(DB_DATABASE* db_handle);
|
||||
void db_exit();
|
||||
int db_dir_entry(const char* filePath, dir_entry* de);
|
||||
int db_read_to_buf(const char* filePath, unsigned char* ptr);
|
||||
DB_FILE* db_fopen(const char* filename, const char* mode);
|
||||
int db_fclose(DB_FILE* stream);
|
||||
size_t db_fread(void* buf, size_t size, size_t count, DB_FILE* stream);
|
||||
int db_fgetc(DB_FILE* stream);
|
||||
int db_ungetc(int ch, DB_FILE* stream);
|
||||
char* db_fgets(char* str, size_t size, DB_FILE* stream);
|
||||
size_t db_fwrite(const void* buf, size_t size, size_t count, DB_FILE* stream);
|
||||
int db_fputc(int ch, DB_FILE* stream);
|
||||
int db_fputs(const char* s, DB_FILE* stream);
|
||||
int db_fseek(DB_FILE* stream, long offset, int origin);
|
||||
long db_ftell(DB_FILE* stream);
|
||||
void db_rewind(DB_FILE* stream);
|
||||
int db_freadByte(DB_FILE* stream, unsigned char* c);
|
||||
int db_freadShort(DB_FILE* stream, unsigned short* s);
|
||||
int db_freadInt(DB_FILE* stream, int* i);
|
||||
int db_freadLong(DB_FILE* stream, unsigned long* l);
|
||||
int db_freadFloat(DB_FILE* stream, float* q);
|
||||
int db_fwriteByte(DB_FILE* stream, unsigned char c);
|
||||
int db_fwriteShort(DB_FILE* stream, unsigned short s);
|
||||
int db_fwriteInt(DB_FILE* stream, int i);
|
||||
int db_fwriteLong(DB_FILE* stream, unsigned long l);
|
||||
int db_fwriteFloat(DB_FILE* stream, float q);
|
||||
int db_freadByteCount(DB_FILE* stream, unsigned char* c, int count);
|
||||
int db_freadShortCount(DB_FILE* stream, unsigned short* s, int count);
|
||||
int db_freadIntCount(DB_FILE* stream, int* i, int count);
|
||||
int db_freadLongCount(DB_FILE* stream, unsigned long* l, int count);
|
||||
int db_freadFloatCount(DB_FILE* stream, float* q, int count);
|
||||
int db_fwriteByteCount(DB_FILE* stream, unsigned char* c, int count);
|
||||
int db_fwriteShortCount(DB_FILE* stream, unsigned short* s, int count);
|
||||
int db_fwriteIntCount(DB_FILE* stream, int* i, int count);
|
||||
int db_fwriteLongCount(DB_FILE* stream, unsigned long* l, int count);
|
||||
int db_fwriteFloatCount(DB_FILE* stream, float* q, int count);
|
||||
int db_fprintf(DB_FILE* stream, const char* format, ...);
|
||||
int db_feof(DB_FILE* stream);
|
||||
int db_get_file_list(const char* filespec, char*** filelist, char*** desclist, int desclen);
|
||||
void db_free_file_list(char*** file_list, char*** desclist);
|
||||
long db_filelength(DB_FILE* stream);
|
||||
void db_register_mem(db_malloc_func* malloc_func, db_strdup_func* strdup_func, db_free_func* free_func);
|
||||
void db_register_callback(db_read_callback* callback, size_t threshold);
|
||||
void db_enable_hash_table();
|
||||
int db_reset_hash_tables();
|
||||
int db_add_hash_entry(const char* path, int sep);
|
||||
|
||||
int db_freadUInt8(DB_FILE* stream, unsigned char* valuePtr);
|
||||
int db_freadInt8(DB_FILE* stream, char* valuePtr);
|
||||
int db_freadUInt16(DB_FILE* stream, unsigned short* valuePtr);
|
||||
int db_freadInt16(DB_FILE* stream, short* valuePtr);
|
||||
int db_freadUInt32(DB_FILE* stream, unsigned int* valuePtr);
|
||||
int db_freadInt32(DB_FILE* stream, int* valuePtr);
|
||||
int db_freadUInt8List(DB_FILE* stream, unsigned char* arr, int count);
|
||||
int db_freadInt8List(DB_FILE* stream, char* arr, int count);
|
||||
int db_freadInt16List(DB_FILE* stream, short* arr, int count);
|
||||
int db_freadInt32List(DB_FILE* stream, int* arr, int count);
|
||||
int db_freadBool(DB_FILE* stream, bool* valuePtr);
|
||||
|
||||
int db_fwriteUInt8(DB_FILE* stream, unsigned char value);
|
||||
int db_fwriteInt8(DB_FILE* stream, char value);
|
||||
int db_fwriteUInt16(DB_FILE* stream, unsigned short value);
|
||||
int db_fwriteInt16(DB_FILE* stream, short value);
|
||||
int db_fwriteUInt32(DB_FILE* stream, unsigned int value);
|
||||
int db_fwriteInt32(DB_FILE* stream, int value);
|
||||
int db_fwriteUInt8List(DB_FILE* stream, unsigned char* arr, int count);
|
||||
int db_fwriteInt8List(DB_FILE* stream, char* arr, int count);
|
||||
int db_fwriteInt16List(DB_FILE* stream, short* arr, int count);
|
||||
int db_fwriteInt32List(DB_FILE* stream, int* arr, int count);
|
||||
int db_fwriteBool(DB_FILE* stream, bool value);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_FO1DB_DB_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user