diff --git a/src/proto.cc b/src/proto.cc index 86d767b..efb05b0 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -249,6 +249,12 @@ int _proto_list_str(int pid, char* proto_path) return 0; } +// 0x49E984 +size_t proto_size(int type) +{ + return type >= 0 && type < OBJ_TYPE_COUNT ? _proto_sizes[type] : 0; +} + // 0x49E99C bool _proto_action_can_use(int pid) { @@ -1704,12 +1710,10 @@ static int _proto_load_pid(int pid, Proto** protoPtr) return 0; } -// allocate memory for proto of given type and adds it to proto cache +// 0x4A1D98 static int _proto_find_free_subnode(int type, Proto** protoPtr) { - size_t size = (type >= 0 && type < 11) ? _proto_sizes[type] : 0; - - Proto* proto = (Proto*)internal_malloc(size); + Proto* proto = (Proto*)internal_malloc(proto_size(type)); *protoPtr = proto; if (proto == NULL) { return -1; diff --git a/src/proto.h b/src/proto.h index c7f481d..d6f13e6 100644 --- a/src/proto.h +++ b/src/proto.h @@ -104,6 +104,7 @@ extern char* _proto_none_str; void _proto_make_path(char* path, int pid); int _proto_list_str(int pid, char* proto_path); +size_t proto_size(int type); bool _proto_action_can_use(int pid); bool _proto_action_can_use_on(int pid); bool _proto_action_can_talk_to(int pid); diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 8d5c57d..82807c7 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -10,6 +10,7 @@ #include "message.h" #include "mouse.h" #include "object.h" +#include "proto.h" #include "sfall_global_vars.h" #include "sfall_lists.h" #include "stat.h" @@ -143,6 +144,56 @@ static void op_set_car_current_town(Program* program) wmCarSetCurrentArea(area); } +// get_proto_data +static void op_get_proto_data(Program* program) +{ + size_t offset = static_cast(programStackPopInteger(program)); + int pid = programStackPopInteger(program); + + Proto* proto; + if (protoGetProto(pid, &proto) != 0) { + debugPrint("op_get_proto_data: bad proto %d", pid); + programStackPushInteger(program, -1); + return; + } + + // CE: Make sure the requested offset is within memory bounds and is + // properly aligned. + if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) { + debugPrint("op_get_proto_data: bad offset %d", offset); + programStackPushInteger(program, -1); + return; + } + + int value = *reinterpret_cast(reinterpret_cast(proto) + offset); + programStackPushInteger(program, value); +} + +// set_proto_data +static void op_set_proto_data(Program* program) +{ + int value = programStackPopInteger(program); + size_t offset = static_cast(programStackPopInteger(program)); + int pid = programStackPopInteger(program); + + Proto* proto; + if (protoGetProto(pid, &proto) != 0) { + debugPrint("op_set_proto_data: bad proto %d", pid); + programStackPushInteger(program, -1); + return; + } + + // CE: Make sure the requested offset is within memory bounds and is + // properly aligned. + if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) { + debugPrint("op_set_proto_data: bad offset %d", offset); + programStackPushInteger(program, -1); + return; + } + + *reinterpret_cast(reinterpret_cast(proto) + offset) = value; +} + // list_begin static void opListBegin(Program* program) { @@ -362,6 +413,8 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x819E, opGetGlobalInt); interpreterRegisterOpcode(0x81AF, opGetGameMode); interpreterRegisterOpcode(0x81B6, op_set_car_current_town); + interpreterRegisterOpcode(0x8204, op_get_proto_data); + interpreterRegisterOpcode(0x8205, op_set_proto_data); interpreterRegisterOpcode(0x820D, opListBegin); interpreterRegisterOpcode(0x820E, opListNext); interpreterRegisterOpcode(0x820F, opListEnd);