Fix storing pointers in game global variables

This commit is contained in:
Alexander Batalov 2023-02-10 11:05:42 +03:00
parent c14f671a0d
commit 81210f46af
3 changed files with 60 additions and 8 deletions

View File

@ -117,6 +117,9 @@ int _game_user_wants_to_quit = 0;
// 0x58E940
MessageList gMiscMessageList;
// CE: Sonora folks like to store objects in global variables.
static void** gGameGlobalPointers = nullptr;
// 0x442580
int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4, int argc, char** argv)
{
@ -993,7 +996,18 @@ int gameSetGlobalVar(int var, int value)
// 0x443CC8
static int gameLoadGlobalVars()
{
return globalVarsRead("data\\vault13.gam", "GAME_GLOBAL_VARS:", &gGameGlobalVarsLength, &gGameGlobalVars);
if (globalVarsRead("data\\vault13.gam", "GAME_GLOBAL_VARS:", &gGameGlobalVarsLength, &gGameGlobalVars) != 0) {
return -1;
}
gGameGlobalPointers = reinterpret_cast<void**>(internal_malloc(sizeof(*gGameGlobalPointers) * gGameGlobalVarsLength));
if (gGameGlobalPointers == nullptr) {
return -1;
}
memset(gGameGlobalPointers, 0, sizeof(*gGameGlobalPointers) * gGameGlobalVarsLength);
return 0;
}
// 0x443CE8
@ -1134,6 +1148,11 @@ static void gameFreeGlobalVars()
internal_free(gGameGlobalVars);
gGameGlobalVars = NULL;
}
if (gGameGlobalPointers != nullptr) {
internal_free(gGameGlobalPointers);
gGameGlobalPointers = nullptr;
}
}
// 0x443F74
@ -1492,6 +1511,28 @@ int gameShowDeathDialog(const char* message)
return rc;
}
void* gameGetGlobalPointer(int var)
{
if (var < 0 || var >= gGameGlobalVarsLength) {
debugPrint("ERROR: attempt to reference global pointer out of range: %d", var);
return nullptr;
}
return gGameGlobalPointers[var];
}
int gameSetGlobalPointer(int var, void* value)
{
if (var < 0 || var >= gGameGlobalVarsLength) {
debugPrint("ERROR: attempt to reference global var out of range: %d", var);
return -1;
}
gGameGlobalPointers[var] = value;
return 0;
}
int GameMode::currentGameMode = 0;
void GameMode::enterGameMode(int gameMode)

View File

@ -38,6 +38,8 @@ void gameUpdateState();
int showQuitConfirmationDialog();
int gameShowDeathDialog(const char* message);
void* gameGetGlobalPointer(int var);
int gameSetGlobalPointer(int var, void* value);
class GameMode {
public:

View File

@ -1207,16 +1207,19 @@ static void opSetMapVar(Program* program)
// 0x455950
static void opGetGlobalVar(Program* program)
{
int data = programStackPopInteger(program);
int variable = programStackPopInteger(program);
int value = -1;
if (gGameGlobalVarsLength != 0) {
value = gameGetGlobalVar(data);
void* ptr = gameGetGlobalPointer(variable);
if (ptr != nullptr) {
programStackPushPointer(program, ptr);
} else {
programStackPushInteger(program, gameGetGlobalVar(variable));
}
} else {
scriptError("\nScript Error: %s: op_global_var: no global vars found!", program->name);
programStackPushInteger(program, -1);
}
programStackPushInteger(program, value);
}
// set_global_var
@ -1224,11 +1227,17 @@ static void opGetGlobalVar(Program* program)
// 0x80C6
static void opSetGlobalVar(Program* program)
{
int value = programStackPopInteger(program);
ProgramValue value = programStackPopValue(program);
int variable = programStackPopInteger(program);
if (gGameGlobalVarsLength != 0) {
gameSetGlobalVar(variable, value);
if (value.opcode == VALUE_TYPE_PTR) {
gameSetGlobalPointer(variable, value.pointerValue);
gameSetGlobalVar(variable, 0);
} else {
gameSetGlobalPointer(variable, nullptr);
gameSetGlobalVar(variable, value.integerValue);
}
} else {
scriptError("\nScript Error: %s: op_set_global_var: no global vars found!", program->name);
}