Merging of the SSCNotes branch to default.

This commit is contained in:
Jason Felds
2011-02-11 22:59:30 -05:00
35 changed files with 2085 additions and 160 deletions
+1
View File
@@ -1237,6 +1237,7 @@
</Class>
<Class name='Steps'>
<Function name='GetDescription'/>
<Function name='GetAuthorCredit'/>
<Function name='GetDifficulty'/>
<Function name='GetFilename'/>
<Function name='GetHash'/>
+3
View File
@@ -3033,6 +3033,9 @@
<Function name='GetDescription' return='string' arguments=''>
Returns the Steps description.
</Function>
<Function name='GetAuthorCredit' return='string' arguments=''>
Returns the author that made that particular Steps pattern.
</Function>
<Function name='GetDifficulty' return='Difficulty' arguments=''>
Returns the Steps difficulty.
</Function>
+7
View File
@@ -989,6 +989,7 @@ SoundResampleQuality=Resampling Quality
SoundVolume=Sound Volume
SoundVolumeAttract=Attract Volume
Speed=Speed
Step Author=Step Author
Steps=Steps
Stream=Stream
Style=Style
@@ -1204,6 +1205,7 @@ Enter a new artist.=Enter a new artist.
Enter a new genre.=Enter a new genre.
Enter a new credit.=Enter a new credit.
Enter a new description.=Enter a new description.
Enter the author who made this step pattern.=Enter the author who made this step pattern.
Enter a new last beat hint.=Enter a new last beat hint.
Enter a new main title transliteration.=Enter a new main title transliteration.
Enter a new main title.=Enter a new main title.
@@ -1373,6 +1375,10 @@ Error deleting the file '%s'.=Error deleting the file "%s".
Error renaming file. Destination file '%s' already exists.=Error renaming file. Destination file '%s' already exists.
Error writing file '%s'.=Error writing file '%s'.
[NotesWriterSSC]
Error renaming file. Destination file '%s' already exists.=Error renaming file. Destination file '%s' already exists.
Error writing file '%s'.=Error writing file '%s'.
[ScreenOptionsManageProfiles]
Are you sure you want to clear all data in the profile '%s'?=Are you sure you want to clear all data in the profile &oq;%s&cq;?
Are you sure you want to delete the profile '%s'?=Are you sure you want to delete the profile &oq;%s&cq;?
@@ -1604,6 +1610,7 @@ The folder "%s" appears to be a song folder. All song folders must reside in a
You must supply a name for your new edit.=You must supply a name for your new edit.
The name you chose conflicts with another edit. Please use a different name.=The name you chose conflicts with another edit. Please use a different name.
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
[SongSort]
FewestPlays=Fewest Plays
@@ -1,4 +1,4 @@
#TITLE:Sync;
#TITLE:Sync;
#SUBTITLE:;
#ARTIST:Unknown artist;
#TITLETRANSLIT:;
@@ -20,18 +20,15 @@
#BGCHANGES:;
#KEYSOUNDS:;
//---------------dance-single - blank----------------
#NOTEDATA:;
#STEPSTYPE:dance-single:;
#DESCRIPTION:blank;
#DIFFICULTY:Beginner;
#METER:1;
#RADARVALUES:0.302,0.205,0.000,0.000,0.000;
#NOTES:
dance-single:
blank:
Beginner:
1:
0.302,0.205,0.000,0.000,0.000:
// measure 1
0000
0000
0000
0000
, // measure 2
1000
0001
@@ -97,18 +94,15 @@
0001
;
//---------------dance-single - blank----------------
#NOTEDATA:;
#STEPSTYPE:pump-single;
#DESCRIPTION:blank;
#DIFFICULTY:Beginner;
#METER:1;
#RADARVALUES:0.302,0.205,0.000,0.000,0.000;
#NOTES:
pump-single:
blank:
Beginner:
1:
0.302,0.205,0.000,0.000,0.000:
// measure 1
00000
00000
00000
00000
, // measure 2
10000
00001
@@ -6,44 +6,28 @@
// a song file here.
#TITLE:ScreenHowToPlay steps;
#ARTIST:foo;
#BPMS:0.000=100.000
#BPMS:0.000=100.000;
#STOPS:16=2,18=2,20=2,22=2;
#NOTEDATA:;
#STEPSTYPE:dance-single;
#DESCRIPTION:BASIC;
#DIFFICULTY:easy;
#METER:1;
#RADARVALUES:0,0,0,0,0;
#NOTES:
dance-single:
BASIC:
easy:
1:
0,0,0,0,0:
0000
0000
0000
0000
,
0000
0000
0000
0000
,
0000
0000
0000
0000
,
0000
0000
0000
0000
,
0100
0000
0010
0000
,
1000
0000
1001
0000
,
1000
0100
@@ -79,51 +63,30 @@
0000
,
0000
0000
0000
0000
,
0000
0000
0000
0000
,;
#NOTEDATA:;
#STEPSTYPE:pump-single;
#DESCRIPTION:NORMAL;
#DIFFICULTY:easy;
#METER:1;
#RADARVALUES:0,0,0,0,0;
#NOTES:
pump-single:
NORMAL:
easy:
1:
0,0,0,0,0:
00000
00000
00000
00000
,
00000
00000
00000
00000
,
00000
00000
00000
00000
,
00000
00000
00000
00000
,
01000
00000
00100
00000
,
10000
00000
10010
00000
,
10000
01000
@@ -159,12 +122,6 @@
00000
,
00000
00000
00000
00000
,
00000
00000
00000
00000
,;
+16
View File
@@ -23,6 +23,10 @@
/* Begin PBXBuildFile section */
1215D7A208C6559A00B87D8B /* ScreenGameplayNormal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1215D7A008C6559A00B87D8B /* ScreenGameplayNormal.cpp */; };
2BA7925E1304F20D002BD8E1 /* NotesLoaderSSC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */; };
2BA7925F1304F20D002BD8E1 /* NotesLoaderSSC.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */; };
2BA792601304F20D002BD8E1 /* NotesWriterSSC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */; };
2BA792611304F20D002BD8E1 /* NotesWriterSSC.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */; };
3659B56F0F902143002B6B68 /* CommandLineActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3659B56D0F902143002B6B68 /* CommandLineActions.cpp */; };
3659B5700F902143002B6B68 /* CommandLineActions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3659B56E0F902143002B6B68 /* CommandLineActions.h */; };
367D575B0EDE56F200B46814 /* ScreenHighScores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 367D57590EDE56F200B46814 /* ScreenHighScores.cpp */; };
@@ -1768,6 +1772,10 @@
1215D7A108C6559A00B87D8B /* ScreenGameplayNormal.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenGameplayNormal.h; path = ../src/ScreenGameplayNormal.h; sourceTree = "<group>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderSSC.cpp; path = ../src/NotesLoaderSSC.cpp; sourceTree = SOURCE_ROOT; };
2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesLoaderSSC.h; path = ../src/NotesLoaderSSC.h; sourceTree = SOURCE_ROOT; };
2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesWriterSSC.cpp; path = ../src/NotesWriterSSC.cpp; sourceTree = SOURCE_ROOT; };
2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesWriterSSC.h; path = ../src/NotesWriterSSC.h; sourceTree = SOURCE_ROOT; };
3659B56D0F902143002B6B68 /* CommandLineActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommandLineActions.cpp; sourceTree = "<group>"; };
3659B56E0F902143002B6B68 /* CommandLineActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommandLineActions.h; sourceTree = "<group>"; };
367D57590EDE56F200B46814 /* ScreenHighScores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenHighScores.cpp; path = ../src/ScreenHighScores.cpp; sourceTree = SOURCE_ROOT; };
@@ -3779,10 +3787,14 @@
EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */,
AA6EFDF504770C79005F316C /* NotesLoaderSM.cpp */,
AA6EFDF604770C79005F316C /* NotesLoaderSM.h */,
2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */,
2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */,
AA6EFDF704770C79005F316C /* NotesWriterDWI.cpp */,
AA6EFDF804770C79005F316C /* NotesWriterDWI.h */,
AA6EFDF904770C79005F316C /* NotesWriterSM.cpp */,
AA6EFDFA04770C79005F316C /* NotesWriterSM.h */,
2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */,
2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */,
AA6EFDFB04770C79005F316C /* NoteTypes.cpp */,
AA6EFDFC04770C79005F316C /* NoteTypes.h */,
AA80C75707F20D6600C99272 /* OptionRowHandler.cpp */,
@@ -4914,6 +4926,8 @@
EE906F7712BF3A6900146C96 /* json_batchallocator.h in Headers */,
EE906F8312BF3AF800146C96 /* JsonUtil.h in Headers */,
EE906F8B12BF3C7C00146C96 /* FileDownload.h in Headers */,
2BA7925F1304F20D002BD8E1 /* NotesLoaderSSC.h in Headers */,
2BA792611304F20D002BD8E1 /* NotesWriterSSC.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -6156,6 +6170,8 @@
EE906F7D12BF3A6900146C96 /* json_writer.cpp in Sources */,
EE906F8212BF3AF800146C96 /* JsonUtil.cpp in Sources */,
EE906F8A12BF3C7C00146C96 /* FileDownload.cpp in Sources */,
2BA7925E1304F20D002BD8E1 /* NotesLoaderSSC.cpp in Sources */,
2BA792601304F20D002BD8E1 /* NotesWriterSSC.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+2 -2
View File
@@ -6,7 +6,7 @@
#include "RageUtil.h"
#include "GameState.h"
#include "TimingData.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "PrefsManager.h"
#include "RageDisplay.h"
#include "AnnouncerManager.h"
@@ -141,7 +141,7 @@ static void StartMusic( MusicToPlay &ToPlay )
{
LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() );
Song song;
if( SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) )
if( SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) )
{
ToPlay.HasTiming = true;
ToPlay.m_TimingData = song.m_Timing;
+5 -2
View File
@@ -144,8 +144,11 @@ LyricsLoader.cpp LyricsLoader.h \
ModsGroup.cpp ModsGroup.h \
NoteData.cpp NoteData.h NoteDataUtil.cpp NoteDataUtil.h NoteDataWithScoring.cpp NoteDataWithScoring.h \
NoteTypes.cpp NoteTypes.h NotesLoader.cpp NotesLoader.h \
NotesLoaderBMS.cpp NotesLoaderBMS.h NotesLoaderDWI.cpp NotesLoaderDWI.h NotesLoaderKSF.cpp NotesLoaderKSF.h NotesLoaderMidi.cpp NotesLoaderMidi.h \
NotesLoaderPMS.cpp NotesLoaderPMS.h NotesLoaderSM.cpp NotesLoaderSM.h NotesWriterDWI.cpp NotesWriterDWI.h NotesWriterSM.cpp NotesWriterSM.h \
NotesLoaderBMS.cpp NotesLoaderBMS.h NotesLoaderDWI.cpp NotesLoaderDWI.h \
NotesLoaderKSF.cpp NotesLoaderKSF.h NotesLoaderMidi.cpp NotesLoaderMidi.h \
NotesLoaderPMS.cpp NotesLoaderPMS.h NotesLoaderSM.cpp NotesLoaderSM.h \
NotesLoaderSSC.cpp NotesLoaderSSC.h NotesWriterDWI.cpp NotesWriterDWI.h \
NotesWriterSM.cpp NotesWriterSM.h NotesWriterSSC.cpp NotesWriterSSC.h \
OptionRowHandler.cpp OptionRowHandler.h OptionsList.cpp OptionsList.h \
PlayerAI.cpp PlayerAI.h PlayerNumber.cpp PlayerNumber.h PlayerOptions.cpp PlayerOptions.h \
PlayerStageStats.cpp PlayerStageStats.h \
+1 -1
View File
@@ -1,4 +1,4 @@
/* MsdFile - Read .SM, .DWI, and .MSD files. */
/* MsdFile - Read .SSC, .SM, .DWI, and .MSD files. */
#ifndef MSDFILE_H
#define MSDFILE_H
+7 -3
View File
@@ -1,6 +1,7 @@
#include "global.h"
#include "NotesLoader.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "NotesLoaderDWI.h"
#include "NotesLoaderBMS.h"
#include "NotesLoaderPMS.h"
@@ -30,14 +31,17 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set<RString> &Bl
vector<RString> list;
BlacklistedImages.clear();
SMLoader::GetApplicableFiles( sPath, list );
SSCLoader::GetApplicableFiles( sPath, list );
if( !list.empty() )
{
if( !SMLoader::LoadFromDir(sPath, out) )
if( !SSCLoader::LoadFromDir( sPath, out ) )
return false;
SMLoader::TidyUpData( out, false );
SSCLoader::TidyUpData( out, false );
return true;
}
SMLoader::GetApplicableFiles( sPath, list );
if (!list.empty() )
return SMLoader::LoadFromDir( sPath, out );
DWILoader::GetApplicableFiles( sPath, list );
if( !list.empty() )
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
+1 -1
View File
@@ -14,7 +14,7 @@
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
static void LoadFromSMTokens(
void SMLoader::LoadFromSMTokens(
RString sStepsType,
RString sDescription,
RString sDifficulty,
+3
View File
@@ -12,6 +12,9 @@ class TimingData;
namespace SMLoader
{
void LoadFromSMTokens( RString sStepsType, RString sDescription, RString sDifficulty,
RString sMeter, RString sRadarValues, RString sNoteData, Steps &out );
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
File diff suppressed because it is too large Load Diff
+59
View File
@@ -0,0 +1,59 @@
/* SSCLoader - Reads a Song and its Steps from a .SSC file. */
#ifndef NotesLoaderSSC_H
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
class MsdFile;
class Song;
class Steps;
class TimingData;
enum SSCLoadingStates
{
GETTING_SONG_INFO,
GETTING_STEP_INFO,
GETTING_STEP_TIMING_INFO,
GETTING_NOTE_INFO,
NUM_SSCLoadingStates
};
namespace SSCLoader
{
bool LoadFromDir( const RString &sPath, Song &out );
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
void TidyUpData( Song &song, bool bFromCache );
}
#endif
/*
* (c) 2011 Jason Felds
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+6 -20
View File
@@ -239,7 +239,7 @@ static RString JoinLineList( vector<RString> &lines )
return join( "\r\n", lines.begin()+j, lines.end() );
}
static RString GetSMNotesTag( const Song &song, const Steps &in, bool bSavingCache )
static RString GetSMNotesTag( const Song &song, const Steps &in )
{
vector<RString> lines;
@@ -271,15 +271,11 @@ static RString GetSMNotesTag( const Song &song, const Steps &in, bool bSavingCac
return JoinLineList( lines );
}
bool NotesWriterSM::Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave, bool bSavingCache )
bool NotesWriterSM::Write( RString sPath, const Song &out )
{
int flags = RageFile::WRITE;
/* If we're not saving cache, we're saving real data, so enable SLOW_FLUSH
* to prevent data loss. If we're saving cache, this will slow things down
* too much. */
if( !bSavingCache )
flags |= RageFile::SLOW_FLUSH;
flags |= RageFile::SLOW_FLUSH;
RageFile f;
if( !f.Open( sPath, flags ) )
@@ -289,23 +285,13 @@ bool NotesWriterSM::Write( RString sPath, const Song &out, const vector<Steps*>&
}
WriteGlobalTags( f, out );
if( bSavingCache )
{
f.PutLine( ssprintf( "// cache tags:" ) );
f.PutLine( ssprintf( "#FIRSTBEAT:%.3f;", out.m_fFirstBeat ) );
f.PutLine( ssprintf( "#LASTBEAT:%.3f;", out.m_fLastBeat ) );
f.PutLine( ssprintf( "#SONGFILENAME:%s;", out.m_sSongFileName.c_str() ) );
f.PutLine( ssprintf( "#HASMUSIC:%i;", out.m_bHasMusic ) );
f.PutLine( ssprintf( "#HASBANNER:%i;", out.m_bHasBanner ) );
f.PutLine( ssprintf( "#MUSICLENGTH:%.3f;", out.m_fMusicLengthSeconds ) );
f.PutLine( ssprintf( "// end cache tags" ) );
}
// Save specified Steps to this file
const vector<Steps*>& vpStepsToSave = out.GetAllSteps();
FOREACH_CONST( Steps*, vpStepsToSave, s )
{
const Steps* pSteps = *s;
RString sTag = GetSMNotesTag( out, *pSteps, bSavingCache );
RString sTag = GetSMNotesTag( out, *pSteps );
f.PutLine( sTag );
}
if( f.Flush() == -1 )
@@ -325,7 +311,7 @@ void NotesWriterSM::GetEditFileContents( const Song *pSong, const Steps *pSteps,
if( asParts.size() )
sDir = join( "/", asParts.begin()+1, asParts.end() );
sOut += ssprintf( "#SONG:%s;\r\n", sDir.c_str() );
sOut += GetSMNotesTag( *pSong, *pSteps, false );
sOut += GetSMNotesTag( *pSong, *pSteps );
}
RString NotesWriterSM::GetEditFileName( const Song *pSong, const Steps *pSteps )
+1 -1
View File
@@ -7,7 +7,7 @@ class Song;
class Steps;
namespace NotesWriterSM
{
bool Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave, bool bSavingCache );
bool Write( RString sPath, const Song &out );
void GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut );
RString GetEditFileName( const Song *pSong, const Steps *pSteps );
bool WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut );
+508
View File
@@ -0,0 +1,508 @@
#include "global.h"
#include <cerrno>
#include <cstring>
#include "NotesWriterSSC.h"
#include "BackgroundUtil.h"
#include "Foreach.h"
#include "GameManager.h"
#include "LocalizedString.h"
#include "NoteTypes.h"
#include "Profile.h"
#include "ProfileManager.h"
#include "RageFile.h"
#include "RageFileManager.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "Song.h"
#include "Steps.h"
static RString BackgroundChangeToString( const BackgroundChange &bgc )
{
// TODO: Technically we need to double-escape the filename (because it might contain '=') and then
// unescape the value returned by the MsdFile.
RString s = ssprintf(
"%.3f=%s=%.3f=%d=%d=%d=%s=%s=%s=%s=%s",
bgc.m_fStartBeat,
SmEscape(bgc.m_def.m_sFile1).c_str(),
bgc.m_fRate,
bgc.m_sTransition == SBT_CrossFade, // backward compat
bgc.m_def.m_sEffect == SBE_StretchRewind, // backward compat
bgc.m_def.m_sEffect != SBE_StretchNoLoop, // backward compat
bgc.m_def.m_sEffect.c_str(),
bgc.m_def.m_sFile2.c_str(),
bgc.m_sTransition.c_str(),
SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor1)).c_str(),
SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor2)).c_str()
);
return s;
}
static void WriteGlobalTags( RageFile &f, const Song &out )
{
//f.PutLine( ssprintf( "#SMVERSION:;", SmEscape(RString("ssc-v1.0")).c_str() ) );
f.PutLine( ssprintf( "#TITLE:%s;", SmEscape(out.m_sMainTitle).c_str() ) );
f.PutLine( ssprintf( "#SUBTITLE:%s;", SmEscape(out.m_sSubTitle).c_str() ) );
f.PutLine( ssprintf( "#ARTIST:%s;", SmEscape(out.m_sArtist).c_str() ) );
f.PutLine( ssprintf( "#TITLETRANSLIT:%s;", SmEscape(out.m_sMainTitleTranslit).c_str() ) );
f.PutLine( ssprintf( "#SUBTITLETRANSLIT:%s;", SmEscape(out.m_sSubTitleTranslit).c_str() ) );
f.PutLine( ssprintf( "#ARTISTTRANSLIT:%s;", SmEscape(out.m_sArtistTranslit).c_str() ) );
f.PutLine( ssprintf( "#VERSION:%f;", out.m_fVersion ) );
f.PutLine( ssprintf( "#GENRE:%s;", SmEscape(out.m_sGenre).c_str() ) );
f.PutLine( ssprintf( "#CREDIT:%s;", SmEscape(out.m_sCredit).c_str() ) );
f.PutLine( ssprintf( "#BANNER:%s;", SmEscape(out.m_sBannerFile).c_str() ) );
f.PutLine( ssprintf( "#BACKGROUND:%s;", SmEscape(out.m_sBackgroundFile).c_str() ) );
f.PutLine( ssprintf( "#LYRICSPATH:%s;", SmEscape(out.m_sLyricsFile).c_str() ) );
f.PutLine( ssprintf( "#CDTITLE:%s;", SmEscape(out.m_sCDTitleFile).c_str() ) );
f.PutLine( ssprintf( "#MUSIC:%s;", SmEscape(out.m_sMusicFile).c_str() ) );
{
vector<RString> vs;
FOREACH_ENUM( InstrumentTrack, it )
if( out.HasInstrumentTrack(it) )
vs.push_back( InstrumentTrackToString(it) + "=" + out.m_sInstrumentTrackFile[it] );
if( !vs.empty() )
{
RString s = join( ",", vs );
f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" );
}
}
f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_Timing.m_fBeat0OffsetInSeconds ) );
f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) );
f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) );
if( out.m_fSpecifiedLastBeat > 0 )
f.PutLine( ssprintf("#LASTBEATHINT:%.6f;", out.m_fSpecifiedLastBeat) );
f.Write( "#SELECTABLE:" );
switch(out.m_SelectionDisplay)
{
default: ASSERT(0); // fall through
case Song::SHOW_ALWAYS: f.Write( "YES" ); break;
//case Song::SHOW_NONSTOP: f.Write( "NONSTOP" ); break;
case Song::SHOW_NEVER: f.Write( "NO" ); break;
}
f.PutLine( ";" );
switch( out.m_DisplayBPMType )
{
case Song::DISPLAY_ACTUAL:
// write nothing
break;
case Song::DISPLAY_SPECIFIED:
if( out.m_fSpecifiedBPMMin == out.m_fSpecifiedBPMMax )
f.PutLine( ssprintf( "#DISPLAYBPM:%.6f;", out.m_fSpecifiedBPMMin ) );
else
f.PutLine( ssprintf( "#DISPLAYBPM:%.6f:%.6f;", out.m_fSpecifiedBPMMin, out.m_fSpecifiedBPMMax ) );
break;
case Song::DISPLAY_RANDOM:
f.PutLine( ssprintf( "#DISPLAYBPM:*;" ) );
break;
}
f.Write( "#BPMS:" );
for( unsigned i=0; i<out.m_Timing.m_BPMSegments.size(); i++ )
{
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
if( i != out.m_Timing.m_BPMSegments.size()-1 )
f.Write( "," );
}
f.PutLine( ";" );
f.Write( "#STOPS:" );
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
{
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
if(!fs.m_bDelay)
{
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
if( i != out.m_Timing.m_StopSegments.size()-1 )
f.Write( "," );
}
}
f.PutLine( ";" );
f.Write( "#DELAYS:" );
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
{
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
if( fs.m_bDelay )
{
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
if( i != out.m_Timing.m_StopSegments.size()-1 )
f.Write( "," );
}
}
f.PutLine( ";" );
/*
f.Write( "#WARPS:" );
for( unsigned i=0; i<out.m_Timing.m_WarpSegments.size(); i++ )
{
const WarpSegment &ws = out.m_Timing.m_WarpSegments[i];
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(ws.m_iStartRow), ws.m_fWarpBeats ) );
if( i != out.m_Timing.m_WarpSegments.size()-1 )
f.Write( "," );
}
f.PutLine( ";" );
*/
ASSERT( !out.m_Timing.m_vTimeSignatureSegments.empty() );
f.Write( "#TIMESIGNATURES:" );
FOREACH_CONST( TimeSignatureSegment, out.m_Timing.m_vTimeSignatureSegments, iter )
{
f.PutLine( ssprintf( "%.6f=%d=%d", NoteRowToBeat(iter->m_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) );
vector<TimeSignatureSegment>::const_iterator iter2 = iter;
iter2++;
if( iter2 != out.m_Timing.m_vTimeSignatureSegments.end() )
f.Write( "," );
}
f.PutLine( ";" );
ASSERT( !out.m_Timing.m_TickcountSegments.empty() );
f.Write( "#TICKCOUNTS:" );
for( unsigned i=0; i<out.m_Timing.m_TickcountSegments.size(); i++ )
{
const TickcountSegment &ts = out.m_Timing.m_TickcountSegments[i];
f.PutLine( ssprintf( "%.6f=%d", NoteRowToBeat(ts.m_iStartRow), ts.m_iTicks ) );
if( i != out.m_Timing.m_TickcountSegments.size()-1 )
f.Write( "," );
}
f.PutLine( ";" );
/*
ASSERT( !out.m_Timing.m_ComboSegments.empty() );
f.Write( "#COMBOS:" );
for( unsigned i=0; i<out.m_Timing.m_ComboSegments.size(); i++ )
{
const ComboSegment &cs = out.m_Timing.m_ComboSegments[i];
f.PutLine( ssprintf( "%.6f=%d", NoteRowToBeat(cs.m_iStartRow), cs.m_iComboFactor ) );
if( i != out.m_Timing.m_ComboSegments.size()-1 )
f.Write( "," );
}
f.PutLine( ";" );
*/
FOREACH_BackgroundLayer( b )
{
if( b==0 )
f.Write( "#BGCHANGES:" );
else if( out.GetBackgroundChanges(b).empty() )
continue; // skip
else
f.Write( ssprintf("#BGCHANGES%d:", b+1) );
FOREACH_CONST( BackgroundChange, out.GetBackgroundChanges(b), bgc )
f.PutLine( BackgroundChangeToString(*bgc)+"," );
/* If there's an animation plan at all, add a dummy "-nosongbg-" tag to indicate that
* this file doesn't want a song BG entry added at the end. See SSCLoader::TidyUpData.
* This tag will be removed on load. Add it at a very high beat, so it won't cause
* problems if loaded in older versions. */
if( b==0 && !out.GetBackgroundChanges(b).empty() )
f.PutLine( "99999=-nosongbg-=1.000=0=0=0 // don't automatically add -songbackground-" );
f.PutLine( ";" );
}
if( out.GetForegroundChanges().size() )
{
f.Write( "#FGCHANGES:" );
FOREACH_CONST( BackgroundChange, out.GetForegroundChanges(), bgc )
{
f.PutLine( BackgroundChangeToString(*bgc)+"," );
}
f.PutLine( ";" );
}
f.Write( "#KEYSOUNDS:" );
for( unsigned i=0; i<out.m_vsKeysoundFile.size(); i++ )
{
f.Write( out.m_vsKeysoundFile[i] );
if( i != out.m_vsKeysoundFile.size()-1 )
f.Write( "," );
}
f.PutLine( ";" );
f.Write( "#ATTACKS:" );
for( unsigned a=0; a < out.m_sAttackString.size(); a++ )
{
RString sData = out.m_sAttackString[a];
f.Write( ssprintf( "%s", sData.c_str() ) );
if( a != (out.m_sAttackString.size() - 1) )
f.Write( ":" ); // Not the end, so write a divider ':'
}
f.PutLine( ";" );
}
static RString JoinLineList( vector<RString> &lines )
{
for( unsigned i = 0; i < lines.size(); ++i )
TrimRight( lines[i] );
/* Skip leading blanks. */
unsigned j = 0;
while( j < lines.size() && lines.size() == 0 )
++j;
return join( "\r\n", lines.begin()+j, lines.end() );
}
static RString GetSSCNotesTag( const Song &song, const Steps &in, bool bSavingCache )
{
vector<RString> lines;
lines.push_back( "" );
// Escape to prevent some clown from making a comment of "\r\n;"
lines.push_back( ssprintf("//---------------%s - %s----------------",
GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName, SmEscape(in.GetDescription()).c_str()) );
lines.push_back( "#NOTEDATA:;" ); // our new separator.
lines.push_back( ssprintf( "#STEPSTYPE:%s;", GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName ) );
lines.push_back( ssprintf( "#DESCRIPTION:%s;", SmEscape(in.GetDescription()).c_str() ) );
lines.push_back( ssprintf( "#DIFFICULTY:%s;", DifficultyToString(in.GetDifficulty()).c_str() ) );
lines.push_back( ssprintf( "#METER:%d;", in.GetMeter() ) );
vector<RString> asRadarValues;
FOREACH_PlayerNumber( pn )
{
const RadarValues &rv = in.GetRadarValues( pn );
FOREACH_ENUM( RadarCategory, rc )
asRadarValues.push_back( ssprintf("%.3f", rv[rc]) );
}
lines.push_back( ssprintf( "#RADARVALUES:%s:", join(",",asRadarValues).c_str() ) );
lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) );
// TODO: Remove this block, uncommon below block for Split Timing. -Wolfman2000
lines.push_back( "#BPMS:;" );
lines.push_back( "#STOPS:;" );
lines.push_back( "#DELAYS:;" );
lines.push_back( "#TIMESIGNATURES:;" );
lines.push_back( "#TICKCOUNTS:;" );
// lines.push_back( "#COMBOS:;" );
/*
vector<RString> asBPMValues;
for( unsigned i=0; i<in.m_Timing.m_BPMSegments.size(); i++ )
{
const BPMSegment &bs = in.m_Timing.m_BPMSegments[i];
asBPMValues.push_back( ssprintf("%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
}
lines.push_back( ssprintf( "#BPMS:%s;", join("\n,", asBPMValues).c_str() ) );
vector<RString> asStopValues;
for( unsigned i=0; i<in.m_Timing.m_StopSegments.size(); i++ )
{
const StopSegment &fs = in.m_Timing.m_StopSegments[i];
if(!fs.m_bDelay)
{
asStopValues.push_back( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
}
}
lines.push_back( ssprintf( "#STOPS:%s;", join("\n,", asStopValues).c_str() ) );
vector<RString> asDelayValues;
for( unsigned i=0; i<in.m_Timing.m_StopSegments.size(); i++ )
{
const StopSegment &fs = in.m_Timing.m_StopSegments[i];
if( fs.m_bDelay )
{
asDelayValues.push_back( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
}
}
lines.push_back( ssprintf( "#DELAYS:%s;", join("\n,", asDelayValues).c_str() ) );
ASSERT( !in.m_Timing.m_vTimeSignatureSegments.empty() );
vector<RString> asTimeSigValues;
FOREACH_CONST( TimeSignatureSegment, in.m_Timing.m_vTimeSignatureSegments, iter )
{
asTimeSigValues.push_back( ssprintf( "%.6f=%d=%d", NoteRowToBeat(iter->m_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) );
vector<TimeSignatureSegment>::const_iterator iter2 = iter;
iter2++;
}
lines.push_back( ssprintf( "#TIMESIGNATURES:%s;", join("\n,", asTimeSigValues).c_str() ) );
ASSERT( !in.m_Timing.m_TickcountSegments.empty() );
vector<RString> asTickValues;
for( unsigned i=0; i<in.m_Timing.m_TickcountSegments.size(); i++ )
{
const TickcountSegment &ts = in.m_Timing.m_TickcountSegments[i];
asTickValues.push_back( ssprintf( "%.6f=%d", NoteRowToBeat(ts.m_iStartRow), ts.m_iTicks ) );
}
lines.push_back( ssprintf( "#TICKCOUNTS:%s;", join("\n,", asTickValues).c_str() ) );
ASSERT( !in.m_Timing.m_ComboSegments.empty() );
vector<RString> asComboValues;
for( unsigned i=0; i<in.m_Timing.m_ComboSegments.size(); i++ )
{
const ComboSegment &cs = in.m_Timing.m_ComboSegments[i];
asComboValues.push_back( ssprintf( "%.6f=%d", NoteRowToBeat(cs.m_iStartRow), cs.m_iComboFactor ) );
}
lines.push_back( ssprintf( "#COMBOS:%s;", join("\n,", asComboValues).c_str() ) );
lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) );
*/
RString sNoteData;
in.GetSMNoteData( sNoteData );
lines.push_back( song.m_vsKeysoundFile.empty() ? "#NOTES:" : "#NOTES2:" );
split( sNoteData, "\n", lines, true );
lines.push_back( ";" );
return JoinLineList( lines );
}
bool NotesWriterSSC::Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave, bool bSavingCache )
{
int flags = RageFile::WRITE;
/* If we're not saving cache, we're saving real data, so enable SLOW_FLUSH
* to prevent data loss. If we're saving cache, this will slow things down
* too much. */
if( !bSavingCache )
flags |= RageFile::SLOW_FLUSH;
RageFile f;
if( !f.Open( sPath, flags ) )
{
LOG->UserLog( "Song file", sPath, "couldn't be opened for writing: %s", f.GetError().c_str() );
return false;
}
WriteGlobalTags( f, out );
if( bSavingCache )
{
f.PutLine( ssprintf( "// cache tags:" ) );
f.PutLine( ssprintf( "#FIRSTBEAT:%.3f;", out.m_fFirstBeat ) );
f.PutLine( ssprintf( "#LASTBEAT:%.3f;", out.m_fLastBeat ) );
f.PutLine( ssprintf( "#SONGFILENAME:%s;", out.m_sSongFileName.c_str() ) );
f.PutLine( ssprintf( "#HASMUSIC:%i;", out.m_bHasMusic ) );
f.PutLine( ssprintf( "#HASBANNER:%i;", out.m_bHasBanner ) );
f.PutLine( ssprintf( "#MUSICLENGTH:%.3f;", out.m_fMusicLengthSeconds ) );
f.PutLine( ssprintf( "// end cache tags" ) );
}
// Save specified Steps to this file
FOREACH_CONST( Steps*, vpStepsToSave, s )
{
const Steps* pSteps = *s;
RString sTag = GetSSCNotesTag( out, *pSteps, bSavingCache );
f.PutLine( sTag );
}
if( f.Flush() == -1 )
return false;
return true;
}
void NotesWriterSSC::GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut )
{
sOut = "";
RString sDir = pSong->GetSongDir();
// "Songs/foo/bar"; strip off "Songs/".
vector<RString> asParts;
split( sDir, "/", asParts );
if( asParts.size() )
sDir = join( "/", asParts.begin()+1, asParts.end() );
sOut += ssprintf( "#SONG:%s;\r\n", sDir.c_str() );
sOut += GetSSCNotesTag( *pSong, *pSteps, false );
}
RString NotesWriterSSC::GetEditFileName( const Song *pSong, const Steps *pSteps )
{
/* Try to make a unique name. This isn't guaranteed. Edit descriptions are
* case-sensitive, filenames on disk are usually not, and we decimate certain
* characters for FAT filesystems. */
RString sFile = pSong->GetTranslitFullTitle() + " - " + pSteps->GetDescription();
// HACK:
if( pSteps->m_StepsType == StepsType_dance_double )
sFile += " (doubles)";
sFile += ".edit";
MakeValidFilename( sFile );
return sFile;
}
static LocalizedString DESTINATION_ALREADY_EXISTS ("NotesWriterSSC", "Error renaming file. Destination file '%s' already exists.");
static LocalizedString ERROR_WRITING_FILE ("NotesWriterSSC", "Error writing file '%s'.");
bool NotesWriterSSC::WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut )
{
RString sDir = PROFILEMAN->GetProfileDir( ProfileSlot_Machine ) + EDIT_STEPS_SUBDIR;
RString sPath = sDir + GetEditFileName(pSong,pSteps);
// Check to make sure that we're not clobering an existing file before opening.
bool bFileNameChanging =
pSteps->GetSavedToDisk() &&
pSteps->GetFilename() != sPath;
if( bFileNameChanging && DoesFileExist(sPath) )
{
sErrorOut = ssprintf( DESTINATION_ALREADY_EXISTS.GetValue(), sPath.c_str() );
return false;
}
RageFile f;
if( !f.Open(sPath, RageFile::WRITE | RageFile::SLOW_FLUSH) )
{
sErrorOut = ssprintf( ERROR_WRITING_FILE.GetValue(), sPath.c_str() );
return false;
}
RString sTag;
GetEditFileContents( pSong, pSteps, sTag );
if( f.PutLine(sTag) == -1 || f.Flush() == -1 )
{
sErrorOut = ssprintf( ERROR_WRITING_FILE.GetValue(), sPath.c_str() );
return false;
}
/* If the file name of the edit has changed since the last save, then delete the old
* file after saving the new one. If we delete it first, then we'll lose data on error. */
if( bFileNameChanging )
FILEMAN->Remove( pSteps->GetFilename() );
pSteps->SetFilename( sPath );
return true;
}
/*
* (c) 2011 Jason Felds
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+41
View File
@@ -0,0 +1,41 @@
/* NotesWriterSSC - Writes a Song to an .SSC file. */
#ifndef NOTES_WRITER_SSC_H
#define NOTES_WRITER_SSC_H
class Song;
class Steps;
namespace NotesWriterSSC
{
bool Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave, bool bSavingCache );
void GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut );
RString GetEditFileName( const Song *pSong, const Steps *pSteps );
bool WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut );
}
#endif
/*
* (c) 2011 Jason Felds
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+2 -2
View File
@@ -838,8 +838,8 @@ RageFileBasic *RageFileManager::OpenForWriting( const RString &sPath, int mode,
*
* The purpose of this is to create files in the expected place. For example, if we
* have both C:/games/StepMania and C:/games/DWI loaded, and we're writing
* "Songs/Music/Waltz/waltz.sm", and the song was loaded out of
* "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SM into the
* "Songs/Music/Waltz/waltz.ssc", and the song was loaded out of
* "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SSC into the
* same directory (if possible). Don't split up files in the same directory any
* more than we have to.
*
+21
View File
@@ -542,6 +542,7 @@ static MenuDef g_StepsInformation(
// xxx: this giant list of numbers SUUUUUUUUUUCKS -aj
MenuRowDef( ScreenEdit::meter, "Meter", true, EditMode_Practice, true, false, 0, "1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25" ),
MenuRowDef( ScreenEdit::description, "Description", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::step_credit, "Step Author", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::predict_meter, "Predicted Meter", false, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::tap_notes, "Tap Steps", false, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::jumps, "Jumps", false, EditMode_Full, true, true, 0, NULL ),
@@ -2862,6 +2863,12 @@ static void ChangeDescription( const RString &sNew )
pSteps->SetDescription(sNew);
}
static void ChangeStepCredit( const RString &sNew )
{
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
pSteps->SetCredit(sNew);
}
static void ChangeMainTitle( const RString &sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
@@ -3003,6 +3010,8 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
g_StepsInformation.rows[predict_meter].SetOneUnthemedChoice( ssprintf("%.2f",pSteps->PredictMeter()) );
g_StepsInformation.rows[description].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full);
g_StepsInformation.rows[description].SetOneUnthemedChoice( pSteps->GetDescription() );
g_StepsInformation.rows[step_credit].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full);
g_StepsInformation.rows[step_credit].SetOneUnthemedChoice( pSteps->GetCredit() );
g_StepsInformation.rows[tap_notes].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumTapNotes()) );
g_StepsInformation.rows[jumps].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumJumps()) );
g_StepsInformation.rows[hands].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumHands()) );
@@ -3466,6 +3475,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
}
static LocalizedString ENTER_NEW_DESCRIPTION( "ScreenEdit", "Enter a new description." );
static LocalizedString ENTER_NEW_STEP_AUTHOR( "ScreenEdit", "Enter the author who made this step pattern." );
void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const vector<int> &iAnswers )
{
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
@@ -3488,6 +3498,17 @@ void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const v
NULL
);
break;
case step_credit:
ScreenTextEntry::TextEntry(
SM_None,
ENTER_NEW_STEP_AUTHOR,
m_pSteps->GetCredit(),
255,
SongUtil::ValidateCurrentStepsCredit,
ChangeStepCredit,
NULL
);
break;
}
}
+1
View File
@@ -407,6 +407,7 @@ public:
difficulty,
meter,
description,
step_credit,
predict_meter,
tap_notes,
jumps,
+3 -3
View File
@@ -1,6 +1,6 @@
#include "global.h"
#include "ScreenGameplaySyncMachine.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "GameState.h"
#include "GameManager.h"
#include "PrefsManager.h"
@@ -18,8 +18,8 @@ void ScreenGameplaySyncMachine::Init()
GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) );
AdjustSync::ResetOriginalSyncData();
RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music.sm");
SMLoader::LoadFromSMFile( sFile, m_Song );
RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music");
SSCLoader::LoadFromSSCFile( sFile, m_Song );
m_Song.SetSongDir( Dirname(sFile) );
m_Song.TidyUpData();
+2 -2
View File
@@ -4,7 +4,7 @@
#include "GameState.h"
#include "Steps.h"
#include "GameManager.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "GameSoundManager.h"
#include "Model.h"
#include "ThemeMetric.h"
@@ -132,7 +132,7 @@ void ScreenHowToPlay::Init()
ActorUtil::LoadAllCommandsAndSetXY( m_pLifeMeterBar, m_sName );
m_pLifeMeterBar->FillForHowToPlay( NUM_W2S, NUM_MISSES );
SMLoader::LoadFromSMFile( THEME->GetPathO(m_sName, "steps"), m_Song, false );
SSCLoader::LoadFromSSCFile( THEME->GetPathO(m_sName, "steps"), m_Song, false );
m_Song.AddAutoGenNotes();
const Style* pStyle = GAMESTATE->GetCurrentStyle();
+2 -2
View File
@@ -15,7 +15,7 @@
#include "PlayerState.h"
#include "LocalizedString.h"
#include "StepMania.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
static LocalizedString BOOKKEEPING_DATA_CLEARED( "ScreenServiceAction", "Bookkeeping data cleared." );
static RString ClearBookkeepingData()
@@ -197,7 +197,7 @@ static void CopyEdits( const RString &sFromProfileDir, const RString &sToProfile
iNumErrored++;
// Test whether the song we need for this edit is present and ignore this edit if not present.
if( !SMLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
if( !SSCLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
{
iNumIgnored++;
continue;
+48 -22
View File
@@ -25,8 +25,10 @@
#include "SpecialFiles.h"
#include "NotesLoader.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "NotesWriterDWI.h"
#include "NotesWriterSM.h"
#include "NotesWriterSSC.h"
#include "UnlockManager.h"
#include "LyricsLoader.h"
@@ -34,7 +36,7 @@
#include <set>
#include <float.h>
const int FILE_CACHE_VERSION = 162; // increment this to invalidate cache
const int FILE_CACHE_VERSION = 163; // increment this to invalidate cache
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
@@ -50,6 +52,8 @@ static const char *InstrumentTrackNames[] = {
XToString( InstrumentTrack );
StringToX( InstrumentTrack );
const static float VERSION_NUMBER = 0.5f;
Song::Song()
{
FOREACH_BackgroundLayer( i )
@@ -57,6 +61,7 @@ Song::Song()
m_ForegroundChanges = AutoPtrCopyOnWrite<VBackgroundChange>(new VBackgroundChange);
m_LoadedFromProfile = ProfileSlot_Invalid;
m_fVersion = VERSION_NUMBER;
m_fMusicSampleStartSeconds = -1;
m_fMusicSampleLengthSeconds = DEFAULT_MUSIC_SAMPLE_LENGTH;
m_fMusicLengthSeconds = 0;
@@ -214,8 +219,8 @@ bool Song::LoadFromSongDir( RString sDir )
if( bUseCache )
{
// LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() );
SMLoader::LoadFromSMFile( sCacheFilePath, *this, true );
SMLoader::TidyUpData( *this, true );
SSCLoader::LoadFromSSCFile( sCacheFilePath, *this, true );
SSCLoader::TidyUpData( *this, true );
}
else
{
@@ -707,7 +712,7 @@ void Song::TidyUpData()
{
/* Generated filename; this doesn't always point to a loadable file,
* but instead points to the file we should write changed files to,
* and will always be an .SM.
* and will always be a .SSC.
*
* This is a little tricky. We can't always use the song title directly,
* since it might contain characters we can't store in filenames. Two
@@ -721,23 +726,32 @@ void Song::TidyUpData()
* but not KSFs and BMSs.
*
* So, let's do this (by priority):
* 1. If there's an .SM file, use that filename. No reason to use anything
* 1. If there's a .SSC file, use that filename. No reason to use anything
* else; it's the filename in use.
* 2. If there's a .DWI, use it with a changed extension.
* 3. Otherwise, use the name of the directory, since it's definitely a valid
* 2. If there's an .SM, use it with a changed extension.
* 3. If there's a .DWI, use it with a changed extension.
* 4. Otherwise, use the name of the directory, since it's definitely a valid
* filename, and should always be the title of the song (unlike KSFs). */
m_sSongFileName = m_sSongDir;
vector<RString> asFileNames;
GetDirListing( m_sSongDir+"*.sm", asFileNames );
GetDirListing( m_sSongDir+"*.ssc", asFileNames );
if( !asFileNames.empty() )
{
m_sSongFileName += asFileNames[0];
else {
GetDirListing( m_sSongDir+"*.dwi", asFileNames );
if( !asFileNames.empty() ) {
m_sSongFileName += SetExtension( asFileNames[0], "sm" );
} else {
m_sSongFileName += Basename(m_sSongDir);
m_sSongFileName += ".sm";
}
else
{
GetDirListing( m_sSongDir+"*.sm", asFileNames );
if( !asFileNames.empty() )
m_sSongFileName += SetExtension( asFileNames[0], "ssc" );
else {
GetDirListing( m_sSongDir+"*.dwi", asFileNames );
if( !asFileNames.empty() ) {
m_sSongFileName += SetExtension( asFileNames[0], "ssc" );
} else {
m_sSongFileName += Basename(m_sSongDir);
m_sSongFileName += ".ssc";
}
}
}
}
@@ -844,9 +858,10 @@ void Song::Save()
TranslateTitles();
// Save the new files. These calls make backups on their own.
if( !SaveToSMFile(GetSongFilePath(), false) )
if( !SaveToSSCFile(GetSongFilePath(), false) )
return;
SaveToDWIFile();
SaveToSMFile();
//SaveToDWIFile();
SaveToCacheFile();
/* We've safely written our files and created backups. Rename non-SM and
@@ -871,10 +886,21 @@ void Song::Save()
}
}
bool Song::SaveToSMFile( RString sPath, bool bSavingCache )
bool Song::SaveToSMFile()
{
LOG->Trace( "Song::SaveToSMFile('%s')", sPath.c_str() );
const RString sPath = SetExtension( GetSongFilePath(), "sm" );
LOG->Trace( "Song::SaveToSMFile(%s)", sPath.c_str() );
// If the file exists, make a backup.
if( IsAFile(sPath) )
FileCopy( sPath, sPath + ".old" );
return NotesWriterSM::Write( sPath, *this );
}
bool Song::SaveToSSCFile( RString sPath, bool bSavingCache )
{
LOG->Trace( "Song::SaveToSSCFile('%s')", sPath.c_str() );
// If the file exists, make a backup.
if( !bSavingCache && IsAFile(sPath) )
@@ -894,7 +920,7 @@ bool Song::SaveToSMFile( RString sPath, bool bSavingCache )
vpStepsToSave.push_back( pSteps );
}
if( !NotesWriterSM::Write(sPath, *this, vpStepsToSave, bSavingCache) )
if( !NotesWriterSSC::Write(sPath, *this, vpStepsToSave, bSavingCache) )
return false;
if( !bSavingCache && g_BackUpAllSongSaves.Get() )
@@ -932,7 +958,7 @@ bool Song::SaveToCacheFile()
{
SONGINDEX->AddCacheIndex(m_sSongDir, GetHashForDirectory(m_sSongDir));
const RString sPath = GetCacheFilePath();
if( !SaveToSMFile(sPath, true) )
if( !SaveToSSCFile(sPath, true) )
return false;
FOREACH( Steps*, m_vpSteps, pSteps )
+11 -6
View File
@@ -61,7 +61,7 @@ public:
enum SelectionDisplay
{
SHOW_ALWAYS, // always
SHOW_NEVER // never (unless song hiding is turned off)
SHOW_NEVER // never (unless song hiding is turned off)
} m_SelectionDisplay;
Song();
@@ -78,9 +78,10 @@ public:
void ReCalculateRadarValuesAndLastBeat(); // called by TidyUpData, and after saving
void TranslateTitles(); // called by TidyUpData
bool SaveToSMFile( RString sPath, bool bSavingCache );
void Save(); // saves SM and DWI
bool SaveToSSCFile( RString sPath, bool bSavingCache );
void Save(); // saves SSC and SM guaranteed.
bool SaveToCacheFile();
bool SaveToSMFile();
bool SaveToDWIFile();
const RString &GetSongFilePath() const;
@@ -93,9 +94,10 @@ public:
// Directory this song data came from:
const RString &GetSongDir() const { return m_sSongDir; }
/* Filename associated with this file. This will always have an .SM extension.
* If we loaded an .SM, this will point to it, but if we loaded any other
* type, this will point to a generated .SM filename. */
/* Filename associated with this file. This will always have a
* .SSC extension. If we loaded a .SSC, this will point to it,
* but if we loaded any other type, this will point to a
* generated .SSC filename. */
RString m_sSongFileName;
RString m_sGroupName;
@@ -121,6 +123,9 @@ public:
// "title subtitle"
RString GetDisplayFullTitle() const;
RString GetTranslitFullTitle() const;
// allow versioning with the song.
float m_fVersion;
RString m_sGenre;
+2 -2
View File
@@ -15,7 +15,7 @@
#include "MsdFile.h"
#include "NoteSkinManager.h"
#include "NotesLoaderDWI.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include "PrefsManager.h"
#include "Profile.h"
#include "ProfileManager.h"
@@ -1653,7 +1653,7 @@ void SongManager::LoadStepEditsFromProfileDir( const RString &sProfileDir, Profi
{
RString fn = vsFiles[i];
SMLoader::LoadEditFromFile( fn, slot, true );
SSCLoader::LoadEditFromFile( fn, slot, true );
}
}
}
+46 -7
View File
@@ -97,7 +97,8 @@ void SongUtil::GetSteps(
Difficulty dc,
int iMeterLow,
int iMeterHigh,
const RString &sDescription,
const RString &sDescription,
const RString &sCredit,
bool bIncludeAutoGen,
unsigned uHash,
int iMaxToGet
@@ -119,6 +120,8 @@ void SongUtil::GetSteps(
continue;
if( sDescription.size() && sDescription != pSteps->GetDescription() )
continue;
if( sCredit.size() && sCredit != pSteps->GetCredit() )
continue;
if( uHash != 0 && uHash != pSteps->GetHash() )
continue;
if( !bIncludeAutoGen && pSteps->IsAutogen() )
@@ -141,13 +144,14 @@ Steps* SongUtil::GetOneSteps(
Difficulty dc,
int iMeterLow,
int iMeterHigh,
const RString &sDescription,
const RString &sDescription,
const RString &sCredit,
unsigned uHash,
bool bIncludeAutoGen
)
{
vector<Steps*> vpSteps;
GetSteps( pSong, vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, bIncludeAutoGen, uHash, 1 ); // get max 1
GetSteps( pSong, vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, sCredit, bIncludeAutoGen, uHash, 1 ); // get max 1
if( vpSteps.empty() )
return NULL;
else
@@ -193,13 +197,23 @@ Steps* SongUtil::GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow
Steps* SongUtil::GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription )
{
vector<Steps*> vNotes;
GetSteps( pSong, vNotes, st, Difficulty_Invalid, -1, -1, sDescription );
GetSteps( pSong, vNotes, st, Difficulty_Invalid, -1, -1, sDescription, "" );
if( vNotes.size() == 0 )
return NULL;
else
return vNotes[0];
}
Steps* SongUtil::GetStepsByCredit( const Song *pSong, StepsType st, RString sCredit )
{
vector<Steps*> vNotes;
GetSteps(pSong, vNotes, st, Difficulty_Invalid, -1, -1, "", sCredit );
if( vNotes.size() == 0 )
return NULL;
else
return vNotes[0];
}
Steps* SongUtil::GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked )
{
@@ -279,7 +293,7 @@ static RString RemoveInitialWhitespace( RString s )
void SongUtil::DeleteDuplicateSteps( Song *pSong, vector<Steps*> &vSteps )
{
/* vSteps have the same StepsType and Difficulty. Delete them if they have the
* same m_sDescription, m_iMeter and SMNoteData. */
* same m_sDescription, m_sCredit, m_iMeter and SMNoteData. */
CHECKPOINT;
for( unsigned i=0; i<vSteps.size(); i++ )
{
@@ -293,6 +307,8 @@ void SongUtil::DeleteDuplicateSteps( Song *pSong, vector<Steps*> &vSteps )
if( s1->GetDescription() != s2->GetDescription() )
continue;
if( s1->GetCredit() != s2->GetCredit() )
continue;
if( s1->GetMeter() != s2->GetMeter() )
continue;
/* Compare, ignoring whitespace. */
@@ -303,8 +319,8 @@ void SongUtil::DeleteDuplicateSteps( Song *pSong, vector<Steps*> &vSteps )
if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) )
continue;
LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\" and meter \"%i\"",
s2, pSong->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetMeter() );
LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\", step author \"%s\", and meter \"%i\"",
s2, pSong->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetCredit().c_str(), s1->GetMeter() );
pSong->DeleteSteps( s2, false );
@@ -803,6 +819,29 @@ bool SongUtil::ValidateCurrentStepsDescription( const RString &sAnswer, RString
return true;
}
static LocalizedString AUTHOR_NAME_CANNOT_CONTAIN( "SongUtil", "The step author's name cannot contain any of the following characters: %s" );
bool SongUtil::ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut )
{
if( sAnswer.empty() )
return true;
Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
// If unchanged:
if( pSteps->GetCredit() == sAnswer )
return true;
// Borrow from EditDescription testing. Perhaps this should be abstracted? -Wolfman2000
static const RString sInvalidChars = "\\/:*?\"<>|";
if( strpbrk(sAnswer, sInvalidChars) != NULL )
{
sErrorOut = ssprintf( AUTHOR_NAME_CANNOT_CONTAIN.GetValue(), sInvalidChars.c_str() );
return false;
}
return true;
}
void SongUtil::GetAllSongGenres( vector<RString> &vsOut )
{
set<RString> genres;
+7 -3
View File
@@ -70,7 +70,8 @@ namespace SongUtil
Difficulty dc = Difficulty_Invalid,
int iMeterLow = -1,
int iMeterHigh = -1,
const RString &sDescription = "",
const RString &sDescription = "",
const RString &sCredit = "",
bool bIncludeAutoGen = true,
unsigned uHash = 0,
int iMaxToGet = -1
@@ -81,15 +82,17 @@ namespace SongUtil
Difficulty dc = Difficulty_Invalid,
int iMeterLow = -1,
int iMeterHigh = -1,
const RString &sDescription = "",
const RString &sDescription = "",
const RString &sCredit = "",
unsigned uHash = 0,
bool bIncludeAutoGen = true
);
Steps* GetStepsByDifficulty( const Song *pSong, StepsType st, Difficulty dc, bool bIncludeAutoGen = true );
Steps* GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow, int iMeterHigh );
Steps* GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription );
Steps* GetStepsByCredit( const Song *pSong, StepsType st, RString sCredit );
Steps* GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked=false );
void AdjustDuplicateSteps( Song *pSong ); // part of TidyUpData
void DeleteDuplicateSteps( Song *pSong, vector<Steps*> &vSteps );
@@ -115,6 +118,7 @@ namespace SongUtil
RString MakeUniqueEditDescription( const Song* pSong, StepsType st, const RString &sPreferredDescription );
bool ValidateCurrentEditStepsDescription( const RString &sAnswer, RString &sErrorOut );
bool ValidateCurrentStepsDescription( const RString &sAnswer, RString &sErrorOut );
bool ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut );
void GetAllSongGenres( vector<RString> &vsOut );
void FilterSongs( const SongCriteria &sc, const vector<Song*> &in, vector<Song*> &out );
+12
View File
@@ -986,6 +986,12 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<File
RelativePath="NotesLoaderSM.h">
</File>
<File
RelativePath="NotesLoaderSSC.cpp">
</File>
<File
RelativePath="NotesLoaderSSC.h">
</File>
<File
RelativePath="NotesWriterDWI.cpp">
</File>
@@ -998,6 +1004,12 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<File
RelativePath="NotesWriterSM.h">
</File>
<File
RelativePath="NotesWriterSSC.cpp">
</File>
<File
RelativePath="NotesWriterSSC.h">
</File>
<File
RelativePath="NoteTypes.cpp">
</File>
+18
View File
@@ -1314,6 +1314,15 @@
RelativePath="NotesLoaderSM.h"
>
</File>
<File
RelativePath="NotesLoaderSSC.cpp"
>
</File>
<File
RelativePath="NotesLoaderSSC.h"
>
</File>
<File
RelativePath="NotesWriterDWI.cpp"
>
@@ -1330,6 +1339,15 @@
RelativePath="NotesWriterSM.h"
>
</File>
<File
RelativePath="NotesWriterSSC.cpp"
>
</File>
<File
RelativePath="NotesWriterSSC.h"
>
</File>
<File
RelativePath="NoteTypes.cpp"
>
+18
View File
@@ -1456,6 +1456,15 @@
RelativePath="NotesLoaderSM.h"
>
</File>
<File
RelativePath="NotesLoaderSSC.cpp"
>
</File>
<File
RelativePath="NotesLoaderSSC.h"
>
</File>
<File
RelativePath="NotesWriterDWI.cpp"
>
@@ -1472,6 +1481,15 @@
RelativePath="NotesWriterSM.h"
>
</File>
<File
RelativePath="NotesWriterSSC.cpp"
>
</File>
<File
RelativePath="NotesWriterSSC.h"
>
</File>
<File
RelativePath="NoteTypes.cpp"
>
+11 -3
View File
@@ -20,7 +20,7 @@
#include "NoteData.h"
#include "GameManager.h"
#include "NoteDataUtil.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderSSC.h"
#include <algorithm>
@@ -231,7 +231,7 @@ void Steps::Decompress() const
{
/* We have data on disk and not in memory. Load it. */
Song s;
if( !SMLoader::LoadFromSMFile(m_sFilename, s, true) )
if( !SSCLoader::LoadFromSSCFile(m_sFilename, s, true) )
{
LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() );
return;
@@ -322,7 +322,7 @@ void Steps::DeAutogen( bool bCopyNoteData )
m_Difficulty = Real()->m_Difficulty;
m_iMeter = Real()->m_iMeter;
copy( Real()->m_CachedRadarValues, Real()->m_CachedRadarValues + NUM_PLAYERS, m_CachedRadarValues );
m_sCredit = Real()->m_sCredit;
parent = NULL;
if( bCopyNoteData )
@@ -366,6 +366,12 @@ void Steps::SetDifficultyAndDescription( Difficulty dc, RString sDescription )
MakeValidEditDescription( m_sDescription );
}
void Steps::SetCredit( RString sCredit )
{
DeAutogen();
m_sCredit = sCredit;
}
bool Steps::MakeValidEditDescription( RString &sPreferredDescription )
{
if( int(sPreferredDescription.size()) > MAX_EDIT_STEPS_DESCRIPTION_LENGTH )
@@ -398,6 +404,7 @@ public:
DEFINE_METHOD( GetStepsType, m_StepsType )
DEFINE_METHOD( GetDifficulty, GetDifficulty() )
DEFINE_METHOD( GetDescription, GetDescription() )
DEFINE_METHOD( GetAuthorCredit, GetCredit() )
DEFINE_METHOD( GetMeter, GetMeter() )
DEFINE_METHOD( GetFilename, GetFilename() )
DEFINE_METHOD( IsAutogen, IsAutogen() )
@@ -428,6 +435,7 @@ public:
ADD_METHOD( GetStepsType );
ADD_METHOD( GetDifficulty );
ADD_METHOD( GetDescription );
ADD_METHOD( GetAuthorCredit );
ADD_METHOD( GetMeter );
ADD_METHOD( GetFilename );
ADD_METHOD( GetRadarValues );
+4 -1
View File
@@ -40,6 +40,7 @@ public:
Difficulty GetDifficulty() const { return Real()->m_Difficulty; }
int GetMeter() const { return Real()->m_iMeter; }
const RadarValues& GetRadarValues( PlayerNumber pn ) const { return Real()->m_CachedRadarValues[pn]; }
RString GetCredit() const { return Real()->m_sCredit; }
void SetFilename( RString fn ) { m_sFilename = fn; }
RString GetFilename() const { return m_sFilename; }
@@ -48,6 +49,7 @@ public:
void SetDifficulty( Difficulty dc ) { SetDifficultyAndDescription( dc, GetDescription() ); }
void SetDescription( RString sDescription ) { SetDifficultyAndDescription( this->GetDifficulty(), sDescription ); }
void SetDifficultyAndDescription( Difficulty dc, RString sDescription );
void SetCredit( RString sCredit );
static bool MakeValidEditDescription( RString &sPreferredDescription ); // return true if was modified
void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; }
@@ -92,10 +94,11 @@ private:
/* These values are pulled from the autogen source first, if there is one. */
mutable unsigned m_iHash; // only used if m_Difficulty == Difficulty_Edit
RString m_sDescription; // Step author, edit name, or something meaningful
RString m_sDescription; // Edit name, or something meaningful
Difficulty m_Difficulty; // difficulty classification
int m_iMeter; // difficulty rating from MIN_METER to MAX_METER
RadarValues m_CachedRadarValues[NUM_PLAYERS];
RString m_sCredit; // Step author
};
#endif
+2 -2
View File
@@ -258,11 +258,11 @@ Steps *StepsID::ToSteps( const Song *p, bool bAllowNull ) const
Steps *pRet = NULL;
if( dc == Difficulty_Edit )
{
pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, uHash, true );
pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, "", uHash, true );
}
else
{
pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", 0, true );
pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", "", 0, true );
}
if( !bAllowNull && pRet == NULL )