Fix storing pointers in map local variables

Closes #152
This commit is contained in:
Alexander Batalov 2022-09-22 12:45:58 +03:00
parent b89c06008b
commit c521dcaf57
6 changed files with 62 additions and 22 deletions

View File

@ -1213,19 +1213,21 @@ static void opGetLocalVar(Program* program)
{ {
int data = programStackPopInteger(program); int data = programStackPopInteger(program);
int value = -1; ProgramValue value;
value.opcode = VALUE_TYPE_INT;
value.integerValue = -1;
int sid = scriptGetSid(program); int sid = scriptGetSid(program);
scriptGetLocalVar(sid, data, &value); scriptGetLocalVar(sid, data, value);
programStackPushInteger(program, value); programStackPushValue(program, value);
} }
// set_local_var // set_local_var
// 0x4557C8 // 0x4557C8
static void opSetLocalVar(Program* program) static void opSetLocalVar(Program* program)
{ {
int value = programStackPopInteger(program); ProgramValue value = programStackPopValue(program);
int variable = programStackPopInteger(program); int variable = programStackPopInteger(program);
int sid = scriptGetSid(program); int sid = scriptGetSid(program);

View File

@ -3,6 +3,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <vector>
#include "animation.h" #include "animation.h"
#include "art.h" #include "art.h"
#include "automap.h" #include "automap.h"
@ -159,6 +161,12 @@ static char _scratchStr[40];
// 0x631E78 // 0x631E78
static char _map_path[COMPAT_MAX_PATH]; 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<void*> gMapLocalPointers;
// iso_init // iso_init
// 0x481CA0 // 0x481CA0
int isoInit() int isoInit()
@ -405,27 +413,41 @@ int mapGetGlobalVar(int var)
} }
// 0x482280 // 0x482280
int mapSetLocalVar(int var, int value) int mapSetLocalVar(int var, ProgramValue& value)
{ {
if (var < 0 || var >= gMapLocalVarsLength) { if (var < 0 || var >= gMapLocalVarsLength) {
debugPrint("ERROR: attempt to reference local var out of range: %d", var); debugPrint("ERROR: attempt to reference local var out of range: %d", var);
return -1; 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; return 0;
} }
// 0x4822B0 // 0x4822B0
int mapGetLocalVar(int var) int mapGetLocalVar(int var, ProgramValue& value)
{ {
if (var < 0 || var >= gMapLocalVarsLength) { if (var < 0 || var >= gMapLocalVarsLength) {
debugPrint("ERROR: attempt to reference local var out of range: %d", var); 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. // Make a room to store more local variables.
@ -444,6 +466,8 @@ int _map_malloc_local_var(int a1)
gMapLocalVars = vars; gMapLocalVars = vars;
memset((unsigned char*)vars + sizeof(*vars) * oldMapLocalVarsLength, 0, sizeof(*vars) * a1); memset((unsigned char*)vars + sizeof(*vars) * oldMapLocalVarsLength, 0, sizeof(*vars) * a1);
gMapLocalPointers.resize(gMapLocalVarsLength);
return oldMapLocalVarsLength; return oldMapLocalVarsLength;
} }
@ -1546,6 +1570,8 @@ static int mapLocalVariablesInit(int count)
if (gMapLocalVars == NULL) { if (gMapLocalVars == NULL) {
return -1; return -1;
} }
gMapLocalPointers.resize(count);
} }
gMapLocalVarsLength = count; gMapLocalVarsLength = count;
@ -1561,6 +1587,8 @@ static void mapLocalVariablesFree()
gMapLocalVars = NULL; gMapLocalVars = NULL;
gMapLocalVarsLength = 0; gMapLocalVarsLength = 0;
} }
gMapLocalPointers.clear();
} }
// NOTE: Inlined. // NOTE: Inlined.

View File

@ -4,6 +4,7 @@
#include "combat_defs.h" #include "combat_defs.h"
#include "db.h" #include "db.h"
#include "geometry.h" #include "geometry.h"
#include "interpreter.h"
#include "map_defs.h" #include "map_defs.h"
#include "message.h" #include "message.h"
#include "platform_compat.h" #include "platform_compat.h"
@ -85,8 +86,8 @@ bool isoIsDisabled();
int mapSetElevation(int elevation); int mapSetElevation(int elevation);
int mapSetGlobalVar(int var, int value); int mapSetGlobalVar(int var, int value);
int mapGetGlobalVar(int var); int mapGetGlobalVar(int var);
int mapSetLocalVar(int var, int value); int mapSetLocalVar(int var, ProgramValue& value);
int mapGetLocalVar(int var); int mapGetLocalVar(int var, ProgramValue& value);
int _map_malloc_local_var(int a1); int _map_malloc_local_var(int a1);
void mapSetStart(int a1, int a2, int a3); void mapSetStart(int a1, int a2, int a3);
char* mapGetName(int map_num, int elev); char* mapGetName(int map_num, int elev);

View File

@ -5,7 +5,10 @@
// 0x4A29D0 // 0x4A29D0
int reactionSetValue(Object* critter, int value) 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; return 0;
} }
@ -36,11 +39,11 @@ int _reaction_influence_()
// 0x4A2B28 // 0x4A2B28
int reactionGetValue(Object* critter) 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 -1;
} }
return reactionValue; return programValue.integerValue;
} }

View File

@ -2732,7 +2732,7 @@ char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3)
} }
// 0x4A6D64 // 0x4A6D64
int scriptGetLocalVar(int sid, int variable, int* value) int scriptGetLocalVar(int sid, int variable, ProgramValue& value)
{ {
if (SID_TYPE(sid) == SCRIPT_TYPE_SYSTEM) { if (SID_TYPE(sid) == SCRIPT_TYPE_SYSTEM) {
debugPrint("\nError! System scripts/Map scripts not allowed local_vars! "); 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); debugPrint(":%s\n", _tempStr1);
*value = -1; value.opcode = VALUE_TYPE_INT;
value.integerValue = -1;
return -1; return -1;
} }
Script* script; Script* script;
if (scriptGetScript(sid, &script) == -1) { if (scriptGetScript(sid, &script) == -1) {
*value = -1; value.opcode = VALUE_TYPE_INT;
value.integerValue = -1;
return -1; return -1;
} }
@ -2762,14 +2764,18 @@ int scriptGetLocalVar(int sid, int variable, int* value)
script->localVarsOffset = _map_malloc_local_var(script->localVarsCount); 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; return 0;
} }
// 0x4A6E58 // 0x4A6E58
int scriptSetLocalVar(int sid, int variable, int value) int scriptSetLocalVar(int sid, int variable, ProgramValue& value)
{ {
Script* script; Script* script;
if (scriptGetScript(sid, &script) == -1) { if (scriptGetScript(sid, &script) == -1) {

View File

@ -215,8 +215,8 @@ void scriptsExecMapUpdateScripts(int a1);
void scriptsExecMapExitProc(); void scriptsExecMapExitProc();
char* _scr_get_msg_str(int messageListId, int messageId); char* _scr_get_msg_str(int messageListId, int messageId);
char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3); char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3);
int scriptGetLocalVar(int a1, int a2, int* a3); int scriptGetLocalVar(int sid, int var, ProgramValue& value);
int scriptSetLocalVar(int a1, int a2, int a3); int scriptSetLocalVar(int sid, int var, ProgramValue& value);
bool _scr_end_combat(); bool _scr_end_combat();
int _scr_explode_scenery(Object* a1, int tile, int radius, int elevation); int _scr_explode_scenery(Object* a1, int tile, int radius, int elevation);