Added "register_hook_proc_spec" script function

Updated documents to address the new function.
This commit is contained in:
NovaRain
2019-09-12 22:16:17 +08:00
parent e23c224535
commit 2bdd469919
11 changed files with 48 additions and 25 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:
@@ -316,6 +316,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
-8
View File
@@ -181,14 +181,6 @@ long GetScriptLocalVars(long sid) {
return (script) ? script->numLocalVars : 0;
}
fo::GameObject* __fastcall LineOfSight(fo::GameObject* obj) {
long objTile = obj->tile;
fo::GameObject* object = fo::func::obj_blocking_at_wrapper(obj, objTile, obj->elevation, (void*)fo::funcoffs::obj_sight_blocking_at_);
if (object) objTile = fo::func::tile_num_in_direction(objTile, fo::func::tile_dir(objTile, fo::var::obj_dude->tile), 1);
fo::func::make_straight_path_func(fo::var::obj_dude, fo::var::obj_dude->tile, objTile, 0, (DWORD*)&object, 4, (void*)fo::funcoffs::obj_sight_blocking_at_);
return object;
}
//---------------------------------------------------------
//print text to surface
void PrintText(char *DisplayText, BYTE ColourIndex, DWORD Xpos, DWORD Ypos, DWORD TxtWidth, DWORD ToWidth, BYTE *ToSurface) {
-2
View File
@@ -76,8 +76,6 @@ bool IsPartyMember(fo::GameObject* critter);
// Returns the number of local variables of the object script
long GetScriptLocalVars(long sid);
fo::GameObject* __fastcall LineOfSight(fo::GameObject* obj);
// Print text to surface
void PrintText(char *displayText, BYTE colorIndex, DWORD x, DWORD y, DWORD textWidth, DWORD destWidth, BYTE *surface);
// gets the height of the currently selected font
+20 -5
View File
@@ -43,6 +43,12 @@ struct HooksInjectInfo {
bool isInject;
};
static struct HooksPositionInfo {
long hsPosition = 0; // index of the hs_* script, or the beginning of the position for registering scripts using register_hook
// long positionShift = 0; // offset to the last script registered by register_hook
bool hasHsScript = false;
} hooksInfo[HOOK_COUNT];
static HooksInjectInfo injectHooks[] = {
{HOOK_TOHIT, Inject_ToHitHook, false},
{HOOK_AFTERHITROLL, Inject_AfterHitRollHook, false},
@@ -167,7 +173,7 @@ bool HookScripts::HookHasScript(int hookId) {
return (hooks[hookId].empty() == false);
}
void _stdcall RegisterHook(fo::Program* script, int id, int procNum) {
void RegisterHook(fo::Program* script, int id, int procNum, bool specReg) {
if (id >= numHooks) return;
for (std::vector<HookScript>::iterator it = hooks[id].begin(); it != hooks[id].end(); ++it) {
if (it->prog.ptr == script) {
@@ -184,7 +190,14 @@ void _stdcall RegisterHook(fo::Program* script, int id, int 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);
switch (id) {
case HOOK_KEYPRESS:
case HOOK_MOUSECLICK:
@@ -218,6 +231,7 @@ void HookScriptClear() {
for(int i = 0; i < numHooks; i++) {
hooks[i].clear();
}
memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo));
}
void LoadHookScripts() {
@@ -226,6 +240,7 @@ void LoadHookScripts() {
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
}
}
@@ -234,10 +249,10 @@ void LoadHookScripts() {
}
// run specific event procedure for all hook scripts
void _stdcall RunHookScriptsAtProc(DWORD procId) {
void 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
}
}
}
+2 -2
View File
@@ -93,7 +93,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(fo::Program* script, int id, int procNum);
void RegisterHook(fo::Program* script, int id, int procNum, bool specReg);
// TODO: move
void HookScriptClear();
@@ -101,6 +101,6 @@ void LoadHookScripts();
extern DWORD initingHookScripts;
extern int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds);
void _stdcall RunHookScriptsAtProc(DWORD procId);
void RunHookScriptsAtProc(DWORD procId);
}
+1 -1
View File
@@ -617,7 +617,7 @@ static DWORD _stdcall HandleMapUpdateForScripts(const DWORD procId) {
}
// run all global scripts of types 0 and 3 at specific procedure (if exist)
void _stdcall RunGlobalScriptsAtProc(DWORD procId) {
void RunGlobalScriptsAtProc(DWORD procId) {
for (DWORD d = 0; d < globalScripts.size(); d++) {
if (globalScripts[d].mode != 0 && globalScripts[d].mode != 3) continue;
RunScriptProc(&globalScripts[d].prog, procId);
+1 -1
View File
@@ -56,7 +56,7 @@ void __fastcall SetGlobalScriptRepeat(fo::Program* script, int frames);
void __fastcall SetGlobalScriptType(fo::Program* script, int type);
bool _stdcall IsGameScript(const char* filename);
void _stdcall RunGlobalScriptsAtProc(DWORD procId);
void RunGlobalScriptsAtProc(DWORD procId);
bool LoadGlobals(HANDLE h);
void SaveGlobals(HANDLE h);
+13 -6
View File
@@ -221,12 +221,19 @@ end:
// used for both register_hook and register_hook_proc
void sf_register_hook(OpcodeContext& ctx) {
int id = ctx.arg(0).asInt();
int proc = (ctx.numArgs() > 1)
? ctx.arg(1).asInt()
: -1;
RegisterHook(ctx.program(), id, proc);
bool specReg = false;
int proc;
switch (ctx.opcode()) {
case 0x27d:
specReg = true;
case 0x262:
proc = ctx.arg(1).rawValue();
if (proc < 0 || (specReg && proc == 0)) return;
break;
default:
proc = -1;
}
RegisterHook(ctx.program(), ctx.arg(0).rawValue(), proc, specReg);
}
void sf_sfall_ver_major(OpcodeContext& ctx) {
+2
View File
@@ -210,6 +210,8 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x27a, "sfall_func4", HandleMetarule, 5, true},
{0x27b, "sfall_func5", HandleMetarule, 6, true},
{0x27c, "sfall_func6", HandleMetarule, 7, true}, // if you need more arguments - use arrays
{0x27d, "register_hook_proc_spec", sf_register_hook, 2, false, {ARG_INT, ARG_INT}},
};
// A hash-table for opcode info, indexed by opcode.