Add load/save global vars (#296)
This commit is contained in:
parent
37e4822ed5
commit
cf5f865a23
|
@ -341,8 +341,8 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||||
// SFALL
|
// SFALL
|
||||||
premadeCharactersInit();
|
premadeCharactersInit();
|
||||||
|
|
||||||
if (!sfallGlobalVarsInit()) {
|
if (!sfall_gl_vars_init()) {
|
||||||
debugPrint("Failed on sfallGlobalVarsInit");
|
debugPrint("Failed on sfall_gl_vars_init");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ void gameReset()
|
||||||
_init_options_menu();
|
_init_options_menu();
|
||||||
|
|
||||||
// SFALL
|
// SFALL
|
||||||
sfallGlobalVarsReset();
|
sfall_gl_vars_reset();
|
||||||
sfallListsReset();
|
sfallListsReset();
|
||||||
messageListRepositoryReset();
|
messageListRepositoryReset();
|
||||||
sfallArraysReset();
|
sfallArraysReset();
|
||||||
|
@ -425,7 +425,7 @@ void gameExit()
|
||||||
sfall_gl_scr_exit();
|
sfall_gl_scr_exit();
|
||||||
sfallArraysExit();
|
sfallArraysExit();
|
||||||
sfallListsExit();
|
sfallListsExit();
|
||||||
sfallGlobalVarsExit();
|
sfall_gl_vars_exit();
|
||||||
premadeCharactersExit();
|
premadeCharactersExit();
|
||||||
|
|
||||||
tileDisable();
|
tileDisable();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "interpreter_lib.h"
|
#include "interpreter_lib.h"
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "platform_compat.h"
|
#include "platform_compat.h"
|
||||||
|
#include "sfall_global_scripts.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
@ -3011,6 +3012,15 @@ Program* runScript(char* name)
|
||||||
// 0x46E1EC
|
// 0x46E1EC
|
||||||
void _updatePrograms()
|
void _updatePrograms()
|
||||||
{
|
{
|
||||||
|
// CE: Implementation is different. Sfall inserts global scripts into
|
||||||
|
// program list upon creation, so engine does not diffirentiate between
|
||||||
|
// global and normal scripts. Global scripts in CE are not part of program
|
||||||
|
// list, so we need a separate call to continue execution (usually
|
||||||
|
// non-critical calls scheduled from managed windows). One more thing to
|
||||||
|
// note is that global scripts in CE cannot handle conditional/timed procs
|
||||||
|
// (which are not used anyway).
|
||||||
|
sfall_gl_scr_update(_cpuBurstSize);
|
||||||
|
|
||||||
ProgramListNode* curr = gInterpreterProgramListHead;
|
ProgramListNode* curr = gInterpreterProgramListHead;
|
||||||
while (curr != NULL) {
|
while (curr != NULL) {
|
||||||
ProgramListNode* next = curr->next;
|
ProgramListNode* next = curr->next;
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "scripts.h"
|
#include "scripts.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sfall_global_scripts.h"
|
#include "sfall_global_scripts.h"
|
||||||
|
#include "sfall_global_vars.h"
|
||||||
#include "skill.h"
|
#include "skill.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
|
@ -1588,6 +1589,73 @@ static int lsgPerformSaveGame()
|
||||||
|
|
||||||
fileClose(_flptr);
|
fileClose(_flptr);
|
||||||
|
|
||||||
|
// SFALL: Save sfallgv.sav.
|
||||||
|
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
|
||||||
|
strcat(_gmpath, "sfallgv.sav");
|
||||||
|
|
||||||
|
_flptr = fileOpen(_gmpath, "wb");
|
||||||
|
if (_flptr != NULL) {
|
||||||
|
do {
|
||||||
|
if (!sfall_gl_vars_save(_flptr)) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving global vars **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: For now fill remaining sections with zeros to that Sfall
|
||||||
|
// can successfully read our global vars and skip the rest.
|
||||||
|
|
||||||
|
int nextObjectId = 0;
|
||||||
|
if (fileWrite(&nextObjectId, sizeof(nextObjectId), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving next object id **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addedYears = 0;
|
||||||
|
if (fileWrite(&addedYears, sizeof(addedYears), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving added years **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fakeTraitsCount = 0;
|
||||||
|
if (fileWrite(&fakeTraitsCount, sizeof(fakeTraitsCount), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving fake traits **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fakePerksCount = 0;
|
||||||
|
if (fileWrite(&fakePerksCount, sizeof(fakePerksCount), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving fake perks **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fakeSelectablePerksCount = 0;
|
||||||
|
if (fileWrite(&fakeSelectablePerksCount, sizeof(fakeSelectablePerksCount), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving fake selectable perks **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arraysCountOld = 0;
|
||||||
|
if (fileWrite(&arraysCountOld, sizeof(arraysCountOld), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving arrays (old fmt) **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arraysCountNew = 0;
|
||||||
|
if (fileWrite(&arraysCountNew, sizeof(arraysCountNew), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving arrays (new fmt) **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drugPidsCount = 0;
|
||||||
|
if (fileWrite(&drugPidsCount, sizeof(drugPidsCount), 1, _flptr) != 1) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error saving drug pids **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
fileClose(_flptr);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
|
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
|
||||||
_MapDirErase(_gmpath, "BAK");
|
_MapDirErase(_gmpath, "BAK");
|
||||||
|
|
||||||
|
@ -1663,6 +1731,24 @@ static int lsgLoadGameInSlot(int slot)
|
||||||
debugPrint("LOADSAVE: Total load data read: %ld bytes.\n", fileTell(_flptr));
|
debugPrint("LOADSAVE: Total load data read: %ld bytes.\n", fileTell(_flptr));
|
||||||
fileClose(_flptr);
|
fileClose(_flptr);
|
||||||
|
|
||||||
|
// SFALL: Load sfallgv.sav.
|
||||||
|
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
|
||||||
|
strcat(_gmpath, "sfallgv.sav");
|
||||||
|
|
||||||
|
_flptr = fileOpen(_gmpath, "rb");
|
||||||
|
if (_flptr != NULL) {
|
||||||
|
do {
|
||||||
|
if (!sfall_gl_vars_load(_flptr)) {
|
||||||
|
debugPrint("LOADSAVE (SFALL): ** Error loading global vars **\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: For now silently ignore remaining sections.
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
fileClose(_flptr);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(_str, sizeof(_str), "%s\\", "MAPS");
|
snprintf(_str, sizeof(_str), "%s\\", "MAPS");
|
||||||
_MapDirErase(_str, "BAK");
|
_MapDirErase(_str, "BAK");
|
||||||
_proto_dude_update_gender();
|
_proto_dude_update_gender();
|
||||||
|
|
|
@ -210,4 +210,11 @@ bool sfall_gl_scr_is_loaded(Program* program)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sfall_gl_scr_update(int burstSize)
|
||||||
|
{
|
||||||
|
for (auto& scr : state->globalScripts) {
|
||||||
|
_interpret(scr.program, burstSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -17,6 +17,7 @@ void sfall_gl_scr_process_worldmap();
|
||||||
void sfall_gl_scr_set_repeat(Program* program, int frames);
|
void sfall_gl_scr_set_repeat(Program* program, int frames);
|
||||||
void sfall_gl_scr_set_type(Program* program, int type);
|
void sfall_gl_scr_set_type(Program* program, int type);
|
||||||
bool sfall_gl_scr_is_loaded(Program* program);
|
bool sfall_gl_scr_is_loaded(Program* program);
|
||||||
|
void sfall_gl_scr_update(int burstSize);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
|
|
|
@ -10,72 +10,127 @@ struct SfallGlobalVarsState {
|
||||||
std::unordered_map<uint64_t, int> vars;
|
std::unordered_map<uint64_t, int> vars;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool sfallGlobalVarsStore(uint64_t key, int value);
|
#pragma pack(push)
|
||||||
static bool sfallGlobalVarsFetch(uint64_t key, int& value);
|
#pragma pack(8)
|
||||||
|
|
||||||
static SfallGlobalVarsState* _state;
|
/// Matches Sfall's `GlobalVar` to maintain binary compatibility.
|
||||||
|
struct GlobalVarEntry {
|
||||||
|
uint64_t key;
|
||||||
|
int32_t value;
|
||||||
|
int32_t unused;
|
||||||
|
};
|
||||||
|
|
||||||
bool sfallGlobalVarsInit()
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static bool sfall_gl_vars_store(uint64_t key, int value);
|
||||||
|
static bool sfall_gl_vars_fetch(uint64_t key, int& value);
|
||||||
|
|
||||||
|
static SfallGlobalVarsState* sfall_gl_vars_state = nullptr;
|
||||||
|
|
||||||
|
bool sfall_gl_vars_init()
|
||||||
{
|
{
|
||||||
_state = new (std::nothrow) SfallGlobalVarsState();
|
sfall_gl_vars_state = new (std::nothrow) SfallGlobalVarsState();
|
||||||
if (_state == nullptr) {
|
if (sfall_gl_vars_state == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfallGlobalVarsReset()
|
void sfall_gl_vars_reset()
|
||||||
{
|
{
|
||||||
_state->vars.clear();
|
sfall_gl_vars_state->vars.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfallGlobalVarsExit()
|
void sfall_gl_vars_exit()
|
||||||
{
|
{
|
||||||
if (_state != nullptr) {
|
if (sfall_gl_vars_state != nullptr) {
|
||||||
delete _state;
|
delete sfall_gl_vars_state;
|
||||||
_state = nullptr;
|
sfall_gl_vars_state = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sfallGlobalVarsStore(const char* key, int value)
|
bool sfall_gl_vars_save(File* stream)
|
||||||
|
{
|
||||||
|
int count = static_cast<int>(sfall_gl_vars_state->vars.size());
|
||||||
|
if (fileWrite(&count, sizeof(count), 1, stream) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalVarEntry entry = { 0 };
|
||||||
|
for (auto& pair : sfall_gl_vars_state->vars) {
|
||||||
|
entry.key = pair.first;
|
||||||
|
entry.value = pair.second;
|
||||||
|
|
||||||
|
if (fileWrite(&entry, sizeof(entry), 1, stream) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sfall_gl_vars_load(File* stream)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
if (fileRead(&count, sizeof(count), 1, stream) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfall_gl_vars_state->vars.reserve(count);
|
||||||
|
|
||||||
|
GlobalVarEntry entry;
|
||||||
|
while (count > 0) {
|
||||||
|
if (fileRead(&entry, sizeof(entry), 1, stream) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfall_gl_vars_state->vars[entry.key] = static_cast<int>(entry.value);
|
||||||
|
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sfall_gl_vars_store(const char* key, int value)
|
||||||
{
|
{
|
||||||
if (strlen(key) != 8) {
|
if (strlen(key) != 8) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t numericKey = *(reinterpret_cast<const uint64_t*>(key));
|
uint64_t numericKey = *(reinterpret_cast<const uint64_t*>(key));
|
||||||
return sfallGlobalVarsStore(numericKey, value);
|
return sfall_gl_vars_store(numericKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sfallGlobalVarsStore(int key, int value)
|
bool sfall_gl_vars_store(int key, int value)
|
||||||
{
|
{
|
||||||
return sfallGlobalVarsStore(static_cast<uint64_t>(key), value);
|
return sfall_gl_vars_store(static_cast<uint64_t>(key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sfallGlobalVarsFetch(const char* key, int& value)
|
bool sfall_gl_vars_fetch(const char* key, int& value)
|
||||||
{
|
{
|
||||||
if (strlen(key) != 8) {
|
if (strlen(key) != 8) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t numericKey = *(reinterpret_cast<const uint64_t*>(key));
|
uint64_t numericKey = *(reinterpret_cast<const uint64_t*>(key));
|
||||||
return sfallGlobalVarsFetch(numericKey, value);
|
return sfall_gl_vars_fetch(numericKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sfallGlobalVarsFetch(int key, int& value)
|
bool sfall_gl_vars_fetch(int key, int& value)
|
||||||
{
|
{
|
||||||
return sfallGlobalVarsFetch(static_cast<uint64_t>(key), value);
|
return sfall_gl_vars_fetch(static_cast<uint64_t>(key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sfallGlobalVarsStore(uint64_t key, int value)
|
static bool sfall_gl_vars_store(uint64_t key, int value)
|
||||||
{
|
{
|
||||||
auto it = _state->vars.find(key);
|
auto it = sfall_gl_vars_state->vars.find(key);
|
||||||
if (it == _state->vars.end()) {
|
if (it == sfall_gl_vars_state->vars.end()) {
|
||||||
_state->vars.emplace(key, value);
|
sfall_gl_vars_state->vars.emplace(key, value);
|
||||||
} else {
|
} else {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
_state->vars.erase(it);
|
sfall_gl_vars_state->vars.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it->second = value;
|
it->second = value;
|
||||||
}
|
}
|
||||||
|
@ -84,10 +139,10 @@ static bool sfallGlobalVarsStore(uint64_t key, int value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sfallGlobalVarsFetch(uint64_t key, int& value)
|
static bool sfall_gl_vars_fetch(uint64_t key, int& value)
|
||||||
{
|
{
|
||||||
auto it = _state->vars.find(key);
|
auto it = sfall_gl_vars_state->vars.find(key);
|
||||||
if (it == _state->vars.end()) {
|
if (it == sfall_gl_vars_state->vars.end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
#ifndef FALLOUT_SFALL_GLOBAL_VARS_H_
|
#ifndef FALLOUT_SFALL_GLOBAL_VARS_H_
|
||||||
#define FALLOUT_SFALL_GLOBAL_VARS_H_
|
#define FALLOUT_SFALL_GLOBAL_VARS_H_
|
||||||
|
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
bool sfallGlobalVarsInit();
|
bool sfall_gl_vars_init();
|
||||||
void sfallGlobalVarsReset();
|
void sfall_gl_vars_reset();
|
||||||
void sfallGlobalVarsExit();
|
void sfall_gl_vars_exit();
|
||||||
bool sfallGlobalVarsStore(const char* key, int value);
|
bool sfall_gl_vars_save(File* stream);
|
||||||
bool sfallGlobalVarsStore(int key, int value);
|
bool sfall_gl_vars_load(File* stream);
|
||||||
bool sfallGlobalVarsFetch(const char* key, int& value);
|
bool sfall_gl_vars_store(const char* key, int value);
|
||||||
bool sfallGlobalVarsFetch(int key, int& value);
|
bool sfall_gl_vars_store(int key, int value);
|
||||||
|
bool sfall_gl_vars_fetch(const char* key, int& value);
|
||||||
|
bool sfall_gl_vars_fetch(int key, int& value);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
|
|
|
@ -167,9 +167,9 @@ static void opSetGlobalVar(Program* program)
|
||||||
|
|
||||||
if ((variable.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
if ((variable.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||||
const char* key = programGetString(program, variable.opcode, variable.integerValue);
|
const char* key = programGetString(program, variable.opcode, variable.integerValue);
|
||||||
sfallGlobalVarsStore(key, value.integerValue);
|
sfall_gl_vars_store(key, value.integerValue);
|
||||||
} else if (variable.opcode == VALUE_TYPE_INT) {
|
} else if (variable.opcode == VALUE_TYPE_INT) {
|
||||||
sfallGlobalVarsStore(variable.integerValue, value.integerValue);
|
sfall_gl_vars_store(variable.integerValue, value.integerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,9 +181,9 @@ static void opGetGlobalInt(Program* program)
|
||||||
int value = 0;
|
int value = 0;
|
||||||
if ((variable.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
if ((variable.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) {
|
||||||
const char* key = programGetString(program, variable.opcode, variable.integerValue);
|
const char* key = programGetString(program, variable.opcode, variable.integerValue);
|
||||||
sfallGlobalVarsFetch(key, value);
|
sfall_gl_vars_fetch(key, value);
|
||||||
} else if (variable.opcode == VALUE_TYPE_INT) {
|
} else if (variable.opcode == VALUE_TYPE_INT) {
|
||||||
sfallGlobalVarsFetch(variable.integerValue, value);
|
sfall_gl_vars_fetch(variable.integerValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
programStackPushInteger(program, value);
|
programStackPushInteger(program, value);
|
||||||
|
|
Loading…
Reference in New Issue