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:31:06 +08:00
parent c1b7e729a8
commit 8d813a952e
8 changed files with 83 additions and 18 deletions
+1 -1
View File
@@ -253,7 +253,7 @@
/* sfall metarule3 function macros */ /* 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 // 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) #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) #define clear_keyboard_buffer metarule3(201, 0, 0, 0)
+14
View File
@@ -2749,6 +2749,17 @@ checkTiles:
} }
} }
static void __declspec(naked) doBkProcesses_hook() {
__asm {
call gdialogActive_;
test eax, eax;
jz skip;
retn;
skip:
jmp gmovieIsPlaying_;
}
}
void BugFixesInit() void BugFixesInit()
{ {
#ifndef NDEBUG #ifndef NDEBUG
@@ -3480,4 +3491,7 @@ void BugFixesInit()
}; };
SafeWriteBytes(0x42A0F4, codeData1, 18); // ai_move_steps_closer_ SafeWriteBytes(0x42A0F4, codeData1, 18); // ai_move_steps_closer_
HookCall(0x42A0F8, (void*)obj_dist_); HookCall(0x42A0F8, (void*)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
@@ -335,6 +335,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 debug_printf_;
add esp, 8;
mov eax, 0x500494; // 'iisxxxx1'
jmp gsound_play_sfx_file_;
}
}
static void __declspec(naked) win_debug_hook() { static void __declspec(naked) win_debug_hook() {
__asm { __asm {
call debug_log_; call debug_log_;
@@ -381,7 +395,7 @@ static void DebugModePatch() {
if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ddrawIniDef)) { if (iniGetInt("Debugging", "HideObjIsNullMsg", 0, ddrawIniDef)) {
MakeJump(0x453FD2, dbg_error_hack); 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); HookCall(0x419B65, art_data_size_hook);
// Fix to prevent crashes when there is a '%' character in the printed message // Fix to prevent crashes when there is a '%' character in the printed message
@@ -408,6 +422,9 @@ static void DontDeleteProtosPatch() {
void DebugEditorInit() { void DebugEditorInit() {
DebugModePatch(); 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; if (!isDebug) return;
DontDeleteProtosPatch(); DontDeleteProtosPatch();
+1 -1
View File
@@ -534,7 +534,7 @@ void ExtraSaveSlotsInit() {
dlogr(" Done", DL_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); MakeJump(0x47F02C, GetComment_hack);
} }
+1
View File
@@ -433,6 +433,7 @@ const DWORD gmouse_3d_set_mode_ = 0x44CA18;
const DWORD gmouse_is_scrolling_ = 0x44B54C; const DWORD gmouse_is_scrolling_ = 0x44B54C;
const DWORD gmouse_set_cursor_ = 0x44C840; const DWORD gmouse_set_cursor_ = 0x44C840;
const DWORD gmovie_play_ = 0x44E690; const DWORD gmovie_play_ = 0x44E690;
const DWORD gmovieIsPlaying_ = 0x44EB14;
const DWORD GNW_do_bk_process_ = 0x4C8D1C; const DWORD GNW_do_bk_process_ = 0x4C8D1C;
const DWORD GNW_find_ = 0x4D7888; const DWORD GNW_find_ = 0x4D7888;
const DWORD GNW_win_refresh_ = 0x4D6FD8; const DWORD GNW_win_refresh_ = 0x4D6FD8;
+1
View File
@@ -712,6 +712,7 @@ extern const DWORD gmouse_3d_set_mode_;
extern const DWORD gmouse_is_scrolling_; extern const DWORD gmouse_is_scrolling_;
extern const DWORD gmouse_set_cursor_; extern const DWORD gmouse_set_cursor_;
extern const DWORD gmovie_play_; extern const DWORD gmovie_play_;
extern const DWORD gmovieIsPlaying_;
extern const DWORD GNW_do_bk_process_; extern const DWORD GNW_do_bk_process_;
extern const DWORD GNW_find_; extern const DWORD GNW_find_;
extern const DWORD GNW_win_refresh_; extern const DWORD GNW_win_refresh_;
+2 -4
View File
@@ -460,8 +460,7 @@ static void Present() {
DWORD move = r.right - r2.right; DWORD move = r.right - r2.right;
windowLeft -= move; windowLeft -= move;
r.right -= move; r.right -= move;
} } else if (r.left < r2.left) {
else if (r.left < r2.left) {
DWORD move = r2.left - r.left; DWORD move = r2.left - r.left;
windowLeft += move; windowLeft += move;
r.right += move; r.right += move;
@@ -470,8 +469,7 @@ static void Present() {
DWORD move = r.bottom - r2.bottom; DWORD move = r.bottom - r2.bottom;
windowTop -= move; windowTop -= move;
r.bottom -= move; r.bottom -= move;
} } else if (r.top < r2.top) {
else if (r.top < r2.top) {
DWORD move = r2.top - r.top; DWORD move = r2.top - r.top;
windowTop += move; windowTop += move;
r.bottom += move; r.bottom += move;
+45 -11
View File
@@ -18,6 +18,7 @@
//#include <unordered_set> //#include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <stack>
#include "main.h" #include "main.h"
#include "FalloutEngine.h" #include "FalloutEngine.h"
@@ -398,16 +399,20 @@ struct SelfOverrideObj {
} }
}; };
// Events in global scripts cannot be saved because the scripts don't have a binding object
struct TimedEvent { struct TimedEvent {
sScriptProgram* script; sScriptProgram* script;
unsigned long time; unsigned long time;
long fixed_param; long fixed_param;
bool isActive;
bool operator() (const TimedEvent &a, const TimedEvent &b) { bool operator() (const TimedEvent &a, const TimedEvent &b) {
return a.time < b.time; return a.time < b.time;
} }
} *timedEvent = nullptr; } *timedEvent = nullptr;
static long executeTimedEventDepth = 0;
static std::stack<TimedEvent*> executeTimedEvents;
static std::list<TimedEvent> timerEventScripts; static std::list<TimedEvent> timerEventScripts;
static std::vector<DWORD> checkedScripts; static std::vector<DWORD> checkedScripts;
@@ -1372,6 +1377,9 @@ static void ClearGlobalScripts() {
selfOverrideMap.clear(); selfOverrideMap.clear();
globalExportedVars.clear(); globalExportedVars.clear();
timerEventScripts.clear(); timerEventScripts.clear();
timedEvent = nullptr;
executeTimedEventDepth = 0;
while (!executeTimedEvents.empty()) executeTimedEvents.pop();
HookScriptClear(); HookScriptClear();
} }
@@ -1523,25 +1531,50 @@ static DWORD __stdcall HandleMapUpdateForScripts(const DWORD procId) {
static DWORD HandleTimedEventScripts() { static DWORD HandleTimedEventScripts() {
DWORD currentTime = *ptr_fallout_game_time; DWORD currentTime = *ptr_fallout_game_time;
bool wasRunning = false; if (timerEventScripts.empty()) return currentTime;
std::list<TimedEvent>::const_iterator timerIt = timerEventScripts.cbegin();
for (; timerIt != timerEventScripts.cend(); ++timerIt) { executeTimedEventDepth++;
DevPrintf("\n[TimedEventScripts] Time: %d / Depth: %d", currentTime, executeTimedEventDepth);
bool eventsWereRunning = false;
for (std::list<TimedEvent>::const_iterator timerIt = timerEventScripts.cbegin(); timerIt != timerEventScripts.cend(); ++timerIt) {
DevPrintf("\n[TimedEventScripts] Event: %d", timerIt->time);
if (timerIt->isActive == false) continue;
if (currentTime >= timerIt->time) { if (currentTime >= timerIt->time) {
if (timedEvent) executeTimedEvents.push(timedEvent); // store a pointer to the currently running event
timedEvent = const_cast<TimedEvent*>(&(*timerIt)); timedEvent = const_cast<TimedEvent*>(&(*timerIt));
DevPrintf("\n[TimedEventScripts] run event: %d", timerIt->time); timedEvent->isActive = false;
DevPrintf("\n[TimedEventScripts] Run event: %d", timerIt->time);
RunScriptProc(timerIt->script, Scripts::timed_event_p_proc); RunScriptProc(timerIt->script, Scripts::timed_event_p_proc);
wasRunning = true; DevPrintf("\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 { } else {
break; break;
} }
} }
if (wasRunning) { executeTimedEventDepth--;
for (std::list<TimedEvent>::const_iterator _it = timerEventScripts.cbegin(); _it != timerIt; ++_it) {
DevPrintf("\n[TimedEventScripts] delete event: %d", _it->time); if (eventsWereRunning && executeTimedEventDepth == 0) {
timedEvent = nullptr;
// delete all previously executed events
for (std::list<TimedEvent>::const_iterator it = timerEventScripts.cbegin(); it != timerEventScripts.cend();) {
if (it->isActive == false) {
DevPrintf("\n[TimedEventScripts] Remove event: %d", it->time);
it = timerEventScripts.erase(it);
} else {
++it;
}
} }
timerEventScripts.erase(timerEventScripts.cbegin(), timerIt);
} }
timedEvent = nullptr;
return currentTime; return currentTime;
} }
@@ -1553,7 +1586,7 @@ static DWORD TimedEventNextTime() {
mov nextTime, eax; mov nextTime, eax;
push edx; push edx;
} }
if (!timerEventScripts.empty()) { if (!timerEventScripts.empty() && timerEventScripts.front().isActive) {
DWORD time = timerEventScripts.front().time; DWORD time = timerEventScripts.front().time;
if (!nextTime || time < nextTime) nextTime = time; if (!nextTime || time < nextTime) nextTime = time;
} }
@@ -1569,6 +1602,7 @@ static DWORD script_chk_timed_events_hook() {
void __stdcall AddTimerEventScripts(DWORD script, long time, long param) { void __stdcall AddTimerEventScripts(DWORD script, long time, long param) {
sScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second); sScriptProgram* scriptProg = &(sfallProgsMap.find(script)->second);
TimedEvent timer; TimedEvent timer;
timer.isActive = true;
timer.script = scriptProg; timer.script = scriptProg;
timer.fixed_param = param; timer.fixed_param = param;
timer.time = *ptr_fallout_game_time + time; timer.time = *ptr_fallout_game_time + time;