From c521dcaf5747e41ec67b4002e8f16a91760e391c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Thu, 22 Sep 2022 12:45:58 +0300 Subject: [PATCH] Fix storing pointers in map local variables Closes #152 --- src/interpreter_extra.cc | 10 ++++++---- src/map.cc | 38 +++++++++++++++++++++++++++++++++----- src/map.h | 5 +++-- src/reaction.cc | 11 +++++++---- src/scripts.cc | 16 +++++++++++----- src/scripts.h | 4 ++-- 6 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index c23bcd7..1fce8bc 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -1213,19 +1213,21 @@ static void opGetLocalVar(Program* program) { int data = programStackPopInteger(program); - int value = -1; + ProgramValue value; + value.opcode = VALUE_TYPE_INT; + value.integerValue = -1; int sid = scriptGetSid(program); - scriptGetLocalVar(sid, data, &value); + scriptGetLocalVar(sid, data, value); - programStackPushInteger(program, value); + programStackPushValue(program, value); } // set_local_var // 0x4557C8 static void opSetLocalVar(Program* program) { - int value = programStackPopInteger(program); + ProgramValue value = programStackPopValue(program); int variable = programStackPopInteger(program); int sid = scriptGetSid(program); diff --git a/src/map.cc b/src/map.cc index 7b1d240..1d3cff8 100644 --- a/src/map.cc +++ b/src/map.cc @@ -3,6 +3,8 @@ #include #include +#include + #include "animation.h" #include "art.h" #include "automap.h" @@ -159,6 +161,12 @@ static char _scratchStr[40]; // 0x631E78 static char _map_path[COMPAT_MAX_PATH]; +// CE: There is a bug in the user-space scripting where they want to store +// pointers to |Object| instances in local vars. This is obviously wrong as it's +// meaningless to save these pointers in file. As a workaround use second array +// to store these pointers. +static std::vector gMapLocalPointers; + // iso_init // 0x481CA0 int isoInit() @@ -405,27 +413,41 @@ int mapGetGlobalVar(int var) } // 0x482280 -int mapSetLocalVar(int var, int value) +int mapSetLocalVar(int var, ProgramValue& value) { if (var < 0 || var >= gMapLocalVarsLength) { debugPrint("ERROR: attempt to reference local var out of range: %d", var); return -1; } - gMapLocalVars[var] = value; + if (value.opcode == VALUE_TYPE_PTR) { + gMapLocalVars[var] = 0; + gMapLocalPointers[var] = value.pointerValue; + } else { + gMapLocalVars[var] = value.integerValue; + gMapLocalPointers[var] = nullptr; + } return 0; } // 0x4822B0 -int mapGetLocalVar(int var) +int mapGetLocalVar(int var, ProgramValue& value) { if (var < 0 || var >= gMapLocalVarsLength) { debugPrint("ERROR: attempt to reference local var out of range: %d", var); - return 0; + return -1; } - return gMapLocalVars[var]; + if (gMapLocalPointers[var] != nullptr) { + value.opcode = VALUE_TYPE_PTR; + value.pointerValue = gMapLocalPointers[var]; + } else { + value.opcode = VALUE_TYPE_INT; + value.integerValue = gMapLocalVars[var]; + } + + return 0; } // Make a room to store more local variables. @@ -444,6 +466,8 @@ int _map_malloc_local_var(int a1) gMapLocalVars = vars; memset((unsigned char*)vars + sizeof(*vars) * oldMapLocalVarsLength, 0, sizeof(*vars) * a1); + gMapLocalPointers.resize(gMapLocalVarsLength); + return oldMapLocalVarsLength; } @@ -1546,6 +1570,8 @@ static int mapLocalVariablesInit(int count) if (gMapLocalVars == NULL) { return -1; } + + gMapLocalPointers.resize(count); } gMapLocalVarsLength = count; @@ -1561,6 +1587,8 @@ static void mapLocalVariablesFree() gMapLocalVars = NULL; gMapLocalVarsLength = 0; } + + gMapLocalPointers.clear(); } // NOTE: Inlined. diff --git a/src/map.h b/src/map.h index 987b3fd..81f5364 100644 --- a/src/map.h +++ b/src/map.h @@ -4,6 +4,7 @@ #include "combat_defs.h" #include "db.h" #include "geometry.h" +#include "interpreter.h" #include "map_defs.h" #include "message.h" #include "platform_compat.h" @@ -85,8 +86,8 @@ bool isoIsDisabled(); int mapSetElevation(int elevation); int mapSetGlobalVar(int var, int value); int mapGetGlobalVar(int var); -int mapSetLocalVar(int var, int value); -int mapGetLocalVar(int var); +int mapSetLocalVar(int var, ProgramValue& value); +int mapGetLocalVar(int var, ProgramValue& value); int _map_malloc_local_var(int a1); void mapSetStart(int a1, int a2, int a3); char* mapGetName(int map_num, int elev); diff --git a/src/reaction.cc b/src/reaction.cc index 169fc46..6a9c5fd 100644 --- a/src/reaction.cc +++ b/src/reaction.cc @@ -5,7 +5,10 @@ // 0x4A29D0 int reactionSetValue(Object* critter, int value) { - scriptSetLocalVar(critter->sid, 0, value); + ProgramValue programValue; + programValue.opcode = VALUE_TYPE_INT; + programValue.integerValue = value; + scriptSetLocalVar(critter->sid, 0, programValue); return 0; } @@ -36,11 +39,11 @@ int _reaction_influence_() // 0x4A2B28 int reactionGetValue(Object* critter) { - int reactionValue; + ProgramValue programValue; - if (scriptGetLocalVar(critter->sid, 0, &reactionValue) == -1) { + if (scriptGetLocalVar(critter->sid, 0, programValue) == -1) { return -1; } - return reactionValue; + return programValue.integerValue; } diff --git a/src/scripts.cc b/src/scripts.cc index b365e8a..88f21ed 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -2732,7 +2732,7 @@ char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3) } // 0x4A6D64 -int scriptGetLocalVar(int sid, int variable, int* value) +int scriptGetLocalVar(int sid, int variable, ProgramValue& value) { if (SID_TYPE(sid) == SCRIPT_TYPE_SYSTEM) { debugPrint("\nError! System scripts/Map scripts not allowed local_vars! "); @@ -2742,13 +2742,15 @@ int scriptGetLocalVar(int sid, int variable, int* value) debugPrint(":%s\n", _tempStr1); - *value = -1; + value.opcode = VALUE_TYPE_INT; + value.integerValue = -1; return -1; } Script* script; if (scriptGetScript(sid, &script) == -1) { - *value = -1; + value.opcode = VALUE_TYPE_INT; + value.integerValue = -1; return -1; } @@ -2762,14 +2764,18 @@ int scriptGetLocalVar(int sid, int variable, int* value) script->localVarsOffset = _map_malloc_local_var(script->localVarsCount); } - *value = mapGetLocalVar(script->localVarsOffset + variable); + if (mapGetLocalVar(script->localVarsOffset + variable, value) == -1) { + value.opcode = VALUE_TYPE_INT; + value.integerValue = -1; + return -1; + } } return 0; } // 0x4A6E58 -int scriptSetLocalVar(int sid, int variable, int value) +int scriptSetLocalVar(int sid, int variable, ProgramValue& value) { Script* script; if (scriptGetScript(sid, &script) == -1) { diff --git a/src/scripts.h b/src/scripts.h index 095dadc..7ff7b7d 100644 --- a/src/scripts.h +++ b/src/scripts.h @@ -215,8 +215,8 @@ void scriptsExecMapUpdateScripts(int a1); void scriptsExecMapExitProc(); char* _scr_get_msg_str(int messageListId, int messageId); char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3); -int scriptGetLocalVar(int a1, int a2, int* a3); -int scriptSetLocalVar(int a1, int a2, int a3); +int scriptGetLocalVar(int sid, int var, ProgramValue& value); +int scriptSetLocalVar(int sid, int var, ProgramValue& value); bool _scr_end_combat(); int _scr_explode_scenery(Object* a1, int tile, int radius, int elevation);