mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
139fc3c440 | ||
|
|
90ca28a13c | ||
|
|
fbae40e9a8 | ||
|
|
4070d29fcb |
@@ -62,6 +62,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
|||||||
"src/combat.h"
|
"src/combat.h"
|
||||||
"src/config.cc"
|
"src/config.cc"
|
||||||
"src/config.h"
|
"src/config.h"
|
||||||
|
"src/content_config.cc"
|
||||||
|
"src/content_config.h"
|
||||||
"src/credits.cc"
|
"src/credits.cc"
|
||||||
"src/credits.h"
|
"src/credits.h"
|
||||||
"src/critter.cc"
|
"src/critter.cc"
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ This document tracks Fallout 2 CE compatibility with sfall. This is for modders
|
|||||||
|
|
||||||
For now, this covers opcodes/metarules, and hooks. In the future, it will include other ways of modifying the engine (like ini files), and other Sfall-specific behaviour.
|
For now, this covers opcodes/metarules, and hooks. In the future, it will include other ways of modifying the engine (like ini files), and other Sfall-specific behaviour.
|
||||||
|
|
||||||
## Settings (ddraw.ini → fallout2.cfg)
|
## Settings (ddraw.ini → fallout2.cfg / game.cfg)
|
||||||
|
|
||||||
Some settings previously read from `ddraw.ini` have been moved into `fallout2.cfg`. The table below maps each setting to its new location. `HiResMode` had no effect in CE and has been removed.
|
Settings previously read from `ddraw.ini` have been moved into standard CE config files.
|
||||||
|
|
||||||
|
Most settings that control game behavior (premade characters, extra message files, combat tweaks, worldmap, etc.) have been moved into [`<DAT>/config/game.cfg`](files/ce.dat/config/game.cfg), which is a content-mod config file intended to be overridden by mods. See that file for the full list with descriptions.
|
||||||
|
|
||||||
|
The following settings were moved into [`fallout2.cfg`](files/fallout2.cfg) instead:
|
||||||
|
|
||||||
| ddraw.ini section | ddraw.ini key | fallout2.cfg section | fallout2.cfg key |
|
| ddraw.ini section | ddraw.ini key | fallout2.cfg section | fallout2.cfg key |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
@@ -66,7 +70,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
|||||||
| Interface / Cursor | get/set_cursor_mode | âś… | - |
|
| Interface / Cursor | get/set_cursor_mode | âś… | - |
|
||||||
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
|
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
|
||||||
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… except get_ini_config, get_ini_config_db | `modified_ini` is intentionally omitted as deprecated. |
|
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… except get_ini_config, get_ini_config_db | `modified_ini` is intentionally omitted as deprecated. |
|
||||||
| Objects and scripts | set_self<br>set_dude_obj<br>real_dude_obj<br>remove_script<br>get/set_script<br>obj_is_carrying_obj<br>loot_obj<br>dialog_obj<br>obj_under_cursor<br>get/set_object_data<br>get/set_flags<br>set_unique_id<br>set_scr_name<br>obj_is_openable<br>get/set_proto_data<br>get_object_ai_data | implemented: set_self, get_script, obj_is_carrying_obj, loot_obj, dialog_obj, obj_under_cursor, get_object_data, get_flags, set_flags, obj_is_openable, get_proto_data, set_proto_data | - |
|
| Objects and scripts | set_self<br>set_dude_obj<br>real_dude_obj<br>remove_script<br>get/set_script<br>obj_is_carrying_obj<br>loot_obj<br>dialog_obj<br>obj_under_cursor<br>get/set_object_data<br>get/set_flags<br>set_unique_id<br>set_scr_name<br>obj_is_openable<br>get/set_proto_data<br>get_object_ai_data | implemented: set_self, get/set/remove_script, obj_is_carrying_obj, loot_obj, dialog_obj, obj_under_cursor, get_object_data, get_flags, set_flags, obj_is_openable, get_proto_data, set_proto_data | - |
|
||||||
| Other / Game management | set_movie_path<br>stop/resume_game<br>mark_movie_played<br>game_loaded<br>get_game_mode<br>get_uptime<br>signal_close_game | implemented: game_loaded, get_game_mode, get_uptime, signal_close_game | - |
|
| Other / Game management | set_movie_path<br>stop/resume_game<br>mark_movie_played<br>game_loaded<br>get_game_mode<br>get_uptime<br>signal_close_game | implemented: game_loaded, get_game_mode, get_uptime, signal_close_game | - |
|
||||||
| Gameplay tweaks | set_pickpocket_max<br>set_hit_chance_max<br>set_xp_mod<br>set_critter_hit_chance_mod<br>set_base_hit_chance_mod<br>set_hp_per_level_mod<br>get_unspent_ap_bonus<br>gdialog_get_barter_mod<br>set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>set_inven_ap_cost<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>get_inven_ap_cost<br>set_drugs_data<br>get_kill_counter<br>mod_kill_counter<br>set_pipboy_available | implemented: gdialog_get_barter_mod | - |
|
| Gameplay tweaks | set_pickpocket_max<br>set_hit_chance_max<br>set_xp_mod<br>set_critter_hit_chance_mod<br>set_base_hit_chance_mod<br>set_hp_per_level_mod<br>get_unspent_ap_bonus<br>gdialog_get_barter_mod<br>set_unspent_ap_bonus<br>get/set_unspent_ap_perk_bonus<br>set_inven_ap_cost<br>set_base_pickpocket_mod<br>set_critter_pickpocket_mod<br>get_inven_ap_cost<br>set_drugs_data<br>get_kill_counter<br>mod_kill_counter<br>set_pipboy_available | implemented: gdialog_get_barter_mod | - |
|
||||||
| NPCs | inc_npc_level<br>get_npc_level<br>npc_engine_level_up | not implemented | - |
|
| NPCs | inc_npc_level<br>get_npc_level<br>npc_engine_level_up | not implemented | - |
|
||||||
@@ -100,8 +104,8 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
|||||||
| InvenWield | `HOOK_INVENWIELD` | đźš« | - |
|
| InvenWield | `HOOK_INVENWIELD` | đźš« | - |
|
||||||
| AdjustFID | `HOOK_ADJUSTFID` | đźš« | - |
|
| AdjustFID | `HOOK_ADJUSTFID` | đźš« | - |
|
||||||
| CombatTurn | `HOOK_COMBATTURN` | âś… | - |
|
| CombatTurn | `HOOK_COMBATTURN` | âś… | - |
|
||||||
| StdProcedure | `HOOK_STDPROCEDURE` | đźš« | Et tu |
|
| StdProcedure | `HOOK_STDPROCEDURE` | âś… | - |
|
||||||
| StdProcedureEnd | `HOOK_STDPROCEDURE_END` | đźš« | - |
|
| StdProcedureEnd | `HOOK_STDPROCEDURE_END` | âś… | - |
|
||||||
| CarTravel | `HOOK_CARTRAVEL` | đźš« | - |
|
| CarTravel | `HOOK_CARTRAVEL` | đźš« | - |
|
||||||
| SetGlobalVar | `HOOK_SETGLOBALVAR` | đźš« | - |
|
| SetGlobalVar | `HOOK_SETGLOBALVAR` | đźš« | - |
|
||||||
| RestTimer | `HOOK_RESTTIMER` | đźš« | Et tu |
|
| RestTimer | `HOOK_RESTTIMER` | đźš« | Et tu |
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
;
|
||||||
|
; Game general config
|
||||||
|
;
|
||||||
|
; Fallout 2
|
||||||
|
;
|
||||||
|
|
||||||
|
[start]
|
||||||
|
; Starting year, month, day. Month and day are 0-indexed (0 = January, 0 = first day of month).
|
||||||
|
year=2241
|
||||||
|
month=6
|
||||||
|
day=24
|
||||||
|
; To start a new game somewhere other than artemple.map, set this to the map file name.
|
||||||
|
map=
|
||||||
|
; Starting (tribal) and default (jumpsuit) player models. Can also be changed in-game via script.
|
||||||
|
model_male=hmwarr
|
||||||
|
model_male_default=hmjmps
|
||||||
|
model_female=hfprim
|
||||||
|
model_female_default=hfjmps
|
||||||
|
; Set to 1 if you want the pipboy to be available at the start of the game.
|
||||||
|
; Set to 2 to make the pipboy available by only skipping the vault suit movie check.
|
||||||
|
pipboy=0
|
||||||
|
|
||||||
|
[karma]
|
||||||
|
; FRM numbers for karma icons on the character screen. Number of points entries should be 1 less than number of frms entries.
|
||||||
|
; Example: frms=47,48,49 points=-100,100
|
||||||
|
frms=
|
||||||
|
points=
|
||||||
|
|
||||||
|
[items]
|
||||||
|
; Proto IDs for healing items.
|
||||||
|
stimpak=40
|
||||||
|
super_stimpak=144
|
||||||
|
healing_powder=273
|
||||||
|
|
||||||
|
[dialog]
|
||||||
|
; Set to 1 to prevent using 0 to escape from dialogue at any time.
|
||||||
|
no_exit_hotkey=1
|
||||||
|
; Set to 1 to allow using '^' in dialog msg files to specify gender-based alternative text.
|
||||||
|
; Text must be enclosed in angle brackets, e.g. <MaleText^FemaleText>.
|
||||||
|
gender_words=0
|
||||||
|
|
||||||
|
[main_menu]
|
||||||
|
; Custom version string shown on the main menu. Supports up to two %d placeholders for the game version numbers.
|
||||||
|
; Example: FALLOUT II v1.02d
|
||||||
|
version_string=
|
||||||
|
; Font color for the version string and copyright text. Last byte picks the color (default 0x3C).
|
||||||
|
; First byte flags: 1 - version string only, 2 - underline, 4 - monospace font.
|
||||||
|
; Example: 0x000055
|
||||||
|
font_color=0
|
||||||
|
; Font color for the main menu button text.
|
||||||
|
big_font_color=0
|
||||||
|
; Pixel offset for main menu buttons.
|
||||||
|
offset_x=0
|
||||||
|
offset_y=0
|
||||||
|
; Pixel offset for the copyright text line.
|
||||||
|
credits_offset_x=0
|
||||||
|
credits_offset_y=0
|
||||||
|
|
||||||
|
[movies]
|
||||||
|
; Number of days after game start when each Hakunin dream sequence becomes available.
|
||||||
|
artimer1=90
|
||||||
|
artimer2=180
|
||||||
|
artimer3=270
|
||||||
|
artimer4=360
|
||||||
|
|
||||||
|
[combat]
|
||||||
|
; Damage formula used to calculate combat damage.
|
||||||
|
; 0 - Fallout default, 1 - Glovz's Damage Fix, 2 - Glovz's Damage Fix with Damage Multiplier tweak, 5 - Haenlomal's Yet Another Ammo Mod
|
||||||
|
; Don't change this unless another mod explicitly requires it.
|
||||||
|
damage_formula=0
|
||||||
|
; Set to 1 to fix the bug that caused bonus HtH damage to not be applied correctly.
|
||||||
|
bonus_hth_damage_fix=1
|
||||||
|
; Set to 1 to remove the time limits that prevent critical hits/misses in the first few days of the game.
|
||||||
|
remove_critical_time_limits=0
|
||||||
|
; Set to 1 to allow science and repair to be used on the player, or 2 for all critters (rather than only brahmin/robots).
|
||||||
|
science_on_critters=0
|
||||||
|
; Set to 1 to enable modified burst bullet distribution (spray mod).
|
||||||
|
burst_enabled=0
|
||||||
|
; Ratio of bullets going to the center group vs. left/right in burst attacks. Multiplier is capped at divisor.
|
||||||
|
burst_center_mult=1
|
||||||
|
burst_center_div=3
|
||||||
|
; Ratio of center-group bullets that target the primary target directly. Multiplier is capped at divisor.
|
||||||
|
burst_target_mult=1
|
||||||
|
burst_target_div=2
|
||||||
|
|
||||||
|
[explosions]
|
||||||
|
; Set to 1 to make explosions and projectiles emit light.
|
||||||
|
emit_light=0
|
||||||
|
; Dynamite damage range. Max is capped at 9999; min is capped at max.
|
||||||
|
dynamite_max=50
|
||||||
|
dynamite_min=30
|
||||||
|
; Plastic explosive damage range. Max is capped at 9999; min is capped at max.
|
||||||
|
plastic_explosive_max=80
|
||||||
|
plastic_explosive_min=40
|
||||||
|
|
||||||
|
[skilldex]
|
||||||
|
; FRM numbers for Skilldex skill cursors. Default is 293 for all skills.
|
||||||
|
lockpick=293
|
||||||
|
steal=293
|
||||||
|
traps=293
|
||||||
|
first_aid=293
|
||||||
|
doctor=293
|
||||||
|
science=293
|
||||||
|
repair=293
|
||||||
|
|
||||||
|
[worldmap]
|
||||||
|
; Set to 1 to prevent using number keys to enter unvisited areas on a town map.
|
||||||
|
town_map_hotkeys_fix=1
|
||||||
|
; Set to 1 to show travel markers on the world map, or 2 to show only when sneaking.
|
||||||
|
trail_markers=0
|
||||||
|
; Set to 1 to skip the encounter with Frank Horrigan.
|
||||||
|
disable_horrigan=0
|
||||||
|
; City reputation overrides. Syntax: city_id:global_id pairs separated by commas.
|
||||||
|
; Example: 0:5001,2:5003,3:5004
|
||||||
|
city_reputation_list=
|
||||||
|
|
||||||
|
[characters]
|
||||||
|
; Custom premade characters for the character selection screen.
|
||||||
|
; premade_paths is a comma-separated list of file names (max 11 chars each) in the premade\ folder, without extension.
|
||||||
|
; premade_fids is a comma-separated list of FRM numbers for the character portrait, matching the order of premade_paths.
|
||||||
|
; Example: premade_paths=combat,diplomat,stealth premade_fids=201,203,202
|
||||||
|
premade_paths=
|
||||||
|
premade_fids=
|
||||||
|
|
||||||
|
[text]
|
||||||
|
; Comma-separated list of extra game message file names (without .msg extension) to load from the game\ folder.
|
||||||
|
; Use 'filename:number' syntax to assign explicit IDs. Access via message_str_game script function.
|
||||||
|
extra_msg_file_list=
|
||||||
-127
@@ -6,19 +6,6 @@
|
|||||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
[Misc]
|
[Misc]
|
||||||
|
|
||||||
;Uncomment these lines to change the timers of how many days after the game starts Hakunin dream sequences will occur
|
|
||||||
;MovieTimer_artimer1=5000
|
|
||||||
;MovieTimer_artimer2=5000
|
|
||||||
;MovieTimer_artimer3=5000
|
|
||||||
;MovieTimer_artimer4=5000
|
|
||||||
|
|
||||||
;To start a new game somewhere other than artemple.map, uncomment the next line and set it to the map you want to load
|
|
||||||
;StartingMap=V13ent.map
|
|
||||||
|
|
||||||
;To change the 'FALLOUT II v1.02d' version string on the main menu, uncomment the next line
|
|
||||||
;You can use up to 2 %d's in this if you want to include Fallout's version number somewhere
|
|
||||||
;VersionString=FALLOUT II v1.02d
|
|
||||||
|
|
||||||
;To use a config file other than fallout2.cfg, uncomment the next line and add the name of your new file
|
;To use a config file other than fallout2.cfg, uncomment the next line and add the name of your new file
|
||||||
;ConfigFile=
|
;ConfigFile=
|
||||||
|
|
||||||
@@ -26,40 +13,6 @@
|
|||||||
;If you want to load multiple patch files (up to 1000) at once, you can include a %d in the file name (sprintf syntax)
|
;If you want to load multiple patch files (up to 1000) at once, you can include a %d in the file name (sprintf syntax)
|
||||||
;PatchFile=patch%03d.dat
|
;PatchFile=patch%03d.dat
|
||||||
|
|
||||||
;Set to 1 to allow using the caret character '^' in dialog msg files to specify alternative text in dialogue based on the player's gender
|
|
||||||
;The text must be enclosed in angle brackets (example: <MaleText^FemaleText>)
|
|
||||||
;DialogGenderWords=0
|
|
||||||
|
|
||||||
;To change the default and starting player models, uncomment the next four lines.
|
|
||||||
;The default models can also be changed in-game via script
|
|
||||||
;MaleStartModel=hmjmps
|
|
||||||
;MaleDefaultModel=hmjmps
|
|
||||||
;FemaleStartModel=hfjmps
|
|
||||||
;FemaleDefaultModel=hfjmps
|
|
||||||
|
|
||||||
;To change the starting year, month or day, uncomment the next 3 lines
|
|
||||||
;Both StartMonth and StartDay are 0-indexed (i.e. 0 is January or the first day of a month)
|
|
||||||
;StartYear=2241
|
|
||||||
;StartMonth=01
|
|
||||||
;StartDay=01
|
|
||||||
|
|
||||||
;Set to 1 if you want the pipboy to be available at the start of the game
|
|
||||||
;Set to 2 to make the pipboy available by only skipping the vault suit movie check
|
|
||||||
;PipBoyAvailableAtGameStart=1
|
|
||||||
|
|
||||||
;Choose the damage formula used to calculate combat damage.
|
|
||||||
;Don't set this to anything other than 0 unless another mod you're using explicitly tells you to!
|
|
||||||
;0 - Fallout default
|
|
||||||
;1 - Glovz's Damage Fix
|
|
||||||
;2 - Glovz's Damage Fix with Damage Multiplier tweak
|
|
||||||
;5 - Haenlomal's Yet Another Ammo Mod
|
|
||||||
;DamageFormula=0
|
|
||||||
|
|
||||||
;Prevents you from using 0 to escape from dialogue at any time.
|
|
||||||
;DialogueFix=1
|
|
||||||
|
|
||||||
;Prevents you from using number keys to enter unvisited areas on a town map
|
|
||||||
TownMapHotkeysFix=1
|
|
||||||
|
|
||||||
;Set to 1 to use a CriticalOverrides.ini file to override the default critical table
|
;Set to 1 to use a CriticalOverrides.ini file to override the default critical table
|
||||||
;Set to 2 to use the default critical with bug fixes (doesn't require an ini)
|
;Set to 2 to use the default critical with bug fixes (doesn't require an ini)
|
||||||
@@ -67,86 +20,9 @@ TownMapHotkeysFix=1
|
|||||||
;If the ExtraKillTypes option is enabled, this should be set to 3, with containing entries for any new types
|
;If the ExtraKillTypes option is enabled, this should be set to 3, with containing entries for any new types
|
||||||
;Must be non-zero to use the edit/get/reset_critical script functions
|
;Must be non-zero to use the edit/get/reset_critical script functions
|
||||||
;OverrideCriticalTable=2
|
;OverrideCriticalTable=2
|
||||||
|
|
||||||
;Change the Skilldex cursor FRM numbers
|
|
||||||
;Default is 293 for all skills
|
|
||||||
Lockpick=293
|
|
||||||
Steal=293
|
|
||||||
Traps=293
|
|
||||||
FirstAid=293
|
|
||||||
Doctor=293
|
|
||||||
Science=293
|
|
||||||
Repair=293
|
|
||||||
|
|
||||||
;Uncomment these lines to control the premade characters offered when starting a new game
|
|
||||||
;Multiple options should be separated by commas, and there must be the same number of entries in both lines
|
|
||||||
;Each name in PremadePaths is limited to 11 characters
|
|
||||||
;PremadePaths=combat,diplomat,stealth
|
|
||||||
;PremadeFIDs=201,203,202
|
|
||||||
|
|
||||||
;Use this line to modify the list of cities and their associated global variables used for city reputations
|
|
||||||
;Syntax is 'city id:global id', with each city/global pair separated by a comma.
|
|
||||||
;CityRepsList=0:5001,2:5003,3:5004,4:5005,5:5006,6:5007,7:5008,8:5009,10:5011,11:5012,60:1640
|
|
||||||
|
|
||||||
;Set to 1 to add additional pages of save slots !!! can be implemented !!!
|
;Set to 1 to add additional pages of save slots !!! can be implemented !!!
|
||||||
;ExtraSaveSlots=1
|
;ExtraSaveSlots=1
|
||||||
|
|
||||||
;These lines allow you to control the karma FRMs displayed on the character screen
|
|
||||||
;Number of KarmaPoints should be 1 less than number of KarmaFRMs
|
|
||||||
;KarmaFRMs=47,48,49
|
|
||||||
;KarmaPoints=-100,100
|
|
||||||
|
|
||||||
;Set to 1 to allow science and repair to be used on the player, or 2 for all critters. (Rather than only brahmin/robots)
|
|
||||||
ScienceOnCritters=0
|
|
||||||
|
|
||||||
;Set to 1 to fix the bug that caused bonus HtH damage to not be applied correctly.
|
|
||||||
BonusHtHDamageFix=1
|
|
||||||
|
|
||||||
;Set to 1 to remove the limits that stop the game from rolling critical successes/failures in the first few days of game time
|
|
||||||
RemoveCriticalTimelimits=0
|
|
||||||
|
|
||||||
;Change the colour of the font used on the main menu for the Fallout/sfall version string and copyright text
|
|
||||||
;It's the last byte ('3C' by default) that picks the colour used. The first byte supplies additional flags for this option
|
|
||||||
;1 - change the colour for the version string only
|
|
||||||
;2 - underline text for the version string
|
|
||||||
;4 - use monospace font for the version string
|
|
||||||
;MainMenuFontColour=0x000055
|
|
||||||
;Change the colour of the font used on the main menu for the button text
|
|
||||||
;MainMenuBigFontColour=0x3C
|
|
||||||
|
|
||||||
;Uncomment the next four lines to move the main menu buttons and credit text (the 'Copyright(c)' line on the main menu)
|
|
||||||
;MainMenuOffsetX=392
|
|
||||||
;MainMenuOffsetY=26
|
|
||||||
;MainMenuCreditsOffsetX=0
|
|
||||||
;MainMenuCreditsOffsetY=0
|
|
||||||
|
|
||||||
;These options modify the bullet distribution of burst attacks
|
|
||||||
;All the bullets are divided into three groups: center, left, and right
|
|
||||||
;These groups will then travel along three parallel tracks, trying to hit targets on the way
|
|
||||||
;CenterMult/Div set the ratio of how many bullets go to the center group, and the remaining are divided equally to the left and right sides
|
|
||||||
;TargetMult/Div set the ratio of how many bullets in the center group will attack the primary target directly
|
|
||||||
;Multiplier values are capped at divisor values
|
|
||||||
;ComputeSpray_CenterMult=1
|
|
||||||
;ComputeSpray_CenterDiv=3
|
|
||||||
;ComputeSpray_TargetMult=1
|
|
||||||
;ComputeSpray_TargetDiv=2
|
|
||||||
|
|
||||||
;Set to 1 to make explosions and projectiles emit light
|
|
||||||
;ExplosionsEmitLight=1
|
|
||||||
|
|
||||||
;Uncomment these lines to change explosives damage. DmgMax can be set to 9999 at max, and DmgMin is capped at DmgMax
|
|
||||||
;Dynamite_DmgMax=50
|
|
||||||
;Dynamite_DmgMin=30
|
|
||||||
;PlasticExplosive_DmgMax=80
|
|
||||||
;PlasticExplosive_DmgMin=40
|
|
||||||
|
|
||||||
;To add additional game msg files, uncomment the next line and set a comma delimited list of filenames without .msg extension
|
|
||||||
;By default, the files will have consecutive numbers assigned beginning with 0
|
|
||||||
;You can use the syntax 'filename:number' to manually assign numbers to specific msg files, with each pair separated by a comma
|
|
||||||
;If a file after the specified pair does not have a number assigned, it will have the next consecutive number from the last pair
|
|
||||||
;You need to use the message_str_game script function to get messages from the files
|
|
||||||
;ExtraGameMsgFileList=
|
|
||||||
|
|
||||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
; Configuration ini files
|
; Configuration ini files
|
||||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
@@ -165,9 +41,6 @@ RemoveCriticalTimelimits=0
|
|||||||
;See the Unarmed.ini in the modders pack for an example file
|
;See the Unarmed.ini in the modders pack for an example file
|
||||||
;UnarmedFile=sfall\Unarmed.ini
|
;UnarmedFile=sfall\Unarmed.ini
|
||||||
|
|
||||||
;To change some engine parameters for the game mechanics, uncomment the next line
|
|
||||||
;TweaksFile=sfall\Tweaks.ini
|
|
||||||
|
|
||||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
[Scripts]
|
[Scripts]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "sfall.h"
|
||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
#define TEST_SCRIPT_INDEX (2)
|
||||||
|
// Depends on Test0.int, which provides a controllable object script helper.
|
||||||
|
// Put the compiled helper at mods/test_script_override/scripts/Test0.int,
|
||||||
|
// and add "test_script_override" to mod_order.txt. The helper must live there
|
||||||
|
// (and not scripts/) because patch000.dat already contains a stock Test0.int and
|
||||||
|
// scripts/ load before it.
|
||||||
|
// Without Test0, these 2 tests will fail:
|
||||||
|
// - "set_script normal hp"
|
||||||
|
// - "set_script no map_enter hp"
|
||||||
|
|
||||||
|
variable testScriptObj := 0;
|
||||||
|
|
||||||
|
procedure create_test_object begin
|
||||||
|
if (testScriptObj != 0) then return;
|
||||||
|
testScriptObj := create_object_sid(obj_pid(dude_obj), tile_num_in_direction(tile_num(dude_obj), has_trait(TRAIT_OBJECT, dude_obj, OBJECT_CUR_ROT), 3), elevation(dude_obj), -1);
|
||||||
|
end
|
||||||
|
|
||||||
|
procedure stdprocedure_hook begin
|
||||||
|
if (get_sfall_arg_at(0) != 15) then return;
|
||||||
|
|
||||||
|
if (get_sfall_arg_at(3)) then begin
|
||||||
|
set_sfall_global("T0HAFTR1", 1);
|
||||||
|
end else begin
|
||||||
|
set_sfall_global("T0HBEFO1", 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
procedure exercise_set_script(variable scriptId, variable expectedHp, variable expectedBeforeHook, variable expectedAfterHook, variable desc) begin
|
||||||
|
set_sfall_global("T0MAPEN1", 0);
|
||||||
|
set_sfall_global("T0HBEFO1", 0);
|
||||||
|
set_sfall_global("T0HAFTR1", 0);
|
||||||
|
set_script(testScriptObj, scriptId);
|
||||||
|
call assertEquals(desc + " get_script", get_script(testScriptObj), TEST_SCRIPT_INDEX);
|
||||||
|
call assertEquals(desc + " map_enter global", get_sfall_global_int("T0MAPEN1"), expectedHp);
|
||||||
|
call assertEquals(desc + " stdprocedure hook before", get_sfall_global_int("T0HBEFO1"), expectedBeforeHook);
|
||||||
|
call assertEquals(desc + " stdprocedure hook after", get_sfall_global_int("T0HAFTR1"), expectedAfterHook);
|
||||||
|
remove_script(testScriptObj);
|
||||||
|
call assertEquals(desc + " remove_script clears get_script", get_script(testScriptObj), 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
procedure start begin
|
||||||
|
if (not game_loaded) then return;
|
||||||
|
|
||||||
|
display_msg("Testing set_script/remove_script/get_script...");
|
||||||
|
register_hook_proc(HOOK_STDPROCEDURE, stdprocedure_hook);
|
||||||
|
register_hook_proc(HOOK_STDPROCEDURE_END, stdprocedure_hook);
|
||||||
|
call create_test_object;
|
||||||
|
|
||||||
|
call exercise_set_script(TEST_SCRIPT_INDEX, 22, 1, 1, "set_script normal");
|
||||||
|
call exercise_set_script(TEST_SCRIPT_INDEX bwor 0x80000000, 11, 0, 0, "set_script no map_enter");
|
||||||
|
|
||||||
|
destroy_object(testScriptObj);
|
||||||
|
testScriptObj := 0;
|
||||||
|
|
||||||
|
call report_test_results("script_manipulation");
|
||||||
|
end
|
||||||
+2
-2
@@ -9,6 +9,7 @@
|
|||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
#include "combat_ai.h"
|
#include "combat_ai.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "critter.h"
|
#include "critter.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "display_monitor.h"
|
#include "display_monitor.h"
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "scripts.h"
|
#include "scripts.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sfall_config.h"
|
|
||||||
#include "sfall_script_hooks.h"
|
#include "sfall_script_hooks.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
@@ -1410,7 +1410,7 @@ int actionUseSkill(Object* user, Object* target, int skill)
|
|||||||
// SFALL: Science on critters patch.
|
// SFALL: Science on critters patch.
|
||||||
if (1) {
|
if (1) {
|
||||||
int targetType = SCIENCE_REPAIR_TARGET_TYPE_DEFAULT;
|
int targetType = SCIENCE_REPAIR_TARGET_TYPE_DEFAULT;
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SCIENCE_REPAIR_TARGET_TYPE_KEY, &targetType);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "science_on_critters", &targetType, SCIENCE_REPAIR_TARGET_TYPE_DEFAULT);
|
||||||
if (targetType == SCIENCE_REPAIR_TARGET_TYPE_DUDE) {
|
if (targetType == SCIENCE_REPAIR_TARGET_TYPE_DUDE) {
|
||||||
if (target == gDude) {
|
if (target == gDude) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
+5
-17
@@ -6,6 +6,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
@@ -13,7 +14,6 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sfall_config.h"
|
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
@@ -190,28 +190,16 @@ int artInit()
|
|||||||
|
|
||||||
// SFALL: Modify player model settings.
|
// SFALL: Modify player model settings.
|
||||||
char* jumpsuitMaleFileName = nullptr;
|
char* jumpsuitMaleFileName = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY, &jumpsuitMaleFileName);
|
configGetString(&gContentConfig, CONTENT_CONFIG_START_SECTION, "model_male_default", &jumpsuitMaleFileName, gDefaultJumpsuitMaleFileName);
|
||||||
if (jumpsuitMaleFileName == nullptr || jumpsuitMaleFileName[0] == '\0') {
|
|
||||||
jumpsuitMaleFileName = gDefaultJumpsuitMaleFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* jumpsuitFemaleFileName = nullptr;
|
char* jumpsuitFemaleFileName = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, &jumpsuitFemaleFileName);
|
configGetString(&gContentConfig, CONTENT_CONFIG_START_SECTION, "model_female_default", &jumpsuitFemaleFileName, gDefaultJumpsuitFemaleFileName);
|
||||||
if (jumpsuitFemaleFileName == nullptr || jumpsuitFemaleFileName[0] == '\0') {
|
|
||||||
jumpsuitFemaleFileName = gDefaultJumpsuitFemaleFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* tribalMaleFileName = nullptr;
|
char* tribalMaleFileName = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, &tribalMaleFileName);
|
configGetString(&gContentConfig, CONTENT_CONFIG_START_SECTION, "model_male", &tribalMaleFileName, gDefaultTribalMaleFileName);
|
||||||
if (tribalMaleFileName == nullptr || tribalMaleFileName[0] == '\0') {
|
|
||||||
tribalMaleFileName = gDefaultTribalMaleFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* tribalFemaleFileName = nullptr;
|
char* tribalFemaleFileName = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, &tribalFemaleFileName);
|
configGetString(&gContentConfig, CONTENT_CONFIG_START_SECTION, "model_female", &tribalFemaleFileName, gDefaultTribalFemaleFileName);
|
||||||
if (tribalFemaleFileName == nullptr || tribalFemaleFileName[0] == '\0') {
|
|
||||||
tribalFemaleFileName = gDefaultTribalFemaleFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* critterFileNames = gArtListDescriptions[OBJ_TYPE_CRITTER].fileNames;
|
char* critterFileNames = gArtListDescriptions[OBJ_TYPE_CRITTER].fileNames;
|
||||||
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) {
|
||||||
|
|||||||
+6
-17
@@ -11,6 +11,7 @@
|
|||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "critter.h"
|
#include "critter.h"
|
||||||
#include "cycle.h"
|
#include "cycle.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
@@ -37,7 +38,6 @@
|
|||||||
#include "platform_compat.h"
|
#include "platform_compat.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "scripts.h"
|
#include "scripts.h"
|
||||||
#include "sfall_config.h"
|
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
@@ -7167,22 +7167,14 @@ static int genericReputationCompare(const void* a1, const void* a2)
|
|||||||
static void customKarmaFolderInit()
|
static void customKarmaFolderInit()
|
||||||
{
|
{
|
||||||
char* karmaFrms = nullptr;
|
char* karmaFrms = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_KARMA_FRMS_KEY, &karmaFrms);
|
configGetString(&gContentConfig, CONTENT_CONFIG_KARMA_SECTION, "frms", &karmaFrms, "");
|
||||||
if (karmaFrms != nullptr && karmaFrms[0] == '\0') {
|
if (!*karmaFrms) {
|
||||||
karmaFrms = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (karmaFrms == nullptr) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* karmaPoints = nullptr;
|
char* karmaPoints = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_KARMA_POINTS_KEY, &karmaPoints);
|
configGetString(&gContentConfig, CONTENT_CONFIG_KARMA_SECTION, "points", &karmaPoints, "");
|
||||||
if (karmaPoints != nullptr && karmaPoints[0] == '\0') {
|
if (!*karmaPoints) {
|
||||||
karmaPoints = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (karmaPoints == nullptr) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7256,10 +7248,7 @@ static int customKarmaFolderGetFrmId()
|
|||||||
static void customTownReputationInit()
|
static void customTownReputationInit()
|
||||||
{
|
{
|
||||||
char* reputationList = nullptr;
|
char* reputationList = nullptr;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CITY_REPUTATION_LIST_KEY, &reputationList);
|
configGetString(&gContentConfig, CONTENT_CONFIG_WORLDMAP_SECTION, "city_reputation_list", &reputationList, nullptr);
|
||||||
if (reputationList != nullptr && *reputationList == '\0') {
|
|
||||||
reputationList = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* curr = reputationList;
|
char* curr = reputationList;
|
||||||
while (curr != nullptr) {
|
while (curr != nullptr) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "character_editor.h"
|
#include "character_editor.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "critter.h"
|
#include "critter.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -26,7 +27,6 @@
|
|||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sfall_config.h"
|
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
@@ -900,16 +900,10 @@ static bool characterSelectorWindowFatalError(bool result)
|
|||||||
void premadeCharactersInit()
|
void premadeCharactersInit()
|
||||||
{
|
{
|
||||||
char* fileNamesString;
|
char* fileNamesString;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FILE_NAMES_KEY, &fileNamesString);
|
configGetString(&gContentConfig, CONTENT_CONFIG_CHARACTERS_SECTION, "premade_paths", &fileNamesString, nullptr);
|
||||||
if (fileNamesString != nullptr && *fileNamesString == '\0') {
|
|
||||||
fileNamesString = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* faceFidsString;
|
char* faceFidsString;
|
||||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FACE_FIDS_KEY, &faceFidsString);
|
configGetString(&gContentConfig, CONTENT_CONFIG_CHARACTERS_SECTION, "premade_fids", &faceFidsString, nullptr);
|
||||||
if (faceFidsString != nullptr && *faceFidsString == '\0') {
|
|
||||||
faceFidsString = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileNamesString != nullptr && faceFidsString != nullptr) {
|
if (fileNamesString != nullptr && faceFidsString != nullptr) {
|
||||||
int fileNamesLength = 0;
|
int fileNamesLength = 0;
|
||||||
|
|||||||
+21
-16
@@ -9,6 +9,7 @@
|
|||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "combat_ai.h"
|
#include "combat_ai.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "critter.h"
|
#include "critter.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -1983,13 +1984,14 @@ static const char* gCritDataMemberKeys[CRIT_DATA_MEMBER_COUNT] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool gBurstModEnabled = false;
|
static bool gBurstModEnabled = false;
|
||||||
static int gBurstModCenterMultiplier = SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER;
|
static int gBurstModCenterMultiplier = 1;
|
||||||
static int gBurstModCenterDivisor = SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR;
|
static int gBurstModCenterDivisor = 3;
|
||||||
static int gBurstModTargetMultiplier = SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_MULTIPLIER;
|
static int gBurstModTargetMultiplier = 1;
|
||||||
static int gBurstModTargetDivisor = SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_DIVISOR;
|
static int gBurstModTargetDivisor = 2;
|
||||||
static UnarmedHitDescription gUnarmedHitDescriptions[HIT_MODE_COUNT];
|
static UnarmedHitDescription gUnarmedHitDescriptions[HIT_MODE_COUNT];
|
||||||
static int gDamageCalculationType;
|
static int gDamageCalculationType;
|
||||||
static bool gBonusHthDamageFix;
|
static bool gBonusHthDamageFix;
|
||||||
|
static bool gRemoveCriticalTimeLimits;
|
||||||
static bool gDisplayBonusDamage;
|
static bool gDisplayBonusDamage;
|
||||||
|
|
||||||
// combat_init
|
// combat_init
|
||||||
@@ -4237,12 +4239,8 @@ static int attackComputeCriticalFailure(Attack* attack)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attack->attacker == gDude) {
|
if (attack->attacker == gDude) {
|
||||||
// SFALL: Remove criticals time limits.
|
|
||||||
bool criticalsTimeLimitsRemoved = false;
|
|
||||||
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_REMOVE_CRITICALS_TIME_LIMITS_KEY, &criticalsTimeLimitsRemoved);
|
|
||||||
|
|
||||||
unsigned int gameTime = gameTimeGetTime();
|
unsigned int gameTime = gameTimeGetTime();
|
||||||
if (!criticalsTimeLimitsRemoved && gameTime / GAME_TIME_TICKS_PER_DAY < 6) {
|
if (!gRemoveCriticalTimeLimits && gameTime / GAME_TIME_TICKS_PER_DAY < 6) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6088,6 +6086,8 @@ int combatGetTargetHighlight()
|
|||||||
|
|
||||||
static void criticalsInit()
|
static void criticalsInit()
|
||||||
{
|
{
|
||||||
|
configGetBool(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "remove_critical_time_limits", &gRemoveCriticalTimeLimits, false);
|
||||||
|
|
||||||
int mode = 2;
|
int mode = 2;
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_OVERRIDE_CRITICALS_MODE_KEY, &mode);
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_OVERRIDE_CRITICALS_MODE_KEY, &mode);
|
||||||
if (mode < 0 || mode > 3) {
|
if (mode < 0 || mode > 3) {
|
||||||
@@ -6346,12 +6346,17 @@ void criticalsResetValue(int killType, int hitLocation, int effect, int dataMemb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool criticalsNoTimeLimits()
|
||||||
|
{
|
||||||
|
return gRemoveCriticalTimeLimits;
|
||||||
|
}
|
||||||
|
|
||||||
static void burstModInit()
|
static void burstModInit()
|
||||||
{
|
{
|
||||||
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_ENABLED_KEY, &gBurstModEnabled);
|
configGetBool(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "burst_enabled", &gBurstModEnabled);
|
||||||
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_CENTER_MULTIPLIER_KEY, &gBurstModCenterMultiplier);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "burst_center_mult", &gBurstModCenterMultiplier, 1);
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_CENTER_DIVISOR_KEY, &gBurstModCenterDivisor);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "burst_center_div", &gBurstModCenterDivisor, 3);
|
||||||
if (gBurstModCenterDivisor < 1) {
|
if (gBurstModCenterDivisor < 1) {
|
||||||
gBurstModCenterDivisor = 1;
|
gBurstModCenterDivisor = 1;
|
||||||
}
|
}
|
||||||
@@ -6359,8 +6364,8 @@ static void burstModInit()
|
|||||||
gBurstModCenterMultiplier = gBurstModCenterDivisor;
|
gBurstModCenterMultiplier = gBurstModCenterDivisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY, &gBurstModTargetMultiplier);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "burst_target_mult", &gBurstModTargetMultiplier, 1);
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY, &gBurstModTargetDivisor);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "burst_target_div", &gBurstModTargetDivisor, 2);
|
||||||
if (gBurstModTargetDivisor < 1) {
|
if (gBurstModTargetDivisor < 1) {
|
||||||
gBurstModTargetDivisor = 1;
|
gBurstModTargetDivisor = 1;
|
||||||
}
|
}
|
||||||
@@ -6701,10 +6706,10 @@ static int unarmedGetHitModeInRange(int firstHitMode, int lastHitMode, bool isSe
|
|||||||
static void damageModInit()
|
static void damageModInit()
|
||||||
{
|
{
|
||||||
gDamageCalculationType = DAMAGE_CALCULATION_TYPE_VANILLA;
|
gDamageCalculationType = DAMAGE_CALCULATION_TYPE_VANILLA;
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DAMAGE_MOD_FORMULA_KEY, &gDamageCalculationType);
|
configGetInt(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "damage_formula", &gDamageCalculationType, DAMAGE_CALCULATION_TYPE_VANILLA);
|
||||||
|
|
||||||
gBonusHthDamageFix = true;
|
gBonusHthDamageFix = true;
|
||||||
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BONUS_HTH_DAMAGE_FIX_KEY, &gBonusHthDamageFix);
|
configGetBool(&gContentConfig, CONTENT_CONFIG_COMBAT_SECTION, "bonus_hth_damage_fix", &gBonusHthDamageFix);
|
||||||
|
|
||||||
gDisplayBonusDamage = settings.ui.display_bonus_damage;
|
gDisplayBonusDamage = settings.ui.display_bonus_damage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ int combatGetTargetHighlight();
|
|||||||
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember);
|
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||||
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value);
|
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value);
|
||||||
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember);
|
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||||
|
bool criticalsNoTimeLimits();
|
||||||
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr);
|
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr);
|
||||||
int unarmedGetBonusCriticalChance(int hitMode);
|
int unarmedGetBonusCriticalChance(int hitMode);
|
||||||
int unarmedGetActionPointCost(int hitMode);
|
int unarmedGetActionPointCost(int hitMode);
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use const char** for valuePtr to enforce read-only API
|
||||||
// 0x42BF48
|
// 0x42BF48
|
||||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr)
|
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr)
|
||||||
{
|
{
|
||||||
@@ -330,6 +331,26 @@ bool configRead(Config* config, const char* filePath, bool isDb)
|
|||||||
configParseLine(config, string);
|
configParseLine(config, string);
|
||||||
}
|
}
|
||||||
fileClose(stream);
|
fileClose(stream);
|
||||||
|
|
||||||
|
// Build patch file path by inserting "#patch" before the extension.
|
||||||
|
char patchPath[COMPAT_MAX_PATH];
|
||||||
|
const char* dot = strrchr(filePath, '.');
|
||||||
|
if (dot != nullptr) {
|
||||||
|
snprintf(patchPath, sizeof(patchPath), "%.*s#patch%s", (int)(dot - filePath), filePath, dot);
|
||||||
|
} else {
|
||||||
|
snprintf(patchPath, sizeof(patchPath), "%s#patch", filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PatchContext {
|
||||||
|
Config* config;
|
||||||
|
char string[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||||
|
} patchCtx = { config };
|
||||||
|
|
||||||
|
xfileOpenEachReverse(patchPath, "rb", [](XFile* file, void* ctx) {
|
||||||
|
auto* pc = static_cast<PatchContext*>(ctx);
|
||||||
|
while (fileReadString(pc->string, sizeof(pc->string), file) != nullptr) {
|
||||||
|
configParseLine(pc->config, pc->string);
|
||||||
|
} }, &patchCtx);
|
||||||
} else {
|
} else {
|
||||||
FILE* stream = compat_fopen(filePath, "rt");
|
FILE* stream = compat_fopen(filePath, "rt");
|
||||||
|
|
||||||
@@ -833,6 +854,17 @@ bool configGetBool(Config* config, const char* sectionKey, const char* key, bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr, const bool defaultValue)
|
||||||
|
{
|
||||||
|
if (config == nullptr || sectionKey == nullptr || key == nullptr || valuePtr == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!configGetBool(config, sectionKey, key, valuePtr)) {
|
||||||
|
*valuePtr = defaultValue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Boolean-typed variant of [configGetInt].
|
// NOTE: Boolean-typed variant of [configGetInt].
|
||||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value)
|
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ void configFree(Config* config);
|
|||||||
bool configParseCommandLineArguments(Config* config, int argc, char** argv);
|
bool configParseCommandLineArguments(Config* config, int argc, char** argv);
|
||||||
// TODO: valuePtr must be const char**
|
// TODO: valuePtr must be const char**
|
||||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr);
|
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr);
|
||||||
|
// Tries to load a string value from Config into valuePtr without any conversion. If value doesn't exist, or it's an empty string, assigns defaultValue instead.
|
||||||
|
// No copy is performed. The returned pointer may refer either to an internal string or to defaultValue; it must be treated as read-only, and callers must ensure defaultValue remains valid for the duration of use.
|
||||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr, const char* defaultValue);
|
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr, const char* defaultValue);
|
||||||
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value);
|
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value);
|
||||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base = 0);
|
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base = 0);
|
||||||
@@ -49,6 +51,7 @@ bool configGetDouble(Config* config, const char* sectionKey, const char* key, do
|
|||||||
bool configSetDouble(Config* config, const char* sectionKey, const char* key, double value);
|
bool configSetDouble(Config* config, const char* sectionKey, const char* key, double value);
|
||||||
|
|
||||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr);
|
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr);
|
||||||
|
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr, bool defaultValue);
|
||||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value);
|
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "content_config.h"
|
||||||
|
|
||||||
|
#include "game_config_migration.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
Config gContentConfig;
|
||||||
|
|
||||||
|
constexpr char kConfigPath[] = R"(config\game.cfg)";
|
||||||
|
constexpr char kConfigPatchPath[] = R"(config\game#patch.cfg)";
|
||||||
|
|
||||||
|
void contentConfigInit()
|
||||||
|
{
|
||||||
|
if (gContentConfig.isInitialized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to migrate some settings from sfall.
|
||||||
|
contentConfigTryMigrateFromSfall(kConfigPatchPath);
|
||||||
|
|
||||||
|
if (!configInit(&gContentConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configRead(&gContentConfig, kConfigPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void contentConfigExit()
|
||||||
|
{
|
||||||
|
if (!gContentConfig.isInitialized()) return;
|
||||||
|
|
||||||
|
configFree(&gContentConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fallout
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef CONTENT_CONFIG_H
|
||||||
|
#define CONTENT_CONFIG_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
#define CONTENT_CONFIG_START_SECTION "start"
|
||||||
|
#define CONTENT_CONFIG_KARMA_SECTION "karma"
|
||||||
|
#define CONTENT_CONFIG_ITEMS_SECTION "items"
|
||||||
|
#define CONTENT_CONFIG_DIALOG_SECTION "dialog"
|
||||||
|
#define CONTENT_CONFIG_MAIN_MENU_SECTION "main_menu"
|
||||||
|
#define CONTENT_CONFIG_MOVIES_SECTION "movies"
|
||||||
|
#define CONTENT_CONFIG_COMBAT_SECTION "combat"
|
||||||
|
#define CONTENT_CONFIG_EXPLOSIONS_SECTION "explosions"
|
||||||
|
#define CONTENT_CONFIG_SKILLDEX_SECTION "skilldex"
|
||||||
|
#define CONTENT_CONFIG_WORLDMAP_SECTION "worldmap"
|
||||||
|
#define CONTENT_CONFIG_CHARACTERS_SECTION "characters"
|
||||||
|
#define CONTENT_CONFIG_TEXT_SECTION "text"
|
||||||
|
|
||||||
|
extern Config gContentConfig;
|
||||||
|
|
||||||
|
// Initialize content config and try to load it from file.
|
||||||
|
void contentConfigInit();
|
||||||
|
void contentConfigExit();
|
||||||
|
|
||||||
|
} // namespace fallout
|
||||||
|
|
||||||
|
#endif // CONTENT_CONFIG_H
|
||||||
@@ -11,7 +11,7 @@ typedef XFile File;
|
|||||||
typedef void FileReadProgressHandler();
|
typedef void FileReadProgressHandler();
|
||||||
typedef char* StrdupProc(const char* string);
|
typedef char* StrdupProc(const char* string);
|
||||||
|
|
||||||
int dbOpen(const char* filePath1, const char* filePath2);
|
int dbOpen(const char* filePath1, const char* filePath2 = nullptr);
|
||||||
int db_total();
|
int db_total();
|
||||||
void dbCloseAll();
|
void dbCloseAll();
|
||||||
int dbGetFileSize(const char* filePath, int* sizePtr);
|
int dbGetFileSize(const char* filePath, int* sizePtr);
|
||||||
|
|||||||
+5
-2
@@ -14,6 +14,11 @@ namespace fallout {
|
|||||||
// with a check for this value.
|
// with a check for this value.
|
||||||
#define DICTIONARY_MARKER 0xFEBAFEBA
|
#define DICTIONARY_MARKER 0xFEBAFEBA
|
||||||
|
|
||||||
|
bool Dictionary::isInitialized() const
|
||||||
|
{
|
||||||
|
return marker == DICTIONARY_MARKER;
|
||||||
|
}
|
||||||
|
|
||||||
static int dictionaryFindIndexForKey(Dictionary* dictionary, const char* key, int* index);
|
static int dictionaryFindIndexForKey(Dictionary* dictionary, const char* key, int* index);
|
||||||
|
|
||||||
// 0x4D9BA8
|
// 0x4D9BA8
|
||||||
@@ -28,8 +33,6 @@ int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize
|
|||||||
} else {
|
} else {
|
||||||
dictionary->io.readProc = nullptr;
|
dictionary->io.readProc = nullptr;
|
||||||
dictionary->io.writeProc = nullptr;
|
dictionary->io.writeProc = nullptr;
|
||||||
dictionary->io.field_8 = 0;
|
|
||||||
dictionary->io.field_C = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|||||||
+3
-5
@@ -8,13 +8,9 @@ namespace fallout {
|
|||||||
typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a3);
|
typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a3);
|
||||||
typedef int(DictionaryWriteProc)(FILE* stream, void* buffer, unsigned int size, int a3);
|
typedef int(DictionaryWriteProc)(FILE* stream, void* buffer, unsigned int size, int a3);
|
||||||
|
|
||||||
// NOTE: Last unnamed fields are likely seek, tell, and filelength.
|
|
||||||
typedef struct DictionaryIO {
|
typedef struct DictionaryIO {
|
||||||
DictionaryReadProc* readProc;
|
DictionaryReadProc* readProc;
|
||||||
DictionaryWriteProc* writeProc;
|
DictionaryWriteProc* writeProc;
|
||||||
int field_8;
|
|
||||||
int field_C;
|
|
||||||
int field_10;
|
|
||||||
} DictionaryIO;
|
} DictionaryIO;
|
||||||
|
|
||||||
// A tuple containing individual key-value pair of a dictionary.
|
// A tuple containing individual key-value pair of a dictionary.
|
||||||
@@ -30,7 +26,7 @@ typedef struct DictionaryEntry {
|
|||||||
// is added to dictionary. For this reason the size of the value's type is
|
// is added to dictionary. For this reason the size of the value's type is
|
||||||
// provided during dictionary initialization.
|
// provided during dictionary initialization.
|
||||||
typedef struct Dictionary {
|
typedef struct Dictionary {
|
||||||
int marker;
|
int marker = 0;
|
||||||
|
|
||||||
// The number of key/value pairs in the dictionary.
|
// The number of key/value pairs in the dictionary.
|
||||||
int entriesLength;
|
int entriesLength;
|
||||||
@@ -46,6 +42,8 @@ typedef struct Dictionary {
|
|||||||
|
|
||||||
// The array of key-value pairs.
|
// The array of key-value pairs.
|
||||||
DictionaryEntry* entries;
|
DictionaryEntry* entries;
|
||||||
|
|
||||||
|
bool isInitialized() const;
|
||||||
} Dictionary;
|
} Dictionary;
|
||||||
|
|
||||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io);
|
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io);
|
||||||
|
|||||||
+28
-3
@@ -13,6 +13,7 @@
|
|||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
#include "combat_ai.h"
|
#include "combat_ai.h"
|
||||||
|
#include "content_config.h"
|
||||||
#include "critter.h"
|
#include "critter.h"
|
||||||
#include "cycle.h"
|
#include "cycle.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
@@ -69,7 +70,6 @@
|
|||||||
#include "trait.h"
|
#include "trait.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "window_manager.h"
|
#include "window_manager.h"
|
||||||
#include "window_manager_private.h"
|
|
||||||
#include "worldmap.h"
|
#include "worldmap.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
@@ -88,6 +88,8 @@ static void showHelp();
|
|||||||
static int gameDbInit();
|
static int gameDbInit();
|
||||||
static void showSplash();
|
static void showSplash();
|
||||||
|
|
||||||
|
inline constexpr char kBaseModPath[] = "ce.dat";
|
||||||
|
|
||||||
// 0x501C9C
|
// 0x501C9C
|
||||||
static char _aGame_0[] = "game\\";
|
static char _aGame_0[] = "game\\";
|
||||||
|
|
||||||
@@ -152,6 +154,9 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Content config reads from the VFS, so it must be initialized after gameDbInit.
|
||||||
|
contentConfigInit();
|
||||||
|
|
||||||
// Message list repository is considered a specialized file manager, so
|
// Message list repository is considered a specialized file manager, so
|
||||||
// it should be initialized early in the process.
|
// it should be initialized early in the process.
|
||||||
messageListRepositoryInit();
|
messageListRepositoryInit();
|
||||||
@@ -495,6 +500,7 @@ void gameExit()
|
|||||||
messageListRepositoryExit();
|
messageListRepositoryExit();
|
||||||
dbCloseAll();
|
dbCloseAll();
|
||||||
settingsExit(true);
|
settingsExit(true);
|
||||||
|
contentConfigExit();
|
||||||
sfallConfigExit();
|
sfallConfigExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1343,6 +1349,18 @@ int showQuitConfirmationDialog()
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TryLoadBaseCEMod()
|
||||||
|
{
|
||||||
|
if (compat_access(kBaseModPath, 0) == 0) {
|
||||||
|
debugPrint("Loading base FO:CE mod: %s\n", kBaseModPath);
|
||||||
|
if (dbOpen(kBaseModPath) == -1) {
|
||||||
|
debugPrint("Error opening base mod file/folder!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrint("Error opening base mod: no file or folder name %s found.\n", kBaseModPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 0x44418C
|
// 0x44418C
|
||||||
static int gameDbInit()
|
static int gameDbInit()
|
||||||
{
|
{
|
||||||
@@ -1363,6 +1381,10 @@ static int gameDbInit()
|
|||||||
if (*patch_file_name == '\0') {
|
if (*patch_file_name == '\0') {
|
||||||
patch_file_name = nullptr;
|
patch_file_name = nullptr;
|
||||||
}
|
}
|
||||||
|
// Try to ensure that patches dir exists early. This is needed for auto-generated game.cfg later.
|
||||||
|
if (patch_file_name != nullptr) {
|
||||||
|
compat_mkdir_recursive(patch_file_name);
|
||||||
|
}
|
||||||
|
|
||||||
int master_db_handle = dbOpen(main_file_name, patch_file_name);
|
int master_db_handle = dbOpen(main_file_name, patch_file_name);
|
||||||
if (master_db_handle == -1) {
|
if (master_db_handle == -1) {
|
||||||
@@ -1397,14 +1419,17 @@ static int gameDbInit()
|
|||||||
snprintf(filename, sizeof(filename), path_file_name_template, patch_index);
|
snprintf(filename, sizeof(filename), path_file_name_template, patch_index);
|
||||||
|
|
||||||
if (compat_access(filename, 0) == 0) {
|
if (compat_access(filename, 0) == 0) {
|
||||||
dbOpen(filename, nullptr);
|
dbOpen(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load CE base mod after vanilla patches but before all regular mods.
|
||||||
|
TryLoadBaseCEMod();
|
||||||
|
|
||||||
sfallLoadMods();
|
sfallLoadMods();
|
||||||
|
|
||||||
if (compat_access("f2_res.dat", 0) == 0) {
|
if (compat_access("f2_res.dat", 0) == 0) {
|
||||||
dbOpen("f2_res.dat", nullptr);
|
dbOpen("f2_res.dat");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -4,8 +4,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "content_config.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "game_config.h"
|
#include "game_config.h"
|
||||||
#include "platform_compat.h"
|
#include "platform_compat.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "sfall_config.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
@@ -125,4 +129,168 @@ bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConf
|
|||||||
return migrated;
|
return migrated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr char kSfallMisc[] = "Misc";
|
||||||
|
constexpr char kSfallInterface[] = "Interface";
|
||||||
|
|
||||||
|
struct SfallMigrationEntry {
|
||||||
|
const char* sfallSection;
|
||||||
|
const char* sfallKey;
|
||||||
|
const char* targetSection;
|
||||||
|
const char* targetKey;
|
||||||
|
// If the sfall value matches this string, skip migration (value is already the default).
|
||||||
|
// nullptr means always migrate when the key is present.
|
||||||
|
const char* defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr SfallMigrationEntry kSfallMigrationEntries[] = {
|
||||||
|
// [start]
|
||||||
|
{ kSfallMisc, "StartingMap", CONTENT_CONFIG_START_SECTION, "map", "" },
|
||||||
|
{ kSfallMisc, "MaleStartModel", CONTENT_CONFIG_START_SECTION, "model_male", "hmwarr" },
|
||||||
|
{ kSfallMisc, "MaleDefaultModel", CONTENT_CONFIG_START_SECTION, "model_male_default", "hmjmps" },
|
||||||
|
{ kSfallMisc, "FemaleStartModel", CONTENT_CONFIG_START_SECTION, "model_female", "hfprim" },
|
||||||
|
{ kSfallMisc, "FemaleDefaultModel", CONTENT_CONFIG_START_SECTION, "model_female_default", "hfjmps" },
|
||||||
|
{ kSfallMisc, "PipBoyAvailableAtGameStart", CONTENT_CONFIG_START_SECTION, "pipboy", "0" },
|
||||||
|
// [karma]
|
||||||
|
{ kSfallMisc, "KarmaFRMs", CONTENT_CONFIG_KARMA_SECTION, "frms" },
|
||||||
|
{ kSfallMisc, "KarmaPoints", CONTENT_CONFIG_KARMA_SECTION, "points" },
|
||||||
|
// [dialog]
|
||||||
|
{ kSfallMisc, "DialogueFix", CONTENT_CONFIG_DIALOG_SECTION, "no_exit_hotkey", "1" },
|
||||||
|
{ kSfallMisc, "DialogGenderWords", CONTENT_CONFIG_DIALOG_SECTION, "gender_words", "0" },
|
||||||
|
// [main_menu]
|
||||||
|
{ kSfallMisc, "VersionString", CONTENT_CONFIG_MAIN_MENU_SECTION, "version_string" },
|
||||||
|
{ kSfallMisc, "MainMenuFontColour", CONTENT_CONFIG_MAIN_MENU_SECTION, "font_color", "0" },
|
||||||
|
{ kSfallMisc, "MainMenuBigFontColour", CONTENT_CONFIG_MAIN_MENU_SECTION, "big_font_color", "0" },
|
||||||
|
{ kSfallMisc, "MainMenuOffsetX", CONTENT_CONFIG_MAIN_MENU_SECTION, "offset_x", "0" },
|
||||||
|
{ kSfallMisc, "MainMenuOffsetY", CONTENT_CONFIG_MAIN_MENU_SECTION, "offset_y", "0" },
|
||||||
|
{ kSfallMisc, "MainMenuCreditsOffsetX", CONTENT_CONFIG_MAIN_MENU_SECTION, "credits_offset_x", "0" },
|
||||||
|
{ kSfallMisc, "MainMenuCreditsOffsetY", CONTENT_CONFIG_MAIN_MENU_SECTION, "credits_offset_y", "0" },
|
||||||
|
// [movies]
|
||||||
|
{ kSfallMisc, "MovieTimer_artimer1", CONTENT_CONFIG_MOVIES_SECTION, "artimer1", "90" },
|
||||||
|
{ kSfallMisc, "MovieTimer_artimer2", CONTENT_CONFIG_MOVIES_SECTION, "artimer2", "180" },
|
||||||
|
{ kSfallMisc, "MovieTimer_artimer3", CONTENT_CONFIG_MOVIES_SECTION, "artimer3", "270" },
|
||||||
|
{ kSfallMisc, "MovieTimer_artimer4", CONTENT_CONFIG_MOVIES_SECTION, "artimer4", "360" },
|
||||||
|
// [combat]
|
||||||
|
{ kSfallMisc, "DamageFormula", CONTENT_CONFIG_COMBAT_SECTION, "damage_formula", "0" },
|
||||||
|
{ kSfallMisc, "BonusHtHDamageFix", CONTENT_CONFIG_COMBAT_SECTION, "bonus_hth_damage_fix", "1" },
|
||||||
|
{ kSfallMisc, "RemoveCriticalTimelimits", CONTENT_CONFIG_COMBAT_SECTION, "remove_critical_time_limits", "0" },
|
||||||
|
{ kSfallMisc, "ScienceOnCritters", CONTENT_CONFIG_COMBAT_SECTION, "science_on_critters", "0" },
|
||||||
|
{ kSfallMisc, "ComputeSprayMod", CONTENT_CONFIG_COMBAT_SECTION, "burst_enabled", "0" },
|
||||||
|
{ kSfallMisc, "ComputeSpray_CenterMult", CONTENT_CONFIG_COMBAT_SECTION, "burst_center_mult", "1" },
|
||||||
|
{ kSfallMisc, "ComputeSpray_CenterDiv", CONTENT_CONFIG_COMBAT_SECTION, "burst_center_div", "3" },
|
||||||
|
{ kSfallMisc, "ComputeSpray_TargetMult", CONTENT_CONFIG_COMBAT_SECTION, "burst_target_mult", "1" },
|
||||||
|
{ kSfallMisc, "ComputeSpray_TargetDiv", CONTENT_CONFIG_COMBAT_SECTION, "burst_target_div", "2" },
|
||||||
|
// [explosions]
|
||||||
|
{ kSfallMisc, "ExplosionsEmitLight", CONTENT_CONFIG_EXPLOSIONS_SECTION, "emit_light", "0" },
|
||||||
|
{ kSfallMisc, "Dynamite_DmgMax", CONTENT_CONFIG_EXPLOSIONS_SECTION, "dynamite_max", "50" },
|
||||||
|
{ kSfallMisc, "Dynamite_DmgMin", CONTENT_CONFIG_EXPLOSIONS_SECTION, "dynamite_min", "30" },
|
||||||
|
{ kSfallMisc, "PlasticExplosive_DmgMax", CONTENT_CONFIG_EXPLOSIONS_SECTION, "plastic_explosive_max", "80" },
|
||||||
|
{ kSfallMisc, "PlasticExplosive_DmgMin", CONTENT_CONFIG_EXPLOSIONS_SECTION, "plastic_explosive_min", "40" },
|
||||||
|
// [skilldex]
|
||||||
|
{ kSfallMisc, "Lockpick", CONTENT_CONFIG_SKILLDEX_SECTION, "lockpick", "293" },
|
||||||
|
{ kSfallMisc, "Steal", CONTENT_CONFIG_SKILLDEX_SECTION, "steal", "293" },
|
||||||
|
{ kSfallMisc, "Traps", CONTENT_CONFIG_SKILLDEX_SECTION, "traps", "293" },
|
||||||
|
{ kSfallMisc, "FirstAid", CONTENT_CONFIG_SKILLDEX_SECTION, "first_aid", "293" },
|
||||||
|
{ kSfallMisc, "Doctor", CONTENT_CONFIG_SKILLDEX_SECTION, "doctor", "293" },
|
||||||
|
{ kSfallMisc, "Science", CONTENT_CONFIG_SKILLDEX_SECTION, "science", "293" },
|
||||||
|
{ kSfallMisc, "Repair", CONTENT_CONFIG_SKILLDEX_SECTION, "repair", "293" },
|
||||||
|
// [worldmap]
|
||||||
|
{ kSfallMisc, "TownMapHotkeysFix", CONTENT_CONFIG_WORLDMAP_SECTION, "town_map_hotkeys_fix", "1" },
|
||||||
|
{ kSfallMisc, "DisableHorrigan", CONTENT_CONFIG_WORLDMAP_SECTION, "disable_horrigan", "0" },
|
||||||
|
{ kSfallMisc, "CityRepsList", CONTENT_CONFIG_WORLDMAP_SECTION, "city_reputation_list" },
|
||||||
|
{ kSfallInterface, "WorldMapTravelMarkers", CONTENT_CONFIG_WORLDMAP_SECTION, "trail_markers", "0" },
|
||||||
|
// [characters]
|
||||||
|
{ kSfallMisc, "PremadePaths", CONTENT_CONFIG_CHARACTERS_SECTION, "premade_paths" },
|
||||||
|
{ kSfallMisc, "PremadeFIDs", CONTENT_CONFIG_CHARACTERS_SECTION, "premade_fids" },
|
||||||
|
// [text]
|
||||||
|
{ kSfallMisc, "ExtraGameMsgFileList", CONTENT_CONFIG_TEXT_SECTION, "extra_msg_file_list" },
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
// Migrate sfall settings from ddraw.ini to game.cfg.
|
||||||
|
//
|
||||||
|
// Runs once when no local game.cfg exists at contentConfigFilePath.
|
||||||
|
// Writes only the settings found in sfallConfig to a new local file.
|
||||||
|
static bool contentConfigMigrateFromSfall(Config* sfallConfig, const char* contentConfigFilePath)
|
||||||
|
{
|
||||||
|
assert(sfallConfig != nullptr && contentConfigFilePath != nullptr);
|
||||||
|
|
||||||
|
// Skip if a local game.cfg already exists (already migrated or user-managed).
|
||||||
|
if (compat_file_exists(contentConfigFilePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config migratedConfig;
|
||||||
|
if (!configInit(&migratedConfig)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool migrated = false;
|
||||||
|
// Migrate start year/month/day only when explicitly set (not the sfall -1 sentinel).
|
||||||
|
auto migrateStartInt = [&](const char* sfallKey, const char* targetKey, int defaultValue) {
|
||||||
|
int value;
|
||||||
|
if (configGetInt(sfallConfig, "Misc", sfallKey, &value) && value >= 0 && value != defaultValue) {
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "%d", value);
|
||||||
|
configSetString(&migratedConfig, CONTENT_CONFIG_START_SECTION, targetKey, buf);
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
migrateStartInt("StartYear", "year", 2241);
|
||||||
|
migrateStartInt("StartMonth", "month", 6);
|
||||||
|
migrateStartInt("StartDay", "day", 24);
|
||||||
|
|
||||||
|
for (const auto& entry : kSfallMigrationEntries) {
|
||||||
|
char* value;
|
||||||
|
if (configGetString(sfallConfig, entry.sfallSection, entry.sfallKey, &value)) {
|
||||||
|
if (value[0] == '\0' || entry.defaultValue != nullptr && strcmp(value, entry.defaultValue) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
configSetString(&migratedConfig, entry.targetSection, entry.targetKey, value);
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrated) {
|
||||||
|
// Ensure all directory components exist before writing.
|
||||||
|
char drive[COMPAT_MAX_DRIVE];
|
||||||
|
char dirPart[COMPAT_MAX_DIR];
|
||||||
|
char pathWithoutFile[COMPAT_MAX_PATH];
|
||||||
|
compat_splitpath(contentConfigFilePath, drive, dirPart, nullptr, nullptr);
|
||||||
|
compat_makepath(pathWithoutFile, drive, dirPart, nullptr, nullptr);
|
||||||
|
compat_mkdir_recursive(pathWithoutFile);
|
||||||
|
|
||||||
|
if (!configWrite(&migratedConfig, contentConfigFilePath, false)) {
|
||||||
|
debugPrint("Failed to write migrated settings to %s!\n", contentConfigFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configFree(&migratedConfig);
|
||||||
|
return migrated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void contentConfigTryMigrateFromSfall(const char* contentConfigPath)
|
||||||
|
{
|
||||||
|
if (!gSfallConfig.isInitialized() || gSfallConfig.entriesLength == 0) {
|
||||||
|
// Nothing to migrate.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& masterPatches = settings.system.master_patches_path;
|
||||||
|
if (masterPatches.empty()) {
|
||||||
|
debugPrint("Failed to migrate from ddraw.ini: no master_patches is set.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compat_file_exists(masterPatches.c_str())) {
|
||||||
|
// Master patches is pointing to a file instead of a folder. This shouldn't normally happen, so don't migrate in this case.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char contentCfgPath[COMPAT_MAX_PATH];
|
||||||
|
snprintf(contentCfgPath, sizeof(contentCfgPath), "%s\\%s", masterPatches.c_str(), contentConfigPath);
|
||||||
|
if (contentConfigMigrateFromSfall(&gSfallConfig, contentCfgPath)) {
|
||||||
|
debugPrint("Migrated settings from ddraw.ini to game.cfg.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user