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"
|
2003-11-16 04:45:12 +00:00
|
|
|
#include "LightsManager.h"
|
2003-11-30 06:20:25 +00:00
|
|
|
#include "RageFile.h"
|
2003-12-07 20:29:42 +00:00
|
|
|
#include "Bookkeeper.h"
|
2003-12-08 04:02:43 +00:00
|
|
|
#include <time.h>
|
2003-12-19 04:52:07 +00:00
|
|
|
#include "MemoryCardManager.h"
|
2003-12-23 00:26:00 +00:00
|
|
|
#include "StageStats.h"
|
2004-03-13 22:18:09 +00:00
|
|
|
#include "GameConstantsAndTypes.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
|
2003-11-14 20:29:51 +00:00
|
|
|
#define DEFAULT_MODIFIERS THEME->GetMetric( "Common","DefaultModifiers" )
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
GameState* GAMESTATE = NULL; // global and accessable from anywhere in our program
|
|
|
|
|
|
2003-12-10 09:26:05 +00:00
|
|
|
#define CHARACTERS_DIR "Characters/"
|
|
|
|
|
#define NAMES_BLACKLIST_FILE "Data/NamesBlacklist.dat"
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
GameState::GameState()
|
|
|
|
|
{
|
2004-01-21 04:59:15 +00:00
|
|
|
m_pPosition = NULL;
|
|
|
|
|
|
2002-07-28 18:19:17 +00:00
|
|
|
m_CurGame = GAME_DANCE;
|
2003-01-19 04:44:22 +00:00
|
|
|
m_iCoins = 0;
|
2004-02-22 23:26:46 +00:00
|
|
|
m_timeGameStarted.SetZero();
|
2004-01-03 03:58:37 +00:00
|
|
|
m_bIsOnSystemMenu = false;
|
2003-02-03 05:53:59 +00:00
|
|
|
|
2003-06-09 19:22:04 +00:00
|
|
|
ReloadCharacters();
|
2003-12-28 19:46:50 +00:00
|
|
|
|
2004-03-13 10:12:59 +00:00
|
|
|
m_iNumTimesThroughAttract = 0;
|
2004-01-21 04:59:15 +00:00
|
|
|
|
|
|
|
|
/* Don't reset yet; let the first screen do it, so we can
|
|
|
|
|
* use PREFSMAN and THEME. */
|
|
|
|
|
// Reset();
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GameState::~GameState()
|
|
|
|
|
{
|
2003-07-07 22:21:31 +00:00
|
|
|
delete m_pPosition;
|
2004-01-21 11:28:31 +00:00
|
|
|
for( unsigned i=0; i<m_pCharacters.size(); i++ )
|
|
|
|
|
delete m_pCharacters[i];
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GameState::Reset()
|
|
|
|
|
{
|
2004-02-22 23:26:46 +00:00
|
|
|
if( !m_timeGameStarted.IsZero() && g_vPlayedStageStats.size() ) // we were in the middle of a game and played at least one song
|
2003-12-08 04:02:43 +00:00
|
|
|
EndGame();
|
|
|
|
|
|
|
|
|
|
|
2003-10-09 03:38:02 +00:00
|
|
|
ASSERT( THEME );
|
|
|
|
|
|
2002-07-23 01:41:40 +00:00
|
|
|
int p;
|
|
|
|
|
|
2004-02-22 23:26:46 +00:00
|
|
|
m_timeGameStarted.SetZero();
|
2003-01-30 07:18:33 +00:00
|
|
|
m_CurStyle = STYLE_INVALID;
|
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++ )
|
2004-01-21 01:35:54 +00:00
|
|
|
{
|
2003-01-21 22:23:01 +00:00
|
|
|
m_PreferredDifficulty[p] = DIFFICULTY_INVALID;
|
2004-03-13 22:18:09 +00:00
|
|
|
m_PreferredCourseDifficulty[p] = COURSE_DIFFICULTY_REGULAR;
|
2004-01-21 01:35:54 +00:00
|
|
|
}
|
2004-03-12 08:31:40 +00:00
|
|
|
m_SortOrder = 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-10-26 03:02:30 +00:00
|
|
|
m_BeatToNoteSkinRev = 0;
|
2004-01-24 19:09:51 +00:00
|
|
|
m_iNumStagesOfThisSong = 0;
|
2002-07-29 03:06:55 +00:00
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
NOTESKIN->RefreshNoteSkinData( this->m_CurGame );
|
2003-09-12 04:18:43 +00:00
|
|
|
|
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-11-30 23:13:38 +00:00
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
m_bAttackBeganThisUpdate[p] = false;
|
|
|
|
|
|
2003-01-25 11:05:12 +00:00
|
|
|
ResetMusicStatistics();
|
2003-07-03 06:38:57 +00:00
|
|
|
ResetStageStatistics();
|
2004-02-27 21:28:15 +00:00
|
|
|
SONGMAN->UpdateBest();
|
|
|
|
|
SONGMAN->UpdateShuffled();
|
2003-01-25 11:05:12 +00:00
|
|
|
|
2003-12-23 00:26:00 +00:00
|
|
|
g_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
|
|
|
{
|
2004-02-04 07:58:02 +00:00
|
|
|
// I can't think of a good reason to have both game-specific
|
|
|
|
|
// default mods and theme specific default mods. We should choose
|
|
|
|
|
// one or the other. -Chris
|
2004-02-05 21:32:50 +00:00
|
|
|
// Having default modifiers in prefs is needed for several things.
|
|
|
|
|
// The theme setting is for eg. BM being reverse by default. (This
|
|
|
|
|
// could be done in the title menu ModeChoice, but then it wouldn't
|
|
|
|
|
// affect demo, and other non-gameplay things ...) -glenn
|
2003-11-14 20:29:51 +00:00
|
|
|
ApplyModifiers( (PlayerNumber)p, DEFAULT_MODIFIERS );
|
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();
|
2004-01-21 04:59:15 +00:00
|
|
|
ASSERT( m_pCurCharacters[p] );
|
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
|
|
|
|
2003-12-19 04:52:07 +00:00
|
|
|
MEMCARDMAN->LockCards( false );
|
2003-10-19 07:40:11 +00:00
|
|
|
|
2003-11-16 04:45:12 +00:00
|
|
|
LIGHTSMAN->SetLightMode( LIGHTMODE_ATTRACT );
|
2003-12-08 04:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GameState::BeginGame()
|
|
|
|
|
{
|
2004-02-22 23:26:46 +00:00
|
|
|
m_timeGameStarted.Touch();
|
2003-12-28 08:20:48 +00:00
|
|
|
|
|
|
|
|
m_vpsNamesThatWereFilled.clear();
|
2003-12-28 19:46:50 +00:00
|
|
|
|
|
|
|
|
m_iNumTimesThroughAttract = 0;
|
2003-12-08 04:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-05 20:09:59 +00:00
|
|
|
void CheckStageStats( const StageStats &ss, int p )
|
|
|
|
|
{
|
2004-01-17 00:36:49 +00:00
|
|
|
if( ss.pSong )
|
|
|
|
|
CHECKPOINT_M( ss.pSong->GetFullTranslitTitle() );
|
2004-02-16 07:39:29 +00:00
|
|
|
ASSERT( ss.pSteps[p] );
|
2004-02-01 00:00:52 +00:00
|
|
|
RAGE_ASSERT_M( ss.playMode < NUM_PLAY_MODES, ssprintf("playmode %i", ss.playMode) );
|
|
|
|
|
RAGE_ASSERT_M( ss.style < NUM_STYLES, ssprintf("style %i", ss.style) );
|
|
|
|
|
RAGE_ASSERT_M( ss.pSteps[p]->GetDifficulty() < NUM_DIFFICULTIES, ssprintf("difficulty %i", ss.pSteps[p]->GetDifficulty()) );
|
2004-01-17 00:36:49 +00:00
|
|
|
/* Meter values can exceed MAX_METER; MAX_METER is just the highest meter value we
|
|
|
|
|
* display/track. */
|
|
|
|
|
// RAGE_ASSERT_M( ss.iMeter[p] < MAX_METER+1, ssprintf("%i", ss.iMeter[p]) );
|
2004-01-05 20:09:59 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-08 01:05:53 +00:00
|
|
|
void GameState::PlayersFinalized()
|
|
|
|
|
{
|
|
|
|
|
MEMCARDMAN->LockCards( true );
|
|
|
|
|
SONGMAN->LoadAllFromProfiles();
|
2004-03-13 12:27:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// apply saved default modifiers if any
|
|
|
|
|
FOREACH_HumanPlayer( pn )
|
|
|
|
|
{
|
2004-03-13 19:20:24 +00:00
|
|
|
if( !PROFILEMAN->IsUsingProfile(pn) )
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
|
|
|
|
Profile* pProfile = PROFILEMAN->GetProfile(pn);
|
|
|
|
|
|
|
|
|
|
if( pProfile->m_bUsingProfileDefaultModifiers )
|
2004-03-13 12:27:24 +00:00
|
|
|
{
|
2004-03-13 19:20:24 +00:00
|
|
|
GAMESTATE->m_PlayerOptions[pn].Init();
|
|
|
|
|
GAMESTATE->ApplyModifiers( pn, pProfile->m_sDefaultModifiers );
|
2004-03-13 12:27:24 +00:00
|
|
|
}
|
2004-03-13 22:18:09 +00:00
|
|
|
// Only set the sort order if it wasn't already set by a ModeChoice
|
|
|
|
|
if( m_SortOrder == SORT_INVALID )
|
|
|
|
|
m_SortOrder = pProfile->m_SortOrder;
|
2004-03-13 19:20:24 +00:00
|
|
|
if( pProfile->m_PreferredDifficulty != DIFFICULTY_INVALID )
|
|
|
|
|
GAMESTATE->m_PreferredDifficulty[pn] = pProfile->m_PreferredDifficulty;
|
2004-03-13 22:18:09 +00:00
|
|
|
if( pProfile->m_PreferredCourseDifficulty != COURSE_DIFFICULTY_INVALID )
|
|
|
|
|
GAMESTATE->m_PreferredCourseDifficulty[pn] = pProfile->m_PreferredCourseDifficulty;
|
2004-03-13 12:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-08 01:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-22 23:26:46 +00:00
|
|
|
/* This data is added to each player profile, and to the machine profile per-player. */
|
|
|
|
|
void AddPlayerStatsToProfile( Profile *pProfile, const StageStats &ss, PlayerNumber p )
|
|
|
|
|
{
|
|
|
|
|
CheckStageStats( ss, p );
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
const int iMeter = clamp( ss.iMeter[p], 0, MAX_METER );
|
|
|
|
|
|
|
|
|
|
pProfile->m_iNumSongsPlayedByPlayMode[ss.playMode]++;
|
|
|
|
|
pProfile->m_iNumSongsPlayedByStyle[ss.style]++;
|
|
|
|
|
pProfile->m_iNumSongsPlayedByDifficulty[ss.pSteps[p]->GetDifficulty()]++;
|
|
|
|
|
pProfile->m_iNumSongsPlayedByMeter[iMeter]++;
|
|
|
|
|
pProfile->m_iTotalDancePoints += ss.iActualDancePoints[p];
|
|
|
|
|
|
|
|
|
|
if( ss.StageType == StageStats::STAGE_EXTRA || ss.StageType == StageStats::STAGE_EXTRA2 )
|
|
|
|
|
{
|
|
|
|
|
if( ss.bFailed[p] )
|
|
|
|
|
++pProfile->m_iNumExtraStagesFailed;
|
|
|
|
|
else
|
|
|
|
|
++pProfile->m_iNumExtraStagesPassed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !ss.bFailed[p] )
|
|
|
|
|
{
|
|
|
|
|
pProfile->m_iNumSongsPassedByPlayMode[ss.playMode]++;
|
|
|
|
|
pProfile->m_iNumSongsPassedByGrade[ss.GetGrade((PlayerNumber)p)]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 04:02:43 +00:00
|
|
|
void GameState::EndGame()
|
|
|
|
|
{
|
|
|
|
|
// Update profile stats
|
2004-02-22 23:26:46 +00:00
|
|
|
int iPlaySeconds = max( 0, (int) m_timeGameStarted.PeekDeltaTime() );
|
2003-12-08 04:02:43 +00:00
|
|
|
|
2003-12-08 06:41:30 +00:00
|
|
|
Profile* pMachineProfile = PROFILEMAN->GetMachineProfile();
|
|
|
|
|
|
2003-12-09 10:20:18 +00:00
|
|
|
int iGameplaySeconds = 0;
|
2003-12-23 00:26:00 +00:00
|
|
|
for( unsigned i=0; i<g_vPlayedStageStats.size(); i++ )
|
|
|
|
|
iGameplaySeconds += (int) roundf(g_vPlayedStageStats[i].fGameplaySeconds);
|
2003-12-09 10:20:18 +00:00
|
|
|
|
|
|
|
|
pMachineProfile->m_iTotalPlaySeconds += iPlaySeconds;
|
|
|
|
|
pMachineProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
|
|
|
|
|
pMachineProfile->m_iTotalPlays++;
|
|
|
|
|
pMachineProfile->m_iCurrentCombo = 0;
|
|
|
|
|
|
2004-01-05 20:09:59 +00:00
|
|
|
CHECKPOINT;
|
2004-02-08 06:29:12 +00:00
|
|
|
int p;
|
|
|
|
|
for( p=0; p<NUM_PLAYERS; p++ )
|
2003-12-08 04:02:43 +00:00
|
|
|
{
|
2003-12-09 10:20:18 +00:00
|
|
|
if( !IsHumanPlayer(p) )
|
|
|
|
|
continue;
|
2003-12-08 04:02:43 +00:00
|
|
|
|
2004-01-05 20:09:59 +00:00
|
|
|
CHECKPOINT;
|
2003-12-08 04:02:43 +00:00
|
|
|
|
2003-12-08 06:41:30 +00:00
|
|
|
Profile* pPlayerProfile = PROFILEMAN->GetProfile( (PlayerNumber)p );
|
|
|
|
|
if( pPlayerProfile )
|
2003-12-09 10:20:18 +00:00
|
|
|
{
|
2003-12-08 06:41:30 +00:00
|
|
|
pPlayerProfile->m_iTotalPlaySeconds += iPlaySeconds;
|
|
|
|
|
pPlayerProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
|
|
|
|
|
pPlayerProfile->m_iTotalPlays++;
|
|
|
|
|
pPlayerProfile->m_iCurrentCombo =
|
2003-12-09 10:20:18 +00:00
|
|
|
PREFSMAN->m_bComboContinuesBetweenSongs ?
|
2003-12-23 00:26:00 +00:00
|
|
|
g_CurStageStats.iCurCombo[p] :
|
2003-12-09 10:20:18 +00:00
|
|
|
0;
|
2004-02-22 02:16:02 +00:00
|
|
|
}
|
2004-01-05 20:09:59 +00:00
|
|
|
|
2004-02-22 02:16:02 +00:00
|
|
|
for( unsigned i=0; i<g_vPlayedStageStats.size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
const StageStats& ss = g_vPlayedStageStats[i];
|
2004-02-22 23:26:46 +00:00
|
|
|
AddPlayerStatsToProfile( pMachineProfile, ss, (PlayerNumber) p );
|
2004-02-22 02:16:02 +00:00
|
|
|
|
|
|
|
|
if( pPlayerProfile )
|
2004-02-22 23:26:46 +00:00
|
|
|
AddPlayerStatsToProfile( pPlayerProfile, ss, (PlayerNumber) p );
|
2003-12-09 10:20:18 +00:00
|
|
|
}
|
2003-12-19 08:17:44 +00:00
|
|
|
|
2004-01-05 20:09:59 +00:00
|
|
|
CHECKPOINT;
|
2003-12-08 04:02:43 +00:00
|
|
|
}
|
2003-12-07 20:29:42 +00:00
|
|
|
BOOKKEEPER->WriteToDisk();
|
2004-02-16 05:35:06 +00:00
|
|
|
PROFILEMAN->SaveMachineProfile();
|
2004-02-08 01:05:53 +00:00
|
|
|
|
2004-03-13 19:20:24 +00:00
|
|
|
FOREACH_HumanPlayer( pn )
|
2004-02-08 01:05:53 +00:00
|
|
|
{
|
2004-03-13 19:20:24 +00:00
|
|
|
if( !PROFILEMAN->IsUsingProfile(pn) )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
Profile* pProfile = PROFILEMAN->GetProfile(pn);
|
|
|
|
|
|
2004-03-13 22:18:09 +00:00
|
|
|
// persist settings
|
|
|
|
|
pProfile->m_bUsingProfileDefaultModifiers = true;
|
|
|
|
|
pProfile->m_sDefaultModifiers = m_PlayerOptions[pn].GetString();
|
|
|
|
|
if( IsSongSort(m_SortOrder) )
|
|
|
|
|
pProfile->m_SortOrder = m_SortOrder;
|
|
|
|
|
if( m_PreferredDifficulty[pn] != DIFFICULTY_INVALID )
|
|
|
|
|
pProfile->m_PreferredDifficulty = m_PreferredDifficulty[pn];
|
|
|
|
|
if( m_PreferredCourseDifficulty[pn] != COURSE_DIFFICULTY_INVALID )
|
|
|
|
|
pProfile->m_PreferredCourseDifficulty = m_PreferredCourseDifficulty[pn];
|
2004-03-13 19:20:24 +00:00
|
|
|
|
|
|
|
|
PROFILEMAN->SaveProfile( pn );
|
|
|
|
|
PROFILEMAN->UnloadProfile( pn );
|
2004-02-08 01:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
2004-03-13 19:20:24 +00:00
|
|
|
// Reset the USB storage device numbers -after- saving
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
MEMCARDMAN->FlushAllDisks();
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
|
2004-02-08 01:05:53 +00:00
|
|
|
SONGMAN->FreeAllLoadedFromProfiles();
|
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
|
|
|
|
2004-01-12 03:47:55 +00:00
|
|
|
bool bRebuildPlayerOptions = false;
|
2003-11-27 02:30:54 +00:00
|
|
|
m_bAttackEndedThisUpdate[p] = false;
|
2003-04-07 03:25:44 +00:00
|
|
|
|
2004-01-26 20:39:14 +00:00
|
|
|
/* See if any delayed attacks are starting or ending. */
|
|
|
|
|
for( unsigned s=0; s<m_ActiveAttacks[p].size(); s++ )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2004-01-26 20:39:14 +00:00
|
|
|
Attack &attack = m_ActiveAttacks[p][s];
|
|
|
|
|
const bool bCurrentlyEnabled =
|
2004-02-07 06:11:36 +00:00
|
|
|
attack.fStartSecond == -1 ||
|
2004-01-26 20:39:14 +00:00
|
|
|
(attack.fStartSecond < this->m_fMusicSeconds &&
|
2004-02-07 06:11:36 +00:00
|
|
|
m_fMusicSeconds < attack.fStartSecond+attack.fSecsRemaining);
|
2003-10-24 09:35:56 +00:00
|
|
|
|
2004-01-26 20:39:14 +00:00
|
|
|
if( m_ActiveAttacks[p][s].bOn == bCurrentlyEnabled )
|
|
|
|
|
continue; /* OK */
|
2003-10-24 09:35:56 +00:00
|
|
|
|
2004-02-07 06:11:36 +00:00
|
|
|
if( m_ActiveAttacks[p][s].bOn && !bCurrentlyEnabled )
|
2004-01-26 20:39:14 +00:00
|
|
|
m_bAttackEndedThisUpdate[p] = true;
|
2003-10-24 09:35:56 +00:00
|
|
|
|
2004-01-12 03:47:55 +00:00
|
|
|
bRebuildPlayerOptions = true;
|
2004-01-26 20:39:14 +00:00
|
|
|
|
|
|
|
|
m_ActiveAttacks[p][s].bOn = bCurrentlyEnabled;
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-12 03:47:55 +00:00
|
|
|
if( bRebuildPlayerOptions )
|
2003-04-07 03:25:44 +00:00
|
|
|
RebuildPlayerOptionsFromActiveAttacks( (PlayerNumber)p );
|
2004-01-12 03:47:55 +00:00
|
|
|
|
|
|
|
|
if( m_fSecondsUntilAttacksPhasedOut[p] > 0 )
|
|
|
|
|
m_fSecondsUntilAttacksPhasedOut[p] = max( 0, m_fSecondsUntilAttacksPhasedOut[p] - fDelta );
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
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 )
|
2003-12-10 09:44:16 +00:00
|
|
|
RageException::Throw( "'Characters/default' is missing." );
|
2003-11-01 06:30:17 +00:00
|
|
|
|
|
|
|
|
// If FoundDefault, then we're not empty. -Chris
|
|
|
|
|
// if( m_pCharacters.empty() )
|
|
|
|
|
// 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()
|
|
|
|
|
{
|
2004-01-29 20:58:11 +00:00
|
|
|
m_fMusicSeconds = 0; // 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-12-23 00:26:00 +00:00
|
|
|
StageStats OldStats = g_CurStageStats;
|
|
|
|
|
g_CurStageStats = StageStats();
|
2003-12-08 04:39:29 +00:00
|
|
|
if( PREFSMAN->m_bComboContinuesBetweenSongs )
|
|
|
|
|
{
|
|
|
|
|
if( GetStageIndex() == 0 )
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
Profile* pProfile = PROFILEMAN->GetProfile((PlayerNumber)p);
|
|
|
|
|
if( pProfile )
|
2003-12-23 00:26:00 +00:00
|
|
|
g_CurStageStats.iCurCombo[p] = pProfile->m_iCurrentCombo;
|
2003-12-08 04:39:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // GetStageIndex() > 0
|
|
|
|
|
{
|
2003-12-23 00:26:00 +00:00
|
|
|
memcpy( g_CurStageStats.iCurCombo, OldStats.iCurCombo, sizeof(OldStats.iCurCombo) );
|
2003-12-08 04:39:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
2003-09-06 04:18:08 +00:00
|
|
|
|
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++ )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
2003-07-03 06:38:57 +00:00
|
|
|
m_fSuperMeter[p] = 0;
|
2003-12-07 20:29:42 +00:00
|
|
|
m_HealthState[p] = ALIVE;
|
2004-01-12 03:47:55 +00:00
|
|
|
|
|
|
|
|
m_iLastPositiveSumOfAttackLevels[p] = 0;
|
|
|
|
|
m_fSecondsUntilAttacksPhasedOut[p] = 0; // PlayerAI not affected
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2004-03-07 04:34:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
m_vLastPerDifficultyAwards[p].clear();
|
|
|
|
|
m_vLastPeakComboAwards[p].clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-07-29 03:06:55 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-18 04:43:56 +00:00
|
|
|
void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp )
|
2003-02-06 17:40:06 +00:00
|
|
|
{
|
2004-01-18 04:43:56 +00:00
|
|
|
if( !timestamp.IsZero() )
|
|
|
|
|
m_LastBeatUpdate = timestamp;
|
|
|
|
|
else
|
|
|
|
|
m_LastBeatUpdate.Touch();
|
|
|
|
|
timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
|
2004-02-04 06:45:56 +00:00
|
|
|
RAGE_ASSERT_M( m_fSongBeat > -2000, ssprintf("%f %f", m_fSongBeat, fPositionSeconds) );
|
2004-01-12 01:10:25 +00:00
|
|
|
|
2004-01-18 04:43:56 +00:00
|
|
|
m_fMusicSeconds = fPositionSeconds;
|
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
|
|
|
}
|
|
|
|
|
|
2003-10-23 06:16:29 +00:00
|
|
|
float GameState::GetSongPercent( float beat ) const
|
|
|
|
|
{
|
|
|
|
|
/* 0 = first step; 1 = last step */
|
|
|
|
|
return (beat - m_pCurSong->m_fFirstBeat) / m_pCurSong->m_fLastBeat;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 03:11:40 +00:00
|
|
|
/* Called by ScreenGameplay. Set the length of the current song. */
|
|
|
|
|
void GameState::BeginStage()
|
2004-01-22 02:16:50 +00:00
|
|
|
{
|
2004-01-22 03:11:40 +00:00
|
|
|
if( m_pCurSong )
|
2004-02-07 22:14:36 +00:00
|
|
|
m_iNumStagesOfThisSong = SongManager::GetNumStagesForSong( this->m_pCurSong );
|
2004-01-22 03:11:40 +00:00
|
|
|
else if( m_pCurCourse )
|
|
|
|
|
m_iNumStagesOfThisSong = 1;
|
|
|
|
|
else
|
|
|
|
|
FAIL_M("fail"); /* what are we playing? */
|
2004-01-22 02:16:50 +00:00
|
|
|
|
2004-01-24 19:09:51 +00:00
|
|
|
ASSERT( m_iNumStagesOfThisSong >= 1 && m_iNumStagesOfThisSong <= 3 );
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->IsExtraStage() || this->IsExtraStage2() )
|
2004-01-22 02:16:50 +00:00
|
|
|
{
|
|
|
|
|
/* If it's an extra stage, always increment by one. This is because in some
|
|
|
|
|
* unusual cases we can pick a long or marathon song as an extra stage. The
|
|
|
|
|
* most common cause of this is when an entire group of songs is long/nonstop mixes.
|
|
|
|
|
*
|
|
|
|
|
* We can't simply not choose long songs as extra stages: if there are no
|
|
|
|
|
* regular songs to choose, we'll end up with no song to use as an extra stage. */
|
2004-01-22 03:11:40 +00:00
|
|
|
m_iNumStagesOfThisSong = 1;
|
2004-01-22 02:16:50 +00:00
|
|
|
}
|
2004-01-22 03:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-23 02:04:34 +00:00
|
|
|
void GameState::CancelStage()
|
|
|
|
|
{
|
|
|
|
|
m_iNumStagesOfThisSong = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 03:11:40 +00:00
|
|
|
/* Called by ScreenSelectMusic (etc). Increment the stage counter if we just played a
|
|
|
|
|
* song. Might be called more than once. */
|
|
|
|
|
void GameState::FinishStage()
|
|
|
|
|
{
|
|
|
|
|
/* If m_iNumStagesOfThisSong is 0, we've been called more than once before calling
|
|
|
|
|
* BeginStage. This can happen when backing out of the player options screen. */
|
|
|
|
|
if( !m_iNumStagesOfThisSong )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Increment the stage counter.
|
2004-01-24 19:09:51 +00:00
|
|
|
ASSERT( m_iNumStagesOfThisSong >= 1 && m_iNumStagesOfThisSong <= 3 );
|
2004-01-22 03:11:40 +00:00
|
|
|
m_iCurrentStageIndex += m_iNumStagesOfThisSong;
|
2004-01-22 02:16:50 +00:00
|
|
|
|
2004-01-22 03:11:40 +00:00
|
|
|
m_iNumStagesOfThisSong = 0;
|
2004-01-22 02:16:50 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
int GameState::GetStageIndex() const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
|
|
|
|
return m_iCurrentStageIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
int GameState::GetNumStagesLeft() const
|
2003-02-10 05:30:12 +00:00
|
|
|
{
|
2004-01-22 02:15:55 +00:00
|
|
|
if( IsExtraStage() || IsExtraStage2() )
|
2003-02-12 20:56:19 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsFinalStage() const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
2003-04-19 19:05:25 +00:00
|
|
|
if( PREFSMAN->m_bEventMode )
|
2002-07-23 01:41:40 +00:00
|
|
|
return false;
|
2004-01-22 03:11:40 +00:00
|
|
|
|
|
|
|
|
/* This changes dynamically on ScreenSelectMusic as the wheel turns. */
|
2003-02-10 05:30:12 +00:00
|
|
|
int iPredictedStageForCurSong = 1;
|
|
|
|
|
if( m_pCurSong != NULL )
|
|
|
|
|
iPredictedStageForCurSong = SongManager::GetNumStagesForSong( m_pCurSong );
|
2004-01-22 23:36:26 +00:00
|
|
|
return m_iCurrentStageIndex + iPredictedStageForCurSong == PREFSMAN->m_iNumArcadeStages;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsExtraStage() const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsExtraStage2() const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
CString GameState::GetStageText() const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
void GameState::GetAllStageTexts( CStringArray &out ) const
|
2003-10-09 04:20:24 +00:00
|
|
|
{
|
|
|
|
|
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" );
|
2003-10-24 04:56:17 +00:00
|
|
|
for( int stage = 0; stage < PREFSMAN->m_iNumArcadeStages; ++stage )
|
|
|
|
|
out.push_back( ssprintf("%d",stage+1) );
|
2003-10-09 04:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
int GameState::GetCourseSongIndex() const
|
2003-02-14 21:42:44 +00:00
|
|
|
{
|
|
|
|
|
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-12-23 00:26:00 +00:00
|
|
|
iSongIndex = max( iSongIndex, g_CurStageStats.iSongsPlayed[p]-1 );
|
2003-02-14 21:42:44 +00:00
|
|
|
return iSongIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-10 16:48:22 +00:00
|
|
|
bool GameState::PlayersCanJoin() const
|
|
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
return GetNumSidesJoined() == 0 || this->m_CurStyle == STYLE_INVALID;
|
2003-11-10 16:48:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GameState::GetNumSidesJoined() const
|
|
|
|
|
{
|
|
|
|
|
int iNumSidesJoined = 0;
|
|
|
|
|
for( int c=0; c<NUM_PLAYERS; c++ )
|
|
|
|
|
if( m_bSideIsJoined[c] )
|
|
|
|
|
iNumSidesJoined++; // left side, and right side
|
|
|
|
|
return iNumSidesJoined;
|
|
|
|
|
}
|
|
|
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
const StyleDef* GameState::GetCurrentStyleDef() const
|
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-02 01:43:33 +00:00
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsPlayerEnabled( PlayerNumber pn ) const
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
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
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
int GameState::GetNumPlayersEnabled() const
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
if( IsPlayerEnabled(p) )
|
|
|
|
|
count++;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-20 17:53:04 +00:00
|
|
|
bool GameState::PlayerUsingBothSides() const
|
|
|
|
|
{
|
|
|
|
|
return this->GetCurrentStyleDef()->m_StyleType==StyleDef::ONE_PLAYER_TWO_CREDITS;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsHumanPlayer( PlayerNumber pn ) const
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-03-16 22:35:04 +00:00
|
|
|
if( m_CurStyle == STYLE_INVALID ) // no style chosen
|
2003-11-10 16:48:22 +00:00
|
|
|
if( this->PlayersCanJoin() )
|
2003-03-16 22:35:04 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2004-03-20 17:45:34 +00:00
|
|
|
int GameState::GetNumHumanPlayers() const
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
if( IsHumanPlayer(p) )
|
|
|
|
|
count++;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
PlayerNumber GameState::GetFirstHumanPlayer() const
|
2003-04-07 21:24:14 +00:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::IsCpuPlayer( PlayerNumber pn ) const
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
|
|
|
|
return IsPlayerEnabled(pn) && !IsHumanPlayer(pn);
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
bool GameState::AnyPlayersAreCpu() const
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
if( IsCpuPlayer(p) )
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-07 03:25:44 +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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-09 20:23:44 +00:00
|
|
|
bool GameState::IsBattleMode() const
|
|
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
switch( this->m_PlayMode )
|
2003-07-09 20:23:44 +00:00
|
|
|
{
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
bool GameState::HasEarnedExtraStage() const
|
2003-01-24 02:43:07 +00:00
|
|
|
{
|
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;
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->m_PlayMode != PLAY_MODE_ARCADE )
|
2003-02-05 18:24:36 +00:00
|
|
|
return false;
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
if( (this->IsFinalStage() || this->IsExtraStage()) )
|
2003-01-24 02:43:07 +00:00
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
if( !this->IsPlayerEnabled(p) )
|
2003-01-24 02:43:07 +00:00
|
|
|
continue; // skip
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_HARD &&
|
|
|
|
|
this->m_pCurNotes[p]->GetDifficulty() != DIFFICULTY_CHALLENGE )
|
2003-02-04 21:44:58 +00:00
|
|
|
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). */
|
2004-02-07 22:14:36 +00:00
|
|
|
if( PREFSMAN->m_bPickExtraStage && this->IsExtraStage() && !this->m_bAllow2ndExtraStage )
|
2003-02-05 09:01:09 +00:00
|
|
|
continue;
|
|
|
|
|
|
2004-02-09 20:01:54 +00:00
|
|
|
if( g_CurStageStats.GetGrade((PlayerNumber)p) <= GRADE_TIER_3 )
|
2003-01-24 02:43:07 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2003-01-27 02:00:38 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
PlayerNumber GameState::GetBestPlayer() const
|
2003-04-15 02:47:24 +00:00
|
|
|
{
|
2003-12-02 21:32:04 +00:00
|
|
|
for( int p=PLAYER_1; p<NUM_PLAYERS; p++ )
|
|
|
|
|
if( GetStageResult( (PlayerNumber)p ) == RESULT_WIN )
|
|
|
|
|
return (PlayerNumber)p;
|
|
|
|
|
return PLAYER_INVALID; // draw
|
2003-04-15 02:47:24 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
StageResult GameState::GetStageResult( PlayerNumber pn ) const
|
2003-04-21 02:41:10 +00:00
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
switch( this->m_PlayMode )
|
2003-05-13 13:35:32 +00:00
|
|
|
{
|
2003-08-19 04:27:50 +00:00
|
|
|
case PLAY_MODE_BATTLE:
|
2003-07-03 06:38:57 +00:00
|
|
|
case PLAY_MODE_RAVE:
|
2003-12-02 21:32:04 +00:00
|
|
|
if( fabsf(m_fTugLifePercentP1 - 0.5f) < 0.0001f )
|
|
|
|
|
return RESULT_DRAW;
|
2003-07-03 06:38:57 +00:00
|
|
|
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
|
|
|
}
|
2003-12-02 21:32:04 +00:00
|
|
|
|
|
|
|
|
StageResult win = RESULT_WIN;
|
|
|
|
|
for( int p=PLAYER_1; p<NUM_PLAYERS; p++ )
|
|
|
|
|
{
|
|
|
|
|
if( p == pn )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* If anyone did just as well, at best it's a draw. */
|
2003-12-23 00:26:00 +00:00
|
|
|
if( g_CurStageStats.iActualDancePoints[p] == g_CurStageStats.iActualDancePoints[pn] )
|
2003-12-02 21:32:04 +00:00
|
|
|
win = RESULT_DRAW;
|
|
|
|
|
|
|
|
|
|
/* If anyone did better, we lost. */
|
2003-12-23 00:26:00 +00:00
|
|
|
if( g_CurStageStats.iActualDancePoints[p] > g_CurStageStats.iActualDancePoints[pn] )
|
2003-12-02 21:32:04 +00:00
|
|
|
return RESULT_LOSE;
|
|
|
|
|
}
|
|
|
|
|
return win;
|
2003-04-21 02:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-22 03:11:40 +00:00
|
|
|
void GameState::GetFinalEvalStatsAndSongs( StageStats& statsOut, vector<Song*>& vSongsOut ) const
|
2003-01-27 02:00:38 +00:00
|
|
|
{
|
|
|
|
|
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-12-23 00:26:00 +00:00
|
|
|
for( int i = (int)g_vPlayedStageStats.size()-1; i >= 0; --i )
|
2003-01-27 02:00:38 +00:00
|
|
|
{
|
2003-12-23 00:26:00 +00:00
|
|
|
const StageStats &s = g_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 */
|
2004-03-11 06:46:52 +00:00
|
|
|
FOREACH_EnabledPlayer( p )
|
2003-02-18 07:22:09 +00:00
|
|
|
{
|
|
|
|
|
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
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
const SongOptions::FailType ft = this->m_SongOptions.m_FailType;
|
2003-09-27 06:38:16 +00:00
|
|
|
|
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
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
if( ft != this->m_SongOptions.m_FailType )
|
|
|
|
|
this->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()
|
|
|
|
|
{
|
2004-03-11 06:46:52 +00:00
|
|
|
FOREACH_PlayerNumber( p )
|
2004-02-07 22:14:36 +00:00
|
|
|
this->m_StoredPlayerOptions[p] = this->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++ )
|
2004-02-07 22:14:36 +00:00
|
|
|
this->m_PlayerOptions[p] = this->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
|
|
|
|
2004-03-09 08:19:55 +00:00
|
|
|
bool GameState::IsDisqualified( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
if( GAMESTATE->IsCourseMode() )
|
|
|
|
|
return GAMESTATE->m_PlayerOptions[pn].IsHandicapForCourse( GAMESTATE->m_pCurCourse );
|
|
|
|
|
else
|
|
|
|
|
return GAMESTATE->m_PlayerOptions[pn].IsHandicapForSong( GAMESTATE->m_pCurSong );
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
void GameState::ResetNoteSkins()
|
|
|
|
|
{
|
|
|
|
|
for( int pn = 0; pn < NUM_PLAYERS; ++pn )
|
2003-10-26 03:02:30 +00:00
|
|
|
ResetNoteSkinsForPlayer( (PlayerNumber) pn );
|
2003-09-12 06:23:51 +00:00
|
|
|
|
2003-10-26 03:02:30 +00:00
|
|
|
++m_BeatToNoteSkinRev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GameState::ResetNoteSkinsForPlayer( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
m_BeatToNoteSkin[pn].clear();
|
2004-02-07 22:14:36 +00:00
|
|
|
m_BeatToNoteSkin[pn][-1000] = this->m_PlayerOptions[pn].m_sNoteSkin;
|
2003-10-26 03:02:30 +00:00
|
|
|
|
|
|
|
|
++m_BeatToNoteSkinRev;
|
2003-09-12 06:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
void GameState::GetAllUsedNoteSkins( vector<CString> &out ) const
|
|
|
|
|
{
|
|
|
|
|
for( int pn=0; pn<NUM_PLAYERS; ++pn )
|
|
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
out.push_back( this->m_PlayerOptions[pn].m_sNoteSkin );
|
2003-10-24 09:35:56 +00:00
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
switch( this->m_PlayMode )
|
2003-10-24 09:35:56 +00:00
|
|
|
{
|
|
|
|
|
case PLAY_MODE_BATTLE:
|
|
|
|
|
case PLAY_MODE_RAVE:
|
|
|
|
|
for( int al=0; al<NUM_ATTACK_LEVELS; al++ )
|
|
|
|
|
{
|
2004-02-07 22:14:36 +00:00
|
|
|
const Character *ch = this->m_pCurCharacters[pn];
|
2003-10-24 09:35:56 +00:00
|
|
|
ASSERT( ch );
|
|
|
|
|
const CString* asAttacks = ch->m_sAttacks[al];
|
|
|
|
|
for( int att = 0; att < NUM_ATTACKS_PER_LEVEL; ++att )
|
|
|
|
|
{
|
|
|
|
|
PlayerOptions po;
|
|
|
|
|
po.FromString( asAttacks[att] );
|
|
|
|
|
if( po.m_sNoteSkin != "" )
|
|
|
|
|
out.push_back( po.m_sNoteSkin );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( map<float,CString>::const_iterator it = m_BeatToNoteSkin[pn].begin();
|
|
|
|
|
it != m_BeatToNoteSkin[pn].end(); ++it )
|
|
|
|
|
out.push_back( it->second );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-12 06:23:51 +00:00
|
|
|
/* From NoteField: */
|
2003-09-23 23:56:15 +00:00
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
void GameState::GetUndisplayedBeats( PlayerNumber pn, float TotalSeconds, float &StartBeat, float &EndBeat ) const
|
2003-09-23 23:56:15 +00:00
|
|
|
{
|
|
|
|
|
/* 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-09-12 06:23:51 +00:00
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
void GameState::SetNoteSkinForBeatRange( PlayerNumber pn, CString sNoteSkin, float StartBeat, float EndBeat )
|
|
|
|
|
{
|
|
|
|
|
map<float,CString> &BeatToNoteSkin = m_BeatToNoteSkin[pn];
|
2003-09-12 06:23:51 +00:00
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
/* Erase any other note skin settings in this range. */
|
|
|
|
|
map<float,CString>::iterator it = BeatToNoteSkin.lower_bound( StartBeat );
|
|
|
|
|
map<float,CString>::iterator end = BeatToNoteSkin.upper_bound( EndBeat );
|
|
|
|
|
while( it != end )
|
|
|
|
|
{
|
|
|
|
|
map<float,CString>::iterator next = it;
|
|
|
|
|
++next;
|
2003-09-12 06:23:51 +00:00
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
BeatToNoteSkin.erase( it );
|
|
|
|
|
|
|
|
|
|
it = next;
|
2003-09-12 06:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
/* Add the skin to m_BeatToNoteSkin. */
|
|
|
|
|
BeatToNoteSkin[StartBeat] = sNoteSkin;
|
|
|
|
|
|
|
|
|
|
/* Return to the default note skin after the duration. */
|
|
|
|
|
BeatToNoteSkin[EndBeat] = m_StoredPlayerOptions[pn].m_sNoteSkin;
|
|
|
|
|
|
|
|
|
|
++m_BeatToNoteSkinRev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is called to launch an attack, or to queue an attack if a.fStartSecond
|
|
|
|
|
* is set. This is also called by GameState::Update when activating a queued attack. */
|
|
|
|
|
void GameState::LaunchAttack( PlayerNumber target, Attack a )
|
|
|
|
|
{
|
|
|
|
|
LOG->Trace( "Launch attack '%s' against P%d at %f", a.sModifier.c_str(), target+1, a.fStartSecond );
|
|
|
|
|
|
2003-11-27 02:30:54 +00:00
|
|
|
m_bAttackBeganThisUpdate[target] = true;
|
|
|
|
|
|
2004-01-30 00:58:33 +00:00
|
|
|
/* If fStartSecond is -1, it means "launch as soon as possible". For m_ActiveAttacks,
|
|
|
|
|
* mark the real time it's starting (now), so Update() can know when the attack started
|
|
|
|
|
* so it can be removed later. For m_ModsToApply, leave the -1 in, so Player::Update
|
|
|
|
|
* knows to apply attack transforms correctly. (yuck) */
|
2003-12-01 21:04:40 +00:00
|
|
|
m_ModsToApply[target].push_back( a );
|
2004-01-30 00:58:33 +00:00
|
|
|
if( a.fStartSecond == -1 )
|
2004-02-07 22:14:36 +00:00
|
|
|
a.fStartSecond = this->m_fMusicSeconds;
|
2004-01-30 00:58:33 +00:00
|
|
|
m_ActiveAttacks[target].push_back( a );
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
this->RebuildPlayerOptionsFromActiveAttacks( target );
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-24 09:35:56 +00:00
|
|
|
void GameState::RemoveActiveAttacksForPlayer( PlayerNumber pn, AttackLevel al )
|
2003-04-07 03:25:44 +00:00
|
|
|
{
|
2003-12-01 21:04:40 +00:00
|
|
|
for( unsigned s=0; s<m_ActiveAttacks[pn].size(); s++ )
|
2003-07-08 19:56:56 +00:00
|
|
|
{
|
2003-10-24 09:35:56 +00:00
|
|
|
if( al != NUM_ATTACK_LEVELS && al != m_ActiveAttacks[pn][s].level )
|
|
|
|
|
continue;
|
2003-12-01 21:04:40 +00:00
|
|
|
m_ActiveAttacks[pn].erase( m_ActiveAttacks[pn].begin()+s, m_ActiveAttacks[pn].begin()+s+1 );
|
|
|
|
|
--s;
|
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-12-01 21:04:40 +00:00
|
|
|
for( unsigned s=0; s<m_ActiveAttacks[pn].size(); s++ )
|
2003-10-24 09:35:56 +00:00
|
|
|
{
|
2004-01-26 20:39:14 +00:00
|
|
|
if( !m_ActiveAttacks[pn][s].bOn )
|
2003-10-24 09:35:56 +00:00
|
|
|
continue; /* hasn't started yet */
|
2003-04-07 05:14:27 +00:00
|
|
|
po.FromString( m_ActiveAttacks[pn][s].sModifier );
|
2003-10-24 09:35:56 +00:00
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
m_PlayerOptions[pn] = po;
|
2004-01-12 03:47:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
int iSumOfAttackLevels = GetSumOfActiveAttackLevels( pn );
|
|
|
|
|
if( iSumOfAttackLevels > 0 )
|
|
|
|
|
{
|
|
|
|
|
m_iLastPositiveSumOfAttackLevels[pn] = iSumOfAttackLevels;
|
|
|
|
|
m_fSecondsUntilAttacksPhasedOut[pn] = 10000; // any positive number that won't run out before the attacks
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// don't change! m_iLastPositiveSumOfAttackLevels[p] = iSumOfAttackLevels;
|
|
|
|
|
m_fSecondsUntilAttacksPhasedOut[pn] = 2; // 2 seconds to phase out
|
|
|
|
|
}
|
2003-04-07 03:25:44 +00:00
|
|
|
}
|
2003-04-07 22:07:44 +00:00
|
|
|
|
2004-01-22 02:15:55 +00:00
|
|
|
void GameState::RemoveAllActiveAttacks() // called on end of song
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
|
|
|
|
RemoveActiveAttacksForPlayer( (PlayerNumber)p );
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
int GameState::GetSumOfActiveAttackLevels( PlayerNumber pn ) const
|
2003-04-07 22:07:44 +00:00
|
|
|
{
|
|
|
|
|
int iSum = 0;
|
|
|
|
|
|
2003-12-01 21:04:40 +00:00
|
|
|
for( unsigned s=0; s<m_ActiveAttacks[pn].size(); s++ )
|
2003-10-24 09:35:56 +00:00
|
|
|
if( m_ActiveAttacks[pn][s].fSecsRemaining > 0 && m_ActiveAttacks[pn][s].level != NUM_ATTACK_LEVELS )
|
2003-04-07 22:07:44 +00:00
|
|
|
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. */
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->m_bChangedFailType )
|
2003-07-24 03:54:34 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find the easiest difficulty notes selected by either player. */
|
|
|
|
|
Difficulty dc = DIFFICULTY_INVALID;
|
2004-03-11 06:46:52 +00:00
|
|
|
FOREACH_HumanPlayer( p )
|
2004-02-07 22:14:36 +00:00
|
|
|
dc = min(dc, this->m_pCurNotes[p]->GetDifficulty());
|
2003-07-24 03:54:34 +00:00
|
|
|
|
|
|
|
|
/* Reset the fail type to the default. */
|
|
|
|
|
SongOptions so;
|
|
|
|
|
so.FromString( PREFSMAN->m_sDefaultModifiers );
|
2004-02-07 22:14:36 +00:00
|
|
|
this->m_SongOptions.m_FailType = so.m_FailType;
|
2003-07-24 03:54:34 +00:00
|
|
|
|
|
|
|
|
/* Easy and beginner are never harder than FAIL_END_OF_SONG. */
|
|
|
|
|
if(dc <= DIFFICULTY_EASY)
|
2004-02-07 22:14:36 +00:00
|
|
|
setmax(this->m_SongOptions.m_FailType, SongOptions::FAIL_END_OF_SONG);
|
2003-07-24 03:54:34 +00:00
|
|
|
|
|
|
|
|
/* 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 */
|
2004-02-07 22:14:36 +00:00
|
|
|
this->m_iCurrentStageIndex == 0)
|
|
|
|
|
setmax(this->m_SongOptions.m_FailType, SongOptions::FAIL_OFF);
|
2003-07-24 03:54:34 +00:00
|
|
|
}
|
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-19 21:38:11 +00:00
|
|
|
struct SongAndSteps
|
|
|
|
|
{
|
|
|
|
|
Song* pSong;
|
|
|
|
|
Steps* pSteps;
|
2003-10-21 06:12:06 +00:00
|
|
|
bool operator==( const SongAndSteps& other ) const { return pSong==other.pSong && pSteps==other.pSteps; }
|
|
|
|
|
bool operator<( const SongAndSteps& other ) const { return pSong<=other.pSong && pSteps<=other.pSteps; }
|
2003-10-19 21:38:11 +00:00
|
|
|
};
|
|
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeat> &asFeatsOut ) const
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2003-10-15 01:09:29 +00:00
|
|
|
if( !IsHumanPlayer(pn) )
|
|
|
|
|
return;
|
|
|
|
|
|
2004-02-09 20:46:39 +00:00
|
|
|
Profile *pProf = PROFILEMAN->GetProfile(pn);
|
|
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
CHECKPOINT_M(ssprintf("PlayMode %i",this->m_PlayMode));
|
|
|
|
|
switch( this->m_PlayMode )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
|
|
|
|
case PLAY_MODE_ARCADE:
|
|
|
|
|
{
|
2003-12-02 19:13:30 +00:00
|
|
|
CHECKPOINT;
|
2003-10-19 21:38:11 +00:00
|
|
|
unsigned i, j;
|
2003-10-14 17:06:30 +00:00
|
|
|
|
2004-02-07 22:14:36 +00:00
|
|
|
StepsType nt = this->GetCurrentStyleDef()->m_StepsType;
|
2003-10-19 21:38:11 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Find unique Song and Steps combinations that were played.
|
|
|
|
|
// We must keep only the unique combination or else we'll double-count
|
|
|
|
|
// high score markers.
|
|
|
|
|
//
|
|
|
|
|
vector<SongAndSteps> vSongAndSteps;
|
|
|
|
|
|
2003-12-23 00:26:00 +00:00
|
|
|
for( i=0; i<g_vPlayedStageStats.size(); i++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2004-01-14 22:15:57 +00:00
|
|
|
CHECKPOINT_M( ssprintf("%u/%i", i, (int)g_vPlayedStageStats.size() ) );
|
2003-10-19 21:38:11 +00:00
|
|
|
SongAndSteps sas;
|
2003-12-23 00:26:00 +00:00
|
|
|
sas.pSong = g_vPlayedStageStats[i].pSong;
|
2003-10-19 21:38:11 +00:00
|
|
|
ASSERT( sas.pSong );
|
2003-12-23 00:26:00 +00:00
|
|
|
sas.pSteps = g_vPlayedStageStats[i].pSteps[pn];
|
2003-10-19 21:38:11 +00:00
|
|
|
ASSERT( sas.pSteps );
|
|
|
|
|
vSongAndSteps.push_back( sas );
|
|
|
|
|
}
|
2003-12-30 05:53:22 +00:00
|
|
|
CHECKPOINT;
|
2003-10-19 21:38:11 +00:00
|
|
|
|
|
|
|
|
sort( vSongAndSteps.begin(), vSongAndSteps.end() );
|
|
|
|
|
|
|
|
|
|
vector<SongAndSteps>::iterator toDelete = unique( vSongAndSteps.begin(), vSongAndSteps.end() );
|
|
|
|
|
vSongAndSteps.erase(toDelete, vSongAndSteps.end());
|
|
|
|
|
|
2003-12-02 19:13:30 +00:00
|
|
|
CHECKPOINT;
|
2003-10-21 06:12:06 +00:00
|
|
|
for( i=0; i<vSongAndSteps.size(); i++ )
|
2003-10-19 21:38:11 +00:00
|
|
|
{
|
|
|
|
|
Song* pSong = vSongAndSteps[i].pSong;
|
|
|
|
|
Steps* pSteps = vSongAndSteps[i].pSteps;
|
|
|
|
|
|
|
|
|
|
// Find Machine Records
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps);
|
|
|
|
|
for( j=0; j<hsl.vHighScores.size(); j++ )
|
|
|
|
|
{
|
|
|
|
|
HighScore &hs = hsl.vHighScores[j];
|
2003-10-14 23:29:34 +00:00
|
|
|
|
2004-02-09 06:26:13 +00:00
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
2003-10-15 20:26:53 +00:00
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.Type = RankingFeat::SONG;
|
|
|
|
|
feat.pSong = pSong;
|
|
|
|
|
feat.pSteps = pSteps;
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.Feat = ssprintf("MR #%d in %s %s", j+1, pSong->GetTranslitMainTitle().c_str(), DifficultyToString(pSteps->GetDifficulty()).c_str() );
|
|
|
|
|
feat.pStringToFill = &hs.sName;
|
|
|
|
|
feat.grade = hs.grade;
|
|
|
|
|
feat.fPercentDP = hs.fPercentDP;
|
|
|
|
|
feat.iScore = hs.iScore;
|
2003-10-15 01:09:29 +00:00
|
|
|
|
2004-02-09 06:26:13 +00:00
|
|
|
if( pSong->HasBanner() )
|
|
|
|
|
feat.Banner = pSong->GetBannerPath();
|
|
|
|
|
|
|
|
|
|
asFeatsOut.push_back( feat );
|
|
|
|
|
}
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
2003-10-19 21:38:11 +00:00
|
|
|
|
|
|
|
|
// Find Personal Records
|
2004-02-09 20:46:39 +00:00
|
|
|
if( pProf )
|
2003-10-19 21:38:11 +00:00
|
|
|
{
|
2004-02-09 20:46:39 +00:00
|
|
|
HighScoreList &hsl = pProf->GetStepsHighScoreList(pSteps);
|
2004-02-09 06:26:13 +00:00
|
|
|
for( j=0; j<hsl.vHighScores.size(); j++ )
|
|
|
|
|
{
|
|
|
|
|
HighScore &hs = hsl.vHighScores[j];
|
2003-10-19 21:38:11 +00:00
|
|
|
|
2004-02-09 06:26:13 +00:00
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
2003-10-19 21:38:11 +00:00
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.pSong = pSong;
|
|
|
|
|
feat.pSteps = pSteps;
|
|
|
|
|
feat.Type = RankingFeat::SONG;
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.Feat = ssprintf("PR #%d in %s %s", j+1, pSong->GetTranslitMainTitle().c_str(), DifficultyToString(pSteps->GetDifficulty()).c_str() );
|
|
|
|
|
feat.pStringToFill = &hs.sName;
|
|
|
|
|
feat.grade = hs.grade;
|
|
|
|
|
feat.fPercentDP = hs.fPercentDP;
|
|
|
|
|
feat.iScore = hs.iScore;
|
|
|
|
|
|
|
|
|
|
// XXX: temporary hack
|
|
|
|
|
if( pSong->HasBackground() )
|
|
|
|
|
feat.Banner = pSong->GetBackgroundPath();
|
|
|
|
|
// if( pSong->HasBanner() )
|
|
|
|
|
// feat.Banner = pSong->GetBannerPath();
|
|
|
|
|
|
|
|
|
|
asFeatsOut.push_back( feat );
|
|
|
|
|
}
|
2003-10-19 21:38:11 +00:00
|
|
|
}
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-02 19:13:30 +00:00
|
|
|
CHECKPOINT;
|
2003-10-14 17:06:30 +00:00
|
|
|
StageStats stats;
|
|
|
|
|
vector<Song*> vSongs;
|
|
|
|
|
GetFinalEvalStatsAndSongs( stats, vSongs );
|
|
|
|
|
|
|
|
|
|
|
2004-02-09 06:26:13 +00:00
|
|
|
// Find Machine Category Records
|
2003-12-07 20:29:42 +00:00
|
|
|
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
RankingCategory rc = (RankingCategory)i;
|
|
|
|
|
HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetCategoryHighScoreList( nt, rc );
|
|
|
|
|
for( unsigned j=0; j<hsl.vHighScores.size(); j++ )
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
HighScore &hs = hsl.vHighScores[j];
|
|
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
2003-12-07 20:29:42 +00:00
|
|
|
continue;
|
|
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.Type = RankingFeat::CATEGORY;
|
2003-12-07 20:29:42 +00:00
|
|
|
feat.Feat = ssprintf("MR #%d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.pStringToFill = &hs.sName;
|
2003-12-10 11:35:34 +00:00
|
|
|
feat.grade = GRADE_NO_DATA;
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.iScore = (int) hs.iScore;
|
|
|
|
|
feat.fPercentDP = (float) hs.fPercentDP;
|
2003-12-07 20:29:42 +00:00
|
|
|
asFeatsOut.push_back( feat );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-09 06:26:13 +00:00
|
|
|
// Find Personal Category Records
|
2003-12-07 20:29:42 +00:00
|
|
|
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
|
|
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
RankingCategory rc = (RankingCategory)i;
|
2004-02-09 20:46:39 +00:00
|
|
|
if( pProf )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
2004-02-09 20:46:39 +00:00
|
|
|
HighScoreList &hsl = pProf->GetCategoryHighScoreList( nt, rc );
|
|
|
|
|
for( unsigned j=0; j<hsl.vHighScores.size(); j++ )
|
|
|
|
|
{
|
|
|
|
|
HighScore &hs = hsl.vHighScores[j];
|
|
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
|
|
|
|
continue;
|
2003-12-07 20:29:42 +00:00
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.Type = RankingFeat::CATEGORY;
|
2004-02-09 20:46:39 +00:00
|
|
|
feat.Feat = ssprintf("PR #%d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
|
|
|
|
|
feat.pStringToFill = &hs.sName;
|
|
|
|
|
feat.grade = GRADE_NO_DATA;
|
|
|
|
|
feat.iScore = (int) hs.iScore;
|
|
|
|
|
feat.fPercentDP = (float) hs.fPercentDP;
|
|
|
|
|
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:
|
|
|
|
|
{
|
2003-12-02 19:13:30 +00:00
|
|
|
CHECKPOINT;
|
2004-02-07 22:14:36 +00:00
|
|
|
StepsType nt = this->GetCurrentStyleDef()->m_StepsType;
|
|
|
|
|
Course* pCourse = this->m_pCurCourse;
|
2003-12-02 19:13:30 +00:00
|
|
|
ASSERT( pCourse );
|
2004-03-13 22:18:09 +00:00
|
|
|
CourseDifficulty cd = this->m_PreferredCourseDifficulty[pn];
|
2003-12-21 04:19:51 +00:00
|
|
|
|
|
|
|
|
// Find Machine Records
|
2003-10-14 17:06:30 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
Profile* pProfile = PROFILEMAN->GetMachineProfile();
|
2004-02-22 06:04:01 +00:00
|
|
|
HighScoreList &hsl = pProfile->GetCourseHighScoreList( pCourse, nt, cd );
|
2004-02-09 06:26:13 +00:00
|
|
|
for( unsigned i=0; i<hsl.vHighScores.size(); i++ )
|
2003-12-21 04:19:51 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
HighScore &hs = hsl.vHighScores[i];
|
|
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
2003-12-21 04:19:51 +00:00
|
|
|
continue;
|
|
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.Type = RankingFeat::COURSE;
|
|
|
|
|
feat.pCourse = pCourse;
|
2003-12-21 04:19:51 +00:00
|
|
|
feat.Feat = ssprintf("MR #%d in %s", i+1, pCourse->m_sName.c_str() );
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.pStringToFill = &hs.sName;
|
2003-12-21 04:19:51 +00:00
|
|
|
feat.grade = GRADE_NO_DATA;
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.iScore = hs.iScore;
|
|
|
|
|
feat.fPercentDP = hs.fPercentDP;
|
2003-12-21 04:19:51 +00:00
|
|
|
if( pCourse->HasBanner() )
|
|
|
|
|
feat.Banner = pCourse->m_sBannerPath;
|
|
|
|
|
asFeatsOut.push_back( feat );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find Personal Records
|
2004-02-09 06:26:13 +00:00
|
|
|
if( PROFILEMAN->IsUsingProfile( pn ) )
|
2003-12-21 04:19:51 +00:00
|
|
|
{
|
2004-02-22 06:04:01 +00:00
|
|
|
HighScoreList &hsl = pProf->GetCourseHighScoreList( pCourse, nt, cd );
|
2004-02-09 06:26:13 +00:00
|
|
|
for( unsigned i=0; i<hsl.vHighScores.size(); i++ )
|
2003-12-21 04:19:51 +00:00
|
|
|
{
|
2004-02-09 06:26:13 +00:00
|
|
|
HighScore& hs = hsl.vHighScores[i];
|
|
|
|
|
if( hs.sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
2003-12-21 04:19:51 +00:00
|
|
|
continue;
|
2003-10-14 23:29:34 +00:00
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
RankingFeat feat;
|
|
|
|
|
feat.Type = RankingFeat::COURSE;
|
|
|
|
|
feat.pCourse = pCourse;
|
2003-12-21 04:19:51 +00:00
|
|
|
feat.Feat = ssprintf("PR #%d in %s", i+1, pCourse->m_sName.c_str() );
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.pStringToFill = &hs.sName;
|
2003-12-21 04:19:51 +00:00
|
|
|
feat.grade = GRADE_NO_DATA;
|
2004-02-09 06:26:13 +00:00
|
|
|
feat.iScore = hs.iScore;
|
|
|
|
|
feat.fPercentDP = hs.fPercentDP;
|
2003-12-21 04:19:51 +00:00
|
|
|
if( pCourse->HasBanner() )
|
|
|
|
|
feat.Banner = pCourse->m_sBannerPath;
|
|
|
|
|
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-22 10:49:58 +00:00
|
|
|
//
|
|
|
|
|
// Filter swear words from name
|
|
|
|
|
//
|
|
|
|
|
name.MakeUpper();
|
2003-11-30 06:20:25 +00:00
|
|
|
RageFile file(NAMES_BLACKLIST_FILE);
|
|
|
|
|
|
2003-12-10 06:49:27 +00:00
|
|
|
if (file.IsOpen())
|
|
|
|
|
{
|
|
|
|
|
CString line;
|
|
|
|
|
|
|
|
|
|
while (!file.AtEOF())
|
2003-10-22 10:49:58 +00:00
|
|
|
{
|
2003-12-10 06:49:27 +00:00
|
|
|
line = file.GetLine();
|
|
|
|
|
line.MakeUpper();
|
|
|
|
|
if( !line.empty() && name.Find(line) != -1 ) // name contains a bad word
|
2003-12-15 07:35:40 +00:00
|
|
|
{
|
2004-02-11 04:06:27 +00:00
|
|
|
LOG->Trace( "entered '%s' matches blacklisted item '%s'", name.c_str(), line.c_str() );
|
2003-12-10 06:49:27 +00:00
|
|
|
name = "";
|
2004-02-11 04:06:27 +00:00
|
|
|
break;
|
2003-12-15 07:35:40 +00:00
|
|
|
}
|
2003-10-22 10:49:58 +00:00
|
|
|
}
|
2003-12-10 06:49:27 +00:00
|
|
|
}
|
2003-10-22 10:49:58 +00:00
|
|
|
|
2004-03-08 02:21:22 +00:00
|
|
|
vector<RankingFeat> aFeats;
|
2003-10-15 01:09:29 +00:00
|
|
|
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-12-28 08:20:48 +00:00
|
|
|
|
|
|
|
|
// save name pointers as we fill them
|
|
|
|
|
m_vpsNamesThatWereFilled.push_back( aFeats[i].pStringToFill );
|
2003-10-14 17:06:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
2003-12-07 20:29:42 +00:00
|
|
|
|
|
|
|
|
bool GameState::AllAreInDangerOrWorse() const
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->IsPlayerEnabled(p) )
|
2003-12-07 20:29:42 +00:00
|
|
|
if( m_HealthState[p] < DANGER )
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GameState::AllAreDead() const
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->IsPlayerEnabled(p) )
|
2003-12-07 20:29:42 +00:00
|
|
|
if( m_HealthState[p] < DEAD )
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GameState::OneIsHot() const
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
2004-02-07 22:14:36 +00:00
|
|
|
if( this->IsPlayerEnabled(PlayerNumber(p)) )
|
2003-12-07 20:29:42 +00:00
|
|
|
if( m_HealthState[p] == HOT )
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-12-28 19:46:50 +00:00
|
|
|
|
|
|
|
|
bool GameState::IsTimeToPlayAttractSounds()
|
|
|
|
|
{
|
2004-03-13 10:12:59 +00:00
|
|
|
// always play attract sounds the first time through after a game over -
|
|
|
|
|
// even if attract sounds are set to "never".
|
|
|
|
|
if( m_iNumTimesThroughAttract==0 )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// 0 means "never play sound". Avoid a divide by 0 below.
|
|
|
|
|
if( PREFSMAN->m_iAttractSoundFrequency == 0 )
|
2003-12-28 19:46:50 +00:00
|
|
|
return false;
|
2004-03-13 10:12:59 +00:00
|
|
|
|
|
|
|
|
// play attract sounds once every m_iAttractSoundFrequency times through
|
|
|
|
|
if( (m_iNumTimesThroughAttract % PREFSMAN->m_iAttractSoundFrequency)==0 )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
2004-01-15 00:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-21 01:35:54 +00:00
|
|
|
bool GameState::ChangeCourseDifficulty( PlayerNumber pn, int dir )
|
|
|
|
|
{
|
2004-03-13 22:18:09 +00:00
|
|
|
CourseDifficulty diff = (CourseDifficulty)(m_PreferredCourseDifficulty[pn]+dir);
|
2004-01-21 01:35:54 +00:00
|
|
|
if( diff < 0 || diff >= NUM_COURSE_DIFFICULTIES )
|
|
|
|
|
return false;
|
|
|
|
|
|
2004-03-13 22:18:09 +00:00
|
|
|
this->m_PreferredCourseDifficulty[pn] = diff;
|
2004-01-21 01:35:54 +00:00
|
|
|
if( PREFSMAN->m_bLockCourseDifficulties )
|
|
|
|
|
for( int p = 0; p < NUM_PLAYERS; ++p )
|
2004-03-13 22:18:09 +00:00
|
|
|
m_PreferredCourseDifficulty[p] = m_PreferredCourseDifficulty[pn];
|
2004-01-21 01:35:54 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-14 23:26:32 +00:00
|
|
|
bool PlayerIsUsingModifier( PlayerNumber pn, const CString sModifier )
|
|
|
|
|
{
|
|
|
|
|
PlayerOptions po = GAMESTATE->m_PlayerOptions[pn];
|
|
|
|
|
SongOptions so = GAMESTATE->m_SongOptions;
|
|
|
|
|
po.FromString( sModifier );
|
|
|
|
|
so.FromString( sModifier );
|
|
|
|
|
|
|
|
|
|
return po == GAMESTATE->m_PlayerOptions[pn] && so == GAMESTATE->m_SongOptions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "LuaFunctions.h"
|
2004-02-15 23:38:32 +00:00
|
|
|
LuaFunction_PlayerNumber( IsPlayerEnabled, GAMESTATE->IsPlayerEnabled(pn) )
|
2004-02-14 23:26:32 +00:00
|
|
|
LuaFunction_PlayerNumber( IsHumanPlayer, GAMESTATE->IsHumanPlayer(pn) )
|
|
|
|
|
LuaFunction_NoArgs( IsCourseMode, GAMESTATE->IsCourseMode() )
|
|
|
|
|
LuaFunction_NoArgs( IsDemonstration, GAMESTATE->m_bDemonstrationOrJukebox )
|
|
|
|
|
LuaFunction_NoArgs( StageIndex, GAMESTATE->GetStageIndex() )
|
|
|
|
|
LuaFunction_NoArgs( NumStagesLeft, GAMESTATE->GetNumStagesLeft() )
|
|
|
|
|
LuaFunction_NoArgs( IsFinalStage, GAMESTATE->IsFinalStage() )
|
|
|
|
|
LuaFunction_NoArgs( IsExtraStage, GAMESTATE->IsExtraStage() )
|
|
|
|
|
LuaFunction_NoArgs( IsExtraStage2, GAMESTATE->IsExtraStage2() )
|
|
|
|
|
LuaFunction_NoArgs( CourseSongIndex, GAMESTATE->GetCourseSongIndex() )
|
|
|
|
|
LuaFunction_NoArgs( CurStyle, GAMESTATE->m_CurStyle )
|
2004-03-01 02:25:41 +00:00
|
|
|
LuaFunction_NoArgs( GetNumPlayersEnabled, GAMESTATE->GetNumPlayersEnabled() )
|
2004-03-20 17:53:04 +00:00
|
|
|
LuaFunction_NoArgs( PlayerUsingBothSides, GAMESTATE->PlayerUsingBothSides() )
|
2004-02-14 23:26:32 +00:00
|
|
|
|
|
|
|
|
/* Return an integer into SONGMAN->m_pSongs. This lets us do input checking, which we
|
|
|
|
|
* can't easily do if we return pointers. */
|
|
|
|
|
LuaFunction_NoArgs( CurSong, GAMESTATE->m_pCurSong )
|
|
|
|
|
LuaFunction_PlayerNumber( CurSteps, GAMESTATE->m_pCurNotes[pn] )
|
|
|
|
|
|
|
|
|
|
int LuaFunc_UsingModifier( lua_State *L )
|
|
|
|
|
{
|
|
|
|
|
REQ_ARGS( "UsingModifier", 2 );
|
|
|
|
|
REQ_ARG_NUMBER_RANGE( "UsingModifier", 1, 1, NUM_PLAYERS );
|
|
|
|
|
REQ_ARG( "UsingModifier", 2, string );
|
|
|
|
|
|
|
|
|
|
const PlayerNumber pn = (PlayerNumber) (int(lua_tonumber( L, 1 ))-1);
|
|
|
|
|
const CString modifier = lua_tostring( L, 2 );
|
|
|
|
|
LUA_RETURN( PlayerIsUsingModifier( pn, modifier ) );
|
|
|
|
|
}
|
|
|
|
|
LuaFunction( UsingModifier );
|