mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
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:
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
+49
-26
@@ -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,18 +1297,36 @@ 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);
|
||||
static void LoadGlobalScriptsList() {
|
||||
sScriptProgram prog;
|
||||
for (std::vector<std::string>::const_iterator it = globalScriptFilesList.begin(); it != globalScriptFilesList.end(); ++it) {
|
||||
const std::string &scriptFile = *it;
|
||||
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** filenames;
|
||||
int count = DbGetFileList(name, &filenames);
|
||||
|
||||
// TODO: refactor script programs
|
||||
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)
|
||||
@@ -1316,26 +1337,25 @@ void LoadGlobalScripts() {
|
||||
|
||||
baseName = baseName.substr(0, lastDot); // script name without extension
|
||||
if (!IsGameScript(baseName.c_str())) {
|
||||
dlog("> ", DL_SCRIPT);
|
||||
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;
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user