1 /***************************************************************************
2 * Mechanized Assault and Exploration Reloaded Projectfile *
3 * *
4 * This program 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 * This program 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 this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19
20 #include "ui/graphical/menu/control/menucontrollermultiplayerhotseat.h"
21 #include "ui/graphical/application.h"
22 #include "ui/graphical/menu/windows/windowgamesettings/windowgamesettings.h"
23 #include "ui/graphical/menu/windows/windowmapselection/windowmapselection.h"
24 #include "ui/graphical/menu/windows/windowplayerselection/windowplayerselection.h"
25 #include "ui/graphical/menu/windows/windowclanselection/windowclanselection.h"
26 #include "ui/graphical/menu/windows/windowlandingunitselection/windowlandingunitselection.h"
27 #include "ui/graphical/menu/windows/windowlandingpositionselection/windowlandingpositionselection.h"
28 #include "ui/graphical/menu/windows/windowgamesettings/gamesettings.h"
29 #include "ui/graphical/menu/dialogs/dialogok.h"
30 #include "ui/graphical/menu/dialogs/dialogyesno.h"
31 #include "game/startup/local/hotseat/localhotseatgamenew.h"
32 #include "game/data/player/playerbasicdata.h"
33 #include "game/data/units/landingunit.h"
34 #include "game/data/map/map.h"
35 #include "game/logic/upgradecalculator.h"
36
37 // TODO: remove
38 std::vector<std::pair<sID, int>> createInitialLandingUnitsList (int clan, const cGameSettings& gameSettings); // defined in windowsingleplayer.cpp
39
40 //------------------------------------------------------------------------------
cMenuControllerMultiplayerHotSeat(cApplication & application_)41 cMenuControllerMultiplayerHotSeat::cMenuControllerMultiplayerHotSeat (cApplication& application_) :
42 application (application_)
43 {}
44
45 //------------------------------------------------------------------------------
start()46 void cMenuControllerMultiplayerHotSeat::start()
47 {
48 game = std::make_shared<cLocalHotSeatGameNew> ();
49
50 selectGameSettings();
51 }
52
53 //------------------------------------------------------------------------------
reset()54 void cMenuControllerMultiplayerHotSeat::reset()
55 {
56 game = nullptr;
57 windowPlayerSelection = nullptr;
58 firstWindow = nullptr;
59 landingPositionManager = nullptr;
60 nextInvalidLandingPositionPlayers.clear();
61 invalidLandingPositionPlayers.clear();
62 playerLandingSelectionWindows.clear();
63 landingSelectionWindowConnections.disconnectAll();
64 }
65
66 //------------------------------------------------------------------------------
selectGameSettings()67 void cMenuControllerMultiplayerHotSeat::selectGameSettings()
68 {
69 if (!game) return;
70
71 auto windowGameSettings = application.show (std::make_shared<cWindowGameSettings> (true));
72 windowGameSettings->applySettings (cGameSettings());
73
74 windowGameSettings->terminated.connect (std::bind (&cMenuControllerMultiplayerHotSeat::reset, this));
75
76 firstWindow = windowGameSettings;
77
78 windowGameSettings->done.connect ([ = ]()
79 {
80 auto gameSettings = std::make_shared<cGameSettings> (windowGameSettings->getGameSettings());
81 game->setGameSettings (gameSettings);
82
83 selectMap();
84 });
85 }
86
87 //------------------------------------------------------------------------------
selectMap()88 void cMenuControllerMultiplayerHotSeat::selectMap()
89 {
90 if (!game) return;
91
92 auto windowMapSelection = application.show (std::make_shared<cWindowMapSelection> ());
93
94 windowMapSelection->done.connect ([ = ]()
95 {
96 auto staticMap = std::make_shared<cStaticMap> ();
97 if (!windowMapSelection->loadSelectedMap (*staticMap))
98 {
99 // TODO: error dialog: could not load selected map!
100 return;
101 }
102 game->setStaticMap (staticMap);
103
104 selectPlayers();
105 });
106 }
107
108 //------------------------------------------------------------------------------
selectPlayers()109 void cMenuControllerMultiplayerHotSeat::selectPlayers()
110 {
111 if (!game) return;
112
113 windowPlayerSelection = application.show (std::make_shared<cWindowPlayerSelection> ());
114
115 windowPlayerSelection->done.connect ([ = ]()
116 {
117 const auto& playerTypes = windowPlayerSelection->getPlayerTypes();
118
119 const char* const playerNames[] =
120 {
121 "Text~Multiplayer~Player1",
122 "Text~Multiplayer~Player2",
123 "Text~Multiplayer~Player3",
124 "Text~Multiplayer~Player4",
125 "Text~Multiplayer~Player5",
126 "Text~Multiplayer~Player6",
127 "Text~Multiplayer~Player7",
128 "Text~Multiplayer~Player8"
129 };
130
131 std::vector<cPlayerBasicData> players;
132 int playerNum = 0;
133 for (size_t i = 0; i < playerTypes.size(); ++i)
134 {
135 if (playerTypes[i] == ePlayerType::Human)
136 {
137 cPlayerBasicData player (lngPack.i18n (playerNames[i]), cPlayerColor (cPlayerColor::predefinedColors[i]), playerNum++);
138 players.push_back (player);
139 }
140 }
141 assert (players.size() > 0);
142
143 game->setPlayers (players);
144
145 playerLandingSelectionWindows.resize (players.size());
146 landingPositionManager = std::make_unique<cLandingPositionManager> (players);
147 landingPositionManager->landingPositionStateChanged.connect ([this] (const cPlayerBasicData & player, eLandingPositionState state)
148 {
149 if (state == eLandingPositionState::TooClose || state == eLandingPositionState::Warning)
150 {
151 for (size_t i = 0; i < game->getPlayerCount(); ++i)
152 {
153 if (game->getPlayer (i).getNr() == player.getNr())
154 {
155 nextInvalidLandingPositionPlayers.push_back (std::make_pair (i, state));
156 break;
157 }
158 }
159 }
160 });
161
162 startNextPlayerGamePreperation (0);
163 });
164 }
165
166 //------------------------------------------------------------------------------
startNextPlayerGamePreperation(size_t playerIndex)167 void cMenuControllerMultiplayerHotSeat::startNextPlayerGamePreperation (size_t playerIndex)
168 {
169 auto dialog = application.show (std::make_shared<cDialogOk> (lngPack.i18n ("Text~Multiplayer~Player_Turn", game->getPlayer (playerIndex).getName()), eWindowBackgrounds::Black));
170 dialog->done.connect ([this, playerIndex]()
171 {
172 if (game->getGameSettings()->getClansEnabled())
173 {
174 selectClan (playerIndex, true);
175 }
176 else
177 {
178 selectLandingUnits (playerIndex, true);
179 }
180 });
181 }
182
183 //------------------------------------------------------------------------------
selectClan(size_t playerIndex,bool firstForPlayer)184 void cMenuControllerMultiplayerHotSeat::selectClan (size_t playerIndex, bool firstForPlayer)
185 {
186 if (!game) return;
187
188 auto windowClanSelection = application.show (std::make_shared<cWindowClanSelection> ());
189
190 windowClanSelection->done.connect ([ = ]()
191 {
192 game->setPlayerClan (playerIndex, windowClanSelection->getSelectedClan());
193
194 selectLandingUnits (playerIndex, false);
195 });
196
197 if (firstForPlayer)
198 {
199 windowClanSelection->canceled.connect ([ = ]()
200 {
201 application.closeTill (*windowPlayerSelection);
202 });
203 }
204 else
205 {
206 windowClanSelection->canceled.connect ([ = ]() { windowClanSelection->close(); });
207 }
208 }
209
210 //------------------------------------------------------------------------------
selectLandingUnits(size_t playerIndex,bool firstForPlayer)211 void cMenuControllerMultiplayerHotSeat::selectLandingUnits (size_t playerIndex, bool firstForPlayer)
212 {
213 if (!game) return;
214
215 auto initialLandingUnits = createInitialLandingUnitsList (game->getPlayerClan (playerIndex), *game->getGameSettings());
216
217 auto windowLandingUnitSelection = application.show (std::make_shared<cWindowLandingUnitSelection> (game->getPlayer (playerIndex).getColor(), game->getPlayerClan (playerIndex), initialLandingUnits, game->getGameSettings()->getStartCredits()));
218
219 windowLandingUnitSelection->done.connect ([ = ]()
220 {
221 game->setLandingUnits (playerIndex, windowLandingUnitSelection->getLandingUnits());
222 game->setUnitUpgrades (playerIndex, windowLandingUnitSelection->getUnitUpgrades());
223
224 selectLandingPosition (playerIndex);
225 });
226
227 if (firstForPlayer)
228 {
229 windowLandingUnitSelection->canceled.connect ([ = ]()
230 {
231 application.closeTill (*windowPlayerSelection);
232 });
233 }
234 else
235 {
236 windowLandingUnitSelection->canceled.connect ([ = ]() { windowLandingUnitSelection->close(); });
237 }
238 }
239
240 //------------------------------------------------------------------------------
selectLandingPosition(size_t playerIndex)241 void cMenuControllerMultiplayerHotSeat::selectLandingPosition (size_t playerIndex)
242 {
243 if (!game) return;
244
245 playerLandingSelectionWindows[playerIndex] = std::make_shared<cWindowLandingPositionSelection> (game->getStaticMap(), false);
246
247 auto windowLandingPositionSelection = application.show (playerLandingSelectionWindows[playerIndex]);
248
249 windowLandingPositionSelection->canceled.connect ([ = ]() {windowLandingPositionSelection->close(); });
250 landingSelectionWindowConnections.connect (windowLandingPositionSelection->selectedPosition, [ = ] (cPosition landingPosition)
251 {
252 landingPositionManager->setLandingPosition (game->getPlayer (playerIndex), landingPosition);
253 game->setLandingPosition (playerIndex, landingPosition);
254
255 if (playerIndex == game->getPlayerCount() - 1)
256 {
257 checkAllLandingPositions();
258 }
259 else
260 {
261 startNextPlayerGamePreperation (playerIndex + 1);
262 }
263 });
264 }
265
266 //------------------------------------------------------------------------------
checkAllLandingPositions()267 void cMenuControllerMultiplayerHotSeat::checkAllLandingPositions()
268 {
269 std::swap (invalidLandingPositionPlayers, nextInvalidLandingPositionPlayers);
270 nextInvalidLandingPositionPlayers.clear();
271
272 landingSelectionWindowConnections.disconnectAll();
273
274 if (!invalidLandingPositionPlayers.empty())
275 {
276 reselectLandingPosition (0);
277 }
278 else
279 {
280 application.closeTill (*firstWindow);
281 firstWindow->close();
282 signalConnectionManager.connect (firstWindow->terminated, [&]() { firstWindow = nullptr; });
283
284 game->start (application);
285 }
286 }
287
288 //------------------------------------------------------------------------------
reselectLandingPosition(size_t reselectIndex)289 void cMenuControllerMultiplayerHotSeat::reselectLandingPosition (size_t reselectIndex)
290 {
291 auto playerIndex = invalidLandingPositionPlayers[reselectIndex].first;
292 auto landingState = invalidLandingPositionPlayers[reselectIndex].second;
293
294 auto dialog = application.show (std::make_shared<cDialogOk> (lngPack.i18n ("Text~Multiplayer~Player_Turn", game->getPlayer (playerIndex).getName()), eWindowBackgrounds::Black));
295 dialog->done.connect ([ = ]()
296 {
297 auto windowLandingPositionSelection = application.show (playerLandingSelectionWindows[playerIndex]);
298
299 windowLandingPositionSelection->applyReselectionState (landingState);
300
301 landingSelectionWindowConnections.connect (windowLandingPositionSelection->selectedPosition, [ = ] (cPosition landingPosition)
302 {
303 landingPositionManager->setLandingPosition (game->getPlayer (playerIndex), landingPosition);
304 game->setLandingPosition (playerIndex, landingPosition);
305
306 if (reselectIndex == invalidLandingPositionPlayers.size() - 1)
307 {
308 checkAllLandingPositions();
309 }
310 else
311 {
312 reselectLandingPosition (reselectIndex + 1);
313 }
314 });
315 });
316 }