Skip to content

Commit 4d948f8

Browse files
committed
First implementation of saving/loading menu
1 parent a4cfcbb commit 4d948f8

File tree

8 files changed

+267
-19
lines changed

8 files changed

+267
-19
lines changed

Menus/MainMenuGUI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define _RTEMAINMENUGUI_
33

44
#include "Controller.h"
5+
6+
#include "SaveLoadMenuGUI.h"
57
#include "SettingsGUI.h"
68
#include "ModManagerGUI.h"
79

Menus/PauseMenuGUI.cpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "UInputMan.h"
88
#include "SettingsMan.h"
99

10+
#include "SaveLoadMenuGUI.h"
1011
#include "SettingsGUI.h"
1112
#include "ModManagerGUI.h"
1213

@@ -30,6 +31,7 @@ namespace RTE {
3031
m_UpdateResult = PauseMenuUpdateResult::NoEvent;
3132
m_ResumeButtonBlinkTimer.Reset();
3233

34+
m_SaveLoadMenu = nullptr;
3335
m_SettingsMenu = nullptr;
3436
m_ModManagerMenu = nullptr;
3537

@@ -60,8 +62,7 @@ namespace RTE {
6062
m_PauseMenuBox->CenterInParent(true, true);
6163

6264
m_PauseMenuButtons[PauseMenuButton::BackToMainButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonBackToMain"));
63-
m_PauseMenuButtons[PauseMenuButton::SaveGameButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonSaveGame"));
64-
m_PauseMenuButtons[PauseMenuButton::LoadLastSaveButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonLoadLastSave"));
65+
m_PauseMenuButtons[PauseMenuButton::SaveOrLoadGameButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonSaveOrLoadGame"));
6566
m_PauseMenuButtons[PauseMenuButton::SettingsButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonSettings"));
6667
m_PauseMenuButtons[PauseMenuButton::ModManagerButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonModManager"));
6768
m_PauseMenuButtons[PauseMenuButton::ResumeButton] = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonResume"));
@@ -84,6 +85,7 @@ namespace RTE {
8485
const BITMAP *backbuffer = g_FrameMan.GetBackBuffer32();
8586
m_BackdropBitmap = create_bitmap_ex(FrameMan::c_BPP, backbuffer->w, backbuffer->h);
8687

88+
m_SaveLoadMenu = std::make_unique<SaveLoadMenuGUI>(guiScreen, guiInput, true);
8789
m_SettingsMenu = std::make_unique<SettingsGUI>(guiScreen, guiInput, true);
8890
m_ModManagerMenu = std::make_unique<ModManagerGUI>(guiScreen, guiInput, true);
8991
}
@@ -119,7 +121,7 @@ namespace RTE {
119121
if (m_SavingButtonsDisabled != disableSaving) {
120122
int yOffset = 0;
121123

122-
for (size_t pauseMenuButton = PauseMenuButton::SaveGameButton; pauseMenuButton < PauseMenuButton::SettingsButton; ++pauseMenuButton) {
124+
for (size_t pauseMenuButton = PauseMenuButton::SaveOrLoadGameButton; pauseMenuButton < PauseMenuButton::SettingsButton; ++pauseMenuButton) {
123125
m_PauseMenuButtons[pauseMenuButton]->SetEnabled(!disableSaving);
124126
m_PauseMenuButtons[pauseMenuButton]->SetVisible(!disableSaving);
125127
yOffset += m_PauseMenuButtons[pauseMenuButton]->GetHeight();
@@ -183,6 +185,9 @@ namespace RTE {
183185
backToMainScreen = HandleInputEvents();
184186
BlinkResumeButton();
185187
break;
188+
case PauseMenuScreen::SaveOrLoadGameScreen:
189+
backToMainScreen = m_SaveLoadMenu->HandleInputEvents();
190+
break;
186191
case PauseMenuScreen::SettingsScreen:
187192
backToMainScreen = m_SettingsMenu->HandleInputEvents();
188193
m_ActiveDialogBox = m_SettingsMenu->GetActiveDialogBox();
@@ -236,20 +241,8 @@ namespace RTE {
236241
if (guiEvent.GetType() == GUIEvent::Command) {
237242
if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::ResumeButton]) {
238243
return true;
239-
} else if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::SaveGameButton]) {
240-
if (g_ActivityMan.GetActivityAllowsSaving() && g_ActivityMan.SaveCurrentGame("QuickSave")) {
241-
g_GUISound.ConfirmSound()->Play();
242-
return true;
243-
} else {
244-
g_GUISound.UserErrorSound()->Play();
245-
}
246-
} else if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::LoadLastSaveButton]) {
247-
if (g_ActivityMan.LoadAndLaunchGame("QuickSave")) {
248-
g_GUISound.ConfirmSound()->Play();
249-
return true;
250-
} else {
251-
g_GUISound.UserErrorSound()->Play();
252-
}
244+
} else if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::SaveOrLoadGameButton]) {
245+
SetActiveMenuScreen(PauseMenuScreen::SaveOrLoadGameScreen);
253246
} else if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::SettingsButton]) {
254247
SetActiveMenuScreen(PauseMenuScreen::SettingsScreen);
255248
} else if (guiEvent.GetControl() == m_PauseMenuButtons[PauseMenuButton::ModManagerButton]) {
@@ -304,6 +297,9 @@ namespace RTE {
304297
blit(m_BackdropBitmap, g_FrameMan.GetBackBuffer32(), 0, 0, 0, 0, m_BackdropBitmap->w, m_BackdropBitmap->h);
305298

306299
switch (m_ActiveMenuScreen) {
300+
case PauseMenuScreen::SaveOrLoadGameScreen:
301+
m_SaveLoadMenu->Draw();
302+
break;
307303
case PauseMenuScreen::SettingsScreen:
308304
m_SettingsMenu->Draw();
309305
break;

Menus/PauseMenuGUI.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace RTE {
1414
class GUIButton;
1515
class SettingsGUI;
1616
class ModManagerGUI;
17+
class SaveLoadMenuGUI;
1718

1819
/// <summary>
1920
/// Handling for the pause menu screen composition and interaction.
@@ -85,6 +86,7 @@ namespace RTE {
8586
/// </summary>
8687
enum PauseMenuScreen {
8788
MainScreen,
89+
SaveOrLoadGameScreen,
8890
SettingsScreen,
8991
ModManagerScreen,
9092
ScreenCount
@@ -95,8 +97,7 @@ namespace RTE {
9597
/// </summary>
9698
enum PauseMenuButton {
9799
BackToMainButton,
98-
SaveGameButton,
99-
LoadLastSaveButton,
100+
SaveOrLoadGameButton,
100101
SettingsButton,
101102
ModManagerButton,
102103
ResumeButton,
@@ -118,6 +119,7 @@ namespace RTE {
118119

119120
Timer m_ResumeButtonBlinkTimer; //!< Activity resume button blink timer.
120121

122+
std::unique_ptr<SaveLoadMenuGUI> m_SaveLoadMenu; //!< The settings menu screen.
121123
std::unique_ptr<SettingsGUI> m_SettingsMenu; //!< The settings menu screen.
122124
std::unique_ptr<ModManagerGUI> m_ModManagerMenu; //!< The mod manager menu screen.
123125

Menus/SaveLoadMenuGUI.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include "SaveLoadMenuGUI.h"
2+
3+
#include "ActivityMan.h"
4+
#include "PresetMan.h"
5+
#include "WindowMan.h"
6+
7+
#include "GUI.h"
8+
#include "AllegroScreen.h"
9+
#include "GUIInputWrapper.h"
10+
#include "GUICollectionBox.h"
11+
#include "GUILabel.h"
12+
#include "GUIButton.h"
13+
#include "GUIListBox.h"
14+
#include "GUITextBox.h"
15+
16+
namespace RTE {
17+
18+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
19+
20+
SaveLoadMenuGUI::SaveLoadMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu) {
21+
m_GUIControlManager = std::make_unique<GUIControlManager>();
22+
RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini");
23+
m_GUIControlManager->Load("Base.rte/GUIs/SaveLoadMenuGUI.ini");
24+
25+
int rootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX();
26+
27+
GUICollectionBox *rootBox = dynamic_cast<GUICollectionBox *>(m_GUIControlManager->GetControl("root"));
28+
rootBox->Resize(rootBoxMaxWidth, g_WindowMan.GetResY());
29+
30+
GUICollectionBox *saveGameMenuBox = dynamic_cast<GUICollectionBox *>(m_GUIControlManager->GetControl("CollectionBoxSaveGameMenu"));
31+
saveGameMenuBox->CenterInParent(true, true);
32+
saveGameMenuBox->SetPositionAbs(saveGameMenuBox->GetXPos(), (rootBox->GetHeight() < 540) ? saveGameMenuBox->GetYPos() - 15 : 140);
33+
34+
m_BackToMainButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonBackToMainMenu"));
35+
36+
if (createForPauseMenu) {
37+
m_BackToMainButton->SetSize(120, 20);
38+
m_BackToMainButton->SetText("Back to Pause Menu");
39+
}
40+
m_BackToMainButton->SetPositionAbs((rootBox->GetWidth() - m_BackToMainButton->GetWidth()) / 2, saveGameMenuBox->GetYPos() + saveGameMenuBox->GetHeight() + 10);
41+
42+
m_SaveGamesListBox = dynamic_cast<GUIListBox *>(m_GUIControlManager->GetControl("ListBoxSaveGames"));
43+
m_SaveGamesListBox->SetMouseScrolling(true);
44+
m_SaveGamesListBox->SetScrollBarThickness(15);
45+
m_SaveGamesListBox->SetScrollBarPadding(2);
46+
47+
m_SaveGameName = dynamic_cast<GUITextBox *>(m_GUIControlManager->GetControl("SaveGameName"));
48+
m_LoadButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonLoad"));
49+
m_CreateButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonCreate"));
50+
m_DescriptionLabel = dynamic_cast<GUILabel *>(m_GUIControlManager->GetControl("LabelDescription"));
51+
52+
m_SaveGamesFetched = false;
53+
}
54+
55+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56+
57+
void SaveLoadMenuGUI::PopulateSaveGamesList() {
58+
m_SaveGames.clear();
59+
m_SaveGamesListBox->ClearList();
60+
61+
std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/";
62+
for (const auto &entry : std::filesystem::directory_iterator(saveFilePath)) {
63+
if (entry.path().extension() == ".ini" && entry.path().filename() != "Index.ini") {
64+
SaveRecord record;
65+
record.SaveName = entry.path().stem().string();
66+
record.SaveDate = entry.last_write_time();
67+
m_SaveGames.push_back(record);
68+
}
69+
}
70+
71+
std::sort(m_SaveGames.begin(), m_SaveGames.end());
72+
73+
for (int i = 0; i < m_SaveGames.size(); i++) {
74+
m_SaveGamesListBox->AddItem(m_SaveGames.at(i).SaveName, std::string(), nullptr, nullptr, i);
75+
}
76+
77+
m_SaveGamesListBox->ScrollToTop();
78+
m_SaveGamesFetched = true;
79+
}
80+
81+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
82+
83+
void SaveLoadMenuGUI::LoadSave() {
84+
bool success = g_ActivityMan.LoadAndLaunchGame(m_SaveGameName->GetText());
85+
if (success) {
86+
g_GUISound.ConfirmSound()->Play();
87+
} else {
88+
g_GUISound.UserErrorSound()->Play();
89+
}
90+
}
91+
92+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93+
94+
void SaveLoadMenuGUI::CreateSave() {
95+
bool success = g_ActivityMan.SaveCurrentGame(m_SaveGameName->GetText());
96+
if (success) {
97+
g_GUISound.ConfirmSound()->Play();
98+
} else {
99+
g_GUISound.UserErrorSound()->Play();
100+
}
101+
PopulateSaveGamesList();
102+
}
103+
104+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
105+
106+
bool SaveLoadMenuGUI::HandleInputEvents() {
107+
if (!ListsFetched()) {
108+
PopulateSaveGamesList();
109+
}
110+
m_GUIControlManager->Update();
111+
112+
GUIEvent guiEvent;
113+
while (m_GUIControlManager->GetEvent(&guiEvent)) {
114+
if (guiEvent.GetType() == GUIEvent::Command) {
115+
if (guiEvent.GetControl() == m_BackToMainButton) {
116+
return true;
117+
} else if (guiEvent.GetControl() == m_LoadButton) {
118+
LoadSave();
119+
} else if (guiEvent.GetControl() == m_CreateButton) {
120+
CreateSave();
121+
}
122+
} else if (guiEvent.GetType() == GUIEvent::Notification) {
123+
if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast<GUIButton *>(guiEvent.GetControl())) {
124+
g_GUISound.SelectionChangeSound()->Play();
125+
}
126+
127+
if (guiEvent.GetControl() == m_SaveGamesListBox && (guiEvent.GetMsg() == GUIListBox::Select && m_SaveGamesListBox->GetSelectedIndex() > -1)) {
128+
const SaveRecord &record = m_SaveGames.at(m_SaveGamesListBox->GetSelected()->m_ExtraIndex);
129+
//m_DescriptionLabel->SetText(record.GetDisplayString());
130+
m_SaveGameName->SetText(record.SaveName);
131+
}
132+
}
133+
}
134+
return false;
135+
}
136+
137+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138+
139+
void SaveLoadMenuGUI::Draw() const {
140+
m_GUIControlManager->Draw();
141+
}
142+
}

Menus/SaveLoadMenuGUI.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#ifndef _RTESAVELOADMENUGUI_
2+
#define _RTESAVELOADMENUGUI_
3+
4+
#include <filesystem>
5+
6+
namespace RTE {
7+
8+
class AllegroScreen;
9+
class GUIInputWrapper;
10+
class GUIControlManager;
11+
class GUILabel;
12+
class GUIButton;
13+
class GUIListBox;
14+
class GUITextBox;
15+
16+
/// <summary>
17+
/// Integrated savegame user interface composition and handling.
18+
/// </summary>
19+
class SaveLoadMenuGUI {
20+
21+
public:
22+
23+
#pragma region Creation
24+
/// <summary>
25+
/// Constructor method used to instantiate a SaveLoadMenuGUI object in system memory and make it ready for use.
26+
/// </summary>
27+
/// <param name="guiScreen">Pointer to a GUIScreen interface that will be used by this SaveLoadMenuGUI's GUIControlManager. Ownership is NOT transferred!</param>
28+
/// <param name="guiInput">Pointer to a GUIInput interface that will be used by this SaveLoadMenuGUI's GUIControlManager. Ownership is NOT transferred!</param>
29+
/// <param name="createForPauseMenu">Whether this SettingsGUI is part of SaveLoadMenuGUI and should have a slightly different layout.</param>
30+
SaveLoadMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu = false);
31+
#pragma endregion
32+
33+
#pragma region Concrete Methods
34+
/// <summary>
35+
/// Handles the player interaction with the SaveLoadMenuGUI GUI elements.
36+
/// </summary>
37+
/// <returns>Whether the player requested to return to the main menu.</returns>
38+
bool HandleInputEvents();
39+
40+
/// <summary>
41+
/// Draws the SaveLoadMenuGUI to the screen.
42+
/// </summary>
43+
void Draw() const;
44+
#pragma endregion
45+
46+
private:
47+
/// <summary>
48+
/// Struct containing information about a valid Savegame.
49+
/// </summary>
50+
struct SaveRecord {
51+
std::string SaveName; //!< Savegame name.
52+
std::filesystem::file_time_type SaveDate; //!< Savegame last modified date.
53+
54+
bool operator<(const SaveRecord &rhs) const { return SaveDate > rhs.SaveDate; }
55+
};
56+
57+
std::unique_ptr<GUIControlManager> m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of the SaveLoadMenuGUI.
58+
59+
std::vector<SaveRecord> m_SaveGames; //!< Contains all SaveGames.
60+
61+
bool m_SaveGamesFetched; //!< Whether the savegames list has been fetched.
62+
63+
/// <summary>
64+
/// GUI elements that compose the Mod Manager menu screen.
65+
/// </summary>
66+
GUIButton *m_BackToMainButton;
67+
GUITextBox *m_SaveGameName;
68+
GUIButton *m_LoadButton;
69+
GUIButton *m_CreateButton;
70+
GUIListBox *m_SaveGamesListBox;
71+
GUILabel *m_DescriptionLabel;
72+
73+
#pragma region Mod and Script Handling
74+
/// <summary>
75+
/// Gets whether both lists were fetched, even if nothing valid was added to them.
76+
/// </summary>
77+
/// <returns>Whether both lists were fetched, even if nothing valid was added to them.</returns>
78+
bool ListsFetched() const { return m_SaveGamesFetched; }
79+
80+
/// <summary>
81+
/// Fills the SaveGames list with all valid savegames, then fills the SaveGamesListBox using it.
82+
/// </summary>
83+
void PopulateSaveGamesList();
84+
85+
/// <summary>
86+
/// Loads the currently selected savefile.
87+
/// </summary>
88+
void LoadSave();
89+
90+
/// <summary>
91+
/// Creates a new savefile (or overwrites the existing one) with the name from the textbox.
92+
/// </summary>
93+
void CreateSave();
94+
#pragma endregion
95+
96+
// Disallow the use of some implicit methods.
97+
SaveLoadMenuGUI(const SaveLoadMenuGUI &reference) = delete;
98+
SaveLoadMenuGUI & operator=(const SaveLoadMenuGUI &rhs) = delete;
99+
};
100+
}
101+
#endif

Menus/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ sources += files(
1111
'ModManagerGUI.cpp',
1212
'ObjectPickerGUI.cpp',
1313
'PauseMenuGUI.cpp',
14+
'SaveLoadMenuGUI.cpp',
1415
'ScenarioActivityConfigGUI.cpp',
1516
'ScenarioGUI.cpp',
1617
'SceneEditorGUI.cpp',

RTEA.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@
608608
<ClInclude Include="Menus\LoadingScreen.h" />
609609
<ClInclude Include="Menus\ModManagerGUI.h" />
610610
<ClInclude Include="Menus\PauseMenuGUI.h" />
611+
<ClInclude Include="Menus\SaveLoadMenuGUI.h" />
611612
<ClInclude Include="Menus\ScenarioActivityConfigGUI.h" />
612613
<ClInclude Include="Menus\SettingsAudioGUI.h" />
613614
<ClInclude Include="Menus\SettingsGameplayGUI.h" />
@@ -844,6 +845,7 @@
844845
<ClCompile Include="Menus\LoadingScreen.cpp" />
845846
<ClCompile Include="Menus\ModManagerGUI.cpp" />
846847
<ClCompile Include="Menus\PauseMenuGUI.cpp" />
848+
<ClCompile Include="Menus\SaveLoadMenuGUI.cpp" />
847849
<ClCompile Include="Menus\ScenarioActivityConfigGUI.cpp" />
848850
<ClCompile Include="Menus\SettingsAudioGUI.cpp" />
849851
<ClCompile Include="Menus\SettingsGameplayGUI.cpp" />

0 commit comments

Comments
 (0)