mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added validation for null arguments #55;
Added scripting function "spatial_radius"; Added scripting function "critter_inven_obj2" #38.
This commit is contained in:
@@ -725,6 +725,14 @@ void SkillSetTags(int* tags, DWORD num) {
|
||||
}
|
||||
}
|
||||
|
||||
int __stdcall ScrPtr(int scriptId, TScript** scriptPtr) {
|
||||
__asm {
|
||||
mov eax, scriptId;
|
||||
mov edx, scriptPtr;
|
||||
call scr_ptr_;
|
||||
}
|
||||
}
|
||||
|
||||
// redraws the main game interface windows (useful after changing some data like active hand, etc.)
|
||||
void InterfaceRedraw() {
|
||||
__asm {
|
||||
@@ -800,4 +808,19 @@ const char* __stdcall FindCurrentProc(TProgram* program) {
|
||||
mov eax, program
|
||||
call findCurrentProc_
|
||||
}
|
||||
}
|
||||
|
||||
TGameObj* __stdcall InvenWorn(TGameObj* critter) {
|
||||
__asm mov eax, critter
|
||||
__asm call inven_worn_
|
||||
}
|
||||
|
||||
TGameObj* __stdcall InvenLeftHand(TGameObj* critter) {
|
||||
__asm mov eax, critter
|
||||
__asm call inven_left_hand_
|
||||
}
|
||||
|
||||
TGameObj* __stdcall InvenRightHand(TGameObj* critter) {
|
||||
__asm mov eax, critter
|
||||
__asm call inven_right_hand_
|
||||
}
|
||||
+14
-1
@@ -854,6 +854,10 @@ void CritterPcSetName(const char* newName);
|
||||
// Returns the name of the critter
|
||||
const char* __stdcall CritterName(TGameObj* critter);
|
||||
|
||||
// Saves pointer to script object into scriptPtr using scriptID.
|
||||
// Returns 0 on success, -1 on failure.
|
||||
int __stdcall ScrPtr(int scriptId, TScript** scriptPtr);
|
||||
|
||||
void SkillGetTags(int* result, DWORD num);
|
||||
void SkillSetTags(int* tags, DWORD num);
|
||||
|
||||
@@ -884,4 +888,13 @@ void __declspec() InterpretError(const char* fmt, ...);
|
||||
void __declspec() DebugPrintf(const char* fmt, ...);
|
||||
|
||||
// returns the name of current procedure by program pointer
|
||||
const char* __stdcall FindCurrentProc(TProgram* program);
|
||||
const char* __stdcall FindCurrentProc(TProgram* program);
|
||||
|
||||
// critter worn item (armor)
|
||||
TGameObj* __stdcall InvenWorn(TGameObj* critter);
|
||||
|
||||
// item in critter's left hand slot
|
||||
TGameObj* __stdcall InvenLeftHand(TGameObj* critter);
|
||||
|
||||
// item in critter's right hand slot
|
||||
TGameObj* __stdcall InvenRightHand(TGameObj* critter);
|
||||
@@ -34,7 +34,7 @@ struct TInvenRec
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
/* 8 */
|
||||
/* 15 */
|
||||
#pragma pack(push, 1)
|
||||
struct TGameObj
|
||||
{
|
||||
@@ -52,7 +52,7 @@ struct TGameObj
|
||||
TInvenRec *invenTablePtr;
|
||||
char gap_38[4];
|
||||
int itemCharges;
|
||||
int movePoints;
|
||||
int critterAP_weaponAmmoPid;
|
||||
char gap_44[16];
|
||||
int lastTarget;
|
||||
char gap_58[12];
|
||||
|
||||
@@ -47,6 +47,7 @@ typedef struct {
|
||||
int i;
|
||||
float f;
|
||||
const char* str;
|
||||
TGameObj* gObj;
|
||||
} val;
|
||||
DWORD type; // TODO: replace with enum class
|
||||
} ScriptValue;
|
||||
@@ -76,6 +77,12 @@ static void _stdcall SetOpReturn(const char* value) {
|
||||
opRet.type = DATATYPE_STR;
|
||||
}
|
||||
|
||||
static void _stdcall SetOpReturn(TGameObj* value) {
|
||||
opRet.val.gObj = value;
|
||||
opRet.type = DATATYPE_INT;
|
||||
}
|
||||
|
||||
|
||||
// TODO: replace these functions with proper ScriptValue class (encapsulation...)
|
||||
static bool _stdcall IsOpArgInt(int num) {
|
||||
return (opArgs[num].type == DATATYPE_INT);
|
||||
@@ -121,6 +128,12 @@ static const char* _stdcall GetOpArgStr(int num) {
|
||||
: "";
|
||||
}
|
||||
|
||||
static TGameObj* _stdcall GetOpArgObj(int num) {
|
||||
return (opArgs[num].type == DATATYPE_INT)
|
||||
? opArgs[num].val.gObj
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
// writes error message to debug.log along with the name of script & procedure
|
||||
static void _stdcall PrintOpcodeError(const char* fmt, ...) {
|
||||
assert(opProgram != nullptr);
|
||||
|
||||
@@ -48,6 +48,8 @@ struct SfallMetarule {
|
||||
#define DATATYPE_MASK_INT (1 << DATATYPE_INT)
|
||||
#define DATATYPE_MASK_FLOAT (1 << DATATYPE_FLOAT)
|
||||
#define DATATYPE_MASK_STR (1 << DATATYPE_STR)
|
||||
#define DATATYPE_MASK_NOT_NULL (0x00010000)
|
||||
#define DATATYPE_MASK_VALID_OBJ (DATATYPE_MASK_INT | DATATYPE_MASK_NOT_NULL)
|
||||
|
||||
typedef std::tr1::unordered_map<std::string, const SfallMetarule*> MetaruleTableType;
|
||||
|
||||
@@ -93,10 +95,24 @@ static void sf_get_metarule_table() {
|
||||
SetOpReturn(arr, DATATYPE_INT);
|
||||
}
|
||||
|
||||
/*
|
||||
Metarule array.
|
||||
|
||||
Add your custom scripting functions here.
|
||||
|
||||
Format is as follows:
|
||||
{ name, handler, minArgs, maxArgs, {MASK1, MASK2, ...} }
|
||||
- name - name of function that will be used to call it from scripts,
|
||||
- handler - pointer to handler function (see examples above),
|
||||
- minArgs/maxArgs - minimum and maximum number of arguments allowed for this function,
|
||||
- MASK1, MASK2, ... - validation parameters for each argument as bit masks (see DATATYPE_MASK_* defines)
|
||||
*/
|
||||
static const SfallMetarule metaruleArray[] = {
|
||||
{"test", sf_test, 0, 6, {}},
|
||||
{"get_metarule_table", sf_get_metarule_table, 0, 0, {}},
|
||||
{"validate_test", sf_test, 2, 5, {DATATYPE_MASK_INT, DATATYPE_MASK_INT | DATATYPE_MASK_FLOAT, DATATYPE_MASK_STR, DATATYPE_NONE}}
|
||||
{"validate_test", sf_test, 2, 5, {DATATYPE_MASK_INT, DATATYPE_MASK_INT | DATATYPE_MASK_FLOAT, DATATYPE_MASK_STR, DATATYPE_NONE}},
|
||||
{"spatial_radius", sf_spatial_radius, 1, 1, {DATATYPE_MASK_VALID_OBJ}},
|
||||
{"critter_inven_obj2", sf_critter_inven_obj2, 2, 2, {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
|
||||
};
|
||||
|
||||
static void InitMetaruleTable() {
|
||||
@@ -121,12 +137,22 @@ static bool ValidateOpcodeArguments(const SfallMetarule* metaruleInfo) {
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
if (metaruleInfo->argTypeMasks[i] != 0 && ((1 << opArgs[i + 1].type) & metaruleInfo->argTypeMasks[i]) == 0) {
|
||||
int typeMask = metaruleInfo->argTypeMasks[i];
|
||||
ScriptValue arg = opArgs[i + 1];
|
||||
if (typeMask != 0 && ((1 << arg.type) & typeMask) == 0) {
|
||||
PrintOpcodeError(
|
||||
"sfall_funcX(\"%s\", ...) - argument #%d has invalid type: %s.",
|
||||
metaruleInfo->name,
|
||||
i + 1,
|
||||
GetSfallTypeName(opArgs[i + 1].type));
|
||||
GetSfallTypeName(arg.type));
|
||||
|
||||
return false;
|
||||
} else if ((typeMask & DATATYPE_MASK_NOT_NULL) && arg.val.dw == 0) {
|
||||
PrintOpcodeError(
|
||||
"sfall_funcX(\"%s\", ...) - argument #%d is null.",
|
||||
metaruleInfo->name,
|
||||
i + 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
//script control functions
|
||||
|
||||
// TODO: rewrite
|
||||
static void __declspec(naked) RemoveScript() {
|
||||
__asm {
|
||||
push ebx;
|
||||
@@ -52,6 +53,7 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rewrite
|
||||
static void __declspec(naked) SetScript() {
|
||||
__asm {
|
||||
pushad;
|
||||
@@ -111,6 +113,7 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rewrite, remove all ASM
|
||||
static void _stdcall op_create_spatial2() {
|
||||
DWORD scriptIndex = GetOpArgInt(0),
|
||||
tile = GetOpArgInt(1),
|
||||
@@ -154,18 +157,13 @@ static void _stdcall op_create_spatial2() {
|
||||
static void __declspec(naked) op_create_spatial() {
|
||||
_WRAP_OPCODE(op_create_spatial2, 4, 1)
|
||||
}
|
||||
static void __declspec(naked) op_spatial_radius() {
|
||||
_OP_BEGIN(ebp)
|
||||
_GET_ARG_R32(ebp, ecx, eax)
|
||||
_CHECK_ARG_INT(cx, fail)
|
||||
__asm {
|
||||
test eax, eax;
|
||||
js fail;
|
||||
mov eax, [eax+0xC];
|
||||
fail:
|
||||
|
||||
static void sf_spatial_radius() {
|
||||
TGameObj* spatialObj = GetOpArgObj(1);
|
||||
TScript* script;
|
||||
if (ScrPtr(spatialObj->scriptID, &script) != -1) {
|
||||
SetOpReturn(script->spatial_radius);
|
||||
}
|
||||
_RET_VAL_INT(ebp)
|
||||
_OP_END
|
||||
}
|
||||
|
||||
static void __declspec(naked) GetScript() {
|
||||
@@ -533,3 +531,24 @@ static void _stdcall op_obj_is_carrying_obj2() {
|
||||
static void __declspec(naked) op_obj_is_carrying_obj() {
|
||||
_WRAP_OPCODE(op_obj_is_carrying_obj2, 2, 1)
|
||||
}
|
||||
|
||||
static void sf_critter_inven_obj2() {
|
||||
TGameObj* critter = GetOpArgObj(1);
|
||||
int slot = GetOpArgInt(2);
|
||||
switch (slot) {
|
||||
case 0:
|
||||
SetOpReturn(InvenWorn(critter));
|
||||
break;
|
||||
case 1:
|
||||
SetOpReturn(InvenRightHand(critter));
|
||||
break;
|
||||
case 2:
|
||||
SetOpReturn(InvenLeftHand(critter));
|
||||
break;
|
||||
case -2:
|
||||
SetOpReturn(critter->invenCount);
|
||||
break;
|
||||
default:
|
||||
PrintOpcodeError("critter_inven_obj2() - invalid type.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user