mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
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:
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user