Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

StateManager.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  */
00009 #include "StateManager.h"
00010 
00011 #include "GameState.h"
00012 
00013 #include "MessagerAgent.h"
00014 #include "SimpleMsg.h"
00015 #include "LogicException.h"
00016 
00017 //-----------------------------------------------------------------
00018 StateManager::~StateManager()
00019 {
00020     emptyTrash();
00021 
00022     t_states::iterator end = m_states.end();
00023     for (t_states::iterator i = m_states.begin(); i != end; ++i) {
00024         delete (*i);
00025     }
00026 }
00027 //-----------------------------------------------------------------
00028     void
00029 StateManager::emptyTrash()
00030 {
00031     t_states::iterator end = m_trash.end();
00032     for (t_states::iterator i = m_trash.begin(); i != end; ++i) {
00033         delete (*i);
00034     }
00035     m_trash.clear();
00036 }
00037 //-----------------------------------------------------------------
00038 /**
00039  * Update current state and states on background
00040  * and empty trash.
00041  * The states at bottom will be updated as first.
00042  */
00043 void
00044 StateManager::updateGame()
00045 {
00046     t_states::iterator end = m_states.end();
00047     for (t_states::iterator i = m_states.begin(); i != end; /* empty */) {
00048         //NOTE: state can remove self and thus invalide current iterator
00049         GameState *cur = *(i++);
00050         if (cur->isRunning()) {
00051             cur->updateState();
00052         }
00053     }
00054 
00055     emptyTrash();
00056 }
00057 
00058 //-----------------------------------------------------------------
00059 /**
00060  * Throw given state to the trash.
00061  * NOTE: given state can be still active, cannot be deleted
00062  */
00063 void
00064 StateManager::removeState(GameState *state)
00065 {
00066     state->cleanState();
00067     m_trash.push_back(state);
00068     m_states.remove(state);
00069 }
00070 //-----------------------------------------------------------------
00071 /**
00072  * Remove given state and set this one.
00073  */
00074 void
00075 StateManager::changeState(GameState *who, GameState *new_state)
00076 {
00077     insertAfter(who, new_state);
00078     removeState(who);
00079     new_state->initState(this);
00080     checkStack();
00081 }
00082 //-----------------------------------------------------------------
00083 /**
00084  * Pause given state and activate this one.
00085  */
00086 void
00087 StateManager::pushState(GameState *who, GameState *new_state)
00088 {
00089     insertAfter(who, new_state);
00090     new_state->initState(this);
00091     checkStack();
00092 }
00093 
00094 //-----------------------------------------------------------------
00095 /**
00096  * Remove given state and resume paused states below it.
00097  */
00098 void
00099 StateManager::popState(GameState *who)
00100 {
00101     removeState(who);
00102 
00103     if (!m_states.empty()) {
00104         checkStack();
00105     }
00106     else {
00107         MessagerAgent::agent()->forwardNewMsg(
00108                 new SimpleMsg(Name::APP_NAME, "quit"));
00109     }
00110 }
00111 
00112 //-----------------------------------------------------------------
00113 /**
00114  * Insert new state after given state.
00115  * @param who active state or NULL to insert at the beginning
00116  * @param new_state state to insert
00117  */
00118 void
00119 StateManager::insertAfter(GameState *who, GameState *new_state)
00120 {
00121     if (NULL == who) {
00122         m_states.push_front(new_state);
00123     }
00124     else {
00125         t_states::iterator it = findIter(who);
00126         m_states.insert(++it, new_state);
00127     }
00128 }
00129 //-----------------------------------------------------------------
00130 /**
00131  * Find iterator under given state.
00132  * @throws LogicException when state is not found
00133  */
00134     StateManager::t_states::iterator
00135 StateManager::findIter(GameState *who)
00136 {
00137     t_states::iterator end = m_states.end();
00138     for (t_states::iterator i = m_states.begin(); i != end; ++i) {
00139         if (who == (*i)) {
00140             return i;
00141         }
00142     }
00143     throw LogicException(ExInfo("game state is not found in stack")
00144             .addInfo("state", who ? who->getName() : "(null)"));
00145 }
00146 //-----------------------------------------------------------------
00147 /**
00148  * Preserve stack consistency.
00149  * - Node at top must be running.
00150  * - Only running node which allowBg have running states below.
00151  * @throws LogicException stack is empty
00152  */
00153 void
00154 StateManager::checkStack()
00155 {
00156     if (m_states.empty()) {
00157         throw LogicException(ExInfo("game state stack is empty"));
00158     }
00159 
00160     t_states::iterator topIt = m_states.end();
00161     --topIt;
00162     GameState *top = (*topIt);
00163     if (top->isOnBg()) {
00164         top->noteFg();
00165     }
00166     pauseBg(topIt);
00167     resumeBg(topIt);
00168     installHandlers();
00169 }
00170 //-----------------------------------------------------------------
00171 /**
00172  * Pause all running states below on stack which all not allowed.
00173  * The toppers will be paused first but the order should be insignificant
00174  * @param stateIt states bellow will be check
00175  */
00176 void
00177 StateManager::pauseBg(t_states::iterator stateIt)
00178 {
00179     if (stateIt != m_states.begin()) {
00180         t_states::iterator prev = stateIt;
00181         --prev;
00182         if (!(*stateIt)->isRunning() || !(*stateIt)->allowBg()) {
00183             if ((*prev)->isRunning()) {
00184                 (*prev)->pauseState();
00185             }
00186         }
00187         pauseBg(prev);
00188     }
00189 }
00190 //-----------------------------------------------------------------
00191 /**
00192  * Recursive resume given state and all states below on stack which is allowed.
00193  * The lowers will be resumed first but the order should be insignificant.
00194  * @param stateIt state to run
00195  */
00196 void
00197 StateManager::resumeBg(t_states::iterator stateIt)
00198 {
00199     if ((*stateIt)->allowBg() && stateIt != m_states.begin()) {
00200         t_states::iterator prev = stateIt;
00201         --prev;
00202         resumeBg(prev);
00203         (*prev)->noteBg();
00204     }
00205 
00206     if (!(*stateIt)->isRunning()) {
00207         (*stateIt)->resumeState();
00208     }
00209 }
00210 //-----------------------------------------------------------------
00211 /**
00212  * Let all running states to install input and draw handler.
00213  * And all paused states will uninstall their handlers.
00214  * The lowers will be called first, order is insignificant.
00215  *
00216  * NOTE: first the handlers will be uninstalled and then
00217  * installed back in right order
00218  */
00219 void
00220 StateManager::installHandlers()
00221 {
00222     t_states::iterator end = m_states.end();
00223     for (t_states::iterator i = m_states.begin(); i != end; ++i) {
00224         if ((*i)->isRunning()) {
00225             (*i)->unHandlers();
00226             (*i)->installHandlers();
00227         }
00228         else {
00229             (*i)->unHandlers();
00230         }
00231     }
00232 }
00233 

Generated on Wed Jun 1 09:54:31 2005 for Fish Fillets - Next Generation by  doxygen 1.4.2