2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: GameState
|
|
|
|
|
|
|
|
|
|
Desc: See Header.
|
|
|
|
|
|
2003-02-03 04:50:37 +00:00
|
|
|
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
|
2002-07-23 01:41:40 +00:00
|
|
|
Chris Danford
|
2003-02-03 04:50:37 +00:00
|
|
|
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"
|
2003-10-14 01:23:16 +00:00
|
|
|
#include "Course.h"
|
2002-09-10 01:13:45 +00:00
|
|
|
#include "RageLog.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
#include "RageUtil.h"
|
2003-02-10 05:30:12 +00:00
|
|
|
#include "SongManager.h"
|
2003-08-03 00:13:55 +00:00
|
|
|
#include "Steps.h"
|
2003-02-22 00:12:45 +00:00
|
|
|
#include "NoteSkinManager.h"
|
2003-03-02 01:43:33 +00:00
|
|
|
#include "ModeChoice.h"
|
2003-04-02 21:57:05 +00:00
|
|
|
#include "NoteFieldPositioning.h"
|
2003-06-09 19:22:04 +00:00
|
|
|
#include "Character.h"
|
2003-07-07 22:21:31 +00:00
|
|
|
#include "UnlockSystem.h"
|
2003-07-10 03:36:41 +00:00
|
|
|
#include "AnnouncerManager.h"
|
2003-09-08 03:26:58 +00:00
|
|
|
#include "ProfileManager.h"
|
2003-07-22 07:47:27 +00:00
|
|
|
#include "arch/arch.h"
|
2003-10-09 03:38:02 +00:00
|
|
|
#include "ThemeManager.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
GameState* GAMESTATE = NULL; // global and accessable from anywhere in our program
|
|
|
|
|
|
2003-07-22 07:47:27 +00:00
|
|
|
#define CHARACTERS_DIR BASE_PATH "Characters" SLASH
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
GameState::GameState()
|
|
|
|
|
{
|
2002-07-28 18:19:17 +00:00
|
|
|
m_CurGame = GAME_DANCE;
|
2003-01-19 04:44:22 +00:00
|
|
|
m_iCoins = 0;
|
2003-02-22 00:12:45 +00:00
|
|
|
/* Don't reset yet; let the first screen do it, so we can
|
|
|
|
|
* use PREFSMAN. */
|
|
|
|
|
// Reset();
|
2003-04-21 23:43:51 +00:00
|
|
|
m_pPosition = NULL;
|
2003-02-03 05:53:59 +00:00
|
|
|
|
2003-07-07 22:21:31 +00:00
|
|
|
m_pUnlockingSys = new UnlockSystem;
|
2003-06-09 19:22:04 +00:00
|
|
|
ReloadCharacters();
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GameState::~GameState()
|
|
|
|
|
{
|
2003-07-07 22:21:31 +00:00
|
|
|
delete m_pUnlockingSys;
|
|
|
|
|
delete m_pPosition;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GameState::Reset()
|
|
|
|
|
{
|
2003-10-09 03:38:02 +00:00
|
|
|
ASSERT( THEME );
|
|
|
|
|
|
2002-07-23 01:41:40 +00:00
|
|
|
int p;
|
|
|
|
|
|
2003-01-30 07:18:33 +00:00
|
|
|
m_CurStyle = STYLE_INVALID;
|
2002-08-13 23:26:46 +00:00
|
|
|
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;
|
2003-07-24 03:54:34 +00:00
|
|
|
m_bChangedFailType = false;
|
2002-07-29 03:06:55 +00:00
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
2003-01-21 22:23:01 +00:00
|
|
|
m_PreferredDifficulty[p] = DIFFICULTY_INVALID;
|
2003-06-30 07:09:13 +00:00
|
|
|
m_SongSortOrder = SORT_INVALID;
|
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;
|
2003-02-05 09:01:09 +00:00
|
|
|
m_bAllow2ndExtraStage = true;
|
2003-03-07 05:24:52 +00:00
|
|
|
m_bDifficultCourses = false;
|
2002-07-29 03:06:55 +00:00
|
|
|
|
2003-09-12 04:18:43 +00:00
|
|
|
NOTESKIN->RefreshNoteSkinData( GAMESTATE->m_CurGame );
|
|
|
|
|
|
2003-07-30 20:34:16 +00:00
|
|
|
m_iGameSeed = rand();
|
|
|
|
|
m_iRoundSeed = rand();
|
|
|
|
|
|
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-06-30 18:55:07 +00:00
|
|
|
SAFE_DELETE( m_pPosition );
|
|
|
|
|
m_pPosition = new NoteFieldPositioning("Positioning.ini");
|
|
|
|
|
|
2003-01-25 11:05:12 +00:00
|
|
|
ResetMusicStatistics();
|
2003-07-03 06:38:57 +00:00
|
|
|
ResetStageStatistics();
|
2003-07-21 21:49:24 +00:00
|
|
|
SONGMAN->UpdateBest();
|
2003-01-25 11:05:12 +00:00
|
|
|
|
2003-09-06 01:37:30 +00:00
|
|
|
m_vPlayedStageStats.clear();
|
2002-07-29 03:06:55 +00:00
|
|
|
|
|
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
2003-02-26 23:26:57 +00:00
|
|
|
{
|
|
|
|
|
m_CurrentPlayerOptions[p].Init();
|
|
|
|
|
m_PlayerOptions[p].Init();
|
|
|
|
|
m_StoredPlayerOptions[p].Init();
|
|
|
|
|
}
|
|
|
|
|
m_SongOptions.Init();
|
2003-04-21 23:43:51 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
2003-10-09 03:38:02 +00:00
|
|
|
{
|
|
|
|
|
ApplyModifiers( (PlayerNumber)p, THEME->GetMetric( "Common","DefaultModifiers" ) );
|
2003-04-22 04:54:04 +00:00
|
|
|
ApplyModifiers( (PlayerNumber)p, PREFSMAN->m_sDefaultModifiers );
|
2003-10-09 03:38:02 +00:00
|
|
|
}
|
2003-04-21 02:41:10 +00:00
|
|
|
|
2003-06-27 08:06:22 +00:00
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
2003-08-27 02:48:32 +00:00
|
|
|
if( PREFSMAN->m_ShowDancingCharacters == PrefsManager::CO_RANDOM)
|
2003-08-25 00:45:12 +00:00
|
|
|
m_pCurCharacters[p] = GetRandomCharacter();
|
2003-06-27 08:06:22 +00:00
|
|
|
else
|
2003-09-25 04:22:51 +00:00
|
|
|
m_pCurCharacters[p] = GetDefaultCharacter();
|
2003-06-27 08:06:22 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-21 02:41:10 +00:00
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
2003-06-30 18:08:27 +00:00
|
|
|
m_fSuperMeterGrowthScale[p] = 1;
|
2003-04-21 02:41:10 +00:00
|
|
|
m_iCpuSkill[p] = 5;
|
|
|
|
|
}
|
2003-09-08 03:26:58 +00:00
|
|
|
|
|
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
PROFILEMAN->UnloadProfile( (PlayerNumber)p );
|
2003-02-03 05:53:59 +00:00
|
|
|
}
|
2003-01-26 02:21:47 +00:00
|
|
|
|
2003-02-26 23:26:57 +00:00
|
|
|
void GameState::Update( float fDelta )
|
|
|
|
|
{
|
2003-04-07 03:25:44 +00:00
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
2003-02-26 23:26:57 +00:00
|
|
|
m_CurrentPlayerOptions[p].Approach( m_PlayerOptions[p], fDelta );
|
2003-04-02 21:57:05 +00:00
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
m_bActiveAttackEndedThisUpdate[p] = false;
|
|
|
|
|
|
2003-07-31 20:34:01 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-04-07 05:14:27 +00:00
|
|
|
if( m_ActiveAttacks[p][s].fSecsRemaining > 0 )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-04-07 05:14:27 +00:00
|
|
|
m_ActiveAttacks[p][s].fSecsRemaining -= fDelta;
|
|
|
|
|
if( m_ActiveAttacks[p][s].fSecsRemaining <= 0 )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-04-07 05:14:27 +00:00
|
|
|
m_ActiveAttacks[p][s].fSecsRemaining = 0;
|
|
|
|
|
m_ActiveAttacks[p][s].sModifier = "";
|
2003-04-07 03:25:44 +00:00
|
|
|
m_bActiveAttackEndedThisUpdate[p] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( m_bActiveAttackEndedThisUpdate[p] )
|
|
|
|
|
RebuildPlayerOptionsFromActiveAttacks( (PlayerNumber)p );
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-02-26 23:26:57 +00:00
|
|
|
|
2003-06-09 19:22:04 +00:00
|
|
|
void GameState::ReloadCharacters()
|
|
|
|
|
{
|
2003-06-10 05:15:23 +00:00
|
|
|
unsigned i;
|
2003-06-09 19:22:04 +00:00
|
|
|
|
|
|
|
|
for( i=0; i<m_pCharacters.size(); i++ )
|
|
|
|
|
delete m_pCharacters[i];
|
|
|
|
|
m_pCharacters.clear();
|
|
|
|
|
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
m_pCurCharacters[p] = NULL;
|
|
|
|
|
|
|
|
|
|
CStringArray as;
|
2003-07-22 07:47:27 +00:00
|
|
|
GetDirListing( CHARACTERS_DIR "*", as, true, true );
|
2003-09-28 00:17:08 +00:00
|
|
|
bool FoundDefault = false;
|
2003-06-09 19:22:04 +00:00
|
|
|
for( i=0; i<as.size(); i++ )
|
|
|
|
|
{
|
2003-09-14 18:30:14 +00:00
|
|
|
CString sCharName, sDummy;
|
|
|
|
|
splitpath(as[i], sDummy, sCharName, sDummy);
|
|
|
|
|
sCharName.MakeLower();
|
|
|
|
|
|
|
|
|
|
if( sCharName == "cvs" ) // the directory called "CVS"
|
|
|
|
|
continue; // ignore it
|
|
|
|
|
|
2003-09-29 00:28:09 +00:00
|
|
|
if( sCharName.CompareNoCase("default")==0 )
|
2003-09-28 00:17:08 +00:00
|
|
|
FoundDefault = true;
|
|
|
|
|
|
2003-06-09 19:22:04 +00:00
|
|
|
Character* pChar = new Character;
|
|
|
|
|
if( pChar->Load( as[i] ) )
|
|
|
|
|
m_pCharacters.push_back( pChar );
|
|
|
|
|
else
|
|
|
|
|
delete pChar;
|
|
|
|
|
}
|
2003-09-25 04:55:46 +00:00
|
|
|
|
2003-09-28 00:17:08 +00:00
|
|
|
if( !FoundDefault )
|
|
|
|
|
RageException::Throw( "Couldn't find \"Characters" SLASH "default\"" );
|
2003-09-25 04:55:46 +00:00
|
|
|
if( !m_pCharacters.size() )
|
|
|
|
|
RageException::Throw( "Couldn't find any character definitions" );
|
2003-06-09 19:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-07 23:49:07 +00:00
|
|
|
const float GameState::MUSIC_SECONDS_INVALID = -5000.0f;
|
|
|
|
|
|
2002-07-29 03:06:55 +00:00
|
|
|
void GameState::ResetMusicStatistics()
|
|
|
|
|
{
|
2003-02-07 23:49:07 +00:00
|
|
|
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-07-03 06:38:57 +00:00
|
|
|
}
|
2003-05-13 13:35:32 +00:00
|
|
|
|
2003-07-03 06:38:57 +00:00
|
|
|
void GameState::ResetStageStatistics()
|
|
|
|
|
{
|
2003-09-06 04:18:08 +00:00
|
|
|
StageStats OldStats = GAMESTATE->m_CurStageStats;
|
2003-07-03 06:38:57 +00:00
|
|
|
m_CurStageStats = StageStats();
|
2003-09-06 04:18:08 +00:00
|
|
|
if( GetStageIndex() > 0 && PREFSMAN->m_bComboContinuesBetweenSongs )
|
|
|
|
|
memcpy( GAMESTATE->m_CurStageStats.iCurCombo, OldStats .iCurCombo, sizeof(OldStats.iCurCombo) );
|
|
|
|
|
|
2003-07-03 06:38:57 +00:00
|
|
|
RemoveAllActiveAttacks();
|
|
|
|
|
RemoveAllInventory();
|
2003-05-13 13:35:32 +00:00
|
|
|
m_fOpponentHealthPercent = 1;
|
2003-07-03 06:38:57 +00:00
|
|
|
m_fTugLifePercentP1 = 0.5f;
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
m_fSuperMeter[p] = 0;
|
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 );
|
2003-05-27 05:27:38 +00:00
|
|
|
// LOG->Trace( "m_fMusicSeconds = %f, m_fSongBeat = %f, m_fCurBPS = %f, m_bFreeze = %f", m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
|
2003-02-06 17:40:06 +00:00
|
|
|
}
|
|
|
|
|
|
2002-07-23 01:41:40 +00:00
|
|
|
int GameState::GetStageIndex()
|
|
|
|
|
{
|
|
|
|
|
return m_iCurrentStageIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-10 05:30:12 +00:00
|
|
|
int GameState::GetNumStagesLeft()
|
|
|
|
|
{
|
2003-02-12 20:56:19 +00:00
|
|
|
if(GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2())
|
|
|
|
|
return 1;
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2003-02-14 08:15:42 +00:00
|
|
|
return 999;
|
2003-02-10 05:30:12 +00:00
|
|
|
return PREFSMAN->m_iNumArcadeStages - m_iCurrentStageIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-23 01:41:40 +00:00
|
|
|
bool GameState::IsFinalStage()
|
|
|
|
|
{
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2002-07-23 01:41:40 +00:00
|
|
|
return false;
|
2003-02-10 05:30:12 +00:00
|
|
|
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()
|
|
|
|
|
{
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2002-07-23 01:41:40 +00:00
|
|
|
return false;
|
|
|
|
|
return m_iCurrentStageIndex == PREFSMAN->m_iNumArcadeStages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GameState::IsExtraStage2()
|
|
|
|
|
{
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2002-07-23 01:41:40 +00:00
|
|
|
return false;
|
|
|
|
|
return m_iCurrentStageIndex == PREFSMAN->m_iNumArcadeStages+1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString GameState::GetStageText()
|
|
|
|
|
{
|
2003-04-01 18:23:27 +00:00
|
|
|
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";
|
2003-04-19 19:05:25 +00:00
|
|
|
else if( PREFSMAN->m_bEventMode ) return "event";
|
2003-04-01 18:23:27 +00:00
|
|
|
else if( IsFinalStage() ) return "final";
|
|
|
|
|
else if( IsExtraStage() ) return "extra1";
|
|
|
|
|
else if( IsExtraStage2() ) return "extra2";
|
|
|
|
|
else return ssprintf("%d",m_iCurrentStageIndex+1);
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-09 04:20:24 +00:00
|
|
|
void GameState::GetAllStageTexts( CStringArray &out )
|
|
|
|
|
{
|
|
|
|
|
out.clear();
|
|
|
|
|
out.push_back( "demo" );
|
|
|
|
|
out.push_back( "oni" );
|
|
|
|
|
out.push_back( "nonstop" );
|
|
|
|
|
out.push_back( "endless" );
|
|
|
|
|
out.push_back( "event" );
|
|
|
|
|
out.push_back( "final" );
|
|
|
|
|
out.push_back( "extra1" );
|
|
|
|
|
out.push_back( "extra2" );
|
|
|
|
|
for( int stage = 0; stage < PREFSMAN->m_iNumArcadeStages; ++stage )
|
|
|
|
|
out.push_back( ssprintf("%d",stage+1) );
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-14 21:42:44 +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. */
|
2003-02-14 21:42:44 +00:00
|
|
|
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 );
|
2003-02-14 21:42:44 +00:00
|
|
|
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-03-25 21:17:29 +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-02 01:43:33 +00:00
|
|
|
|
2002-07-23 01:41:40 +00:00
|
|
|
bool GameState::IsPlayerEnabled( PlayerNumber pn )
|
|
|
|
|
{
|
2003-05-13 05:24:30 +00:00
|
|
|
// In rave, all players are present. Non-human players are CPU controlled.
|
2003-08-19 04:27:50 +00:00
|
|
|
switch( m_PlayMode )
|
|
|
|
|
{
|
|
|
|
|
case PLAY_MODE_BATTLE:
|
|
|
|
|
case PLAY_MODE_RAVE:
|
2003-04-07 05:14:27 +00:00
|
|
|
return true;
|
2003-08-19 04:27:50 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
return IsHumanPlayer( pn );
|
|
|
|
|
}
|
2002-07-23 01:41:40 +00:00
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
bool GameState::IsHumanPlayer( PlayerNumber pn )
|
|
|
|
|
{
|
2003-03-16 22:35:04 +00:00
|
|
|
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
|
2003-03-09 03:28:34 +00:00
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
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;
|
2002-08-13 23:26:46 +00:00
|
|
|
default:
|
2002-08-20 21:00:56 +00:00
|
|
|
ASSERT(0); // invalid style type
|
2002-08-13 23:26:46 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2002-07-29 03:06:55 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-07 21:24:14 +00:00
|
|
|
PlayerNumber GameState::GetFirstHumanPlayer()
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
if( IsHumanPlayer(p) )
|
|
|
|
|
return (PlayerNumber)p;
|
|
|
|
|
ASSERT(0); // there must be at least 1 human player
|
|
|
|
|
return PLAYER_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
bool GameState::IsCpuPlayer( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
return IsPlayerEnabled(pn) && !IsHumanPlayer(pn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-09 20:23:44 +00:00
|
|
|
bool GameState::IsBattleMode() const
|
|
|
|
|
{
|
|
|
|
|
switch( GAMESTATE->m_PlayMode )
|
|
|
|
|
{
|
2003-08-19 04:27:50 +00:00
|
|
|
case PLAY_MODE_BATTLE:
|
2003-07-09 20:23:44 +00:00
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-24 02:43:07 +00:00
|
|
|
bool GameState::HasEarnedExtraStage()
|
|
|
|
|
{
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2003-02-04 21:44:58 +00:00
|
|
|
return false;
|
|
|
|
|
|
2003-10-17 08:03:46 +00:00
|
|
|
if( !PREFSMAN->m_bAllowExtraStage )
|
|
|
|
|
return false;
|
|
|
|
|
|
2003-02-05 18:24:36 +00:00
|
|
|
if( GAMESTATE->m_PlayMode != PLAY_MODE_ARCADE )
|
|
|
|
|
return false;
|
|
|
|
|
|
2003-01-24 02:43:07 +00:00
|
|
|
if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) )
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
if( !GAMESTATE->IsPlayerEnabled(p) )
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
2003-02-04 21:44:58 +00:00
|
|
|
if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_HARD &&
|
|
|
|
|
GAMESTATE->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_CHALLENGE )
|
|
|
|
|
continue; /* not hard enough! */
|
|
|
|
|
|
2003-03-27 21:25:33 +00:00
|
|
|
/* 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). */
|
2003-02-05 09:01:09 +00:00
|
|
|
if( PREFSMAN->m_bPickExtraStage && GAMESTATE->IsExtraStage() && !GAMESTATE->m_bAllow2ndExtraStage )
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-02-04 21:44:58 +00:00
|
|
|
if( m_CurStageStats.GetGrade((PlayerNumber)p) >= GRADE_AA )
|
2003-01-24 02:43:07 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2003-01-27 02:00:38 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-10 03:36:41 +00:00
|
|
|
PlayerNumber GameState::GetBestPlayer()
|
2003-04-15 02:47:24 +00:00
|
|
|
{
|
|
|
|
|
PlayerNumber winner = PLAYER_1;
|
2003-04-21 02:41:10 +00:00
|
|
|
for( int p=PLAYER_1+1; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
if( GAMESTATE->m_CurStageStats.iActualDancePoints[p] == GAMESTATE->m_CurStageStats.iActualDancePoints[winner] )
|
|
|
|
|
return PLAYER_INVALID; // draw
|
|
|
|
|
else if( GAMESTATE->m_CurStageStats.iActualDancePoints[p] > GAMESTATE->m_CurStageStats.iActualDancePoints[winner] )
|
2003-04-15 02:47:24 +00:00
|
|
|
winner = (PlayerNumber)p;
|
2003-04-21 02:41:10 +00:00
|
|
|
}
|
2003-04-15 02:47:24 +00:00
|
|
|
return winner;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-30 18:08:27 +00:00
|
|
|
StageResult GameState::GetStageResult( PlayerNumber pn )
|
2003-04-21 02:41:10 +00:00
|
|
|
{
|
2003-05-13 13:35:32 +00:00
|
|
|
switch( GAMESTATE->m_PlayMode )
|
|
|
|
|
{
|
2003-08-19 04:27:50 +00:00
|
|
|
case PLAY_MODE_BATTLE:
|
2003-07-03 06:38:57 +00:00
|
|
|
case PLAY_MODE_RAVE:
|
|
|
|
|
switch( pn )
|
|
|
|
|
{
|
|
|
|
|
case PLAYER_1: return (m_fTugLifePercentP1>=0.5f)?RESULT_WIN:RESULT_LOSE;
|
|
|
|
|
case PLAYER_2: return (m_fTugLifePercentP1<0.5f)?RESULT_WIN:RESULT_LOSE;
|
|
|
|
|
default: ASSERT(0); return RESULT_LOSE;
|
|
|
|
|
}
|
2003-05-13 13:35:32 +00:00
|
|
|
default:
|
2003-07-10 03:36:41 +00:00
|
|
|
return (GetBestPlayer()==pn)?RESULT_WIN:RESULT_LOSE;
|
2003-05-13 13:35:32 +00:00
|
|
|
}
|
2003-04-21 02:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
2003-09-06 01:35:29 +00:00
|
|
|
int PassedRegularSongsLeft = 3;
|
2003-09-06 01:37:30 +00:00
|
|
|
for( int i = (int)GAMESTATE->m_vPlayedStageStats.size()-1; i >= 0; --i )
|
2003-01-27 02:00:38 +00:00
|
|
|
{
|
2003-09-06 01:37:30 +00:00
|
|
|
const StageStats &s = GAMESTATE->m_vPlayedStageStats[i];
|
2003-09-06 01:35:29 +00:00
|
|
|
|
|
|
|
|
if( !s.OnePassed() )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if( s.StageType == StageStats::STAGE_NORMAL )
|
|
|
|
|
{
|
|
|
|
|
if( PassedRegularSongsLeft == 0 )
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
--PassedRegularSongsLeft;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statsOut.AddStats( s );
|
2003-08-02 21:47:04 +00:00
|
|
|
|
2003-09-06 01:35:29 +00:00
|
|
|
vSongsOut.insert( vSongsOut.begin(), s.pSong );
|
2003-01-27 02:00:38 +00:00
|
|
|
}
|
2003-02-18 07:22:09 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
}
|
2003-02-24 03:26:00 +00:00
|
|
|
|
2003-03-26 23:08:05 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
void GameState::ApplyModifiers( PlayerNumber pn, CString sModifiers )
|
2003-04-21 23:43:51 +00:00
|
|
|
{
|
2003-09-27 06:38:16 +00:00
|
|
|
const SongOptions::FailType ft = GAMESTATE->m_SongOptions.m_FailType;
|
|
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
m_PlayerOptions[pn].FromString( sModifiers );
|
2003-04-21 23:43:51 +00:00
|
|
|
m_SongOptions.FromString( sModifiers );
|
2003-09-27 06:38:16 +00:00
|
|
|
|
|
|
|
|
if( ft != GAMESTATE->m_SongOptions.m_FailType )
|
|
|
|
|
GAMESTATE->m_bChangedFailType = true;
|
2003-04-21 23:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-24 03:26:00 +00:00
|
|
|
/* 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++ )
|
2003-02-26 23:26:57 +00:00
|
|
|
GAMESTATE->m_StoredPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p];
|
2003-03-26 23:08:05 +00:00
|
|
|
m_StoredSongOptions = m_SongOptions;
|
2003-02-24 03:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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++ )
|
2003-02-26 23:26:57 +00:00
|
|
|
GAMESTATE->m_PlayerOptions[p] = GAMESTATE->m_StoredPlayerOptions[p];
|
2003-03-26 23:08:05 +00:00
|
|
|
m_SongOptions = m_StoredSongOptions;
|
2003-02-24 03:26:00 +00:00
|
|
|
}
|
2003-04-07 03:25:44 +00:00
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
void GameState::ResetNoteSkins()
|
|
|
|
|
{
|
|
|
|
|
for( int pn = 0; pn < NUM_PLAYERS; ++pn )
|
|
|
|
|
{
|
|
|
|
|
m_BeatToNoteSkin[pn].clear();
|
|
|
|
|
m_BeatToNoteSkin[pn][-1000] = GAMESTATE->m_PlayerOptions[pn].m_sNoteSkin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_BeatToNoteSkinRev = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* From NoteField: */
|
2003-09-23 23:56:15 +00:00
|
|
|
|
|
|
|
|
void GameState::GetUndisplayedBeats( PlayerNumber pn, float TotalSeconds, float &StartBeat, float &EndBeat )
|
|
|
|
|
{
|
|
|
|
|
/* If reasonable, push the attack forward so notes on screen don't change suddenly. */
|
|
|
|
|
StartBeat = min( this->m_fSongBeat+BEATS_PER_MEASURE*2, m_fLastDrawnBeat[pn] );
|
|
|
|
|
StartBeat = truncf(StartBeat)+1;
|
|
|
|
|
|
|
|
|
|
const float StartSecond = this->m_pCurSong->GetElapsedTimeFromBeat( StartBeat );
|
|
|
|
|
const float EndSecond = StartSecond + TotalSeconds;
|
|
|
|
|
EndBeat = this->m_pCurSong->GetBeatFromElapsedTime( EndSecond );
|
|
|
|
|
EndBeat = truncf(EndBeat)+1;
|
|
|
|
|
}
|
2003-04-07 03:25:44 +00:00
|
|
|
|
2003-04-14 22:12:54 +00:00
|
|
|
void GameState::LaunchAttack( PlayerNumber target, Attack a )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-07-03 06:38:57 +00:00
|
|
|
LOG->Trace( "Launch attack '%s' against P%d", a.sModifier.c_str(), target+1 );
|
|
|
|
|
|
2003-08-18 02:37:43 +00:00
|
|
|
//
|
|
|
|
|
// Peek at the effect being applied. If it's a transform, add it to
|
|
|
|
|
// a list of transforms that should be applied by the Player on its
|
|
|
|
|
// next update.
|
|
|
|
|
//
|
|
|
|
|
PlayerOptions po;
|
|
|
|
|
po.FromString( a.sModifier );
|
|
|
|
|
if( po.m_Transform != PlayerOptions::TRANSFORM_NONE )
|
|
|
|
|
{
|
|
|
|
|
m_TransformsToApply[target].push_back( po.m_Transform );
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
if( po.m_sNoteSkin != "" )
|
|
|
|
|
{
|
|
|
|
|
map<float,CString> &BeatToNoteSkin = m_BeatToNoteSkin[target];
|
|
|
|
|
/* Add it in the future, past what's currently on screen, so new arrows will scroll
|
|
|
|
|
* on screen with this skin. */
|
2003-09-23 23:56:15 +00:00
|
|
|
float StartBeat, EndBeat;
|
|
|
|
|
GetUndisplayedBeats( target, a.fSecsRemaining, StartBeat, EndBeat );
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
/* If there are any note skins after the point we're adding, remove them. We probably
|
|
|
|
|
* have overlapping note skin attacks. */
|
|
|
|
|
map<float,CString>::iterator it = BeatToNoteSkin.begin();
|
|
|
|
|
while( it != BeatToNoteSkin.end() )
|
|
|
|
|
{
|
|
|
|
|
map<float,CString>::iterator next = it;
|
|
|
|
|
++next;
|
2003-09-23 23:56:15 +00:00
|
|
|
if( it->first >= StartBeat )
|
2003-09-12 06:23:51 +00:00
|
|
|
{
|
|
|
|
|
LOG->Trace( "erase old %f", it->first );
|
|
|
|
|
BeatToNoteSkin.erase( it );
|
|
|
|
|
}
|
|
|
|
|
it = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add the skin to m_BeatToNoteSkin. */
|
2003-09-23 23:56:15 +00:00
|
|
|
BeatToNoteSkin[StartBeat] = po.m_sNoteSkin;
|
2003-09-12 06:23:51 +00:00
|
|
|
|
|
|
|
|
/* Return to the default note skin after the duration. */
|
|
|
|
|
BeatToNoteSkin[EndBeat] = GAMESTATE->m_PlayerOptions[target].m_sNoteSkin;
|
|
|
|
|
|
|
|
|
|
++m_BeatToNoteSkinRev;
|
|
|
|
|
po.m_sNoteSkin = "";
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
// search for an open slot
|
2003-07-31 20:34:01 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-04-07 05:14:27 +00:00
|
|
|
if( m_ActiveAttacks[target][s].fSecsRemaining <= 0 )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-04-14 22:12:54 +00:00
|
|
|
m_ActiveAttacks[target][s] = a;
|
2003-05-13 13:35:32 +00:00
|
|
|
GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( target );
|
2003-04-07 03:25:44 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-28 07:56:25 +00:00
|
|
|
void GameState::RemoveActiveAttacksForPlayer( PlayerNumber pn )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-07-31 20:34:01 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-07-08 19:56:56 +00:00
|
|
|
{
|
2003-07-28 07:56:25 +00:00
|
|
|
m_ActiveAttacks[pn][s].fSecsRemaining = 0;
|
|
|
|
|
m_ActiveAttacks[pn][s].sModifier = "";
|
2003-07-08 19:56:56 +00:00
|
|
|
}
|
2003-07-28 07:56:25 +00:00
|
|
|
RebuildPlayerOptionsFromActiveAttacks( (PlayerNumber)pn );
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-14 22:12:54 +00:00
|
|
|
void GameState::RemoveAllInventory()
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
2003-07-31 20:34:01 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-04-14 22:12:54 +00:00
|
|
|
{
|
|
|
|
|
m_Inventory[p][s].fSecsRemaining = 0;
|
|
|
|
|
m_Inventory[p][s].sModifier = "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-07 03:25:44 +00:00
|
|
|
void GameState::RebuildPlayerOptionsFromActiveAttacks( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
// rebuild player options
|
2003-04-22 04:54:04 +00:00
|
|
|
PlayerOptions po = m_StoredPlayerOptions[pn];
|
2003-04-07 03:25:44 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-04-07 05:14:27 +00:00
|
|
|
po.FromString( m_ActiveAttacks[pn][s].sModifier );
|
2003-04-22 04:54:04 +00:00
|
|
|
m_PlayerOptions[pn] = po;
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
2003-04-07 22:07:44 +00:00
|
|
|
|
|
|
|
|
int GameState::GetSumOfActiveAttackLevels( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
int iSum = 0;
|
|
|
|
|
|
2003-07-31 20:34:01 +00:00
|
|
|
for( int s=0; s<NUM_INVENTORY_SLOTS; s++ )
|
2003-04-07 22:07:44 +00:00
|
|
|
if( m_ActiveAttacks[pn][s].fSecsRemaining > 0 )
|
|
|
|
|
iSum += m_ActiveAttacks[pn][s].level;
|
|
|
|
|
|
|
|
|
|
return iSum;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-24 03:54:34 +00:00
|
|
|
template<class T>
|
|
|
|
|
void setmin( T &a, const T &b )
|
|
|
|
|
{
|
|
|
|
|
a = min(a, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
|
void setmax( T &a, const T &b )
|
|
|
|
|
{
|
|
|
|
|
a = max(a, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Adjust the fail mode based on the chosen difficulty. This must be called
|
|
|
|
|
* after the difficulty has been finalized (usually in ScreenSelectMusic or
|
|
|
|
|
* ScreenPlayerOptions), and before the fail mode is displayed or used (usually
|
|
|
|
|
* in ScreenSongOptions). */
|
|
|
|
|
void GameState::AdjustFailType()
|
|
|
|
|
{
|
2003-07-28 23:13:00 +00:00
|
|
|
/* Single song mode only. */
|
|
|
|
|
if( this->IsCourseMode() )
|
|
|
|
|
return;
|
|
|
|
|
|
2003-07-24 03:54:34 +00:00
|
|
|
/* If the player changed the fail mode explicitly, leave it alone. */
|
|
|
|
|
if( GAMESTATE->m_bChangedFailType )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find the easiest difficulty notes selected by either player. */
|
|
|
|
|
Difficulty dc = DIFFICULTY_INVALID;
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
if( !GAMESTATE->IsHumanPlayer(p) )
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
|
|
|
|
dc = min(dc, GAMESTATE->m_pCurNotes[p]->GetDifficulty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset the fail type to the default. */
|
|
|
|
|
SongOptions so;
|
|
|
|
|
so.FromString( PREFSMAN->m_sDefaultModifiers );
|
|
|
|
|
GAMESTATE->m_SongOptions.m_FailType = so.m_FailType;
|
|
|
|
|
|
|
|
|
|
/* Easy and beginner are never harder than FAIL_END_OF_SONG. */
|
|
|
|
|
if(dc <= DIFFICULTY_EASY)
|
|
|
|
|
setmax(GAMESTATE->m_SongOptions.m_FailType, SongOptions::FAIL_END_OF_SONG);
|
|
|
|
|
|
|
|
|
|
/* If beginner's steps were chosen, and this is the first stage,
|
|
|
|
|
* turn off failure completely--always give a second try. */
|
|
|
|
|
if(dc == DIFFICULTY_BEGINNER &&
|
|
|
|
|
!PREFSMAN->m_bEventMode && /* stage index is meaningless in event mode */
|
|
|
|
|
GAMESTATE->m_iCurrentStageIndex == 0)
|
|
|
|
|
setmax(GAMESTATE->m_SongOptions.m_FailType, SongOptions::FAIL_OFF);
|
|
|
|
|
}
|
2003-07-25 08:05:29 +00:00
|
|
|
|
|
|
|
|
bool GameState::ShowMarvelous() const
|
|
|
|
|
{
|
|
|
|
|
if (PREFSMAN->m_iMarvelousTiming == 2)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (PREFSMAN->m_iMarvelousTiming == 1)
|
|
|
|
|
if (IsCourseMode())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
2003-08-10 03:23:17 +00:00
|
|
|
}
|
2003-09-25 04:22:51 +00:00
|
|
|
|
2003-09-25 23:24:10 +00:00
|
|
|
void GameState::GetCharacters( vector<Character*> &apCharactersOut )
|
2003-09-25 04:22:51 +00:00
|
|
|
{
|
|
|
|
|
for( unsigned i=0; i<m_pCharacters.size(); i++ )
|
|
|
|
|
if( m_pCharacters[i]->m_sName.CompareNoCase("default")!=0 )
|
|
|
|
|
apCharactersOut.push_back( m_pCharacters[i] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character* GameState::GetRandomCharacter()
|
|
|
|
|
{
|
|
|
|
|
vector<Character*> apCharacters;
|
|
|
|
|
GetCharacters( apCharacters );
|
|
|
|
|
if( apCharacters.size() )
|
2003-09-27 22:23:35 +00:00
|
|
|
return apCharacters[rand()%apCharacters.size()];
|
2003-09-25 04:22:51 +00:00
|
|
|
else
|
2003-09-25 23:24:10 +00:00
|
|
|
return GetDefaultCharacter();
|
2003-09-25 04:22:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character* GameState::GetDefaultCharacter()
|
|
|
|
|
{
|
|
|
|
|
for( unsigned i=0; i<m_pCharacters.size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
if( m_pCharacters[i]->m_sName.CompareNoCase("default")==0 )
|
|
|
|
|
return m_pCharacters[i];
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-28 00:17:08 +00:00
|
|
|
/* We always have the default character. */
|
|
|
|
|
ASSERT(0);
|
2003-09-25 04:22:51 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-10-14 17:06:30 +00:00
|
|
|
|
2003-10-15 01:09:29 +00:00
|
|
|
void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeats> &asFeatsOut )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-15 01:09:29 +00:00
|
|
|
if( !IsHumanPlayer(pn) )
|
|
|
|
|
return;
|
|
|
|
|
|
2003-10-14 17:06:30 +00:00
|
|
|
switch( GAMESTATE->m_PlayMode )
|
|
|
|
|
{
|
|
|
|
|
case PLAY_MODE_ARCADE:
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
|
2003-10-14 21:38:48 +00:00
|
|
|
for( i=0; i<(int)m_vPlayedStageStats.size(); i++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
|
|
|
|
Song* pSong = m_vPlayedStageStats[i].pSong;
|
2003-10-18 20:57:28 +00:00
|
|
|
ASSERT( pSong );
|
2003-10-14 17:06:30 +00:00
|
|
|
Steps* pSteps = m_vPlayedStageStats[i].pSteps[pn];
|
2003-10-18 20:57:28 +00:00
|
|
|
ASSERT( pSteps );
|
2003-10-14 17:06:30 +00:00
|
|
|
vector<Steps::MemCardData::HighScore> &vHighScores = pSteps->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores;
|
2003-10-14 21:38:48 +00:00
|
|
|
for( unsigned j=0; j<vHighScores.size(); j++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-14 23:29:34 +00:00
|
|
|
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-10-15 01:09:29 +00:00
|
|
|
RankingFeats feat;
|
|
|
|
|
feat.Type = RankingFeats::SONG;
|
|
|
|
|
feat.Feat = ssprintf("No. %d in %s", j+1, pSong->GetFullTranslitTitle().c_str() );
|
|
|
|
|
feat.pStringToFill = &vHighScores[j].sName;
|
|
|
|
|
feat.g = vHighScores[j].grade;
|
|
|
|
|
feat.Score = vHighScores[j].fScore;
|
2003-10-15 20:26:53 +00:00
|
|
|
|
|
|
|
|
// XXX: temporary hack
|
|
|
|
|
if( pSong->HasBackground() )
|
|
|
|
|
feat.Banner = pSong->GetBackgroundPath();
|
|
|
|
|
// if( pSong->HasBanner() )
|
|
|
|
|
// feat.Banner = pSong->GetBannerPath();
|
2003-10-15 01:09:29 +00:00
|
|
|
|
|
|
|
|
asFeatsOut.push_back( feat );
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StageStats stats;
|
|
|
|
|
vector<Song*> vSongs;
|
|
|
|
|
GetFinalEvalStatsAndSongs( stats, vSongs );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
|
|
|
|
|
{
|
|
|
|
|
vector<SongManager::CategoryData::HighScore> &vHighScores = SONGMAN->m_CategoryDatas[nt][i].vHighScores;
|
2003-10-14 21:38:48 +00:00
|
|
|
for( unsigned j=0; j<vHighScores.size(); j++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-14 23:29:34 +00:00
|
|
|
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-10-15 01:09:29 +00:00
|
|
|
RankingFeats feat;
|
|
|
|
|
feat.Type = RankingFeats::RANKING;
|
|
|
|
|
feat.Feat = ssprintf("No. %d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
|
|
|
|
|
feat.pStringToFill = &vHighScores[j].sName;
|
|
|
|
|
feat.g = GRADE_NO_DATA;
|
|
|
|
|
feat.Score = (float) vHighScores[j].iScore;
|
|
|
|
|
asFeatsOut.push_back( feat );
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PLAY_MODE_BATTLE:
|
|
|
|
|
case PLAY_MODE_RAVE:
|
|
|
|
|
break;
|
|
|
|
|
case PLAY_MODE_NONSTOP:
|
|
|
|
|
case PLAY_MODE_ONI:
|
|
|
|
|
case PLAY_MODE_ENDLESS:
|
|
|
|
|
{
|
|
|
|
|
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
|
|
|
|
|
Course* pCourse = GAMESTATE->m_pCurCourse;
|
|
|
|
|
vector<Course::MemCardData::HighScore> &vHighScores = pCourse->m_MemCardDatas[nt][MEMORY_CARD_MACHINE].vHighScores;
|
2003-10-14 21:38:48 +00:00
|
|
|
for( unsigned i=0; i<vHighScores.size(); i++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-14 23:29:34 +00:00
|
|
|
if( vHighScores[i].sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-10-15 01:09:29 +00:00
|
|
|
RankingFeats feat;
|
|
|
|
|
feat.Type = RankingFeats::COURSE;
|
|
|
|
|
feat.Feat = ssprintf("No. %d in %s", i+1, pCourse->m_sName.c_str() );
|
|
|
|
|
feat.pStringToFill = &vHighScores[i].sName;
|
|
|
|
|
feat.g = GRADE_NO_DATA;
|
|
|
|
|
feat.Score = (float) vHighScores[i].iScore;
|
2003-10-15 04:29:28 +00:00
|
|
|
if( pCourse->HasBanner() )
|
|
|
|
|
feat.Banner = pCourse->m_sBannerPath;
|
2003-10-15 01:09:29 +00:00
|
|
|
asFeatsOut.push_back( feat );
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GameState::StoreRankingName( PlayerNumber pn, CString name )
|
|
|
|
|
{
|
2003-10-15 01:09:29 +00:00
|
|
|
vector<RankingFeats> aFeats;
|
|
|
|
|
GetRankingFeats( pn, aFeats );
|
|
|
|
|
|
|
|
|
|
for( unsigned i=0; i<aFeats.size(); i++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-15 01:09:29 +00:00
|
|
|
*aFeats[i].pStringToFill = name;
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
}
|