// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2005 Marti�o Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "menu_state_custom_game.h" #include "renderer.h" #include "sound_renderer.h" #include "core_data.h" #include "config.h" #include "menu_state_new_game.h" #include "metrics.h" #include "network_manager.h" #include "network_message.h" #include "client_interface.h" #include "conversion.h" #include "socket.h" #include "game.h" #include "util.h" #include #include #include #include "leak_dumper.h" namespace Glest{ namespace Game{ using namespace Shared::Util; struct FormatString { void operator()(string &s) { s = formatString(s); } }; // ===================================================== // class MenuStateCustomGame // ===================================================== MenuStateCustomGame::MenuStateCustomGame(Program *program, MainMenu *mainMenu, bool openNetworkSlots): MenuState(program, mainMenu, "new-game") { Lang &lang= Lang::getInstance(); NetworkManager &networkManager= NetworkManager::getInstance(); Config &config = Config::getInstance(); needToSetChangedGameSettings = false; lastSetChangedGameSettings = time(NULL); lastMasterserverPublishing = time(NULL); vector teamItems, controlItems, results; //create buttonReturn.init(350, 180, 125); buttonPlayNow.init(525, 180, 125); //map listBox // put them all in a set, to weed out duplicates (gbm & mgm with same name) // will also ensure they are alphabetically listed (rather than how the OS provides them) set allMaps; findAll(config.getPathListForType(ptMaps), "*.gbm", results, true, false); copy(results.begin(), results.end(), std::inserter(allMaps, allMaps.begin())); results.clear(); findAll(config.getPathListForType(ptMaps), "*.mgm", results, true, false); copy(results.begin(), results.end(), std::inserter(allMaps, allMaps.begin())); results.clear(); if (allMaps.empty()) { throw runtime_error("No maps were found!"); } copy(allMaps.begin(), allMaps.end(), std::back_inserter(results)); mapFiles = results; std::for_each(results.begin(), results.end(), FormatString()); listBoxMap.init(100, 260, 200); listBoxMap.setItems(results); labelMap.init(100, 290); labelMapInfo.init(100, 230, 200, 40); // fog - o - war // @350 ? 300 ? labelFogOfWar.init(350, 290, 100); listBoxFogOfWar.init(350, 260, 100); listBoxFogOfWar.pushBackItem(lang.get("Yes")); listBoxFogOfWar.pushBackItem(lang.get("No")); listBoxFogOfWar.setSelectedItemIndex(0); //tileset listBox findDirs(config.getPathListForType(ptTilesets), results); if (results.empty()) { throw runtime_error("No tile-sets were found!"); } tilesetFiles= results; std::for_each(results.begin(), results.end(), FormatString()); listBoxTileset.init(500, 260, 150); listBoxTileset.setItems(results); labelTileset.init(500, 290); //tech Tree listBox findDirs(config.getPathListForType(ptTechs), results); if(results.empty()) { throw runtime_error("No tech-trees were found!"); } techTreeFiles= results; std::for_each(results.begin(), results.end(), FormatString()); listBoxTechTree.init(700, 260, 150); listBoxTechTree.setItems(results); labelTechTree.init(700, 290); labelPublishServer.init(350, 690, 100); labelPublishServer.setText(lang.get("Publish Server")); listBoxPublishServer.init(350, 660, 100); listBoxPublishServer.pushBackItem(lang.get("Yes")); listBoxPublishServer.pushBackItem(lang.get("No")); listBoxPublishServer.setSelectedItemIndex(1); //list boxes for(int i=0; i techPaths = config.getPathListForType(ptTechs); for(int idx = 0; idx < techPaths.size(); idx++) { string &techPath = techPaths[idx]; findAll(techPath + "/" + techTreeFiles[listBoxTechTree.getSelectedItemIndex()] + "/factions/*.", results, false, false); if(results.size() > 0) { break; } } if(results.size() == 0) { throw runtime_error("(1)There are no factions for the tech tree [" + techTreeFiles[listBoxTechTree.getSelectedItemIndex()] + "]"); } for(int i=0; isetState(new MenuStateNewGame(program, mainMenu)); } else if(buttonPlayNow.mouseClick(x,y) && buttonPlayNow.getEnabled()) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); closeUnusedSlots(); soundRenderer.playFx(coreData.getClickSoundC()); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); GameSettings gameSettings; loadGameSettings(&gameSettings); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); // Send the game settings to each client if we have at least one networked client if( hasNetworkGameSettings() == true && needToSetChangedGameSettings == true) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); serverInterface->setGameSettings(&gameSettings,true); needToSetChangedGameSettings = false; lastSetChangedGameSettings = time(NULL); } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); bool bOkToStart = serverInterface->launchGame(&gameSettings); if(bOkToStart == true) { program->setState(new Game(program, &gameSettings)); } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); } else if(listBoxMap.mouseClick(x, y)){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n", mapFiles[listBoxMap.getSelectedItemIndex()].c_str()); loadMapInfo(Map::getMapPath(mapFiles[listBoxMap.getSelectedItemIndex()]), &mapInfo); labelMapInfo.setText(mapInfo.desc); updateControlers(); updateNetworkSlots(); if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if (listBoxFogOfWar.mouseClick(x, y)) { if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if(listBoxTileset.mouseClick(x, y)){ if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if(listBoxTechTree.mouseClick(x, y)){ reloadFactions(); if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if(listBoxPublishServer.mouseClick(x, y)&&listBoxPublishServer.getEditable()){ soundRenderer.playFx(coreData.getClickSoundC()); } else { for(int i=0; i(listBoxControls[j].getSelectedItemIndex()); if(ct==ctHuman){ if(humanIndex1==-1){ humanIndex1= j; } else{ humanIndex2= j; } } } //no human if(humanIndex1==-1 && humanIndex2==-1){ listBoxControls[i].setSelectedItemIndex(ctHuman); } //2 humans if(humanIndex1!=-1 && humanIndex2!=-1){ listBoxControls[humanIndex1==i? humanIndex2: humanIndex1].setSelectedItemIndex(ctClosed); } updateNetworkSlots(); if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if(listBoxFactions[i].mouseClick(x, y)){ if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } else if(listBoxTeams[i].mouseClick(x, y)) { if(hasNetworkGameSettings() == true) { needToSetChangedGameSettings = true; lastSetChangedGameSettings = time(NULL);; } } } } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); } void MenuStateCustomGame::mouseMove(int x, int y, const MouseState *ms){ buttonReturn.mouseMove(x, y); buttonPlayNow.mouseMove(x, y); for(int i=0; igetSwitchSetupRequests(); for(int i= 0; igetSelectedFactionName()=%s\n",switchSetupRequests[i]->getSelectedFactionName().c_str()); //printf("switchSetupRequests[i]->getToTeam()=%d\n",switchSetupRequests[i]->getToTeam()); if(switchSetupRequests[i]->getToFactionIndex()!=-1) { //printf("switchSlot request from %d to %d\n",switchSetupRequests[i]->getCurrentFactionIndex(),switchSetupRequests[i]->getToFactionIndex()); if(serverInterface->switchSlot(switchSetupRequests[i]->getCurrentFactionIndex(),switchSetupRequests[i]->getToFactionIndex())){ int k=switchSetupRequests[i]->getToFactionIndex(); try { if(switchSetupRequests[i]->getSelectedFactionName()!=""){ listBoxFactions[k].setSelectedItem(switchSetupRequests[i]->getSelectedFactionName()); } if(switchSetupRequests[i]->getToTeam()!=-1) listBoxTeams[k].setSelectedItemIndex(switchSetupRequests[i]->getToTeam()); } catch(const runtime_error &e) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] caught exception error = [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what()); } } } else { try { if(switchSetupRequests[i]->getSelectedFactionName()!=""){ listBoxFactions[i].setSelectedItem(switchSetupRequests[i]->getSelectedFactionName()); } if(switchSetupRequests[i]->getToTeam()!=-1) listBoxTeams[i].setSelectedItemIndex(switchSetupRequests[i]->getToTeam()); } catch(const runtime_error &e) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] caught exception error = [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what()); } } } delete switchSetupRequests[i]; switchSetupRequests[i]=NULL; } } for(int i= 0; igetSlot(i); assert(connectionSlot!=NULL); hasOneNetworkSlotOpen=true; //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] A - ctNetwork\n",__FILE__,__FUNCTION__); if(connectionSlot->isConnected()) { haveAtLeastOneNetworkClientConnected = true; //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] B - ctNetwork\n",__FILE__,__FUNCTION__); string label = connectionSlot->getName(); if(connectionSlot->getAllowDownloadDataSynch() == true && connectionSlot->getAllowGameDataSynchCheck() == true) { if(connectionSlot->getNetworkGameDataSynchCheckOk() == false) { label = connectionSlot->getName() + " - waiting to synch:"; if(connectionSlot->getNetworkGameDataSynchCheckOkMap() == false) { label = label + " map"; } if(connectionSlot->getNetworkGameDataSynchCheckOkTile() == false) { label = label + " tile"; } if(connectionSlot->getNetworkGameDataSynchCheckOkTech() == false) { label = label + " techtree"; } //if(connectionSlot->getNetworkGameDataSynchCheckOkFogOfWar() == false) //{ // label = label + " FogOfWar == false"; //} } else { label = connectionSlot->getName() + " - data synch is ok"; } } else { label = connectionSlot->getName(); if(connectionSlot->getAllowGameDataSynchCheck() == true && connectionSlot->getNetworkGameDataSynchCheckOk() == false) { label += " - warning synch mismatch for:"; if(connectionSlot->getNetworkGameDataSynchCheckOkMap() == false) { label = label + " map"; } if(connectionSlot->getNetworkGameDataSynchCheckOkTile() == false) { label = label + " tile"; } if(connectionSlot->getNetworkGameDataSynchCheckOkTech() == false) { label = label + " techtree"; } //if(connectionSlot->getNetworkGameDataSynchCheckOkFogOfWar() == false) //{ // label = label + " FogOfWar == false"; //} } } labelNetStatus[i].setText(label); } else { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] C - ctNetwork\n",__FILE__,__FUNCTION__); string port=intToStr(config.getInt("ServerPort")); if(port!="61357"){ port=port +lang.get(" NonStandardPort")+"!"; } else { port=port+")"; } port="("+port; labelNetStatus[i].setText("--- "+port); } //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] END - ctNetwork\n",__FILE__,__FUNCTION__); } else{ labelNetStatus[i].setText(""); } } // Send the game settings to each client if we have at least one networked client if( serverInterface->getAllowGameDataSynchCheck() == true && haveAtLeastOneNetworkClientConnected == true && needToSetChangedGameSettings == true && difftime(time(NULL),lastSetChangedGameSettings) >= 2) { GameSettings gameSettings; loadGameSettings(&gameSettings); serverInterface->setGameSettings(&gameSettings); needToSetChangedGameSettings = false; } if(hasOneNetworkSlotOpen) { //listBoxPublishServer.setSelectedItemIndex(0); listBoxPublishServer.setEditable(true); } else { listBoxPublishServer.setSelectedItemIndex(1); listBoxPublishServer.setEditable(false); } if(listBoxPublishServer.getEditable() && listBoxPublishServer.getSelectedItemIndex()==0 && (difftime(time(NULL),lastMasterserverPublishing) >= 15) ){ // give it to me baby, aha aha ... lastMasterserverPublishing = time(NULL); publishToMasterserver(); } if(difftime(time(NULL),lastSetChangedGameSettings) >= 2) { GameSettings gameSettings; loadGameSettings(&gameSettings); serverInterface->setGameSettings(&gameSettings); serverInterface->broadcastGameSetup(&gameSettings); } //call the chat manager chatManager.updateNetwork(); //console console.update(); if(difftime(time(NULL),lastSetChangedGameSettings) >= 2) {// reset timer here on bottom becasue used for different things lastSetChangedGameSettings = time(NULL); } //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); } catch(const std::exception &ex) { char szBuf[1024]=""; sprintf(szBuf,"In [%s::%s %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); throw runtime_error(szBuf); } } void MenuStateCustomGame::publishToMasterserver() { int slotCountUsed=0; int slotCountHumans=0; int slotCountConnectedPlayers=0; ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface(); GameSettings gameSettings; loadGameSettings(&gameSettings); string serverinfo=""; for(int i= 0; igetSlot(i); if((connectionSlot!=NULL) && (connectionSlot->isConnected())) { slotCountConnectedPlayers++; } } else if(listBoxControls[i].getSelectedItemIndex() == ctHuman) { slotCountHumans++; slotCountConnectedPlayers++; } } //?status=waiting&system=linux&info=titus serverinfo+="glestVersion="+escapeURL(glestVersionString)+"&"; serverinfo+="platform="+escapeURL(getPlatformNameString())+"&"; serverinfo+="binaryCompileDate="+escapeURL(getCompileDateTime())+"&"; //game info: serverinfo+="serverTitle="+escapeURL(Config::getInstance().getString("NetPlayerName")+"'s game")+"&"; //ip is automatically set //game setup info: serverinfo+="tech="+escapeURL(listBoxTechTree.getSelectedItem())+"&"; serverinfo+="map="+escapeURL(listBoxMap.getSelectedItem())+"&"; serverinfo+="tileset="+escapeURL(listBoxTileset.getSelectedItem())+"&"; serverinfo+="activeSlots="+intToStr(slotCountUsed)+"&"; serverinfo+="networkSlots="+intToStr(slotCountHumans)+"&"; serverinfo+="connectedClients="+intToStr(slotCountConnectedPlayers); string request = Config::getInstance().getString("Masterserver")+"addServerInfo.php?"+serverinfo; printf("the request is:\n%s\n",request.c_str()); std::string serverInfo = SystemFlags::getHTTP(request); } string MenuStateCustomGame::escapeURL(string in) { char *escaped=curl_easy_escape(SystemFlags::curl_handle,in.c_str(),0); if(escaped==NULL) abort(); string out=escaped; curl_free(escaped); return out; } void MenuStateCustomGame::loadGameSettings(GameSettings *gameSettings) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); int factionCount= 0; ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface(); gameSettings->setDescription(formatString(mapFiles[listBoxMap.getSelectedItemIndex()])); gameSettings->setMap(mapFiles[listBoxMap.getSelectedItemIndex()]); gameSettings->setTileset(tilesetFiles[listBoxTileset.getSelectedItemIndex()]); gameSettings->setTech(techTreeFiles[listBoxTechTree.getSelectedItemIndex()]); gameSettings->setDefaultUnits(true); gameSettings->setDefaultResources(true); gameSettings->setDefaultVictoryConditions(true); gameSettings->setFogOfWar(listBoxFogOfWar.getSelectedItemIndex() == 0); for(int i=0; i(listBoxControls[i].getSelectedItemIndex()); if(ct != ctClosed) { if(ct == ctHuman) { gameSettings->setThisFactionIndex(factionCount); } gameSettings->setFactionControl(factionCount, ct); gameSettings->setTeam(factionCount, listBoxTeams[i].getSelectedItemIndex()); gameSettings->setStartLocationIndex(factionCount, i); gameSettings->setFactionTypeName(factionCount, factionFiles[listBoxFactions[i].getSelectedItemIndex()]); if(listBoxControls[i].getSelectedItemIndex() == ctNetwork) { ConnectionSlot* connectionSlot= serverInterface->getSlot(i); if((connectionSlot!=NULL) && (connectionSlot->isConnected())) { gameSettings->setNetworkPlayerName(factionCount, connectionSlot->getName()); } else { gameSettings->setNetworkPlayerName(factionCount, "???"); } } else if (listBoxControls[i].getSelectedItemIndex() == ctHuman) { gameSettings->setNetworkPlayerName(factionCount, Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str())); } else { gameSettings->setNetworkPlayerName(factionCount, ""); } factionCount++; } } gameSettings->setFactionCount(factionCount); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] gameSettings->getTileset() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getTileset().c_str()); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] gameSettings->getTech() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getTech().c_str()); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] gameSettings->getMap() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getMap().c_str()); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); } // ============ PRIVATE =========================== bool MenuStateCustomGame::hasNetworkGameSettings() { bool hasNetworkSlot = false; try { for(int i=0; i(listBoxControls[i].getSelectedItemIndex()); if(ct != ctClosed) { if(ct == ctNetwork) { hasNetworkSlot = true; break; } } } } catch(const std::exception &ex) { char szBuf[1024]=""; sprintf(szBuf,"In [%s::%s %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); throw runtime_error(szBuf); } return hasNetworkSlot; } void MenuStateCustomGame::loadMapInfo(string file, MapInfo *mapInfo){ struct MapFileHeader{ int32 version; int32 maxPlayers; int32 width; int32 height; int32 altFactor; int32 waterLevel; int8 title[128]; }; Lang &lang= Lang::getInstance(); try{ FILE *f= fopen(file.c_str(), "rb"); if(f==NULL) throw runtime_error("Can't open file"); MapFileHeader header; size_t readBytes = fread(&header, sizeof(MapFileHeader), 1, f); mapInfo->size.x= header.width; mapInfo->size.y= header.height; mapInfo->players= header.maxPlayers; mapInfo->desc= lang.get("MaxPlayers")+": "+intToStr(mapInfo->players)+"\n"; mapInfo->desc+=lang.get("Size")+": "+intToStr(mapInfo->size.x) + " x " + intToStr(mapInfo->size.y); fclose(f); } catch(exception e){ throw runtime_error("Error loading map file: "+file+'\n'+e.what()); } } void MenuStateCustomGame::reloadFactions(){ vector results; Config &config = Config::getInstance(); vector techPaths = config.getPathListForType(ptTechs); for(int idx = 0; idx < techPaths.size(); idx++) { string &techPath = techPaths[idx]; findAll(techPath + "/" + techTreeFiles[listBoxTechTree.getSelectedItemIndex()] + "/factions/*.", results, false, false); if(results.size() > 0) { break; } } if(results.size() == 0) { throw runtime_error("(2)There are no factions for the tech tree [" + techTreeFiles[listBoxTechTree.getSelectedItemIndex()] + "]"); } factionFiles= results; for(int i= 0; igetSlot(i)->isConnected()){ listBoxControls[i].setSelectedItemIndex(ctClosed); } } } updateNetworkSlots(); } catch(const std::exception &ex) { char szBuf[1024]=""; sprintf(szBuf,"In [%s::%s %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); throw runtime_error(szBuf); } } void MenuStateCustomGame::updateNetworkSlots() { try { ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface(); for(int i= 0; igetSlot(i) == NULL && listBoxControls[i].getSelectedItemIndex() == ctNetwork) { serverInterface->addSlot(i); } if(serverInterface->getSlot(i) != NULL && listBoxControls[i].getSelectedItemIndex() != ctNetwork) { serverInterface->removeSlot(i); } } } catch(const std::exception &ex) { char szBuf[1024]=""; sprintf(szBuf,"In [%s::%s %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); throw runtime_error(szBuf); } } void MenuStateCustomGame::keyDown(char key) { //send key to the chat manager chatManager.keyDown(key); } void MenuStateCustomGame::keyPress(char c) { chatManager.keyPress(c); } }}//end namespace