diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 874e230a6e..254e40a4ce 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -5,9 +5,25 @@ from StepMania 4 alpha 5 to sm-ssc v1.2.5, see Changelog_sm-ssc.txt. ________________________________________________________________________________ ================================================================================ -StepMania 5.0 Preview 2 | 20110??? +StepMania 5.0 Preview 2 | 201106?? -------------------------------------------------------------------------------- +2011/06/19 +* [EditMenu] Allow all songs to work in Practice Mode, regardless of folder + location. This fixes a crash if everyone had songs in AdditionalSongs. + [Wolfman2000] + +2011/06/17 +---------- +* [LifeMeterBattery] Fixed a bug where MinesSubtractLives was not being honored. + Also added LifeChanged message to changing of life on holds. [AJ] + +2011/06/15 +---------- +* [TimingData] Added many lua bindings for the other timing segments. GetWarps, + GetCombos, GetTimeSignatures, GetTickcounts, GetFakes, GetScrolls, GetSpeeds. + This should cover all of them now. [Wolfman2000] + 2011/06/13 ---------- * [InputHandler_DirectInput] Fixed MouseWheel input not resetting. [AJ] diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index f88325bed1..521b2c5e68 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1430,10 +1430,17 @@ + + + + + + + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 30e4ff0436..659e951332 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -3611,6 +3611,27 @@ Returns a table of the Labels and the times they happen as strings with the format "beat=label name." + + Returns a table of the Warps and the times they happen as strings with the format "beat=number of beats warped over." + + + Returns a table of the Combos and the times they happen as strings with the format "beat=combo value." + + + Returns a table of the Time Signatures and the times they happen as strings with the format "beat=beats per measure (numerator)=denominator." + + + Returns a table of the Tickcountss and the times they happen as strings with the format "beat=number of ticks per beat." + + + Returns a table of the Fakes and the times they happen as strings with the format "beat=number of beats to not judge." + + + Returns a table of the Scrolls and the times they happen as strings with the format "beat=scroll rate ratio." + + + Returns a table of the Speeds and the times they happen as strings with the format "beat=scroll rate ratio=length of time to fully activate=unit of activation (0 for beats, 1 for seconds)." + Returns true if the TimingData contains BPM changes. diff --git a/Themes/_fallback/Scripts/03 HSV.lua b/Themes/_fallback/Scripts/03 HSV.lua index a4b56baa5d..c2fd988ea7 100644 --- a/Themes/_fallback/Scripts/03 HSV.lua +++ b/Themes/_fallback/Scripts/03 HSV.lua @@ -246,4 +246,16 @@ function Hue(color,newHue) end c.Hue = newHue return HSVToColor(c) +end; + +function Alpha(color,percent) + local c = ColorToHSV(color); + -- error checking + if percent < 0 then + percent = 0.0; + elseif percent > 1 then + percent = 1.0; + end; + c.Alpha = percent; + return HSVToColor(c); end; \ No newline at end of file diff --git a/Themes/_fallback/Scripts/04 Scoring.lua b/Themes/_fallback/Scripts/04 Scoring.lua index fd579db996..c918bb60d7 100644 --- a/Themes/_fallback/Scripts/04 Scoring.lua +++ b/Themes/_fallback/Scripts/04 Scoring.lua @@ -84,14 +84,19 @@ r['DDR Extreme'] = function(params, pss) setmetatable(judgmentBase, ZeroIfNotFound); local steps = GAMESTATE:GetCurrentSteps(params.Player); local radarValues = steps:GetRadarValues(params.Player); - local baseScore = (steps:IsAnEdit() and - 5 or steps:GetMeter()) * 1000000; + local meter = steps:GetMeter(); + if (steps:IsAnEdit()) then + meter = 5; + elseif (meter < 1) then + meter = 1; + elseif (meter > 10) then + meter = 10; + end; + local baseScore = meter * 1000000; if (GAMESTATE:GetCurrentSong():IsMarathon()) then baseScore = baseScore * 3; - else - if (GAMESTATE:GetCurrentSong():IsLong()) then - baseScore = baseScore * 2; - end; + elseif (GAMESTATE:GetCurrentSong():IsLong()) then + baseScore = baseScore * 2; end; local totalItems = GetTotalItems(radarValues); local singleStep = (1 + totalItems) * totalItems / 2; diff --git a/sm-ssc.nsi b/sm-ssc.nsi index a7560744b1..653fe7458e 100644 --- a/sm-ssc.nsi +++ b/sm-ssc.nsi @@ -42,7 +42,7 @@ ; don't forget to change this before releasing a new verson. ; wish this could be automated, but it requires "X.Y.Z.a" format. -aj - VIProductVersion "1.2.3.0" + VIProductVersion "5.0.0.3" VIAddVersionKey "ProductName" "${PRODUCT_ID}" VIAddVersionKey "FileVersion" "${PRODUCT_VER}" VIAddVersionKey "FileDescription" "${PRODUCT_ID} Installer" diff --git a/src/AutoKeysounds.cpp b/src/AutoKeysounds.cpp index 068036bd69..b536a3aa95 100644 --- a/src/AutoKeysounds.cpp +++ b/src/AutoKeysounds.cpp @@ -63,6 +63,10 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain ) if( t >= m_ndAutoKeysoundsOnly[pn].GetNumTracks() ) continue; int iNextRowForPlayer = iRow; + /* XXX: If a BMS file only has one tap note per track, + * this will prevent any keysounds from loading. + * This leads to failure later on. + * We need a better way to prevent this. */ if( m_ndAutoKeysoundsOnly[pn].GetNextTapNoteRowForTrack( t, iNextRowForPlayer ) ) iNextRow = min( iNextRow, iNextRowForPlayer ); } @@ -274,7 +278,7 @@ void AutoKeysounds::FinishLoading() delete pChain; } } - ASSERT( m_pSharedSound ); + ASSERT_M( m_pSharedSound, ssprintf("No keysounds were loaded for the song %s!", pSong->m_sMainTitle.c_str() )); m_pSharedSound = new RageSoundReader_PitchChange( m_pSharedSound ); m_pSharedSound = new RageSoundReader_PostBuffering( m_pSharedSound ); diff --git a/src/EditMenu.cpp b/src/EditMenu.cpp index 8b39585144..274ff975b8 100644 --- a/src/EditMenu.cpp +++ b/src/EditMenu.cpp @@ -60,7 +60,7 @@ void EditMenu::GetSongsToShowForGroup( const RString &sGroup, vector &vpS for( int i=vpSongsOut.size()-1; i>=0; i-- ) { const Song* pSong = vpSongsOut[i]; - if( !pSong->NormallyDisplayed() || pSong->IsTutorial() || SONGMAN->WasLoadedFromAdditionalSongs(pSong) ) + if( !pSong->NormallyDisplayed() || pSong->IsTutorial() ) vpSongsOut.erase( vpSongsOut.begin()+i ); } break; diff --git a/src/EditMenu.h b/src/EditMenu.h index 28c9730d81..dac6767899 100644 --- a/src/EditMenu.h +++ b/src/EditMenu.h @@ -10,6 +10,7 @@ #include "EnumHelper.h" #include "ThemeMetric.h" +/** @brief What type of row is needed for the EditMenu? */ enum EditMenuRow { ROW_GROUP, @@ -19,11 +20,19 @@ enum EditMenuRow ROW_SOURCE_STEPS_TYPE, ROW_SOURCE_STEPS, ROW_ACTION, - NUM_EditMenuRow + NUM_EditMenuRow /**< The number of EditMenuRows available. */ }; /** @brief Loop through each EditMenuRow. */ #define FOREACH_EditMenuRow( r ) FOREACH_ENUM( EditMenuRow, r ) +/** + * @brief Turn the EditMenuRow into a string. + * @param r the row. + * @return the string. */ const RString& EditMenuRowToString( EditMenuRow r ); +/** + * @brief Turn the EditMenuRow into a localized string. + * @param r the row. + * @return the localized string. */ const RString& EditMenuRowToLocalizedString( EditMenuRow r ); /** @brief The different actions one can take on a step. */ @@ -38,9 +47,18 @@ enum EditMenuAction }; /** @brief Loop through each EditMenuAction. */ #define FOREACH_EditMenuAction( ema ) FOREACH_ENUM( EditMenuAction, ema ) +/** + * @brief Turn the EditMenuAction into a string. + * @param ema the action. + * @return the string. */ const RString& EditMenuActionToString( EditMenuAction ema ); +/** + * @brief Turn the EditMenuAction into a localized string. + * @param ema the action. + * @return the localized string. */ const RString& EditMenuActionToLocalizedString( EditMenuAction ema ); +/** @brief How many arrows are used for the EditMenu? */ const int NUM_ARROWS = 2; /** @@ -50,39 +68,110 @@ const int NUM_ARROWS = 2; class EditMenu: public ActorFrame { public: + /** @brief Set up the EditMenu. */ EditMenu(); + /** @brief Destroy the EditMenu. */ ~EditMenu(); void Load( const RString &sType ); + /** @brief Determine if we can move up. + * @return true if we can, false otherwise. */ bool CanGoUp(); + /** @brief Determine if we can move down. + * @return true if we can, false otherwise. */ bool CanGoDown(); + /** @brief Determine if we can move left. + * @return true if we can, false otherwise. */ bool CanGoLeft(); + /** @brief Determine if we can move right. + * @return true if we can, false otherwise. */ bool CanGoRight(); + /** @brief Determine if the EditMenuRow is selectable. + * @param row the row in question. + * @return true if it can be selected, false otherwise. */ bool RowIsSelectable( EditMenuRow row ); + /** @brief Move up to the next selection. */ void Up(); + /** @brief Move down to the next selection. */ void Down(); + /** @brief Move left to the next selection. */ void Left(); + /** @brief Move right to the next selection. */ void Right(); void RefreshAll(); - RString GetSelectedGroup() const + /** @brief Retrieve the currently selected group. + * @return the current group. */ + RString GetSelectedGroup() const { if( !SHOW_GROUPS.GetValue() ) return GROUP_ALL; - ASSERT_M((int)m_iSelection[ROW_GROUP] < (int)m_sGroups.size(), - ssprintf("Group selection %d < Number of groups %d", m_iSelection[ROW_GROUP], (int)m_sGroups.size())); + int groups = static_cast(m_sGroups.size()); + ASSERT_M(m_iSelection[ROW_GROUP] < groups, + ssprintf("Group selection %d < Number of groups %d", + m_iSelection[ROW_GROUP], + groups)); return m_sGroups[m_iSelection[ROW_GROUP]]; } - Song* GetSelectedSong() const { ASSERT(m_iSelection[ROW_SONG] < (int)m_pSongs.size()); return m_pSongs[m_iSelection[ROW_SONG]]; } - StepsType GetSelectedStepsType() const { ASSERT(m_iSelection[ROW_STEPS_TYPE] < (int)m_StepsTypes.size()); return m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]]; } - Steps* GetSelectedSteps() const { ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); return m_vpSteps[m_iSelection[ROW_STEPS]].pSteps; } - Difficulty GetSelectedDifficulty() const { ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); return m_vpSteps[m_iSelection[ROW_STEPS]].dc; } - StepsType GetSelectedSourceStepsType() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS_TYPE] < (int)m_StepsTypes.size()); return m_StepsTypes[m_iSelection[ROW_SOURCE_STEPS_TYPE]]; } - Steps* GetSelectedSourceSteps() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].pSteps; } - Difficulty GetSelectedSourceDifficulty() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].dc; } - EditMenuAction GetSelectedAction() const { ASSERT(m_iSelection[ROW_ACTION] < (int)m_Actions.size()); return m_Actions[m_iSelection[ROW_ACTION]]; } - + /** @brief Retrieve the currently selected song. + * @return the current song. */ + Song* GetSelectedSong() const + { + ASSERT(m_iSelection[ROW_SONG] < (int)m_pSongs.size()); + return m_pSongs[m_iSelection[ROW_SONG]]; + } + /** @brief Retrieve the currently selected steps type. + * @return the current steps type. */ + StepsType GetSelectedStepsType() const + { + ASSERT(m_iSelection[ROW_STEPS_TYPE] < (int)m_StepsTypes.size()); + return m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]]; + } + /** @brief Retrieve the currently selected steps. + * @return the current steps. */ + Steps* GetSelectedSteps() const + { + ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); + return m_vpSteps[m_iSelection[ROW_STEPS]].pSteps; + } + /** @brief Retrieve the currently selected difficulty. + * @return the current difficulty. */ + Difficulty GetSelectedDifficulty() const + { + ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); + return m_vpSteps[m_iSelection[ROW_STEPS]].dc; + } + /** @brief Retrieve the currently selected source steps type. + * @return the current source steps type. */ + StepsType GetSelectedSourceStepsType() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS_TYPE] < (int)m_StepsTypes.size()); + return m_StepsTypes[m_iSelection[ROW_SOURCE_STEPS_TYPE]]; + } + /** @brief Retrieve the currently selected source steps. + * @return the current source steps. */ + Steps* GetSelectedSourceSteps() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); + return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].pSteps; + } + /** @brief Retrieve the currently selected difficulty. + * @return the current difficulty. */ + Difficulty GetSelectedSourceDifficulty() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); + return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].dc; + } + /** @brief Retrieve the currently selected action. + * @return the current action. */ + EditMenuAction GetSelectedAction() const + { + ASSERT(m_iSelection[ROW_ACTION] < (int)m_Actions.size()); + return m_Actions[m_iSelection[ROW_ACTION]]; + } + /** @brief Retrieve the currently selected row. + * @return the current row. */ EditMenuRow GetSelectedRow() const { return m_SelectedRow; } private: diff --git a/src/EnumHelper.h b/src/EnumHelper.h index 3f9c60c295..dc1049cc0c 100644 --- a/src/EnumHelper.h +++ b/src/EnumHelper.h @@ -15,7 +15,12 @@ extern "C" /** @brief A general foreach loop for enumerators. */ #define FOREACH_ENUM( e, var ) for( e var=(e)0; var( var, +1 ) ) -int CheckEnum( lua_State *L, LuaReference &table, int iPos, int iInvalid, const char *szType, bool bAllowInvalid ); +int CheckEnum(lua_State *L, + LuaReference &table, + int iPos, + int iInvalid, + const char *szType, + bool bAllowInvalid); template struct EnumTraits @@ -33,7 +38,12 @@ namespace Enum template static T Check( lua_State *L, int iPos, bool bAllowInvalid = false ) { - return (T) CheckEnum( L, EnumTraits::StringToEnum, iPos, EnumTraits::Invalid, EnumTraits::szName, bAllowInvalid ); + return (T) CheckEnum(L, + EnumTraits::StringToEnum, + iPos, + EnumTraits::Invalid, + EnumTraits::szName, + bAllowInvalid); } template static void Push( lua_State *L, T iVal ) @@ -57,40 +67,47 @@ namespace Enum const RString &EnumToString( int iVal, int iMax, const char **szNameArray, auto_ptr *pNameCache ); // XToString helper #define XToString(X) \ - const RString& X##ToString(X x); \ - COMPILE_ASSERT( NUM_##X == ARRAYLEN(X##Names) ); \ - const RString& X##ToString( X x ) \ - { \ - static auto_ptr as_##X##Name[NUM_##X+2]; \ - return EnumToString( x, NUM_##X, X##Names, as_##X##Name ); \ - } \ - namespace StringConversion { template<> RString ToString( const X &value ) { return X##ToString(value); } } +const RString& X##ToString(X x); \ +COMPILE_ASSERT( NUM_##X == ARRAYLEN(X##Names) ); \ +const RString& X##ToString( X x ) \ +{ \ + static auto_ptr as_##X##Name[NUM_##X+2]; \ + return EnumToString( x, NUM_##X, X##Names, as_##X##Name ); \ +} \ +namespace StringConversion { template<> RString ToString( const X &value ) { return X##ToString(value); } } #define XToLocalizedString(X) \ - const RString &X##ToLocalizedString(X x); \ - const RString &X##ToLocalizedString( X x ) \ - { \ - static auto_ptr g_##X##Name[NUM_##X]; \ - if( g_##X##Name[0].get() == NULL ) { \ - for( unsigned i = 0; i < NUM_##X; ++i ) \ - { \ - auto_ptr ap( new LocalizedString(#X, X##ToString((X)i)) ); \ - g_##X##Name[i] = ap; \ - } \ +const RString &X##ToLocalizedString(X x); \ +const RString &X##ToLocalizedString( X x ) \ +{ \ + static auto_ptr g_##X##Name[NUM_##X]; \ + if( g_##X##Name[0].get() == NULL ) { \ + for( unsigned i = 0; i < NUM_##X; ++i ) \ + { \ + auto_ptr ap( new LocalizedString(#X, X##ToString((X)i)) ); \ + g_##X##Name[i] = ap; \ } \ - return g_##X##Name[x]->GetValue(); \ - } + } \ + return g_##X##Name[x]->GetValue(); \ +} #define StringToX(X) \ - X StringTo##X(const RString&); \ - X StringTo##X( const RString& s ) \ - { \ - for( unsigned i = 0; i < ARRAYLEN(X##Names); ++i ) \ - if( !s.CompareNoCase(X##Names[i]) ) \ - return (X)i; \ - return X##_Invalid; \ +X StringTo##X(const RString&); \ +X StringTo##X( const RString& s ) \ +{ \ + for( unsigned i = 0; i < ARRAYLEN(X##Names); ++i ) \ + if( !s.CompareNoCase(X##Names[i]) ) \ + return (X)i; \ + return X##_Invalid; \ +} \ +namespace StringConversion \ +{ \ + template<> bool FromString( const RString &sValue, X &out ) \ + { \ + out = StringTo##X(sValue); \ + return out != X##_Invalid; \ } \ - namespace StringConversion { template<> bool FromString( const RString &sValue, X &out ) { out = StringTo##X(sValue); return out != X##_Invalid; } } +} // currently unused #define LuaDeclareType(X) @@ -126,8 +143,21 @@ static void Lua##X(lua_State* L) \ REGISTER_WITH_LUA_FUNCTION( Lua##X ); \ template<> X EnumTraits::Invalid = X##_Invalid; \ template<> const char *EnumTraits::szName = #X; \ -namespace LuaHelpers { template<> bool FromStack( lua_State *L, X &Object, int iOffset ) { Object = Enum::Check( L, iOffset, true ); return Object != EnumTraits::Invalid; } } \ -namespace LuaHelpers { template<> void Push( lua_State *L, const X &Object ) { Enum::Push( L, Object ); } } +namespace LuaHelpers \ +{ \ + template<> bool FromStack( lua_State *L, X &Object, int iOffset ) \ + { \ + Object = Enum::Check( L, iOffset, true ); \ + return Object != EnumTraits::Invalid; \ + } \ +} \ +namespace LuaHelpers \ +{ \ + template<> void Push( lua_State *L, const X &Object ) \ + { \ + Enum::Push( L, Object ); \ + } \ +} #endif diff --git a/src/LifeMeterBattery.cpp b/src/LifeMeterBattery.cpp index 20f42ff4e7..3f49487a17 100644 --- a/src/LifeMeterBattery.cpp +++ b/src/LifeMeterBattery.cpp @@ -155,7 +155,7 @@ void LifeMeterBattery::ChangeLife( TapNoteScore score ) SubtractLives(MINES_SUBTRACT_LIVES); else { - if( score < MIN_SCORE_TO_KEEP_LIFE && SUBTRACT_LIVES > 0 ) + if( score < MIN_SCORE_TO_KEEP_LIFE && score > TNS_CheckpointMiss && SUBTRACT_LIVES > 0 ) SubtractLives(SUBTRACT_LIVES); } @@ -175,6 +175,12 @@ void LifeMeterBattery::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) AddLives(HELD_ADD_LIVES); if( score == HNS_LetGo && LET_GO_SUBTRACT_LIVES > 0 ) SubtractLives(LET_GO_SUBTRACT_LIVES); + + Message msg( "LifeChanged" ); + msg.SetParam( "Player", m_pPlayerState->m_PlayerNumber ); + msg.SetParam( "LifeMeter", LuaReference::CreateFromPush(*this) ); + msg.SetParam( "LivesLeft", GetLivesLeft() ); + MESSAGEMAN->Broadcast( msg ); } void LifeMeterBattery::HandleTapScoreNone() diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 68151e4cae..eff74fb0ae 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -803,6 +803,7 @@ RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out ) case TapNote::mine: case TapNote::empty: case TapNote::fake: + case TapNote::autoKeysound: continue; // skip these types - they don't count } diff --git a/src/NotesLoaderBMS.cpp b/src/NotesLoaderBMS.cpp index 4f53c0e152..c6bab7c292 100644 --- a/src/NotesLoaderBMS.cpp +++ b/src/NotesLoaderBMS.cpp @@ -696,6 +696,8 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } NameToData_t::const_iterator it; + + bool hasBGM = false; for( it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it ) { const RString &sName = it->first; @@ -745,6 +747,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo { if( bmsTrack == BMS_AUTO_KEYSOUND_1 ) { + hasBGM = true; // shift the auto keysound as far right as possible int iLastEmptyTrack = -1; if( ndNotes.GetTapLastEmptyTrack(row, iLastEmptyTrack) && @@ -772,6 +775,12 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } } + if (!hasBGM) + { + LOG->Warn("The song at %s is missing a #XXX01 tag! We're unable to load.", sPath.c_str()); + return false; + } + /* Handles hold notes like uBMPlay. * Different BMS simulators support hold notes differently. * See http://nvyu.net/rdm/ex.php for more info. @@ -964,7 +973,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo iTransformNewToOld[15] = BMS_P2_TURN; break; default: - ASSERT(0); + ASSERT_M(0, ssprintf("Invalid StepsType when parsing BMS file %s!", sPath.c_str())); } // shift all of the autokeysound tracks onto the main tracks @@ -990,7 +999,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } else { - LOG->UserLog( "Song file", sPath, "has too much simultenous autokeysound tracks." ); + LOG->UserLog( "Song file", sPath, "has too much simultaneous autokeysound tracks." ); } } } diff --git a/src/NotesLoaderKSF.cpp b/src/NotesLoaderKSF.cpp index c283ce7b53..3ad22bfbc4 100644 --- a/src/NotesLoaderKSF.cpp +++ b/src/NotesLoaderKSF.cpp @@ -20,66 +20,6 @@ static void HandleBunki( TimingData &timing, const float fEarlyBPM, timing.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), fCurBPM) ); } -static bool HandlePipeChars( TimingData &timing, const RString sNoteRow, - const float fCurBeat, int &iTickCount ) -{ - // gotta do something tricky here: if the bpm is below one then a couple of calculations - // for scrollsegments will be made, example, bpm 0.2, tick 4000, the scrollsegment will - // be 0. if the tickcount is non a stepmania standard then it will be adapted, a scroll - // segment will then be added based on approximations. - - RString temp = sNoteRow.substr(2,sNoteRow.size()-3); - float numTemp = StringToFloat(temp); - if (BeginsWith(sNoteRow, "|T")) - { - iTickCount = static_cast(numTemp); - timing.SetTickcountAtBeat( fCurBeat, clamp(iTickCount, 0, ROWS_PER_BEAT) ); - return true; - } - else if (BeginsWith(sNoteRow, "|B")) - { - timing.SetBPMAtBeat( fCurBeat, numTemp ); - return true; - } - else if (BeginsWith(sNoteRow, "|E")) - { - // Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster - float fCurDelay = 60 / timing.GetBPMAtBeat(fCurBeat) * numTemp / iTickCount; - fCurDelay += timing.GetDelayAtRow(BeatToNoteRow(fCurBeat) ); - timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); - return true; - } - else if (BeginsWith(sNoteRow, "|D")) - { - float fCurDelay = timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); - fCurDelay += numTemp / 1000; - timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); - return true; - } - else if (BeginsWith(sNoteRow, "|M") || BeginsWith(sNoteRow, "|C")) - { - // multipliers/combo - timing.SetComboAtBeat( fCurBeat, static_cast(numTemp) ); - return true; - } - else if (BeginsWith(sNoteRow, "|S")) - { - return false; - } - else if (BeginsWith(sNoteRow, "|F")) - { - // - return false; - } - - else if (BeginsWith(sNoteRow, "|X")) - { - timing.SetScrollAtBeat( fCurBeat, numTemp ); - return true; - } - return false; -} - static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, bool bKIUCompliant ) { LOG->Trace( "Steps::LoadFromKSFFile( '%s' )", sPath.c_str() ); @@ -91,7 +31,10 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, return false; } - int iTickCount = -1; // this is the value we read for TICKCOUNT + // this is the value we read for TICKCOUNT + int iTickCount = -1; + // used to adapt weird tickcounts + float fScrollRatio = 1.0f; vector vNoteRows; // According to Aldo_MX, there is a default BPM and it's 60. -aj @@ -350,21 +293,109 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, // Log an error, ignore the line. continue; } - if ( !HandlePipeChars( stepsTiming, sRowString, fCurBeat, iTickCount ) ) - { - // LOG it first. - } - continue; + // gotta do something tricky here: if the bpm is below one then a couple of calculations + // for scrollsegments will be made, example, bpm 0.2, tick 4000, the scrollsegment will + // be 0. if the tickcount is non a stepmania standard then it will be adapted, a scroll + // segment will then be added based on approximations. -DaisuMaster + // eh better do it considering the tickcount (high tickcounts) - } - - else - { - // Is this why improper ksf or some kiucompilant ksf mixed with dm05 ksf are ignored?? -DaisuMaster - //LOG->UserLog( "Song file", sPath, "has a RowString with an improper length \"%s\"; corrupt notes ignored.", - // sRowString.c_str() ); - //return false; - //continue; + // I'm making some experiments, please spare me... + + RString temp = sRowString.substr(2,sRowString.size()-3); + float numTemp = StringToFloat(temp); + if (BeginsWith(sRowString, "|T")) + { + // duh + iTickCount = static_cast(numTemp); + //if( iTickCount > ROWS_PER_BEAT ) + + /* adapt tickcounts // + // valid tickcounts for SM: 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 64, ROWS_PER_BEAT + // put this inside the tickcount handling condition yes/no + + if( iTickCount > ROWS_PER_BEAT ) // beyond 48 + { + // clamp/scale/whatever and use scroll segments + } + else if( iTickCount > 32 || iTickCount < ROWS_PER_BEAT ) // ranging from 33 to 48, approximate to 32 + { + fScrollRatio = 32; + iTickCount = 32; + } + else if( iTickCount > 24 || iTickCount < 32 ) // ranging from 25 to 31, approximate to 24 + { + fScrollRatio = 24; + iTickCount = 24; + } + else if( iTickCount > 16 || iTickCount < 24 ) // ranging from 17 to 23, approximate to 16 + { + fScrollRatio = 16; + iTickCount = 16; + } + else if( iTickCount > 12 || iTickCount < 16 ) // ranging from 13 to 15, approximate to 12 + { + fScrollRatio = 12; + iTickCount = 12; + } + else if( iTickCount > 8 || iTickCount < 12 ) // ranging from 9 to 11, approximate to 8 + { + fScrollRatio = 8; + iTickCount = 8; + } + else if( iTickCount > 6 || iTickCount < 8 ) // 7, approximate to 6 + { + fScrollRatio = 6 / iTickCountt; + iTickCount = 6; + } + else if( iTickCount > 4 || iTickCount < 6 ) // 5, approximate to 4 + { + fScrollRatio = iTickCount / 4; + iTickCount = 4; + } + //*/ + + stepsTiming.SetTickcountAtBeat( fCurBeat, clamp(iTickCount, 0, ROWS_PER_BEAT) ); + } + else if (BeginsWith(sRowString, "|B")) + { + // BPM + stepsTiming.SetBPMAtBeat( fCurBeat, numTemp ); + } + else if (BeginsWith(sRowString, "|E")) + { + // DelayBeat + float fCurDelay = 60 / stepsTiming.GetBPMAtBeat(fCurBeat) * numTemp / iTickCount; + fCurDelay += stepsTiming.GetDelayAtRow(BeatToNoteRow(fCurBeat) ); + stepsTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); + } + else if (BeginsWith(sRowString, "|D")) + { + // Delays + float fCurDelay = stepsTiming.GetStopAtRow(BeatToNoteRow(fCurBeat) ); + fCurDelay += numTemp / 1000; + stepsTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); + } + else if (BeginsWith(sRowString, "|M") || BeginsWith(sRowString, "|C")) + { + // multipliers/combo + stepsTiming.SetComboAtBeat( fCurBeat, static_cast(numTemp) ); + } + else if (BeginsWith(sRowString, "|S")) + { + // speed segments + } + else if (BeginsWith(sRowString, "|F")) + { + // fakes + } + else if (BeginsWith(sRowString, "|X")) + { + // scroll segments + stepsTiming.SetScrollAtBeat( fCurBeat, numTemp ); + return true; + } + + continue; } // Half-doubles is offset; "0011111100000". @@ -485,7 +516,7 @@ static void LoadTags( const RString &str, Song &out ) out.m_sArtist = artist; } -static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant ) +static bool LoadGlobalData( const RString &sPath, Song &out, bool bKIUCompliant ) { MsdFile msd; if( !msd.ReadFile( sPath, false ) ) // don't unescape @@ -658,14 +689,11 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant } // This is where the DMRequired test will take place. - if (BeginsWith(NoteRowString, "|T") || BeginsWith(NoteRowString, "|B") || - BeginsWith(NoteRowString, "|D") || BeginsWith(NoteRowString, "|E") ) + //if (BeginsWith(NoteRowString, "|T") || BeginsWith(NoteRowString, "|B") || BeginsWith(NoteRowString, "|D") || BeginsWith(NoteRowString, "|E") ) + if ( BeginsWith( NoteRowString, "|" ) ) { + // have a static timing for everything bDMRequired = true; - if ( !HandlePipeChars( out.m_SongTiming, NoteRowString, fCurBeat, iTickCount ) ) - { - // LOG it first. - } continue; } else @@ -705,21 +733,32 @@ bool KSFLoader::LoadFromDir( const RString &sDir, Song &out ) // We shouldn't have been called to begin with if there were no KSFs. ASSERT( arrayKSFFileNames.size() ); - bool bKIUCompliant = false; + //bool bKIUCompliant = false; /* With Split Timing, there has to be a backup Song Timing in case * anything goes wrong. As these files are kept in alphabetical * order (hopefully), it is best to use the LAST file for timing * purposes, for that is the "normal", or easiest difficulty. * Usually. */ + // Nevermind, kiu compilancy is screwing things up: + // IE, I have two simfiles, oh wich each have four ksf files, the first one has + // the first ksf with directmove timing changes, and the rest are not, everything + // goes fine. In the other hand I have my second simfile with the first ksf file + // without directmove timing changes and the rest have changes, changes are not + // loaded due to kiucompilancy in the first ksf file. + // About the "normal" thing, my simfiles' ksfs uses non-standard naming so + // the last chart is usually nightmare or normal, I use easy and normal + // indistinctly for SM so it shouldn't matter, I use piu fiesta/ex naming + // for directmove though, and we're just gathering basic info anyway, and + // most of the time all the KSF files have the same info in the #TITLE:; section unsigned files = arrayKSFFileNames.size(); - if( !LoadGlobalData(out.GetSongDir() + arrayKSFFileNames[files - 1], out, bKIUCompliant) ) + if( !LoadGlobalData(out.GetSongDir() + arrayKSFFileNames[0], out, false) ) return false; // load the Steps from the rest of the KSF files for( unsigned i=0; i apDriverList; + ReferenceAllDrivers( apDriverList ); + + for( unsigned i = 0; i < apDriverList.size(); ++i ) + { + LoadedDriver *pDriver = apDriverList[i]; + const RString driverPath = pDriver->GetPath( tmpPath ); + + if ( driverPath.empty() || pDriver->m_sRoot.empty() ) + continue; + + if ( pDriver->m_sType != "dir" && pDriver->m_sType != "dirro" ) + continue; + + int iMountPointLen = pDriver->m_sMountPoint.length(); + if( tmpPath.substr(0, iMountPointLen) != pDriver->m_sMountPoint ) + continue; + + resolvedPath = pDriver->m_sRoot + "/" + RString(tmpPath.substr(iMountPointLen)); + break; + } + + UnreferenceAllDrivers( apDriverList ); + + NormalizePath( resolvedPath ); + + return resolvedPath; +} + static bool SortBySecond( const pair &a, const pair &b ) { return a.second < b.second; diff --git a/src/RageFileManager.h b/src/RageFileManager.h index 12c6ca1fe0..7eaa445852 100644 --- a/src/RageFileManager.h +++ b/src/RageFileManager.h @@ -37,6 +37,12 @@ public: int GetFileSizeInBytes( const RString &sPath ); int GetFileHash( const RString &sPath ); + + /** + * @brief Get the absolte path from the VPS. + * @param path the VPS path. + * @return the absolute path. */ + RString ResolvePath(const RString &path); bool Mount( const RString &sType, const RString &sRealPath, const RString &sMountPoint, bool bAddToEnd = true ); void Mount( RageFileDriver *pDriver, const RString &sMountPoint, bool bAddToEnd = true ); diff --git a/src/Song.cpp b/src/Song.cpp index 8cf6d352a7..ba1069f731 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -41,7 +41,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 180; +const int FILE_CACHE_VERSION = 182; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; @@ -190,7 +190,9 @@ RString Song::GetCacheFilePath() const // Get a path to the SM containing data for this song. It might be a cache file. const RString &Song::GetSongFilePath() const { - ASSERT( !m_sSongFileName.empty() ); + ASSERT_M( !m_sSongFileName.empty(), + ssprintf("The song %s has no filename associated with it!", + this->m_sMainTitle.c_str())); return m_sSongFileName; } diff --git a/src/SongManager.cpp b/src/SongManager.cpp index 56afe8f93e..9550ae3c75 100644 --- a/src/SongManager.cpp +++ b/src/SongManager.cpp @@ -999,11 +999,14 @@ void SongManager::Cleanup() for( unsigned i=0; i& vpSteps = pSong->GetAllSteps(); - for( unsigned n=0; nCompress(); + const vector& vpSteps = pSong->GetAllSteps(); + for( unsigned n=0; nCompress(); + } } } } diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 660b5e50c0..579d11c635 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -1670,6 +1670,93 @@ public: static int HasFakes( T* p, lua_State *L ) { lua_pushboolean(L, p->HasFakes()); return 1; } static int HasSpeedChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSpeedChanges()); return 1; } static int HasScrollChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasScrollChanges()); return 1; } + static int GetWarps( T* p, lua_State *L ) + { + vector vWarps; + FOREACH_CONST( WarpSegment, p->m_WarpSegments, seg ) + { + const float length = seg->GetLength(); + const float beat = seg->GetBeat(); + vWarps.push_back( ssprintf("%f=%f", beat, length) ); + } + LuaHelpers::CreateTableFromArray(vWarps, L); + return 1; + } + static int GetFakes( T* p, lua_State *L ) + { + vector vFakes; + FOREACH_CONST( FakeSegment, p->m_FakeSegments, seg ) + { + const float length = seg->GetLength(); + const float beat = seg->GetBeat(); + vFakes.push_back( ssprintf("%f=%f", beat, length) ); + } + LuaHelpers::CreateTableFromArray(vFakes, L); + return 1; + } + static int GetScrolls( T* p, lua_State *L ) + { + vector vScrolls; + FOREACH_CONST( ScrollSegment, p->m_ScrollSegments, seg ) + { + const float ratio = seg->GetRatio(); + const float beat = seg->GetBeat(); + vScrolls.push_back( ssprintf("%f=%f", beat, ratio) ); + } + LuaHelpers::CreateTableFromArray(vScrolls, L); + return 1; + } + static int GetSpeeds( T* p, lua_State *L ) + { + vector vSpeeds; + FOREACH_CONST( SpeedSegment, p->m_SpeedSegments, seg ) + { + const float length = seg->GetLength(); + const float ratio = seg->GetRatio(); + const unsigned short unit = seg->GetUnit(); + const float beat = seg->GetBeat(); + vSpeeds.push_back( ssprintf("%f=%f=%f=%uh", beat, ratio, length, unit) ); + } + LuaHelpers::CreateTableFromArray(vSpeeds, L); + return 1; + } + static int GetTimeSignatures( T* p, lua_State *L ) + { + vector vTimes; + FOREACH_CONST( TimeSignatureSegment, p->m_vTimeSignatureSegments, seg ) + { + const int numerator = seg->GetNum(); + const int denominator = seg->GetDen(); + const float beat = seg->GetBeat(); + vTimes.push_back( ssprintf("%f=%d=%d", beat, numerator, denominator) ); + } + LuaHelpers::CreateTableFromArray(vTimes, L); + return 1; + } + static int GetCombos( T* p, lua_State *L ) + { + vector vCombos; + FOREACH_CONST( ComboSegment, p->m_ComboSegments, seg ) + { + const int combo = seg->GetCombo(); + const float beat = seg->GetBeat(); + vCombos.push_back( ssprintf("%f=%d", beat, combo) ); + } + LuaHelpers::CreateTableFromArray(vCombos, L); + return 1; + } + static int GetTickcounts( T* p, lua_State *L ) + { + vector vTicks; + FOREACH_CONST( TickcountSegment, p->m_TickcountSegments, seg ) + { + const int ticks = seg->GetTicks(); + const float beat = seg->GetBeat(); + vTicks.push_back( ssprintf("%f=%d", beat, ticks) ); + } + LuaHelpers::CreateTableFromArray(vTicks, L); + return 1; + } static int GetStops( T* p, lua_State *L ) { vector vStops; @@ -1763,6 +1850,13 @@ public: ADD_METHOD( GetStops ); ADD_METHOD( GetDelays ); ADD_METHOD( GetBPMs ); + ADD_METHOD( GetWarps ); + ADD_METHOD( GetFakes ); + ADD_METHOD( GetTimeSignatures ); + ADD_METHOD( GetTickcounts ); + ADD_METHOD( GetSpeeds ); + ADD_METHOD( GetScrolls ); + ADD_METHOD( GetCombos ); ADD_METHOD( GetLabels ); ADD_METHOD( GetBPMsAndTimes ); ADD_METHOD( GetActualBPM ); diff --git a/src/UnlockManager.cpp b/src/UnlockManager.cpp index 47af088551..18cee4407f 100644 --- a/src/UnlockManager.cpp +++ b/src/UnlockManager.cpp @@ -295,7 +295,7 @@ void UnlockManager::GetPoints( const Profile *pProfile, float fScores[NUM_Unlock fScores[UnlockRequirement_SongPoints] = GetSongPoints( pProfile ); fScores[UnlockRequirement_DancePoints] = (float) pProfile->m_iTotalDancePoints; fScores[UnlockRequirement_StagesCleared] = (float) pProfile->GetTotalNumSongsPassed(); - fScores[UnlockRequirement_NumUnlocked] = (float) GetNumUnlocked(); + //fScores[UnlockRequirement_NumUnlocked] = (float) GetNumUnlocked(); } /* Return true if all songs and/or courses referenced by an unlock are available. */ @@ -330,8 +330,13 @@ UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const UNLOCKMAN->GetPoints( PROFILEMAN->GetMachineProfile(), fScores ); for( int i = 0; i < NUM_UnlockRequirement; ++i ) + { + if( i == UnlockRequirement_NumUnlocked ) + continue; + if( m_fRequirement[i] && fScores[i] >= m_fRequirement[i] ) return UnlockEntryStatus_RequirementsMet; + } if( m_bRequirePassHardSteps && m_Song.IsValid() ) { @@ -348,7 +353,6 @@ UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const return UnlockEntryStatus_RequirementsMet; } - return UnlockEntryStatus_RequrementsNotMet; } @@ -601,7 +605,7 @@ int UnlockManager::GetNumUnlocked() const int count = 0; FOREACH_CONST( UnlockEntry, m_UnlockEntries, ue ) { - if( ue->GetUnlockEntryStatus() == UnlockEntryStatus_Unlocked ) + if( !ue->IsLocked() ) count++; } return count;