Fixed and improved the behavior of nested timer events in global scripts

Added a fix to prevent the execution of critter_p_proc and game events
when playing movies.

Added a debug message about a corrupted proto file.

Some minor code/document edits.
This commit is contained in:
NovaRain
2020-08-14 21:23:08 +08:00
parent ff4757d529
commit 46a5616b34
8 changed files with 86 additions and 21 deletions
+1 -1
View File
@@ -281,7 +281,7 @@
/* sfall metarule3 function macros */
// sets the number of days (range 1...127) for the Frank Horrigan encounter, or disable the encounter if days is set to 0
#define set_horrigan_days(day) metarule3(200, day, 0, 0)
// clears the keyboard input buffer, use it in the HOOK_KEYPRESS hook to clear keyboard events before calling script functions that accept key input
// clears the keyboard input buffer, use it in the HOOK_KEYPRESS hook to clear keyboard events before calling functions that are waiting for keyboard input
#define clear_keyboard_buffer metarule3(201, 0, 0, 0)
+1
View File
@@ -726,6 +726,7 @@ struct Window {
long *drawFunc;
};
#pragma pack(1)
struct sWindow {
char name[32];
long wID;
+14
View File
@@ -2766,6 +2766,17 @@ checkTiles:
}
}
static void __declspec(naked) doBkProcesses_hook() {
__asm {
call fo::funcoffs::gdialogActive_;
test eax, eax;
jz skip;
retn;
skip:
jmp fo::funcoffs::gmovieIsPlaying_;
}
}
void BugFixes::init()
{
#ifndef NDEBUG
@@ -3489,6 +3500,9 @@ void BugFixes::init()
};
SafeWriteBytes(0x42A0F4, codeData1, 18); // ai_move_steps_closer_
HookCall(0x42A0F8, (void*)fo::funcoffs::obj_dist_);
// Fix to prevent the execution of critter_p_proc and game events when playing movies (same as when the dialog is active)
HookCall(0x4A3C89, doBkProcesses_hook);
}
}
+18 -1
View File
@@ -338,6 +338,20 @@ display:
}
}
static void __declspec(naked) proto_load_pid_hack() {
static char* proDbgMsg = "\nERROR reading prototype file: %s\n";
__asm {
mov dword ptr [esp + 0x120 - 0x1C + 4], -1;
lea eax, [esp + 0x120 - 0x120 + 4]; // pro file
push eax;
push proDbgMsg;
call fo::funcoffs::debug_printf_;
add esp, 8;
mov eax, 0x500494; // 'iisxxxx1'
jmp fo::funcoffs::gsound_play_sfx_file_;
}
}
static void __declspec(naked) win_debug_hook() {
__asm {
call fo::funcoffs::debug_log_;
@@ -384,7 +398,7 @@ static void DebugModePatch() {
if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ::sfall::ddrawIni)) {
MakeJump(0x453FD2, dbg_error_hack);
}
// prints a debug message about missing art file for critters to both debug.log and the message window in sfall debugging mode
// prints a debug message about a missing critter art file to both debug.log and the message window in sfall debugging mode
HookCall(0x419B65, art_data_size_hook);
// Fix to prevent crashes when there is a '%' character in the printed message
@@ -411,6 +425,9 @@ static void DontDeleteProtosPatch() {
void DebugEditor::init() {
DebugModePatch();
// Notifies and prints a debug message about a corrupted proto file to debug.log
MakeCall(0x4A1D73, proto_load_pid_hack, 6);
if (!isDebug) return;
DontDeleteProtosPatch();
+1 -1
View File
@@ -535,7 +535,7 @@ void ExtraSaveSlots::init() {
dlogr(" Done", DL_INIT);
}
// Adds the city name in the description of a save slot
// Adds the city name in the description for empty save slots
MakeJump(0x47F02C, GetComment_hack);
}
+2 -4
View File
@@ -359,8 +359,7 @@ static void Present() {
DWORD move = r.right - r2.right;
windowLeft -= move;
r.right -= move;
}
else if (r.left < r2.left) {
} else if (r.left < r2.left) {
DWORD move = r2.left - r.left;
windowLeft += move;
r.right += move;
@@ -369,8 +368,7 @@ static void Present() {
DWORD move = r.bottom - r2.bottom;
windowTop -= move;
r.bottom -= move;
}
else if (r.top < r2.top) {
} else if (r.top < r2.top) {
DWORD move = r2.top - r.top;
windowTop += move;
r.bottom += move;
+1 -2
View File
@@ -527,8 +527,7 @@ static long __fastcall TargetObjectHook(DWORD isValid, DWORD object, long type)
targetRet = (rets[0] != 0) ? rets[0] : object; // 0 - default object, -1 - invalid target, or object override
object = (targetRet != -1) ? targetRet : 0; // object can't be -1
targetObjHookHasRet = true;
}
else if (targetObjHookHasRet && type == 1) {
} else if (targetObjHookHasRet && type == 1) {
targetObjHookHasRet = false;
if (targetRet != -1) object = targetRet;
}
+48 -12
View File
@@ -19,6 +19,7 @@
//#include <unordered_set>
#include <unordered_map>
#include <map>
#include <stack>
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
@@ -84,16 +85,20 @@ struct SelfOverrideObj {
}
};
// Events in global scripts cannot be saved because the scripts don't have a binding object
struct TimedEvent {
ScriptProgram* script;
unsigned long time;
long fixed_param;
bool isActive;
bool operator() (const TimedEvent &a, const TimedEvent &b) {
return a.time < b.time;
}
} *timedEvent = nullptr;
static long executeTimedEventDepth = 0;
static std::stack<TimedEvent*> executeTimedEvents;
static std::list<TimedEvent> timerEventScripts;
static std::vector<std::string> globalScriptPathList;
@@ -559,6 +564,9 @@ static void ClearGlobalScripts() {
selfOverrideMap.clear();
globalExportedVars.clear();
timerEventScripts.clear();
timedEvent = nullptr;
executeTimedEventDepth = 0;
while (!executeTimedEvents.empty()) executeTimedEvents.pop();
HookScriptClear();
}
@@ -637,7 +645,9 @@ static DWORD __stdcall HandleMapUpdateForScripts(const DWORD procId) {
for (std::vector<GlobalScript>::const_iterator it = globalScripts.cbegin(); it != globalScripts.cend(); ++it) {
fo::func::runProgram(it->prog.ptr);
}
} else if (procId == fo::Scripts::ScriptProc::map_exit_p_proc) onMapExit.invoke();
} else if (procId == fo::Scripts::ScriptProc::map_exit_p_proc) {
onMapExit.invoke();
}
RunGlobalScriptsAtProc(procId); // gl* scripts of types 0 and 3
RunHookScriptsAtProc(procId); // all hs_ scripts
@@ -647,25 +657,50 @@ static DWORD __stdcall HandleMapUpdateForScripts(const DWORD procId) {
static DWORD HandleTimedEventScripts() {
DWORD currentTime = fo::var::fallout_game_time;
bool wasRunning = false;
auto timerIt = timerEventScripts.cbegin();
for (; timerIt != timerEventScripts.cend(); ++timerIt) {
if (timerEventScripts.empty()) return currentTime;
executeTimedEventDepth++;
fo::func::dev_printf("\n[TimedEventScripts] Time: %d / Depth: %d", currentTime, executeTimedEventDepth);
bool eventsWereRunning = false;
for (auto timerIt = timerEventScripts.cbegin(); timerIt != timerEventScripts.cend(); ++timerIt) {
fo::func::dev_printf("\n[TimedEventScripts] Event: %d", timerIt->time);
if (timerIt->isActive == false) continue;
if (currentTime >= timerIt->time) {
if (timedEvent) executeTimedEvents.push(timedEvent); // store a pointer to the currently running event
timedEvent = const_cast<TimedEvent*>(&(*timerIt));
fo::func::dev_printf("\n[TimedEventScripts] run event: %d", timerIt->time);
timedEvent->isActive = false;
fo::func::dev_printf("\n[TimedEventScripts] Run event: %d", timerIt->time);
RunScriptProc(timerIt->script, fo::Scripts::ScriptProc::timed_event_p_proc);
wasRunning = true;
fo::func::dev_printf("\n[TimedEventScripts] Event done: %d", timerIt->time);
timedEvent = nullptr;
if (!executeTimedEvents.empty()) {
timedEvent = executeTimedEvents.top(); // restore a pointer to a previously running event
executeTimedEvents.pop();
}
eventsWereRunning = true;
} else {
break;
}
}
if (wasRunning) {
for (auto _it = timerEventScripts.cbegin(); _it != timerIt; ++_it) {
fo::func::dev_printf("\n[TimedEventScripts] delete event: %d", _it->time);
executeTimedEventDepth--;
if (eventsWereRunning && executeTimedEventDepth == 0) {
timedEvent = nullptr;
// delete all previously executed events
for (auto it = timerEventScripts.cbegin(); it != timerEventScripts.cend();) {
if (it->isActive == false) {
fo::func::dev_printf("\n[TimedEventScripts] Remove event: %d", it->time);
it = timerEventScripts.erase(it);
} else {
++it;
}
}
timerEventScripts.erase(timerEventScripts.cbegin(), timerIt);
}
timedEvent = nullptr;
return currentTime;
}
@@ -677,7 +712,7 @@ static DWORD TimedEventNextTime() {
mov nextTime, eax;
push edx;
}
if (!timerEventScripts.empty()) {
if (!timerEventScripts.empty() && timerEventScripts.front().isActive) {
DWORD time = timerEventScripts.front().time;
if (!nextTime || time < nextTime) nextTime = time;
}
@@ -693,6 +728,7 @@ static DWORD script_chk_timed_events_hook() {
void ScriptExtender::AddTimerEventScripts(fo::Program* script, long time, long param) {
ScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second);
TimedEvent timer;
timer.isActive = true;
timer.script = scriptProg;
timer.fixed_param = param;
timer.time = fo::var::fallout_game_time + time;