From d9a440f667fb6ebeb71ae198bddc24271eb8cb27 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 31 Oct 2019 11:42:20 +0800 Subject: [PATCH] Fixed PM's weapon being misplaced after level up Moved some codes from Worldmap.cpp to new Interface.cpp (same as 4.x). Moved some option codes from main.cpp to other modules. Removed CorpseLineOfFireFix from ddraw.ini (always enabled). --- artifacts/ddraw.ini | 3 - sfall/BugFixes.cpp | 58 +++++++++++++ sfall/DebugEditor.cpp | 4 +- sfall/Interface.cpp | 164 ++++++++++++++++++++++++++++++++++++ sfall/Interface.h | 3 + sfall/Karma.cpp | 13 ++- sfall/LoadOrder.cpp | 11 +++ sfall/Worldmap.cpp | 98 --------------------- sfall/ddraw.vcxproj | 2 + sfall/ddraw.vcxproj.filters | 6 ++ sfall/main.cpp | 97 +-------------------- 11 files changed, 260 insertions(+), 199 deletions(-) create mode 100644 sfall/Interface.cpp create mode 100644 sfall/Interface.h diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index ed130b60..1f92d208 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -367,9 +367,6 @@ AlwaysReloadMsgs=0 ;Set to 1 to force the player to play the idle animation when reloading their weapon PlayIdleAnimOnReload=0 -;Set to 1 to prevent corpses from blocking line of fire -CorpseLineOfFireFix=1 - ;Changes the timer (in days) for deleting corpses on a map after you leave (valid range: 0..13) ;The corpses of critters with 'Ages' flag or on maps with 'dead_bodies_age=No' set in maps.txt will not disappear ;Default is 6. Set to 0 for a 12-hour timer diff --git a/sfall/BugFixes.cpp b/sfall/BugFixes.cpp index 76b96552..94d809dd 100644 --- a/sfall/BugFixes.cpp +++ b/sfall/BugFixes.cpp @@ -376,6 +376,15 @@ static void __declspec(naked) queue_clear_type_mem_free_hook() { } } +static void __declspec(naked) partyMemberCopyLevelInfo_hack() { + __asm { + mov eax, esi; // source + xor ecx, ecx; // animation + mov ebx, 1; // right slot + retn; + } +} + static void __declspec(naked) partyMemberCopyLevelInfo_hook_stat_level() { __asm { nextArmor: @@ -2403,6 +2412,44 @@ end: } } +static const DWORD CorpseShotBlockFix_continue_loop[] = {0x48B99B, 0x48BA0B}; +static void __declspec(naked) obj_shoot_blocking_at_hack0() { + __asm { + mov edx, eax; + mov eax, [eax]; + call critter_is_dead_; // found some object, check if it's a dead critter + test eax, eax; + jz endLoop; // if not, allow breaking the loop (will return this object) + mov eax, edx; + jmp CorpseShotBlockFix_continue_loop[0]; // otherwise continue searching +endLoop: + mov eax, [edx]; + pop ebp; + pop edi; + pop esi; + pop ecx; + retn; + } +} + +// same logic as above, for different loop +static void __declspec(naked) obj_shoot_blocking_at_hack1() { + __asm { + mov eax, [edx]; + call critter_is_dead_; + test eax, eax; + jz endLoop; + jmp CorpseShotBlockFix_continue_loop[1]; +endLoop: + mov eax, [edx]; + pop ebp; + pop edi; + pop esi; + pop ecx; + retn; + } +} + void BugFixesInit() { #ifndef NDEBUG @@ -3026,4 +3073,15 @@ void BugFixesInit() // Note: pass negative amount values to critter_rm_trait to remove all ranks of the perk (vanilla behavior) HookCall(0x458CDB, op_critter_rm_trait_hook); HookCall(0x458B3D, op_critter_add_trait_hook); + + // Fix to prevent corpses from blocking line of fire + //if (GetConfigInt("Misc", "CorpseLineOfFireFix", 1)) { + dlog("Applying fix for corpses blocking line of fire.", DL_INIT); + MakeJump(0x48B994, obj_shoot_blocking_at_hack0); + MakeJump(0x48BA04, obj_shoot_blocking_at_hack1); + dlogr(" Done", DL_INIT); + //} + + // Fix for party member's equipped weapon being placed in the incorrect item slot after leveling up + MakeCall(0x495FD9, partyMemberCopyLevelInfo_hack, 1); } diff --git a/sfall/DebugEditor.cpp b/sfall/DebugEditor.cpp index 995f260f..7c63ef7e 100644 --- a/sfall/DebugEditor.cpp +++ b/sfall/DebugEditor.cpp @@ -328,7 +328,7 @@ static void __declspec(naked) win_debug_hook() { } } -void DebugModePatch() { +static void DebugModePatch() { DWORD dbgMode = iniGetInt("Debugging", "DebugMode", 0, ddrawIniDef); if (dbgMode) { dlog("Applying debugmode patch.", DL_INIT); @@ -361,7 +361,7 @@ void DebugModePatch() { } } -void DontDeleteProtosPatch() { +static void DontDeleteProtosPatch() { if (iniGetInt("Debugging", "DontDeleteProtos", 0, ddrawIniDef)) { dlog("Applying permanent protos patch.", DL_INIT); SafeWrite8(0x48007E, 0xEB); diff --git a/sfall/Interface.cpp b/sfall/Interface.cpp new file mode 100644 index 00000000..e23146e0 --- /dev/null +++ b/sfall/Interface.cpp @@ -0,0 +1,164 @@ +/* + * sfall + * Copyright (C) 2008-2019 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "main.h" +#include "FalloutEngine.h" + +////////////////////////////// WORLDMAP INTERFACE ////////////////////////////// + +static int mapSlotsScrollMax = 27 * (17 - 7); +static int mapSlotsScrollLimit = 0; + +static const DWORD ScrollCityListAddr[] = { + 0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D, +}; + +static __declspec(naked) void ScrollCityListFix() { + __asm { + push ebx; + mov ebx, ds:[0x672F10]; // _wmLastTabsYOffset + test eax, eax; + jl up; + cmp ebx, mapSlotsScrollMax; + pop ebx; + jl run; + retn; +up: + test ebx, ebx; + pop ebx; + jnz run; + retn; +run: + jmp wmInterfaceScrollTabsStart_; + } +} + +static void __declspec(naked) wmInterfaceInit_text_font_hook() { + __asm { + mov eax, 0x65; // normal text font + jmp text_font_; + } +} + +static void __declspec(naked) wmInterfaceRefreshCarFuel_hack_empty() { + __asm { + mov byte ptr [eax - 1], 13; + mov byte ptr [eax + 1], 13; + add eax, 640; + dec ebx; + mov byte ptr [eax], 14; + mov byte ptr [eax - 1], 15; + mov byte ptr [eax + 1], 15; + add eax, 640; + retn; + } +} + +static void __declspec(naked) wmInterfaceRefreshCarFuel_hack() { + __asm { + mov byte ptr [eax - 1], 196; + mov byte ptr [eax + 1], 196; + add eax, 640; + mov byte ptr [eax - 1], 200; + mov byte ptr [eax + 1], 200; + retn; + } +} + +static void WorldMapInterfacePatch() { + if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) { + dlog("Applying world map font patch.", DL_INIT); + HookCall(0x4C2343, wmInterfaceInit_text_font_hook); + dlogr(" Done", DL_INIT); + } + // Fix images for up/down buttons + SafeWrite32(0x4C2C0A, 199); // index of UPARWOFF.FRM + SafeWrite8(0x4C2C7C, 0x43); // dec ebx > inc ebx + SafeWrite32(0x4C2C92, 181); // index of DNARWOFF.FRM + SafeWrite8(0x4C2D04, 0x46); // dec esi > inc esi + + //if (GetConfigInt("Misc", "WorldMapCitiesListFix", 0)) { + dlog("Applying world map cities list patch.", DL_INIT); + for (int i = 0; i < sizeof(ScrollCityListAddr) / 4; i++) { + HookCall(ScrollCityListAddr[i], ScrollCityListFix); + } + dlogr(" Done", DL_INIT); + //} + + DWORD wmSlots = GetConfigInt("Misc", "WorldMapSlots", 0); + if (wmSlots && wmSlots < 128) { + dlog("Applying world map slots patch.", DL_INIT); + if (wmSlots < 7) wmSlots = 7; + mapSlotsScrollMax = (wmSlots - 7) * 27; // height value after which scrolling is not possible + mapSlotsScrollLimit = wmSlots * 27; + SafeWrite32(0x4C21FD, 189); // 27 * 7 + SafeWrite32(0x4C21F1, (DWORD)&mapSlotsScrollLimit); + dlogr(" Done", DL_INIT); + } + + // Car fuel gauge graphics patch + MakeCall(0x4C528A, wmInterfaceRefreshCarFuel_hack_empty); + MakeCall(0x4C529E, wmInterfaceRefreshCarFuel_hack); + SafeWrite8(0x4C52A8, 197); + SafeWrite8(0x4C5289, 12); +} + +static void __declspec(naked) intface_rotate_numbers_hack() { + __asm { + push edi; + push ebp; + sub esp, 0x54; + mov edi, 0x460BA6; + // ebx - old value, ecx - new value + cmp ebx, ecx; + je end; + mov ebx, ecx; + jg decrease; + dec ebx; +end: + jmp edi; +decrease: + test ecx, ecx; + jl negative; + inc ebx; + jmp edi; +negative: + xor ebx, ebx; + jmp edi; + } +} + +static void SpeedInterfaceCounterAnimsPatch() { + switch (GetConfigInt("Misc", "SpeedInterfaceCounterAnims", 0)) { + case 1: + dlog("Applying SpeedInterfaceCounterAnims patch.", DL_INIT); + MakeJump(0x460BA1, intface_rotate_numbers_hack); + dlogr(" Done", DL_INIT); + break; + case 2: + dlog("Applying SpeedInterfaceCounterAnims patch (Instant).", DL_INIT); + SafeWrite32(0x460BB6, 0xDB319090); // xor ebx, ebx + dlogr(" Done", DL_INIT); + break; + } +} + +void InterfaceInit() { + WorldMapInterfacePatch(); + SpeedInterfaceCounterAnimsPatch(); +} diff --git a/sfall/Interface.h b/sfall/Interface.h new file mode 100644 index 00000000..1284ea18 --- /dev/null +++ b/sfall/Interface.h @@ -0,0 +1,3 @@ +#pragma once + +void InterfaceInit(); diff --git a/sfall/Karma.cpp b/sfall/Karma.cpp index 14f151d3..e3366045 100644 --- a/sfall/Karma.cpp +++ b/sfall/Karma.cpp @@ -91,7 +91,7 @@ end: } } -void KarmaInit() { +static void ApplyDisplayKarmaChangesPatch() { if (GetConfigInt("Misc", "DisplayKarmaChanges", 0)) { dlog("Applying display karma changes patch.", DL_INIT); Translate("sfall", "KarmaGain", "You gained %d karma.", KarmaGainMsg); @@ -99,7 +99,9 @@ void KarmaInit() { HookCall(0x455A6D, SetGlobalVarWrapper); dlogr(" Done", DL_INIT); } +} +static void ApplyKarmaFRMsPatch() { std::vector karmaFrmList = GetConfigList("Misc", "KarmaFRMs", "", 512); size_t countFrm = karmaFrmList.size(); if (countFrm) { @@ -111,11 +113,16 @@ void KarmaInit() { for (size_t i = 0; i < countFrm; i++) { karmaFrms[i].frm = atoi(karmaFrmList[i].c_str()); karmaFrms[i].points = (countPoints > i) - ? atoi(karmaPointsList[i].c_str()) - : INT_MAX; + ? atoi(karmaPointsList[i].c_str()) + : INT_MAX; } HookCall(0x4367A9, DrawInfoWin_hook); dlogr(" Done", DL_INIT); } } + +void KarmaInit() { + ApplyDisplayKarmaChangesPatch(); + ApplyKarmaFRMsPatch(); +} diff --git a/sfall/LoadOrder.cpp b/sfall/LoadOrder.cpp index 7d105597..fd1f7d78 100644 --- a/sfall/LoadOrder.cpp +++ b/sfall/LoadOrder.cpp @@ -91,6 +91,15 @@ skip: } } +static void MultiPatchesPatch() { + //if (GetConfigInt("Misc", "MultiPatches", 0)) { + dlog("Applying load multiple patches patch.", DL_INIT); + SafeWrite8(0x444354, 0x90); // Change step from 2 to 1 + SafeWrite8(0x44435C, 0xC4); // Disable check + dlogr(" Done", DL_INIT); + //} +} + ////////////////////////////// SAVE PARTY MEMBER PROTOTYPES ////////////////////////////// static void __fastcall AddSavPrototype(long pid) { @@ -233,6 +242,8 @@ void ClearSavPrototypes() { } void LoadOrderInit() { + MultiPatchesPatch(); + if (GetConfigInt("Misc", "DataLoadOrderPatch", 1)) { dlog("Applying data load order patch.", DL_INIT); MakeCall(0x444259, game_init_databases_hack1); diff --git a/sfall/Worldmap.cpp b/sfall/Worldmap.cpp index ec3511a2..37d9d114 100644 --- a/sfall/Worldmap.cpp +++ b/sfall/Worldmap.cpp @@ -31,9 +31,6 @@ static DWORD AutomapPipboyList[AUTOMAP_MAX]; static DWORD ViewportX; static DWORD ViewportY; -static int mapSlotsScrollMax = 27 * (17 - 7); -static int mapSlotsScrollLimit = 0; - static DWORD worldMapDelay; static DWORD worldMapTicks; @@ -46,10 +43,6 @@ static float scriptMapMulti = 1.0; static bool addYear = false; // used as additional years indicator static DWORD addedYears = 0; -static const DWORD ScrollCityListAddr[] = { - 0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D, -}; - static __declspec(naked) void TimeDateFix() { __asm { test edi, edi; // year buf @@ -110,26 +103,6 @@ end: } } -static __declspec(naked) void ScrollCityListFix() { - __asm { - push ebx; - mov ebx, ds:[0x672F10]; // _wmLastTabsYOffset - test eax, eax; - jl up; - cmp ebx, mapSlotsScrollMax; - pop ebx; - jl run; - retn; -up: - test ebx, ebx; - pop ebx; - jnz run; - retn; -run: - jmp wmInterfaceScrollTabsStart_; - } -} - static void __declspec(naked) WorldMapFpsPatch() { __asm { push dword ptr ds:[_last_buttons]; @@ -267,38 +240,6 @@ static __declspec(naked) void PathfinderFix() { } } -static void __declspec(naked) wmInterfaceInit_text_font_hook() { - __asm { - mov eax, 0x65; // normal text font - jmp text_font_; - } -} - -static void __declspec(naked) wmInterfaceRefreshCarFuel_hack_empty() { - __asm { - mov byte ptr [eax - 1], 13; - mov byte ptr [eax + 1], 13; - add eax, 640; - dec ebx; - mov byte ptr [eax], 14; - mov byte ptr [eax - 1], 15; - mov byte ptr [eax + 1], 15; - add eax, 640; - retn; - } -} - -static void __declspec(naked) wmInterfaceRefreshCarFuel_hack() { - __asm { - mov byte ptr [eax - 1], 196; - mov byte ptr [eax + 1], 196; - add eax, 640; - mov byte ptr [eax - 1], 200; - mov byte ptr [eax + 1], 200; - retn; - } -} - static const char* automap = "automap"; // no/yes overrides the value in the table to display the automap in pipboy static void __declspec(naked) wmMapInit_hack() { __asm { @@ -346,14 +287,6 @@ void WorldLimitsPatches() { dlogr(" Done", DL_INIT); } - //if (GetConfigInt("Misc", "WorldMapCitiesListFix", 0)) { - dlog("Applying world map cities list patch.", DL_INIT); - for (int i = 0; i < sizeof(ScrollCityListAddr) / 4; i++) { - HookCall(ScrollCityListAddr[i], ScrollCityListFix); - } - dlogr(" Done", DL_INIT); - //} - //if (GetConfigInt("Misc", "CitiesLimitFix", 0)) { dlog("Applying cities limit patch.", DL_INIT); if (*((BYTE*)0x4BF3BB) != 0xEB) { @@ -361,17 +294,6 @@ void WorldLimitsPatches() { } dlogr(" Done", DL_INIT); //} - - DWORD wmSlots = GetConfigInt("Misc", "WorldMapSlots", 0); - if (wmSlots && wmSlots < 128) { - dlog("Applying world map slots patch.", DL_INIT); - if (wmSlots < 7) wmSlots = 7; - mapSlotsScrollMax = (wmSlots - 7) * 27; // height value after which scrolling is not possible - mapSlotsScrollLimit = wmSlots * 27; - SafeWrite32(0x4C21FD, 189); // 27 * 7 - SafeWrite32(0x4C21F1, (DWORD)&mapSlotsScrollLimit); - dlogr(" Done", DL_INIT); - } } void TimeLimitPatch() { @@ -503,25 +425,6 @@ void StartingStatePatches() { if (ViewportX != -1 || ViewportY != -1) HookCall(0x4BCF07, ViewportHook); // game_reset_ } -void WorldMapInterfacePatch() { - if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) { - dlog("Applying world map font patch.", DL_INIT); - HookCall(0x4C2343, wmInterfaceInit_text_font_hook); - dlogr(" Done", DL_INIT); - } - // Fix images for up/down buttons - SafeWrite32(0x4C2C0A, 199); // index of UPARWOFF.FRM - SafeWrite8(0x4C2C7C, 0x43); // dec ebx > inc ebx - SafeWrite32(0x4C2C92, 181); // index of DNARWOFF.FRM - SafeWrite8(0x4C2D04, 0x46); // dec esi > inc esi - - // Car fuel gauge graphics patch - MakeCall(0x4C528A, wmInterfaceRefreshCarFuel_hack_empty); - MakeCall(0x4C529E, wmInterfaceRefreshCarFuel_hack); - SafeWrite8(0x4C52A8, 197); - SafeWrite8(0x4C5289, 12); -} - void PipBoyAutomapsPatch() { dlog("Applying Pip-Boy automaps patch.", DL_INIT); MakeCall(0x4BF931, wmMapInit_hack, 2); @@ -549,6 +452,5 @@ void WorldmapInit() { TownMapsHotkeyFix(); WorldLimitsPatches(); WorldmapFpsPatch(); - WorldMapInterfacePatch(); PipBoyAutomapsPatch(); } diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index e11a61a2..1a5b3aa7 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -293,6 +293,7 @@ + @@ -363,6 +364,7 @@ + diff --git a/sfall/ddraw.vcxproj.filters b/sfall/ddraw.vcxproj.filters index 4b3c7799..7a73a90c 100644 --- a/sfall/ddraw.vcxproj.filters +++ b/sfall/ddraw.vcxproj.filters @@ -211,6 +211,9 @@ Headers + + Headers + Headers @@ -364,6 +367,9 @@ Source + + Source + Source diff --git a/sfall/main.cpp b/sfall/main.cpp index 2ebd0e32..aa80d363 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -43,6 +43,7 @@ #include "FileSystem.h" #include "Graphics.h" #include "HeroAppearance.h" +#include "Interface.h" #include "Inventory.h" #include "Karma.h" #include "KillCounter.h" @@ -210,72 +211,6 @@ static void __declspec(naked) ReloadHook() { } } -static const DWORD CorpseHitFix2_continue_loop1 = 0x48B99B; -static void __declspec(naked) CorpseHitFix2() { - __asm { - push eax; - mov eax, [eax]; - call critter_is_dead_; // found some object, check if it's a dead critter - test eax, eax; - pop eax; - jz really_end; // if not, allow breaking the loop (will return this object) - jmp CorpseHitFix2_continue_loop1; // otherwise continue searching - -really_end: - mov eax, [eax]; - pop ebp; - pop edi; - pop esi; - pop ecx; - retn; - } -} - -static const DWORD CorpseHitFix2_continue_loop2 = 0x48BA0B; -// same logic as above, for different loop -static void __declspec(naked) CorpseHitFix2b() { - __asm { - mov eax, [edx]; - call critter_is_dead_; - test eax, eax; - jz really_end; - jmp CorpseHitFix2_continue_loop2; - -really_end: - mov eax, [edx]; - pop ebp; - pop edi; - pop esi; - pop ecx; - retn; - } -} - -static void __declspec(naked) intface_rotate_numbers_hack() { - __asm { - push edi - push ebp - sub esp, 0x54 -// ebx=old value, ecx=new value - cmp ebx, ecx - je end - mov ebx, ecx - jg decrease - dec ebx - jmp end -decrease: - test ecx, ecx - jl negative - inc ebx - jmp end -negative: - xor ebx, ebx -end: - push 0x460BA6 - retn - } -} - static void __declspec(naked) ScienceCritterCheckHook() { __asm { cmp esi, ds:[_obj_dude]; @@ -405,6 +340,9 @@ static void DllMain2() { MainMenuInit(); dlogr(" Done", DL_INIT); + dlogr("Running InterfaceInit().", DL_INIT); + InterfaceInit(); + dlogr("Running ObjectsInit().", DL_INIT); ObjectsInit(); @@ -598,13 +536,6 @@ static void DllMain2() { dlogr(" Done", DL_INIT); } - //if (GetConfigInt("Misc", "MultiPatches", 0)) { - dlog("Applying load multiple patches patch.", DL_INIT); - SafeWrite8(0x444354, 0x90); // Change step from 2 to 1 - SafeWrite8(0x44435C, 0xC4); // Disable check - dlogr(" Done", DL_INIT); - //} - if (GetConfigInt("Misc", "AlwaysReloadMsgs", 0)) { dlog("Applying always reload messages patch.", DL_INIT); SafeWrite8(0x4A6B8D, 0x0); @@ -617,13 +548,6 @@ static void DllMain2() { dlogr(" Done", DL_INIT); } - if (GetConfigInt("Misc", "CorpseLineOfFireFix", 1)) { - dlog("Applying corpse line of fire patch.", DL_INIT); - MakeJump(0x48B994, CorpseHitFix2); - MakeJump(0x48BA04, CorpseHitFix2b); - dlogr(" Done", DL_INIT); - } - dlog("Checking for changed skilldex images.", DL_INIT); tmp = GetConfigInt("Misc", "Lockpick", 293); if (tmp != 293) SafeWrite32(0x518D54, tmp); @@ -641,19 +565,6 @@ static void DllMain2() { if (tmp != 293) SafeWrite32(0x518D64, tmp); dlogr(" Done", DL_INIT); - switch (GetConfigInt("Misc", "SpeedInterfaceCounterAnims", 0)) { - case 1: - dlog("Applying SpeedInterfaceCounterAnims patch.", DL_INIT); - MakeJump(0x460BA1, intface_rotate_numbers_hack); - dlogr(" Done", DL_INIT); - break; - case 2: - dlog("Applying SpeedInterfaceCounterAnims patch. (Instant)", DL_INIT); - SafeWrite32(0x460BB6, 0x90DB3190); // xor ebx, ebx - dlogr(" Done", DL_INIT); - break; - } - switch (GetConfigInt("Misc", "ScienceOnCritters", 0)) { case 1: HookCall(0x41276E, ScienceCritterCheckHook);