#ifndef STEPS_H #define STEPS_H #include "Attack.h" #include "GameConstantsAndTypes.h" #include "PlayerNumber.h" #include "Grade.h" #include "RadarValues.h" #include "Difficulty.h" #include "RageUtil_AutoPtr.h" #include "RageUtil_CachedObject.h" #include "TimingData.h" class Profile; class NoteData; struct lua_State; /** * @brief Enforce a limit on the number of chars for the description. * * In In The Groove, this limit was 12: we do not need such a limit now. */ const int MAX_STEPS_DESCRIPTION_LENGTH = 255; /** @brief The different ways of displaying the BPM. */ enum DisplayBPM { DISPLAY_BPM_ACTUAL, /**< Display the song's actual BPM. */ DISPLAY_BPM_SPECIFIED, /**< Display a specified value or values. */ DISPLAY_BPM_RANDOM, /**< Display a random selection of BPMs. */ NUM_DisplayBPM, DisplayBPM_Invalid }; const RString& DisplayBPMToString( DisplayBPM dbpm ); LuaDeclareType( DisplayBPM ); /** * @brief Holds note information for a Song. * * A Song may have one or more Notes. */ class Steps { public: /** @brief Set up the Steps with initial values. */ Steps( Song* song ); /** @brief Destroy the Steps that are no longer needed. */ ~Steps(); // initializers void AutogenFrom( const Steps *parent, StepsType ntTo ); void CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds ); void CreateBlank( StepsType ntTo ); void Compress() const; void Decompress() const; void Decompress(); /** * @brief Determine if these steps were created by the autogenerator. * @return true if they were, false otherwise. */ bool IsAutogen() const { return parent != NULL; } /** * @brief Determine if this set of Steps is an edit. * * Edits have a special value of difficulty to make it easy to determine. * @return true if this is an edit, false otherwise. */ bool IsAnEdit() const { return m_Difficulty == Difficulty_Edit; } /** * @brief Determine if this set of Steps is a player edit. * * Player edits also have to be loaded from a player's profile slot, not the machine. * @return true if this is a player edit, false otherwise. */ bool IsAPlayerEdit() const { return IsAnEdit() && GetLoadedFromProfileSlot() < ProfileSlot_Machine; } /** * @brief Determine if these steps were loaded from a player's profile. * @return true if they were from a player profile, false otherwise. */ bool WasLoadedFromProfile() const { return m_LoadedFromProfile != ProfileSlot_Invalid; } ProfileSlot GetLoadedFromProfileSlot() const { return m_LoadedFromProfile; } /** * @brief Retrieve the description used for this edit. * @return the description used for this edit. */ RString GetDescription() const { return Real()->m_sDescription; } /** * @brief Retrieve the ChartStyle used for this chart. * @return the description used for this chart. */ RString GetChartStyle() const { return Real()->m_sChartStyle; } /** * @brief Retrieve the difficulty used for this edit. * @return the difficulty used for this edit. */ Difficulty GetDifficulty() const { return Real()->m_Difficulty; } /** * @brief Retrieve the meter used for this edit. * @return the meter used for this edit. */ int GetMeter() const { return Real()->m_iMeter; } const RadarValues& GetRadarValues( PlayerNumber pn ) const { return Real()->m_CachedRadarValues[pn]; } /** * @brief Retrieve the author credit used for this edit. * @return the author credit used for this edit. */ RString GetCredit() const { return Real()->m_sCredit; } /** @brief The list of attacks. */ AttackArray m_Attacks; /** @brief The stringified list of attacks. */ vector m_sAttackString; RString GetChartName() const { return parent ? Real()->GetChartName() : this->chartName; } void SetChartName(const RString name) { this->chartName = name; } void SetFilename( RString fn ) { m_sFilename = fn; } RString GetFilename() const { return m_sFilename; } void SetSavedToDisk( bool b ) { DeAutogen(); m_bSavedToDisk = b; } bool GetSavedToDisk() const { return Real()->m_bSavedToDisk; } void SetDifficulty( Difficulty dc ) { SetDifficultyAndDescription( dc, GetDescription() ); } void SetDescription( RString sDescription ) { SetDifficultyAndDescription( this->GetDifficulty(), sDescription ); } void SetDifficultyAndDescription( Difficulty dc, RString sDescription ); void SetCredit( RString sCredit ); void SetChartStyle( RString sChartStyle ); static bool MakeValidEditDescription( RString &sPreferredDescription ); // return true if was modified void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; } void SetMeter( int meter ); void SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] ); float PredictMeter() const; unsigned GetHash() const; void GetNoteData( NoteData& noteDataOut ) const; NoteData GetNoteData() const; void SetNoteData( const NoteData& noteDataNew ); void SetSMNoteData( const RString ¬es_comp ); void GetSMNoteData( RString ¬es_comp_out ) const; /** * @brief Retrieve the NoteData from the original source. * @return true if successful, false for failure. */ bool GetNoteDataFromSimfile(); /** * @brief Determine if we are missing any note data. * * This takes advantage of the fact that we usually compress our data. * @return true if our notedata is empty, false otherwise. */ bool IsNoteDataEmpty() const; void TidyUpData(); void CalculateRadarValues( float fMusicLengthSeconds ); /** * @brief The TimingData used by the Steps. * * This is required to allow Split Timing. */ TimingData m_Timing; /** * @brief Retrieves the appropriate timing data for the Steps. Falls * back on the Song if needed. */ const TimingData *GetTimingData() const; TimingData *GetTimingData() { return const_cast( static_cast( this )->GetTimingData() ); }; /** * @brief Determine if the Steps have any major timing changes during gameplay. * @return true if it does, or false otherwise. */ bool HasSignificantTimingChanges() const; /** * @brief Determine if the Steps have any attacks. * @return true if it does, or false otherwise. */ bool HasAttacks() const; // Lua void PushSelf( lua_State *L ); StepsType m_StepsType; /** @brief The string form of the StepsType, for dealing with unrecognized styles. */ RString m_StepsTypeStr; /** @brief The Song these Steps are associated with */ Song *m_pSong; CachedObject m_CachedObject; void SetDisplayBPM(const DisplayBPM type) { this->displayBPMType = type; } DisplayBPM GetDisplayBPM() const { return this->displayBPMType; } void SetMinBPM(const float f) { this->specifiedBPMMin = f; } float GetMinBPM() const { return this->specifiedBPMMin; } void SetMaxBPM(const float f) { this->specifiedBPMMax = f; } float GetMaxBPM() const { return this->specifiedBPMMax; } void GetDisplayBpms( DisplayBpms &addTo) const; RString GetAttackString() const { return join(":", this->m_sAttackString); } private: inline const Steps *Real() const { return parent ? parent : this; } void DeAutogen( bool bCopyNoteData = true ); /* If this Steps is autogenerated, make it a real Steps. */ /** * @brief Identify this Steps' parent. * * If this Steps is autogenerated, this will point to the autogen * source. If this is true, m_sNoteDataCompressed will always be empty. */ const Steps *parent; /* We can have one or both of these; if we have both, they're always identical. * Call Compress() to force us to only have m_sNoteDataCompressed; otherwise, creation of * these is transparent. */ mutable HiddenPtr m_pNoteData; mutable bool m_bNoteDataIsFilled; mutable RString m_sNoteDataCompressed; /** @brief The name of the file where these steps are stored. */ RString m_sFilename; /** @brief true if these Steps were loaded from or saved to disk. */ bool m_bSavedToDisk; /** @brief What profile was used? This is ProfileSlot_Invalid if not from a profile. */ ProfileSlot m_LoadedFromProfile; /* These values are pulled from the autogen source first, if there is one. */ /** @brief The hash of the steps. This is used only for Edit Steps. */ mutable unsigned m_iHash; /** @brief The name of the edit, or some other useful description. This used to also contain the step author's name. */ RString m_sDescription; /** @brief The style of the chart. (e.g. "Pad", "Keyboard") */ RString m_sChartStyle; /** @brief The difficulty that these steps are assigned to. */ Difficulty m_Difficulty; /** @brief The numeric difficulty of the Steps, ranging from MIN_METER to MAX_METER. */ int m_iMeter; /** @brief The radar values used for each player. */ RadarValues m_CachedRadarValues[NUM_PLAYERS]; bool m_bAreCachedRadarValuesJustLoaded; /** @brief The name of the person who created the Steps. */ RString m_sCredit; /** @brief The name of the chart. */ RString chartName; /** @brief How is the BPM displayed for this chart? */ DisplayBPM displayBPMType; /** @brief What is the minimum specified BPM? */ float specifiedBPMMin; /** * @brief What is the maximum specified BPM? * If this is a range, then min should not be equal to max. */ float specifiedBPMMax; }; #endif /** * @file * @author Chris Danford, Glenn Maynard (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. */