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 // 0x58E940
MessageList gMiscMessageList; MessageList gMiscMessageList;
// CE: Sonora folks like to store objects in global variables.
static void** gGameGlobalPointers = nullptr;
// 0x442580 // 0x442580
int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4, int argc, char** argv) 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 // 0x443CC8
static int gameLoadGlobalVars() 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 // 0x443CE8
@ -1134,6 +1148,11 @@ static void gameFreeGlobalVars()
internal_free(gGameGlobalVars); internal_free(gGameGlobalVars);
gGameGlobalVars = NULL; gGameGlobalVars = NULL;
} }
if (gGameGlobalPointers != nullptr) {
internal_free(gGameGlobalPointers);
gGameGlobalPointers = nullptr;
}
} }
// 0x443F74 // 0x443F74
@ -1492,6 +1511,28 @@ int gameShowDeathDialog(const char* message)
return rc; 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; int GameMode::currentGameMode = 0;
void GameMode::enterGameMode(int gameMode) void GameMode::enterGameMode(int gameMode)

View File

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

View File

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