Adjusted how the fix for create_object_sid works

Added CreateObjectSidFix option.
This commit is contained in:
NovaRain
2021-05-02 10:34:16 +08:00
parent 7df0407798
commit 2e337d246b
6 changed files with 64 additions and 18 deletions
+4
View File
@@ -609,6 +609,10 @@ StartGDialogFix=0
;num_attacks - the number of free action points on the first turn only ;num_attacks - the number of free action points on the first turn only
AttackComplexFix=0 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 ;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 ;Note: To perform the unsigned integer division, use the new 'div' operator
DivisionOperatorFix=1 DivisionOperatorFix=1
+1
View File
@@ -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_FUNC2(long, roll_random, long, minValue, long, maxValue)
WRAP_WATCOM_FUNC1(long*, runProgram, fo::Program*, progPtr) WRAP_WATCOM_FUNC1(long*, runProgram, fo::Program*, progPtr)
WRAP_WATCOM_FUNC1(long, selectWindowID, long, sWinID) 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_FUNC1(fo::ScriptInstance*, scr_find_first_at, long, elevation)
WRAP_WATCOM_FUNC0(fo::ScriptInstance*, scr_find_next_at) WRAP_WATCOM_FUNC0(fo::ScriptInstance*, scr_find_next_at)
WRAP_WATCOM_FUNC1(fo::GameObject*, scr_find_obj_from_program, fo::Program*, program) WRAP_WATCOM_FUNC1(fo::GameObject*, scr_find_obj_from_program, fo::Program*, program)
+22 -3
View File
@@ -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() { static void __declspec(naked) ai_best_weapon_hack() {
__asm { __asm {
sar edx, 31; add edx, 3;
sub eax, edx test eax, eax;
cmovs eax, edx;
sar eax, 1; sar eax, 1;
retn; retn;
} }
@@ -2994,6 +2996,8 @@ skip:
} }
} }
static bool createObjectSidStartFix = false;
static void __declspec(naked) op_create_object_sid_hack() { static void __declspec(naked) op_create_object_sid_hack() {
static const char* proDbgMsg = "\nError: attempt to create object with PID of %d: %s!"; static const char* proDbgMsg = "\nError: attempt to create object with PID of %d: %s!";
using fo::Scripts::start; using fo::Scripts::start;
@@ -3001,8 +3005,22 @@ static void __declspec(naked) op_create_object_sid_hack() {
mov ebx, [esp + 0x50 - 0x20 + 4]; // createObj mov ebx, [esp + 0x50 - 0x20 + 4]; // createObj
test ebx, ebx; test ebx, ebx;
jz noObject; 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 edx, start; // procedure
mov eax, [ebx + scriptId]; mov eax, ecx;
call fo::funcoffs::exec_script_proc_; call fo::funcoffs::exec_script_proc_;
end: end:
mov edx, ebx; mov edx, ebx;
@@ -3795,6 +3813,7 @@ void BugFixes::init()
HookCall(0x4B6C13, checkAllRegions_hook); HookCall(0x4B6C13, checkAllRegions_hook);
// Fix for the script attached to an object not being initialized properly upon object creation // 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); 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 // Fix the error handling in create_object_sid function to prevent a crash when the proto is missing
SafeWrite8(0x45507B, 0x51); // jz 0x4550CD SafeWrite8(0x45507B, 0x51); // jz 0x4550CD
+12 -13
View File
@@ -39,6 +39,15 @@ static bool cutsPatch = false;
static std::vector<std::string> patchFiles; static std::vector<std::string> patchFiles;
static std::vector<int> savPrototypes; static std::vector<int> 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() { static void CheckPlayerGender() {
isFemale = fo::HeroIsFemale(); isFemale = fo::HeroIsFemale();
@@ -49,11 +58,8 @@ static void CheckPlayerGender() {
SafeWrite32(0x43FA9F, (DWORD)cutsEndGameFemale); SafeWrite32(0x43FA9F, (DWORD)cutsEndGameFemale);
SafeWrite32(0x44EB5B, (DWORD)cutsSubFemale); SafeWrite32(0x44EB5B, (DWORD)cutsSubFemale);
SafeWrite32(0x48152E, (DWORD)cutsDeathFemale); SafeWrite32(0x48152E, (DWORD)cutsDeathFemale);
} else if (cutsPatch) { } else {
SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); PlayerGenderCutsRestore();
SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS);
SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS);
cutsPatch = false;
} }
} }
} }
@@ -497,14 +503,7 @@ void LoadOrder::init() {
LoadGameHook::OnAfterGameStarted() += CheckPlayerGender; LoadGameHook::OnAfterGameStarted() += CheckPlayerGender;
if (femaleMsgs > 1) { 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) 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() += []() { LoadGameHook::OnGameExit() += PlayerGenderCutsRestore;
if (cutsPatch) { // restore
SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts);
SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS);
SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS);
cutsPatch = false;
}
};
} }
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
} }
+22 -2
View File
@@ -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 // 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) { void InitScriptProgram(ScriptProgram &prog, const char* fileName, bool fullPath) {
fo::Program* scriptPtr = fullPath fo::Program* scriptPtr = (fullPath)
? fo::func::allocateProgram(fileName) ? fo::func::allocateProgram(fileName)
: fo::func::loadProgram(fileName); : fo::func::loadProgram(fileName);
if (scriptPtr) { if (scriptPtr) {
const char** procTable = fo::var::procTableStrs;
prog.ptr = scriptPtr; prog.ptr = scriptPtr;
// fill lookup table // fill lookup table
const char** procTable = fo::var::procTableStrs;
for (int i = 0; i < fo::Scripts::ScriptProc::count; ++i) { for (int i = 0; i < fo::Scripts::ScriptProc::count; ++i) {
prog.procLookup[i] = fo::func::interpretFindProcedure(prog.ptr, procTable[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 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() { static void LoadGlobalScriptsList() {
dlogr("Running global scripts...", DL_SCRIPT); dlogr("Running global scripts...", DL_SCRIPT);
+3
View File
@@ -58,6 +58,9 @@ public:
static int __stdcall ScriptHasLoaded(fo::Program* script); 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) // Called before map exit (before map_exit_p_proc handlers in normal scripts)
static Delegate<>& OnMapExit(); static Delegate<>& OnMapExit();
}; };