From 398ad650b99505780694b31a2131276e38d5708d Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 5 Sep 2020 10:47:53 +0800 Subject: [PATCH] Added a fix to the weapon check in the Fast Shot trait * changed range check to type+range check, the same fix is also applied to FastShotTraitFix. Added more info to the description of FastShotFix option. --- artifacts/ddraw.ini | 12 ++-- artifacts/scripting/headers/define_extra.h | 3 +- sfall/Perks.cpp | 69 +++++++++++++++------- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 59a44e17..95bc1bc4 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -518,10 +518,10 @@ RemoveCriticalTimelimits=0 ;Change the colour of the font used on the main menu for the button text ;MainMenuBigFontColour=0x3C -;Two alternate fixes to the interaction between HtH attacks and the fast shot trait -;0 - Fallout 2 original behaviour -;1 - Haenlomal's fix, called shots are enabled for HtH attacks -;2 - Restoring the -1 AP bonus for HtH attacks (i.e. Fallout 1 behaviour) +;Alternative behaviors to the Fast Shot trait +;0 - Fallout 2 original behavior: -1 AP cost for ranged weapons; no aimed shots for all attacks +;1 - Haenlomal's fix: aimed shots are enabled for melee/unarmed weapons and HtH attacks +;2 - Alternative behavior: apply -1 AP cost to melee/unarmed weapons and HtH attacks FastShotFix=1 ;Set to 1 to boost the maximum number of script names from 1450 to 10000 @@ -542,9 +542,9 @@ CritterInvSizeLimit=100 MotionScannerFlags=1 ;Set a value greater than 40 to change the maximum encounter table size (enc_## in worldmap.txt) -;Note: Setting this greater than 50 requires renumbering all message lines for the encounter tables in worldmap.msg -;so that the message numbers for each table will start from (3000 + table number * 100) ;Default is 40, and the maximum is 100 +;Note: Setting this greater than 50 requires renumbering all message lines for the encounter tables in worldmap.msg +;The messages for each table must be numbered from (3000 + table number * 100) to (3099 + table number * 100) EncounterTableSize=0 ;Set to 1 to disable the pipboy alarm button diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index ae0e4d04..56935c7a 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -349,7 +349,8 @@ #define Stereo16bit (soundstereo bwor sound16bit) #define Stereo16bitLoop (soundstereo bwor sound16bit bwor soundloop) -// Adjust/reduce volume: 0x0000XXXX - max volume, 0x7FFFXXXX - mute +// Adjust (reduce) volume for soundplay and play_sfall_sound +// range: 0x0000XXXX (max volume) - 0x7FFFXXXX (mute) #define SoundVolume25 (0x20000000) #define SoundVolumeHalf (0x40000000) #define SoundVolume75 (0x60000000) diff --git a/sfall/Perks.cpp b/sfall/Perks.cpp index 94358355..e18a9473 100644 --- a/sfall/Perks.cpp +++ b/sfall/Perks.cpp @@ -994,40 +994,67 @@ dlgExit: } } -static void __declspec(naked) item_w_called_shot_hack() { - static const DWORD FastShotTraitFixEnd1 = 0x478E7F; - static const DWORD FastShotTraitFixEnd2 = 0x478E7B; +static void __declspec(naked) item_w_mp_cost_hook() { __asm { - test eax, eax; // does player have Fast Shot trait? - je ajmp; // skip ahead if no - mov edx, ecx; // argument for item_w_range_: hit_mode - mov eax, ebx; // argument for item_w_range_: pointer to source_obj (always dude_obj due to code path) - call item_w_range_; // get weapon's range - cmp eax, 0x2; // is weapon range less than or equal 2 (i.e. melee/unarmed attack)? - jle ajmp; // skip ahead if yes - xor eax, eax; // otherwise, disallow called shot attempt - jmp bjmp; -ajmp: - jmp FastShotTraitFixEnd1; // continue processing called shot attempt -bjmp: - jmp FastShotTraitFixEnd2; // clean up and exit function item_w_called_shot + call item_w_range_; + cmp eax, 2; + jge checkType; // is weapon range less than 2? + retn; // yes, skip -1 AP cost (0x478CA2) +checkType: + mov eax, edi; // source + mov edx, ecx; // hit_mode + call item_hit_with_; // get pointer to weapon + mov edx, ecx; // hit_mode + jmp item_w_subtype_; // eax - item + } +} + +// Haenlomal's fix +static void __declspec(naked) item_w_called_shot_hack() { + static const DWORD FastShotTraitFix_End = 0x478E7F; + __asm { + mov edx, ecx; // argument for item_hit_with_: hit_mode + mov eax, ebx; // argument for item_hit_with_: pointer to source_obj (always dude_obj due to code path) + call item_hit_with_; // get pointer to weapon + mov edx, ecx; + call item_w_subtype_; + cmp eax, 3; // is weapon type GUNS or THROWING? + jge checkRange; // yes + jmp FastShotTraitFix_End; // continue processing called shot attempt +checkRange: + mov edx, ecx; // argument for item_w_range_: hit_mode + mov eax, ebx; // argument for item_w_range_: pointer to source_obj (always dude_obj due to code path) + call item_w_range_; // get weapon's range + cmp eax, 2; // is weapon range greater than or equal to 2 (i.e. ranged attack)? + jge cantUse; // yes, disallow called shot attempt + jmp FastShotTraitFix_End; // continue processing called shot attempt +cantUse: + xor eax, eax; // clean up and exit function item_w_called_shot + pop esi; + pop ecx; + pop ebx; + retn; } } static void FastShotTraitFix() { switch (GetConfigInt("Misc", "FastShotFix", 1)) { case 1: - dlog("Applying Fast Shot Trait Fix.", DL_INIT); - MakeJump(0x478E75, item_w_called_shot_hack); - goto done; + dlog("Applying Fast Shot trait patch. (Haenlomal's fix)", DL_INIT); + MakeJump(0x478E79, item_w_called_shot_hack); + goto fix; case 2: - dlog("Applying Fast Shot Trait Fix. (Fallout 1 version)", DL_INIT); + dlog("Applying Fast Shot trait patch. (Alternative behavior)", DL_INIT); SafeWrite16(0x478C9F, 0x9090); const DWORD fastShotFixF1[] = {0x478BB8, 0x478BC7, 0x478BD6, 0x478BEA, 0x478BF9, 0x478C08, 0x478C2F}; HookCalls((void*)0x478C7D, fastShotFixF1); + goto done; + default: + dlog("Applying Fast Shot trait fix.", DL_INIT); + fix: + HookCall(0x478C97, item_w_mp_cost_hook); done: dlogr(" Done", DL_INIT); - break; } }