From 846f79879c067079e3a69e17a1d55b219f61ce60 Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Mon, 2 Mar 2015 18:44:01 -0700 Subject: [PATCH 1/2] Added MUSIC tag to note data to allow each chart in a simfile to use a different music file. --- Themes/_fallback/Languages/en.ini | 3 ++ src/AutoKeysounds.cpp | 2 +- src/GameState.cpp | 71 +++++++++++++++++++++++++++++++ src/GameState.h | 1 + src/NotesLoaderSSC.cpp | 5 +++ src/NotesWriterSSC.cpp | 6 +++ src/ScreenEdit.cpp | 35 ++++++++++++++- src/ScreenEdit.h | 1 + src/ScreenSelectMusic.cpp | 1 + src/Song.cpp | 2 +- src/Song.h | 1 + src/SongUtil.cpp | 18 ++++++++ src/SongUtil.h | 1 + src/Steps.cpp | 17 ++++++++ src/Steps.h | 8 +++- 15 files changed, 167 insertions(+), 5 deletions(-) diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 8f23a9e5c8..2b044f4113 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -1115,6 +1115,7 @@ Modify Attacks at current beat=Modify attacks at current beat MoveRandomToEnd=Random At End More Options=More Options MovieColorDepth=Movie Color +Music File=Music File MusicWheelSwitchSpeed=Wheel Speed MusicWheelUsesSections=Wheel Sections Network Options=Network Options @@ -1512,6 +1513,7 @@ Enter a new preview start.=Enter when the music sample starts. Enter a new preview length.=Enter how long the music sample lasts. Enter a new min BPM.=Enter the minimum displayed BPM. Enter a new max BPM.=Enter the maximum displayed BPM. +Enter the music file for this chart.=Enter the music file for this chart. Leave blank to use the song music. Enter the new track mapping.=Enter the new track mapping. Entry %d, '%d', is out of range 1 to %d.=Entry %d, '%d', is out of range 1 to %d. More than %d notes per measure is not allowed. This change has been reverted.=More than %d notes per measure is not allowed. This change has been reverted. @@ -1997,6 +1999,7 @@ The name you chose conflicts with another edit. Please use a different name.=The The chart name cannot contain any of the following characters: %s=The chart name cannot contain any of the following characters: %s The edit name cannot contain any of the following characters: %s=The edit name can not contain any of the following characters: %s The step author's name cannot contain any of the following characters: %s=The step author's name cannot contain any of the following characters: %s +The music file '%s' does not exist.=The music file '%s' does not exist. [SongSort] FewestPlays=Fewest Plays diff --git a/src/AutoKeysounds.cpp b/src/AutoKeysounds.cpp index 8c6c59f857..9789059c14 100644 --- a/src/AutoKeysounds.cpp +++ b/src/AutoKeysounds.cpp @@ -127,7 +127,7 @@ void AutoKeysounds::LoadTracks( const Song *pSong, RageSoundReader *&pShared, Ra pShared = NULL; vector vsMusicFile; - const RString sMusicPath = pSong->GetMusicPath(); + const RString sMusicPath = GAMESTATE->m_pCurSteps[GAMESTATE->GetMasterPlayerNumber()]->GetMusicPath(); if( !sMusicPath.empty() ) vsMusicFile.push_back( sMusicPath ); diff --git a/src/GameState.cpp b/src/GameState.cpp index b3d91d9b90..84dcfdb74f 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -1077,6 +1077,75 @@ void GameState::ForceSharedSidesMatch() } } +void GameState::ForceOtherPlayersToCompatibleSteps(PlayerNumber main) +{ + if(IsCourseMode()) + { + Trail* steps_to_match= m_pCurTrail[main].Get(); + if(steps_to_match == NULL) { return; } + int num_players= GAMESTATE->GetNumPlayersEnabled(); + StyleType styletype_to_match= GAMEMAN->GetFirstCompatibleStyle( + GAMESTATE->GetCurrentGame(), num_players, steps_to_match->m_StepsType) + ->m_StyleType; + FOREACH_EnabledPlayer(pn) + { + Trail* pn_steps= m_pCurTrail[pn].Get(); + bool match_failed= false; + if(steps_to_match != pn_steps && pn_steps != NULL) + { + StyleType pn_styletype= GAMEMAN->GetFirstCompatibleStyle( + GAMESTATE->GetCurrentGame(), num_players, pn_steps->m_StepsType) + ->m_StyleType; + if(styletype_to_match == StyleType_TwoPlayersSharedSides || + pn_styletype == StyleType_TwoPlayersSharedSides) + { + match_failed= true; + } + + if(match_failed) + { + m_pCurTrail[pn].Set(steps_to_match); + } + } + } + } + else + { + Steps* steps_to_match= m_pCurSteps[main].Get(); + if(steps_to_match == NULL) { return; } + int num_players= GAMESTATE->GetNumPlayersEnabled(); + StyleType styletype_to_match= GAMEMAN->GetFirstCompatibleStyle( + GAMESTATE->GetCurrentGame(), num_players, steps_to_match->m_StepsType) + ->m_StyleType; + RString music_to_match= steps_to_match->GetMusicFile(); + FOREACH_EnabledPlayer(pn) + { + Steps* pn_steps= m_pCurSteps[pn].Get(); + bool match_failed= false; + if(steps_to_match != pn_steps && pn_steps != NULL) + { + StyleType pn_styletype= GAMEMAN->GetFirstCompatibleStyle( + GAMESTATE->GetCurrentGame(), num_players, pn_steps->m_StepsType) + ->m_StyleType; + if(styletype_to_match == StyleType_TwoPlayersSharedSides || + pn_styletype == StyleType_TwoPlayersSharedSides) + { + match_failed= true; + } + if(music_to_match != pn_steps->GetMusicFile()) + { + match_failed= true; + } + + if(match_failed) + { + m_pCurSteps[pn].Set(steps_to_match); + } + } + } + } +} + void GameState::Update( float fDelta ) { m_SongOptions.Update( fDelta ); @@ -2602,6 +2671,7 @@ public: Steps *pS = Luna::check(L,2); SetCompatibleStyleOrError(p, L, pS->m_StepsType, pn); p->m_pCurSteps[pn].Set(pS); + p->ForceOtherPlayersToCompatibleSteps(pn); } COMMON_RETURN_SELF; } @@ -2632,6 +2702,7 @@ public: Trail *pS = Luna::check(L,2); SetCompatibleStyleOrError(p, L, pS->m_StepsType, pn); p->m_pCurTrail[pn].Set(pS); + p->ForceOtherPlayersToCompatibleSteps(pn); } COMMON_RETURN_SELF; } diff --git a/src/GameState.h b/src/GameState.h index 0001dd15f1..929822b625 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -76,6 +76,7 @@ public: bool CanSafelyEnterGameplay(RString& reason); void SetCompatibleStylesForPlayers(); void ForceSharedSidesMatch(); + void ForceOtherPlayersToCompatibleSteps(PlayerNumber main); void Update( float fDelta ); diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 5f1d084dfb..f4c867439b 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -722,6 +722,11 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach pNewNotes->SetFilename(sPath); out.AddSteps( pNewNotes ); } + + else if(sValueName == "MUSIC") + { + pNewNotes->SetMusicFile(sParams[1]); + } else if( sValueName=="BPMS" ) { diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 1f5971f149..1e7a627573 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -358,6 +358,12 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa lines.push_back( ssprintf( "#DIFFICULTY:%s;", DifficultyToString(in.GetDifficulty()).c_str() ) ); lines.push_back( ssprintf( "#METER:%d;", in.GetMeter() ) ); + const RString& music= in.GetMusicFile(); + if(!music.empty()) + { + lines.push_back(ssprintf("#MUSIC:%s;", music.c_str())); + } + vector asRadarValues; FOREACH_PlayerNumber( pn ) { diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 3caf613f97..bde1114bc2 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -105,6 +105,7 @@ AutoScreenMessage( SM_BackFromSpeedWaitChange ); AutoScreenMessage( SM_BackFromSpeedModeChange ); AutoScreenMessage( SM_BackFromScrollChange ); AutoScreenMessage( SM_BackFromFakeChange ); +AutoScreenMessage( SM_BackFromStepMusicChange ); AutoScreenMessage( SM_DoEraseStepTiming ); AutoScreenMessage( SM_DoSaveAndExit ); AutoScreenMessage( SM_DoExit ); @@ -914,7 +915,9 @@ static MenuDef g_StepsInformation( true, EditMode_Full, true, true, 0, NULL ), MenuRowDef(ScreenEdit::step_max_bpm, "Max BPM", - true, EditMode_Full, true, true, 0, NULL ) + true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::step_music, + "Music File", true, EditMode_Full,true, true, 0, NULL) ); static MenuDef g_StepsData( @@ -2339,6 +2342,9 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) int(vSteps.size()) ); SCREENMAN->SystemMessage( s ); m_soundSwitchSteps.Play(); + // Reload the music because it can be different for every steps. -Kyz + m_AutoKeysounds.FinishLoading(); + m_pSoundMusic = m_AutoKeysounds.GetSound(); ScrollTo( GetAppropriateTiming().GetBeatFromElapsedTime(curSecond) ); } @@ -3659,7 +3665,12 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) SetDirty( true ); } } - + else if ( SM == SM_BackFromStepMusicChange && !ScreenTextEntry::s_bCancelledLast ) + { + // Reload the music because it just changed. -Kyz + m_AutoKeysounds.FinishLoading(); + m_pSoundMusic = m_AutoKeysounds.GetSound(); + } else if( SM == SM_BackFromBGChange ) { HandleBGChangeChoice( (BGChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); @@ -4288,6 +4299,12 @@ static void ChangeStepMeter( const RString &sNew ) GAMESTATE->m_pCurSteps[PLAYER_1]->SetMeter(max(diff, 1)); } +static void ChangeStepMusic(const RString& sNew) +{ + Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + pSteps->SetMusicFile(sNew); +} + static void ChangeMainTitle( const RString &sNew ) { Song* pSong = GAMESTATE->m_pCurSong; @@ -4571,6 +4588,8 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_StepsInformation.rows[step_display_bpm].iDefaultChoice = pSteps->GetDisplayBPM(); g_StepsInformation.rows[step_min_bpm].SetOneUnthemedChoice( FloatToString(pSteps->GetMinBPM())); g_StepsInformation.rows[step_max_bpm].SetOneUnthemedChoice( FloatToString(pSteps->GetMaxBPM())); + g_StepsInformation.rows[step_music].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); + g_StepsInformation.rows[step_music].SetOneUnthemedChoice( pSteps->GetMusicFile() ); EditMiniMenu( &g_StepsInformation, SM_BackFromStepsInformation, SM_None ); } break; @@ -5328,6 +5347,7 @@ static LocalizedString ENTER_NEW_STEP_AUTHOR( "ScreenEdit", "Enter the author wh static LocalizedString ENTER_NEW_METER( "ScreenEdit", "Enter a new meter." ); static LocalizedString ENTER_MIN_BPM ("ScreenEdit","Enter a new min BPM."); static LocalizedString ENTER_MAX_BPM ("ScreenEdit","Enter a new max BPM."); +static LocalizedString ENTER_NEW_STEP_MUSIC("ScreenEdit", "Enter the music file for this chart."); void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ) { Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; @@ -5408,6 +5428,17 @@ void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const v ChangeStepsMaxBPM, NULL); break; } + case step_music: + { + ScreenTextEntry::TextEntry(SM_BackFromStepMusicChange, + ENTER_NEW_STEP_MUSIC, + m_pSteps->GetMusicFile(), + 255, + SongUtil::ValidateCurrentStepsMusic, + ChangeStepMusic, + NULL); + break; + } default: break; } diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index 73958de654..7778604039 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -537,6 +537,7 @@ public: step_display_bpm, step_min_bpm, step_max_bpm, + step_music, NUM_STEPS_INFORMATION_CHOICES }; void HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ); diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index 985c019e5b..768e348a73 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -1039,6 +1039,7 @@ void ScreenSelectMusic::ChangeSteps( PlayerNumber pn, int dir ) m_soundDifficultyHarder.SetProperty( "Pan", fBalance ); m_soundDifficultyHarder.PlayCopy(); } + GAMESTATE->ForceOtherPlayersToCompatibleSteps(pn); Message msg( "ChangeSteps" ); msg.SetParam( "Player", pn ); diff --git a/src/Song.cpp b/src/Song.cpp index 343a61009c..5d742dde71 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -1394,7 +1394,7 @@ vector Song::GetInstrumentTracksToVectorString() const return ret; } -RString GetSongAssetPath( RString sPath, const RString &sSongPath ) +RString Song::GetSongAssetPath( RString sPath, const RString &sSongPath ) { if( sPath == "" ) return RString(); diff --git a/src/Song.h b/src/Song.h index 76c1bd360d..d26167ebba 100644 --- a/src/Song.h +++ b/src/Song.h @@ -247,6 +247,7 @@ public: AttackArray m_Attacks; vector m_sAttackString; + static RString GetSongAssetPath( RString sPath, const RString &sSongPath ); RString GetMusicPath() const; RString GetInstrumentTrackPath( InstrumentTrack it ) const; RString GetBannerPath() const; diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index e5017a44ec..c86d232432 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -899,6 +899,24 @@ bool SongUtil::ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErr return true; } +static LocalizedString MUSIC_DOES_NOT_EXIST("SongUtil", "The music file '%s' does not exist."); +bool SongUtil::ValidateCurrentStepsMusic(const RString &answer, RString &error) +{ + if(answer.empty()) + return true; + Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + RString real_file= pSteps->GetMusicFile(); + pSteps->SetMusicFile(answer); + RString path= pSteps->GetMusicPath(); + bool valid= DoesFileExist(path); + pSteps->SetMusicFile(real_file); + if(!valid) + { + error= ssprintf(MUSIC_DOES_NOT_EXIST.GetValue(), answer.c_str()); + } + return valid; +} + void SongUtil::GetAllSongGenres( vector &vsOut ) { set genres; diff --git a/src/SongUtil.h b/src/SongUtil.h index 97ea6e5616..0594eb3f83 100644 --- a/src/SongUtil.h +++ b/src/SongUtil.h @@ -165,6 +165,7 @@ namespace SongUtil bool ValidateCurrentStepsDescription( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsChartName(const RString &answer, RString &error); + bool ValidateCurrentStepsMusic(const RString &answer, RString &error); void GetAllSongGenres( vector &vsOut ); /** diff --git a/src/Steps.cpp b/src/Steps.cpp index 0dbc71c05c..d8847deb24 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -589,6 +589,23 @@ bool Steps::HasSignificantTimingChanges() const return false; } +const RString Steps::GetMusicPath() const +{ + return Song::GetSongAssetPath( + m_MusicFile.empty() ? m_pSong->m_sMusicFile : m_MusicFile, + m_pSong->GetSongDir()); +} + +const RString& Steps::GetMusicFile() const +{ + return m_MusicFile; +} + +void Steps::SetMusicFile(const RString& file) +{ + m_MusicFile= file; +} + void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] ) { DeAutogen(); diff --git a/src/Steps.h b/src/Steps.h index 05440011b6..15fd7f882a 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -173,6 +173,10 @@ public: * @return true if it does, or false otherwise. */ bool HasAttacks() const; + const RString GetMusicPath() const; // Returns the path for loading. + const RString& GetMusicFile() const; // Returns the filename for the simfile. + void SetMusicFile(const RString& file); + // Lua void PushSelf( lua_State *L ); @@ -218,7 +222,9 @@ private: /** @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; + bool m_bSavedToDisk; + /** @brief allows the steps to specify their own music file. */ + RString m_MusicFile; /** @brief What profile was used? This is ProfileSlot_Invalid if not from a profile. */ ProfileSlot m_LoadedFromProfile; From fc8da6b485db3a4184f7cb85d4b4baf1045b06d9 Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Mon, 2 Mar 2015 19:01:17 -0700 Subject: [PATCH 2/2] Update file cache version. --- src/Song.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Song.cpp b/src/Song.cpp index 5d742dde71..6a30587d34 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -43,7 +43,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 222; +const int FILE_CACHE_VERSION = 223; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;