#include "gamestate.h" #include "game.h" #include "astleaf.h" #include "astleafliteral.h" #include using namespace Bu; GameState::GameState( Game *pGame ) : pGame( pGame ) { } GameState::~GameState() { } void GameState::parse( class AstBranch *pAst ) { if( pAst->getType() != AstNode::tScope ) throw Bu::ExceptionBase("Nope, nothing doing, you can't parse a non-scope AstBranch."); lsLocal.push( new Scope() ); int iDepth = lsLocal.getSize(); parse( pAst->getNodeList() ); if( lsLocal.getSize() == iDepth ) delete lsLocal.peekPop(); } void GameState::init() { Variable vStart = pGame->getParam("start"); if( vStart.getType() != Variable::tSituation ) throw Bu::ExceptionBase("game.start is not set to a situation name."); gotoSituation( vStart.getString() ); } void GameState::gotoSituation( const Bu::String &sName ) { lStack.clear(); for( ScopeList::iterator i = lsLocal.begin(); i; i++ ) delete *i; lsLocal.clear(); Situation *pSit = pGame->getSituation( sName ); sCurSituation = sName; if( !hsSituation.has( sName ) ) { hsSituation.insert( sName, new Scope() ); pSit->exec( *this, Situation::modeSetup ); } // This is here in case you use a goto in a setup mode if( bEscape ) return; pSit->exec( *this, Situation::modeEnter ); } void GameState::callFunction( const Bu::String &sName ) { pGame->getFunction( sName )->call( *this ); } Variable GameState::getVariable( const Bu::String &sName, ScopeId id ) { try { switch( id ) { case sidLocal: return lsLocal.peek()->get( sName ); case sidGlobal: return sGlobal.get( sName ); case sidPlayer: return sPlayer.get( sName ); case sidSituation: return hsSituation.get( sCurSituation )->get( sName ); } } catch( Bu::HashException &e ) { throw Bu::ExceptionBase("No %d variable named %s found.", id, sName.getStr() ); } throw Bu::ExceptionBase("Really bad scopeid passed into getVariable"); } void GameState::setVariable( const Bu::String &sName, const Variable &v, ScopeId id ) { switch( id ) { case sidLocal: lsLocal.peek()->insert( sName, v ); return; case sidGlobal: sGlobal.insert( sName, v ); return; case sidPlayer: sPlayer.insert( sName, v ); return; case sidSituation: hsSituation.get( sCurSituation )->insert( sName, v ); return; } throw Bu::ExceptionBase("Really bad scopeid passed into setVariable"); } Variable GameState::deref( const Variable &src ) { if( src.getType() == Variable::tVariable ) { VariableRef r = src.getVariableRef(); return getVariable( r.sName, r.sid ); } return src; } Variable GameState::popDeref() { Variable v = lStack.peekPop(); if( v.getType() == Variable::tVariable ) { VariableRef r = v.getVariableRef(); return getVariable( r.sName, r.sid ); } return v; } void GameState::parse( const AstBranch::NodeList &lCode ) { bEscape = false; for( AstBranch::NodeList::const_iterator i = lCode.begin(); i; i++ ) { // sio << "Stack: " << lStack << sio.nl; // sio << "exec: " << (*i)->getType() << sio.nl; switch( (*i)->getType() ) { // tLeaf case AstNode::tNot: { Variable x = popDeref(); if( x.getType() != Variable::tBool ) throw Bu::ExceptionBase("Non-bool used with logical not operator."); push( Variable( !x.getBool() ) ); } break; case AstNode::tComp: { push( popDeref() == popDeref() ); } break; case AstNode::tCompGt: { Variable y = popDeref(); Variable x = popDeref(); push( x > y ); } break; case AstNode::tCompLt: { Variable y = popDeref(); Variable x = popDeref(); push( x < y ); } break; case AstNode::tCompGtEq: { Variable y = popDeref(); Variable x = popDeref(); push( x >= y ); } break; case AstNode::tCompLtEq: { Variable y = popDeref(); Variable x = popDeref(); push( x <= y ); } break; case AstNode::tStore: { Variable y = popDeref(); Variable dst = pop(); VariableRef r = dst.getVariableRef(); setVariable( r.sName, y, r.sid ); } break; case AstNode::tAnd: { Variable y = popDeref(); Variable x = popDeref(); if( x.getType() != Variable::tBool || y.getType() != Variable::tBool ) { throw Bu::ExceptionBase("Non-bool used in logical AND operator."); } lStack.push( Variable( x.getBool() && y.getBool() ) ); } break; case AstNode::tOr: { Variable y = popDeref(); Variable x = popDeref(); if( x.getType() != Variable::tBool || y.getType() != Variable::tBool ) { throw Bu::ExceptionBase("Non-bool used in logical OR operator."); } lStack.push( Variable( x.getBool() || y.getBool() ) ); } break; case AstNode::tPlus: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x + y ); } break; case AstNode::tMinus: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x - y ); } break; case AstNode::tDivide: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x / y ); } break; case AstNode::tMultiply: { Variable y = popDeref(); Variable x = popDeref(); lStack.push( x * y ); } break; case AstNode::tPlusStore: { Variable y = popDeref(); Variable x = pop(); VariableRef r = x.getVariableRef(); setVariable( r.sName, getVariable( r.sName, r.sid ) + y, r.sid ); } break; case AstNode::tMinusStore: { Variable y = popDeref(); Variable x = pop(); VariableRef r = x.getVariableRef(); setVariable( r.sName, getVariable( r.sName, r.sid ) - y, r.sid ); } break; case AstNode::tDivideStore: { Variable y = popDeref(); Variable x = pop(); VariableRef r = x.getVariableRef(); setVariable( r.sName, getVariable( r.sName, r.sid ) / y, r.sid ); } break; case AstNode::tMultiplyStore: { Variable y = popDeref(); Variable x = pop(); VariableRef r = x.getVariableRef(); setVariable( r.sName, getVariable( r.sName, r.sid ) * y, r.sid ); } break; case AstNode::tNegate: push( -popDeref() ); break; case AstNode::tIn: case AstNode::tGoto: { Variable x = popDeref(); if( x.getType() != Variable::tSituation ) throw Bu::ExceptionBase("You cannot goto anything but a situation."); gotoSituation( x.getString() ); bEscape = true; return; } break; case AstNode::tSwap: { Variable y = pop(); Variable x = pop(); push( y ); push( x ); } break; // tLeafLiteral case AstNode::tVarName: case AstNode::tLiteral: lStack.push( dynamic_cast(*i)->getValue() ); break; case AstNode::tFuncCall: callFunction( dynamic_cast(*i) ->getValue().getString() ); break; // tBranch case AstNode::tScope: case AstNode::tIf: { AstBranch::NodeList lIf = dynamic_cast(*i)->getNodeList(); AstBranch::NodeList::const_iterator iIf = lIf.begin(); parse( dynamic_cast(*iIf)->getNodeList() ); Variable v = popDeref(); if( v.getType() != Variable::tBool ) throw Bu::ExceptionBase("conditional did not evaluate to boolean."); iIf++; if( v.getBool() ) { parse( dynamic_cast(*iIf)-> getNodeList() ); } else { iIf++; if( iIf ) parse( dynamic_cast(*iIf)-> getNodeList() ); } } break; case AstNode::tForEach: case AstNode::tWhile: break; } if( bEscape ) { return; } } }