diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index bf0d919e..8da90558 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -710,7 +710,7 @@ SkipSizeCheck=0 ;Does not require sfall debugging mode ;ExtraCRC=0x00000000,0x00000000 -;Set to 1 to stop Fallout from deleting non readonly protos at startup +;Set to 1 to stop Fallout from deleting non read-only protos at startup ;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay DontDeleteProtos=0 diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index efe32808..cd51f0a7 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -44,6 +44,7 @@ #include "SuperSave.h" #include "TalkingHeads.h" #include "version.h" +#include "Worldmap.h" #define MAX_GLOBAL_SIZE (MaxGlobalVars * 12 + 4) diff --git a/sfall/ScriptOps/WorldmapOps.hpp b/sfall/ScriptOps/WorldmapOps.hpp index 3308f7af..a4a2dc3a 100644 --- a/sfall/ScriptOps/WorldmapOps.hpp +++ b/sfall/ScriptOps/WorldmapOps.hpp @@ -21,7 +21,7 @@ #include "main.h" #include "Arrays.h" #include "ScriptExtender.h" - +#include "Worldmap.h" static DWORD EncounteredHorrigan; static DWORD ForceEnconterMapID; @@ -185,7 +185,6 @@ end: } } -void _stdcall SetMapMulti(float d); static void __declspec(naked) set_map_time_multi() { __asm { push ebx; diff --git a/sfall/Worldmap.cpp b/sfall/Worldmap.cpp new file mode 100644 index 00000000..703d9cbf --- /dev/null +++ b/sfall/Worldmap.cpp @@ -0,0 +1,520 @@ +/* + * 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 + +#include "main.h" + +#include "Define.h" +#include "FalloutEngine.h" +#include "LoadGameHook.h" +#include "ScriptExtender.h" +#include "SpeedPatch.h" + +static DWORD AutomapPipboyList[AUTOMAP_MAX]; + +static DWORD ViewportX; +static DWORD ViewportY; + +static int mapSlotsScrollMax = 27 * (17 - 7); + +static DWORD worldMapDelay; +static DWORD worldMapTicks; + +static DWORD WorldMapEncounterRate; + +static double tickFract = 0.0; +static double mapMultiMod = 1.0; +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 + jz end; + add esi, addedYears; + mov [edi], esi; +end: + retn; + } +} + +static void TimerReset() { + __asm push ecx; + + const DWORD time = ONE_GAME_YEAR * 13; + *ptr_fallout_game_time -= time; + addedYears += 13; + + // fix queue time + Queue* queue = (Queue*)(*ptr_queue); + while (queue) { + if (queue->time > time) { + queue->time -= time; + } else { + queue->time = 0; + } + queue = queue->next; + } + __asm pop ecx; +} + +static __declspec(naked) void script_chk_timed_events_hack() { + __asm { + mov eax, dword ptr ds:[_fallout_game_time]; + inc eax; + mov dword ptr ds:[_fallout_game_time], eax; + cmp eax, ONE_GAME_YEAR * 13; + jae reset; + retn; +reset: + jmp TimerReset; + } +} + +static __declspec(naked) void set_game_time_hack() { + __asm { + mov dword ptr ds:[_fallout_game_time], eax; + mov edx, eax; + call IsMapLoaded; + test al, al; + jz end; + cmp edx, ONE_GAME_YEAR * 13; + jb end; + call TimerReset; +end: + xor edx, edx; + retn; + } +} + +static __declspec(naked) void ScrollCityListFix() { + __asm { + push ebx; + mov ebx, ds:[0x672F10]; + test eax, eax; + jl up; + cmp ebx, mapSlotsScrollMax; + pop ebx; + jne 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]; + push dword ptr ds:[0x6AC7B0]; // _mouse_buttons + mov esi, worldMapTicks; + mov ebx, esi; // previous ticks +loopDelay: + call RunGlobalScripts3; + call process_bk_; +subLoop: + call ds:[sf_GetTickCount]; // current ticks + mov edx, eax; + sub eax, ebx; // get elapsed time (cur.ticks - prev.ticks) + cmp eax, 10; // delay - GetTickCount returns minimum difference of 15 units + jb subLoop; // elapsed < invoke delay + mov ebx, edx; + sub edx, esi; // get elapsed time (cur.ticks - worldMapTicks) + cmp edx, worldMapDelay; + jb loopDelay; // elapsed < worldMapDelay + + pop dword ptr ds:[0x6AC7B0]; // _mouse_buttons + pop dword ptr ds:[_last_buttons]; + call ds:[sf_GetTickCount]; + mov worldMapTicks, eax; + jmp get_input_; + } +} + +static void __declspec(naked) WorldMapFpsPatch2() { + __asm { + mov esi, worldMapTicks; + mov ebx, esi; +loopDelay: + call RunGlobalScripts3; +subLoop: + call ds:[sf_GetTickCount]; // current ticks + mov edx, eax; + sub eax, ebx; // get elapsed time + jz subLoop; + mov ebx, edx; + sub edx, esi; // get elapsed time + cmp edx, worldMapDelay; + jb loopDelay; // elapsed < worldMapDelay + + call ds:[sf_GetTickCount]; + mov worldMapTicks, eax; + jmp get_input_; + } +} + +// Only used if the world map speed patch is disabled, so that world map scripts are still run +static void __declspec(naked) wmWorldMap_hook() { + __asm { + pushadc; + call RunGlobalScripts3; + popadc; + jmp get_input_; + } +} + +static void __declspec(naked) wmWorldMapFunc_hook() { + __asm { + inc dword ptr ds:[_wmLastRndTime]; + jmp wmPartyWalkingStep_; + } +} + +static void __declspec(naked) wmRndEncounterOccurred_hack() { + __asm { + xor ecx, ecx; + cmp edx, WorldMapEncounterRate; + retn; + } +} + +static void __declspec(naked) ViewportHook() { + __asm { + call wmWorldMapLoadTempData_; + mov eax, ViewportX; + mov ds:[_wmWorldOffsetX], eax; + mov eax, ViewportY; + mov ds:[_wmWorldOffsetY], eax; + retn; + } +} + +static void __declspec(naked) wmTownMapFunc_hack() { + __asm { + cmp dword ptr [edi][eax * 4 + 0], 0; // Visited + je end; + cmp dword ptr [edi][eax * 4 + 4], -1; // Xpos + je end; + cmp dword ptr [edi][eax * 4 + 8], -1; // Ypos + je end; + // engine code + mov edx, [edi][eax * 4 + 0xC]; + mov [esi], edx + retn; +end: + add esp, 4; // destroy the return address + mov eax, 0x4C4976; + jmp eax; + } +} + +static DWORD _stdcall PathfinderCalc(DWORD perkLevel, DWORD ticks) { + double multi = mapMultiMod * scriptMapMulti; + + switch (perkLevel) { + case 1: + multi *= 0.75; + break; + case 2: + multi *= 0.5; + break; + case 3: + multi *= 0.25; + break; + } + multi = ((double)ticks) * multi + tickFract; + tickFract = modf(multi, &multi); + + return static_cast(multi); +} + +static __declspec(naked) void PathfinderFix() { + __asm { + push eax; // ticks + mov eax, ds:[_obj_dude]; + mov edx, PERK_pathfinder; + call perk_level_; + push eax; + call PathfinderCalc; + jmp inc_game_time_; + } +} + +static void __declspec(naked) wmInterfaceInit_text_font_hook() { + __asm { + mov eax, 0x65; // normal text font + jmp text_font_; + } +} + +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 { + mov esi, [esp + 0xA0 - 0x20 + 4]; // curent map number + cmp esi, AUTOMAP_MAX; + jge end; + lea eax, [esp + 4]; // file + lea edx, [esp + 0xA0 - 0x50 + 4]; // section + mov ebx, automap; // key + lea ecx, [esp + 0xA0 - 0x24 + 4]; // value buf + call config_get_string_; + test eax, eax; + jz end; + mov ecx, 2; // max index + mov ebx, _wmYesNoStrs; + lea eax, [esp + 0xA0 - 0x24 + 4]; // key value + sub esp, 4; + mov edx, esp; // index buf + call strParseStrFromList_; + cmp eax, -1; + jz skip; + mov edx, [esp]; // value index + dec edx; + mov [AutomapPipboyList][esi * 4], edx; // no = -1, yes = 0 +skip: + add esp, 4; +end: + inc esi; + mov [esp + 0xA0 - 0x20 + 4], esi; + retn; + } +} + +void WorldLimitsPatches() { + DWORD data = GetPrivateProfileIntA("Misc", "LocalMapXLimit", 0, ini); + if (data) { + dlog("Applying local map x limit patch.", DL_INIT); + SafeWrite32(0x4B13B9, data); + dlogr(" Done", DL_INIT); + } + data = GetPrivateProfileIntA("Misc", "LocalMapYLimit", 0, ini); + if (data) { + dlog("Applying local map y limit patch.", DL_INIT); + SafeWrite32(0x4B13C7, data); + dlogr(" Done", DL_INIT); + } + + //if (GetPrivateProfileIntA("Misc", "WorldMapCitiesListFix", 0, ini)) { + 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 (GetPrivateProfileIntA("Misc", "CitiesLimitFix", 0, ini)) { + dlog("Applying cities limit patch.", DL_INIT); + if (*((BYTE*)0x4BF3BB) != 0xEB) { + SafeWrite8(0x4BF3BB, 0xEB); + } + dlogr(" Done", DL_INIT); + //} + + DWORD wmSlots = GetPrivateProfileIntA("Misc", "WorldMapSlots", 0, ini); + if (wmSlots && wmSlots < 128) { + dlog("Applying world map slots patch.", DL_INIT); + if (wmSlots < 7) wmSlots = 7; + mapSlotsScrollMax = (wmSlots - 7) * 27; + if (wmSlots < 25) { + SafeWrite32(0x4C21FD, 230 - (wmSlots - 17) * 27); + } else { + SafeWrite8(0x4C21FC, 0xC2); // sub > add + SafeWrite32(0x4C21FD, 2 + 27 * (wmSlots - 26)); + } + dlogr(" Done", DL_INIT); + } +} + +void TimeLimitPatch() { + int limit = GetPrivateProfileIntA("Misc", "TimeLimit", 13, ini); + if (limit == -2 || limit == -3) { + addYear = true; + MakeCall(0x4A33B8, TimeDateFix, 1); // game_time_date_ + limit = -1; // also reset time + } + if (limit >= -1 && limit < 13) { + dlog("Applying time limit patch.", DL_INIT); + if (limit == -1) { + MakeCall(0x4A3DF5, script_chk_timed_events_hack, 1); + MakeCall(0x4A3488, set_game_time_hack); + MakeCall(0x4A34EF, TimerReset); // inc_game_time_ + MakeCall(0x4A3547, TimerReset); // inc_game_time_in_seconds_ + SafeMemSet(0x4A34F4, 0x90, 16); + SafeMemSet(0x4A354C, 0x90, 16); + } else { + SafeWrite8(0x4A34EC, limit); + SafeWrite8(0x4A3544, limit); + } + dlogr(" Done", DL_INIT); + } +} + +void TownMapsHotkeyFix() { + if (GetPrivateProfileIntA("Misc", "TownMapHotkeysFix", 1, ini)) { + dlog("Applying town map hotkeys patch.", DL_INIT); + MakeCall(0x4C495A, wmTownMapFunc_hack, 1); + dlogr(" Done", DL_INIT); + } +} + +void WorldmapFpsPatch() { + bool fpsPatchOK = (*(DWORD*)0x4BFE5E == 0x8D16); + if (GetPrivateProfileIntA("Misc", "WorldMapFPSPatch", 0, ini)) { + dlog("Applying world map fps patch.", DL_INIT); + if (!fpsPatchOK) { + dlogr(" Failed", DL_INIT); + } else { + int delay = GetPrivateProfileIntA("Misc", "WorldMapDelay2", 66, ini); + worldMapDelay = max(1, delay); + dlogr(" Done", DL_INIT); + } + } + if (fpsPatchOK) { + void* func; + if (worldMapDelay == 0) { + func = wmWorldMap_hook; + } else if (worldMapDelay > 25) { + func = WorldMapFpsPatch; + } else { + func = WorldMapFpsPatch2; + } + HookCall(0x4BFE5D, func); + AvailableGlobalScriptTypes |= 2; + } + + if (GetPrivateProfileIntA("Misc", "WorldMapEncounterFix", 0, ini)) { + dlog("Applying world map encounter patch.", DL_INIT); + WorldMapEncounterRate = GetPrivateProfileIntA("Misc", "WorldMapEncounterRate", 5, ini); + SafeWrite32(0x4C232D, 0x01EBC031); // xor eax, eax; jmps 0x4C2332 (wmInterfaceInit_) + HookCall(0x4BFEE0, wmWorldMapFunc_hook); + MakeCall(0x4C0667, wmRndEncounterOccurred_hack); + dlogr(" Done", DL_INIT); + } +} + +void PathfinderFixInit() { + //if (GetPrivateProfileIntA("Misc", "PathfinderFix", 0, ini)) { + dlog("Applying Pathfinder patch.", DL_INIT); + SafeWrite16(0x4C1FF6, 0x9090); // wmPartyWalkingStep_ + HookCall(0x4C1C78, PathfinderFix); // wmGameTimeIncrement_ + mapMultiMod = (double)GetPrivateProfileIntA("Misc", "WorldMapTimeMod", 100, ini) / 100.0; + dlogr(" Done", DL_INIT); + //} +} + +void StartingStatePatches() { + int date = GetPrivateProfileIntA("Misc", "StartYear", -1, ini); + if (date >= 0) { + dlog("Applying starting year patch.", DL_INIT); + SafeWrite32(0x4A336C, date); + dlogr(" Done", DL_INIT); + } + date = GetPrivateProfileIntA("Misc", "StartMonth", -1, ini); + if (date >= 0 && date < 12) { + dlog("Applying starting month patch.", DL_INIT); + SafeWrite32(0x4A3382, date); + dlogr(" Done", DL_INIT); + } + date = GetPrivateProfileIntA("Misc", "StartDay", -1, ini); + if (date >= 0 && date < 31) { + dlog("Applying starting day patch.", DL_INIT); + SafeWrite8(0x4A3356, date); + dlogr(" Done", DL_INIT); + } + + date = GetPrivateProfileIntA("Misc", "StartXPos", -1, ini); + if (date != -1) { + dlog("Applying starting x position patch.", DL_INIT); + SafeWrite32(0x4BC990, date); + SafeWrite32(0x4BCC08, date); + dlogr(" Done", DL_INIT); + } + date = GetPrivateProfileIntA("Misc", "StartYPos", -1, ini); + if (date != -1) { + dlog("Applying starting y position patch.", DL_INIT); + SafeWrite32(0x4BC995, date); + SafeWrite32(0x4BCC0D, date); + dlogr(" Done", DL_INIT); + } + + ViewportX = GetPrivateProfileIntA("Misc", "ViewXPos", -1, ini); + if (ViewportX != -1) { + dlog("Applying starting x view patch.", DL_INIT); + SafeWrite32(_wmWorldOffsetX, ViewportX); + dlogr(" Done", DL_INIT); + } + ViewportY = GetPrivateProfileIntA("Misc", "ViewYPos", -1, ini); + if (ViewportY != -1) { + dlog("Applying starting y view patch.", DL_INIT); + SafeWrite32(_wmWorldOffsetY, ViewportY); + dlogr(" Done", DL_INIT); + } + if (ViewportX != -1 || ViewportY != -1) HookCall(0x4BCF07, ViewportHook); // game_reset_ +} + +void WorldMapFontPatch() { + if (GetPrivateProfileIntA("Misc", "WorldMapFontPatch", 0, ini)) { + dlog("Applying world map font patch.", DL_INIT); + HookCall(0x4C2343, wmInterfaceInit_text_font_hook); + dlogr(" Done", DL_INIT); + } +} + +void PipBoyAutomapsPatch() { + //if (GetPrivateProfileIntA("Misc", "PipBoyAutomaps", 0, ini)) { + dlog("Applying Pip-Boy automaps patch.", DL_INIT); + MakeCall(0x4BF931, wmMapInit_hack, 2); + SafeWrite32(0x41B8B7, (DWORD)AutomapPipboyList); + memcpy(AutomapPipboyList, (void*)_displayMapList, sizeof(AutomapPipboyList)); // copy vanilla data + dlogr(" Done", DL_INIT); + //} +} + +void _stdcall SetMapMulti(float value) { + scriptMapMulti = value; +} + +void SetAddedYears(DWORD years) { + addedYears = years; +} + +DWORD GetAddedYears(bool isCheck) { + return (isCheck && !addYear) ? 0 : addedYears; +} + +void WorldmapInit() { + PathfinderFixInit(); + StartingStatePatches(); + TimeLimitPatch(); + TownMapsHotkeyFix(); + WorldLimitsPatches(); + WorldmapFpsPatch(); + WorldMapFontPatch(); + PipBoyAutomapsPatch(); +} diff --git a/sfall/Worldmap.h b/sfall/Worldmap.h new file mode 100644 index 00000000..8409c02b --- /dev/null +++ b/sfall/Worldmap.h @@ -0,0 +1,26 @@ +/* + * 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 . + */ + +#pragma once + +void WorldmapInit(); + +DWORD GetAddedYears(bool isCheck = true); +void SetAddedYears(DWORD years); + +void _stdcall SetMapMulti(float value); diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index bfa93efa..938cb981 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -327,6 +327,7 @@ + @@ -380,6 +381,7 @@ + diff --git a/sfall/ddraw.vcxproj.filters b/sfall/ddraw.vcxproj.filters index 6500632f..bacf96ea 100644 --- a/sfall/ddraw.vcxproj.filters +++ b/sfall/ddraw.vcxproj.filters @@ -196,6 +196,9 @@ Headers + + Headers + Headers @@ -337,6 +340,9 @@ Source + + Source + Source diff --git a/sfall/main.cpp b/sfall/main.cpp index cdd3a62a..89402049 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -62,6 +62,7 @@ #include "TalkingHeads.h" #include "Tiles.h" #include "version.h" +#include "Worldmap.h" ddrawDll ddraw; @@ -87,15 +88,6 @@ static const char* musicOverridePath = "data\\sound\\music\\"; static int* scriptDialog = nullptr; -static DWORD AutomapPipboyList[AUTOMAP_MAX]; - -static DWORD ViewportX; -static DWORD ViewportY; - -static const DWORD ScrollCityListAddr[] = { - 0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D, -}; - static const DWORD FastShotFixF1[] = { 0x478BB8, 0x478BC7, 0x478BD6, 0x478BEA, 0x478BF9, 0x478C08, 0x478C2F, }; @@ -121,214 +113,6 @@ static const DWORD WalkDistanceAddr[] = { 0x411FF0, 0x4121C4, 0x412475, 0x412906, }; -static bool addYear = false; // used as additional years indicator -static DWORD addedYears = 0; -void SetAddedYears(DWORD years) { - addedYears = years; -} - -DWORD GetAddedYears(bool isCheck) { - return (isCheck && !addYear) ? 0 : addedYears; -} - -static __declspec(naked) void TimeDateFix() { - __asm { - test edi, edi; // year buf - jz end; - add esi, addedYears; - mov [edi], esi; -end: - retn; - } -} - -static void TimerReset() { - __asm push ecx; - - const DWORD time = ONE_GAME_YEAR * 13; - *ptr_fallout_game_time -= time; - addedYears += 13; - - // fix queue time - Queue* queue = (Queue*)(*ptr_queue); - while (queue) { - if (queue->time > time) { - queue->time -= time; - } else { - queue->time = 0; - } - queue = queue->next; - } - __asm pop ecx; -} - -static __declspec(naked) void script_chk_timed_events_hack() { - __asm { - mov eax, dword ptr ds:[_fallout_game_time]; - inc eax; - mov dword ptr ds:[_fallout_game_time], eax; - cmp eax, ONE_GAME_YEAR * 13; - jae reset; - retn; -reset: - jmp TimerReset; - } -} - -static __declspec(naked) void set_game_time_hack() { - __asm { - mov dword ptr ds:[_fallout_game_time], eax; - mov edx, eax; - call IsMapLoaded; - test al, al; - jz end; - cmp edx, ONE_GAME_YEAR * 13; - jb end; - call TimerReset; -end: - xor edx, edx; - retn; - } -} - -static double tickFract = 0.0; -static double mapMultiMod = 1.0; -static float scriptMapMulti = 1.0; -void _stdcall SetMapMulti(float value) { - scriptMapMulti = value; -} - -static DWORD _stdcall PathfinderCalc(DWORD perkLevel, DWORD ticks) { - double multi = mapMultiMod * scriptMapMulti; - - switch (perkLevel) { - case 1: - multi *= 0.75; - break; - case 2: - multi *= 0.5; - break; - case 3: - multi *= 0.25; - break; - } - multi = ((double)ticks) * multi + tickFract; - tickFract = modf(multi, &multi); - - return static_cast(multi); -} - -static __declspec(naked) void PathfinderFix() { - __asm { - push eax; // ticks - mov eax, ds:[_obj_dude]; - mov edx, PERK_pathfinder; - call perk_level_; - push eax; - call PathfinderCalc; - jmp inc_game_time_; - } -} - -static int mapSlotsScrollMax = 27 * (17 - 7); -static __declspec(naked) void ScrollCityListFix() { - __asm { - push ebx; - mov ebx, ds:[0x672F10]; - test eax, eax; - jl up; - cmp ebx, mapSlotsScrollMax; - pop ebx; - jne run; - retn; -up: - test ebx, ebx; - pop ebx; - jnz run; - retn; -run: - jmp wmInterfaceScrollTabsStart_; - } -} - -static DWORD worldMapDelay; -static DWORD worldMapTicks; -static void __declspec(naked) WorldMapFpsPatch() { - __asm { - push dword ptr ds:[_last_buttons]; - push dword ptr ds:[0x6AC7B0]; // _mouse_buttons - mov esi, worldMapTicks; - mov ebx, esi; // previous ticks -loopDelay: - call RunGlobalScripts3; - call process_bk_; -subLoop: - call ds:[sf_GetTickCount]; // current ticks - mov edx, eax; - sub eax, ebx; // get elapsed time (cur.ticks - prev.ticks) - cmp eax, 10; // delay - GetTickCount returns minimum difference of 15 units - jb subLoop; // elapsed < invoke delay - mov ebx, edx; - sub edx, esi; // get elapsed time (cur.ticks - worldMapTicks) - cmp edx, worldMapDelay; - jb loopDelay; // elapsed < worldMapDelay - - pop dword ptr ds:[0x6AC7B0]; // _mouse_buttons - pop dword ptr ds:[_last_buttons]; - call ds:[sf_GetTickCount]; - mov worldMapTicks, eax; - jmp get_input_; - } -} - -static void __declspec(naked) WorldMapFpsPatch2() { - __asm { - mov esi, worldMapTicks; - mov ebx, esi; -loopDelay: - call RunGlobalScripts3; -subLoop: - call ds:[sf_GetTickCount]; // current ticks - mov edx, eax; - sub eax, ebx; // get elapsed time - jz subLoop; - mov ebx, edx; - sub edx, esi; // get elapsed time - cmp edx, worldMapDelay; - jb loopDelay; // elapsed < worldMapDelay - - call ds:[sf_GetTickCount]; - mov worldMapTicks, eax; - jmp get_input_; - } -} - -// Only used if the world map speed patch is disabled, so that world map scripts are still run -static void __declspec(naked) wmWorldMap_hook() { - __asm { - pushadc; - call RunGlobalScripts3; - popadc; - jmp get_input_; - } -} - -static DWORD WorldMapEncounterRate; -static void __declspec(naked) wmWorldMapFunc_hook() { - __asm { - inc dword ptr ds:[_wmLastRndTime]; - jmp wmPartyWalkingStep_; - } -} - -static void __declspec(naked) wmRndEncounterOccurred_hack() { - __asm { - xor ecx, ecx; - cmp edx, WorldMapEncounterRate; - retn; - } -} - static void __declspec(naked) Combat_p_procFix() { __asm { push eax; @@ -377,17 +161,6 @@ end_cppf: } } -static void __declspec(naked) ViewportHook() { - __asm { - call wmWorldMapLoadTempData_; - mov eax, ViewportX; - mov ds:[_wmWorldOffsetX], eax; - mov eax, ViewportY; - mov ds:[_wmWorldOffsetY], eax; - retn; - } -} - static void __declspec(naked) WeaponAnimHook() { __asm { cmp edx, 11; @@ -879,65 +652,6 @@ static void __declspec(naked) op_obj_can_see_obj_hook() { } } -static void __declspec(naked) wmTownMapFunc_hack() { - __asm { - cmp dword ptr [edi][eax * 4 + 0], 0; // Visited - je end; - cmp dword ptr [edi][eax * 4 + 4], -1; // Xpos - je end; - cmp dword ptr [edi][eax * 4 + 8], -1; // Ypos - je end; - // engine code - mov edx, [edi][eax * 4 + 0xC]; - mov [esi], edx - retn; -end: - add esp, 4; // destroy the return address - mov eax, 0x4C4976; - jmp eax; - } -} - -static void __declspec(naked) wmInterfaceInit_text_font_hook() { - __asm { - mov eax, 0x65; // normal text font - jmp text_font_; - } -} - -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 { - mov esi, [esp + 0xA0 - 0x20 + 4]; // curent map number - cmp esi, AUTOMAP_MAX; - jge end; - lea eax, [esp + 4]; // file - lea edx, [esp + 0xA0 - 0x50 + 4]; // section - mov ebx, automap; // key - lea ecx, [esp + 0xA0 - 0x24 + 4]; // value buf - call config_get_string_; - test eax, eax; - jz end; - mov ecx, 2; // max index - mov ebx, _wmYesNoStrs; - lea eax, [esp + 0xA0 - 0x24 + 4]; // key value - sub esp, 4; - mov edx, esp; // index buf - call strParseStrFromList_; - cmp eax, -1; - jz skip; - mov edx, [esp]; // value index - dec edx; - mov [AutomapPipboyList][esi * 4], edx; // no = -1, yes = 0 -skip: - add esp, 4; -end: - inc esi; - mov [esp + 0xA0 - 0x20 + 4], esi; - retn; - } -} - static void __declspec(naked) register_object_take_out_hack() { __asm { push ecx @@ -1084,110 +798,8 @@ static void DllMain2() { SafeWrite32(0x418B6D, (DWORD)&dfModelName); dlogr(" Done", DL_INIT); - int date = GetPrivateProfileInt("Misc", "StartYear", -1, ini); - if (date >= 0) { - dlog("Applying starting year patch.", DL_INIT); - SafeWrite32(0x4A336C, date); - dlogr(" Done", DL_INIT); - } - - date = GetPrivateProfileInt("Misc", "StartMonth", -1, ini); - if (date >= 0 && date < 12) { - dlog("Applying starting month patch.", DL_INIT); - SafeWrite32(0x4A3382, date); - dlogr(" Done", DL_INIT); - } - - date = GetPrivateProfileInt("Misc", "StartDay", -1, ini); - if (date >= 0 && date < 31) { - dlog("Applying starting day patch.", DL_INIT); - SafeWrite8(0x4A3356, date); - dlogr(" Done", DL_INIT); - } - - tmp = GetPrivateProfileInt("Misc", "LocalMapXLimit", 0, ini); - if (tmp) { - dlog("Applying local map x limit patch.", DL_INIT); - SafeWrite32(0x4B13B9, tmp); - dlogr(" Done", DL_INIT); - } - tmp = GetPrivateProfileInt("Misc", "LocalMapYLimit", 0, ini); - if (tmp) { - dlog("Applying local map y limit patch.", DL_INIT); - SafeWrite32(0x4B13C7, tmp); - dlogr(" Done", DL_INIT); - } - - date = GetPrivateProfileInt("Misc", "StartXPos", -1, ini); - if (date != -1) { - dlog("Applying starting x position patch.", DL_INIT); - SafeWrite32(0x4BC990, date); - SafeWrite32(0x4BCC08, date); - dlogr(" Done", DL_INIT); - } - - date = GetPrivateProfileInt("Misc", "StartYPos", -1, ini); - if (date != -1) { - dlog("Applying starting y position patch.", DL_INIT); - SafeWrite32(0x4BC995, date); - SafeWrite32(0x4BCC0D, date); - dlogr(" Done", DL_INIT); - } - - ViewportX = GetPrivateProfileInt("Misc", "ViewXPos", -1, ini); - if (ViewportX != -1) { - dlog("Applying starting x view patch.", DL_INIT); - SafeWrite32(_wmWorldOffsetX, ViewportX); - dlogr(" Done", DL_INIT); - } - ViewportY = GetPrivateProfileInt("Misc", "ViewYPos", -1, ini); - if (ViewportY != -1) { - dlog("Applying starting y view patch.", DL_INIT); - SafeWrite32(_wmWorldOffsetY, ViewportY); - dlogr(" Done", DL_INIT); - } - if (ViewportX != -1 || ViewportY != -1) HookCall(0x4BCF07, ViewportHook); // game_reset_ - - //if (GetPrivateProfileIntA("Misc", "PathfinderFix", 0, ini)) { - dlog("Applying Pathfinder patch.", DL_INIT); - SafeWrite16(0x4C1FF6, 0x9090); // wmPartyWalkingStep_ - HookCall(0x4C1C78, PathfinderFix); // wmGameTimeIncrement_ - mapMultiMod = (double)GetPrivateProfileIntA("Misc", "WorldMapTimeMod", 100, ini) / 100.0; - dlogr(" Done", DL_INIT); - //} - - bool fpsPatchOK = (*(DWORD*)0x4BFE5E == 0x8D16); - if (GetPrivateProfileIntA("Misc", "WorldMapFPSPatch", 0, ini)) { - dlog("Applying world map fps patch.", DL_INIT); - if (!fpsPatchOK) { - dlogr(" Failed", DL_INIT); - } else { - int delay = GetPrivateProfileIntA("Misc", "WorldMapDelay2", 66, ini); - worldMapDelay = max(1, delay); - dlogr(" Done", DL_INIT); - } - } - if (fpsPatchOK) { - void* func; - if (worldMapDelay == 0) { - func = wmWorldMap_hook; - } else if (worldMapDelay > 25) { - func = WorldMapFpsPatch; - } else { - func = WorldMapFpsPatch2; - } - HookCall(0x4BFE5D, func); - AvailableGlobalScriptTypes |= 2; - } - - if (GetPrivateProfileIntA("Misc", "WorldMapEncounterFix", 0, ini)) { - dlog("Applying world map encounter patch.", DL_INIT); - WorldMapEncounterRate = GetPrivateProfileIntA("Misc", "WorldMapEncounterRate", 5, ini); - SafeWrite32(0x4C232D, 0x01EBC031); // xor eax, eax; jmps 0x4C2332 (wmInterfaceInit_) - HookCall(0x4BFEE0, wmWorldMapFunc_hook); - MakeCall(0x4C0667, wmRndEncounterOccurred_hack); - dlogr(" Done", DL_INIT); - } + dlogr("Running WorldmapInit().", DL_INIT); + WorldmapInit(); if (GetPrivateProfileIntA("Misc", "DialogueFix", 1, ini)) { dlog("Applying dialogue patch.", DL_INIT); @@ -1228,58 +840,6 @@ static void DllMain2() { dlogr(" Done", DL_INIT); //} - //if (GetPrivateProfileIntA("Misc", "WorldMapCitiesListFix", 0, ini)) { - 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 (GetPrivateProfileIntA("Misc", "CitiesLimitFix", 0, ini)) { - dlog("Applying cities limit patch.", DL_INIT); - if (*((BYTE*)0x4BF3BB) != 0xEB) { - SafeWrite8(0x4BF3BB, 0xEB); - } - dlogr(" Done", DL_INIT); - //} - - tmp = GetPrivateProfileIntA("Misc", "WorldMapSlots", 0, ini); - if (tmp && tmp < 128) { - dlog("Applying world map slots patch.", DL_INIT); - if (tmp < 7) tmp = 7; - mapSlotsScrollMax = (tmp - 7) * 27; - if (tmp < 25) { - SafeWrite32(0x4C21FD, 230 - (tmp - 17) * 27); - } else { - SafeWrite8(0x4C21FC, 0xC2); // sub > add - SafeWrite32(0x4C21FD, 2 + 27 * (tmp - 26)); - } - dlogr(" Done", DL_INIT); - } - - int limit = GetPrivateProfileIntA("Misc", "TimeLimit", 13, ini); - if (limit == -2 || limit == -3) { - addYear = true; - MakeCall(0x4A33B8, TimeDateFix, 1); // game_time_date_ - limit = -1; // also reset time - } - if (limit >= -1 && limit < 13) { - dlog("Applying time limit patch.", DL_INIT); - if (limit == -1) { - MakeCall(0x4A3DF5, script_chk_timed_events_hack, 1); - MakeCall(0x4A3488, set_game_time_hack); - MakeCall(0x4A34EF, TimerReset); // inc_game_time_ - MakeCall(0x4A3547, TimerReset); // inc_game_time_in_seconds_ - SafeMemSet(0x4A34F4, 0x90, 16); - SafeMemSet(0x4A354C, 0x90, 16); - } else { - SafeWrite8(0x4A34EC, limit); - SafeWrite8(0x4A3544, limit); - } - dlogr(" Done", DL_INIT); - } - dlogr("Running FileSystemInit().", DL_INIT); FileSystemInit(); @@ -1612,26 +1172,6 @@ static void DllMain2() { dlogr(" Done", DL_INIT); } - if (GetPrivateProfileIntA("Misc", "TownMapHotkeysFix", 1, ini)) { - dlog("Applying town map hotkeys patch.", DL_INIT); - MakeCall(0x4C495A, wmTownMapFunc_hack, 1); - dlogr(" Done", DL_INIT); - } - - if (GetPrivateProfileIntA("Misc", "WorldMapFontPatch", 0, ini)) { - dlog("Applying world map font patch.", DL_INIT); - HookCall(0x4C2343, wmInterfaceInit_text_font_hook); - dlogr(" Done", DL_INIT); - } - - //if (GetPrivateProfileIntA("Misc", "PipBoyAutomaps", 0, ini)) { - dlog("Applying Pip-Boy automaps patch.", DL_INIT); - MakeCall(0x4BF931, wmMapInit_hack, 2); - SafeWrite32(0x41B8B7, (DWORD)AutomapPipboyList); - memcpy(AutomapPipboyList, (void*)_displayMapList, sizeof(AutomapPipboyList)); // copy vanilla data - dlogr(" Done", DL_INIT); - //} - if (GetPrivateProfileIntA("Misc", "DontTurnOffSneakIfYouRun", 0, ini)) { dlog("Applying DontTurnOffSneakIfYouRun patch.", DL_INIT); SafeWrite8(0x418135, 0xEB); diff --git a/sfall/main.h b/sfall/main.h index 30cc3a7e..e46d888c 100644 --- a/sfall/main.h +++ b/sfall/main.h @@ -70,9 +70,6 @@ extern DWORD modifiedIni; extern char dmModelName[65]; extern char dfModelName[65]; -DWORD GetAddedYears(bool isCheck = true); -void SetAddedYears(DWORD years); - void RemoveSavFiles(); void ClearSavPrototypes();