From b4dac84dddd59035d8a3a2bbb25a51348cf8a966 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 9 Dec 2019 11:07:40 +0800 Subject: [PATCH] Rewrote some script functions in ObjectsOps in C++ * remove_script, set/get_script, set_critter_burst_disable. Changed the return value of get_script to 0 for unscripted objects. --- artifacts/scripting/sfall function notes.txt | 5 +- sfall/Combat.cpp | 4 +- sfall/Combat.h | 2 +- sfall/FalloutEngine.cpp | 36 ++- sfall/FalloutEngine.h | 10 +- sfall/FalloutStructs.h | 4 +- sfall/ScriptOps/ObjectsOps.hpp | 261 +++++++------------ sfall/ScriptOps/ScriptArrays.hpp | 6 +- 8 files changed, 145 insertions(+), 183 deletions(-) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 5082aee7..986f6b8d 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -153,12 +153,13 @@ array - array ID to be used with array-related functions (actually an integer) - accepts a pointer to an object and will remove the script from that object. > void set_script(object, int scriptid) -- accepts a pointer to an object and scriptID, and applies the given script to an object (scriptID accept the same values as create_object_sid from sfall 3.6) +- accepts a pointer to an object and scriptID, and applies the given script to an object (scriptID accepts the same values as create_object_sid) - If used on an object that is already scripted, it will remove the existing script first; you cannot have multiple scripts attached to a single object. Calling set_script on self_obj will have all sorts of wacky side effects, and should be avoided. - if you add 0x80000000 to the sid when calling set_script, map_enter_p_proc will be SKIPPED. The start proc will always be run. > int get_script(object) -- accepts a pointer to an object and returns its scriptID (line number in scripts.lst), or -1 if the object is unscripted. +- accepts a pointer to an object and returns its scriptID (line number in scripts.lst), or 0 if the object is unscripted. +- returns -1 on argument error. > void set_self(int obj) - overrides the scripts self_obj for the next function call. diff --git a/sfall/Combat.cpp b/sfall/Combat.cpp index 956d30a1..722433d3 100644 --- a/sfall/Combat.cpp +++ b/sfall/Combat.cpp @@ -243,7 +243,7 @@ static void __declspec(naked) determine_to_hit_func_hack() { } static long __fastcall CheckDisableBurst(TGameObj* critter) { - for (DWORD i = 0; i < noBursts.size(); i++) { + for (size_t i = 0; i < noBursts.size(); i++) { if (noBursts[i] == critter->ID) { return 10; // Disable Burst (area_attack_mode - non-existent value) } @@ -354,7 +354,7 @@ void _stdcall SetHitChanceMax(TGameObj* critter, DWORD maximum, DWORD mod) { hitChanceMods.push_back(cm); } -void _stdcall SetNoBurstMode(TGameObj* critter, DWORD on) { +void _stdcall SetNoBurstMode(TGameObj* critter, bool on) { if (critter == *ptr_obj_dude || critter->pid >> 24 != OBJ_TYPE_CRITTER) return; long id = SetObjectUniqueID(critter); diff --git a/sfall/Combat.h b/sfall/Combat.h index 3c3ace6b..ce8226c0 100644 --- a/sfall/Combat.h +++ b/sfall/Combat.h @@ -29,6 +29,6 @@ void _stdcall KnockbackSetMod(TGameObj* object, DWORD type, float val, DWORD mod void _stdcall KnockbackRemoveMod(TGameObj* object, DWORD mode); void CombatInit(); void Combat_OnGameLoad(); -void _stdcall SetNoBurstMode(TGameObj* critter, DWORD on); +void _stdcall SetNoBurstMode(TGameObj* critter, bool on); void _stdcall DisableAimedShots(DWORD pid); void _stdcall ForceAimedShots(DWORD pid); diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index e5bc82f2..0da0c276 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -873,16 +873,38 @@ void SkillSetTags(int* tags, DWORD num) { } } +TGameObj* __stdcall ScrFindObjFromProgram(TProgram* program) { + __asm { + mov eax, program; + call scr_find_obj_from_program_; + } +} + // Saves pointer to script object into scriptPtr using scriptID. // Returns 0 on success, -1 on failure. long __stdcall ScrPtr(long scriptId, TScript** scriptPtr) { __asm { - mov eax, scriptId; mov edx, scriptPtr; + mov eax, scriptId; call scr_ptr_; } } +long __stdcall ScrNew(long* scriptID, long sType) { + __asm { + mov edx, sType; + mov eax, scriptID; + call scr_new_; + } +} + +long __stdcall ScrRemove(long scriptID) { + __asm { + mov eax, scriptID; + call scr_remove_; + } +} + // Returns the number of local variables of the object script long GetScriptLocalVars(long sid) { TScript* script = nullptr; @@ -1037,10 +1059,10 @@ TGameObj* __stdcall InvenRightHand(TGameObj* critter) { } } -long __fastcall CreateWindowFunc(const char* winName, long x, long y, long width, long height, long bgColorIndex, long flags) { +long __fastcall CreateWindowFunc(const char* winName, DWORD x, DWORD y, DWORD width, DWORD height, long color, long flags) { __asm { push flags; - push bgColorIndex; + push color; push height; mov eax, ecx; mov ebx, y; @@ -1300,6 +1322,14 @@ TGameObj* __fastcall ObjBlockingAt(TGameObj* object, long tile, long elevation) } } +long __fastcall ObjNewSidInst(TGameObj* object, long sType, long scriptIndex) { + __asm { + mov ebx, scriptIndex; + mov eax, ecx; + call obj_new_sid_inst_; + } +} + long __fastcall TileNumInDirection(long tile, long rotation, long distance) { __asm { mov ebx, distance; diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index d0d1f547..9ca710f6 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -1042,10 +1042,16 @@ void __stdcall CritterPcSetName(const char* newName); // Checks if given file exists in DB bool __stdcall DbAccess(const char* fileName); +TGameObj* __stdcall ScrFindObjFromProgram(TProgram* program); + // Saves pointer to script object into scriptPtr using scriptID. // Returns 0 on success, -1 on failure. long __stdcall ScrPtr(long scriptId, TScript** scriptPtr); +long __stdcall ScrNew(long* scriptID, long sType); + +long __stdcall ScrRemove(long scriptID); + // Returns the number of local variables of the object script long GetScriptLocalVars(long sid); @@ -1099,7 +1105,7 @@ void __declspec() InterpretError(const char* fmt, ...); const char* __stdcall FindCurrentProc(TProgram* program); // creates a window with the name and flags -long __fastcall CreateWindowFunc(const char* winName, long x, long y, long width, long height, long bgColorIndex, long flags); +long __fastcall CreateWindowFunc(const char* winName, DWORD x, DWORD y, DWORD width, DWORD height, long color, long flags); // creates a button long __stdcall WinRegisterButton(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType); @@ -1156,6 +1162,8 @@ void __stdcall MapDirErase(const char* folder, const char* ext); TGameObj* __fastcall ObjBlockingAt(TGameObj* object, long tile, long elevation); +long __fastcall ObjNewSidInst(TGameObj* object, long sType, long scriptIndex); + long __fastcall TileNumInDirection(long tile, long rotation, long distance); long __stdcall TileDir(long scrTile, long dstTile); diff --git a/sfall/FalloutStructs.h b/sfall/FalloutStructs.h index 1a81cc3f..fafd9b26 100644 --- a/sfall/FalloutStructs.h +++ b/sfall/FalloutStructs.h @@ -128,7 +128,7 @@ struct TScript { }; #pragma pack(pop) -enum ScriptTypes +enum ScriptTypes : long { SCRIPT_SYSTEM = 0, SCRIPT_SPATIAL = 1, @@ -138,7 +138,7 @@ enum ScriptTypes }; /* 24 */ -enum ObjectTypes +enum ObjectTypes : char { OBJ_TYPE_ITEM = 0, OBJ_TYPE_CRITTER = 1, diff --git a/sfall/ScriptOps/ObjectsOps.hpp b/sfall/ScriptOps/ObjectsOps.hpp index b9cb3ca7..86e8540f 100644 --- a/sfall/ScriptOps/ObjectsOps.hpp +++ b/sfall/ScriptOps/ObjectsOps.hpp @@ -24,97 +24,66 @@ #include "Objects.h" #include "PartyControl.h" -//script control functions +#define exec_script_proc(script, proc) __asm { \ + __asm mov eax, script \ + __asm mov edx, proc \ + __asm call exec_script_proc_ \ +} -// TODO: rewrite -static void __declspec(naked) RemoveScript() { - __asm { - push ebx; - push ecx; - push edx; - mov ecx, eax; - call interpretPopShort_; - mov edx, eax; - mov eax, ecx; - call interpretPopLong_; - cmp dx, VAR_TYPE_INT; - jnz end; - test eax, eax; - jz end; - mov edx, eax; - mov eax, [eax+0x78]; - cmp eax, 0xffffffff; - jz end; - call scr_remove_ - mov dword ptr [edx+0x78], 0xffffffff; -end: - pop edx; - pop ecx; - pop ebx; - retn; +static void _stdcall RemoveScript2() { + TGameObj* object = opHandler.arg(0).asObject(); + if (object) { + if (object->scriptID != 0xFFFFFFFF) { + ScrRemove(object->scriptID); + object->scriptID = 0xFFFFFFFF; + } + } else { + OpcodeInvalidArgs("remove_script"); } } -// TODO: rewrite -static void __declspec(naked) SetScript() { - __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; - test eax, eax; - jz end; - mov esi, [eax+0x78]; - cmp esi, 0xffffffff; - jz newscript - push eax; - mov eax, esi; - call scr_remove_ - pop eax; - mov dword ptr [eax+0x78], 0xffffffff; -newscript: - mov esi, 1; - test ebx, 0x80000000; - jz execMapEnter; - xor esi, esi; - xor ebx, 0x80000000; -execMapEnter: - mov ecx, eax; - mov edx, 3; // script_type_item - mov edi, [eax+0x64]; - shr edi, 24; - cmp edi, 1; - jnz notCritter; - inc edx; // 4 - "critter" type script -notCritter: - dec ebx; - call obj_new_sid_inst_ - mov eax, [ecx+0x78]; - mov edx, 1; // start - call exec_script_proc_ - cmp esi, 1; // run map enter? - jnz end; - mov eax, [ecx+0x78]; - mov edx, 0xf; // map_enter_p_proc - call exec_script_proc_ -end: - popad; - retn; +static void __declspec(naked) RemoveScript() { + _WRAP_OPCODE(RemoveScript2, 1, 0) +} + +static void _stdcall SetScript2() { + TGameObj* object = opHandler.arg(0).asObject(); + const ScriptValue &scriptIdxArg = opHandler.arg(1); + + if (object && scriptIdxArg.isInt()) { + long scriptType; + unsigned long valArg = scriptIdxArg.rawValue(); + + long scriptIndex = valArg & ~0xF0000000; + if (scriptIndex == 0 || valArg > 0x8FFFFFFF) { // negative values are not allowed + opHandler.printOpcodeError("set_script() - the script index number is incorrect."); + return; + } + scriptIndex--; + + if (object->scriptID != 0xFFFFFFFF) { + ScrRemove(object->scriptID); + object->scriptID = 0xFFFFFFFF; + } + if (object->pid >> 24 == OBJ_TYPE_CRITTER) { + scriptType = SCRIPT_CRITTER; + } else { + scriptType = SCRIPT_ITEM; + } + ObjNewSidInst(object, scriptType, scriptIndex); + + long scriptId = object->scriptID; + exec_script_proc(scriptId, start); + if ((valArg & 0x80000000) == 0) exec_script_proc(scriptId, map_enter_p_proc); + } else { + OpcodeInvalidArgs("set_script"); } } +static void __declspec(naked) SetScript() { + _WRAP_OPCODE(SetScript2, 2, 0) +} + static void _stdcall op_create_spatial2() { const ScriptValue &scriptIdxArg = opHandler.arg(0), &tileArg = opHandler.arg(1), @@ -125,38 +94,21 @@ static void _stdcall op_create_spatial2() { DWORD scriptIndex = scriptIdxArg.rawValue(), tile = tileArg.rawValue(), elevation = elevArg.rawValue(), - radius = radiusArg.rawValue(), - scriptId, tmp, objectPtr, - scriptPtr; - __asm { - lea eax, scriptId; - mov edx, 1; - call scr_new_; - mov tmp, eax; - } - if (tmp == -1) return; - __asm { - mov eax, scriptId; - lea edx, scriptPtr; - call scr_ptr_; - mov tmp, eax; - } - if (tmp == -1) return; - // fill spatial script properties: - *(DWORD*)(scriptPtr + 0x14) = scriptIndex - 1; - *(DWORD*)(scriptPtr + 0x8) = (elevation << 29) & 0xE0000000 | tile; - *(DWORD*)(scriptPtr + 0xC) = radius; + radius = radiusArg.rawValue(); + + long scriptId; + TScript* scriptPtr; + if (ScrNew(&scriptId, SCRIPT_SPATIAL) == -1 || ScrPtr(scriptId, &scriptPtr) == -1) return; + + // set spatial script properties: + scriptPtr->script_index = scriptIndex - 1; + scriptPtr->elevation_and_tile = (elevation << 29) & 0xE0000000 | tile; + scriptPtr->spatial_radius = radius; + // this will load appropriate script program and link it to the script instance we just created: - __asm { - mov eax, scriptId; - mov edx, 1; // start_p_proc - call exec_script_proc_; - mov eax, scriptPtr; - mov eax, [eax + 0x18]; // program pointer - call scr_find_obj_from_program_; - mov objectPtr, eax; - } - opHandler.setReturn(objectPtr); + exec_script_proc(scriptId, start); + + opHandler.setReturn(ScrFindObjFromProgram(scriptPtr->program_ptr)); } else { OpcodeInvalidArgs("create_spatial"); opHandler.setReturn(0); @@ -180,64 +132,36 @@ static void sf_spatial_radius() { } } +static void _stdcall GetScript2() { + TGameObj* object = opHandler.arg(0).asObject(); + if (object) { + long scriptIndex = object->script_index; + opHandler.setReturn((scriptIndex >= 0) ? ++scriptIndex : 0); + } else { + OpcodeInvalidArgs("get_script"); + opHandler.setReturn(-1); + } +} + static void __declspec(naked) GetScript() { - __asm { - pushad; - mov ecx, eax; - mov ecx, eax; - call interpretPopShort_; - mov edx, eax; - mov eax, ecx; - call interpretPopLong_; - cmp dx, VAR_TYPE_INT; - jnz fail; - test eax, eax; - jz fail; - mov edx, [eax+0x80]; - cmp edx, -1; - jz fail; - inc edx; - jmp end; -fail: - xor edx, edx; - dec edx; -end: - mov eax, ecx; - call interpretPushLong_; - mov eax, ecx; - mov edx, VAR_TYPE_INT; - call interpretPushShort_; - popad; - retn; + _WRAP_OPCODE(GetScript2, 1, 1) +} + +static void _stdcall set_critter_burst_disable2() { + TGameObj* critter = opHandler.arg(0).asObject(); + const ScriptValue &disableArg = opHandler.arg(1); + + if (critter && disableArg.isInt()) { + SetNoBurstMode(critter, disableArg.asBool()); + } else { + OpcodeInvalidArgs("set_critter_burst_disable"); } } static void __declspec(naked) set_critter_burst_disable() { - __asm { - pushad; - mov ebp, eax; - call interpretPopShort_; - mov edi, eax; - mov eax, ebp; - call interpretPopLong_; - mov ecx, eax; - mov eax, ebp; - call interpretPopShort_; - mov esi, eax; - mov eax, ebp; - call interpretPopLong_; - cmp di, VAR_TYPE_INT; - jnz end; - cmp si, VAR_TYPE_INT; - jnz end; - push ecx; - push eax; - call SetNoBurstMode; -end: - popad; - retn; - } + _WRAP_OPCODE(set_critter_burst_disable2, 2, 0) } + static void __declspec(naked) get_weapon_ammo_pid() { __asm { pushad; @@ -265,6 +189,7 @@ end: retn; } } + static void __declspec(naked) set_weapon_ammo_pid() { __asm { pushad; @@ -291,6 +216,7 @@ end: retn; } } + static void __declspec(naked) get_weapon_ammo_count() { __asm { pushad; @@ -317,6 +243,7 @@ end: retn; } } + static void __declspec(naked) set_weapon_ammo_count() { __asm { pushad; diff --git a/sfall/ScriptOps/ScriptArrays.hpp b/sfall/ScriptOps/ScriptArrays.hpp index 6d44b169..3ba19287 100644 --- a/sfall/ScriptOps/ScriptArrays.hpp +++ b/sfall/ScriptOps/ScriptArrays.hpp @@ -529,11 +529,7 @@ static void FillListVector(DWORD type, std::vector& vec) { self_obj = scriptPtr->self_obj; if (self_obj == nullptr) { programPtr = scriptPtr->program_ptr; - __asm { - mov eax, programPtr; - call scr_find_obj_from_program_; - mov self_obj, eax; - } + self_obj = ScrFindObjFromProgram(programPtr); } vec.push_back(self_obj); __asm {