From 81ba15d451e0f31b327cb9e991c2259ce7f01c16 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 12 Aug 2019 21:12:28 +0800 Subject: [PATCH] Rewrote the code of force_encounter functions Added a new flag to force_encounter_with_flags. --- artifacts/scripting/headers/sfall.h | 3 +- sfall/FalloutEngine.cpp | 1 + sfall/FalloutEngine.h | 2 + sfall/LoadGameHook.cpp | 5 +- sfall/ScriptExtender.h | 1 + sfall/ScriptOps/InterfaceOp.hpp | 6 +- sfall/ScriptOps/WorldmapOps.hpp | 106 +++++++++++++--------------- 7 files changed, 62 insertions(+), 62 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index a89b593f..471e9d27 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -57,7 +57,8 @@ #define LIST_ALL (9) //Valid flags for force_encounter_with_flags -#define ENCOUNTER_FLAG_NO_CAR (1) +#define ENCOUNTER_FLAG_NO_CAR (1) +#define ENCOUNTER_FLAG_LOCK (2) // block new forced encounter by the next function call until the current specified encounter occurs //The attack types returned by get_attack_type #define ATKTYPE_LWEP1 (0) diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 4bd0d582..fcdb1007 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -672,6 +672,7 @@ const DWORD wmFindCurSubTileFromPos_ = 0x4C0C00; const DWORD wmInterfaceScrollTabsStart_ = 0x4C219C; const DWORD wmMapIsSaveable_ = 0x4BFA64; const DWORD wmMarkSubTileRadiusVisited_ = 0x4C3550; +const DWORD wmMatchAreaContainingMapIdx_ = 0x4C59A4; const DWORD wmPartyInitWalking_ = 0x4C1E54; const DWORD wmPartyWalkingStep_ = 0x4C1F90; const DWORD wmSubTileMarkRadiusVisited_ = 0x4C35A8; diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 8c7e5efa..a0dce1aa 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -148,6 +148,7 @@ #define _max 0x56FB50 #define _maxScriptNum 0x51C7CC #define _Meet_Frank_Horrigan 0x672E04 +#define _Move_on_Car 0x672E64 #define _mouse_hotx 0x6AC7D0 #define _mouse_hoty 0x6AC7CC #define _mouse_is_hidden 0x6AC790 @@ -903,6 +904,7 @@ extern const DWORD wmFindCurSubTileFromPos_; extern const DWORD wmInterfaceScrollTabsStart_; extern const DWORD wmMapIsSaveable_; extern const DWORD wmMarkSubTileRadiusVisited_; +extern const DWORD wmMatchAreaContainingMapIdx_; extern const DWORD wmPartyInitWalking_; extern const DWORD wmPartyWalkingStep_; extern const DWORD wmSubTileMarkRadiusVisited_; diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index 5a489986..72a27a89 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -86,9 +86,10 @@ static void _stdcall ResetState(DWORD onLoad) { InLoop = 0; PerksReset(); InventoryReset(); - RegAnimCombatCheck(1); - AfterAttackCleanup(); ClearSavPrototypes(); + RegAnimCombatCheck(1); + ForceEncounterRestore(); // restore if the encounter did not happen + AfterAttackCleanup(); ResetExplosionRadius(); PartyControlReset(); NpcEngineLevelUpReset(); diff --git a/sfall/ScriptExtender.h b/sfall/ScriptExtender.h index 0129d753..97087368 100644 --- a/sfall/ScriptExtender.h +++ b/sfall/ScriptExtender.h @@ -71,6 +71,7 @@ void SetAppearanceGlobals(int race, int style); void GetAppearanceGlobals(int *race, int *style); void _stdcall RegAnimCombatCheck(DWORD newValue); +DWORD _stdcall ForceEncounterRestore(); bool _stdcall ScriptHasLoaded(DWORD script); // finds procedure ID for given script program pointer and procedure name diff --git a/sfall/ScriptOps/InterfaceOp.hpp b/sfall/ScriptOps/InterfaceOp.hpp index 6e0bfdde..1f0432ad 100644 --- a/sfall/ScriptOps/InterfaceOp.hpp +++ b/sfall/ScriptOps/InterfaceOp.hpp @@ -205,7 +205,7 @@ static void _stdcall create_message_window2() { DialogOut(str); dialogShow = false; } else { - opHandler.printOpcodeError("create_message_window() - argument is not a string."); + OpcodeInvalidArgs("create_message_window"); } } @@ -274,7 +274,7 @@ static void _stdcall ShowIfaceTag2() { AddBox(tag); } } else { - opHandler.printOpcodeError("show_iface_tag() - argument is not an integer."); + OpcodeInvalidArgs("show_iface_tag"); } } @@ -293,7 +293,7 @@ static void _stdcall HideIfaceTag2() { RemoveBox(tag); } } else { - opHandler.printOpcodeError("hide_iface_tag() - argument is not an integer."); + OpcodeInvalidArgs("hide_iface_tag"); } } diff --git a/sfall/ScriptOps/WorldmapOps.hpp b/sfall/ScriptOps/WorldmapOps.hpp index 51ffbb05..33965267 100644 --- a/sfall/ScriptOps/WorldmapOps.hpp +++ b/sfall/ScriptOps/WorldmapOps.hpp @@ -23,77 +23,71 @@ #include "ScriptExtender.h" #include "Worldmap.h" -static DWORD EncounteredHorrigan; -static DWORD ForceEnconterMapID; +static DWORD ForceEnconterMapID = -1; +static DWORD ForceEnconterFlags; -static void _stdcall ForceEncounterRestore() { - *(DWORD*)0x672E04 = EncounteredHorrigan; - SafeWrite32(0x4C070E, *(DWORD*)0x4C0718); // map id - SafeWrite16(0x4C06D8, 0x5175); - SafeWrite32(0x4C071D, 0xFFFC2413); - SafeWrite8(0x4C0706, 0x75); +DWORD _stdcall ForceEncounterRestore() { + long long data = 0x672E043D83; // cmp ds:_Meet_Frank_Horrigan, 0 + SafeWriteBytes(0x4C06D1, (BYTE*)&data, 5); + ForceEnconterFlags = 0; + DWORD mapID = ForceEnconterMapID; + ForceEnconterMapID = -1; + return mapID; } -static void __declspec(naked) wmRndEncounterOccurred_hook() { +static void __declspec(naked) wmRndEncounterOccurred_hack() { __asm { - push ecx; - call ForceEncounterRestore; - pop ecx; + test ForceEnconterFlags, 0x1; // _NoCar flag + jnz noCar; + cmp ds:[_Move_on_Car], 0; + jz noCar; + mov edx, _CarCurrArea; mov eax, ForceEnconterMapID; - jmp map_load_idx_; + call wmMatchAreaContainingMapIdx_; +noCar: + //push ecx; + // TODO: implement a blinking red icon + call ForceEncounterRestore; + //pop ecx; + push 0x4C0721; // return addr + jmp map_load_idx_; // eax - mapID } } -static void __fastcall ForceEncounter2(DWORD mapID, DWORD flags) { - EncounteredHorrigan = *(DWORD*)0x672E04; - ForceEnconterMapID = mapID; - SafeWrite32(0x4C070E, mapID); - SafeWrite16(0x4C06D8, 0x13EB); // jmp 0x4C06ED - HookCall(0x4C071C, wmRndEncounterOccurred_hook); +static void _stdcall ForceEncounter2() { + if (ForceEnconterFlags & (1 << 31)) return; // wait prev. encounter - if (flags & 1) SafeWrite8(0x4C0706, 0xEB); + const ScriptValue &mapIDArg = opHandler.arg(0); + if (mapIDArg.isInt()) { + DWORD mapID = mapIDArg.rawValue(); + if (mapID < 0) { + opHandler.printOpcodeError("force_encounter() - invalid map number."); + return; + } + if (ForceEnconterMapID == -1) MakeJump(0x4C06D1, wmRndEncounterOccurred_hack); + + ForceEnconterMapID = mapID; + DWORD flags = 0; + if (opHandler.numArgs() > 1) { + flags = opHandler.arg(1).asInt(); + if (flags & 2) { // _Lock flag + flags |= (1 << 31); // set bit 31 + } else { + flags = flags & ~(1 << 31); + } + } + ForceEnconterFlags = flags; + } else { + OpcodeInvalidArgs("force_encounter"); + } } static void __declspec(naked) ForceEncounter() { - __asm { - push ecx; - push edx; - _GET_ARG_INT(end); - xor edx, edx; // flags - mov ecx, eax; // mapID - call ForceEncounter2; -end: - pop edx; - pop ecx; - retn; - } + _WRAP_OPCODE(ForceEncounter2, 1, 0) } static void __declspec(naked) ForceEncounterWithFlags() { - __asm { - pushad; - mov ecx, eax; - call interpretPopShort_; - mov edx, eax; - mov eax, ecx; - call interpretPopLong_; - mov ebx, eax; - mov eax, ecx; - call interpretPopShort_; - mov edi, eax; - mov eax, ecx; - call interpretPopLong_; - cmp dx, VAR_TYPE_INT; - jnz end; - cmp di, VAR_TYPE_INT; - jnz end; - mov edx, ebx; // flags - mov ecx, eax; // mapID - call ForceEncounter2; -end: - popad; - retn; - } + _WRAP_OPCODE(ForceEncounter2, 2, 0) } // world_map_functions