1 /*
2  *  Copyright (C) 2011-2016  OpenDungeons Team
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 3 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, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "modes/MenuModeSkirmish.h"
19 
20 #include "utils/Helper.h"
21 #include "render/Gui.h"
22 #include "modes/ModeManager.h"
23 #include "sound/MusicPlayer.h"
24 #include "gamemap/GameMap.h"
25 #include "render/ODFrameListener.h"
26 #include "network/ODServer.h"
27 #include "network/ODClient.h"
28 #include "network/ServerMode.h"
29 #include "utils/LogManager.h"
30 #include "gamemap/MapHandler.h"
31 #include "utils/ConfigManager.h"
32 #include "utils/ResourceManager.h"
33 
34 #include <CEGUI/CEGUI.h>
35 #include "boost/filesystem.hpp"
36 
MenuModeSkirmish(ModeManager * modeManager)37 MenuModeSkirmish::MenuModeSkirmish(ModeManager* modeManager):
38     AbstractApplicationMode(modeManager, ModeManager::MENU_SKIRMISH)
39 {
40     CEGUI::Window* window = modeManager->getGui().getGuiSheet(Gui::guiSheet::skirmishMenu);
41 
42     // Fills the Level type combo box with the available level types.
43     const CEGUI::Image* selImg = &CEGUI::ImageManager::getSingleton().get("OpenDungeonsSkin/SelectionBrush");
44     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(window->getChild(Gui::SKM_LIST_LEVEL_TYPES));
45     levelTypeCb->resetList();
46 
47     CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem("Official Skirmish Levels", 0);
48     item->setSelectionBrushImage(selImg);
49     levelTypeCb->addItem(item);
50 
51     item = new CEGUI::ListboxTextItem("Official Multiplayer Levels", 1);
52     item->setSelectionBrushImage(selImg);
53     levelTypeCb->addItem(item);
54 
55     item = new CEGUI::ListboxTextItem("Custom Skirmish Levels", 2);
56     item->setSelectionBrushImage(selImg);
57     levelTypeCb->addItem(item);
58 
59     item = new CEGUI::ListboxTextItem("Custom Multiplayer Levels", 3);
60     item->setSelectionBrushImage(selImg);
61     levelTypeCb->addItem(item);
62 
63     addEventConnection(
64         window->getChild(Gui::SKM_BUTTON_LAUNCH)->subscribeEvent(
65             CEGUI::PushButton::EventClicked,
66             CEGUI::Event::Subscriber(&MenuModeSkirmish::launchSelectedButtonPressed, this)
67         )
68     );
69     addEventConnection(
70         window->getChild(Gui::SKM_LIST_LEVELS)->subscribeEvent(
71             CEGUI::Listbox::EventMouseDoubleClick,
72             CEGUI::Event::Subscriber(&MenuModeSkirmish::launchSelectedButtonPressed, this)
73         )
74     );
75     addEventConnection(
76         window->getChild(Gui::SKM_LIST_LEVELS)->subscribeEvent(
77             CEGUI::Listbox::EventMouseClick,
78             CEGUI::Event::Subscriber(&MenuModeSkirmish::updateDescription, this)
79         )
80     );
81     addEventConnection(
82         window->getChild(Gui::SKM_BUTTON_BACK)->subscribeEvent(
83             CEGUI::PushButton::EventClicked,
84             CEGUI::Event::Subscriber(&AbstractApplicationMode::goBack,
85                                      static_cast<AbstractApplicationMode*>(this))
86         )
87     );
88     addEventConnection(
89         window->getChild("LevelWindowFrame")->subscribeEvent(
90             CEGUI::FrameWindow::EventCloseClicked,
91             CEGUI::Event::Subscriber(&AbstractApplicationMode::goBack,
92                                      static_cast<AbstractApplicationMode*>(this))
93         )
94     );
95 
96     addEventConnection(
97         window->getChild(Gui::SKM_LIST_LEVEL_TYPES)->subscribeEvent(
98             CEGUI::Combobox::EventListSelectionAccepted,
99             CEGUI::Event::Subscriber(&MenuModeSkirmish::updateFilesList, this)
100         )
101     );
102 }
103 
activate()104 void MenuModeSkirmish::activate()
105 {
106     // Loads the corresponding Gui sheet.
107     getModeManager().getGui().loadGuiSheet(Gui::guiSheet::skirmishMenu);
108 
109     giveFocus();
110 
111     // Play the main menu music
112     MusicPlayer::getSingleton().play(ConfigManager::getSingleton().getMainMenuMusic());
113 
114     GameMap* gameMap = ODFrameListener::getSingleton().getClientGameMap();
115     gameMap->clearAll();
116     gameMap->setGamePaused(true);
117 
118     // Select skirmish
119     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(getModeManager().getGui().
120                                        getGuiSheet(Gui::skirmishMenu)->getChild(Gui::SKM_LIST_LEVEL_TYPES));
121     levelTypeCb->setItemSelectState(static_cast<size_t>(0), true);
122     updateFilesList();
123 
124     // Set the player name if valid. (Will use the defaut one if not.)
125     ConfigManager& config = ConfigManager::getSingleton();
126     std::string nickname = config.getGameValue(Config::NICKNAME, std::string(), false);
127     if (!nickname.empty())
128         ODFrameListener::getSingleton().getClientGameMap()->setLocalPlayerNick(nickname);
129 }
130 
updateFilesList(const CEGUI::EventArgs &)131 bool MenuModeSkirmish::updateFilesList(const CEGUI::EventArgs&)
132 {
133     CEGUI::Window* window = getModeManager().getGui().getGuiSheet(Gui::guiSheet::skirmishMenu);
134     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(window->getChild(Gui::SKM_LIST_LEVELS));
135 
136     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(window->getChild(Gui::SKM_LIST_LEVEL_TYPES));
137 
138     CEGUI::Window* loadText = window->getChild(Gui::SKM_TEXT_LOADING);
139     loadText->setText("");
140     mFilesList.clear();
141     mDescriptionList.clear();
142     levelSelectList->resetList();
143 
144     std::string levelPath;
145     size_t selection = levelTypeCb->getItemIndex(levelTypeCb->getSelectedItem());
146     switch (selection)
147     {
148         default:
149         case 0:
150             levelPath = ResourceManager::getSingleton().getGameLevelPathSkirmish();
151             break;
152         case 1:
153             levelPath = ResourceManager::getSingleton().getGameLevelPathMultiplayer();
154             break;
155         case 2:
156             levelPath = ResourceManager::getSingleton().getUserLevelPathSkirmish();
157             break;
158         case 3:
159             levelPath = ResourceManager::getSingleton().getUserLevelPathMultiplayer();
160             break;
161     }
162 
163     if(Helper::fillFilesList(levelPath, mFilesList, MapHandler::LEVEL_EXTENSION))
164     {
165         for (uint32_t n = 0; n < mFilesList.size(); ++n)
166         {
167             std::string filename = mFilesList[n];
168 
169             LevelInfo levelInfo;
170             std::string mapName;
171             std::string mapDescription;
172             if(MapHandler::getMapInfo(filename, levelInfo))
173             {
174                 mapName = levelInfo.mLevelName;
175                 mapDescription = levelInfo.mLevelDescription;
176             }
177             else
178             {
179                 mapName = "invalid map";
180                 mapDescription = "invalid map";
181             }
182 
183             mDescriptionList.push_back(mapDescription);
184             CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(mapName);
185             item->setID(n);
186             item->setSelectionBrushImage("OpenDungeonsSkin/SelectionBrush");
187             levelSelectList->addItem(item);
188         }
189     }
190 
191     updateDescription();
192     return true;
193 }
194 
launchSelectedButtonPressed(const CEGUI::EventArgs &)195 bool MenuModeSkirmish::launchSelectedButtonPressed(const CEGUI::EventArgs&)
196 {
197     CEGUI::Window* mainWin = getModeManager().getGui().getGuiSheet(Gui::skirmishMenu);
198     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(mainWin->getChild(Gui::SKM_LIST_LEVELS));
199 
200     if(levelSelectList->getSelectedCount() == 0)
201     {
202         mainWin->getChild(Gui::SKM_TEXT_LOADING)->setText("Please select a level first.");
203         return true;
204     }
205 
206     mainWin->getChild(Gui::SKM_TEXT_LOADING)->setText("Loading...");
207 
208     CEGUI::ListboxItem* selItem = levelSelectList->getFirstSelectedItem();
209     int id = selItem->getID();
210 
211     const std::string& level = mFilesList[id];
212     // In single player mode, we act as a server
213     const std::string& nickname = ODFrameListener::getSingleton().getClientGameMap()->getLocalPlayerNick();
214     if(!ODServer::getSingleton().startServer(nickname, level, ServerMode::ModeGameSinglePlayer, false))
215     {
216         OD_LOG_ERR("Could not start server for single player game !!!");
217         mainWin->getChild(Gui::SKM_TEXT_LOADING)->setText("ERROR: Could not start server for single player game !!!");
218         return true;
219     }
220 
221     int port = ODServer::getSingleton().getNetworkPort();
222     uint32_t timeout = ConfigManager::getSingleton().getClientConnectionTimeout();
223     std::string replayFilename = ResourceManager::getSingleton().getReplayDataPath()
224         + ResourceManager::getSingleton().buildReplayFilename();
225     if(!ODClient::getSingleton().connect("localhost", port, timeout, replayFilename))
226     {
227         OD_LOG_ERR("Could not connect to server for single player game !!!");
228         mainWin->getChild(Gui::SKM_TEXT_LOADING)->setText("Error: Couldn't connect to local server!");
229         return true;
230     }
231     return true;
232 }
233 
updateDescription(const CEGUI::EventArgs &)234 bool MenuModeSkirmish::updateDescription(const CEGUI::EventArgs&)
235 {
236     // Get the level corresponding id
237     CEGUI::Window* mainWin = getModeManager().getGui().getGuiSheet(Gui::skirmishMenu);
238     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(mainWin->getChild(Gui::SKM_LIST_LEVELS));
239 
240     CEGUI::Window* descTxt = mainWin->getChild("LevelWindowFrame/MapDescriptionText");
241 
242     if(levelSelectList->getSelectedCount() == 0)
243     {
244         descTxt->setText("");
245         return true;
246     }
247 
248     getModeManager().getGui().playButtonClickSound();
249 
250     CEGUI::ListboxItem* selItem = levelSelectList->getFirstSelectedItem();
251     int id = selItem->getID();
252 
253     std::string description = mDescriptionList[id];
254     descTxt->setText(reinterpret_cast<const CEGUI::utf8*>(description.c_str()));
255 
256     return true;
257 }
258