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/CustomGamePlayers.h>
19 
20 #include <FileClasses/GFXManager.h>
21 #include <FileClasses/TextManager.h>
22 #include <FileClasses/INIFile.h>
23 
24 #include <Network/NetworkManager.h>
25 
26 #include <GUI/Spacer.h>
27 #include <GUI/GUIStyle.h>
28 #include <GUI/MsgBox.h>
29 #include <GUI/dune/DuneStyle.h>
30 
31 #include <players/PlayerFactory.h>
32 
33 #include <misc/fnkdat.h>
34 #include <misc/FileSystem.h>
35 #include <misc/draw_util.h>
36 #include <misc/string_util.h>
37 #include <misc/IMemoryStream.h>
38 
39 #include <INIMap/INIMapPreviewCreator.h>
40 
41 #include <sand.h>
42 #include <globals.h>
43 
44 
45 #define PLAYER_HUMAN        0
46 #define PLAYER_OPEN         -1
47 #define PLAYER_CLOSED       -2
48 
49 
CustomGamePlayers(const GameInitSettings & newGameInitSettings,bool server,bool LANServer)50 CustomGamePlayers::CustomGamePlayers(const GameInitSettings& newGameInitSettings, bool server, bool LANServer)
51  : MenuBase(), gameInitSettings(newGameInitSettings), bServer(server), bLANServer(LANServer), startGameTime(0), brainEqHumanSlot(-1) {
52 
53     // set up window
54     SDL_Texture *pBackground = pGFXManager->getUIGraphic(UI_MenuBackground);
55     setBackground(pBackground, false);
56     resize(getTextureSize(pBackground));
57 
58     setWindowWidget(&windowWidget);
59 
60     windowWidget.addWidget(&mainVBox, Point(24,23), Point(getRendererWidth() - 48, getRendererHeight() - 32));
61 
62     captionLabel.setText(getBasename(gameInitSettings.getFilename(), true));
63     captionLabel.setAlignment(Alignment_HCenter);
64     mainVBox.addWidget(&captionLabel, 24);
65     mainVBox.addWidget(VSpacer::create(24));
66 
67     mainVBox.addWidget(Spacer::create(), 0.04);
68 
69     mainVBox.addWidget(&mainHBox, 0.6);
70 
71     mainHBox.addWidget(Spacer::create(), 0.05);
72     leftVBox.addWidget(Spacer::create(), 0.1);
73     leftVBox.addWidget(&playerListHBox);
74     playerListHBox.addWidget(Spacer::create(), 0.4);
75     playerListHBox.addWidget(&playerListVBox, 0.2);
76     playerListHBox.addWidget(Spacer::create(), 0.4);
77     mainHBox.addWidget(&leftVBox, 0.8);
78 
79     mainHBox.addWidget(Spacer::create(), 0.05);
80 
81     mainHBox.addWidget(HSpacer::create(8));
82 
83     mainHBox.addWidget(&rightVBox, 180);
84     mainHBox.addWidget(Spacer::create(), 0.05);
85     minimap.setSurface( GUIStyle::getInstance().createButtonSurface(130,130,_("Choose map"), true, false), true);
86     rightVBox.addWidget(&minimap);
87 
88     if(gameInitSettings.getGameType() == GameType::CustomGame || gameInitSettings.getGameType() == GameType::CustomMultiplayer) {
89         SDL_RWops* RWops = SDL_RWFromConstMem(gameInitSettings.getFiledata().c_str(), gameInitSettings.getFiledata().size());
90 
91         std::shared_ptr<INIFile> map(new INIFile(RWops));
92         extractMapInfo(map);
93 
94         SDL_RWclose(RWops);
95     } else if(gameInitSettings.getGameType() == GameType::LoadMultiplayer) {
96         IMemoryStream memStream(gameInitSettings.getFiledata().c_str(), gameInitSettings.getFiledata().size());
97 
98         Uint32 magicNum = memStream.readUint32();
99         if(magicNum != SAVEMAGIC) {
100             SDL_Log("CustomGamePlayers: No valid savegame! Expected magic number %.8X, but got %.8X!", SAVEMAGIC, magicNum);
101         }
102 
103         Uint32 savegameVersion = memStream.readUint32();
104         if (savegameVersion != SAVEGAMEVERSION) {
105             SDL_Log("CustomGamePlayers: No valid savegame! Expected savegame version %d, but got %d!", SAVEGAMEVERSION, savegameVersion);
106         }
107 
108         memStream.readString();     // dune legacy version
109 
110         // read gameInitSettings
111         GameInitSettings tmpGameInitSettings(memStream);
112 
113         Uint32 numHouseInfo = memStream.readUint32();
114         for(Uint32 i=0;i<numHouseInfo;i++) {
115             houseInfoListSetup.push_back(GameInitSettings::HouseInfo(memStream));
116         }
117 
118         SDL_RWops* RWops = SDL_RWFromConstMem(tmpGameInitSettings.getFiledata().c_str(), tmpGameInitSettings.getFiledata().size());
119 
120         std::shared_ptr<INIFile> map(new INIFile(RWops));
121         extractMapInfo(map);
122 
123         SDL_RWclose(RWops);
124 
125         // adjust multiple players per house as this was not known before actually loading the saved game
126         gameInitSettings.setMultiplePlayersPerHouse(tmpGameInitSettings.isMultiplePlayersPerHouse());
127 
128         // adjust numHouses to the actually used houses (which might be smaller than the houses on the map)
129         numHouses = houseInfoListSetup.size();
130     } else {
131         std::shared_ptr<INIFile> map(new INIFile(gameInitSettings.getFilename()));
132         extractMapInfo(map);
133     }
134 
135     rightVBox.addWidget(VSpacer::create(10));
136     rightVBox.addWidget(&mapPropertiesHBox, 0.01);
137     mapPropertiesHBox.addWidget(&mapPropertyNamesVBox, 75);
138     mapPropertiesHBox.addWidget(&mapPropertyValuesVBox, 105);
139     mapPropertyNamesVBox.addWidget(Label::create(_("Size") + ":"));
140     mapPropertyValuesVBox.addWidget(&mapPropertySize);
141     mapPropertyNamesVBox.addWidget(Label::create(_("Players") + ":"));
142     mapPropertyValuesVBox.addWidget(&mapPropertyPlayers);
143     mapPropertyNamesVBox.addWidget(Label::create(_("Author") + ":"));
144     mapPropertyValuesVBox.addWidget(&mapPropertyAuthors);
145     mapPropertyNamesVBox.addWidget(Label::create(_("License") + ":"));
146     mapPropertyValuesVBox.addWidget(&mapPropertyLicense);
147     rightVBox.addWidget(Spacer::create());
148 
149     mainVBox.addWidget(Spacer::create(), 0.04);
150 
151     mainVBox.addWidget(&buttonHBox, 0.32);
152 
153     buttonHBox.addWidget(HSpacer::create(70));
154 
155     backButtonVBox.addWidget(Spacer::create());
156     backButton.setText(_("Back"));
157     backButton.setOnClick(std::bind(&CustomGamePlayers::onCancel, this));
158     backButtonVBox.addWidget(&backButton, 24);
159     backButtonVBox.addWidget(VSpacer::create(14));
160     buttonHBox.addWidget(&backButtonVBox, 0.1);
161 
162     buttonHBox.addWidget(Spacer::create(), 0.0625);
163 
164     chatTextView.setTextFont(FONT_STD10);
165     chatVBox.addWidget(&chatTextView, 0.77);
166     if(getRendererHeight() <= 600) {
167         chatTextBox.setTextFont(FONT_STD10);
168     }
169     chatTextBox.setOnReturn(std::bind(&CustomGamePlayers::onSendChatMessage, this));
170     chatVBox.addWidget(&chatTextBox, 0.2);
171     chatVBox.addWidget(Spacer::create(), 0.03);
172     buttonHBox.addWidget(&chatVBox, 0.675);
173 
174     if(gameInitSettings.getGameType() != GameType::CustomMultiplayer && gameInitSettings.getGameType() != GameType::LoadMultiplayer) {
175         chatVBox.setVisible(false);
176         chatVBox.setEnabled(false);
177     }
178 
179     bool bLoadMultiplayer = (gameInitSettings.getGameType() == GameType::LoadMultiplayer);
180 
181     buttonHBox.addWidget(Spacer::create(), 0.0625);
182 
183     nextButtonVBox.addWidget(Spacer::create());
184     nextButton.setText(_("Next"));
185     nextButton.setOnClick(std::bind(&CustomGamePlayers::onNext, this));
186     nextButtonVBox.addWidget(&nextButton, 24);
187     nextButtonVBox.addWidget(VSpacer::create(14));
188     if(bServer == false) {
189         nextButton.setEnabled(false);
190         nextButton.setVisible(false);
191     }
192     buttonHBox.addWidget(&nextButtonVBox, 0.1);
193 
194     buttonHBox.addWidget(HSpacer::create(90));
195 
196     std::list<HOUSETYPE>  tmpBoundHousesOnMap = boundHousesOnMap;
197 
198     bool thisPlayerPlaced = false;
199 
200     for(int i=0;i<NUM_HOUSES;i++) {
201         HouseInfo& curHouseInfo = houseInfo[i];
202 
203         // set up header row with Label "House", DropDown for house selection and DropDown for team selection
204         curHouseInfo.houseLabel.setText(_("House"));
205         curHouseInfo.houseHBox.addWidget(&curHouseInfo.houseLabel, 60);
206 
207         if(bLoadMultiplayer) {
208             if(i < (int) houseInfoListSetup.size()) {
209                 GameInitSettings::HouseInfo gisHouseInfo = houseInfoListSetup.at(i);
210 
211                 if(gisHouseInfo.houseID == HOUSE_INVALID) {
212                     addToHouseDropDown(curHouseInfo.houseDropDown, HOUSE_INVALID, true);
213                 } else {
214                     addToHouseDropDown(curHouseInfo.houseDropDown, gisHouseInfo.houseID, true);
215                 }
216             }
217 
218             curHouseInfo.houseDropDown.setEnabled(false);
219         } else if(tmpBoundHousesOnMap.empty() == false) {
220             HOUSETYPE housetype = tmpBoundHousesOnMap.front();
221             tmpBoundHousesOnMap.pop_front();
222 
223             addToHouseDropDown(curHouseInfo.houseDropDown, housetype, true);
224             curHouseInfo.houseDropDown.setEnabled(bServer);
225         } else {
226             addToHouseDropDown(curHouseInfo.houseDropDown, HOUSE_INVALID, true);
227             curHouseInfo.houseDropDown.setEnabled(bServer);
228         }
229         curHouseInfo.houseDropDown.setOnSelectionChange(std::bind(&CustomGamePlayers::onChangeHousesDropDownBoxes, this, std::placeholders::_1, i));
230         curHouseInfo.houseHBox.addWidget(&curHouseInfo.houseDropDown, 95);
231 
232         if(bLoadMultiplayer) {
233             if(i < (int) houseInfoListSetup.size()) {
234                 GameInitSettings::HouseInfo gisHouseInfo = houseInfoListSetup.at(i);
235 
236                 curHouseInfo.teamDropDown.addEntry(_("Team") + " " + stringify(gisHouseInfo.team), gisHouseInfo.team);
237                 curHouseInfo.teamDropDown.setSelectedItem(0);
238             }
239             curHouseInfo.teamDropDown.setEnabled(false);
240             curHouseInfo.teamDropDown.setOnClickEnabled(false);
241         } else {
242             for(int team = 0 ; team<numHouses ; team++) {
243                 curHouseInfo.teamDropDown.addEntry(_("Team") + " " + stringify(team+1), team+1);
244             }
245             curHouseInfo.teamDropDown.setSelectedItem(slotToTeam[i]);
246             curHouseInfo.teamDropDown.setEnabled(bServer);
247         }
248         curHouseInfo.teamDropDown.setOnSelectionChange(std::bind(&CustomGamePlayers::onChangeTeamDropDownBoxes, this, std::placeholders::_1, i));
249         curHouseInfo.houseHBox.addWidget(HSpacer::create(10));
250         curHouseInfo.houseHBox.addWidget(&curHouseInfo.teamDropDown, 85);
251 
252         curHouseInfo.houseInfoVBox.addWidget(&curHouseInfo.houseHBox);
253 
254         // add 1. player
255         curHouseInfo.player1ArrowLabel.setTexture(pGFXManager->getUIGraphic(UI_CustomGamePlayersArrowNeutral), false);
256         curHouseInfo.playerHBox.addWidget(&curHouseInfo.player1ArrowLabel);
257         curHouseInfo.player1Label.setText(_("Player") + (gameInitSettings.isMultiplePlayersPerHouse() ? " 1" : ""));
258         curHouseInfo.player1Label.setTextFont(FONT_STD10);
259         curHouseInfo.playerHBox.addWidget(&curHouseInfo.player1Label, 68);
260 
261         if(bLoadMultiplayer) {
262             if(i < (int) houseInfoListSetup.size()) {
263                 GameInitSettings::HouseInfo gisHouseInfo = houseInfoListSetup.at(i);
264 
265                 if(gisHouseInfo.houseID == HOUSE_UNUSED) {
266                     curHouseInfo.player1DropDown.addEntry(_("closed"), PLAYER_CLOSED);
267                 } else if(gisHouseInfo.playerInfoList.empty() == false) {
268                     GameInitSettings::PlayerInfo playerInfo = gisHouseInfo.playerInfoList.front();
269                     if(playerInfo.playerClass == HUMANPLAYERCLASS) {
270                         if(thisPlayerPlaced == false) {
271                             curHouseInfo.player1DropDown.addEntry(settings.general.playerName, PLAYER_HUMAN);
272                             curHouseInfo.player1DropDown.setSelectedItem(0);
273                             thisPlayerPlaced = true;
274                         } else {
275                             curHouseInfo.player1DropDown.addEntry(_("open"), PLAYER_OPEN);
276                             curHouseInfo.player1DropDown.setSelectedItem(0);
277                         }
278                     } else {
279                         const PlayerFactory::PlayerData* pPlayerData = PlayerFactory::getByPlayerClass(playerInfo.playerClass);
280                         int index = PlayerFactory::getIndexByPlayerClass(playerInfo.playerClass);
281 
282                         if(pPlayerData != nullptr) {
283                             curHouseInfo.player1DropDown.addEntry(pPlayerData->getName(), -(index+2));
284                             curHouseInfo.player1DropDown.setSelectedItem(0);
285                             curHouseInfo.player1DropDown.setEnabled(false);
286                             curHouseInfo.player1DropDown.setOnClickEnabled(false);
287                         }
288                     }
289                 }
290 
291             }
292 
293         } else if(bServer && (thisPlayerPlaced == false)) {
294             curHouseInfo.player1DropDown.addEntry(settings.general.playerName, PLAYER_HUMAN);
295             curHouseInfo.player1DropDown.setSelectedItem(0);
296             curHouseInfo.player1DropDown.setEnabled(bServer);
297             thisPlayerPlaced = true;
298         } else {
299             curHouseInfo.player1DropDown.addEntry(_("open"), PLAYER_OPEN);
300             curHouseInfo.player1DropDown.setSelectedItem(0);
301             curHouseInfo.player1DropDown.addEntry(_("closed"), PLAYER_CLOSED);
302             for(unsigned int k = 1; k < PlayerFactory::getList().size(); k++) {
303                 curHouseInfo.player1DropDown.addEntry(PlayerFactory::getByIndex(k)->getName(), k);
304             }
305             curHouseInfo.player1DropDown.setEnabled(bServer);
306         }
307         curHouseInfo.player1DropDown.setOnSelectionChange(std::bind(&CustomGamePlayers::onChangePlayerDropDownBoxes, this, std::placeholders::_1, 2*i));
308         curHouseInfo.player1DropDown.setOnClick(std::bind(&CustomGamePlayers::onClickPlayerDropDownBox, this, 2*i));
309         curHouseInfo.playerHBox.addWidget(&curHouseInfo.player1DropDown, 100);
310 
311         curHouseInfo.playerHBox.addWidget(HSpacer::create(10));
312 
313         // add 2. player
314         curHouseInfo.player2Label.setText(_("Player") + " 2");
315         curHouseInfo.player2Label.setTextFont(FONT_STD10);
316         curHouseInfo.playerHBox.addWidget(&curHouseInfo.player2Label, 68);
317 
318         if(bLoadMultiplayer) {
319             if(i < (int) houseInfoListSetup.size()) {
320                 GameInitSettings::HouseInfo gisHouseInfo = houseInfoListSetup.at(i);
321 
322                 if(gisHouseInfo.houseID == HOUSE_UNUSED) {
323                     curHouseInfo.player2DropDown.addEntry(_("closed"), PLAYER_CLOSED);
324                 } else if(gisHouseInfo.playerInfoList.size() >= 2) {
325                     GameInitSettings::PlayerInfo playerInfo = *(++gisHouseInfo.playerInfoList.begin());
326                     if(playerInfo.playerClass == HUMANPLAYERCLASS) {
327                         if(thisPlayerPlaced == false) {
328                             curHouseInfo.player2DropDown.addEntry(settings.general.playerName, PLAYER_HUMAN);
329                             curHouseInfo.player2DropDown.setSelectedItem(0);
330                             thisPlayerPlaced = true;
331                         } else {
332                             curHouseInfo.player2DropDown.addEntry(_("open"), PLAYER_OPEN);
333                             curHouseInfo.player2DropDown.setSelectedItem(0);
334                         }
335                     } else {
336                         const PlayerFactory::PlayerData* pPlayerData = PlayerFactory::getByPlayerClass(playerInfo.playerClass);
337                         int index = PlayerFactory::getIndexByPlayerClass(playerInfo.playerClass);
338 
339                         if(pPlayerData != nullptr) {
340                             curHouseInfo.player1DropDown.addEntry(pPlayerData->getName(), -(index+2));
341                             curHouseInfo.player1DropDown.setSelectedItem(0);
342                             curHouseInfo.player1DropDown.setEnabled(false);
343                             curHouseInfo.player1DropDown.setOnClickEnabled(false);
344                         }
345                     }
346                 }
347             }
348         } else if(bServer && (thisPlayerPlaced == false)) {
349             curHouseInfo.player2DropDown.addEntry(settings.general.playerName, PLAYER_HUMAN);
350             curHouseInfo.player2DropDown.setSelectedItem(0);
351             curHouseInfo.player2DropDown.setEnabled(bServer);
352             thisPlayerPlaced = true;
353         } else {
354             curHouseInfo.player2DropDown.addEntry(_("open"), PLAYER_OPEN);
355             curHouseInfo.player2DropDown.setSelectedItem(0);
356             curHouseInfo.player2DropDown.addEntry(_("closed"), PLAYER_CLOSED);
357             for(unsigned int k = 1; k < PlayerFactory::getList().size(); k++) {
358                 curHouseInfo.player2DropDown.addEntry(PlayerFactory::getByIndex(k)->getName(), k);
359             }
360             curHouseInfo.player2DropDown.setEnabled(bServer);
361         }
362         curHouseInfo.player2DropDown.setOnSelectionChange(std::bind(&CustomGamePlayers::onChangePlayerDropDownBoxes, this, std::placeholders::_1, 2*i + 1));
363         curHouseInfo.player2DropDown.setOnClick(std::bind(&CustomGamePlayers::onClickPlayerDropDownBox, this, 2*i + 1));
364         curHouseInfo.playerHBox.addWidget(&curHouseInfo.player2DropDown, 100);
365 
366         curHouseInfo.houseInfoVBox.addWidget(&curHouseInfo.playerHBox);
367 
368         playerListVBox.addWidget(&curHouseInfo.houseInfoVBox, 0.01);
369 
370         playerListVBox.addWidget(VSpacer::create(4), 0.0);
371         playerListVBox.addWidget(Spacer::create(), 0.07);
372 
373         if(i >= numHouses) {
374             curHouseInfo.houseInfoVBox.setEnabled(false);
375             curHouseInfo.houseInfoVBox.setVisible(false);
376         }
377     }
378 
379     onChangeHousesDropDownBoxes(false);
380 
381     checkPlayerBoxes();
382 
383     leftVBox.addWidget(Spacer::create(), 0.3);
384 
385     // maybe there is a better fitting slot if we are loading a map in the old format with Brain=CPU and Brain=Human
386     if(brainEqHumanSlot >= 0) {
387         DropDownBox& dropDownBox1 = houseInfo[brainEqHumanSlot].player1DropDown;
388         DropDownBox& dropDownBox2 = houseInfo[brainEqHumanSlot].player2DropDown;
389 
390         if(dropDownBox1.getSelectedEntry() != settings.general.playerName && dropDownBox2.getSelectedEntry() != settings.general.playerName) {
391             if(dropDownBox1.getSelectedEntryIntData() == PLAYER_OPEN) {
392                 setPlayer2Slot(settings.general.playerName, brainEqHumanSlot*2);
393             } else if((dropDownBox2.getSelectedEntryIntData() == PLAYER_OPEN) && gameInitSettings.isMultiplePlayersPerHouse()) {
394                 setPlayer2Slot(settings.general.playerName, brainEqHumanSlot*2+1);
395             }
396         }
397     }
398 
399     if(pNetworkManager != nullptr) {
400         if(bServer) {
401             pNetworkManager->startServer(bLANServer, gameInitSettings.getServername(), settings.general.playerName, &gameInitSettings, 1, gameInitSettings.isMultiplePlayersPerHouse() ? numHouses*2 : numHouses);
402         }
403 
404         pNetworkManager->setOnPeerDisconnected(std::bind(&CustomGamePlayers::onPeerDisconnected, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
405         pNetworkManager->setOnReceiveChangeEventList(std::bind(&CustomGamePlayers::onReceiveChangeEventList, this, std::placeholders::_1));
406         pNetworkManager->setOnReceiveChatMessage(std::bind(&CustomGamePlayers::onReceiveChatMessage, this, std::placeholders::_1, std::placeholders::_2));
407 
408         if(bServer) {
409             pNetworkManager->setGetChangeEventListForNewPlayerCallback(std::bind(&CustomGamePlayers::getChangeEventListForNewPlayer, this, std::placeholders::_1));
410         } else {
411             pNetworkManager->setOnStartGame(std::bind(&CustomGamePlayers::onStartGame, this, std::placeholders::_1));
412         }
413     }
414 }
415 
~CustomGamePlayers()416 CustomGamePlayers::~CustomGamePlayers()
417 {
418     if(pNetworkManager != nullptr) {
419         pNetworkManager->disconnect();
420 
421         pNetworkManager->setOnPeerDisconnected(std::function<void (const std::string&, bool, int)>());
422         pNetworkManager->setGetChangeEventListForNewPlayerCallback(std::function<ChangeEventList (const std::string&)>());
423         pNetworkManager->setOnReceiveChangeEventList(std::function<void (const ChangeEventList&)>());
424         pNetworkManager->setOnReceiveChatMessage(std::function<void (const std::string&, const std::string&)>());
425         pNetworkManager->setOnStartGame(std::function<void (unsigned int)>());
426 
427         if(bServer) {
428             pNetworkManager->stopServer();
429         }
430     }
431 }
432 
update()433 void CustomGamePlayers::update() {
434     if(startGameTime > 0) {
435         if(SDL_GetTicks() >= startGameTime) {
436             startGameTime = 0;
437 
438             pNetworkManager->setOnPeerDisconnected(std::function<void (const std::string&, bool, int)>());
439             pNetworkManager->setGetChangeEventListForNewPlayerCallback(std::function<ChangeEventList (const std::string&)>());
440             pNetworkManager->setOnReceiveChangeEventList(std::function<void (const ChangeEventList&)>());
441             pNetworkManager->setOnReceiveChatMessage(std::function<void (const std::string&, const std::string&)>());
442             pNetworkManager->setOnStartGame(std::function<void (unsigned int)>());
443 
444             if(bServer) {
445                 pNetworkManager->stopServer();
446             }
447 
448             addAllPlayersToGameInitSettings();
449             startMultiPlayerGame(gameInitSettings);
450 
451             quit(MENU_QUIT_GAME_FINISHED);
452         } else {
453             static Uint32 lastSecondLeft = 0;
454             Uint32 secondsLeft = ((startGameTime - SDL_GetTicks())/1000) + 1;
455             if(lastSecondLeft != secondsLeft) {
456                 lastSecondLeft = secondsLeft;
457                 addInfoMessage("Starting game in " + stringify(secondsLeft) + "...");
458             }
459         }
460     }
461 }
462 
onReceiveChangeEventList(const ChangeEventList & changeEventList)463 void CustomGamePlayers::onReceiveChangeEventList(const ChangeEventList& changeEventList)
464 {
465     for(const ChangeEventList::ChangeEvent& changeEvent : changeEventList.changeEventList) {
466 
467         switch(changeEvent.eventType) {
468             case ChangeEventList::ChangeEvent::EventType::ChangeHouse: {
469                 HOUSETYPE houseType = (HOUSETYPE) changeEvent.newValue;
470 
471                 HouseInfo& curHouseInfo = houseInfo[changeEvent.slot];
472 
473                 for(int i=0;i<curHouseInfo.houseDropDown.getNumEntries();i++) {
474                     if(curHouseInfo.houseDropDown.getEntryIntData(i) == houseType) {
475                         curHouseInfo.houseDropDown.setSelectedItem(i);
476                         break;
477                     }
478                 }
479             } break;
480 
481             case ChangeEventList::ChangeEvent::EventType::ChangeTeam: {
482                 int newTeam = (int) changeEvent.newValue;
483 
484                 HouseInfo& curHouseInfo = houseInfo[changeEvent.slot];
485 
486                 for(int i=0;i<curHouseInfo.teamDropDown.getNumEntries();i++) {
487                     if(curHouseInfo.teamDropDown.getEntryIntData(i) == newTeam) {
488                         curHouseInfo.teamDropDown.setSelectedItem(i);
489                         break;
490                     }
491                 }
492             } break;
493 
494             case ChangeEventList::ChangeEvent::EventType::ChangePlayer: {
495                 int newPlayer = (int) changeEvent.newValue;
496 
497                 HouseInfo& curHouseInfo = houseInfo[changeEvent.slot/2];
498 
499                 if(changeEvent.slot % 2 == 0) {
500                     for(int i=0;i<curHouseInfo.player1DropDown.getNumEntries();i++) {
501                         if(curHouseInfo.player1DropDown.getEntryIntData(i) == newPlayer) {
502                             curHouseInfo.player1DropDown.setSelectedItem(i);
503                             break;
504                         }
505                     }
506                 } else {
507                     for(int i=0;i<curHouseInfo.player2DropDown.getNumEntries();i++) {
508                         if(curHouseInfo.player2DropDown.getEntryIntData(i) == newPlayer) {
509                             curHouseInfo.player2DropDown.setSelectedItem(i);
510                             break;
511                         }
512                     }
513                 }
514 
515                 checkPlayerBoxes();
516             } break;
517 
518             case ChangeEventList::ChangeEvent::EventType::SetHumanPlayer: {
519                 const std::string& name = changeEvent.newStringValue;
520                 int slot = changeEvent.slot;
521 
522                 setPlayer2Slot(name, slot);
523 
524                 checkPlayerBoxes();
525             } break;
526 
527             default: {
528             } break;
529         }
530     }
531 
532     if((pNetworkManager != nullptr) && bServer) {
533         ChangeEventList changeEventList2 = getChangeEventList();
534 
535         pNetworkManager->sendChangeEventList(changeEventList2);
536     }
537 }
538 
getChangeEventList()539 ChangeEventList CustomGamePlayers::getChangeEventList()
540 {
541     ChangeEventList changeEventList;
542 
543     for(int i=0;i<NUM_HOUSES;i++) {
544         HouseInfo& curHouseInfo = houseInfo[i];
545 
546         int houseID = curHouseInfo.houseDropDown.getSelectedEntryIntData();
547         int team = curHouseInfo.teamDropDown.getSelectedEntryIntData();
548         int player1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
549         int player2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
550 
551         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangeHouse, i, houseID));
552         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangeTeam, i, team));
553 
554         if(player1 == PLAYER_HUMAN) {
555             std::string playername = curHouseInfo.player1DropDown.getSelectedEntry();
556             changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(2*i, playername));
557         } else {
558             changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangePlayer, 2*i, player1));
559         }
560 
561         if(player2 == PLAYER_HUMAN) {
562             std::string playername = curHouseInfo.player2DropDown.getSelectedEntry();
563             changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(2*i+1, playername));
564         } else {
565             changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangePlayer, 2*i+1, player2));
566         }
567     }
568 
569     return changeEventList;
570 }
571 
getChangeEventListForNewPlayer(const std::string & newPlayerName)572 ChangeEventList CustomGamePlayers::getChangeEventListForNewPlayer(const std::string& newPlayerName)
573 {
574     ChangeEventList changeEventList = getChangeEventList();
575 
576     // find a place for the new player
577 
578     int newPlayerSlot = INVALID;
579 
580     // look for an open left slot
581     for(int i=0;i<numHouses;i++) {
582         HouseInfo& curHouseInfo = houseInfo[i];
583         int player1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
584 
585         if(player1 == PLAYER_OPEN) {
586             newPlayerSlot = 2*i;
587             break;
588         }
589     }
590 
591     // if multiple players per house look for an open right slot
592     if((newPlayerSlot == INVALID) && gameInitSettings.isMultiplePlayersPerHouse()) {
593         for(int i=0;i<numHouses;i++) {
594             HouseInfo& curHouseInfo = houseInfo[i];
595             int player2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
596 
597             if(player2 == PLAYER_OPEN) {
598                 newPlayerSlot = 2*i + 1;
599                 break;
600             }
601         }
602     }
603 
604     // as a fallback look for any non-human slot
605     if(newPlayerSlot == INVALID) {
606         for(int i=0;i<numHouses;i++) {
607             HouseInfo& curHouseInfo = houseInfo[i];
608             int player1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
609             int player2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
610 
611             if(player1 != PLAYER_HUMAN) {
612                 newPlayerSlot = 2*i;
613                 break;
614             } else if(gameInitSettings.isMultiplePlayersPerHouse() && (player2 != PLAYER_HUMAN)) {
615                 newPlayerSlot = 2*i + 1;
616                 break;
617             }
618         }
619     }
620 
621     if(newPlayerSlot != INVALID) {
622         setPlayer2Slot(newPlayerName, newPlayerSlot);
623 
624         ChangeEventList::ChangeEvent changeEvent(newPlayerSlot, newPlayerName);
625 
626         // add changeEvent to changeEventList for the new player
627         changeEventList.changeEventList.push_back(changeEvent);
628 
629         // send it to all other connected peers
630         ChangeEventList changeEventList2;
631         changeEventList2.changeEventList.push_back(changeEvent);
632 
633         pNetworkManager->sendChangeEventList(changeEventList2);
634     }
635 
636     return changeEventList;
637 }
638 
onReceiveChatMessage(const std::string & name,const std::string & message)639 void CustomGamePlayers::onReceiveChatMessage(const std::string& name, const std::string& message) {
640     addChatMessage(name, message);
641 }
642 
onNext()643 void CustomGamePlayers::onNext()
644 {
645     // check if we have at least two houses on the map and if we have more than one team
646     int numUsedHouses = 0;
647     int numTeams = 0;
648     for(int i=0;i<NUM_HOUSES;i++) {
649         HouseInfo& curHouseInfo = houseInfo[i];
650 
651         int currentPlayer1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
652         int currentPlayer2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
653 
654         if((currentPlayer1 != PLAYER_OPEN && currentPlayer1 != PLAYER_CLOSED) || (currentPlayer2 != PLAYER_OPEN && currentPlayer2 != PLAYER_CLOSED)) {
655             numUsedHouses++;
656 
657             int currentTeam = curHouseInfo.teamDropDown.getSelectedEntryIntData();
658             bool bTeamFound = false;
659             for(int j=0;j<i;j++) {
660                 int player1 = houseInfo[j].player1DropDown.getSelectedEntryIntData();
661                 int player2 = houseInfo[j].player2DropDown.getSelectedEntryIntData();
662 
663                 if((player1 != PLAYER_OPEN && player1 != PLAYER_CLOSED) || (player2 != PLAYER_OPEN && player2 != PLAYER_CLOSED)) {
664 
665                     int team = houseInfo[j].teamDropDown.getSelectedEntryIntData();
666                     if(currentTeam == team) {
667                         bTeamFound = true;
668                     }
669                 }
670             }
671 
672             if(bTeamFound == false) {
673                 numTeams++;
674             }
675         }
676     }
677 
678     if(numUsedHouses < 2) {
679         // No game possible with only 1 house
680         openWindow(MsgBox::create(_("At least 2 houses must be controlled\nby a human player or an AI player!")));
681     } else if(numTeams < 2) {
682         // No game possible with only 1 team
683         openWindow(MsgBox::create(_("There must be at least two different teams!")));
684     } else {
685         // start game
686 
687         addAllPlayersToGameInitSettings();
688 
689         if(pNetworkManager != nullptr) {
690             unsigned int timeLeft = 5000;
691             startGameTime = SDL_GetTicks() + timeLeft;
692             pNetworkManager->sendStartGame(timeLeft);
693 
694             disableAllDropDownBoxes();
695         } else {
696             startSinglePlayerGame(gameInitSettings);
697 
698             quit(MENU_QUIT_GAME_FINISHED);
699         }
700     }
701 }
702 
addAllPlayersToGameInitSettings()703 void CustomGamePlayers::addAllPlayersToGameInitSettings()
704 {
705     gameInitSettings.clearHouseInfo();
706 
707     for(int i=0;i<NUM_HOUSES;i++) {
708         HouseInfo& curHouseInfo = houseInfo[i];
709 
710         int houseID = curHouseInfo.houseDropDown.getSelectedEntryIntData();
711         int team = curHouseInfo.teamDropDown.getSelectedEntryIntData();
712         int player1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
713         std::string player1name = curHouseInfo.player1DropDown.getSelectedEntry();
714         int player2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
715         std::string player2name = curHouseInfo.player2DropDown.getSelectedEntry();
716 
717         GameInitSettings::HouseInfo newHouseInfo((HOUSETYPE) houseID, team);
718 
719         bool bAdded = false;
720         bAdded |= addPlayerToHouseInfo(newHouseInfo, player1, player1name);
721         bAdded |= addPlayerToHouseInfo(newHouseInfo, player2, player2name);
722 
723         if(bAdded == true) {
724             gameInitSettings.addHouseInfo(newHouseInfo);
725         }
726     }
727 }
728 
addPlayerToHouseInfo(GameInitSettings::HouseInfo & newHouseInfo,int player,const std::string & playername)729 bool CustomGamePlayers::addPlayerToHouseInfo(GameInitSettings::HouseInfo& newHouseInfo, int player, const std::string& playername)
730 {
731     std::string playerName;
732     std::string playerClass;
733 
734     HOUSETYPE houseID = newHouseInfo.houseID;
735 
736     switch(player) {
737         case PLAYER_HUMAN: {
738             playerName = playername;
739             playerClass = HUMANPLAYERCLASS;
740         } break;
741 
742         case PLAYER_OPEN:
743         case PLAYER_CLOSED: {
744             return false;
745         } break;
746 
747 
748         default: {
749             // AI player
750             const PlayerFactory::PlayerData* pPlayerData = PlayerFactory::getByIndex(player);
751             if(pPlayerData == nullptr) {
752                 return false;
753             }
754 
755             playerName = (houseID == HOUSE_INVALID) ? pPlayerData->getName() : getHouseNameByNumber(houseID);
756             playerClass = pPlayerData->getPlayerClass();
757 
758         } break;
759     }
760 
761     newHouseInfo.addPlayerInfo(GameInitSettings::PlayerInfo(playerName, playerClass));
762     return true;
763 }
764 
onCancel()765 void CustomGamePlayers::onCancel()
766 {
767     quit();
768 }
769 
onSendChatMessage()770 void CustomGamePlayers::onSendChatMessage()
771 {
772     std::string message = chatTextBox.getText();
773     addChatMessage(settings.general.playerName, message);
774     chatTextBox.setText("");
775 
776     pNetworkManager->sendChatMessage(message);
777 
778 }
779 
addInfoMessage(const std::string & message)780 void CustomGamePlayers::addInfoMessage(const std::string& message) {
781     std::string text = chatTextView.getText();
782     if(text.length() > 0) {
783         text += "\n";
784     }
785     text += "* " + message;
786     chatTextView.setText(text);
787     chatTextView.scrollToEnd();
788 }
789 
addChatMessage(const std::string & name,const std::string & message)790 void CustomGamePlayers::addChatMessage(const std::string& name, const std::string& message)
791 {
792     std::string text = chatTextView.getText();
793     if(text.length() > 0) {
794         text += "\n";
795     }
796     text += name + ": " + message;
797     chatTextView.setText(text);
798     chatTextView.scrollToEnd();
799 }
800 
extractMapInfo(std::shared_ptr<INIFile> & pMap)801 void CustomGamePlayers::extractMapInfo(std::shared_ptr<INIFile>& pMap)
802 {
803     int sizeX = 0;
804     int sizeY = 0;
805 
806     if(pMap->hasKey("MAP","Seed")) {
807         // old map format with seed value
808         int mapscale = pMap->getIntValue("BASIC", "MapScale", -1);
809 
810         switch(mapscale) {
811             case 0: {
812                 sizeX = 62;
813                 sizeY = 62;
814             } break;
815 
816             case 1: {
817                 sizeX = 32;
818                 sizeY = 32;
819             } break;
820 
821             case 2: {
822                 sizeX = 21;
823                 sizeY = 21;
824             } break;
825 
826             default: {
827                 sizeX = 64;
828                 sizeY = 64;
829             }
830         }
831     } else {
832         // new map format with saved map
833         sizeX = pMap->getIntValue("MAP","SizeX", 0);
834         sizeY = pMap->getIntValue("MAP","SizeY", 0);
835     }
836 
837     mapPropertySize.setText(stringify(sizeX) + " x " + stringify(sizeY));
838 
839     SDL_Surface* pMapSurface = nullptr;
840     try {
841         INIMapPreviewCreator mapPreviewCreator(pMap);
842         pMapSurface = mapPreviewCreator.createMinimapImageOfMap(1, DuneStyle::buttonBorderColor);
843     } catch(...) {
844         pMapSurface = GUIStyle::getInstance().createButtonSurface(130, 130, "Error", true, false);
845         nextButton.setEnabled(false);
846     }
847     minimap.setSurface(pMapSurface, true);
848 
849 
850     boundHousesOnMap.clear();
851     if(pMap->hasSection("Harkonnen")) boundHousesOnMap.push_back(HOUSE_HARKONNEN);
852     if(pMap->hasSection("Atreides"))  boundHousesOnMap.push_back(HOUSE_ATREIDES);
853     if(pMap->hasSection("Ordos"))     boundHousesOnMap.push_back(HOUSE_ORDOS);
854     if(pMap->hasSection("Fremen"))    boundHousesOnMap.push_back(HOUSE_FREMEN);
855     if(pMap->hasSection("Sardaukar")) boundHousesOnMap.push_back(HOUSE_SARDAUKAR);
856     if(pMap->hasSection("Mercenary")) boundHousesOnMap.push_back(HOUSE_MERCENARY);
857 
858     numHouses = boundHousesOnMap.size();
859     if(pMap->hasSection("Player1"))   numHouses++;
860     if(pMap->hasSection("Player2"))   numHouses++;
861     if(pMap->hasSection("Player3"))   numHouses++;
862     if(pMap->hasSection("Player4"))   numHouses++;
863     if(pMap->hasSection("Player5"))   numHouses++;
864     if(pMap->hasSection("Player6"))   numHouses++;
865 
866     mapPropertyPlayers.setText(stringify(numHouses));
867 
868     std::string authors = pMap->getStringValue("BASIC","Author", "-");
869     if(authors.size() > 11) {
870         authors = authors.substr(0,9) + "...";
871     }
872     mapPropertyAuthors.setText(authors);
873 
874 
875     mapPropertyLicense.setText(pMap->getStringValue("BASIC","License", "-"));
876 
877     // find Brain=Human
878     int currentIndex = 0;
879     for(const HOUSETYPE& houseType : boundHousesOnMap) {
880         if(strToUpper(pMap->getStringValue(getHouseNameByNumber(houseType),"Brain","")) == "HUMAN") {
881             brainEqHumanSlot = currentIndex;
882         }
883         currentIndex++;
884     }
885 
886     currentIndex = 0;
887     int currentTeam = 0;
888     std::vector<std::string> teamNames;
889     for(const HOUSETYPE& houseType : boundHousesOnMap) {
890         std::string teamName = strToUpper(pMap->getStringValue(getHouseNameByNumber(houseType),"Brain","Team " + stringify(currentIndex+1)));
891         teamNames.push_back(teamName);
892         slotToTeam[currentIndex] = currentTeam;
893         currentTeam++;
894 
895         // let's see if we can reuse an old team number
896         for(unsigned int i = 0; i < teamNames.size()-1; i++) {
897             if(teamNames[i] == teamName) {
898                 slotToTeam[currentIndex] = slotToTeam[i];
899                 currentTeam--;
900                 break;
901             }
902         }
903 
904         currentIndex++;
905     }
906 
907     for(int p = 0; (p < NUM_HOUSES) && (currentIndex < NUM_HOUSES); p++) {
908         if(pMap->hasSection("Player" + stringify(p+1))) {
909             std::string teamName = strToUpper(pMap->getStringValue("Player" + stringify(p+1),"Brain","Team " + stringify(currentIndex+p+1)));
910             teamNames.push_back(teamName);
911             slotToTeam[currentIndex] = currentTeam;
912             currentTeam++;
913 
914             // let's see if we can reuse an old team number
915             for(unsigned int i = 0; i < teamNames.size()-1; i++) {
916                 if(teamNames[i] == teamName) {
917                     slotToTeam[currentIndex] = slotToTeam[i];
918                     currentTeam--;
919                     break;
920                 }
921             }
922 
923             currentIndex++;
924         }
925     }
926 
927     for(;currentIndex < NUM_HOUSES; currentIndex++) {
928         slotToTeam[currentIndex] = -1;
929     }
930 }
931 
onChangeHousesDropDownBoxes(bool bInteractive,int houseInfoNum)932 void CustomGamePlayers::onChangeHousesDropDownBoxes(bool bInteractive, int houseInfoNum) {
933     if(bInteractive && houseInfoNum >= 0 && pNetworkManager != nullptr) {
934         int selectedHouseID = houseInfo[houseInfoNum].houseDropDown.getSelectedEntryIntData();
935 
936         ChangeEventList changeEventList;
937         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangeHouse, houseInfoNum, selectedHouseID));
938 
939         pNetworkManager->sendChangeEventList(changeEventList);
940     }
941 
942     int numBoundHouses = boundHousesOnMap.size();
943     int numUsedBoundHouses = 0;
944     int numUsedRandomHouses = 0;
945     for(int i=0;i<numHouses;i++) {
946         int selectedHouseID = houseInfo[i].houseDropDown.getSelectedEntryIntData();
947 
948         if(selectedHouseID == HOUSE_INVALID) {
949             numUsedRandomHouses++;
950         } else {
951             if(isBoundedHouseOnMap((HOUSETYPE) selectedHouseID)) {
952                 numUsedBoundHouses++;
953             }
954         }
955     }
956 
957 
958     for(int i=0;i<numHouses;i++) {
959         HouseInfo& curHouseInfo = houseInfo[i];
960 
961         int house = curHouseInfo.houseDropDown.getSelectedEntryIntData();
962 
963         if(houseInfoNum == -1 || houseInfoNum == i) {
964 
965             Uint32 color = (house == HOUSE_INVALID) ? COLOR_RGB(20,20,40) : SDL2RGB(palette[houseToPaletteIndex[house] + 3]);
966             curHouseInfo.houseLabel.setTextColor(color);
967             curHouseInfo.houseDropDown.setColor(color);
968             curHouseInfo.teamDropDown.setColor(color);
969             curHouseInfo.player1Label.setTextColor(color);
970             curHouseInfo.player1DropDown.setColor(color);
971             curHouseInfo.player2Label.setTextColor(color);
972             curHouseInfo.player2DropDown.setColor(color);
973 
974             if(house == HOUSE_INVALID) {
975                 curHouseInfo.player1ArrowLabel.setTexture(pGFXManager->getUIGraphic(UI_CustomGamePlayersArrowNeutral), false);
976             } else {
977                 curHouseInfo.player1ArrowLabel.setTexture(pGFXManager->getUIGraphic(UI_CustomGamePlayersArrow, house), false);
978             }
979         }
980 
981         if(gameInitSettings.getGameType() == GameType::LoadMultiplayer) {
982             // no house changes possible
983             continue;
984         }
985 
986         addToHouseDropDown(curHouseInfo.houseDropDown, HOUSE_INVALID);
987 
988         for(int h=0;h<NUM_HOUSES;h++) {
989             bool bAddHouse;
990 
991             bool bCheck;
992 
993             if((house == HOUSE_INVALID) || (isBoundedHouseOnMap((HOUSETYPE) house))) {
994                 if(numUsedBoundHouses + numUsedRandomHouses - 1 >= numBoundHouses) {
995                     bCheck = true;
996                 } else {
997                     bCheck = false;
998                 }
999             } else {
1000                 if(numUsedBoundHouses + numUsedRandomHouses >= numBoundHouses) {
1001                     bCheck = true;
1002                 } else {
1003                     bCheck = false;
1004                 }
1005             }
1006 
1007             if(bCheck == true) {
1008                 bAddHouse = true;
1009                 for(int j = 0; j < numHouses; j++) {
1010                     if(i != j) {
1011                         DropDownBox& tmpDropDown = houseInfo[j].houseDropDown;
1012                         if(tmpDropDown.getSelectedEntryIntData() == h) {
1013                             bAddHouse = false;
1014                             break;
1015                         }
1016                     }
1017                 }
1018             } else {
1019                 bAddHouse = (h == house);
1020 
1021                 if(((house == HOUSE_INVALID) || (isBoundedHouseOnMap((HOUSETYPE) house))) && isBoundedHouseOnMap((HOUSETYPE) h)) {
1022                     // check if this entry is random or a bounded house but is needed for a bounded house
1023                     bAddHouse = true;
1024                     for(int j = 0; j < numHouses; j++) {
1025                         if(i != j) {
1026                             DropDownBox& tmpDropDown = houseInfo[j].houseDropDown;
1027                             if(tmpDropDown.getSelectedEntryIntData() == h) {
1028                                 bAddHouse = false;
1029                                 break;
1030                             }
1031                         }
1032                     }
1033                 }
1034             }
1035 
1036             if(bAddHouse == true) {
1037                 addToHouseDropDown(curHouseInfo.houseDropDown, h);
1038             } else {
1039                 removeFromHouseDropDown(curHouseInfo.houseDropDown, h);
1040             }
1041         }
1042     }
1043 }
1044 
onChangeTeamDropDownBoxes(bool bInteractive,int houseInfoNum)1045 void CustomGamePlayers::onChangeTeamDropDownBoxes(bool bInteractive, int houseInfoNum) {
1046 
1047     if(bInteractive && houseInfoNum >= 0 && pNetworkManager != nullptr) {
1048         int selectedTeam = houseInfo[houseInfoNum].teamDropDown.getSelectedEntryIntData();
1049 
1050         ChangeEventList changeEventList;
1051         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangeTeam, houseInfoNum, selectedTeam));
1052 
1053         pNetworkManager->sendChangeEventList(changeEventList);
1054     }
1055 }
1056 
onChangePlayerDropDownBoxes(bool bInteractive,int boxnum)1057 void CustomGamePlayers::onChangePlayerDropDownBoxes(bool bInteractive, int boxnum) {
1058     if(bInteractive && boxnum >= 0 && pNetworkManager != nullptr) {
1059         DropDownBox& dropDownBox = (boxnum % 2 == 0) ? houseInfo[boxnum / 2].player1DropDown : houseInfo[boxnum / 2].player2DropDown;
1060 
1061         int selectedPlayer = dropDownBox.getSelectedEntryIntData();
1062 
1063         ChangeEventList changeEventList;
1064         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(ChangeEventList::ChangeEvent::EventType::ChangePlayer, boxnum, selectedPlayer));
1065 
1066         pNetworkManager->sendChangeEventList(changeEventList);
1067     }
1068 
1069     checkPlayerBoxes();
1070 }
1071 
onClickPlayerDropDownBox(int boxnum)1072 void CustomGamePlayers::onClickPlayerDropDownBox(int boxnum) {
1073     DropDownBox& dropDownBox = (boxnum % 2 == 0) ? houseInfo[boxnum / 2].player1DropDown : houseInfo[boxnum / 2].player2DropDown;
1074 
1075     if(dropDownBox.getSelectedEntryIntData() == PLAYER_CLOSED) {
1076         return;
1077     }
1078 
1079     setPlayer2Slot(settings.general.playerName, boxnum);
1080 
1081     if(boxnum >= 0 && pNetworkManager != nullptr) {
1082         ChangeEventList changeEventList;
1083         changeEventList.changeEventList.push_back(ChangeEventList::ChangeEvent(boxnum, settings.general.playerName));
1084 
1085         pNetworkManager->sendChangeEventList(changeEventList);
1086     }
1087 }
1088 
onPeerDisconnected(const std::string & playername,bool bHost,int cause)1089 void CustomGamePlayers::onPeerDisconnected(const std::string& playername, bool bHost, int cause) {
1090     if(bHost) {
1091         quit(cause);
1092     } else {
1093         for(int i=0;i<numHouses*2;i++) {
1094             DropDownBox& curDropDownBox = (i % 2 == 0) ? houseInfo[i / 2].player1DropDown : houseInfo[i / 2].player2DropDown;
1095 
1096             if(curDropDownBox.getSelectedEntryIntData() == PLAYER_HUMAN && curDropDownBox.getSelectedEntry() == playername) {
1097 
1098                 curDropDownBox.clearAllEntries();
1099                 curDropDownBox.addEntry(_("open"), PLAYER_OPEN);
1100                 curDropDownBox.setSelectedItem(0);
1101 
1102                 if(gameInitSettings.getGameType() != GameType::LoadMultiplayer) {
1103                     curDropDownBox.addEntry(_("closed"), PLAYER_CLOSED);
1104                     for(unsigned int k = 1; k < PlayerFactory::getList().size(); k++) {
1105                         curDropDownBox.addEntry(PlayerFactory::getByIndex(k)->getName(), k);
1106                     }
1107                 }
1108 
1109                 break;
1110             }
1111         }
1112 
1113         if(bServer == false) {
1114             for(int i=0;i<numHouses;i++) {
1115                 bool bIsThisPlayer = false;
1116                 if(houseInfo[i].player1DropDown.getSelectedEntryIntData() == PLAYER_HUMAN) {
1117                     if(houseInfo[i].player1DropDown.getSelectedEntry() == settings.general.playerName) {
1118                         bIsThisPlayer = true;
1119                     }
1120                 }
1121 
1122                 if(houseInfo[i].player2DropDown.getSelectedEntryIntData() == PLAYER_HUMAN) {
1123                     if(houseInfo[i].player2DropDown.getSelectedEntry() == settings.general.playerName) {
1124                         bIsThisPlayer = true;
1125                     }
1126                 }
1127 
1128                 houseInfo[i].player1DropDown.setEnabled(bIsThisPlayer);
1129                 houseInfo[i].player2DropDown.setEnabled(bIsThisPlayer);
1130                 houseInfo[i].houseDropDown.setEnabled(bIsThisPlayer);
1131                 houseInfo[i].teamDropDown.setEnabled(bIsThisPlayer);
1132             }
1133         }
1134 
1135         checkPlayerBoxes();
1136 
1137         addInfoMessage(playername + " disconnected!");
1138     }
1139 }
1140 
onStartGame(unsigned int timeLeft)1141 void CustomGamePlayers::onStartGame(unsigned int timeLeft) {
1142     startGameTime = SDL_GetTicks() + timeLeft;
1143     disableAllDropDownBoxes();
1144 }
1145 
setPlayer2Slot(const std::string & playername,int slot)1146 void CustomGamePlayers::setPlayer2Slot(const std::string& playername, int slot) {
1147     DropDownBox& dropDownBox = (slot % 2 == 0) ? houseInfo[slot / 2].player1DropDown : houseInfo[slot / 2].player2DropDown;
1148 
1149     std::string oldPlayerName = "";
1150     int oldPlayerType = dropDownBox.getSelectedEntryIntData();
1151     if(oldPlayerType == PLAYER_HUMAN) {
1152         oldPlayerName = dropDownBox.getSelectedEntry();
1153     }
1154 
1155     for(int i=0;i<numHouses*2;i++) {
1156         DropDownBox& curDropDownBox = (i % 2 == 0) ? houseInfo[i / 2].player1DropDown : houseInfo[i / 2].player2DropDown;
1157 
1158         if(curDropDownBox.getSelectedEntryIntData() == PLAYER_HUMAN && curDropDownBox.getSelectedEntry() == playername) {
1159 
1160             if(oldPlayerType == PLAYER_HUMAN) {
1161                 curDropDownBox.clearAllEntries();
1162                 curDropDownBox.addEntry(oldPlayerName, PLAYER_HUMAN);
1163                 curDropDownBox.setSelectedItem(0);
1164             } else {
1165                 curDropDownBox.clearAllEntries();
1166                 curDropDownBox.addEntry(_("open"), PLAYER_OPEN);
1167 
1168                 if(gameInitSettings.getGameType() != GameType::LoadMultiplayer) {
1169                     curDropDownBox.addEntry(_("closed"), PLAYER_CLOSED);
1170                     for(unsigned int k = 1; k < PlayerFactory::getList().size(); k++) {
1171                         curDropDownBox.addEntry(PlayerFactory::getByIndex(k)->getName(), k);
1172                     }
1173                 }
1174 
1175                 for(int j = 0; j < curDropDownBox.getNumEntries(); j++) {
1176                     if(curDropDownBox.getEntryIntData(j) == oldPlayerType) {
1177                         curDropDownBox.setSelectedItem(j);
1178                         break;
1179                     }
1180                 }
1181             }
1182 
1183             break;
1184         }
1185     }
1186 
1187     dropDownBox.clearAllEntries();
1188     dropDownBox.addEntry(playername, PLAYER_HUMAN);
1189     dropDownBox.setSelectedItem(0);
1190 
1191     if(bServer == false) {
1192         for(int i=0;i<numHouses;i++) {
1193             bool bIsThisPlayer = false;
1194 
1195             if(gameInitSettings.getGameType() != GameType::LoadMultiplayer) {
1196                 if(houseInfo[i].player1DropDown.getSelectedEntryIntData() == PLAYER_HUMAN) {
1197                     if(houseInfo[i].player1DropDown.getSelectedEntry() == settings.general.playerName) {
1198                         bIsThisPlayer = true;
1199                     }
1200                 }
1201 
1202                 if(houseInfo[i].player2DropDown.getSelectedEntryIntData() == PLAYER_HUMAN) {
1203                     if(houseInfo[i].player2DropDown.getSelectedEntry() == settings.general.playerName) {
1204                         bIsThisPlayer = true;
1205                     }
1206                 }
1207             }
1208 
1209             houseInfo[i].player1DropDown.setEnabled(bIsThisPlayer);
1210             houseInfo[i].player2DropDown.setEnabled(bIsThisPlayer);
1211             houseInfo[i].houseDropDown.setEnabled(bIsThisPlayer);
1212             houseInfo[i].teamDropDown.setEnabled(bIsThisPlayer);
1213         }
1214     }
1215 
1216     checkPlayerBoxes();
1217 }
1218 
checkPlayerBoxes()1219 void CustomGamePlayers::checkPlayerBoxes() {
1220     int numPlayers = 0;
1221 
1222     for(int i=0;i<numHouses;i++) {
1223         HouseInfo& curHouseInfo = houseInfo[i];
1224 
1225         int player1 = curHouseInfo.player1DropDown.getSelectedEntryIntData();
1226         int player2 = curHouseInfo.player2DropDown.getSelectedEntryIntData();
1227 
1228         if(player1 != PLAYER_OPEN) {
1229             numPlayers++;
1230         }
1231 
1232         if(gameInitSettings.isMultiplePlayersPerHouse() && player2 != PLAYER_OPEN) {
1233             numPlayers++;
1234         }
1235 
1236         if((gameInitSettings.isMultiplePlayersPerHouse() == false) || (player1 == PLAYER_OPEN && player2 == PLAYER_OPEN) || (curHouseInfo.player2DropDown.getNumEntries() == 0)) {
1237             curHouseInfo.player2DropDown.setVisible(false);
1238             curHouseInfo.player2DropDown.setEnabled(false);
1239             curHouseInfo.player2Label.setVisible(false);
1240         } else {
1241             curHouseInfo.player2DropDown.setVisible(true);
1242 
1243             bool bEnableDropDown2 = bServer;
1244             if(bServer == false) {
1245                 if(player1 == PLAYER_HUMAN) {
1246                     if(curHouseInfo.player1DropDown.getSelectedEntry() == settings.general.playerName) {
1247                         bEnableDropDown2 = true;
1248                     }
1249                 }
1250 
1251                 if(player2 == PLAYER_HUMAN) {
1252                     if(curHouseInfo.player2DropDown.getSelectedEntry() == settings.general.playerName) {
1253                         bEnableDropDown2 = true;
1254                     }
1255                 }
1256             }
1257 
1258             if((gameInitSettings.getGameType() == GameType::LoadMultiplayer) && (player2 != PLAYER_OPEN) && (player2 != PLAYER_HUMAN)) {
1259                 curHouseInfo.player2DropDown.setEnabled(false);
1260             } else {
1261                 curHouseInfo.player2DropDown.setEnabled(bEnableDropDown2);
1262             }
1263             curHouseInfo.player2Label.setVisible(true);
1264         }
1265     }
1266 
1267     if(pNetworkManager != nullptr) {
1268         if(bServer) {
1269             pNetworkManager->updateServer(numPlayers);
1270         }
1271     }
1272 }
1273 
1274 
addToHouseDropDown(DropDownBox & houseDropDownBox,int house,bool bSelect)1275 void CustomGamePlayers::addToHouseDropDown(DropDownBox& houseDropDownBox, int house, bool bSelect) {
1276 
1277     if(houseDropDownBox.getNumEntries() == 0) {
1278         if(house == HOUSE_INVALID) {
1279             houseDropDownBox.addEntry(_("Random"), HOUSE_INVALID);
1280         } else {
1281             houseDropDownBox.addEntry(getHouseNameByNumber((HOUSETYPE) house), house);
1282         }
1283 
1284         if(bSelect) {
1285             houseDropDownBox.setSelectedItem(0);
1286         }
1287     } else {
1288 
1289         if(house == HOUSE_INVALID) {
1290             if(houseDropDownBox.getEntryIntData(0) != HOUSE_INVALID) {
1291                 houseDropDownBox.insertEntry(0, _("Random"), HOUSE_INVALID);
1292             }
1293 
1294             if(bSelect) {
1295                 houseDropDownBox.setSelectedItem(houseDropDownBox.getNumEntries()-1);
1296             }
1297         } else {
1298 
1299             int currentItemIndex = (houseDropDownBox.getEntryIntData(0) == HOUSE_INVALID) ? 1 : 0;
1300 
1301             for(int h = 0; h < NUM_HOUSES; h++) {
1302                 if(currentItemIndex < houseDropDownBox.getNumEntries() && houseDropDownBox.getEntryIntData(currentItemIndex) == h) {
1303                     if(h == house) {
1304                         if(bSelect) {
1305                             houseDropDownBox.setSelectedItem(currentItemIndex);
1306                         }
1307                         break;
1308                     }
1309 
1310                     currentItemIndex++;
1311                 } else {
1312                     if(h == house) {
1313                         houseDropDownBox.insertEntry(currentItemIndex, getHouseNameByNumber((HOUSETYPE) h), h);
1314 
1315                         if(bSelect) {
1316                             houseDropDownBox.setSelectedItem(currentItemIndex);
1317                         }
1318                         break;
1319                     }
1320                 }
1321 
1322 
1323             }
1324         }
1325     }
1326 }
1327 
removeFromHouseDropDown(DropDownBox & houseDropDownBox,int house)1328 void CustomGamePlayers::removeFromHouseDropDown(DropDownBox& houseDropDownBox, int house) {
1329 
1330     for(int i=0;i<houseDropDownBox.getNumEntries(); i++) {
1331         if(houseDropDownBox.getEntryIntData(i) == house) {
1332             houseDropDownBox.removeEntry(i);
1333             break;
1334         }
1335     }
1336 }
1337 
isBoundedHouseOnMap(HOUSETYPE houseID)1338 bool CustomGamePlayers::isBoundedHouseOnMap(HOUSETYPE houseID) {
1339     return (std::find(boundHousesOnMap.begin(), boundHousesOnMap.end(), houseID) != boundHousesOnMap.end());
1340 }
1341 
disableAllDropDownBoxes()1342 void CustomGamePlayers::disableAllDropDownBoxes() {
1343     for(int i=0;i<NUM_HOUSES;i++) {
1344         HouseInfo& curHouseInfo = houseInfo[i];
1345 
1346         curHouseInfo.houseDropDown.setEnabled(false);
1347         curHouseInfo.houseDropDown.setOnClickEnabled(false);
1348         curHouseInfo.teamDropDown.setEnabled(false);
1349         curHouseInfo.teamDropDown.setOnClickEnabled(false);
1350         curHouseInfo.player1DropDown.setEnabled(false);
1351         curHouseInfo.player1DropDown.setOnClickEnabled(false);
1352         curHouseInfo.player2DropDown.setEnabled(false);
1353         curHouseInfo.player2DropDown.setOnClickEnabled(false);
1354     }
1355 
1356     backButton.setEnabled(false);
1357     nextButton.setEnabled(false);
1358 }
1359