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:
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -726,6 +726,7 @@ struct Window {
|
||||
long *drawFunc;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct sWindow {
|
||||
char name[32];
|
||||
long wID;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user