From 534bc3e5cd78b2cd6e39cfcfdf86398eb0216c98 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 11 Nov 2019 09:50:34 +0800 Subject: [PATCH] Implemented executing timed_event_p_proc in sfall global scripts Added "add_g_timer_event" and "remove_timer_event" script functions for timed_event_p_proc in global scripts. Fixed the check on the 'hidden' flag for previous commit. --- artifacts/scripting/headers/sfall.h | 3 + artifacts/scripting/sfall function notes.txt | 11 +++ sfall/FalloutEngine/Functions.cpp | 4 +- sfall/Modules/Interface.cpp | 6 +- sfall/Modules/ScriptExtender.cpp | 74 ++++++++++++++++++- sfall/Modules/ScriptExtender.h | 5 ++ sfall/Modules/Scripting/Handlers/Core.cpp | 12 +++ sfall/Modules/Scripting/Handlers/Core.h | 4 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 3 + 9 files changed, 113 insertions(+), 9 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 490d995a..fa3dff18 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -249,6 +249,7 @@ // sfall_funcX macros #define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name) +#define add_global_timer_event(time, param) sfall_func2("add_g_timer_event", time, param) #define add_iface_tag sfall_func0("add_iface_tag") #define add_trait(traitId) sfall_func1("add_trait", traitId) #define art_cache_clear sfall_func0("art_cache_clear") @@ -293,6 +294,8 @@ #define obj_under_cursor(crSwitch, inclDude) sfall_func2("obj_under_cursor", crSwitch, inclDude) #define outlined_object sfall_func0("outlined_object") #define real_dude_obj sfall_func0("real_dude_obj") +#define remove_all_timer_events sfall_func0("remove_timer_event") +#define remove_timer_event(param) sfall_func1("remove_timer_event", param) #define set_can_rest_on_map(map, elev, value) sfall_func3("set_can_rest_on_map", map, elev, value) #define set_car_intface_art(artIndex) sfall_func1("set_car_intface_art", artIndex) #define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 52132f1c..6311862b 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -633,6 +633,17 @@ optional argument: > int sfall_func0("get_inven_ap_cost") - returns the current AP cost to access the inventory in combat +> void sfall_func2("add_g_timer_event", int time, int param) +- adds a timer event that calls the timed_event_p_proc procedure in the current global script +- time: the number of ticks after which the event timer is triggered +- param: the value that is passed to the timed_event_p_proc procedure for the fixed_param function + +> void sfall_func0("remove_timer_event") +- clears all set timer events for the current global script + +> void sfall_func1("remove_timer_event", int param) +- removes all timer events with the specified 'param' value for the current global script + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 85ea645a..2a449a2d 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -26,7 +26,7 @@ namespace fo namespace func { -// prints debug message to debug.log file for develop build +// Prints debug message to debug.log file for develop build #ifndef NDEBUG void __declspec(naked) dev_printf(const char* fmt, ...) { __asm jmp fo::funcoffs::debug_printf_; @@ -181,7 +181,7 @@ long __stdcall db_dir_entry(const char *fileName, DWORD *sizeOut) { // prints message to debug.log file void __declspec(naked) debug_printf(const char* fmt, ...) { - __asm jmp fo::funcoffs::debug_printf_ + __asm jmp fo::funcoffs::debug_printf_; } // Displays message in main UI console window diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index 9f6a2db4..8520b0c3 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -591,8 +591,8 @@ static void __declspec(naked) gmouse_bk_process_hook() { retn; checkFlag: call fo::funcoffs::GNW_find_; - cmp [eax + 4], Hidden; // window flags - jnz skip; + test [eax + 4], Hidden; // window flags + jz skip; mov eax, ds:[FO_VAR_display_win]; // window is hidden, so return the number of the display_win skip: retn; @@ -609,7 +609,7 @@ void Interface::init() { // Fix for interface windows with 'Hidden' and 'ScriptWindow' flags // Hidden - will not toggle the mouse cursor when the cursor hovers over a hidden window - // ScriptWindow - prevents player's movement when clicking on the window if the 'Transparent' flag is not set + // ScriptWindow - prevents the player from moving when clicking on the window if the 'Transparent' flag is not set HookCall(0x44B737, gmouse_bk_process_hook); LoadGameHook::OnBeforeGameInit() += []() { if (hrpVersionValid) IFACE_BAR_MODE = *(BYTE*)HRPAddress(0x1006EB0C) != 0; diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index d6f3d5ff..9bad83f0 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -16,9 +16,7 @@ * along with this program. If not, see . */ -#include //#include -#include #include #include @@ -84,6 +82,18 @@ struct SelfOverrideObj { } }; +struct TimedEvent { + ScriptProgram* script; + long time; + long fixed_param; + + bool operator() (const TimedEvent &a, const TimedEvent &b) { + return a.time < b.time; + } +} *timedEvent = nullptr; + +static std::list timerEventScripts; + static std::vector globalScriptPathList; static std::map globalScriptFilesList; @@ -132,6 +142,11 @@ static DWORD _stdcall FindSid(fo::Program* script) { } // this will allow to use functions like roll_vs_skill, etc without calling set_self (they don't really need self object) if (sfallProgsMap.find(script) != sfallProgsMap.end()) { + if (timedEvent && timedEvent->script->ptr == script) { + overrideScriptStruct.fixedParam = timedEvent->fixed_param; + } else { + overrideScriptStruct.fixedParam = 0; + } overrideScriptStruct.targetObject = overrideScriptStruct.selfObject = 0; return -2; // override struct } @@ -499,7 +514,9 @@ static void PrepareGlobalScriptsListByMask() { static void LoadGlobalScripts() { static bool listIsPrepared = false; isGameLoading = false; + LoadHookScripts(); + dlogr("Loading global scripts:", DL_SCRIPT|DL_INIT); if (!listIsPrepared) { // only once PrepareGlobalScriptsListByMask(); @@ -528,6 +545,7 @@ static void ClearGlobalScripts() { globalScripts.clear(); selfOverrideMap.clear(); globalExportedVars.clear(); + timerEventScripts.clear(); HookScriptClear(); } @@ -617,6 +635,54 @@ static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId) { return procId; // restore eax (don't delete) } +static long HandleTimedEventScripts() { + long currentTime = fo::var::fallout_game_time; + bool wereRunning = false; + auto timerIt = timerEventScripts.cbegin(); + for (; timerIt != timerEventScripts.cend(); timerIt++) { + if (currentTime >= timerIt->time) { + timedEvent = const_cast(&(*timerIt)); + fo::func::dev_printf("\n[TimedEventScripts] run event: %d", timerIt->time); + RunScriptProc(timerIt->script, fo::ScriptProc::timed_event_p_proc); + wereRunning = true; + } else { + break; + } + } + if (wereRunning) { + for (auto _it = timerEventScripts.cbegin(); _it != timerIt; _it++) { + fo::func::dev_printf("\n[TimedEventScripts] delete events: %d", _it->time); + } + timerEventScripts.erase(timerEventScripts.cbegin(), timerIt); + } + timedEvent = nullptr; + return currentTime; +} + +void ScriptExtender::AddTimerEventScripts(fo::Program* script, long time, long param) { + ScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second); + TimedEvent timer; + timer.script = scriptProg; + timer.fixed_param = param; + timer.time = fo::var::fallout_game_time + time; + timerEventScripts.push_back(std::move(timer)); + timerEventScripts.sort(TimedEvent()); +} + +void ScriptExtender::RemoveTimerEventScripts(fo::Program* script, long param) { + ScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second); + timerEventScripts.remove_if([scriptProg, param] (TimedEvent timer) { + return timer.script == scriptProg && timer.fixed_param == param; + }); +} + +void ScriptExtender::RemoveTimerEventScripts(fo::Program* script) { + ScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second); + timerEventScripts.remove_if([scriptProg] (TimedEvent timer) { + return timer.script == scriptProg; + }); +} + // run all global scripts of types 0 and 3 at specific procedure (if exist) void RunGlobalScriptsAtProc(DWORD procId) { for (DWORD d = 0; d < globalScripts.size(); d++) { @@ -754,9 +820,9 @@ void ScriptExtender::init() { alwaysFindScripts = isDebug && (iniGetInt("Debugging", "AlwaysFindScripts", 0, ::sfall::ddrawIni) != 0); if (alwaysFindScripts) dlogr("Always searching for global scripts behavior enabled.", DL_SCRIPT); - MakeJump(0x4A390C, FindSidHack); + MakeJump(0x4A390C, FindSidHack); // scr_find_sid_from_program_ MakeJump(0x4A5E34, ScrPtrHack); - + HookCall(0x4A26D6, HandleTimedEventScripts); // queue_process_ MakeJump(0x4A67F0, ExecMapScriptsHack); // this patch makes it possible to export variables from sfall global scripts diff --git a/sfall/Modules/ScriptExtender.h b/sfall/Modules/ScriptExtender.h index c491b08c..2d24ad2a 100644 --- a/sfall/Modules/ScriptExtender.h +++ b/sfall/Modules/ScriptExtender.h @@ -34,6 +34,10 @@ public: static std::string iniConfigFolder; + static void AddTimerEventScripts(fo::Program* script, long time, long param); + static void RemoveTimerEventScripts(fo::Program* script, long param); + static void RemoveTimerEventScripts(fo::Program* script); + // Called before map exit (before map_exit_p_proc handlers in normal scripts) static Delegate<>& OnMapExit(); }; @@ -67,6 +71,7 @@ void SetGlobals(GlobalVar* globals); long SetGlobalVar(const char* var, int val); void SetGlobalVarInt(DWORD var, int val); + long GetGlobalVar(const char* var); long GetGlobalVarInt(DWORD var); long GetGlobalVarInternal(__int64 val); diff --git a/sfall/Modules/Scripting/Handlers/Core.cpp b/sfall/Modules/Scripting/Handlers/Core.cpp index ea0a17e1..750957fb 100644 --- a/sfall/Modules/Scripting/Handlers/Core.cpp +++ b/sfall/Modules/Scripting/Handlers/Core.cpp @@ -184,6 +184,18 @@ void sf_register_hook(OpcodeContext& ctx) { RegisterHook(ctx.program(), ctx.arg(0).rawValue(), proc, specReg); } +void sf_add_g_timer_event(OpcodeContext& ctx) { + ScriptExtender::AddTimerEventScripts(ctx.program(), ctx.arg(0).rawValue(), ctx.arg(1).rawValue()); +} + +void sf_remove_timer_event(OpcodeContext& ctx) { + if (ctx.numArgs() > 0) { + ScriptExtender::RemoveTimerEventScripts(ctx.program(), ctx.arg(0).rawValue()); + } else { + ScriptExtender::RemoveTimerEventScripts(ctx.program()); // remove all + } +} + void sf_sfall_ver_major(OpcodeContext& ctx) { ctx.setReturn(VERSION_MAJOR); } diff --git a/sfall/Modules/Scripting/Handlers/Core.h b/sfall/Modules/Scripting/Handlers/Core.h index f3d76a91..c6682b2c 100644 --- a/sfall/Modules/Scripting/Handlers/Core.h +++ b/sfall/Modules/Scripting/Handlers/Core.h @@ -54,6 +54,10 @@ void __declspec() op_set_self(); // used for both register_hook and register_hook_proc void sf_register_hook(OpcodeContext&); +void sf_add_g_timer_event(OpcodeContext&); + +void sf_remove_timer_event(OpcodeContext&); + void sf_sfall_ver_major(OpcodeContext&); void sf_sfall_ver_minor(OpcodeContext&); diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index b65209b1..7f41beb2 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -21,6 +21,7 @@ #include "..\Arrays.h" #include "..\OpcodeContext.h" #include "Anims.h" +#include "Core.h" #include "Interface.h" #include "Misc.h" #include "Objects.h" @@ -61,6 +62,7 @@ static MetaruleTableType metaruleTable; static const SfallMetarule metarules[] = { {"add_extra_msg_file", sf_add_extra_msg_file, 1, 2, {ARG_STRING, ARG_INT}}, {"add_iface_tag", sf_add_iface_tag, 0, 0}, + {"add_g_timer_event", sf_add_g_timer_event, 2, 2, {ARG_INT, ARG_INT}}, {"add_trait", sf_add_trait, 1, 1, {ARG_INT}}, {"art_cache_clear", sf_art_cache_flush, 0, 0}, {"attack_is_aimed", sf_attack_is_aimed, 0, 0}, @@ -103,6 +105,7 @@ static const SfallMetarule metarules[] = { {"obj_under_cursor", sf_get_obj_under_cursor, 2, 2, {ARG_INT, ARG_INT}}, {"outlined_object", sf_outlined_object, 0, 0}, {"real_dude_obj", sf_real_dude_obj, 0, 0}, + {"remove_timer_event", sf_remove_timer_event, 0, 1, {ARG_INT}}, {"set_can_rest_on_map", sf_set_rest_on_map, 3, 3, {ARG_INT, ARG_INT, ARG_INT}}, {"set_car_intface_art", sf_set_car_intface_art, 1, 1, {ARG_INT}}, {"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}},