diff --git a/src/Difficulty.cpp b/src/Difficulty.cpp index 0201139495..1d49ae4615 100644 --- a/src/Difficulty.cpp +++ b/src/Difficulty.cpp @@ -47,43 +47,29 @@ CourseDifficulty GetNextShownCourseDifficulty( CourseDifficulty cd ) return Difficulty_Invalid; } -struct OldStyleStringToDifficultyMapHolder -{ - std::map conversion_map; - OldStyleStringToDifficultyMapHolder() - { - conversion_map["beginner"]= Difficulty_Beginner; - conversion_map["easy"]= Difficulty_Easy; - conversion_map["basic"]= Difficulty_Easy; - conversion_map["light"]= Difficulty_Easy; - conversion_map["medium"]= Difficulty_Medium; - conversion_map["another"]= Difficulty_Medium; - conversion_map["trick"]= Difficulty_Medium; - conversion_map["standard"]= Difficulty_Medium; - conversion_map["difficult"]= Difficulty_Medium; - conversion_map["hard"]= Difficulty_Hard; - conversion_map["ssr"]= Difficulty_Hard; - conversion_map["maniac"]= Difficulty_Hard; - conversion_map["heavy"]= Difficulty_Hard; - conversion_map["smaniac"]= Difficulty_Challenge; - conversion_map["challenge"]= Difficulty_Challenge; - conversion_map["expert"]= Difficulty_Challenge; - conversion_map["oni"]= Difficulty_Challenge; - conversion_map["edit"]= Difficulty_Edit; - } -}; -OldStyleStringToDifficultyMapHolder OldStyleStringToDifficulty_converter; Difficulty OldStyleStringToDifficulty( const RString& sDC ) { RString s2 = sDC; s2.MakeLower(); - std::map::iterator diff= - OldStyleStringToDifficulty_converter.conversion_map.find(s2); - if(diff != OldStyleStringToDifficulty_converter.conversion_map.end()) - { - return diff->second; - } - return Difficulty_Invalid; + if( s2 == "beginner" ) return Difficulty_Beginner; + else if( s2 == "easy" ) return Difficulty_Easy; + else if( s2 == "basic" ) return Difficulty_Easy; + else if( s2 == "light" ) return Difficulty_Easy; + else if( s2 == "medium" ) return Difficulty_Medium; + else if( s2 == "another" ) return Difficulty_Medium; + else if( s2 == "trick" ) return Difficulty_Medium; + else if( s2 == "standard" ) return Difficulty_Medium; + else if( s2 == "difficult") return Difficulty_Medium; + else if( s2 == "hard" ) return Difficulty_Hard; + else if( s2 == "ssr" ) return Difficulty_Hard; + else if( s2 == "maniac" ) return Difficulty_Hard; + else if( s2 == "heavy" ) return Difficulty_Hard; + else if( s2 == "smaniac" ) return Difficulty_Challenge; + else if( s2 == "challenge" ) return Difficulty_Challenge; + else if( s2 == "expert" ) return Difficulty_Challenge; + else if( s2 == "oni" ) return Difficulty_Challenge; + else if( s2 == "edit" ) return Difficulty_Edit; + else return Difficulty_Invalid; } LuaFunction( OldStyleStringToDifficulty, OldStyleStringToDifficulty(SArg(1)) ); diff --git a/src/GameConstantsAndTypes.cpp b/src/GameConstantsAndTypes.cpp index 8bfec7c0b9..8c406f82c9 100644 --- a/src/GameConstantsAndTypes.cpp +++ b/src/GameConstantsAndTypes.cpp @@ -201,34 +201,30 @@ static const char *TapNoteScoreNames[] = { "W1", "CheckpointHit", }; -struct tns_conversion_helper -{ - std::map conversion_map; - tns_conversion_helper() - { - FOREACH_ENUM(TapNoteScore, tns) - { - conversion_map[TapNoteScoreNames[tns]]= tns; - } - // for backward compatibility - conversion_map["Boo"]= TNS_W5; - conversion_map["Good"]= TNS_W4; - conversion_map["Great"]= TNS_W3; - conversion_map["Perfect"]= TNS_W2; - conversion_map["Marvelous"]= TNS_W1; - } -}; -tns_conversion_helper tns_converter; XToString( TapNoteScore ); LuaXType( TapNoteScore ); TapNoteScore StringToTapNoteScore( const RString &s ) { - std::map::iterator tns= - tns_converter.conversion_map.find(s); - if(tns != tns_converter.conversion_map.end()) - { - return tns->second; - } + // new style + if ( s == "None" ) return TNS_None; + else if( s == "HitMine" ) return TNS_HitMine; + else if( s == "AvoidMine" ) return TNS_AvoidMine; + else if( s == "CheckpointHit" ) return TNS_CheckpointHit; + else if( s == "CheckpointMiss" )return TNS_CheckpointMiss; + else if( s == "Miss" ) return TNS_Miss; + else if( s == "W5" ) return TNS_W5; + else if( s == "W4" ) return TNS_W4; + else if( s == "W3" ) return TNS_W3; + else if( s == "W2" ) return TNS_W2; + else if( s == "W1" ) return TNS_W1; + + // for backward compatibility + else if( s == "Boo" ) return TNS_W5; + else if( s == "Good" ) return TNS_W4; + else if( s == "Great" ) return TNS_W3; + else if( s == "Perfect" ) return TNS_W2; + else if( s == "Marvelous" ) return TNS_W1; + return TapNoteScore_Invalid; } // This is necessary because the StringToX macro wasn't used, and Preference diff --git a/src/IniFile.cpp b/src/IniFile.cpp index a4766f509d..95a08d63d4 100644 --- a/src/IniFile.cpp +++ b/src/IniFile.cpp @@ -34,8 +34,6 @@ bool IniFile::ReadFile( const RString &sPath ) bool IniFile::ReadFile( RageFileBasic &f ) { RString keyname; - // keychild is used to cache the node that values are being added to. -Kyz - XNode* keychild= NULL; while( 1 ) { RString line; @@ -63,47 +61,34 @@ bool IniFile::ReadFile( RageFileBasic &f ) } - if( line.empty() ) + if( line.size() == 0 ) continue; - switch(line[0]) + if( line[0] == ';' ) + continue; // comment + if( line[0] == '#' ) + continue; // comment + if( line.size() > 1 && line[0] == '/' && line[1] == '/' ) + continue; // comment + if( line.size() > 1 && line[0] == '-' && line[1] == '-' ) + continue; // comment (Lua style) + + if( line[0] == '[' && line[line.size()-1] == ']' ) { - case ';': - case '#': - continue; // comment - case '/': - case '-': - if(line.size() > 1 && line[0] == line[1]) - { continue; } // comment (Lua or C++ style) - goto keyvalue; - case '[': - if(line[line.size()-1] == ']') - { - // New section. - keyname = line.substr(1, line.size()-2); - keychild= GetChild(keyname); - if(keychild == NULL) - { - keychild= AppendChild(keyname); - } - break; - } - default: - keyvalue: - if(keychild == NULL) - { break; } - // New value. - size_t iEqualIndex = line.find("="); - if( iEqualIndex != string::npos ) - { - RString valuename = line.Left((int) iEqualIndex); - RString value = line.Right(line.size()-valuename.size()-1); - Trim(valuename); - if(!valuename.empty()) - { - SetKeyValue(keychild, valuename, value); - } - } - break; + // New section. + keyname = line.substr(1, line.size()-2); + } + else + { + // New value. + size_t iEqualIndex = line.find("="); + if( iEqualIndex != string::npos ) + { + RString valuename = line.Left( (int) iEqualIndex ); + RString value = line.Right( line.size()-valuename.size()-1 ); + Trim( valuename ); + if( keyname.size() && valuename.size() ) + SetValue( keyname, valuename, value ); + } } } } diff --git a/src/IniFile.h b/src/IniFile.h index 010dc3a214..d2eb04ac20 100644 --- a/src/IniFile.h +++ b/src/IniFile.h @@ -44,11 +44,6 @@ public: pNode = AppendChild( sKey ); pNode->AppendAttr( sValueName, value ); } - template - void SetKeyValue(XNode* keynode, const RString &sValueName, const T &value) - { - keynode->AppendAttr(sValueName, value); - } bool DeleteKey( const RString &keyname ); bool DeleteValue( const RString &keyname, const RString &valuename ); diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index f6bdff43cd..11d91d5226 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -13,242 +13,6 @@ #include "Attack.h" #include "PrefsManager.h" -// Everything from this line to the creation of sm_parser_helper exists to -// speed up parsing by allowing the use of std::map. All these functions -// are put into a map of function pointers which is used when loading. -// -Kyz -/****************************************************************/ -struct SMSongTagInfo -{ - SMLoader* loader; - Song* song; - const MsdFile::value_t* params; - const RString& path; - vector< pair > BPMChanges, Stops; - SMSongTagInfo(SMLoader* l, Song* s, const RString& p) - :loader(l), song(s), path(p) - {} -}; - -typedef void (*song_tag_func_t)(SMSongTagInfo& info); - -// Functions for song tags go below this line. -Kyz -/****************************************************************/ -void SMSetTitle(SMSongTagInfo& info) -{ - info.song->m_sMainTitle = (*info.params)[1]; - info.loader->SetSongTitle((*info.params)[1]); -} -void SMSetSubtitle(SMSongTagInfo& info) -{ - info.song->m_sSubTitle = (*info.params)[1]; -} -void SMSetArtist(SMSongTagInfo& info) -{ - info.song->m_sArtist = (*info.params)[1]; -} -void SMSetTitleTranslit(SMSongTagInfo& info) -{ - info.song->m_sMainTitleTranslit = (*info.params)[1]; -} -void SMSetSubtitleTranslit(SMSongTagInfo& info) -{ - info.song->m_sSubTitleTranslit = (*info.params)[1]; -} -void SMSetArtistTranslit(SMSongTagInfo& info) -{ - info.song->m_sArtistTranslit = (*info.params)[1]; -} -void SMSetGenre(SMSongTagInfo& info) -{ - info.song->m_sGenre = (*info.params)[1]; -} -void SMSetCredit(SMSongTagInfo& info) -{ - info.song->m_sCredit = (*info.params)[1]; -} -void SMSetBanner(SMSongTagInfo& info) -{ - info.song->m_sBannerFile = (*info.params)[1]; -} -void SMSetBackground(SMSongTagInfo& info) -{ - info.song->m_sBackgroundFile = (*info.params)[1]; -} -void SMSetLyricsPath(SMSongTagInfo& info) -{ - info.song->m_sLyricsFile = (*info.params)[1]; -} -void SMSetCDTitle(SMSongTagInfo& info) -{ - info.song->m_sCDTitleFile = (*info.params)[1]; -} -void SMSetMusic(SMSongTagInfo& info) -{ - info.song->m_sMusicFile = (*info.params)[1]; -} -void SMSetOffset(SMSongTagInfo& info) -{ - info.song->m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat((*info.params)[1]); -} -void SMSetBPMs(SMSongTagInfo& info) -{ - info.BPMChanges.clear(); - info.loader->ParseBPMs(info.BPMChanges, (*info.params)[1]); -} -void SMSetStops(SMSongTagInfo& info) -{ - info.Stops.clear(); - info.loader->ParseStops(info.Stops, (*info.params)[1]); -} -void SMSetDelays(SMSongTagInfo& info) -{ - info.loader->ProcessDelays(info.song->m_SongTiming, (*info.params)[1]); -} -void SMSetTimeSignatures(SMSongTagInfo& info) -{ - info.loader->ProcessTimeSignatures(info.song->m_SongTiming, (*info.params)[1]); -} -void SMSetTickCounts(SMSongTagInfo& info) -{ - info.loader->ProcessTickcounts(info.song->m_SongTiming, (*info.params)[1]); -} -void SMSetInstrumentTrack(SMSongTagInfo& info) -{ - info.loader->ProcessInstrumentTracks(*info.song, (*info.params)[1]); -} -void SMSetSampleStart(SMSongTagInfo& info) -{ - info.song->m_fMusicSampleStartSeconds = HHMMSSToSeconds((*info.params)[1]); -} -void SMSetSampleLength(SMSongTagInfo& info) -{ - info.song->m_fMusicSampleLengthSeconds = HHMMSSToSeconds((*info.params)[1]); -} -void SMSetDisplayBPM(SMSongTagInfo& info) -{ - // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; - if((*info.params)[1] == "*") - { info.song->m_DisplayBPMType = DISPLAY_BPM_RANDOM; } - else - { - info.song->m_DisplayBPMType = DISPLAY_BPM_SPECIFIED; - info.song->m_fSpecifiedBPMMin = StringToFloat((*info.params)[1]); - if((*info.params)[2].empty()) - { info.song->m_fSpecifiedBPMMax = info.song->m_fSpecifiedBPMMin; } - else - { info.song->m_fSpecifiedBPMMax = StringToFloat((*info.params)[2]); } - } -} -void SMSetSelectable(SMSongTagInfo& info) -{ - if((*info.params)[1].EqualsNoCase("YES")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else if((*info.params)[1].EqualsNoCase("NO")) - { info.song->m_SelectionDisplay = info.song->SHOW_NEVER; } - // ROULETTE from 3.9. It was removed since UnlockManager can serve - // the same purpose somehow. This, of course, assumes you're using - // unlocks. -aj - else if((*info.params)[1].EqualsNoCase("ROULETTE")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - /* The following two cases are just fixes to make sure simfiles that - * used 3.9+ features are not excluded here */ - else if((*info.params)[1].EqualsNoCase("ES") || (*info.params)[1].EqualsNoCase("OMES")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else if(StringToInt((*info.params)[1]) > 0) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else - { LOG->UserLog("Song file", info.path, "has an unknown #SELECTABLE value, \"%s\"; ignored.", (*info.params)[1].c_str()); } -} -void SMSetBGChanges(SMSongTagInfo& info) -{ - info.loader->ProcessBGChanges(*info.song, (*info.params)[0], info.path, (*info.params)[1]); -} -void SMSetFGChanges(SMSongTagInfo& info) -{ - vector aFGChangeExpressions; - split((*info.params)[1], ",", aFGChangeExpressions); - - for(unsigned int b = 0; b < aFGChangeExpressions.size(); ++b) - { - BackgroundChange change; - if(info.loader->LoadFromBGChangesString(change, aFGChangeExpressions[b])) - info.song->AddForegroundChange(change); - } -} -void SMSetKeysounds(SMSongTagInfo& info) -{ - split((*info.params)[1], ",", info.song->m_vsKeysoundFile); -} -void SMSetAttacks(SMSongTagInfo& info) -{ - info.loader->ProcessAttackString(info.song->m_sAttackString, (*info.params)); - info.loader->ProcessAttacks(info.song->m_Attacks, (*info.params)); -} - -typedef std::map song_handler_map_t; - -struct sm_parser_helper_t -{ - song_handler_map_t song_tag_handlers; - // Unless signed, the comments in this tag list are not by me. They were - // moved here when converting from the else if chain. -Kyz - sm_parser_helper_t() - { - song_tag_handlers["TITLE"]= &SMSetTitle; - song_tag_handlers["SUBTITLE"]= &SMSetSubtitle; - song_tag_handlers["ARTIST"]= &SMSetArtist; - song_tag_handlers["TITLETRANSLIT"]= &SMSetTitleTranslit; - song_tag_handlers["SUBTITLETRANSLIT"]= &SMSetSubtitleTranslit; - song_tag_handlers["ARTISTTRANSLIT"]= &SMSetArtistTranslit; - song_tag_handlers["GENRE"]= &SMSetGenre; - song_tag_handlers["CREDIT"]= &SMSetCredit; - song_tag_handlers["BANNER"]= &SMSetBanner; - song_tag_handlers["BACKGROUND"]= &SMSetBackground; - // Save "#LYRICS" for later, so we can add an internal lyrics tag. - song_tag_handlers["LYRICSPATH"]= &SMSetLyricsPath; - song_tag_handlers["CDTITLE"]= &SMSetCDTitle; - song_tag_handlers["MUSIC"]= &SMSetMusic; - song_tag_handlers["OFFSET"]= &SMSetOffset; - song_tag_handlers["BPMS"]= &SMSetBPMs; - song_tag_handlers["STOPS"]= &SMSetStops; - song_tag_handlers["FREEZES"]= &SMSetStops; - song_tag_handlers["DELAYS"]= &SMSetDelays; - song_tag_handlers["TIMESIGNATURES"]= &SMSetTimeSignatures; - song_tag_handlers["TICKCOUNTS"]= &SMSetTickCounts; - song_tag_handlers["INSTRUMENTTRACK"]= &SMSetInstrumentTrack; - song_tag_handlers["SAMPLESTART"]= &SMSetSampleStart; - song_tag_handlers["SAMPLELENGTH"]= &SMSetSampleLength; - song_tag_handlers["DISPLAYBPM"]= &SMSetDisplayBPM; - song_tag_handlers["SELECTABLE"]= &SMSetSelectable; - // It's a bit odd to have the tag that exists for backwards compatibility - // in this list and not the replacement, but the BGCHANGES tag has a - // number on the end, allowing up to NUM_BackgroundLayer tags, so it - // can't fit in the map. -Kyz - song_tag_handlers["ANIMATIONS"]= &SMSetBGChanges; - song_tag_handlers["FGCHANGES"]= &SMSetFGChanges; - song_tag_handlers["KEYSOUNDS"]= &SMSetKeysounds; - // Attacks loaded from file - song_tag_handlers["ATTACKS"]= &SMSetAttacks; - /* Tags that no longer exist, listed for posterity. May their names - * never be forgotten for their service to Stepmania. -Kyz - * LASTBEATHINT: // unable to identify at this point: ignore - * MUSICBYTES: // ignore - * FIRSTBEAT: // cache tags from older SM files: ignore. - * LASTBEAT: // cache tags from older SM files: ignore. - * SONGFILENAME: // cache tags from older SM files: ignore. - * HASMUSIC: // cache tags from older SM files: ignore. - * HASBANNER: // cache tags from older SM files: ignore. - * SAMPLEPATH: // SamplePath was used when the song has a separate preview clip. -aj - * LEADTRACK: // XXX: Does anyone know what LEADTRACK is for? -Wolfman2000 - * MUSICLENGTH: // Loaded from the cache now. -Kyz - */ - } -}; -sm_parser_helper_t sm_parser_helper; -// End sm_parser_helper related functions. -Kyz -/****************************************************************/ - void SMLoader::SetSongTitle(const RString & title) { this->songTitle = title; @@ -1121,11 +885,10 @@ bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache return false; } + vector< pair > vBPMChanges, vStops; out.m_SongTiming.m_sFile = sPath; out.m_sSongFileName = sPath; - SMSongTagInfo reused_song_info(&*this, &out, sPath); - for( unsigned i=0; isecond(reused_song_info); - } - else if(sValueName.Left(strlen("BGCHANGES")) == "BGCHANGES") + if( sValueName=="TITLE" ) { - SMSetBGChanges(reused_song_info); + out.m_sMainTitle = sParams[1]; + this->SetSongTitle(sParams[1]); } - else if(sValueName == "NOTES" || sValueName == "NOTES2") + + else if( sValueName=="SUBTITLE" ) + out.m_sSubTitle = sParams[1]; + + else if( sValueName=="ARTIST" ) + out.m_sArtist = sParams[1]; + + else if( sValueName=="TITLETRANSLIT" ) + out.m_sMainTitleTranslit = sParams[1]; + + else if( sValueName=="SUBTITLETRANSLIT" ) + out.m_sSubTitleTranslit = sParams[1]; + + else if( sValueName=="ARTISTTRANSLIT" ) + out.m_sArtistTranslit = sParams[1]; + + else if( sValueName=="GENRE" ) + out.m_sGenre = sParams[1]; + + else if( sValueName=="CREDIT" ) + out.m_sCredit = sParams[1]; + + else if( sValueName=="BANNER" ) + out.m_sBannerFile = sParams[1]; + + else if( sValueName=="BACKGROUND" ) + out.m_sBackgroundFile = sParams[1]; + + // Save "#LYRICS" for later, so we can add an internal lyrics tag. + else if( sValueName=="LYRICSPATH" ) + out.m_sLyricsFile = sParams[1]; + + else if( sValueName=="CDTITLE" ) + out.m_sCDTitleFile = sParams[1]; + + else if( sValueName=="MUSIC" ) + out.m_sMusicFile = sParams[1]; + + else if( sValueName=="OFFSET" ) { - if(iNumParams < 7) + out.m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + } + else if( sValueName=="BPMS" ) + { + vBPMChanges.clear(); + ParseBPMs(vBPMChanges, sParams[1]); + } + + else if( sValueName=="STOPS" || sValueName=="FREEZES" ) + { + vStops.clear(); + ParseStops(vStops, sParams[1]); + } + + else if( sValueName=="DELAYS" ) + { + ProcessDelays(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="TIMESIGNATURES" ) + { + ProcessTimeSignatures(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="TICKCOUNTS" ) + { + ProcessTickcounts(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="INSTRUMENTTRACK" ) + { + ProcessInstrumentTracks( out, sParams[1] ); + } + + else if( sValueName=="MUSICLENGTH" ) + { + if( !bFromCache ) + continue; + out.m_fMusicLengthSeconds = StringToFloat( sParams[1] ); + } + + else if( sValueName=="LASTBEATHINT" ) + { + // unable to identify at this point: ignore + } + + else if( sValueName=="MUSICBYTES" ) + ; /* ignore */ + + // cache tags from older SM files: ignore. + else if(sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" || + sValueName=="SONGFILENAME" || sValueName=="HASMUSIC" || + sValueName=="HASBANNER") + { + ; + } + + else if( sValueName=="SAMPLESTART" ) + out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); + + else if( sValueName=="SAMPLELENGTH" ) + out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); + + // SamplePath is used when the song has a separate preview clip. -aj + //else if( sValueName=="SAMPLEPATH" ) + //out.m_sMusicSamplePath = sParams[1]; + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + out.m_DisplayBPMType = DISPLAY_BPM_RANDOM; + else + { + out.m_DisplayBPMType = DISPLAY_BPM_SPECIFIED; + out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); + if( sParams[2].empty() ) + out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; + else + out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); + } + } + + else if( sValueName=="SELECTABLE" ) + { + if(sParams[1].EqualsNoCase("YES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if(sParams[1].EqualsNoCase("NO")) + out.m_SelectionDisplay = out.SHOW_NEVER; + // ROULETTE from 3.9. It was removed since UnlockManager can serve + // the same purpose somehow. This, of course, assumes you're using + // unlocks. -aj + else if(sParams[1].EqualsNoCase("ROULETTE")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + /* The following two cases are just fixes to make sure simfiles that + * used 3.9+ features are not excluded here */ + else if(sParams[1].EqualsNoCase("ES") || sParams[1].EqualsNoCase("OMES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if( StringToInt(sParams[1]) > 0 ) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else + LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); + } + + else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) + { + ProcessBGChanges( out, sValueName, sPath, sParams[1]); + } + + else if( sValueName=="FGCHANGES" ) + { + vector aFGChangeExpressions; + split( sParams[1], ",", aFGChangeExpressions ); + + for( unsigned b=0; bUserLog( "Song file", sPath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); continue; @@ -1162,19 +1094,20 @@ bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache sParams[4], sParams[5], sParams[6], - *pNewNotes); + *pNewNotes ); pNewNotes->SetFilename(sPath); out.AddSteps( pNewNotes ); } + // XXX: Does anyone know what LEADTRACK is for? -Wolfman2000 + else if( sValueName=="LEADTRACK" ) + ; else - { - LOG->UserLog("Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str()); - } + LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); } // Turn negative time changes into warps - ProcessBPMsAndStops(out.m_SongTiming, reused_song_info.BPMChanges, reused_song_info.Stops); + ProcessBPMsAndStops(out.m_SongTiming, vBPMChanges, vStops); TidyUpData( out, bFromCache ); return true; diff --git a/src/NotesLoaderSM.h b/src/NotesLoaderSM.h index 70f1841510..358515ec51 100644 --- a/src/NotesLoaderSM.h +++ b/src/NotesLoaderSM.h @@ -198,10 +198,7 @@ protected: * @brief Retrieve the file extension associated with this loader. * @return the file extension. */ RString GetFileExtension() const { return fileExt; } - -public: - // SetSongTitle and GetSongTitle changed to public to allow the functions - // used by the parser helper to access them. -Kyz + /** * @brief Set the song title. * @param t the song title. */ diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 0ed7639637..ca647b5c55 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -14,627 +14,6 @@ #include "Attack.h" #include "PrefsManager.h" -// Everything from this line to the creation of parser_helper exists to -// speed up parsing by allowing the use of std::map. All these functions -// are put into a map of function pointers which is used when loading. -// -Kyz -/****************************************************************/ -struct StepsTagInfo -{ - SSCLoader* loader; - Song* song; - Steps* steps; - TimingData* timing; - const MsdFile::value_t* params; - const RString& path; - bool has_own_timing; - bool ssc_format; - bool from_cache; - bool for_load_edit; - StepsTagInfo(SSCLoader* l, Song* s, const RString& p, bool fc) - :loader(l), song(s), path(p), has_own_timing(false), ssc_format(false), - from_cache(fc), for_load_edit(false) - {} -}; -struct SongTagInfo -{ - SSCLoader* loader; - Song* song; - const MsdFile::value_t* params; - const RString& path; - bool from_cache; - SongTagInfo(SSCLoader* l, Song* s, const RString& p, bool fc) - :loader(l), song(s), path(p), from_cache(fc) - {} -}; -// LoadNoteDataFromSimfile uses LoadNoteDataTagIDs because its parts operate -// on state variables internal to the function. -enum LoadNoteDataTagIDs -{ - LNDID_version, - LNDID_stepstype, - LNDID_chartname, - LNDID_description, - LNDID_difficulty, - LNDID_meter, - LNDID_credit, - LNDID_notes, - LNDID_notes2, - LNDID_notedata -}; - -typedef void (*steps_tag_func_t)(StepsTagInfo& info); -typedef void (*song_tag_func_t)(SongTagInfo& info); - -// Functions for song tags go below this line. -Kyz -/****************************************************************/ -void SetVersion(SongTagInfo& info) -{ - info.song->m_fVersion = StringToFloat((*info.params)[1]); -} -void SetTitle(SongTagInfo& info) -{ - info.song->m_sMainTitle = (*info.params)[1]; - info.loader->SetSongTitle((*info.params)[1]); -} -void SetSubtitle(SongTagInfo& info) -{ - info.song->m_sSubTitle = (*info.params)[1]; -} -void SetArtist(SongTagInfo& info) -{ - info.song->m_sArtist = (*info.params)[1]; -} -void SetMainTitleTranslit(SongTagInfo& info) -{ - info.song->m_sMainTitleTranslit = (*info.params)[1]; -} -void SetSubtitleTranslit(SongTagInfo& info) -{ - info.song->m_sSubTitleTranslit = (*info.params)[1]; -} -void SetArtistTranslit(SongTagInfo& info) -{ - info.song->m_sArtistTranslit = (*info.params)[1]; -} -void SetGenre(SongTagInfo& info) -{ - info.song->m_sGenre = (*info.params)[1]; -} -void SetOrigin(SongTagInfo& info) -{ - info.song->m_sOrigin = (*info.params)[1]; -} -void SetCredit(SongTagInfo& info) -{ - info.song->m_sCredit = (*info.params)[1]; -} -void SetBanner(SongTagInfo& info) -{ - info.song->m_sBannerFile = (*info.params)[1]; -} -void SetBackground(SongTagInfo& info) -{ - info.song->m_sBackgroundFile = (*info.params)[1]; -} -void SetPreviewVid(SongTagInfo& info) -{ - info.song->m_sPreviewVidFile = (*info.params)[1]; -} -void SetJacket(SongTagInfo& info) -{ - info.song->m_sJacketFile = (*info.params)[1]; -} -void SetCDImage(SongTagInfo& info) -{ - info.song->m_sCDFile = (*info.params)[1]; -} -void SetDiscImage(SongTagInfo& info) -{ - info.song->m_sDiscFile = (*info.params)[1]; -} -void SetLyricsPath(SongTagInfo& info) -{ - info.song->m_sLyricsFile = (*info.params)[1]; -} -void SetCDTitle(SongTagInfo& info) -{ - info.song->m_sCDTitleFile = (*info.params)[1]; -} -void SetMusic(SongTagInfo& info) -{ - info.song->m_sMusicFile = (*info.params)[1]; -} -void SetPreview(SongTagInfo& info) -{ - info.song->m_PreviewFile= (*info.params)[1]; -} -void SetInstrumentTrack(SongTagInfo& info) -{ - info.loader->ProcessInstrumentTracks(*info.song, (*info.params)[1]); -} -void SetMusicLength(SongTagInfo& info) -{ - if(info.from_cache) - info.song->m_fMusicLengthSeconds = StringToFloat((*info.params)[1]); -} -void SetLastSecondHint(SongTagInfo& info) -{ - info.song->SetSpecifiedLastSecond(StringToFloat((*info.params)[1])); -} -void SetSampleStart(SongTagInfo& info) -{ - info.song->m_fMusicSampleStartSeconds = HHMMSSToSeconds((*info.params)[1]); -} -void SetSampleLength(SongTagInfo& info) -{ - info.song->m_fMusicSampleLengthSeconds = HHMMSSToSeconds((*info.params)[1]); -} -void SetDisplayBPM(SongTagInfo& info) -{ - // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; - if((*info.params)[1] == "*") - { info.song->m_DisplayBPMType = DISPLAY_BPM_RANDOM; } - else - { - info.song->m_DisplayBPMType = DISPLAY_BPM_SPECIFIED; - info.song->m_fSpecifiedBPMMin = StringToFloat((*info.params)[1]); - if((*info.params)[2].empty()) - { info.song->m_fSpecifiedBPMMax = info.song->m_fSpecifiedBPMMin; } - else - { info.song->m_fSpecifiedBPMMax = StringToFloat((*info.params)[2]); } - } -} -void SetSelectable(SongTagInfo& info) -{ - if((*info.params)[1].EqualsNoCase("YES")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else if((*info.params)[1].EqualsNoCase("NO")) - { info.song->m_SelectionDisplay = info.song->SHOW_NEVER; } - // ROULETTE from 3.9 is no longer in use. - else if((*info.params)[1].EqualsNoCase("ROULETTE")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - /* The following two cases are just fixes to make sure simfiles that - * used 3.9+ features are not excluded here */ - else if((*info.params)[1].EqualsNoCase("ES") || (*info.params)[1].EqualsNoCase("OMES")) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else if(StringToInt((*info.params)[1]) > 0) - { info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; } - else - { LOG->UserLog("Song file", info.path, "has an unknown #SELECTABLE value, \"%s\"; ignored.", (*info.params)[1].c_str()); } -} -void SetBGChanges(SongTagInfo& info) -{ - info.loader->ProcessBGChanges(*info.song, (*info.params)[0], info.path, (*info.params)[1]); -} -void SetFGChanges(SongTagInfo& info) -{ - vector aFGChangeExpressions; - split((*info.params)[1], ",", aFGChangeExpressions); - - for(size_t b = 0; b < aFGChangeExpressions.size(); ++b) - { - BackgroundChange change; - if(info.loader->LoadFromBGChangesString(change, aFGChangeExpressions[b])) - { info.song->AddForegroundChange(change); } - } -} -void SetKeysounds(SongTagInfo& info) -{ - RString keysounds = (*info.params)[1]; - if(keysounds.length() >= 2 && keysounds.substr(0, 2) == "\\#") - { keysounds = keysounds.substr(1); } - split(keysounds, ",", info.song->m_vsKeysoundFile); -} -void SetAttacks(SongTagInfo& info) -{ - info.loader->ProcessAttackString(info.song->m_sAttackString, (*info.params)); - info.loader->ProcessAttacks(info.song->m_Attacks, (*info.params)); -} -void SetOffset(SongTagInfo& info) -{ - info.song->m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat((*info.params)[1]); -} -void SetSongStops(SongTagInfo& info) -{ - info.loader->ProcessStops(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongDelays(SongTagInfo& info) -{ - info.loader->ProcessDelays(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongBPMs(SongTagInfo& info) -{ - info.loader->ProcessBPMs(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongWarps(SongTagInfo& info) -{ - info.loader->ProcessWarps( info.song->m_SongTiming, (*info.params)[1], info.song->m_fVersion ); -} -void SetSongLabels(SongTagInfo& info) -{ - info.loader->ProcessLabels( info.song->m_SongTiming, (*info.params)[1] ); -} -void SetSongTimeSignatures(SongTagInfo& info) -{ - info.loader->ProcessTimeSignatures(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongTickCounts(SongTagInfo& info) -{ - info.loader->ProcessTickcounts(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongCombos(SongTagInfo& info) -{ - info.loader->ProcessCombos( info.song->m_SongTiming, (*info.params)[1] ); -} -void SetSongSpeeds(SongTagInfo& info) -{ - info.loader->ProcessSpeeds(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongScrolls(SongTagInfo& info) -{ - info.loader->ProcessScrolls(info.song->m_SongTiming, (*info.params)[1]); -} -void SetSongFakes(SongTagInfo& info) -{ - info.loader->ProcessFakes(info.song->m_SongTiming, (*info.params)[1]); -} -void SetFirstSecond(SongTagInfo& info) -{ - if(info.from_cache) - { info.song->SetFirstSecond(StringToFloat((*info.params)[1])); } -} -void SetLastSecond(SongTagInfo& info) -{ - if(info.from_cache) - { info.song->SetLastSecond(StringToFloat((*info.params)[1])); } -} -void SetSongFilename(SongTagInfo& info) -{ - if(info.from_cache) - { info.song->m_sSongFileName = (*info.params)[1]; } -} -void SetHasMusic(SongTagInfo& info) -{ - if(info.from_cache) - { info.song->m_bHasMusic = StringToInt((*info.params)[1]) != 0; } -} -void SetHasBanner(SongTagInfo& info) -{ - if(info.from_cache) - { info.song->m_bHasBanner = StringToInt((*info.params)[1]) != 0; } -} - -// Functions for steps tags go below this line. -Kyz -/****************************************************************/ -void SetStepsVersion(StepsTagInfo& info) -{ - info.song->m_fVersion = StringToFloat((*info.params)[1]); -} -void SetChartName(StepsTagInfo& info) -{ - info.steps->SetChartName((*info.params)[1]); -} -void SetStepsType(StepsTagInfo& info) -{ - info.steps->m_StepsType = GAMEMAN->StringToStepsType((*info.params)[1]); - info.steps->m_StepsTypeStr= (*info.params)[1]; - info.ssc_format= true; -} -void SetChartStyle(StepsTagInfo& info) -{ - info.steps->SetChartStyle((*info.params)[1]); - info.ssc_format= true; -} -void SetDescription(StepsTagInfo& info) -{ - if(info.song->m_fVersion < VERSION_CHART_NAME_TAG && !info.for_load_edit) - { - info.steps->SetChartName((*info.params)[1]); - } - else - { - info.steps->SetDescription((*info.params)[1]); - } - info.ssc_format= true; -} -void SetDifficulty(StepsTagInfo& info) -{ - info.steps->SetDifficulty(StringToDifficulty((*info.params)[1])); - info.ssc_format= true; -} -void SetMeter(StepsTagInfo& info) -{ - info.steps->SetMeter(StringToInt((*info.params)[1])); - info.ssc_format= true; -} -void SetRadarValues(StepsTagInfo& info) -{ - if(info.from_cache || info.for_load_edit) - { - vector saValues; - split((*info.params)[1], ",", saValues, true); - int categories = NUM_RadarCategory; - if(info.song->m_fVersion < VERSION_RADAR_FAKE && !info.for_load_edit) - { categories -= 1; } - if(saValues.size() == (unsigned int)categories * NUM_PLAYERS) - { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber(pn) - { - // Can't use the foreach anymore due to flexible radar lines. - for(RadarCategory rc = (RadarCategory)0; rc < categories; - enum_add(rc, +1)) - { - v[pn][rc] = StringToFloat(saValues[pn*categories + rc]); - } - } - info.steps->SetCachedRadarValues(v); - } - } - else - { - // just recalc at time. - } - info.ssc_format= true; -} -void SetCredit(StepsTagInfo& info) -{ - info.steps->SetCredit((*info.params)[1]); - info.ssc_format= true; -} -void SetStepsBPMs(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessBPMs(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsStops(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessStops(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsDelays(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessDelays(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsTimeSignatures(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessTimeSignatures(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsTickCounts(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessTickcounts(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsCombos(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessCombos(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsWarps(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessWarps(*info.timing, (*info.params)[1], info.song->m_fVersion); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsSpeeds(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessSpeeds(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsScrolls(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessScrolls(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsFakes(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessFakes(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsLabels(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessLabels(*info.timing, (*info.params)[1]); - info.has_own_timing = true; - } - info.ssc_format= true; -} -void SetStepsAttacks(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.loader->ProcessAttackString(info.steps->m_sAttackString, *info.params); - info.loader->ProcessAttacks(info.steps->m_Attacks, *info.params); - } -} -void SetStepsOffset(StepsTagInfo& info) -{ - if(info.song->m_fVersion >= VERSION_SPLIT_TIMING || info.for_load_edit) - { - info.timing->m_fBeat0OffsetInSeconds = StringToFloat((*info.params)[1]); - info.has_own_timing = true; - } -} -void SetStepsDisplayBPM(StepsTagInfo& info) -{ - // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; - if((*info.params)[1] == "*") - { info.steps->SetDisplayBPM(DISPLAY_BPM_RANDOM); } - else - { - info.steps->SetDisplayBPM(DISPLAY_BPM_SPECIFIED); - float min = StringToFloat((*info.params)[1]); - info.steps->SetMinBPM(min); - if((*info.params)[2].empty()) - { info.steps->SetMaxBPM(min); } - else - { info.steps->SetMaxBPM(StringToFloat((*info.params)[2])); } - } -} - - -typedef std::map steps_handler_map_t; -typedef std::map song_handler_map_t; -typedef std::map load_note_data_handler_map_t; - -struct ssc_parser_helper_t -{ - steps_handler_map_t steps_tag_handlers; - song_handler_map_t song_tag_handlers; - load_note_data_handler_map_t load_note_data_handlers; - // Unless signed, the comments in this tag list are not by me. They were - // moved here when converting from the else if chain. -Kyz - ssc_parser_helper_t() - { - song_tag_handlers["VERSION"]= &SetVersion; - song_tag_handlers["TITLE"]= &SetTitle; - song_tag_handlers["SUBTITLE"]= &SetSubtitle; - song_tag_handlers["ARTIST"]= &SetArtist; - song_tag_handlers["TITLETRANSLIT"]= &SetMainTitleTranslit; - song_tag_handlers["SUBTITLETRANSLIT"]= &SetSubtitleTranslit; - song_tag_handlers["ARTISTTRANSLIT"]= &SetArtistTranslit; - song_tag_handlers["GENRE"]= &SetGenre; - song_tag_handlers["ORIGIN"]= &SetOrigin; - song_tag_handlers["CREDIT"]= &SetCredit; - song_tag_handlers["BANNER"]= &SetBanner; - song_tag_handlers["BACKGROUND"]= &SetBackground; - song_tag_handlers["PREVIEWVID"]= &SetPreviewVid; - song_tag_handlers["JACKET"]= &SetJacket; - song_tag_handlers["CDIMAGE"]= &SetCDImage; - song_tag_handlers["DISCIMAGE"]= &SetDiscImage; - song_tag_handlers["LYRICSPATH"]= &SetLyricsPath; - song_tag_handlers["CDTITLE"]= &SetCDTitle; - song_tag_handlers["MUSIC"]= &SetMusic; - song_tag_handlers["PREVIEW"]= &SetPreview; - song_tag_handlers["INSTRUMENTTRACK"]= &SetInstrumentTrack; - song_tag_handlers["MUSICLENGTH"]= &SetMusicLength; - song_tag_handlers["LASTSECONDHINT"]= &SetLastSecondHint; - song_tag_handlers["SAMPLESTART"]= &SetSampleStart; - song_tag_handlers["SAMPLELENGTH"]= &SetSampleLength; - song_tag_handlers["DISPLAYBPM"]= &SetDisplayBPM; - song_tag_handlers["SELECTABLE"]= &SetSelectable; - // It's a bit odd to have the tag that exists for backwards compatibility - // in this list and not the replacement, but the BGCHANGES tag has a - // number on the end, allowing up to NUM_BackgroundLayer tags, so it - // can't fit in the map. -Kyz - song_tag_handlers["ANIMATIONS"]= &SetBGChanges; - song_tag_handlers["FGCHANGES"]= &SetFGChanges; - song_tag_handlers["KEYSOUNDS"]= &SetKeysounds; - song_tag_handlers["ATTACKS"]= &SetAttacks; - song_tag_handlers["OFFSET"]= &SetOffset; - /* Below are the song based timings that should only be used - * if the steps do not have their own timing. */ - song_tag_handlers["STOPS"]= &SetSongStops; - song_tag_handlers["DELAYS"]= &SetSongDelays; - song_tag_handlers["BPMS"]= &SetSongBPMs; - song_tag_handlers["WARPS"]= &SetSongWarps; - song_tag_handlers["LABELS"]= &SetSongLabels; - song_tag_handlers["TIMESIGNATURES"]= &SetSongTimeSignatures; - song_tag_handlers["TICKCOUNTS"]= &SetSongTickCounts; - song_tag_handlers["COMBOS"]= &SetSongCombos; - song_tag_handlers["SPEEDS"]= &SetSongSpeeds; - song_tag_handlers["SCROLLS"]= &SetSongScrolls; - song_tag_handlers["FAKES"]= &SetSongFakes; - /* The following are cache tags. Never fill their values - * directly: only from the cached version. */ - song_tag_handlers["FIRSTSECOND"]= &SetFirstSecond; - song_tag_handlers["LASTSECOND"]= &SetLastSecond; - song_tag_handlers["SONGFILENAME"]= &SetSongFilename; - song_tag_handlers["HASMUSIC"]= &SetHasMusic; - song_tag_handlers["HASBANNER"]= &SetHasBanner; - /* Tags that no longer exist, listed for posterity. May their names - * never be forgotten for their service to Stepmania. -Kyz - * LASTBEATHINT: // unable to parse due to tag position. Ignore. - * MUSICBYTES: // ignore - * FIRSTBEAT: // no longer used. - * LASTBEAT: // no longer used. - */ - - steps_tag_handlers["VERSION"]= &SetStepsVersion; - steps_tag_handlers["CHARTNAME"]= &SetChartName; - steps_tag_handlers["STEPSTYPE"]= &SetStepsType; - steps_tag_handlers["CHARTSTYLE"]= &SetChartStyle; - steps_tag_handlers["DESCRIPTION"]= &SetDescription; - steps_tag_handlers["DIFFICULTY"]= &SetDifficulty; - steps_tag_handlers["METER"]= &SetMeter; - steps_tag_handlers["RADARVALUES"]= &SetRadarValues; - steps_tag_handlers["CREDIT"]= &SetCredit; - steps_tag_handlers["BPMS"]= &SetStepsBPMs; - steps_tag_handlers["STOPS"]= &SetStepsStops; - steps_tag_handlers["DELAYS"]= &SetStepsDelays; - steps_tag_handlers["TIMESIGNATURES"]= &SetStepsTimeSignatures; - steps_tag_handlers["TICKCOUNTS"]= &SetStepsTickCounts; - steps_tag_handlers["COMBOS"]= &SetStepsCombos; - steps_tag_handlers["WARPS"]= &SetStepsWarps; - steps_tag_handlers["SPEEDS"]= &SetStepsSpeeds; - steps_tag_handlers["SCROLLS"]= &SetStepsScrolls; - steps_tag_handlers["FAKES"]= &SetStepsFakes; - steps_tag_handlers["LABELS"]= &SetStepsLabels; - /* If this is called, the chart does not use the same attacks - * as the Song's timing. No other changes are required. */ - steps_tag_handlers["ATTACKS"]= &SetStepsAttacks; - steps_tag_handlers["OFFSET"]= &SetStepsOffset; - steps_tag_handlers["DISPLAYBPM"]= &SetStepsDisplayBPM; - - load_note_data_handlers["VERSION"]= LNDID_version; - load_note_data_handlers["STEPSTYPE"]= LNDID_stepstype; - load_note_data_handlers["CHARTNAME"]= LNDID_chartname; - load_note_data_handlers["DESCRIPTION"]= LNDID_description; - load_note_data_handlers["DIFFICULTY"]= LNDID_difficulty; - load_note_data_handlers["METER"]= LNDID_meter; - load_note_data_handlers["CREDIT"]= LNDID_credit; - load_note_data_handlers["NOTES"]= LNDID_notes; - load_note_data_handlers["NOTES2"]= LNDID_notes2; - load_note_data_handlers["NOTEDATA"]= LNDID_notedata; - } -}; -ssc_parser_helper_t parser_helper; -// End parser_helper related functions. -Kyz -/****************************************************************/ - void SSCLoader::ProcessBPMs( TimingData &out, const RString sParam ) { vector arrayBPMExpressions; @@ -857,76 +236,65 @@ bool SSCLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps &out ) valueName.MakeUpper(); RString matcher = params[1]; // mainly for debugging. Trim(matcher); - - load_note_data_handler_map_t::iterator handler= - parser_helper.load_note_data_handlers.find(valueName); - if(handler != parser_helper.load_note_data_handlers.end()) + + if (valueName=="VERSION") { - if(tryingSteps) + storedVersion = StringToFloat(matcher); + } + if (tryingSteps) + { + if( valueName=="STEPSTYPE" ) { - switch(handler->second) - { - case LNDID_version: - // Note that version is in both switches. Formerly, it was - // checked before the tryingSteps condition. -Kyz - storedVersion = StringToFloat(matcher); - break; - case LNDID_stepstype: - if(out.m_StepsType != GAMEMAN->StringToStepsType(matcher)) - { tryingSteps = false; } - break; - case LNDID_chartname: - if(storedVersion >= VERSION_CHART_NAME_TAG && - out.GetChartName() != matcher) - { tryingSteps = false; } - break; - case LNDID_description: - if(storedVersion < VERSION_CHART_NAME_TAG) - { - if(out.GetChartName() != matcher) - { tryingSteps = false; } - } - else if(out.GetDescription() != matcher) - { tryingSteps = false; } - break; - case LNDID_difficulty: - if(out.GetDifficulty() != StringToDifficulty(matcher)) - { tryingSteps = false; } - break; - case LNDID_meter: - if(out.GetMeter() != StringToInt(matcher)) - { tryingSteps = false; } - break; - case LNDID_credit: - if(out.GetCredit() != matcher) - { tryingSteps = false; } - break; - case LNDID_notes: - case LNDID_notes2: - out.SetSMNoteData(matcher); - out.TidyUpData(); - return true; - break; - } + if (out.m_StepsType != GAMEMAN->StringToStepsType(matcher)) + tryingSteps = false; } - else + else if( valueName=="CHARTNAME") { - switch(handler->second) + if (storedVersion >= VERSION_CHART_NAME_TAG && out.GetChartName() != matcher) + tryingSteps = false; + } + else if( valueName=="DESCRIPTION" ) + { + if (storedVersion < VERSION_CHART_NAME_TAG) { - case LNDID_version: - // Note that version is in both switches. Formerly, it was - // checked before the tryingSteps condition. -Kyz - storedVersion = StringToFloat(matcher); - break; - case LNDID_notedata: - tryingSteps = true; - break; + if (out.GetChartName() != matcher) + tryingSteps = false; } + else if (out.GetDescription() != matcher) + tryingSteps = false; + } + + else if( valueName=="DIFFICULTY" ) + { + if (out.GetDifficulty() != StringToDifficulty(matcher)) + tryingSteps = false; + } + + else if( valueName=="METER" ) + { + if (out.GetMeter() != StringToInt(matcher)) + tryingSteps = false; + } + + else if( valueName=="CREDIT" ) + { + if (out.GetCredit() != matcher) + tryingSteps = false; + } + + else if( valueName=="NOTES" || valueName=="NOTES2" ) + { + out.SetSMNoteData(matcher); + out.TidyUpData(); + return true; } } else { - // Silently ignore unrecognized tags, as was done before. -Kyz + if(valueName == "NOTEDATA") + { + tryingSteps = true; + } } } return false; @@ -950,9 +318,7 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach const unsigned values = msd.GetNumValues(); Steps* pNewNotes = NULL; TimingData stepsTiming; - - SongTagInfo reused_song_info(&*this, &out, sPath, bFromCache); - StepsTagInfo reused_steps_info(&*this, &out, sPath, bFromCache); + bool bHasOwnTiming = false; for( unsigned i = 0; i < values; i++ ) { @@ -964,65 +330,546 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach { case GETTING_SONG_INFO: { - reused_song_info.params= &sParams; - song_handler_map_t::iterator handler= - parser_helper.song_tag_handlers.find(sValueName); - if(handler != parser_helper.song_tag_handlers.end()) + if( sValueName=="VERSION" ) { - handler->second(reused_song_info); + out.m_fVersion = StringToFloat( sParams[1] ); } - else if(sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES") + + else if( sValueName=="TITLE" ) { - SetBGChanges(reused_song_info); + out.m_sMainTitle = sParams[1]; + this->SetSongTitle(sParams[1]); } + + else if( sValueName=="SUBTITLE" ) + { + out.m_sSubTitle = sParams[1]; + } + + else if( sValueName=="ARTIST" ) + { + out.m_sArtist = sParams[1]; + } + + else if( sValueName=="TITLETRANSLIT" ) + { + out.m_sMainTitleTranslit = sParams[1]; + } + + else if( sValueName=="SUBTITLETRANSLIT" ) + { + out.m_sSubTitleTranslit = sParams[1]; + } + + else if( sValueName=="ARTISTTRANSLIT" ) + { + out.m_sArtistTranslit = sParams[1]; + } + + else if( sValueName=="GENRE" ) + { + out.m_sGenre = sParams[1]; + } + + else if( sValueName=="ORIGIN" ) + { + out.m_sOrigin = sParams[1]; + } + + else if( sValueName=="CREDIT" ) + { + out.m_sCredit = sParams[1]; + } + + else if( sValueName=="BANNER" ) + { + out.m_sBannerFile = sParams[1]; + } + + else if( sValueName=="BACKGROUND" ) + { + out.m_sBackgroundFile = sParams[1]; + } + + else if( sValueName=="PREVIEWVID" ) + { + out.m_sPreviewVidFile = sParams[1]; + } + + else if( sValueName=="JACKET" ) + { + out.m_sJacketFile = sParams[1]; + } + + else if( sValueName=="CDIMAGE" ) + { + out.m_sCDFile = sParams[1]; + } + + else if( sValueName=="DISCIMAGE" ) + { + out.m_sDiscFile = sParams[1]; + } + + else if( sValueName=="LYRICSPATH" ) + { + out.m_sLyricsFile = sParams[1]; + } + + else if( sValueName=="CDTITLE" ) + { + out.m_sCDTitleFile = sParams[1]; + } + + else if( sValueName=="MUSIC" ) + { + out.m_sMusicFile = sParams[1]; + } + + else if(sValueName == "PREVIEW") + { + out.m_PreviewFile= sParams[1]; + } + + else if( sValueName=="INSTRUMENTTRACK" ) + { + SMLoader::ProcessInstrumentTracks( out, sParams[1] ); + } + + else if( sValueName=="MUSICLENGTH" ) + { + if( !bFromCache ) + continue; + out.m_fMusicLengthSeconds = StringToFloat( sParams[1] ); + } + + else if( sValueName=="LASTBEATHINT" ) + { + // unable to parse due to tag position. Ignore. + } + + else if (sValueName == "LASTSECONDHINT") + { + out.SetSpecifiedLastSecond(StringToFloat(sParams[1])); + } + + else if( sValueName=="MUSICBYTES" ) + { + ; // ignore + } + + else if( sValueName=="SAMPLESTART" ) + { + out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="SAMPLELENGTH" ) + { + out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + out.m_DisplayBPMType = DISPLAY_BPM_RANDOM; + else + { + out.m_DisplayBPMType = DISPLAY_BPM_SPECIFIED; + out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); + if( sParams[2].empty() ) + out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; + else + out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); + } + } + + else if( sValueName=="SELECTABLE" ) + { + if(sParams[1].EqualsNoCase("YES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if(sParams[1].EqualsNoCase("NO")) + out.m_SelectionDisplay = out.SHOW_NEVER; + // ROULETTE from 3.9 is no longer in use. + else if(sParams[1].EqualsNoCase("ROULETTE")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + /* The following two cases are just fixes to make sure simfiles that + * used 3.9+ features are not excluded here */ + else if(sParams[1].EqualsNoCase("ES") || sParams[1].EqualsNoCase("OMES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if( StringToInt(sParams[1]) > 0 ) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else + LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); + } + + else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) + { + SMLoader::ProcessBGChanges( out, sValueName, sPath, sParams[1]); + } + + else if( sValueName=="FGCHANGES" ) + { + vector aFGChangeExpressions; + split( sParams[1], ",", aFGChangeExpressions ); + + for( unsigned b=0; b= 2 && keysounds.substr(0, 2) == "\\#" ) + keysounds = keysounds.substr(1); + split( keysounds, ",", out.m_vsKeysoundFile ); + } + + // Attacks loaded from file + else if( sValueName=="ATTACKS" ) + { + ProcessAttackString(out.m_sAttackString, sParams); + ProcessAttacks(out.m_Attacks, sParams); + } + + else if( sValueName=="OFFSET" ) + { + out.m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + } + /* Below are the song based timings that should only be used + * if the steps do not have their own timing. */ + else if( sValueName=="STOPS" ) + { + ProcessStops(out.m_SongTiming, sParams[1]); + } + else if( sValueName=="DELAYS" ) + { + SMLoader::ProcessDelays(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="BPMS" ) + { + ProcessBPMs(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="WARPS" ) // Older versions allowed em here. + { + ProcessWarps( out.m_SongTiming, sParams[1], out.m_fVersion ); + } + + else if( sValueName=="LABELS" ) + { + ProcessLabels( out.m_SongTiming, sParams[1] ); + } + + else if( sValueName=="TIMESIGNATURES" ) + { + SMLoader::ProcessTimeSignatures(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="TICKCOUNTS" ) + { + SMLoader::ProcessTickcounts(out.m_SongTiming, sParams[1]); + } + + else if( sValueName=="COMBOS" ) + { + ProcessCombos( out.m_SongTiming, sParams[1] ); + } + else if (sValueName=="SPEEDS") + { + ProcessSpeeds(out.m_SongTiming, sParams[1]); + } + else if (sValueName=="SCROLLS") + { + ProcessScrolls(out.m_SongTiming, sParams[1]); + } + else if (sValueName=="FAKES") + { + ProcessFakes(out.m_SongTiming, sParams[1]); + } + + /* The following are cache tags. Never fill their values + * directly: only from the cached version. */ + else if( sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" ) + { + // no longer used. + } + else if (sValueName=="FIRSTSECOND") + { + if( bFromCache ) + out.SetFirstSecond(StringToFloat(sParams[1])); + } + + else if( sValueName=="LASTSECOND" ) + { + if( bFromCache ) + out.SetLastSecond(StringToFloat(sParams[1])); + } + + else if( sValueName=="SONGFILENAME" ) + { + if( bFromCache ) + out.m_sSongFileName = sParams[1]; + } + + else if( sValueName=="HASMUSIC" ) + { + if( bFromCache ) + out.m_bHasMusic = StringToInt( sParams[1] ) != 0; + } + + else if( sValueName=="HASBANNER" ) + { + if( bFromCache ) + out.m_bHasBanner = StringToInt( sParams[1] ) != 0; + } + // This tag will get us to the next section. - else if(sValueName == "NOTEDATA") + else if( sValueName=="NOTEDATA" ) { state = GETTING_STEP_INFO; pNewNotes = out.CreateSteps(); - stepsTiming = TimingData(out.m_SongTiming.m_fBeat0OffsetInSeconds); - reused_steps_info.has_own_timing = false; - reused_steps_info.steps= pNewNotes; - reused_steps_info.timing= &stepsTiming; - } - else - { - // Silently ignore unrecognized tags, as was done before. -Kyz + stepsTiming = TimingData( out.m_SongTiming.m_fBeat0OffsetInSeconds ); + bHasOwnTiming = false; } break; } case GETTING_STEP_INFO: { - reused_steps_info.params= &sParams; - steps_handler_map_t::iterator handler= - parser_helper.steps_tag_handlers.find(sValueName); - if(handler != parser_helper.steps_tag_handlers.end()) + if (sValueName == "CHARTNAME") { - handler->second(reused_steps_info); + pNewNotes->SetChartName(sParams[1]); } - else if(sValueName=="NOTES" || sValueName=="NOTES2") + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + pNewNotes->m_StepsTypeStr= sParams[1]; + } + + else if( sValueName=="CHARTSTYLE" ) + { + pNewNotes->SetChartStyle( sParams[1] ); + } + + else if( sValueName=="DESCRIPTION" ) + { + if (out.m_fVersion < VERSION_CHART_NAME_TAG) + { + pNewNotes->SetChartName(sParams[1]); + } + else + { + pNewNotes->SetDescription(sParams[1]); + } + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( StringToDifficulty( sParams[1] ) ); + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( StringToInt( sParams[1] ) ); + } + + else if( sValueName=="RADARVALUES" ) + { + if (bFromCache) + { + vector saValues; + split( sParams[1], ",", saValues, true ); + + int categories = NUM_RadarCategory; + if( out.m_fVersion < VERSION_RADAR_FAKE ) + categories -= 1; + + if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + { + // Can't use the foreach anymore due to flexible radar lines. + for( RadarCategory rc = (RadarCategory)0; rc < categories; + enum_add( rc, +1 ) ) + { + v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); + } + } + pNewNotes->SetCachedRadarValues( v ); + } + } + else + { + // just recalc at time. + } + + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + } + + else if( sValueName=="NOTES" || sValueName=="NOTES2" ) { state = GETTING_SONG_INFO; - if(reused_steps_info.has_own_timing) - { pNewNotes->m_Timing = stepsTiming; } - reused_steps_info.has_own_timing = false; - pNewNotes->SetSMNoteData(sParams[1]); + if( bHasOwnTiming ) + pNewNotes->m_Timing = stepsTiming; + bHasOwnTiming = false; + pNewNotes->SetSMNoteData( sParams[1] ); pNewNotes->TidyUpData(); pNewNotes->SetFilename(sPath); - out.AddSteps(pNewNotes); + out.AddSteps( pNewNotes ); } - else if(sValueName=="STEPFILENAME") + + else if( sValueName=="BPMS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessBPMs(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="STOPS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessStops(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="DELAYS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + SMLoader::ProcessDelays(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="TIMESIGNATURES" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + SMLoader::ProcessTimeSignatures(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="TICKCOUNTS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + SMLoader::ProcessTickcounts(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="COMBOS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessCombos(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + + else if( sValueName=="WARPS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessWarps(stepsTiming, sParams[1], out.m_fVersion); + bHasOwnTiming = true; + } + } + + else if( sValueName=="SPEEDS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessSpeeds( stepsTiming, sParams[1] ); + bHasOwnTiming = true; + } + } + + else if( sValueName=="SCROLLS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessScrolls( stepsTiming, sParams[1] ); + bHasOwnTiming = true; + } + } + + else if( sValueName=="FAKES" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessFakes( stepsTiming, sParams[1] ); + bHasOwnTiming = true; + } + } + + else if( sValueName=="LABELS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessLabels(stepsTiming, sParams[1]); + bHasOwnTiming = true; + } + } + /* If this is called, the chart does not use the same attacks + * as the Song's timing. No other changes are required. */ + else if( sValueName=="ATTACKS" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + ProcessAttackString(pNewNotes->m_sAttackString, sParams); + ProcessAttacks(pNewNotes->m_Attacks, sParams); + } + } + + else if( sValueName=="OFFSET" ) + { + if (out.m_fVersion >= VERSION_SPLIT_TIMING) + { + stepsTiming.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + bHasOwnTiming = true; + } + } + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + pNewNotes->SetDisplayBPM(DISPLAY_BPM_RANDOM); + else + { + pNewNotes->SetDisplayBPM(DISPLAY_BPM_SPECIFIED); + float min = StringToFloat(sParams[1]); + pNewNotes->SetMinBPM(min); + if(sParams[2].empty()) + pNewNotes->SetMaxBPM(min); + else + pNewNotes->SetMaxBPM(StringToFloat(sParams[2])); + } + } + else if( sValueName=="STEPFILENAME" ) { state = GETTING_SONG_INFO; - if(reused_steps_info.has_own_timing) - { pNewNotes->m_Timing = stepsTiming; } - reused_steps_info.has_own_timing = false; + if( bHasOwnTiming ) + pNewNotes->m_Timing = stepsTiming; + bHasOwnTiming = false; pNewNotes->SetFilename(sParams[1]); - out.AddSteps(pNewNotes); - } - else - { - // Silently ignore unrecognized tags, as was done before. -Kyz + out.AddSteps( pNewNotes ); } break; } @@ -1066,133 +913,249 @@ bool SSCLoader::LoadEditFromMsd(const MsdFile &msd, { Song* pSong = givenSong; Steps* pNewNotes = NULL; + bool bSSCFormat = false; + bool bHasOwnTiming = false; TimingData stepsTiming; - StepsTagInfo reused_steps_info(&*this, pSong, sEditFilePath, false); - reused_steps_info.for_load_edit= true; - - for(unsigned int i = 0; i < msd.GetNumValues(); ++i) + for( unsigned i=0; im_fVersion = StringToFloat( sParams[1] ); + } + + else if( sValueName=="SONG" ) + { + if( pSong ) { - handler->second(reused_steps_info); + /* LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); + return false; */ + continue; } - else if(sValueName=="NOTEDATA") + + RString sSongFullTitle = sParams[1]; + this->SetSongTitle(sParams[1]); + sSongFullTitle.Replace( '\\', '/' ); + + pSong = SONGMAN->FindSong( sSongFullTitle ); + if( pSong == NULL ) { - pNewNotes = pSong->CreateSteps(); - reused_steps_info.steps= pNewNotes; - reused_steps_info.ssc_format= true; + LOG->UserLog("Edit file", + sEditFilePath, + "requires a song \"%s\" that isn't present.", + sSongFullTitle.c_str() ); + return false; } - else if(sValueName=="NOTES") + + if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) { - if(pSong == NULL) - { - LOG->UserLog("Edit file", sEditFilePath, - "doesn't have a #SONG tag preceeding the first #NOTES tag," - " and is not in a valid song-specific folder."); - return false; - } + LOG->UserLog("Song file", + sSongFullTitle, + "already has the maximum number of edits allowed for ProfileSlotP%d.", + slot+1 ); + return false; + } + } - if(!reused_steps_info.ssc_format && iNumParams < 7) - { - LOG->UserLog("Edit file", sEditFilePath, - "has %d fields in a #NOTES tag, but should have at least 7.", - iNumParams); - continue; - } + else if( sValueName=="NOTEDATA" ) + { + pNewNotes = pSong->CreateSteps(); + bSSCFormat = true; + } + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + pNewNotes->m_StepsTypeStr= sParams[1]; + bSSCFormat = true; + } - // I have no idea what the purpose of this bAddStepsToSong flag is. - // It looks like it causes LoadEditFromMsd to just throw away - // whatever steps data was loaded, possibly leaking the memory used - // by pNewNotes. It was here before I rewrote LoadEditFromMsd to - // use a map instead of an else if chain, so I preserved it. -Kyz - if(!bAddStepsToSong) - { return true; } + else if( sValueName=="CHARTSTYLE" ) + { + pNewNotes->SetChartStyle( sParams[1] ); + bSSCFormat = true; + } - if(reused_steps_info.ssc_format) - { - if(reused_steps_info.has_own_timing) + else if( sValueName=="DESCRIPTION" ) + { + pNewNotes->SetDescription( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( StringToDifficulty( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( StringToInt( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="RADARVALUES" ) + { + vector saValues; + split( sParams[1], ",", saValues, true ); + if( saValues.size() == NUM_RadarCategory * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + FOREACH_ENUM( RadarCategory, rc ) + v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); + pNewNotes->SetCachedRadarValues( v ); + } + bSSCFormat = true; + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="BPMS" ) + { + ProcessBPMs(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="STOPS" ) + { + ProcessStops(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="DELAYS" ) + { + SMLoader::ProcessDelays(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="TIMESIGNATURES" ) + { + SMLoader::ProcessTimeSignatures(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="TICKCOUNTS" ) + { + SMLoader::ProcessTickcounts(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="COMBOS" ) + { + ProcessCombos(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="WARPS" ) + { + ProcessWarps(stepsTiming, sParams[1], pSong->m_fVersion); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="SPEEDS" ) + { + ProcessSpeeds( stepsTiming, sParams[1] ); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="FAKES" ) + { + ProcessFakes( stepsTiming, sParams[1] ); + bSSCFormat = true; + bHasOwnTiming = true; + } + + else if( sValueName=="LABELS" ) + { + ProcessLabels(stepsTiming, sParams[1]); + bSSCFormat = true; + bHasOwnTiming = true; + } + else if( sValueName=="NOTES" ) + { + if( pSong == NULL ) + { + LOG->UserLog("Edit file", + sEditFilePath, + "doesn't have a #SONG tag preceeding the first #NOTES tag, and is not in a valid song-specific folder." ); + return false; + } + + if ( !bSSCFormat && iNumParams < 7 ) + { + LOG->UserLog("Edit file", + sEditFilePath, + "has %d fields in a #NOTES tag, but should have at least 7.", + iNumParams ); + continue; + } + + if( !bAddStepsToSong ) + return true; + + if( bSSCFormat ) + { + if ( bHasOwnTiming ) pNewNotes->m_Timing = stepsTiming; - pNewNotes->SetSMNoteData(sParams[1]); - pNewNotes->TidyUpData(); - pSong->AddSteps(pNewNotes); - } - else - { - pNewNotes = pSong->CreateSteps(); - LoadFromTokens(sParams[1], - sParams[2], - sParams[3], - sParams[4], - sParams[5], - sParams[6], - *pNewNotes); - } - - pNewNotes->SetLoadedFromProfile(slot); - pNewNotes->SetDifficulty(Difficulty_Edit); - pNewNotes->SetFilename(sEditFilePath); - - if(pSong->IsEditAlreadyLoaded(pNewNotes)) - { - LOG->UserLog("Edit file", sEditFilePath, - "is a duplicate of another edit that was already loaded."); - SAFE_DELETE(pNewNotes); - return false; - } - - pSong->AddSteps(pNewNotes); - return true; // Only allow one Steps per edit file! + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + pSong->AddSteps( pNewNotes ); } else { - LOG->UserLog("Edit file", sEditFilePath, - "has an unexpected value \"%s\".", sValueName.c_str()); + pNewNotes = pSong->CreateSteps(); + LoadFromTokens(sParams[1], + sParams[2], + sParams[3], + sParams[4], + sParams[5], + sParams[6], + *pNewNotes); } + + pNewNotes->SetLoadedFromProfile( slot ); + pNewNotes->SetDifficulty( Difficulty_Edit ); + pNewNotes->SetFilename( sEditFilePath ); + + if( pSong->IsEditAlreadyLoaded(pNewNotes) ) + { + LOG->UserLog("Edit file", + sEditFilePath, + "is a duplicate of another edit that was already loaded." ); + SAFE_DELETE( pNewNotes ); + return false; + } + + pSong->AddSteps( pNewNotes ); + return true; // Only allow one Steps per edit file! } else { - if(sValueName == "SONG") - { - if(pSong) - { - /* LOG->UserLog("Edit file", sEditFilePath, "has more than one #SONG tag."); - return false; */ - continue; - } - - RString sSongFullTitle = sParams[1]; - this->SetSongTitle(sParams[1]); - sSongFullTitle.Replace('\\', '/'); - pSong = SONGMAN->FindSong(sSongFullTitle); - if(pSong == NULL) - { - LOG->UserLog("Edit file", sEditFilePath, - "requires a song \"%s\" that isn't present.", - sSongFullTitle.c_str()); - return false; - } - if(pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE) - { - LOG->UserLog("Song file", sSongFullTitle, - "already has the maximum number of edits allowed for ProfileSlotP%d.", - slot+1); - return false; - } - reused_steps_info.song= pSong; - } + LOG->UserLog("Edit file", + sEditFilePath, + "has an unexpected value \"%s\".", + sValueName.c_str() ); } } + // Edit had no valid #NOTES sections return false; } diff --git a/src/PrefsManager.cpp b/src/PrefsManager.cpp index 17629dbc96..e18e3ef944 100644 --- a/src/PrefsManager.cpp +++ b/src/PrefsManager.cpp @@ -466,17 +466,16 @@ void PrefsManager::ReadGamePrefsFromIni( const RString &sIni ) FOREACH_CONST_Child( &ini, section ) { - RString section_name= section->GetName(); - if( !BeginsWith(section_name, GAME_SECTION_PREFIX) ) + if( !BeginsWith(section->GetName(), GAME_SECTION_PREFIX) ) continue; - RString sGame = section_name.Right( section_name.length() - GAME_SECTION_PREFIX.length() ); + RString sGame = section->GetName().Right( section->GetName().length() - GAME_SECTION_PREFIX.length() ); GamePrefs &gp = m_mapGameNameToGamePrefs[ sGame ]; // todo: read more prefs here? -aj - ini.GetValue(section_name, "Announcer", gp.m_sAnnouncer); - ini.GetValue(section_name, "Theme", gp.m_sTheme); - ini.GetValue(section_name, "DefaultModifiers", gp.m_sDefaultModifiers); + ini.GetValue( section->GetName(), "Announcer", gp.m_sAnnouncer ); + ini.GetValue( section->GetName(), "Theme", gp.m_sTheme ); + ini.GetValue( section->GetName(), "DefaultModifiers", gp.m_sDefaultModifiers ); } } diff --git a/src/RageTimer.h b/src/RageTimer.h index fda5ab3a9a..da863c11d5 100644 --- a/src/RageTimer.h +++ b/src/RageTimer.h @@ -53,7 +53,7 @@ extern const RageTimer RageZeroTimer; // For profiling how long some chunk of code takes. -Kyz #define START_TIME(name) float name##_start_time= RageTimer::GetTimeSinceStartFast(); -#define END_TIME(name) float name##_end_time= RageTimer::GetTimeSinceStartFast(); LOG->Warn(#name " time: %f to %f = %f", name##_start_time, name##_end_time, name##_end_time - name##_start_time); +#define END_TIME(name) float name##_end_time= RageTimer::GetTimeSinceStartFast(); LOG->Warn(#name " time: %f", name##_end_time - name##_start_time); #endif