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 }