1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2009-2015 Marianne Gagnon
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #include "states_screens/state_manager.hpp"
20
21 #include "audio/sfx_manager.hpp"
22 #include "audio/music_manager.hpp"
23 #include "config/stk_config.hpp"
24 #include "graphics/irr_driver.hpp"
25 #include "guiengine/engine.hpp"
26 #include "guiengine/modaldialog.hpp"
27 #include "guiengine/screen.hpp"
28 #include "guiengine/screen_keyboard.hpp"
29 #include "input/input_device.hpp"
30 #include "input/input_manager.hpp"
31 #include "main_loop.hpp"
32 #include "modes/world.hpp"
33 #include "modes/profile_world.hpp"
34 #include "utils/log.hpp"
35 #include "utils/stk_process.hpp"
36
37 #include <cstring>
38
39 using namespace GUIEngine;
40
41 static StateManager* state_manager_singleton[PT_COUNT];
42
get()43 StateManager* StateManager::get()
44 {
45 ProcessType type = STKProcess::getType();
46 if (state_manager_singleton[type] == NULL)
47 state_manager_singleton[type] = new StateManager();
48 return state_manager_singleton[type];
49 } // get
50
deallocate()51 void StateManager::deallocate()
52 {
53 ProcessType type = STKProcess::getType();
54 delete state_manager_singleton[type];
55 state_manager_singleton[type] = NULL;
56 } // deallocate
57
clear()58 void StateManager::clear()
59 {
60 memset(state_manager_singleton, 0, sizeof(state_manager_singleton));
61 } // clear
62
63 // ============================================================================
64
65 #if 0
66 #pragma mark -
67 #pragma mark Player Management
68 #endif
69
70 // ----------------------------------------------------------------------------
71
getActivePlayer(const int id)72 StateManager::ActivePlayer* StateManager::getActivePlayer(const int id)
73 {
74 ActivePlayer *returnPlayer = NULL;
75 if (id < (int)m_active_players.size() && id >= 0)
76 {
77 returnPlayer = m_active_players.get(id);
78 }
79 else
80 {
81 Log::error("StateManager", "getActivePlayer(): id %d out of bounds", id);
82 assert(false);
83 return NULL;
84 }
85
86 assert( returnPlayer->m_id == id );
87
88 return returnPlayer;
89 } // getActivePlayer
90
91 // ----------------------------------------------------------------------------
92
getActivePlayerProfile(const int id)93 const PlayerProfile* StateManager::getActivePlayerProfile(const int id)
94 {
95 ActivePlayer* a = getActivePlayer(id);
96 if (a == NULL) return NULL;
97 return a->getProfile();
98 } // getActivePlayerProfile
99
100 // ----------------------------------------------------------------------------
101
updateActivePlayerIDs()102 void StateManager::updateActivePlayerIDs()
103 {
104 const int amount = m_active_players.size();
105 for (int n=0; n<amount; n++)
106 {
107 m_active_players[n].m_id = n;
108 }
109 } // updateActivePlayerIDs
110
111 // ----------------------------------------------------------------------------
112
createActivePlayer(PlayerProfile * profile,InputDevice * device)113 int StateManager::createActivePlayer(PlayerProfile *profile,
114 InputDevice *device)
115 {
116 ActivePlayer *p;
117 int i;
118 p = new ActivePlayer(profile, device);
119 i = m_active_players.size();
120 m_active_players.push_back(p);
121
122 updateActivePlayerIDs();
123
124 return i;
125 } // createActivePlayer
126
127 // ----------------------------------------------------------------------------
128
removeActivePlayer(int id)129 void StateManager::removeActivePlayer(int id)
130 {
131 m_active_players.erase(id);
132 updateActivePlayerIDs();
133 } // removeActivePlayer
134
135 // ----------------------------------------------------------------------------
136
activePlayerCount()137 unsigned int StateManager::activePlayerCount()
138 {
139 return m_active_players.size();
140 } // activePlayerCount
141
142 // ----------------------------------------------------------------------------
143
resetActivePlayers()144 void StateManager::resetActivePlayers()
145 {
146 const int amount = m_active_players.size();
147 for(int i=0; i<amount; i++)
148 {
149 m_active_players[i].setDevice(NULL);
150 }
151 m_active_players.clearAndDeleteAll();
152 } // resetActivePlayers
153
154 // ----------------------------------------------------------------------------
155
156 #if 0
157 #pragma mark -
158 #pragma mark misc stuff
159 #endif
160
throttleFPS()161 bool StateManager::throttleFPS()
162 {
163 #ifndef SERVER_ONLY
164 return m_game_mode != GUIEngine::GAME && GUIEngine::getCurrentScreen() &&
165 GUIEngine::getCurrentScreen()->throttleFPS();
166 #else
167 return true;
168 #endif
169 } // throttleFPS
170
171 // ----------------------------------------------------------------------------
172
escapePressed()173 void StateManager::escapePressed()
174 {
175 // in input sensing mode
176 if(input_manager->isInMode(InputManager::INPUT_SENSE_KEYBOARD) ||
177 input_manager->isInMode(InputManager::INPUT_SENSE_GAMEPAD) )
178 {
179 ScreenKeyboard::dismiss();
180 ModalDialog::dismiss();
181 input_manager->setMode(InputManager::MENU);
182 }
183 // when another modal dialog is visible
184 else if(ScreenKeyboard::isActive())
185 {
186 if(ScreenKeyboard::getCurrent()->onEscapePressed())
187 ScreenKeyboard::getCurrent()->dismiss();
188 }
189 // when another modal dialog is visible
190 else if(ModalDialog::isADialogActive())
191 {
192 if(ModalDialog::getCurrent()->onEscapePressed())
193 ModalDialog::getCurrent()->dismiss();
194 }
195 // In-game
196 else if(m_game_mode == GAME)
197 {
198 if(World::getWorld()->getPhase()!=WorldStatus::RESULT_DISPLAY_PHASE
199 && !ProfileWorld::isProfileMode())
200 World::getWorld()->escapePressed();
201 }
202 // In menus
203 else
204 {
205 if (getCurrentScreen() != NULL &&
206 getCurrentScreen()->onEscapePressed()) popMenu();
207 }
208 } // escapePressed
209
210 // ----------------------------------------------------------------------------
211
onGameStateChange(GameState new_state)212 void StateManager::onGameStateChange(GameState new_state)
213 {
214 if (GUIEngine::isNoGraphics())
215 return;
216
217 if (new_state == GAME)
218 {
219 if (RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_OVERWORLD)
220 irr_driver->hidePointer();
221 input_manager->setMode(InputManager::INGAME);
222 }
223 else // menu (including in-game menu)
224 {
225 irr_driver->showPointer();
226 input_manager->setMode(InputManager::MENU);
227 SFXManager::get()->positionListener( Vec3(0,0,0), Vec3(0,1,0), Vec3(0, 1, 0) );
228
229 if (new_state == MENU)
230 {
231 GUIEngine::Screen* screen = GUIEngine::getCurrentScreen();
232 if (screen != NULL && music_manager)
233 {
234 music_manager->startMusic(
235 GUIEngine::getCurrentScreen()->getMusic());
236 }
237 }
238 }
239 } // onGameStateChange
240
241 // ----------------------------------------------------------------------------
242
onTopMostScreenChanged()243 void StateManager::onTopMostScreenChanged()
244 {
245 if (GUIEngine::isNoGraphics())
246 return;
247
248 if (m_game_mode == MENU && GUIEngine::getCurrentScreen() != NULL)
249 {
250 if (GUIEngine::getCurrentScreen()->getMusic() != NULL && music_manager)
251 {
252 music_manager->startMusic(GUIEngine::getCurrentScreen()->getMusic());
253 }
254 }
255 else if (m_game_mode == INGAME_MENU && GUIEngine::getCurrentScreen() != NULL)
256 {
257 if (GUIEngine::getCurrentScreen()->getInGameMenuMusic() != NULL && music_manager)
258 {
259 music_manager->startMusic(GUIEngine::getCurrentScreen()->getInGameMenuMusic());
260 }
261 }
262
263 } // onTopMostScreenChanged
264
265 // ----------------------------------------------------------------------------
266
onStackEmptied()267 void StateManager::onStackEmptied()
268 {
269 GUIEngine::cleanUp();
270 GUIEngine::deallocate();
271 main_loop->abort();
272 } // onStackEmptied
273
274 // ============================================================================
275
276 #if 0
277 #pragma mark -
278 #pragma mark ActivePlayer
279 #endif
280
ActivePlayer(PlayerProfile * player,InputDevice * device)281 StateManager::ActivePlayer::ActivePlayer(PlayerProfile* player,
282 InputDevice *device)
283 {
284 #ifdef DEBUG
285 m_magic_number = 0xAC1EF1AE;
286 #endif
287
288 m_player = player;
289 m_device = NULL;
290 m_kart = NULL;
291 setDevice(device);
292 } // ActivePlayer
293
294 // ----------------------------------------------------------------------------
~ActivePlayer()295 StateManager::ActivePlayer::~ActivePlayer()
296 {
297 setDevice(NULL);
298
299 #ifdef DEBUG
300 m_magic_number = 0xDEADBEEF;
301 #endif
302 } // ~ActivePlayer
303
304 // ----------------------------------------------------------------------------
305
setPlayerProfile(PlayerProfile * player)306 void StateManager::ActivePlayer::setPlayerProfile(PlayerProfile* player)
307 {
308 #ifdef DEBUG
309 assert(m_magic_number == 0xAC1EF1AE);
310 #endif
311 m_player = player;
312 } // setPlayerProfile
313
314 // ----------------------------------------------------------------------------
315
setDevice(InputDevice * device)316 void StateManager::ActivePlayer::setDevice(InputDevice* device)
317 {
318 #ifdef DEBUG
319 assert(m_magic_number == 0xAC1EF1AE);
320 #endif
321
322 // unset player from previous device he was assigned to, if any
323 if (m_device != NULL) m_device->setPlayer(NULL);
324
325 m_device = device;
326
327 // inform the devce of its new owner
328 if (device != NULL) device->setPlayer(this);
329 } // setDevice
330