Files
sfall/sfall/ScriptOps/ObjectsOps.hpp
T

816 lines
18 KiB
C++
Raw Normal View History

/*
* sfall
* Copyright (C) 2008, 2009, 2010, 2012 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "main.h"
#include "Inventory.h"
#include "Objects.h"
#include "PartyControl.h"
//script control functions
2016-11-04 17:22:05 +07:00
// TODO: rewrite
static void __declspec(naked) RemoveScript() {
__asm {
push ebx;
push ecx;
push edx;
mov ecx, eax;
call interpretPopShort_;
mov edx, eax;
mov eax, ecx;
call interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz end;
test eax, eax;
jz end;
mov edx, eax;
mov eax, [eax+0x78];
cmp eax, 0xffffffff;
jz end;
2015-07-16 00:37:05 +07:00
call scr_remove_
mov dword ptr [edx+0x78], 0xffffffff;
end:
pop edx;
pop ecx;
pop ebx;
retn;
}
}
// TODO: rewrite
static void __declspec(naked) SetScript() {
__asm {
pushad;
mov ecx, eax;
call interpretPopShort_;
mov edx, eax;
mov eax, ecx;
call interpretPopLong_;
mov ebx, eax;
mov eax, ecx;
call interpretPopShort_;
mov edi, eax;
mov eax, ecx;
call interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz end;
cmp di, VAR_TYPE_INT;
jnz end;
test eax, eax;
jz end;
mov esi, [eax+0x78];
cmp esi, 0xffffffff;
jz newscript
push eax;
mov eax, esi;
2015-07-16 00:37:05 +07:00
call scr_remove_
pop eax;
mov dword ptr [eax+0x78], 0xffffffff;
newscript:
mov esi, 1;
test ebx, 0x80000000;
jz execMapEnter;
xor esi, esi;
xor ebx, 0x80000000;
execMapEnter:
mov ecx, eax;
mov edx, 3; // script_type_item
mov edi, [eax+0x64];
shr edi, 24;
cmp edi, 1;
jnz notCritter;
inc edx; // 4 - "critter" type script
notCritter:
dec ebx;
2015-07-16 00:37:05 +07:00
call obj_new_sid_inst_
mov eax, [ecx+0x78];
mov edx, 1; // start
2015-07-16 00:37:05 +07:00
call exec_script_proc_
cmp esi, 1; // run map enter?
jnz end;
mov eax, [ecx+0x78];
mov edx, 0xf; // map_enter_p_proc
2015-07-16 00:37:05 +07:00
call exec_script_proc_
end:
popad;
retn;
}
}
static void _stdcall op_create_spatial2() {
2019-11-28 10:24:40 +08:00
const ScriptValue &scriptIdxArg = opHandler.arg(0),
&tileArg = opHandler.arg(1),
&elevArg = opHandler.arg(2),
&radiusArg = opHandler.arg(3);
if (scriptIdxArg.isInt() && tileArg.isInt() && elevArg.isInt() && radiusArg.isInt()) {
2019-11-28 14:42:07 +08:00
DWORD scriptIndex = scriptIdxArg.rawValue(),
tile = tileArg.rawValue(),
elevation = elevArg.rawValue(),
radius = radiusArg.rawValue(),
2019-11-28 10:24:40 +08:00
scriptId, tmp, objectPtr,
scriptPtr;
__asm {
lea eax, scriptId;
mov edx, 1;
call scr_new_;
mov tmp, eax;
}
2019-11-28 14:42:07 +08:00
if (tmp == -1) return;
2019-11-28 10:24:40 +08:00
__asm {
mov eax, scriptId;
lea edx, scriptPtr;
call scr_ptr_;
mov tmp, eax;
}
2019-11-28 14:42:07 +08:00
if (tmp == -1) return;
2019-11-28 10:24:40 +08:00
// fill spatial script properties:
*(DWORD*)(scriptPtr + 0x14) = scriptIndex - 1;
*(DWORD*)(scriptPtr + 0x8) = (elevation << 29) & 0xE0000000 | tile;
*(DWORD*)(scriptPtr + 0xC) = radius;
// this will load appropriate script program and link it to the script instance we just created:
__asm {
mov eax, scriptId;
mov edx, 1; // start_p_proc
call exec_script_proc_;
mov eax, scriptPtr;
mov eax, [eax + 0x18]; // program pointer
call scr_find_obj_from_program_;
mov objectPtr, eax;
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(objectPtr);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("create_spatial");
opHandler.setReturn(0);
}
}
static void __declspec(naked) op_create_spatial() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_create_spatial2, 4, 1)
}
2016-11-04 17:22:05 +07:00
static void sf_spatial_radius() {
TGameObj* spatialObj = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
if (spatialObj) {
TScript* script;
if (ScrPtr(spatialObj->scriptID, &script) != -1) {
opHandler.setReturn(script->spatial_radius);
}
} else {
OpcodeInvalidArgs("spatial_radius");
opHandler.setReturn(0);
}
}
static void __declspec(naked) GetScript() {
__asm {
pushad;
mov ecx, eax;
mov ecx, eax;
call interpretPopShort_;
mov edx, eax;
mov eax, ecx;
call interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz fail;
test eax, eax;
jz fail;
mov edx, [eax+0x80];
cmp edx, -1;
jz fail;
inc edx;
jmp end;
fail:
xor edx, edx;
dec edx;
end:
mov eax, ecx;
call interpretPushLong_;
mov eax, ecx;
mov edx, VAR_TYPE_INT;
call interpretPushShort_;
popad;
retn;
}
}
static void __declspec(naked) set_critter_burst_disable() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
mov ecx, eax;
mov eax, ebp;
call interpretPopShort_;
mov esi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz end;
cmp si, VAR_TYPE_INT;
jnz end;
push ecx;
push eax;
call SetNoBurstMode;
end:
popad;
retn;
}
}
static void __declspec(naked) get_weapon_ammo_pid() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz fail;
test eax, eax;
jz fail;
mov edx, [eax+0x40];
jmp end;
fail:
xor edx, edx;
dec edx;
end:
mov eax, ebp;
call interpretPushLong_;
mov eax, ebp;
mov edx, VAR_TYPE_INT;
call interpretPushShort_;
popad;
retn;
}
}
static void __declspec(naked) set_weapon_ammo_pid() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
mov ecx, eax;
mov eax, ebp;
call interpretPopShort_;
mov esi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz end;
cmp si, VAR_TYPE_INT;
jnz end;
test eax, eax;
jz end;
mov [eax+0x40], ecx;
end:
popad;
retn;
}
}
static void __declspec(naked) get_weapon_ammo_count() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz fail;
test eax, eax;
jz fail;
mov edx, [eax+0x3c];
jmp end;
fail:
xor edx, edx;
end:
mov eax, ebp;
call interpretPushLong_;
mov eax, ebp;
mov edx, VAR_TYPE_INT;
call interpretPushShort_;
popad;
retn;
}
}
static void __declspec(naked) set_weapon_ammo_count() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
mov ecx, eax;
mov eax, ebp;
call interpretPopShort_;
mov esi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz end;
cmp si, VAR_TYPE_INT;
jnz end;
test eax, eax;
jz end;
mov [eax+0x3c], ecx;
end:
popad;
retn;
}
}
#define BLOCKING_TYPE_BLOCK (0)
#define BLOCKING_TYPE_SHOOT (1)
#define BLOCKING_TYPE_AI (2)
#define BLOCKING_TYPE_SIGHT (3)
#define BLOCKING_TYPE_SCROLL (4)
static DWORD getBlockingFunc(DWORD type) {
switch (type) {
case BLOCKING_TYPE_BLOCK: default:
return obj_blocking_at_;
case BLOCKING_TYPE_SHOOT:
return obj_shoot_blocking_at_;
case BLOCKING_TYPE_AI:
return obj_ai_blocking_at_;
case BLOCKING_TYPE_SIGHT:
2015-07-16 00:37:05 +07:00
return obj_sight_blocking_at_;
//case 4:
// return obj_scroll_blocking_at_;
}
}
static void _stdcall op_make_straight_path2() {
TGameObj* objFrom = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
const ScriptValue &tileToArg = opHandler.arg(1),
&typeArg = opHandler.arg(2);
2019-11-28 10:24:40 +08:00
if (objFrom && tileToArg.isInt() && typeArg.isInt()) {
2019-11-28 14:42:07 +08:00
DWORD tileTo = tileToArg.rawValue(),
type = typeArg.rawValue();
2019-11-28 10:24:40 +08:00
long flag = (type == BLOCKING_TYPE_SHOOT) ? 32 : 0;
DWORD resultObj = 0;
make_straight_path_func_wrapper(objFrom, objFrom->tile, tileTo, 0, &resultObj, flag, (void*)getBlockingFunc(type));
2019-11-28 14:42:07 +08:00
opHandler.setReturn(resultObj);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("obj_blocking_line");
opHandler.setReturn(0);
}
}
static void __declspec(naked) op_make_straight_path() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_make_straight_path2, 3, 1)
}
static void _stdcall op_make_path2() {
TGameObj* objFrom = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
const ScriptValue &tileToArg = opHandler.arg(1),
&typeArg = opHandler.arg(2);
2019-11-28 10:24:40 +08:00
if (objFrom && tileToArg.isInt() && typeArg.isInt()) {
DWORD tileFrom = 0,
2019-11-28 14:42:07 +08:00
tileTo = tileToArg.rawValue(),
type = typeArg.rawValue(),
2019-11-28 10:24:40 +08:00
func = getBlockingFunc(type);
2019-11-28 10:24:40 +08:00
// if the object is not a critter, then there is no need to check tile (tileTo) for blocking
long pathLength, checkFlag = (objFrom->pid >> 24 == OBJ_TYPE_CRITTER);
tileFrom = objFrom->tile;
char pathData[800];
char* pathDataPtr = pathData;
__asm {
mov eax, objFrom;
mov edx, tileFrom;
mov ecx, pathDataPtr;
mov ebx, tileTo;
push func;
push checkFlag;
call make_path_func_;
mov pathLength, eax;
}
DWORD arrayId = TempArray(pathLength, 0);
for (int i = 0; i < pathLength; i++) {
arrays[arrayId].val[i].set((long)pathData[i]);
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(arrayId);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("path_find_to");
opHandler.setReturn(-1);
}
}
static void __declspec(naked) op_make_path() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_make_path2, 3, 1)
}
static void _stdcall op_obj_blocking_at2() {
2019-11-28 10:24:40 +08:00
const ScriptValue &tileArg = opHandler.arg(0),
&elevArg = opHandler.arg(1),
&typeArg = opHandler.arg(2);
2019-11-28 10:24:40 +08:00
if (tileArg.isInt() && elevArg.isInt() && typeArg.isInt()) {
2019-11-28 14:42:07 +08:00
DWORD tile = tileArg.rawValue(),
elevation = elevArg.rawValue(),
type = typeArg.rawValue();
2019-11-28 10:24:40 +08:00
TGameObj* resultObj = obj_blocking_at_wrapper(0, tile, elevation, (void*)getBlockingFunc(type));
if (resultObj && type == BLOCKING_TYPE_SHOOT && (resultObj->flags & 0x80000000)) { // don't know what this flag means, copy-pasted from the engine code
// this check was added because the engine always does exactly this when using shoot blocking checks
resultObj = nullptr;
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(resultObj);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("obj_blocking_tile");
opHandler.setReturn(0);
}
}
static void __declspec(naked) op_obj_blocking_at() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_obj_blocking_at2, 3, 1)
}
static void _stdcall op_tile_get_objects2() {
2019-11-28 10:24:40 +08:00
const ScriptValue &tileArg = opHandler.arg(0),
&elevArg = opHandler.arg(1);
if (tileArg.isInt() && elevArg.isInt()) {
2019-11-28 14:42:07 +08:00
DWORD tile = tileArg.rawValue(),
elevation = elevArg.rawValue();
2019-11-28 10:24:40 +08:00
DWORD arrayId = TempArray(0, 4);
TGameObj* obj = ObjFindFirstAtTile(elevation, tile);
while (obj) {
arrays[arrayId].push_back(reinterpret_cast<long>(obj));
obj = ObjFindNextAtTile();
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(arrayId);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("tile_get_objs");
opHandler.setReturn(-1);
}
}
static void __declspec(naked) op_tile_get_objects() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_tile_get_objects2, 2, 1)
}
static void _stdcall op_get_party_members2() {
2019-11-28 10:24:40 +08:00
const ScriptValue &modeArg = opHandler.arg(0);
if (modeArg.isInt()) {
2019-11-28 14:42:07 +08:00
DWORD mode = modeArg.rawValue(), isDead;
2019-11-28 10:24:40 +08:00
int actualCount = *ptr_partyMemberCount;
DWORD arrayId = TempArray(0, 4);
DWORD* partyMemberList = *ptr_partyMemberList;
for (int i = 0; i < actualCount; i++) {
TGameObj* obj = reinterpret_cast<TGameObj*>(partyMemberList[i * 4]);
if (mode == 0) { // mode 0 will act just like op_party_member_count in fallout2
if (obj->pid >> 24 != OBJ_TYPE_CRITTER) // obj type != critter
continue;
__asm {
mov eax, obj;
call critter_is_dead_;
mov isDead, eax;
}
if (isDead)
continue;
if (obj->flags & 1) // Mouse_3d flag
continue;
}
2019-11-28 10:24:40 +08:00
arrays[arrayId].push_back((long)obj);
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(arrayId);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("party_member_list");
opHandler.setReturn(-1);
}
}
static void __declspec(naked) op_get_party_members() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_get_party_members2, 1, 1)
}
static void __declspec(naked) op_art_exists() {
_OP_BEGIN(ebp)
_GET_ARG_R32(ebp, ecx, eax)
_CHECK_ARG_INT(cx, fail)
__asm {
call art_exists_;
jmp end;
fail:
xor eax, eax;
end:
}
_RET_VAL_INT(ebp)
_OP_END
}
static void _stdcall op_obj_is_carrying_obj2() {
int num = 0;
const ScriptValue &invenObjArg = opHandler.arg(0),
&itemObjArg = opHandler.arg(1);
2019-11-28 10:24:40 +08:00
TGameObj *invenObj = invenObjArg.asObject(),
*itemObj = itemObjArg.asObject();
if (invenObj != nullptr && itemObj != nullptr) {
for (int i = 0; i < invenObj->invenCount; i++) {
if (invenObj->invenTablePtr[i].object == itemObj) {
num = invenObj->invenTablePtr[i].count;
break;
}
}
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("obj_is_carrying_obj");
}
opHandler.setReturn(num);
}
static void __declspec(naked) op_obj_is_carrying_obj() {
2016-11-03 20:55:59 +07:00
_WRAP_OPCODE(op_obj_is_carrying_obj2, 2, 1)
}
2016-11-04 17:22:05 +07:00
static void sf_critter_inven_obj2() {
TGameObj* critter = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
const ScriptValue &slotArg = opHandler.arg(1);
if (critter && slotArg.isInt()) {
2019-11-28 14:42:07 +08:00
int slot = slotArg.rawValue();
2019-11-28 10:24:40 +08:00
switch (slot) {
case 0:
opHandler.setReturn(InvenWorn(critter));
break;
case 1:
opHandler.setReturn(InvenRightHand(critter));
break;
case 2:
opHandler.setReturn(InvenLeftHand(critter));
break;
case -2:
opHandler.setReturn(critter->invenCount);
break;
default:
opHandler.printOpcodeError("critter_inven_obj2() - invalid type.");
}
} else {
OpcodeInvalidArgs("critter_inven_obj2");
opHandler.setReturn(0);
2016-11-04 17:22:05 +07:00
}
}
static void sf_set_outline() {
2019-11-28 14:42:07 +08:00
TGameObj* obj = opHandler.arg(0).object();
int color = opHandler.arg(1).rawValue();
obj->outline = color;
}
static void sf_get_outline() {
TGameObj* obj = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
if (obj) {
2019-11-28 14:42:07 +08:00
opHandler.setReturn(obj->outline);
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("get_outline");
opHandler.setReturn(0);
}
}
static void sf_set_flags() {
2019-11-28 14:42:07 +08:00
TGameObj* obj = opHandler.arg(0).object();
int flags = opHandler.arg(1).rawValue();
obj->flags = flags;
}
static void sf_get_flags() {
TGameObj* obj = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
if (obj) {
opHandler.setReturn(obj->flags);
} else {
OpcodeInvalidArgs("get_flags");
opHandler.setReturn(0);
}
}
static void sf_outlined_object() {
2019-11-28 14:42:07 +08:00
opHandler.setReturn(*ptr_outlined_object);
}
static void sf_item_weight() {
TGameObj* item = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
int weight = 0;
if (item) {
weight = ItemWeight(item);
} else {
OpcodeInvalidArgs("item_weight");
}
opHandler.setReturn(weight);
}
static void sf_real_dude_obj() {
opHandler.setReturn(RealDudeObject());
}
2018-11-04 09:14:02 +08:00
static void sf_lock_is_jammed() {
TGameObj* obj = opHandler.arg(0).asObject();
2019-11-28 10:24:40 +08:00
int result = 0;
if (obj) {
__asm {
mov eax, obj;
call obj_lock_is_jammed_;
mov result, eax;
}
} else {
OpcodeInvalidArgs("lock_is_jammed");
2018-11-04 09:14:02 +08:00
}
opHandler.setReturn(result);
}
static void sf_unjam_lock() {
2019-11-28 14:42:07 +08:00
TGameObj* obj = opHandler.arg(0).object();
2018-11-04 09:14:02 +08:00
__asm {
mov eax, obj;
call obj_unjam_lock_;
}
}
static void sf_set_unjam_locks_time() {
2019-11-28 14:42:07 +08:00
int time = opHandler.arg(0).rawValue();
if (time < 0 || time > 127) {
opHandler.printOpcodeError("set_unjam_locks_time() - time argument must be in the range of 0 to 127.");
2019-11-28 14:42:07 +08:00
opHandler.setReturn(-1);
} else {
SetAutoUnjamLockTime(time);
}
}
static void sf_get_current_inven_size() {
2019-11-28 10:24:40 +08:00
TGameObj* obj = opHandler.arg(0).asObject();
if (obj) {
2019-11-28 14:42:07 +08:00
opHandler.setReturn(sf_item_total_size(obj));
2019-11-28 10:24:40 +08:00
} else {
OpcodeInvalidArgs("get_current_inven_size");
opHandler.setReturn(0);
}
}
2019-05-08 21:04:18 +08:00
static void sf_get_dialog_object() {
2019-11-28 14:42:07 +08:00
opHandler.setReturn(InDialog() ? *ptr_dialog_target : 0);
2019-05-08 21:04:18 +08:00
}
static void sf_get_obj_under_cursor() {
2019-11-28 10:24:40 +08:00
const ScriptValue &crSwitchArg = opHandler.arg(0),
&inclDudeArg = opHandler.arg(1);
2019-11-28 10:24:40 +08:00
long obj = 0;
if (crSwitchArg.isInt() && inclDudeArg.isInt()) {
int crSwitch = crSwitchArg.asBool() ? 1 : -1,
inclDude = inclDudeArg.rawValue();
__asm {
mov ebx, dword ptr ds:[_map_elevation];
mov edx, inclDude;
mov eax, crSwitch;
call object_under_mouse_;
mov obj, eax;
}
} else {
OpcodeInvalidArgs("obj_under_cursor");
}
opHandler.setReturn(obj);
}
2019-05-08 21:04:18 +08:00
static void sf_get_loot_object() {
2019-11-28 14:42:07 +08:00
opHandler.setReturn((GetLoopFlags() & INTFACELOOT) ? LoadGameHook_LootTarget : 0);
2019-05-08 21:04:18 +08:00
}
2019-10-20 12:02:14 +08:00
static const char* failedLoad = "%s() - failed to load a prototype ID: %d";
static bool protoMaxLimitPatch = false;
static void _stdcall get_proto_data2() {
const ScriptValue &pidArg = opHandler.arg(0),
&offsetArg = opHandler.arg(1);
2019-11-28 10:24:40 +08:00
if (pidArg.isInt() && offsetArg.isInt()) {
char* protoPtr;
int pid = pidArg.rawValue();
int result;
__asm {
lea edx, protoPtr;
mov eax, pid;
call proto_ptr_;
mov result, eax;
}
if (result != -1) {
result = *(long*)((BYTE*)protoPtr + offsetArg.rawValue());
} else {
opHandler.printOpcodeError(failedLoad, "get_proto_data", pid);
}
opHandler.setReturn(result);
} else {
OpcodeInvalidArgs("get_proto_data");
opHandler.setReturn(-1);
}
}
static void __declspec(naked) get_proto_data() {
_WRAP_OPCODE(get_proto_data2, 2, 1)
}
static void _stdcall set_proto_data2() {
const ScriptValue &pidArg = opHandler.arg(0),
&offsetArg = opHandler.arg(1),
&valueArg = opHandler.arg(2);
2019-11-28 10:24:40 +08:00
if (pidArg.isInt() && offsetArg.isInt() && valueArg.isInt()) {
char* protoPtr;
int pid = pidArg.rawValue();
int result;
__asm {
lea edx, protoPtr;
mov eax, pid;
call proto_ptr_;
mov result, eax;
}
if (result != -1) {
*(long*)((BYTE*)protoPtr + offsetArg.rawValue()) = valueArg.rawValue();
if (!protoMaxLimitPatch) {
LoadProtoAutoMaxLimit();
protoMaxLimitPatch = true;
}
} else {
opHandler.printOpcodeError(failedLoad, "set_proto_data", pid);
}
} else {
OpcodeInvalidArgs("set_proto_data");
}
}
static void __declspec(naked) set_proto_data() {
_WRAP_OPCODE(set_proto_data2, 3, 0)
}
static void sf_get_object_data() {
2019-09-30 07:51:43 +08:00
DWORD result = 0;
2019-11-28 10:24:40 +08:00
TGameObj* obj = opHandler.arg(0).asObject();
const ScriptValue &offsetArg = opHandler.arg(1);
if (obj && offsetArg.isInt()) {
DWORD* object_ptr = (DWORD*)obj;
if (*(object_ptr - 1) != 0xFEEDFACE) {
opHandler.printOpcodeError("get_object_data() - invalid object pointer.");
} else {
result = *(long*)((BYTE*)object_ptr + offsetArg.rawValue());
}
2019-09-30 07:51:43 +08:00
} else {
2019-11-28 10:24:40 +08:00
OpcodeInvalidArgs("get_object_data");
2019-09-30 07:51:43 +08:00
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(result);
}
static void sf_set_object_data() {
2019-09-30 07:51:43 +08:00
DWORD* object_ptr = (DWORD*)opHandler.arg(0).rawValue();
if (*(object_ptr - 1) != 0xFEEDFACE) {
opHandler.printOpcodeError("set_object_data() - invalid object pointer.");
2019-11-28 14:42:07 +08:00
opHandler.setReturn(-1);
2019-09-30 07:51:43 +08:00
} else {
*(long*)((BYTE*)object_ptr + opHandler.arg(1).rawValue()) = opHandler.arg(2).rawValue();
}
}
2019-04-12 21:27:14 +08:00
static void sf_set_unique_id() {
2019-11-28 14:42:07 +08:00
TGameObj* obj = opHandler.arg(0).object();
2019-04-16 20:53:41 +08:00
long id;
2019-11-28 14:42:07 +08:00
if (opHandler.numArgs() > 1 && opHandler.arg(1).rawValue() == -1) {
2019-04-16 20:53:41 +08:00
id = NewObjId();
obj->ID = id;
} else {
id = SetObjectUniqueID(obj);
}
2019-11-28 14:42:07 +08:00
opHandler.setReturn(id);
2019-04-12 21:27:14 +08:00
}