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.
This commit is contained in:
NovaRain
2019-11-11 10:01:38 +08:00
parent e62b5c03db
commit 6a566087ca
10 changed files with 134 additions and 22 deletions
+3
View File
@@ -224,6 +224,7 @@
#define ADD_PERK_MODE_REMOVE (4) // remove from the list of selectable perks
// sfall_funcX macros
#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")
@@ -256,6 +257,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_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
#define set_flags(obj, flags) sfall_func2("set_flags", obj, flags)
#define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color)
@@ -528,6 +528,17 @@ Some utility/math functions are available:
> 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 -------
------------------------
+10 -6
View File
@@ -720,6 +720,14 @@ const DWORD xvfprintf_ = 0x4DF1AC;
// WRAPPERS
// please, use CamelCase for those
// Prints debug message to debug.log file for develop build
#ifndef NDEBUG
void __declspec(naked) DevPrintf(const char* fmt, ...) {
__asm jmp debug_printf_;
}
#else
void DevPrintf(const char* fmt, ...) {}
#endif
long __stdcall ItemGetType(TGameObj* item) {
__asm {
@@ -923,15 +931,11 @@ const char* __stdcall InterpretGetString(TProgram* scriptPtr, DWORD strId, DWORD
}
void __declspec(naked) InterpretError(const char* fmt, ...) {
__asm {
jmp interpretError_;
}
__asm jmp interpretError_;
}
void __declspec(naked) DebugPrintf(const char* fmt, ...) {
__asm {
jmp debug_printf_;
}
__asm jmp debug_printf_;
}
const char* __stdcall FindCurrentProc(TProgram* program) {
+4
View File
@@ -993,6 +993,10 @@ extern const DWORD xvfprintf_;
// WRAPPERS:
// TODO: move these to different namespace
// Prints debug message to debug.log file for develop build
void DevPrintf(const char* fmt, ...);
long __stdcall ItemGetType(TGameObj* item);
long __stdcall ItemSize(TGameObj* item);
+1 -2
View File
@@ -22,8 +22,7 @@
#include "FalloutEngine.h"
#include "FileSystem.h"
extern void GetSavePath(char* buf, char* ftype);
#include "LoadGameHook.h"
#define MAX_FILE_SIZE 0xA00000
+4 -4
View File
@@ -206,7 +206,7 @@ static void SpeedInterfaceCounterAnimsPatch() {
}
static bool IFACE_BAR_MODE = false;
static long gmouse_handle_event_hook() {
static long __stdcall gmouse_handle_event_hook() {
long countWin = *(DWORD*)_num_windows;
long ifaceWin = *ptr_interfaceWindow;
WINinfo* win = nullptr;
@@ -234,8 +234,8 @@ static void __declspec(naked) gmouse_bk_process_hook() {
retn;
checkFlag:
call GNW_find_;
cmp [eax + 4], WIN_Hidden; // window flags
jnz skip;
test [eax + 4], WIN_Hidden; // window flags
jz skip;
mov eax, ds:[_display_win]; // window is hidden, so return the number of the display_win
skip:
retn;
@@ -254,7 +254,7 @@ void InterfaceInit() {
// 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);
// InterfaceGmouseHandleHook will be run before game initialization
}
+2
View File
@@ -60,3 +60,5 @@ void SetLoopFlag(LoopFlag flag);
// unset the given flag
void ClearLoopFlag(LoopFlag flag);
void GetSavePath(char* buf, char* ftype);
+91 -8
View File
@@ -18,10 +18,8 @@
#include "main.h"
#include <cassert>
#include <hash_map>
//#include <set>
#include <string>
#include "Arrays.h"
#include "BarBoxes.h"
@@ -37,6 +35,11 @@
#include "version.h"
static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId);
static long _stdcall HandleTimedEventScripts();
static void RunGlobalScripts1();
static void sf_add_g_timer_event();
static void sf_remove_timer_event();
// variables for new opcodes
#define OP_MAX_ARGUMENTS (8)
@@ -390,6 +393,7 @@ static void OpcodeInvalidArgs(const char* opcodeName) {
If you don't include opcode in this array, you should take care of all argument validation inside handler itself.
*/
static const SfallOpcodeMetadata opcodeMetaArray[] = {
{sf_add_g_timer_event, "add_g_timer_event", {DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
{sf_add_trait, "add_trait", {DATATYPE_MASK_INT}},
{sf_create_win, "create_win", {DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
{sf_critter_inven_obj2, "critter_inven_obj2", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
@@ -401,6 +405,7 @@ static const SfallOpcodeMetadata opcodeMetaArray[] = {
{sf_item_weight, "item_weight", {DATATYPE_MASK_VALID_OBJ}},
{sf_lock_is_jammed, "lock_is_jammed", {DATATYPE_MASK_VALID_OBJ}},
{sf_get_obj_under_cursor, "obj_under_cursor", {DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
{sf_remove_timer_event, "remove_timer_event", {DATATYPE_MASK_INT}},
{sf_set_cursor_mode, "set_cursor_mode", {DATATYPE_MASK_INT}},
{sf_set_flags, "set_flags", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
{sf_set_iface_tag_text, "set_iface_tag_text", {DATATYPE_MASK_INT, DATATYPE_MASK_STR, DATATYPE_MASK_INT}},
@@ -464,6 +469,18 @@ struct SelfOverrideObj {
}
};
struct TimedEvent {
sScriptProgram* script;
long time;
long fixed_param;
bool operator() (const TimedEvent &a, const TimedEvent &b) {
return a.time < b.time;
}
} *timedEvent = nullptr;
static std::list<TimedEvent> timerEventScripts;
static std::vector<DWORD> checkedScripts;
static std::vector<sGlobalScript> globalScripts;
@@ -835,6 +852,18 @@ static void __declspec(naked) register_hook_proc_spec() {
_WRAP_OPCODE(register_hook_proc_spec2, 2, 0)
}
static void sf_add_g_timer_event() {
AddTimerEventScripts((DWORD)opHandler.program(), opHandler.arg(0).rawValue(), opHandler.arg(1).rawValue());
}
static void sf_remove_timer_event() {
if (opHandler.numArgs() > 0) {
RemoveTimerEventScripts((DWORD)opHandler.program(), opHandler.arg(0).rawValue());
} else {
RemoveTimerEventScripts((DWORD)opHandler.program()); // remove all
}
}
static void __declspec(naked) sfall_ver_major() {
_OP_BEGIN(ebp)
__asm {
@@ -884,6 +913,11 @@ static DWORD _stdcall FindSid(DWORD 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.fixed_param = timedEvent->fixed_param;
} else {
OverrideScriptStruct.fixed_param = 0;
}
OverrideScriptStruct.target_obj = OverrideScriptStruct.self_obj = 0;
return -2; // override struct
}
@@ -1232,13 +1266,13 @@ void ScriptExtenderInit() {
dlogr("New arrays behavior enabled.", DL_SCRIPT);
} else dlogr("Arrays in backward-compatiblity mode.", DL_SCRIPT);
HookCall(0x480E7B, MainGameLoopHook); //hook the main game loop
HookCall(0x422845, CombatLoopHook); //hook the combat loop
MakeJump(0x4A390C, FindSidHack);
MakeJump(0x4A5E34, ScrPtrHack);
HookCall(0x480E7B, MainGameLoopHook); // hook the main game loop
HookCall(0x422845, CombatLoopHook); // hook the combat loop
MakeCall(0x4230D5, AfterCombatAttackHook);
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
@@ -1705,6 +1739,7 @@ void ClearGlobalScripts() {
globalScripts.clear();
selfOverrideMap.clear();
globalExportedVars.clear();
timerEventScripts.clear();
HookScriptClear();
}
@@ -1855,6 +1890,54 @@ static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId) {
return procId; // restore eax (don't delete)
}
static long _stdcall HandleTimedEventScripts() {
long currentTime = *ptr_fallout_game_time;
bool wereRunning = false;
auto timerIt = timerEventScripts.cbegin();
for (; timerIt != timerEventScripts.cend(); timerIt++) {
if (currentTime >= timerIt->time) {
timedEvent = const_cast<TimedEvent*>(&(*timerIt));
DevPrintf("\n[TimedEventScripts] run event: %d", timerIt->time);
RunScriptProc(timerIt->script, timed_event_p_proc);
wereRunning = true;
} else {
break;
}
}
if (wereRunning) {
for (auto _it = timerEventScripts.cbegin(); _it != timerIt; _it++) {
DevPrintf("\n[TimedEventScripts] delete events: %d", _it->time);
}
timerEventScripts.erase(timerEventScripts.cbegin(), timerIt);
}
timedEvent = nullptr;
return currentTime;
}
void _stdcall AddTimerEventScripts(DWORD script, long time, long param) {
sScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second);
TimedEvent timer;
timer.script = scriptProg;
timer.fixed_param = param;
timer.time = *ptr_fallout_game_time + time;
timerEventScripts.push_back(std::move(timer));
timerEventScripts.sort(TimedEvent());
}
void _stdcall RemoveTimerEventScripts(DWORD script, long param) {
sScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second);
timerEventScripts.remove_if([scriptProg, param] (TimedEvent timer) {
return timer.script == scriptProg && timer.fixed_param == param;
});
}
void _stdcall RemoveTimerEventScripts(DWORD script) {
sScriptProgram* 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 _stdcall RunGlobalScriptsAtProc(DWORD procId) {
for (DWORD d = 0; d < globalScripts.size(); d++) {
+5 -1
View File
@@ -17,6 +17,7 @@
*/
#pragma once
#include "main.h"
#include "FalloutStructs.h"
@@ -48,12 +49,15 @@ bool _stdcall IsGameScript(const char* filename);
void LoadGlobalScripts();
void ClearGlobalScripts();
void RunGlobalScripts1();
void RunGlobalScripts2();
void RunGlobalScripts3();
void _stdcall RunGlobalScriptsAtProc(DWORD procId);
void AfterAttackCleanup();
void _stdcall AddTimerEventScripts(DWORD script, long time, long param);
void _stdcall RemoveTimerEventScripts(DWORD script, long param);
void _stdcall RemoveTimerEventScripts(DWORD script);
bool LoadGlobals(HANDLE h);
void SaveGlobals(HANDLE h);
void ClearGlobals();
+2
View File
@@ -119,6 +119,7 @@ static void sf_metarule_exist() {
*/
static const SfallMetarule metaruleArray[] = {
{"add_iface_tag", sf_add_iface_tag, 0, 0},
{"add_g_timer_event", sf_add_g_timer_event, 2, 2},
{"add_trait", sf_add_trait, 1, 1},
{"art_cache_clear", sf_art_cache_flush, 0, 0},
{"attack_is_aimed", sf_attack_is_aimed, 0, 0},
@@ -149,6 +150,7 @@ static const SfallMetarule metaruleArray[] = {
{"obj_under_cursor", sf_get_obj_under_cursor, 2, 2},
{"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},
{"set_cursor_mode", sf_set_cursor_mode, 1, 1},
{"set_flags", sf_set_flags, 2, 2},
{"set_iface_tag_text", sf_set_iface_tag_text, 3, 3},