Files
itgmania212121/src/GameState.h
T

484 lines
17 KiB
C++

#ifndef GAMESTATE_H
#define GAMESTATE_H
#include "Attack.h"
#include "Difficulty.h"
#include "GameConstantsAndTypes.h"
#include "Grade.h"
#include "MessageManager.h"
#include "ModsGroup.h"
#include "RageTimer.h"
#include "PlayerOptions.h"
#include "SongOptions.h"
#include "SongPosition.h"
#include "Preference.h"
#include <map>
#include <deque>
#include <set>
class Character;
class Course;
struct Game;
struct lua_State;
class LuaTable;
class PlayerState;
class PlayerOptions;
class Profile;
class Song;
class Steps;
class StageStats;
class Style;
class TimingData;
class Trail;
SortOrder GetDefaultSort();
/** @brief Holds game data that is not saved between sessions. */
class GameState
{
/** @brief The player number used with Styles where one player controls both sides. */
PlayerNumber masterPlayerNumber;
/** @brief The TimingData that is used for processing certain functions. */
TimingData * processedTiming;
public:
/** @brief Set up the GameState with initial values. */
GameState();
~GameState();
/** @brief Reset the GameState back to initial values. */
void Reset();
void ResetPlayer( PlayerNumber pn );
void ResetPlayerOptions( PlayerNumber pn );
void ApplyCmdline(); // called by Reset
void ApplyGameCommand( const RString &sCommand, PlayerNumber pn=PLAYER_INVALID );
/** @brief Start the game when the first player joins in. */
void BeginGame();
void JoinPlayer( PlayerNumber pn );
void UnjoinPlayer( PlayerNumber pn );
bool JoinInput( PlayerNumber pn );
bool JoinPlayers();
void LoadProfiles( bool bLoadEdits = true );
void SavePlayerProfiles();
void SavePlayerProfile( PlayerNumber pn );
bool HaveProfileToLoad();
bool HaveProfileToSave();
void SaveLocalData();
void AddStageToPlayer( PlayerNumber pn );
void LoadCurrentSettingsFromProfile( PlayerNumber pn );
/**
* @brief Save the specified player's settings to his/her profile.
*
* This is called at the beginning of each stage.
* @param pn the PlayerNumber to save the stats to. */
void SaveCurrentSettingsToProfile( PlayerNumber pn );
Song* GetDefaultSong() const;
bool CanSafelyEnterGameplay(RString& reason);
void SetCompatibleStylesForPlayers();
void ForceSharedSidesMatch();
void ForceOtherPlayersToCompatibleSteps(PlayerNumber main);
void Update( float fDelta );
// Main state info
/**
* @brief State what the current game is.
*
* Call this instead of m_pCurGame.Set to make sure that
* PREFSMAN->m_sCurrentGame stays in sync.
* @param pGame the game to start using. */
void SetCurGame( const Game *pGame );
BroadcastOnChangePtr<const Game> m_pCurGame;
private: // DO NOT access directly. Use Get/SetCurrentStyle.
BroadcastOnChangePtr<const Style> m_pCurStyle;
// Only used if the Game specifies that styles are separate.
Style const* m_SeparatedStyles[NUM_PlayerNumber];
public:
/** @brief Determine which side is joined.
*
* The left side is player 1, and the right side is player 2. */
bool m_bSideIsJoined[NUM_PLAYERS]; // left side, right side
MultiPlayerStatus m_MultiPlayerStatus[NUM_MultiPlayer];
BroadcastOnChange<PlayMode> m_PlayMode; // many screens display different info depending on this value
/**
* @brief The number of coins presently in the machine.
*
* Note that coins are not "credits". One may have to put in two coins
* to get one credit, only to have to put in another four coins to get
* the three credits needed to begin the game. */
BroadcastOnChange<int> m_iCoins;
bool m_bMultiplayer;
int m_iNumMultiplayerNoteFields;
bool DifficultiesLocked() const;
bool ChangePreferredDifficultyAndStepsType( PlayerNumber pn, Difficulty dc, StepsType st );
bool ChangePreferredDifficulty( PlayerNumber pn, int dir );
bool ChangePreferredCourseDifficultyAndStepsType( PlayerNumber pn, CourseDifficulty cd, StepsType st );
bool ChangePreferredCourseDifficulty( PlayerNumber pn, int dir );
bool IsCourseDifficultyShown( CourseDifficulty cd );
Difficulty GetClosestShownDifficulty( PlayerNumber pn ) const;
Difficulty GetEasiestStepsDifficulty() const;
Difficulty GetHardestStepsDifficulty() const;
RageTimer m_timeGameStarted; // from the moment the first player pressed Start
LuaTable *m_Environment;
// This is set to a random number per-game/round; it can be used for a random seed.
int m_iGameSeed, m_iStageSeed;
RString m_sStageGUID;
void SetNewStageSeed();
/**
* @brief Determine if a second player can join in at this time.
* @return true if a player can still enter the game, false otherwise. */
bool PlayersCanJoin() const;
int GetCoinsNeededToJoin() const;
bool EnoughCreditsToJoin() const { return m_iCoins >= GetCoinsNeededToJoin(); }
int GetNumSidesJoined() const;
const Game* GetCurrentGame() const;
const Style* GetCurrentStyle(PlayerNumber pn) const;
void SetCurrentStyle(const Style *style, PlayerNumber pn);
bool SetCompatibleStyle(StepsType stype, PlayerNumber pn);
void GetPlayerInfo( PlayerNumber pn, bool& bIsEnabledOut, bool& bIsHumanOut );
bool IsPlayerEnabled( PlayerNumber pn ) const;
bool IsMultiPlayerEnabled( MultiPlayer mp ) const;
bool IsPlayerEnabled( const PlayerState* pPlayerState ) const;
int GetNumPlayersEnabled() const;
/**
* @brief Is the specified Player a human Player?
* @param pn the numbered Player to check.
* @return true if it's a human Player, or false otherwise. */
bool IsHumanPlayer( PlayerNumber pn ) const;
int GetNumHumanPlayers() const;
PlayerNumber GetFirstHumanPlayer() const;
PlayerNumber GetFirstDisabledPlayer() const;
bool IsCpuPlayer( PlayerNumber pn ) const;
bool AnyPlayersAreCpu() const;
/**
* @brief Retrieve the present master player number.
* @return The master player number. */
PlayerNumber GetMasterPlayerNumber() const;
/**
* @brief Set the master player number.
* @param p the master player number. */
void SetMasterPlayerNumber(const PlayerNumber p);
/**
* @brief Retrieve the present timing data being processed.
* @return the timing data pointer. */
TimingData * GetProcessedTimingData() const;
/**
* @brief Set the timing data to be used with processing.
* @param t the timing data. */
void SetProcessedTimingData(TimingData * t);
bool IsCourseMode() const;
bool IsBattleMode() const; // not Rave
/**
* @brief Do we show the W1 timing judgment?
* @return true if we do, or false otherwise. */
bool ShowW1() const;
BroadcastOnChange<RString> m_sPreferredSongGroup; // GROUP_ALL denotes no preferred group
BroadcastOnChange<RString> m_sPreferredCourseGroup; // GROUP_ALL denotes no preferred group
bool m_bFailTypeWasExplicitlySet; // true if FailType was changed in the song options screen
BroadcastOnChange<StepsType> m_PreferredStepsType;
BroadcastOnChange1D<Difficulty,NUM_PLAYERS> m_PreferredDifficulty;
BroadcastOnChange1D<CourseDifficulty,NUM_PLAYERS> m_PreferredCourseDifficulty;// used in nonstop
BroadcastOnChange<SortOrder> m_SortOrder; // set by MusicWheel
SortOrder m_PreferredSortOrder; // used by MusicWheel
EditMode m_EditMode;
bool IsEditing() const { return m_EditMode != EditMode_Invalid; }
/**
* @brief Are we in the demonstration or jukebox mode?
*
* ScreenGameplay often does special things when this is set to true. */
bool m_bDemonstrationOrJukebox;
bool m_bJukeboxUsesModifiers;
int m_iNumStagesOfThisSong;
/**
* @brief Increase this every stage while not resetting on a continue.
*
* This is cosmetic: it's not use for Stage or Screen branching logic. */
int m_iCurrentStageIndex;
/**
* @brief The number of stages available for the players.
*
* This resets whenever a player joins or continues. */
int m_iPlayerStageTokens[NUM_PLAYERS];
// This is necessary so that IsFinalStageForEveryHumanPlayer knows to
// adjust for the current song cost.
bool m_AdjustTokensBySongCostForFinalStageCheck;
RString sExpandedSectionName;
static int GetNumStagesMultiplierForSong( const Song* pSong );
static int GetNumStagesForSongAndStyleType( const Song* pSong, StyleType st );
int GetNumStagesForCurrentSongAndStepsOrCourse() const;
void BeginStage();
void CancelStage();
void CommitStageStats();
void FinishStage();
int GetNumStagesLeft( PlayerNumber pn ) const;
int GetSmallestNumStagesLeftForAnyHumanPlayer() const;
bool IsFinalStageForAnyHumanPlayer() const;
bool IsFinalStageForEveryHumanPlayer() const;
bool IsAnExtraStage() const;
bool IsAnExtraStageAndSelectionLocked() const;
bool IsExtraStage() const;
bool IsExtraStage2() const;
Stage GetCurrentStage() const;
int GetCourseSongIndex() const;
RString GetPlayerDisplayName( PlayerNumber pn ) const;
bool m_bLoadingNextSong;
int GetLoadingCourseSongIndex() const;
// State Info used during gameplay
// NULL on ScreenSelectMusic if the currently selected wheel item isn't a Song.
BroadcastOnChangePtr<Song> m_pCurSong;
// The last Song that the user manually changed to.
Song* m_pPreferredSong;
BroadcastOnChangePtr1D<Steps,NUM_PLAYERS> m_pCurSteps;
// NULL on ScreenSelectMusic if the currently selected wheel item isn't a Course.
BroadcastOnChangePtr<Course> m_pCurCourse;
// The last Course that the user manually changed to.
Course* m_pPreferredCourse;
BroadcastOnChangePtr1D<Trail,NUM_PLAYERS> m_pCurTrail;
bool m_bBackedOutOfFinalStage;
// Music statistics:
SongPosition m_Position;
BroadcastOnChange<bool> m_bGameplayLeadIn;
// if re-adding noteskin changes in courses, add functions and such here -aj
void GetAllUsedNoteSkins( vector<RString> &out ) const;
static const float MUSIC_SECONDS_INVALID;
void ResetMusicStatistics(); // Call this when it's time to play a new song. Clears the values above.
void UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer &timestamp = RageZeroTimer );
float GetSongPercent( float beat ) const;
bool AllAreInDangerOrWorse() const;
bool OneIsHot() const;
// Haste
float m_fHasteRate; // [-1,+1]; 0 = normal speed
float m_fLastHasteUpdateMusicSeconds;
float m_fAccumulatedHasteSeconds;
// used by themes that support heart rate entry.
RageTimer m_DanceStartTime;
float m_DanceDuration;
// Random Attacks & Attack Mines
vector<RString> m_RandomAttacks;
// used in PLAY_MODE_BATTLE
float m_fOpponentHealthPercent;
// used in PLAY_MODE_RAVE
float m_fTugLifePercentP1;
// used in workout
bool m_bGoalComplete[NUM_PLAYERS];
bool m_bWorkoutGoalComplete;
/** @brief Primarily called at the end of a song to stop all attacks. */
void RemoveAllActiveAttacks();
PlayerNumber GetBestPlayer() const;
StageResult GetStageResult( PlayerNumber pn ) const;
/** @brief Call this function when it's time to play a new stage. */
void ResetStageStatistics();
// Options stuff
ModsGroup<SongOptions> m_SongOptions;
/**
* @brief Did the current game mode change the default Noteskin?
*
* This is true if it has: see Edit/Sync Songs for a common example.
* Note: any mode that wants to use this must set it explicitly. */
bool m_bDidModeChangeNoteSkin;
void GetDefaultPlayerOptions( PlayerOptions &po );
void GetDefaultSongOptions( SongOptions &so );
void ResetToDefaultSongOptions( ModsLevel l );
void ApplyPreferredModifiers( PlayerNumber pn, RString sModifiers );
void ApplyStageModifiers( PlayerNumber pn, RString sModifiers );
void ClearStageModifiersIllegalForCourse();
void ResetOptions();
bool CurrentOptionsDisqualifyPlayer( PlayerNumber pn );
bool PlayerIsUsingModifier( PlayerNumber pn, const RString &sModifier );
FailType GetPlayerFailType( const PlayerState *pPlayerState ) const;
// character stuff
Character* m_pCurCharacters[NUM_PLAYERS];
bool HasEarnedExtraStage() const { return m_bEarnedExtraStage; }
EarnedExtraStage GetEarnedExtraStage() const { return CalculateEarnedExtraStage(); }
// Ranking Stuff
struct RankingFeat
{
enum { SONG, COURSE, CATEGORY } Type;
Song* pSong; // valid if Type == SONG
Steps* pSteps; // valid if Type == SONG
Course* pCourse; // valid if Type == COURSE
Grade grade;
int iScore;
float fPercentDP;
RString Banner;
RString Feat;
RString *pStringToFill;
};
void GetRankingFeats( PlayerNumber pn, vector<RankingFeat> &vFeatsOut ) const;
bool AnyPlayerHasRankingFeats() const;
void StoreRankingName( PlayerNumber pn, RString name ); // Called by name entry screens
vector<RString*> m_vpsNamesThatWereFilled; // filled on StoreRankingName,
// Award stuff
// lowest priority in front, highest priority at the back.
deque<StageAward> m_vLastStageAwards[NUM_PLAYERS];
deque<PeakComboAward> m_vLastPeakComboAwards[NUM_PLAYERS];
// Attract stuff
int m_iNumTimesThroughAttract; // negative means play regardless of m_iAttractSoundFrequency setting
bool IsTimeToPlayAttractSounds() const;
void VisitAttractScreen( const RString sScreenName );
// PlayerState
/** @brief Allow access to each player's PlayerState. */
PlayerState* m_pPlayerState[NUM_PLAYERS];
PlayerState* m_pMultiPlayerState[NUM_MultiPlayer];
// Preferences
static Preference<bool> m_bAutoJoin;
// These options have weird interactions depending on m_bEventMode,
// so wrap them.
bool m_bTemporaryEventMode;
bool IsEventMode() const;
CoinMode GetCoinMode() const;
Premium GetPremium() const;
// Edit stuff
/**
* @brief Is the game right now using Song timing or Steps timing?
*
* Different options are available depending on this setting. */
bool m_bIsUsingStepTiming;
/**
* @brief Are we presently in the Step Editor, where some rules apply differently?
*
* TODO: Find a better way to implement this. */
bool m_bInStepEditor;
BroadcastOnChange<StepsType> m_stEdit;
BroadcastOnChange<CourseDifficulty> m_cdEdit;
BroadcastOnChangePtr<Steps> m_pEditSourceSteps;
BroadcastOnChange<StepsType> m_stEditSource;
BroadcastOnChange<int> m_iEditCourseEntryIndex;
BroadcastOnChange<RString> m_sEditLocalProfileID;
Profile* GetEditLocalProfile();
// Workout stuff
float GetGoalPercentComplete( PlayerNumber pn );
bool IsGoalComplete( PlayerNumber pn ) { return GetGoalPercentComplete( pn ) >= 1; }
bool m_bDopefish;
// Autogen stuff. This should probably be moved to its own singleton or
// something when autogen is generalized and more customizable. -Kyz
float GetAutoGenFarg(size_t i)
{
if(i >= m_autogen_fargs.size()) { return 0.0f; }
return m_autogen_fargs[i];
}
vector<float> m_autogen_fargs;
// Lua
void PushSelf( lua_State *L );
// Keep extra stage logic internal to GameState.
private:
EarnedExtraStage CalculateEarnedExtraStage() const;
int m_iAwardedExtraStages[NUM_PLAYERS];
bool m_bEarnedExtraStage;
// Timing position corrections
RageTimer m_LastPositionTimer;
float m_LastPositionSeconds;
GameState(const GameState& rhs);
GameState& operator=(const GameState& rhs);
};
PlayerNumber GetNextHumanPlayer( PlayerNumber pn );
PlayerNumber GetNextEnabledPlayer( PlayerNumber pn );
PlayerNumber GetNextCpuPlayer( PlayerNumber pn );
PlayerNumber GetNextPotentialCpuPlayer( PlayerNumber pn );
MultiPlayer GetNextEnabledMultiPlayer( MultiPlayer mp );
/** @brief A foreach loop to act on each human Player. */
#define FOREACH_HumanPlayer( pn ) for( PlayerNumber pn=GetNextHumanPlayer((PlayerNumber)-1); pn!=PLAYER_INVALID; pn=GetNextHumanPlayer(pn) )
/** @brief A foreach loop to act on each enabled Player. */
#define FOREACH_EnabledPlayer( pn ) for( PlayerNumber pn=GetNextEnabledPlayer((PlayerNumber)-1); pn!=PLAYER_INVALID; pn=GetNextEnabledPlayer(pn) )
/** @brief A foreach loop to act on each CPU Player. */
#define FOREACH_CpuPlayer( pn ) for( PlayerNumber pn=GetNextCpuPlayer((PlayerNumber)-1); pn!=PLAYER_INVALID; pn=GetNextCpuPlayer(pn) )
/** @brief A foreach loop to act on each potential CPU Player. */
#define FOREACH_PotentialCpuPlayer( pn ) for( PlayerNumber pn=GetNextPotentialCpuPlayer((PlayerNumber)-1); pn!=PLAYER_INVALID; pn=GetNextPotentialCpuPlayer(pn) )
/** @brief A foreach loop to act on each Player in MultiPlayer. */
#define FOREACH_EnabledMultiPlayer( mp ) for( MultiPlayer mp=GetNextEnabledMultiPlayer((MultiPlayer)-1); mp!=MultiPlayer_Invalid; mp=GetNextEnabledMultiPlayer(mp) )
extern GameState* GAMESTATE; // global and accessible from anywhere in our program
#endif
/**
* @file
* @author Chris Danford, Glenn Maynard, Chris Gomez (c) 2001-2004
* @section LICENSE
* 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.
*/