From 81210f46af4177958e2c4932c33ddf86b3e96258 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Fri, 10 Feb 2023 11:05:42 +0300 Subject: [PATCH] Fix storing pointers in game global variables --- src/game.cc | 43 +++++++++++++++++++++++++++++++++++++++- src/game.h | 2 ++ src/interpreter_extra.cc | 23 ++++++++++++++------- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/game.cc b/src/game.cc index 277e34f..c0ffb89 100644 --- a/src/game.cc +++ b/src/game.cc @@ -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(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) diff --git a/src/game.h b/src/game.h index 4ec43f5..967e291 100644 --- a/src/game.h +++ b/src/game.h @@ -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: diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index 3a2d929..1cce7b4 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -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); }