tr2/ui: port save/load dialog to ui

This commit is contained in:
Marcin Kurczewski 2025-04-19 21:52:45 +02:00
parent ef72c674b3
commit f04a18f208
12 changed files with 311 additions and 117 deletions

View file

@ -535,7 +535,7 @@
"KEYMAP_USE_FLARE": "Flare", "KEYMAP_USE_FLARE": "Flare",
"KEYMAP_WALK": "Walk", "KEYMAP_WALK": "Walk",
"MISC_DEMO_MODE": "Demo Mode", "MISC_DEMO_MODE": "Demo Mode",
"MISC_EMPTY_SLOT": "- EMPTY SLOT -", "MISC_EMPTY_SLOT_FMT": "- EMPTY SLOT -",
"MISC_EXIT": "Exit", "MISC_EXIT": "Exit",
"MISC_NONE": "None", "MISC_NONE": "None",
"MISC_OFF": "Off", "MISC_OFF": "Off",

View file

@ -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 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 visible enemies from 5 to 32 (#1624)
- changed the maximum number of effects (flames, embers, exploding parts etc) from 100 to 1000 (#1581) - 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 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 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) - fixed Lara's holsters being empty if a game flow level removes all weapons but also re-adds the pistols (#2677)

View file

@ -29,7 +29,7 @@ GS_DEFINE(STATS_ASSAULT_NO_TIMES_SET, "No Times Set")
GS_DEFINE(STATS_ASSAULT_FINISH, "Finish") GS_DEFINE(STATS_ASSAULT_FINISH, "Finish")
GS_DEFINE(PASSPORT_EXIT_DEMO, "Exit Demo") GS_DEFINE(PASSPORT_EXIT_DEMO, "Exit Demo")
GS_DEFINE(MISC_NONE, "None") 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_ON, "Bilinear filter: on")
GS_DEFINE(OSD_BILINEAR_FILTER_OFF, "Bilinear filter: off") GS_DEFINE(OSD_BILINEAR_FILTER_OFF, "Bilinear filter: off")
GS_DEFINE(OSD_WIREFRAME_MODE_ON, "Wireframe mode: on") GS_DEFINE(OSD_WIREFRAME_MODE_ON, "Wireframe mode: on")

View file

@ -9,6 +9,7 @@
#include "game/savegame.h" #include "game/savegame.h"
#include "game/sound.h" #include "game/sound.h"
#include "game/text.h" #include "game/text.h"
#include "game/ui/dialogs/save_slot.h"
#include "global/vars.h" #include "global/vars.h"
#include <libtrx/config.h> #include <libtrx/config.h>
@ -39,11 +40,14 @@ static struct {
int32_t active_page; int32_t active_page;
int32_t selection; int32_t selection;
M_PAGE pages[3]; M_PAGE pages[3];
bool page_ready; bool is_ready;
struct { struct {
bool is_ready; bool is_ready;
UI_NEW_GAME_STATE state; UI_NEW_GAME_STATE state;
} new_game; } new_game;
struct {
UI_SAVE_SLOT_DIALOG_STATE *state;
} save_slot;
} m_State = { .active_page = -1 }; } m_State = { .active_page = -1 };
TEXTSTRING *m_SubtitleText = nullptr; TEXTSTRING *m_SubtitleText = nullptr;
@ -54,11 +58,15 @@ static void M_InitRequesters(void);
static void M_FreeRequesters(void); static void M_FreeRequesters(void);
static void M_DeterminePages(void); static void M_DeterminePages(void);
static void M_RemoveAllText(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_NewGame(void);
static void M_FlipLeft(INVENTORY_ITEM *inv_item); static void M_FlipLeft(INVENTORY_ITEM *inv_item);
static void M_FlipRight(INVENTORY_ITEM *inv_item); static void M_FlipRight(INVENTORY_ITEM *inv_item);
static void M_Close(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_HandleFlipInputs(void);
static void M_ChangePageTextContent(const char *const title) 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); UI_NewGame_Free(&m_State.new_game.state);
m_State.new_game.is_ready = false; m_State.new_game.is_ready = false;
m_State.is_ready = false;
} }
static void M_DeterminePages(void) static void M_DeterminePages(void)
@ -175,17 +184,76 @@ static void M_DeterminePages(void)
static void M_RemoveAllText(void) static void M_RemoveAllText(void)
{ {
if (g_LoadGameRequester.ready) { if (m_SubtitleText != nullptr) {
Requester_Shutdown(&g_LoadGameRequester); 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) { if (g_SaveGameRequester.ready) {
Requester_Shutdown(&g_SaveGameRequester); Requester_Shutdown(&g_SaveGameRequester);
} }
M_FreeRequesters(); 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) 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) static void M_Close(INVENTORY_ITEM *const inv_item)
{ {
m_State.active_page = -1;
M_RemoveAllText(); M_RemoveAllText();
if (m_State.current_page == 2) { if (m_State.current_page == 2) {
inv_item->anim_direction = 1; 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) { switch (m_State.pages[m_State.active_page].role) {
case M_ROLE_LOAD_GAME: case M_ROLE_LOAD_GAME:
M_ChangePageTextContent(GS(PASSPORT_LOAD_GAME)); M_LoadGame(inv_item);
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) {};
}
break; break;
case M_ROLE_SAVE_GAME: { case M_ROLE_SAVE_GAME:
M_ChangePageTextContent(GS(PASSPORT_SAVE_GAME)); M_SaveGame(inv_item);
break;
if (!g_LoadGameRequester.ready) {
Requester_SetHeading( case M_ROLE_NEW_GAME:
&g_LoadGameRequester, GS(PASSPORT_SAVE_GAME), 0, nullptr, 0); M_NewGame();
Requester_SetSize(&g_LoadGameRequester, 10, -32);
g_LoadGameRequester.ready = true;
}
m_State.selection =
Requester_Display(&g_LoadGameRequester, true, true) - 1;
break; break;
}
case M_ROLE_PLAY_ANY_LEVEL: { case M_ROLE_PLAY_ANY_LEVEL: {
if (!g_SaveGameRequester.ready) { if (!g_SaveGameRequester.ready) {
@ -307,10 +355,6 @@ static void M_ShowPage(const INVENTORY_ITEM *const inv_item)
break; break;
} }
case M_ROLE_NEW_GAME:
M_NewGame();
break;
case M_ROLE_EXIT: case M_ROLE_EXIT:
if (g_Inv_Mode == INV_TITLE_MODE) { if (g_Inv_Mode == INV_TITLE_MODE) {
M_ChangePageTextContent(GS(PASSPORT_EXIT_GAME)); 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) { } else if (m_State.current_page > m_State.active_page) {
M_FlipLeft(item); M_FlipLeft(item);
} else { } else {
m_State.is_ready = true;
M_ShowPage(item); M_ShowPage(item);
if (g_InputDB.menu_confirm) { if (g_InputDB.menu_confirm) {
g_Inv_ExtraData[0] = m_State.active_page; g_Inv_ExtraData[0] = m_State.active_page;
g_Inv_ExtraData[1] = m_State.selection; g_Inv_ExtraData[1] = m_State.selection;
m_State.active_page = -1;
M_Close(item); M_Close(item);
} else if (g_InputDB.menu_back) { } else if (g_InputDB.menu_back) {
if (g_Inv_Mode != INV_DEATH_MODE) { if (g_Inv_Mode == INV_DEATH_MODE) {
m_State.active_page = -1;
M_Close(item);
} else {
g_Input = (INPUT_STATE) {}; g_Input = (INPUT_STATE) {};
g_InputDB = (INPUT_STATE) {}; g_InputDB = (INPUT_STATE) {};
} else {
M_Close(item);
} }
} else { } else {
M_HandleFlipInputs(); M_HandleFlipInputs();
@ -399,6 +442,14 @@ void Option_Passport_Draw(INVENTORY_ITEM *const item)
UI_NewGame(&m_State.new_game.state); UI_NewGame(&m_State.new_game.state);
} }
break; 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: default:
break; break;
} }

View file

@ -4,5 +4,4 @@
#include <libtrx/game/savegame.h> #include <libtrx/game/savegame.h>
void Savegame_FillAvailableSaves(REQUEST_INFO *req);
void Savegame_FillAvailableLevels(REQUEST_INFO *req); void Savegame_FillAvailableLevels(REQUEST_INFO *req);

View file

@ -25,7 +25,6 @@ void Savegame_HighlightNewestSlot(void)
{ {
const int32_t slot = Savegame_GetMostRecentlyCreatedSlot(); const int32_t slot = Savegame_GetMostRecentlyCreatedSlot();
g_SaveGameRequester.selected = MAX(0, slot); g_SaveGameRequester.selected = MAX(0, slot);
g_LoadGameRequester.selected = MAX(0, slot);
} }
void Savegame_ApplyLogicToCurrentInfo(const GF_LEVEL *const level) 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; 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) void Savegame_FillAvailableLevels(REQUEST_INFO *const req)
{ {
ASSERT(req != nullptr); ASSERT(req != nullptr);

View file

@ -441,7 +441,6 @@ void Shell_Main(void)
Savegame_Init(); Savegame_Init();
Savegame_InitCurrentInfo(); Savegame_InitCurrentInfo();
Savegame_ScanSavedGames(); Savegame_ScanSavedGames();
Savegame_FillAvailableSaves(&g_LoadGameRequester);
Savegame_HighlightNewestSlot(); Savegame_HighlightNewestSlot();
if (m_Args.level_to_play != nullptr) { if (m_Args.level_to_play != nullptr) {

View file

@ -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 <libtrx/game/game_string.h>
#include <libtrx/game/input.h>
#include <libtrx/game/savegame.h>
#include <libtrx/game/ui/common.h>
#include <libtrx/game/ui/elements/anchor.h>
#include <libtrx/game/ui/elements/hide.h>
#include <libtrx/game/ui/elements/label.h>
#include <libtrx/game/ui/elements/modal.h>
#include <libtrx/game/ui/elements/offset.h>
#include <libtrx/game/ui/elements/requester.h>
#include <libtrx/game/ui/elements/resize.h>
#include <libtrx/game/ui/elements/spacer.h>
#include <libtrx/game/ui/elements/stack.h>
#include <libtrx/memory.h>
#include <stdio.h>
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();
}

View file

@ -0,0 +1,34 @@
// UI dialog for selecting a save slot (load or save game)
#pragma once
#include <libtrx/game/ui/common.h>
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);

View file

@ -175,45 +175,6 @@ int16_t g_FinalBossItem[5];
static char m_LoadGameRequesterStrings1[MAX_LEVELS][50]; static char m_LoadGameRequesterStrings1[MAX_LEVELS][50];
static char m_LoadGameRequesterStrings2[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 = { REQUEST_INFO g_SaveGameRequester = {
.no_selector = 0, .no_selector = 0,
.ready = 0, .ready = 0,

View file

@ -62,7 +62,6 @@ extern int16_t g_FinalBossActive;
extern uint16_t g_FinalLevelCount; extern uint16_t g_FinalLevelCount;
extern int16_t g_FinalBossCount; extern int16_t g_FinalBossCount;
extern int16_t g_FinalBossItem[5]; extern int16_t g_FinalBossItem[5];
extern REQUEST_INFO g_LoadGameRequester;
extern REQUEST_INFO g_SaveGameRequester; extern REQUEST_INFO g_SaveGameRequester;
extern bool g_GF_RemoveAmmo; extern bool g_GF_RemoveAmmo;

View file

@ -271,6 +271,7 @@ sources = [
'game/text.c', 'game/text.c',
'game/ui/common.c', 'game/ui/common.c',
'game/ui/dialogs/graphic_settings.c', 'game/ui/dialogs/graphic_settings.c',
'game/ui/dialogs/save_slot.c',
'game/ui/dialogs/stats.c', 'game/ui/dialogs/stats.c',
'game/viewport.c', 'game/viewport.c',
'global/enum_map.c', 'global/enum_map.c',