mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Merge pull request #473 from sfall-team/hook_return_string_v2
Allow passing string directly to set_sfall_return in HOOK_DESCRIPTIONOBJ (v2)
This commit is contained in:
@@ -1098,7 +1098,7 @@
|
||||
opcode: 0x8251
|
||||
- name: get_string_pointer
|
||||
detail: int get_string_pointer(string text)
|
||||
doc: Returns a pointer to a string variable or to a text.
|
||||
doc: Returns a pointer to a string variable or to a text. DEPRECATED, just use normal strings instead.
|
||||
macro: sfall.h
|
||||
- name: string_format
|
||||
detail: string string_format(string format, any val1, any val2, ...)
|
||||
|
||||
@@ -321,7 +321,6 @@
|
||||
#define get_npc_stat_max(stat) sfall_func2("get_stat_max", stat, 1)
|
||||
#define get_npc_stat_min(stat) sfall_func2("get_stat_min", stat, 1)
|
||||
#define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum)
|
||||
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
|
||||
#define get_terrain_name(x, y) sfall_func2("get_terrain_name", x, y)
|
||||
#define get_text_width(text) sfall_func1("get_text_width", text)
|
||||
#define has_fake_perk_npc(npc, perk) sfall_func2("has_fake_perk_npc", npc, perk)
|
||||
|
||||
@@ -610,7 +610,7 @@
|
||||
```
|
||||
Obj arg0 - the object
|
||||
|
||||
int ret0 - a pointer to the new text received by using the get_string_pointer function
|
||||
str ret0 - new description text to use
|
||||
```
|
||||
|
||||
- name: UseSkillOn
|
||||
|
||||
@@ -694,7 +694,7 @@ Does not run if the script of the object overrides the description.
|
||||
```
|
||||
Obj arg0 - the object
|
||||
|
||||
int ret0 - a pointer to the new text received by using the get_string_pointer function
|
||||
str ret0 - new description text to use
|
||||
```
|
||||
|
||||
-------------------------------------------
|
||||
|
||||
@@ -706,6 +706,7 @@ sfall_funcX metarule functions
|
||||
----
|
||||
#### get_string_pointer
|
||||
`int sfall_func1("get_string_pointer", string text)`
|
||||
- DEPRECATED, use normal strings
|
||||
- Returns a pointer to a string variable or to a text
|
||||
|
||||
----
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
using namespace sfall::script;
|
||||
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
@@ -12,17 +14,21 @@ constexpr int maxDepth = 8; // Maximum recursion depth for hook calls
|
||||
|
||||
struct {
|
||||
DWORD hookID;
|
||||
bool allowNonIntReturn;
|
||||
DWORD argCount;
|
||||
DWORD cArg;
|
||||
DWORD cRet;
|
||||
DWORD cRetTmp;
|
||||
DWORD oldArgs[maxArgs];
|
||||
DWORD oldRets[maxRets];
|
||||
DWORD args[maxArgs];
|
||||
DWORD rets[maxRets];
|
||||
DataType retTypes[maxRets];
|
||||
} savedArgs[maxDepth];
|
||||
|
||||
static DWORD callDepth;
|
||||
static DWORD currentRunHook = -1;
|
||||
|
||||
bool allowNonIntReturn;
|
||||
DataType retTypes[maxRets]; // current hook return value types
|
||||
DWORD args[maxArgs]; // current hook arguments
|
||||
DWORD rets[maxRets]; // current hook return values
|
||||
|
||||
@@ -37,25 +43,27 @@ DWORD HookCommon::GetHSArgCount() {
|
||||
return argCount;
|
||||
}
|
||||
|
||||
DWORD HookCommon::GetHSArg() {
|
||||
return (cArg == argCount) ? 0 : args[cArg++];
|
||||
ScriptValue HookCommon::GetHSArg() {
|
||||
return (cArg == argCount) ? 0 : GetHSArgAt(cArg++);
|
||||
}
|
||||
|
||||
void HookCommon::SetHSArg(DWORD id, DWORD value) {
|
||||
if (id < argCount) args[id] = value;
|
||||
void HookCommon::SetHSArg(DWORD id, const ScriptValue& value) {
|
||||
if (id < argCount) {
|
||||
args[id] = value.rawValue();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD* HookCommon::GetHSArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
DWORD HookCommon::GetHSArgAt(DWORD id) {
|
||||
ScriptValue HookCommon::GetHSArgAt(DWORD id) {
|
||||
return args[id];
|
||||
}
|
||||
|
||||
void __stdcall HookCommon::SetHSReturn(DWORD value) {
|
||||
void __stdcall HookCommon::SetHSReturn(const ScriptValue& value) {
|
||||
// For backward compatibility - ignore non-int return values
|
||||
if (!allowNonIntReturn && !value.isInt()) return;
|
||||
|
||||
if (cRetTmp < maxRets) {
|
||||
rets[cRetTmp++] = value;
|
||||
retTypes[cRetTmp] = value.type();
|
||||
rets[cRetTmp++] = value.rawValue();
|
||||
}
|
||||
if (cRetTmp > cRet) {
|
||||
cRet = cRetTmp;
|
||||
@@ -81,12 +89,16 @@ void __stdcall BeginHook() {
|
||||
// save all values of the current hook if another hook was called during the execution of the current hook
|
||||
int cDepth = callDepth - 1;
|
||||
savedArgs[cDepth].hookID = currentRunHook;
|
||||
savedArgs[cDepth].allowNonIntReturn = allowNonIntReturn;
|
||||
savedArgs[cDepth].argCount = argCount; // number of arguments of the current hook
|
||||
savedArgs[cDepth].cArg = cArg; // current count of taken arguments
|
||||
savedArgs[cDepth].cRet = cRet; // number of return values for the current hook
|
||||
savedArgs[cDepth].cRetTmp = cRetTmp;
|
||||
std::memcpy(&savedArgs[cDepth].oldArgs, args, maxArgs * sizeof(DWORD)); // values of the arguments
|
||||
if (cRet) std::memcpy(&savedArgs[cDepth].oldRets, rets, maxRets * sizeof(DWORD)); // return values
|
||||
std::memcpy(&savedArgs[cDepth].args, args, maxArgs * sizeof(DWORD)); // values of the arguments
|
||||
if (cRet) {
|
||||
std::memcpy(&savedArgs[cDepth].rets, rets, maxRets * sizeof(DWORD)); // return values
|
||||
std::memcpy(&savedArgs[cDepth].retTypes, retTypes, maxRets * sizeof(DataType)); // return value types
|
||||
}
|
||||
|
||||
//devlog_f("\nSaved cArgs/cRet: %d / %d(%d)\n", DL_HOOK, savedArgs[cDepth].argCount, savedArgs[cDepth].cRet, cRetTmp);
|
||||
//for (unsigned int i = 0; i < maxArgs; i++) {
|
||||
@@ -94,6 +106,7 @@ void __stdcall BeginHook() {
|
||||
//}
|
||||
}
|
||||
callDepth++;
|
||||
allowNonIntReturn = false;
|
||||
|
||||
devlog_f("Begin running hook, current depth: %d, current executable hook: %d\n", DL_HOOK, callDepth, currentRunHook);
|
||||
}
|
||||
@@ -146,12 +159,16 @@ void __stdcall EndHook() {
|
||||
// restore all saved values of the previous hook
|
||||
int cDepth = callDepth - 1;
|
||||
currentRunHook = savedArgs[cDepth].hookID;
|
||||
allowNonIntReturn = savedArgs[cDepth].allowNonIntReturn;
|
||||
argCount = savedArgs[cDepth].argCount;
|
||||
cArg = savedArgs[cDepth].cArg;
|
||||
cRet = savedArgs[cDepth].cRet;
|
||||
cRetTmp = savedArgs[cDepth].cRetTmp; // also restore current count of the number of return values
|
||||
std::memcpy(args, &savedArgs[cDepth].oldArgs, maxArgs * sizeof(DWORD));
|
||||
if (cRet) std::memcpy(rets, &savedArgs[cDepth].oldRets, maxRets * sizeof(DWORD));
|
||||
std::memcpy(args, &savedArgs[cDepth].args, maxArgs * sizeof(DWORD));
|
||||
if (cRet > 0) {
|
||||
std::memcpy(rets, &savedArgs[cDepth].rets, maxRets * sizeof(DWORD));
|
||||
std::memcpy(retTypes, &savedArgs[cDepth].retTypes, maxRets * sizeof(DataType));
|
||||
}
|
||||
|
||||
//devlog_f("Restored cArgs/cRet: %d / %d(%d)\n", DL_HOOK, argCount, cRet, cRetTmp);
|
||||
//for (unsigned int i = 0; i < maxArgs; i++) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "..\HookScripts.h"
|
||||
#include "..\ScriptExtender.h"
|
||||
#include "..\Scripting\ScriptValue.h"
|
||||
|
||||
// Common variables and functions for hook script implementations
|
||||
|
||||
@@ -11,11 +12,10 @@ namespace sfall
|
||||
class HookCommon {
|
||||
public:
|
||||
static DWORD GetHSArgCount();
|
||||
static DWORD GetHSArg();
|
||||
static DWORD GetHSArgAt(DWORD id);
|
||||
static DWORD* GetHSArgs();
|
||||
static void SetHSArg(DWORD id, DWORD value);
|
||||
static void __stdcall SetHSReturn(DWORD d);
|
||||
static script::ScriptValue GetHSArg();
|
||||
static script::ScriptValue GetHSArgAt(DWORD id);
|
||||
static void SetHSArg(DWORD id, const script::ScriptValue& value);
|
||||
static void __stdcall SetHSReturn(const script::ScriptValue& value);
|
||||
|
||||
static void GameModeChangeHook(DWORD exit);
|
||||
static void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey);
|
||||
@@ -34,11 +34,12 @@ struct HookScript {
|
||||
// All currently registered hook scripts
|
||||
extern std::vector<HookScript> hooks[];
|
||||
|
||||
extern bool allowNonIntReturn; // allow set_sfall_return with non-int values (validate value in the hook code)
|
||||
extern script::DataType retTypes[]; // current hook return value types
|
||||
extern DWORD args[]; // current hook arguments
|
||||
extern DWORD rets[]; // current hook return values
|
||||
|
||||
extern DWORD argCount;
|
||||
extern DWORD cArg; // how many arguments were taken by current hook script
|
||||
extern DWORD cRet; // how many return values were set by current hook script
|
||||
extern DWORD cRetTmp; // how many return values were set by specific hook script (when using register_hook)
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "ObjectHs.h"
|
||||
|
||||
using namespace sfall::script;
|
||||
|
||||
// Object hook scripts
|
||||
namespace sfall
|
||||
{
|
||||
@@ -157,16 +159,19 @@ end:
|
||||
|
||||
static DWORD __fastcall DescriptionObjHook_Script(DWORD object) {
|
||||
BeginHook();
|
||||
allowNonIntReturn = true;
|
||||
argCount = 1;
|
||||
|
||||
args[0] = object;
|
||||
|
||||
RunHookScript(HOOK_DESCRIPTIONOBJ);
|
||||
|
||||
DWORD textPrt = (cRet > 0) ? rets[0] : 0;
|
||||
EndHook();
|
||||
DWORD textPtr = cRet > 0 && (retTypes[0] == DataType::INT || retTypes[0] == DataType::STR)
|
||||
? rets[0]
|
||||
: 0;
|
||||
|
||||
return textPrt;
|
||||
EndHook();
|
||||
return textPtr;
|
||||
}
|
||||
|
||||
static void __declspec(naked) DescriptionObjHook() {
|
||||
|
||||
@@ -81,6 +81,11 @@ void sArrayElement::setByType( DWORD val, DataType dataType )
|
||||
}
|
||||
}
|
||||
|
||||
void sArrayElement::set(const ScriptValue& val)
|
||||
{
|
||||
setByType(val.rawValue(), val.type());
|
||||
}
|
||||
|
||||
void sArrayElement::set( long val )
|
||||
{
|
||||
clearData();
|
||||
@@ -542,15 +547,15 @@ void setArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool all
|
||||
// add pair
|
||||
el = arr.val.size();
|
||||
arr.val.resize(el + 2);
|
||||
arr.val[el].setByType(key.rawValue(), key.type()); // copy data
|
||||
arr.val[el].set(key); // copy data
|
||||
arr.keyHash[arr.val[el]] = el;
|
||||
}
|
||||
arr.val[el + 1].setByType(val.rawValue(), val.type());
|
||||
arr.val[el + 1].set(val);
|
||||
}
|
||||
} else if (key.isInt()) { // only update normal array if key is an integer and within array size
|
||||
size_t index = key.rawValue();
|
||||
if (arr.val.size() > index) {
|
||||
arr.val[index].setByType(val.rawValue(), val.type());
|
||||
arr.val[index].set(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,7 +740,7 @@ void SaveArray(const ScriptValue& key, DWORD id) {
|
||||
}
|
||||
}
|
||||
// make array "saved"
|
||||
itArray->second.key.setByType(key.rawValue(), key.type());
|
||||
itArray->second.key.set(key);
|
||||
savedArrays.emplace(itArray->second.key, id); // savedArrays[itArray->second.key] = id;
|
||||
} else { // key of int(0) is used to "unsave" array without destroying it
|
||||
savedArrays.erase(itArray->second.key);
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
setByType(el.intVal, el.type);
|
||||
}
|
||||
|
||||
void set(const ScriptValue& val);
|
||||
void set(long val);
|
||||
void set(float val);
|
||||
void set(const char* val, int _len = -1);
|
||||
|
||||
@@ -105,53 +105,35 @@ void op_get_sfall_global_float(OpcodeContext& ctx) {
|
||||
GetGlobalVar(ctx, DataType::FLOAT);
|
||||
}
|
||||
|
||||
void __declspec(naked) op_get_sfall_arg() {
|
||||
__asm {
|
||||
mov esi, ecx;
|
||||
call HookCommon::GetHSArg;
|
||||
mov edx, eax;
|
||||
mov eax, ebx;
|
||||
_RET_VAL_INT;
|
||||
mov ecx, esi;
|
||||
retn;
|
||||
}
|
||||
void op_get_sfall_arg(OpcodeContext& ctx) {
|
||||
ctx.setReturn(HookCommon::GetHSArg());
|
||||
}
|
||||
|
||||
void mf_get_sfall_arg_at(OpcodeContext& ctx) {
|
||||
long argVal = 0;
|
||||
long id = ctx.arg(0).rawValue();
|
||||
if (id >= static_cast<long>(HookCommon::GetHSArgCount()) || id < 0) {
|
||||
ctx.printOpcodeError("%s() - invalid value for argument.", ctx.getMetaruleName());
|
||||
} else {
|
||||
argVal = HookCommon::GetHSArgAt(id);
|
||||
ctx.setReturn(0);
|
||||
return;
|
||||
}
|
||||
ctx.setReturn(argVal);
|
||||
ctx.setReturn(HookCommon::GetHSArgAt(id));
|
||||
}
|
||||
|
||||
void op_get_sfall_args(OpcodeContext& ctx) {
|
||||
DWORD argCount = HookCommon::GetHSArgCount();
|
||||
DWORD id = CreateTempArray(argCount, 0);
|
||||
DWORD* args = HookCommon::GetHSArgs();
|
||||
for (DWORD i = 0; i < argCount; i++) {
|
||||
arrays[id].val[i].set(*(long*)&args[i]);
|
||||
arrays[id].val[i].set(HookCommon::GetHSArgAt(i));
|
||||
}
|
||||
ctx.setReturn(id);
|
||||
}
|
||||
|
||||
void op_set_sfall_arg(OpcodeContext& ctx) {
|
||||
HookCommon::SetHSArg(ctx.arg(0).rawValue(), ctx.arg(1).rawValue());
|
||||
HookCommon::SetHSArg(ctx.arg(0).rawValue(), ctx.arg(1));
|
||||
}
|
||||
|
||||
void __declspec(naked) op_set_sfall_return() {
|
||||
__asm {
|
||||
mov esi, ecx;
|
||||
_GET_ARG_INT(end);
|
||||
push eax;
|
||||
call HookCommon::SetHSReturn;
|
||||
end:
|
||||
mov ecx, esi;
|
||||
retn;
|
||||
}
|
||||
void op_set_sfall_return(OpcodeContext& ctx) {
|
||||
HookCommon::SetHSReturn(ctx.arg(0));
|
||||
}
|
||||
|
||||
void __declspec(naked) op_game_loaded() {
|
||||
|
||||
@@ -41,7 +41,7 @@ void op_get_sfall_global_int(OpcodeContext&);
|
||||
|
||||
void op_get_sfall_global_float(OpcodeContext&);
|
||||
|
||||
void __declspec() op_get_sfall_arg();
|
||||
void op_get_sfall_arg(OpcodeContext&);
|
||||
|
||||
void mf_get_sfall_arg_at(OpcodeContext&);
|
||||
|
||||
@@ -49,7 +49,7 @@ void op_get_sfall_args(OpcodeContext&);
|
||||
|
||||
void op_set_sfall_arg(OpcodeContext&);
|
||||
|
||||
void __declspec() op_set_sfall_return();
|
||||
void op_set_sfall_return(OpcodeContext&);
|
||||
|
||||
void __declspec() op_game_loaded();
|
||||
|
||||
|
||||
@@ -114,6 +114,8 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
|
||||
{0x1e1, "set_critical_table", op_set_critical_table, 5, false, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
|
||||
{0x1e2, "get_critical_table", op_get_critical_table, 4, true, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
|
||||
{0x1e3, "reset_critical_table", op_reset_critical_table, 4, false, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
|
||||
{0x1e4, "get_sfall_arg", op_get_sfall_arg, 0, true},
|
||||
{0x1e5, "set_sfall_return", op_set_sfall_return, 1, false, 0, {ARG_ANY}}, // hook script system will validate type
|
||||
{0x1eb, "get_ini_string", op_get_ini_string, 1, true, -1, {ARG_STRING}},
|
||||
{0x1ec, "sqrt", op_sqrt, 1, true, 0, {ARG_NUMBER}},
|
||||
{0x1ed, "abs", op_abs, 1, true, 0, {ARG_NUMBER}},
|
||||
@@ -176,7 +178,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
|
||||
{0x238, "atof", op_atof, 1, true, 0, {ARG_STRING}},
|
||||
{0x239, "scan_array", op_scan_array, 2, true, -1, {ARG_OBJECT, ARG_ANY}},
|
||||
{0x23c, "get_sfall_args", op_get_sfall_args, 0, true},
|
||||
{0x23d, "set_sfall_arg", op_set_sfall_arg, 2, false, 0, {ARG_INT, ARG_INT}},
|
||||
{0x23d, "set_sfall_arg", op_set_sfall_arg, 2, false, 0, {ARG_INT, ARG_ANY}}, // hookscript system will validate type
|
||||
{0x241, "get_npc_level", op_get_npc_level, 1, true, -1, {ARG_INTSTR}},
|
||||
{0x242, "set_critter_skill_points", op_set_critter_skill_points, 3, false, 0, {ARG_OBJECT, ARG_INT, ARG_INT}},
|
||||
{0x243, "get_critter_skill_points", op_get_critter_skill_points, 2, true, 0, {ARG_OBJECT, ARG_INT}},
|
||||
@@ -379,8 +381,6 @@ void Opcodes::InitNew() {
|
||||
|
||||
opcodes[0x1df] = op_get_bodypart_hit_modifier;
|
||||
opcodes[0x1e0] = op_set_bodypart_hit_modifier;
|
||||
opcodes[0x1e4] = op_get_sfall_arg;
|
||||
opcodes[0x1e5] = op_set_sfall_return;
|
||||
opcodes[0x1e6] = op_set_unspent_ap_bonus;
|
||||
opcodes[0x1e7] = op_get_unspent_ap_bonus;
|
||||
opcodes[0x1e8] = op_set_unspent_ap_perk_bonus;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace sfall
|
||||
namespace script
|
||||
{
|
||||
|
||||
ScriptValue::ScriptValue( DataType type, unsigned long value )
|
||||
ScriptValue::ScriptValue(DataType type, unsigned long value)
|
||||
{
|
||||
_val.dw = value;
|
||||
_type = type;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace sfall
|
||||
namespace script
|
||||
{
|
||||
|
||||
enum class DataType : unsigned long {
|
||||
enum class DataType : unsigned short {
|
||||
NONE = 0,
|
||||
INT = 1,
|
||||
FLOAT = 2,
|
||||
|
||||
Reference in New Issue
Block a user