#include "global.h" /* ----------------------------------------------------------------------------- Class: GameState Desc: See Header. Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved. Chris Danford Chris Gomez ----------------------------------------------------------------------------- */ #include "GameState.h" #include "IniFile.h" #include "GameManager.h" #include "PrefsManager.h" #include "InputMapper.h" #include "song.h" #include "RageLog.h" #include "RageUtil.h" #include "SongManager.h" #include "Notes.h" #include "NoteSkinManager.h" #include "ModeChoice.h" #include "NoteFieldPositioning.h" GameState* GAMESTATE = NULL; // global and accessable from anywhere in our program GameState::GameState() { m_CurGame = GAME_DANCE; m_iCoins = 0; /* Don't reset yet; let the first screen do it, so we can * use PREFSMAN. */ // Reset(); m_pPosition = NULL; ResetLastRanking(); } GameState::~GameState() { SAFE_DELETE( m_pPosition ); } void GameState::Reset() { int p; m_CurStyle = STYLE_INVALID; m_bPlayersCanJoin = false; for( p=0; pm_sDefaultModifiers ); for( p=0; p 0 ) { m_ActiveAttacks[p][s].fSecsRemaining -= fDelta; if( m_ActiveAttacks[p][s].fSecsRemaining <= 0 ) { m_ActiveAttacks[p][s].fSecsRemaining = 0; m_ActiveAttacks[p][s].sModifier = ""; m_bActiveAttackEndedThisUpdate[p] = true; } } } if( m_bActiveAttackEndedThisUpdate[p] ) RebuildPlayerOptionsFromActiveAttacks( (PlayerNumber)p ); } } void GameState::ResetLastRanking() { for( int p=0; pGetBeatAndBPSFromElapsedTime( m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze ); // LOG->Trace( "m_fMusicSeconds = %f, m_fSongBeat = %f, m_fCurBPS = %f, m_bFreeze = %f", m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze ); } int GameState::GetStageIndex() { return m_iCurrentStageIndex; } int GameState::GetNumStagesLeft() { if(GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2()) return 1; if( PREFSMAN->m_bEventMode ) return 999; return PREFSMAN->m_iNumArcadeStages - m_iCurrentStageIndex; } bool GameState::IsFinalStage() { if( PREFSMAN->m_bEventMode ) return false; int iPredictedStageForCurSong = 1; if( m_pCurSong != NULL ) iPredictedStageForCurSong = SongManager::GetNumStagesForSong( m_pCurSong ); return m_iCurrentStageIndex + iPredictedStageForCurSong == PREFSMAN->m_iNumArcadeStages; } bool GameState::IsExtraStage() { if( PREFSMAN->m_bEventMode ) return false; return m_iCurrentStageIndex == PREFSMAN->m_iNumArcadeStages; } bool GameState::IsExtraStage2() { if( PREFSMAN->m_bEventMode ) return false; return m_iCurrentStageIndex == PREFSMAN->m_iNumArcadeStages+1; } CString GameState::GetStageText() { if( m_bDemonstrationOrJukebox ) return "demo"; else if( m_PlayMode == PLAY_MODE_ONI ) return "oni"; else if( m_PlayMode == PLAY_MODE_NONSTOP ) return "nonstop"; else if( m_PlayMode == PLAY_MODE_ENDLESS ) return "endless"; else if( PREFSMAN->m_bEventMode ) return "event"; else if( IsFinalStage() ) return "final"; else if( IsExtraStage() ) return "extra1"; else if( IsExtraStage2() ) return "extra2"; else return ssprintf("%d",m_iCurrentStageIndex+1); } int GameState::GetCourseSongIndex() { int iSongIndex = 0; /* iSongsPlayed includes the current song, so it's 1-based; subtract one. */ for( int p=0; pGetGameDefForGame( m_CurGame ); } const StyleDef* GameState::GetCurrentStyleDef() { ASSERT( m_CurStyle != STYLE_INVALID ); // the style must be set before calling this return GAMEMAN->GetStyleDefForStyle( m_CurStyle ); } void GameState::ApplyModeChoice( const ModeChoice& mc, PlayerNumber pn ) { if( mc.game != GAME_INVALID ) m_CurGame = mc.game; if( mc.pm != PLAY_MODE_INVALID ) m_PlayMode = mc.pm; if( mc.style != STYLE_INVALID ) m_CurStyle = mc.style; if( mc.dc != DIFFICULTY_INVALID && pn != PLAYER_INVALID ) m_PreferredDifficulty[pn] = mc.dc; } bool GameState::IsPlayable( const ModeChoice& mc ) { return mc.numSidesJoinedToPlay == GAMESTATE->GetNumSidesJoined(); } bool GameState::IsPlayerEnabled( PlayerNumber pn ) { // In rave, all players are present. Non-human players are CPU controlled. if( m_PlayMode == PLAY_MODE_RAVE ) return true; return IsHumanPlayer( pn ); } bool GameState::IsHumanPlayer( PlayerNumber pn ) { if( m_CurStyle == STYLE_INVALID ) // no style chosen if( this->m_bPlayersCanJoin ) return m_bSideIsJoined[pn]; // only allow input from sides that have already joined else return true; // if we can't join, then we're on a screen like MusicScroll or GameOver switch( GetCurrentStyleDef()->m_StyleType ) { case StyleDef::TWO_PLAYERS_TWO_CREDITS: return true; case StyleDef::ONE_PLAYER_ONE_CREDIT: case StyleDef::ONE_PLAYER_TWO_CREDITS: return pn == m_MasterPlayerNumber; default: ASSERT(0); // invalid style type return false; } } PlayerNumber GameState::GetFirstHumanPlayer() { for( int p=0; pm_bEventMode ) return false; if( GAMESTATE->m_PlayMode != PLAY_MODE_ARCADE ) return false; if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) ) { for( int p=0; pIsPlayerEnabled(p) ) continue; // skip if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_HARD && GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_CHALLENGE ) continue; /* not hard enough! */ /* If "choose EX" is enabled, then we should only grant EX2 if the chosen * stage was the EX we would have chosen (m_bAllow2ndExtraStage is true). */ if( PREFSMAN->m_bPickExtraStage && GAMESTATE->IsExtraStage() && !GAMESTATE->m_bAllow2ndExtraStage ) continue; if( m_CurStageStats.GetGrade((PlayerNumber)p) >= GRADE_AA ) return true; } } return false; } PlayerNumber GameState::GetWinner() { PlayerNumber winner = PLAYER_1; for( int p=PLAYER_1+1; pm_CurStageStats.iActualDancePoints[p] == GAMESTATE->m_CurStageStats.iActualDancePoints[winner] ) return PLAYER_INVALID; // draw else if( GAMESTATE->m_CurStageStats.iActualDancePoints[p] > GAMESTATE->m_CurStageStats.iActualDancePoints[winner] ) winner = (PlayerNumber)p; } return winner; } BattleResult GameState::GetBattleResult( PlayerNumber pn ) { // PlayerNumber winner = GetWinner(); // if( winner == PLAYER_INVALID ) // return RESULT_DRAW; // return (winner==pn) ? RESULT_WIN : RESULT_LOSE; switch( GAMESTATE->m_PlayMode ) { case PLAY_MODE_BATTLE: return (m_fOpponentHealthPercent==0)?RESULT_WIN:RESULT_LOSE; default: ASSERT(0); return RESULT_WIN; } } void GameState::GetFinalEvalStatsAndSongs( StageStats& statsOut, vector& vSongsOut ) { statsOut = StageStats(); // Show stats only for the latest 3 normal songs + passed extra stages int iNumSongsToThrowAway = max( 0, PREFSMAN->m_iNumArcadeStages-3 ); for( unsigned i=iNumSongsToThrowAway; im_vPassedStageStats.size(); i++ ) { statsOut += GAMESTATE->m_vPassedStageStats[i]; vSongsOut.push_back( GAMESTATE->m_vPassedStageStats[i].pSong ); } if(!vSongsOut.size()) return; /* XXX: I have no idea if this is correct--but it's better than overflowing, * anyway. -glenn */ for( int p=0; pm_StoredPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p]; m_StoredSongOptions = m_SongOptions; } /* Restore the preferred options. This is called after a song ends, before * setting new course options, so options from one song don't carry into the * next and we default back to the preferred options. This is also called * at the end of gameplay to restore options. */ void GameState::RestoreSelectedOptions() { for( int p=0; pm_PlayerOptions[p] = GAMESTATE->m_StoredPlayerOptions[p]; m_SongOptions = m_StoredSongOptions; } void GameState::LaunchAttack( PlayerNumber target, Attack a ) { // search for an open slot for( unsigned s=0; sRebuildPlayerOptionsFromActiveAttacks( target ); return; } } void GameState::RemoveAllActiveAttacks() { for( int p=0; p 0 ) iSum += m_ActiveAttacks[pn][s].level; return iSum; }