Added "register_hook_proc_spec" script function

Updated documents to address the new function.
This commit is contained in:
NovaRain
2019-09-12 22:23:02 +08:00
parent aa22575ec9
commit 9693c0d439
6 changed files with 47 additions and 7 deletions
+3
View File
@@ -46,6 +46,9 @@ Used from a normal global script if you want to run it at the same point a full
> void register_hook_proc(int hook, procedure proc)
The same as register_hook, except that you specifically define which procedure in the current script should be called as a hook (instead of "start" by default). Pass procedure the same as how you use dialog option functions. This IS the recommended way to use hook scripts, as it gives both modularity (each mod logic in a separate global script, no conflicts if you don't use "hs_*.int" scripts) and flexibility (you can place all related hook scripts for specific mod in a single script!).
> void register_hook_proc_spec(int hook, procedure proc)
Works very similar to register_hook_proc, except that it registers the current script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the hs_*.int script.) All scripts hooked to a single hook point with this function are executed in exact order of how they were registered, as opposed to the description below, which refers to using register_hook/register_hook_proc functions.
NOTE: you can hook several scripts to a single hook point, for example if it's different mods from different authors or just some different aspects of one larger mod. In this case scripts are executed in reverse order of how they were registered. When one of the scripts in a chain returns value with "set_sfall_return", the next script may override this value if calls "set_sfall_return" again. Sometimes you need to multiply certain value in a chain of hook scripts.
Example: let's say we have a Mod A which reduces all "to hit" chances by 50%. The code might look like this:
@@ -302,6 +302,10 @@ Some utility/math functions are available:
- second argument should be passed just like you pass procedures to functions like gsay_option, giq_option, etc (name without quotes)
- see "hookscripts.txt" for more details
> void register_hook_proc_spec(int hook, procedure proc)
- works just like "register_hook_proc", but allows to register a script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the hs_*.int script)
- to unregister hook script from current global script, use the register_hook_proc function
> string message_str_game(int fileId, int messageId)
- works exactly the same as message_str, except you get messages from files in "text\<language>\game\" directory
- use GAME_MSG_* defines or mstr_* macros from sfall.h to use specific msg file
@@ -357,6 +357,8 @@
0x827b - any sfall_func5(string funcName, arg1, arg2, arg3, arg4, arg5)
0x827c - any sfall_func6(string funcName, arg1, arg2, arg3, arg4, arg5, arg6)
0x827d - void register_hook_proc_spec(int hook, procedure proc)
* These functions require AllowUnsafeScripting to be enabled in ddraw.ini
+18 -4
View File
@@ -67,6 +67,12 @@ static DWORD cArg; // how many arguments were taken by current hook script
static DWORD cRet; // how many return values were set by current hook script
static DWORD cRetTmp; // how many return values were set by specific hook script (when using register_hook)
static struct HooksPositionInfo {
long hsPosition; // index of the hs_* script, or the beginning of the position for registering scripts using register_hook
// long positionShift; // offset to the last script registered by register_hook
bool hasHsScript;
} hooksInfo[HOOK_COUNT];
#define hookbegin(a) pushadc __asm call BeginHook popadc __asm mov argCount, a
#define hookend pushadc __asm call EndHook popadc
#define HookBegin pushadc __asm call BeginHook popadc
@@ -1372,7 +1378,7 @@ void _stdcall SetHSReturn(DWORD value) {
}
}
void _stdcall RegisterHook(DWORD script, DWORD id, DWORD procNum) {
void _stdcall RegisterHook(DWORD script, DWORD id, DWORD procNum, bool specReg) {
if (id >= numHooks) return;
for (std::vector<sHookScript>::iterator it = hooks[id].begin(); it != hooks[id].end(); ++it) {
if (it->prog.ptr == script) {
@@ -1389,7 +1395,13 @@ void _stdcall RegisterHook(DWORD script, DWORD id, DWORD procNum) {
hook.prog = *prog;
hook.callback = procNum;
hook.isGlobalScript = true;
hooks[id].push_back(hook);
auto c_it = hooks[id].cend();
if (specReg) {
c_it = hooks[id].cbegin();
hooksInfo[id].hsPosition++;
}
hooks[id].insert(c_it, hook);
}
}
@@ -1607,6 +1619,7 @@ void HookScriptClear() {
for (int i = 0; i < numHooks; i++) {
hooks[i].clear();
}
memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo));
}
void HookScriptInit() {
@@ -1615,6 +1628,7 @@ void HookScriptInit() {
InitingHookScripts = 1;
for (int i = 0; i < numHooks; i++) {
if (!hooks[i].empty()) {
hooksInfo[i].hasHsScript = true;
InitScriptProgram(hooks[i][0].prog);// zero hook is always hs_*.int script because Hook scripts are loaded BEFORE global scripts
}
}
@@ -1625,8 +1639,8 @@ void HookScriptInit() {
// run specific event procedure for all hook scripts
void _stdcall RunHookScriptsAtProc(DWORD procId) {
for (int i = 0; i < numHooks; i++) {
if (!hooks[i].empty() && !hooks[i][0].isGlobalScript) {
RunScriptProc(&hooks[i][0].prog, procId); // run hs_*.int
if (hooksInfo[i].hasHsScript /*&& !hooks[i][hooksInfo[i].hsPosition].isGlobalScript*/) {
RunScriptProc(&hooks[i][hooksInfo[i].hsPosition].prog, procId); // run hs_*.int
}
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ 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(DWORD script, DWORD id, DWORD procNum);
void _stdcall RegisterHook(DWORD script, DWORD id, DWORD procNum, bool specReg);
void HookScriptInit();
void HookScriptClear();
+19 -2
View File
@@ -805,7 +805,7 @@ static void _stdcall register_hook2() {
const ScriptValue &idArg = opHandler.arg(0);
if (idArg.isInt()) {
RegisterHook((DWORD)opHandler.program(), idArg.rawValue(), -1);
RegisterHook((DWORD)opHandler.program(), idArg.rawValue(), -1, false);
} else {
OpcodeInvalidArgs("register_hook");
}
@@ -820,7 +820,7 @@ static void _stdcall register_hook_proc2() {
&procArg = opHandler.arg(1);
if (idArg.isInt() && procArg.isInt()) {
RegisterHook((DWORD)opHandler.program(), idArg.rawValue(), procArg.rawValue());
RegisterHook((DWORD)opHandler.program(), idArg.rawValue(), procArg.rawValue(), false);
} else {
OpcodeInvalidArgs("register_hook_proc");
}
@@ -830,6 +830,21 @@ static void __declspec(naked) register_hook_proc() {
_WRAP_OPCODE(register_hook_proc2, 2, 0)
}
static void _stdcall register_hook_proc_spec2() {
const ScriptValue &idArg = opHandler.arg(0),
&procArg = opHandler.arg(1);
if (idArg.isInt() && procArg.isInt()) {
RegisterHook((DWORD)opHandler.program(), idArg.rawValue(), procArg.rawValue(), true);
} else {
OpcodeInvalidArgs("register_hook_proc_spec");
}
}
static void __declspec(naked) register_hook_proc_spec() {
_WRAP_OPCODE(register_hook_proc_spec2, 2, 0)
}
static void __declspec(naked) sfall_ver_major() {
_OP_BEGIN(ebp)
__asm {
@@ -1728,6 +1743,8 @@ void ScriptExtenderSetup() {
opcodes[0x27b] = op_sfall_metarule5;
opcodes[0x27c] = op_sfall_metarule6; // if you need more arguments - use arrays
opcodes[0x27d] = register_hook_proc_spec;
InitOpcodeMetaTable();
InitMetaruleTable();
}