From f04a18f208d93fadd4ea22d0e2e865ee14fc1f6f Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Sat, 19 Apr 2025 21:52:45 +0200 Subject: [PATCH] tr2/ui: port save/load dialog to ui --- data/tr2/ship/cfg/TR2X_strings.json5 | 2 +- docs/tr2/CHANGELOG.md | 1 + src/tr2/game/game_string.def | 2 +- src/tr2/game/option/option_passport.c | 141 +++++++++++++------- src/tr2/game/savegame.h | 1 - src/tr2/game/savegame/common.c | 28 ---- src/tr2/game/shell/common.c | 1 - src/tr2/game/ui/dialogs/save_slot.c | 177 ++++++++++++++++++++++++++ src/tr2/game/ui/dialogs/save_slot.h | 34 +++++ src/tr2/global/vars.c | 39 ------ src/tr2/global/vars.h | 1 - src/tr2/meson.build | 1 + 12 files changed, 311 insertions(+), 117 deletions(-) create mode 100644 src/tr2/game/ui/dialogs/save_slot.c create mode 100644 src/tr2/game/ui/dialogs/save_slot.h diff --git a/data/tr2/ship/cfg/TR2X_strings.json5 b/data/tr2/ship/cfg/TR2X_strings.json5 index 02080ac0a..0fbca703e 100644 --- a/data/tr2/ship/cfg/TR2X_strings.json5 +++ b/data/tr2/ship/cfg/TR2X_strings.json5 @@ -535,7 +535,7 @@ "KEYMAP_USE_FLARE": "Flare", "KEYMAP_WALK": "Walk", "MISC_DEMO_MODE": "Demo Mode", - "MISC_EMPTY_SLOT": "- EMPTY SLOT -", + "MISC_EMPTY_SLOT_FMT": "- EMPTY SLOT -", "MISC_EXIT": "Exit", "MISC_NONE": "None", "MISC_OFF": "Off", diff --git a/docs/tr2/CHANGELOG.md b/docs/tr2/CHANGELOG.md index e83a6723c..5601ba34d 100644 --- a/docs/tr2/CHANGELOG.md +++ b/docs/tr2/CHANGELOG.md @@ -19,6 +19,7 @@ - changed the maximum number of items (moveables) per level from 256 to 10240 (1024 remains the limit for triggered items) (#1794) - changed the maximum number of visible enemies from 5 to 32 (#1624) - changed the maximum number of effects (flames, embers, exploding parts etc) from 100 to 1000 (#1581) +- changed default pitch of the save/load dialog ingame - it's now higher. - fixed the inability to completely mute the sounds, even at sound volume 0 (#2722) - fixed the final two levels not allowing for secrets to be counted in the statistics (#1582) - fixed Lara's holsters being empty if a game flow level removes all weapons but also re-adds the pistols (#2677) diff --git a/src/tr2/game/game_string.def b/src/tr2/game/game_string.def index 6c4ac4e2f..1103d5e7a 100644 --- a/src/tr2/game/game_string.def +++ b/src/tr2/game/game_string.def @@ -29,7 +29,7 @@ GS_DEFINE(STATS_ASSAULT_NO_TIMES_SET, "No Times Set") GS_DEFINE(STATS_ASSAULT_FINISH, "Finish") GS_DEFINE(PASSPORT_EXIT_DEMO, "Exit Demo") GS_DEFINE(MISC_NONE, "None") -GS_DEFINE(MISC_EMPTY_SLOT, "- EMPTY SLOT -") +GS_DEFINE(MISC_EMPTY_SLOT_FMT, "- EMPTY SLOT -") GS_DEFINE(OSD_BILINEAR_FILTER_ON, "Bilinear filter: on") GS_DEFINE(OSD_BILINEAR_FILTER_OFF, "Bilinear filter: off") GS_DEFINE(OSD_WIREFRAME_MODE_ON, "Wireframe mode: on") diff --git a/src/tr2/game/option/option_passport.c b/src/tr2/game/option/option_passport.c index c961774b3..6f1a73a13 100644 --- a/src/tr2/game/option/option_passport.c +++ b/src/tr2/game/option/option_passport.c @@ -9,6 +9,7 @@ #include "game/savegame.h" #include "game/sound.h" #include "game/text.h" +#include "game/ui/dialogs/save_slot.h" #include "global/vars.h" #include @@ -39,11 +40,14 @@ static struct { int32_t active_page; int32_t selection; M_PAGE pages[3]; - bool page_ready; + bool is_ready; struct { bool is_ready; UI_NEW_GAME_STATE state; } new_game; + struct { + UI_SAVE_SLOT_DIALOG_STATE *state; + } save_slot; } m_State = { .active_page = -1 }; TEXTSTRING *m_SubtitleText = nullptr; @@ -54,11 +58,15 @@ static void M_InitRequesters(void); static void M_FreeRequesters(void); static void M_DeterminePages(void); static void M_RemoveAllText(void); +static void M_InitSaveRequester(M_PAGE_ROLE page_role); +static void M_ShowSaves(INVENTORY_ITEM *inv_item); +static void M_LoadGame(INVENTORY_ITEM *inv_item); +static void M_SaveGame(INVENTORY_ITEM *inv_item); static void M_NewGame(void); static void M_FlipLeft(INVENTORY_ITEM *inv_item); static void M_FlipRight(INVENTORY_ITEM *inv_item); static void M_Close(INVENTORY_ITEM *inv_item); -static void M_ShowPage(const INVENTORY_ITEM *inv_item); +static void M_ShowPage(INVENTORY_ITEM *inv_item); static void M_HandleFlipInputs(void); static void M_ChangePageTextContent(const char *const title) @@ -86,6 +94,7 @@ static void M_FreeRequesters(void) { UI_NewGame_Free(&m_State.new_game.state); m_State.new_game.is_ready = false; + m_State.is_ready = false; } static void M_DeterminePages(void) @@ -175,17 +184,76 @@ static void M_DeterminePages(void) static void M_RemoveAllText(void) { - if (g_LoadGameRequester.ready) { - Requester_Shutdown(&g_LoadGameRequester); + if (m_SubtitleText != nullptr) { + Text_Remove(m_SubtitleText); + m_SubtitleText = nullptr; + } + if (m_State.save_slot.state != nullptr) { + UI_SaveSlotDialog_Free(m_State.save_slot.state); + m_State.save_slot.state = nullptr; } if (g_SaveGameRequester.ready) { Requester_Shutdown(&g_SaveGameRequester); } M_FreeRequesters(); - if (m_SubtitleText != nullptr) { - Text_Remove(m_SubtitleText); - m_SubtitleText = nullptr; +} + +static void M_InitSaveRequester(const M_PAGE_ROLE role) +{ + int32_t save_slot = Savegame_GetMostRecentlyUsedSlot(); + if (save_slot == -1) { + save_slot = Savegame_GetMostRecentlyCreatedSlot(); } + + const UI_SAVE_SLOT_DIALOG_TYPE dialog_type = role == M_ROLE_LOAD_GAME + ? UI_SAVE_SLOT_DIALOG_LOAD_GAME + : UI_SAVE_SLOT_DIALOG_SAVE_GAME; + m_State.save_slot.state = UI_SaveSlotDialog_Init(dialog_type, save_slot); +} + +static void M_ShowSaves(INVENTORY_ITEM *const inv_item) +{ + if (m_State.save_slot.state == nullptr) { + M_InitSaveRequester(m_State.pages[m_State.active_page].role); + } + const UI_SAVE_SLOT_DIALOG_CHOICE choice = + UI_SaveSlotDialog_Control(m_State.save_slot.state); + switch (choice.action) { + case UI_SAVE_SLOT_DIALOG_NO_CHOICE: + // prevent propagating confirmation input up + if (g_Input.menu_confirm) { + g_Input = (INPUT_STATE) {}; + g_InputDB = (INPUT_STATE) {}; + } + break; + + case UI_SAVE_SLOT_DIALOG_CANCEL: + if (g_Inv_Mode != INV_SAVE_MODE && g_Inv_Mode != INV_LOAD_MODE) { + M_Close(inv_item); + } + break; + + case UI_SAVE_SLOT_DIALOG_DETAILS: + g_Input = (INPUT_STATE) {}; + g_InputDB = (INPUT_STATE) {}; + break; + + case UI_SAVE_SLOT_DIALOG_CONFIRM: + m_State.selection = choice.slot_num; + break; + } +} + +static void M_LoadGame(INVENTORY_ITEM *const inv_item) +{ + M_ChangePageTextContent(GS(PASSPORT_LOAD_GAME)); + M_ShowSaves(inv_item); +} + +static void M_SaveGame(INVENTORY_ITEM *const inv_item) +{ + M_ChangePageTextContent(GS(PASSPORT_SAVE_GAME)); + M_ShowSaves(inv_item); } static void M_NewGame(void) @@ -251,6 +319,7 @@ static void M_FlipRight(INVENTORY_ITEM *const inv_item) static void M_Close(INVENTORY_ITEM *const inv_item) { + m_State.active_page = -1; M_RemoveAllText(); if (m_State.current_page == 2) { inv_item->anim_direction = 1; @@ -261,41 +330,20 @@ static void M_Close(INVENTORY_ITEM *const inv_item) } } -static void M_ShowPage(const INVENTORY_ITEM *const inv_item) +static void M_ShowPage(INVENTORY_ITEM *const inv_item) { switch (m_State.pages[m_State.active_page].role) { case M_ROLE_LOAD_GAME: - M_ChangePageTextContent(GS(PASSPORT_LOAD_GAME)); - - if (!g_LoadGameRequester.ready) { - Savegame_FillAvailableSaves(&g_LoadGameRequester); - Requester_SetHeading( - &g_LoadGameRequester, GS(PASSPORT_LOAD_GAME), 0, nullptr, 0); - Requester_SetSize(&g_LoadGameRequester, 10, -32); - g_LoadGameRequester.ready = true; - } - m_State.selection = - Requester_Display(&g_LoadGameRequester, false, true) - 1; - if (m_State.selection >= 0 && Savegame_IsSlotFree(m_State.selection)) { - m_State.selection = -1; - g_Input = (INPUT_STATE) {}; - g_InputDB = (INPUT_STATE) {}; - } + M_LoadGame(inv_item); break; - case M_ROLE_SAVE_GAME: { - M_ChangePageTextContent(GS(PASSPORT_SAVE_GAME)); - - if (!g_LoadGameRequester.ready) { - Requester_SetHeading( - &g_LoadGameRequester, GS(PASSPORT_SAVE_GAME), 0, nullptr, 0); - Requester_SetSize(&g_LoadGameRequester, 10, -32); - g_LoadGameRequester.ready = true; - } - m_State.selection = - Requester_Display(&g_LoadGameRequester, true, true) - 1; + case M_ROLE_SAVE_GAME: + M_SaveGame(inv_item); + break; + + case M_ROLE_NEW_GAME: + M_NewGame(); break; - } case M_ROLE_PLAY_ANY_LEVEL: { if (!g_SaveGameRequester.ready) { @@ -307,10 +355,6 @@ static void M_ShowPage(const INVENTORY_ITEM *const inv_item) break; } - case M_ROLE_NEW_GAME: - M_NewGame(); - break; - case M_ROLE_EXIT: if (g_Inv_Mode == INV_TITLE_MODE) { M_ChangePageTextContent(GS(PASSPORT_EXIT_GAME)); @@ -371,19 +415,18 @@ void Option_Passport_Control(INVENTORY_ITEM *const item, const bool is_busy) } else if (m_State.current_page > m_State.active_page) { M_FlipLeft(item); } else { + m_State.is_ready = true; M_ShowPage(item); if (g_InputDB.menu_confirm) { g_Inv_ExtraData[0] = m_State.active_page; g_Inv_ExtraData[1] = m_State.selection; - m_State.active_page = -1; M_Close(item); } else if (g_InputDB.menu_back) { - if (g_Inv_Mode != INV_DEATH_MODE) { - m_State.active_page = -1; - M_Close(item); - } else { + if (g_Inv_Mode == INV_DEATH_MODE) { g_Input = (INPUT_STATE) {}; g_InputDB = (INPUT_STATE) {}; + } else { + M_Close(item); } } else { M_HandleFlipInputs(); @@ -399,6 +442,14 @@ void Option_Passport_Draw(INVENTORY_ITEM *const item) UI_NewGame(&m_State.new_game.state); } break; + + case M_ROLE_LOAD_GAME: + case M_ROLE_SAVE_GAME: + if (m_State.is_ready && m_State.save_slot.state != nullptr) { + UI_SaveSlotDialog(m_State.save_slot.state); + } + break; + default: break; } diff --git a/src/tr2/game/savegame.h b/src/tr2/game/savegame.h index fcd5755d5..d55ec2bd6 100644 --- a/src/tr2/game/savegame.h +++ b/src/tr2/game/savegame.h @@ -4,5 +4,4 @@ #include -void Savegame_FillAvailableSaves(REQUEST_INFO *req); void Savegame_FillAvailableLevels(REQUEST_INFO *req); diff --git a/src/tr2/game/savegame/common.c b/src/tr2/game/savegame/common.c index 199cdfb56..45f7623e3 100644 --- a/src/tr2/game/savegame/common.c +++ b/src/tr2/game/savegame/common.c @@ -25,7 +25,6 @@ void Savegame_HighlightNewestSlot(void) { const int32_t slot = Savegame_GetMostRecentlyCreatedSlot(); g_SaveGameRequester.selected = MAX(0, slot); - g_LoadGameRequester.selected = MAX(0, slot); } void Savegame_ApplyLogicToCurrentInfo(const GF_LEVEL *const level) @@ -139,33 +138,6 @@ void Savegame_ApplyLogicToCurrentInfo(const GF_LEVEL *const level) resume->stats.max_secret_count = default_stats.max_secret_count; } -void Savegame_FillAvailableSaves(REQUEST_INFO *const req) -{ - Requester_Init(req); - - for (int32_t i = 0; i < MAX_SAVE_SLOTS; i++) { - const SAVEGAME_INFO *const savegame_info = Savegame_GetSavegameInfo(i); - if (savegame_info->level_title != nullptr) { - char save_num_text[16]; - sprintf(save_num_text, "%d", savegame_info->counter); - Requester_AddItem( - req, savegame_info->level_title, REQ_ALIGN_LEFT, save_num_text, - REQ_ALIGN_RIGHT); - } else { - Requester_AddItem(req, GS(MISC_EMPTY_SLOT), 0, 0, 0); - } - } - - Requester_SetSize(req, 10, -32); - if (req->selected >= req->visible_count) { - req->line_offset = req->selected - req->visible_count + 1; - } else if (req->selected < req->line_offset) { - req->line_offset = req->selected; - } - memcpy(m_ReqFlags1, g_RequesterFlags1, sizeof(m_ReqFlags1)); - memcpy(m_ReqFlags2, g_RequesterFlags2, sizeof(m_ReqFlags2)); -} - void Savegame_FillAvailableLevels(REQUEST_INFO *const req) { ASSERT(req != nullptr); diff --git a/src/tr2/game/shell/common.c b/src/tr2/game/shell/common.c index 75d013521..16d23027e 100644 --- a/src/tr2/game/shell/common.c +++ b/src/tr2/game/shell/common.c @@ -441,7 +441,6 @@ void Shell_Main(void) Savegame_Init(); Savegame_InitCurrentInfo(); Savegame_ScanSavedGames(); - Savegame_FillAvailableSaves(&g_LoadGameRequester); Savegame_HighlightNewestSlot(); if (m_Args.level_to_play != nullptr) { diff --git a/src/tr2/game/ui/dialogs/save_slot.c b/src/tr2/game/ui/dialogs/save_slot.c new file mode 100644 index 000000000..a5eaec78a --- /dev/null +++ b/src/tr2/game/ui/dialogs/save_slot.c @@ -0,0 +1,177 @@ +#include "game/ui/dialogs/save_slot.h" + +#include "game/inventory_ring/vars.h" +#include "game/scaler.h" +#include "global/vars.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct UI_SAVE_SLOT_DIALOG_STATE { + UI_SAVE_SLOT_DIALOG_TYPE type; + UI_REQUESTER_STATE req; +} UI_SAVE_SLOT_DIALOG_STATE; + +static int32_t M_GetVisibleRows(void); +static bool M_ShowDetails(const UI_SAVE_SLOT_DIALOG_STATE *s, int32_t slot_idx); +static void M_NonEmptySlot( + const UI_SAVE_SLOT_DIALOG_STATE *s, int32_t slot_idx, + const SAVEGAME_INFO *info); +static void M_EmptySlot(const UI_SAVE_SLOT_DIALOG_STATE *s, int32_t slot_idx); + +static int32_t M_GetVisibleRows(void) +{ + return 10; +} + +static bool M_ShowDetails( + const UI_SAVE_SLOT_DIALOG_STATE *const s, const int32_t slot_idx) +{ + return false; +} + +static void M_NonEmptySlot( + const UI_SAVE_SLOT_DIALOG_STATE *const s, const int32_t slot_idx, + const SAVEGAME_INFO *const info) +{ + const bool show_details = M_ShowDetails(s, slot_idx); + + if (show_details) { + UI_BeginStackEx((UI_STACK_SETTINGS) { + .orientation = UI_STACK_HORIZONTAL, + .align = { .h = UI_STACK_H_ALIGN_DISTRIBUTE }, + }); + // Balance both sides so that the row text appears centered + UI_BeginHide(true); + UI_Label("\\{button right}"); + UI_EndHide(); + } else { + UI_BeginStackEx((UI_STACK_SETTINGS) { + .orientation = UI_STACK_HORIZONTAL, + .align = { .h = UI_STACK_H_ALIGN_DISTRIBUTE }, + }); + } + + // Level title with the save counter + UI_Label(info->level_title); + if (info->counter > 0) { + UI_Spacer(8.0f, 0.0f); + char buf[16]; + sprintf(buf, "%d", info->counter); + UI_Label(buf); + } + + if (show_details) { + UI_BeginOffset(0.0f, -1.0f); + UI_Label("\\{button right}"); + UI_EndOffset(); + UI_EndStack(); + } else { + UI_EndStack(); + } +} + +static void M_EmptySlot( + const UI_SAVE_SLOT_DIALOG_STATE *const s, const int32_t slot_idx) +{ + char buf[16]; + sprintf(buf, GS(MISC_EMPTY_SLOT_FMT), slot_idx + 1); + UI_BeginAnchor(0.5f, 0.5f); + UI_Label(buf); + UI_EndAnchor(); +} + +UI_SAVE_SLOT_DIALOG_STATE *UI_SaveSlotDialog_Init( + const UI_SAVE_SLOT_DIALOG_TYPE type, const int32_t save_slot) +{ + UI_SAVE_SLOT_DIALOG_STATE *const s = + Memory_Alloc(sizeof(UI_SAVE_SLOT_DIALOG_STATE)); + s->type = type; + + UI_Requester_Init( + &s->req, M_GetVisibleRows(), Savegame_GetSlotCount(), true); + s->req.row_pad = 2.0f; + s->req.row_spacing = 2.0f; + s->req.show_arrows = false; + s->req.reserve_space = true; + s->req.sel_row = save_slot; + CLAMP(s->req.sel_row, 0, s->req.max_rows); + return s; +} + +void UI_SaveSlotDialog_Free(UI_SAVE_SLOT_DIALOG_STATE *const s) +{ + UI_Requester_Free(&s->req); +} + +UI_SAVE_SLOT_DIALOG_CHOICE UI_SaveSlotDialog_Control( + UI_SAVE_SLOT_DIALOG_STATE *const s) +{ + UI_Requester_SetVisibleRows(&s->req, M_GetVisibleRows()); + const int32_t sel_row = UI_Requester_GetCurrentRow(&s->req); + if (M_ShowDetails(s, sel_row) && g_InputDB.menu_right) { + return (UI_SAVE_SLOT_DIALOG_CHOICE) { + .action = UI_SAVE_SLOT_DIALOG_DETAILS, + .slot_num = sel_row, + }; + } + const int32_t choice = UI_Requester_Control(&s->req); + if (choice == UI_REQUESTER_CANCEL) { + return (UI_SAVE_SLOT_DIALOG_CHOICE) { + .action = UI_SAVE_SLOT_DIALOG_CANCEL, + }; + } else if ( + choice != UI_REQUESTER_NO_CHOICE + && (s->type == UI_SAVE_SLOT_DIALOG_SAVE_GAME + || !Savegame_IsSlotFree(choice))) { + return (UI_SAVE_SLOT_DIALOG_CHOICE) { + .action = UI_SAVE_SLOT_DIALOG_CONFIRM, + .slot_num = sel_row, + }; + } + return (UI_SAVE_SLOT_DIALOG_CHOICE) { + .action = UI_SAVE_SLOT_DIALOG_NO_CHOICE, + }; +} + +void UI_SaveSlotDialog(const UI_SAVE_SLOT_DIALOG_STATE *const s) +{ + UI_BeginModal(0.5f, g_Inv_Mode == INV_TITLE_MODE ? 0.8f : 0.63f); + UI_BeginResize(300.0f, -1.0f); + + const char *const title = (s->type == UI_SAVE_SLOT_DIALOG_SAVE_GAME) + ? GS(PASSPORT_SAVE_GAME) + : GS(PASSPORT_LOAD_GAME); + UI_BeginRequester(&s->req, title); + + const int32_t first = UI_Requester_GetFirstRow(&s->req); + const int32_t last = UI_Requester_GetLastRow(&s->req); + for (int32_t i = first; i < last; ++i) { + UI_BeginRequesterRow(&s->req, i); + const SAVEGAME_INFO *const info = Savegame_GetSavegameInfo(i); + if (info != nullptr && info->level_title != nullptr) { + M_NonEmptySlot(s, i, info); + } else { + M_EmptySlot(s, i); + } + UI_EndRequesterRow(&s->req, i); + } + + UI_EndRequester(&s->req); + UI_EndResize(); + UI_EndModal(); +} diff --git a/src/tr2/game/ui/dialogs/save_slot.h b/src/tr2/game/ui/dialogs/save_slot.h new file mode 100644 index 000000000..0da67e0d1 --- /dev/null +++ b/src/tr2/game/ui/dialogs/save_slot.h @@ -0,0 +1,34 @@ +// UI dialog for selecting a save slot (load or save game) + +#pragma once + +#include + +typedef enum { + UI_SAVE_SLOT_DIALOG_LOAD_GAME, + UI_SAVE_SLOT_DIALOG_SAVE_GAME, +} UI_SAVE_SLOT_DIALOG_TYPE; + +typedef enum { + UI_SAVE_SLOT_DIALOG_NO_CHOICE, + UI_SAVE_SLOT_DIALOG_CANCEL, + UI_SAVE_SLOT_DIALOG_CONFIRM, + UI_SAVE_SLOT_DIALOG_DETAILS, +} UI_SAVE_SLOT_DIALOG_ACTION; + +typedef struct { + UI_SAVE_SLOT_DIALOG_ACTION action; + int32_t slot_num; +} UI_SAVE_SLOT_DIALOG_CHOICE; + +typedef struct UI_SAVE_SLOT_DIALOG_STATE UI_SAVE_SLOT_DIALOG_STATE; + +// state functions +struct UI_SAVE_SLOT_DIALOG_STATE *UI_SaveSlotDialog_Init( + UI_SAVE_SLOT_DIALOG_TYPE type, int32_t save_slot); +void UI_SaveSlotDialog_Free(struct UI_SAVE_SLOT_DIALOG_STATE *s); +UI_SAVE_SLOT_DIALOG_CHOICE UI_SaveSlotDialog_Control( + struct UI_SAVE_SLOT_DIALOG_STATE *s); + +// draw functions +void UI_SaveSlotDialog(const struct UI_SAVE_SLOT_DIALOG_STATE *s); diff --git a/src/tr2/global/vars.c b/src/tr2/global/vars.c index cdd9c71a1..91ca6283a 100644 --- a/src/tr2/global/vars.c +++ b/src/tr2/global/vars.c @@ -175,45 +175,6 @@ int16_t g_FinalBossItem[5]; static char m_LoadGameRequesterStrings1[MAX_LEVELS][50]; static char m_LoadGameRequesterStrings2[MAX_LEVELS][50]; -REQUEST_INFO g_LoadGameRequester = { - .no_selector = 0, - .ready = 0, - .pad = 0, - .items_count = 1, - .selected = 0, - .visible_count = 5, - .line_offset = 0, - .line_old_offset = 0, - .pix_width = 296, - .line_height = 18, - .x_pos = 0, - .y_pos = -32, - .z_pos = 0, - .item_string_len = 50, - .pitem_strings1 = (char *)m_LoadGameRequesterStrings1, - .pitem_strings2 = (char *)m_LoadGameRequesterStrings2, - .pitem_flags1 = nullptr, - .pitem_flags2 = nullptr, - .heading_flags1 = 0, - .heading_flags2 = 0, - .background_flags = 0, - .moreup_flags = 0, - .moredown_flags = 0, - .item_flags1 = {}, - .item_flags2 = {}, - .heading_text1 = nullptr, - .heading_text2 = nullptr, - .background_text = nullptr, - .moreup_text = nullptr, - .moredown_text = nullptr, - .item_texts1 = { nullptr }, - .item_texts2 = { nullptr }, - .heading_string1 = {}, - .heading_string2 = {}, - .render_width = 0, - .render_height = 0, -}; - REQUEST_INFO g_SaveGameRequester = { .no_selector = 0, .ready = 0, diff --git a/src/tr2/global/vars.h b/src/tr2/global/vars.h index af002cd67..6e058ba24 100644 --- a/src/tr2/global/vars.h +++ b/src/tr2/global/vars.h @@ -62,7 +62,6 @@ extern int16_t g_FinalBossActive; extern uint16_t g_FinalLevelCount; extern int16_t g_FinalBossCount; extern int16_t g_FinalBossItem[5]; -extern REQUEST_INFO g_LoadGameRequester; extern REQUEST_INFO g_SaveGameRequester; extern bool g_GF_RemoveAmmo; diff --git a/src/tr2/meson.build b/src/tr2/meson.build index 0ef24d53b..6a050e560 100644 --- a/src/tr2/meson.build +++ b/src/tr2/meson.build @@ -271,6 +271,7 @@ sources = [ 'game/text.c', 'game/ui/common.c', 'game/ui/dialogs/graphic_settings.c', + 'game/ui/dialogs/save_slot.c', 'game/ui/dialogs/stats.c', 'game/viewport.c', 'global/enum_map.c',