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 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);

View File

@ -3,6 +3,8 @@
#include <stdio.h>
#include <string.h>
#include <vector>
#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<void*> 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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);