[default -> loading window] YAM

This commit is contained in:
Henrik Andersson
2011-06-11 12:22:06 +02:00
48 changed files with 1094 additions and 1016 deletions
+20
View File
@@ -8,6 +8,26 @@ ________________________________________________________________________________
StepMania 5.0 Preview 2 | 20110???
--------------------------------------------------------------------------------
2011/06/10
----------
* [ScreenEdit] Split the Area Menu into the Area Menu and Alter Menu. Use the
"A" key to enter the Alter Menu when a selection of notes/rows are
highlighted. Use the Enter key to enter the old Area Menu for the options that
do not depend on selecting NoteData. [Wolfman2000]
* [ScreenEdit] Allow converting selections to Delays, Warps, or Fakes as well
as Stops. Remember, use the Alter Menu for this. [Wolfman2000]
2011/06/09
----------
* [ScreenSyncOverlay] Ensure that F11 / F12 work with all charts due to Split
Timing. [Wolfman2000]
2011/06/08
----------
* Any notes in a fake segment or warp segment are completely ignored for
scoring purposes. Now you can get 100% on your warping goodness!
[Wolfman2000]
2011/06/06
----------
* [PlayerOptions] Removed the ScoreDisplay mod choices. Use lua to make your
+57 -5
View File
@@ -39,11 +39,8 @@
<Function name='FormatNumberAndSuffix'/>
<Function name='FormatPercentScore'/>
<Function name='GameCompatibleModes'/>
<Function name='GamePrefAutoSetStyle'/>
<Function name='GamePrefComboOnRolls'/>
<Function name='GamePrefComboUnderField'/>
<Function name='GamePrefDefaultFail'/>
<Function name='GamePrefNotePosition'/>
<Function name='GetCoursesToShowRanking'/>
<Function name='GetCustomDifficulty'/>
<Function name='GetDefaultOptionLines'/>
@@ -57,6 +54,7 @@
<Function name='GetGradeFromPercent'/>
<Function name='GetLifeDifficulty'/>
<Function name='GetOSName'/>
<Function name='GetPlayerOrMachineProfile'/>
<Function name='GetProTiming'/>
<Function name='GetRandomSongBackground'/>
<Function name='GetReal'/>
@@ -130,7 +128,6 @@
<Function name='PrintTable'/>
<Function name='ProductID'/>
<Function name='ProductVersion'/>
<Function name='Profile'/>
<Function name='RadarCategoryToLocalizedString'/>
<Function name='ReadGamePrefFromFile'/>
<Function name='ReadPrefFromFile'/>
@@ -143,6 +140,8 @@
<Function name='Saturation'/>
<Function name='ScoreKeeperClass'/>
<Function name='ScoreMissedHoldsAndRolls'/>
<Function name='ScreenMetric'/>
<Function name='ScreenString'/>
<Function name='Second'/>
<Function name='SecondsToHHMMSS'/>
<Function name='SecondsToMMSS'/>
@@ -1026,6 +1025,52 @@
<Function name='SetPreference'/>
<Function name='SetPreferenceToDefault'/>
</Class>
<Class name='Profile'>
<Function name='GetCaloriesBurnedToday'/>
<Function name='GetCharacter'/>
<Function name='GetCoursesActual'/>
<Function name='GetCoursesPercentComplete'/>
<Function name='GetCoursesPossible'/>
<Function name='GetDisplayName'/>
<Function name='GetDisplayTotalCaloriesBurned'/>
<Function name='GetGoalCalories'/>
<Function name='GetGoalSeconds'/>
<Function name='GetGoalType'/>
<Function name='GetHighScoreList'/>
<Function name='GetLastUsedHighScoreName'/>
<Function name='GetMostPopularCourse'/>
<Function name='GetMostPopularSong'/>
<Function name='GetNumToasties'/>
<Function name='GetNumTotalSongsPlayed'/>
<Function name='GetSongNumTimesPlayed'/>
<Function name='GetSongsActual'/>
<Function name='GetSongsAndCoursesPercentCompleteAllDifficulties'/>
<Function name='GetSongsPercentComplete'/>
<Function name='GetSongsPossible'/>
<Function name='GetTotalCaloriesBurned'/>
<Function name='GetTotalGameplaySeconds'/>
<Function name='GetTotalHands'/>
<Function name='GetTotalHolds'/>
<Function name='GetTotalJumps'/>
<Function name='GetTotalLifts'/>
<Function name='GetTotalMines'/>
<Function name='GetTotalNumSongsPlayed'/>
<Function name='GetTotalRolls'/>
<Function name='GetTotalSessionSeconds'/>
<Function name='GetTotalSessions'/>
<Function name='GetTotalStepsWithTopGrade'/>
<Function name='GetTotalTapsAndHolds'/>
<Function name='GetTotalTrailsWithTopGrade'/>
<Function name='GetUserData'/>
<Function name='GetWeightPounds'/>
<Function name='HasPassedAnyStepsInSong'/>
<Function name='IsCodeUnlocked'/>
<Function name='SetCharacter'/>
<Function name='SetGoalCalories'/>
<Function name='SetGoalSeconds'/>
<Function name='SetGoalType'/>
<Function name='SetWeightPounds'/>
</Class>
<Class name='ProfileManager'>
<Function name='GetLocalProfile'/>
<Function name='GetLocalProfileFromIndex'/>
@@ -1093,6 +1138,13 @@
</Class>
<Class base='BitmapText' name='ScoreDisplayAliveTime'/>
<Class base='BitmapText' name='ScoreDisplayCalories'/>
<Class base='ActorFrame' name='Screen'>
<Function name='GetNextScreenName'/>
<Function name='GetPrevScreenName'/>
<Function name='GetScreenType'/>
<Function name='PostScreenMessage'/>
<Function name='lockinput'/>
</Class>
<Class base='ScreenWithMenuElements' name='ScreenAttract'/>
<Class base='ScreenWithMenuElements' name='ScreenEdit'>
<Function name='GetEditState'/>
@@ -2061,5 +2113,5 @@
<Constant name='top' value='&apos;VertAlign_Top&apos;'/>
</Constants>
<Version>StepMania 5 v5.0 Preview 1a</Version>
<Date>2011-06-04</Date>
<Date>2011-06-11</Date>
</Lua>
+6 -1
View File
@@ -395,7 +395,12 @@
$type='bool' or
$type='table' or
$type='color' or
$type='Enum'">
$type='Enum' or
$type='ThreadVariable' or
$type='LuaOptionRow' or
$type='ActorDef' or
$type='chunk' or
$type='various'">
<span class="primitiveType">
<xsl:value-of select="$type" />
</span>
+6 -1
View File
@@ -807,12 +807,16 @@ Clear Machine Edits=Clear Machine Edits
Clear Machine Stats=Clear Machine Scores
Clear USB edits=Clear USB edits
Clear area=Clear area
Clear clipboard=Clear clipboard
CoinMode=Coin Mode
CoinModeNoHome=Coin Mode
CoinsPerCredit=Coins&nbsp;Per Credit
Connection=Connection
Convert pause to beats=Convert pause to beats
Convert selection to pause=Convert selection to pause
Convert selection to delay=Convert selection to delay
Convert selection to warp=Convert selection to Warp Segment
Convert selection to fake=Convert selection to Fake Segment
Copy=Copy
CourseSortOrder=Course Sort
Create New=Create New
@@ -1257,7 +1261,7 @@ Enter a new min BPM.=Enter the minimum displayed BPM.
Enter a new max BPM.=Enter the maximum displayed BPM.
More than %d notes per measure is not allowed. This change has been reverted.=More than %d notes per measure is not allowed. This change has been reverted.
No backgrounds available=No backgrounds available
EditHelpText=Up/Down:\n change beat\nLeft/Right:\n change snap\nNumber keys:\n add/remove\n tap note\nN and M keys:\n swap tap notes\nCreate hold note:\n Hold a number\n while moving\n Up or Down\nCreate roll note:\n Hold Shift,\n then create a\n hold note.\nSpace bar:\n Set area\n marker\nEnter:\n Area Menu\nEscape:\n Main Menu\nF4:\n Timing Menu\nF1:\n Show help\n
EditHelpText=Up/Down:\n change beat\nLeft/Right:\n change snap\nNumber keys:\n add/remove\n tap note\nN and M keys:\n swap tap notes\nCreate hold note:\n Hold a number\n while moving\n Up or Down\nCreate roll note:\n Hold Shift,\n then create a\n hold note.\nSpace bar:\n Set area\n marker\nT key:\n Switch Timing\nEnter:\n Area Menu\nA Key: Alter Menu\nEscape:\n Main Menu\nF4:\n Timing Menu\nF1:\n Show help\n
PlayRecordHelpText=Press START to end
Save successful.=Save successful.
Saved as SM and DWI.=Saved as SM and DWI.
@@ -1269,6 +1273,7 @@ This change creates notes past the end of the music and is not allowed.=This cha
This will destroy all unsaved changes.=This will destroy all unsaved changes.
Undo=Undo
You must be in Song Timing Mode to edit BG Changes.=You must be in Song Timing Mode to edit BG Changes.
You must have an area selected to enter the Alter Menu.=You must have an area selected to enter the Alter Menu.
Current beat=Current beat
Current second=Current second
+8
View File
@@ -21,3 +21,11 @@ local _screen = {
cx = SCREEN_CENTER_X,
cy = SCREEN_CENTER_Y
}
if Screen.String then
ScreenString = Screen.String
end
if Screen.Metric then
ScreenMetric = Screen.Metric
end
+9 -10
View File
@@ -98,16 +98,15 @@ end
-- Get a metric from the currently-loading screen. This is only valid while loading
-- an actor, such as from File or InitCommand attributes; not from commands.
Screen = {
Metric = function ( sName )
local sClass = Var "LoadingScreen"
return THEME:GetMetric( sClass, sName )
end,
String = function ( sName )
local sClass = Var "LoadingScreen";
return THEME:GetString( sClass, sName )
end
};
Screen.Metric = function ( sName )
local sClass = Var "LoadingScreen"
return THEME:GetMetric( sClass, sName )
end
Screen.String = function ( sName )
local sClass = Var "LoadingScreen";
return THEME:GetString( sClass, sName )
end
function TextBannerAfterSet(self,param)
local Title=self:GetChild("Title");
@@ -148,7 +148,9 @@ end
-- MaskSource([clearzbuffer])
-- Sets an actor up as the source for a mask. Clears zBuffer by default.
function Actor:MaskSource(noclear)
self:clearzbuffer(noclear or true)
if noclear == true then
self:clearzbuffer(true)
end
self:zwrite(true)
self:blend('BlendMode_NoEffect')
end
+1 -1
View File
@@ -150,7 +150,7 @@ function InitUserPrefs()
end;
function UserPrefScoringMode()
local baseChoices = { 'DDR 1stMIX', 'DDR 4thMIX', 'DDR Extreme', 'DDR SuperNOVA', 'DDR SuperNOVA 2', 'MIGS' }; --'[SSC] Radar Master'
local baseChoices = { 'DDR 1stMIX', 'DDR 4thMIX', 'DDR Extreme', 'DDR SuperNOVA', 'DDR SuperNOVA 2', 'MIGS', 'HYBRID' }; --'[SSC] Radar Master'
local t = {
Name = "UserPrefScoringMode";
LayoutType = "ShowAllInRow";
+78 -13
View File
@@ -122,6 +122,48 @@ r['DDR Extreme'] = function(params, pss)
Shared.CurrentStep[pn] = 0; -- Reset for the next song.
end;
end;
-----------------------------------------------------------
--HYBRID Scoring
-----------------------------------------------------------
r['HYBRID'] = function(params, pss)
local multLookup =
{
['TapNoteScore_W1'] = 10,
['TapNoteScore_W2'] = 9,
['TapNoteScore_W3'] = 5
};
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues)
- radarValues:GetValue('RadarCategory_Lifts');
-- 1+2+3+...+totalItems の値
local sTotal = (totalItems+1)*totalItems/2;
-- [en] Score for one song
-- [ja] 1つあたりのスコア
local sOne = math.floor(100000000/sTotal);
-- [ja] 端数は最後の1ステップで加算するのでその値を取得
local sLast = 100000000-(sOne*sTotal);
-- [ja] 現在何個目の譜面か
pss:SetCurMaxScore(pss:GetCurMaxScore()+1);
-- [en] current score
-- [ja] 今回のスコア
local vScore = sOne*(pss:GetCurMaxScore());
if (params.HoldNoteScore == 'HoldNoteScore_Held') then
vScore = vScore;
else
if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then
vScore = 0;
else
vScore = vScore*multLookup[params.TapNoteScore]/10;
end;
end;
if ((vScore > 0) and (pss:GetCurMaxScore() == totalItems)) then
vScore = vScore+sLast;
end;
pss:SetScore(pss:GetScore()+vScore);
end;
-----------------------------------------------------------
--DDR SuperNOVA(-esque) scoring
-----------------------------------------------------------
@@ -148,24 +190,47 @@ end;
r['DDR SuperNOVA 2'] = function(params, pss)
local multLookup =
{
['TapNoteScore_W1'] = 1,
['TapNoteScore_W2'] = 1,
['TapNoteScore_W3'] = 0.5
['TapNoteScore_W1'] = 10,
['TapNoteScore_W2'] = 10,
['TapNoteScore_W3'] = 5
};
setmetatable(multLookup, ZeroIfNotFound);
local radarValues = GetDirectRadar(params.Player);
local totalItems = GetTotalItems(radarValues);
local base = 100000 / totalItems;
local hold = base * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0);
local maxScore = (base * multLookup['TapNoteScore_W1']) + hold;
pss:SetCurMaxScore(pss:GetCurMaxScore() + (math.round(maxScore) * 10));
local preW1 = base * multLookup[params.TapNoteScore];
local buildScore = (preW1 - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + hold;
pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10));
local numLifts = radarValues:GetCategory('RadarCategory_Lifts')
local numFakes = radarValues:GetCategory('RadarCategory_Fakes')
local totalItems = GetTotalItems(radarValues) - (numLifts + numFakes);
-- handle holds
local maxAdd = 0
if params.HoldNoteScore == 'HoldNoteScore_Held' then
maxAdd = 10
else
if params.HoldNoteScore == 'HoldNoteScore_LetGo' then
maxAdd = 0
else
maxAdd = multLookup[params.TapNoteScore]
if params.TapNoteScore == 'TapNoteScore_W2' or 'TapNoteScore_W3' then
-- [ja] 超最終手段
pss:SetCurMaxScore( pss:GetCurMaxScore() + 1000000 )
end
end
end
pss:SetCurMaxScore(pss:GetCurMaxScore() + maxAdd);
--[[
[ja] パフェ数取得 この方法で取得するとロングノートの場合2つカウントされる そのため使えない
pss:GetTapNoteScores('TapNoteScore_W2')
仕方がないのでパフェ数を 1000000 単位で GetCurMaxScore に記録
その後、情報を分解して取り出す
--]]
local vScore = pss:GetCurMaxScore() % 1000000
local vSub = math.floor( pss:GetCurMaxScore()/1000000 )
pss:SetScore( math.floor(10000*vScore/totalItems) * 10 - (vSub*10) );
end;
-----------------------------------------------------------
--Radar Master (doesn't work in 1.2.1, disabled)
--don't try to "fix it up", either. you *cannot* make it work in 1.2.1.
--Radar Master (doesn't work in sm-ssc 1.2.1, disabled)
--todo: get this working with StepMania 5
-----------------------------------------------------------
r['[SSC] Radar Master'] = function(params, pss)
local masterTable = {
+3
View File
@@ -3752,6 +3752,9 @@ TitleX=SCREEN_CENTER_X-80
[ScreenMiniMenuAreaMenu]
Fallback="ScreenMiniMenu"
[ScreenMiniMenuAlterMenu]
Fallback="ScreenMiniMenu"
[ScreenMiniMenuStepsInformation]
Fallback="ScreenMiniMenu"
@@ -5,7 +5,10 @@ t[#t+1] = Def.ActorFrame {
Def.Sprite {
OnCommand=function(self)
if GAMESTATE:GetCurrentSong() then
self:LoadBackground( GAMESTATE:GetCurrentSong():GetBackgroundPath() );
local song = GAMESTATE:GetCurrentSong();
if song:HasBackground() then
self:LoadBackground(song:GetBackgroundPath());
end;
self:scaletoclipped( SCREEN_WIDTH+1,SCREEN_HEIGHT );
(cmd(fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480))(self);
else
@@ -6,7 +6,10 @@ t[#t+1] = Def.ActorFrame {
Condition=not GAMESTATE:IsCourseMode();
OnCommand=function(self)
if GAMESTATE:GetCurrentSong() then
self:LoadBackground( GAMESTATE:GetCurrentSong():GetBackgroundPath() );
local song = GAMESTATE:GetCurrentSong();
if song:HasBackground() then
self:LoadBackground(song:GetBackgroundPath());
end;
self:scaletoclipped( SCREEN_WIDTH+1,SCREEN_HEIGHT );
(cmd(fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480))(self);
else
-1
View File
@@ -27,7 +27,6 @@ static ThemeMetric<float> LEFT_EDGE ("Background","LeftEdge");
static ThemeMetric<float> TOP_EDGE ("Background","TopEdge");
static ThemeMetric<float> RIGHT_EDGE ("Background","RightEdge");
static ThemeMetric<float> BOTTOM_EDGE ("Background","BottomEdge");
#define RECT_BACKGROUND RectF (LEFT_EDGE,TOP_EDGE,RIGHT_EDGE,BOTTOM_EDGE)
static ThemeMetric<float> CLAMP_OUTPUT_PERCENT ("Background","ClampOutputPercent");
static ThemeMetric<bool> SHOW_DANCING_CHARACTERS ("Background","ShowDancingCharacters");
static ThemeMetric<bool> USE_STATIC_BG ("Background","UseStaticBackground");
+6 -4
View File
@@ -142,8 +142,10 @@ static void StartMusic( MusicToPlay &ToPlay )
{
LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() );
Song song;
if( GetExtension(ToPlay.m_sTimingFile) == ".ssc" &&
SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) )
SSCLoader loaderSSC;
SMLoader loaderSM;
if(GetExtension(ToPlay.m_sTimingFile) == ".ssc" &&
loaderSSC.LoadFromSimfile(ToPlay.m_sTimingFile, song) )
{
ToPlay.HasTiming = true;
ToPlay.m_TimingData = song.m_SongTiming;
@@ -152,8 +154,8 @@ static void StartMusic( MusicToPlay &ToPlay )
if( pStepsCabinetLights )
pStepsCabinetLights->GetNoteData( ToPlay.m_LightsData );
}
else if( GetExtension(ToPlay.m_sTimingFile) == ".sm" &&
SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) )
else if(GetExtension(ToPlay.m_sTimingFile) == ".sm" &&
loaderSM.LoadFromSimfile(ToPlay.m_sTimingFile, song) )
{
ToPlay.HasTiming = true;
ToPlay.m_TimingData = song.m_SongTiming;
+11
View File
@@ -106,6 +106,7 @@ static Preference<Premium> g_Premium( "Premium", Premium_Off );
Preference<bool> GameState::m_bAutoJoin( "AutoJoin", false );
GameState::GameState() :
processedTiming( NULL ),
m_pCurGame( Message_CurrentGameChanged ),
m_pCurStyle( Message_CurrentStyleChanged ),
m_PlayMode( Message_PlayModeChanged ),
@@ -200,6 +201,16 @@ void GameState::SetMasterPlayerNumber(const PlayerNumber p)
this->masterPlayerNumber = p;
}
TimingData * GameState::GetProcessedTimingData() const
{
return this->processedTiming;
}
void GameState::SetProcessedTimingData(TimingData * t)
{
this->processedTiming = t;
}
void GameState::ApplyGameCommand( const RString &sCommand, PlayerNumber pn )
{
GameCommand m;
+12
View File
@@ -37,6 +37,8 @@ class GameState
{
/** @brief The player number used with Styles where one player controls both sides. */
PlayerNumber masterPlayerNumber;
/** @brief The TimingData that is used for processing certain functions. */
TimingData * processedTiming;
public:
/** @brief Set up the GameState with initial values. */
GameState();
@@ -149,6 +151,16 @@ public:
* @brief Set the master player number.
* @param p the master player number. */
void SetMasterPlayerNumber(const PlayerNumber p);
/**
* @brief Retrieve the present timing data being processed.
* @return the timing data pointer. */
TimingData * GetProcessedTimingData() const;
/**
* @brief Set the timing data to be used with processing.
* @param t the timing data. */
void SetProcessedTimingData(TimingData * t);
bool IsCourseMode() const;
bool IsBattleMode() const; // not Rave
+1 -1
View File
@@ -47,7 +47,7 @@ void GameplayAssist::PlayTicks( const NoteData &nd, const PlayerState *ps )
if( nd.IsThereATapOrHoldHeadAtRow( r ) )
iClapRow = r;
if( iClapRow != -1 && !timing.IsWarpAtRow( iClapRow ) && !timing.IsFakeAtRow( iClapRow ) )
if( iClapRow != -1 && timing.IsJudgableAtRow(iClapRow))
{
const float fTickBeat = NoteRowToBeat( iClapRow );
const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat );
+21 -8
View File
@@ -9,6 +9,7 @@
#include "RageUtil.h"
#include "RageLog.h"
#include "XmlFile.h"
#include "GameState.h" // blame radar calculations.
#include "Foreach.h"
#include "RageUtil_AutoPtr.h"
@@ -467,7 +468,8 @@ int NoteData::GetNumTapNotes( int iStartIndex, int iEndIndex ) const
{
const TapNote &tn = GetTapNote(t, r);
if( tn.type != TapNote::empty && tn.type != TapNote::mine
&& tn.type != TapNote::lift && tn.type != TapNote::fake )
&& tn.type != TapNote::lift && tn.type != TapNote::fake
&& GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r) )
iNumNotes++;
}
}
@@ -485,7 +487,7 @@ int NoteData::GetNumRowsWithTap( int iStartIndex, int iEndIndex ) const
{
int iNumNotes = 0;
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( *this, r, iStartIndex, iEndIndex )
if( IsThereATapAtRow(r) )
if( IsThereATapAtRow(r) && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r) )
iNumNotes++;
return iNumNotes;
@@ -498,7 +500,8 @@ int NoteData::GetNumMines( int iStartIndex, int iEndIndex ) const
for( int t=0; t<GetNumTracks(); t++ )
{
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, r, iStartIndex, iEndIndex )
if( GetTapNote(t, r).type == TapNote::mine )
if( GetTapNote(t, r).type == TapNote::mine
&& GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
iNumMines++;
}
@@ -509,7 +512,7 @@ int NoteData::GetNumRowsWithTapOrHoldHead( int iStartIndex, int iEndIndex ) cons
{
int iNumNotes = 0;
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( *this, r, iStartIndex, iEndIndex )
if( IsThereATapOrHoldHeadAtRow(r) )
if( IsThereATapOrHoldHeadAtRow(r) && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r) )
iNumNotes++;
return iNumNotes;
@@ -560,7 +563,8 @@ int NoteData::GetNumRowsWithSimultaneousPresses( int iMinSimultaneousPresses, in
{
if( !RowNeedsAtLeastSimultaneousPresses(iMinSimultaneousPresses,r) )
continue;
if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
continue;
iNum++;
}
@@ -576,7 +580,10 @@ int NoteData::GetNumRowsWithSimultaneousTaps( int iMinTaps, int iStartIndex, int
for( int t=0; t<GetNumTracks(); t++ )
{
const TapNote &tn = GetTapNote(t, r);
if( tn.type != TapNote::mine && tn.type != TapNote::empty && tn.type != TapNote::fake ) // mines don't count
if( tn.type != TapNote::mine // mines don't count.
&& tn.type != TapNote::empty
&& tn.type != TapNote::fake
&& GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
iNumNotesThisIndex++;
}
if( iNumNotesThisIndex >= iMinTaps )
@@ -598,6 +605,8 @@ int NoteData::GetNumHoldNotes( int iStartIndex, int iEndIndex ) const
if( lBegin->second.type != TapNote::hold_head ||
lBegin->second.subType != TapNote::hold_head_hold )
continue;
if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first))
continue;
iNumHolds++;
}
}
@@ -616,6 +625,8 @@ int NoteData::GetNumRolls( int iStartIndex, int iEndIndex ) const
if( lBegin->second.type != TapNote::hold_head ||
lBegin->second.subType != TapNote::hold_head_roll )
continue;
if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first))
continue;
iNumRolls++;
}
}
@@ -629,7 +640,8 @@ int NoteData::GetNumLifts( int iStartIndex, int iEndIndex ) const
for( int t=0; t<GetNumTracks(); t++ )
{
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, r, iStartIndex, iEndIndex )
if( GetTapNote(t, r).type == TapNote::lift )
if( GetTapNote(t, r).type == TapNote::lift
&& GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
iNumLifts++;
}
@@ -643,7 +655,8 @@ int NoteData::GetNumFakes( int iStartIndex, int iEndIndex ) const
for( int t=0; t<GetNumTracks(); t++ )
{
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, r, iStartIndex, iEndIndex )
if( GetTapNote(t, r).type == TapNote::fake )
if( GetTapNote(t, r).type == TapNote::fake
|| !GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
iNumFakes++;
}
+5
View File
@@ -799,6 +799,11 @@ RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out )
{
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( in, t, r, 0, MAX_NOTE_ROW )
{
/* This function deals strictly with taps, jumps, hands, and quads.
* As such, all rows in here have to be judgable. */
if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r))
continue;
const TapNote &tn = in.GetTapNote(t, r);
switch( tn.type )
{
+1 -1
View File
@@ -164,7 +164,7 @@ struct TapNote
{
if (type_ > TapNote::fake )
{
LOG->Trace(ssprintf("Invalid tap note type %d (most likely) due to random vanish issues. Assume it doesn't need judging.", type_ ) );
LOG->Trace("Invalid tap note type %d (most likely) due to random vanish issues. Assume it doesn't need judging.", (int)type_ );
type = TapNote::empty;
}
}
+10 -7
View File
@@ -32,20 +32,23 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set<RString> &Bl
vector<RString> list;
BlacklistedImages.clear();
SSCLoader::GetApplicableFiles( sPath, list );
SSCLoader loaderSSC;
loaderSSC.GetApplicableFiles( sPath, list );
if( !list.empty() )
{
if( !SSCLoader::LoadFromDir( sPath, out ) )
if( !loaderSSC.LoadFromDir( sPath, out ) )
return false;
SSCLoader::TidyUpData( out, false );
loaderSSC.TidyUpData( out, false );
return true;
}
SMALoader::GetApplicableFiles( sPath, list );
SMALoader loaderSMA;
loaderSMA.GetApplicableFiles( sPath, list );
if (!list.empty() )
return SMALoader::LoadFromDir( sPath, out );
SMLoader::GetApplicableFiles( sPath, list );
return loaderSMA.LoadFromDir( sPath, out );
SMLoader loaderSM;
loaderSM.GetApplicableFiles( sPath, list );
if (!list.empty() )
return SMLoader::LoadFromDir( sPath, out );
return loaderSM.LoadFromDir( sPath, out );
DWILoader::GetApplicableFiles( sPath, list );
if( !list.empty() )
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
+134 -56
View File
@@ -13,10 +13,39 @@
#include "Attack.h"
#include "PrefsManager.h"
/** @brief The maximum file size for edits. */
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
{
vector<RString> aFileNames;
GetApplicableFiles( sPath, aFileNames );
if( aFileNames.size() > 1 )
{
// Need to break this up first.
RString tmp = "Song " + sPath + " has more than one";
LOG->UserLog(tmp, this->GetFileExtension(), "file. There can only be one!");
return false;
}
ASSERT( aFileNames.size() == 1 );
return LoadFromSimfile( sPath + aFileNames[0], out );
}
void SMLoader::LoadFromSMTokens(
float SMLoader::RowToBeat( RString line, const int rowsPerBeat )
{
RString backup = line;
Trim(line, "r");
Trim(line, "R");
if( backup != line )
{
return StringToFloat( line ) / rowsPerBeat;
}
else
{
return StringToFloat( line );
}
}
void SMLoader::LoadFromTokens(
RString sStepsType,
RString sDescription,
RString sDifficulty,
@@ -34,7 +63,7 @@ void SMLoader::LoadFromSMTokens(
Trim( sDifficulty );
Trim( sNoteData );
// LOG->Trace( "Steps::LoadFromSMTokens()" );
// LOG->Trace( "Steps::LoadFromTokens()" );
// insert stepstype hacks from GameManager.cpp here? -aj
out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType );
@@ -79,11 +108,6 @@ void SMLoader::LoadFromSMTokens(
out.TidyUpData();
}
void SMLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
{
GetDirListing( sPath + RString("*.sm"), out );
}
void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam )
{
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
@@ -171,10 +195,10 @@ void SMLoader::ProcessInstrumentTracks( Song &out, const RString &sParam )
}
}
bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
bool SMLoader::ProcessBPMs( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayBPMChangeExpressions;
split( sParam, ",", arrayBPMChangeExpressions );
split( line, ",", arrayBPMChangeExpressions );
// prepare storage variables for negative BPMs -> Warps.
float negBeat = -1;
@@ -196,7 +220,7 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
bNotEmpty = true;
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
const float fBeat = RowToBeat( arrayBPMChangeValues[0], rowsPerBeat );
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
if( fNewBPM < 0.0f )
@@ -242,10 +266,10 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
return bNotEmpty;
}
void SMLoader::ProcessStops( TimingData &out, const RString sParam )
void SMLoader::ProcessStops( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayFreezeExpressions;
split( sParam, ",", arrayFreezeExpressions );
split( line, ",", arrayFreezeExpressions );
// Prepare variables for negative stop conversion.
float negBeat = -1;
@@ -263,7 +287,7 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam )
continue;
}
const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] );
const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], rowsPerBeat );
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
// Process the prior stop.
@@ -308,10 +332,10 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam )
}
}
void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
void SMLoader::ProcessDelays( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayDelayExpressions;
split( sParam, ",", arrayDelayExpressions );
split( line, ",", arrayDelayExpressions );
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
{
@@ -325,7 +349,7 @@ void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
continue;
}
const float fFreezeBeat = StringToFloat( arrayDelayValues[0] );
const float fFreezeBeat = RowToBeat( arrayDelayValues[0], rowsPerBeat );
const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] );
StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true );
@@ -342,10 +366,10 @@ void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
}
}
void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
void SMLoader::ProcessTimeSignatures( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> vs1;
split( sParam, ",", vs1 );
split( line, ",", vs1 );
FOREACH_CONST( RString, vs1, s1 )
{
@@ -358,9 +382,9 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
continue;
}
const float fBeat = StringToFloat( vs2[0] );
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), StringToInt( vs2[2] ));
TimeSignatureSegment seg( fBeat, StringToInt( vs2[1] ), StringToInt( vs2[2] ));
if( fBeat < 0 )
{
@@ -384,10 +408,10 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
}
}
void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam )
void SMLoader::ProcessTickcounts( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayTickcountExpressions;
split( sParam, ",", arrayTickcountExpressions );
split( line, ",", arrayTickcountExpressions );
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
{
@@ -401,14 +425,90 @@ void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam )
continue;
}
const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] );
const float fTickcountBeat = RowToBeat( arrayTickcountValues[0], rowsPerBeat );
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
TickcountSegment new_seg( fTickcountBeat, iTicks );
out.AddTickcountSegment( new_seg );
}
}
void SMLoader::ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> vs1;
split( line, ",", vs1 );
FOREACH_CONST( RString, vs1, s1 )
{
vector<RString> vs2;
split( *s1, "=", vs2 );
if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2.
{
vs2.push_back("0");
}
if( vs2.size() == 3 ) // use beats by default.
{
vs2.push_back("0");
}
if( vs2.size() < 4 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() );
continue;
}
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] ));
seg.SetUnit(StringToInt(vs2[3]));
if( fBeat < 0 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat );
continue;
}
if( seg.GetLength() < 0 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() );
continue;
}
out.AddSpeedSegment( seg );
}
}
void SMLoader::ProcessFakes( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayFakeExpressions;
split( line, ",", arrayFakeExpressions );
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
{
vector<RString> arrayFakeValues;
split( arrayFakeExpressions[b], "=", arrayFakeValues );
// XXX: Hard to tell which file caused this.
if( arrayFakeValues.size() != 2 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
arrayFakeExpressions[b].c_str() );
continue;
}
const float fBeat = RowToBeat( arrayFakeValues[0], rowsPerBeat );
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
if(fNewBeat > 0)
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
else
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
}
}
}
bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression )
{
vector<RString> aBGChangeValues;
@@ -495,7 +595,7 @@ bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString
return aBGChangeValues.size() >= 2;
}
bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache )
bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
{
LOG->Trace( "Song::LoadFromSMFile(%s)", sPath.c_str() );
@@ -719,7 +819,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
}
Steps* pNewNotes = out.CreateSteps();
LoadFromSMTokens(
LoadFromTokens(
sParams[1],
sParams[2],
sParams[3],
@@ -743,33 +843,6 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
return true;
}
bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
{
vector<RString> aFileNames;
GetApplicableFiles( sPath, aFileNames );
if( aFileNames.size() > 1 )
{
LOG->UserLog( "Song", sPath, "has more than one SM file. There can be only one (unless you are using TougaKiryuu's AnimeMix files somehow, which assume a different version of StepMania)!" );
return false;
/*
for( unsigned i=0; i<aFileNames.size(); i++ )
{
if(!LoadFromSMFile( sPath + aFileNames[i], out ))
return false;
}
return true;
*/
}
ASSERT( aFileNames.size() == 1 );
/* We should have at least one; if we had none, we shouldn't have been
* called to begin with. */
//ASSERT( aFileNames.size() >= 1 );
return LoadFromSMFile( sPath + aFileNames[0], out );
}
bool SMLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
{
LOG->Trace( "SMLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
@@ -853,7 +926,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
return true;
Steps* pNewNotes = pSong->CreateSteps();
LoadFromSMTokens(
LoadFromTokens(
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
*pNewNotes);
@@ -881,6 +954,11 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
}
void SMLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
{
GetDirListing( sPath + RString("*" + this->GetFileExtension() ), out );
}
void SMLoader::TidyUpData( Song &song, bool bFromCache )
{
/*
+145 -21
View File
@@ -15,33 +15,157 @@ class TimingData;
* This was brought in from StepMania 4's recent betas. */
const float FAST_BPM_WARP = 9999999.f;
/** @brief Reads a Song from an .SM file. */
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 );
/** @brief The maximum file size for edits. */
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
bool LoadFromSMFile( 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 LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
/** @brief Reads a Song from an .SM file. */
struct SMLoader
{
SMLoader() : fileExt(".sm") {}
SMLoader(RString ext) : fileExt(ext) {}
bool ProcessBPMs( TimingData &, const RString );
void ProcessStops( TimingData &, const RString );
void ProcessDelays( TimingData &, const RString );
void ProcessTimeSignatures( TimingData &, const RString );
void ProcessTickcounts( TimingData &, const RString );
void ProcessBGChanges( Song &out, const RString &sValueName,
virtual ~SMLoader() {}
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
virtual bool LoadFromDir( const RString &sPath, Song &out );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
virtual void TidyUpData( Song &song, bool bFromCache );
/**
* @brief Attempt to load the specified sm file.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .sm files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
virtual void GetApplicableFiles( const RString &sPath, vector<RString> &out );
virtual bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
virtual bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
virtual bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
virtual bool LoadFromBGChangesString(BackgroundChange &change,
const RString &sBGChangeExpression );
/**
* @brief Process the BPM Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose.
* @return true if there was at least one segment found, false otherwise. */
bool ProcessBPMs(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
/**
* @brief Process the Stop Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
void ProcessStops(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
/**
* @brief Process the Delay Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
void ProcessDelays(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
/**
* @brief Process the Time Signature Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
void ProcessTimeSignatures(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
/**
* @brief Process the Tickcount Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
void ProcessTickcounts(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
/**
* @brief Process the Speed Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
virtual void ProcessSpeeds(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
virtual void ProcessCombos(TimingData & out,
const RString line,
const int rowsPerBeat = -1) {}
/**
* @brief Process the Fake Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
virtual void ProcessFakes(TimingData & out,
const RString line,
const int rowsPerBeat = -1);
virtual void ProcessBGChanges( Song &out, const RString &sValueName,
const RString &sPath, const RString &sParam );
void ProcessAttacks( Song &out, MsdFile::value_t sParams );
void ProcessInstrumentTracks( Song &out, const RString &sParam );
}
/**
* @brief Convert a row value to the proper beat value.
*
* This is primarily used for assistance with converting SMA files.
* @param line The line that contains the value.
* @param rowsPerBeat the number of rows per beat according to the original file.
* @return the converted beat value. */
float RowToBeat(RString line, const int rowsPerBeat);
protected:
/**
* @brief Process the different tokens we have available to get NoteData.
* @param stepsType The current StepsType.
* @param description The description of the chart.
* @param difficulty The difficulty (in words) of the chart.
* @param meter the difficulty (in numbers) of the chart.
* @param radarValues the calculated radar values.
* @param noteData the note data itself.
* @param out the Steps getting the data. */
virtual void LoadFromTokens(RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out);
/**
* @brief Retrieve the file extension associated with this loader.
* @return the file extension. */
RString GetFileExtension() const { return fileExt; }
private:
/** @brief The file extension in use. */
const RString fileExt;
};
#endif
+11 -415
View File
@@ -14,240 +14,6 @@
#include "Steps.h"
#include "Attack.h"
/**
* @brief A custom .edit file can only be so big before we have to reject it.
*/
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB
bool SMALoader::LoadFromBGChangesString( BackgroundChange &change,
const RString &sBGChangeExpression )
{
return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression);
}
bool SMALoader::LoadFromDir( const RString &sPath, Song &out )
{
vector<RString> aFileNames;
GetApplicableFiles( sPath, aFileNames );
if( aFileNames.size() > 1 )
{
LOG->UserLog( "Song", sPath, "has more than one SMA file. Only one SMA file is allowed per song." );
return false;
}
ASSERT( aFileNames.size() == 1 );
return LoadFromSMAFile( sPath + aFileNames[0], out );
}
float SMALoader::RowToBeat( RString sLine, const int iRowsPerBeat )
{
if( sLine.find("R") || sLine.find("r") )
{
sLine = sLine.Left(sLine.size()-1);
return StringToFloat( sLine ) / iRowsPerBeat;
}
else
{
return StringToFloat( sLine );
}
}
bool SMALoader::ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayBPMChangeExpressions;
split( sParam, ",", arrayBPMChangeExpressions );
// prepare storage variables for negative BPMs -> Warps.
float negBeat = -1;
float negBPM = 1;
float highspeedBeat = -1;
bool bNotEmpty = false;
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
{
vector<RString> arrayBPMChangeValues;
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
// XXX: Hard to tell which file caused this.
if( arrayBPMChangeValues.size() != 2 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.",
arrayBPMChangeExpressions[b].c_str() );
continue;
}
bNotEmpty = true;
const float fBeat = RowToBeat( arrayBPMChangeValues[0], iRowsPerBeat );
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
if( fNewBPM < 0.0f )
{
out.m_bHasNegativeBpms = true;
negBeat = fBeat;
negBPM = fNewBPM;
}
else if( fNewBPM > 0.0f )
{
// add in a warp.
if( negBPM < 0 )
{
float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat);
WarpSegment new_seg(negBeat, endBeat - negBeat);
out.AddWarpSegment( new_seg );
negBeat = -1;
negBPM = 1;
}
// too fast. make it a warp.
if( fNewBPM > FAST_BPM_WARP )
{
highspeedBeat = fBeat;
}
else
{
// add in a warp.
if( highspeedBeat > 0 )
{
WarpSegment new_seg(highspeedBeat, fBeat - highspeedBeat);
out.AddWarpSegment( new_seg );
highspeedBeat = -1;
}
{
BPMSegment new_seg( BeatToNoteRow( fBeat ), fNewBPM );
out.AddBPMSegment( new_seg );
}
}
}
}
return bNotEmpty;
}
void SMALoader::ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayFreezeExpressions;
split( sParam, ",", arrayFreezeExpressions );
// Prepare variables for negative stop conversion.
float negBeat = -1;
float negPause = 0;
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
{
vector<RString> arrayFreezeValues;
split( arrayFreezeExpressions[f], "=", arrayFreezeValues );
if( arrayFreezeValues.size() != 2 )
{
// XXX: Hard to tell which file caused this.
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.",
arrayFreezeExpressions[f].c_str() );
continue;
}
const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], iRowsPerBeat );
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
// Process the prior stop.
if( negPause > 0 )
{
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
float fSkipBeats = negPause / fSecondsPerBeat;
if( negBeat + fSkipBeats > fFreezeBeat )
fSkipBeats = fFreezeBeat - negBeat;
WarpSegment ws( negBeat, fSkipBeats);
out.AddWarpSegment( ws );
negBeat = -1;
negPause = 0;
}
if( fFreezeSeconds < 0.0f )
{
negBeat = fFreezeBeat;
negPause = -fFreezeSeconds;
}
else if( fFreezeSeconds > 0.0f )
{
StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
out.AddStopSegment( ss );
}
}
// Process the prior stop if there was one.
if( negPause > 0 )
{
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
float fSkipBeats = negPause / fSecondsPerBeat;
WarpSegment ws( negBeat, fSkipBeats);
out.AddWarpSegment( ws );
}
}
void SMALoader::ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayDelayExpressions;
split( sParam, ",", arrayDelayExpressions );
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
{
vector<RString> arrayDelayValues;
split( arrayDelayExpressions[f], "=", arrayDelayValues );
if( arrayDelayValues.size() != 2 )
{
// XXX: Hard to tell which file caused this.
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #DELAYS value \"%s\" (must have exactly one '='), ignored.",
arrayDelayExpressions[f].c_str() );
continue;
}
const float fFreezeBeat = RowToBeat( arrayDelayValues[0], iRowsPerBeat );
const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] );
StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true );
// XXX: Remove Negatives Bug?
new_seg.SetBeat(fFreezeBeat);
new_seg.SetPause(fFreezeSeconds);
// LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
if(fFreezeSeconds > 0.0f)
out.AddStopSegment( new_seg );
else
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
}
}
void SMALoader::ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayTickcountExpressions;
split( sParam, ",", arrayTickcountExpressions );
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
{
vector<RString> arrayTickcountValues;
split( arrayTickcountExpressions[f], "=", arrayTickcountValues );
if( arrayTickcountValues.size() != 2 )
{
// XXX: Hard to tell which file caused this.
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #TICKCOUNTS value \"%s\" (must have exactly one '='), ignored.",
arrayTickcountExpressions[f].c_str() );
continue;
}
const float fTickcountBeat = RowToBeat( arrayTickcountValues[0], iRowsPerBeat );
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
out.AddTickcountSegment( new_seg );
}
}
void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayMultiplierExpressions;
@@ -306,15 +72,10 @@ void SMALoader::ProcessBeatsPerMeasure( TimingData &out, const RString sParam )
}
}
float BeatToSeconds(float fromBeat, RString toSomething)
{
return 0;
}
void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam )
void SMALoader::ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> vs1;
split( sParam, ",", vs1 );
split( line, ",", vs1 );
FOREACH_CONST( RString, vs1, s1 )
{
@@ -335,7 +96,7 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS
continue;
}
const float fBeat = RowToBeat( vs2[0], iRowsPerBeat );
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
RString backup = vs2[2];
Trim(vs2[2], "s");
@@ -362,57 +123,7 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS
}
}
void SMALoader::ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam )
{
vector<RString> arrayFakeExpressions;
split( sParam, ",", arrayFakeExpressions );
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
{
vector<RString> arrayFakeValues;
split( arrayFakeExpressions[b], "=", arrayFakeValues );
// XXX: Hard to tell which file caused this.
if( arrayFakeValues.size() != 2 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
arrayFakeExpressions[b].c_str() );
continue;
}
const float fBeat = RowToBeat( arrayFakeValues[0], iRowsPerBeat );
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
if(fNewBeat > 0)
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
else
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
}
}
}
void SMALoader::LoadFromSMATokens(
RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out
)
{
SMLoader::LoadFromSMTokens( sStepsType, sDescription,
sDifficulty, sMeter, sRadarValues,
sNoteData, out );
}
void SMALoader::TidyUpData( Song &song, bool bFromCache )
{
SMLoader::TidyUpData( song, bFromCache );
}
bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
{
LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() );
@@ -635,28 +346,28 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
{
TimingData &timing = (state == SMA_GETTING_STEP_INFO
? pNewNotes->m_Timing : out.m_SongTiming);
ProcessBPMs( timing, iRowsPerBeat, sParams[1] );
ProcessBPMs( timing, sParams[1], iRowsPerBeat );
}
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
{
TimingData &timing = (state == SMA_GETTING_STEP_INFO
? pNewNotes->m_Timing : out.m_SongTiming);
ProcessStops( timing, iRowsPerBeat, sParams[1] );
ProcessStops( timing, sParams[1], iRowsPerBeat );
}
else if( sValueName=="DELAYS" )
{
TimingData &timing = (state == SMA_GETTING_STEP_INFO
? pNewNotes->m_Timing : out.m_SongTiming);
ProcessDelays( timing, iRowsPerBeat, sParams[1] );
ProcessDelays( timing, sParams[1], iRowsPerBeat );
}
else if( sValueName=="TICKCOUNT" )
{
TimingData &timing = (state == SMA_GETTING_STEP_INFO
? pNewNotes->m_Timing : out.m_SongTiming);
ProcessTickcounts( timing, iRowsPerBeat, sParams[1] );
ProcessTickcounts( timing, sParams[1], iRowsPerBeat );
}
else if( sValueName=="SPEED" )
@@ -665,7 +376,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
? pNewNotes->m_Timing : out.m_SongTiming);
RString tmp = sParams[1];
Trim( tmp );
ProcessSpeeds( timing, iRowsPerBeat, tmp );
ProcessSpeeds( timing, tmp, iRowsPerBeat );
}
else if( sValueName=="MULTIPLIER" )
@@ -679,7 +390,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
{
TimingData &timing = (state == SMA_GETTING_STEP_INFO
? pNewNotes->m_Timing : out.m_SongTiming);
ProcessFakes( timing, iRowsPerBeat, sParams[1] );
ProcessFakes( timing, sParams[1], iRowsPerBeat );
}
else if( sValueName=="METERTYPE" )
@@ -706,7 +417,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
continue;
}
LoadFromSMATokens(
LoadFromTokens(
sParams[1],
sParams[2],
sParams[3],
@@ -727,121 +438,6 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
return true;
}
void SMALoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
{
GetDirListing( sPath + RString("*.sma"), out );
}
bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
{
LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath );
if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES )
{
LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." );
return false;
}
MsdFile msd;
if( !msd.ReadFile( sEditFilePath, true ) ) // unescape
{
LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() );
return false;
}
return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong );
}
bool SMALoader::LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot )
{
MsdFile msd;
msd.ReadFromString( sBuffer, true ); // unescape
return LoadEditFromMsd( msd, sEditFilePath, slot, true );
}
bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
{
Song* pSong = NULL;
for( unsigned i=0; i<msd.GetNumValues(); i++ )
{
int iNumParams = msd.GetNumParams(i);
const MsdFile::value_t &sParams = msd.GetValue(i);
RString sValueName = sParams[0];
sValueName.MakeUpper();
// handle the data
if( sValueName=="SONG" )
{
if( pSong )
{
LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." );
return false;
}
RString sSongFullTitle = 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;
}
}
else if( sValueName=="NOTES" )
{
if( pSong == NULL )
{
LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." );
return false;
}
if( 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;
Steps* pNewNotes = pSong->CreateSteps();
LoadFromSMATokens(
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
{
LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() );
}
}
return true;
}
/**
* @file
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
+12 -27
View File
@@ -2,6 +2,7 @@
#define NOTES_LOADER_SMA_H
#include "GameConstantsAndTypes.h"
#include "NotesLoaderSM.h"
#include "BackgroundUtil.h"
class MsdFile;
@@ -20,37 +21,21 @@ enum SMALoadingStates
};
/** @brief Reads a Song from a .SMA file. */
namespace SMALoader
{
void LoadFromSMATokens( RString sStepsType,
RString sDescription,
RString sDifficulty,
RString sMeter,
RString sRadarValues,
RString sNoteData,
Steps &out );
struct SMALoader : public SMLoader
{
SMALoader() : SMLoader(".sma") {}
bool LoadFromDir( const RString &sPath, Song &out );
void TidyUpData( Song &song, bool bFromCache );
bool LoadFromSMAFile( const RString &sPath, Song &out );
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
void ProcessBeatsPerMeasure( TimingData &out, const RString sParam );
bool ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam );
void ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam );
float RowToBeat( RString sLine, const int iRowsPerBeat );
/**
* @brief Process the Speed Segments from the string.
* @param out the TimingData being modified.
* @param line the string in question.
* @param rowsPerBeat the number of rows per beat for this purpose. */
virtual void ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat );
};
#endif
+11 -125
View File
@@ -14,38 +14,6 @@
#include "Attack.h"
#include "PrefsManager.h"
/**
* @brief A custom .edit file can only be so big before we have to reject it.
*/
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB
/**
* @brief Attempt to load any background changes in use by this song.
* @param change a reference to the background change.
* @param sBGChangeExpression a reference to the list of changes to be made.
* @return its success or failure.
*/
bool LoadFromBGSSCChangesString( BackgroundChange &change, const RString &sBGChangeExpression )
{
return SMLoader::LoadFromBGChangesString( change, sBGChangeExpression );
}
bool SSCLoader::LoadFromDir( const RString &sPath, Song &out )
{
vector<RString> aFileNames;
GetApplicableFiles( sPath, aFileNames );
if( aFileNames.size() > 1 )
{
LOG->UserLog( "Song", sPath, "has more than one SSC file. Only one SSC file is allowed per song." );
return false;
}
ASSERT( aFileNames.size() == 1 ); // Ensure one was found entirely.
return LoadFromSSCFile( sPath + aFileNames[0], out );
}
void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float fVersion )
{
vector<RString> arrayWarpExpressions;
@@ -108,10 +76,10 @@ void SSCLoader::ProcessLabels( TimingData &out, const RString sParam )
}
}
void SSCLoader::ProcessCombos( TimingData &out, const RString sParam )
void SSCLoader::ProcessCombos( TimingData &out, const RString line, const int rowsPerBeat )
{
vector<RString> arrayComboExpressions;
split( sParam, ",", arrayComboExpressions );
split( line, ",", arrayComboExpressions );
for( unsigned f=0; f<arrayComboExpressions.size(); f++ )
{
@@ -130,53 +98,6 @@ void SSCLoader::ProcessCombos( TimingData &out, const RString sParam )
}
}
void SSCLoader::ProcessSpeeds( TimingData &out, const RString sParam )
{
vector<RString> vs1;
split( sParam, ",", vs1 );
FOREACH_CONST( RString, vs1, s1 )
{
vector<RString> vs2;
split( *s1, "=", vs2 );
if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2.
{
vs2.push_back("0");
}
if( vs2.size() == 3 ) // use beats by default.
{
vs2.push_back("0");
}
if( vs2.size() < 4 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() );
continue;
}
const float fBeat = StringToFloat( vs2[0] );
SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] ));
seg.SetUnit(StringToInt(vs2[3]));
if( fBeat < 0 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat );
continue;
}
if( seg.GetLength() < 0 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() );
continue;
}
out.AddSpeedSegment( seg );
}
}
void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam )
{
vector<RString> vs1;
@@ -207,37 +128,8 @@ void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam )
}
}
void SSCLoader::ProcessFakes( TimingData &out, const RString sParam )
{
vector<RString> arrayFakeExpressions;
split( sParam, ",", arrayFakeExpressions );
for( unsigned b=0; b<arrayFakeExpressions.size(); b++ )
{
vector<RString> arrayFakeValues;
split( arrayFakeExpressions[b], "=", arrayFakeValues );
// XXX: Hard to tell which file caused this.
if( arrayFakeValues.size() != 2 )
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.",
arrayFakeExpressions[b].c_str() );
continue;
}
const float fBeat = StringToFloat( arrayFakeValues[0] );
const float fNewBeat = StringToFloat( arrayFakeValues[1] );
if(fNewBeat > 0)
out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) );
else
{
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat );
}
}
}
bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache )
bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache )
{
LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() );
@@ -421,7 +313,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
for( unsigned b=0; b<aFGChangeExpressions.size(); b++ )
{
BackgroundChange change;
if( LoadFromBGSSCChangesString( change, aFGChangeExpressions[b] ) )
if( LoadFromBGChangesString( change, aFGChangeExpressions[b] ) )
out.AddForegroundChange( change );
}
}
@@ -665,11 +557,6 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
return true;
}
void SSCLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
{
GetDirListing( sPath + RString("*.ssc"), out );
}
bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
{
LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
@@ -883,9 +770,13 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
else
{
pNewNotes = pSong->CreateSteps();
SMLoader::LoadFromSMTokens(
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
*pNewNotes);
LoadFromTokens(sParams[1],
sParams[2],
sParams[3],
sParams[4],
sParams[5],
sParams[6],
*pNewNotes);
}
pNewNotes->SetLoadedFromProfile( slot );
@@ -913,11 +804,6 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
return bSSCFormat;
}
void SSCLoader::TidyUpData( Song &song, bool bFromCache )
{
SMLoader::TidyUpData(song, bFromCache);
}
/*
* (c) 2011 Jason Felds
* All rights reserved.
+9 -25
View File
@@ -3,6 +3,7 @@
#define NotesLoaderSSC_H
#include "GameConstantsAndTypes.h"
#include "NotesLoaderSM.h"
class MsdFile;
class Song;
@@ -29,15 +30,10 @@ const float VERSION_SPLIT_TIMING = 0.7f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
*/
namespace SSCLoader
struct SSCLoader : public SMLoader
{
/**
* @brief Attempt to load a song from a specified path.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a reference to the Song that will retrieve the song information.
* @return its success or failure.
*/
bool LoadFromDir( const RString &sPath, Song &out );
SSCLoader() : SMLoader(".ssc") {}
/**
* @brief Attempt to load the specified ssc file.
* @param sPath a const reference to the path on the hard drive to check.
@@ -45,13 +41,8 @@ namespace SSCLoader
* @param bFromCache a check to see if we are getting certain information from the cache file.
* @return its success or failure.
*/
bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Retrieve the list of .ssc files.
* @param sPath a const reference to the path on the hard drive to check.
* @param out a vector of files found in the path.
*/
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false );
/**
* @brief Attempt to load an edit from the hard drive.
* @param sEditFilePath a path on the hard drive to check.
@@ -69,21 +60,14 @@ namespace SSCLoader
* @return its success or failure.
*/
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
/**
* @brief Perform some cleanup on the loaded song.
* @param song a reference to the song that may need cleaning up.
* @param bFromCache a flag to determine if this song is loaded from a cache file.
*/
void TidyUpData( Song &song, bool bFromCache );
void ProcessWarps( TimingData &, const RString, const float );
void ProcessLabels( TimingData &, const RString );
void ProcessCombos( TimingData &, const RString );
void ProcessSpeeds( TimingData &, const RString );
virtual void ProcessCombos( TimingData &, const RString, const int = -1 );
void ProcessScrolls( TimingData &, const RString );
void ProcessFakes( TimingData &, const RString );
}
};
#endif
/**
* @file
+14 -9
View File
@@ -1538,7 +1538,7 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool
// Is this the row we want?
do {
const TapNote &tn = begin->second;
if( m_Timing->IsWarpAtRow( begin->first ) || m_Timing->IsFakeAtRow( begin->first ) )
if (!m_Timing->IsJudgableAtRow( begin->first ))
break;
if( tn.type == TapNote::empty )
break;
@@ -1594,7 +1594,7 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b
++iter;
continue;
}
if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) )
if (!m_Timing->IsJudgableAtRow(iter.Row()))
{
++iter;
continue;
@@ -2118,7 +2118,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
// Stepped too close to mine?
if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) &&
fSecondsFromExact <= GetWindowSeconds(TW_Mine) &&
!m_Timing->IsWarpAtRow(iSongRow) && !m_Timing->IsFakeAtRow(iSongRow))
m_Timing->IsJudgableAtRow(iSongRow))
score = TNS_HitMine;
break;
@@ -2616,7 +2616,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
continue;
// Ignore all notes in WarpSegments or FakeSegments.
if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) )
if (!m_Timing->IsJudgableAtRow(iter.Row()))
continue;
if( tn.type == TapNote::mine )
@@ -2651,7 +2651,7 @@ void Player::UpdateJudgedRows()
int iRow = iter.Row();
// Do not judge arrows in WarpSegments or FakeSegments
if( m_Timing->IsWarpAtRow(iRow) || m_Timing->IsFakeAtRow(iRow) )
if (!m_Timing->IsJudgableAtRow(iRow))
continue;
if( iLastSeenRow != iRow )
@@ -2852,7 +2852,8 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now )
// check to see if there's a note at the crossed row
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
{
if( tn.type != TapNote::empty && tn.type != TapNote::fake && tn.result.tns == TNS_None )
if(tn.type != TapNote::empty && tn.type != TapNote::fake && tn.result.tns == TNS_None
&& this->m_Timing->IsJudgableAtRow(iRow) )
{
Step( iTrack, iRow, now, false, false );
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
@@ -2878,7 +2879,7 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now )
}
else if( CHECKPOINTS_USE_TIME_SIGNATURES )
{
TimeSignatureSegment tSignature = m_Timing->GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) );
TimeSignatureSegment & tSignature = m_Timing->GetTimeSignatureSegmentAtRow( iLastRowCrossed );
// Most songs are in 4/4 time. The frequency for checking tick counts should reflect that.
iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.GetDen() / (tSignature.GetNum() * 4);
@@ -2921,8 +2922,11 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now )
bool bHoldOverlapsRow = iFirstCheckpointOfHold <= r && r <= iLastCheckpointOfHold;
if( !bHoldOverlapsRow )
continue;
viColsWithHold.push_back( iTrack );
if( tn.HoldResult.fLife > 0 )
{
++iNumHoldsHeldThisRow;
@@ -2934,6 +2938,7 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now )
++tn.HoldResult.iCheckpointsMissed;
}
}
GAMESTATE->SetProcessedTimingData(this->m_Timing);
// TODO: Find a better way of handling hold checkpoints with other taps.
if( !viColsWithHold.empty() && ( CHECKPOINTS_TAPS_SEPARATE_JUDGMENT || m_NoteData.GetNumTapNotesInRow( iLastRowCrossed ) == 0 ) )
@@ -2990,7 +2995,7 @@ void Player::HandleTapRowScore( unsigned row )
#endif
// Do not score rows in WarpSegments or FakeSegments
if( m_Timing->IsWarpAtRow( row ) || m_Timing->IsFakeAtRow( row ) )
if (!m_Timing->IsJudgableAtRow(row))
return;
if( GAMESTATE->m_bDemonstrationOrJukebox )
@@ -3094,7 +3099,7 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH
#endif
// WarpSegments and FakeSegments aren't judged in any way.
if( m_Timing->IsWarpAtRow( iRow ) || m_Timing->IsFakeAtRow( iRow ) )
if (!m_Timing->IsJudgableAtRow(iRow))
return;
// don't accumulate combo if AutoPlay is on.
+1
View File
@@ -15,6 +15,7 @@
RageSoundReader_Extend::RageSoundReader_Extend( RageSoundReader *pSource ):
RageSoundReader_Filter( pSource )
{
ASSERT_M(pSource, "The music file was not found! Was it deleted or moved while the game was on?");
m_iPositionFrames = pSource->GetNextSourceFrame();
m_StopMode = M_STOP;
+6
View File
@@ -120,6 +120,7 @@ void ScoreKeeperNormal::Load(
* forced and not chosen by the user. */
NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong );
RadarValues rvPre;
GAMESTATE->SetProcessedTimingData(&pSteps->m_Timing);
NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre );
/* Apply user transforms to find out how the notes will really look.
@@ -132,6 +133,7 @@ void ScoreKeeperNormal::Load(
NoteDataUtil::TransformNoteData( nd, m_pPlayerState->m_PlayerOptions.GetStage(), pSteps->m_StepsType );
RadarValues rvPost;
NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPost );
GAMESTATE->SetProcessedTimingData(NULL);
iTotalPossibleDancePoints += this->GetPossibleDancePoints( rvPre, rvPost );
iTotalPossibleGradePoints += this->GetPossibleGradePoints( rvPre, rvPost );
@@ -217,6 +219,8 @@ void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps,
ASSERT( m_iMaxPossiblePoints >= 0 );
m_iMaxScoreSoFar += m_iMaxPossiblePoints;
GAMESTATE->SetProcessedTimingData(const_cast<TimingData *>(&pSteps->m_Timing));
m_iNumTapsAndHolds = pNoteData->GetNumRowsWithTapOrHoldHead() + pNoteData->GetNumHoldNotes()
+ pNoteData->GetNumRolls();
@@ -230,6 +234,8 @@ void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps,
ASSERT( m_iPointBonus >= 0 );
m_iTapNotesHit = 0;
GAMESTATE->SetProcessedTimingData(NULL);
}
static int GetScore(int p, int Z, int S, int n)
+343 -250
View File
@@ -61,6 +61,7 @@ const float RECORD_HOLD_SECONDS = 0.3f;
AutoScreenMessage( SM_UpdateTextInfo );
AutoScreenMessage( SM_BackFromMainMenu );
AutoScreenMessage( SM_BackFromAreaMenu );
AutoScreenMessage( SM_BackFromAlterMenu );
AutoScreenMessage( SM_BackFromStepsInformation );
AutoScreenMessage( SM_BackFromOptions );
AutoScreenMessage( SM_BackFromSongInformation );
@@ -170,6 +171,7 @@ void ScreenEdit::InitEditMappings()
m_EditMappingsMenuButton.button [EDIT_BUTTON_OPEN_EDIT_MENU][0] = GAME_BUTTON_START;
m_EditMappingsMenuButton.button [EDIT_BUTTON_OPEN_EDIT_MENU][1] = GAME_BUTTON_BACK;
// Escape, Enter = exit play/record
m_PlayMappingsDeviceInput.button [EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER);
m_PlayMappingsDeviceInput.button [EDIT_BUTTON_RETURN_TO_EDIT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC);
@@ -280,6 +282,7 @@ void ScreenEdit::InitEditMappings()
m_EditMappingsMenuButton.button[EDIT_BUTTON_OPEN_EDIT_MENU][0] = GAME_BUTTON_START;
m_EditMappingsMenuButton.button[EDIT_BUTTON_OPEN_EDIT_MENU][1] = GAME_BUTTON_BACK;
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_AREA_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_ALTER_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Ca);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_INPUT_HELP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F1);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cb);
@@ -505,27 +508,58 @@ static MenuDef g_MainMenu(
MenuRowDef( ScreenEdit::exit, "Exit Edit Mode", true, EditMode_Practice, true, true, 0, NULL )
);
static MenuDef g_AlterMenu(
"ScreenMiniMenuAlterMenu",
MenuRowDef(ScreenEdit::cut, "Cut", true,
EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::copy, "Copy", true,
EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::clear, "Clear area", true,
EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::quantize, "Quantize", true,
EditMode_Practice, true, true, 0,
"4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
MenuRowDef(ScreenEdit::turn, "Turn", true,
EditMode_Practice, true, true, 0, "Left","Right","Mirror","Shuffle","SuperShuffle" ),
MenuRowDef(ScreenEdit::transform, "Transform", true,
EditMode_Practice, true, true, 0, "NoHolds","NoMines","Little","Wide",
"Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored",
"Twister","NoJumps","NoHands","NoQuads","NoStretch" ),
MenuRowDef(ScreenEdit::alter, "Alter", true,
EditMode_Practice, true, true, 0, "Autogen To Fill Width","Backwards","Swap Sides",
"Copy Left To Right","Copy Right To Left","Clear Left","Clear Right",
"Collapse To One","Collapse Left","Shift Left","Shift Right" ),
MenuRowDef(ScreenEdit::tempo, "Tempo", true,
EditMode_Full, true, true, 0, "Compress 2x","Compress 3->2",
"Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
MenuRowDef(ScreenEdit::play, "Play selection", true,
EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::record, "Record in selection", true,
EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_to_pause, "Convert selection to pause", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_to_delay, "Convert selection to delay", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_to_warp, "Convert selection to warp", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_to_fake, "Convert selection to fake", true,
EditMode_Full, true, true, 0, NULL )
);
static MenuDef g_AreaMenu(
"ScreenMiniMenuAreaMenu",
MenuRowDef( ScreenEdit::cut, "Cut", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::copy, "Copy", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::paste_at_current_beat, "Paste at current beat", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::paste_at_begin_marker, "Paste at begin marker", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::clear, "Clear area", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::quantize, "Quantize", true, EditMode_Practice, true, true, 0, "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
MenuRowDef( ScreenEdit::turn, "Turn", true, EditMode_Practice, true, true, 0, "Left","Right","Mirror","Shuffle","SuperShuffle" ),
MenuRowDef( ScreenEdit::transform, "Transform", true, EditMode_Practice, true, true, 0, "NoHolds","NoMines","Little","Wide","Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored","Twister","NoJumps","NoHands","NoQuads","NoStretch" ),
MenuRowDef( ScreenEdit::alter, "Alter", true, EditMode_Practice, true, true, 0, "Autogen To Fill Width","Backwards","Swap Sides","Copy Left To Right","Copy Right To Left","Clear Left","Clear Right","Collapse To One","Collapse Left","Shift Left","Shift Right" ),
MenuRowDef( ScreenEdit::tempo, "Tempo", true, EditMode_Full, true, true, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
MenuRowDef( ScreenEdit::play, "Play selection", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::record, "Record in selection", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::insert_and_shift, "Insert beat and shift down", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::delete_and_shift, "Delete beat and shift up", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::shift_pauses_forward, "Shift all timing changes down", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::shift_pauses_backward, "Shift all timing changes up", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::convert_to_pause, "Convert selection to pause", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::undo, "Undo", true, EditMode_Practice, true, true, 0, NULL )
MenuRowDef(ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::undo, "Undo", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::clear_clipboard, "Clear clipboard", true,
EditMode_Practice, true, true, 0, NULL )
);
static MenuDef g_StepsInformation(
@@ -1152,6 +1186,9 @@ void ScreenEdit::UpdateTextInfo()
sText += ssprintf( TAP_NOTE_TYPE_FORMAT.GetValue(), TAP_NOTE_TYPE.GetValue().c_str(), TapNoteTypeToString( m_selectedTap.type ).c_str() );
break;
}
GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing);
sText += ssprintf( NUM_STEPS_FORMAT.GetValue(), TAP_STEPS.GetValue().c_str(), m_NoteDataEdit.GetNumTapNotes() );
sText += ssprintf( NUM_JUMPS_FORMAT.GetValue(), JUMPS.GetValue().c_str(), m_NoteDataEdit.GetNumJumps() );
sText += ssprintf( NUM_HANDS_FORMAT.GetValue(), HANDS.GetValue().c_str(), m_NoteDataEdit.GetNumHands() );
@@ -1182,6 +1219,8 @@ void ScreenEdit::UpdateTextInfo()
}
m_textInfo.SetText( sText );
GAMESTATE->SetProcessedTimingData(NULL);
}
void ScreenEdit::DrawPrimitives()
@@ -1294,7 +1333,7 @@ static int FindAttackAtTime( const AttackArray& attacks, float fStartTime )
}
static LocalizedString BG_CHANGE_STEP_TIMING ( "ScreenEdit", "You must be in Song Timing Mode to edit BG Changes." );
static LocalizedString ALTER_MENU_NO_SELECTION ( "ScreenEdit", "You must have an area selected to enter the Alter Menu." );
static LocalizedString SWITCHED_TO ( "ScreenEdit", "Switched to" );
static LocalizedString NO_BACKGROUNDS_AVAILABLE ( "ScreenEdit", "No backgrounds available" );
static ThemeMetric<bool> INVERT_SCROLL_BUTTONS ( "ScreenEdit", "InvertScrollSpeedButtons" );
@@ -1556,24 +1595,27 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
case EDIT_BUTTON_OPEN_AREA_MENU:
{
// update enabled/disabled in g_AreaMenu
bool bAreaSelected = m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1;
g_AreaMenu.rows[cut].bEnabled = bAreaSelected;
g_AreaMenu.rows[copy].bEnabled = bAreaSelected;
g_AreaMenu.rows[paste_at_current_beat].bEnabled = !m_Clipboard.IsEmpty();
g_AreaMenu.rows[paste_at_begin_marker].bEnabled = !m_Clipboard.IsEmpty() != 0 && m_NoteFieldEdit.m_iBeginMarker!=-1;
g_AreaMenu.rows[clear].bEnabled = bAreaSelected;
g_AreaMenu.rows[quantize].bEnabled = bAreaSelected;
g_AreaMenu.rows[turn].bEnabled = bAreaSelected;
g_AreaMenu.rows[transform].bEnabled = bAreaSelected;
g_AreaMenu.rows[alter].bEnabled = bAreaSelected;
g_AreaMenu.rows[tempo].bEnabled = bAreaSelected;
g_AreaMenu.rows[play].bEnabled = bAreaSelected;
g_AreaMenu.rows[record].bEnabled = bAreaSelected;
g_AreaMenu.rows[convert_to_pause].bEnabled = bAreaSelected;
g_AreaMenu.rows[undo].bEnabled = m_bHasUndo;
EditMiniMenu( &g_AreaMenu, SM_BackFromAreaMenu );
}
break;
case EDIT_BUTTON_OPEN_ALTER_MENU:
{
bool bAreaSelected = m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1;
if (!bAreaSelected)
{
SCREENMAN->SystemMessage( ALTER_MENU_NO_SELECTION );
SCREENMAN->PlayInvalidSound();
}
else
{
EditMiniMenu(&g_AlterMenu, SM_BackFromAlterMenu);
}
break;
}
case EDIT_BUTTON_OPEN_EDIT_MENU:
EditMiniMenu( &g_MainMenu, SM_BackFromMainMenu );
break;
@@ -2039,7 +2081,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
case EDIT_BUTTON_RECORD_SELECTION:
if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 )
{
HandleAreaMenuChoice( record );
HandleAlterMenuChoice( record );
}
else
{
@@ -2639,6 +2681,10 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{
HandleAreaMenuChoice( (AreaMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromAlterMenu )
{
HandleAlterMenuChoice( (AlterMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromStepsInformation )
{
HandleStepsInformationChoice( (StepsInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
@@ -3237,12 +3283,13 @@ static LocalizedString SAVE_CHANGES_BEFORE_EXITING ( "ScreenEdit", "Do you want
void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAnswers )
{
GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing);
switch( c )
{
DEFAULT_FAIL( c );
case play_selection:
if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 )
HandleAreaMenuChoice( play );
HandleAlterMenuChoice( play );
else if( m_NoteFieldEdit.m_iBeginMarker!=-1 )
HandleMainMenuChoice( play_selection_start_to_end );
else
@@ -3455,36 +3502,277 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
}
break;
};
GAMESTATE->SetProcessedTimingData(NULL);
}
void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector<int> &iAnswers, bool bAllowUndo)
{
bool bSaveUndo = true;
switch (c)
{
case play:
case record:
case cut:
case copy:
{
bSaveUndo = false;
}
default:
break;
}
if( bSaveUndo )
SetDirty( true );
/* We call HandleAreaMenuChoice recursively. Only the outermost
* HandleAreaMenuChoice should allow Undo so that the inner calls don't
* also save Undo and mess up the outermost */
if( !bAllowUndo )
bSaveUndo = false;
if( bSaveUndo )
SaveUndo();
switch(c)
{
case cut:
{
HandleAlterMenuChoice( copy );
HandleAlterMenuChoice( clear );
}
break;
case copy:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_Clipboard.ClearAll();
m_Clipboard.CopyRange( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
}
break;
case clear:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
}
break;
case quantize:
{
NoteType nt = (NoteType)iAnswers[c];
NoteDataUtil::SnapToNearestNoteType(m_NoteDataEdit, nt, nt,
m_NoteFieldEdit.m_iBeginMarker,
m_NoteFieldEdit.m_iEndMarker );
break;
}
case turn:
{
const NoteData OldClipboard( m_Clipboard );
HandleAlterMenuChoice( cut );
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
TurnType tt = (TurnType)iAnswers[c];
switch( tt )
{
DEFAULT_FAIL( tt );
case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break;
case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break;
case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break;
case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break;
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break;
}
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
}
break;
case transform:
{
int iBeginRow = m_NoteFieldEdit.m_iBeginMarker;
int iEndRow = m_NoteFieldEdit.m_iEndMarker;
TransformType tt = (TransformType)iAnswers[c];
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
switch( tt )
{
DEFAULT_FAIL( tt );
case noholds: NoteDataUtil::RemoveHoldNotes( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nomines: NoteDataUtil::RemoveMines( m_NoteDataEdit, iBeginRow, iBeginRow ); break;
case little: NoteDataUtil::Little( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case wide: NoteDataUtil::Wide( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case big: NoteDataUtil::Big( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case quick: NoteDataUtil::Quick( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case skippy: NoteDataUtil::Skippy( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case add_mines: NoteDataUtil::AddMines( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case echo: NoteDataUtil::Echo( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case stomp: NoteDataUtil::Stomp( m_NoteDataEdit, st, iBeginRow, iEndRow ); break;
case planted: NoteDataUtil::Planted( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case floored: NoteDataUtil::Floored( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case twister: NoteDataUtil::Twister( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nojumps: NoteDataUtil::RemoveJumps( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nohands: NoteDataUtil::RemoveHands( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case noquads: NoteDataUtil::RemoveQuads( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nostretch: NoteDataUtil::RemoveStretch( m_NoteDataEdit, st, iBeginRow, iBeginRow );break;
}
// bake in the additions
NoteDataUtil::ConvertAdditionsToRegular( m_NoteDataEdit );
break;
}
case alter:
{
const NoteData OldClipboard( m_Clipboard );
HandleAlterMenuChoice( cut );
AlterType at = (AlterType)iAnswers[c];
switch( at )
{
DEFAULT_FAIL( at );
case autogen_to_fill_width:
{
NoteData temp( m_Clipboard );
int iMaxNonEmptyTrack = NoteDataUtil::GetMaxNonEmptyTrack( temp );
if( iMaxNonEmptyTrack == -1 )
break;
temp.SetNumTracks( iMaxNonEmptyTrack+1 );
NoteDataUtil::LoadTransformedSlidingWindow( temp, m_Clipboard, m_Clipboard.GetNumTracks() );
NoteDataUtil::RemoveStretch( m_Clipboard, GAMESTATE->m_pCurSteps[0]->m_StepsType );
}
break;
case backwards: NoteDataUtil::Backwards( m_Clipboard ); break;
case swap_sides: NoteDataUtil::SwapSides( m_Clipboard ); break;
case copy_left_to_right: NoteDataUtil::CopyLeftToRight( m_Clipboard ); break;
case copy_right_to_left: NoteDataUtil::CopyRightToLeft( m_Clipboard ); break;
case clear_left: NoteDataUtil::ClearLeft( m_Clipboard ); break;
case clear_right: NoteDataUtil::ClearRight( m_Clipboard ); break;
case collapse_to_one: NoteDataUtil::CollapseToOne( m_Clipboard ); break;
case collapse_left: NoteDataUtil::CollapseLeft( m_Clipboard ); break;
case shift_left: NoteDataUtil::ShiftLeft( m_Clipboard ); break;
case shift_right: NoteDataUtil::ShiftRight( m_Clipboard ); break;
}
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
break;
}
case tempo:
{
// This affects all steps.
AlterType at = (AlterType)iAnswers[c];
float fScale = -1;
switch( at )
{
DEFAULT_FAIL( at );
case compress_2x: fScale = 0.5f; break;
case compress_3_2: fScale = 2.0f/3; break;
case compress_4_3: fScale = 0.75f; break;
case expand_4_3: fScale = 4.0f/3; break;
case expand_3_2: fScale = 1.5f; break;
case expand_2x: fScale = 2; break;
}
int iStartIndex = m_NoteFieldEdit.m_iBeginMarker;
int iEndIndex = m_NoteFieldEdit.m_iEndMarker;
int iNewEndIndex = iEndIndex + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) );
// scale currently editing notes
NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex );
// scale timing data
GetAppropriateTiming().ScaleRegion(fScale,
m_NoteFieldEdit.m_iBeginMarker,
m_NoteFieldEdit.m_iEndMarker, true );
m_NoteFieldEdit.m_iEndMarker = iNewEndIndex;
break;
}
case play:
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker;
m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker;
TransitionEditState( STATE_PLAYING );
break;
case record:
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker;
m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker;
TransitionEditState( STATE_RECORDING );
break;
case convert_to_pause:
{
ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" );
float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) );
float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) );
// The length of the stop segment we're going to create. This includes time spent in any
// stops in the selection, which will be deleted and subsumed into the new stop.
float fStopLength = fMarkerEnd - fMarkerStart;
// be sure not to clobber the row at the start - a row at the end
// can be dropped safely, though
NoteDataUtil::DeleteRows( m_NoteDataEdit,
m_NoteFieldEdit.m_iBeginMarker + 1,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker
);
GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker );
GetAppropriateTiming().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength );
m_NoteFieldEdit.m_iBeginMarker = -1;
m_NoteFieldEdit.m_iEndMarker = -1;
break;
}
case convert_to_delay:
{
ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" );
float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) );
float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) );
// The length of the delay segment we're going to create. This includes time spent in any
// stops in the selection, which will be deleted and subsumed into the new stop.
float fStopLength = fMarkerEnd - fMarkerStart;
NoteDataUtil::DeleteRows( m_NoteDataEdit,
m_NoteFieldEdit.m_iBeginMarker,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker
);
GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker );
GetAppropriateTiming().SetDelayAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength );
m_NoteFieldEdit.m_iBeginMarker = -1;
m_NoteFieldEdit.m_iEndMarker = -1;
break;
}
case convert_to_warp:
{
float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker);
float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - startBeat;
GetAppropriateTiming().SetWarpAtBeat(startBeat,lengthBeat);
SetDirty(true);
break;
}
case convert_to_fake:
{
float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker);
float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - startBeat;
GetAppropriateTiming().SetFakeAtBeat(startBeat,lengthBeat);
SetDirty(true);
break;
}
}
}
void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAnswers, bool bAllowUndo )
{
bool bSaveUndo = false;
bool bSaveUndo = true;
switch( c )
{
DEFAULT_FAIL( c );
case cut:
case copy:
case play:
case record:
case clear_clipboard:
case undo:
bSaveUndo = false;
break;
case paste_at_current_beat:
case paste_at_begin_marker:
case clear:
case quantize:
case turn:
case transform:
case alter:
case tempo:
case insert_and_shift:
case delete_and_shift:
case shift_pauses_forward:
case shift_pauses_backward:
case convert_to_pause:
case convert_pause_to_beat:
bSaveUndo = true;
default:
break;
}
@@ -3503,19 +3791,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
switch( c )
{
DEFAULT_FAIL( c );
case cut:
{
HandleAreaMenuChoice( copy );
HandleAreaMenuChoice( clear );
}
break;
case copy:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_Clipboard.ClearAll();
m_Clipboard.CopyRange( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
}
break;
case paste_at_current_beat:
case paste_at_begin_marker:
{
@@ -3536,172 +3812,6 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
m_NoteDataEdit.CopyRange( m_Clipboard, 0, iRowsToCopy, iDestFirstRow );
}
break;
case clear:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
}
break;
case quantize:
{
NoteType nt = (NoteType)iAnswers[c];
NoteDataUtil::SnapToNearestNoteType( m_NoteDataEdit, nt, nt, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
}
break;
case turn:
{
const NoteData OldClipboard( m_Clipboard );
HandleAreaMenuChoice( cut );
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
TurnType tt = (TurnType)iAnswers[c];
switch( tt )
{
DEFAULT_FAIL( tt );
case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break;
case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break;
case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break;
case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break;
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break;
}
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
}
break;
case transform:
{
int iBeginRow = m_NoteFieldEdit.m_iBeginMarker;
int iEndRow = m_NoteFieldEdit.m_iEndMarker;
TransformType tt = (TransformType)iAnswers[c];
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
switch( tt )
{
DEFAULT_FAIL( tt );
case noholds: NoteDataUtil::RemoveHoldNotes( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nomines: NoteDataUtil::RemoveMines( m_NoteDataEdit, iBeginRow, iBeginRow ); break;
case little: NoteDataUtil::Little( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case wide: NoteDataUtil::Wide( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case big: NoteDataUtil::Big( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case quick: NoteDataUtil::Quick( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case skippy: NoteDataUtil::Skippy( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case add_mines: NoteDataUtil::AddMines( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case echo: NoteDataUtil::Echo( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case stomp: NoteDataUtil::Stomp( m_NoteDataEdit, st, iBeginRow, iEndRow ); break;
case planted: NoteDataUtil::Planted( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case floored: NoteDataUtil::Floored( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case twister: NoteDataUtil::Twister( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nojumps: NoteDataUtil::RemoveJumps( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nohands: NoteDataUtil::RemoveHands( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case noquads: NoteDataUtil::RemoveQuads( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nostretch: NoteDataUtil::RemoveStretch( m_NoteDataEdit, st, iBeginRow, iBeginRow );break;
}
// bake in the additions
NoteDataUtil::ConvertAdditionsToRegular( m_NoteDataEdit );
}
break;
case alter:
{
const NoteData OldClipboard( m_Clipboard );
HandleAreaMenuChoice( cut );
AlterType at = (AlterType)iAnswers[c];
switch( at )
{
DEFAULT_FAIL( at );
case autogen_to_fill_width:
{
NoteData temp( m_Clipboard );
int iMaxNonEmptyTrack = NoteDataUtil::GetMaxNonEmptyTrack( temp );
if( iMaxNonEmptyTrack == -1 )
break;
temp.SetNumTracks( iMaxNonEmptyTrack+1 );
NoteDataUtil::LoadTransformedSlidingWindow( temp, m_Clipboard, m_Clipboard.GetNumTracks() );
NoteDataUtil::RemoveStretch( m_Clipboard, GAMESTATE->m_pCurSteps[0]->m_StepsType );
}
break;
case backwards: NoteDataUtil::Backwards( m_Clipboard ); break;
case swap_sides: NoteDataUtil::SwapSides( m_Clipboard ); break;
case copy_left_to_right: NoteDataUtil::CopyLeftToRight( m_Clipboard ); break;
case copy_right_to_left: NoteDataUtil::CopyRightToLeft( m_Clipboard ); break;
case clear_left: NoteDataUtil::ClearLeft( m_Clipboard ); break;
case clear_right: NoteDataUtil::ClearRight( m_Clipboard ); break;
case collapse_to_one: NoteDataUtil::CollapseToOne( m_Clipboard ); break;
case collapse_left: NoteDataUtil::CollapseLeft( m_Clipboard ); break;
case shift_left: NoteDataUtil::ShiftLeft( m_Clipboard ); break;
case shift_right: NoteDataUtil::ShiftRight( m_Clipboard ); break;
}
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
}
break;
case tempo:
{
// This affects all steps.
AlterType at = (AlterType)iAnswers[c];
float fScale = -1;
switch( at )
{
DEFAULT_FAIL( at );
case compress_2x: fScale = 0.5f; break;
case compress_3_2: fScale = 2.0f/3; break;
case compress_4_3: fScale = 0.75f; break;
case expand_4_3: fScale = 4.0f/3; break;
case expand_3_2: fScale = 1.5f; break;
case expand_2x: fScale = 2; break;
}
int iStartIndex = m_NoteFieldEdit.m_iBeginMarker;
int iEndIndex = m_NoteFieldEdit.m_iEndMarker;
int iNewEndIndex = iEndIndex + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) );
// scale currently editing notes
NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex );
// scale timing data
GetAppropriateTiming().ScaleRegion( fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, true );
// scale all other steps.
/*
const vector<Steps*> sIter = m_pSong->GetAllSteps();
RString sTempStyle, sTempDiff;
for( unsigned i = 0; i < sIter.size(); i++ )
{
if( sIter[i]->IsAutogen() )
continue;
// XXX: Edits are distinguished by description.
// Compare vs m_pSteps.
if( (sIter[i]->m_StepsType == GAMESTATE->m_pCurSteps[PLAYER_1]->m_StepsType) &&
(sIter[i]->GetDifficulty() == GAMESTATE->m_pCurSteps[PLAYER_1]->GetDifficulty()) )
continue;
NoteData ndTemp;
sIter[i]->GetNoteData( ndTemp );
NoteDataUtil::ScaleRegion( ndTemp, fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
sIter[i]->SetNoteData( ndTemp );
}
*/
m_NoteFieldEdit.m_iEndMarker = iNewEndIndex;
}
break;
case play:
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker;
m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker;
TransitionEditState( STATE_PLAYING );
break;
case record:
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker;
m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker;
TransitionEditState( STATE_RECORDING );
break;
case insert_and_shift:
NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow( GetBeat() ), BeatToNoteRow(1) );
break;
@@ -3714,29 +3824,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
case shift_pauses_backward:
GetAppropriateTiming().DeleteRows( GetRow() + 1, BeatToNoteRow(1) );
break;
case convert_to_pause:
{
ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" );
float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) );
float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) );
// The length of the stop segment we're going to create. This includes time spent in any
// stops in the selection, which will be deleted and subsumed into the new stop.
float fStopLength = fMarkerEnd - fMarkerStart;
// be sure not to clobber the row at the start - a row at the end
// can be dropped safely, though
NoteDataUtil::DeleteRows( m_NoteDataEdit,
m_NoteFieldEdit.m_iBeginMarker + 1,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker
);
GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1,
m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker );
GetAppropriateTiming().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength );
m_NoteFieldEdit.m_iBeginMarker = -1;
m_NoteFieldEdit.m_iEndMarker = -1;
break;
}
case convert_pause_to_beat:
{
// TODO: Convert both Delays and Stops at once.
@@ -3753,6 +3841,11 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
case undo:
Undo();
break;
case clear_clipboard:
{
m_Clipboard.ClearAll();
break;
}
};
if( bSaveUndo )
+41 -9
View File
@@ -87,6 +87,7 @@ enum EditButton
EDIT_BUTTON_OPEN_EDIT_MENU,
EDIT_BUTTON_OPEN_TIMING_MENU,
EDIT_BUTTON_OPEN_ALTER_MENU,
EDIT_BUTTON_OPEN_AREA_MENU,
EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU,
EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU,
@@ -209,7 +210,12 @@ public:
virtual void PushSelf( lua_State *L );
protected:
virtual ScreenType GetScreenType() const { return m_EditState==STATE_PLAYING ? gameplay : ScreenWithMenuElements::GetScreenType(); }
virtual ScreenType GetScreenType() const
{
return m_EditState==STATE_PLAYING ?
gameplay :
ScreenWithMenuElements::GetScreenType();
}
void TransitionEditState( EditState em );
void ScrollTo( float fDestinationBeat );
@@ -268,7 +274,8 @@ protected:
BitmapText m_textPlayRecordHelp;
// keep track of where we are and what we're doing
float m_fTrailingBeat; // this approaches GAMESTATE->m_fSongBeat, which is the actual beat
float m_fTrailingBeat;
// the above approaches GAMESTATE->m_fSongBeat, which is the actual beat
/**
* @brief The location we were at when shift was pressed.
*
@@ -365,12 +372,10 @@ public:
void HandleMainMenuChoice( MainMenuChoice c ) { const vector<int> v; HandleMainMenuChoice( c, v ); }
MainMenuChoice m_CurrentAction;
enum AreaMenuChoice
enum AlterMenuChoice
{
cut,
copy,
paste_at_current_beat,
paste_at_begin_marker,
clear,
quantize,
turn,
@@ -379,17 +384,41 @@ public:
tempo,
play,
record,
convert_to_pause,
convert_to_delay,
convert_to_warp,
convert_to_fake,
NUM_ALTER_MENU_CHOICES
};
enum AreaMenuChoice
{
paste_at_current_beat,
paste_at_begin_marker,
insert_and_shift,
delete_and_shift,
shift_pauses_forward,
shift_pauses_backward,
convert_to_pause,
convert_pause_to_beat,
undo,
clear_clipboard,
NUM_AREA_MENU_CHOICES
};
void HandleAlterMenuChoice(AlterMenuChoice c,
const vector<int> &iAnswers,
bool bAllowUndo = true);
void HandleAlterMenuChoice(AlterMenuChoice c,
bool bAllowUndo = true)
{
const vector<int> v; HandleAlterMenuChoice(c, v, bAllowUndo);
}
void HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAnswers, bool bAllowUndo = true );
void HandleAreaMenuChoice( AreaMenuChoice c, bool bAllowUndo = true ) { const vector<int> v; HandleAreaMenuChoice( c, v, bAllowUndo ); }
void HandleAreaMenuChoice( AreaMenuChoice c, bool bAllowUndo = true )
{
const vector<int> v; HandleAreaMenuChoice( c, v, bAllowUndo );
}
/** @brief How should the selected notes be transformed? */
enum TurnType
{
@@ -511,7 +540,8 @@ public:
NUM_TIMING_DATA_INFORMATION_CHOICES
};
void HandleTimingDataInformationChoice ( TimingDataInformationChoice c, const vector<int> &iAnswers );
void HandleTimingDataInformationChoice (TimingDataInformationChoice c,
const vector<int> &iAnswers );
enum BGChangeChoice
{
@@ -581,7 +611,9 @@ public:
MapEditButtonToMenuButton m_RecordPausedMappingsMenuButton;
void MakeFilteredMenuDef( const MenuDef* pDef, MenuDef &menu );
void EditMiniMenu( const MenuDef* pDef, ScreenMessage SM_SendOnOK = SM_None, ScreenMessage SM_SendOnCancel = SM_None );
void EditMiniMenu(const MenuDef* pDef,
ScreenMessage SM_SendOnOK = SM_None,
ScreenMessage SM_SendOnCancel = SM_None );
private:
/**
* @brief Retrieve the appropriate TimingData based on GAMESTATE.
+3 -1
View File
@@ -2294,12 +2294,14 @@ void ScreenGameplay::SaveStats()
RadarValues rv;
PlayerStageStats &pss = *pi->GetPlayerStageStats();
const NoteData &nd = pi->m_pPlayer->GetNoteData();
PlayerNumber pn = pi->m_pn;
GAMESTATE->SetProcessedTimingData(&GAMESTATE->m_pCurSteps[pn]->m_Timing);
NoteDataUtil::CalculateRadarValues( nd, fMusicLen, rv );
pss.m_radarPossible += rv;
NoteDataWithScoring::GetActualRadarValues( nd, pss, fMusicLen, rv );
pss.m_radarActual += rv;
GAMESTATE->SetProcessedTimingData(NULL);
}
}
+4 -2
View File
@@ -21,10 +21,12 @@ void ScreenGameplaySyncMachine::Init()
RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music");
// Allow themers to use either a .ssc or .sm file for this. -aj
SSCLoader loaderSSC;
SMLoader loaderSM;
if(sFile.Right(4) == ".ssc")
SSCLoader::LoadFromSSCFile( sFile, m_Song );
loaderSSC.LoadFromSimfile( sFile, m_Song );
else
SMLoader::LoadFromSMFile( sFile, m_Song );
loaderSM.LoadFromSimfile( sFile, m_Song );
m_Song.SetSongDir( Dirname(sFile) );
m_Song.TidyUpData();
+4 -2
View File
@@ -135,10 +135,12 @@ void ScreenHowToPlay::Init()
// Allow themers to use either a .ssc or .sm file for this. -aj
RString sStepsPath = THEME->GetPathO(m_sName, "steps");
SSCLoader loaderSSC;
SMLoader loaderSM;
if( sStepsPath.Right(4) == ".ssc" )
SSCLoader::LoadFromSSCFile( sStepsPath, m_Song, false );
loaderSSC.LoadFromSimfile( sStepsPath, m_Song, false );
else
SMLoader::LoadFromSMFile( sStepsPath, m_Song, false );
loaderSM.LoadFromSimfile( sStepsPath, m_Song, false );
m_Song.AddAutoGenNotes();
const Style* pStyle = GAMESTATE->GetCurrentStyle();
+1 -1
View File
@@ -145,7 +145,7 @@ void ScreenOptionsEditCourse::Init()
sc.m_Tutorial = SongCriteria::Tutorial_No;
sc.m_Locked = SongCriteria::Locked_Unlocked;
SongUtil::FilterSongs( sc, SONGMAN->GetAllSongs(), m_vpSongs );
SongUtil::FilterSongs( sc, SONGMAN->GetAllSongs(), m_vpSongs, true );
SongUtil::SortSongPointerArrayByTitle( m_vpSongs );
}
+3
View File
@@ -1,4 +1,6 @@
#include "global.h"
#if !defined(WITHOUT_NETWORKING)
#include "ScreenPackagesSSC.h"
#include "ThemeManager.h"
#include "RageDisplay.h"
@@ -50,6 +52,7 @@ RString ScreenPackagesSSC::JSONParse( const RString &string_in )
return "";
}
#endif
/*
* (c) 2009 Colby Klein
* All rights reserved.
+3
View File
@@ -7,6 +7,8 @@
#include "RageFileManager.h"
#include "RageFile.h"
#include "Sprite.h"
#if !defined(WITHOUT_NETWORKING)
/** @brief Parses JSON for downloadable content. */
class ScreenPackagesSSC : public ScreenWithMenuElements
{
@@ -24,6 +26,7 @@ public:
private:
RString JSONParse( const RString &string_in );
};
#endif // WITHOUT_NETWORKING?
#endif
+2 -1
View File
@@ -197,7 +197,8 @@ 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( !SSCLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
SSCLoader loaderSSC;
if( !loaderSSC.LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) )
{
iNumIgnored++;
continue;
+7
View File
@@ -253,7 +253,14 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input )
case ChangeSongOffset:
if( GAMESTATE->m_pCurSong != NULL )
{
GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fDelta;
const vector<Steps *>& vpSteps = GAMESTATE->m_pCurSong->GetAllSteps();
FOREACH( Steps*, const_cast<vector<Steps *>&>(vpSteps), s )
{
(*s)->m_Timing.m_fBeat0OffsetInSeconds += fDelta;
}
}
break;
}
}
+10 -7
View File
@@ -41,7 +41,7 @@
* @brief The internal version of the cache for StepMania.
*
* Increment this value to invalidate the current cache. */
const int FILE_CACHE_VERSION = 179;
const int FILE_CACHE_VERSION = 180;
/** @brief How long does a song sample last by default? */
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
@@ -235,12 +235,14 @@ bool Song::LoadFromSongDir( RString sDir )
if( bUseCache )
{
// LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() );
bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile( sCacheFilePath, *this, true );
SSCLoader loaderSSC;
bool bLoadedFromSSC = loaderSSC.LoadFromSimfile( sCacheFilePath, *this, true );
if( !bLoadedFromSSC )
{
// load from .sm
SMLoader::LoadFromSMFile( sCacheFilePath, *this, true );
SMLoader::TidyUpData( *this, true );
SMLoader loaderSM;
loaderSM.LoadFromSimfile( sCacheFilePath, *this, true );
loaderSM.TidyUpData( *this, true );
}
}
else
@@ -1502,9 +1504,10 @@ public:
static int GetBackgroundPath( T* p, lua_State *L )
{
RString s = p->GetBackgroundPath();
if( s.empty() )
s = "";
lua_pushstring(L, s);
if( !s.empty() )
lua_pushstring(L, s);
else
lua_pushnil(L);
return 1;
}
static int GetCDTitlePath( T* p, lua_State *L ) { RString s = p->GetCDTitlePath(); if( s.empty() ) return 0; LuaHelpers::Push(L, s); return 1; }
+6 -3
View File
@@ -1692,12 +1692,15 @@ void SongManager::LoadStepEditsFromProfileDir( const RString &sProfileDir, Profi
for( int i=0; i<size; i++ )
{
RString fn = vsFiles[i];
bool bLoadedFromSSC = SSCLoader::LoadEditFromFile( fn, slot, true );
SSCLoader loaderSSC;
bool bLoadedFromSSC = loaderSSC.LoadEditFromFile( fn, slot, true );
// If we don't load the edit from a .ssc-style .edit, then we should
// also try the .sm-style edit file. -aj
if( !bLoadedFromSSC )
SMLoader::LoadEditFromFile( fn, slot, true );
{
SMLoader loaderSM;
loaderSM.LoadEditFromFile( fn, slot, true );
}
}
}
}
+19 -2
View File
@@ -871,13 +871,15 @@ void SongUtil::GetAllSongGenres( vector<RString> &vsOut )
}
}
void SongUtil::FilterSongs( const SongCriteria &sc, const vector<Song*> &in, vector<Song*> &out )
void SongUtil::FilterSongs( const SongCriteria &sc, const vector<Song*> &in,
vector<Song*> &out, bool doCareAboutGame )
{
out.reserve( in.size() );
FOREACH_CONST( Song*, in, s )
{
if( sc.Matches( *s ) )
if( sc.Matches( *s ) && (!doCareAboutGame || IsSongPlayable(*s) ) )
{
out.push_back( *s );
}
}
@@ -963,6 +965,21 @@ bool SongUtil::IsStepsPlayable( Song *pSong, Steps *pSteps )
return find( vpSteps.begin(), vpSteps.end(), pSteps ) != vpSteps.end();
}
bool SongUtil::IsSongPlayable( Song *s )
{
const vector<Steps*> & steps = s->GetAllSteps();
// I'm sure there is a foreach loop, but I don't
FOREACH( Steps*, const_cast<vector<Steps*>&>(steps), step )
{
if (IsStepsPlayable(s, *step))
{
return true;
}
}
return false;
}
bool SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &stOut, Difficulty &dcOut )
{
switch( so )
+14 -1
View File
@@ -163,12 +163,25 @@ namespace SongUtil
bool ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut );
void GetAllSongGenres( vector<RString> &vsOut );
void FilterSongs( const SongCriteria &sc, const vector<Song*> &in, vector<Song*> &out );
/**
* @brief Filter the selection of songs to only match certain criteria.
* @param sc the intended song criteria.
* @param in the starting batch of songs.
* @param out the resulting batch.
* @param doCareAboutGame a flag to see if we should only get playable steps. */
void FilterSongs( const SongCriteria &sc, const vector<Song*> &in, vector<Song*> &out,
bool doCareAboutGame = false );
void GetPlayableStepsTypes( const Song *pSong, set<StepsType> &vOut );
void GetPlayableSteps( const Song *pSong, vector<Steps*> &vOut );
bool IsStepsTypePlayable( Song *pSong, StepsType st );
bool IsStepsPlayable( Song *pSong, Steps *pSteps );
/**
* @brief Determine if the song has any playable steps in the present game.
* @param s the current song.
* @return true if the song has playable steps, false otherwise. */
bool IsSongPlayable( Song *s );
bool GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &st, Difficulty &dc );
}
+7 -2
View File
@@ -14,6 +14,7 @@
#include "global.h"
#include "Steps.h"
#include "StepsUtil.h"
#include "GameState.h"
#include "Song.h"
#include "RageUtil.h"
#include "RageLog.h"
@@ -192,6 +193,7 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds )
FOREACH_PlayerNumber( pn )
m_CachedRadarValues[pn].Zero();
GAMESTATE->SetProcessedTimingData(&this->m_Timing);
if( tempNoteData.IsComposite() )
{
vector<NoteData> vParts;
@@ -205,6 +207,7 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds )
NoteDataUtil::CalculateRadarValues( tempNoteData, fMusicLengthSeconds, m_CachedRadarValues[0] );
fill_n( m_CachedRadarValues + 1, NUM_PLAYERS-1, m_CachedRadarValues[0] );
}
GAMESTATE->SetProcessedTimingData(NULL);
}
void Steps::Decompress() const
@@ -239,11 +242,13 @@ void Steps::Decompress() const
{
// We have data on disk and not in memory. Load it.
Song s;
bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile(m_sFilename, s, true);
SSCLoader loaderSSC;
bool bLoadedFromSSC = loaderSSC.LoadFromSimfile(m_sFilename, s, true);
if( !bLoadedFromSSC )
{
// try reading from .sm instead
if( !SMLoader::LoadFromSMFile(m_sFilename, s, true) )
SMLoader loaderSM;
if( !loaderSM.LoadFromSimfile(m_sFilename, s, true) )
{
LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() );
return;
+1 -1
View File
@@ -1746,7 +1746,7 @@ public:
LuaHelpers::CreateTableFromArray(fBPMs, L);
return 1;
}
static int HasNegativeBPMs( T* p, lua_State *L ) { lua_pushboolean(L, p->m_bHasNegativeBpms); return 1; }
static int HasNegativeBPMs( T* p, lua_State *L ) { lua_pushboolean(L, p->HasWarps()); return 1; }
// formerly in Song.cpp in sm-ssc private beta 1.x:
static int GetBPMAtBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBPMAtBeat(FArg(1))); return 1; }
static int GetBeatFromElapsedTime( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBeatFromElapsedTime(FArg(1))); return 1; }
+14
View File
@@ -845,6 +845,20 @@ public:
*/
void AddFakeSegment( const FakeSegment &seg );
/**
* @brief Determine if this notes on this row can be judged.
* @param row the row to focus on.
* @return true if the row can be judged, false otherwise. */
bool IsJudgableAtRow( int row ) const
{
return !(IsWarpAtRow(row) || IsFakeAtRow(row));
}
/**
* @brief Determine if this notes on this beat can be judged.
* @param beat the beat to focus on.
* @return true if the row can be judged, false otherwise. */
bool IsJudgableAtBeat( float beat ) const { return IsJudgableAtRow( BeatToNoteRow( beat ) ); }
void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor );
+3
View File
@@ -1,6 +1,7 @@
#include "global.h"
#include "Trail.h"
#include "Foreach.h"
#include "GameState.h"
#include "Steps.h"
#include "Song.h"
#include "PlayerOptions.h"
@@ -116,6 +117,7 @@ const RadarValues &Trail::GetRadarValues() const
NoteData nd;
pSteps->GetNoteData( nd );
RadarValues rv_orig;
GAMESTATE->SetProcessedTimingData(const_cast<TimingData *>(&pSteps->m_Timing));
NoteDataUtil::CalculateRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv_orig );
PlayerOptions po;
po.FromString( e->Modifiers );
@@ -124,6 +126,7 @@ const RadarValues &Trail::GetRadarValues() const
NoteDataUtil::TransformNoteData( nd, e->Attacks, pSteps->m_StepsType, e->pSong );
RadarValues transformed_rv;
NoteDataUtil::CalculateRadarValues( nd, e->pSong->m_fMusicLengthSeconds, transformed_rv );
GAMESTATE->SetProcessedTimingData(NULL);
rv += transformed_rv;
}
else