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/MenuModeEditorLoad.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/ResourceManager.h"
32 #include "utils/ConfigManager.h"
33 
34 #include <CEGUI/CEGUI.h>
35 
36 #include <boost/filesystem.hpp>
37 
MenuModeEditorLoad(ModeManager * modeManager)38 MenuModeEditorLoad::MenuModeEditorLoad(ModeManager* modeManager):
39     AbstractApplicationMode(modeManager, ModeManager::MENU_EDITOR_LOAD)
40 {
41     CEGUI::Window* window = modeManager->getGui().getGuiSheet(Gui::guiSheet::editorLoadMenu);
42 
43     // Fills the Level type combo box with the available level types.
44     const CEGUI::Image* selImg = &CEGUI::ImageManager::getSingleton().get("OpenDungeonsSkin/SelectionBrush");
45     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(window->getChild(Gui::EDM_LIST_LEVEL_TYPES));
46     levelTypeCb->resetList();
47 
48     CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem("Official Skirmish Levels", 0);
49     item->setSelectionBrushImage(selImg);
50     levelTypeCb->addItem(item);
51 
52     item = new CEGUI::ListboxTextItem("Official Multiplayer Levels", 1);
53     item->setSelectionBrushImage(selImg);
54     levelTypeCb->addItem(item);
55 
56     item = new CEGUI::ListboxTextItem("Custom Skirmish Levels", 2);
57     item->setSelectionBrushImage(selImg);
58     levelTypeCb->addItem(item);
59 
60     item = new CEGUI::ListboxTextItem("Custom Multiplayer Levels", 3);
61     item->setSelectionBrushImage(selImg);
62     levelTypeCb->addItem(item);
63 
64     addEventConnection(
65         window->getChild(Gui::EDM_BUTTON_LAUNCH)->subscribeEvent(
66             CEGUI::PushButton::EventClicked,
67             CEGUI::Event::Subscriber(&MenuModeEditorLoad::launchSelectedButtonPressed, this)
68         )
69     );
70     addEventConnection(
71         window->getChild(Gui::EDM_LIST_LEVELS)->subscribeEvent(
72             CEGUI::Listbox::EventMouseDoubleClick,
73             CEGUI::Event::Subscriber(&MenuModeEditorLoad::launchSelectedButtonPressed, this)
74         )
75     );
76     addEventConnection(
77         window->getChild(Gui::EDM_LIST_LEVELS)->subscribeEvent(
78             CEGUI::Listbox::EventMouseClick,
79             CEGUI::Event::Subscriber(&MenuModeEditorLoad::updateDescription, this)
80         )
81     );
82     addEventConnection(
83         window->getChild(Gui::EDM_BUTTON_BACK)->subscribeEvent(
84             CEGUI::PushButton::EventClicked,
85             CEGUI::Event::Subscriber(&AbstractApplicationMode::goBack,
86                                      static_cast<AbstractApplicationMode*>(this))
87         )
88     );
89     addEventConnection(
90         window->getChild("LevelWindowFrame")->subscribeEvent(
91             CEGUI::FrameWindow::EventCloseClicked,
92             CEGUI::Event::Subscriber(&AbstractApplicationMode::goBack,
93                                      static_cast<AbstractApplicationMode*>(this))
94         )
95     );
96 
97     addEventConnection(
98         window->getChild(Gui::EDM_LIST_LEVEL_TYPES)->subscribeEvent(
99             CEGUI::Combobox::EventListSelectionAccepted,
100             CEGUI::Event::Subscriber(&MenuModeEditorLoad::updateFilesList, this)
101         )
102     );
103 }
104 
activate()105 void MenuModeEditorLoad::activate()
106 {
107     // Loads the corresponding Gui sheet.
108     getModeManager().getGui().loadGuiSheet(Gui::editorLoadMenu);
109 
110     giveFocus();
111 
112     // Play the main menu music
113     MusicPlayer::getSingleton().play(ConfigManager::getSingleton().getMainMenuMusic());
114 
115     GameMap* gameMap = ODFrameListener::getSingleton().getClientGameMap();
116     gameMap->clearAll();
117     gameMap->setGamePaused(true);
118 
119     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(getModeManager().getGui().
120                                        getGuiSheet(Gui::editorLoadMenu)->getChild(Gui::EDM_LIST_LEVEL_TYPES));
121     levelTypeCb->setItemSelectState(static_cast<size_t>(0), true);
122     updateFilesList();
123 }
124 
findFileStemIn(const std::vector<std::string> & fileList,std::string filename)125 static bool findFileStemIn(const std::vector<std::string>& fileList, std::string filename)
126 {
127     for (const std::string& file : fileList)
128     {
129         if (boost::filesystem::path(file).stem().string() ==
130             boost::filesystem::path(filename).stem().string())
131             return true;
132     }
133     return false;
134 }
135 
updateFilesList(const CEGUI::EventArgs &)136 bool MenuModeEditorLoad::updateFilesList(const CEGUI::EventArgs&)
137 {
138     CEGUI::Window* window = getModeManager().getGui().getGuiSheet(Gui::guiSheet::editorLoadMenu);
139     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(window->getChild(Gui::EDM_LIST_LEVELS));
140 
141     CEGUI::Combobox* levelTypeCb = static_cast<CEGUI::Combobox*>(window->getChild(Gui::EDM_LIST_LEVEL_TYPES));
142 
143     CEGUI::Window* loadText = window->getChild(Gui::EDM_TEXT_LOADING);
144     loadText->setText("");
145     mFilesList.clear();
146     mDescriptionList.clear();
147     levelSelectList->resetList();
148 
149     std::string levelPath;
150     size_t selection = levelTypeCb->getItemIndex(levelTypeCb->getSelectedItem());
151     bool officialSkirmishMaps = false;
152     bool officialMultiplayerMaps = false;
153     switch (selection)
154     {
155         default:
156         case 0:
157             levelPath = ResourceManager::getSingleton().getGameLevelPathSkirmish();
158             officialSkirmishMaps = true;
159             break;
160         case 1:
161             levelPath = ResourceManager::getSingleton().getGameLevelPathMultiplayer();
162             officialMultiplayerMaps = true;
163             break;
164         case 2:
165             levelPath = ResourceManager::getSingleton().getUserLevelPathSkirmish();
166             break;
167         case 3:
168             levelPath = ResourceManager::getSingleton().getUserLevelPathMultiplayer();
169             break;
170     }
171 
172     if(Helper::fillFilesList(levelPath, mFilesList, MapHandler::LEVEL_EXTENSION))
173     {
174         std::vector<std::string> officialFileList;
175         if (officialSkirmishMaps)
176             levelPath = ResourceManager::getSingleton().getUserLevelPathSkirmish();
177         if (officialMultiplayerMaps)
178             levelPath = ResourceManager::getSingleton().getUserLevelPathMultiplayer();
179 
180         if (officialSkirmishMaps || officialMultiplayerMaps)
181         {
182             if (!Helper::fillFilesList(levelPath, officialFileList, MapHandler::LEVEL_EXTENSION))
183                 officialFileList.clear();
184         }
185 
186         for (uint32_t n = 0; n < mFilesList.size(); ++n)
187         {
188             std::string filename = mFilesList[n];
189 
190             LevelInfo levelInfo;
191             std::string mapName;
192             std::string mapDescription;
193             bool customMapExists = findFileStemIn(officialFileList, filename);
194             if(MapHandler::getMapInfo(filename, levelInfo))
195             {
196                 mapName.clear();
197                 if (customMapExists)
198                     mapName = "[image-size='w:16 h:16'][image='OpenDungeonsIcons/CogIcon'][vert-alignment='centre'] ";
199                 mapName += levelInfo.mLevelName;
200                 mapDescription = levelInfo.mLevelDescription;
201                 if (customMapExists)
202                     mapDescription += "\n(A custom map exists for this level.)";
203             }
204             else
205             {
206                 mapName = "invalid map";
207                 mapDescription = "invalid map";
208             }
209 
210             mDescriptionList.push_back(mapDescription);
211             CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(mapName);
212             item->setID(n);
213             item->setSelectionBrushImage("OpenDungeonsSkin/SelectionBrush");
214             levelSelectList->addItem(item);
215         }
216     }
217 
218     updateDescription();
219     return true;
220 }
221 
launchSelectedButtonPressed(const CEGUI::EventArgs &)222 bool MenuModeEditorLoad::launchSelectedButtonPressed(const CEGUI::EventArgs&)
223 {
224     CEGUI::Window* window = getModeManager().getGui().getGuiSheet(Gui::guiSheet::editorLoadMenu);
225     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(window->getChild(Gui::EDM_LIST_LEVELS));
226 
227     if(levelSelectList->getSelectedCount() == 0)
228     {
229         window->getChild(Gui::EDM_TEXT_LOADING)->setText("Please select a level first.");
230         return true;
231     }
232 
233     window->getChild(Gui::EDM_TEXT_LOADING)->setText("Loading...");
234 
235     CEGUI::ListboxItem* selItem = levelSelectList->getFirstSelectedItem();
236     int id = selItem->getID();
237 
238     const std::string& level = mFilesList[id];
239 
240     // In editor mode, we act as a server
241     ConfigManager& config = ConfigManager::getSingleton();
242     std::string nickname = config.getGameValue(Config::NICKNAME, std::string(), false);
243     if(!ODServer::getSingleton().startServer(nickname, level, ServerMode::ModeEditor, false))
244     {
245         OD_LOG_ERR("Could not start server for editor !!!");
246         window->getChild(Gui::EDM_TEXT_LOADING)->setText("ERROR: Could not start server for editor !!!");
247     }
248 
249     int port = ODServer::getSingleton().getNetworkPort();
250     uint32_t timeout = ConfigManager::getSingleton().getClientConnectionTimeout();
251     std::string replayFilename = ResourceManager::getSingleton().getReplayDataPath()
252         + ResourceManager::getSingleton().buildReplayFilename();
253     if(!ODClient::getSingleton().connect("localhost", port, timeout, replayFilename))
254     {
255         OD_LOG_ERR("Could not connect to server for editor !!!");
256         window->getChild(Gui::EDM_TEXT_LOADING)->setText("Error: Couldn't connect to local server!");
257         return true;
258     }
259     return true;
260 }
261 
updateDescription(const CEGUI::EventArgs &)262 bool MenuModeEditorLoad::updateDescription(const CEGUI::EventArgs&)
263 {
264     CEGUI::Window* window = getModeManager().getGui().getGuiSheet(Gui::editorLoadMenu);
265     CEGUI::Listbox* levelSelectList = static_cast<CEGUI::Listbox*>(window->getChild(Gui::SKM_LIST_LEVELS));
266     CEGUI::Window* descTxt = window->getChild("LevelWindowFrame/MapDescriptionText");
267 
268     if(levelSelectList->getSelectedCount() == 0)
269     {
270         descTxt->setText("");
271         return true;
272     }
273 
274     getModeManager().getGui().playButtonClickSound();
275 
276     // Get the level corresponding id
277     CEGUI::ListboxItem* selItem = levelSelectList->getFirstSelectedItem();
278     int id = selItem->getID();
279 
280     std::string description = mDescriptionList[id];
281     descTxt->setText(description);
282     return true;
283 }
284