Added a fix to limit the maximum distance for knockback animation

* 20 hexes at max. This does not affect the knockback value in
Combat Damage hook, only the animation part.

Backported AlwaysFindScripts option from 4.x for global scripts.
This commit is contained in:
NovaRain
2020-08-18 13:45:49 +08:00
parent a35487d0aa
commit 13976a5278
5 changed files with 70 additions and 32 deletions
+3
View File
@@ -792,6 +792,9 @@ HideObjIsNullMsg=0
;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay ;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay
DontDeleteProtos=0 DontDeleteProtos=0
;Set to 1 to force sfall to search for global scripts every time the game loads rather than only the first time
AlwaysFindScripts=0
;Set to 1 to force critters to display combat float messages ;Set to 1 to force critters to display combat float messages
;Requires AllowSoundForFloats to be enabled ;Requires AllowSoundForFloats to be enabled
Test_ForceFloats=0 Test_ForceFloats=0
+13 -1
View File
@@ -2778,7 +2778,6 @@ isDeath:
static void __declspec(naked) obj_move_to_tile_hack_ondeath() { static void __declspec(naked) obj_move_to_tile_hack_ondeath() {
static const DWORD obj_move_to_tile_Ret = 0x48A759; static const DWORD obj_move_to_tile_Ret = 0x48A759;
__asm { __asm {
test esi, esi;
jz skip; jz skip;
cmp dudeIsAnimDeath, 0; cmp dudeIsAnimDeath, 0;
jnz skip; jnz skip;
@@ -2789,6 +2788,16 @@ skip:
} }
} }
static void __declspec(naked) action_knockback_hack() {
__asm {
mov ecx, 20; // cap knockback distance
cmp ebp, ecx;
cmovg ebp, ecx;
mov ecx, 1;
retn;
}
}
void BugFixes_OnGameLoad() { void BugFixes_OnGameLoad() {
dudeIsAnimDeath = false; dudeIsAnimDeath = false;
} }
@@ -3532,4 +3541,7 @@ void BugFixesInit()
// (e.g. fire dance or knockback animation) // (e.g. fire dance or knockback animation)
MakeCall(0x41094B, show_damage_to_object_hack, 1); MakeCall(0x41094B, show_damage_to_object_hack, 1);
MakeCall(0x48A6CB, obj_move_to_tile_hack_ondeath, 1); MakeCall(0x48A6CB, obj_move_to_tile_hack_ondeath, 1);
// Fix to limit the maximum distance for knockback animation
MakeCall(0x4104D5, action_knockback_hack);
} }
+3 -3
View File
@@ -1613,7 +1613,7 @@ static void LoadHookScript(const char* name, int id) {
} }
} }
static void HookScriptInit2() { static void HookScriptInit() {
dlogr("Loading hook scripts:", DL_HOOK|DL_INIT); dlogr("Loading hook scripts:", DL_HOOK|DL_INIT);
char* mask = "scripts\\hs_*.int"; char* mask = "scripts\\hs_*.int";
@@ -1812,9 +1812,9 @@ void HookScriptClear() {
std::memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo)); std::memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo));
} }
void HookScriptInit() { void LoadHookScripts() {
isGlobalScriptLoading = 1; // this should allow to register global exported variables isGlobalScriptLoading = 1; // this should allow to register global exported variables
HookScriptInit2(); HookScriptInit();
initingHookScripts = 1; initingHookScripts = 1;
for (int i = 0; i < numHooks; i++) { for (int i = 0; i < numHooks; i++) {
if (!hooks[i].empty()) { if (!hooks[i].empty()) {
+2 -2
View File
@@ -51,16 +51,16 @@ enum HookType
DWORD __stdcall GetHSArgCount(); DWORD __stdcall GetHSArgCount();
DWORD __stdcall GetHSArg(); DWORD __stdcall GetHSArg();
DWORD* __stdcall GetHSArgs();
DWORD __stdcall GetHSArgAt(DWORD id); DWORD __stdcall GetHSArgAt(DWORD id);
DWORD* __stdcall GetHSArgs();
void __stdcall SetHSArg(DWORD id, DWORD value); void __stdcall SetHSArg(DWORD id, DWORD value);
void __stdcall SetHSReturn(DWORD d); void __stdcall SetHSReturn(DWORD d);
// register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister) // register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister)
void __stdcall RegisterHook(TProgram* script, int id, int procNum, bool specReg); void __stdcall RegisterHook(TProgram* script, int id, int procNum, bool specReg);
void HookScriptInit();
void HookScriptClear(); void HookScriptClear();
void LoadHookScripts();
extern DWORD initingHookScripts; extern DWORD initingHookScripts;
int __fastcall AmmoCostHook_Script(DWORD hookType, TGameObj* weapon, DWORD &rounds); int __fastcall AmmoCostHook_Script(DWORD hookType, TGameObj* weapon, DWORD &rounds);
+49 -26
View File
@@ -415,6 +415,8 @@ static long executeTimedEventDepth = 0;
static std::stack<TimedEvent*> executeTimedEvents; static std::stack<TimedEvent*> executeTimedEvents;
static std::list<TimedEvent> timerEventScripts; static std::list<TimedEvent> timerEventScripts;
static std::vector<std::string> globalScriptFilesList;
static std::vector<TProgram*> checkedScripts; static std::vector<TProgram*> checkedScripts;
static std::vector<sGlobalScript> globalScripts; static std::vector<sGlobalScript> globalScripts;
@@ -437,6 +439,7 @@ static void* opcodes[0x300];
DWORD availableGlobalScriptTypes = 0; DWORD availableGlobalScriptTypes = 0;
DWORD isGlobalScriptLoading = 0; DWORD isGlobalScriptLoading = 0;
bool isGameLoading; bool isGameLoading;
bool alwaysFindScripts;
bool displayWinUpdateState = false; bool displayWinUpdateState = false;
TScript overrideScriptStruct = {0}; TScript overrideScriptStruct = {0};
@@ -1294,18 +1297,36 @@ bool __stdcall IsGameScript(const char* filename) {
return false; return false;
} }
// this runs after the game was loaded/started static void LoadGlobalScriptsList() {
void LoadGlobalScripts() { sScriptProgram prog;
isGameLoading = false; for (std::vector<std::string>::const_iterator it = globalScriptFilesList.begin(); it != globalScriptFilesList.end(); ++it) {
HookScriptInit(); const std::string &scriptFile = *it;
dlogr("Loading global scripts:", DL_SCRIPT|DL_INIT); dlog("> ", DL_SCRIPT);
dlog(scriptFile.c_str(), DL_SCRIPT);
isGlobalScriptLoading = 1;
LoadScriptProgram(prog, scriptFile.c_str());
if (prog.ptr) {
dlogr(" Done", DL_SCRIPT);
sGlobalScript gscript = sGlobalScript(prog);
gscript.startProc = prog.procLookup[Scripts::start]; // get 'start' procedure position
globalScripts.push_back(gscript);
AddProgramToMap(prog);
// initialize script (start proc will be executed for the first time) -- this needs to be after script is added to "globalScripts" array
InitScriptProgram(prog);
} else {
dlogr(" Error!", DL_SCRIPT);
}
isGlobalScriptLoading = 0;
}
}
static void PrepareGlobalScriptsList() {
globalScriptFilesList.clear();
char* name = "scripts\\gl*.int"; char* name = "scripts\\gl*.int";
char** filenames; char** filenames;
int count = DbGetFileList(name, &filenames); int count = DbGetFileList(name, &filenames);
// TODO: refactor script programs
sScriptProgram prog;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
name = _strlwr(filenames[i]); // name of the script in lower case name = _strlwr(filenames[i]); // name of the script in lower case
if (name[0] != 'g' || name[1] != 'l') continue; // fix bug in db_get_file_list fuction (if the script name begins with a non-Latin character) if (name[0] != 'g' || name[1] != 'l') continue; // fix bug in db_get_file_list fuction (if the script name begins with a non-Latin character)
@@ -1316,26 +1337,25 @@ void LoadGlobalScripts() {
baseName = baseName.substr(0, lastDot); // script name without extension baseName = baseName.substr(0, lastDot); // script name without extension
if (!IsGameScript(baseName.c_str())) { if (!IsGameScript(baseName.c_str())) {
dlog("> ", DL_SCRIPT); globalScriptFilesList.push_back(baseName);
dlog(name, DL_SCRIPT);
isGlobalScriptLoading = 1;
LoadScriptProgram(prog, baseName.c_str());
if (prog.ptr) {
dlogr(" Done", DL_SCRIPT);
sGlobalScript gscript = sGlobalScript(prog);
gscript.startProc = prog.procLookup[Scripts::start]; // get 'start' procedure position
globalScripts.push_back(gscript);
AddProgramToMap(prog);
// initialize script (start proc will be executed for the first time) -- this needs to be after script is added to "globalScripts" array
InitScriptProgram(prog);
} else {
dlogr(" Error!", DL_SCRIPT);
}
isGlobalScriptLoading = 0;
} }
} }
DbFreeFileList(&filenames, 0); DbFreeFileList(&filenames, 0);
}
// this runs after the game was loaded/started
void LoadGlobalScripts() {
static bool listIsPrepared = false;
isGameLoading = false;
LoadHookScripts();
dlogr("Loading global scripts:", DL_SCRIPT|DL_INIT);
if (!listIsPrepared) { // only once
PrepareGlobalScriptsList();
listIsPrepared = !alwaysFindScripts;
}
LoadGlobalScriptsList();
dlogr("Finished loading global scripts.", DL_SCRIPT|DL_INIT); dlogr("Finished loading global scripts.", DL_SCRIPT|DL_INIT);
} }
@@ -1509,7 +1529,7 @@ static DWORD HandleTimedEventScripts() {
DevPrintf("\n[TimedEventScripts] Event: %d", it->time); DevPrintf("\n[TimedEventScripts] Event: %d", it->time);
} }
bool eventsWereRunning = false; bool eventWasRunning = false;
for (std::list<TimedEvent>::const_iterator timerIt = timerEventScripts.cbegin(); timerIt != timerEventScripts.cend(); ++timerIt) { for (std::list<TimedEvent>::const_iterator timerIt = timerEventScripts.cbegin(); timerIt != timerEventScripts.cend(); ++timerIt) {
if (timerIt->isActive == false) continue; if (timerIt->isActive == false) continue;
if (currentTime >= timerIt->time) { if (currentTime >= timerIt->time) {
@@ -1527,14 +1547,14 @@ static DWORD HandleTimedEventScripts() {
timedEvent = executeTimedEvents.top(); // restore a pointer to a previously running event timedEvent = executeTimedEvents.top(); // restore a pointer to a previously running event
executeTimedEvents.pop(); executeTimedEvents.pop();
} }
eventsWereRunning = true; eventWasRunning = true;
} else { } else {
break; break;
} }
} }
executeTimedEventDepth--; executeTimedEventDepth--;
if (eventsWereRunning && executeTimedEventDepth == 0) { if (eventWasRunning && executeTimedEventDepth == 0) {
timedEvent = nullptr; timedEvent = nullptr;
// delete all previously executed events // delete all previously executed events
for (std::list<TimedEvent>::const_iterator it = timerEventScripts.cbegin(); it != timerEventScripts.cend();) { for (std::list<TimedEvent>::const_iterator it = timerEventScripts.cbegin(); it != timerEventScripts.cend();) {
@@ -1719,6 +1739,9 @@ void ScriptExtenderInit() {
dlogr("Arrays in backward-compatiblity mode.", DL_SCRIPT); dlogr("Arrays in backward-compatiblity mode.", DL_SCRIPT);
} }
alwaysFindScripts = isDebug && (iniGetInt("Debugging", "AlwaysFindScripts", 0, ddrawIniDef) != 0);
if (alwaysFindScripts) dlogr("Always searching for global scripts behavior enabled.", DL_SCRIPT);
HookCall(0x480E7B, MainGameLoopHook); // hook the main game loop HookCall(0x480E7B, MainGameLoopHook); // hook the main game loop
HookCall(0x422845, CombatLoopHook); // hook the combat loop HookCall(0x422845, CombatLoopHook); // hook the combat loop
MakeCall(0x4230D5, AfterCombatAttackHook); MakeCall(0x4230D5, AfterCombatAttackHook);