diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 5cfc45a0..b3768725 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -609,6 +609,10 @@ StartGDialogFix=0 ;num_attacks - the number of free action points on the first turn only AttackComplexFix=0 +;Set to 1 to enable the create_object_sid script function to run the 'start' script procedure when creating an object +;It is recommended to enable this option only if you are developing a new project (TC), otherwise it may affect some existing game scripts +CreateObjectSidFix=0 + ;Set to 1 to fix the issue with the division operator treating negative integers as unsigned ;Note: To perform the unsigned integer division, use the new 'div' operator DivisionOperatorFix=1 diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 5b2d1013..8c04114f 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -220,6 +220,7 @@ WRAP_WATCOM_FUNC3(long, register_object_turn_towards, fo::GameObject*, object, l WRAP_WATCOM_FUNC2(long, roll_random, long, minValue, long, maxValue) WRAP_WATCOM_FUNC1(long*, runProgram, fo::Program*, progPtr) WRAP_WATCOM_FUNC1(long, selectWindowID, long, sWinID) +WRAP_WATCOM_FUNC1(void, scr_build_lookup_table, fo::ScriptInstance*, script) WRAP_WATCOM_FUNC1(fo::ScriptInstance*, scr_find_first_at, long, elevation) WRAP_WATCOM_FUNC0(fo::ScriptInstance*, scr_find_next_at) WRAP_WATCOM_FUNC1(fo::GameObject*, scr_find_obj_from_program, fo::Program*, program) diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 11dec951..da971ec4 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -1824,10 +1824,12 @@ static void __declspec(naked) op_obj_can_hear_obj_hack() { } } +// correct signed division by 4 static void __declspec(naked) ai_best_weapon_hack() { __asm { - sar edx, 31; - sub eax, edx + add edx, 3; + test eax, eax; + cmovs eax, edx; sar eax, 1; retn; } @@ -2994,6 +2996,8 @@ skip: } } +static bool createObjectSidStartFix = false; + static void __declspec(naked) op_create_object_sid_hack() { static const char* proDbgMsg = "\nError: attempt to create object with PID of %d: %s!"; using fo::Scripts::start; @@ -3001,8 +3005,22 @@ static void __declspec(naked) op_create_object_sid_hack() { mov ebx, [esp + 0x50 - 0x20 + 4]; // createObj test ebx, ebx; jz noObject; + mov ecx, [ebx + scriptId]; + cmp ecx, -1; + jne init; + mov edx, ebx; + mov eax, esi; + retn; +init: + cmp createObjectSidStartFix, 0; + jne runStart; + call ScriptExtender::InitScript; + mov edx, ebx; + mov eax, esi; + retn; +runStart: mov edx, start; // procedure - mov eax, [ebx + scriptId]; + mov eax, ecx; call fo::funcoffs::exec_script_proc_; end: mov edx, ebx; @@ -3795,6 +3813,7 @@ void BugFixes::init() HookCall(0x4B6C13, checkAllRegions_hook); // Fix for the script attached to an object not being initialized properly upon object creation + createObjectSidStartFix = (IniReader::GetConfigInt("Misc", "CreateObjectSidFix", 0) != 0); MakeCall(0x4551C0, op_create_object_sid_hack, 1); // Fix the error handling in create_object_sid function to prevent a crash when the proto is missing SafeWrite8(0x45507B, 0x51); // jz 0x4550CD diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index 2933c181..882c3c1f 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -39,6 +39,15 @@ static bool cutsPatch = false; static std::vector patchFiles; static std::vector savPrototypes; +static void PlayerGenderCutsRestore() { + if (cutsPatch) { // restore + SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); + SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS); + SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS); + cutsPatch = false; + } +} + static void CheckPlayerGender() { isFemale = fo::HeroIsFemale(); @@ -49,11 +58,8 @@ static void CheckPlayerGender() { SafeWrite32(0x43FA9F, (DWORD)cutsEndGameFemale); SafeWrite32(0x44EB5B, (DWORD)cutsSubFemale); SafeWrite32(0x48152E, (DWORD)cutsDeathFemale); - } else if (cutsPatch) { - SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); - SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS); - SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS); - cutsPatch = false; + } else { + PlayerGenderCutsRestore(); } } } @@ -497,14 +503,7 @@ void LoadOrder::init() { LoadGameHook::OnAfterGameStarted() += CheckPlayerGender; if (femaleMsgs > 1) { MakeCall(0x480A95, gnw_main_hack); // before new game start from main menu. TODO: need moved to address 0x480A9A (it busy in movies.cpp) - LoadGameHook::OnGameExit() += []() { - if (cutsPatch) { // restore - SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); - SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS); - SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS); - cutsPatch = false; - } - }; + LoadGameHook::OnGameExit() += PlayerGenderCutsRestore; } dlogr(" Done", DL_INIT); } diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 65856d91..03e30a64 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -428,14 +428,14 @@ void __fastcall SetSelfObject(fo::Program* script, fo::GameObject* obj) { // loads script from .int file into a sScriptProgram struct, filling script pointer and proc lookup table void InitScriptProgram(ScriptProgram &prog, const char* fileName, bool fullPath) { - fo::Program* scriptPtr = fullPath + fo::Program* scriptPtr = (fullPath) ? fo::func::allocateProgram(fileName) : fo::func::loadProgram(fileName); if (scriptPtr) { - const char** procTable = fo::var::procTableStrs; prog.ptr = scriptPtr; // fill lookup table + const char** procTable = fo::var::procTableStrs; for (int i = 0; i < fo::Scripts::ScriptProc::count; ++i) { prog.procLookup[i] = fo::func::interpretFindProcedure(prog.ptr, procTable[i]); } @@ -481,6 +481,26 @@ bool IsGameScript(const char* filename) { return false; // script name was not found in scripts.lst } +// loads and initializes script file (for normal game scripts) +long __fastcall ScriptExtender::InitScript(long sid) { + fo::ScriptInstance* scriptPtr; + if (fo::func::scr_ptr(sid, &scriptPtr) == -1) return -1; + + scriptPtr->program = fo::func::loadProgram(fo::var::scriptListInfo[scriptPtr->scriptIdx & 0xFFFFFF].fileName); + if (!scriptPtr->program) return -1; + if (scriptPtr->program->flags & 0x124) return 0; + + // fill lookup table + fo::func::scr_build_lookup_table(scriptPtr); + + scriptPtr->flags |= 4 | 1; // init | loaded + scriptPtr->action = fo::Scripts::ScriptProc::no_p_proc; + scriptPtr->scriptOverrides = 0; + + fo::func::runProgram(scriptPtr->program); + return 0; +} + static void LoadGlobalScriptsList() { dlogr("Running global scripts...", DL_SCRIPT); diff --git a/sfall/Modules/ScriptExtender.h b/sfall/Modules/ScriptExtender.h index 0608a07d..b9801209 100644 --- a/sfall/Modules/ScriptExtender.h +++ b/sfall/Modules/ScriptExtender.h @@ -58,6 +58,9 @@ public: static int __stdcall ScriptHasLoaded(fo::Program* script); + // loads and initializes script file (for normal game scripts) + static long __fastcall InitScript(long sid); + // Called before map exit (before map_exit_p_proc handlers in normal scripts) static Delegate<>& OnMapExit(); };