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