mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
tr2/ui: port save/load dialog to ui
This commit is contained in:
parent
ef72c674b3
commit
f04a18f208
12 changed files with 311 additions and 117 deletions
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
177
src/tr2/game/ui/dialogs/save_slot.c
Normal file
177
src/tr2/game/ui/dialogs/save_slot.c
Normal 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();
|
||||||
|
}
|
34
src/tr2/game/ui/dialogs/save_slot.h
Normal file
34
src/tr2/game/ui/dialogs/save_slot.h
Normal 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);
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue