fallout2-ce/src/loadsave.cc

2875 lines
86 KiB
C++
Raw Normal View History

2022-05-19 01:51:26 -07:00
#include "loadsave.h"
2022-09-15 02:38:23 -07:00
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <algorithm>
2022-06-19 04:07:58 -07:00
#include "art.h"
2022-05-19 01:51:26 -07:00
#include "automap.h"
#include "character_editor.h"
#include "color.h"
#include "combat.h"
#include "combat_ai.h"
#include "critter.h"
#include "cycle.h"
2022-06-19 04:07:58 -07:00
#include "db.h"
2022-05-19 01:51:26 -07:00
#include "dbox.h"
#include "debug.h"
#include "display_monitor.h"
#include "draw.h"
#include "file_utils.h"
#include "game.h"
#include "game_mouse.h"
#include "game_movie.h"
#include "game_sound.h"
2022-06-19 04:07:58 -07:00
#include "geometry.h"
2022-10-04 23:23:27 -07:00
#include "input.h"
2022-05-19 01:51:26 -07:00
#include "interface.h"
#include "item.h"
2022-10-03 06:42:34 -07:00
#include "kb.h"
2022-05-19 01:51:26 -07:00
#include "map.h"
#include "memory.h"
2022-06-19 04:07:58 -07:00
#include "message.h"
2022-10-03 02:41:33 -07:00
#include "mouse.h"
2022-05-19 01:51:26 -07:00
#include "object.h"
#include "options.h"
2022-06-19 02:00:14 -07:00
#include "party_member.h"
2022-05-19 01:51:26 -07:00
#include "perk.h"
#include "pipboy.h"
2022-06-19 04:07:58 -07:00
#include "platform_compat.h"
2022-05-19 01:51:26 -07:00
#include "proto.h"
#include "queue.h"
#include "random.h"
#include "scripts.h"
#include "settings.h"
2022-05-19 01:51:26 -07:00
#include "skill.h"
#include "stat.h"
2022-10-05 00:35:05 -07:00
#include "svga.h"
2022-05-19 01:51:26 -07:00
#include "text_font.h"
#include "tile.h"
#include "trait.h"
#include "version.h"
#include "window_manager.h"
#include "word_wrap.h"
2022-09-14 23:00:11 -07:00
#include "worldmap.h"
2022-05-19 01:51:26 -07:00
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-05-19 01:51:26 -07:00
#define LS_WINDOW_WIDTH 640
#define LS_WINDOW_HEIGHT 480
#define LS_PREVIEW_WIDTH 224
#define LS_PREVIEW_HEIGHT 133
#define LS_PREVIEW_SIZE ((LS_PREVIEW_WIDTH) * (LS_PREVIEW_HEIGHT))
#define LS_COMMENT_WINDOW_X 169
#define LS_COMMENT_WINDOW_Y 116
// NOTE: The following are "normalized" path components for "proto/critters" and
// "proto/items". The original code does not use uniform case for them (as
// opposed to other path components like MAPS, SAVE.DAT, etc). It does not have
// effect on Windows, but it's important on Linux and Mac, where filesystem is
// case-sensitive. Lowercase is preferred as it is used in other parts of the
// codebase (see `protoInit`, `gArtListDescriptions`).
#define PROTO_DIR_NAME "proto"
#define CRITTERS_DIR_NAME "critters"
#define ITEMS_DIR_NAME "items"
#define PROTO_FILE_EXT "pro"
2022-06-19 04:07:58 -07:00
#define LOAD_SAVE_DESCRIPTION_LENGTH (30)
#define LOAD_SAVE_HANDLER_COUNT (27)
typedef enum LoadSaveWindowType {
LOAD_SAVE_WINDOW_TYPE_SAVE_GAME,
LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_SAVE_SLOT,
LOAD_SAVE_WINDOW_TYPE_LOAD_GAME,
LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU,
LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_LOAD_SLOT,
} LoadSaveWindowType;
typedef enum LoadSaveSlotState {
SLOT_STATE_EMPTY,
SLOT_STATE_OCCUPIED,
SLOT_STATE_ERROR,
SLOT_STATE_UNSUPPORTED_VERSION,
} LoadSaveSlotState;
typedef enum LoadSaveScrollDirection {
LOAD_SAVE_SCROLL_DIRECTION_NONE,
LOAD_SAVE_SCROLL_DIRECTION_UP,
LOAD_SAVE_SCROLL_DIRECTION_DOWN,
} LoadSaveScrollDirection;
2022-06-19 04:07:58 -07:00
typedef int LoadGameHandler(File* stream);
typedef int SaveGameHandler(File* stream);
#define LSGAME_MSG_NAME ("LSGAME.MSG")
typedef struct STRUCT_613D30 {
char field_0[24];
short field_18;
short field_1A;
// TODO: The type is probably char, but it's read with the same function as
// reading unsigned chars, which in turn probably result of collapsing
// reading functions.
unsigned char field_1C;
char character_name[32];
char description[LOAD_SAVE_DESCRIPTION_LENGTH];
short field_5C;
short field_5E;
short field_60;
int field_64;
short field_68;
short field_6A;
short field_6C;
int field_70;
short field_74;
short field_76;
char file_name[16];
} STRUCT_613D30;
typedef enum LoadSaveFrm {
LOAD_SAVE_FRM_BACKGROUND,
LOAD_SAVE_FRM_BOX,
LOAD_SAVE_FRM_PREVIEW_COVER,
LOAD_SAVE_FRM_RED_BUTTON_PRESSED,
LOAD_SAVE_FRM_RED_BUTTON_NORMAL,
LOAD_SAVE_FRM_ARROW_DOWN_NORMAL,
LOAD_SAVE_FRM_ARROW_DOWN_PRESSED,
LOAD_SAVE_FRM_ARROW_UP_NORMAL,
LOAD_SAVE_FRM_ARROW_UP_PRESSED,
LOAD_SAVE_FRM_COUNT,
} LoadSaveFrm;
static int _QuickSnapShot();
static int lsgWindowInit(int windowType);
static int lsgWindowFree(int windowType);
static int lsgPerformSaveGame();
static int lsgLoadGameInSlot(int slot);
static int lsgSaveHeaderInSlot(int slot);
static int lsgLoadHeaderInSlot(int slot);
static int _GetSlotList();
static void _ShowSlotList(int a1);
static void _DrawInfoBox(int a1);
static int _LoadTumbSlot(int a1);
static int _GetComment(int a1);
static int _get_input_str2(int win, int doneKeyCode, int cancelKeyCode, char* description, int maxLength, int x, int y, int textColor, int backgroundColor, int flags);
static int _DummyFunc(File* stream);
static int _PrepLoad(File* stream);
static int _EndLoad(File* stream);
static int _GameMap2Slot(File* stream);
static int _SlotMap2Game(File* stream);
static int _mygets(char* dest, File* stream);
static int _copy_file(const char* a1, const char* a2);
static int _MapDirErase(const char* path, const char* a2);
static int _SaveBackup();
static int _RestoreSave();
static int _LoadObjDudeCid(File* stream);
static int _SaveObjDudeCid(File* stream);
static int _EraseSave();
2022-05-19 01:51:26 -07:00
// 0x47B7C0
2022-06-19 04:07:58 -07:00
static const int gLoadSaveFrmIds[LOAD_SAVE_FRM_COUNT] = {
2022-05-19 01:51:26 -07:00
237, // lsgame.frm - load/save game
238, // lsgbox.frm - load/save game
239, // lscover.frm - load/save game
9, // lilreddn.frm - little red button down
8, // lilredup.frm - little red button up
181, // dnarwoff.frm - character editor
182, // dnarwon.frm - character editor
199, // uparwoff.frm - character editor
200, // uparwon.frm - character editor
};
// 0x5193B8
2022-06-19 04:07:58 -07:00
static int _slot_cursor = 0;
2022-05-19 01:51:26 -07:00
// 0x5193BC
2022-06-19 04:07:58 -07:00
static bool _quick_done = false;
2022-05-19 01:51:26 -07:00
// 0x5193C0
2022-06-19 04:07:58 -07:00
static bool gLoadSaveWindowIsoWasEnabled = false;
2022-05-19 01:51:26 -07:00
// 0x5193C4
2022-06-19 04:07:58 -07:00
static int _map_backup_count = -1;
2022-05-19 01:51:26 -07:00
// 0x5193C8
2022-06-19 04:07:58 -07:00
static int _automap_db_flag = 0;
2022-05-19 01:51:26 -07:00
// 0x5193CC
static const char* _patches = NULL;
2022-05-19 01:51:26 -07:00
// 0x5193EC
2022-06-19 04:07:58 -07:00
static SaveGameHandler* _master_save_list[LOAD_SAVE_HANDLER_COUNT] = {
2022-05-19 01:51:26 -07:00
_DummyFunc,
_SaveObjDudeCid,
scriptsSaveGameGlobalVars,
_GameMap2Slot,
scriptsSaveGameGlobalVars,
_obj_save_dude,
critterSave,
killsSave,
skillsSave,
randomSave,
perksSave,
combatSave,
aiSave,
statsSave,
itemsSave,
traitsSave,
automapSave,
preferencesSave,
2022-06-10 14:32:57 -07:00
characterEditorSave,
2022-09-15 01:42:02 -07:00
wmWorldMap_save,
2022-05-19 01:51:26 -07:00
pipboySave,
gameMoviesSave,
skillsUsageSave,
partyMembersSave,
queueSave,
interfaceSave,
_DummyFunc,
};
// 0x519458
2022-06-19 04:07:58 -07:00
static LoadGameHandler* _master_load_list[LOAD_SAVE_HANDLER_COUNT] = {
2022-05-19 01:51:26 -07:00
_PrepLoad,
_LoadObjDudeCid,
scriptsLoadGameGlobalVars,
_SlotMap2Game,
scriptsSkipGameGlobalVars,
_obj_load_dude,
critterLoad,
killsLoad,
skillsLoad,
randomLoad,
perksLoad,
combatLoad,
aiLoad,
statsLoad,
itemsLoad,
traitsLoad,
automapLoad,
preferencesLoad,
2022-06-10 14:32:57 -07:00
characterEditorLoad,
2022-09-15 01:42:02 -07:00
wmWorldMap_load,
2022-05-19 01:51:26 -07:00
pipboyLoad,
gameMoviesLoad,
skillsUsageLoad,
partyMembersLoad,
queueLoad,
interfaceLoad,
_EndLoad,
};
// 0x5194C4
2022-06-19 04:07:58 -07:00
static int _loadingGame = 0;
2022-05-19 01:51:26 -07:00
// lsgame.msg
//
// 0x613D28
2022-06-19 04:07:58 -07:00
static MessageList gLoadSaveMessageList;
2022-05-19 01:51:26 -07:00
// 0x613D30
2022-06-19 04:07:58 -07:00
static STRUCT_613D30 _LSData[10];
2022-05-19 01:51:26 -07:00
// 0x614280
2022-06-19 04:07:58 -07:00
static int _LSstatus[10];
2022-05-19 01:51:26 -07:00
// 0x6142A8
2022-06-19 04:07:58 -07:00
static unsigned char* _thumbnail_image;
2022-05-19 01:51:26 -07:00
// 0x6142AC
2022-06-19 04:07:58 -07:00
static unsigned char* _snapshotBuf;
2022-05-19 01:51:26 -07:00
// 0x6142B0
2022-06-19 04:07:58 -07:00
static MessageListItem gLoadSaveMessageListItem;
2022-05-19 01:51:26 -07:00
// 0x6142C0
2022-06-19 04:07:58 -07:00
static int _dbleclkcntr;
2022-05-19 01:51:26 -07:00
// 0x6142C4
2022-06-19 04:07:58 -07:00
static int gLoadSaveWindow;
2022-05-19 01:51:26 -07:00
// 0x6142EC
2022-06-19 04:07:58 -07:00
static unsigned char* _snapshot;
2022-05-19 01:51:26 -07:00
// 0x6142F0
2022-06-19 04:07:58 -07:00
static char _str2[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// 0x6143F4
2022-06-19 04:07:58 -07:00
static char _str0[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// 0x6144F8
2022-06-19 04:07:58 -07:00
static char _str1[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// 0x6145FC
2022-06-19 04:07:58 -07:00
static char _str[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// 0x614700
2022-06-19 04:07:58 -07:00
static unsigned char* gLoadSaveWindowBuffer;
2022-05-19 01:51:26 -07:00
// 0x614704
2022-06-19 04:07:58 -07:00
static char _gmpath[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// 0x614808
2022-06-19 04:07:58 -07:00
static File* _flptr;
2022-05-19 01:51:26 -07:00
// 0x61480C
2022-06-19 04:07:58 -07:00
static int _ls_error_code;
2022-05-19 01:51:26 -07:00
// 0x614810
2022-06-19 04:07:58 -07:00
static int gLoadSaveWindowOldFont;
2022-05-19 01:51:26 -07:00
static FrmImage _loadsaveFrmImages[LOAD_SAVE_FRM_COUNT];
2022-05-19 01:51:26 -07:00
// 0x47B7E4
void _InitLoadSave()
{
_quick_done = false;
_slot_cursor = 0;
_patches = settings.system.master_patches_path.c_str();
2022-05-19 01:51:26 -07:00
_MapDirErase("MAPS\\", "SAV");
_MapDirErase(PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME "\\", PROTO_FILE_EXT);
_MapDirErase(PROTO_DIR_NAME "\\" ITEMS_DIR_NAME "\\", PROTO_FILE_EXT);
2022-05-19 01:51:26 -07:00
}
// 0x47B85C
void _ResetLoadSave()
{
_MapDirErase("MAPS\\", "SAV");
_MapDirErase(PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME "\\", PROTO_FILE_EXT);
_MapDirErase(PROTO_DIR_NAME "\\" ITEMS_DIR_NAME "\\", PROTO_FILE_EXT);
2022-05-19 01:51:26 -07:00
}
// SaveGame
// 0x47B88C
int lsgSaveGame(int mode)
{
2022-12-06 06:22:30 -08:00
ScopedGameMode gm(GameMode::kSaveGame);
2022-05-19 01:51:26 -07:00
MessageListItem messageListItem;
_ls_error_code = 0;
_patches = settings.system.master_patches_path.c_str();
2022-05-19 01:51:26 -07:00
if (mode == LOAD_SAVE_MODE_QUICK && _quick_done) {
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcat(_gmpath, "SAVE.DAT");
_flptr = fileOpen(_gmpath, "rb");
if (_flptr != NULL) {
lsgLoadHeaderInSlot(_slot_cursor);
fileClose(_flptr);
}
_snapshotBuf = NULL;
int v6 = _QuickSnapShot();
if (v6 == 1) {
int v7 = lsgPerformSaveGame();
if (v7 != -1) {
v6 = v7;
}
}
if (_snapshotBuf != NULL) {
internal_free(_snapshot);
}
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
if (v6 != -1) {
return 1;
}
if (!messageListInit(&gLoadSaveMessageList)) {
return -1;
}
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s%s", asc_5186C8, "LSGAME.MSG");
2022-05-19 01:51:26 -07:00
if (!messageListLoad(&gLoadSaveMessageList, path)) {
return -1;
}
soundPlayFile("iisxxxx1");
// Error saving game!
strcpy(_str0, getmsg(&gLoadSaveMessageList, &messageListItem, 132));
// Unable to save game.
strcpy(_str1, getmsg(&gLoadSaveMessageList, &messageListItem, 133));
const char* body[] = {
_str1,
};
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
messageListFree(&gLoadSaveMessageList);
return -1;
}
_quick_done = false;
int windowType = mode == LOAD_SAVE_MODE_QUICK
? LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_SAVE_SLOT
: LOAD_SAVE_WINDOW_TYPE_SAVE_GAME;
if (lsgWindowInit(windowType) == -1) {
debugPrint("\nLOADSAVE: ** Error loading save game screen data! **\n");
return -1;
}
if (_GetSlotList() == -1) {
windowRefresh(gLoadSaveWindow);
soundPlayFile("iisxxxx1");
// Error loading save game list!
strcpy(_str0, getmsg(&gLoadSaveMessageList, &messageListItem, 106));
// Save game directory:
strcpy(_str1, getmsg(&gLoadSaveMessageList, &messageListItem, 107));
2022-12-08 12:05:50 -08:00
snprintf(_str2, sizeof(_str2), "\"%s\\\"", "SAVEGAME");
2022-05-19 01:51:26 -07:00
// TODO: Check.
strcpy(_str2, getmsg(&gLoadSaveMessageList, &messageListItem, 108));
const char* body[] = {
_str1,
_str2,
};
showDialogBox(_str0, body, 2, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
lsgWindowFree(0);
return -1;
}
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_snapshotBuf,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
default:
2022-05-19 01:51:26 -07:00
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
2022-05-19 01:51:26 -07:00
}
_ShowSlotList(0);
_DrawInfoBox(_slot_cursor);
windowRefresh(gLoadSaveWindow);
_dbleclkcntr = 24;
int rc = -1;
int doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
while (rc == -1) {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
unsigned int tick = getTicks();
2022-10-05 00:11:47 -07:00
int keyCode = inputGetInput();
bool selectionChanged = false;
int scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
2022-05-19 01:51:26 -07:00
2022-08-07 04:52:44 -07:00
convertMouseWheelToArrowKey(&keyCode);
2022-05-19 01:51:26 -07:00
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) {
rc = 0;
} else {
switch (keyCode) {
case KEY_ARROW_UP:
_slot_cursor -= 1;
if (_slot_cursor < 0) {
_slot_cursor = 0;
}
selectionChanged = true;
doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
break;
case KEY_ARROW_DOWN:
_slot_cursor += 1;
if (_slot_cursor > 9) {
_slot_cursor = 9;
}
selectionChanged = true;
doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
break;
case KEY_HOME:
_slot_cursor = 0;
selectionChanged = true;
doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
break;
case KEY_END:
_slot_cursor = 9;
selectionChanged = true;
doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
break;
case 506:
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_UP;
2022-05-19 01:51:26 -07:00
break;
case 504:
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_DOWN;
2022-05-19 01:51:26 -07:00
break;
case 502:
if (1) {
int mouseX;
int mouseY;
mouseGetPositionInWindow(gLoadSaveWindow, &mouseX, &mouseY);
2022-05-19 01:51:26 -07:00
_slot_cursor = (mouseY - 79) / (3 * fontGetLineHeight() + 4);
2022-05-19 01:51:26 -07:00
if (_slot_cursor < 0) {
_slot_cursor = 0;
}
if (_slot_cursor > 9) {
_slot_cursor = 9;
}
selectionChanged = 1;
2022-05-19 01:51:26 -07:00
if (_slot_cursor == doubleClickSlot) {
2022-05-19 01:51:26 -07:00
keyCode = 500;
soundPlayFile("ib1p1xx1");
}
doubleClickSlot = _slot_cursor;
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
2022-05-19 01:51:26 -07:00
}
break;
case KEY_CTRL_Q:
case KEY_CTRL_X:
case KEY_F10:
showQuitConfirmationDialog();
if (_game_user_wants_to_quit != 0) {
rc = 0;
}
break;
case KEY_PLUS:
case KEY_EQUAL:
brightnessIncrease();
break;
case KEY_MINUS:
case KEY_UNDERSCORE:
brightnessDecrease();
break;
case KEY_RETURN:
keyCode = 500;
break;
}
}
if (keyCode == 500) {
if (_LSstatus[_slot_cursor] == SLOT_STATE_OCCUPIED) {
rc = 1;
2022-05-19 01:51:26 -07:00
// Save game already exists, overwrite?
const char* title = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 131);
if (showDialogBox(title, NULL, 0, 169, 131, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_YES_NO) == 0) {
rc = -1;
}
} else {
rc = 1;
}
selectionChanged = true;
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
2022-05-19 01:51:26 -07:00
}
if (scrollDirection) {
unsigned int scrollVelocity = 4;
bool isScrolling = false;
int scrollCounter = 0;
do {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
unsigned int start = getTicks();
scrollCounter += 1;
if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) {
isScrolling = true;
if (scrollCounter > 14.4) {
scrollVelocity += 1;
if (scrollVelocity > 24) {
scrollVelocity = 24;
}
}
if (scrollDirection == LOAD_SAVE_SCROLL_DIRECTION_UP) {
_slot_cursor -= 1;
if (_slot_cursor < 0) {
_slot_cursor = 0;
}
} else {
_slot_cursor += 1;
if (_slot_cursor > 9) {
_slot_cursor = 9;
}
}
// TODO: Does not check for unsupported version error like
// other switches do.
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
blitBufferToBuffer(_snapshotBuf,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
default:
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
}
_ShowSlotList(LOAD_SAVE_WINDOW_TYPE_SAVE_GAME);
_DrawInfoBox(_slot_cursor);
windowRefresh(gLoadSaveWindow);
}
if (scrollCounter > 14.4) {
while (getTicksSince(start) < 1000 / scrollVelocity) { }
2022-05-19 01:51:26 -07:00
} else {
while (getTicksSince(start) < 1000 / 24) { }
2022-05-19 01:51:26 -07:00
}
keyCode = inputGetInput();
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
} while (keyCode != 505 && keyCode != 503);
} else {
if (selectionChanged) {
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_snapshotBuf,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
default:
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
}
2022-05-19 01:51:26 -07:00
_DrawInfoBox(_slot_cursor);
_ShowSlotList(LOAD_SAVE_WINDOW_TYPE_SAVE_GAME);
2022-05-19 01:51:26 -07:00
}
windowRefresh(gLoadSaveWindow);
_dbleclkcntr -= 1;
if (_dbleclkcntr == 0) {
_dbleclkcntr = 24;
doubleClickSlot = -1;
2022-05-19 01:51:26 -07:00
}
while (getTicksSince(tick) < 1000 / 24) {
}
}
if (rc == 1) {
int v50 = _GetComment(_slot_cursor);
if (v50 == -1) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
soundPlayFile("iisxxxx1");
debugPrint("\nLOADSAVE: ** Error getting save file comment **\n");
// Error saving game!
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 132));
// Unable to save game.
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 133));
const char* body[1] = {
_str1,
};
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
rc = -1;
2022-05-19 01:51:26 -07:00
} else if (v50 == 0) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
rc = -1;
} else if (v50 == 1) {
if (lsgPerformSaveGame() == -1) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
soundPlayFile("iisxxxx1");
// Error saving game!
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 132));
// Unable to save game.
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 133));
rc = -1;
const char* body[1] = {
_str1,
};
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
if (_GetSlotList() == -1) {
windowRefresh(gLoadSaveWindow);
soundPlayFile("iisxxxx1");
// Error loading save agme list!
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 106));
// Save game directory:
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 107));
2022-12-08 12:05:50 -08:00
snprintf(_str2, sizeof(_str2), "\"%s\\\"", "SAVEGAME");
2022-05-19 01:51:26 -07:00
char text[260];
// Doesn't exist or is corrupted.
strcpy(text, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 107));
const char* body[2] = {
_str1,
_str2,
};
showDialogBox(_str0, body, 2, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
lsgWindowFree(0);
return -1;
}
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_snapshotBuf,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
default:
2022-05-19 01:51:26 -07:00
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
2022-05-19 01:51:26 -07:00
}
_ShowSlotList(LOAD_SAVE_WINDOW_TYPE_SAVE_GAME);
2022-05-19 01:51:26 -07:00
_DrawInfoBox(_slot_cursor);
windowRefresh(gLoadSaveWindow);
_dbleclkcntr = 24;
}
}
}
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
2022-05-19 01:51:26 -07:00
}
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
lsgWindowFree(LOAD_SAVE_WINDOW_TYPE_SAVE_GAME);
2022-05-19 01:51:26 -07:00
tileWindowRefresh();
if (mode == LOAD_SAVE_MODE_QUICK) {
if (rc == 1) {
_quick_done = true;
}
}
return rc;
}
// 0x47C5B4
2022-06-19 04:07:58 -07:00
static int _QuickSnapShot()
2022-05-19 01:51:26 -07:00
{
2022-05-21 08:22:03 -07:00
_snapshot = (unsigned char*)internal_malloc(LS_PREVIEW_SIZE);
2022-05-19 01:51:26 -07:00
if (_snapshot == NULL) {
return -1;
}
bool gameMouseWasVisible = gameMouseObjectsIsVisible();
if (gameMouseWasVisible) {
gameMouseObjectsHide();
}
mouseHideCursor();
tileWindowRefresh();
mouseShowCursor();
if (gameMouseWasVisible) {
gameMouseObjectsShow();
}
2022-05-23 01:16:04 -07:00
// For preview take 640x380 area in the center of isometric window.
2022-06-07 14:14:52 -07:00
Window* window = windowGetWindow(gIsoWindow);
unsigned char* isoWindowBuffer = window->buffer
+ window->width * (window->height - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (window->width - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
2022-05-23 01:16:04 -07:00
blitBufferToBufferStretch(isoWindowBuffer,
ORIGINAL_ISO_WINDOW_WIDTH,
ORIGINAL_ISO_WINDOW_HEIGHT,
windowGetWidth(gIsoWindow),
_snapshot,
LS_PREVIEW_WIDTH,
LS_PREVIEW_HEIGHT,
LS_PREVIEW_WIDTH);
2022-05-19 01:51:26 -07:00
_snapshotBuf = _snapshot;
return 1;
}
// LoadGame
// 0x47C640
int lsgLoadGame(int mode)
{
2022-12-06 06:22:30 -08:00
ScopedGameMode gm(GameMode::kLoadGame);
2022-05-19 01:51:26 -07:00
MessageListItem messageListItem;
const char* body[] = {
_str1,
_str2,
};
_ls_error_code = 0;
_patches = settings.system.master_patches_path.c_str();
2022-05-19 01:51:26 -07:00
if (mode == LOAD_SAVE_MODE_QUICK && _quick_done) {
int quickSaveWindowX = (screenGetWidth() - LS_WINDOW_WIDTH) / 2;
int quickSaveWindowY = (screenGetHeight() - LS_WINDOW_HEIGHT) / 2;
int window = windowCreate(quickSaveWindowX,
quickSaveWindowY,
LS_WINDOW_WIDTH,
LS_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
2022-05-19 01:51:26 -07:00
if (window != -1) {
unsigned char* windowBuffer = windowGetBuffer(window);
bufferFill(windowBuffer, LS_WINDOW_WIDTH, LS_WINDOW_HEIGHT, LS_WINDOW_WIDTH, _colorTable[0]);
windowRefresh(window);
2022-10-07 14:54:27 -07:00
renderPresent();
2022-05-19 01:51:26 -07:00
}
if (lsgLoadGameInSlot(_slot_cursor) != -1) {
if (window != -1) {
windowDestroy(window);
}
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return 1;
}
if (!messageListInit(&gLoadSaveMessageList)) {
return -1;
}
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s\\%s", asc_5186C8, "LSGAME.MSG");
2022-05-19 01:51:26 -07:00
if (!messageListLoad(&gLoadSaveMessageList, path)) {
return -1;
}
if (window != -1) {
windowDestroy(window);
}
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
soundPlayFile("iisxxxx1");
strcpy(_str0, getmsg(&gLoadSaveMessageList, &messageListItem, 134));
strcpy(_str1, getmsg(&gLoadSaveMessageList, &messageListItem, 135));
2022-05-19 01:51:26 -07:00
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_LARGE);
messageListFree(&gLoadSaveMessageList);
2022-09-15 07:49:40 -07:00
mapNewMap();
2022-05-19 01:51:26 -07:00
_game_user_wants_to_quit = 2;
return -1;
}
2022-05-19 01:51:26 -07:00
_quick_done = false;
2022-05-19 01:51:26 -07:00
int windowType;
switch (mode) {
case LOAD_SAVE_MODE_FROM_MAIN_MENU:
windowType = LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU;
break;
case LOAD_SAVE_MODE_NORMAL:
windowType = LOAD_SAVE_WINDOW_TYPE_LOAD_GAME;
break;
case LOAD_SAVE_MODE_QUICK:
windowType = LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_LOAD_SLOT;
break;
default:
assert(false && "Should be unreachable");
}
2022-05-19 01:51:26 -07:00
if (lsgWindowInit(windowType) == -1) {
debugPrint("\nLOADSAVE: ** Error loading save game screen data! **\n");
return -1;
}
2022-05-19 01:51:26 -07:00
if (_GetSlotList() == -1) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
windowRefresh(gLoadSaveWindow);
2022-10-07 14:54:27 -07:00
renderPresent();
soundPlayFile("iisxxxx1");
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 106));
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 107));
2022-12-08 12:05:50 -08:00
snprintf(_str2, sizeof(_str2), "\"%s\\\"", "SAVEGAME");
showDialogBox(_str0, body, 2, 169, 116, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_LARGE);
lsgWindowFree(windowType);
return -1;
}
2022-05-19 01:51:26 -07:00
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getHeight(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 39 + 340,
LS_WINDOW_WIDTH);
break;
default:
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
}
2022-05-19 01:51:26 -07:00
_ShowSlotList(2);
_DrawInfoBox(_slot_cursor);
windowRefresh(gLoadSaveWindow);
2022-10-07 14:54:27 -07:00
renderPresent();
_dbleclkcntr = 24;
2022-05-19 01:51:26 -07:00
int rc = -1;
int doubleClickSlot = -1;
while (rc == -1) {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
unsigned int time = getTicks();
int keyCode = inputGetInput();
bool selectionChanged = false;
int scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
2022-05-19 01:51:26 -07:00
convertMouseWheelToArrowKey(&keyCode);
2022-05-19 01:51:26 -07:00
if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) {
rc = 0;
} else {
switch (keyCode) {
case KEY_ARROW_UP:
_slot_cursor--;
if (_slot_cursor < 0) {
_slot_cursor = 0;
}
selectionChanged = true;
doubleClickSlot = -1;
break;
case KEY_ARROW_DOWN:
_slot_cursor++;
if (_slot_cursor > 9) {
_slot_cursor = 9;
}
selectionChanged = true;
doubleClickSlot = -1;
break;
case KEY_HOME:
_slot_cursor = 0;
selectionChanged = true;
doubleClickSlot = -1;
break;
case KEY_END:
_slot_cursor = 9;
selectionChanged = true;
doubleClickSlot = -1;
break;
case 506:
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_UP;
break;
case 504:
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_DOWN;
break;
case 502:
if (1) {
int mouseX;
int mouseY;
mouseGetPositionInWindow(gLoadSaveWindow, &mouseX, &mouseY);
2022-05-19 01:51:26 -07:00
int clickedSlot = (mouseY - 79) / (3 * fontGetLineHeight() + 4);
if (clickedSlot < 0) {
clickedSlot = 0;
} else if (clickedSlot > 9) {
clickedSlot = 9;
}
2022-08-07 04:52:44 -07:00
_slot_cursor = clickedSlot;
if (clickedSlot == doubleClickSlot) {
2022-05-19 01:51:26 -07:00
keyCode = 500;
soundPlayFile("ib1p1xx1");
2022-05-19 01:51:26 -07:00
}
selectionChanged = true;
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
doubleClickSlot = _slot_cursor;
2022-05-19 01:51:26 -07:00
}
break;
case KEY_MINUS:
case KEY_UNDERSCORE:
brightnessDecrease();
break;
case KEY_EQUAL:
case KEY_PLUS:
brightnessIncrease();
break;
case KEY_RETURN:
keyCode = 500;
break;
case KEY_CTRL_Q:
case KEY_CTRL_X:
case KEY_F10:
showQuitConfirmationDialog();
if (_game_user_wants_to_quit != 0) {
rc = 0;
}
break;
}
}
2022-05-19 01:51:26 -07:00
if (keyCode == 500) {
if (_LSstatus[_slot_cursor] != SLOT_STATE_EMPTY) {
rc = 1;
} else {
rc = -1;
}
2022-05-19 01:51:26 -07:00
selectionChanged = true;
scrollDirection = LOAD_SAVE_SCROLL_DIRECTION_NONE;
}
2022-05-19 01:51:26 -07:00
if (scrollDirection != LOAD_SAVE_SCROLL_DIRECTION_NONE) {
unsigned int scrollVelocity = 4;
bool isScrolling = false;
int scrollCounter = 0;
do {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
unsigned int start = getTicks();
scrollCounter += 1;
if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) {
isScrolling = true;
if (scrollCounter > 14.4) {
scrollVelocity += 1;
if (scrollVelocity > 24) {
scrollVelocity = 24;
2022-05-19 01:51:26 -07:00
}
}
2022-05-19 01:51:26 -07:00
if (scrollDirection == LOAD_SAVE_SCROLL_DIRECTION_UP) {
_slot_cursor -= 1;
if (_slot_cursor < 0) {
_slot_cursor = 0;
2022-05-19 01:51:26 -07:00
}
} else {
_slot_cursor += 1;
if (_slot_cursor > 9) {
_slot_cursor = 9;
2022-05-19 01:51:26 -07:00
}
}
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getHeight(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 39 + 340,
LS_WINDOW_WIDTH);
break;
default:
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_BACKGROUND].getData() + LS_WINDOW_WIDTH * 39 + 340,
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getHeight(),
LS_WINDOW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 39 + 340,
LS_WINDOW_WIDTH);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
2022-05-19 01:51:26 -07:00
}
_ShowSlotList(2);
_DrawInfoBox(_slot_cursor);
windowRefresh(gLoadSaveWindow);
2022-05-19 01:51:26 -07:00
}
if (scrollCounter > 14.4) {
while (getTicksSince(start) < 1000 / scrollVelocity) { }
} else {
while (getTicksSince(start) < 1000 / 24) { }
}
2022-05-19 01:51:26 -07:00
keyCode = inputGetInput();
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
} while (keyCode != 505 && keyCode != 503);
} else {
if (selectionChanged) {
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_EMPTY:
case SLOT_STATE_ERROR:
case SLOT_STATE_UNSUPPORTED_VERSION:
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getHeight(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 39 + 340,
LS_WINDOW_WIDTH);
break;
default:
_LoadTumbSlot(_slot_cursor);
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_BACKGROUND].getData() + LS_WINDOW_WIDTH * 39 + 340,
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_PREVIEW_COVER].getHeight(),
LS_WINDOW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 39 + 340,
LS_WINDOW_WIDTH);
blitBufferToBuffer(_thumbnail_image,
LS_PREVIEW_WIDTH - 1,
LS_PREVIEW_HEIGHT - 1,
LS_PREVIEW_WIDTH,
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 58 + 366,
LS_WINDOW_WIDTH);
break;
}
2022-05-19 01:51:26 -07:00
_DrawInfoBox(_slot_cursor);
_ShowSlotList(2);
}
2022-05-19 01:51:26 -07:00
windowRefresh(gLoadSaveWindow);
2022-05-19 01:51:26 -07:00
_dbleclkcntr -= 1;
if (_dbleclkcntr == 0) {
_dbleclkcntr = 24;
doubleClickSlot = -1;
}
2022-05-19 01:51:26 -07:00
while (getTicksSince(time) < 1000 / 24) { }
}
2022-05-19 01:51:26 -07:00
if (rc == 1) {
switch (_LSstatus[_slot_cursor]) {
case SLOT_STATE_UNSUPPORTED_VERSION:
soundPlayFile("iisxxxx1");
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 134));
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 136));
strcpy(_str2, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 135));
showDialogBox(_str0, body, 2, 169, 116, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_LARGE);
rc = -1;
break;
case SLOT_STATE_ERROR:
soundPlayFile("iisxxxx1");
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 134));
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 136));
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_LARGE);
rc = -1;
break;
default:
if (lsgLoadGameInSlot(_slot_cursor) == -1) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
2022-05-19 01:51:26 -07:00
soundPlayFile("iisxxxx1");
strcpy(_str0, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 134));
strcpy(_str1, getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 135));
2022-05-19 01:51:26 -07:00
showDialogBox(_str0, body, 1, 169, 116, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_LARGE);
mapNewMap();
_game_user_wants_to_quit = 2;
2022-05-19 01:51:26 -07:00
rc = -1;
}
break;
2022-05-19 01:51:26 -07:00
}
}
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
}
2022-05-19 01:51:26 -07:00
lsgWindowFree(mode == LOAD_SAVE_MODE_FROM_MAIN_MENU
? LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU
: LOAD_SAVE_WINDOW_TYPE_LOAD_GAME);
2022-05-19 01:51:26 -07:00
if (mode == LOAD_SAVE_MODE_QUICK) {
if (rc == 1) {
_quick_done = true;
2022-05-19 01:51:26 -07:00
}
}
return rc;
2022-05-19 01:51:26 -07:00
}
// 0x47D2E4
2022-06-19 04:07:58 -07:00
static int lsgWindowInit(int windowType)
2022-05-19 01:51:26 -07:00
{
gLoadSaveWindowOldFont = fontGetCurrent();
fontSetCurrent(103);
gLoadSaveWindowIsoWasEnabled = false;
if (!messageListInit(&gLoadSaveMessageList)) {
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s%s", asc_5186C8, LSGAME_MSG_NAME);
2022-05-19 01:51:26 -07:00
if (!messageListLoad(&gLoadSaveMessageList, _str)) {
return -1;
}
2022-05-21 08:22:03 -07:00
_snapshot = (unsigned char*)internal_malloc(61632);
2022-05-19 01:51:26 -07:00
if (_snapshot == NULL) {
messageListFree(&gLoadSaveMessageList);
fontSetCurrent(gLoadSaveWindowOldFont);
return -1;
}
_thumbnail_image = _snapshot;
_snapshotBuf = _snapshot + LS_PREVIEW_SIZE;
if (windowType != LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU) {
gLoadSaveWindowIsoWasEnabled = isoDisable();
}
colorCycleDisable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
if (windowType == LOAD_SAVE_WINDOW_TYPE_SAVE_GAME || windowType == LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_SAVE_SLOT) {
bool gameMouseWasVisible = gameMouseObjectsIsVisible();
if (gameMouseWasVisible) {
gameMouseObjectsHide();
}
mouseHideCursor();
tileWindowRefresh();
mouseShowCursor();
if (gameMouseWasVisible) {
gameMouseObjectsShow();
}
2022-05-23 01:16:04 -07:00
// For preview take 640x380 area in the center of isometric window.
2022-06-07 14:14:52 -07:00
Window* window = windowGetWindow(gIsoWindow);
unsigned char* isoWindowBuffer = window->buffer
+ window->width * (window->height - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (window->width - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
2022-05-23 01:16:04 -07:00
blitBufferToBufferStretch(isoWindowBuffer,
ORIGINAL_ISO_WINDOW_WIDTH,
ORIGINAL_ISO_WINDOW_HEIGHT,
windowGetWidth(gIsoWindow),
_snapshotBuf,
LS_PREVIEW_WIDTH,
LS_PREVIEW_HEIGHT,
LS_PREVIEW_WIDTH);
2022-05-19 01:51:26 -07:00
}
for (int index = 0; index < LOAD_SAVE_FRM_COUNT; index++) {
int fid = buildFid(OBJ_TYPE_INTERFACE, gLoadSaveFrmIds[index], 0, 0, 0);
if (!_loadsaveFrmImages[index].lock(fid)) {
2022-05-19 01:51:26 -07:00
while (--index >= 0) {
_loadsaveFrmImages[index].unlock();
2022-05-19 01:51:26 -07:00
}
internal_free(_snapshot);
messageListFree(&gLoadSaveMessageList);
fontSetCurrent(gLoadSaveWindowOldFont);
if (windowType != LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU) {
if (gLoadSaveWindowIsoWasEnabled) {
isoEnable();
}
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
}
int lsWindowX = (screenGetWidth() - LS_WINDOW_WIDTH) / 2;
int lsWindowY = (screenGetHeight() - LS_WINDOW_HEIGHT) / 2;
gLoadSaveWindow = windowCreate(lsWindowX,
lsWindowY,
LS_WINDOW_WIDTH,
LS_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
2022-05-19 01:51:26 -07:00
if (gLoadSaveWindow == -1) {
// FIXME: Leaking frms.
internal_free(_snapshot);
messageListFree(&gLoadSaveMessageList);
fontSetCurrent(gLoadSaveWindowOldFont);
if (windowType != LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU) {
if (gLoadSaveWindowIsoWasEnabled) {
isoEnable();
}
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
gLoadSaveWindowBuffer = windowGetBuffer(gLoadSaveWindow);
memcpy(gLoadSaveWindowBuffer, _loadsaveFrmImages[LOAD_SAVE_FRM_BACKGROUND].getData(), LS_WINDOW_WIDTH * LS_WINDOW_HEIGHT);
2022-05-19 01:51:26 -07:00
int messageId;
switch (windowType) {
case LOAD_SAVE_WINDOW_TYPE_SAVE_GAME:
// SAVE GAME
messageId = 102;
break;
case LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_SAVE_SLOT:
// PICK A QUICK SAVE SLOT
messageId = 103;
break;
case LOAD_SAVE_WINDOW_TYPE_LOAD_GAME:
case LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU:
// LOAD GAME
messageId = 100;
break;
case LOAD_SAVE_WINDOW_TYPE_PICK_QUICK_LOAD_SLOT:
// PICK A QUICK LOAD SLOT
messageId = 101;
break;
default:
assert(false && "Should be unreachable");
}
char* msg;
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, messageId);
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 27 + 48, msg, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, _colorTable[18979]);
// DONE
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 104);
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 348 + 410, msg, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, _colorTable[18979]);
// CANCEL
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 105);
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 348 + 515, msg, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, _colorTable[18979]);
int btn;
btn = buttonCreate(gLoadSaveWindow,
391,
349,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
-1,
-1,
500,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(gLoadSaveWindow,
495,
349,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
-1,
-1,
501,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(gLoadSaveWindow,
35,
58,
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_UP_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_UP_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
505,
506,
505,
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_UP_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_UP_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(gLoadSaveWindow,
35,
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_UP_PRESSED].getHeight() + 58,
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_DOWN_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_DOWN_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
503,
504,
503,
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_DOWN_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_ARROW_DOWN_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
buttonCreate(gLoadSaveWindow, 55, 87, 230, 353, -1, -1, -1, 502, NULL, NULL, NULL, BUTTON_FLAG_TRANSPARENT);
fontSetCurrent(101);
return 0;
}
// 0x47D824
2022-06-19 04:07:58 -07:00
static int lsgWindowFree(int windowType)
2022-05-19 01:51:26 -07:00
{
windowDestroy(gLoadSaveWindow);
fontSetCurrent(gLoadSaveWindowOldFont);
messageListFree(&gLoadSaveMessageList);
for (int index = 0; index < LOAD_SAVE_FRM_COUNT; index++) {
_loadsaveFrmImages[index].unlock();
2022-05-19 01:51:26 -07:00
}
internal_free(_snapshot);
if (windowType != LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU) {
if (gLoadSaveWindowIsoWasEnabled) {
isoEnable();
}
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return 0;
}
// 0x47D88C
2022-06-19 04:07:58 -07:00
static int lsgPerformSaveGame()
2022-05-19 01:51:26 -07:00
{
_ls_error_code = 0;
_map_backup_count = -1;
gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET);
backgroundSoundPause();
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s", _patches, "SAVEGAME");
compat_mkdir(_gmpath);
2022-05-19 01:51:26 -07:00
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
compat_mkdir(_gmpath);
2022-05-19 01:51:26 -07:00
strcat(_gmpath, "\\" PROTO_DIR_NAME);
compat_mkdir(_gmpath);
2022-05-19 01:51:26 -07:00
char* protoBasePath = _gmpath + strlen(_gmpath);
strcpy(protoBasePath, "\\" CRITTERS_DIR_NAME);
compat_mkdir(_gmpath);
2022-05-19 01:51:26 -07:00
strcpy(protoBasePath, "\\" ITEMS_DIR_NAME);
compat_mkdir(_gmpath);
2022-05-19 01:51:26 -07:00
if (_SaveBackup() == -1) {
debugPrint("\nLOADSAVE: Warning, can't backup save file!\n");
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcat(_gmpath, "SAVE.DAT");
debugPrint("\nLOADSAVE: Save name: %s\n", _gmpath);
_flptr = fileOpen(_gmpath, "wb");
if (_flptr == NULL) {
debugPrint("\nLOADSAVE: ** Error opening save game for writing! **\n");
_RestoreSave();
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
_MapDirErase(_gmpath, "BAK");
_partyMemberUnPrepSave();
backgroundSoundResume();
return -1;
}
long pos = fileTell(_flptr);
if (lsgSaveHeaderInSlot(_slot_cursor) == -1) {
debugPrint("\nLOADSAVE: ** Error writing save game header! **\n");
debugPrint("LOADSAVE: Save file header size written: %d bytes.\n", fileTell(_flptr) - pos);
fileClose(_flptr);
_RestoreSave();
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
_MapDirErase(_gmpath, "BAK");
_partyMemberUnPrepSave();
backgroundSoundResume();
return -1;
}
for (int index = 0; index < LOAD_SAVE_HANDLER_COUNT; index++) {
long pos = fileTell(_flptr);
SaveGameHandler* handler = _master_save_list[index];
if (handler(_flptr) == -1) {
debugPrint("\nLOADSAVE: ** Error writing save function #%d data! **\n", index);
fileClose(_flptr);
_RestoreSave();
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
_MapDirErase(_gmpath, "BAK");
_partyMemberUnPrepSave();
backgroundSoundResume();
return -1;
}
debugPrint("LOADSAVE: Save function #%d data size written: %d bytes.\n", index, fileTell(_flptr) - pos);
}
debugPrint("LOADSAVE: Total save data written: %ld bytes.\n", fileTell(_flptr));
fileClose(_flptr);
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
_MapDirErase(_gmpath, "BAK");
gLoadSaveMessageListItem.num = 140;
if (messageListGetItem(&gLoadSaveMessageList, &gLoadSaveMessageListItem)) {
displayMonitorAddMessage(gLoadSaveMessageListItem.text);
} else {
debugPrint("\nError: Couldn't find LoadSave Message!");
}
backgroundSoundResume();
return 0;
}
// 0x47DC60
int _isLoadingGame()
{
return _loadingGame;
}
// 0x47DC68
2022-06-19 04:07:58 -07:00
static int lsgLoadGameInSlot(int slot)
2022-05-19 01:51:26 -07:00
{
_loadingGame = 1;
if (isInCombat()) {
interfaceBarEndButtonsHide(false);
_combat_over_from_load();
gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET);
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcat(_gmpath, "SAVE.DAT");
STRUCT_613D30* ptr = &(_LSData[slot]);
debugPrint("\nLOADSAVE: Load name: %s\n", ptr->description);
_flptr = fileOpen(_gmpath, "rb");
if (_flptr == NULL) {
debugPrint("\nLOADSAVE: ** Error opening load game file for reading! **\n");
_loadingGame = 0;
return -1;
}
long pos = fileTell(_flptr);
if (lsgLoadHeaderInSlot(slot) == -1) {
debugPrint("\nLOADSAVE: ** Error reading save game header! **\n");
fileClose(_flptr);
gameReset();
_loadingGame = 0;
return -1;
}
debugPrint("LOADSAVE: Load file header size read: %d bytes.\n", fileTell(_flptr) - pos);
for (int index = 0; index < LOAD_SAVE_HANDLER_COUNT; index += 1) {
long pos = fileTell(_flptr);
LoadGameHandler* handler = _master_load_list[index];
if (handler(_flptr) == -1) {
debugPrint("\nLOADSAVE: ** Error reading load function #%d data! **\n", index);
int v12 = fileTell(_flptr);
debugPrint("LOADSAVE: Load function #%d data size read: %d bytes.\n", index, fileTell(_flptr) - pos);
fileClose(_flptr);
gameReset();
_loadingGame = 0;
return -1;
}
debugPrint("LOADSAVE: Load function #%d data size read: %d bytes.\n", index, fileTell(_flptr) - pos);
}
debugPrint("LOADSAVE: Total load data read: %ld bytes.\n", fileTell(_flptr));
fileClose(_flptr);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s\\", "MAPS");
2022-05-19 01:51:26 -07:00
_MapDirErase(_str, "BAK");
_proto_dude_update_gender();
// Game Loaded.
gLoadSaveMessageListItem.num = 141;
if (messageListGetItem(&gLoadSaveMessageList, &gLoadSaveMessageListItem) == 1) {
displayMonitorAddMessage(gLoadSaveMessageListItem.text);
} else {
debugPrint("\nError: Couldn't find LoadSave Message!");
}
_loadingGame = 0;
return 0;
}
// 0x47DF10
2022-06-19 04:07:58 -07:00
static int lsgSaveHeaderInSlot(int slot)
2022-05-19 01:51:26 -07:00
{
_ls_error_code = 4;
STRUCT_613D30* ptr = &(_LSData[slot]);
strncpy(ptr->field_0, "FALLOUT SAVE FILE", 24);
if (fileWrite(ptr->field_0, 1, 24, _flptr) == -1) {
return -1;
}
short temp[3];
temp[0] = VERSION_MAJOR;
temp[1] = VERSION_MINOR;
ptr->field_18 = temp[0];
ptr->field_1A = temp[1];
if (fileWriteInt16List(_flptr, temp, 2) == -1) {
return -1;
}
ptr->field_1C = VERSION_RELEASE;
if (fileWriteUInt8(_flptr, VERSION_RELEASE) == -1) {
return -1;
}
char* characterName = critterGetName(gDude);
strncpy(ptr->character_name, characterName, 32);
if (fileWrite(ptr->character_name, 32, 1, _flptr) != 1) {
return -1;
}
if (fileWrite(ptr->description, 30, 1, _flptr) != 1) {
return -1;
}
time_t now = time(NULL);
struct tm* local = localtime(&now);
temp[0] = local->tm_mday;
temp[1] = local->tm_mon + 1;
temp[2] = local->tm_year + 1900;
ptr->field_5E = temp[0];
ptr->field_5C = temp[1];
ptr->field_60 = temp[2];
ptr->field_64 = local->tm_hour + local->tm_min;
if (fileWriteInt16List(_flptr, temp, 3) == -1) {
return -1;
}
if (_db_fwriteLong(_flptr, ptr->field_64) == -1) {
return -1;
}
int month;
int day;
int year;
gameTimeGetDate(&month, &day, &year);
temp[0] = month;
temp[1] = day;
temp[2] = year;
ptr->field_70 = gameTimeGetTime();
if (fileWriteInt16List(_flptr, temp, 3) == -1) {
return -1;
}
if (_db_fwriteLong(_flptr, ptr->field_70) == -1) {
return -1;
}
ptr->field_74 = gElevation;
if (fileWriteInt16(_flptr, ptr->field_74) == -1) {
return -1;
}
ptr->field_76 = mapGetCurrentMap();
if (fileWriteInt16(_flptr, ptr->field_76) == -1) {
return -1;
}
char mapName[128];
strcpy(mapName, gMapHeader.name);
// NOTE: Uppercased from "sav".
char* v1 = _strmfe(_str, mapName, "SAV");
2022-05-19 01:51:26 -07:00
strncpy(ptr->file_name, v1, 16);
if (fileWrite(ptr->file_name, 16, 1, _flptr) != 1) {
return -1;
}
if (fileWrite(_snapshotBuf, LS_PREVIEW_SIZE, 1, _flptr) != 1) {
return -1;
}
memset(mapName, 0, 128);
if (fileWrite(mapName, 1, 128, _flptr) != 128) {
return -1;
}
_ls_error_code = 0;
return 0;
}
// 0x47E2E4
2022-06-19 04:07:58 -07:00
static int lsgLoadHeaderInSlot(int slot)
2022-05-19 01:51:26 -07:00
{
_ls_error_code = 3;
STRUCT_613D30* ptr = &(_LSData[slot]);
if (fileRead(ptr->field_0, 1, 24, _flptr) != 24) {
return -1;
}
if (strncmp(ptr->field_0, "FALLOUT SAVE FILE", 18) != 0) {
debugPrint("\nLOADSAVE: ** Invalid save file on load! **\n");
_ls_error_code = 2;
return -1;
}
short v8[3];
if (fileReadInt16List(_flptr, v8, 2) == -1) {
return -1;
}
ptr->field_18 = v8[0];
ptr->field_1A = v8[1];
if (fileReadUInt8(_flptr, &(ptr->field_1C)) == -1) {
return -1;
}
if (ptr->field_18 != 1 || ptr->field_1A != 2 || ptr->field_1C != 'R') {
debugPrint("\nLOADSAVE: Load slot #%d Version: %d.%d%c\n", slot, ptr->field_18, ptr->field_1A, ptr->field_1C);
_ls_error_code = 1;
return -1;
}
if (fileRead(ptr->character_name, 32, 1, _flptr) != 1) {
return -1;
}
if (fileRead(ptr->description, 30, 1, _flptr) != 1) {
return -1;
}
if (fileReadInt16List(_flptr, v8, 3) == -1) {
return -1;
}
ptr->field_5C = v8[0];
ptr->field_5E = v8[1];
ptr->field_60 = v8[2];
if (_db_freadInt(_flptr, &(ptr->field_64)) == -1) {
return -1;
}
if (fileReadInt16List(_flptr, v8, 3) == -1) {
return -1;
}
ptr->field_68 = v8[0];
ptr->field_6A = v8[1];
ptr->field_6C = v8[2];
if (_db_freadInt(_flptr, &(ptr->field_70)) == -1) {
return -1;
}
if (fileReadInt16(_flptr, &(ptr->field_74)) == -1) {
return -1;
}
if (fileReadInt16(_flptr, &(ptr->field_76)) == -1) {
return -1;
}
if (fileRead(ptr->file_name, 1, 16, _flptr) != 16) {
return -1;
}
if (fileSeek(_flptr, LS_PREVIEW_SIZE, SEEK_CUR) != 0) {
return -1;
}
if (fileSeek(_flptr, 128, 1) != 0) {
return -1;
}
_ls_error_code = 0;
return 0;
}
// 0x47E5D0
2022-06-19 04:07:58 -07:00
static int _GetSlotList()
2022-05-19 01:51:26 -07:00
{
int index = 0;
for (; index < 10; index += 1) {
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s\\%s%.2d\\%s", "SAVEGAME", "SLOT", index + 1, "SAVE.DAT");
2022-05-19 01:51:26 -07:00
int fileSize;
if (dbGetFileSize(_str, &fileSize) != 0) {
_LSstatus[index] = SLOT_STATE_EMPTY;
} else {
_flptr = fileOpen(_str, "rb");
if (_flptr == NULL) {
debugPrint("\nLOADSAVE: ** Error opening save game for reading! **\n");
return -1;
}
if (lsgLoadHeaderInSlot(index) == -1) {
if (_ls_error_code == 1) {
debugPrint("LOADSAVE: ** save file #%d is an older version! **\n", _slot_cursor);
_LSstatus[index] = SLOT_STATE_UNSUPPORTED_VERSION;
} else {
debugPrint("LOADSAVE: ** Save file #%d corrupt! **", index);
_LSstatus[index] = SLOT_STATE_ERROR;
}
} else {
_LSstatus[index] = SLOT_STATE_OCCUPIED;
}
fileClose(_flptr);
}
}
return index;
}
// 0x47E6D8
2022-06-19 04:07:58 -07:00
static void _ShowSlotList(int a1)
2022-05-19 01:51:26 -07:00
{
bufferFill(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 87 + 55, 230, 353, LS_WINDOW_WIDTH, gLoadSaveWindowBuffer[LS_WINDOW_WIDTH * 86 + 55] & 0xFF);
int y = 87;
for (int index = 0; index < 10; index += 1) {
int color = index == _slot_cursor ? _colorTable[32747] : _colorTable[992];
const char* text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, a1 != 0 ? 110 : 109);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "[ %s %.2d: ]", text, index + 1);
2022-05-19 01:51:26 -07:00
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * y + 55, _str, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, color);
y += fontGetLineHeight();
switch (_LSstatus[index]) {
case SLOT_STATE_OCCUPIED:
strcpy(_str, _LSData[index].description);
break;
case SLOT_STATE_EMPTY:
// - EMPTY -
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 111);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), " %s", text);
2022-05-19 01:51:26 -07:00
break;
case SLOT_STATE_ERROR:
// - CORRUPT SAVE FILE -
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 112);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s", text);
2022-05-19 01:51:26 -07:00
color = _colorTable[32328];
break;
case SLOT_STATE_UNSUPPORTED_VERSION:
// - OLD VERSION -
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 113);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), " %s", text);
2022-05-19 01:51:26 -07:00
color = _colorTable[32328];
break;
}
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * y + 55, _str, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, color);
y += 2 * fontGetLineHeight() + 4;
}
}
// 0x47E8E0
2022-06-19 04:07:58 -07:00
static void _DrawInfoBox(int a1)
2022-05-19 01:51:26 -07:00
{
blitBufferToBuffer(_loadsaveFrmImages[LOAD_SAVE_FRM_BACKGROUND].getData() + LS_WINDOW_WIDTH * 254 + 396, 164, 60, LS_WINDOW_WIDTH, gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 254 + 396, 640);
2022-05-19 01:51:26 -07:00
unsigned char* dest;
const char* text;
int color = _colorTable[992];
switch (_LSstatus[a1]) {
case SLOT_STATE_OCCUPIED:
do {
STRUCT_613D30* ptr = &(_LSData[a1]);
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 254 + 396, ptr->character_name, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, color);
int v4 = ptr->field_70 / 600;
int v5 = v4 % 60;
int v6 = 25 * (v4 / 60 % 24);
int v21 = 4 * v6 + v5;
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 116 + ptr->field_68);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%.2d %s %.4d %.4d", ptr->field_6A, text, ptr->field_6C, v21);
2022-05-19 01:51:26 -07:00
int v2 = fontGetLineHeight();
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * (256 + v2) + 397, _str, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, color);
const char* v22 = mapGetName(ptr->field_76, ptr->field_74);
const char* v9 = mapGetCityName(ptr->field_76);
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s %s", v9, v22);
2022-05-19 01:51:26 -07:00
int y = v2 + 3 + v2 + 256;
short beginnings[WORD_WRAP_MAX_COUNT];
short count;
if (wordWrap(_str, 164, beginnings, &count) == 0) {
for (int index = 0; index < count - 1; index += 1) {
char* beginning = _str + beginnings[index];
char* ending = _str + beginnings[index + 1];
char c = *ending;
*ending = '\0';
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * y + 399, beginning, 164, LS_WINDOW_WIDTH, color);
y += v2 + 2;
}
}
} while (0);
return;
case SLOT_STATE_EMPTY:
// Empty.
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 114);
dest = gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 262 + 404;
break;
case SLOT_STATE_ERROR:
// Error!
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 115);
dest = gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 262 + 404;
color = _colorTable[32328];
break;
case SLOT_STATE_UNSUPPORTED_VERSION:
// Old version.
text = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 116);
dest = gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * 262 + 400;
color = _colorTable[32328];
break;
default:
assert(false && "Should be unreachable");
}
fontDrawText(dest, text, LS_WINDOW_WIDTH, LS_WINDOW_WIDTH, color);
}
// 0x47EC48
2022-06-19 04:07:58 -07:00
static int _LoadTumbSlot(int a1)
2022-05-19 01:51:26 -07:00
{
File* stream;
int v2;
v2 = _LSstatus[_slot_cursor];
if (v2 != 0 && v2 != 2 && v2 != 3) {
2022-12-08 12:05:50 -08:00
snprintf(_str, sizeof(_str), "%s\\%s%.2d\\%s", "SAVEGAME", "SLOT", _slot_cursor + 1, "SAVE.DAT");
2022-05-19 01:51:26 -07:00
debugPrint(" Filename %s\n", _str);
stream = fileOpen(_str, "rb");
if (stream == NULL) {
debugPrint("\nLOADSAVE: ** (A) Error reading thumbnail #%d! **\n", a1);
return -1;
}
if (fileSeek(stream, 131, SEEK_SET) != 0) {
debugPrint("\nLOADSAVE: ** (B) Error reading thumbnail #%d! **\n", a1);
fileClose(stream);
return -1;
}
if (fileRead(_thumbnail_image, LS_PREVIEW_SIZE, 1, stream) != 1) {
debugPrint("\nLOADSAVE: ** (C) Error reading thumbnail #%d! **\n", a1);
fileClose(stream);
return -1;
}
fileClose(stream);
}
return 0;
}
// 0x47ED5C
2022-06-19 04:07:58 -07:00
static int _GetComment(int a1)
2022-05-19 01:51:26 -07:00
{
// Maintain original position in original resolution, otherwise center it.
int commentWindowX = screenGetWidth() != 640
? (screenGetWidth() - _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth()) / 2
: LS_COMMENT_WINDOW_X;
int commentWindowY = screenGetHeight() != 480
? (screenGetHeight() - _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getHeight()) / 2
: LS_COMMENT_WINDOW_Y;
int window = windowCreate(commentWindowX,
commentWindowY,
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getHeight(),
2022-05-19 01:51:26 -07:00
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
if (window == -1) {
return -1;
}
unsigned char* windowBuffer = windowGetBuffer(window);
memcpy(windowBuffer,
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getHeight() * _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth());
2022-05-19 01:51:26 -07:00
fontSetCurrent(103);
const char* msg;
// DONE
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 104);
fontDrawText(windowBuffer + _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth() * 57 + 56,
2022-05-19 01:51:26 -07:00
msg,
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
2022-05-19 01:51:26 -07:00
_colorTable[18979]);
// CANCEL
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 105);
fontDrawText(windowBuffer + _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth() * 57 + 181,
2022-05-19 01:51:26 -07:00
msg,
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
2022-05-19 01:51:26 -07:00
_colorTable[18979]);
// DESCRIPTION
msg = getmsg(&gLoadSaveMessageList, &gLoadSaveMessageListItem, 130);
char title[260];
strcpy(title, msg);
int width = fontGetStringWidth(title);
fontDrawText(windowBuffer + _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth() * 7 + (_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth() - width) / 2,
2022-05-19 01:51:26 -07:00
title,
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth(),
2022-05-19 01:51:26 -07:00
_colorTable[18979]);
fontSetCurrent(101);
int btn;
// DONE
btn = buttonCreate(window,
34,
58,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
-1,
-1,
507,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn == -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
// CANCEL
btn = buttonCreate(window,
160,
58,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getWidth(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
-1,
-1,
508,
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_NORMAL].getData(),
_loadsaveFrmImages[LOAD_SAVE_FRM_RED_BUTTON_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn == -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
windowRefresh(window);
char description[LOAD_SAVE_DESCRIPTION_LENGTH];
if (_LSstatus[_slot_cursor] == SLOT_STATE_OCCUPIED) {
strncpy(description, _LSData[a1].description, LOAD_SAVE_DESCRIPTION_LENGTH);
} else {
memset(description, '\0', LOAD_SAVE_DESCRIPTION_LENGTH);
}
int rc;
int backgroundColor = *(_loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getData() + _loadsaveFrmImages[LOAD_SAVE_FRM_BOX].getWidth() * 35 + 24);
if (_get_input_str2(window, 507, 508, description, LOAD_SAVE_DESCRIPTION_LENGTH - 1, 24, 35, _colorTable[992], backgroundColor, 0) == 0) {
2022-05-19 01:51:26 -07:00
strncpy(_LSData[a1].description, description, LOAD_SAVE_DESCRIPTION_LENGTH);
_LSData[a1].description[LOAD_SAVE_DESCRIPTION_LENGTH - 1] = '\0';
rc = 1;
} else {
rc = 0;
}
windowDestroy(window);
return rc;
}
// 0x47F084
2022-06-19 04:07:58 -07:00
static int _get_input_str2(int win, int doneKeyCode, int cancelKeyCode, char* description, int maxLength, int x, int y, int textColor, int backgroundColor, int flags)
2022-05-19 01:51:26 -07:00
{
int cursorWidth = fontGetStringWidth("_") - 4;
int windowWidth = windowGetWidth(win);
int lineHeight = fontGetLineHeight();
unsigned char* windowBuffer = windowGetBuffer(win);
if (maxLength > 255) {
maxLength = 255;
}
char text[256];
strcpy(text, description);
2022-08-31 08:52:01 -07:00
size_t textLength = strlen(text);
2022-05-19 01:51:26 -07:00
text[textLength] = ' ';
text[textLength + 1] = '\0';
int nameWidth = fontGetStringWidth(text);
bufferFill(windowBuffer + windowWidth * y + x, nameWidth, lineHeight, windowWidth, backgroundColor);
fontDrawText(windowBuffer + windowWidth * y + x, text, windowWidth, windowWidth, textColor);
windowRefresh(win);
2022-10-07 14:54:27 -07:00
renderPresent();
2022-05-19 01:51:26 -07:00
2022-12-08 09:41:59 -08:00
beginTextInput();
2022-05-19 01:51:26 -07:00
int blinkCounter = 3;
bool blink = false;
int v1 = 0;
int rc = 1;
while (rc == 1) {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
2022-10-05 00:11:47 -07:00
int tick = getTicks();
2022-05-19 01:51:26 -07:00
2022-10-05 00:11:47 -07:00
int keyCode = inputGetInput();
2022-05-19 01:51:26 -07:00
if ((keyCode & 0x80000000) == 0) {
v1++;
}
if (keyCode == doneKeyCode || keyCode == KEY_RETURN) {
rc = 0;
} else if (keyCode == cancelKeyCode || keyCode == KEY_ESCAPE) {
rc = -1;
} else {
if ((keyCode == KEY_DELETE || keyCode == KEY_BACKSPACE) && textLength > 0) {
bufferFill(windowBuffer + windowWidth * y + x, fontGetStringWidth(text), lineHeight, windowWidth, backgroundColor);
// TODO: Probably incorrect, needs testing.
if (v1 == 1) {
textLength = 1;
}
text[textLength - 1] = ' ';
text[textLength] = '\0';
fontDrawText(windowBuffer + windowWidth * y + x, text, windowWidth, windowWidth, textColor);
textLength--;
} else if ((keyCode >= KEY_FIRST_INPUT_CHARACTER && keyCode <= KEY_LAST_INPUT_CHARACTER) && textLength < maxLength) {
if ((flags & 0x01) != 0) {
if (!_isdoschar(keyCode)) {
break;
}
}
bufferFill(windowBuffer + windowWidth * y + x, fontGetStringWidth(text), lineHeight, windowWidth, backgroundColor);
text[textLength] = keyCode & 0xFF;
text[textLength + 1] = ' ';
text[textLength + 2] = '\0';
fontDrawText(windowBuffer + windowWidth * y + x, text, windowWidth, windowWidth, textColor);
textLength++;
windowRefresh(win);
}
}
blinkCounter -= 1;
if (blinkCounter == 0) {
blinkCounter = 3;
blink = !blink;
int color = blink ? backgroundColor : textColor;
bufferFill(windowBuffer + windowWidth * y + x + fontGetStringWidth(text) - cursorWidth, cursorWidth, lineHeight - 2, windowWidth, color);
windowRefresh(win);
}
while (getTicksSince(tick) < 1000 / 24) {
}
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
2022-05-19 01:51:26 -07:00
}
2022-12-08 09:41:59 -08:00
endTextInput();
2022-05-19 01:51:26 -07:00
if (rc == 0) {
text[textLength] = '\0';
strcpy(description, text);
}
return rc;
}
// 0x47F48C
2022-06-19 04:07:58 -07:00
static int _DummyFunc(File* stream)
2022-05-19 01:51:26 -07:00
{
return 0;
}
// 0x47F490
2022-06-19 04:07:58 -07:00
static int _PrepLoad(File* stream)
2022-05-19 01:51:26 -07:00
{
gameReset();
gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET);
gMapHeader.name[0] = '\0';
gameTimeSetTime(_LSData[_slot_cursor].field_70);
return 0;
}
// 0x47F4C8
2022-06-19 04:07:58 -07:00
static int _EndLoad(File* stream)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmMapMusicStart();
2022-05-19 01:51:26 -07:00
dudeSetName(_LSData[_slot_cursor].character_name);
interfaceBarRefresh();
indicatorBarRefresh();
tileWindowRefresh();
if (isInCombat()) {
scriptsRequestCombat(NULL);
}
return 0;
}
// 0x47F510
2022-06-19 04:07:58 -07:00
static int _GameMap2Slot(File* stream)
2022-05-19 01:51:26 -07:00
{
if (_partyMemberPrepSave() == -1) {
return -1;
}
if (_map_save_in_game(false) == -1) {
return -1;
}
for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) {
int pid = gPartyMemberPids[index];
if (pid == -2) {
continue;
}
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
if (_proto_list_str(pid, path) != 0) {
continue;
}
const char* critterItemPath = (pid >> 24) == OBJ_TYPE_CRITTER
? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME
: PROTO_DIR_NAME "\\" ITEMS_DIR_NAME;
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s", _patches, critterItemPath, path);
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, critterItemPath, path);
2022-05-19 01:51:26 -07:00
if (fileCopyCompressed(_str0, _str1) == -1) {
return -1;
}
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\*.%s", "MAPS", "SAV");
2022-05-19 01:51:26 -07:00
char** fileNameList;
int fileNameListLength = fileNameListInit(_str0, &fileNameList, 0, 0);
if (fileNameListLength == -1) {
return -1;
}
if (fileWriteInt32(stream, fileNameListLength) == -1) {
fileNameListFree(&fileNameList, 0);
return -1;
}
if (fileNameListLength == 0) {
fileNameListFree(&fileNameList, 0);
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
if (_MapDirErase(_gmpath, "SAV") == -1) {
fileNameListFree(&fileNameList, 0);
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
_strmfe(_str0, "AUTOMAP.DB", "SAV");
strcat(_gmpath, _str0);
compat_remove(_gmpath);
2022-05-19 01:51:26 -07:00
for (int index = 0; index < fileNameListLength; index += 1) {
char* string = fileNameList[index];
if (fileWrite(string, strlen(string) + 1, 1, stream) == -1) {
fileNameListFree(&fileNameList, 0);
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s", _patches, "MAPS", string);
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, string);
2022-05-19 01:51:26 -07:00
if (fileCopyCompressed(_str0, _str1) == -1) {
fileNameListFree(&fileNameList, 0);
return -1;
}
}
fileNameListFree(&fileNameList, 0);
_strmfe(_str0, "AUTOMAP.DB", "SAV");
2022-12-08 12:05:50 -08:00
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, _str0);
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB");
2022-05-19 01:51:26 -07:00
if (fileCopyCompressed(_str0, _str1) == -1) {
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s", "MAPS", "AUTOMAP.DB");
2022-05-19 01:51:26 -07:00
File* inStream = fileOpen(_str0, "rb");
if (inStream == NULL) {
return -1;
}
int fileSize = fileGetSize(inStream);
if (fileSize == -1) {
fileClose(inStream);
return -1;
}
fileClose(inStream);
if (fileWriteInt32(stream, fileSize) == -1) {
return -1;
}
if (_partyMemberUnPrepSave() == -1) {
return -1;
}
return 0;
}
// SlotMap2Game
// 0x47F990
2022-06-19 04:07:58 -07:00
static int _SlotMap2Game(File* stream)
2022-05-19 01:51:26 -07:00
{
debugPrint("LOADSAVE: in SlotMap2Game\n");
2022-10-29 11:27:08 -07:00
int fileNameListLength;
if (fileReadInt32(stream, &fileNameListLength) == -1) {
2022-05-19 01:51:26 -07:00
debugPrint("LOADSAVE: returning 1\n");
return -1;
}
2022-10-29 11:27:08 -07:00
if (fileNameListLength == 0) {
2022-05-19 01:51:26 -07:00
debugPrint("LOADSAVE: returning 2\n");
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\", PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME);
2022-05-19 01:51:26 -07:00
if (_MapDirErase(_str0, PROTO_FILE_EXT) == -1) {
2022-05-19 01:51:26 -07:00
debugPrint("LOADSAVE: returning 3\n");
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\", PROTO_DIR_NAME "\\" ITEMS_DIR_NAME);
if (_MapDirErase(_str0, PROTO_FILE_EXT) == -1) {
2022-05-19 01:51:26 -07:00
debugPrint("LOADSAVE: returning 4\n");
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\", "MAPS");
2022-05-19 01:51:26 -07:00
if (_MapDirErase(_str0, "SAV") == -1) {
debugPrint("LOADSAVE: returning 5\n");
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB");
compat_remove(_str0);
2022-05-19 01:51:26 -07:00
2022-10-29 11:27:08 -07:00
for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) {
int pid = gPartyMemberPids[index];
if (pid != -2) {
char protoPath[COMPAT_MAX_PATH];
if (_proto_list_str(pid, protoPath) == 0) {
const char* basePath = PID_TYPE(pid) == OBJ_TYPE_CRITTER
? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME
: PROTO_DIR_NAME "\\" ITEMS_DIR_NAME;
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s", _patches, basePath, protoPath);
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath);
2022-10-29 11:27:08 -07:00
if (_gzdecompress_file(_str1, _str0) == -1) {
debugPrint("LOADSAVE: returning 6\n");
return -1;
2022-05-19 01:51:26 -07:00
}
}
}
}
2022-10-29 11:27:08 -07:00
for (int index = 0; index < fileNameListLength; index += 1) {
char fileName[COMPAT_MAX_PATH];
if (_mygets(fileName, stream) == -1) {
break;
}
2022-05-19 01:51:26 -07:00
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, fileName);
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s", _patches, "MAPS", fileName);
2022-05-19 01:51:26 -07:00
2022-10-29 11:27:08 -07:00
if (_gzdecompress_file(_str0, _str1) == -1) {
debugPrint("LOADSAVE: returning 7\n");
return -1;
2022-05-19 01:51:26 -07:00
}
}
2022-10-29 11:27:08 -07:00
const char* automapFileName = _strmfe(_str1, "AUTOMAP.DB", "SAV");
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, automapFileName);
snprintf(_str1, sizeof(_str1), "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB");
2022-05-19 01:51:26 -07:00
if (fileCopyDecompressed(_str0, _str1) == -1) {
debugPrint("LOADSAVE: returning 8\n");
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_str1, sizeof(_str1), "%s\\%s", "MAPS", "AUTOMAP.DB");
2022-05-19 01:51:26 -07:00
int v12;
if (fileReadInt32(stream, &v12) == -1) {
debugPrint("LOADSAVE: returning 9\n");
return -1;
}
if (mapLoadSaved(_LSData[_slot_cursor].file_name) == -1) {
debugPrint("LOADSAVE: returning 13\n");
return -1;
}
return 0;
}
// 0x47FE14
2022-06-19 04:07:58 -07:00
static int _mygets(char* dest, File* stream)
2022-05-19 01:51:26 -07:00
{
int index = 14;
while (true) {
int c = fileReadChar(stream);
if (c == -1) {
return -1;
}
index -= 1;
*dest = c & 0xFF;
dest += 1;
if (index == -1 || c == '\0') {
break;
}
}
if (index == 0) {
return -1;
}
return 0;
}
// 0x47FE58
2022-06-19 04:07:58 -07:00
static int _copy_file(const char* a1, const char* a2)
2022-05-19 01:51:26 -07:00
{
File* stream1;
File* stream2;
int length;
int chunk_length;
void* buf;
int result;
stream1 = NULL;
stream2 = NULL;
buf = NULL;
result = -1;
stream1 = fileOpen(a1, "rb");
if (stream1 == NULL) {
goto out;
}
length = fileGetSize(stream1);
if (length == -1) {
goto out;
}
stream2 = fileOpen(a2, "wb");
if (stream2 == NULL) {
goto out;
}
buf = internal_malloc(0xFFFF);
if (buf == NULL) {
goto out;
}
while (length != 0) {
2022-05-28 04:45:48 -07:00
chunk_length = std::min(length, 0xFFFF);
2022-05-19 01:51:26 -07:00
if (fileRead(buf, chunk_length, 1, stream1) != 1) {
break;
}
if (fileWrite(buf, chunk_length, 1, stream2) != 1) {
break;
}
length -= chunk_length;
}
if (length != 0) {
goto out;
}
result = 0;
out:
if (stream1 != NULL) {
fileClose(stream1);
}
if (stream2 != NULL) {
fileClose(stream1);
}
if (buf != NULL) {
internal_free(buf);
}
return result;
}
// InitLoadSave
// 0x48000C
void lsgInit()
{
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s\\", "MAPS");
2022-05-19 01:51:26 -07:00
_MapDirErase(path, "SAV");
}
// 0x480040
2022-06-19 04:07:58 -07:00
static int _MapDirErase(const char* relativePath, const char* extension)
2022-05-19 01:51:26 -07:00
{
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s*.%s", relativePath, extension);
2022-05-19 01:51:26 -07:00
char** fileList;
int fileListLength = fileNameListInit(path, &fileList, 0, 0);
while (--fileListLength >= 0) {
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s\\%s%s", _patches, relativePath, fileList[fileListLength]);
compat_remove(path);
2022-05-19 01:51:26 -07:00
}
fileNameListFree(&fileList, 0);
return 0;
}
// 0x4800C8
int _MapDirEraseFile_(const char* a1, const char* a2)
{
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s\\%s%s", _patches, a1, a2);
if (compat_remove(path) != 0) {
2022-05-19 01:51:26 -07:00
return -1;
}
return 0;
}
// 0x480104
2022-06-19 04:07:58 -07:00
static int _SaveBackup()
2022-05-19 01:51:26 -07:00
{
debugPrint("\nLOADSAVE: Backing up save slot files..\n");
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcpy(_str0, _gmpath);
strcat(_str0, "SAVE.DAT");
_strmfe(_str1, _str0, "BAK");
File* stream1 = fileOpen(_str0, "rb");
if (stream1 != NULL) {
fileClose(stream1);
if (compat_rename(_str0, _str1) != 0) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
snprintf(_str0, sizeof(_str0), "%s*.%s", _gmpath, "SAV");
2022-05-19 01:51:26 -07:00
char** fileList;
int fileListLength = fileNameListInit(_str0, &fileList, 0, 0);
if (fileListLength == -1) {
return -1;
}
_map_backup_count = fileListLength;
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
for (int index = fileListLength - 1; index >= 0; index--) {
strcpy(_str0, _gmpath);
strcat(_str0, fileList[index]);
_strmfe(_str1, _str0, "BAK");
if (compat_rename(_str0, _str1) != 0) {
2022-05-19 01:51:26 -07:00
fileNameListFree(&fileList, 0);
return -1;
}
}
fileNameListFree(&fileList, 0);
debugPrint("\nLOADSAVE: %d map files backed up.\n", fileListLength);
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
char* v1 = _strmfe(_str2, "AUTOMAP.DB", "SAV");
2022-12-08 12:05:50 -08:00
snprintf(_str0, sizeof(_str0), "%s\\%s", _gmpath, v1);
2022-05-19 01:51:26 -07:00
char* v2 = _strmfe(_str2, "AUTOMAP.DB", "BAK");
2022-12-08 12:05:50 -08:00
snprintf(_str1, sizeof(_str1), "%s\\%s", _gmpath, v2);
2022-05-19 01:51:26 -07:00
_automap_db_flag = 0;
File* stream2 = fileOpen(_str0, "rb");
if (stream2 != NULL) {
fileClose(stream2);
if (_copy_file(_str0, _str1) == -1) {
return -1;
}
_automap_db_flag = 1;
}
return 0;
}
// 0x4803D8
2022-06-19 04:07:58 -07:00
static int _RestoreSave()
2022-05-19 01:51:26 -07:00
{
debugPrint("\nLOADSAVE: Restoring save file backup...\n");
_EraseSave();
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcpy(_str0, _gmpath);
strcat(_str0, "SAVE.DAT");
_strmfe(_str1, _str0, "BAK");
compat_remove(_str0);
2022-05-19 01:51:26 -07:00
if (compat_rename(_str1, _str0) != 0) {
2022-05-19 01:51:26 -07:00
_EraseSave();
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
snprintf(_str0, sizeof(_str0), "%s*.%s", _gmpath, "BAK");
2022-05-19 01:51:26 -07:00
char** fileList;
int fileListLength = fileNameListInit(_str0, &fileList, 0, 0);
if (fileListLength == -1) {
return -1;
}
if (fileListLength != _map_backup_count) {
// FIXME: Probably leaks fileList.
_EraseSave();
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
for (int index = fileListLength - 1; index >= 0; index--) {
strcpy(_str0, _gmpath);
strcat(_str0, fileList[index]);
_strmfe(_str1, _str0, "SAV");
compat_remove(_str1);
if (compat_rename(_str0, _str1) != 0) {
2022-05-19 01:51:26 -07:00
// FIXME: Probably leaks fileList.
_EraseSave();
return -1;
}
}
fileNameListFree(&fileList, 0);
if (!_automap_db_flag) {
return 0;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
char* v1 = _strmfe(_str2, "AUTOMAP.DB", "BAK");
strcpy(_str0, _gmpath);
strcat(_str0, v1);
char* v2 = _strmfe(_str2, "AUTOMAP.DB", "SAV");
strcpy(_str1, _gmpath);
strcat(_str1, v2);
if (compat_rename(_str0, _str1) != 0) {
2022-05-19 01:51:26 -07:00
_EraseSave();
return -1;
}
return 0;
}
// 0x480710
2022-06-19 04:07:58 -07:00
static int _LoadObjDudeCid(File* stream)
2022-05-19 01:51:26 -07:00
{
int value;
if (fileReadInt32(stream, &value) == -1) {
return -1;
}
gDude->cid = value;
return 0;
}
// 0x480734
2022-06-19 04:07:58 -07:00
static int _SaveObjDudeCid(File* stream)
2022-05-19 01:51:26 -07:00
{
return fileWriteInt32(stream, gDude->cid);
}
// 0x480754
2022-06-19 04:07:58 -07:00
static int _EraseSave()
2022-05-19 01:51:26 -07:00
{
debugPrint("\nLOADSAVE: Erasing save(bad) slot...\n");
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
strcpy(_str0, _gmpath);
strcat(_str0, "SAVE.DAT");
compat_remove(_str0);
2022-05-19 01:51:26 -07:00
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s%.2d\\", "SAVEGAME", "SLOT", _slot_cursor + 1);
snprintf(_str0, sizeof(_str0), "%s*.%s", _gmpath, "SAV");
2022-05-19 01:51:26 -07:00
char** fileList;
int fileListLength = fileNameListInit(_str0, &fileList, 0, 0);
if (fileListLength == -1) {
return -1;
}
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
for (int index = fileListLength - 1; index >= 0; index--) {
strcpy(_str0, _gmpath);
strcat(_str0, fileList[index]);
compat_remove(_str0);
2022-05-19 01:51:26 -07:00
}
fileNameListFree(&fileList, 0);
2022-12-08 12:05:50 -08:00
snprintf(_gmpath, sizeof(_gmpath), "%s\\%s\\%s%.2d\\", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1);
2022-05-19 01:51:26 -07:00
char* v1 = _strmfe(_str1, "AUTOMAP.DB", "SAV");
strcpy(_str0, _gmpath);
strcat(_str0, v1);
compat_remove(_str0);
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-23 05:43:44 -07:00
} // namespace fallout