Skip to content

Commit dd02bc4

Browse files
committed
Lots of fixes and improvements. Added save menu to main menu. Lots of QoL fixes.
1 parent 65fef08 commit dd02bc4

File tree

6 files changed

+122
-16
lines changed

6 files changed

+122
-16
lines changed

Menus/MainMenuGUI.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace RTE {
3838
m_ResumeButtonBlinkTimer.Reset();
3939
m_CreditsScrollTimer.Reset();
4040

41+
m_SaveLoadMenu = nullptr;
4142
m_SettingsMenu = nullptr;
4243
m_ModManagerMenu = nullptr;
4344

@@ -81,6 +82,7 @@ namespace RTE {
8182
CreateCreditsScreen();
8283
CreateQuitScreen();
8384

85+
m_SaveLoadMenu = std::make_unique<SaveLoadMenuGUI>(guiScreen, guiInput);
8486
m_SettingsMenu = std::make_unique<SettingsGUI>(guiScreen, guiInput);
8587
m_ModManagerMenu = std::make_unique<ModManagerGUI>(guiScreen, guiInput);
8688

@@ -97,14 +99,15 @@ namespace RTE {
9799
m_MainMenuButtons[MenuButton::MetaGameButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMetaGame"));
98100
m_MainMenuButtons[MenuButton::ScenarioButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToSkirmish"));
99101
m_MainMenuButtons[MenuButton::MultiplayerButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMultiplayer"));
102+
m_MainMenuButtons[MenuButton::SaveOrLoadGameButton] = dynamic_cast<GUIButton*>(m_MainMenuScreenGUIControlManager->GetControl("ButtonSaveOrLoadGame"));
100103
m_MainMenuButtons[MenuButton::SettingsButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToOptions"));
101104
m_MainMenuButtons[MenuButton::ModManagerButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToModManager"));
102105
m_MainMenuButtons[MenuButton::EditorsButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToEditor"));
103106
m_MainMenuButtons[MenuButton::CreditsButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToCreds"));
104107
m_MainMenuButtons[MenuButton::QuitButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonQuit"));
105108
m_MainMenuButtons[MenuButton::ResumeButton] = dynamic_cast<GUIButton *>(m_MainMenuScreenGUIControlManager->GetControl("ButtonResume"));
106109

107-
for (int mainScreenButton = 0; mainScreenButton < 9; ++mainScreenButton) {
110+
for (int mainScreenButton = MenuButton::MetaGameButton; mainScreenButton <= MenuButton::ResumeButton; ++mainScreenButton) {
108111
m_MainMenuButtons.at(mainScreenButton)->CenterInParent(true, false);
109112
std::string buttonText = m_MainMenuButtons.at(mainScreenButton)->GetText();
110113
std::transform(buttonText.begin(), buttonText.end(), buttonText.begin(), ::toupper);
@@ -336,6 +339,9 @@ namespace RTE {
336339
if (m_MenuScreenChange) { ShowMetaGameNoticeScreen(); }
337340
backToMainMenu = HandleInputEvents();
338341
break;
342+
case MenuScreen::SaveOrLoadGameScreen:
343+
backToMainMenu = m_SaveLoadMenu->HandleInputEvents();
344+
break;
339345
case MenuScreen::SettingsScreen:
340346
backToMainMenu = m_SettingsMenu->HandleInputEvents();
341347
m_ActiveDialogBox = m_SettingsMenu->GetActiveDialogBox();
@@ -440,6 +446,8 @@ namespace RTE {
440446
m_UpdateResult = MainMenuUpdateResult::ActivityStarted;
441447
g_GUISound.BackButtonPressSound()->Play();
442448
g_ActivityMan.SetStartMultiplayerActivity();
449+
} else if (guiEventControl == m_MainMenuButtons[MenuButton::SaveOrLoadGameButton]) {
450+
SetActiveMenuScreen(MenuScreen::SaveOrLoadGameScreen);
443451
} else if (guiEventControl == m_MainMenuButtons[MenuButton::SettingsButton]) {
444452
SetActiveMenuScreen(MenuScreen::SettingsScreen);
445453
} else if (guiEventControl == m_MainMenuButtons[MenuButton::EditorsButton]) {
@@ -508,7 +516,7 @@ namespace RTE {
508516
void MainMenuGUI::UpdateMainScreenHoveredButton(const GUIButton *hoveredButton) {
509517
int hoveredButtonIndex = -1;
510518
if (hoveredButton) {
511-
hoveredButtonIndex = std::distance(m_MainMenuButtons.begin(), std::find(m_MainMenuButtons.begin(), m_MainMenuButtons.begin() + 8, hoveredButton));
519+
hoveredButtonIndex = std::distance(m_MainMenuButtons.begin(), std::find(m_MainMenuButtons.begin(), m_MainMenuButtons.end(), hoveredButton));
512520
if (hoveredButton != m_MainScreenHoveredButton) { m_MainMenuButtons.at(hoveredButtonIndex)->SetText(m_MainScreenButtonHoveredText.at(hoveredButtonIndex)); }
513521
m_MainScreenHoveredButton = m_MainMenuButtons.at(hoveredButtonIndex);
514522
}
@@ -529,6 +537,9 @@ namespace RTE {
529537
return;
530538
}
531539
switch (m_ActiveMenuScreen) {
540+
case MenuScreen::SaveOrLoadGameScreen:
541+
m_SaveLoadMenu->Draw();
542+
break;
532543
case MenuScreen::SettingsScreen:
533544
m_SettingsMenu->Draw();
534545
break;

Menus/MainMenuGUI.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ namespace RTE {
7575
enum MenuScreen {
7676
MainScreen,
7777
MetaGameNoticeScreen,
78+
SaveOrLoadGameScreen,
7879
SettingsScreen,
7980
ModManagerScreen,
8081
EditorScreen,
@@ -90,6 +91,7 @@ namespace RTE {
9091
MetaGameButton,
9192
ScenarioButton,
9293
MultiplayerButton,
94+
SaveOrLoadGameButton,
9395
SettingsButton,
9496
ModManagerButton,
9597
EditorsButton,
@@ -124,13 +126,14 @@ namespace RTE {
124126
Timer m_ResumeButtonBlinkTimer; //!< Activity resume button blink timer.
125127
Timer m_CreditsScrollTimer; //!< Credits scrolling timer.
126128

129+
std::unique_ptr<SaveLoadMenuGUI> m_SaveLoadMenu; //!< The save/load menu screen.
127130
std::unique_ptr<SettingsGUI> m_SettingsMenu; //!< The settings menu screen.
128131
std::unique_ptr<ModManagerGUI> m_ModManagerMenu; //!< The mod manager menu screen.
129132

130133
// TODO: Rework this hacky garbage implementation when setting button font at runtime without loading a different skin is fixed. Would eliminate the need for a second GUIControlManager as well.
131134
// Right now the way this works is the font graphic has different character visuals for uppercase and lowercase and the visual change happens by applying the appropriate case string when hovering/unhovering.
132-
std::array<std::string, 9> m_MainScreenButtonHoveredText; //!< Array containing uppercase strings of the main screen buttons text that are used to display the larger font when a button is hovered over.
133-
std::array<std::string, 9> m_MainScreenButtonUnhoveredText; //!< Array containing lowercase strings of the main menu screen buttons text that are used to display the smaller font when a button is not hovered over.
135+
std::array<std::string, MenuButton::ResumeButton + 1> m_MainScreenButtonHoveredText; //!< Array containing uppercase strings of the main screen buttons text that are used to display the larger font when a button is hovered over.
136+
std::array<std::string, MenuButton::ResumeButton + 1> m_MainScreenButtonUnhoveredText; //!< Array containing lowercase strings of the main menu screen buttons text that are used to display the smaller font when a button is not hovered over.
134137
GUIButton *m_MainScreenHoveredButton; //!< The currently hovered main screen button.
135138
int m_MainScreenPrevHoveredButtonIndex; //!< The index of the previously hovered main screen button in the main menu button array.
136139

Menus/PauseMenuGUI.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ namespace RTE {
152152
draw_trans_sprite(m_BackdropBitmap, g_FrameMan.GetOverlayBitmap32(), 0, 0);
153153
}
154154

155+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
156+
157+
void PauseMenuGUI::ClearBackdrop() {
158+
clear_bitmap(m_BackdropBitmap);
159+
}
160+
155161
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
156162

157163
PauseMenuGUI::PauseMenuUpdateResult PauseMenuGUI::Update() {
@@ -169,7 +175,7 @@ namespace RTE {
169175
BlinkResumeButton();
170176
break;
171177
case PauseMenuScreen::SaveOrLoadGameScreen:
172-
backToMainScreen = m_SaveLoadMenu->HandleInputEvents();
178+
backToMainScreen = m_SaveLoadMenu->HandleInputEvents(this);
173179
break;
174180
case PauseMenuScreen::SettingsScreen:
175181
backToMainScreen = m_SettingsMenu->HandleInputEvents();

Menus/PauseMenuGUI.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ namespace RTE {
6767
/// </summary>
6868
void StoreFrameForUseAsBackdrop();
6969

70+
/// <summary>
71+
/// Clears the current backdrop back to black.
72+
/// </summary>
73+
void ClearBackdrop();
74+
7075
/// <summary>
7176
/// Updates the PauseMenuGUI state.
7277
/// </summary>

Menus/SaveLoadMenuGUI.cpp

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include "PresetMan.h"
55
#include "WindowMan.h"
66

7+
#include "PauseMenuGUI.h"
8+
#include "SettingsGUI.h"
9+
#include "ModManagerGUI.h"
10+
711
#include "GUI.h"
812
#include "AllegroScreen.h"
913
#include "GAScripted.h"
@@ -56,7 +60,8 @@ namespace RTE {
5660
m_SaveGameName = dynamic_cast<GUITextBox *>(m_GUIControlManager->GetControl("SaveGameName"));
5761
m_LoadButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonLoad"));
5862
m_CreateButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonCreate"));
59-
m_DescriptionLabel = dynamic_cast<GUILabel *>(m_GUIControlManager->GetControl("LabelDescription"));
63+
m_DeleteButton = dynamic_cast<GUIButton *>(m_GUIControlManager->GetControl("ButtonDelete"));
64+
m_ActivityCannotBeSavedLabel = dynamic_cast<GUILabel *>(m_GUIControlManager->GetControl("ActivityCannotBeSavedWarning"));
6065

6166
m_SaveGamesFetched = false;
6267
}
@@ -65,6 +70,9 @@ namespace RTE {
6570

6671
void SaveLoadMenuGUI::PopulateSaveGamesList() {
6772
m_SaveGames.clear();
73+
m_SaveGameName->SetText("");
74+
75+
m_GUIControlManager->GetManager()->SetFocus(nullptr);
6876

6977
std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/";
7078
for (const auto &entry : std::filesystem::directory_iterator(saveFilePath)) {
@@ -146,13 +154,16 @@ namespace RTE {
146154

147155
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
148156

149-
void SaveLoadMenuGUI::LoadSave() {
157+
bool SaveLoadMenuGUI::LoadSave() {
150158
bool success = g_ActivityMan.LoadAndLaunchGame(m_SaveGameName->GetText());
159+
151160
if (success) {
152161
g_GUISound.ConfirmSound()->Play();
153162
} else {
154163
g_GUISound.UserErrorSound()->Play();
155164
}
165+
166+
return success;
156167
}
157168

158169
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -164,15 +175,60 @@ namespace RTE {
164175
} else {
165176
g_GUISound.UserErrorSound()->Play();
166177
}
178+
167179
PopulateSaveGamesList();
168180
}
169181

170182
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
171183

172-
bool SaveLoadMenuGUI::HandleInputEvents() {
184+
void SaveLoadMenuGUI::DeleteSave() {
185+
std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/" + m_SaveGameName->GetText();
186+
187+
// TODO - it'd be nice to have this all zipped up into one file...
188+
std::vector<std::filesystem::path> filePaths;
189+
filePaths.emplace_back(saveFilePath + ".ini");
190+
filePaths.emplace_back(saveFilePath + " BG.png");
191+
filePaths.emplace_back(saveFilePath + " FG.png");
192+
filePaths.emplace_back(saveFilePath + " Mat.png");
193+
filePaths.emplace_back(saveFilePath + " UST1.png");
194+
filePaths.emplace_back(saveFilePath + " UST2.png");
195+
filePaths.emplace_back(saveFilePath + " UST3.png");
196+
filePaths.emplace_back(saveFilePath + " UST4.png");
197+
198+
std::for_each(std::execution::par_unseq,
199+
filePaths.begin(), filePaths.end(),
200+
[](const std::filesystem::path &path) {
201+
std::filesystem::remove(path);
202+
});
203+
204+
g_GUISound.ConfirmSound()->Play();
205+
206+
PopulateSaveGamesList();
207+
}
208+
209+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
210+
211+
void SaveLoadMenuGUI::UpdateButtonEnabledStates() {
212+
bool allowSave = g_ActivityMan.GetActivityAllowsSaving() && m_SaveGameName->GetText() != "";
213+
bool allowLoad = m_SaveGamesListBox->GetSelectedIndex() > -1 && m_SaveGameName->GetText() != "" && m_SaveGameName->GetText() == m_SaveGames[m_SaveGamesListBox->GetSelected()->m_ExtraIndex].SavePath.stem().string();
214+
bool allowDelete = allowLoad;
215+
216+
m_CreateButton->SetVisible(allowSave);
217+
m_CreateButton->SetEnabled(allowSave);
218+
m_LoadButton->SetEnabled(allowLoad);
219+
m_DeleteButton->SetEnabled(allowDelete);
220+
221+
m_ActivityCannotBeSavedLabel->SetVisible(g_ActivityMan.GetActivity() && !g_ActivityMan.GetActivityAllowsSaving());
222+
}
223+
224+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
225+
226+
bool SaveLoadMenuGUI::HandleInputEvents(PauseMenuGUI *pauseMenu) {
173227
if (!ListsFetched()) {
174228
PopulateSaveGamesList();
229+
UpdateButtonEnabledStates();
175230
}
231+
176232
m_GUIControlManager->Update();
177233

178234
GUIEvent guiEvent;
@@ -181,18 +237,25 @@ namespace RTE {
181237
if (guiEvent.GetControl() == m_BackToMainButton) {
182238
return true;
183239
} else if (guiEvent.GetControl() == m_LoadButton) {
184-
LoadSave();
240+
bool gameLoaded = LoadSave();
241+
if (gameLoaded) {
242+
if (pauseMenu) {
243+
pauseMenu->ClearBackdrop();
244+
}
245+
return true;
246+
}
185247
} else if (guiEvent.GetControl() == m_CreateButton) {
186248
CreateSave();
249+
} else if (guiEvent.GetControl() == m_DeleteButton) {
250+
DeleteSave();
187251
}
188252
} else if (guiEvent.GetType() == GUIEvent::Notification) {
189253
if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast<GUIButton *>(guiEvent.GetControl())) {
190254
g_GUISound.SelectionChangeSound()->Play();
191255
}
192256

193257
if (guiEvent.GetControl() == m_SaveGamesListBox && (guiEvent.GetMsg() == GUIListBox::Select && m_SaveGamesListBox->GetSelectedIndex() > -1)) {
194-
const SaveRecord &record = m_SaveGames.at(m_SaveGamesListBox->GetSelected()->m_ExtraIndex);
195-
//m_DescriptionLabel->SetText(record.GetDisplayString());
258+
const SaveRecord &record = m_SaveGames[m_SaveGamesListBox->GetSelected()->m_ExtraIndex];
196259
m_SaveGameName->SetText(record.SavePath.stem().string());
197260
}
198261

@@ -201,6 +264,9 @@ namespace RTE {
201264
}
202265
}
203266
}
267+
268+
UpdateButtonEnabledStates();
269+
204270
return false;
205271
}
206272

Menus/SaveLoadMenuGUI.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
namespace RTE {
77

8+
class PauseMenuGUI;
9+
810
class AllegroScreen;
911
class GUIInputWrapper;
1012
class GUIControlManager;
@@ -35,8 +37,9 @@ namespace RTE {
3537
/// <summary>
3638
/// Handles the player interaction with the SaveLoadMenuGUI GUI elements.
3739
/// </summary>
40+
/// <param name="pauseMenu">Pointer to the pause menu, if we're being called from the pause menu. Ownership is NOT transferred!</param>
3841
/// <returns>Whether the player requested to return to the main menu.</returns>
39-
bool HandleInputEvents();
42+
bool HandleInputEvents(PauseMenuGUI *pauseMenu = nullptr);
4043

4144
/// <summary>
4245
/// Draws the SaveLoadMenuGUI to the screen.
@@ -68,15 +71,16 @@ namespace RTE {
6871
GUITextBox *m_SaveGameName;
6972
GUIButton *m_LoadButton;
7073
GUIButton *m_CreateButton;
74+
GUIButton *m_DeleteButton;
7175
GUIListBox *m_SaveGamesListBox;
72-
GUILabel* m_DescriptionLabel;
76+
GUILabel *m_ActivityCannotBeSavedLabel;
7377
GUIComboBox *m_OrderByComboBox;
7478

75-
#pragma region Mod and Script Handling
79+
#pragma region Savegame Handling
7680
/// <summary>
7781
/// Gets whether both lists were fetched, even if nothing valid was added to them.
7882
/// </summary>
79-
/// <returns>Whether both lists were fetched, even if nothing valid was added to them.</returns>
83+
/// <returns>Whether save games were fetched, even if nothing valid was added to them.</returns>
8084
bool ListsFetched() const { return m_SaveGamesFetched; }
8185

8286
/// <summary>
@@ -92,14 +96,25 @@ namespace RTE {
9296
/// <summary>
9397
/// Loads the currently selected savefile.
9498
/// </summary>
95-
void LoadSave();
99+
/// <returns>Whether a same was succesfully loaded.</returns>
100+
bool LoadSave();
96101

97102
/// <summary>
98103
/// Creates a new savefile (or overwrites the existing one) with the name from the textbox.
99104
/// </summary>
100105
void CreateSave();
106+
107+
/// <summary>
108+
/// Deletes the savefile with the name from the textbox.
109+
/// </summary>
110+
void DeleteSave();
101111
#pragma endregion
102112

113+
/// <summary>
114+
/// Updates buttons and sets whether or not they should be enabled.
115+
/// </summary>
116+
void UpdateButtonEnabledStates();
117+
103118
// Disallow the use of some implicit methods.
104119
SaveLoadMenuGUI(const SaveLoadMenuGUI &reference) = delete;
105120
SaveLoadMenuGUI & operator=(const SaveLoadMenuGUI &rhs) = delete;

0 commit comments

Comments
 (0)