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
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
;Requires AllowSoundForFloats to be enabled
Test_ForceFloats=0
+13 -1
View File
@@ -2778,7 +2778,6 @@ isDeath:
static void __declspec(naked) obj_move_to_tile_hack_ondeath() {
static const DWORD obj_move_to_tile_Ret = 0x48A759;
__asm {
test esi, esi;
jz skip;
cmp dudeIsAnimDeath, 0;
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() {
dudeIsAnimDeath = false;
}
@@ -3532,4 +3541,7 @@ void BugFixesInit()
// (e.g. fire dance or knockback animation)
MakeCall(0x41094B, show_damage_to_object_hack, 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);
char* mask = "scripts\\hs_*.int";
@@ -1812,9 +1812,9 @@ void HookScriptClear() {
std::memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo));
}
void HookScriptInit() {
void LoadHookScripts() {
isGlobalScriptLoading = 1; // this should allow to register global exported variables
HookScriptInit2();
HookScriptInit();
initingHookScripts = 1;
for (int i = 0; i < numHooks; i++) {
if (!hooks[i].empty()) {
+2 -2
View File
@@ -51,16 +51,16 @@ enum HookType
DWORD __stdcall GetHSArgCount();
DWORD __stdcall GetHSArg();
DWORD* __stdcall GetHSArgs();
DWORD __stdcall GetHSArgAt(DWORD id);
DWORD* __stdcall GetHSArgs();
void __stdcall SetHSArg(DWORD id, DWORD value);
void __stdcall SetHSReturn(DWORD d);
// 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 HookScriptInit();
void HookScriptClear();
void LoadHookScripts();
extern DWORD initingHookScripts;
int __fastcall AmmoCostHook_Script(DWORD hookType, TGameObj* weapon, DWORD &rounds);
+50 -27
View File
@@ -415,6 +415,8 @@ static long executeTimedEventDepth = 0;
static std::stack<TimedEvent*> executeTimedEvents;
static std::list<TimedEvent> timerEventScripts;
static std::vector<std::string> globalScriptFilesList;
static std::vector<TProgram*> checkedScripts;
static std::vector<sGlobalScript> globalScripts;
@@ -437,6 +439,7 @@ static void* opcodes[0x300];
DWORD availableGlobalScriptTypes = 0;
DWORD isGlobalScriptLoading = 0;
bool isGameLoading;
bool alwaysFindScripts;
bool displayWinUpdateState = false;
TScript overrideScriptStruct = {0};
@@ -1294,32 +1297,14 @@ bool __stdcall IsGameScript(const char* filename) {
return false;
}
// this runs after the game was loaded/started
void LoadGlobalScripts() {
isGameLoading = false;
HookScriptInit();
dlogr("Loading global scripts:", DL_SCRIPT|DL_INIT);
char* name = "scripts\\gl*.int";
char** filenames;
int count = DbGetFileList(name, &filenames);
// TODO: refactor script programs
static void LoadGlobalScriptsList() {
sScriptProgram prog;
for (int i = 0; i < count; i++) {
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)
std::string baseName(name);
int lastDot = baseName.find_last_of('.');
if ((baseName.length() - lastDot) > 4) continue; // skip files with invalid extension (bug in db_get_file_list fuction)
baseName = baseName.substr(0, lastDot); // script name without extension
if (!IsGameScript(baseName.c_str())) {
for (std::vector<std::string>::const_iterator it = globalScriptFilesList.begin(); it != globalScriptFilesList.end(); ++it) {
const std::string &scriptFile = *it;
dlog("> ", DL_SCRIPT);
dlog(name, DL_SCRIPT);
dlog(scriptFile.c_str(), DL_SCRIPT);
isGlobalScriptLoading = 1;
LoadScriptProgram(prog, baseName.c_str());
LoadScriptProgram(prog, scriptFile.c_str());
if (prog.ptr) {
dlogr(" Done", DL_SCRIPT);
sGlobalScript gscript = sGlobalScript(prog);
@@ -1334,8 +1319,43 @@ void LoadGlobalScripts() {
isGlobalScriptLoading = 0;
}
}
DbFreeFileList(&filenames, 0);
static void PrepareGlobalScriptsList() {
globalScriptFilesList.clear();
char* name = "scripts\\gl*.int";
char** filenames;
int count = DbGetFileList(name, &filenames);
for (int i = 0; i < count; i++) {
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)
std::string baseName(name);
int lastDot = baseName.find_last_of('.');
if ((baseName.length() - lastDot) > 4) continue; // skip files with invalid extension (bug in db_get_file_list fuction)
baseName = baseName.substr(0, lastDot); // script name without extension
if (!IsGameScript(baseName.c_str())) {
globalScriptFilesList.push_back(baseName);
}
}
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);
}
@@ -1509,7 +1529,7 @@ static DWORD HandleTimedEventScripts() {
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) {
if (timerIt->isActive == false) continue;
if (currentTime >= timerIt->time) {
@@ -1527,14 +1547,14 @@ static DWORD HandleTimedEventScripts() {
timedEvent = executeTimedEvents.top(); // restore a pointer to a previously running event
executeTimedEvents.pop();
}
eventsWereRunning = true;
eventWasRunning = true;
} else {
break;
}
}
executeTimedEventDepth--;
if (eventsWereRunning && executeTimedEventDepth == 0) {
if (eventWasRunning && executeTimedEventDepth == 0) {
timedEvent = nullptr;
// delete all previously executed events
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);
}
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(0x422845, CombatLoopHook); // hook the combat loop
MakeCall(0x4230D5, AfterCombatAttackHook);