2011-03-17 01:47:30 -04:00
# include "global.h"
# include "GameState.h"
2011-10-02 21:40:33 -05:00
# include "Actor.h"
2011-03-17 01:47:30 -04:00
# include "AdjustSync.h"
# include "AnnouncerManager.h"
2013-06-04 23:47:22 -04:00
# include "Bookkeeper.h"
2011-03-17 01:47:30 -04:00
# include "Character.h"
# include "CharacterManager.h"
# include "CommonMetrics.h"
# include "Course.h"
# include "CryptManager.h"
# include "Foreach.h"
# include "Game.h"
# include "GameCommand.h"
# include "GameConstantsAndTypes.h"
# include "GameManager.h"
# include "GamePreferences.h"
# include "HighScore.h"
# include "LightsManager.h"
# include "LuaReference.h"
# include "MessageManager.h"
# include "MemoryCardManager.h"
2014-12-07 01:53:17 -07:00
# include "NoteData.h"
2011-03-17 01:47:30 -04:00
# include "NoteSkinManager.h"
# include "PlayerState.h"
# include "PrefsManager.h"
# include "Profile.h"
# include "ProfileManager.h"
# include "RageFile.h"
# include "RageLog.h"
# include "RageUtil.h"
# include "Song.h"
# include "SongManager.h"
# include "SongUtil.h"
# include "StatsManager.h"
2014-09-01 19:00:00 -04:00
# include "StepMania.h"
2011-03-17 01:47:30 -04:00
# include "Steps.h"
# include "Style.h"
# include "ThemeManager.h"
# include "UnlockManager.h"
# include "ScreenManager.h"
# include "Screen.h"
# include <ctime>
# include <set>
2013-11-30 09:50:54 -06:00
GameState * GAMESTATE = NULL ; // global and accessible from anywhere in our program
2011-03-17 01:47:30 -04:00
# define NAME_BLACKLIST_FILE " / Data / NamesBlacklist.txt"
class GameStateMessageHandler : public MessageSubscriber
{
void HandleMessage ( const Message & msg )
{
if ( msg . GetName ( ) = = " RefreshCreditText " )
{
RString sJoined ;
FOREACH_HumanPlayer ( pn )
{
if ( sJoined ! = " " )
sJoined + = " , " ;
sJoined + = ssprintf ( " P%i " , pn + 1 ) ;
}
if ( sJoined = = " " )
sJoined = " none " ;
LOG - > MapLog ( " JOINED " , " Players joined: %s " , sJoined . c_str ( ) ) ;
}
}
} ;
struct GameStateImpl
{
GameStateMessageHandler m_Subscriber ;
GameStateImpl ( )
{
m_Subscriber . SubscribeToMessage ( " RefreshCreditText " ) ;
}
} ;
static GameStateImpl * g_pImpl = NULL ;
ThemeMetric < bool > ALLOW_LATE_JOIN ( " GameState " , " AllowLateJoin " ) ;
ThemeMetric < bool > USE_NAME_BLACKLIST ( " GameState " , " UseNameBlacklist " ) ;
ThemeMetric < RString > DEFAULT_SORT ( " GameState " , " DefaultSort " ) ;
SortOrder GetDefaultSort ( )
{
return StringToSortOrder ( DEFAULT_SORT ) ;
}
ThemeMetric < RString > DEFAULT_SONG ( " GameState " , " DefaultSong " ) ;
Song * GameState : : GetDefaultSong ( ) const
{
SongID sid ;
sid . FromString ( DEFAULT_SONG ) ;
return sid . ToSong ( ) ;
}
2011-09-29 22:09:52 -04:00
static const ThemeMetric < bool > EDIT_ALLOWED_FOR_EXTRA ( " GameState " , " EditAllowedForExtra " ) ;
2011-03-17 01:47:30 -04:00
static const ThemeMetric < Difficulty > MIN_DIFFICULTY_FOR_EXTRA ( " GameState " , " MinDifficultyForExtra " ) ;
static const ThemeMetric < Grade > GRADE_TIER_FOR_EXTRA_1 ( " GameState " , " GradeTierForExtra1 " ) ;
static const ThemeMetric < bool > ALLOW_EXTRA_2 ( " GameState " , " AllowExtra2 " ) ;
static const ThemeMetric < Grade > GRADE_TIER_FOR_EXTRA_2 ( " GameState " , " GradeTierForExtra2 " ) ;
static ThemeMetric < bool > ARE_STAGE_PLAYER_MODS_FORCED ( " GameState " , " AreStagePlayerModsForced " ) ;
static ThemeMetric < bool > ARE_STAGE_SONG_MODS_FORCED ( " GameState " , " AreStageSongModsForced " ) ;
2012-03-01 17:20:10 -06:00
static Preference < Premium > g_Premium ( " Premium " , Premium_DoubleFor1Credit ) ;
2011-03-17 01:47:30 -04:00
Preference < bool > GameState : : m_bAutoJoin ( " AutoJoin " , false ) ;
GameState : : GameState ( ) :
2011-06-08 14:43:59 -04:00
processedTiming ( NULL ) ,
2011-03-17 01:47:30 -04:00
m_pCurGame ( Message_CurrentGameChanged ) ,
m_pCurStyle ( Message_CurrentStyleChanged ) ,
m_PlayMode ( Message_PlayModeChanged ) ,
2013-06-04 23:47:22 -04:00
m_iCoins ( Message_CoinsChanged ) ,
2011-03-17 01:47:30 -04:00
m_sPreferredSongGroup ( Message_PreferredSongGroupChanged ) ,
m_sPreferredCourseGroup ( Message_PreferredCourseGroupChanged ) ,
m_PreferredStepsType ( Message_PreferredStepsTypeChanged ) ,
m_PreferredDifficulty ( Message_PreferredDifficultyP1Changed ) ,
m_PreferredCourseDifficulty ( Message_PreferredCourseDifficultyP1Changed ) ,
m_SortOrder ( Message_SortOrderChanged ) ,
m_pCurSong ( Message_CurrentSongChanged ) ,
m_pCurSteps ( Message_CurrentStepsP1Changed ) ,
m_pCurCourse ( Message_CurrentCourseChanged ) ,
m_pCurTrail ( Message_CurrentTrailP1Changed ) ,
m_bGameplayLeadIn ( Message_GameplayLeadInChanged ) ,
m_bDidModeChangeNoteSkin ( false ) ,
2011-06-11 09:36:17 -04:00
m_bIsUsingStepTiming ( true ) ,
m_bInStepEditor ( false ) ,
2011-03-17 01:47:30 -04:00
m_stEdit ( Message_EditStepsTypeChanged ) ,
m_cdEdit ( Message_EditCourseDifficultyChanged ) ,
m_pEditSourceSteps ( Message_EditSourceStepsChanged ) ,
m_stEditSource ( Message_EditSourceStepsTypeChanged ) ,
m_iEditCourseEntryIndex ( Message_EditCourseEntryIndexChanged ) ,
2011-06-11 09:36:17 -04:00
m_sEditLocalProfileID ( Message_EditLocalProfileIDChanged )
2011-03-17 01:47:30 -04:00
{
g_pImpl = new GameStateImpl ;
2014-12-07 01:53:17 -07:00
m_pCurStyle . Set ( NULL ) ;
FOREACH_PlayerNumber ( rpn )
{
m_SeparatedStyles [ rpn ] = NULL ;
}
2011-03-17 01:47:30 -04:00
m_pCurGame . Set ( NULL ) ;
2013-06-04 23:47:22 -04:00
m_iCoins . Set ( 0 ) ;
2011-03-17 01:47:30 -04:00
m_timeGameStarted . SetZero ( ) ;
m_bDemonstrationOrJukebox = false ;
m_iNumTimesThroughAttract = - 1 ; // initial screen will bump this up to 0
m_iStageSeed = m_iGameSeed = 0 ;
m_PlayMode . Set ( PlayMode_Invalid ) ; // used by IsPlayerEnabled before the first screen
FOREACH_PlayerNumber ( p )
m_bSideIsJoined [ p ] = false ; // used by GetNumSidesJoined before the first screen
FOREACH_PlayerNumber ( p )
{
m_pPlayerState [ p ] = new PlayerState ;
2014-12-07 01:53:17 -07:00
m_pPlayerState [ p ] - > SetPlayerNumber ( p ) ;
2011-03-17 01:47:30 -04:00
}
FOREACH_MultiPlayer ( p )
{
m_pMultiPlayerState [ p ] = new PlayerState ;
2014-12-07 01:53:17 -07:00
m_pMultiPlayerState [ p ] - > SetPlayerNumber ( PLAYER_1 ) ;
2011-03-17 01:47:30 -04:00
m_pMultiPlayerState [ p ] - > m_mp = p ;
}
m_Environment = new LuaTable ;
m_bDopefish = false ;
2011-08-03 23:56:04 -05:00
sExpandedSectionName = " " ;
2011-03-17 01:47:30 -04:00
// Don't reset yet; let the first screen do it, so we can use PREFSMAN and THEME.
//Reset();
// Register with Lua.
{
Lua * L = LUA - > Get ( ) ;
lua_pushstring ( L , " GAMESTATE " ) ;
this - > PushSelf ( L ) ;
lua_settable ( L , LUA_GLOBALSINDEX ) ;
LUA - > Release ( L ) ;
}
}
GameState : : ~ GameState ( )
{
// Unregister with Lua.
LUA - > UnsetGlobal ( " GAMESTATE " ) ;
FOREACH_PlayerNumber ( p )
SAFE_DELETE ( m_pPlayerState [ p ] ) ;
FOREACH_MultiPlayer ( p )
SAFE_DELETE ( m_pMultiPlayerState [ p ] ) ;
SAFE_DELETE ( m_Environment ) ;
SAFE_DELETE ( g_pImpl ) ;
2011-06-15 02:36:53 -04:00
SAFE_DELETE ( processedTiming ) ;
2011-03-17 01:47:30 -04:00
}
2011-06-06 20:40:11 -04:00
PlayerNumber GameState : : GetMasterPlayerNumber ( ) const
{
return this - > masterPlayerNumber ;
}
void GameState : : SetMasterPlayerNumber ( const PlayerNumber p )
{
this - > masterPlayerNumber = p ;
}
2011-06-08 14:43:59 -04:00
TimingData * GameState : : GetProcessedTimingData ( ) const
{
return this - > processedTiming ;
}
2011-06-08 15:02:54 -04:00
void GameState : : SetProcessedTimingData ( TimingData * t )
2011-06-08 14:43:59 -04:00
{
2011-06-08 15:02:54 -04:00
this - > processedTiming = t ;
2011-06-08 14:43:59 -04:00
}
2011-03-17 01:47:30 -04:00
void GameState : : ApplyGameCommand ( const RString & sCommand , PlayerNumber pn )
{
GameCommand m ;
m . Load ( 0 , ParseCommands ( sCommand ) ) ;
RString sWhy ;
if ( ! m . IsPlayable ( & sWhy ) )
2014-07-12 14:59:10 -06:00
{
2014-07-15 13:28:06 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " Can't apply GameCommand \" %s \" : %s " , sCommand . c_str ( ) , sWhy . c_str ( ) ) ;
2014-07-12 14:59:10 -06:00
return ;
}
2011-03-17 01:47:30 -04:00
if ( pn = = PLAYER_INVALID )
m . ApplyToAllPlayers ( ) ;
else
m . Apply ( pn ) ;
}
void GameState : : ApplyCmdline ( )
{
// We need to join players before we can set the style.
RString sPlayer ;
for ( int i = 0 ; GetCommandlineArgument ( " player " , & sPlayer , i ) ; + + i )
{
2011-05-11 15:58:31 -04:00
int pn = StringToInt ( sPlayer ) - 1 ;
2011-03-17 01:47:30 -04:00
if ( ! IsAnInt ( sPlayer ) | | pn < 0 | | pn > = NUM_PLAYERS )
RageException : : Throw ( " Invalid argument \" --player=%s \" . " , sPlayer . c_str ( ) ) ;
JoinPlayer ( ( PlayerNumber ) pn ) ;
}
RString sMode ;
for ( int i = 0 ; GetCommandlineArgument ( " mode " , & sMode , i ) ; + + i )
{
ApplyGameCommand ( sMode ) ;
}
}
void GameState : : ResetPlayer ( PlayerNumber pn )
{
m_PreferredStepsType . Set ( StepsType_Invalid ) ;
m_PreferredDifficulty [ pn ] . Set ( Difficulty_Invalid ) ;
m_PreferredCourseDifficulty [ pn ] . Set ( Difficulty_Medium ) ;
m_iPlayerStageTokens [ pn ] = 0 ;
m_iAwardedExtraStages [ pn ] = 0 ;
m_pCurSteps [ pn ] . Set ( NULL ) ;
m_pCurTrail [ pn ] . Set ( NULL ) ;
m_pPlayerState [ pn ] - > Reset ( ) ;
PROFILEMAN - > UnloadProfile ( pn ) ;
2011-10-29 11:43:49 -04:00
ResetPlayerOptions ( pn ) ;
}
2011-03-17 01:47:30 -04:00
2011-10-29 11:43:49 -04:00
void GameState : : ResetPlayerOptions ( PlayerNumber pn )
{
2011-03-17 01:47:30 -04:00
PlayerOptions po ;
GetDefaultPlayerOptions ( po ) ;
m_pPlayerState [ pn ] - > m_PlayerOptions . Assign ( ModsLevel_Preferred , po ) ;
}
void GameState : : Reset ( )
{
2011-06-06 20:40:11 -04:00
this - > SetMasterPlayerNumber ( PLAYER_INVALID ) ; // must initialize for UnjoinPlayer
2011-03-17 01:47:30 -04:00
FOREACH_PlayerNumber ( pn )
UnjoinPlayer ( pn ) ;
2012-12-27 11:38:53 -05:00
ASSERT ( THEME ! = NULL ) ;
2011-03-17 01:47:30 -04:00
m_timeGameStarted . SetZero ( ) ;
2014-12-07 01:53:17 -07:00
SetCurrentStyle ( NULL , PLAYER_INVALID ) ;
2011-03-17 01:47:30 -04:00
FOREACH_MultiPlayer ( p )
m_MultiPlayerStatus [ p ] = MultiPlayerStatus_NotJoined ;
FOREACH_PlayerNumber ( pn )
MEMCARDMAN - > UnlockCard ( pn ) ;
2013-06-04 23:47:22 -04:00
//m_iCoins = 0; // don't reset coin count!
2011-03-17 01:47:30 -04:00
m_bMultiplayer = false ;
m_iNumMultiplayerNoteFields = 1 ;
* m_Environment = LuaTable ( ) ;
m_sPreferredSongGroup . Set ( GROUP_ALL ) ;
m_sPreferredCourseGroup . Set ( GROUP_ALL ) ;
2014-06-20 13:54:56 -06:00
m_bFailTypeWasExplicitlySet = false ;
2011-03-17 01:47:30 -04:00
m_SortOrder . Set ( SortOrder_Invalid ) ;
m_PreferredSortOrder = GetDefaultSort ( ) ;
m_PlayMode . Set ( PlayMode_Invalid ) ;
m_EditMode = EditMode_Invalid ;
m_bDemonstrationOrJukebox = false ;
m_bJukeboxUsesModifiers = false ;
m_iCurrentStageIndex = 0 ;
m_bGameplayLeadIn . Set ( false ) ;
m_iNumStagesOfThisSong = 0 ;
m_bLoadingNextSong = false ;
NOTESKIN - > RefreshNoteSkinData ( m_pCurGame ) ;
m_iGameSeed = rand ( ) ;
m_iStageSeed = rand ( ) ;
2014-09-07 04:05:10 -06:00
m_AdjustTokensBySongCostForFinalStageCheck = true ;
2011-03-17 01:47:30 -04:00
m_pCurSong . Set ( GetDefaultSong ( ) ) ;
m_pPreferredSong = NULL ;
m_pCurCourse . Set ( NULL ) ;
m_pPreferredCourse = NULL ;
FOREACH_MultiPlayer ( p )
m_pMultiPlayerState [ p ] - > Reset ( ) ;
m_SongOptions . Init ( ) ;
ResetMusicStatistics ( ) ;
ResetStageStatistics ( ) ;
AdjustSync : : ResetOriginalSyncData ( ) ;
SONGMAN - > UpdatePopular ( ) ;
SONGMAN - > UpdateShuffled ( ) ;
/* We may have cached trails from before everything was loaded (eg. from
* before SongManager::UpdatePopular could be called). Erase the cache. */
SONGMAN - > RegenerateNonFixedCourses ( ) ;
STATSMAN - > Reset ( ) ;
FOREACH_PlayerNumber ( p )
{
if ( PREFSMAN - > m_ShowDancingCharacters = = SDC_Random )
m_pCurCharacters [ p ] = CHARMAN - > GetRandomCharacter ( ) ;
else
m_pCurCharacters [ p ] = CHARMAN - > GetDefaultCharacter ( ) ;
2012-12-27 11:38:53 -05:00
ASSERT ( m_pCurCharacters [ p ] ! = NULL ) ;
2011-03-17 01:47:30 -04:00
}
m_bTemporaryEventMode = false ;
LIGHTSMAN - > SetLightsMode ( LIGHTSMODE_ATTRACT ) ;
m_stEdit . Set ( StepsType_Invalid ) ;
m_pEditSourceSteps . Set ( NULL ) ;
m_stEditSource . Set ( StepsType_Invalid ) ;
m_iEditCourseEntryIndex . Set ( - 1 ) ;
m_sEditLocalProfileID . Set ( " " ) ;
m_bBackedOutOfFinalStage = false ;
m_bEarnedExtraStage = false ;
2011-08-03 23:56:04 -05:00
sExpandedSectionName = " " ;
2011-03-17 01:47:30 -04:00
ApplyCmdline ( ) ;
}
void GameState : : JoinPlayer ( PlayerNumber pn )
{
2014-02-02 12:53:26 -06:00
/* If joint premium and we're not taking away a credit for the 2nd join,
* give the new player the same number of stage tokens that the old player
* has. */
if ( GetCoinMode ( ) = = CoinMode_Pay & & GetPremium ( ) = = Premium_2PlayersFor1Credit & & GetNumSidesJoined ( ) = = 1 )
m_iPlayerStageTokens [ pn ] = m_iPlayerStageTokens [ this - > GetMasterPlayerNumber ( ) ] ;
else
m_iPlayerStageTokens [ pn ] = PREFSMAN - > m_iSongsPerPlay ;
2011-03-17 01:47:30 -04:00
m_bSideIsJoined [ pn ] = true ;
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = PLAYER_INVALID )
this - > SetMasterPlayerNumber ( pn ) ;
2011-03-17 01:47:30 -04:00
// if first player to join, set start time
if ( GetNumSidesJoined ( ) = = 1 )
BeginGame ( ) ;
// Count each player join as a play.
{
Profile * pMachineProfile = PROFILEMAN - > GetMachineProfile ( ) ;
pMachineProfile - > m_iTotalSessions + + ;
}
// Set the current style to something appropriate for the new number of joined players.
2014-12-07 01:53:17 -07:00
if ( ALLOW_LATE_JOIN & & GetCurrentStyle ( PLAYER_INVALID ) ! = NULL )
2011-03-17 01:47:30 -04:00
{
const Style * pStyle ;
2011-04-02 00:32:30 -05:00
// Only use one player for StyleType_OnePlayerTwoSides and StepsTypes
// that can only be played by one player (e.g. dance-solo,
// dance-threepanel, popn-nine). -aj
2011-03-17 01:47:30 -04:00
// XXX?: still shows joined player as "Insert Card". May not be an issue? -aj
2014-12-07 01:53:17 -07:00
if ( GetCurrentStyle ( PLAYER_INVALID ) - > m_StyleType = = StyleType_OnePlayerTwoSides | |
GetCurrentStyle ( PLAYER_INVALID ) - > m_StepsType = = StepsType_dance_solo | |
GetCurrentStyle ( PLAYER_INVALID ) - > m_StepsType = = StepsType_dance_threepanel | |
GetCurrentStyle ( PLAYER_INVALID ) - > m_StepsType = = StepsType_popn_nine )
pStyle = GAMEMAN - > GetFirstCompatibleStyle ( m_pCurGame , 1 , GetCurrentStyle ( PLAYER_INVALID ) - > m_StepsType ) ;
2011-03-17 01:47:30 -04:00
else
2014-12-07 01:53:17 -07:00
pStyle = GAMEMAN - > GetFirstCompatibleStyle ( m_pCurGame , GetNumSidesJoined ( ) , GetCurrentStyle ( PLAYER_INVALID ) - > m_StepsType ) ;
2011-03-17 01:47:30 -04:00
// use SetCurrentStyle in case of StyleType_OnePlayerTwoSides
2014-12-07 01:53:17 -07:00
SetCurrentStyle ( pStyle , pn ) ;
2011-03-17 01:47:30 -04:00
}
Message msg ( MessageIDToString ( Message_PlayerJoined ) ) ;
msg . SetParam ( " Player " , pn ) ;
MESSAGEMAN - > Broadcast ( msg ) ;
}
void GameState : : UnjoinPlayer ( PlayerNumber pn )
{
2014-03-10 21:54:53 -06:00
/* Unjoin STATSMAN first, so steps used by this player are released
* and can be released by PROFILEMAN. */
STATSMAN - > UnjoinPlayer ( pn ) ;
2011-03-17 01:47:30 -04:00
m_bSideIsJoined [ pn ] = false ;
m_iPlayerStageTokens [ pn ] = 0 ;
ResetPlayer ( pn ) ;
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = pn )
2014-03-10 21:54:53 -06:00
{
// We can't use GetFirstHumanPlayer() because if both players were joined, GetFirstHumanPlayer() will always return PLAYER_1, even when PLAYER_1 is the player we're unjoining.
FOREACH_HumanPlayer ( hp )
{
if ( pn ! = hp )
{
this - > SetMasterPlayerNumber ( hp ) ;
}
}
if ( this - > GetMasterPlayerNumber ( ) = = pn )
{
this - > SetMasterPlayerNumber ( PLAYER_INVALID ) ;
}
}
2011-03-17 01:47:30 -04:00
Message msg ( MessageIDToString ( Message_PlayerUnjoined ) ) ;
msg . SetParam ( " Player " , pn ) ;
MESSAGEMAN - > Broadcast ( msg ) ;
// If there are no players left, reset some non-player-specific stuff, too.
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = PLAYER_INVALID )
2011-03-17 01:47:30 -04:00
{
SongOptions so ;
GetDefaultSongOptions ( so ) ;
m_SongOptions . Assign ( ModsLevel_Preferred , so ) ;
m_bDidModeChangeNoteSkin = false ;
}
}
/* xxx: handle multiplayer join? -aj */
namespace
{
bool JoinInputInternal ( PlayerNumber pn )
{
if ( ! GAMESTATE - > PlayersCanJoin ( ) )
return false ;
// If this side is already in, don't re-join.
if ( GAMESTATE - > m_bSideIsJoined [ pn ] )
return false ;
2013-06-04 23:47:22 -04:00
// subtract coins
int iCoinsNeededToJoin = GAMESTATE - > GetCoinsNeededToJoin ( ) ;
if ( GAMESTATE - > m_iCoins < iCoinsNeededToJoin )
return false ; // not enough coins
GAMESTATE - > m_iCoins . Set ( GAMESTATE - > m_iCoins - iCoinsNeededToJoin ) ;
2011-03-17 01:47:30 -04:00
GAMESTATE - > JoinPlayer ( pn ) ;
return true ;
}
} ;
// Handle an input that can join a player. Return true if the player joined.
bool GameState : : JoinInput ( PlayerNumber pn )
{
// When AutoJoin is enabled, join all players on a single start press.
if ( GAMESTATE - > m_bAutoJoin . Get ( ) )
return JoinPlayers ( ) ;
else
return JoinInputInternal ( pn ) ;
}
// Attempt to join all players, as if each player pressed Start.
bool GameState : : JoinPlayers ( )
{
bool bJoined = false ;
FOREACH_PlayerNumber ( pn )
{
if ( JoinInputInternal ( pn ) )
bJoined = true ;
}
return bJoined ;
}
2013-06-04 23:47:22 -04:00
int GameState : : GetCoinsNeededToJoin ( ) const
{
2014-02-02 12:53:26 -06:00
int iCoinsToCharge = 0 ;
if ( GetCoinMode ( ) = = CoinMode_Pay )
iCoinsToCharge = PREFSMAN - > m_iCoinsPerCredit ;
// If joint premium, don't take away a credit for the second join.
if ( GetPremium ( ) = = Premium_2PlayersFor1Credit & &
GetNumSidesJoined ( ) = = 1 )
iCoinsToCharge = 0 ;
return iCoinsToCharge ;
2013-06-04 23:47:22 -04:00
}
2011-03-17 01:47:30 -04:00
/* Game flow:
*
* BeginGame() - the first player has joined; the game is starting.
*
* PlayersFinalized() - player memory cards are loaded; later joins won't have memory cards this stage
*
* BeginStage() - gameplay is beginning
*
* optional: CancelStage() - gameplay aborted (Back pressed), undo BeginStage and back up
*
* CommitStageStats() - gameplay is finished
* Saves STATSMAN->m_CurStageStats to the profiles, so profile information
* is up-to-date for Evaluation.
*
* FinishStage() - gameplay and evaluation is finished
* Clears data which was stored by CommitStageStats. */
void GameState : : BeginGame ( )
{
m_timeGameStarted . Touch ( ) ;
m_vpsNamesThatWereFilled . clear ( ) ;
// Play attract on the ending screen, then on the ranking screen
// even if attract sounds are set to off.
m_iNumTimesThroughAttract = - 1 ;
FOREACH_PlayerNumber ( pn )
MEMCARDMAN - > UnlockCard ( pn ) ;
}
void GameState : : LoadProfiles ( bool bLoadEdits )
{
// Unlock any cards that we might want to load.
FOREACH_HumanPlayer ( pn )
if ( ! PROFILEMAN - > IsPersistentProfile ( pn ) )
MEMCARDMAN - > UnlockCard ( pn ) ;
MEMCARDMAN - > WaitForCheckingToComplete ( ) ;
FOREACH_HumanPlayer ( pn )
{
// If a profile is already loaded, this was already called.
if ( PROFILEMAN - > IsPersistentProfile ( pn ) )
continue ;
MEMCARDMAN - > MountCard ( pn ) ;
bool bSuccess = PROFILEMAN - > LoadFirstAvailableProfile ( pn , bLoadEdits ) ; // load full profile
MEMCARDMAN - > UnmountCard ( pn ) ;
if ( ! bSuccess )
continue ;
// Lock the card on successful load, so we won't allow it to be changed.
MEMCARDMAN - > LockCard ( pn ) ;
LoadCurrentSettingsFromProfile ( pn ) ;
Profile * pPlayerProfile = PROFILEMAN - > GetProfile ( pn ) ;
if ( pPlayerProfile )
pPlayerProfile - > m_iTotalSessions + + ;
}
}
void GameState : : SavePlayerProfiles ( )
{
FOREACH_HumanPlayer ( pn )
SavePlayerProfile ( pn ) ;
}
void GameState : : SavePlayerProfile ( PlayerNumber pn )
{
if ( ! PROFILEMAN - > IsPersistentProfile ( pn ) )
return ;
// AutoplayCPU should not save scores. -aj
// xxx: this MAY cause issues with Multiplayer. However, without a working
// Multiplayer build, we'll never know. -aj
if ( m_pPlayerState [ pn ] - > m_PlayerController ! = PC_HUMAN )
return ;
bool bWasMemoryCard = PROFILEMAN - > ProfileWasLoadedFromMemoryCard ( pn ) ;
if ( bWasMemoryCard )
MEMCARDMAN - > MountCard ( pn ) ;
PROFILEMAN - > SaveProfile ( pn ) ;
if ( bWasMemoryCard )
MEMCARDMAN - > UnmountCard ( pn ) ;
}
bool GameState : : HaveProfileToLoad ( )
{
FOREACH_HumanPlayer ( pn )
{
// We won't load this profile if it's already loaded.
if ( PROFILEMAN - > IsPersistentProfile ( pn ) )
continue ;
// If a memory card is inserted, we'l try to load it.
if ( MEMCARDMAN - > CardInserted ( pn ) )
return true ;
if ( ! PROFILEMAN - > m_sDefaultLocalProfileID [ pn ] . Get ( ) . empty ( ) )
return true ;
}
return false ;
}
bool GameState : : HaveProfileToSave ( )
{
FOREACH_HumanPlayer ( pn )
if ( PROFILEMAN - > IsPersistentProfile ( pn ) )
return true ;
return false ;
}
void GameState : : SaveLocalData ( )
{
2013-06-04 23:47:22 -04:00
BOOKKEEPER - > WriteToDisk ( ) ;
2011-03-17 01:47:30 -04:00
PROFILEMAN - > SaveMachineProfile ( ) ;
}
int GameState : : GetNumStagesMultiplierForSong ( const Song * pSong )
{
int iNumStages = 1 ;
2012-12-27 11:38:53 -05:00
ASSERT ( pSong ! = NULL ) ;
2011-03-17 01:47:30 -04:00
if ( pSong - > IsMarathon ( ) )
iNumStages * = 3 ;
if ( pSong - > IsLong ( ) )
iNumStages * = 2 ;
return iNumStages ;
}
int GameState : : GetNumStagesForCurrentSongAndStepsOrCourse ( ) const
{
int iNumStagesOfThisSong = 1 ;
if ( m_pCurSong )
{
2014-12-07 01:53:17 -07:00
const Style * pStyle = GetCurrentStyle ( PLAYER_INVALID ) ;
2011-03-17 01:47:30 -04:00
int numSidesJoined = GetNumSidesJoined ( ) ;
if ( pStyle = = NULL )
{
const Steps * pSteps = NULL ;
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) ! = PlayerNumber_Invalid )
pSteps = m_pCurSteps [ this - > GetMasterPlayerNumber ( ) ] ;
2011-03-17 01:47:30 -04:00
// Don't call GetFirstCompatibleStyle if numSidesJoined == 0.
// This happens because on SContinue when players are unjoined,
// pCurSteps will still be set while no players are joined. -Chris
if ( pSteps & & numSidesJoined > 0 )
{
// If a style isn't set, use the style of the selected steps.
StepsType st = pSteps - > m_StepsType ;
pStyle = GAMEMAN - > GetFirstCompatibleStyle ( m_pCurGame , numSidesJoined , st ) ;
}
else
{
/* If steps aren't set either, pick any style for the number of
* joined players, or one player if no players are joined. */
vector < const Style * > vpStyles ;
int iJoined = max ( numSidesJoined , 1 ) ;
GAMEMAN - > GetCompatibleStyles ( m_pCurGame , iJoined , vpStyles ) ;
ASSERT ( ! vpStyles . empty ( ) ) ;
pStyle = vpStyles [ 0 ] ;
}
}
/* Extra stages need to only count as one stage in case a multi-stage
* song is chosen. */
if ( IsAnExtraStage ( ) )
iNumStagesOfThisSong = 1 ;
else
2011-08-07 18:33:35 -05:00
iNumStagesOfThisSong = GameState : : GetNumStagesMultiplierForSong ( m_pCurSong ) ;
2011-03-17 01:47:30 -04:00
}
else if ( m_pCurCourse )
iNumStagesOfThisSong = PREFSMAN - > m_iSongsPerPlay ;
else
return - 1 ;
iNumStagesOfThisSong = max ( iNumStagesOfThisSong , 1 ) ;
return iNumStagesOfThisSong ;
}
// Called by ScreenGameplay. Set the length of the current song.
void GameState : : BeginStage ( )
{
if ( m_bDemonstrationOrJukebox )
return ;
// This should only be called once per stage.
if ( m_iNumStagesOfThisSong ! = 0 )
LOG - > Warn ( " XXX: m_iNumStagesOfThisSong == %i? " , m_iNumStagesOfThisSong ) ;
ResetStageStatistics ( ) ;
AdjustSync : : ResetOriginalSyncData ( ) ;
if ( ! ARE_STAGE_PLAYER_MODS_FORCED )
{
2011-07-06 22:22:45 -04:00
FOREACH_PlayerNumber ( p )
2011-07-06 21:34:01 -04:00
{
ModsGroup < PlayerOptions > & po = m_pPlayerState [ p ] - > m_PlayerOptions ;
po . Assign ( ModsLevel_Stage ,
m_pPlayerState [ p ] - > m_PlayerOptions . GetPreferred ( ) ) ;
}
2011-03-17 01:47:30 -04:00
}
if ( ! ARE_STAGE_SONG_MODS_FORCED )
m_SongOptions . Assign ( ModsLevel_Stage , m_SongOptions . GetPreferred ( ) ) ;
STATSMAN - > m_CurStageStats . m_fMusicRate = m_SongOptions . GetSong ( ) . m_fMusicRate ;
m_iNumStagesOfThisSong = GetNumStagesForCurrentSongAndStepsOrCourse ( ) ;
ASSERT ( m_iNumStagesOfThisSong ! = - 1 ) ;
FOREACH_EnabledPlayer ( p )
{
// only do this check with human players, assume CPU players (Rave)
// always have tokens. -aj (this could probably be moved below, even.)
if ( ! IsEventMode ( ) & & ! IsCpuPlayer ( p ) )
ASSERT ( m_iPlayerStageTokens [ p ] > = m_iNumStagesOfThisSong ) ;
m_iPlayerStageTokens [ p ] - = m_iNumStagesOfThisSong ;
}
FOREACH_HumanPlayer ( pn )
if ( CurrentOptionsDisqualifyPlayer ( pn ) )
STATSMAN - > m_CurStageStats . m_player [ pn ] . m_bDisqualified = true ;
m_bEarnedExtraStage = false ;
m_sStageGUID = CryptManager : : GenerateRandomUUID ( ) ;
}
void GameState : : CancelStage ( )
{
FOREACH_CpuPlayer ( p )
{
switch ( m_PlayMode )
{
case PLAY_MODE_BATTLE :
case PLAY_MODE_RAVE :
2011-07-20 11:11:04 -04:00
m_iPlayerStageTokens [ p ] = PREFSMAN - > m_iSongsPerPlay ;
default :
break ;
2011-03-17 01:47:30 -04:00
}
}
FOREACH_EnabledPlayer ( p )
m_iPlayerStageTokens [ p ] + = m_iNumStagesOfThisSong ;
m_iNumStagesOfThisSong = 0 ;
ResetStageStatistics ( ) ;
}
void GameState : : CommitStageStats ( )
{
if ( m_bDemonstrationOrJukebox )
return ;
STATSMAN - > CommitStatsToProfiles ( & STATSMAN - > m_CurStageStats ) ;
// Update TotalPlaySeconds.
int iPlaySeconds = max ( 0 , ( int ) m_timeGameStarted . GetDeltaTime ( ) ) ;
Profile * pMachineProfile = PROFILEMAN - > GetMachineProfile ( ) ;
pMachineProfile - > m_iTotalSessionSeconds + = iPlaySeconds ;
FOREACH_HumanPlayer ( p )
{
Profile * pPlayerProfile = PROFILEMAN - > GetProfile ( p ) ;
if ( pPlayerProfile )
pPlayerProfile - > m_iTotalSessionSeconds + = iPlaySeconds ;
}
}
/* Called by ScreenSelectMusic (etc). Increment the stage counter if we just
* played a song. Might be called more than once. */
void GameState : : FinishStage ( )
{
// Increment the stage counter.
const int iOldStageIndex = m_iCurrentStageIndex ;
+ + m_iCurrentStageIndex ;
m_iNumStagesOfThisSong = 0 ;
EarnedExtraStage e = CalculateEarnedExtraStage ( ) ;
STATSMAN - > m_CurStageStats . m_EarnedExtraStage = e ;
if ( e ! = EarnedExtraStage_No )
{
LOG - > Trace ( " awarded extra stage " ) ;
FOREACH_HumanPlayer ( p )
{
// todo: unhardcode the extra stage limit? -aj
if ( m_iAwardedExtraStages [ p ] < 2 )
{
+ + m_iAwardedExtraStages [ p ] ;
+ + m_iPlayerStageTokens [ p ] ;
m_bEarnedExtraStage = true ;
}
}
}
2014-02-16 11:43:28 -07:00
// Save the current combo to the profiles so it can be used for ComboContinuesBetweenSongs.
FOREACH_HumanPlayer ( p )
{
Profile * pProfile = PROFILEMAN - > GetProfile ( p ) ;
pProfile - > m_iCurrentCombo = STATSMAN - > m_CurStageStats . m_player [ p ] . m_iCurCombo ;
}
2011-03-17 01:47:30 -04:00
if ( m_bDemonstrationOrJukebox )
return ;
// todo: simplify. profile saving is accomplished in ScreenProfileSave
// now; all this code does differently is save machine profile as well. -aj
if ( IsEventMode ( ) )
{
const int iSaveProfileEvery = 3 ;
if ( iOldStageIndex / iSaveProfileEvery < m_iCurrentStageIndex / iSaveProfileEvery )
{
LOG - > Trace ( " Played %i stages; saving profiles ... " , iSaveProfileEvery ) ;
PROFILEMAN - > SaveMachineProfile ( ) ;
this - > SavePlayerProfiles ( ) ;
}
}
}
void GameState : : LoadCurrentSettingsFromProfile ( PlayerNumber pn )
{
if ( ! PROFILEMAN - > IsPersistentProfile ( pn ) )
return ;
const Profile * pProfile = PROFILEMAN - > GetProfile ( pn ) ;
// apply saved default modifiers if any
RString sModifiers ;
if ( pProfile - > GetDefaultModifiers ( m_pCurGame , sModifiers ) )
{
/* We don't save negative preferences (eg. "no reverse"). If the theme
* sets a default of "reverse", and the player turns it off, we should
* set it off. However, don't reset modifiers that aren't saved by the
* profile, so we don't ignore unsaved modifiers when a profile is in use. */
PO_GROUP_CALL ( m_pPlayerState [ pn ] - > m_PlayerOptions , ModsLevel_Preferred , ResetSavedPrefs ) ;
ApplyPreferredModifiers ( pn , sModifiers ) ;
}
// Only set the sort order if it wasn't already set by a GameCommand (or by an earlier profile)
if ( m_PreferredSortOrder = = SortOrder_Invalid & & pProfile - > m_SortOrder ! = SortOrder_Invalid )
m_PreferredSortOrder = pProfile - > m_SortOrder ;
if ( pProfile - > m_LastDifficulty ! = Difficulty_Invalid )
m_PreferredDifficulty [ pn ] . Set ( pProfile - > m_LastDifficulty ) ;
if ( pProfile - > m_LastCourseDifficulty ! = Difficulty_Invalid )
m_PreferredCourseDifficulty [ pn ] . Set ( pProfile - > m_LastCourseDifficulty ) ;
// Only set the PreferredStepsType if it wasn't already set by a GameCommand (or by an earlier profile)
if ( m_PreferredStepsType = = StepsType_Invalid & & pProfile - > m_LastStepsType ! = StepsType_Invalid )
m_PreferredStepsType . Set ( pProfile - > m_LastStepsType ) ;
if ( m_pPreferredSong = = NULL )
m_pPreferredSong = pProfile - > m_lastSong . ToSong ( ) ;
if ( m_pPreferredCourse = = NULL )
m_pPreferredCourse = pProfile - > m_lastCourse . ToCourse ( ) ;
}
void GameState : : SaveCurrentSettingsToProfile ( PlayerNumber pn )
{
if ( ! PROFILEMAN - > IsPersistentProfile ( pn ) )
return ;
if ( m_bDemonstrationOrJukebox )
return ;
Profile * pProfile = PROFILEMAN - > GetProfile ( pn ) ;
pProfile - > SetDefaultModifiers ( m_pCurGame , m_pPlayerState [ pn ] - > m_PlayerOptions . GetPreferred ( ) . GetSavedPrefsString ( ) ) ;
if ( IsSongSort ( m_PreferredSortOrder ) )
pProfile - > m_SortOrder = m_PreferredSortOrder ;
if ( m_PreferredDifficulty [ pn ] ! = Difficulty_Invalid )
pProfile - > m_LastDifficulty = m_PreferredDifficulty [ pn ] ;
if ( m_PreferredCourseDifficulty [ pn ] ! = Difficulty_Invalid )
pProfile - > m_LastCourseDifficulty = m_PreferredCourseDifficulty [ pn ] ;
if ( m_PreferredStepsType ! = StepsType_Invalid )
pProfile - > m_LastStepsType = m_PreferredStepsType ;
if ( m_pPreferredSong )
pProfile - > m_lastSong . FromSong ( m_pPreferredSong ) ;
if ( m_pPreferredCourse )
pProfile - > m_lastCourse . FromCourse ( m_pPreferredCourse ) ;
}
2014-12-07 01:53:17 -07:00
bool GameState : : CanSafelyEnterGameplay ( RString & reason )
{
if ( ! IsCourseMode ( ) )
{
Song const * song = m_pCurSong ;
if ( song = = NULL )
{
reason = " Current song is NULL. " ;
return false ;
}
}
else
{
Course const * song = m_pCurCourse ;
if ( song = = NULL )
{
reason = " Current course is NULL. " ;
return false ;
}
}
FOREACH_EnabledPlayer ( pn )
{
Style const * style = GetCurrentStyle ( pn ) ;
if ( style = = NULL )
{
reason = ssprintf ( " Style for player %d is NULL. " , pn + 1 ) ;
return false ;
}
if ( ! IsCourseMode ( ) )
{
Steps const * steps = m_pCurSteps [ pn ] ;
if ( steps = = NULL )
{
reason = ssprintf ( " Steps for player %d is NULL. " , pn + 1 ) ;
return false ;
}
if ( steps - > m_StepsType ! = style - > m_StepsType )
{
reason = ssprintf ( " Player %d StepsType %s for steps does not equal "
" StepsType %s for style. " , pn + 1 ,
GAMEMAN - > GetStepsTypeInfo ( steps - > m_StepsType ) . szName ,
GAMEMAN - > GetStepsTypeInfo ( style - > m_StepsType ) . szName ) ;
return false ;
}
if ( steps - > m_pSong ! = m_pCurSong )
{
reason = ssprintf ( " Steps for player %d are not for the current song. " ,
pn + 1 ) ;
return false ;
}
NoteData ndtemp ;
steps - > GetNoteData ( ndtemp ) ;
if ( ndtemp . GetNumTracks ( ) ! = style - > m_iColsPerPlayer )
{
reason = ssprintf ( " Steps for player %d have %d columns, style has %d "
" columns. " , pn + 1 , ndtemp . GetNumTracks ( ) , style - > m_iColsPerPlayer ) ;
return false ;
}
}
else
{
Trail const * steps = m_pCurTrail [ pn ] ;
if ( steps = = NULL )
{
reason = ssprintf ( " Steps for player %d is NULL. " , pn + 1 ) ;
return false ;
}
if ( steps - > m_StepsType ! = style - > m_StepsType )
{
reason = ssprintf ( " Player %d StepsType %s for steps does not equal "
" StepsType %s for style. " , pn + 1 ,
GAMEMAN - > GetStepsTypeInfo ( steps - > m_StepsType ) . szName ,
GAMEMAN - > GetStepsTypeInfo ( style - > m_StepsType ) . szName ) ;
return false ;
}
}
}
return true ;
}
2011-03-17 01:47:30 -04:00
void GameState : : Update ( float fDelta )
{
m_SongOptions . Update ( fDelta ) ;
FOREACH_PlayerNumber ( p )
{
m_pPlayerState [ p ] - > Update ( fDelta ) ;
if ( ! m_bGoalComplete [ p ] & & IsGoalComplete ( p ) )
{
m_bGoalComplete [ p ] = true ;
MESSAGEMAN - > Broadcast ( ( MessageID ) ( Message_GoalCompleteP1 + p ) ) ;
}
}
if ( GAMESTATE - > m_pCurCourse )
{
if ( GAMESTATE - > m_pCurCourse - > m_fGoalSeconds > 0 & & ! m_bWorkoutGoalComplete )
{
const StageStats & ssCurrent = STATSMAN - > m_CurStageStats ;
bool bGoalComplete = ssCurrent . m_fGameplaySeconds > GAMESTATE - > m_pCurCourse - > m_fGoalSeconds ;
if ( bGoalComplete )
{
MESSAGEMAN - > Broadcast ( " WorkoutGoalComplete " ) ;
m_bWorkoutGoalComplete = true ;
}
}
}
}
void GameState : : SetCurGame ( const Game * pGame )
{
m_pCurGame . Set ( pGame ) ;
RString sGame = pGame ? RString ( pGame - > m_szName ) : RString ( ) ;
PREFSMAN - > SetCurrentGame ( sGame ) ;
}
const float GameState : : MUSIC_SECONDS_INVALID = - 5000.0f ;
void GameState : : ResetMusicStatistics ( )
{
2011-05-10 21:22:01 +07:00
m_Position . Reset ( ) ;
2012-12-17 16:43:31 -08:00
m_LastPositionTimer . Touch ( ) ;
m_LastPositionSeconds = 0.0f ;
2011-05-10 21:22:01 +07:00
2011-03-17 01:47:30 -04:00
Actor : : SetBGMTime ( 0 , 0 , 0 , 0 ) ;
FOREACH_PlayerNumber ( p )
2011-05-10 21:22:01 +07:00
{
2011-03-17 01:47:30 -04:00
m_pPlayerState [ p ] - > ClearHopoState ( ) ;
2011-05-10 21:22:01 +07:00
m_pPlayerState [ p ] - > m_Position . Reset ( ) ;
}
2011-03-17 01:47:30 -04:00
}
void GameState : : ResetStageStatistics ( )
{
2014-02-16 11:43:28 -07:00
StageStats OldStats = STATSMAN - > m_CurStageStats ;
2011-03-17 01:47:30 -04:00
STATSMAN - > m_CurStageStats = StageStats ( ) ;
2014-02-16 11:43:28 -07:00
if ( PREFSMAN - > m_bComboContinuesBetweenSongs )
{
FOREACH_PlayerNumber ( p )
{
bool FirstSong = m_iCurrentStageIndex = = 0 ;
if ( FirstSong )
{
Profile * pProfile = PROFILEMAN - > GetProfile ( p ) ;
STATSMAN - > m_CurStageStats . m_player [ p ] . m_iCurCombo = pProfile - > m_iCurrentCombo ;
}
else
{
STATSMAN - > m_CurStageStats . m_player [ p ] . m_iCurCombo = OldStats . m_player [ p ] . m_iCurCombo ;
}
}
}
2011-03-17 01:47:30 -04:00
RemoveAllActiveAttacks ( ) ;
FOREACH_PlayerNumber ( p )
m_pPlayerState [ p ] - > RemoveAllInventory ( ) ;
m_fOpponentHealthPercent = 1 ;
m_fHasteRate = 0 ;
m_fLastHasteUpdateMusicSeconds = 0 ;
m_fAccumulatedHasteSeconds = 0 ;
m_fTugLifePercentP1 = 0.5f ;
FOREACH_PlayerNumber ( p )
{
m_pPlayerState [ p ] - > m_fSuperMeter = 0 ;
m_pPlayerState [ p ] - > m_HealthState = HealthState_Alive ;
m_pPlayerState [ p ] - > m_iLastPositiveSumOfAttackLevels = 0 ;
m_pPlayerState [ p ] - > m_fSecondsUntilAttacksPhasedOut = 0 ; // PlayerAI not affected
m_bGoalComplete [ p ] = false ;
}
m_bWorkoutGoalComplete = false ;
FOREACH_PlayerNumber ( p )
{
m_vLastStageAwards [ p ] . clear ( ) ;
m_vLastPeakComboAwards [ p ] . clear ( ) ;
}
// Reset the round seed. Do this here and not in FinishStage so that players
// get new shuffle patterns if they Back out of gameplay and play again.
m_iStageSeed = rand ( ) ;
}
2014-07-24 19:45:17 -05:00
void GameState : : UpdateSongPosition ( float fPositionSeconds , const TimingData & timing , const RageTimer & timestamp )
2011-03-17 01:47:30 -04:00
{
2012-12-17 16:43:31 -08:00
/* It's not uncommon to get a lot of duplicated positions from the sound
* driver, like so: 13.120953,13.130975,13.130975,13.130975,13.140998,...
* This causes visual stuttering of the arrows. To compensate, keep a
* RageTimer since the last change. */
if ( fPositionSeconds = = m_LastPositionSeconds )
fPositionSeconds + = m_LastPositionTimer . Ago ( ) ;
else
{
//LOG->Info("Time difference: %+f",
// m_LastPositionTimer.Ago() - (fPositionSeconds - m_LastPositionSeconds)
//);
m_LastPositionTimer . Touch ( ) ;
m_LastPositionSeconds = fPositionSeconds ;
}
2011-05-10 19:54:05 +07:00
m_Position . UpdateSongPosition ( fPositionSeconds , timing , timestamp ) ;
2011-03-17 01:47:30 -04:00
2014-07-24 19:45:17 -05:00
FOREACH_EnabledPlayer ( pn )
2011-05-14 18:17:48 -04:00
{
2014-07-24 19:45:17 -05:00
if ( m_pCurSteps [ pn ] )
2011-05-14 18:17:48 -04:00
{
2014-07-24 19:45:17 -05:00
m_pPlayerState [ pn ] - > m_Position . UpdateSongPosition ( fPositionSeconds , * m_pCurSteps [ pn ] - > GetTimingData ( ) , timestamp ) ;
Actor : : SetPlayerBGMBeat ( pn , m_pPlayerState [ pn ] - > m_Position . m_fSongBeatVisible , m_pPlayerState [ pn ] - > m_Position . m_fSongBeatNoOffset ) ;
2011-05-14 18:17:48 -04:00
}
}
2011-05-11 20:53:40 +07:00
Actor : : SetBGMTime ( GAMESTATE - > m_Position . m_fMusicSecondsVisible , GAMESTATE - > m_Position . m_fSongBeatVisible , fPositionSeconds , GAMESTATE - > m_Position . m_fSongBeatNoOffset ) ;
2011-03-17 01:47:30 -04:00
// LOG->Trace( "m_fMusicSeconds = %f, m_fSongBeat = %f, m_fCurBPS = %f, m_bFreeze = %f", m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
}
/*
update player position code goes here
*/
float GameState : : GetSongPercent ( float beat ) const
{
// 0 = first step; 1 = last step
2011-06-30 01:11:38 -04:00
float curTime = this - > m_pCurSong - > m_SongTiming . GetElapsedTimeFromBeat ( beat ) ;
2011-06-30 02:10:58 -04:00
return ( curTime - m_pCurSong - > GetFirstSecond ( ) ) / m_pCurSong - > GetLastSecond ( ) ;
2011-03-17 01:47:30 -04:00
}
int GameState : : GetNumStagesLeft ( PlayerNumber pn ) const
{
return m_iPlayerStageTokens [ pn ] ;
}
int GameState : : GetSmallestNumStagesLeftForAnyHumanPlayer ( ) const
{
if ( IsEventMode ( ) )
return 999 ;
int iSmallest = INT_MAX ;
FOREACH_HumanPlayer ( p )
iSmallest = min ( iSmallest , m_iPlayerStageTokens [ p ] ) ;
return iSmallest ;
}
bool GameState : : IsFinalStageForAnyHumanPlayer ( ) const
{
return GetSmallestNumStagesLeftForAnyHumanPlayer ( ) = = 1 ;
}
2014-09-07 04:05:10 -06:00
bool GameState : : IsFinalStageForEveryHumanPlayer ( ) const
{
int song_cost = 1 ;
if ( m_pCurSong ! = NULL )
{
if ( m_pCurSong - > IsLong ( ) )
{
song_cost = 2 ;
}
else if ( m_pCurSong - > IsMarathon ( ) )
{
song_cost = 3 ;
}
}
// If we're on gameplay or evaluation, they set this to false because those
// screens have already had the stage tokens subtracted.
song_cost * = m_AdjustTokensBySongCostForFinalStageCheck ;
int num_on_final = 0 ;
int num_humans = 0 ;
FOREACH_HumanPlayer ( p )
{
if ( m_iPlayerStageTokens [ p ] - song_cost < = 0 )
{
+ + num_on_final ;
}
+ + num_humans ;
}
return num_on_final > = num_humans ;
}
2011-03-17 01:47:30 -04:00
bool GameState : : IsAnExtraStage ( ) const
{
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = PlayerNumber_Invalid )
2011-03-17 01:47:30 -04:00
return false ;
2011-06-06 20:40:11 -04:00
return ! IsEventMode ( ) & & ! IsCourseMode ( ) & & m_iAwardedExtraStages [ this - > GetMasterPlayerNumber ( ) ] > 0 ;
2011-03-17 01:47:30 -04:00
}
static ThemeMetric < bool > LOCK_EXTRA_STAGE_SELECTION ( " GameState " , " LockExtraStageSelection " ) ;
bool GameState : : IsAnExtraStageAndSelectionLocked ( ) const
{
return IsAnExtraStage ( ) & & LOCK_EXTRA_STAGE_SELECTION ;
}
bool GameState : : IsExtraStage ( ) const
{
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = PlayerNumber_Invalid )
2011-03-17 01:47:30 -04:00
return false ;
2011-06-06 20:40:11 -04:00
return ! IsEventMode ( ) & & ! IsCourseMode ( ) & & m_iAwardedExtraStages [ this - > GetMasterPlayerNumber ( ) ] = = 1 ;
2011-03-17 01:47:30 -04:00
}
bool GameState : : IsExtraStage2 ( ) const
{
2011-06-06 20:40:11 -04:00
if ( this - > GetMasterPlayerNumber ( ) = = PlayerNumber_Invalid )
2011-03-17 01:47:30 -04:00
return false ;
2011-06-06 20:40:11 -04:00
return ! IsEventMode ( ) & & ! IsCourseMode ( ) & & m_iAwardedExtraStages [ this - > GetMasterPlayerNumber ( ) ] = = 2 ;
2011-03-17 01:47:30 -04:00
}
Stage GameState : : GetCurrentStage ( ) const
{
if ( m_bDemonstrationOrJukebox ) return Stage_Demo ;
// "event" has precedence
else if ( IsEventMode ( ) ) return Stage_Event ;
else if ( m_PlayMode = = PLAY_MODE_ONI ) return Stage_Oni ;
else if ( m_PlayMode = = PLAY_MODE_NONSTOP ) return Stage_Nonstop ;
else if ( m_PlayMode = = PLAY_MODE_ENDLESS ) return Stage_Endless ;
else if ( IsExtraStage ( ) ) return Stage_Extra1 ;
else if ( IsExtraStage2 ( ) ) return Stage_Extra2 ;
2014-09-07 04:05:10 -06:00
// Previous logic did not factor in current song length, or the fact that
// players aren't allowed to start a song with 0 tokens. This new
// function also has logic for handling the Gameplay and Evaluation cases
// which used to require workarounds on the theme side. -Kyz
else if ( IsFinalStageForEveryHumanPlayer ( ) ) return Stage_Final ;
2011-03-17 01:47:30 -04:00
else
{
switch ( this - > m_iCurrentStageIndex )
{
case 0 : return Stage_1st ;
case 1 : return Stage_2nd ;
case 2 : return Stage_3rd ;
case 3 : return Stage_4th ;
case 4 : return Stage_5th ;
case 5 : return Stage_6th ;
default : return Stage_Next ;
}
}
}
int GameState : : GetCourseSongIndex ( ) const
{
// iSongsPlayed includes the current song, so it's 1-based; subtract one.
if ( GAMESTATE - > m_bMultiplayer )
{
FOREACH_EnabledMultiPlayer ( mp )
return STATSMAN - > m_CurStageStats . m_multiPlayer [ mp ] . m_iSongsPlayed - 1 ;
FAIL_M ( " At least one MultiPlayer must be joined. " ) ;
}
else
{
2011-06-06 20:40:11 -04:00
return STATSMAN - > m_CurStageStats . m_player [ this - > GetMasterPlayerNumber ( ) ] . m_iSongsPlayed - 1 ;
2011-03-17 01:47:30 -04:00
}
}
/* Hack: when we're loading a new course song, we want to display the new song
* number, even though we haven't started that song yet. */
int GameState : : GetLoadingCourseSongIndex ( ) const
{
int iIndex = GetCourseSongIndex ( ) ;
if ( m_bLoadingNextSong )
+ + iIndex ;
return iIndex ;
}
static LocalizedString PLAYER1 ( " GameState " , " Player 1 " ) ;
static LocalizedString PLAYER2 ( " GameState " , " Player 2 " ) ;
static LocalizedString CPU ( " GameState " , " CPU " ) ;
RString GameState : : GetPlayerDisplayName ( PlayerNumber pn ) const
{
ASSERT ( IsPlayerEnabled ( pn ) ) ;
const LocalizedString * pDefaultNames [ ] = { & PLAYER1 , & PLAYER2 } ;
if ( IsHumanPlayer ( pn ) )
{
if ( ! PROFILEMAN - > GetPlayerName ( pn ) . empty ( ) )
return PROFILEMAN - > GetPlayerName ( pn ) ;
else
return pDefaultNames [ pn ] - > GetValue ( ) ;
}
else
{
return CPU . GetValue ( ) ;
}
}
bool GameState : : PlayersCanJoin ( ) const
{
2014-12-07 01:53:17 -07:00
bool b = GetNumSidesJoined ( ) = = 0 | | GetCurrentStyle ( PLAYER_INVALID ) = = NULL ; // selecting a style finalizes the players
2011-03-17 01:47:30 -04:00
if ( ALLOW_LATE_JOIN . IsLoaded ( ) & & ALLOW_LATE_JOIN )
{
Screen * pScreen = SCREENMAN - > GetTopScreen ( ) ;
if ( pScreen )
b | = pScreen - > AllowLateJoin ( ) ;
}
return b ;
}
int GameState : : GetNumSidesJoined ( ) const
{
int iNumSidesJoined = 0 ;
FOREACH_PlayerNumber ( p )
if ( m_bSideIsJoined [ p ] )
iNumSidesJoined + + ; // left side, and right side
return iNumSidesJoined ;
}
2014-12-07 01:53:17 -07:00
const Game * GameState : : GetCurrentGame ( ) const
2011-03-17 01:47:30 -04:00
{
ASSERT ( m_pCurGame ! = NULL ) ; // the game must be set before calling this
return m_pCurGame ;
}
2014-12-07 01:53:17 -07:00
const Style * GameState : : GetCurrentStyle ( PlayerNumber pn ) const
2011-03-17 01:47:30 -04:00
{
2014-12-07 01:53:17 -07:00
if ( GetCurrentGame ( ) = = NULL ) { return NULL ; }
if ( ! GetCurrentGame ( ) - > m_PlayersHaveSeparateStyles )
{
return m_pCurStyle ;
}
else
{
if ( pn > = NUM_PLAYERS )
{
return m_SeparatedStyles [ PLAYER_1 ] = = NULL ? m_SeparatedStyles [ PLAYER_2 ]
: m_SeparatedStyles [ PLAYER_1 ] ;
}
return m_SeparatedStyles [ pn ] ;
}
2011-03-17 01:47:30 -04:00
}
2014-12-07 01:53:17 -07:00
void GameState : : SetCurrentStyle ( const Style * style , PlayerNumber pn )
2011-03-17 01:47:30 -04:00
{
2014-12-07 01:53:17 -07:00
if ( ! GetCurrentGame ( ) - > m_PlayersHaveSeparateStyles )
{
m_pCurStyle . Set ( style ) ;
}
else
{
m_SeparatedStyles [ pn ] = style ;
if ( pn = = PLAYER_INVALID )
{
FOREACH_PlayerNumber ( rpn )
{
m_SeparatedStyles [ rpn ] = style ;
}
}
}
if ( INPUTMAPPER )
2011-03-17 01:47:30 -04:00
{
2014-12-07 01:53:17 -07:00
if ( GetCurrentStyle ( pn ) & & GetCurrentStyle ( pn ) - > m_StyleType = = StyleType_OnePlayerTwoSides )
INPUTMAPPER - > SetJoinControllers ( this - > GetMasterPlayerNumber ( ) ) ;
2011-03-17 01:47:30 -04:00
else
2014-12-07 01:53:17 -07:00
INPUTMAPPER - > SetJoinControllers ( PLAYER_INVALID ) ;
2011-03-17 01:47:30 -04:00
}
}
2014-12-07 01:53:17 -07:00
bool GameState : : SetCompatibleStyle ( StepsType stype , PlayerNumber pn )
2014-06-27 20:20:50 -06:00
{
2014-06-27 21:11:34 -06:00
bool style_incompatible = false ;
2014-12-07 01:53:17 -07:00
if ( ! GetCurrentStyle ( pn ) )
2014-06-27 21:11:34 -06:00
{
style_incompatible = true ;
}
else
{
2014-12-07 01:53:17 -07:00
style_incompatible = stype ! = GetCurrentStyle ( pn ) - > m_StepsType ;
2014-06-27 21:11:34 -06:00
}
if ( CommonMetrics : : AUTO_SET_STYLE & & style_incompatible )
2014-06-27 20:20:50 -06:00
{
const Style * compatible_style = GAMEMAN - > GetFirstCompatibleStyle (
m_pCurGame , GetNumSidesJoined ( ) , stype ) ;
if ( ! compatible_style )
{
return false ;
}
2014-12-07 01:53:17 -07:00
SetCurrentStyle ( compatible_style , pn ) ;
2014-06-27 20:20:50 -06:00
}
2014-12-07 01:53:17 -07:00
return stype = = GetCurrentStyle ( pn ) - > m_StepsType ;
2014-06-27 20:20:50 -06:00
}
2011-03-17 01:47:30 -04:00
bool GameState : : IsPlayerEnabled ( PlayerNumber pn ) const
{
// In rave, all players are present. Non-human players are CPU controlled.
switch ( m_PlayMode )
{
2011-07-20 11:11:04 -04:00
case PLAY_MODE_BATTLE :
case PLAY_MODE_RAVE :
return true ;
default :
return IsHumanPlayer ( pn ) ;
2011-03-17 01:47:30 -04:00
}
}
bool GameState : : IsMultiPlayerEnabled ( MultiPlayer mp ) const
{
return m_MultiPlayerStatus [ mp ] = = MultiPlayerStatus_Joined ;
}
bool GameState : : IsPlayerEnabled ( const PlayerState * pPlayerState ) const
{
if ( pPlayerState - > m_mp ! = MultiPlayer_Invalid )
return IsMultiPlayerEnabled ( pPlayerState - > m_mp ) ;
if ( pPlayerState - > m_PlayerNumber ! = PLAYER_INVALID )
return IsPlayerEnabled ( pPlayerState - > m_PlayerNumber ) ;
return false ;
}
int GameState : : GetNumPlayersEnabled ( ) const
{
int count = 0 ;
FOREACH_EnabledPlayer ( pn )
count + + ;
return count ;
}
bool GameState : : IsHumanPlayer ( PlayerNumber pn ) const
{
if ( pn = = PLAYER_INVALID )
return false ;
2014-12-07 01:53:17 -07:00
if ( GetCurrentStyle ( pn ) = = NULL ) // no style chosen
2011-03-17 01:47:30 -04:00
{
if ( PlayersCanJoin ( ) )
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
}
2014-12-07 01:53:17 -07:00
StyleType type = GetCurrentStyle ( pn ) - > m_StyleType ;
2012-12-27 16:59:35 -05:00
switch ( type )
2011-03-17 01:47:30 -04:00
{
case StyleType_TwoPlayersTwoSides :
case StyleType_TwoPlayersSharedSides :
return true ;
case StyleType_OnePlayerOneSide :
case StyleType_OnePlayerTwoSides :
2011-06-06 20:40:11 -04:00
return pn = = this - > GetMasterPlayerNumber ( ) ;
2011-03-17 01:47:30 -04:00
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( " Invalid style type: %i " , type ) ) ;
2011-03-17 01:47:30 -04:00
}
}
int GameState : : GetNumHumanPlayers ( ) const
{
int count = 0 ;
FOREACH_HumanPlayer ( pn )
count + + ;
return count ;
}
PlayerNumber GameState : : GetFirstHumanPlayer ( ) const
{
FOREACH_HumanPlayer ( pn )
return pn ;
return PLAYER_INVALID ;
}
PlayerNumber GameState : : GetFirstDisabledPlayer ( ) const
{
FOREACH_PlayerNumber ( pn )
if ( ! IsPlayerEnabled ( pn ) )
return pn ;
return PLAYER_INVALID ;
}
bool GameState : : IsCpuPlayer ( PlayerNumber pn ) const
{
return IsPlayerEnabled ( pn ) & & ! IsHumanPlayer ( pn ) ;
}
bool GameState : : AnyPlayersAreCpu ( ) const
{
FOREACH_CpuPlayer ( pn )
return true ;
return false ;
}
bool GameState : : IsCourseMode ( ) const
{
switch ( m_PlayMode )
{
case PLAY_MODE_ONI :
case PLAY_MODE_NONSTOP :
case PLAY_MODE_ENDLESS :
return true ;
default :
return false ;
}
}
bool GameState : : IsBattleMode ( ) const
{
switch ( m_PlayMode )
{
case PLAY_MODE_BATTLE :
return true ;
default :
return false ;
}
}
EarnedExtraStage GameState : : CalculateEarnedExtraStage ( ) const
{
if ( IsEventMode ( ) )
return EarnedExtraStage_No ;
if ( ! PREFSMAN - > m_bAllowExtraStage )
return EarnedExtraStage_No ;
if ( m_PlayMode ! = PLAY_MODE_REGULAR )
return EarnedExtraStage_No ;
if ( m_bBackedOutOfFinalStage )
return EarnedExtraStage_No ;
if ( GetSmallestNumStagesLeftForAnyHumanPlayer ( ) > 0 )
return EarnedExtraStage_No ;
2011-06-06 20:40:11 -04:00
if ( m_iAwardedExtraStages [ this - > GetMasterPlayerNumber ( ) ] > = 2 )
2011-03-17 01:47:30 -04:00
return EarnedExtraStage_No ;
FOREACH_EnabledPlayer ( pn )
{
Difficulty dc = m_pCurSteps [ pn ] - > GetDifficulty ( ) ;
switch ( dc )
{
case Difficulty_Edit :
2011-09-29 22:09:52 -04:00
if ( ! EDIT_ALLOWED_FOR_EXTRA )
continue ; // can't use edit steps
2011-03-17 01:47:30 -04:00
break ;
default :
if ( dc < MIN_DIFFICULTY_FOR_EXTRA )
continue ; // not hard enough!
break ;
}
if ( IsExtraStage ( ) )
{
if ( ALLOW_EXTRA_2 & & STATSMAN - > m_CurStageStats . m_player [ pn ] . GetGrade ( ) < = GRADE_TIER_FOR_EXTRA_2 )
return EarnedExtraStage_Extra2 ;
}
else if ( STATSMAN - > m_CurStageStats . m_player [ pn ] . GetGrade ( ) < = GRADE_TIER_FOR_EXTRA_1 )
{
return EarnedExtraStage_Extra1 ;
}
}
return EarnedExtraStage_No ;
}
PlayerNumber GameState : : GetBestPlayer ( ) const
{
FOREACH_PlayerNumber ( pn )
if ( GetStageResult ( pn ) = = RESULT_WIN )
return pn ;
return PLAYER_INVALID ; // draw
}
StageResult GameState : : GetStageResult ( PlayerNumber pn ) const
{
switch ( m_PlayMode )
{
2011-07-20 11:11:04 -04:00
case PLAY_MODE_BATTLE :
case PLAY_MODE_RAVE :
if ( fabsf ( m_fTugLifePercentP1 - 0.5f ) < 0.0001f )
return RESULT_DRAW ;
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 : FAIL_M ( " Invalid player for battle! Aborting... " ) ; return RESULT_LOSE ;
}
default : break ;
2011-03-17 01:47:30 -04:00
}
StageResult win = RESULT_WIN ;
FOREACH_PlayerNumber ( p )
{
if ( p = = pn )
continue ;
// If anyone did just as well, at best it's a draw.
if ( STATSMAN - > m_CurStageStats . m_player [ p ] . m_iActualDancePoints = = STATSMAN - > m_CurStageStats . m_player [ pn ] . m_iActualDancePoints )
win = RESULT_DRAW ;
// If anyone did better, we lost.
if ( STATSMAN - > m_CurStageStats . m_player [ p ] . m_iActualDancePoints > STATSMAN - > m_CurStageStats . m_player [ pn ] . m_iActualDancePoints )
return RESULT_LOSE ;
}
return win ;
}
void GameState : : GetDefaultPlayerOptions ( PlayerOptions & po )
{
po . Init ( ) ;
po . FromString ( PREFSMAN - > m_sDefaultModifiers ) ;
po . FromString ( CommonMetrics : : DEFAULT_MODIFIERS ) ;
if ( po . m_sNoteSkin . empty ( ) )
po . m_sNoteSkin = CommonMetrics : : DEFAULT_NOTESKIN_NAME ;
}
void GameState : : GetDefaultSongOptions ( SongOptions & so )
{
so . Init ( ) ;
so . FromString ( PREFSMAN - > m_sDefaultModifiers ) ;
so . FromString ( CommonMetrics : : DEFAULT_MODIFIERS ) ;
}
void GameState : : ResetToDefaultSongOptions ( ModsLevel l )
{
SongOptions so ;
GetDefaultSongOptions ( so ) ;
m_SongOptions . Assign ( l , so ) ;
}
void GameState : : ApplyPreferredModifiers ( PlayerNumber pn , RString sModifiers )
{
m_pPlayerState [ pn ] - > m_PlayerOptions . FromString ( ModsLevel_Preferred , sModifiers ) ;
m_SongOptions . FromString ( ModsLevel_Preferred , sModifiers ) ;
}
void GameState : : ApplyStageModifiers ( PlayerNumber pn , RString sModifiers )
{
m_pPlayerState [ pn ] - > m_PlayerOptions . FromString ( ModsLevel_Stage , sModifiers ) ;
m_SongOptions . FromString ( ModsLevel_Stage , sModifiers ) ;
}
void GameState : : ClearStageModifiersIllegalForCourse ( )
{
FOREACH_EnabledPlayer ( pn )
PO_GROUP_CALL ( m_pPlayerState [ pn ] - > m_PlayerOptions , ModsLevel_Stage , ResetSavedPrefsInvalidForCourse ) ;
}
bool GameState : : CurrentOptionsDisqualifyPlayer ( PlayerNumber pn )
{
if ( ! PREFSMAN - > m_bDisqualification )
return false ;
if ( ! IsHumanPlayer ( pn ) )
return false ;
const PlayerOptions & po = m_pPlayerState [ pn ] - > m_PlayerOptions . GetPreferred ( ) ;
// Check the stored player options for disqualify. Don't disqualify because
// of mods that were forced.
if ( IsCourseMode ( ) )
return po . IsEasierForCourseAndTrail ( m_pCurCourse , m_pCurTrail [ pn ] ) ;
else
return po . IsEasierForSongAndSteps ( m_pCurSong , m_pCurSteps [ pn ] , pn ) ;
}
/* reset noteskins (?)
* GameState::ResetNoteSkins()
* GameState::ResetNoteSkinsForPlayer( PlayerNumber pn )
*
*/
void GameState : : GetAllUsedNoteSkins ( vector < RString > & out ) const
{
FOREACH_EnabledPlayer ( pn )
{
out . push_back ( m_pPlayerState [ pn ] - > m_PlayerOptions . GetCurrent ( ) . m_sNoteSkin ) ;
// Add noteskins that are used in courses.
if ( IsCourseMode ( ) )
{
const Trail * pTrail = m_pCurTrail [ pn ] ;
2012-12-27 11:38:53 -05:00
ASSERT ( pTrail ! = NULL ) ;
2011-03-17 01:47:30 -04:00
FOREACH_CONST ( TrailEntry , pTrail - > m_vEntries , e )
{
PlayerOptions po ;
po . FromString ( e - > Modifiers ) ;
if ( ! po . m_sNoteSkin . empty ( ) )
out . push_back ( po . m_sNoteSkin ) ;
}
}
}
// Remove duplicates.
sort ( out . begin ( ) , out . end ( ) ) ;
out . erase ( unique ( out . begin ( ) , out . end ( ) ) , out . end ( ) ) ;
}
void GameState : : RemoveAllActiveAttacks ( ) // called on end of song
{
FOREACH_PlayerNumber ( p )
m_pPlayerState [ p ] - > RemoveActiveAttacks ( ) ;
}
2011-09-21 16:21:23 -06:00
void GameState : : AddStageToPlayer ( PlayerNumber pn )
{
// Add one stage more to player (bonus) -cerbo
+ + m_iPlayerStageTokens [ pn ] ;
}
2011-03-17 01:47:30 -04: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 ) ;
}
2014-05-01 23:23:20 -06:00
FailType GameState : : GetPlayerFailType ( const PlayerState * pPlayerState ) const
2011-03-17 01:47:30 -04:00
{
PlayerNumber pn = pPlayerState - > m_PlayerNumber ;
2014-05-01 23:23:20 -06:00
FailType ft = pPlayerState - > m_PlayerOptions . GetCurrent ( ) . m_FailType ;
2011-03-17 01:47:30 -04:00
// If the player changed the fail mode explicitly, leave it alone.
2014-06-20 13:54:56 -06:00
if ( m_bFailTypeWasExplicitlySet )
2011-03-17 01:47:30 -04:00
return ft ;
if ( IsCourseMode ( ) )
{
if ( PREFSMAN - > m_bMinimum1FullSongInCourses & & GetCourseSongIndex ( ) = = 0 )
2014-05-01 23:23:20 -06:00
ft = max ( ft , FailType_ImmediateContinue ) ; // take the least harsh of the two FailTypes
2011-03-17 01:47:30 -04:00
}
else
{
Difficulty dc = Difficulty_Invalid ;
if ( m_pCurSteps [ pn ] )
dc = m_pCurSteps [ pn ] - > GetDifficulty ( ) ;
bool bFirstStage = false ;
if ( ! IsEventMode ( ) )
bFirstStage | = m_iPlayerStageTokens [ pPlayerState - > m_PlayerNumber ] = = PREFSMAN - > m_iSongsPerPlay - 1 ; // HACK; -1 because this is called during gameplay
// Easy and beginner are never harder than FAIL_IMMEDIATE_CONTINUE.
if ( dc < = Difficulty_Easy )
2014-05-01 23:23:20 -06:00
setmax ( ft , FailType_ImmediateContinue ) ;
2011-03-17 01:47:30 -04:00
if ( dc < = Difficulty_Easy & & bFirstStage & & PREFSMAN - > m_bFailOffForFirstStageEasy )
2014-05-01 23:23:20 -06:00
setmax ( ft , FailType_Off ) ;
2011-03-17 01:47:30 -04:00
/* If beginner's steps were chosen, and this is the first stage,
* turn off failure completely. */
if ( dc = = Difficulty_Beginner & & bFirstStage )
2014-05-01 23:23:20 -06:00
setmax ( ft , FailType_Off ) ;
2011-03-17 01:47:30 -04:00
if ( dc = = Difficulty_Beginner & & PREFSMAN - > m_bFailOffInBeginner )
2014-05-01 23:23:20 -06:00
setmax ( ft , FailType_Off ) ;
2011-03-17 01:47:30 -04:00
}
return ft ;
}
bool GameState : : ShowW1 ( ) const
{
2012-12-27 16:59:35 -05:00
AllowW1 pref = PREFSMAN - > m_AllowW1 ;
switch ( pref )
2011-03-17 01:47:30 -04:00
{
case ALLOW_W1_NEVER : return false ;
case ALLOW_W1_COURSES_ONLY : return IsCourseMode ( ) ;
case ALLOW_W1_EVERYWHERE : return true ;
2012-12-27 16:59:35 -05:00
default :
FAIL_M ( ssprintf ( " Invalid AllowW1 preference: %i " , pref ) ) ;
2011-03-17 01:47:30 -04:00
}
}
static ThemeMetric < bool > PROFILE_RECORD_FEATS ( " GameState " , " ProfileRecordFeats " ) ;
static ThemeMetric < bool > CATEGORY_RECORD_FEATS ( " GameState " , " CategoryRecordFeats " ) ;
void GameState : : GetRankingFeats ( PlayerNumber pn , vector < RankingFeat > & asFeatsOut ) const
{
if ( ! IsHumanPlayer ( pn ) )
return ;
Profile * pProf = PROFILEMAN - > GetProfile ( pn ) ;
// Check for feats even if the PlayMode is rave or battle because the player
// may have made high scores then switched modes.
CHECKPOINT_M ( ssprintf ( " PlayMode %i " , int ( m_PlayMode ) ) ) ;
switch ( m_PlayMode )
{
case PLAY_MODE_REGULAR :
case PLAY_MODE_BATTLE :
case PLAY_MODE_RAVE :
{
CHECKPOINT ;
2014-12-07 01:53:17 -07:00
StepsType st = GetCurrentStyle ( pn ) - > m_StepsType ;
2011-03-17 01:47:30 -04: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 ;
for ( unsigned i = 0 ; i < STATSMAN - > m_vPlayedStageStats . size ( ) ; i + + )
{
CHECKPOINT_M ( ssprintf ( " %u/%i " , i , ( int ) STATSMAN - > m_vPlayedStageStats . size ( ) ) ) ;
SongAndSteps sas ;
ASSERT ( ! STATSMAN - > m_vPlayedStageStats [ i ] . m_vpPlayedSongs . empty ( ) ) ;
sas . pSong = STATSMAN - > m_vPlayedStageStats [ i ] . m_vpPlayedSongs [ 0 ] ;
2012-12-27 11:38:53 -05:00
ASSERT ( sas . pSong ! = NULL ) ;
2011-03-17 01:47:30 -04:00
if ( STATSMAN - > m_vPlayedStageStats [ i ] . m_player [ pn ] . m_vpPossibleSteps . empty ( ) )
continue ;
sas . pSteps = STATSMAN - > m_vPlayedStageStats [ i ] . m_player [ pn ] . m_vpPossibleSteps [ 0 ] ;
2012-12-27 11:38:53 -05:00
ASSERT ( sas . pSteps ! = NULL ) ;
2011-03-17 01:47:30 -04:00
vSongAndSteps . push_back ( sas ) ;
}
CHECKPOINT ;
sort ( vSongAndSteps . begin ( ) , vSongAndSteps . end ( ) ) ;
vector < SongAndSteps > : : iterator toDelete = unique ( vSongAndSteps . begin ( ) , vSongAndSteps . end ( ) ) ;
vSongAndSteps . erase ( toDelete , vSongAndSteps . end ( ) ) ;
CHECKPOINT ;
for ( unsigned i = 0 ; i < vSongAndSteps . size ( ) ; i + + )
{
Song * pSong = vSongAndSteps [ i ] . pSong ;
Steps * pSteps = vSongAndSteps [ i ] . pSteps ;
// Find Machine Records
{
HighScoreList & hsl = PROFILEMAN - > GetMachineProfile ( ) - > GetStepsHighScoreList ( pSong , pSteps ) ;
for ( unsigned j = 0 ; j < hsl . vHighScores . size ( ) ; j + + )
{
HighScore & hs = hsl . vHighScores [ j ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . Type = RankingFeat : : SONG ;
feat . pSong = pSong ;
feat . pSteps = pSteps ;
feat . Feat = ssprintf ( " MR #%d in %s %s " , j + 1 , pSong - > GetTranslitMainTitle ( ) . c_str ( ) , DifficultyToString ( pSteps - > GetDifficulty ( ) ) . c_str ( ) ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = hs . GetGrade ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
feat . iScore = hs . GetScore ( ) ;
if ( pSong - > HasBanner ( ) )
feat . Banner = pSong - > GetBannerPath ( ) ;
asFeatsOut . push_back ( feat ) ;
}
}
// Find Personal Records
if ( pProf & & PROFILE_RECORD_FEATS )
{
HighScoreList & hsl = pProf - > GetStepsHighScoreList ( pSong , pSteps ) ;
for ( unsigned j = 0 ; j < hsl . vHighScores . size ( ) ; j + + )
{
HighScore & hs = hsl . vHighScores [ j ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . pSong = pSong ;
feat . pSteps = pSteps ;
feat . Type = RankingFeat : : SONG ;
feat . Feat = ssprintf ( " PR #%d in %s %s " , j + 1 , pSong - > GetTranslitMainTitle ( ) . c_str ( ) , DifficultyToString ( pSteps - > GetDifficulty ( ) ) . c_str ( ) ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = hs . GetGrade ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
feat . iScore = hs . GetScore ( ) ;
// XXX: temporary hack
// Why is this here? -aj
if ( pSong - > HasBackground ( ) )
feat . Banner = pSong - > GetBackgroundPath ( ) ;
// if( pSong->HasBanner() )
// feat.Banner = pSong->GetBannerPath();
asFeatsOut . push_back ( feat ) ;
}
}
}
CHECKPOINT ;
StageStats stats ;
STATSMAN - > GetFinalEvalStageStats ( stats ) ;
// Find Machine Category Records
FOREACH_ENUM ( RankingCategory , rc )
{
if ( ! CATEGORY_RECORD_FEATS )
continue ;
HighScoreList & hsl = PROFILEMAN - > GetMachineProfile ( ) - > GetCategoryHighScoreList ( st , rc ) ;
for ( unsigned j = 0 ; j < hsl . vHighScores . size ( ) ; j + + )
{
HighScore & hs = hsl . vHighScores [ j ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . Type = RankingFeat : : CATEGORY ;
feat . Feat = ssprintf ( " MR #%d in Type %c (%d) " , j + 1 , ' A ' + rc , stats . GetAverageMeter ( pn ) ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = Grade_NoData ;
feat . iScore = hs . GetScore ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
asFeatsOut . push_back ( feat ) ;
}
}
// Find Personal Category Records
FOREACH_ENUM ( RankingCategory , rc )
{
if ( ! CATEGORY_RECORD_FEATS )
continue ;
if ( pProf & & PROFILE_RECORD_FEATS )
{
HighScoreList & hsl = pProf - > GetCategoryHighScoreList ( st , rc ) ;
for ( unsigned j = 0 ; j < hsl . vHighScores . size ( ) ; j + + )
{
HighScore & hs = hsl . vHighScores [ j ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . Type = RankingFeat : : CATEGORY ;
feat . Feat = ssprintf ( " PR #%d in Type %c (%d) " , j + 1 , ' A ' + rc , stats . GetAverageMeter ( pn ) ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = Grade_NoData ;
feat . iScore = hs . GetScore ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
asFeatsOut . push_back ( feat ) ;
}
}
}
}
break ;
case PLAY_MODE_NONSTOP :
case PLAY_MODE_ONI :
case PLAY_MODE_ENDLESS :
{
CHECKPOINT ;
Course * pCourse = m_pCurCourse ;
2012-12-27 11:38:53 -05:00
ASSERT ( pCourse ! = NULL ) ;
2011-03-17 01:47:30 -04:00
Trail * pTrail = m_pCurTrail [ pn ] ;
2012-12-27 11:38:53 -05:00
ASSERT ( pTrail ! = NULL ) ;
2011-03-17 01:47:30 -04:00
CourseDifficulty cd = pTrail - > m_CourseDifficulty ;
// Find Machine Records
{
Profile * pProfile = PROFILEMAN - > GetMachineProfile ( ) ;
HighScoreList & hsl = pProfile - > GetCourseHighScoreList ( pCourse , pTrail ) ;
for ( unsigned i = 0 ; i < hsl . vHighScores . size ( ) ; i + + )
{
HighScore & hs = hsl . vHighScores [ i ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . Type = RankingFeat : : COURSE ;
feat . pCourse = pCourse ;
feat . Feat = ssprintf ( " MR #%d in %s " , i + 1 , pCourse - > GetDisplayFullTitle ( ) . c_str ( ) ) ;
if ( cd ! = Difficulty_Medium )
feat . Feat + = " " + CourseDifficultyToLocalizedString ( cd ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = Grade_NoData ;
feat . iScore = hs . GetScore ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
if ( pCourse - > HasBanner ( ) )
feat . Banner = pCourse - > GetBannerPath ( ) ;
asFeatsOut . push_back ( feat ) ;
}
}
// Find Personal Records
if ( PROFILE_RECORD_FEATS & & PROFILEMAN - > IsPersistentProfile ( pn ) )
{
HighScoreList & hsl = pProf - > GetCourseHighScoreList ( pCourse , pTrail ) ;
for ( unsigned i = 0 ; i < hsl . vHighScores . size ( ) ; i + + )
{
HighScore & hs = hsl . vHighScores [ i ] ;
if ( hs . GetName ( ) ! = RANKING_TO_FILL_IN_MARKER [ pn ] )
continue ;
RankingFeat feat ;
feat . Type = RankingFeat : : COURSE ;
feat . pCourse = pCourse ;
feat . Feat = ssprintf ( " PR #%d in %s " , i + 1 , pCourse - > GetDisplayFullTitle ( ) . c_str ( ) ) ;
feat . pStringToFill = hs . GetNameMutable ( ) ;
feat . grade = Grade_NoData ;
feat . iScore = hs . GetScore ( ) ;
feat . fPercentDP = hs . GetPercentDP ( ) ;
if ( pCourse - > HasBanner ( ) )
feat . Banner = pCourse - > GetBannerPath ( ) ;
asFeatsOut . push_back ( feat ) ;
}
}
}
break ;
default :
2013-01-03 03:17:30 -06:00
FAIL_M ( ssprintf ( " Invalid play mode: %i " , int ( m_PlayMode ) ) ) ;
2011-03-17 01:47:30 -04:00
}
}
bool GameState : : AnyPlayerHasRankingFeats ( ) const
{
vector < RankingFeat > vFeats ;
FOREACH_PlayerNumber ( p )
{
GetRankingFeats ( p , vFeats ) ;
if ( ! vFeats . empty ( ) )
return true ;
}
return false ;
}
void GameState : : StoreRankingName ( PlayerNumber pn , RString sName )
{
2014-05-12 22:01:22 -06:00
// The theme can upper it if desired. -Kyz
// sName.MakeUpper();
2011-03-17 01:47:30 -04:00
if ( USE_NAME_BLACKLIST )
{
RageFile file ;
if ( file . Open ( NAME_BLACKLIST_FILE ) )
{
RString sLine ;
while ( ! file . AtEOF ( ) )
{
if ( file . GetLine ( sLine ) = = - 1 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " Error reading \" %s \" : %s " , NAME_BLACKLIST_FILE , file . GetError ( ) . c_str ( ) ) ;
2011-03-17 01:47:30 -04:00
break ;
}
sLine . MakeUpper ( ) ;
if ( ! sLine . empty ( ) & & sName . find ( sLine ) ! = string : : npos ) // name contains a bad word
{
LOG - > Trace ( " entered '%s' matches blacklisted item '%s' " , sName . c_str ( ) , sLine . c_str ( ) ) ;
sName = " " ;
break ;
}
}
}
}
vector < RankingFeat > aFeats ;
GetRankingFeats ( pn , aFeats ) ;
for ( unsigned i = 0 ; i < aFeats . size ( ) ; i + + )
{
* aFeats [ i ] . pStringToFill = sName ;
// save name pointers as we fill them
m_vpsNamesThatWereFilled . push_back ( aFeats [ i ] . pStringToFill ) ;
}
Profile * pProfile = PROFILEMAN - > GetMachineProfile ( ) ;
if ( ! PREFSMAN - > m_bAllowMultipleHighScoreWithSameName )
{
// erase all but the highest score for each name
FOREACHM ( SongID , Profile : : HighScoresForASong , pProfile - > m_SongHighScores , iter )
FOREACHM ( StepsID , Profile : : HighScoresForASteps , iter - > second . m_StepsHighScores , iter2 )
iter2 - > second . hsl . RemoveAllButOneOfEachName ( ) ;
FOREACHM ( CourseID , Profile : : HighScoresForACourse , pProfile - > m_CourseHighScores , iter )
FOREACHM ( TrailID , Profile : : HighScoresForATrail , iter - > second . m_TrailHighScores , iter2 )
iter2 - > second . hsl . RemoveAllButOneOfEachName ( ) ;
}
// clamp high score sizes
FOREACHM ( SongID , Profile : : HighScoresForASong , pProfile - > m_SongHighScores , iter )
FOREACHM ( StepsID , Profile : : HighScoresForASteps , iter - > second . m_StepsHighScores , iter2 )
iter2 - > second . hsl . ClampSize ( true ) ;
FOREACHM ( CourseID , Profile : : HighScoresForACourse , pProfile - > m_CourseHighScores , iter )
FOREACHM ( TrailID , Profile : : HighScoresForATrail , iter - > second . m_TrailHighScores , iter2 )
iter2 - > second . hsl . ClampSize ( true ) ;
}
bool GameState : : AllAreInDangerOrWorse ( ) const
{
FOREACH_EnabledPlayer ( p )
if ( m_pPlayerState [ p ] - > m_HealthState < HealthState_Danger )
return false ;
return true ;
}
bool GameState : : OneIsHot ( ) const
{
FOREACH_EnabledPlayer ( p )
if ( m_pPlayerState [ p ] - > m_HealthState = = HealthState_Hot )
return true ;
return false ;
}
bool GameState : : IsTimeToPlayAttractSounds ( ) const
{
// m_iNumTimesThroughAttract will be -1 from the first attract screen after
// the end of a game until the next time FIRST_ATTRACT_SCREEN is reached.
// Play attract sounds for this sort span of time regardless of
// m_AttractSoundFrequency because it's awkward to have the machine go
// silent immediately after the end of a game.
if ( m_iNumTimesThroughAttract = = - 1 )
return true ;
if ( PREFSMAN - > m_AttractSoundFrequency = = ASF_NEVER )
return false ;
// play attract sounds once every m_iAttractSoundFrequency times through
if ( ( m_iNumTimesThroughAttract % PREFSMAN - > m_AttractSoundFrequency ) = = 0 )
return true ;
return false ;
}
void GameState : : VisitAttractScreen ( const RString sScreenName )
{
if ( sScreenName = = CommonMetrics : : FIRST_ATTRACT_SCREEN . GetValue ( ) )
m_iNumTimesThroughAttract + + ;
}
bool GameState : : DifficultiesLocked ( ) const
{
if ( m_PlayMode = = PLAY_MODE_RAVE )
return true ;
if ( IsCourseMode ( ) )
return PREFSMAN - > m_bLockCourseDifficulties ;
2014-12-07 01:53:17 -07:00
if ( GetCurrentStyle ( PLAYER_INVALID ) - > m_bLockDifficulties )
2011-03-17 01:47:30 -04:00
return true ;
return false ;
}
bool GameState : : ChangePreferredDifficultyAndStepsType ( PlayerNumber pn , Difficulty dc , StepsType st )
{
m_PreferredDifficulty [ pn ] . Set ( dc ) ;
m_PreferredStepsType . Set ( st ) ;
if ( DifficultiesLocked ( ) )
FOREACH_PlayerNumber ( p )
if ( p ! = pn )
m_PreferredDifficulty [ p ] . Set ( m_PreferredDifficulty [ pn ] ) ;
return true ;
}
/* When only displaying difficulties in DIFFICULTIES_TO_SHOW, use GetClosestShownDifficulty
* to find which difficulty to show, and ChangePreferredDifficulty(pn, dir) to change
* difficulty. */
bool GameState : : ChangePreferredDifficulty ( PlayerNumber pn , int dir )
{
const vector < Difficulty > & v = CommonMetrics : : DIFFICULTIES_TO_SHOW . GetValue ( ) ;
Difficulty d = GetClosestShownDifficulty ( pn ) ;
while ( 1 )
{
d = enum_add2 ( d , dir ) ;
if ( d < 0 | | d > = NUM_Difficulty )
return false ;
if ( find ( v . begin ( ) , v . end ( ) , d ) ! = v . end ( ) )
break ; // found
}
m_PreferredDifficulty [ pn ] . Set ( d ) ;
return true ;
}
/* The user may be set to prefer a difficulty that isn't always shown; typically,
* Difficulty_Edit. Return the closest shown difficulty <= m_PreferredDifficulty. */
Difficulty GameState : : GetClosestShownDifficulty ( PlayerNumber pn ) const
{
const vector < Difficulty > & v = CommonMetrics : : DIFFICULTIES_TO_SHOW . GetValue ( ) ;
Difficulty iClosest = ( Difficulty ) 0 ;
int iClosestDist = - 1 ;
FOREACH_CONST ( Difficulty , v , dc )
{
int iDist = m_PreferredDifficulty [ pn ] - * dc ;
if ( iDist < 0 )
continue ;
if ( iClosestDist ! = - 1 & & iDist > iClosestDist )
continue ;
iClosestDist = iDist ;
iClosest = * dc ;
}
return iClosest ;
}
bool GameState : : ChangePreferredCourseDifficultyAndStepsType ( PlayerNumber pn , CourseDifficulty cd , StepsType st )
{
m_PreferredCourseDifficulty [ pn ] . Set ( cd ) ;
m_PreferredStepsType . Set ( st ) ;
if ( PREFSMAN - > m_bLockCourseDifficulties )
FOREACH_PlayerNumber ( p )
if ( p ! = pn )
m_PreferredCourseDifficulty [ p ] . Set ( m_PreferredCourseDifficulty [ pn ] ) ;
return true ;
}
bool GameState : : ChangePreferredCourseDifficulty ( PlayerNumber pn , int dir )
{
/* If we have a course selected, only choose among difficulties available in the course. */
const Course * pCourse = m_pCurCourse ;
const vector < CourseDifficulty > & v = CommonMetrics : : COURSE_DIFFICULTIES_TO_SHOW . GetValue ( ) ;
CourseDifficulty cd = m_PreferredCourseDifficulty [ pn ] ;
while ( 1 )
{
cd = enum_add2 ( cd , dir ) ;
if ( cd < 0 | | cd > = NUM_Difficulty )
return false ;
if ( find ( v . begin ( ) , v . end ( ) , cd ) = = v . end ( ) )
continue ; /* not available */
2014-12-07 01:53:17 -07:00
if ( ! pCourse | | pCourse - > GetTrail ( GetCurrentStyle ( pn ) - > m_StepsType , cd ) )
2011-03-17 01:47:30 -04:00
break ;
}
return ChangePreferredCourseDifficulty ( pn , cd ) ;
}
bool GameState : : IsCourseDifficultyShown ( CourseDifficulty cd )
{
const vector < CourseDifficulty > & v = CommonMetrics : : COURSE_DIFFICULTIES_TO_SHOW . GetValue ( ) ;
return find ( v . begin ( ) , v . end ( ) , cd ) ! = v . end ( ) ;
}
Difficulty GameState : : GetEasiestStepsDifficulty ( ) const
{
Difficulty dc = Difficulty_Invalid ;
FOREACH_HumanPlayer ( p )
{
if ( m_pCurSteps [ p ] = = NULL )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " GetEasiestStepsDifficulty called but p%i hasn't chosen notes " , p + 1 ) ;
2011-03-17 01:47:30 -04:00
continue ;
}
dc = min ( dc , m_pCurSteps [ p ] - > GetDifficulty ( ) ) ;
}
return dc ;
}
Difficulty GameState : : GetHardestStepsDifficulty ( ) const
{
Difficulty dc = Difficulty_Beginner ;
FOREACH_HumanPlayer ( p )
{
if ( m_pCurSteps [ p ] = = NULL )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " GetHardestStepsDifficulty called but p%i hasn't chosen notes " , p + 1 ) ;
2011-03-17 01:47:30 -04:00
continue ;
}
dc = max ( dc , m_pCurSteps [ p ] - > GetDifficulty ( ) ) ;
}
return dc ;
}
2014-09-10 02:44:49 -06:00
void GameState : : SetNewStageSeed ( )
{
m_iStageSeed = rand ( ) ;
}
2011-03-17 01:47:30 -04:00
bool GameState : : IsEventMode ( ) const
{
return m_bTemporaryEventMode | | PREFSMAN - > m_bEventMode ;
}
CoinMode GameState : : GetCoinMode ( ) const
{
2014-02-02 12:53:26 -06:00
// XXX: Event mode shouldn't be valid if CoinMode_Pay
if ( IsEventMode ( ) & & GamePreferences : : m_CoinMode = = CoinMode_Pay )
return CoinMode_Free ;
else
return GamePreferences : : m_CoinMode ;
2011-03-17 01:47:30 -04:00
}
ThemeMetric < bool > DISABLE_PREMIUM_IN_EVENT_MODE ( " GameState " , " DisablePremiumInEventMode " ) ;
Premium GameState : : GetPremium ( ) const
{
return DISABLE_PREMIUM_IN_EVENT_MODE ? Premium_Off : g_Premium ;
}
float GameState : : GetGoalPercentComplete ( PlayerNumber pn )
{
const Profile * pProfile = PROFILEMAN - > GetProfile ( pn ) ;
const StageStats & ssCurrent = STATSMAN - > m_CurStageStats ;
const PlayerStageStats & pssCurrent = ssCurrent . m_player [ pn ] ;
float fActual = 0 ;
float fGoal = 0 ;
switch ( pProfile - > m_GoalType )
{
case GoalType_Calories :
fActual = pssCurrent . m_fCaloriesBurned ;
fGoal = ( float ) pProfile - > m_iGoalCalories ;
break ;
case GoalType_Time :
fActual = ssCurrent . m_fGameplaySeconds ;
fGoal = ( float ) pProfile - > m_iGoalSeconds ;
break ;
case GoalType_None :
return 0 ; // never complete
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( " Invalid GoalType: %i " , pProfile - > m_GoalType ) ) ;
2011-03-17 01:47:30 -04:00
}
if ( fGoal = = 0 )
return 0 ;
else
return fActual / fGoal ;
}
bool GameState : : PlayerIsUsingModifier ( PlayerNumber pn , const RString & sModifier )
{
PlayerOptions po = m_pPlayerState [ pn ] - > m_PlayerOptions . GetCurrent ( ) ;
SongOptions so = m_SongOptions . GetCurrent ( ) ;
po . FromString ( sModifier ) ;
so . FromString ( sModifier ) ;
return po = = m_pPlayerState [ pn ] - > m_PlayerOptions . GetCurrent ( ) & & so = = m_SongOptions . GetCurrent ( ) ;
}
Profile * GameState : : GetEditLocalProfile ( )
{
if ( m_sEditLocalProfileID . Get ( ) . empty ( ) )
return NULL ;
return PROFILEMAN - > GetLocalProfile ( m_sEditLocalProfileID ) ;
}
PlayerNumber GetNextHumanPlayer ( PlayerNumber pn )
{
for ( enum_add ( pn , 1 ) ; pn < NUM_PLAYERS ; enum_add ( pn , 1 ) )
if ( GAMESTATE - > IsHumanPlayer ( pn ) )
return pn ;
return PLAYER_INVALID ;
}
PlayerNumber GetNextEnabledPlayer ( PlayerNumber pn )
{
for ( enum_add ( pn , 1 ) ; pn < NUM_PLAYERS ; enum_add ( pn , 1 ) )
if ( GAMESTATE - > IsPlayerEnabled ( pn ) )
return pn ;
return PLAYER_INVALID ;
}
PlayerNumber GetNextCpuPlayer ( PlayerNumber pn )
{
for ( enum_add ( pn , 1 ) ; pn < NUM_PLAYERS ; enum_add ( pn , 1 ) )
if ( GAMESTATE - > IsCpuPlayer ( pn ) )
return pn ;
return PLAYER_INVALID ;
}
PlayerNumber GetNextPotentialCpuPlayer ( PlayerNumber pn )
{
for ( enum_add ( pn , 1 ) ; pn < NUM_PLAYERS ; enum_add ( pn , 1 ) )
if ( ! GAMESTATE - > IsHumanPlayer ( pn ) )
return pn ;
return PLAYER_INVALID ;
}
MultiPlayer GetNextEnabledMultiPlayer ( MultiPlayer mp )
{
for ( enum_add ( mp , 1 ) ; mp < NUM_MultiPlayer ; enum_add ( mp , 1 ) )
if ( GAMESTATE - > IsMultiPlayerEnabled ( mp ) )
return mp ;
return MultiPlayer_Invalid ;
}
// lua start
# include "LuaBinding.h"
# include "Game.h"
2014-09-01 19:00:00 -04:00
/** @brief Allow Lua to have access to the GameState. */
2011-03-17 01:47:30 -04:00
class LunaGameState : public Luna < GameState >
{
public :
DEFINE_METHOD ( IsPlayerEnabled , IsPlayerEnabled ( Enum : : Check < PlayerNumber > ( L , 1 ) ) )
DEFINE_METHOD ( IsHumanPlayer , IsHumanPlayer ( Enum : : Check < PlayerNumber > ( L , 1 ) ) )
DEFINE_METHOD ( GetPlayerDisplayName , GetPlayerDisplayName ( Enum : : Check < PlayerNumber > ( L , 1 ) ) )
2011-06-06 20:40:11 -04:00
DEFINE_METHOD ( GetMasterPlayerNumber , GetMasterPlayerNumber ( ) )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetMultiplayer , m_bMultiplayer )
static int SetMultiplayer ( T * p , lua_State * L )
{
p - > m_bMultiplayer = BArg ( 1 ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2011-12-12 18:49:10 -05:00
DEFINE_METHOD ( InStepEditor , m_bInStepEditor ) ;
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetNumMultiplayerNoteFields , m_iNumMultiplayerNoteFields )
DEFINE_METHOD ( ShowW1 , ShowW1 ( ) )
static int SetNumMultiplayerNoteFields ( T * p , lua_State * L )
{
p - > m_iNumMultiplayerNoteFields = IArg ( 1 ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int GetPlayerState ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
p - > m_pPlayerState [ pn ] - > PushSelf ( L ) ;
return 1 ;
}
static int GetMultiPlayerState ( T * p , lua_State * L )
{
MultiPlayer mp = Enum : : Check < MultiPlayer > ( L , 1 ) ;
p - > m_pMultiPlayerState [ mp ] - > PushSelf ( L ) ;
return 1 ;
}
static int ApplyGameCommand ( T * p , lua_State * L )
{
PlayerNumber pn = PLAYER_INVALID ;
2014-02-23 16:41:19 -05:00
if ( lua_gettop ( L ) > = 2 & & ! lua_isnil ( L , 2 ) ) {
// Legacy behavior: if an old-style numerical argument
// is given, decrement it before trying to parse
if ( lua_isnumber ( L , 2 ) ) {
int arg = ( int ) lua_tonumber ( L , 2 ) ;
arg - - ;
LuaHelpers : : Push ( L , arg ) ;
lua_replace ( L , - 2 ) ;
}
2011-03-17 01:47:30 -04:00
pn = Enum : : Check < PlayerNumber > ( L , 2 ) ;
2014-02-23 16:41:19 -05:00
}
2011-03-17 01:47:30 -04:00
p - > ApplyGameCommand ( SArg ( 1 ) , pn ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int GetCurrentSong ( T * p , lua_State * L ) { if ( p - > m_pCurSong ) p - > m_pCurSong - > PushSelf ( L ) ; else lua_pushnil ( L ) ; return 1 ; }
static int SetCurrentSong ( T * p , lua_State * L )
{
if ( lua_isnil ( L , 1 ) ) { p - > m_pCurSong . Set ( NULL ) ; }
else { Song * pS = Luna < Song > : : check ( L , 1 , true ) ; p - > m_pCurSong . Set ( pS ) ; }
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2014-12-07 01:53:17 -07:00
static int CanSafelyEnterGameplay ( T * p , lua_State * L )
{
RString reason ;
bool can = p - > CanSafelyEnterGameplay ( reason ) ;
lua_pushboolean ( L , can ) ;
LuaHelpers : : Push ( L , reason ) ;
return 2 ;
}
static void SetCompatibleStyleOrError ( T * p , lua_State * L , StepsType stype , PlayerNumber pn )
2014-06-27 20:20:50 -06:00
{
2014-12-07 01:53:17 -07:00
if ( ! p - > SetCompatibleStyle ( stype , pn ) )
2014-06-27 20:20:50 -06:00
{
luaL_error ( L , " No compatible style for steps/trail. " ) ;
}
2014-12-07 01:53:17 -07:00
if ( ! p - > GetCurrentStyle ( pn ) )
2014-06-27 20:20:50 -06:00
{
luaL_error ( L , " No style set and AutoSetStyle is false, cannot set steps/trail. " ) ;
}
}
2011-03-17 01:47:30 -04:00
static int GetCurrentSteps ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
Steps * pSteps = p - > m_pCurSteps [ pn ] ;
if ( pSteps ) { pSteps - > PushSelf ( L ) ; }
else { lua_pushnil ( L ) ; }
return 1 ;
}
static int SetCurrentSteps ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
2014-06-27 20:20:50 -06:00
if ( lua_isnil ( L , 2 ) )
{
p - > m_pCurSteps [ pn ] . Set ( NULL ) ;
}
else
{
Steps * pS = Luna < Steps > : : check ( L , 2 ) ;
2014-12-07 01:53:17 -07:00
SetCompatibleStyleOrError ( p , L , pS - > m_StepsType , pn ) ;
2014-06-27 20:20:50 -06:00
p - > m_pCurSteps [ pn ] . Set ( pS ) ;
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int GetCurrentCourse ( T * p , lua_State * L ) { if ( p - > m_pCurCourse ) p - > m_pCurCourse - > PushSelf ( L ) ; else lua_pushnil ( L ) ; return 1 ; }
static int SetCurrentCourse ( T * p , lua_State * L )
{
if ( lua_isnil ( L , 1 ) ) { p - > m_pCurCourse . Set ( NULL ) ; }
else { Course * pC = Luna < Course > : : check ( L , 1 ) ; p - > m_pCurCourse . Set ( pC ) ; }
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int GetCurrentTrail ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
Trail * pTrail = p - > m_pCurTrail [ pn ] ;
if ( pTrail ) { pTrail - > PushSelf ( L ) ; }
else { lua_pushnil ( L ) ; }
return 1 ;
}
static int SetCurrentTrail ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
2014-06-27 20:20:50 -06:00
if ( lua_isnil ( L , 2 ) )
{
p - > m_pCurTrail [ pn ] . Set ( NULL ) ;
}
else
{
Trail * pS = Luna < Trail > : : check ( L , 2 ) ;
2014-12-07 01:53:17 -07:00
SetCompatibleStyleOrError ( p , L , pS - > m_StepsType , pn ) ;
2014-06-27 20:20:50 -06:00
p - > m_pCurTrail [ pn ] . Set ( pS ) ;
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int GetPreferredSong ( T * p , lua_State * L ) { if ( p - > m_pPreferredSong ) p - > m_pPreferredSong - > PushSelf ( L ) ; else lua_pushnil ( L ) ; return 1 ; }
static int SetPreferredSong ( T * p , lua_State * L )
{
if ( lua_isnil ( L , 1 ) ) { p - > m_pPreferredSong = NULL ; }
else { Song * pS = Luna < Song > : : check ( L , 1 ) ; p - > m_pPreferredSong = pS ; }
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2014-12-01 22:31:30 -07:00
static int SetTemporaryEventMode ( T * p , lua_State * L ) { p - > m_bTemporaryEventMode = BArg ( 1 ) ; COMMON_RETURN_SELF ; }
2011-03-17 01:47:30 -04:00
static int Env ( T * p , lua_State * L ) { p - > m_Environment - > PushSelf ( L ) ; return 1 ; }
static int GetEditSourceSteps ( T * p , lua_State * L )
{
Steps * pSteps = p - > m_pEditSourceSteps ;
if ( pSteps ) { pSteps - > PushSelf ( L ) ; }
else { lua_pushnil ( L ) ; }
return 1 ;
}
static int SetPreferredDifficulty ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
Difficulty dc = Enum : : Check < Difficulty > ( L , 2 ) ;
p - > m_PreferredDifficulty [ pn ] . Set ( dc ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
DEFINE_METHOD ( GetPreferredDifficulty , m_PreferredDifficulty [ Enum : : Check < PlayerNumber > ( L , 1 ) ] )
DEFINE_METHOD ( AnyPlayerHasRankingFeats , AnyPlayerHasRankingFeats ( ) )
DEFINE_METHOD ( IsCourseMode , IsCourseMode ( ) )
DEFINE_METHOD ( IsBattleMode , IsBattleMode ( ) )
DEFINE_METHOD ( IsDemonstration , m_bDemonstrationOrJukebox )
DEFINE_METHOD ( GetPlayMode , m_PlayMode )
DEFINE_METHOD ( GetSortOrder , m_SortOrder )
DEFINE_METHOD ( GetCurrentStageIndex , m_iCurrentStageIndex )
DEFINE_METHOD ( IsGoalComplete , IsGoalComplete ( Enum : : Check < PlayerNumber > ( L , 1 ) ) )
DEFINE_METHOD ( PlayerIsUsingModifier , PlayerIsUsingModifier ( Enum : : Check < PlayerNumber > ( L , 1 ) , SArg ( 2 ) ) )
DEFINE_METHOD ( GetCourseSongIndex , GetCourseSongIndex ( ) )
DEFINE_METHOD ( GetLoadingCourseSongIndex , GetLoadingCourseSongIndex ( ) )
DEFINE_METHOD ( GetSmallestNumStagesLeftForAnyHumanPlayer , GetSmallestNumStagesLeftForAnyHumanPlayer ( ) )
DEFINE_METHOD ( IsAnExtraStage , IsAnExtraStage ( ) )
DEFINE_METHOD ( IsExtraStage , IsExtraStage ( ) )
DEFINE_METHOD ( IsExtraStage2 , IsExtraStage2 ( ) )
DEFINE_METHOD ( GetCurrentStage , GetCurrentStage ( ) )
DEFINE_METHOD ( HasEarnedExtraStage , HasEarnedExtraStage ( ) )
2011-09-07 23:48:04 -05:00
DEFINE_METHOD ( GetEarnedExtraStage , GetEarnedExtraStage ( ) )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetEasiestStepsDifficulty , GetEasiestStepsDifficulty ( ) )
DEFINE_METHOD ( GetHardestStepsDifficulty , GetHardestStepsDifficulty ( ) )
DEFINE_METHOD ( IsEventMode , IsEventMode ( ) )
DEFINE_METHOD ( GetNumPlayersEnabled , GetNumPlayersEnabled ( ) )
2011-05-15 08:21:16 -05:00
/*DEFINE_METHOD( GetSongBeat, m_Position.m_fSongBeat )
2011-05-11 20:53:40 +07:00
DEFINE_METHOD( GetSongBeatVisible, m_Position.m_fSongBeatVisible )
2011-05-10 14:53:59 -04:00
DEFINE_METHOD( GetSongBPS, m_Position.m_fCurBPS )
DEFINE_METHOD( GetSongFreeze, m_Position.m_bFreeze )
2011-05-15 08:21:16 -05:00
DEFINE_METHOD( GetSongDelay, m_Position.m_bDelay )*/
2011-05-15 13:34:01 -05:00
static int GetSongPosition ( T * p , lua_State * L )
{
p - > m_Position . PushSelf ( L ) ;
return 1 ;
}
2014-09-12 15:07:46 -06:00
DEFINE_METHOD ( GetLastGameplayDuration , m_DanceDuration )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetGameplayLeadIn , m_bGameplayLeadIn )
2013-06-04 23:47:22 -04:00
DEFINE_METHOD ( GetCoins , m_iCoins )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( IsSideJoined , m_bSideIsJoined [ Enum : : Check < PlayerNumber > ( L , 1 ) ] )
2013-06-04 23:47:22 -04:00
DEFINE_METHOD ( GetCoinsNeededToJoin , GetCoinsNeededToJoin ( ) )
DEFINE_METHOD ( EnoughCreditsToJoin , EnoughCreditsToJoin ( ) )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( PlayersCanJoin , PlayersCanJoin ( ) )
DEFINE_METHOD ( GetNumSidesJoined , GetNumSidesJoined ( ) )
DEFINE_METHOD ( GetCoinMode , GetCoinMode ( ) )
DEFINE_METHOD ( GetPremium , GetPremium ( ) )
DEFINE_METHOD ( GetSongOptionsString , m_SongOptions . GetCurrent ( ) . GetString ( ) )
static int GetSongOptions ( T * p , lua_State * L )
{
ModsLevel m = Enum : : Check < ModsLevel > ( L , 1 ) ;
RString s = p - > m_SongOptions . Get ( m ) . GetString ( ) ;
LuaHelpers : : Push ( L , s ) ;
return 1 ;
}
2014-05-03 19:27:32 -06:00
static int GetSongOptionsObject ( T * p , lua_State * L )
{
ModsLevel m = Enum : : Check < ModsLevel > ( L , 1 ) ;
p - > m_SongOptions . Get ( m ) . PushSelf ( L ) ;
return 1 ;
}
2011-03-17 01:47:30 -04:00
static int GetDefaultSongOptions ( T * p , lua_State * L )
{
SongOptions so ;
p - > GetDefaultSongOptions ( so ) ;
lua_pushstring ( L , so . GetString ( ) ) ;
return 1 ;
}
2014-12-09 21:59:01 -07:00
static int ApplyPreferredSongOptionsToOtherLevels ( T * p , lua_State * L )
{
p - > m_SongOptions . Assign ( ModsLevel_Preferred ,
p - > m_SongOptions . Get ( ModsLevel_Preferred ) ) ;
return 0 ;
}
2011-09-30 14:50:18 -05:00
static int ApplyStageModifiers ( T * p , lua_State * L )
{
p - > ApplyStageModifiers ( Enum : : Check < PlayerNumber > ( L , 1 ) , SArg ( 2 ) ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-09-30 14:50:18 -05:00
}
2011-09-30 13:44:05 -05:00
static int ApplyPreferredModifiers ( T * p , lua_State * L )
{
p - > ApplyPreferredModifiers ( Enum : : Check < PlayerNumber > ( L , 1 ) , SArg ( 2 ) ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-09-30 13:44:05 -05:00
}
2011-03-17 01:47:30 -04:00
static int ClearStageModifiersIllegalForCourse ( T * p , lua_State * L )
{
p - > ClearStageModifiersIllegalForCourse ( ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
static int SetSongOptions ( T * p , lua_State * L )
{
ModsLevel m = Enum : : Check < ModsLevel > ( L , 1 ) ;
SongOptions so ;
so . FromString ( SArg ( 2 ) ) ;
p - > m_SongOptions . Assign ( m , so ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2012-03-28 18:55:17 -05:00
static int GetStageResult ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
LuaHelpers : : Push ( L , p - > GetStageResult ( pn ) ) ;
return 1 ;
}
2011-03-17 01:47:30 -04:00
static int IsWinner ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
lua_pushboolean ( L , p - > GetStageResult ( pn ) = = RESULT_WIN ) ; return 1 ;
}
static int IsDraw ( T * p , lua_State * L )
{
lua_pushboolean ( L , p - > GetStageResult ( PLAYER_1 ) = = RESULT_DRAW ) ; return 1 ;
}
static int GetCurrentGame ( T * p , lua_State * L ) { const_cast < Game * > ( p - > GetCurrentGame ( ) ) - > PushSelf ( L ) ; return 1 ; }
DEFINE_METHOD ( GetEditCourseEntryIndex , m_iEditCourseEntryIndex )
DEFINE_METHOD ( GetEditLocalProfileID , m_sEditLocalProfileID . Get ( ) )
static int GetEditLocalProfile ( T * p , lua_State * L )
{
Profile * pProfile = p - > GetEditLocalProfile ( ) ;
if ( pProfile )
pProfile - > PushSelf ( L ) ;
else
lua_pushnil ( L ) ;
return 1 ;
}
static int GetCurrentStepsCredits ( T * t , lua_State * L )
{
const Song * pSong = t - > m_pCurSong ;
if ( pSong = = NULL )
return 0 ;
// use a vector and not a set so that ordering is maintained
vector < const Steps * > vpStepsToShow ;
FOREACH_HumanPlayer ( p )
{
const Steps * pSteps = GAMESTATE - > m_pCurSteps [ p ] ;
if ( pSteps = = NULL )
return 0 ;
bool bAlreadyAdded = find ( vpStepsToShow . begin ( ) , vpStepsToShow . end ( ) , pSteps ) ! = vpStepsToShow . end ( ) ;
if ( ! bAlreadyAdded )
vpStepsToShow . push_back ( pSteps ) ;
}
for ( unsigned i = 0 ; i < vpStepsToShow . size ( ) ; i + + )
{
const Steps * pSteps = vpStepsToShow [ i ] ;
RString sDifficulty = CustomDifficultyToLocalizedString ( GetCustomDifficulty ( pSteps - > m_StepsType , pSteps - > GetDifficulty ( ) , CourseType_Invalid ) ) ;
lua_pushstring ( L , sDifficulty ) ;
lua_pushstring ( L , pSteps - > GetDescription ( ) ) ;
}
return vpStepsToShow . size ( ) * 2 ;
}
2014-12-01 22:31:30 -07:00
static int SetPreferredSongGroup ( T * p , lua_State * L ) { p - > m_sPreferredSongGroup . Set ( SArg ( 1 ) ) ; COMMON_RETURN_SELF ; }
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetPreferredSongGroup , m_sPreferredSongGroup . Get ( ) ) ;
static int GetHumanPlayers ( T * p , lua_State * L )
{
vector < PlayerNumber > vHP ;
FOREACH_HumanPlayer ( pn )
vHP . push_back ( pn ) ;
LuaHelpers : : CreateTableFromArray ( vHP , L ) ;
return 1 ;
}
2014-04-15 12:09:03 -05:00
static int GetEnabledPlayers ( T * , lua_State * L )
{
vector < PlayerNumber > vEP ;
FOREACH_EnabledPlayer ( pn )
vEP . push_back ( pn ) ;
LuaHelpers : : CreateTableFromArray ( vEP , L ) ;
return 1 ;
2014-09-01 19:00:00 -04:00
}
2011-03-17 01:47:30 -04:00
static int GetCurrentStyle ( T * p , lua_State * L )
{
2014-12-07 01:53:17 -07:00
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 , true , true ) ;
Style * pStyle = const_cast < Style * > ( p - > GetCurrentStyle ( pn ) ) ;
2011-03-17 01:47:30 -04:00
LuaHelpers : : Push ( L , pStyle ) ;
return 1 ;
}
2012-12-27 12:07:02 -05:00
static int IsAnyHumanPlayerUsingMemoryCard ( T * , lua_State * L )
2011-03-17 01:47:30 -04:00
{
bool bUsingMemoryCard = false ;
FOREACH_HumanPlayer ( pn )
{
if ( MEMCARDMAN - > GetCardState ( pn ) = = MemoryCardState_Ready )
bUsingMemoryCard = true ;
}
lua_pushboolean ( L , bUsingMemoryCard ) ;
return 1 ;
}
2012-12-27 12:07:02 -05:00
static int GetNumStagesForCurrentSongAndStepsOrCourse ( T * , lua_State * L )
2014-09-01 19:00:00 -04:00
{
2012-12-27 12:07:02 -05:00
lua_pushnumber ( L , GAMESTATE - > GetNumStagesForCurrentSongAndStepsOrCourse ( ) ) ;
2014-09-01 19:00:00 -04:00
return 1 ;
2012-12-27 12:07:02 -05:00
}
2011-03-17 01:47:30 -04:00
static int GetNumStagesLeft ( T * p , lua_State * L )
{
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 1 ) ;
lua_pushnumber ( L , p - > GetNumStagesLeft ( pn ) ) ;
return 1 ;
}
static int GetGameSeed ( T * p , lua_State * L ) { LuaHelpers : : Push ( L , p - > m_iGameSeed ) ; return 1 ; }
static int GetStageSeed ( T * p , lua_State * L ) { LuaHelpers : : Push ( L , p - > m_iStageSeed ) ; return 1 ; }
2014-12-01 22:31:30 -07:00
static int SaveLocalData ( T * p , lua_State * L ) { p - > SaveLocalData ( ) ; COMMON_RETURN_SELF ; }
2011-03-17 01:47:30 -04:00
static int SetJukeboxUsesModifiers ( T * p , lua_State * L )
{
2014-12-01 22:31:30 -07:00
p - > m_bJukeboxUsesModifiers = BArg ( 1 ) ; COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2014-12-01 22:31:30 -07:00
static int Reset ( T * p , lua_State * L ) { p - > Reset ( ) ; COMMON_RETURN_SELF ; }
static int JoinPlayer ( T * p , lua_State * L ) { p - > JoinPlayer ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ; COMMON_RETURN_SELF ; }
static int UnjoinPlayer ( T * p , lua_State * L ) { p - > UnjoinPlayer ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ; COMMON_RETURN_SELF ; }
2014-02-12 15:45:26 -07:00
static int JoinInput ( T * p , lua_State * L )
{
lua_pushboolean ( L , p - > JoinInput ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ) ;
return 1 ;
}
2011-03-17 01:47:30 -04:00
static int GetSongPercent ( T * p , lua_State * L ) { lua_pushnumber ( L , p - > GetSongPercent ( FArg ( 1 ) ) ) ; return 1 ; }
2011-05-10 14:53:59 -04:00
DEFINE_METHOD ( GetCurMusicSeconds , m_Position . m_fMusicSeconds )
2011-03-17 01:47:30 -04:00
DEFINE_METHOD ( GetWorkoutGoalComplete , m_bWorkoutGoalComplete )
static int GetCharacter ( T * p , lua_State * L ) { p - > m_pCurCharacters [ Enum : : Check < PlayerNumber > ( L , 1 ) ] - > PushSelf ( L ) ; return 1 ; }
static int SetCharacter ( T * p , lua_State * L ) {
Character * c = CHARMAN - > GetCharacterFromID ( SArg ( 2 ) ) ;
if ( c )
p - > m_pCurCharacters [ Enum : : Check < PlayerNumber > ( L , 1 ) ] = c ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-03-17 01:47:30 -04:00
}
2011-08-07 19:08:47 -05:00
static int GetExpandedSectionName ( T * p , lua_State * L ) { lua_pushstring ( L , p - > sExpandedSectionName ) ; return 1 ; }
2014-12-01 22:31:30 -07:00
static int AddStageToPlayer ( T * p , lua_State * L ) { p - > AddStageToPlayer ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ; COMMON_RETURN_SELF ; }
2014-09-01 19:00:00 -04:00
static int InsertCoin ( T * p , lua_State * L )
{
2014-09-01 20:03:45 -04:00
int numCoins = IArg ( 1 ) ;
if ( GAMESTATE - > m_iCoins + numCoins > = 0 )
2014-09-01 20:26:55 -04:00
{
2014-09-01 20:03:45 -04:00
StepMania : : InsertCoin ( numCoins , false ) ;
2014-09-01 20:26:55 -04:00
} else {
// Warn themers if they attempt to set credits to a negative value.
2014-09-01 20:03:45 -04:00
luaL_error ( L , " Credits may not be negative. " ) ;
2014-09-01 20:26:55 -04:00
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-09-01 19:00:00 -04:00
}
static int InsertCredit ( T * p , lua_State * L )
{
StepMania : : InsertCredit ( ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-09-01 19:00:00 -04:00
}
2011-09-30 13:33:57 -05:00
static int CurrentOptionsDisqualifyPlayer ( T * p , lua_State * L ) { lua_pushboolean ( L , p - > CurrentOptionsDisqualifyPlayer ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ) ; return 1 ; }
2014-09-01 19:00:00 -04:00
2011-10-29 11:43:49 -04:00
static int ResetPlayerOptions ( T * p , lua_State * L )
{
p - > ResetPlayerOptions ( Enum : : Check < PlayerNumber > ( L , 1 ) ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-10-29 11:43:49 -04:00
}
2014-09-01 19:00:00 -04:00
2011-11-06 10:36:08 -05:00
static int RefreshNoteSkinData ( T * p , lua_State * L )
{
NOTESKIN - > RefreshNoteSkinData ( p - > m_pCurGame ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2011-11-06 10:36:08 -05:00
}
2014-09-01 19:00:00 -04:00
2011-03-17 01:47:30 -04:00
static int Dopefish ( T * p , lua_State * L )
{
lua_pushboolean ( L , p - > m_bDopefish ) ;
return 1 ;
}
2014-04-15 12:09:03 -05:00
static int LoadProfiles ( T * p , lua_State * L )
{
bool LoadEdits = true ;
if ( lua_isboolean ( L , 1 ) )
{
LoadEdits = BArg ( 1 ) ;
}
p - > LoadProfiles ( LoadEdits ) ;
SCREENMAN - > ZeroNextUpdate ( ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-15 12:09:03 -05:00
}
2014-09-01 19:00:00 -04:00
2014-04-15 12:09:03 -05:00
static int SaveProfiles ( T * p , lua_State * L )
{
p - > SavePlayerProfiles ( ) ;
SCREENMAN - > ZeroNextUpdate ( ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-15 12:09:03 -05:00
}
2014-04-02 18:09:21 -05:00
2014-06-20 13:54:56 -06:00
static int SetFailTypeExplicitlySet ( T * p , lua_State * L )
{
p - > m_bFailTypeWasExplicitlySet = true ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-06-20 13:54:56 -06:00
}
2014-05-12 22:01:22 -06:00
static int StoreRankingName ( T * p , lua_State * L )
{
p - > StoreRankingName ( Enum : : Check < PlayerNumber > ( L , 1 ) , SArg ( 2 ) ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-05-12 22:01:22 -06:00
}
2014-04-02 18:09:21 -05:00
DEFINE_METHOD ( HaveProfileToLoad , HaveProfileToLoad ( ) )
DEFINE_METHOD ( HaveProfileToSave , HaveProfileToSave ( ) )
2014-08-13 22:04:54 -05:00
static bool AreStyleAndPlayModeCompatible ( T * p , lua_State * L , const Style * style , PlayMode pm )
{
if ( pm ! = PLAY_MODE_BATTLE & & pm ! = PLAY_MODE_RAVE )
{
return true ;
}
// Do not allow styles with StepsTypes with shared sides or that are one player only with Battle or Rave.
if ( style - > m_StyleType ! = StyleType_TwoPlayersSharedSides )
{
vector < const Style * > vpStyles ;
GAMEMAN - > GetCompatibleStyles ( p - > m_pCurGame , 2 , vpStyles ) ;
FOREACH_CONST ( const Style * , vpStyles , s )
{
if ( ( * s ) - > m_StepsType = = style - > m_StepsType )
{
return true ;
}
}
}
luaL_error ( L , " Style %s is incompatible with PlayMode %s " ,
style - > m_szName , PlayModeToString ( pm ) . c_str ( ) ) ;
return false ;
}
static void ClearIncompatibleStepsAndTrails ( T * p , lua_State * L )
{
FOREACH_HumanPlayer ( pn )
{
2014-12-07 01:53:17 -07:00
const Style * style = p - > GetCurrentStyle ( pn ) ;
2014-08-13 22:04:54 -05:00
if ( p - > m_pCurSteps [ pn ] & & ( ! style | | style - > m_StepsType ! = p - > m_pCurSteps [ pn ] - > m_StepsType ) )
{
p - > m_pCurSteps [ pn ] . Set ( NULL ) ;
}
if ( p - > m_pCurTrail [ pn ] & & ( ! style | | style - > m_StepsType ! = p - > m_pCurTrail [ pn ] - > m_StepsType ) )
{
p - > m_pCurTrail [ pn ] . Set ( NULL ) ;
}
}
}
static int SetCurrentStyle ( T * p , lua_State * L )
{
const Style * pStyle = NULL ;
if ( lua_isstring ( L , 1 ) )
{
RString style = SArg ( 1 ) ;
pStyle = GAMEMAN - > GameAndStringToStyle ( GAMESTATE - > m_pCurGame , style ) ;
if ( ! pStyle )
{
luaL_error ( L , " SetCurrentStyle: %s is not a valid style. " , style . c_str ( ) ) ;
}
}
else
{
pStyle = Luna < Style > : : check ( L , 1 ) ;
}
StyleType st = pStyle - > m_StyleType ;
2014-09-01 19:00:00 -04:00
if ( p - > GetNumSidesJoined ( ) = = 2 & &
2014-08-13 22:04:54 -05:00
( st = = StyleType_OnePlayerOneSide | | st = = StyleType_OnePlayerTwoSides ) )
{
luaL_error ( L , " Too many sides joined for style %s " , pStyle - > m_szName ) ;
}
2014-09-01 19:00:00 -04:00
else if ( p - > GetNumSidesJoined ( ) = = 1 & &
2014-08-13 22:04:54 -05:00
( st = = StyleType_TwoPlayersTwoSides | | st = = StyleType_TwoPlayersSharedSides ) )
{
luaL_error ( L , " Too few sides joined for style %s " , pStyle - > m_szName ) ;
}
if ( ! AreStyleAndPlayModeCompatible ( p , L , pStyle , p - > m_PlayMode ) )
2014-09-01 19:00:00 -04:00
{
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-08-13 22:04:54 -05:00
}
2014-12-07 01:53:17 -07:00
PlayerNumber pn = Enum : : Check < PlayerNumber > ( L , 2 , true , true ) ;
2014-09-01 19:00:00 -04:00
2014-12-07 01:53:17 -07:00
p - > SetCurrentStyle ( pStyle , pn ) ;
2014-08-13 22:04:54 -05:00
ClearIncompatibleStepsAndTrails ( p , L ) ;
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-08-13 22:04:54 -05:00
}
static int SetCurrentPlayMode ( T * p , lua_State * L )
{
PlayMode pm = Enum : : Check < PlayMode > ( L , 1 ) ;
2014-12-07 01:53:17 -07:00
if ( AreStyleAndPlayModeCompatible ( p , L , p - > GetCurrentStyle ( PLAYER_INVALID ) , pm ) )
2014-08-13 22:04:54 -05:00
{
p - > m_PlayMode . Set ( pm ) ;
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-08-13 22:04:54 -05:00
}
2011-03-17 01:47:30 -04:00
LunaGameState ( )
{
ADD_METHOD ( IsPlayerEnabled ) ;
ADD_METHOD ( IsHumanPlayer ) ;
ADD_METHOD ( GetPlayerDisplayName ) ;
ADD_METHOD ( GetMasterPlayerNumber ) ;
ADD_METHOD ( GetMultiplayer ) ;
ADD_METHOD ( SetMultiplayer ) ;
2011-12-12 18:49:10 -05:00
ADD_METHOD ( InStepEditor ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetNumMultiplayerNoteFields ) ;
ADD_METHOD ( SetNumMultiplayerNoteFields ) ;
ADD_METHOD ( ShowW1 ) ;
ADD_METHOD ( GetPlayerState ) ;
ADD_METHOD ( GetMultiPlayerState ) ;
ADD_METHOD ( ApplyGameCommand ) ;
2014-12-07 01:53:17 -07:00
ADD_METHOD ( CanSafelyEnterGameplay ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetCurrentSong ) ;
ADD_METHOD ( SetCurrentSong ) ;
ADD_METHOD ( GetCurrentSteps ) ;
ADD_METHOD ( SetCurrentSteps ) ;
ADD_METHOD ( GetCurrentCourse ) ;
ADD_METHOD ( SetCurrentCourse ) ;
ADD_METHOD ( GetCurrentTrail ) ;
ADD_METHOD ( SetCurrentTrail ) ;
ADD_METHOD ( SetPreferredSong ) ;
ADD_METHOD ( GetPreferredSong ) ;
ADD_METHOD ( SetTemporaryEventMode ) ;
ADD_METHOD ( Env ) ;
ADD_METHOD ( GetEditSourceSteps ) ;
ADD_METHOD ( SetPreferredDifficulty ) ;
ADD_METHOD ( GetPreferredDifficulty ) ;
ADD_METHOD ( AnyPlayerHasRankingFeats ) ;
ADD_METHOD ( IsCourseMode ) ;
ADD_METHOD ( IsBattleMode ) ;
ADD_METHOD ( IsDemonstration ) ;
ADD_METHOD ( GetPlayMode ) ;
ADD_METHOD ( GetSortOrder ) ;
ADD_METHOD ( GetCurrentStageIndex ) ;
ADD_METHOD ( IsGoalComplete ) ;
ADD_METHOD ( PlayerIsUsingModifier ) ;
ADD_METHOD ( GetCourseSongIndex ) ;
ADD_METHOD ( GetLoadingCourseSongIndex ) ;
ADD_METHOD ( GetSmallestNumStagesLeftForAnyHumanPlayer ) ;
ADD_METHOD ( IsAnExtraStage ) ;
ADD_METHOD ( IsExtraStage ) ;
ADD_METHOD ( IsExtraStage2 ) ;
ADD_METHOD ( GetCurrentStage ) ;
ADD_METHOD ( HasEarnedExtraStage ) ;
2011-09-07 23:48:04 -05:00
ADD_METHOD ( GetEarnedExtraStage ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetEasiestStepsDifficulty ) ;
ADD_METHOD ( GetHardestStepsDifficulty ) ;
ADD_METHOD ( IsEventMode ) ;
ADD_METHOD ( GetNumPlayersEnabled ) ;
2011-05-15 08:17:32 -05:00
/*ADD_METHOD( GetSongBeat );
2011-03-17 01:47:30 -04:00
ADD_METHOD( GetSongBeatVisible );
ADD_METHOD( GetSongBPS );
ADD_METHOD( GetSongFreeze );
2011-05-15 08:17:32 -05:00
ADD_METHOD( GetSongDelay );*/
2011-05-15 07:53:06 -05:00
ADD_METHOD ( GetSongPosition ) ;
2014-09-12 15:07:46 -06:00
ADD_METHOD ( GetLastGameplayDuration ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetGameplayLeadIn ) ;
2013-06-04 23:47:22 -04:00
ADD_METHOD ( GetCoins ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( IsSideJoined ) ;
2013-06-04 23:47:22 -04:00
ADD_METHOD ( GetCoinsNeededToJoin ) ;
ADD_METHOD ( EnoughCreditsToJoin ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( PlayersCanJoin ) ;
ADD_METHOD ( GetNumSidesJoined ) ;
ADD_METHOD ( GetCoinMode ) ;
ADD_METHOD ( GetPremium ) ;
ADD_METHOD ( GetSongOptionsString ) ;
ADD_METHOD ( GetSongOptions ) ;
2014-05-03 19:27:32 -06:00
ADD_METHOD ( GetSongOptionsObject ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetDefaultSongOptions ) ;
2014-12-09 21:59:01 -07:00
ADD_METHOD ( ApplyPreferredSongOptionsToOtherLevels ) ;
2011-09-30 13:44:05 -05:00
ADD_METHOD ( ApplyPreferredModifiers ) ;
2011-09-30 14:50:18 -05:00
ADD_METHOD ( ApplyStageModifiers ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( ClearStageModifiersIllegalForCourse ) ;
ADD_METHOD ( SetSongOptions ) ;
2012-03-28 18:55:17 -05:00
ADD_METHOD ( GetStageResult ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( IsWinner ) ;
ADD_METHOD ( IsDraw ) ;
ADD_METHOD ( GetCurrentGame ) ;
//ADD_METHOD( SetCurrentGame );
ADD_METHOD ( GetEditCourseEntryIndex ) ;
ADD_METHOD ( GetEditLocalProfileID ) ;
ADD_METHOD ( GetEditLocalProfile ) ;
ADD_METHOD ( GetCurrentStepsCredits ) ;
ADD_METHOD ( SetPreferredSongGroup ) ;
ADD_METHOD ( GetPreferredSongGroup ) ;
ADD_METHOD ( GetHumanPlayers ) ;
2012-05-27 12:55:57 -05:00
ADD_METHOD ( GetEnabledPlayers ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetCurrentStyle ) ;
ADD_METHOD ( IsAnyHumanPlayerUsingMemoryCard ) ;
ADD_METHOD ( GetNumStagesForCurrentSongAndStepsOrCourse ) ;
ADD_METHOD ( GetNumStagesLeft ) ;
ADD_METHOD ( GetGameSeed ) ;
ADD_METHOD ( GetStageSeed ) ;
ADD_METHOD ( SaveLocalData ) ;
ADD_METHOD ( SetJukeboxUsesModifiers ) ;
ADD_METHOD ( GetWorkoutGoalComplete ) ;
ADD_METHOD ( Reset ) ;
ADD_METHOD ( JoinPlayer ) ;
ADD_METHOD ( UnjoinPlayer ) ;
2014-02-12 15:45:26 -07:00
ADD_METHOD ( JoinInput ) ;
2011-03-17 01:47:30 -04:00
ADD_METHOD ( GetSongPercent ) ;
ADD_METHOD ( GetCurMusicSeconds ) ;
ADD_METHOD ( GetCharacter ) ;
ADD_METHOD ( SetCharacter ) ;
2011-08-07 19:08:47 -05:00
ADD_METHOD ( GetExpandedSectionName ) ;
2011-09-21 16:21:23 -06:00
ADD_METHOD ( AddStageToPlayer ) ;
2014-09-01 19:00:00 -04:00
ADD_METHOD ( InsertCoin ) ;
ADD_METHOD ( InsertCredit ) ;
2011-09-30 13:33:57 -05:00
ADD_METHOD ( CurrentOptionsDisqualifyPlayer ) ;
2011-10-29 11:43:49 -04:00
ADD_METHOD ( ResetPlayerOptions ) ;
2011-11-06 10:36:08 -05:00
ADD_METHOD ( RefreshNoteSkinData ) ;
2011-09-30 13:33:57 -05:00
ADD_METHOD ( Dopefish ) ;
2014-04-02 18:09:21 -05:00
ADD_METHOD ( LoadProfiles ) ;
ADD_METHOD ( SaveProfiles ) ;
ADD_METHOD ( HaveProfileToLoad ) ;
ADD_METHOD ( HaveProfileToSave ) ;
2014-06-20 13:54:56 -06:00
ADD_METHOD ( SetFailTypeExplicitlySet ) ;
2014-05-12 22:01:22 -06:00
ADD_METHOD ( StoreRankingName ) ;
2014-08-13 22:04:54 -05:00
ADD_METHOD ( SetCurrentStyle ) ;
ADD_METHOD ( SetCurrentPlayMode ) ;
2011-03-17 01:47:30 -04:00
}
} ;
LUA_REGISTER_CLASS ( GameState )
// lua end
/*
* (c) 2001-2004 Chris Danford, Glenn Maynard, Chris Gomez
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/