Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Apr 8, 2009, 12:58:47 AM (16 years ago)
Author:
dafrick
Message:

Reverted to revision 2906 (because I'm too stupid to merge correctly, 2nd try will follow shortly. ;))

Location:
code/branches/questsystem5
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/branches/questsystem5

  • code/branches/questsystem5/src/core/GameState.cc

    r2907 r2908  
    3030@file
    3131@brief
    32     Implementation of GameState class.
     32    Implementation of GameStateBase class.
    3333*/
    3434
    3535#include "GameState.h"
    36 #include <cassert>
    3736#include "util/Debug.h"
    3837#include "util/Exception.h"
    39 #include "Clock.h"
    4038
    4139namespace orxonox
     
    4543        Constructor only initialises variables and sets the name permanently.
    4644    */
    47     GameState::GameState(const std::string& name)
     45    GameStateBase::GameStateBase(const std::string& name)
    4846        : name_(name)
    49         , parent_(0)
    50     {
    51         this->activity_.activating   = false;
    52         this->activity_.active       = false;
    53         this->activity_.deactivating = false;
    54         this->activity_.suspended    = false;
    55         this->activity_.topState     = false;
    56         this->activity_.updating     = false;
     47        //, parent_(0)
     48        , activeChild_(0)
     49        //, bPausegetParent()(false)
     50    {
     51        Operations temp = {false, false, false, false, false};
     52        this->operation_ = temp;
    5753    }
    5854
     
    6157        Destructor only checks that we don't delete an active state.
    6258    */
    63     GameState::~GameState()
    64     {
    65         OrxAssert(this->activity_.active == false, "Deleting an active GameState is a very bad idea..");
     59    GameStateBase::~GameStateBase()
     60    {
     61        OrxAssert(this->operation_.active == false, "Deleting an active GameState is a very bad idea..");
    6662    }
    6763
     
    7369        The state to be added.
    7470    */
    75     void GameState::addChild(GameState* state)
    76     {
    77         assert(state != NULL);
    78 
    79         std::map<std::string, GameState*>::const_iterator it = this->children_.find(state->getName());
    80         if (it == this->children_.end())
    81         {
    82             this->children_[state->getName()] = state;
    83             // mark us as parent
    84             state->setParent(this);
    85         }
    86         else
    87         {
    88             ThrowException(GameState, "Cannot add two children with the same name");
    89         }
     71    void GameStateBase::addChild(GameStateBase* state)
     72    {
     73        if (!state)
     74            return;
     75        // check if the state/tree to be added has states in it that already exist in this tree.
     76        for (std::map<std::string, GameStateBase*>::const_iterator it = state->allChildren_.begin();
     77            it != state->allChildren_.end(); ++it)
     78        {
     79            if (this->getState(it->second->getName()))
     80            {
     81                ThrowException(GameState, "Cannot add a GameState to the hierarchy twice.");
     82                return;
     83            }
     84        }
     85        if (this->getState(state->name_))
     86        {
     87            ThrowException(GameState, "Cannot add a GameState to the hierarchy twice.");
     88            return;
     89        }
     90        // Make sure we don't add a tree that already has an active state.
     91        if (state->getCurrentState())
     92        {
     93            ThrowException(GameState, "Cannot merge a tree that is already active.");
     94            return;
     95        }
     96
     97        // merge the child's children into this tree
     98        for (std::map<std::string, GameStateBase*>::const_iterator it = state->allChildren_.begin();
     99            it != state->allChildren_.end(); ++it)
     100            this->grandchildAdded(state, it->second);
     101        // merge 'state' into this tree
     102        this->grandchildAdded(state, state);
     103
     104        // mark us as parent
     105        state->setParent(this);
    90106    }
    91107
     
    97113        GameState by instance pointer
    98114    */
    99     void GameState::removeChild(GameState* state)
    100     {
    101         assert(state != NULL);
    102 
    103         std::map<std::string, GameState*>::iterator it = this->children_.find(state->getName());
    104         if (it != this->children_.end())
    105             this->children_.erase(it);
     115    void GameStateBase::removeChild(GameStateBase* state)
     116    {
     117        std::map<GameStateBase*, GameStateBase*>::iterator it = this->grandchildrenToChildren_.find(state);
     118        if (it != this->grandchildrenToChildren_.end())
     119        {
     120            if (state->isInSubtree(getCurrentState()))
     121            {
     122                ThrowException(GameState, "Cannot remove an active game state child '"
     123                    + state->getName() + "' from '" + name_ + "'.");
     124                //COUT(2) << "Warning: Cannot remove an active game state child '" << state->getName()
     125                //    << "' from '" << name_ << "'." << std::endl;
     126            }
     127            else
     128            {
     129                for (std::map<GameStateBase*, GameStateBase*>::const_iterator it = state->grandchildrenToChildren_.begin();
     130                    it != state->grandchildrenToChildren_.end(); ++it)
     131                    this->grandchildRemoved(it->first);
     132                this->grandchildRemoved(state);
     133            }
     134        }
    106135        else
    107136        {
    108137            ThrowException(GameState, "Game state '" + name_ + "' doesn't have a child named '"
    109138                + state->getName() + "'.");
    110         }
    111     }
    112 
    113     void GameState::activateInternal()
    114     {
    115         this->activity_.activating = true;
    116         this->activate();
    117         this->activity_.activating = false;
    118         this->activity_.active = true;
    119     }
    120 
    121     void GameState::deactivateInternal()
    122     {
    123         this->activity_.active = false;
    124         this->activity_.deactivating = true;
    125         this->activate();
    126         this->activity_.deactivating = false;
    127         this->activity_.suspended = false;
    128         this->activity_.updating = false;
    129     }
    130 
    131     void GameState::updateInternal(const Clock& time)
    132     {
    133         this->activity_.updating = true;
    134         this->update(time);
    135         this->activity_.updating = false;
     139            //COUT(2) << "Warning: Game state '" << name_ << "' doesn't have a child named '"
     140            //    << state->getName() << "'. Removal skipped." << std::endl;
     141        }
     142    }
     143
     144    /**
     145    @brief
     146        Removes a child by name. This splits the tree in two parts,
     147        each of them functional on its own.
     148    @param state
     149        GameState by name
     150    */
     151
     152    void GameStateBase::removeChild(const std::string& name)
     153    {
     154        GameStateBase* state = getState(name);
     155        if (state)
     156        {
     157            removeChild(state);
     158        }
     159        else
     160        {
     161            ThrowException(GameState, "GameState '" + name + "' doesn't exist.");
     162            //COUT(2) << "Warning: GameState '" << name << "' doesn't exist." << std::endl;
     163        }
     164    }
     165
     166    /**
     167    @brief
     168        Tells a state that one of its children has added a child. This is necessary
     169        to fill the internal maps correctly.
     170    @param child
     171        The child who notices this state.
     172    @param grandchild
     173        The child that has been added.
     174    */
     175    inline void GameStateBase::grandchildAdded(GameStateBase* child, GameStateBase* grandchild)
     176    {
     177        // fill the two maps correctly.
     178        this->allChildren_[grandchild->getName()] = grandchild;
     179        this->grandchildrenToChildren_[grandchild] = child;
     180        if (this->getParent())
     181            this->getParent()->grandchildAdded(this, grandchild);
     182    }
     183
     184    /**
     185    @brief
     186        Tells a state that one of its children has removed a child. This is necessary
     187        to fill the internal maps correctly.
     188    @param child
     189        The child who notices this state.
     190    @param grandchild
     191        The child that has been removed.
     192    */
     193    inline void GameStateBase::grandchildRemoved(GameStateBase* grandchild)
     194    {
     195        // adjust the two maps correctly.
     196        this->allChildren_.erase(grandchild->getName());
     197        this->grandchildrenToChildren_.erase(grandchild);
     198        if (this->getParent())
     199            this->getParent()->grandchildRemoved(grandchild);
     200    }
     201
     202    /**
     203    @brief
     204        Checks whether a specific game states exists in the hierarchy.
     205    @remarks
     206        Remember that the every node has a map with all its child nodes.
     207    */
     208    GameStateBase* GameStateBase::getState(const std::string& name)
     209    {
     210        if (this->getParent())
     211            return this->getParent()->getState(name);
     212        else
     213        {
     214            // The map only contains children, so check ourself first
     215            if (name == this->name_)
     216                return this;
     217            // Search in the map. If there is no entry, we can be sure the state doesn't exist.
     218            std::map<std::string, GameStateBase*>::const_iterator it = this->allChildren_.find(name);
     219            return (it!= this->allChildren_.end() ? it->second : 0);
     220        }
     221    }
     222
     223    /**
     224    @brief
     225        Returns the root node of the tree.
     226    */
     227    GameStateBase* GameStateBase::getRoot()
     228    {
     229        if (this->getParent())
     230            return this->getParent()->getRoot();
     231        else
     232            return this;
     233    }
     234
     235    /**
     236    @brief
     237        Returns the current active state.
     238    @remarks
     239        Remember that the current active state is the one that does not
     240        have active children itself. Many states can be active at once.
     241    */
     242    GameStateBase* GameStateBase::getCurrentState()
     243    {
     244        if (this->operation_.active)
     245        {
     246            if (this->activeChild_)
     247                return this->activeChild_->getCurrentState();
     248            else
     249                return this;
     250        }
     251        else
     252        {
     253            if (this->getParent())
     254                return this->getParent()->getCurrentState();
     255            else
     256                return 0;
     257        }
     258    }
     259
     260    /**
     261    @brief
     262        Determines whether 'state' is in this subtree, including this node.
     263    */
     264    bool GameStateBase::isInSubtree(GameStateBase* state) const
     265    {
     266        return (grandchildrenToChildren_.find(state) != grandchildrenToChildren_.end()
     267                || state == this);
     268    }
     269
     270    /**
     271    @brief
     272        Makes a state transition according to the state tree. You can choose any state
     273        in the tree to do the call. The function finds the current state on its own.
     274    @param state
     275        The state to be entered, has to exist in the tree.
     276    */
     277    void GameStateBase::requestState(const std::string& name)
     278    {
     279        assert(getRoot());
     280        getRoot()->requestState(name);
     281    }
     282
     283    /**
     284    @brief
     285        Internal method that actually makes the state transition. Since it is internal,
     286        the method can assume certain things to be granted (like 'this' is always active).
     287    */
     288    void GameStateBase::makeTransition(GameStateBase* source, GameStateBase* destination)
     289    {
     290        if (source == this->getParent())
     291        {
     292            // call is from the parent
     293            this->activate();
     294        }
     295        else if (source == 0)
     296        {
     297            // call was just started by root
     298            // don't do anyting yet
     299        }
     300        else
     301        {
     302            // call is from a child
     303            this->activeChild_ = 0;
     304        }
     305
     306        if (destination == this)
     307            return;
     308
     309        // Check for 'destination' in the children map first
     310        std::map<GameStateBase*, GameStateBase*>::const_iterator it
     311            = this->grandchildrenToChildren_.find(destination);
     312        if (it != this->grandchildrenToChildren_.end())
     313        {
     314            // child state. Don't use 'state', might be a grandchild!
     315            this->activeChild_ = it->second;
     316            it->second->makeTransition(this, destination);
     317        }
     318        else
     319        {
     320            // parent. We can be sure of this.
     321            assert(this->getParent() != 0);
     322
     323            this->deactivate();
     324            this->getParent()->makeTransition(this, destination);
     325        }
     326    }
     327
     328    /**
     329    @brief
     330        Activates the state. Only sets bActive_ to true and notifies the parent.
     331    */
     332    void GameStateBase::activate()
     333    {
     334        this->operation_.active = true;
     335        this->operation_.entering = true;
     336        this->enter();
     337        this->operation_.entering = false;
     338    }
     339
     340    /**
     341        Activates the state. Only sets bActive_ to false and notifies the parent.
     342    */
     343    void GameStateBase::deactivate()
     344    {
     345        this->operation_.leaving = true;
     346        this->leave();
     347        this->operation_.leaving = false;
     348        this->operation_.active = false;
     349    }
     350
     351    /**
     352    @brief
     353        Update method that calls ticked() with enclosed bRunning_ = true
     354        If there was a state transition request within ticked() then this
     355        method will transition in the end.
     356    @param dt Delta time
     357    @note
     358        This method is not virtual! You cannot override it therefore.
     359    */
     360    void GameStateBase::tick(const Clock& time)
     361    {
     362        this->operation_.running = true;
     363        this->ticked(time);
     364        this->operation_.running = false;
    136365    }
    137366}
Note: See TracChangeset for help on using the changeset viewer.