Files
itgmania212121/stepmania/src/GameState.cpp
T

379 lines
10 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
2002-07-23 01:41:40 +00:00
/*
-----------------------------------------------------------------------------
Class: GameState
Desc: See Header.
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
2002-07-23 01:41:40 +00:00
Chris Danford
Chris Gomez
2002-07-23 01:41:40 +00:00
-----------------------------------------------------------------------------
*/
#include "GameState.h"
#include "IniFile.h"
#include "GameManager.h"
#include "PrefsManager.h"
#include "InputMapper.h"
2003-02-16 04:28:17 +00:00
#include "song.h"
#include "RageLog.h"
#include "ThemeManager.h"
#include "RageUtil.h"
#include "SongManager.h"
#include "Notes.h"
#include "NoteSkinManager.h"
2003-03-02 01:43:33 +00:00
#include "ModeChoice.h"
2002-07-23 01:41:40 +00:00
GameState* GAMESTATE = NULL; // global and accessable from anywhere in our program
2002-08-28 22:42:40 +00:00
#define STAGE_COLOR_DEMO THEME->GetMetricC("GameState","StageColorDemo")
#define STAGE_COLOR( i ) THEME->GetMetricC("GameState",ssprintf("StageColor%d",i+1))
2002-08-28 22:42:40 +00:00
#define STAGE_COLOR_FINAL THEME->GetMetricC("GameState","StageColorFinal")
#define STAGE_COLOR_EXTRA1 THEME->GetMetricC("GameState","StageColorExtra1")
#define STAGE_COLOR_EXTRA2 THEME->GetMetricC("GameState","StageColorExtra2")
#define STAGE_COLOR_NONSTOP THEME->GetMetricC("GameState","StageColorNonstop")
2002-08-28 22:42:40 +00:00
#define STAGE_COLOR_ONI THEME->GetMetricC("GameState","StageColorOni")
#define STAGE_COLOR_ENDLESS THEME->GetMetricC("GameState","StageColorEndless")
2002-08-28 22:42:40 +00:00
#define STAGE_TEXT_DEMO THEME->GetMetric("GameState","StageTextDemo")
#define STAGE_TEXT_FINAL THEME->GetMetric("GameState","StageTextFinal")
#define STAGE_TEXT_EXTRA1 THEME->GetMetric("GameState","StageTextExtra1")
#define STAGE_TEXT_EXTRA2 THEME->GetMetric("GameState","StageTextExtra2")
2002-07-23 01:41:40 +00:00
GameState::GameState()
{
m_CurGame = GAME_DANCE;
2003-01-19 04:44:22 +00:00
m_iCoins = 0;
/* Don't reset yet; let the first screen do it, so we can
* use PREFSMAN. */
// Reset();
ResetLastRanking();
2002-07-23 01:41:40 +00:00
}
GameState::~GameState()
{
}
void GameState::Reset()
{
int p;
2003-01-30 07:18:33 +00:00
m_CurStyle = STYLE_INVALID;
m_bPlayersCanJoin = false;
2003-01-19 04:44:22 +00:00
for( p=0; p<NUM_PLAYERS; p++ )
m_bSideIsJoined[p] = false;
// m_iCoins = 0; // don't reset coin count!
2002-08-20 21:00:56 +00:00
m_MasterPlayerNumber = PLAYER_INVALID;
2003-02-25 00:33:42 +00:00
m_sPreferredGroup = GROUP_ALL_MUSIC;
2002-07-29 03:06:55 +00:00
for( p=0; p<NUM_PLAYERS; p++ )
m_PreferredDifficulty[p] = DIFFICULTY_INVALID;
m_SongSortOrder = SORT_GROUP;
2002-07-29 03:06:55 +00:00
m_PlayMode = PLAY_MODE_INVALID;
m_bEditing = false;
2003-03-09 00:55:49 +00:00
m_bDemonstrationOrJukebox = false;
2003-02-11 02:20:38 +00:00
m_bJukeboxUsesModifiers = false;
2002-07-29 03:06:55 +00:00
m_iCurrentStageIndex = 0;
m_bAllow2ndExtraStage = true;
2003-03-07 05:24:52 +00:00
m_bDifficultCourses = false;
2002-07-29 03:06:55 +00:00
2002-07-23 01:41:40 +00:00
m_pCurSong = NULL;
for( p=0; p<NUM_PLAYERS; p++ )
m_pCurNotes[p] = NULL;
m_pCurCourse = NULL;
2003-01-25 11:05:12 +00:00
ResetMusicStatistics();
m_CurStageStats = StageStats();
m_vPassedStageStats.clear();
2002-07-29 03:06:55 +00:00
for( p=0; p<NUM_PLAYERS; p++ )
{
m_CurrentPlayerOptions[p].Init();
m_PlayerOptions[p].Init();
m_StoredPlayerOptions[p].Init();
}
m_SongOptions.Init();
for( p=0; p<NUM_PLAYERS; p++ )
NOTESKIN->SwitchNoteSkin( PlayerNumber(p), PREFSMAN->m_sDefaultNoteSkin );
}
2003-01-26 02:21:47 +00:00
void GameState::Update( float fDelta )
{
for( int p=0; p<NUM_PLAYERS; p++ )
m_CurrentPlayerOptions[p].Approach( m_PlayerOptions[p], fDelta );
}
void GameState::ResetLastRanking()
{
for( int p=0; p<NUM_PLAYERS; p++ )
2003-01-26 02:21:47 +00:00
{
m_RankingCategory[p] = (RankingCategory)-1;
m_iRankingIndex[p] = -1;
2003-01-26 02:21:47 +00:00
}
2002-07-29 03:06:55 +00:00
}
const float GameState::MUSIC_SECONDS_INVALID = -5000.0f;
2002-07-29 03:06:55 +00:00
void GameState::ResetMusicStatistics()
{
m_fMusicSeconds = MUSIC_SECONDS_INVALID;
2002-07-29 03:06:55 +00:00
m_fSongBeat = 0;
m_fCurBPS = 10;
m_bFreeze = false;
2003-01-25 11:05:12 +00:00
m_bPastHereWeGo = false;
2003-02-25 00:33:42 +00:00
for( int p=0; p<NUM_PLAYERS; p++ )
2003-02-25 02:51:04 +00:00
for( int s=0; s<NUM_ITEM_SLOTS; s++ )
m_iItems[p][s] = ITEM_NONE;
2002-07-29 03:06:55 +00:00
}
2003-02-06 17:40:06 +00:00
void GameState::UpdateSongPosition(float fPositionSeconds)
{
ASSERT(m_pCurSong);
m_fMusicSeconds = fPositionSeconds;
m_pCurSong->GetBeatAndBPSFromElapsedTime( m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
}
2002-07-23 01:41:40 +00:00
int GameState::GetStageIndex()
{
return m_iCurrentStageIndex;
}
int GameState::GetNumStagesLeft()
{
2003-02-12 20:56:19 +00:00
if(GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2())
return 1;
2003-02-14 08:15:42 +00:00
if(PREFSMAN->m_bEventMode)
return 999;
return PREFSMAN->m_iNumArcadeStages - m_iCurrentStageIndex;
}
2002-07-23 01:41:40 +00:00
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;
2002-07-23 01:41:40 +00:00
}
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()
{
2003-03-09 00:55:49 +00:00
if( m_bDemonstrationOrJukebox ) return STAGE_TEXT_DEMO;
2002-08-28 22:42:40 +00:00
else if( IsFinalStage() ) return STAGE_TEXT_FINAL;
else if( IsExtraStage() ) return STAGE_TEXT_EXTRA1;
else if( IsExtraStage2() ) return STAGE_TEXT_EXTRA2;
2002-07-23 01:41:40 +00:00
int iStageNo = m_iCurrentStageIndex+1;
CString sNumberSuffix;
if( ( (iStageNo/10) % 10 ) == 1 ) // in the teens (e.g. 19, 213)
{
sNumberSuffix = "th";
}
else // not in the teens
{
const int iLastDigit = iStageNo%10;
switch( iLastDigit )
{
case 1: sNumberSuffix = "st"; break;
case 2: sNumberSuffix = "nd"; break;
case 3: sNumberSuffix = "rd"; break;
default:sNumberSuffix = "th"; break;
}
}
return ssprintf( "%d%s", iStageNo, sNumberSuffix.GetString() );
2002-07-23 01:41:40 +00:00
}
RageColor GameState::GetStageColor()
2002-07-23 01:41:40 +00:00
{
2003-03-09 00:55:49 +00:00
if( m_bDemonstrationOrJukebox ) return STAGE_COLOR_DEMO;
else if( m_PlayMode==PLAY_MODE_NONSTOP ) return STAGE_COLOR_NONSTOP;
else if( m_PlayMode==PLAY_MODE_ONI ) return STAGE_COLOR_ONI;
else if( m_PlayMode==PLAY_MODE_ENDLESS ) return STAGE_COLOR_ENDLESS;
else if( IsFinalStage() ) return STAGE_COLOR_FINAL;
else if( IsExtraStage() ) return STAGE_COLOR_EXTRA1;
else if( IsExtraStage2() ) return STAGE_COLOR_EXTRA2;
else return STAGE_COLOR( min(m_iCurrentStageIndex,4) );
2002-07-23 01:41:40 +00:00
}
int GameState::GetCourseSongIndex()
{
int iSongIndex = 0;
2003-02-25 21:23:21 +00:00
/* iSongsPlayed includes the current song, so it's 1-based; subtract one. */
for( int p=0; p<NUM_PLAYERS; p++ )
if( IsPlayerEnabled(p) )
2003-02-25 21:23:21 +00:00
iSongIndex = max( iSongIndex, m_CurStageStats.iSongsPlayed[p]-1 );
return iSongIndex;
}
2002-07-23 01:41:40 +00:00
GameDef* GameState::GetCurrentGameDef()
{
2002-09-29 05:06:18 +00:00
ASSERT( m_CurGame != GAME_INVALID ); // the game must be set before calling this
2002-07-23 01:41:40 +00:00
return GAMEMAN->GetGameDefForGame( m_CurGame );
}
2002-08-22 23:05:49 +00:00
const StyleDef* GameState::GetCurrentStyleDef()
2002-07-23 01:41:40 +00:00
{
2003-01-30 07:18:33 +00:00
ASSERT( m_CurStyle != STYLE_INVALID ); // the style must be set before calling this
2002-07-23 01:41:40 +00:00
return GAMEMAN->GetStyleDefForStyle( m_CurStyle );
}
2003-03-03 10:03:02 +00:00
void GameState::ApplyModeChoice( const ModeChoice& mc, PlayerNumber pn )
2003-03-02 01:43:33 +00:00
{
2003-03-03 10:03:02 +00:00
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();
2003-03-02 01:43:33 +00:00
}
2002-07-23 01:41:40 +00:00
bool GameState::IsPlayerEnabled( PlayerNumber pn )
{
2003-01-30 07:18:33 +00:00
if( m_CurStyle == STYLE_INVALID ) // if no style set (we're in TitleMenu, ConfigInstruments or something)
2002-07-23 01:41:40 +00:00
return true; // allow input from both sides
switch( GetCurrentStyleDef()->m_StyleType )
{
case StyleDef::TWO_PLAYERS_TWO_CREDITS:
return true;
case StyleDef::ONE_PLAYER_ONE_CREDIT:
case StyleDef::ONE_PLAYER_TWO_CREDITS:
2002-08-20 21:00:56 +00:00
return pn == m_MasterPlayerNumber;
default:
2002-08-20 21:00:56 +00:00
ASSERT(0); // invalid style type
return false;
}
2002-07-29 03:06:55 +00:00
}
2003-02-28 07:26:43 +00:00
bool GameState::IsCourseMode() const
{
switch(m_PlayMode)
{
case PLAY_MODE_ONI:
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ENDLESS:
return true;
default:
return false;
}
}
bool GameState::HasEarnedExtraStage()
{
if( PREFSMAN->m_bEventMode )
return false;
2003-02-05 18:24:36 +00:00
if( GAMESTATE->m_PlayMode != PLAY_MODE_ARCADE )
return false;
if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) )
{
for( int p=0; p<NUM_PLAYERS; p++ )
{
if( !GAMESTATE->IsPlayerEnabled(p) )
continue; // skip
if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_HARD &&
GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_CHALLENGE )
continue; /* not hard enough! */
2003-02-04 22:19:24 +00:00
/* XXX: if "choose EX" is enabled, then we should only grant EX2
* if the chosen stage was the EX we would have chosen (the hardest
* song or extra1.crs). Also, that song should be highlighted in the
* music wheel. */
if( PREFSMAN->m_bPickExtraStage && GAMESTATE->IsExtraStage() && !GAMESTATE->m_bAllow2ndExtraStage )
continue;
if( m_CurStageStats.GetGrade((PlayerNumber)p) >= GRADE_AA )
return true;
}
}
return false;
2003-01-27 02:00:38 +00:00
}
void GameState::GetFinalEvalStatsAndSongs( StageStats& statsOut, vector<Song*>& 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; i<GAMESTATE->m_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; p<NUM_PLAYERS; p++ )
{
if( !IsPlayerEnabled(p) )
continue;
for( int r = 0; r < NUM_RADAR_CATEGORIES; r++)
{
statsOut.fRadarPossible[p][r] /= vSongsOut.size();
statsOut.fRadarActual[p][r] /= vSongsOut.size();
}
}
2003-01-27 02:00:38 +00:00
}
/* XXX: Should we store song options, too? */
/* Store the player's preferred options. This is called at the very beginning
* of gameplay. */
void GameState::StoreSelectedOptions()
{
for( int p=0; p<NUM_PLAYERS; p++ )
GAMESTATE->m_StoredPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p];
}
/* 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; p<NUM_PLAYERS; p++ )
GAMESTATE->m_PlayerOptions[p] = GAMESTATE->m_StoredPlayerOptions[p];
/* Oops. We can't do this; it'll reset lives back to 4, and we need it
* to stick around for the length of the course (for regaining). Let's
* just reset the options that can actually be set per-song. XXX */
// GAMESTATE->m_SongOptions.Init();
GAMESTATE->m_SongOptions.m_DrainType = SongOptions::DRAIN_NORMAL;
GAMESTATE->m_SongOptions.m_fMusicRate = 1.0f;
}