1 /*
2 * This file is part of Dune Legacy.
3 *
4 * Dune Legacy is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * Dune Legacy is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Dune Legacy. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <Menu/CustomGameMenu.h>
19 #include <Menu/CustomGamePlayers.h>
20
21 #include <FileClasses/GFXManager.h>
22 #include <FileClasses/TextManager.h>
23 #include <FileClasses/INIFile.h>
24
25 #include <GUI/Spacer.h>
26 #include <GUI/GUIStyle.h>
27 #include <GUI/dune/GameOptionsWindow.h>
28 #include <GUI/dune/LoadSaveWindow.h>
29 #include <GUI/dune/DuneStyle.h>
30
31 #include <config.h>
32 #include <misc/fnkdat.h>
33 #include <misc/FileSystem.h>
34 #include <misc/draw_util.h>
35 #include <misc/string_util.h>
36
37 #include <INIMap/INIMapPreviewCreator.h>
38 #include <GameInitSettings.h>
39
40 #include <globals.h>
41
42 #include <memory>
43
44
CustomGameMenu(bool multiplayer,bool LANServer)45 CustomGameMenu::CustomGameMenu(bool multiplayer, bool LANServer)
46 : MenuBase(), bMultiplayer(multiplayer), bLANServer(LANServer), currentGameOptions(settings.gameOptions) {
47 // set up window
48 SDL_Texture *pBackground = pGFXManager->getUIGraphic(UI_MenuBackground);
49 setBackground(pBackground, false);
50 resize(getTextureSize(pBackground));
51
52 setWindowWidget(&windowWidget);
53
54 windowWidget.addWidget(&mainVBox, Point(24,23), Point(getRendererWidth() - 48, getRendererHeight() - 32));
55
56 captionLabel.setText(bMultiplayer ? (bLANServer ? _("LAN Game") : _("Internet Game")) : _("Custom Game"));
57 captionLabel.setAlignment(Alignment_HCenter);
58 mainVBox.addWidget(&captionLabel, 24);
59 mainVBox.addWidget(VSpacer::create(24));
60
61 mainVBox.addWidget(Spacer::create(), 0.05);
62
63 mainVBox.addWidget(&mainHBox, 0.80);
64
65 mainHBox.addWidget(Spacer::create(), 0.05);
66 mainHBox.addWidget(&leftVBox, 0.8);
67
68 leftVBox.addWidget(&mapTypeButtonsHBox, 24);
69
70 singleplayerMapsButton.setText(_("SP Maps"));
71 singleplayerMapsButton.setToggleButton(true);
72 singleplayerMapsButton.setOnClick(std::bind(&CustomGameMenu::onMapTypeChange, this, 0));
73 mapTypeButtonsHBox.addWidget(&singleplayerMapsButton);
74
75 singleplayerUserMapsButton.setText(_("SP User Maps"));
76 singleplayerUserMapsButton.setToggleButton(true);
77 singleplayerUserMapsButton.setOnClick(std::bind(&CustomGameMenu::onMapTypeChange, this, 1));
78 mapTypeButtonsHBox.addWidget(&singleplayerUserMapsButton);
79
80 multiplayerMapsButton.setText(_("MP Maps"));
81 multiplayerMapsButton.setToggleButton(true);
82 multiplayerMapsButton.setOnClick(std::bind(&CustomGameMenu::onMapTypeChange, this, 2));
83 mapTypeButtonsHBox.addWidget(&multiplayerMapsButton);
84
85 multiplayerUserMapsButton.setText(_("MP User Maps"));
86 multiplayerUserMapsButton.setToggleButton(true);
87 multiplayerUserMapsButton.setOnClick(std::bind(&CustomGameMenu::onMapTypeChange, this, 3));
88 mapTypeButtonsHBox.addWidget(&multiplayerUserMapsButton);
89
90 dummyButton.setEnabled(false);
91 mapTypeButtonsHBox.addWidget(&dummyButton, 17);
92 mapList.setAutohideScrollbar(false);
93 mapList.setOnSelectionChange(std::bind(&CustomGameMenu::onMapListSelectionChange, this, std::placeholders::_1));
94 mapList.setOnDoubleClick(std::bind(&CustomGameMenu::onNext, this));
95 leftVBox.addWidget(&mapList, 0.95);
96
97 leftVBox.addWidget(VSpacer::create(10));
98
99 multiplePlayersPerHouseCheckbox.setText(_("Multiple players per house"));
100 optionsHBox.addWidget(&multiplePlayersPerHouseCheckbox);
101 optionsHBox.addWidget(Spacer::create());
102 gameOptionsButton.setText(_("Game Options..."));
103 gameOptionsButton.setOnClick(std::bind(&CustomGameMenu::onGameOptions, this));
104 optionsHBox.addWidget(&gameOptionsButton, 140);
105
106 leftVBox.addWidget(Spacer::create(), 0.05);
107
108 leftVBox.addWidget(&optionsHBox, 0.05);
109
110 mainHBox.addWidget(HSpacer::create(8));
111 mainHBox.addWidget(Spacer::create(), 0.05);
112
113 mainHBox.addWidget(&rightVBox, 180);
114 mainHBox.addWidget(Spacer::create(), 0.05);
115 minimap.setSurface( GUIStyle::getInstance().createButtonSurface(130,130,_("Choose map"), true, false), true);
116 rightVBox.addWidget(&minimap);
117
118 rightVBox.addWidget(VSpacer::create(10));
119 rightVBox.addWidget(&mapPropertiesHBox, 0.01);
120 mapPropertiesHBox.addWidget(&mapPropertyNamesVBox, 75);
121 mapPropertiesHBox.addWidget(&mapPropertyValuesVBox, 105);
122 mapPropertyNamesVBox.addWidget(Label::create(_("Size") + ":"));
123 mapPropertyValuesVBox.addWidget(&mapPropertySize);
124 mapPropertyNamesVBox.addWidget(Label::create(_("Players") + ":"));
125 mapPropertyValuesVBox.addWidget(&mapPropertyPlayers);
126 mapPropertyNamesVBox.addWidget(Label::create(_("Author") + ":"));
127 mapPropertyValuesVBox.addWidget(&mapPropertyAuthors);
128 mapPropertyNamesVBox.addWidget(Label::create(_("License") + ":"));
129 mapPropertyValuesVBox.addWidget(&mapPropertyLicense);
130 rightVBox.addWidget(Spacer::create());
131
132 mainVBox.addWidget(Spacer::create(), 0.05);
133
134 mainVBox.addWidget(VSpacer::create(20));
135 mainVBox.addWidget(&buttonHBox, 24);
136 mainVBox.addWidget(VSpacer::create(14), 0.0);
137
138 buttonHBox.addWidget(HSpacer::create(70));
139 cancelButton.setText(_("Back"));
140 cancelButton.setOnClick(std::bind(&CustomGameMenu::onCancel, this));
141 buttonHBox.addWidget(&cancelButton, 0.1);
142
143 buttonHBox.addWidget(Spacer::create(), 0.0625);
144
145 buttonHBox.addWidget(Spacer::create(), 0.25);
146 loadButton.setText(_("Load"));
147 loadButton.setVisible(bMultiplayer);
148 loadButton.setEnabled(bMultiplayer);
149 loadButton.setOnClick(std::bind(&CustomGameMenu::onLoad, this));
150 buttonHBox.addWidget(&loadButton, 0.175);
151 buttonHBox.addWidget(Spacer::create(), 0.25);
152
153 buttonHBox.addWidget(Spacer::create(), 0.0625);
154
155 nextButton.setText(_("Next"));
156 nextButton.setOnClick(std::bind(&CustomGameMenu::onNext, this));
157 buttonHBox.addWidget(&nextButton, 0.1);
158 buttonHBox.addWidget(HSpacer::create(90));
159
160 onMapTypeChange(0);
161 }
162
~CustomGameMenu()163 CustomGameMenu::~CustomGameMenu()
164 {
165 ;
166 }
167
168
onChildWindowClose(Window * pChildWindow)169 void CustomGameMenu::onChildWindowClose(Window* pChildWindow) {
170 LoadSaveWindow* pLoadSaveWindow = dynamic_cast<LoadSaveWindow*>(pChildWindow);
171 if(pLoadSaveWindow != nullptr) {
172 std::string filename = pLoadSaveWindow->getFilename();
173
174 if(filename != "") {
175 std::string savegamedata = readCompleteFile(filename);
176
177 std::string servername = settings.general.playerName + "'s Game";
178 GameInitSettings gameInitSettings(getBasename(filename, true), savegamedata, servername);
179
180 CustomGamePlayers* pCustomGamePlayers = new CustomGamePlayers(gameInitSettings, true, bLANServer);
181 int ret = pCustomGamePlayers->showMenu();
182 delete pCustomGamePlayers;
183 if(ret != MENU_QUIT_DEFAULT) {
184 quit(ret);
185 }
186 }
187 }
188
189 GameOptionsWindow* pGameOptionsWindow = dynamic_cast<GameOptionsWindow*>(pChildWindow);
190 if(pGameOptionsWindow != nullptr) {
191 currentGameOptions = pGameOptionsWindow->getGameOptions();
192 }
193 }
194
onNext()195 void CustomGameMenu::onNext()
196 {
197 if(mapList.getSelectedIndex() < 0) {
198 return;
199 }
200
201 std::string mapFilename = currentMapDirectory + mapList.getSelectedEntry() + ".ini";
202 getCaseInsensitiveFilename(mapFilename);
203
204 GameInitSettings gameInitSettings;
205 if(bMultiplayer) {
206 std::string servername = settings.general.playerName + "'s Game";
207 gameInitSettings = GameInitSettings(getBasename(mapFilename, true), readCompleteFile(mapFilename), servername, multiplePlayersPerHouseCheckbox.isChecked(), currentGameOptions);
208 } else {
209 gameInitSettings = GameInitSettings(getBasename(mapFilename, true), readCompleteFile(mapFilename), multiplePlayersPerHouseCheckbox.isChecked(), currentGameOptions);
210 }
211
212 CustomGamePlayers* pCustomGamePlayers = new CustomGamePlayers(gameInitSettings, true, bLANServer);
213 int ret = pCustomGamePlayers->showMenu();
214 delete pCustomGamePlayers;
215 if(ret != MENU_QUIT_DEFAULT) {
216 quit(ret);
217 }
218 }
219
onCancel()220 void CustomGameMenu::onCancel()
221 {
222 quit();
223 }
224
onLoad()225 void CustomGameMenu::onLoad()
226 {
227 char tmp[FILENAME_MAX];
228 fnkdat("mpsave/", tmp, FILENAME_MAX, FNKDAT_USER | FNKDAT_CREAT);
229 std::string savepath(tmp);
230 openWindow(LoadSaveWindow::create(false, _("Load Game"), savepath, "dls"));
231 }
232
onGameOptions()233 void CustomGameMenu::onGameOptions()
234 {
235 openWindow(GameOptionsWindow::create(currentGameOptions));
236 }
237
onMapTypeChange(int buttonID)238 void CustomGameMenu::onMapTypeChange(int buttonID)
239 {
240 singleplayerMapsButton.setToggleState(buttonID == 0);
241 singleplayerUserMapsButton.setToggleState(buttonID == 1);
242 multiplayerMapsButton.setToggleState(buttonID == 2);
243 multiplayerUserMapsButton.setToggleState(buttonID == 3);
244
245 switch(buttonID) {
246 case 0: {
247 currentMapDirectory = getDuneLegacyDataDir() + "/maps/singleplayer/";
248 } break;
249 case 1: {
250 char tmp[FILENAME_MAX];
251 fnkdat("maps/singleplayer/", tmp, FILENAME_MAX, FNKDAT_USER | FNKDAT_CREAT);
252 currentMapDirectory = tmp;
253 } break;
254 case 2: {
255 currentMapDirectory = getDuneLegacyDataDir() + "/maps/multiplayer/";
256 } break;
257 case 3: {
258 char tmp[FILENAME_MAX];
259 fnkdat("maps/multiplayer/", tmp, FILENAME_MAX, FNKDAT_USER | FNKDAT_CREAT);
260 currentMapDirectory = tmp;
261 } break;
262 }
263
264 mapList.clearAllEntries();
265
266 for(const std::string& file : getFileNamesList(currentMapDirectory, "ini", true, FileListOrder_Name_CaseInsensitive_Asc)) {
267 mapList.addEntry(file.substr(0, file.length() - 4));
268 }
269
270 if(mapList.getNumEntries() > 0) {
271 mapList.setSelectedItem(0);
272 } else {
273 minimap.setSurface( GUIStyle::getInstance().createButtonSurface(130,130,_("No map available"), true, false), true);
274 mapPropertySize.setText("");
275 mapPropertyPlayers.setText("");
276 mapPropertyAuthors.setText("");
277 mapPropertyLicense.setText("");
278 }
279 }
280
onMapListSelectionChange(bool bInteractive)281 void CustomGameMenu::onMapListSelectionChange(bool bInteractive)
282 {
283 nextButton.setEnabled(true);
284
285 if(mapList.getSelectedIndex() < 0) {
286 return;
287 }
288
289 std::string mapFilename = currentMapDirectory + mapList.getSelectedEntry() + ".ini";
290 getCaseInsensitiveFilename(mapFilename);
291
292 std::shared_ptr<INIFile> pMap(new INIFile(mapFilename));
293
294 int sizeX = 0;
295 int sizeY = 0;
296
297 if(pMap->hasKey("MAP","Seed")) {
298 // old map format with seed value
299 int mapscale = pMap->getIntValue("BASIC", "MapScale", -1);
300
301 switch(mapscale) {
302 case 0: {
303 sizeX = 62;
304 sizeY = 62;
305 } break;
306
307 case 1: {
308 sizeX = 32;
309 sizeY = 32;
310 } break;
311
312 case 2: {
313 sizeX = 21;
314 sizeY = 21;
315 } break;
316
317 default: {
318 sizeX = 64;
319 sizeY = 64;
320 }
321 }
322 } else {
323 // new map format with saved map
324 sizeX = pMap->getIntValue("MAP","SizeX", 0);
325 sizeY = pMap->getIntValue("MAP","SizeY", 0);
326 }
327
328 mapPropertySize.setText(stringify(sizeX) + " x " + stringify(sizeY));
329
330 SDL_Surface* pMapSurface = nullptr;
331 try {
332 INIMapPreviewCreator mapPreviewCreator(pMap);
333 pMapSurface = mapPreviewCreator.createMinimapImageOfMap(1, DuneStyle::buttonBorderColor);
334 } catch(...) {
335 pMapSurface = GUIStyle::getInstance().createButtonSurface(130, 130, "Error", true, false);
336 loadButton.setEnabled(false);
337 }
338 minimap.setSurface(pMapSurface, true);
339
340 int numPlayers = 0;
341 if(pMap->hasSection("Atreides")) numPlayers++;
342 if(pMap->hasSection("Ordos")) numPlayers++;
343 if(pMap->hasSection("Harkonnen")) numPlayers++;
344 if(pMap->hasSection("Fremen")) numPlayers++;
345 if(pMap->hasSection("Mercenary")) numPlayers++;
346 if(pMap->hasSection("Sardaukar")) numPlayers++;
347 if(pMap->hasSection("Player1")) numPlayers++;
348 if(pMap->hasSection("Player2")) numPlayers++;
349 if(pMap->hasSection("Player3")) numPlayers++;
350 if(pMap->hasSection("Player4")) numPlayers++;
351 if(pMap->hasSection("Player5")) numPlayers++;
352 if(pMap->hasSection("Player6")) numPlayers++;
353
354 mapPropertyPlayers.setText(stringify(numPlayers));
355
356
357
358 std::string authors = pMap->getStringValue("BASIC","Author", "-");
359 if(authors.size() > 11) {
360 authors = authors.substr(0,9) + "...";
361 }
362 mapPropertyAuthors.setText(authors);
363
364
365 mapPropertyLicense.setText(pMap->getStringValue("BASIC","License", "-"));
366
367 }
368