[splittiming -> default] Bring it in.
Any bugs left in here will be fixed as a team. Now let's kick some StepMania 5 booty!
This commit is contained in:
@@ -64,6 +64,7 @@ lib*_link.a
|
|||||||
Data/UserPrefs
|
Data/UserPrefs
|
||||||
Data/uPrefs
|
Data/uPrefs
|
||||||
Data/GamePrefs/*.cfg
|
Data/GamePrefs/*.cfg
|
||||||
|
Data/Static.ini
|
||||||
PBProject/Hardware.plist
|
PBProject/Hardware.plist
|
||||||
Themes/pump
|
Themes/pump
|
||||||
Themes/optical-release
|
Themes/optical-release
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ change to JSON, but it is unsure if this will be done.
|
|||||||
Implement .ssc at your own risk.
|
Implement .ssc at your own risk.
|
||||||
________________________________________________________________________________
|
________________________________________________________________________________
|
||||||
|
|
||||||
|
[v0.7] - theDtTvB, Wolfman2000
|
||||||
|
* Split Timing officially implemented.
|
||||||
|
* #SPEEDS tag for modified scroll speeds.
|
||||||
|
* #FAKES tag for ignoring judgments within a range.
|
||||||
|
* #WARPS modified so that second parameter is now relative to the start.
|
||||||
|
|
||||||
[v0.59] - Wolfman2000
|
[v0.59] - Wolfman2000
|
||||||
* Typo fix: #RADARVALUES needed a semicolon at the end, not a colon.
|
* Typo fix: #RADARVALUES needed a semicolon at the end, not a colon.
|
||||||
|
|
||||||
|
|||||||
@@ -8,16 +8,30 @@ ________________________________________________________________________________
|
|||||||
StepMania 5.0 $NEXT | 20110xyy
|
StepMania 5.0 $NEXT | 20110xyy
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
2011/05/17
|
||||||
|
----------
|
||||||
|
* [NotesWriterSM] Write out OpenITG compatible SM files from here on out.
|
||||||
|
This includes turning Warps into Negative Stops. For those that wanted
|
||||||
|
negative BPMs specifically, my apologies, but stops are easier on math.
|
||||||
|
[Wolfman2000]
|
||||||
|
|
||||||
2011/05/16
|
2011/05/16
|
||||||
----------
|
----------
|
||||||
* [ProfileManager] Added ProfileWasLoadedFromMemoryCard(PlayerNumber)
|
* [ProfileManager] Added ProfileWasLoadedFromMemoryCard(PlayerNumber)
|
||||||
Lua binding. [AJ]
|
Lua binding. [AJ]
|
||||||
|
* Added #FAKES to the SSC format. Similar to the fake arrows, these blocks
|
||||||
|
prevent all judgments within the range. [Wolfman2000]
|
||||||
|
* Changed the syntax of #WARPS slightly. Now the second value is the relative
|
||||||
|
distance that is skipped, not the absolute value when you start hitting
|
||||||
|
arrows again. [Wolfman2000]
|
||||||
|
|
||||||
2011/05/15
|
2011/05/15
|
||||||
----------
|
----------
|
||||||
* [ScreenGameplay] Removed hardcoded commands for Debug (give up text) and
|
* [ScreenGameplay] Removed hardcoded commands for Debug (give up text) and
|
||||||
replace them with DebugStartOnCommand, DebugBackOnCommand, and
|
replace them with DebugStartOnCommand, DebugBackOnCommand, and
|
||||||
DebugTweenOffCommand. [AJ]
|
DebugTweenOffCommand. [AJ]
|
||||||
|
* Added #SPEEDS to the SSC format. This multiplies your scrolling speed during
|
||||||
|
gameplay, not replaces it (see mod attacks for replacing). [Wolfman2000]
|
||||||
|
|
||||||
2011/05/14
|
2011/05/14
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -1349,6 +1349,7 @@
|
|||||||
<Function name='GetMeter'/>
|
<Function name='GetMeter'/>
|
||||||
<Function name='GetRadarValues'/>
|
<Function name='GetRadarValues'/>
|
||||||
<Function name='GetStepsType'/>
|
<Function name='GetStepsType'/>
|
||||||
|
<Function name='HasSignificantTimingChanges'/>
|
||||||
<Function name='IsAPlayerEdit'/>
|
<Function name='IsAPlayerEdit'/>
|
||||||
<Function name='IsAnEdit'/>
|
<Function name='IsAnEdit'/>
|
||||||
<Function name='IsAutogen'/>
|
<Function name='IsAutogen'/>
|
||||||
@@ -1405,6 +1406,8 @@
|
|||||||
<Function name='HasNegativeBPMs'/>
|
<Function name='HasNegativeBPMs'/>
|
||||||
<Function name='HasStops'/>
|
<Function name='HasStops'/>
|
||||||
<Function name='HasWarps'/>
|
<Function name='HasWarps'/>
|
||||||
|
<Function name='HasFakes'/>
|
||||||
|
<Function name='HasSpeedChanges'/>
|
||||||
</Class>
|
</Class>
|
||||||
<Class name='Trail'>
|
<Class name='Trail'>
|
||||||
<Function name='GetArtists'/>
|
<Function name='GetArtists'/>
|
||||||
|
|||||||
@@ -3367,6 +3367,9 @@
|
|||||||
<Function name='GetMeter' return='int' arguments=''>
|
<Function name='GetMeter' return='int' arguments=''>
|
||||||
Returns the numerical difficulty of the Steps.
|
Returns the numerical difficulty of the Steps.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='HasSignificantTimingChanges' sm-ssc='true' return='bool' arguments=''>
|
||||||
|
Returns <code>true</code> if the song has significant timing changes.
|
||||||
|
</Function>
|
||||||
<Function name='GetRadarValues' return='RadarValues' arguments='PlayerNumber pn'>
|
<Function name='GetRadarValues' return='RadarValues' arguments='PlayerNumber pn'>
|
||||||
Returns the complete list of RadarValues for player <code>pn</code>. Use <Link class='RadarValues' function='GetValue' /> to grab a specific value.
|
Returns the complete list of RadarValues for player <code>pn</code>. Use <Link class='RadarValues' function='GetValue' /> to grab a specific value.
|
||||||
</Function>
|
</Function>
|
||||||
@@ -3515,6 +3518,12 @@
|
|||||||
<Function name='HasWarps' sm-ssc='true' return='bool' arguments=''>
|
<Function name='HasWarps' sm-ssc='true' return='bool' arguments=''>
|
||||||
Returns <code>true</code> if the TimingData contains warps.
|
Returns <code>true</code> if the TimingData contains warps.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='HasFakes' sm-ssc='true' return='bool' arguments=''>
|
||||||
|
Returns <code>true</code> if the TimingData contains fake segments.
|
||||||
|
</Function>
|
||||||
|
<Function name='HasSpeedChanges' sm-ssc='true' return='bool' arguments=''>
|
||||||
|
Returns <code>true</code> if the TimingData contains speed scrolling changes.
|
||||||
|
</Function>
|
||||||
</Class>
|
</Class>
|
||||||
<Class name='Trail'>
|
<Class name='Trail'>
|
||||||
<Function name='GetArtists' return='{string}' arguments=''>
|
<Function name='GetArtists' return='{string}' arguments=''>
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
#INSTRUMENTTRACK:;
|
#INSTRUMENTTRACK:;
|
||||||
#MUSICLENGTH:;
|
#MUSICLENGTH:;
|
||||||
#OFFSET:;
|
#OFFSET:;
|
||||||
|
#BPMS:;
|
||||||
#STOPS:;
|
#STOPS:;
|
||||||
#DELAYS:;
|
#DELAYS:;
|
||||||
#BPMS:;
|
#LABELS:;
|
||||||
#TIMESIGNATURES:;
|
#TIMESIGNATURES:;
|
||||||
#LASTBEATHINT:;
|
#LASTBEATHINT:;
|
||||||
#SAMPLESTART:;
|
#SAMPLESTART:;
|
||||||
@@ -43,17 +44,24 @@
|
|||||||
// information from #NOTES moved here
|
// information from #NOTES moved here
|
||||||
#STEPSTYPE:;
|
#STEPSTYPE:;
|
||||||
#DESCRIPTION:;
|
#DESCRIPTION:;
|
||||||
|
#CHARTSTYLE:;
|
||||||
#DIFFICULTY:;
|
#DIFFICULTY:;
|
||||||
#METER:;
|
#METER:;
|
||||||
#RADARVALUES:;
|
#RADARVALUES:;
|
||||||
#CREDIT:;
|
#CREDIT:;
|
||||||
|
|
||||||
// steps-based timingdata
|
// steps-based timingdata
|
||||||
|
#BPMS:;
|
||||||
#STOPS:;
|
#STOPS:;
|
||||||
#DELAYS:;
|
#DELAYS:;
|
||||||
#BPMS:;
|
|
||||||
#TIMESIGNATURES:;
|
#TIMESIGNATURES:;
|
||||||
#LASTBEATHINT:;
|
#TICKCOUNTS:;
|
||||||
|
#COMBOS:;
|
||||||
|
#SPEEDS:;
|
||||||
|
#FAKES:;
|
||||||
|
#LABELS:;
|
||||||
|
#ATTACKS:; // Not yet in use.
|
||||||
|
#OFFSET:;
|
||||||
|
|
||||||
// actual step data
|
// actual step data
|
||||||
#NOTES:;
|
#NOTES:;
|
||||||
@@ -6,7 +6,7 @@ local function Beat(self)
|
|||||||
local part = beat%1
|
local part = beat%1
|
||||||
part = clamp(part,0,0.5)
|
part = clamp(part,0,0.5)
|
||||||
local eff = scale(part,0,0.5,1,0)
|
local eff = scale(part,0,0.5,1,0)
|
||||||
if (GAMESTATE:GetSongDelay() or false) and part == 0 then eff = 0 end
|
if (GAMESTATE:GetSongPosition:GetDelay() or false) and part == 0 then eff = 0 end
|
||||||
if beat < 0 then
|
if beat < 0 then
|
||||||
eff = 0
|
eff = 0
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -558,6 +558,7 @@ Baked Random=Baked Random
|
|||||||
Bar=Bar
|
Bar=Bar
|
||||||
Battery=Battery
|
Battery=Battery
|
||||||
Beat=Beat
|
Beat=Beat
|
||||||
|
Beats=Beats
|
||||||
Big=Big
|
Big=Big
|
||||||
Blind=Blind
|
Blind=Blind
|
||||||
Blink=Blink
|
Blink=Blink
|
||||||
@@ -694,6 +695,7 @@ Right=Right
|
|||||||
Roll=Roll
|
Roll=Roll
|
||||||
Romanization=Transliterate
|
Romanization=Transliterate
|
||||||
SHOW=Show
|
SHOW=Show
|
||||||
|
Seconds=Seconds
|
||||||
Select=Select
|
Select=Select
|
||||||
Servers=Servers
|
Servers=Servers
|
||||||
Shift Left=Shift Left
|
Shift Left=Shift Left
|
||||||
@@ -845,15 +847,18 @@ Exit Edit Mode=Exit Edit Mode
|
|||||||
Edit stop=Edit stop
|
Edit stop=Edit stop
|
||||||
Edit delay=Edit delay
|
Edit delay=Edit delay
|
||||||
Edit Timing Data=Edit Timing Data
|
Edit Timing Data=Edit Timing Data
|
||||||
Edit time signature=Edit time signature (not working yet)
|
Edit time signature=Edit time signature
|
||||||
Edit time signature (top)=Edit time signature (beats per measure)
|
|
||||||
Edit time signature (bottom)=Edit time signature (single beat note value)
|
|
||||||
Edit tickcount=Edit tickcount
|
Edit tickcount=Edit tickcount
|
||||||
Edit combo=Edit combo
|
Edit combo=Edit combo
|
||||||
Edit label=Edit label
|
Edit label=Edit label
|
||||||
Edit warp=Edit warp
|
Edit warp=Edit warp
|
||||||
|
Edit speed (percent)=Edit speed (percent)
|
||||||
|
Edit speed (wait)=Edit speed (length)
|
||||||
|
Edit speed (mode)=Edit speed (mode)
|
||||||
|
Edit fake=Edit fake segment
|
||||||
Editor options=Options
|
Editor options=Options
|
||||||
EditorShowBGChangesPlay=Show Backgrounds
|
EditorShowBGChangesPlay=Show Backgrounds
|
||||||
|
Erase step timing=Erase step timing
|
||||||
Effect=Effect
|
Effect=Effect
|
||||||
EnableAttackSounds=Attack Sounds
|
EnableAttackSounds=Attack Sounds
|
||||||
EnableMineHitSound=Mine Sounds
|
EnableMineHitSound=Mine Sounds
|
||||||
@@ -1217,15 +1222,19 @@ Can't undo - no undo data.=Can't undo - no undo data.
|
|||||||
Do you want to revert from disk?=Do you want to revert from disk?
|
Do you want to revert from disk?=Do you want to revert from disk?
|
||||||
Do you want to revert to your last save?=Do you want to revert to your last save?
|
Do you want to revert to your last save?=Do you want to revert to your last save?
|
||||||
Do you want to save changes before exiting?=Do you want to save changes before exiting?
|
Do you want to save changes before exiting?=Do you want to save changes before exiting?
|
||||||
Enter a new BPM value.=Enter a new BPM value.
|
Enter a new BPM value.=Enter a new BPM value.\n\nEnter the previous value to remove.
|
||||||
Enter a new Stop value.=Enter a new Stop value.
|
Enter a new Stop value.=Enter a new Stop value.\n\nType "0" to remove.
|
||||||
Enter a new Delay value.=Enter a new Delay value.
|
Enter a new Delay value.=Enter a new Delay value.\n\nType "0" to remove.
|
||||||
Enter a new Time Signature numerator value.=Enter the number of beats per measure.
|
Enter a new Time Signature.=Enter a new time signature.\nUse the format "x/y".\nEnter the previous value to remove.
|
||||||
Enter a new Time Signature denominator value.=Enter the note value that represents one beat.
|
Enter a new Tickcount value.=Enter a new Tickcount value.\n\nEnter the previous value to remove.
|
||||||
Enter a new Tickcount value.=Enter a new Tickcount value.
|
Enter a new Combo value.=Enter a new Combo value.\n\nEnter the previous value to remove.
|
||||||
Enter a new Combo value.=Enter a new Combo value.
|
Enter a new Label value.=Enter a name for this section of the chart.\n\nEnter a previously used label to remove.
|
||||||
Enter a new Label value.=Enter a name for this section of the chart.
|
Enter a new Warp value.=Enter the number of beats you will warp over.\n\nType "0" to remove this segment.
|
||||||
Enter a new Warp value.=Enter the beat you will warp to when you reach this point.
|
Enter a new Speed percent value.=Enter the ratio for speed scrolling.\nEnter the previous value to remove.\n1 is the default scroll.
|
||||||
|
Enter a new Speed wait value.=Enter how long in seconds/beats it takes to change.\n\n0 is instant.
|
||||||
|
Enter a new Speed mode value.=Enter how this segment is handled.\n\nType "0" for beats, "1" for seconds.
|
||||||
|
Enter a new Fake value.=Enter the number of beats that won't be judged.\n\nType "0" to remove this.
|
||||||
|
Are you sure you want to erase this chart's timing data?=Are you sure you want to erase this chart's timing data?
|
||||||
Enter a new artist transliteration.=Enter a new artist transliteration.
|
Enter a new artist transliteration.=Enter a new artist transliteration.
|
||||||
Enter a new artist.=Enter a new artist.
|
Enter a new artist.=Enter a new artist.
|
||||||
Enter a new genre.=Enter a new genre.
|
Enter a new genre.=Enter a new genre.
|
||||||
@@ -1246,7 +1255,7 @@ Enter a new min BPM.=Enter the minimum displayed BPM.
|
|||||||
Enter a new max BPM.=Enter the maximum 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.
|
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
|
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\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\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\nEnter:\n Area Menu\nEscape:\n Main Menu\nF4:\n Timing Menu\nF1:\n Show help\n
|
||||||
PlayRecordHelpText=Press START to end
|
PlayRecordHelpText=Press START to end
|
||||||
Save successful.=Save successful.
|
Save successful.=Save successful.
|
||||||
Saved as SM and DWI.=Saved as SM and DWI.
|
Saved as SM and DWI.=Saved as SM and DWI.
|
||||||
@@ -1257,6 +1266,7 @@ This change creates more than %d notes in a measure.=This change creates more th
|
|||||||
This change creates notes past the end of the music and is not allowed.=This change creates notes past the end of the music and is not allowed.
|
This change creates notes past the end of the music and is not allowed.=This change creates notes past the end of the music and is not allowed.
|
||||||
This will destroy all unsaved changes.=This will destroy all unsaved changes.
|
This will destroy all unsaved changes.=This will destroy all unsaved changes.
|
||||||
Undo=Undo
|
Undo=Undo
|
||||||
|
You must be in Song Timing Mode to edit BG Changes.=You must be in Song Timing Mode to edit BG Changes.
|
||||||
|
|
||||||
Current beat=Current beat
|
Current beat=Current beat
|
||||||
Current second=Current second
|
Current second=Current second
|
||||||
@@ -1276,6 +1286,9 @@ Mines=Mines
|
|||||||
Rolls=Rolls
|
Rolls=Rolls
|
||||||
Lifts=Lifts
|
Lifts=Lifts
|
||||||
Fakes=Fakes
|
Fakes=Fakes
|
||||||
|
Timing Mode=Timing Mode
|
||||||
|
Step Timing=Step Timing
|
||||||
|
Song Timing=Song Timing
|
||||||
Beat 0 offset=Beat 0 offset
|
Beat 0 offset=Beat 0 offset
|
||||||
Preview Start=Preview Start
|
Preview Start=Preview Start
|
||||||
Preview Length=Preview Length
|
Preview Length=Preview Length
|
||||||
@@ -1944,7 +1957,7 @@ Decrease/increase music offset=Decrease/increase music offset
|
|||||||
Decrease/increase sample music start=Decrease/increase sample music start
|
Decrease/increase sample music start=Decrease/increase sample music start
|
||||||
Decrease/increase sample music length=Decrease/increase sample music length
|
Decrease/increase sample music length=Decrease/increase sample music length
|
||||||
Play sample music=Play sample music
|
Play sample music=Play sample music
|
||||||
Add/Edit Background Change=Add/Edit Background Change
|
Add/Edit Background Change=Add/Edit Background Change (Song Timing Only)
|
||||||
Insert beat and shift down=Insert beat and shift down
|
Insert beat and shift down=Insert beat and shift down
|
||||||
Shift BPM changes and stops down one beat=Shift BPM changes and stops down one beat
|
Shift BPM changes and stops down one beat=Shift BPM changes and stops down one beat
|
||||||
Delete beat and shift up=Delete beat and shift up
|
Delete beat and shift up=Delete beat and shift up
|
||||||
@@ -1953,6 +1966,7 @@ Cycle between tap notes=Cycle between tap notes
|
|||||||
Lay mine=Lay mine
|
Lay mine=Lay mine
|
||||||
Lay lift=Lay lift
|
Lay lift=Lay lift
|
||||||
Add to/remove from right half=Add to/remove from right half
|
Add to/remove from right half=Add to/remove from right half
|
||||||
|
Switch Timing=Switch Timing
|
||||||
Switch player (Routine only)=Switch player (Routine only)
|
Switch player (Routine only)=Switch player (Routine only)
|
||||||
|
|
||||||
[Grade]
|
[Grade]
|
||||||
|
|||||||
@@ -64,3 +64,13 @@ end
|
|||||||
if ScreenMetric then
|
if ScreenMetric then
|
||||||
ScreenMetric = Screen.Metric
|
ScreenMetric = Screen.Metric
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--[[ GameState ]]
|
||||||
|
--Aliases for old GAMESTATE timing functions.
|
||||||
|
--These have been converted to SongPosition, but most themes still use these old functions.
|
||||||
|
|
||||||
|
function GameState:GetSongBeat() return self:GetSongPosition():GetSongBeat() end
|
||||||
|
function GameState:GetSongBeatNoOffset() return self:GetSongPosition():GetSongBeatNoOffset() end
|
||||||
|
function GameState:GetSongBPS() return self:GetSongPosition():GetCurBPS() end
|
||||||
|
function GameState:GetSongDelay() return self:GetSongPosition:GetDelay() end
|
||||||
|
function GameState:GetSongFreeze() return self:GetSongPosition:GetFreeze() end
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
MusicWheel sort
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
MusicWheel sort
|
||||||
@@ -989,6 +989,8 @@ TimeSignatureColor=color("1,0.55,0,1")
|
|||||||
TickcountColor=color("0,1,0,1")
|
TickcountColor=color("0,1,0,1")
|
||||||
ComboColor=color("0.55,1,0,1")
|
ComboColor=color("0.55,1,0,1")
|
||||||
LabelColor=color("1,0,0,1")
|
LabelColor=color("1,0,0,1")
|
||||||
|
SpeedColor=color("0.5,1,1,1")
|
||||||
|
FakeColor=color("1,1,0.5,1")
|
||||||
#
|
#
|
||||||
BPMIsLeftSide=true
|
BPMIsLeftSide=true
|
||||||
StopIsLeftSide=true
|
StopIsLeftSide=true
|
||||||
@@ -998,15 +1000,19 @@ TimeSignatureIsLeftSide=true
|
|||||||
TickcountIsLeftSide=false
|
TickcountIsLeftSide=false
|
||||||
ComboIsLeftSide=false
|
ComboIsLeftSide=false
|
||||||
LabelIsLeftSide=false
|
LabelIsLeftSide=false
|
||||||
|
SpeedIsLeftSide=false
|
||||||
|
FakeIsLeftSide=true
|
||||||
#
|
#
|
||||||
BPMOffsetX=60
|
BPMOffsetX=60
|
||||||
StopOffsetX=50
|
StopOffsetX=50
|
||||||
DelayOffsetX=120
|
DelayOffsetX=120
|
||||||
WarpOffsetX=60
|
WarpOffsetX=90
|
||||||
TimeSignatureOffsetX=30
|
TimeSignatureOffsetX=30
|
||||||
TickcountOffsetX=10
|
TickcountOffsetX=70
|
||||||
ComboOffsetX=30
|
ComboOffsetX=50
|
||||||
LabelOffsetX=80
|
LabelOffsetX=130
|
||||||
|
SpeedOffsetX=30
|
||||||
|
FakeOffsetX=90
|
||||||
|
|
||||||
[PlayerStageStats]
|
[PlayerStageStats]
|
||||||
# Original CVS Grading
|
# Original CVS Grading
|
||||||
@@ -3607,7 +3613,7 @@ TimerSeconds=-1
|
|||||||
EditModifiers="no reverse"
|
EditModifiers="no reverse"
|
||||||
EditHelpX=SCREEN_LEFT+4
|
EditHelpX=SCREEN_LEFT+4
|
||||||
EditHelpY=SCREEN_TOP+16
|
EditHelpY=SCREEN_TOP+16
|
||||||
EditHelpOnCommand=halign,0;valign,0;zoom,0.675;shadowlength,1
|
EditHelpOnCommand=halign,0;valign,0;zoom,0.5;shadowlength,1
|
||||||
InfoX=SCREEN_RIGHT-128
|
InfoX=SCREEN_RIGHT-128
|
||||||
InfoY=SCREEN_TOP+16
|
InfoY=SCREEN_TOP+16
|
||||||
InfoOnCommand=halign,0;valign,0;zoom,0.5;shadowlength,1
|
InfoOnCommand=halign,0;valign,0;zoom,0.5;shadowlength,1
|
||||||
@@ -3636,6 +3642,7 @@ NumHandsFormat="%s: %d\n"
|
|||||||
NumRollsFormat="%s: %d\n"
|
NumRollsFormat="%s: %d\n"
|
||||||
NumLiftsFormat="%s: %d\n"
|
NumLiftsFormat="%s: %d\n"
|
||||||
NumFakesFormat="%s: %d\n"
|
NumFakesFormat="%s: %d\n"
|
||||||
|
TimingModeFormat="%s:\n %s\n"
|
||||||
Beat0OffsetFormat="%s:\n %.5f secs\n"
|
Beat0OffsetFormat="%s:\n %.5f secs\n"
|
||||||
PreviewStartFormat="%s:\n %.5f secs\n"
|
PreviewStartFormat="%s:\n %.5f secs\n"
|
||||||
PreviewLengthFormat="%s:\n %.5f secs\n"
|
PreviewLengthFormat="%s:\n %.5f secs\n"
|
||||||
|
|||||||
@@ -1657,6 +1657,8 @@
|
|||||||
AAFF41A40F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; };
|
AAFF41A40F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; };
|
||||||
AAFF41A50F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF41A10F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp */; };
|
AAFF41A50F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF41A10F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp */; };
|
||||||
AAFF41A60F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; };
|
AAFF41A60F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; };
|
||||||
|
B75CE3B5137963350076A82D /* SongPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = B75CE3B3137963350076A82D /* SongPosition.h */; };
|
||||||
|
B75CE3B6137963350076A82D /* SongPosition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B75CE3B4137963350076A82D /* SongPosition.cpp */; };
|
||||||
EE2153A910A75BEE0074B01B /* NotesLoaderPMS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */; };
|
EE2153A910A75BEE0074B01B /* NotesLoaderPMS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */; };
|
||||||
EE2153AA10A75BEE0074B01B /* NotesLoaderPMS.h in Headers */ = {isa = PBXBuildFile; fileRef = EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */; };
|
EE2153AA10A75BEE0074B01B /* NotesLoaderPMS.h in Headers */ = {isa = PBXBuildFile; fileRef = EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */; };
|
||||||
EE879B60132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE879B5C132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp */; };
|
EE879B60132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE879B5C132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp */; };
|
||||||
@@ -3025,6 +3027,8 @@
|
|||||||
AAFF55220549F43A00D02EE9 /* ComboGraph.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ComboGraph.h; path = ../src/ComboGraph.h; sourceTree = "<group>"; };
|
AAFF55220549F43A00D02EE9 /* ComboGraph.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ComboGraph.h; path = ../src/ComboGraph.h; sourceTree = "<group>"; };
|
||||||
AAFF5541054E736D00D02EE9 /* Attack.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Attack.cpp; path = ../src/Attack.cpp; sourceTree = "<group>"; };
|
AAFF5541054E736D00D02EE9 /* Attack.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Attack.cpp; path = ../src/Attack.cpp; sourceTree = "<group>"; };
|
||||||
AAFF5542054E736D00D02EE9 /* Attack.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Attack.h; path = ../src/Attack.h; sourceTree = "<group>"; };
|
AAFF5542054E736D00D02EE9 /* Attack.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Attack.h; path = ../src/Attack.h; sourceTree = "<group>"; };
|
||||||
|
B75CE3B3137963350076A82D /* SongPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SongPosition.h; path = ../src/SongPosition.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
B75CE3B4137963350076A82D /* SongPosition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SongPosition.cpp; path = ../src/SongPosition.cpp; sourceTree = SOURCE_ROOT; };
|
||||||
EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderPMS.cpp; path = ../src/NotesLoaderPMS.cpp; sourceTree = SOURCE_ROOT; };
|
EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderPMS.cpp; path = ../src/NotesLoaderPMS.cpp; sourceTree = SOURCE_ROOT; };
|
||||||
EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesLoaderPMS.h; path = ../src/NotesLoaderPMS.h; sourceTree = SOURCE_ROOT; };
|
EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesLoaderPMS.h; path = ../src/NotesLoaderPMS.h; sourceTree = SOURCE_ROOT; };
|
||||||
EE879B5C132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RageDisplay_Legacy_Helpers.cpp; path = ../src/RageDisplay_Legacy_Helpers.cpp; sourceTree = SOURCE_ROOT; };
|
EE879B5C132DEE720078FDDC /* RageDisplay_Legacy_Helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RageDisplay_Legacy_Helpers.cpp; path = ../src/RageDisplay_Legacy_Helpers.cpp; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -3938,6 +3942,8 @@
|
|||||||
AA7CDD930D8395F90001DAFC /* Song.h */,
|
AA7CDD930D8395F90001DAFC /* Song.h */,
|
||||||
AA6EFE0704770C79005F316C /* SongOptions.cpp */,
|
AA6EFE0704770C79005F316C /* SongOptions.cpp */,
|
||||||
AA6EFE0804770C79005F316C /* SongOptions.h */,
|
AA6EFE0804770C79005F316C /* SongOptions.h */,
|
||||||
|
B75CE3B4137963350076A82D /* SongPosition.cpp */,
|
||||||
|
B75CE3B3137963350076A82D /* SongPosition.h */,
|
||||||
AA5C73F90637A5F000AFB891 /* SongUtil.cpp */,
|
AA5C73F90637A5F000AFB891 /* SongUtil.cpp */,
|
||||||
AA5C73FA0637A5F000AFB891 /* SongUtil.h */,
|
AA5C73FA0637A5F000AFB891 /* SongUtil.h */,
|
||||||
AAEBF57C0B5C83F4005F3C7C /* SoundEffectControl.cpp */,
|
AAEBF57C0B5C83F4005F3C7C /* SoundEffectControl.cpp */,
|
||||||
@@ -5056,6 +5062,7 @@
|
|||||||
2BC6132D13773C8E00CC8BBD /* pngpriv.h in Headers */,
|
2BC6132D13773C8E00CC8BBD /* pngpriv.h in Headers */,
|
||||||
2BC6133313773C8E00CC8BBD /* pngstruct.h in Headers */,
|
2BC6133313773C8E00CC8BBD /* pngstruct.h in Headers */,
|
||||||
2BC6133E13773D2C00CC8BBD /* pnglibconf.h in Headers */,
|
2BC6133E13773D2C00CC8BBD /* pnglibconf.h in Headers */,
|
||||||
|
B75CE3B5137963350076A82D /* SongPosition.h in Headers */,
|
||||||
2B9C2E8E137A138B004C92F3 /* NotesLoaderJson.h in Headers */,
|
2B9C2E8E137A138B004C92F3 /* NotesLoaderJson.h in Headers */,
|
||||||
2B9C2E90137A138B004C92F3 /* NotesWriterJson.h in Headers */,
|
2B9C2E90137A138B004C92F3 /* NotesWriterJson.h in Headers */,
|
||||||
);
|
);
|
||||||
@@ -6317,6 +6324,7 @@
|
|||||||
2BC6133813773C8E00CC8BBD /* pngwrite.c in Sources */,
|
2BC6133813773C8E00CC8BBD /* pngwrite.c in Sources */,
|
||||||
2BC6133913773C8E00CC8BBD /* pngwtran.c in Sources */,
|
2BC6133913773C8E00CC8BBD /* pngwtran.c in Sources */,
|
||||||
2BC6133A13773C8E00CC8BBD /* pngwutil.c in Sources */,
|
2BC6133A13773C8E00CC8BBD /* pngwutil.c in Sources */,
|
||||||
|
B75CE3B6137963350076A82D /* SongPosition.cpp in Sources */,
|
||||||
2B9C2E8D137A138B004C92F3 /* NotesLoaderJson.cpp in Sources */,
|
2B9C2E8D137A138B004C92F3 /* NotesLoaderJson.cpp in Sources */,
|
||||||
2B9C2E8F137A138B004C92F3 /* NotesWriterJson.cpp in Sources */,
|
2B9C2E8F137A138B004C92F3 /* NotesWriterJson.cpp in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
+18
-1
@@ -34,6 +34,8 @@ REGISTER_ACTOR_CLASS_WITH_NAME( HiddenActor, Actor );
|
|||||||
|
|
||||||
float Actor::g_fCurrentBGMTime = 0, Actor::g_fCurrentBGMBeat;
|
float Actor::g_fCurrentBGMTime = 0, Actor::g_fCurrentBGMBeat;
|
||||||
float Actor::g_fCurrentBGMTimeNoOffset = 0, Actor::g_fCurrentBGMBeatNoOffset = 0;
|
float Actor::g_fCurrentBGMTimeNoOffset = 0, Actor::g_fCurrentBGMBeatNoOffset = 0;
|
||||||
|
vector<float> Actor::g_vfCurrentBGMBeatPlayer(NUM_PlayerNumber, 0);
|
||||||
|
vector<float> Actor::g_vfCurrentBGMBeatPlayerNoOffset(NUM_PlayerNumber, 0);
|
||||||
|
|
||||||
|
|
||||||
Actor *Actor::Copy() const { return new Actor(*this); }
|
Actor *Actor::Copy() const { return new Actor(*this); }
|
||||||
@@ -68,6 +70,12 @@ void Actor::SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBe
|
|||||||
g_fCurrentBGMBeatNoOffset = fBeatNoOffset;
|
g_fCurrentBGMBeatNoOffset = fBeatNoOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actor::SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset )
|
||||||
|
{
|
||||||
|
g_vfCurrentBGMBeatPlayer[pn] = fBeat;
|
||||||
|
g_vfCurrentBGMBeatPlayerNoOffset[pn] = fBeatNoOffset;
|
||||||
|
}
|
||||||
|
|
||||||
void Actor::SetBGMLight( int iLightNumber, float fCabinetLights )
|
void Actor::SetBGMLight( int iLightNumber, float fCabinetLights )
|
||||||
{
|
{
|
||||||
ASSERT( iLightNumber < NUM_CabinetLight );
|
ASSERT( iLightNumber < NUM_CabinetLight );
|
||||||
@@ -151,7 +159,6 @@ Actor::Actor()
|
|||||||
lua_pop( L, 1 );
|
lua_pop( L, 1 );
|
||||||
LUA->Release( L );
|
LUA->Release( L );
|
||||||
|
|
||||||
|
|
||||||
m_size = RageVector2( 1, 1 );
|
m_size = RageVector2( 1, 1 );
|
||||||
InitState();
|
InitState();
|
||||||
m_pParent = NULL;
|
m_pParent = NULL;
|
||||||
@@ -676,6 +683,16 @@ void Actor::UpdateInternal( float fDeltaTime )
|
|||||||
m_fSecsIntoEffect = g_fCurrentBGMBeat;
|
m_fSecsIntoEffect = g_fCurrentBGMBeat;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLOCK_BGM_BEAT_PLAYER1:
|
||||||
|
m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_1] - m_fSecsIntoEffect;
|
||||||
|
m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLOCK_BGM_BEAT_PLAYER2:
|
||||||
|
m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_2] - m_fSecsIntoEffect;
|
||||||
|
m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_2];
|
||||||
|
break;
|
||||||
|
|
||||||
case CLOCK_BGM_TIME:
|
case CLOCK_BGM_TIME:
|
||||||
m_fEffectDelta = g_fCurrentBGMTime - m_fSecsIntoEffect;
|
m_fEffectDelta = g_fCurrentBGMTime - m_fSecsIntoEffect;
|
||||||
m_fSecsIntoEffect = g_fCurrentBGMTime;
|
m_fSecsIntoEffect = g_fCurrentBGMTime;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ACTOR_H
|
#ifndef ACTOR_H
|
||||||
#define ACTOR_H
|
#define ACTOR_H
|
||||||
|
|
||||||
|
#include "PlayerNumber.h"
|
||||||
#include "RageTypes.h"
|
#include "RageTypes.h"
|
||||||
#include "RageUtil_AutoPtr.h"
|
#include "RageUtil_AutoPtr.h"
|
||||||
#include "LuaReference.h"
|
#include "LuaReference.h"
|
||||||
@@ -109,6 +110,7 @@ public:
|
|||||||
virtual void LoadFromNode( const XNode* pNode );
|
virtual void LoadFromNode( const XNode* pNode );
|
||||||
|
|
||||||
static void SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset );
|
static void SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset );
|
||||||
|
static void SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset );
|
||||||
static void SetBGMLight( int iLightNumber, float fCabinetLights );
|
static void SetBGMLight( int iLightNumber, float fCabinetLights );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,6 +133,8 @@ public:
|
|||||||
CLOCK_BGM_BEAT,
|
CLOCK_BGM_BEAT,
|
||||||
CLOCK_BGM_TIME_NO_OFFSET,
|
CLOCK_BGM_TIME_NO_OFFSET,
|
||||||
CLOCK_BGM_BEAT_NO_OFFSET,
|
CLOCK_BGM_BEAT_NO_OFFSET,
|
||||||
|
CLOCK_BGM_BEAT_PLAYER1,
|
||||||
|
CLOCK_BGM_BEAT_PLAYER2,
|
||||||
CLOCK_LIGHT_1 = 1000,
|
CLOCK_LIGHT_1 = 1000,
|
||||||
CLOCK_LIGHT_LAST = 1100,
|
CLOCK_LIGHT_LAST = 1100,
|
||||||
NUM_CLOCKS
|
NUM_CLOCKS
|
||||||
@@ -713,6 +717,8 @@ protected:
|
|||||||
// global state
|
// global state
|
||||||
static float g_fCurrentBGMTime, g_fCurrentBGMBeat;
|
static float g_fCurrentBGMTime, g_fCurrentBGMBeat;
|
||||||
static float g_fCurrentBGMTimeNoOffset, g_fCurrentBGMBeatNoOffset;
|
static float g_fCurrentBGMTimeNoOffset, g_fCurrentBGMBeatNoOffset;
|
||||||
|
static vector<float> g_vfCurrentBGMBeatPlayer;
|
||||||
|
static vector<float> g_vfCurrentBGMBeatPlayerNoOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// commands
|
// commands
|
||||||
|
|||||||
+12
-12
@@ -58,7 +58,7 @@ void AdjustSync::ResetOriginalSyncData()
|
|||||||
s_pTimingDataOriginal = new TimingData;
|
s_pTimingDataOriginal = new TimingData;
|
||||||
|
|
||||||
if( GAMESTATE->m_pCurSong )
|
if( GAMESTATE->m_pCurSong )
|
||||||
*s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_Timing;
|
*s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_SongTiming;
|
||||||
else
|
else
|
||||||
*s_pTimingDataOriginal = TimingData();
|
*s_pTimingDataOriginal = TimingData();
|
||||||
s_fGlobalOffsetSecondsOriginal = PREFSMAN->m_fGlobalOffsetSeconds;
|
s_fGlobalOffsetSecondsOriginal = PREFSMAN->m_fGlobalOffsetSeconds;
|
||||||
@@ -87,7 +87,7 @@ void AdjustSync::SaveSyncChanges()
|
|||||||
{
|
{
|
||||||
if( GAMESTATE->IsCourseMode() )
|
if( GAMESTATE->IsCourseMode() )
|
||||||
return;
|
return;
|
||||||
if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_Timing )
|
if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_SongTiming )
|
||||||
{
|
{
|
||||||
if( GAMESTATE->IsEditing() )
|
if( GAMESTATE->IsEditing() )
|
||||||
{
|
{
|
||||||
@@ -110,7 +110,7 @@ void AdjustSync::RevertSyncChanges()
|
|||||||
if( GAMESTATE->IsCourseMode() )
|
if( GAMESTATE->IsCourseMode() )
|
||||||
return;
|
return;
|
||||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( s_fGlobalOffsetSecondsOriginal );
|
PREFSMAN->m_fGlobalOffsetSeconds.Set( s_fGlobalOffsetSecondsOriginal );
|
||||||
GAMESTATE->m_pCurSong->m_Timing = *s_pTimingDataOriginal;
|
GAMESTATE->m_pCurSong->m_SongTiming = *s_pTimingDataOriginal;
|
||||||
ResetOriginalSyncData();
|
ResetOriginalSyncData();
|
||||||
s_fStandardDeviation = 0.0f;
|
s_fStandardDeviation = 0.0f;
|
||||||
s_fAverageError = 0.0f;
|
s_fAverageError = 0.0f;
|
||||||
@@ -186,7 +186,7 @@ void AdjustSync::AutosyncOffset()
|
|||||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
||||||
{
|
{
|
||||||
case SongOptions::AUTOSYNC_SONG:
|
case SongOptions::AUTOSYNC_SONG:
|
||||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += mean;
|
GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += mean;
|
||||||
break;
|
break;
|
||||||
case SongOptions::AUTOSYNC_MACHINE:
|
case SongOptions::AUTOSYNC_MACHINE:
|
||||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean );
|
PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean );
|
||||||
@@ -232,15 +232,15 @@ void AdjustSync::AutosyncTempo()
|
|||||||
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, fFilteredError ) )
|
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, fFilteredError ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fIntercept;
|
GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fIntercept;
|
||||||
const float fScaleBPM = 1.0f/(1.0f - fSlope);
|
const float fScaleBPM = 1.0f/(1.0f - fSlope);
|
||||||
FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, i )
|
FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments, i )
|
||||||
i->SetBPM( i->GetBPM() * fScaleBPM );
|
i->SetBPM( i->GetBPM() * fScaleBPM );
|
||||||
|
|
||||||
// We assume that the stops were measured as a number of beats.
|
// We assume that the stops were measured as a number of beats.
|
||||||
// Therefore, if we change the bpms, we need to make a similar
|
// Therefore, if we change the bpms, we need to make a similar
|
||||||
// change to the stops.
|
// change to the stops.
|
||||||
FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, i )
|
FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments, i )
|
||||||
i->m_fStopSeconds *= 1.0f - fSlope;
|
i->m_fStopSeconds *= 1.0f - fSlope;
|
||||||
|
|
||||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
||||||
@@ -296,7 +296,7 @@ void AdjustSync::GetSyncChangeTextSong( vector<RString> &vsAddTo )
|
|||||||
|
|
||||||
{
|
{
|
||||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_fBeat0OffsetInSeconds, 0.001f );
|
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_fBeat0OffsetInSeconds, 0.001f );
|
||||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds, 0.001f );
|
float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds, 0.001f );
|
||||||
float fDelta = fNew - fOld;
|
float fDelta = fNew - fOld;
|
||||||
|
|
||||||
if( fabsf(fDelta) > 0.0001f )
|
if( fabsf(fDelta) > 0.0001f )
|
||||||
@@ -309,10 +309,10 @@ void AdjustSync::GetSyncChangeTextSong( vector<RString> &vsAddTo )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments.size(); i++ )
|
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_BPMSegments[i].GetBPM(), 0.001f );
|
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_BPMSegments[i].GetBPM(), 0.001f );
|
||||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments[i].GetBPM(), 0.001f );
|
float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments[i].GetBPM(), 0.001f );
|
||||||
float fDelta = fNew - fOld;
|
float fDelta = fNew - fOld;
|
||||||
|
|
||||||
if( fabsf(fDelta) > 0.0001f )
|
if( fabsf(fDelta) > 0.0001f )
|
||||||
@@ -330,10 +330,10 @@ void AdjustSync::GetSyncChangeTextSong( vector<RString> &vsAddTo )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_StopSegments.size(); i++ )
|
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_StopSegments[i].m_fStopSeconds, 0.001f );
|
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_StopSegments[i].m_fStopSeconds, 0.001f );
|
float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||||
float fDelta = fNew - fOld;
|
float fDelta = fNew - fOld;
|
||||||
|
|
||||||
if( fabsf(fDelta) > 0.0001f )
|
if( fabsf(fDelta) > 0.0001f )
|
||||||
|
|||||||
+75
-18
@@ -67,13 +67,13 @@ static float GetNoteFieldHeight( const PlayerState* pPlayerState )
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
float g_fExpandSeconds = 0;
|
|
||||||
struct PerPlayerData
|
struct PerPlayerData
|
||||||
{
|
{
|
||||||
float m_fMinTornadoX[MAX_COLS_PER_PLAYER];
|
float m_fMinTornadoX[MAX_COLS_PER_PLAYER];
|
||||||
float m_fMaxTornadoX[MAX_COLS_PER_PLAYER];
|
float m_fMaxTornadoX[MAX_COLS_PER_PLAYER];
|
||||||
float m_fInvertDistance[MAX_COLS_PER_PLAYER];
|
float m_fInvertDistance[MAX_COLS_PER_PLAYER];
|
||||||
float m_fBeatFactor;
|
float m_fBeatFactor;
|
||||||
|
float m_fExpandSeconds;
|
||||||
};
|
};
|
||||||
PerPlayerData g_EffectData[NUM_PLAYERS];
|
PerPlayerData g_EffectData[NUM_PLAYERS];
|
||||||
};
|
};
|
||||||
@@ -82,22 +82,25 @@ void ArrowEffects::Update()
|
|||||||
{
|
{
|
||||||
const Style* pStyle = GAMESTATE->GetCurrentStyle();
|
const Style* pStyle = GAMESTATE->GetCurrentStyle();
|
||||||
|
|
||||||
|
FOREACH_PlayerNumber( pn )
|
||||||
|
{
|
||||||
|
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn];
|
||||||
|
const SongPosition &position = GAMESTATE->m_bIsUsingStepTiming
|
||||||
|
? GAMESTATE->m_pPlayerState[pn]->m_Position : GAMESTATE->m_Position;
|
||||||
|
|
||||||
|
PerPlayerData &data = g_EffectData[pn];
|
||||||
|
|
||||||
{
|
{
|
||||||
static float fLastTime = 0;
|
static float fLastTime = 0;
|
||||||
float fTime = RageTimer::GetTimeSinceStartFast();
|
float fTime = RageTimer::GetTimeSinceStartFast();
|
||||||
if( !GAMESTATE->m_bFreeze || !GAMESTATE->m_bDelay )
|
if( !position.m_bFreeze || !position.m_bDelay )
|
||||||
{
|
{
|
||||||
g_fExpandSeconds += fTime - fLastTime;
|
data.m_fExpandSeconds += fTime - fLastTime;
|
||||||
g_fExpandSeconds = fmodf( g_fExpandSeconds, PI*2 );
|
data.m_fExpandSeconds = fmodf( data.m_fExpandSeconds, PI*2 );
|
||||||
}
|
}
|
||||||
fLastTime = fTime;
|
fLastTime = fTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_PlayerNumber( pn )
|
|
||||||
{
|
|
||||||
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn];
|
|
||||||
|
|
||||||
PerPlayerData &data = g_EffectData[pn];
|
|
||||||
// Update Tornado
|
// Update Tornado
|
||||||
for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum )
|
for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum )
|
||||||
{
|
{
|
||||||
@@ -176,7 +179,7 @@ void ArrowEffects::Update()
|
|||||||
// Update Beat
|
// Update Beat
|
||||||
do {
|
do {
|
||||||
float fAccelTime = 0.2f, fTotalTime = 0.5f;
|
float fAccelTime = 0.2f, fTotalTime = 0.5f;
|
||||||
float fBeat = GAMESTATE->m_fSongBeatVisible + fAccelTime;
|
float fBeat = position.m_fSongBeatVisible + fAccelTime;
|
||||||
|
|
||||||
const bool bEvenBeat = ( int(fBeat) % 2 ) != 0;
|
const bool bEvenBeat = ( int(fBeat) % 2 ) != 0;
|
||||||
|
|
||||||
@@ -208,6 +211,50 @@ void ArrowEffects::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GetSpeedMultiplier( float fSongBeat, float fMusicSeconds, const TimingData &tim )
|
||||||
|
{
|
||||||
|
if( tim.m_SpeedSegments.size() == 0 )
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
const int index = tim.GetSpeedSegmentIndexAtBeat( fSongBeat );
|
||||||
|
|
||||||
|
const SpeedSegment &seg = tim.m_SpeedSegments[index];
|
||||||
|
float fStartBeat = NoteRowToBeat(seg.m_iStartRow);
|
||||||
|
float fStartTime = tim.GetElapsedTimeFromBeat( fStartBeat ) - tim.GetDelayAtBeat( fStartBeat );
|
||||||
|
float fEndTime;
|
||||||
|
float fCurTime = fMusicSeconds;
|
||||||
|
|
||||||
|
if( seg.m_usMode == 1 ) // seconds
|
||||||
|
{
|
||||||
|
fEndTime = fStartTime + seg.m_fWait;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fEndTime = tim.GetElapsedTimeFromBeat( fStartBeat + seg.m_fWait ) - tim.GetDelayAtBeat( fStartBeat + seg.m_fWait );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( index == 0 && tim.m_SpeedSegments[0].m_fWait > 0.0 ) && fCurTime < fStartTime )
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else if( fEndTime >= fCurTime && ( index > 0 || tim.m_SpeedSegments[0].m_fWait > 0.0 ) )
|
||||||
|
{
|
||||||
|
const float fPriorSpeed = ( index == 0 ? 1 : tim.m_SpeedSegments[index - 1].m_fPercent );
|
||||||
|
float fTimeUsed = fCurTime - fStartTime;
|
||||||
|
float fDuration = fEndTime - fStartTime;
|
||||||
|
float fRatioUsed = fDuration == 0.0 ? 1 : fTimeUsed / fDuration;
|
||||||
|
|
||||||
|
float fDistance = fPriorSpeed - seg.m_fPercent;
|
||||||
|
float fRatioNeed = fRatioUsed * -fDistance;
|
||||||
|
return (fPriorSpeed + fRatioNeed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return seg.m_fPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* For visibility testing: if bAbsolute is false, random modifiers must return
|
/* For visibility testing: if bAbsolute is false, random modifiers must return
|
||||||
* the minimum possible scroll speed. */
|
* the minimum possible scroll speed. */
|
||||||
float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakOut, bool bAbsolute )
|
float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakOut, bool bAbsolute )
|
||||||
@@ -217,21 +264,27 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
|
|||||||
bIsPastPeakOut = true;
|
bIsPastPeakOut = true;
|
||||||
|
|
||||||
float fYOffset = 0;
|
float fYOffset = 0;
|
||||||
|
const SongPosition &position = GAMESTATE->m_bIsUsingStepTiming
|
||||||
|
? pPlayerState->m_Position : GAMESTATE->m_Position;
|
||||||
|
|
||||||
|
float fSongBeat = position.m_fSongBeatVisible;
|
||||||
|
|
||||||
|
Steps *pCurSteps = GAMESTATE->m_pCurSteps[pPlayerState->m_PlayerNumber];
|
||||||
|
|
||||||
/* Usually, fTimeSpacing is 0 or 1, in which case we use entirely beat spacing or
|
/* Usually, fTimeSpacing is 0 or 1, in which case we use entirely beat spacing or
|
||||||
* entirely time spacing (respectively). Occasionally, we tween between them. */
|
* entirely time spacing (respectively). Occasionally, we tween between them. */
|
||||||
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing != 1.0f )
|
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing != 1.0f )
|
||||||
{
|
{
|
||||||
float fSongBeat = GAMESTATE->m_fSongBeatVisible;
|
|
||||||
float fBeatsUntilStep = fNoteBeat - fSongBeat;
|
float fBeatsUntilStep = fNoteBeat - fSongBeat;
|
||||||
float fYOffsetBeatSpacing = fBeatsUntilStep;
|
float fYOffsetBeatSpacing = fBeatsUntilStep;
|
||||||
fYOffset += fYOffsetBeatSpacing * (1-pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing);
|
float fSpeedMultiplier = ( GAMESTATE->m_bInStepEditor || !GAMESTATE->m_bIsUsingStepTiming ) ? 1.0 : GetSpeedMultiplier( position.m_fSongBeatVisible, position.m_fMusicSecondsVisible, pCurSteps->m_Timing );
|
||||||
|
fYOffset += fSpeedMultiplier * fYOffsetBeatSpacing * (1-pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing != 0.0f )
|
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing != 0.0f )
|
||||||
{
|
{
|
||||||
float fSongSeconds = GAMESTATE->m_fMusicSecondsVisible;
|
float fSongSeconds = GAMESTATE->m_Position.m_fMusicSecondsVisible;
|
||||||
float fNoteSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat(fNoteBeat);
|
float fNoteSeconds = pCurSteps->m_Timing.GetElapsedTimeFromBeat(fNoteBeat);
|
||||||
float fSecondsUntilStep = fNoteSeconds - fSongSeconds;
|
float fSecondsUntilStep = fNoteSeconds - fSongSeconds;
|
||||||
float fBPM = pPlayerState->m_PlayerOptions.GetCurrent().m_fScrollBPM;
|
float fBPM = pPlayerState->m_PlayerOptions.GetCurrent().m_fScrollBPM;
|
||||||
float fBPS = fBPM/60.f;
|
float fBPS = fBPM/60.f;
|
||||||
@@ -288,6 +341,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
|
|||||||
|
|
||||||
// Factor in scroll speed
|
// Factor in scroll speed
|
||||||
float fScrollSpeed = pPlayerState->m_PlayerOptions.GetCurrent().m_fScrollSpeed;
|
float fScrollSpeed = pPlayerState->m_PlayerOptions.GetCurrent().m_fScrollSpeed;
|
||||||
|
|
||||||
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fRandomSpeed > 0 && !bAbsolute )
|
if( pPlayerState->m_PlayerOptions.GetCurrent().m_fRandomSpeed > 0 && !bAbsolute )
|
||||||
{
|
{
|
||||||
// Generate a deterministically "random" speed for each arrow.
|
// Generate a deterministically "random" speed for each arrow.
|
||||||
@@ -307,7 +361,10 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float
|
|||||||
|
|
||||||
if( fAccels[PlayerOptions::ACCEL_EXPAND] != 0 )
|
if( fAccels[PlayerOptions::ACCEL_EXPAND] != 0 )
|
||||||
{
|
{
|
||||||
float fExpandMultiplier = SCALE( RageFastCos(g_fExpandSeconds*EXPAND_MULTIPLIER_FREQUENCY),
|
// TODO: Don't index by PlayerNumber.
|
||||||
|
PerPlayerData &data = g_EffectData[pPlayerState->m_PlayerNumber];
|
||||||
|
|
||||||
|
float fExpandMultiplier = SCALE( RageFastCos(data.m_fExpandSeconds*EXPAND_MULTIPLIER_FREQUENCY),
|
||||||
EXPAND_MULTIPLIER_SCALE_FROM_LOW, EXPAND_MULTIPLIER_SCALE_FROM_HIGH,
|
EXPAND_MULTIPLIER_SCALE_FROM_LOW, EXPAND_MULTIPLIER_SCALE_FROM_HIGH,
|
||||||
EXPAND_MULTIPLIER_SCALE_TO_LOW, EXPAND_MULTIPLIER_SCALE_TO_HIGH );
|
EXPAND_MULTIPLIER_SCALE_TO_LOW, EXPAND_MULTIPLIER_SCALE_TO_HIGH );
|
||||||
fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND],
|
fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND],
|
||||||
@@ -511,7 +568,7 @@ float ArrowEffects::GetRotationZ( const PlayerState* pPlayerState, float fNoteBe
|
|||||||
// As usual, enable dizzy hold heads at your own risk. -Wolfman2000
|
// As usual, enable dizzy hold heads at your own risk. -Wolfman2000
|
||||||
if( fEffects[PlayerOptions::EFFECT_DIZZY] != 0 && ( DIZZY_HOLD_HEADS || !bIsHoldHead ) )
|
if( fEffects[PlayerOptions::EFFECT_DIZZY] != 0 && ( DIZZY_HOLD_HEADS || !bIsHoldHead ) )
|
||||||
{
|
{
|
||||||
const float fSongBeat = GAMESTATE->m_fSongBeatVisible;
|
const float fSongBeat = pPlayerState->m_Position.m_fSongBeatVisible;
|
||||||
float fDizzyRotation = fNoteBeat - fSongBeat;
|
float fDizzyRotation = fNoteBeat - fSongBeat;
|
||||||
fDizzyRotation *= fEffects[PlayerOptions::EFFECT_DIZZY];
|
fDizzyRotation *= fEffects[PlayerOptions::EFFECT_DIZZY];
|
||||||
fDizzyRotation = fmodf( fDizzyRotation, 2*PI );
|
fDizzyRotation = fmodf( fDizzyRotation, 2*PI );
|
||||||
@@ -528,7 +585,7 @@ float ArrowEffects::ReceptorGetRotationZ( const PlayerState* pPlayerState )
|
|||||||
|
|
||||||
if( fEffects[PlayerOptions::EFFECT_CONFUSION] != 0 )
|
if( fEffects[PlayerOptions::EFFECT_CONFUSION] != 0 )
|
||||||
{
|
{
|
||||||
float fConfRotation = GAMESTATE->m_fSongBeatVisible;
|
float fConfRotation = pPlayerState->m_Position.m_fSongBeatVisible;
|
||||||
fConfRotation *= fEffects[PlayerOptions::EFFECT_CONFUSION];
|
fConfRotation *= fEffects[PlayerOptions::EFFECT_CONFUSION];
|
||||||
fConfRotation = fmodf( fConfRotation, 2*PI );
|
fConfRotation = fmodf( fConfRotation, 2*PI );
|
||||||
fConfRotation *= -180/PI;
|
fConfRotation *= -180/PI;
|
||||||
@@ -680,7 +737,7 @@ float ArrowEffects::GetBrightness( const PlayerState* pPlayerState, float fNoteB
|
|||||||
if( GAMESTATE->IsEditing() )
|
if( GAMESTATE->IsEditing() )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
float fSongBeat = GAMESTATE->m_fSongBeatVisible;
|
float fSongBeat = pPlayerState->m_Position.m_fSongBeatVisible;
|
||||||
float fBeatsUntilStep = fNoteBeat - fSongBeat;
|
float fBeatsUntilStep = fNoteBeat - fSongBeat;
|
||||||
|
|
||||||
float fBrightness = SCALE( fBeatsUntilStep, 0, -1, 1.f, 0.f );
|
float fBrightness = SCALE( fBeatsUntilStep, 0, -1, 1.f, 0.f );
|
||||||
|
|||||||
+7
-5
@@ -12,8 +12,9 @@ void Attack::GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBe
|
|||||||
ASSERT( pSong );
|
ASSERT( pSong );
|
||||||
ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) );
|
ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) );
|
||||||
|
|
||||||
fStartBeat = pSong->GetBeatFromElapsedTime( fStartSecond );
|
const TimingData &timing = pSong->m_SongTiming;
|
||||||
fEndBeat = pSong->GetBeatFromElapsedTime( fStartSecond+fSecsRemaining );
|
fStartBeat = timing.GetBeatFromElapsedTime( fStartSecond );
|
||||||
|
fEndBeat = timing.GetBeatFromElapsedTime( fStartSecond+fSecsRemaining );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the range for an attack that's being applied in realtime, eg. during battle
|
/* Get the range for an attack that's being applied in realtime, eg. during battle
|
||||||
@@ -31,12 +32,13 @@ void Attack::GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlay
|
|||||||
ASSERT( pSong );
|
ASSERT( pSong );
|
||||||
|
|
||||||
/* If reasonable, push the attack forward 8 beats so that notes on screen don't change suddenly. */
|
/* If reasonable, push the attack forward 8 beats so that notes on screen don't change suddenly. */
|
||||||
fStartBeat = min( GAMESTATE->m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat );
|
fStartBeat = min( GAMESTATE->m_Position.m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat );
|
||||||
fStartBeat = truncf(fStartBeat)+1;
|
fStartBeat = truncf(fStartBeat)+1;
|
||||||
|
|
||||||
const float lStartSecond = pSong->GetElapsedTimeFromBeat( fStartBeat );
|
const TimingData &timing = pSong->m_SongTiming;
|
||||||
|
const float lStartSecond = timing.GetElapsedTimeFromBeat( fStartBeat );
|
||||||
const float fEndSecond = lStartSecond + fSecsRemaining;
|
const float fEndSecond = lStartSecond + fSecsRemaining;
|
||||||
fEndBeat = pSong->GetBeatFromElapsedTime( fEndSecond );
|
fEndBeat = timing.GetBeatFromElapsedTime( fEndSecond );
|
||||||
fEndBeat = truncf(fEndBeat)+1;
|
fEndBeat = truncf(fEndBeat)+1;
|
||||||
|
|
||||||
// loading the course should have caught this.
|
// loading the course should have caught this.
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain )
|
|||||||
if( tn[pn].iKeysoundIndex >= 0 )
|
if( tn[pn].iKeysoundIndex >= 0 )
|
||||||
{
|
{
|
||||||
RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex];
|
RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex];
|
||||||
float fSeconds = pSong->m_Timing.GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency();
|
float fSeconds = GAMESTATE->m_pCurSteps[pn]->m_Timing.GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency();
|
||||||
|
|
||||||
float fPan = 0;
|
float fPan = 0;
|
||||||
if( !bSoundIsGlobal )
|
if( !bSoundIsGlobal )
|
||||||
|
|||||||
+1
-1
@@ -277,7 +277,7 @@ SongBPMDisplay::SongBPMDisplay()
|
|||||||
|
|
||||||
void SongBPMDisplay::Update( float fDeltaTime )
|
void SongBPMDisplay::Update( float fDeltaTime )
|
||||||
{
|
{
|
||||||
float fGameStateBPM = GAMESTATE->m_fCurBPS * 60.0f;
|
float fGameStateBPM = GAMESTATE->m_Position.m_fCurBPS * 60.0f;
|
||||||
if( m_fLastGameStateBPM != fGameStateBPM )
|
if( m_fLastGameStateBPM != fGameStateBPM )
|
||||||
{
|
{
|
||||||
m_fLastGameStateBPM = fGameStateBPM;
|
m_fLastGameStateBPM = fGameStateBPM;
|
||||||
|
|||||||
+5
-5
@@ -419,7 +419,7 @@ void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fEndBeat, const Bac
|
|||||||
int iStartRow = BeatToNoteRow(fFirstBeat);
|
int iStartRow = BeatToNoteRow(fFirstBeat);
|
||||||
int iEndRow = BeatToNoteRow(fEndBeat);
|
int iEndRow = BeatToNoteRow(fEndBeat);
|
||||||
|
|
||||||
const TimingData &timing = m_pSong->m_Timing;
|
const TimingData &timing = m_pSong->m_SongTiming;
|
||||||
|
|
||||||
// change BG every time signature change or 4 measures
|
// change BG every time signature change or 4 measures
|
||||||
FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter )
|
FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter )
|
||||||
@@ -697,7 +697,7 @@ void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMus
|
|||||||
float fBeat, fBPS, fThrowAway;
|
float fBeat, fBPS, fThrowAway;
|
||||||
bool bFreeze;
|
bool bFreeze;
|
||||||
int iThrowAway;
|
int iThrowAway;
|
||||||
pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze, iThrowAway, fThrowAway );
|
pSong->m_SongTiming.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze, iThrowAway, fThrowAway );
|
||||||
|
|
||||||
// Calls to Update() should *not* be scaled by music rate; fCurrentTime is. Undo it.
|
// Calls to Update() should *not* be scaled by music rate; fCurrentTime is. Undo it.
|
||||||
const float fRate = GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
const float fRate = GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
||||||
@@ -762,7 +762,7 @@ void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMus
|
|||||||
m_pCurrentBGA->PlayCommand( "GainFocus" );
|
m_pCurrentBGA->PlayCommand( "GainFocus" );
|
||||||
|
|
||||||
/* How much time of this BGA have we skipped? (This happens with SetSeconds.) */
|
/* How much time of this BGA have we skipped? (This happens with SetSeconds.) */
|
||||||
const float fStartSecond = pSong->m_Timing.GetElapsedTimeFromBeat( change.m_fStartBeat );
|
const float fStartSecond = pSong->m_SongTiming.GetElapsedTimeFromBeat( change.m_fStartBeat );
|
||||||
|
|
||||||
/* This is affected by the music rate. */
|
/* This is affected by the music rate. */
|
||||||
fDeltaTime = fCurrentTime - fStartSecond;
|
fDeltaTime = fCurrentTime - fStartSecond;
|
||||||
@@ -800,9 +800,9 @@ void BackgroundImpl::Update( float fDeltaTime )
|
|||||||
FOREACH_BackgroundLayer( i )
|
FOREACH_BackgroundLayer( i )
|
||||||
{
|
{
|
||||||
Layer &layer = m_Layer[i];
|
Layer &layer = m_Layer[i];
|
||||||
layer.UpdateCurBGChange( m_pSong, m_fLastMusicSeconds, GAMESTATE->m_fMusicSeconds, m_mapNameToTransition );
|
layer.UpdateCurBGChange( m_pSong, m_fLastMusicSeconds, GAMESTATE->m_Position.m_fMusicSeconds, m_mapNameToTransition );
|
||||||
}
|
}
|
||||||
m_fLastMusicSeconds = GAMESTATE->m_fMusicSeconds;
|
m_fLastMusicSeconds = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundImpl::DrawPrimitives()
|
void BackgroundImpl::DrawPrimitives()
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ void BeginnerHelper::ShowStepCircle( PlayerNumber pn, int CSTEP )
|
|||||||
m_sStepCircle[pn][isc].StopEffect();
|
m_sStepCircle[pn][isc].StopEffect();
|
||||||
m_sStepCircle[pn][isc].SetZoom( 2 );
|
m_sStepCircle[pn][isc].SetZoom( 2 );
|
||||||
m_sStepCircle[pn][isc].StopTweening();
|
m_sStepCircle[pn][isc].StopTweening();
|
||||||
m_sStepCircle[pn][isc].BeginTweening( GAMESTATE->m_fCurBPS/3, TWEEN_LINEAR );
|
m_sStepCircle[pn][isc].BeginTweening( GAMESTATE->m_Position.m_fCurBPS/3, TWEEN_LINEAR );
|
||||||
m_sStepCircle[pn][isc].SetZoom( 0 );
|
m_sStepCircle[pn][isc].SetZoom( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,19 +318,19 @@ void BeginnerHelper::Step( PlayerNumber pn, int CSTEP )
|
|||||||
ShowStepCircle( pn, ST_DOWN );
|
ShowStepCircle( pn, ST_DOWN );
|
||||||
m_pDancer[pn]->StopTweening();
|
m_pDancer[pn]->StopTweening();
|
||||||
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
|
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
|
||||||
m_pDancer[pn]->BeginTweening( GAMESTATE->m_fCurBPS/8, TWEEN_LINEAR );
|
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS/8, TWEEN_LINEAR );
|
||||||
m_pDancer[pn]->SetRotationY( 90 );
|
m_pDancer[pn]->SetRotationY( 90 );
|
||||||
m_pDancer[pn]->BeginTweening( 1/(GAMESTATE->m_fCurBPS * 2) ); //sleep between jump-frames
|
m_pDancer[pn]->BeginTweening( 1/(GAMESTATE->m_Position.m_fCurBPS * 2) ); //sleep between jump-frames
|
||||||
m_pDancer[pn]->BeginTweening( GAMESTATE->m_fCurBPS /6, TWEEN_LINEAR );
|
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR );
|
||||||
m_pDancer[pn]->SetRotationY( 0 );
|
m_pDancer[pn]->SetRotationY( 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sFlash.StopEffect();
|
m_sFlash.StopEffect();
|
||||||
m_sFlash.StopTweening();
|
m_sFlash.StopTweening();
|
||||||
m_sFlash.Sleep( GAMESTATE->m_fCurBPS/16 );
|
m_sFlash.Sleep( GAMESTATE->m_Position.m_fCurBPS/16 );
|
||||||
m_sFlash.SetDiffuseAlpha( 1 );
|
m_sFlash.SetDiffuseAlpha( 1 );
|
||||||
m_sFlash.BeginTweening( 1/GAMESTATE->m_fCurBPS * 0.5f );
|
m_sFlash.BeginTweening( 1/GAMESTATE->m_Position.m_fCurBPS * 0.5f );
|
||||||
m_sFlash.SetDiffuseAlpha( 0 );
|
m_sFlash.SetDiffuseAlpha( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ void BeginnerHelper::Update( float fDeltaTime )
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// the row we want to check on this update
|
// the row we want to check on this update
|
||||||
int iCurRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat + 0.4f );
|
int iCurRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.4f );
|
||||||
FOREACH_EnabledPlayer( pn )
|
FOREACH_EnabledPlayer( pn )
|
||||||
{
|
{
|
||||||
for( int iRow=m_iLastRowChecked; iRow<iCurRow; iRow++ )
|
for( int iRow=m_iLastRowChecked; iRow<iCurRow; iRow++ )
|
||||||
@@ -369,7 +369,7 @@ void BeginnerHelper::Update( float fDeltaTime )
|
|||||||
m_pDancePad->Update( fDeltaTime );
|
m_pDancePad->Update( fDeltaTime );
|
||||||
m_sFlash.Update( fDeltaTime );
|
m_sFlash.Update( fDeltaTime );
|
||||||
|
|
||||||
float beat = fDeltaTime*GAMESTATE->m_fCurBPS;
|
float beat = fDeltaTime*GAMESTATE->m_Position.m_fCurBPS;
|
||||||
// If this is not a human player, the dancer is not shown
|
// If this is not a human player, the dancer is not shown
|
||||||
FOREACH_HumanPlayer( pu )
|
FOREACH_HumanPlayer( pu )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ int Neg1OrPos1() { return RandomInt( 2 ) ? -1 : +1; }
|
|||||||
|
|
||||||
void DancingCharacters::Update( float fDelta )
|
void DancingCharacters::Update( float fDelta )
|
||||||
{
|
{
|
||||||
if( GAMESTATE->m_bFreeze || GAMESTATE->m_bDelay )
|
if( GAMESTATE->m_Position.m_bFreeze || GAMESTATE->m_Position.m_bDelay )
|
||||||
{
|
{
|
||||||
// spin the camera Matrix-style
|
// spin the camera Matrix-style
|
||||||
m_CameraPanYStart += fDelta*40;
|
m_CameraPanYStart += fDelta*40;
|
||||||
@@ -184,7 +184,7 @@ void DancingCharacters::Update( float fDelta )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// make the characters move
|
// make the characters move
|
||||||
float fBPM = GAMESTATE->m_fCurBPS*60;
|
float fBPM = GAMESTATE->m_Position.m_fCurBPS*60;
|
||||||
float fUpdateScale = SCALE( fBPM, 60.f, 300.f, 0.75f, 1.5f );
|
float fUpdateScale = SCALE( fBPM, 60.f, 300.f, 0.75f, 1.5f );
|
||||||
CLAMP( fUpdateScale, 0.75f, 1.5f );
|
CLAMP( fUpdateScale, 0.75f, 1.5f );
|
||||||
|
|
||||||
@@ -209,8 +209,8 @@ void DancingCharacters::Update( float fDelta )
|
|||||||
}
|
}
|
||||||
bWasGameplayStarting = bGameplayStarting;
|
bWasGameplayStarting = bGameplayStarting;
|
||||||
|
|
||||||
static float fLastBeat = GAMESTATE->m_fSongBeat;
|
static float fLastBeat = GAMESTATE->m_Position.m_fSongBeat;
|
||||||
float fThisBeat = GAMESTATE->m_fSongBeat;
|
float fThisBeat = GAMESTATE->m_Position.m_fSongBeat;
|
||||||
if( fLastBeat < GAMESTATE->m_pCurSong->m_fFirstBeat &&
|
if( fLastBeat < GAMESTATE->m_pCurSong->m_fFirstBeat &&
|
||||||
fThisBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat )
|
fThisBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat )
|
||||||
{
|
{
|
||||||
@@ -220,7 +220,7 @@ void DancingCharacters::Update( float fDelta )
|
|||||||
fLastBeat = fThisBeat;
|
fLastBeat = fThisBeat;
|
||||||
|
|
||||||
// time for a new sweep?
|
// time for a new sweep?
|
||||||
if( GAMESTATE->m_fSongBeat > m_fThisCameraEndBeat )
|
if( GAMESTATE->m_Position.m_fSongBeat > m_fThisCameraEndBeat )
|
||||||
{
|
{
|
||||||
if( RandomInt(6) >= 4 )
|
if( RandomInt(6) >= 4 )
|
||||||
{
|
{
|
||||||
@@ -248,7 +248,7 @@ void DancingCharacters::Update( float fDelta )
|
|||||||
m_fLookAtHeight = CAMERA_STILL_LOOK_AT_HEIGHT;
|
m_fLookAtHeight = CAMERA_STILL_LOOK_AT_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iCurBeat = (int)GAMESTATE->m_fSongBeat;
|
int iCurBeat = (int)GAMESTATE->m_Position.m_fSongBeat;
|
||||||
iCurBeat -= iCurBeat%8;
|
iCurBeat -= iCurBeat%8;
|
||||||
|
|
||||||
m_fThisCameraStartBeat = (float) iCurBeat;
|
m_fThisCameraStartBeat = (float) iCurBeat;
|
||||||
@@ -313,7 +313,7 @@ void DancingCharacters::DrawPrimitives()
|
|||||||
if(m_fThisCameraStartBeat == m_fThisCameraEndBeat)
|
if(m_fThisCameraStartBeat == m_fThisCameraEndBeat)
|
||||||
fPercentIntoSweep = 0;
|
fPercentIntoSweep = 0;
|
||||||
else
|
else
|
||||||
fPercentIntoSweep = SCALE(GAMESTATE->m_fSongBeat, m_fThisCameraStartBeat, m_fThisCameraEndBeat, 0.f, 1.f );
|
fPercentIntoSweep = SCALE(GAMESTATE->m_Position.m_fSongBeat, m_fThisCameraStartBeat, m_fThisCameraEndBeat, 0.f, 1.f );
|
||||||
float fCameraPanY = SCALE( fPercentIntoSweep, 0.f, 1.f, m_CameraPanYStart, m_CameraPanYEnd );
|
float fCameraPanY = SCALE( fPercentIntoSweep, 0.f, 1.f, m_CameraPanYStart, m_CameraPanYEnd );
|
||||||
float fCameraHeight = SCALE( fPercentIntoSweep, 0.f, 1.f, m_fCameraHeightStart, m_fCameraHeightEnd );
|
float fCameraHeight = SCALE( fPercentIntoSweep, 0.f, 1.f, m_fCameraHeightStart, m_fCameraHeightEnd );
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -41,9 +41,9 @@ void Foreground::LoadFromSong( const Song *pSong )
|
|||||||
bga.m_fStartBeat = change.m_fStartBeat;
|
bga.m_fStartBeat = change.m_fStartBeat;
|
||||||
bga.m_bFinished = false;
|
bga.m_bFinished = false;
|
||||||
|
|
||||||
const float fStartSecond = pSong->m_Timing.GetElapsedTimeFromBeat( bga.m_fStartBeat );
|
const float fStartSecond = pSong->m_SongTiming.GetElapsedTimeFromBeat( bga.m_fStartBeat );
|
||||||
const float fStopSecond = fStartSecond + bga.m_bga->GetTweenTimeLeft();
|
const float fStopSecond = fStartSecond + bga.m_bga->GetTweenTimeLeft();
|
||||||
bga.m_fStopBeat = pSong->m_Timing.GetBeatFromElapsedTime( fStopSecond );
|
bga.m_fStopBeat = pSong->m_SongTiming.GetBeatFromElapsedTime( fStopSecond );
|
||||||
|
|
||||||
bga.m_bga->SetVisible( false );
|
bga.m_bga->SetVisible( false );
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ void Foreground::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
LoadedBGA &bga = m_BGAnimations[i];
|
LoadedBGA &bga = m_BGAnimations[i];
|
||||||
|
|
||||||
if( GAMESTATE->m_fSongBeat < bga.m_fStartBeat )
|
if( GAMESTATE->m_Position.m_fSongBeat < bga.m_fStartBeat )
|
||||||
{
|
{
|
||||||
// The animation hasn't started yet.
|
// The animation hasn't started yet.
|
||||||
continue;
|
continue;
|
||||||
@@ -82,12 +82,12 @@ void Foreground::Update( float fDeltaTime )
|
|||||||
bga.m_bga->SetVisible( true );
|
bga.m_bga->SetVisible( true );
|
||||||
bga.m_bga->PlayCommand( "On" );
|
bga.m_bga->PlayCommand( "On" );
|
||||||
|
|
||||||
const float fStartSecond = m_pSong->m_Timing.GetElapsedTimeFromBeat( bga.m_fStartBeat );
|
const float fStartSecond = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( bga.m_fStartBeat );
|
||||||
lDeltaTime = GAMESTATE->m_fMusicSeconds - fStartSecond;
|
lDeltaTime = GAMESTATE->m_Position.m_fMusicSeconds - fStartSecond;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lDeltaTime = GAMESTATE->m_fMusicSeconds - m_fLastMusicSeconds;
|
lDeltaTime = GAMESTATE->m_Position.m_fMusicSeconds - m_fLastMusicSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This shouldn't go down, but be safe:
|
// This shouldn't go down, but be safe:
|
||||||
@@ -95,7 +95,7 @@ void Foreground::Update( float fDeltaTime )
|
|||||||
|
|
||||||
bga.m_bga->Update( lDeltaTime / fRate );
|
bga.m_bga->Update( lDeltaTime / fRate );
|
||||||
|
|
||||||
if( GAMESTATE->m_fSongBeat > bga.m_fStopBeat )
|
if( GAMESTATE->m_Position.m_fSongBeat > bga.m_fStopBeat )
|
||||||
{
|
{
|
||||||
// Finished.
|
// Finished.
|
||||||
bga.m_bga->SetVisible( false );
|
bga.m_bga->SetVisible( false );
|
||||||
@@ -104,7 +104,7 @@ void Foreground::Update( float fDeltaTime )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fLastMusicSeconds = GAMESTATE->m_fMusicSeconds;
|
m_fLastMusicSeconds = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+14
-14
@@ -146,7 +146,7 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) )
|
SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) )
|
||||||
{
|
{
|
||||||
ToPlay.HasTiming = true;
|
ToPlay.HasTiming = true;
|
||||||
ToPlay.m_TimingData = song.m_Timing;
|
ToPlay.m_TimingData = song.m_SongTiming;
|
||||||
// get cabinet lights if any
|
// get cabinet lights if any
|
||||||
Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet );
|
Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet );
|
||||||
if( pStepsCabinetLights )
|
if( pStepsCabinetLights )
|
||||||
@@ -156,7 +156,7 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) )
|
SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) )
|
||||||
{
|
{
|
||||||
ToPlay.HasTiming = true;
|
ToPlay.HasTiming = true;
|
||||||
ToPlay.m_TimingData = song.m_Timing;
|
ToPlay.m_TimingData = song.m_SongTiming;
|
||||||
// get cabinet lights if any
|
// get cabinet lights if any
|
||||||
Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet );
|
Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet );
|
||||||
if( pStepsCabinetLights )
|
if( pStepsCabinetLights )
|
||||||
@@ -201,7 +201,7 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
{
|
{
|
||||||
/* This song has no real timing data. The offset is arbitrary. Change it so
|
/* This song has no real timing data. The offset is arbitrary. Change it so
|
||||||
* the beat will line up to where we are now, so we don't have to delay. */
|
* the beat will line up to where we are now, so we don't have to delay. */
|
||||||
float fDestBeat = fmodfp( GAMESTATE->m_fSongBeatNoOffset, 1 );
|
float fDestBeat = fmodfp( GAMESTATE->m_Position.m_fSongBeatNoOffset, 1 );
|
||||||
float fTime = NewMusic->m_NewTiming.GetElapsedTimeFromBeatNoOffset( fDestBeat );
|
float fTime = NewMusic->m_NewTiming.GetElapsedTimeFromBeatNoOffset( fDestBeat );
|
||||||
|
|
||||||
NewMusic->m_NewTiming.m_fBeat0OffsetInSeconds = fTime;
|
NewMusic->m_NewTiming.m_fBeat0OffsetInSeconds = fTime;
|
||||||
@@ -223,7 +223,7 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
* common when starting a precached sound, but our sound isn't, so it'll
|
* common when starting a precached sound, but our sound isn't, so it'll
|
||||||
* probably take a little longer. Nudge the latency up. */
|
* probably take a little longer. Nudge the latency up. */
|
||||||
const float fPresumedLatency = SOUNDMAN->GetPlayLatency() + 0.040f;
|
const float fPresumedLatency = SOUNDMAN->GetPlayLatency() + 0.040f;
|
||||||
const float fCurSecond = GAMESTATE->m_fMusicSeconds + fPresumedLatency;
|
const float fCurSecond = GAMESTATE->m_Position.m_fMusicSeconds + fPresumedLatency;
|
||||||
const float fCurBeat = g_Playing->m_Timing.GetBeatFromElapsedTimeNoOffset( fCurSecond );
|
const float fCurBeat = g_Playing->m_Timing.GetBeatFromElapsedTimeNoOffset( fCurSecond );
|
||||||
|
|
||||||
/* The beat that the new sound will start on. */
|
/* The beat that the new sound will start on. */
|
||||||
@@ -236,9 +236,9 @@ static void StartMusic( MusicToPlay &ToPlay )
|
|||||||
|
|
||||||
const float fSecondToStartOn = g_Playing->m_Timing.GetElapsedTimeFromBeatNoOffset( fCurBeatToStartOn );
|
const float fSecondToStartOn = g_Playing->m_Timing.GetElapsedTimeFromBeatNoOffset( fCurBeatToStartOn );
|
||||||
const float fMaximumDistance = 2;
|
const float fMaximumDistance = 2;
|
||||||
const float fDistance = min( fSecondToStartOn - GAMESTATE->m_fMusicSeconds, fMaximumDistance );
|
const float fDistance = min( fSecondToStartOn - GAMESTATE->m_Position.m_fMusicSeconds, fMaximumDistance );
|
||||||
|
|
||||||
when = GAMESTATE->m_LastBeatUpdate + fDistance;
|
when = GAMESTATE->m_Position.m_LastBeatUpdate + fDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Important: don't hold the mutex while we load and seek the actual sound. */
|
/* Important: don't hold the mutex while we load and seek the actual sound. */
|
||||||
@@ -552,8 +552,8 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
if( !g_Playing->m_Music->IsPlaying() )
|
if( !g_Playing->m_Music->IsPlaying() )
|
||||||
{
|
{
|
||||||
/* There's no song playing. Fake it. */
|
/* There's no song playing. Fake it. */
|
||||||
CHECKPOINT_M( ssprintf("%f, delta %f", GAMESTATE->m_fMusicSeconds, fDeltaTime) );
|
CHECKPOINT_M( ssprintf("%f, delta %f", GAMESTATE->m_Position.m_fMusicSeconds, fDeltaTime) );
|
||||||
GAMESTATE->UpdateSongPosition( GAMESTATE->m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
|
GAMESTATE->UpdateSongPosition( GAMESTATE->m_Position.m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,8 +570,8 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
//
|
//
|
||||||
if( PREFSMAN->m_bLogSkips && !g_Playing->m_bTimingDelayed )
|
if( PREFSMAN->m_bLogSkips && !g_Playing->m_bTimingDelayed )
|
||||||
{
|
{
|
||||||
const float fExpectedTimePassed = (tm - GAMESTATE->m_LastBeatUpdate) * g_Playing->m_Music->GetPlaybackRate();
|
const float fExpectedTimePassed = (tm - GAMESTATE->m_Position.m_LastBeatUpdate) * g_Playing->m_Music->GetPlaybackRate();
|
||||||
const float fSoundTimePassed = fSeconds - GAMESTATE->m_fMusicSeconds;
|
const float fSoundTimePassed = fSeconds - GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
const float fDiff = fExpectedTimePassed - fSoundTimePassed;
|
const float fDiff = fExpectedTimePassed - fSoundTimePassed;
|
||||||
|
|
||||||
static RString sLastFile = "";
|
static RString sLastFile = "";
|
||||||
@@ -580,7 +580,7 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
/* If fSoundTimePassed < 0, the sound has probably looped. */
|
/* If fSoundTimePassed < 0, the sound has probably looped. */
|
||||||
if( sLastFile == ThisFile && fSoundTimePassed >= 0 && fabsf(fDiff) > 0.003f )
|
if( sLastFile == ThisFile && fSoundTimePassed >= 0 && fabsf(fDiff) > 0.003f )
|
||||||
LOG->Trace("Song position skip in %s: expected %.3f, got %.3f (cur %f, prev %f) (%.3f difference)",
|
LOG->Trace("Song position skip in %s: expected %.3f, got %.3f (cur %f, prev %f) (%.3f difference)",
|
||||||
Basename(ThisFile).c_str(), fExpectedTimePassed, fSoundTimePassed, fSeconds, GAMESTATE->m_fMusicSeconds, fDiff );
|
Basename(ThisFile).c_str(), fExpectedTimePassed, fSoundTimePassed, fSeconds, GAMESTATE->m_Position.m_fMusicSeconds, fDiff );
|
||||||
sLastFile = ThisFile;
|
sLastFile = ThisFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,7 +599,7 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
/* We're still waiting for the new sound to start playing, so keep using the
|
/* We're still waiting for the new sound to start playing, so keep using the
|
||||||
* old timing data and fake the time. */
|
* old timing data and fake the time. */
|
||||||
GAMESTATE->UpdateSongPosition( GAMESTATE->m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
|
GAMESTATE->UpdateSongPosition( GAMESTATE->m_Position.m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -614,7 +614,7 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
static int iBeatLastCrossed = 0;
|
static int iBeatLastCrossed = 0;
|
||||||
|
|
||||||
float fSongBeat = GAMESTATE->m_fSongBeat;
|
float fSongBeat = GAMESTATE->m_Position.m_fSongBeat;
|
||||||
|
|
||||||
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
||||||
iRowNow = max( 0, iRowNow );
|
iRowNow = max( 0, iRowNow );
|
||||||
@@ -638,7 +638,7 @@ void GameSoundManager::Update( float fDeltaTime )
|
|||||||
NoteData &lights = g_Playing->m_Lights;
|
NoteData &lights = g_Playing->m_Lights;
|
||||||
if( lights.GetNumTracks() > 0 ) // lights data was loaded
|
if( lights.GetNumTracks() > 0 ) // lights data was loaded
|
||||||
{
|
{
|
||||||
const float fSongBeat = GAMESTATE->m_fLightSongBeat;
|
const float fSongBeat = GAMESTATE->m_Position.m_fLightSongBeat;
|
||||||
const int iSongRow = BeatToNoteRowNotRounded( fSongBeat );
|
const int iSongRow = BeatToNoteRowNotRounded( fSongBeat );
|
||||||
|
|
||||||
static int iRowLastCrossed = 0;
|
static int iRowLastCrossed = 0;
|
||||||
|
|||||||
+31
-64
@@ -127,7 +127,9 @@ GameState::GameState() :
|
|||||||
m_pEditSourceSteps( Message_EditSourceStepsChanged ),
|
m_pEditSourceSteps( Message_EditSourceStepsChanged ),
|
||||||
m_stEditSource( Message_EditSourceStepsTypeChanged ),
|
m_stEditSource( Message_EditSourceStepsTypeChanged ),
|
||||||
m_iEditCourseEntryIndex( Message_EditCourseEntryIndexChanged ),
|
m_iEditCourseEntryIndex( Message_EditCourseEntryIndexChanged ),
|
||||||
m_sEditLocalProfileID( Message_EditLocalProfileIDChanged )
|
m_sEditLocalProfileID( Message_EditLocalProfileIDChanged ),
|
||||||
|
m_bIsUsingStepTiming( true ),
|
||||||
|
m_bInStepEditor( false )
|
||||||
{
|
{
|
||||||
g_pImpl = new GameStateImpl;
|
g_pImpl = new GameStateImpl;
|
||||||
|
|
||||||
@@ -893,22 +895,15 @@ const float GameState::MUSIC_SECONDS_INVALID = -5000.0f;
|
|||||||
|
|
||||||
void GameState::ResetMusicStatistics()
|
void GameState::ResetMusicStatistics()
|
||||||
{
|
{
|
||||||
m_fMusicSeconds = 0; // MUSIC_SECONDS_INVALID;
|
m_Position.Reset();
|
||||||
// todo: move me to FOREACH_EnabledPlayer( p ) after [NUM_PLAYERS]ing
|
|
||||||
m_fSongBeat = 0;
|
|
||||||
m_fSongBeatNoOffset = 0;
|
|
||||||
m_fCurBPS = 10;
|
|
||||||
//m_bStop = false;
|
|
||||||
m_bFreeze = false;
|
|
||||||
m_bDelay = false;
|
|
||||||
m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj
|
|
||||||
m_fWarpDestination = -1; // Set when a warp is encountered. also see above. -aj
|
|
||||||
m_fMusicSecondsVisible = 0;
|
|
||||||
m_fSongBeatVisible = 0;
|
|
||||||
Actor::SetBGMTime( 0, 0, 0, 0 );
|
Actor::SetBGMTime( 0, 0, 0, 0 );
|
||||||
|
|
||||||
FOREACH_PlayerNumber( p )
|
FOREACH_PlayerNumber( p )
|
||||||
|
{
|
||||||
m_pPlayerState[p]->ClearHopoState();
|
m_pPlayerState[p]->ClearHopoState();
|
||||||
|
m_pPlayerState[p]->m_Position.Reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::ResetStageStatistics()
|
void GameState::ResetStageStatistics()
|
||||||
@@ -947,57 +942,23 @@ void GameState::ResetStageStatistics()
|
|||||||
m_iStageSeed = rand();
|
m_iStageSeed = rand();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Preference<float> g_fVisualDelaySeconds( "VisualDelaySeconds", 0.0f );
|
void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp, bool bUpdatePlayers )
|
||||||
|
|
||||||
void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp )
|
|
||||||
{
|
{
|
||||||
if( !timestamp.IsZero() )
|
|
||||||
m_LastBeatUpdate = timestamp;
|
|
||||||
else
|
|
||||||
m_LastBeatUpdate.Touch();
|
|
||||||
|
|
||||||
// xxx testing: only do this on monotune survivor
|
m_Position.UpdateSongPosition( fPositionSeconds, timing, timestamp );
|
||||||
/*
|
|
||||||
if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" )
|
|
||||||
LOG->Trace( ssprintf("[GameState::UpdateSongPosition] cur BPS = %f, fPositionSeconds = %f",m_fCurBPS,fPositionSeconds) );
|
|
||||||
*/
|
|
||||||
|
|
||||||
timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay, m_iWarpBeginRow, m_fWarpDestination );
|
if( bUpdatePlayers )
|
||||||
// "Crash reason : -243478.890625 -48695.773438"
|
|
||||||
ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds", m_fSongBeat, fPositionSeconds) );
|
|
||||||
|
|
||||||
m_fMusicSeconds = fPositionSeconds;
|
|
||||||
|
|
||||||
m_fLightSongBeat = timing.GetBeatFromElapsedTime( fPositionSeconds + g_fLightsAheadSeconds );
|
|
||||||
|
|
||||||
m_fSongBeatNoOffset = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds );
|
|
||||||
|
|
||||||
m_fMusicSecondsVisible = fPositionSeconds - g_fVisualDelaySeconds.Get();
|
|
||||||
float fThrowAway, fThrowAway2;
|
|
||||||
bool bThrowAway;
|
|
||||||
int iThrowAway;
|
|
||||||
timing.GetBeatAndBPSFromElapsedTime( m_fMusicSecondsVisible, m_fSongBeatVisible, fThrowAway, bThrowAway, bThrowAway, iThrowAway, fThrowAway2 );
|
|
||||||
|
|
||||||
/*
|
|
||||||
// xxx testing: only do this on monotune survivor
|
|
||||||
if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" )
|
|
||||||
{
|
{
|
||||||
// and only do it in the known negative bpm region. HACKITY HACK
|
FOREACH_EnabledPlayer( pn )
|
||||||
if(m_fSongBeat >= 445.490f && m_fSongBeat <= 453.72f)
|
|
||||||
{
|
{
|
||||||
LOG->Trace( ssprintf("fPositionSeconds = %f",fPositionSeconds) );
|
if( m_pCurSteps[pn] )
|
||||||
LOG->Trace( ssprintf("Song beat: %f (%f seconds), BPS = %f (%f BPM)",m_fSongBeat,m_fMusicSecondsVisible,m_fCurBPS,m_fCurBPS*60.0f) );
|
|
||||||
//LOG->Trace( ssprintf("Music seconds visible %f = fPositionSeconds %f - g_fVisualDelaySeconds %f", m_fMusicSecondsVisible,fPositionSeconds,g_fVisualDelaySeconds.Get()) );
|
|
||||||
}
|
|
||||||
else if(m_fSongBeat == 445.500f)
|
|
||||||
{
|
{
|
||||||
LOG->Trace( ssprintf("[beat 445.500] fPositionSeconds = %f",fPositionSeconds) );
|
m_pPlayerState[pn]->m_Position.UpdateSongPosition( fPositionSeconds, m_pCurSteps[pn]->m_Timing, timestamp );
|
||||||
LOG->Trace( ssprintf("Song beat: %f (%f seconds), BPS = %f (%f BPM)",m_fSongBeat,m_fMusicSecondsVisible,m_fCurBPS,m_fCurBPS*60.0f) );
|
Actor::SetPlayerBGMBeat( pn, m_pPlayerState[pn]->m_Position.m_fSongBeatVisible, m_pPlayerState[pn]->m_Position.m_fSongBeatNoOffset );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
}
|
||||||
|
Actor::SetBGMTime( GAMESTATE->m_Position.m_fMusicSecondsVisible, GAMESTATE->m_Position.m_fSongBeatVisible, fPositionSeconds, GAMESTATE->m_Position.m_fSongBeatNoOffset );
|
||||||
Actor::SetBGMTime( m_fMusicSecondsVisible, m_fSongBeatVisible, fPositionSeconds, m_fSongBeatNoOffset );
|
|
||||||
// LOG->Trace( "m_fMusicSeconds = %f, m_fSongBeat = %f, m_fCurBPS = %f, m_bFreeze = %f", m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
|
// LOG->Trace( "m_fMusicSeconds = %f, m_fSongBeat = %f, m_fCurBPS = %f, m_bFreeze = %f", m_fMusicSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2291,11 +2252,16 @@ public:
|
|||||||
DEFINE_METHOD( GetHardestStepsDifficulty, GetHardestStepsDifficulty() )
|
DEFINE_METHOD( GetHardestStepsDifficulty, GetHardestStepsDifficulty() )
|
||||||
DEFINE_METHOD( IsEventMode, IsEventMode() )
|
DEFINE_METHOD( IsEventMode, IsEventMode() )
|
||||||
DEFINE_METHOD( GetNumPlayersEnabled, GetNumPlayersEnabled() )
|
DEFINE_METHOD( GetNumPlayersEnabled, GetNumPlayersEnabled() )
|
||||||
DEFINE_METHOD( GetSongBeat, m_fSongBeat )
|
/*DEFINE_METHOD( GetSongBeat, m_Position.m_fSongBeat )
|
||||||
DEFINE_METHOD( GetSongBeatVisible, m_fSongBeatVisible )
|
DEFINE_METHOD( GetSongBeatVisible, m_Position.m_fSongBeatVisible )
|
||||||
DEFINE_METHOD( GetSongBPS, m_fCurBPS )
|
DEFINE_METHOD( GetSongBPS, m_Position.m_fCurBPS )
|
||||||
DEFINE_METHOD( GetSongFreeze, m_bFreeze )
|
DEFINE_METHOD( GetSongFreeze, m_Position.m_bFreeze )
|
||||||
DEFINE_METHOD( GetSongDelay, m_bDelay )
|
DEFINE_METHOD( GetSongDelay, m_Position.m_bDelay )*/
|
||||||
|
static int GetSongPosition( T* p, lua_State *L )
|
||||||
|
{
|
||||||
|
p->m_Position.PushSelf(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
DEFINE_METHOD( GetGameplayLeadIn, m_bGameplayLeadIn )
|
DEFINE_METHOD( GetGameplayLeadIn, m_bGameplayLeadIn )
|
||||||
DEFINE_METHOD( GetCoins, m_iCoins )
|
DEFINE_METHOD( GetCoins, m_iCoins )
|
||||||
DEFINE_METHOD( IsSideJoined, m_bSideIsJoined[Enum::Check<PlayerNumber>(L, 1)] )
|
DEFINE_METHOD( IsSideJoined, m_bSideIsJoined[Enum::Check<PlayerNumber>(L, 1)] )
|
||||||
@@ -2434,7 +2400,7 @@ public:
|
|||||||
static int JoinPlayer( T* p, lua_State *L ) { p->JoinPlayer(Enum::Check<PlayerNumber>(L, 1)); return 0; }
|
static int JoinPlayer( T* p, lua_State *L ) { p->JoinPlayer(Enum::Check<PlayerNumber>(L, 1)); return 0; }
|
||||||
static int UnjoinPlayer( T* p, lua_State *L ) { p->UnjoinPlayer(Enum::Check<PlayerNumber>(L, 1)); return 0; }
|
static int UnjoinPlayer( T* p, lua_State *L ) { p->UnjoinPlayer(Enum::Check<PlayerNumber>(L, 1)); return 0; }
|
||||||
static int GetSongPercent( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongPercent(FArg(1))); return 1; }
|
static int GetSongPercent( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongPercent(FArg(1))); return 1; }
|
||||||
DEFINE_METHOD( GetCurMusicSeconds, m_fMusicSeconds )
|
DEFINE_METHOD( GetCurMusicSeconds, m_Position.m_fMusicSeconds )
|
||||||
|
|
||||||
DEFINE_METHOD( GetWorkoutGoalComplete, m_bWorkoutGoalComplete )
|
DEFINE_METHOD( GetWorkoutGoalComplete, m_bWorkoutGoalComplete )
|
||||||
static int GetCharacter( T* p, lua_State *L ) { p->m_pCurCharacters[Enum::Check<PlayerNumber>(L, 1)]->PushSelf(L); return 1; }
|
static int GetCharacter( T* p, lua_State *L ) { p->m_pCurCharacters[Enum::Check<PlayerNumber>(L, 1)]->PushSelf(L); return 1; }
|
||||||
@@ -2500,11 +2466,12 @@ public:
|
|||||||
ADD_METHOD( GetHardestStepsDifficulty );
|
ADD_METHOD( GetHardestStepsDifficulty );
|
||||||
ADD_METHOD( IsEventMode );
|
ADD_METHOD( IsEventMode );
|
||||||
ADD_METHOD( GetNumPlayersEnabled );
|
ADD_METHOD( GetNumPlayersEnabled );
|
||||||
ADD_METHOD( GetSongBeat );
|
/*ADD_METHOD( GetSongBeat );
|
||||||
ADD_METHOD( GetSongBeatVisible );
|
ADD_METHOD( GetSongBeatVisible );
|
||||||
ADD_METHOD( GetSongBPS );
|
ADD_METHOD( GetSongBPS );
|
||||||
ADD_METHOD( GetSongFreeze );
|
ADD_METHOD( GetSongFreeze );
|
||||||
ADD_METHOD( GetSongDelay );
|
ADD_METHOD( GetSongDelay );*/
|
||||||
|
ADD_METHOD( GetSongPosition );
|
||||||
ADD_METHOD( GetGameplayLeadIn );
|
ADD_METHOD( GetGameplayLeadIn );
|
||||||
ADD_METHOD( GetCoins );
|
ADD_METHOD( GetCoins );
|
||||||
ADD_METHOD( IsSideJoined );
|
ADD_METHOD( IsSideJoined );
|
||||||
|
|||||||
+44
-29
@@ -10,6 +10,7 @@
|
|||||||
#include "RageTimer.h"
|
#include "RageTimer.h"
|
||||||
#include "PlayerOptions.h"
|
#include "PlayerOptions.h"
|
||||||
#include "SongOptions.h"
|
#include "SongOptions.h"
|
||||||
|
#include "SongPosition.h"
|
||||||
#include "Preference.h"
|
#include "Preference.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -43,7 +44,8 @@ public:
|
|||||||
void ResetPlayer( PlayerNumber pn );
|
void ResetPlayer( PlayerNumber pn );
|
||||||
void ApplyCmdline(); // called by Reset
|
void ApplyCmdline(); // called by Reset
|
||||||
void ApplyGameCommand( const RString &sCommand, PlayerNumber pn=PLAYER_INVALID );
|
void ApplyGameCommand( const RString &sCommand, PlayerNumber pn=PLAYER_INVALID );
|
||||||
void BeginGame(); // called when first player joins
|
/** @brief Start the game when the first player joins in. */
|
||||||
|
void BeginGame();
|
||||||
void JoinPlayer( PlayerNumber pn );
|
void JoinPlayer( PlayerNumber pn );
|
||||||
void UnjoinPlayer( PlayerNumber pn );
|
void UnjoinPlayer( PlayerNumber pn );
|
||||||
bool JoinInput( PlayerNumber pn );
|
bool JoinInput( PlayerNumber pn );
|
||||||
@@ -55,13 +57,25 @@ public:
|
|||||||
bool HaveProfileToSave();
|
bool HaveProfileToSave();
|
||||||
void SaveLocalData();
|
void SaveLocalData();
|
||||||
void LoadCurrentSettingsFromProfile( PlayerNumber pn );
|
void LoadCurrentSettingsFromProfile( PlayerNumber pn );
|
||||||
void SaveCurrentSettingsToProfile( PlayerNumber pn ); // called at the beginning of each stage
|
/**
|
||||||
|
* @brief Save the specified player's settings to his/her profile.
|
||||||
|
*
|
||||||
|
* This is called at the beginning of each stage.
|
||||||
|
* @param pn the PlayerNumber to save the stats to. */
|
||||||
|
void SaveCurrentSettingsToProfile( PlayerNumber pn );
|
||||||
Song* GetDefaultSong() const;
|
Song* GetDefaultSong() const;
|
||||||
|
|
||||||
void Update( float fDelta );
|
void Update( float fDelta );
|
||||||
|
|
||||||
// Main state info
|
// Main state info
|
||||||
void SetCurGame( const Game *pGame ); // Call this instead of m_pCurGame.Set to make sure PREFSMAN->m_sCurrentGame stays in sync
|
|
||||||
|
/**
|
||||||
|
* @brief State what the current game is.
|
||||||
|
*
|
||||||
|
* Call this instead of m_pCurGame.Set to make sure that
|
||||||
|
* PREFSMAN->m_sCurrentGame stays in sync.
|
||||||
|
* @param pGame the game to start using. */
|
||||||
|
void SetCurGame( const Game *pGame );
|
||||||
BroadcastOnChangePtr<const Game> m_pCurGame;
|
BroadcastOnChangePtr<const Game> m_pCurGame;
|
||||||
BroadcastOnChangePtr<const Style> m_pCurStyle;
|
BroadcastOnChangePtr<const Style> m_pCurStyle;
|
||||||
/** @brief Determine which side is joined.
|
/** @brief Determine which side is joined.
|
||||||
@@ -129,6 +143,9 @@ public:
|
|||||||
bool IsCourseMode() const;
|
bool IsCourseMode() const;
|
||||||
bool IsBattleMode() const; // not Rave
|
bool IsBattleMode() const; // not Rave
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Do we show the W1 timing judgment?
|
||||||
|
* @return true if we do, or false otherwise. */
|
||||||
bool ShowW1() const;
|
bool ShowW1() const;
|
||||||
|
|
||||||
BroadcastOnChange<RString> m_sPreferredSongGroup; // GROUP_ALL denotes no preferred group
|
BroadcastOnChange<RString> m_sPreferredSongGroup; // GROUP_ALL denotes no preferred group
|
||||||
@@ -141,7 +158,11 @@ public:
|
|||||||
SortOrder m_PreferredSortOrder; // used by MusicWheel
|
SortOrder m_PreferredSortOrder; // used by MusicWheel
|
||||||
EditMode m_EditMode;
|
EditMode m_EditMode;
|
||||||
bool IsEditing() const { return m_EditMode != EditMode_Invalid; }
|
bool IsEditing() const { return m_EditMode != EditMode_Invalid; }
|
||||||
bool m_bDemonstrationOrJukebox; // ScreenGameplay does special stuff when this is true
|
/**
|
||||||
|
* @brief Are we in the demonstration or jukebox mode?
|
||||||
|
*
|
||||||
|
* ScreenGameplay often does special things when this is set to true. */
|
||||||
|
bool m_bDemonstrationOrJukebox;
|
||||||
bool m_bJukeboxUsesModifiers;
|
bool m_bJukeboxUsesModifiers;
|
||||||
int m_iNumStagesOfThisSong;
|
int m_iNumStagesOfThisSong;
|
||||||
/**
|
/**
|
||||||
@@ -194,29 +215,9 @@ public:
|
|||||||
bool m_bBackedOutOfFinalStage;
|
bool m_bBackedOutOfFinalStage;
|
||||||
|
|
||||||
// Music statistics:
|
// Music statistics:
|
||||||
// Arcade - the current stage (one song).
|
SongPosition m_Position;
|
||||||
// Oni/Endless - a single song in a course.
|
|
||||||
// Let a lot of classes access this info here so they don't have to keep their own copies.
|
|
||||||
// todo: [NUM_PLAYERS] this for split bpm lolol -aj
|
|
||||||
float m_fMusicSeconds; // time into the current song, not scaled by music rate
|
|
||||||
float m_fSongBeat;
|
|
||||||
float m_fSongBeatNoOffset;
|
|
||||||
float m_fCurBPS;
|
|
||||||
float m_fLightSongBeat; // g_fLightsFalloffSeconds ahead
|
|
||||||
//bool m_bStop; // in the middle of a stop (freeze or delay)
|
|
||||||
/** @brief A flag to determine if we're in the middle of a freeze/stop. */
|
|
||||||
bool m_bFreeze;
|
|
||||||
/** @brief A flag to determine if we're in the middle of a delay (Pump style stop). */
|
|
||||||
bool m_bDelay;
|
|
||||||
/** @brief The row used to start a warp. */
|
|
||||||
int m_iWarpBeginRow;
|
|
||||||
/** @brief The beat to warp to afterwards. */
|
|
||||||
float m_fWarpDestination;
|
|
||||||
RageTimer m_LastBeatUpdate; // time of last m_fSongBeat, etc. update
|
|
||||||
BroadcastOnChange<bool> m_bGameplayLeadIn;
|
|
||||||
|
|
||||||
float m_fMusicSecondsVisible;
|
BroadcastOnChange<bool> m_bGameplayLeadIn;
|
||||||
float m_fSongBeatVisible;
|
|
||||||
|
|
||||||
// if re-adding noteskin changes in courses, add functions and such here -aj
|
// if re-adding noteskin changes in courses, add functions and such here -aj
|
||||||
void GetAllUsedNoteSkins( vector<RString> &out ) const;
|
void GetAllUsedNoteSkins( vector<RString> &out ) const;
|
||||||
@@ -224,7 +225,7 @@ public:
|
|||||||
static const float MUSIC_SECONDS_INVALID;
|
static const float MUSIC_SECONDS_INVALID;
|
||||||
|
|
||||||
void ResetMusicStatistics(); // Call this when it's time to play a new song. Clears the values above.
|
void ResetMusicStatistics(); // Call this when it's time to play a new song. Clears the values above.
|
||||||
void UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp = RageZeroTimer );
|
void UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp = RageZeroTimer, bool bUpdatePlayers = false );
|
||||||
float GetSongPercent( float beat ) const;
|
float GetSongPercent( float beat ) const;
|
||||||
|
|
||||||
bool AllAreInDangerOrWorse() const;
|
bool AllAreInDangerOrWorse() const;
|
||||||
@@ -259,8 +260,11 @@ public:
|
|||||||
// Options stuff
|
// Options stuff
|
||||||
ModsGroup<SongOptions> m_SongOptions;
|
ModsGroup<SongOptions> m_SongOptions;
|
||||||
|
|
||||||
// True if the current mode has changed the default NoteSkin, such as Edit/Sync Songs does.
|
/**
|
||||||
// Note: any mode that wants to use it must set it
|
* @brief Did the current game mode change the default Noteskin?
|
||||||
|
*
|
||||||
|
* This is true if it has: see Edit/Sync Songs for a common example.
|
||||||
|
* Note: any mode that wants to use this must set it explicitly. */
|
||||||
bool m_bDidModeChangeNoteSkin;
|
bool m_bDidModeChangeNoteSkin;
|
||||||
|
|
||||||
void GetDefaultPlayerOptions( PlayerOptions &po );
|
void GetDefaultPlayerOptions( PlayerOptions &po );
|
||||||
@@ -327,6 +331,17 @@ public:
|
|||||||
Premium GetPremium() const;
|
Premium GetPremium() const;
|
||||||
|
|
||||||
// Edit stuff
|
// Edit stuff
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Is the game right now using Song timing or Steps timing?
|
||||||
|
*
|
||||||
|
* Different options are available depending on this setting. */
|
||||||
|
bool m_bIsUsingStepTiming;
|
||||||
|
/**
|
||||||
|
* @brief Are we presently in the Step Editor, where some rules apply differently?
|
||||||
|
*
|
||||||
|
* TODO: Find a better way to implement this. */
|
||||||
|
bool m_bInStepEditor;
|
||||||
BroadcastOnChange<StepsType> m_stEdit;
|
BroadcastOnChange<StepsType> m_stEdit;
|
||||||
BroadcastOnChange<CourseDifficulty> m_cdEdit;
|
BroadcastOnChange<CourseDifficulty> m_cdEdit;
|
||||||
BroadcastOnChangePtr<Steps> m_pEditSourceSteps;
|
BroadcastOnChangePtr<Steps> m_pEditSourceSteps;
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ void GameplayAssist::PlayTicks( const NoteData &nd )
|
|||||||
* will start coming out the speaker. Compensate for this by boosting fPositionSeconds
|
* will start coming out the speaker. Compensate for this by boosting fPositionSeconds
|
||||||
* ahead. This is just to make sure that we request the sound early enough for it to
|
* ahead. This is just to make sure that we request the sound early enough for it to
|
||||||
* come out on time; the actual precise timing is handled by SetStartTime. */
|
* come out on time; the actual precise timing is handled by SetStartTime. */
|
||||||
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
|
float fPositionSeconds = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
fPositionSeconds += SOUNDMAN->GetPlayLatency() + (float)CommonMetrics::TICK_EARLY_SECONDS + 0.250f;
|
fPositionSeconds += SOUNDMAN->GetPlayLatency() + (float)CommonMetrics::TICK_EARLY_SECONDS + 0.250f;
|
||||||
const TimingData &timing = GAMESTATE->m_pCurSong->m_Timing;
|
const TimingData &timing = GAMESTATE->m_pCurSong->m_SongTiming;
|
||||||
const float fSongBeat = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds );
|
const float fSongBeat = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds );
|
||||||
|
|
||||||
const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) );
|
const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) );
|
||||||
@@ -47,11 +47,11 @@ void GameplayAssist::PlayTicks( const NoteData &nd )
|
|||||||
{
|
{
|
||||||
const float fTickBeat = NoteRowToBeat( iClapRow );
|
const float fTickBeat = NoteRowToBeat( iClapRow );
|
||||||
const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat );
|
const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat );
|
||||||
float fSecondsUntil = fTickSecond - GAMESTATE->m_fMusicSeconds;
|
float fSecondsUntil = fTickSecond - GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
fSecondsUntil /= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; /* 2x music rate means the time until the tick is halved */
|
fSecondsUntil /= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; /* 2x music rate means the time until the tick is halved */
|
||||||
|
|
||||||
RageSoundParams p;
|
RageSoundParams p;
|
||||||
p.m_StartTime = GAMESTATE->m_LastBeatUpdate + (fSecondsUntil - (float)CommonMetrics::TICK_EARLY_SECONDS);
|
p.m_StartTime = GAMESTATE->m_Position.m_LastBeatUpdate + (fSecondsUntil - (float)CommonMetrics::TICK_EARLY_SECONDS);
|
||||||
m_soundAssistClap.Play( &p );
|
m_soundAssistClap.Play( &p );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,11 +83,11 @@ void GameplayAssist::PlayTicks( const NoteData &nd )
|
|||||||
{
|
{
|
||||||
const float fTickBeat = NoteRowToBeat( iMetronomeRow );
|
const float fTickBeat = NoteRowToBeat( iMetronomeRow );
|
||||||
const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat );
|
const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat );
|
||||||
float fSecondsUntil = fTickSecond - GAMESTATE->m_fMusicSeconds;
|
float fSecondsUntil = fTickSecond - GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
fSecondsUntil /= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; /* 2x music rate means the time until the tick is halved */
|
fSecondsUntil /= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; /* 2x music rate means the time until the tick is halved */
|
||||||
|
|
||||||
RageSoundParams p;
|
RageSoundParams p;
|
||||||
p.m_StartTime = GAMESTATE->m_LastBeatUpdate + (fSecondsUntil - (float)CommonMetrics::TICK_EARLY_SECONDS);
|
p.m_StartTime = GAMESTATE->m_Position.m_LastBeatUpdate + (fSecondsUntil - (float)CommonMetrics::TICK_EARLY_SECONDS);
|
||||||
if( bIsMeasure )
|
if( bIsMeasure )
|
||||||
m_soundAssistMetronomeMeasure.Play( &p );
|
m_soundAssistMetronomeMeasure.Play( &p );
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ void Inventory::Update( float fDelta )
|
|||||||
|
|
||||||
// use items if this player is CPU-controlled
|
// use items if this player is CPU-controlled
|
||||||
if( m_pPlayerState->m_PlayerController != PC_HUMAN &&
|
if( m_pPlayerState->m_PlayerController != PC_HUMAN &&
|
||||||
GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
|
GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
|
||||||
{
|
{
|
||||||
// every 1 seconds, try to use an item
|
// every 1 seconds, try to use an item
|
||||||
int iLastSecond = (int)(RageTimer::GetTimeSinceStartFast() - fDelta);
|
int iLastSecond = (int)(RageTimer::GetTimeSinceStartFast() - fDelta);
|
||||||
|
|||||||
@@ -230,12 +230,12 @@ void LightsManager::Update( float fDeltaTime )
|
|||||||
static float fLastBeat;
|
static float fLastBeat;
|
||||||
static int iLight;
|
static int iLight;
|
||||||
|
|
||||||
if( fracf(GAMESTATE->m_fLightSongBeat) < fracf(fLastBeat) )
|
if( fracf(GAMESTATE->m_Position.m_fLightSongBeat) < fracf(fLastBeat) )
|
||||||
{
|
{
|
||||||
++iLight;
|
++iLight;
|
||||||
wrap( iLight, 4 );
|
wrap( iLight, 4 );
|
||||||
}
|
}
|
||||||
fLastBeat = GAMESTATE->m_fLightSongBeat;
|
fLastBeat = GAMESTATE->m_Position.m_fLightSongBeat;
|
||||||
switch( iLight )
|
switch( iLight )
|
||||||
{
|
{
|
||||||
case 0: m_LightsState.m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT] = true; break;
|
case 0: m_LightsState.m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT] = true; break;
|
||||||
@@ -405,7 +405,7 @@ void LightsManager::Update( float fDeltaTime )
|
|||||||
// If not joined, has enough credits, and not too late to join, then
|
// If not joined, has enough credits, and not too late to join, then
|
||||||
// blink the menu buttons rapidly so they'll press Start
|
// blink the menu buttons rapidly so they'll press Start
|
||||||
{
|
{
|
||||||
int iBeat = (int)(GAMESTATE->m_fLightSongBeat*4);
|
int iBeat = (int)(GAMESTATE->m_Position.m_fLightSongBeat*4);
|
||||||
bool bBlinkOn = (iBeat%2)==0;
|
bool bBlinkOn = (iBeat%2)==0;
|
||||||
FOREACH_PlayerNumber( pn )
|
FOREACH_PlayerNumber( pn )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ void LyricDisplay::Update( float fDeltaTime )
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If the song has changed (in a course), reset.
|
// If the song has changed (in a course), reset.
|
||||||
if( GAMESTATE->m_fMusicSeconds < m_fLastSecond )
|
if( GAMESTATE->m_Position.m_fMusicSeconds < m_fLastSecond )
|
||||||
Init();
|
Init();
|
||||||
m_fLastSecond = GAMESTATE->m_fMusicSeconds;
|
m_fLastSecond = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
|
|
||||||
if( m_iCurLyricNumber >= GAMESTATE->m_pCurSong->m_LyricSegments.size() )
|
if( m_iCurLyricNumber >= GAMESTATE->m_pCurSong->m_LyricSegments.size() )
|
||||||
return;
|
return;
|
||||||
@@ -51,7 +51,7 @@ void LyricDisplay::Update( float fDeltaTime )
|
|||||||
const Song *pSong = GAMESTATE->m_pCurSong;
|
const Song *pSong = GAMESTATE->m_pCurSong;
|
||||||
const float fStartTime = (pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime) - IN_LENGTH.GetValue();
|
const float fStartTime = (pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime) - IN_LENGTH.GetValue();
|
||||||
|
|
||||||
if( GAMESTATE->m_fMusicSeconds < fStartTime )
|
if( GAMESTATE->m_Position.m_fMusicSeconds < fStartTime )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clamp this lyric to the beginning of the next or the end of the music.
|
// Clamp this lyric to the beginning of the next or the end of the music.
|
||||||
@@ -59,7 +59,7 @@ void LyricDisplay::Update( float fDeltaTime )
|
|||||||
if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() )
|
if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() )
|
||||||
fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime;
|
fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime;
|
||||||
else
|
else
|
||||||
fEndTime = pSong->GetElapsedTimeFromBeat( pSong->m_fLastBeat );
|
fEndTime = pSong->m_SongTiming.GetElapsedTimeFromBeat( pSong->m_fLastBeat );
|
||||||
|
|
||||||
const float fDistance = fEndTime - pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime;
|
const float fDistance = fEndTime - pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime;
|
||||||
const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue();
|
const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue();
|
||||||
|
|||||||
+2
-1
@@ -373,7 +373,8 @@ ScoreDisplayBattle.cpp ScoreDisplayBattle.h \
|
|||||||
ScoreDisplayCalories.cpp ScoreDisplayCalories.h \
|
ScoreDisplayCalories.cpp ScoreDisplayCalories.h \
|
||||||
ScoreDisplayLifeTime.cpp ScoreDisplayLifeTime.h \
|
ScoreDisplayLifeTime.cpp ScoreDisplayLifeTime.h \
|
||||||
ScoreDisplayNormal.cpp ScoreDisplayNormal.h ScoreDisplayOni.cpp ScoreDisplayOni.h \
|
ScoreDisplayNormal.cpp ScoreDisplayNormal.h ScoreDisplayOni.cpp ScoreDisplayOni.h \
|
||||||
ScoreDisplayPercentage.cpp ScoreDisplayPercentage.h ScoreDisplayRave.cpp ScoreDisplayRave.h
|
ScoreDisplayPercentage.cpp ScoreDisplayPercentage.h ScoreDisplayRave.cpp ScoreDisplayRave.h \
|
||||||
|
SongPosition.cpp SongPosition.h
|
||||||
|
|
||||||
PCRE = ../extern/pcre/get.c ../extern/pcre/internal.h ../extern/pcre/maketables.c ../extern/pcre/pcre.c ../extern/pcre/pcre.h ../extern/pcre/study.c
|
PCRE = ../extern/pcre/get.c ../extern/pcre/internal.h ../extern/pcre/maketables.c ../extern/pcre/pcre.c ../extern/pcre/pcre.h ../extern/pcre/study.c
|
||||||
EXTRA_DIST += ../extern/pcre/chartables.c
|
EXTRA_DIST += ../extern/pcre/chartables.c
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ void SongMeterDisplay::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
if( GAMESTATE->m_pCurSong )
|
if( GAMESTATE->m_pCurSong )
|
||||||
{
|
{
|
||||||
float fSongStartSeconds = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat );
|
float fSongStartSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat );
|
||||||
float fSongEndSeconds = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
|
float fSongEndSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
|
||||||
float fPercentPositionSong = SCALE( GAMESTATE->m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f );
|
float fPercentPositionSong = SCALE( GAMESTATE->m_Position.m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f );
|
||||||
CLAMP( fPercentPositionSong, 0, 1 );
|
CLAMP( fPercentPositionSong, 0, 1 );
|
||||||
|
|
||||||
SetPercent( fPercentPositionSong );
|
SetPercent( fPercentPositionSong );
|
||||||
|
|||||||
@@ -2215,7 +2215,7 @@ void NoteDataUtil::AddTapAttacks( NoteData &nd, Song* pSong )
|
|||||||
|
|
||||||
for( float sec=15; sec<pSong->m_fMusicLengthSeconds; sec+=30 )
|
for( float sec=15; sec<pSong->m_fMusicLengthSeconds; sec+=30 )
|
||||||
{
|
{
|
||||||
float fBeat = pSong->GetBeatFromElapsedTime( sec );
|
float fBeat = pSong->m_SongTiming.GetBeatFromElapsedTime( sec );
|
||||||
int iBeat = (int)fBeat;
|
int iBeat = (int)fBeat;
|
||||||
int iTrack = iBeat % nd.GetNumTracks(); // deterministically calculates track
|
int iTrack = iBeat % nd.GetNumTracks(); // deterministically calculates track
|
||||||
TapNote tn(
|
TapNote tn(
|
||||||
@@ -2448,7 +2448,7 @@ void NoteDataUtil::SetHopoPossibleFlags( const Song *pSong, NoteData& ndInOut )
|
|||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS( ndInOut, r )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS( ndInOut, r )
|
||||||
{
|
{
|
||||||
float fBeat = NoteRowToBeat( r );
|
float fBeat = NoteRowToBeat( r );
|
||||||
float fSeconds = pSong->GetElapsedTimeFromBeat( fBeat );
|
float fSeconds = pSong->m_SongTiming.GetElapsedTimeFromBeat( fBeat );
|
||||||
|
|
||||||
int iLastTapTrack = ndInOut.GetLastTrackWithTapOrHoldHead( r );
|
int iLastTapTrack = ndInOut.GetLastTrackWithTapOrHoldHead( r );
|
||||||
if( iLastTapTrack != -1 && fSeconds <= fLastRowMusicSeconds + g_fTimingWindowHopo )
|
if( iLastTapTrack != -1 && fSeconds <= fLastRowMusicSeconds + g_fTimingWindowHopo )
|
||||||
|
|||||||
+1
-1
@@ -286,7 +286,7 @@ void NoteDisplay::Update( float fDeltaTime )
|
|||||||
void NoteDisplay::SetActiveFrame( float fNoteBeat, Actor &actorToSet, float fAnimationLength, bool bVivid )
|
void NoteDisplay::SetActiveFrame( float fNoteBeat, Actor &actorToSet, float fAnimationLength, bool bVivid )
|
||||||
{
|
{
|
||||||
/* -inf ... inf */
|
/* -inf ... inf */
|
||||||
float fBeatOrSecond = cache->m_bAnimationBasedOnBeats ? GAMESTATE->m_fSongBeat : GAMESTATE->m_fMusicSeconds;
|
float fBeatOrSecond = cache->m_bAnimationBasedOnBeats ? m_pPlayerState->m_Position.m_fSongBeat : m_pPlayerState->m_Position.m_fMusicSeconds;
|
||||||
/* -len ... +len */
|
/* -len ... +len */
|
||||||
float fPercentIntoAnimation = fmodf( fBeatOrSecond, fAnimationLength );
|
float fPercentIntoAnimation = fmodf( fBeatOrSecond, fAnimationLength );
|
||||||
/* -1 ... 1 */
|
/* -1 ... 1 */
|
||||||
|
|||||||
+146
-22
@@ -32,6 +32,33 @@ static ThemeMetric<float> FADE_FAIL_TIME( "NoteField", "FadeFailTime" );
|
|||||||
static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); }
|
static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); }
|
||||||
static ThemeMetric1D<RString> ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS );
|
static ThemeMetric1D<RString> ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS );
|
||||||
|
|
||||||
|
|
||||||
|
inline const TimingData *GetRealTiming(const PlayerState *pPlayerState)
|
||||||
|
{
|
||||||
|
if( GAMESTATE->m_pCurSteps[pPlayerState->m_PlayerNumber] != NULL )
|
||||||
|
return &GAMESTATE->m_pCurSteps[pPlayerState->m_PlayerNumber]->m_Timing;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const TimingData *GetDisplayedTiming(const PlayerState *pPlayerState)
|
||||||
|
{
|
||||||
|
if( !GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
return &GAMESTATE->m_pCurSong->m_SongTiming;
|
||||||
|
return GetRealTiming(pPlayerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const SongPosition *GetRealPosition(const PlayerState *pPlayerState)
|
||||||
|
{
|
||||||
|
return &pPlayerState->m_Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const SongPosition *GetDisplayedPosition(const PlayerState *pPlayerState)
|
||||||
|
{
|
||||||
|
if( !GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
return &GAMESTATE->m_Position;
|
||||||
|
return GetRealPosition(pPlayerState);
|
||||||
|
}
|
||||||
|
|
||||||
NoteField::NoteField()
|
NoteField::NoteField()
|
||||||
{
|
{
|
||||||
m_pNoteData = NULL;
|
m_pNoteData = NULL;
|
||||||
@@ -240,7 +267,7 @@ void NoteField::Update( float fDeltaTime )
|
|||||||
ActorFrame::Update( fDeltaTime );
|
ActorFrame::Update( fDeltaTime );
|
||||||
|
|
||||||
// update m_fBoardOffsetPixels, m_fCurrentBeatLastUpdate, m_fYPosCurrentBeatLastUpdate
|
// update m_fBoardOffsetPixels, m_fCurrentBeatLastUpdate, m_fYPosCurrentBeatLastUpdate
|
||||||
const float fCurrentBeat = GAMESTATE->m_fSongBeat;
|
const float fCurrentBeat = GetDisplayedPosition(m_pPlayerState)->m_fSongBeat;
|
||||||
bool bTweeningOn = m_sprBoard->GetCurrentDiffuseAlpha() >= 0.98 && m_sprBoard->GetCurrentDiffuseAlpha() < 1.00; // HACK
|
bool bTweeningOn = m_sprBoard->GetCurrentDiffuseAlpha() >= 0.98 && m_sprBoard->GetCurrentDiffuseAlpha() < 1.00; // HACK
|
||||||
if( !bTweeningOn && m_fCurrentBeatLastUpdate != -1 )
|
if( !bTweeningOn && m_fCurrentBeatLastUpdate != -1 )
|
||||||
{
|
{
|
||||||
@@ -427,6 +454,8 @@ static ThemeMetric<RageColor> TIME_SIGNATURE_COLOR ( "NoteField", "TimeSignature
|
|||||||
static ThemeMetric<RageColor> TICKCOUNT_COLOR ( "NoteField", "TickcountColor" );
|
static ThemeMetric<RageColor> TICKCOUNT_COLOR ( "NoteField", "TickcountColor" );
|
||||||
static ThemeMetric<RageColor> COMBO_COLOR ( "NoteField", "ComboColor" );
|
static ThemeMetric<RageColor> COMBO_COLOR ( "NoteField", "ComboColor" );
|
||||||
static ThemeMetric<RageColor> LABEL_COLOR ( "NoteField", "LabelColor" );
|
static ThemeMetric<RageColor> LABEL_COLOR ( "NoteField", "LabelColor" );
|
||||||
|
static ThemeMetric<RageColor> SPEED_COLOR ( "NoteField", "SpeedColor" );
|
||||||
|
static ThemeMetric<RageColor> FAKE_COLOR ("NoteField", "FakeColor" );
|
||||||
static ThemeMetric<bool> BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" );
|
static ThemeMetric<bool> BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" );
|
||||||
static ThemeMetric<bool> STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" );
|
static ThemeMetric<bool> STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" );
|
||||||
static ThemeMetric<bool> DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" );
|
static ThemeMetric<bool> DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" );
|
||||||
@@ -435,6 +464,8 @@ static ThemeMetric<bool> TIME_SIGNATURE_IS_LEFT_SIDE ( "NoteField", "TimeSignatu
|
|||||||
static ThemeMetric<bool> TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" );
|
static ThemeMetric<bool> TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" );
|
||||||
static ThemeMetric<bool> COMBO_IS_LEFT_SIDE ( "NoteField", "ComboIsLeftSide" );
|
static ThemeMetric<bool> COMBO_IS_LEFT_SIDE ( "NoteField", "ComboIsLeftSide" );
|
||||||
static ThemeMetric<bool> LABEL_IS_LEFT_SIDE ( "NoteField", "LabelIsLeftSide" );
|
static ThemeMetric<bool> LABEL_IS_LEFT_SIDE ( "NoteField", "LabelIsLeftSide" );
|
||||||
|
static ThemeMetric<bool> SPEED_IS_LEFT_SIDE ( "NoteField", "SpeedIsLeftSide" );
|
||||||
|
static ThemeMetric<bool> FAKE_IS_LEFT_SIDE ( "NoteField", "FakeIsLeftSide" );
|
||||||
static ThemeMetric<float> BPM_OFFSETX ( "NoteField", "BPMOffsetX" );
|
static ThemeMetric<float> BPM_OFFSETX ( "NoteField", "BPMOffsetX" );
|
||||||
static ThemeMetric<float> STOP_OFFSETX ( "NoteField", "StopOffsetX" );
|
static ThemeMetric<float> STOP_OFFSETX ( "NoteField", "StopOffsetX" );
|
||||||
static ThemeMetric<float> DELAY_OFFSETX ( "NoteField", "DelayOffsetX" );
|
static ThemeMetric<float> DELAY_OFFSETX ( "NoteField", "DelayOffsetX" );
|
||||||
@@ -443,6 +474,8 @@ static ThemeMetric<float> TIME_SIGNATURE_OFFSETX ( "NoteField", "TimeSignatureOf
|
|||||||
static ThemeMetric<float> TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" );
|
static ThemeMetric<float> TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" );
|
||||||
static ThemeMetric<float> COMBO_OFFSETX ( "NoteField", "ComboOffsetX" );
|
static ThemeMetric<float> COMBO_OFFSETX ( "NoteField", "ComboOffsetX" );
|
||||||
static ThemeMetric<float> LABEL_OFFSETX ( "NoteField", "LabelOffsetX" );
|
static ThemeMetric<float> LABEL_OFFSETX ( "NoteField", "LabelOffsetX" );
|
||||||
|
static ThemeMetric<float> SPEED_OFFSETX ( "NoteField", "SpeedOffsetX" );
|
||||||
|
static ThemeMetric<float> FAKE_OFFSETX ( "NoteField", "FakeOffsetX" );
|
||||||
|
|
||||||
void NoteField::DrawBPMText( const float fBeat, const float fBPM )
|
void NoteField::DrawBPMText( const float fBeat, const float fBPM )
|
||||||
{
|
{
|
||||||
@@ -572,6 +605,40 @@ void NoteField::DrawLabelText( const float fBeat, RString sLabel )
|
|||||||
m_textMeasureNumber.Draw();
|
m_textMeasureNumber.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoteField::DrawSpeedText( const float fBeat, float fPercent, float fWait, unsigned short usMode )
|
||||||
|
{
|
||||||
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
||||||
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
||||||
|
const float fZoom = ArrowEffects::GetZoom( m_pPlayerState );
|
||||||
|
const float xBase = GetWidth()/2.f;
|
||||||
|
const float xOffset = SPEED_OFFSETX * fZoom;
|
||||||
|
|
||||||
|
m_textMeasureNumber.SetZoom( fZoom );
|
||||||
|
m_textMeasureNumber.SetHorizAlign( SPEED_IS_LEFT_SIDE ? align_right : align_left );
|
||||||
|
m_textMeasureNumber.SetDiffuse( SPEED_COLOR );
|
||||||
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) );
|
||||||
|
m_textMeasureNumber.SetText( ssprintf("%.3f\n%s\n%.3f", fPercent, (usMode == 1 ? "S" : "B"), fWait) );
|
||||||
|
m_textMeasureNumber.SetXY( (SPEED_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos );
|
||||||
|
m_textMeasureNumber.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteField::DrawFakeText( const float fBeat, const float fNewBeat )
|
||||||
|
{
|
||||||
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
||||||
|
const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels );
|
||||||
|
const float fZoom = ArrowEffects::GetZoom( m_pPlayerState );
|
||||||
|
const float xBase = GetWidth()/2.f;
|
||||||
|
const float xOffset = FAKE_OFFSETX * fZoom;
|
||||||
|
|
||||||
|
m_textMeasureNumber.SetZoom( fZoom );
|
||||||
|
m_textMeasureNumber.SetHorizAlign( FAKE_IS_LEFT_SIDE ? align_right : align_left );
|
||||||
|
m_textMeasureNumber.SetDiffuse( FAKE_COLOR );
|
||||||
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) );
|
||||||
|
m_textMeasureNumber.SetText( ssprintf("%.3f", fNewBeat) );
|
||||||
|
m_textMeasureNumber.SetXY( (FAKE_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos );
|
||||||
|
m_textMeasureNumber.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
void NoteField::DrawAttackText( const float fBeat, const Attack &attack )
|
void NoteField::DrawAttackText( const float fBeat, const Attack &attack )
|
||||||
{
|
{
|
||||||
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
||||||
@@ -606,7 +673,7 @@ void NoteField::DrawBGChangeText( const float fBeat, const RString sNewBGName )
|
|||||||
// change this probing to binary search
|
// change this probing to binary search
|
||||||
float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceAfterTargetsPixels )
|
float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceAfterTargetsPixels )
|
||||||
{
|
{
|
||||||
float fFirstBeatToDraw = GAMESTATE->m_fSongBeat-4; // Adjust to balance off performance and showing enough notes.
|
float fFirstBeatToDraw = GetDisplayedPosition(pPlayerState)->m_fSongBeat-4; // Adjust to balance off performance and showing enough notes.
|
||||||
|
|
||||||
/* In Boomerang, we'll usually have two sections of notes: before and after
|
/* In Boomerang, we'll usually have two sections of notes: before and after
|
||||||
* the peak. We always start drawing before the peak, and end after it, or
|
* the peak. We always start drawing before the peak, and end after it, or
|
||||||
@@ -618,7 +685,7 @@ float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistance
|
|||||||
bBoomerang = (fAccels[PlayerOptions::ACCEL_BOOMERANG] != 0);
|
bBoomerang = (fAccels[PlayerOptions::ACCEL_BOOMERANG] != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while( fFirstBeatToDraw < GAMESTATE->m_fSongBeat )
|
while( fFirstBeatToDraw < GetDisplayedPosition(pPlayerState)->m_fSongBeat )
|
||||||
{
|
{
|
||||||
bool bIsPastPeakYOffset;
|
bool bIsPastPeakYOffset;
|
||||||
float fPeakYOffset;
|
float fPeakYOffset;
|
||||||
@@ -640,7 +707,7 @@ float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceB
|
|||||||
// Probe for last note to draw. Worst case is 0.25x + boost.
|
// Probe for last note to draw. Worst case is 0.25x + boost.
|
||||||
// Adjust search distance so that notes don't pop onto the screen.
|
// Adjust search distance so that notes don't pop onto the screen.
|
||||||
float fSearchDistance = 10;
|
float fSearchDistance = 10;
|
||||||
float fLastBeatToDraw = GAMESTATE->m_fSongBeat+fSearchDistance;
|
float fLastBeatToDraw = GetDisplayedPosition(pPlayerState)->m_fSongBeat+fSearchDistance;
|
||||||
|
|
||||||
const int NUM_ITERATIONS = 20;
|
const int NUM_ITERATIONS = 20;
|
||||||
|
|
||||||
@@ -669,6 +736,19 @@ float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceB
|
|||||||
return fLastBeatToDraw;
|
return fLastBeatToDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float NoteRowToVisibleBeat( const PlayerState *pPlayerState, int iRow )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
|
*/
|
||||||
|
return NoteRowToBeat(iRow);
|
||||||
|
/*
|
||||||
|
}
|
||||||
|
return GetDisplayedTiming(pPlayerState)->GetBeatFromElapsedTime(GetRealTiming(pPlayerState)->GetElapsedTimeFromBeat(NoteRowToBeat(iRow)));
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
bool NoteField::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const
|
bool NoteField::IsOnScreen( float fBeat, int iCol, int iDrawDistanceAfterTargetsPixels, int iDrawDistanceBeforeTargetsPixels ) const
|
||||||
{
|
{
|
||||||
// TRICKY: If boomerang is on, then ones in the range
|
// TRICKY: If boomerang is on, then ones in the range
|
||||||
@@ -739,10 +819,13 @@ void NoteField::DrawPrimitives()
|
|||||||
cur->m_ReceptorArrowRow.Draw();
|
cur->m_ReceptorArrowRow.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TimingData *pTiming = GetDisplayedTiming(m_pPlayerState);
|
||||||
|
|
||||||
// Draw beat bars
|
// Draw beat bars
|
||||||
if( GAMESTATE->IsEditing() || SHOW_BEAT_BARS )
|
if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && pTiming != NULL )
|
||||||
{
|
{
|
||||||
const vector<TimeSignatureSegment> &vTimeSignatureSegments = GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments;
|
const TimingData &timing = *pTiming;
|
||||||
|
const vector<TimeSignatureSegment> &vTimeSignatureSegments = timing.m_vTimeSignatureSegments;
|
||||||
int iMeasureIndex = 0;
|
int iMeasureIndex = 0;
|
||||||
FOREACH_CONST( TimeSignatureSegment, vTimeSignatureSegments, iter )
|
FOREACH_CONST( TimeSignatureSegment, vTimeSignatureSegments, iter )
|
||||||
{
|
{
|
||||||
@@ -781,12 +864,14 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( GAMESTATE->IsEditing() )
|
if( GAMESTATE->IsEditing() && pTiming != NULL )
|
||||||
{
|
{
|
||||||
ASSERT(GAMESTATE->m_pCurSong);
|
ASSERT(GAMESTATE->m_pCurSong);
|
||||||
|
|
||||||
|
const TimingData &timing = *pTiming;
|
||||||
|
|
||||||
// BPM text
|
// BPM text
|
||||||
FOREACH_CONST( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, seg )
|
FOREACH_CONST( BPMSegment, timing.m_BPMSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -797,7 +882,7 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Freeze text
|
// Freeze text
|
||||||
FOREACH_CONST( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, seg )
|
FOREACH_CONST( StopSegment, timing.m_StopSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -808,18 +893,21 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Warp text
|
// Warp text
|
||||||
FOREACH_CONST( WarpSegment, GAMESTATE->m_pCurSong->m_Timing.m_WarpSegments, seg )
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
|
FOREACH_CONST( WarpSegment, timing.m_WarpSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
float fBeat = NoteRowToBeat(seg->m_iStartRow);
|
float fBeat = NoteRowToBeat(seg->m_iStartRow);
|
||||||
if( IS_ON_SCREEN(fBeat) )
|
if( IS_ON_SCREEN(fBeat) )
|
||||||
DrawWarpText( fBeat, seg->m_fEndBeat );
|
DrawWarpText( fBeat, seg->m_fLengthBeats );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time Signature text
|
// Time Signature text
|
||||||
FOREACH_CONST( TimeSignatureSegment, GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments, seg )
|
FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -829,8 +917,10 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
// Tickcount text
|
// Tickcount text
|
||||||
FOREACH_CONST( TickcountSegment, GAMESTATE->m_pCurSong->m_Timing.m_TickcountSegments, seg )
|
FOREACH_CONST( TickcountSegment, timing.m_TickcountSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -839,9 +929,12 @@ void NoteField::DrawPrimitives()
|
|||||||
DrawTickcountText( fBeat, seg->m_iTicks );
|
DrawTickcountText( fBeat, seg->m_iTicks );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
// Combo text
|
// Combo text
|
||||||
FOREACH_CONST( ComboSegment, GAMESTATE->m_pCurSong->m_Timing.m_ComboSegments, seg )
|
FOREACH_CONST( ComboSegment, timing.m_ComboSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -850,9 +943,10 @@ void NoteField::DrawPrimitives()
|
|||||||
DrawComboText( fBeat, seg->m_iCombo );
|
DrawComboText( fBeat, seg->m_iCombo );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Label text
|
// Label text
|
||||||
FOREACH_CONST( LabelSegment, GAMESTATE->m_pCurSong->m_Timing.m_LabelSegments, seg )
|
FOREACH_CONST( LabelSegment, timing.m_LabelSegments, seg )
|
||||||
{
|
{
|
||||||
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
{
|
{
|
||||||
@@ -862,6 +956,33 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
|
FOREACH_CONST( SpeedSegment, timing.m_SpeedSegments, seg )
|
||||||
|
{
|
||||||
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
|
{
|
||||||
|
float fBeat = NoteRowToBeat(seg->m_iStartRow);
|
||||||
|
if( IS_ON_SCREEN(fBeat) )
|
||||||
|
DrawSpeedText( fBeat, seg->m_fPercent, seg->m_fWait, seg->m_usMode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speed text
|
||||||
|
if( GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
|
FOREACH_CONST( FakeSegment, timing.m_FakeSegments, seg )
|
||||||
|
{
|
||||||
|
if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw )
|
||||||
|
{
|
||||||
|
float fBeat = NoteRowToBeat(seg->m_iStartRow);
|
||||||
|
if( IS_ON_SCREEN(fBeat) )
|
||||||
|
DrawFakeText( fBeat, seg->m_fLengthBeats );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Course mods text
|
// Course mods text
|
||||||
const Course *pCourse = GAMESTATE->m_pCurCourse;
|
const Course *pCourse = GAMESTATE->m_pCurCourse;
|
||||||
if( pCourse )
|
if( pCourse )
|
||||||
@@ -872,7 +993,7 @@ void NoteField::DrawPrimitives()
|
|||||||
FOREACH_CONST( Attack, ce.attacks, a )
|
FOREACH_CONST( Attack, ce.attacks, a )
|
||||||
{
|
{
|
||||||
float fSecond = a->fStartSecond;
|
float fSecond = a->fStartSecond;
|
||||||
float fBeat = GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( fSecond );
|
float fBeat = timing.GetBeatFromElapsedTime( fSecond );
|
||||||
|
|
||||||
if( BeatToNoteRow(fBeat) >= iFirstRowToDraw &&
|
if( BeatToNoteRow(fBeat) >= iFirstRowToDraw &&
|
||||||
BeatToNoteRow(fBeat) <= iLastRowToDraw)
|
BeatToNoteRow(fBeat) <= iLastRowToDraw)
|
||||||
@@ -883,6 +1004,8 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !GAMESTATE->m_bIsUsingStepTiming )
|
||||||
|
{
|
||||||
// BGChange text
|
// BGChange text
|
||||||
switch( GAMESTATE->m_EditMode )
|
switch( GAMESTATE->m_EditMode )
|
||||||
{
|
{
|
||||||
@@ -948,6 +1071,7 @@ void NoteField::DrawPrimitives()
|
|||||||
default:
|
default:
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw marker bars
|
// Draw marker bars
|
||||||
if( m_iBeginMarker != -1 && m_iEndMarker != -1 )
|
if( m_iBeginMarker != -1 && m_iEndMarker != -1 )
|
||||||
@@ -1012,8 +1136,8 @@ void NoteField::DrawPrimitives()
|
|||||||
float fThrowAway;
|
float fThrowAway;
|
||||||
bool bStartIsPastPeak = false;
|
bool bStartIsPastPeak = false;
|
||||||
bool bEndIsPastPeak = false;
|
bool bEndIsPastPeak = false;
|
||||||
float fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iStartRow), fThrowAway, bStartIsPastPeak );
|
float fStartYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToVisibleBeat(m_pPlayerState, iStartRow), fThrowAway, bStartIsPastPeak );
|
||||||
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iEndRow), fThrowAway, bEndIsPastPeak );
|
float fEndYOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToVisibleBeat(m_pPlayerState, iEndRow), fThrowAway, bEndIsPastPeak );
|
||||||
|
|
||||||
bool bTailIsOnVisible = iDrawDistanceAfterTargetsPixels <= fEndYOffset && fEndYOffset <= iDrawDistanceBeforeTargetsPixels;
|
bool bTailIsOnVisible = iDrawDistanceAfterTargetsPixels <= fEndYOffset && fEndYOffset <= iDrawDistanceBeforeTargetsPixels;
|
||||||
bool bHeadIsVisible = iDrawDistanceAfterTargetsPixels <= fStartYOffset && fStartYOffset <= iDrawDistanceBeforeTargetsPixels;
|
bool bHeadIsVisible = iDrawDistanceAfterTargetsPixels <= fStartYOffset && fStartYOffset <= iDrawDistanceBeforeTargetsPixels;
|
||||||
@@ -1043,7 +1167,7 @@ void NoteField::DrawPrimitives()
|
|||||||
displayCols->display[c].DrawHold( tn, c, iStartRow, bIsHoldingNote, Result, bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
displayCols->display[c].DrawHold( tn, c, iStartRow, bIsHoldingNote, Result, bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
||||||
m_fYReverseOffsetPixels, (float) iDrawDistanceAfterTargetsPixels, (float) iDrawDistanceBeforeTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT );
|
m_fYReverseOffsetPixels, (float) iDrawDistanceAfterTargetsPixels, (float) iDrawDistanceBeforeTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT );
|
||||||
|
|
||||||
bool bNoteIsUpcoming = NoteRowToBeat(iStartRow) > GAMESTATE->m_fSongBeat;
|
bool bNoteIsUpcoming = NoteRowToBeat(iStartRow) > GetDisplayedPosition(m_pPlayerState)->m_fSongBeat;
|
||||||
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1209,7 @@ void NoteField::DrawPrimitives()
|
|||||||
continue; // skip
|
continue; // skip
|
||||||
|
|
||||||
ASSERT_M( NoteRowToBeat(q) > -2000, ssprintf("%i %i %i, %f %f", q, iLastRowToDraw,
|
ASSERT_M( NoteRowToBeat(q) > -2000, ssprintf("%i %i %i, %f %f", q, iLastRowToDraw,
|
||||||
iFirstRowToDraw, GAMESTATE->m_fSongBeat, GAMESTATE->m_fMusicSeconds) );
|
iFirstRowToDraw, GetDisplayedPosition(m_pPlayerState)->m_fSongBeat, GetDisplayedPosition(m_pPlayerState)->m_fMusicSeconds) );
|
||||||
|
|
||||||
// See if there is a hold step that begins on this index.
|
// See if there is a hold step that begins on this index.
|
||||||
// Only do this if the noteskin cares.
|
// Only do this if the noteskin cares.
|
||||||
@@ -1110,12 +1234,12 @@ void NoteField::DrawPrimitives()
|
|||||||
bool bIsHopoPossible = (tn.bHopoPossible);
|
bool bIsHopoPossible = (tn.bHopoPossible);
|
||||||
bool bUseAdditionColoring = bIsAddition || bIsHopoPossible;
|
bool bUseAdditionColoring = bIsAddition || bIsHopoPossible;
|
||||||
NoteDisplayCols *displayCols = tn.pn == PLAYER_INVALID ? m_pCurDisplay : m_pDisplays[tn.pn];
|
NoteDisplayCols *displayCols = tn.pn == PLAYER_INVALID ? m_pCurDisplay : m_pDisplays[tn.pn];
|
||||||
displayCols->display[c].DrawTap( tn, c, NoteRowToBeat(q), bHoldNoteBeginsOnThisBeat,
|
displayCols->display[c].DrawTap( tn, c, NoteRowToVisibleBeat(m_pPlayerState, q), bHoldNoteBeginsOnThisBeat,
|
||||||
bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail,
|
||||||
m_fYReverseOffsetPixels, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels,
|
m_fYReverseOffsetPixels, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels,
|
||||||
FADE_BEFORE_TARGETS_PERCENT );
|
FADE_BEFORE_TARGETS_PERCENT );
|
||||||
|
|
||||||
bool bNoteIsUpcoming = NoteRowToBeat(q) > GAMESTATE->m_fSongBeat;
|
bool bNoteIsUpcoming = NoteRowToBeat(q) > GetDisplayedPosition(m_pPlayerState)->m_fSongBeat;
|
||||||
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
bAnyUpcomingInThisCol |= bNoteIsUpcoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef NOTE_FIELD_H
|
#ifndef NOTE_FIELD_H
|
||||||
#define NOTE_FIELD_H
|
#define NOTE_FIELD_H
|
||||||
|
|
||||||
|
#include "TimingData.h"
|
||||||
|
#include "SongPosition.h"
|
||||||
#include "Sprite.h"
|
#include "Sprite.h"
|
||||||
#include "ActorFrame.h"
|
#include "ActorFrame.h"
|
||||||
#include "BitmapText.h"
|
#include "BitmapText.h"
|
||||||
@@ -62,6 +64,8 @@ protected:
|
|||||||
void DrawTickcountText( const float fBeat, int iTicks );
|
void DrawTickcountText( const float fBeat, int iTicks );
|
||||||
void DrawComboText( const float fBeat, int iCombo );
|
void DrawComboText( const float fBeat, int iCombo );
|
||||||
void DrawLabelText( const float fBeat, RString sLabel );
|
void DrawLabelText( const float fBeat, RString sLabel );
|
||||||
|
void DrawSpeedText( const float fBeat, float fPercent, float fWait, unsigned short usMode );
|
||||||
|
void DrawFakeText( const float fBeat, const float fNewBeat );
|
||||||
void DrawAttackText( const float fBeat, const Attack &attack );
|
void DrawAttackText( const float fBeat, const Attack &attack );
|
||||||
void DrawBGChangeText( const float fBeat, const RString sNewBGName );
|
void DrawBGChangeText( const float fBeat, const RString sNewBGName );
|
||||||
float GetWidth() const;
|
float GetWidth() const;
|
||||||
|
|||||||
@@ -43,11 +43,9 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set<RString> &Bl
|
|||||||
SMLoader::GetApplicableFiles( sPath, list );
|
SMLoader::GetApplicableFiles( sPath, list );
|
||||||
if (!list.empty() )
|
if (!list.empty() )
|
||||||
return SMLoader::LoadFromDir( sPath, out );
|
return SMLoader::LoadFromDir( sPath, out );
|
||||||
#if defined(_MSC_VER) || defined(MACOSX)
|
|
||||||
SMALoader::GetApplicableFiles( sPath, list );
|
SMALoader::GetApplicableFiles( sPath, list );
|
||||||
if (!list.empty() )
|
if (!list.empty() )
|
||||||
return SMALoader::LoadFromDir( sPath, out );
|
return SMALoader::LoadFromDir( sPath, out );
|
||||||
#endif
|
|
||||||
DWILoader::GetApplicableFiles( sPath, list );
|
DWILoader::GetApplicableFiles( sPath, list );
|
||||||
if( !list.empty() )
|
if( !list.empty() )
|
||||||
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
|
return DWILoader::LoadFromDir( sPath, out, BlacklistedImages );
|
||||||
|
|||||||
+232
-178
@@ -435,9 +435,121 @@ static void ReadTimeSigs( const NameToData_t &mapNameToData, MeasureToTimeSig_t
|
|||||||
static const int BEATS_PER_MEASURE = 4;
|
static const int BEATS_PER_MEASURE = 4;
|
||||||
static const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE;
|
static const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE;
|
||||||
|
|
||||||
static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameToData, Steps &out,
|
static bool SearchForKeysound( const RString &sPath, RString nDataOriginal, map<RString, int> &mapFilenameToKeysoundIndex, Song &out, int &outKeysoundIndex )
|
||||||
const MeasureToTimeSig_t &sigAdjustments, const map<RString,int> &idToKeySoundIndex )
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Search for memoized file names:
|
||||||
|
{
|
||||||
|
RString nDataToSearchFor = nDataOriginal;
|
||||||
|
nDataToSearchFor.MakeLower();
|
||||||
|
map<RString, int>::iterator it = mapFilenameToKeysoundIndex.find(nDataToSearchFor);
|
||||||
|
if (it != mapFilenameToKeysoundIndex.end()) {
|
||||||
|
outKeysoundIndex = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: garbled song names seem to crash the app.
|
||||||
|
// this might not be the best place to put this code.
|
||||||
|
if( !utf8_is_valid(nDataOriginal) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Due to bugs in some programs, many BMS files have a "WAV" extension
|
||||||
|
* on files in the BMS for files that actually have some other extension.
|
||||||
|
* Do a search. Don't do a wildcard search; if sData is "song.wav",
|
||||||
|
* we might also have "song.png", which we shouldn't match. */
|
||||||
|
RString nData = nDataOriginal;
|
||||||
|
if( !IsAFile(out.GetSongDir()+nData) )
|
||||||
|
{
|
||||||
|
const char *exts[] = { "oga", "ogg", "wav", "mp3", NULL }; // XXX: stop duplicating these everywhere
|
||||||
|
for( unsigned i = 0; exts[i] != NULL; ++i )
|
||||||
|
{
|
||||||
|
RString fn = SetExtension( nData, exts[i] );
|
||||||
|
if( IsAFile(out.GetSongDir()+fn) )
|
||||||
|
{
|
||||||
|
nData = fn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !IsAFile(out.GetSongDir()+nData) )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", out.GetSongDir(), "references key \"%s\" that can't be found", nData.c_str() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's again search for memoized file names (we got the normalized one!):
|
||||||
|
{
|
||||||
|
RString nDataToSearchFor = nData;
|
||||||
|
nDataToSearchFor.MakeLower();
|
||||||
|
map<RString, int>::iterator it = mapFilenameToKeysoundIndex.find(nDataToSearchFor);
|
||||||
|
if (it != mapFilenameToKeysoundIndex.end()) {
|
||||||
|
outKeysoundIndex = it->second;
|
||||||
|
|
||||||
|
{
|
||||||
|
RString nDataToAdd = nDataOriginal;
|
||||||
|
nDataToAdd.MakeLower();
|
||||||
|
mapFilenameToKeysoundIndex[nDataToAdd] = outKeysoundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now this is a new sample.
|
||||||
|
out.m_vsKeysoundFile.push_back( nData );
|
||||||
|
outKeysoundIndex = out.m_vsKeysoundFile.size() - 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
RString nDataToAdd = nDataOriginal;
|
||||||
|
nDataToAdd.MakeLower();
|
||||||
|
mapFilenameToKeysoundIndex[nDataToAdd] = outKeysoundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RString nDataToAdd = nData;
|
||||||
|
nDataToAdd.MakeLower();
|
||||||
|
mapFilenameToKeysoundIndex[nDataToAdd] = outKeysoundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SearchForKeysound( const RString &sPath, RString sNoteId, const NameToData_t &mapNameToData, map<RString, int> &mapIdToKeysoundIndex, map<RString, int> &mapFilenameToKeysoundIndex, Song &out, int &outKeysoundIndex )
|
||||||
|
{
|
||||||
|
|
||||||
|
sNoteId.MakeLower();
|
||||||
|
{
|
||||||
|
map<RString, int>::iterator it = mapIdToKeysoundIndex.find(sNoteId);
|
||||||
|
if (it != mapIdToKeysoundIndex.end())
|
||||||
|
{
|
||||||
|
outKeysoundIndex = it->second;
|
||||||
|
return outKeysoundIndex >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RString sTagToLookFor = ssprintf( "#wav%s", sNoteId.c_str() );
|
||||||
|
RString nDataOriginal;
|
||||||
|
if( !GetTagFromMap( mapNameToData, sTagToLookFor, nDataOriginal ) )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", sPath.c_str(), "has tag \"%s\" which cannot be found.", sTagToLookFor.c_str() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool retval = SearchForKeysound(sPath, nDataOriginal, mapFilenameToKeysoundIndex, out, outKeysoundIndex);
|
||||||
|
mapIdToKeysoundIndex[sNoteId] = outKeysoundIndex;
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameToData, Steps &out, Song &outSong, map<RString, int> &mapFilenameToKeysoundIndex )
|
||||||
|
{
|
||||||
|
|
||||||
|
map<RString, int> mapIdToKeysoundIndex;
|
||||||
|
MeasureToTimeSig_t sigAdjustments;
|
||||||
|
|
||||||
LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() );
|
LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() );
|
||||||
|
|
||||||
out.m_StepsType = StepsType_Invalid;
|
out.m_StepsType = StepsType_Invalid;
|
||||||
@@ -453,11 +565,121 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo
|
|||||||
NoteData ndNotes;
|
NoteData ndNotes;
|
||||||
ndNotes.SetNumTracks( NUM_BMS_TRACKS );
|
ndNotes.SetNumTracks( NUM_BMS_TRACKS );
|
||||||
|
|
||||||
|
// Read BPM
|
||||||
|
if( GetTagFromMap(mapNameToData, "#bpm", sData) )
|
||||||
|
{
|
||||||
|
const float fBPM = StringToFloat( sData );
|
||||||
|
|
||||||
|
if( fBPM > 0.0f )
|
||||||
|
{
|
||||||
|
BPMSegment newSeg( 0, fBPM );
|
||||||
|
out.m_Timing.AddBPMSegment( newSeg );
|
||||||
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", sPath.c_str(), "has an invalid BPM change at beat %f, BPM %f.",
|
||||||
|
NoteRowToBeat(0), fBPM );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read time signatures. Note that these can differ across files in the same
|
/* Read time signatures. Note that these can differ across files in the same
|
||||||
* song. */
|
* song. */
|
||||||
MeasureToTimeSig_t mapMeasureToTimeSig;
|
MeasureToTimeSig_t mapMeasureToTimeSig;
|
||||||
ReadTimeSigs( mapNameToData, mapMeasureToTimeSig );
|
ReadTimeSigs( mapNameToData, mapMeasureToTimeSig );
|
||||||
|
|
||||||
|
for( NameToData_t::const_iterator it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it )
|
||||||
|
{
|
||||||
|
const RString &sName = it->first;
|
||||||
|
if( sName.size() != 6 || sName[0] != '#' || !IsAnInt( sName.substr(1,5) ) )
|
||||||
|
continue;
|
||||||
|
// this is step or offset data. Looks like "#00705"
|
||||||
|
int iMeasureNo = atoi( sName.substr(1, 3).c_str() );
|
||||||
|
int iBMSTrackNo = atoi( sName.substr(4, 2).c_str() );
|
||||||
|
int iStepIndex = GetMeasureStartRow( mapMeasureToTimeSig, iMeasureNo, sigAdjustments );
|
||||||
|
float fBeatsPerMeasure = GetBeatsPerMeasure( mapMeasureToTimeSig, iMeasureNo, sigAdjustments );
|
||||||
|
int iRowsPerMeasure = BeatToNoteRow( fBeatsPerMeasure );
|
||||||
|
|
||||||
|
RString nData = it->second;
|
||||||
|
int totalPairs = nData.size() / 2;
|
||||||
|
for( int i = 0; i < totalPairs; ++i )
|
||||||
|
{
|
||||||
|
RString sPair = nData.substr( i*2, 2 );
|
||||||
|
|
||||||
|
int iRow = iStepIndex + (i * iRowsPerMeasure) / totalPairs;
|
||||||
|
float fBeat = NoteRowToBeat( iRow );
|
||||||
|
int iVal = 0;
|
||||||
|
sscanf( sPair, "%x", &iVal );
|
||||||
|
|
||||||
|
if (sPair == "00")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( iBMSTrackNo )
|
||||||
|
{
|
||||||
|
case BMS_TRACK_BPM:
|
||||||
|
if( iVal > 0 )
|
||||||
|
{
|
||||||
|
out.m_Timing.SetBPMAtBeat( fBeat, (float) iVal );
|
||||||
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", sPath.c_str(), "has an invalid BPM change at beat %f, BPM %d.",
|
||||||
|
fBeat, iVal );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMS_TRACK_BPM_REF:
|
||||||
|
{
|
||||||
|
RString sTagToLookFor = ssprintf( "#bpm%s", sPair.c_str() );
|
||||||
|
RString sBPM;
|
||||||
|
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBPM ) )
|
||||||
|
{
|
||||||
|
float fBPM = StringToFloat( sBPM );
|
||||||
|
out.m_Timing.SetBPMAtBeat( fBeat, fBPM );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", sPath.c_str(), "has tag \"%s\" which cannot be found.", sTagToLookFor.c_str() );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BMS_TRACK_STOP:
|
||||||
|
{
|
||||||
|
if( iVal == 0 )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RString sTagToLookFor = ssprintf( "#stop%02x", iVal );
|
||||||
|
RString sBeats;
|
||||||
|
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) )
|
||||||
|
{
|
||||||
|
// find the BPM at the time of this freeze
|
||||||
|
float fBPS = out.m_Timing.GetBPMAtBeat(fBeat) / 60.0f;
|
||||||
|
float fBeats = StringToFloat( sBeats ) / 48.0f;
|
||||||
|
float fFreezeSecs = fBeats / fBPS;
|
||||||
|
|
||||||
|
StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs );
|
||||||
|
out.m_Timing.AddStopSegment( newSeg );
|
||||||
|
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", sPath.c_str(), "has tag \"%s\" which cannot be found.", sTagToLookFor.c_str() );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we're done reading BPMs, factor out weird time signatures.
|
||||||
|
SetTimeSigAdjustments( mapMeasureToTimeSig, outSong, sigAdjustments );
|
||||||
|
|
||||||
int iHoldStarts[NUM_BMS_TRACKS];
|
int iHoldStarts[NUM_BMS_TRACKS];
|
||||||
TapNote iHoldHeads[NUM_BMS_TRACKS];
|
TapNote iHoldHeads[NUM_BMS_TRACKS];
|
||||||
|
|
||||||
@@ -487,10 +709,9 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo
|
|||||||
RString sNoteId = sNoteData.substr( i, 2 );
|
RString sNoteId = sNoteData.substr( i, 2 );
|
||||||
if( sNoteId != "00" )
|
if( sNoteId != "00" )
|
||||||
{
|
{
|
||||||
vTapNotes.push_back( TAP_ORIGINAL_TAP );
|
TapNote tn = TAP_ORIGINAL_TAP;
|
||||||
map<RString,int>::const_iterator rInt = idToKeySoundIndex.find( sNoteId );
|
SearchForKeysound( sPath, sNoteId, mapNameToData, mapIdToKeysoundIndex, mapFilenameToKeysoundIndex, outSong, tn.iKeysoundIndex );
|
||||||
if( rInt != idToKeySoundIndex.end() )
|
vTapNotes.push_back( tn );
|
||||||
vTapNotes.back().iKeysoundIndex = rInt->second;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -781,7 +1002,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, MeasureToTimeSig_t &sigAdjustmentsOut, map<RString,int> &idToKeySoundIndexOut )
|
static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
|
||||||
{
|
{
|
||||||
RString sData;
|
RString sData;
|
||||||
if( GetTagFromMap(mapNameToData, "#title", sData) )
|
if( GetTagFromMap(mapNameToData, "#title", sData) )
|
||||||
@@ -792,172 +1013,6 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
GetTagFromMap( mapNameToData, "#backbmp", out.m_sBackgroundFile );
|
GetTagFromMap( mapNameToData, "#backbmp", out.m_sBackgroundFile );
|
||||||
GetTagFromMap( mapNameToData, "#wav", out.m_sMusicFile );
|
GetTagFromMap( mapNameToData, "#wav", out.m_sMusicFile );
|
||||||
|
|
||||||
if( GetTagFromMap(mapNameToData, "#bpm", sData) )
|
|
||||||
{
|
|
||||||
const float fBPM = StringToFloat( sData );
|
|
||||||
|
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
|
||||||
{
|
|
||||||
BPMSegment newSeg( 0, fBPM );
|
|
||||||
out.AddBPMSegment( newSeg );
|
|
||||||
if( fBPM > 0.0f )
|
|
||||||
LOG->Trace( "Inserting new positive BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
|
||||||
else
|
|
||||||
LOG->Trace( "Inserting new negative BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( fBPM > 0.0f )
|
|
||||||
{
|
|
||||||
BPMSegment newSeg( 0, fBPM );
|
|
||||||
out.AddBPMSegment( newSeg );
|
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", out.GetSongDir(), "has an invalid BPM change at beat %f, BPM %f.",
|
|
||||||
NoteRowToBeat(0), fBPM );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NameToData_t::const_iterator it;
|
|
||||||
for( it = mapNameToData.lower_bound("#wav"); it != mapNameToData.end(); ++it )
|
|
||||||
{
|
|
||||||
const RString &sName = it->first;
|
|
||||||
|
|
||||||
if( sName.size() != 6 || sName.Left(4) != "#wav" )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// this is keysound file name. Looks like "#WAV1A"
|
|
||||||
RString nData = it->second;
|
|
||||||
RString sWavID = sName.Right(2);
|
|
||||||
|
|
||||||
// FIXME: garbled song names seem to crash the app.
|
|
||||||
// this might not be the best place to put this code.
|
|
||||||
if( !utf8_is_valid(nData) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Due to bugs in some programs, many BMS files have a "WAV" extension
|
|
||||||
* on files in the BMS for files that actually have some other extension.
|
|
||||||
* Do a search. Don't do a wildcard search; if sData is "song.wav",
|
|
||||||
* we might also have "song.png", which we shouldn't match. */
|
|
||||||
if( !IsAFile(out.GetSongDir()+nData) )
|
|
||||||
{
|
|
||||||
const char *exts[] = { "oga", "ogg", "wav", "mp3", NULL }; // XXX: stop duplicating these everywhere
|
|
||||||
for( unsigned i = 0; exts[i] != NULL; ++i )
|
|
||||||
{
|
|
||||||
RString fn = SetExtension( nData, exts[i] );
|
|
||||||
if( IsAFile(out.GetSongDir()+fn) )
|
|
||||||
{
|
|
||||||
nData = fn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( !IsAFile(out.GetSongDir()+nData) )
|
|
||||||
LOG->UserLog( "Song file", out.GetSongDir(), "references key \"%s\" that can't be found", nData.c_str() );
|
|
||||||
|
|
||||||
sWavID.MakeUpper(); // HACK: undo the MakeLower()
|
|
||||||
out.m_vsKeysoundFile.push_back( nData );
|
|
||||||
idToKeySoundIndexOut[ sWavID ] = out.m_vsKeysoundFile.size()-1;
|
|
||||||
LOG->Trace( "Inserting keysound index %u '%s'", unsigned(out.m_vsKeysoundFile.size()-1), sWavID.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time signature tags affect all other global timing tags, so read them first.
|
|
||||||
MeasureToTimeSig_t mapMeasureToTimeSig;
|
|
||||||
ReadTimeSigs( mapNameToData, mapMeasureToTimeSig );
|
|
||||||
|
|
||||||
for( it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it )
|
|
||||||
{
|
|
||||||
const RString &sName = it->first;
|
|
||||||
if( sName.size() != 6 || sName[0] != '#' || !IsAnInt( sName.substr(1,5) ) )
|
|
||||||
continue;
|
|
||||||
// this is step or offset data. Looks like "#00705"
|
|
||||||
int iMeasureNo = atoi( sName.substr(1, 3).c_str() );
|
|
||||||
int iBMSTrackNo = atoi( sName.substr(4, 2).c_str() );
|
|
||||||
int iStepIndex = GetMeasureStartRow( mapMeasureToTimeSig, iMeasureNo, sigAdjustmentsOut );
|
|
||||||
float fBeatsPerMeasure = GetBeatsPerMeasure( mapMeasureToTimeSig, iMeasureNo, sigAdjustmentsOut );
|
|
||||||
int iRowsPerMeasure = BeatToNoteRow( fBeatsPerMeasure );
|
|
||||||
|
|
||||||
RString nData = it->second;
|
|
||||||
int totalPairs = nData.size() / 2;
|
|
||||||
for( int i = 0; i < totalPairs; ++i )
|
|
||||||
{
|
|
||||||
RString sPair = nData.substr( i*2, 2 );
|
|
||||||
|
|
||||||
int iRow = iStepIndex + (i * iRowsPerMeasure) / totalPairs;
|
|
||||||
float fBeat = NoteRowToBeat( iRow );
|
|
||||||
int iVal = 0;
|
|
||||||
sscanf( sPair, "%x", &iVal );
|
|
||||||
|
|
||||||
if (sPair == "00")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( iBMSTrackNo )
|
|
||||||
{
|
|
||||||
case BMS_TRACK_BPM:
|
|
||||||
if( iVal > 0 )
|
|
||||||
{
|
|
||||||
out.SetBPMAtBeat( fBeat, (float) iVal );
|
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", out.GetSongDir(), "has an invalid BPM change at beat %f, BPM %d.",
|
|
||||||
fBeat, iVal );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMS_TRACK_BPM_REF:
|
|
||||||
{
|
|
||||||
RString sTagToLookFor = ssprintf( "#bpm%s", sPair.c_str() );
|
|
||||||
RString sBPM;
|
|
||||||
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBPM ) )
|
|
||||||
{
|
|
||||||
float fBPM = StringToFloat( sBPM );
|
|
||||||
out.SetBPMAtBeat( fBeat, fBPM );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", out.GetSongDir(), "has tag \"%s\" which cannot be found.", sTagToLookFor.c_str() );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BMS_TRACK_STOP:
|
|
||||||
{
|
|
||||||
if( iVal == 0 )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
RString sTagToLookFor = ssprintf( "#stop%02x", iVal );
|
|
||||||
RString sBeats;
|
|
||||||
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) )
|
|
||||||
{
|
|
||||||
// find the BPM at the time of this freeze
|
|
||||||
float fBPS = out.m_Timing.GetBPMAtBeat(fBeat) / 60.0f;
|
|
||||||
float fBeats = StringToFloat( sBeats ) / 48.0f;
|
|
||||||
float fFreezeSecs = fBeats / fBPS;
|
|
||||||
|
|
||||||
StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs );
|
|
||||||
out.AddStopSegment( newSeg );
|
|
||||||
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", out.GetSongDir(), "has tag \"%s\" which cannot be found.", sTagToLookFor.c_str() );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we're done reading BPMs, factor out weird time signatures.
|
|
||||||
SetTimeSigAdjustments( mapMeasureToTimeSig, out, sigAdjustmentsOut );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SlideDuplicateDifficulties( Song &p )
|
static void SlideDuplicateDifficulties( Song &p )
|
||||||
@@ -1031,7 +1086,7 @@ bool BMSLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
// Create a Steps for each.
|
// Create a Steps for each.
|
||||||
vector<Steps*> apSteps;
|
vector<Steps*> apSteps;
|
||||||
for( unsigned i=0; i<arrayBMSFileNames.size(); i++ )
|
for( unsigned i=0; i<arrayBMSFileNames.size(); i++ )
|
||||||
apSteps.push_back( new Steps );
|
apSteps.push_back( out.CreateSteps() );
|
||||||
|
|
||||||
// Now, with our fancy little substring, trim the titles and
|
// Now, with our fancy little substring, trim the titles and
|
||||||
// figure out where each goes.
|
// figure out where each goes.
|
||||||
@@ -1100,9 +1155,7 @@ bool BMSLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
if( apSteps[i]->GetDifficulty() == Difficulty_Medium )
|
if( apSteps[i]->GetDifficulty() == Difficulty_Medium )
|
||||||
iMainDataIndex = i;
|
iMainDataIndex = i;
|
||||||
|
|
||||||
MeasureToTimeSig_t sigAdjustments;
|
ReadGlobalTags( aBMSData[iMainDataIndex], out );
|
||||||
map<RString,int> idToKeysoundIndex;
|
|
||||||
ReadGlobalTags( aBMSData[iMainDataIndex], out, sigAdjustments, idToKeysoundIndex );
|
|
||||||
|
|
||||||
// The brackets before the difficulty are in common substring, so remove them if it's found.
|
// The brackets before the difficulty are in common substring, so remove them if it's found.
|
||||||
if( commonSubstring.size() > 2 && commonSubstring[commonSubstring.size() - 2] == ' ' )
|
if( commonSubstring.size() > 2 && commonSubstring[commonSubstring.size() - 2] == ' ' )
|
||||||
@@ -1124,10 +1177,11 @@ bool BMSLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
|
|
||||||
// Now that we've parsed the keysound data, load the Steps from the rest
|
// Now that we've parsed the keysound data, load the Steps from the rest
|
||||||
// of the .bms files.
|
// of the .bms files.
|
||||||
|
map<RString, int> mapFilenameToKeysoundIndex;
|
||||||
for( unsigned i=0; i<arrayBMSFileNames.size(); i++ )
|
for( unsigned i=0; i<arrayBMSFileNames.size(); i++ )
|
||||||
{
|
{
|
||||||
Steps* pNewNotes = apSteps[i];
|
Steps* pNewNotes = apSteps[i];
|
||||||
const bool ok = LoadFromBMSFile( out.GetSongDir() + arrayBMSFileNames[i], aBMSData[i], *pNewNotes, sigAdjustments, idToKeysoundIndex );
|
const bool ok = LoadFromBMSFile( out.GetSongDir() + arrayBMSFileNames[i], aBMSData[i], *pNewNotes, out, mapFilenameToKeysoundIndex );
|
||||||
if( ok )
|
if( ok )
|
||||||
out.AddSteps( pNewNotes );
|
out.AddSteps( pNewNotes );
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -509,11 +509,11 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
|
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
if( PREFSMAN->m_bQuirksMode )
|
||||||
{
|
{
|
||||||
out.AddBPMSegment( BPMSegment(0, fBPM) );
|
out.m_SongTiming.AddBPMSegment( BPMSegment(0, fBPM) );
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if( fBPM > 0.0f )
|
if( fBPM > 0.0f )
|
||||||
out.AddBPMSegment( BPMSegment(0, fBPM) );
|
out.m_SongTiming.AddBPMSegment( BPMSegment(0, fBPM) );
|
||||||
else
|
else
|
||||||
LOG->UserLog( "Song file", sPath, "has an invalid BPM change at beat %f, BPM %f.",
|
LOG->UserLog( "Song file", sPath, "has an invalid BPM change at beat %f, BPM %f.",
|
||||||
NoteRowToBeat(0), fBPM );
|
NoteRowToBeat(0), fBPM );
|
||||||
@@ -545,7 +545,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
|
|
||||||
else if( sValueName.EqualsNoCase("GAP") )
|
else if( sValueName.EqualsNoCase("GAP") )
|
||||||
// the units of GAP is 1/1000 second
|
// the units of GAP is 1/1000 second
|
||||||
out.m_Timing.m_fBeat0OffsetInSeconds = -StringToInt( sParams[1] ) / 1000.0f;
|
out.m_SongTiming.m_fBeat0OffsetInSeconds = -StringToInt( sParams[1] ) / 1000.0f;
|
||||||
|
|
||||||
else if( sValueName.EqualsNoCase("SAMPLESTART") )
|
else if( sValueName.EqualsNoCase("SAMPLESTART") )
|
||||||
out.m_fMusicSampleStartSeconds = ParseBrokenDWITimestamp(sParams[1], sParams[2], sParams[3]);
|
out.m_fMusicSampleStartSeconds = ParseBrokenDWITimestamp(sParams[1], sParams[2], sParams[3]);
|
||||||
@@ -570,7 +570,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
int iFreezeRow = BeatToNoteRow( StringToFloat(arrayFreezeValues[0]) / 4.0f );
|
int iFreezeRow = BeatToNoteRow( StringToFloat(arrayFreezeValues[0]) / 4.0f );
|
||||||
float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ) / 1000.0f;
|
float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ) / 1000.0f;
|
||||||
|
|
||||||
out.AddStopSegment( StopSegment(iFreezeRow, fFreezeSeconds) );
|
out.m_SongTiming.AddStopSegment( StopSegment(iFreezeRow, fFreezeSeconds) );
|
||||||
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", fFreezeBeat, fFreezeSeconds );
|
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", fFreezeBeat, fFreezeSeconds );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,7 +595,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
if( fBPM > 0.0f )
|
if( fBPM > 0.0f )
|
||||||
{
|
{
|
||||||
BPMSegment bs( iStartIndex, fBPM );
|
BPMSegment bs( iStartIndex, fBPM );
|
||||||
out.AddBPMSegment( bs );
|
out.m_SongTiming.AddBPMSegment( bs );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -610,7 +610,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
sValueName.EqualsNoCase("COUPLE") ||
|
sValueName.EqualsNoCase("COUPLE") ||
|
||||||
sValueName.EqualsNoCase("SOLO") )
|
sValueName.EqualsNoCase("SOLO") )
|
||||||
{
|
{
|
||||||
Steps* pNewNotes = new Steps;
|
Steps* pNewNotes = out.CreateSteps();
|
||||||
LoadFromDWITokens(
|
LoadFromDWITokens(
|
||||||
sParams[0],
|
sParams[0],
|
||||||
sParams[1],
|
sParams[1],
|
||||||
@@ -656,7 +656,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
|
|||||||
// do nothing. We don't care about this value name
|
// do nothing. We don't care about this value name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out.TidyUpData();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ static void Deserialize( Song &out, const Json::Value &root )
|
|||||||
out.m_sLyricsFile = root["LyricsFile"].asString();
|
out.m_sLyricsFile = root["LyricsFile"].asString();
|
||||||
out.m_sCDTitleFile = root["CDTitle"].asString();
|
out.m_sCDTitleFile = root["CDTitle"].asString();
|
||||||
out.m_sMusicFile = root["Music"].asString();
|
out.m_sMusicFile = root["Music"].asString();
|
||||||
out.m_Timing.m_fBeat0OffsetInSeconds = (float)root["Offset"].asDouble();
|
out.m_SongTiming.m_fBeat0OffsetInSeconds = (float)root["Offset"].asDouble();
|
||||||
out.m_fMusicSampleStartSeconds = (float)root["SampleStart"].asDouble();
|
out.m_fMusicSampleStartSeconds = (float)root["SampleStart"].asDouble();
|
||||||
out.m_fMusicSampleLengthSeconds = (float)root["SampleLength"].asDouble();
|
out.m_fMusicSampleLengthSeconds = (float)root["SampleLength"].asDouble();
|
||||||
RString sSelectable = root["Selectable"].asString();
|
RString sSelectable = root["Selectable"].asString();
|
||||||
@@ -167,7 +167,7 @@ static void Deserialize( Song &out, const Json::Value &root )
|
|||||||
out.m_fSpecifiedBPMMax = (float)root["SpecifiedBpmMax"].asDouble();
|
out.m_fSpecifiedBPMMax = (float)root["SpecifiedBpmMax"].asDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
Deserialize( out.m_Timing, root["TimingData"] );
|
Deserialize( out.m_SongTiming, root["TimingData"] );
|
||||||
JsonUtil::DeserializeVectorObjects( out.m_LyricSegments, Deserialize, root["LyricSegments"] );
|
JsonUtil::DeserializeVectorObjects( out.m_LyricSegments, Deserialize, root["LyricSegments"] );
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
+183
-78
@@ -9,6 +9,51 @@
|
|||||||
#include "Song.h"
|
#include "Song.h"
|
||||||
#include "Steps.h"
|
#include "Steps.h"
|
||||||
|
|
||||||
|
static void HandleBunki( TimingData &timing, const float fEarlyBPM,
|
||||||
|
const float fCurBPM, const float fGap,
|
||||||
|
const float fPos )
|
||||||
|
{
|
||||||
|
const float BeatsPerSecond = fEarlyBPM / 60.0f;
|
||||||
|
const float beat = (fPos + fGap) * BeatsPerSecond;
|
||||||
|
LOG->Trace( "BPM %f, BPS %f, BPMPos %f, beat %f",
|
||||||
|
fEarlyBPM, BeatsPerSecond, fPos, beat );
|
||||||
|
timing.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), fCurBPM) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandlePipeChars( TimingData &timing, const RString sNoteRow,
|
||||||
|
const float fCurBeat, int &iTickCount )
|
||||||
|
{
|
||||||
|
RString temp = sNoteRow.substr(2,sNoteRow.size()-3);
|
||||||
|
float numTemp = StringToFloat(temp);
|
||||||
|
if (BeginsWith(sNoteRow, "|T"))
|
||||||
|
{
|
||||||
|
iTickCount = static_cast<int>(numTemp);
|
||||||
|
timing.SetTickcountAtBeat( fCurBeat, clamp(iTickCount, 0, ROWS_PER_BEAT) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (BeginsWith(sNoteRow, "|B"))
|
||||||
|
{
|
||||||
|
timing.SetBPMAtBeat( fCurBeat, numTemp );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (BeginsWith(sNoteRow, "|E"))
|
||||||
|
{
|
||||||
|
// Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster
|
||||||
|
float fCurDelay = 60 / timing.GetBPMAtBeat(fCurBeat) * numTemp / iTickCount;
|
||||||
|
fCurDelay += timing.GetDelayAtRow(BeatToNoteRow(fCurBeat) );
|
||||||
|
timing.SetStopAtBeat( fCurBeat, fCurDelay, true );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (BeginsWith(sNoteRow, "|D"))
|
||||||
|
{
|
||||||
|
float fCurDelay = timing.GetStopAtRow(BeatToNoteRow(fCurBeat) );
|
||||||
|
fCurDelay += numTemp / 1000;
|
||||||
|
timing.SetStopAtBeat( fCurBeat, fCurDelay, true );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, bool bKIUCompliant )
|
static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, bool bKIUCompliant )
|
||||||
{
|
{
|
||||||
LOG->Trace( "Steps::LoadFromKSFFile( '%s' )", sPath.c_str() );
|
LOG->Trace( "Steps::LoadFromKSFFile( '%s' )", sPath.c_str() );
|
||||||
@@ -26,14 +71,96 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
// According to Aldo_MX, there is a default BPM and it's 60. -aj
|
// According to Aldo_MX, there is a default BPM and it's 60. -aj
|
||||||
bool bDoublesChart = false;
|
bool bDoublesChart = false;
|
||||||
|
|
||||||
|
TimingData stepsTiming;
|
||||||
|
float SMGap1 = 0, SMGap2 = 0, BPM1 = -1, BPMPos2 = -1, BPM2 = -1, BPMPos3 = -1, BPM3 = -1;
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
||||||
{
|
{
|
||||||
const MsdFile::value_t &sParams = msd.GetValue( i );
|
const MsdFile::value_t &sParams = msd.GetValue( i );
|
||||||
RString sValueName = sParams[0];
|
RString sValueName = sParams[0];
|
||||||
sValueName.MakeUpper();
|
sValueName.MakeUpper();
|
||||||
|
|
||||||
// handle the data
|
/* handle the data...well, not this data: not related to steps.
|
||||||
if( sValueName=="TICKCOUNT" )
|
* Skips INTRO, MUSICINTRO, TITLEFILE, DISCFILE, SONGFILE. */
|
||||||
|
if (sValueName=="TITLE" || EndsWith(sValueName, "INTRO")
|
||||||
|
|| EndsWith(sValueName, "FILE") )
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="BPM" )
|
||||||
|
{
|
||||||
|
BPM1 = StringToFloat(sParams[1]);
|
||||||
|
stepsTiming.AddBPMSegment( BPMSegment(0, BPM1) );
|
||||||
|
}
|
||||||
|
else if( sValueName=="BPM2" )
|
||||||
|
{
|
||||||
|
if (bKIUCompliant)
|
||||||
|
{
|
||||||
|
BPM2 = StringToFloat( sParams[1] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LOG an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( sValueName=="BPM3" )
|
||||||
|
{
|
||||||
|
if (bKIUCompliant)
|
||||||
|
{
|
||||||
|
BPM3 = StringToFloat( sParams[1] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LOG an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( sValueName=="BUNKI" )
|
||||||
|
{
|
||||||
|
if (bKIUCompliant)
|
||||||
|
{
|
||||||
|
BPMPos2 = StringToFloat( sParams[1] ) / 100.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LOG an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( sValueName=="BUNKI2" )
|
||||||
|
{
|
||||||
|
if (bKIUCompliant)
|
||||||
|
{
|
||||||
|
BPMPos3 = StringToFloat( sParams[1] ) / 100.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LOG an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( sValueName=="STARTTIME" )
|
||||||
|
{
|
||||||
|
SMGap1 = -StringToFloat( sParams[1] )/100;
|
||||||
|
stepsTiming.m_fBeat0OffsetInSeconds = SMGap1;
|
||||||
|
}
|
||||||
|
// This is currently required for more accurate KIU BPM changes.
|
||||||
|
else if( sValueName=="STARTTIME2" )
|
||||||
|
{
|
||||||
|
if (bKIUCompliant)
|
||||||
|
{
|
||||||
|
SMGap2 = -StringToFloat( sParams[1] )/100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LOG an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( sValueName=="STARTTIME3" )
|
||||||
|
{
|
||||||
|
// STARTTIME3 only ensures this is a KIU compliant simfile.
|
||||||
|
bKIUCompliant = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="TICKCOUNT" )
|
||||||
{
|
{
|
||||||
iTickCount = StringToInt( sParams[1] );
|
iTickCount = StringToInt( sParams[1] );
|
||||||
if( iTickCount <= 0 )
|
if( iTickCount <= 0 )
|
||||||
@@ -41,13 +168,9 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
LOG->UserLog( "Song file", sPath, "has an invalid tick count: %d.", iTickCount );
|
LOG->UserLog( "Song file", sPath, "has an invalid tick count: %d.", iTickCount );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
stepsTiming.AddTickcountSegment(TickcountSegment(0, iTickCount));
|
||||||
}
|
}
|
||||||
else if( sValueName=="STEP" )
|
|
||||||
{
|
|
||||||
RString theSteps = sParams[1];
|
|
||||||
TrimLeft( theSteps );
|
|
||||||
split( theSteps, "\n", vNoteRows, true );
|
|
||||||
}
|
|
||||||
else if( sValueName=="DIFFICULTY" )
|
else if( sValueName=="DIFFICULTY" )
|
||||||
{
|
{
|
||||||
out.SetMeter( max(StringToInt(sParams[1]), 0) );
|
out.SetMeter( max(StringToInt(sParams[1]), 0) );
|
||||||
@@ -60,14 +183,35 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
if( sPlayer.find( "double" ) != string::npos )
|
if( sPlayer.find( "double" ) != string::npos )
|
||||||
bDoublesChart = true;
|
bDoublesChart = true;
|
||||||
}
|
}
|
||||||
|
// This should always be last.
|
||||||
|
else if( sValueName=="STEP" )
|
||||||
|
{
|
||||||
|
RString theSteps = sParams[1];
|
||||||
|
TrimLeft( theSteps );
|
||||||
|
split( theSteps, "\n", vNoteRows, true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( iTickCount == -1 )
|
if( iTickCount == -1 )
|
||||||
{
|
{
|
||||||
iTickCount = 2; // Direct Move 0.5 has a default value of 4... -aj
|
iTickCount = 4;
|
||||||
LOG->UserLog( "Song file", sPath, "doesn't have a TICKCOUNT. Defaulting to %i.", iTickCount );
|
LOG->UserLog( "Song file", sPath, "doesn't have a TICKCOUNT. Defaulting to %i.", iTickCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare BPM stuff already if the file uses KSF syntax.
|
||||||
|
if( bKIUCompliant )
|
||||||
|
{
|
||||||
|
if( BPM2 > 0 && BPMPos2 > 0 )
|
||||||
|
{
|
||||||
|
HandleBunki( stepsTiming, BPM1, BPM2, SMGap1, BPMPos2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( BPM3 > 0 && BPMPos3 > 0 )
|
||||||
|
{
|
||||||
|
HandleBunki( stepsTiming, BPM2, BPM3, SMGap2, BPMPos3 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NoteData notedata; // read it into here
|
NoteData notedata; // read it into here
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -133,6 +277,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
case StepsType_pump_single: notedata.SetNumTracks( 5 ); break;
|
case StepsType_pump_single: notedata.SetNumTracks( 5 ); break;
|
||||||
case StepsType_pump_couple: notedata.SetNumTracks( 10 ); break;
|
case StepsType_pump_couple: notedata.SetNumTracks( 10 ); break;
|
||||||
case StepsType_pump_double: notedata.SetNumTracks( 10 ); break;
|
case StepsType_pump_double: notedata.SetNumTracks( 10 ); break;
|
||||||
|
case StepsType_pump_routine: notedata.SetNumTracks( 10 ); break; // future files may have this?
|
||||||
case StepsType_pump_halfdouble: notedata.SetNumTracks( 6 ); break;
|
case StepsType_pump_halfdouble: notedata.SetNumTracks( 6 ); break;
|
||||||
default: FAIL_M( ssprintf("%i", out.m_StepsType) );
|
default: FAIL_M( ssprintf("%i", out.m_StepsType) );
|
||||||
}
|
}
|
||||||
@@ -146,6 +291,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
int newTick = -1;
|
int newTick = -1;
|
||||||
float fCurBeat = 0.0f;
|
float fCurBeat = 0.0f;
|
||||||
float prevBeat = 0.0f; // Used for hold tails.
|
float prevBeat = 0.0f; // Used for hold tails.
|
||||||
|
|
||||||
for( unsigned r=0; r<vNoteRows.size(); r++ )
|
for( unsigned r=0; r<vNoteRows.size(); r++ )
|
||||||
{
|
{
|
||||||
RString& sRowString = vNoteRows[r];
|
RString& sRowString = vNoteRows[r];
|
||||||
@@ -155,7 +301,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
continue; // skip
|
continue; // skip
|
||||||
|
|
||||||
// All 2s indicates the end of the song.
|
// All 2s indicates the end of the song.
|
||||||
if( sRowString == "2222222222222" )
|
else if( sRowString == "2222222222222" )
|
||||||
{
|
{
|
||||||
// Finish any holds that didn't get...well, finished.
|
// Finish any holds that didn't get...well, finished.
|
||||||
for( t=0; t < notedata.GetNumTracks(); t++ )
|
for( t=0; t < notedata.GetNumTracks(); t++ )
|
||||||
@@ -171,29 +317,21 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Why do this? Rows made with precise DM05 tags can go up to 13 too -DaisuMaster
|
else if( BeginsWith(sRowString, "|") )
|
||||||
//if( sRowString.size() != 13 )
|
|
||||||
//this is wrong in many ways...
|
|
||||||
/*if( bKIUCompliant )
|
|
||||||
{
|
{
|
||||||
LOG->UserLog( "Song file", sPath, "has illegal syntax \"%s\" which can't be in KIU complient files.",
|
if (bKIUCompliant)
|
||||||
sRowString.c_str() );
|
|
||||||
return false;
|
|
||||||
//In other words: you can't mix ksf's with DM05 tags and ksf's without any DM05 tags
|
|
||||||
//Either one set or another will be read...
|
|
||||||
}*/
|
|
||||||
if( BeginsWith(sRowString, "|B") || BeginsWith(sRowString, "|D") || BeginsWith(sRowString, "|E") )
|
|
||||||
{
|
{
|
||||||
// These don't have to be worried about here: the changes and stops were already added.
|
// Log an error, ignore the line.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( BeginsWith(sRowString, "|T") )
|
if ( !HandlePipeChars( stepsTiming, sRowString, fCurBeat, iTickCount ) )
|
||||||
{
|
{
|
||||||
RString temp = sRowString.substr(2,sRowString.size()-3);
|
// LOG it first.
|
||||||
newTick = StringToInt(temp);
|
|
||||||
bTickChangeNeeded = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Is this why improper ksf or some kiucompilant ksf mixed with dm05 ksf are ignored?? -DaisuMaster
|
// Is this why improper ksf or some kiucompilant ksf mixed with dm05 ksf are ignored?? -DaisuMaster
|
||||||
@@ -270,6 +408,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.SetNoteData( notedata );
|
out.SetNoteData( notedata );
|
||||||
|
out.m_Timing = stepsTiming;
|
||||||
|
|
||||||
out.TidyUpData();
|
out.TidyUpData();
|
||||||
|
|
||||||
@@ -358,7 +497,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant
|
|||||||
else if( sValueName=="BPM" )
|
else if( sValueName=="BPM" )
|
||||||
{
|
{
|
||||||
BPM1 = StringToFloat(sParams[1]);
|
BPM1 = StringToFloat(sParams[1]);
|
||||||
out.AddBPMSegment( BPMSegment(0, BPM1) );
|
out.m_SongTiming.AddBPMSegment( BPMSegment(0, BPM1) );
|
||||||
}
|
}
|
||||||
else if( sValueName=="BPM2" )
|
else if( sValueName=="BPM2" )
|
||||||
{
|
{
|
||||||
@@ -383,7 +522,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant
|
|||||||
else if( sValueName=="STARTTIME" )
|
else if( sValueName=="STARTTIME" )
|
||||||
{
|
{
|
||||||
SMGap1 = -StringToFloat( sParams[1] )/100;
|
SMGap1 = -StringToFloat( sParams[1] )/100;
|
||||||
out.m_Timing.m_fBeat0OffsetInSeconds = SMGap1;
|
out.m_SongTiming.m_fBeat0OffsetInSeconds = SMGap1;
|
||||||
}
|
}
|
||||||
// This is currently required for more accurate KIU BPM changes.
|
// This is currently required for more accurate KIU BPM changes.
|
||||||
else if( sValueName=="STARTTIME2" )
|
else if( sValueName=="STARTTIME2" )
|
||||||
@@ -409,7 +548,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant
|
|||||||
TickcountSegment tcs;
|
TickcountSegment tcs;
|
||||||
tcs.m_iStartRow = BeatToNoteRow(0.0f);
|
tcs.m_iStartRow = BeatToNoteRow(0.0f);
|
||||||
tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount;
|
tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount;
|
||||||
out.m_Timing.AddTickcountSegment( tcs );
|
out.m_SongTiming.AddTickcountSegment( tcs );
|
||||||
}
|
}
|
||||||
else if ( sValueName=="STEP" )
|
else if ( sValueName=="STEP" )
|
||||||
{
|
{
|
||||||
@@ -465,21 +604,12 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant
|
|||||||
{
|
{
|
||||||
if( BPM2 > 0 && BPMPos2 > 0 )
|
if( BPM2 > 0 && BPMPos2 > 0 )
|
||||||
{
|
{
|
||||||
const float BeatsPerSecond = BPM1 / 60.0f;
|
HandleBunki( out.m_SongTiming, BPM1, BPM2, SMGap1, BPMPos2 );
|
||||||
const float beat = (BPMPos2 + SMGap1) * BeatsPerSecond;
|
|
||||||
LOG->Trace( "BPM %f, BPS %f, BPMPos2 %f, beat %f",
|
|
||||||
BPM1, BeatsPerSecond, BPMPos2, beat );
|
|
||||||
out.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM2) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( BPM3 > 0 && BPMPos3 > 0 )
|
if( BPM3 > 0 && BPMPos3 > 0 )
|
||||||
{
|
{
|
||||||
const float BeatsPerSecond = BPM2 / 60.0f;
|
HandleBunki( out.m_SongTiming, BPM2, BPM3, SMGap2, BPMPos3 );
|
||||||
//The line below isn't perfect, but works better than previous versions.
|
|
||||||
const float beat = (BPMPos3 + SMGap2) * BeatsPerSecond;
|
|
||||||
LOG->Trace( "BPM %f, BPS %f, BPMPos3 %f, beat %f",
|
|
||||||
BPM2, BeatsPerSecond, BPMPos3, beat );
|
|
||||||
out.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM3) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -507,41 +637,12 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant
|
|||||||
BeginsWith(NoteRowString, "|D") || BeginsWith(NoteRowString, "|E") )
|
BeginsWith(NoteRowString, "|D") || BeginsWith(NoteRowString, "|E") )
|
||||||
{
|
{
|
||||||
bDMRequired = true;
|
bDMRequired = true;
|
||||||
RString temp = NoteRowString.substr(2,NoteRowString.size()-3);
|
if ( !HandlePipeChars( out.m_SongTiming, NoteRowString, fCurBeat, iTickCount ) )
|
||||||
float numTemp = StringToFloat(temp);
|
|
||||||
if (BeginsWith(NoteRowString, "|T"))
|
|
||||||
{
|
{
|
||||||
iTickCount = (int)numTemp;
|
// LOG it first.
|
||||||
TickcountSegment tcs;
|
|
||||||
tcs.m_iStartRow = BeatToNoteRow(fCurBeat);
|
|
||||||
tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount;
|
|
||||||
out.m_Timing.AddTickcountSegment( tcs );
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
else if (BeginsWith(NoteRowString, "|B"))
|
|
||||||
{
|
|
||||||
float fCurBpm = (float)numTemp;
|
|
||||||
//out.m_Timing.AddBPMSegment( BPMSegment( BeatToNoteRow(fCurBeat), (float)numTemp ) );
|
|
||||||
out.m_Timing.SetBPMAtBeat( fCurBeat, fCurBpm );
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (BeginsWith(NoteRowString, "|E"))
|
|
||||||
{
|
|
||||||
// Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster
|
|
||||||
float fCurDelay = 60 / out.m_Timing.GetBPMAtBeat(fCurBeat) * (float)numTemp / iTickCount;
|
|
||||||
fCurDelay += out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) );
|
|
||||||
out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (BeginsWith(NoteRowString, "|D"))
|
|
||||||
{
|
|
||||||
float fCurDelay = out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) );
|
|
||||||
fCurDelay += (float)numTemp / 1000;
|
|
||||||
out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ignore whatever else...
|
// ignore whatever else...
|
||||||
@@ -580,16 +681,19 @@ bool KSFLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
ASSERT( arrayKSFFileNames.size() );
|
ASSERT( arrayKSFFileNames.size() );
|
||||||
|
|
||||||
bool bKIUCompliant = false;
|
bool bKIUCompliant = false;
|
||||||
/* If only the first file is read, it will cause problems for other simfiles with
|
/* With Split Timing, there has to be a backup Song Timing in case
|
||||||
* different BPM changes and tickcounts. This command will probably have to be
|
* anything goes wrong. As these files are kept in alphabetical
|
||||||
* changed in the future. */
|
* order (hopefully), it is best to use the LAST file for timing
|
||||||
if( !LoadGlobalData(out.GetSongDir() + arrayKSFFileNames[0], out, bKIUCompliant) )
|
* purposes, for that is the "normal", or easiest difficulty.
|
||||||
|
* Usually. */
|
||||||
|
unsigned files = arrayKSFFileNames.size();
|
||||||
|
if( !LoadGlobalData(out.GetSongDir() + arrayKSFFileNames[files - 1], out, bKIUCompliant) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// load the Steps from the rest of the KSF files
|
// load the Steps from the rest of the KSF files
|
||||||
for( unsigned i=0; i<arrayKSFFileNames.size(); i++ )
|
for( unsigned i=0; i<files; i++ )
|
||||||
{
|
{
|
||||||
Steps* pNewNotes = new Steps;
|
Steps* pNewNotes = out.CreateSteps();
|
||||||
if( !LoadFromKSFFile(out.GetSongDir() + arrayKSFFileNames[i], *pNewNotes, out, bKIUCompliant) )
|
if( !LoadFromKSFFile(out.GetSongDir() + arrayKSFFileNames[i], *pNewNotes, out, bKIUCompliant) )
|
||||||
{
|
{
|
||||||
delete pNewNotes;
|
delete pNewNotes;
|
||||||
@@ -598,6 +702,7 @@ bool KSFLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
|
|
||||||
out.AddSteps( pNewNotes );
|
out.AddSteps( pNewNotes );
|
||||||
}
|
}
|
||||||
|
out.TidyUpData();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -682,7 +682,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
double fSecondsPerBeat = (iter->tickSeconds * GUITAR_MIDI_COUNTS_PER_BEAT);
|
double fSecondsPerBeat = (iter->tickSeconds * GUITAR_MIDI_COUNTS_PER_BEAT);
|
||||||
bpmSeg.m_fBPS = float( 1. / fSecondsPerBeat );
|
bpmSeg.m_fBPS = float( 1. / fSecondsPerBeat );
|
||||||
|
|
||||||
songOut.m_Timing.AddBPMSegment( bpmSeg );
|
songOut.m_SongTiming.AddBPMSegment( bpmSeg );
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_CONST( MidiFileIn::TimeSignatureChange, midi.timeSignatureEvents_, iter )
|
FOREACH_CONST( MidiFileIn::TimeSignatureChange, midi.timeSignatureEvents_, iter )
|
||||||
@@ -692,7 +692,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
seg.m_iNumerator = iter->numerator;
|
seg.m_iNumerator = iter->numerator;
|
||||||
seg.m_iDenominator = iter->denominator;
|
seg.m_iDenominator = iter->denominator;
|
||||||
|
|
||||||
songOut.m_Timing.AddTimeSignatureSegment( seg );
|
songOut.m_SongTiming.AddTimeSignatureSegment( seg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -877,7 +877,7 @@ skip_track:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Steps *pSteps = new Steps;
|
Steps *pSteps = songOut.CreateSteps();
|
||||||
pSteps->m_StepsType = StepsType_guitar_five;
|
pSteps->m_StepsType = StepsType_guitar_five;
|
||||||
pSteps->SetDifficulty( (Difficulty)(gd+1) );
|
pSteps->SetDifficulty( (Difficulty)(gd+1) );
|
||||||
pSteps->SetNoteData( noteData );
|
pSteps->SetNoteData( noteData );
|
||||||
@@ -956,6 +956,7 @@ bool MidiLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
if( !LoadFromMidi(sDir+vsFiles[0], out) )
|
if( !LoadFromMidi(sDir+vsFiles[0], out) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
out.TidyUpData();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
if( fBPM > 0.0f )
|
if( fBPM > 0.0f )
|
||||||
{
|
{
|
||||||
BPMSegment newSeg( 0, fBPM );
|
BPMSegment newSeg( 0, fBPM );
|
||||||
out.AddBPMSegment( newSeg );
|
out.m_SongTiming.AddBPMSegment( newSeg );
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -673,7 +673,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
case PMS_TRACK_BPM:
|
case PMS_TRACK_BPM:
|
||||||
if( iVal > 0 )
|
if( iVal > 0 )
|
||||||
{
|
{
|
||||||
out.SetBPMAtBeat( fBeat, (float) iVal );
|
out.m_SongTiming.SetBPMAtBeat( fBeat, (float) iVal );
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal );
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -694,7 +694,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
if( fBPM > 0.0f )
|
if( fBPM > 0.0f )
|
||||||
{
|
{
|
||||||
BPMSegment newSeg( BeatToNoteRow(fBeat), fBPM );
|
BPMSegment newSeg( BeatToNoteRow(fBeat), fBPM );
|
||||||
out.AddBPMSegment( newSeg );
|
out.m_SongTiming.AddBPMSegment( newSeg );
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg.GetBPM() );
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg.GetBPM() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -716,12 +716,12 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) )
|
if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) )
|
||||||
{
|
{
|
||||||
// find the BPM at the time of this freeze
|
// find the BPM at the time of this freeze
|
||||||
float fBPS = out.m_Timing.GetBPMAtBeat(fBeat) / 60.0f;
|
float fBPS = out.m_SongTiming.GetBPMAtBeat(fBeat) / 60.0f;
|
||||||
float fBeats = StringToFloat( sBeats ) / 48.0f;
|
float fBeats = StringToFloat( sBeats ) / 48.0f;
|
||||||
float fFreezeSecs = fBeats / fBPS;
|
float fFreezeSecs = fBeats / fBPS;
|
||||||
|
|
||||||
StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs );
|
StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs );
|
||||||
out.AddStopSegment( newSeg );
|
out.m_SongTiming.AddStopSegment( newSeg );
|
||||||
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds );
|
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -750,7 +750,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur
|
|||||||
if( fBPM > 0.0f )
|
if( fBPM > 0.0f )
|
||||||
{
|
{
|
||||||
BPMSegment newSeg( iStepIndex, fBPM );
|
BPMSegment newSeg( iStepIndex, fBPM );
|
||||||
out.AddBPMSegment( newSeg );
|
out.m_SongTiming.AddBPMSegment( newSeg );
|
||||||
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(newSeg.m_iStartRow), newSeg.GetBPM() );
|
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(newSeg.m_iStartRow), newSeg.GetBPM() );
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -843,7 +843,7 @@ bool PMSLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
/* Create a Steps for each. */
|
/* Create a Steps for each. */
|
||||||
vector<Steps*> apSteps;
|
vector<Steps*> apSteps;
|
||||||
for( unsigned i=0; i<arrayPMSFileNames.size(); i++ )
|
for( unsigned i=0; i<arrayPMSFileNames.size(); i++ )
|
||||||
apSteps.push_back( new Steps );
|
apSteps.push_back( out.CreateSteps() );
|
||||||
|
|
||||||
// Now, with our fancy little substring, trim the titles and
|
// Now, with our fancy little substring, trim the titles and
|
||||||
// figure out where each goes.
|
// figure out where each goes.
|
||||||
@@ -940,7 +940,7 @@ bool PMSLoader::LoadFromDir( const RString &sDir, Song &out )
|
|||||||
ConvertString( out.m_sArtist, "utf-8,japanese" );
|
ConvertString( out.m_sArtist, "utf-8,japanese" );
|
||||||
ConvertString( out.m_sGenre, "utf-8,japanese" );
|
ConvertString( out.m_sGenre, "utf-8,japanese" );
|
||||||
|
|
||||||
|
out.TidyUpData();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+166
-145
@@ -15,11 +15,6 @@
|
|||||||
|
|
||||||
/** @brief The maximum file size for edits. */
|
/** @brief The maximum file size for edits. */
|
||||||
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
||||||
/**
|
|
||||||
* @brief The highest allowable speed before Warps come in.
|
|
||||||
*
|
|
||||||
* This was brought in from StepMania 4's recent betas. */
|
|
||||||
const float FAST_BPM_WARP = 9999999.f;
|
|
||||||
|
|
||||||
void SMLoader::LoadFromSMTokens(
|
void SMLoader::LoadFromSMTokens(
|
||||||
RString sStepsType,
|
RString sStepsType,
|
||||||
@@ -103,33 +98,103 @@ bool SMLoader::LoadTimingFromFile( const RString &fn, TimingData &out )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam )
|
||||||
{
|
{
|
||||||
out.m_fBeat0OffsetInSeconds = 0;
|
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
|
||||||
out.m_BPMSegments.clear();
|
if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 )
|
||||||
out.m_StopSegments.clear();
|
enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2
|
||||||
out.m_WarpSegments.clear();
|
|
||||||
out.m_vTimeSignatureSegments.clear();
|
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer;
|
||||||
|
if( !bValid )
|
||||||
{
|
{
|
||||||
const MsdFile::value_t &sParams = msd.GetValue(i);
|
LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() );
|
||||||
RString sValueName = sParams[0];
|
|
||||||
sValueName.MakeUpper();
|
|
||||||
|
|
||||||
if( sValueName=="OFFSET" )
|
|
||||||
{
|
|
||||||
out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
|
||||||
}
|
}
|
||||||
else if( sValueName=="BPMS" )
|
else
|
||||||
{
|
{
|
||||||
|
vector<RString> aBGChangeExpressions;
|
||||||
|
split( sParam, ",", aBGChangeExpressions );
|
||||||
|
|
||||||
|
for( unsigned b=0; b<aBGChangeExpressions.size(); b++ )
|
||||||
|
{
|
||||||
|
BackgroundChange change;
|
||||||
|
if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) )
|
||||||
|
out.AddBackgroundChange( iLayer, change );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams )
|
||||||
|
{
|
||||||
|
// Build the RString vector here so we can write it to file again later
|
||||||
|
for( unsigned s=1; s < sParams.params.size(); ++s )
|
||||||
|
out.m_sAttackString.push_back( sParams[s] );
|
||||||
|
|
||||||
|
Attack attack;
|
||||||
|
float end = -9999;
|
||||||
|
|
||||||
|
for( unsigned j=1; j < sParams.params.size(); ++j )
|
||||||
|
{
|
||||||
|
vector<RString> sBits;
|
||||||
|
split( sParams[j], "=", sBits, false );
|
||||||
|
|
||||||
|
// Need an identifer and a value for this to work
|
||||||
|
if( sBits.size() < 2 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TrimLeft( sBits[0] );
|
||||||
|
TrimRight( sBits[0] );
|
||||||
|
|
||||||
|
if( !sBits[0].CompareNoCase("TIME") )
|
||||||
|
attack.fStartSecond = strtof( sBits[1], NULL );
|
||||||
|
else if( !sBits[0].CompareNoCase("LEN") )
|
||||||
|
attack.fSecsRemaining = strtof( sBits[1], NULL );
|
||||||
|
else if( !sBits[0].CompareNoCase("END") )
|
||||||
|
end = strtof( sBits[1], NULL );
|
||||||
|
else if( !sBits[0].CompareNoCase("MODS") )
|
||||||
|
{
|
||||||
|
attack.sModifiers = sBits[1];
|
||||||
|
|
||||||
|
if( end != -9999 )
|
||||||
|
{
|
||||||
|
attack.fSecsRemaining = end - attack.fStartSecond;
|
||||||
|
end = -9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( attack.fSecsRemaining < 0.0f )
|
||||||
|
attack.fSecsRemaining = 0.0f;
|
||||||
|
|
||||||
|
out.m_Attacks.push_back( attack );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLoader::ProcessInstrumentTracks( Song &out, const RString &sParam )
|
||||||
|
{
|
||||||
|
vector<RString> vs1;
|
||||||
|
split( sParam, ",", vs1 );
|
||||||
|
FOREACH_CONST( RString, vs1, s )
|
||||||
|
{
|
||||||
|
vector<RString> vs2;
|
||||||
|
split( *s, "=", vs2 );
|
||||||
|
if( vs2.size() >= 2 )
|
||||||
|
{
|
||||||
|
InstrumentTrack it = StringToInstrumentTrack( vs2[0] );
|
||||||
|
if( it != InstrumentTrack_Invalid )
|
||||||
|
out.m_sInstrumentTrackFile[it] = vs2[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam )
|
||||||
|
{
|
||||||
vector<RString> arrayBPMChangeExpressions;
|
vector<RString> arrayBPMChangeExpressions;
|
||||||
split( sParams[1], ",", arrayBPMChangeExpressions );
|
split( sParam, ",", arrayBPMChangeExpressions );
|
||||||
|
|
||||||
// prepare storage variables for negative BPMs -> Warps.
|
// prepare storage variables for negative BPMs -> Warps.
|
||||||
float negBeat = -1;
|
float negBeat = -1;
|
||||||
float negBPM = 1;
|
float negBPM = 1;
|
||||||
float highspeedBeat = -1;
|
float highspeedBeat = -1;
|
||||||
|
bool bNotEmpty = false;
|
||||||
|
|
||||||
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
||||||
{
|
{
|
||||||
@@ -138,11 +203,13 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
// XXX: Hard to tell which file caused this.
|
// XXX: Hard to tell which file caused this.
|
||||||
if( arrayBPMChangeValues.size() != 2 )
|
if( arrayBPMChangeValues.size() != 2 )
|
||||||
{
|
{
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.",
|
||||||
sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() );
|
arrayBPMChangeExpressions[b].c_str() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bNotEmpty = true;
|
||||||
|
|
||||||
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
||||||
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
||||||
|
|
||||||
@@ -179,20 +246,20 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
highspeedBeat = -1;
|
highspeedBeat = -1;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
BPMSegment new_seg;
|
BPMSegment new_seg( BeatToNoteRow( fBeat ), fNewBPM );
|
||||||
new_seg.m_iStartRow = BeatToNoteRow(fBeat);
|
|
||||||
new_seg.SetBPM( fNewBPM );
|
|
||||||
out.AddBPMSegment( new_seg );
|
out.AddBPMSegment( new_seg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
return bNotEmpty;
|
||||||
{
|
}
|
||||||
|
|
||||||
|
void SMLoader::ProcessStops( TimingData &out, const RString sParam )
|
||||||
|
{
|
||||||
vector<RString> arrayFreezeExpressions;
|
vector<RString> arrayFreezeExpressions;
|
||||||
split( sParams[1], ",", arrayFreezeExpressions );
|
split( sParam, ",", arrayFreezeExpressions );
|
||||||
|
|
||||||
// Prepare variables for negative stop conversion.
|
// Prepare variables for negative stop conversion.
|
||||||
float negBeat = -1;
|
float negBeat = -1;
|
||||||
@@ -205,8 +272,8 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
if( arrayFreezeValues.size() != 2 )
|
if( arrayFreezeValues.size() != 2 )
|
||||||
{
|
{
|
||||||
// XXX: Hard to tell which file caused this.
|
// XXX: Hard to tell which file caused this.
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.",
|
||||||
sValueName.c_str(), arrayFreezeExpressions[f].c_str() );
|
arrayFreezeExpressions[f].c_str() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +290,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
if( negBeat + fSkipBeats > fFreezeBeat )
|
if( negBeat + fSkipBeats > fFreezeBeat )
|
||||||
fSkipBeats = fFreezeBeat - negBeat;
|
fSkipBeats = fFreezeBeat - negBeat;
|
||||||
|
|
||||||
WarpSegment ws( negBeat, negBeat + fSkipBeats);
|
WarpSegment ws( negBeat, fSkipBeats);
|
||||||
out.AddWarpSegment( ws );
|
out.AddWarpSegment( ws );
|
||||||
|
|
||||||
negBeat = -1;
|
negBeat = -1;
|
||||||
@@ -253,12 +320,12 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
WarpSegment ws( negBeat, negBeat + fSkipBeats);
|
WarpSegment ws( negBeat, negBeat + fSkipBeats);
|
||||||
out.AddWarpSegment( ws );
|
out.AddWarpSegment( ws );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="DELAYS" )
|
void SMLoader::ProcessDelays( TimingData &out, const RString sParam )
|
||||||
{
|
{
|
||||||
vector<RString> arrayDelayExpressions;
|
vector<RString> arrayDelayExpressions;
|
||||||
split( sParams[1], ",", arrayDelayExpressions );
|
split( sParam, ",", arrayDelayExpressions );
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
@@ -267,8 +334,8 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
if( arrayDelayValues.size() != 2 )
|
if( arrayDelayValues.size() != 2 )
|
||||||
{
|
{
|
||||||
// XXX: Hard to tell which file caused this.
|
// XXX: Hard to tell which file caused this.
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #DELAYS value \"%s\" (must have exactly one '='), ignored.",
|
||||||
sValueName.c_str(), arrayDelayExpressions[f].c_str() );
|
arrayDelayExpressions[f].c_str() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,12 +354,12 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
else
|
else
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="TIMESIGNATURES" )
|
void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
split( sParams[1], ",", vs1 );
|
split( sParam, ",", vs1 );
|
||||||
|
|
||||||
FOREACH_CONST( RString, vs1, s1 )
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
{
|
{
|
||||||
@@ -307,10 +374,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
|
|
||||||
const float fBeat = StringToFloat( vs2[0] );
|
const float fBeat = StringToFloat( vs2[0] );
|
||||||
|
|
||||||
TimeSignatureSegment seg;
|
TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), StringToInt( vs2[2] ));
|
||||||
seg.m_iStartRow = BeatToNoteRow(fBeat);
|
|
||||||
seg.m_iNumerator = StringToInt( vs2[1] );
|
|
||||||
seg.m_iDenominator = StringToInt( vs2[2] );
|
|
||||||
|
|
||||||
if( fBeat < 0 )
|
if( fBeat < 0 )
|
||||||
{
|
{
|
||||||
@@ -332,12 +396,12 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
|
|
||||||
out.AddTimeSignatureSegment( seg );
|
out.AddTimeSignatureSegment( seg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="TICKCOUNTS" )
|
void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam )
|
||||||
{
|
{
|
||||||
vector<RString> arrayTickcountExpressions;
|
vector<RString> arrayTickcountExpressions;
|
||||||
split( sParams[1], ",", arrayTickcountExpressions );
|
split( sParam, ",", arrayTickcountExpressions );
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
@@ -346,32 +410,60 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
if( arrayTickcountValues.size() != 2 )
|
if( arrayTickcountValues.size() != 2 )
|
||||||
{
|
{
|
||||||
// XXX: Hard to tell which file caused this.
|
// XXX: Hard to tell which file caused this.
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #TICKCOUNTS value \"%s\" (must have exactly one '='), ignored.",
|
||||||
sValueName.c_str(), arrayTickcountExpressions[f].c_str() );
|
arrayTickcountExpressions[f].c_str() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] );
|
const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] );
|
||||||
int iTicks = StringToInt( arrayTickcountValues[1] );
|
int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT);
|
||||||
// you're lazy, let SM do the work for you... -DaisuMaster
|
|
||||||
if( iTicks < 1) iTicks = 1;
|
|
||||||
if( iTicks > ROWS_PER_BEAT ) iTicks = ROWS_PER_BEAT;
|
|
||||||
|
|
||||||
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
|
TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks );
|
||||||
out.AddTickcountSegment( new_seg );
|
out.AddTickcountSegment( new_seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants
|
void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
||||||
|
{
|
||||||
|
out.m_fBeat0OffsetInSeconds = 0;
|
||||||
|
out.m_BPMSegments.clear();
|
||||||
|
out.m_StopSegments.clear();
|
||||||
|
out.m_WarpSegments.clear();
|
||||||
|
out.m_vTimeSignatureSegments.clear();
|
||||||
|
|
||||||
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
||||||
{
|
{
|
||||||
// LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks );
|
const MsdFile::value_t &sParams = msd.GetValue(i);
|
||||||
//out.AddTickcountSegment( new_seg );
|
RString sValueName = sParams[0];
|
||||||
}
|
sValueName.MakeUpper();
|
||||||
else
|
|
||||||
|
if( sValueName=="OFFSET" )
|
||||||
{
|
{
|
||||||
//LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks );
|
out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
||||||
//LOG->UserLog( "Song file", "(UNKNOWN)", "Clamping tickcount value to %d at beat %f.", iTicks, fTickcountBeat);
|
|
||||||
//etc
|
|
||||||
}
|
}
|
||||||
|
else if( sValueName=="BPMS" )
|
||||||
|
{
|
||||||
|
ProcessBPMs(out, sParams[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
||||||
|
{
|
||||||
|
ProcessStops(out, sParams[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="DELAYS" )
|
||||||
|
{
|
||||||
|
ProcessDelays(out, sParams[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="TIMESIGNATURES" )
|
||||||
|
{
|
||||||
|
ProcessTimeSignatures(out, sParams[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="TICKCOUNTS" )
|
||||||
|
{
|
||||||
|
ProcessTickcounts(out, sParams[1]);
|
||||||
}
|
}
|
||||||
// Ensure all of the warps are handled right.
|
// Ensure all of the warps are handled right.
|
||||||
sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end());
|
sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end());
|
||||||
@@ -457,8 +549,8 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.m_Timing.m_sFile = sPath;
|
out.m_SongTiming.m_sFile = sPath;
|
||||||
LoadTimingFromSMFile( msd, out.m_Timing );
|
LoadTimingFromSMFile( msd, out.m_SongTiming );
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
||||||
{
|
{
|
||||||
@@ -512,19 +604,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
|
|
||||||
else if( sValueName=="INSTRUMENTTRACK" )
|
else if( sValueName=="INSTRUMENTTRACK" )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
ProcessInstrumentTracks( out, sParams[1] );
|
||||||
split( sParams[1], ",", vs1 );
|
|
||||||
FOREACH_CONST( RString, vs1, s )
|
|
||||||
{
|
|
||||||
vector<RString> vs2;
|
|
||||||
split( *s, "=", vs2 );
|
|
||||||
if( vs2.size() >= 2 )
|
|
||||||
{
|
|
||||||
InstrumentTrack it = StringToInstrumentTrack( vs2[0] );
|
|
||||||
if( it != InstrumentTrack_Invalid )
|
|
||||||
out.m_sInstrumentTrackFile[it] = vs2[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="MUSICLENGTH" )
|
else if( sValueName=="MUSICLENGTH" )
|
||||||
@@ -617,27 +697,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
|
|
||||||
else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" )
|
else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" )
|
||||||
{
|
{
|
||||||
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
|
ProcessBGChanges( out, sValueName, sPath, sParams[1]);
|
||||||
if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 )
|
|
||||||
enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2
|
|
||||||
|
|
||||||
bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer;
|
|
||||||
if( !bValid )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vector<RString> aBGChangeExpressions;
|
|
||||||
split( sParams[1], ",", aBGChangeExpressions );
|
|
||||||
|
|
||||||
for( unsigned b=0; b<aBGChangeExpressions.size(); b++ )
|
|
||||||
{
|
|
||||||
BackgroundChange change;
|
|
||||||
if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) )
|
|
||||||
out.AddBackgroundChange( iLayer, change );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="FGCHANGES" )
|
else if( sValueName=="FGCHANGES" )
|
||||||
@@ -661,47 +721,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
// Attacks loaded from file
|
// Attacks loaded from file
|
||||||
else if( sValueName=="ATTACKS" )
|
else if( sValueName=="ATTACKS" )
|
||||||
{
|
{
|
||||||
// Build the RString vector here so we can write it to file again later
|
ProcessAttacks( out, sParams );
|
||||||
for( unsigned s=1; s < sParams.params.size(); ++s )
|
|
||||||
out.m_sAttackString.push_back( sParams[s] );
|
|
||||||
|
|
||||||
Attack attack;
|
|
||||||
float end = -9999;
|
|
||||||
|
|
||||||
for( unsigned j=1; j < sParams.params.size(); ++j )
|
|
||||||
{
|
|
||||||
vector<RString> sBits;
|
|
||||||
split( sParams[j], "=", sBits, false );
|
|
||||||
|
|
||||||
// Need an identifer and a value for this to work
|
|
||||||
if( sBits.size() < 2 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TrimLeft( sBits[0] );
|
|
||||||
TrimRight( sBits[0] );
|
|
||||||
|
|
||||||
if( !sBits[0].CompareNoCase("TIME") )
|
|
||||||
attack.fStartSecond = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("LEN") )
|
|
||||||
attack.fSecsRemaining = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("END") )
|
|
||||||
end = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("MODS") )
|
|
||||||
{
|
|
||||||
attack.sModifiers = sBits[1];
|
|
||||||
|
|
||||||
if( end != -9999 )
|
|
||||||
{
|
|
||||||
attack.fSecsRemaining = end - attack.fStartSecond;
|
|
||||||
end = -9999;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( attack.fSecsRemaining < 0.0f )
|
|
||||||
attack.fSecsRemaining = 0.0f;
|
|
||||||
|
|
||||||
out.m_Attacks.push_back( attack );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
|
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
|
||||||
@@ -712,7 +732,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steps* pNewNotes = new Steps;
|
Steps* pNewNotes = out.CreateSteps();
|
||||||
LoadFromSMTokens(
|
LoadFromSMTokens(
|
||||||
sParams[1],
|
sParams[1],
|
||||||
sParams[2],
|
sParams[2],
|
||||||
@@ -733,7 +753,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
|
|||||||
else
|
else
|
||||||
LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() );
|
LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() );
|
||||||
}
|
}
|
||||||
|
TidyUpData( out, bFromCache );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,7 +866,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
|
|||||||
if( !bAddStepsToSong )
|
if( !bAddStepsToSong )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Steps* pNewNotes = new Steps;
|
Steps* pNewNotes = pSong->CreateSteps();
|
||||||
LoadFromSMTokens(
|
LoadFromSMTokens(
|
||||||
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
||||||
*pNewNotes);
|
*pNewNotes);
|
||||||
@@ -926,6 +946,7 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache )
|
|||||||
bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) );
|
bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) );
|
||||||
} while(0);
|
} while(0);
|
||||||
}
|
}
|
||||||
|
song.TidyUpData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+19
-1
@@ -3,11 +3,18 @@
|
|||||||
|
|
||||||
#include "GameConstantsAndTypes.h"
|
#include "GameConstantsAndTypes.h"
|
||||||
#include "BackgroundUtil.h"
|
#include "BackgroundUtil.h"
|
||||||
|
#include "MsdFile.h" // we require the struct from here.
|
||||||
|
|
||||||
class MsdFile;
|
|
||||||
class Song;
|
class Song;
|
||||||
class Steps;
|
class Steps;
|
||||||
class TimingData;
|
class TimingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The highest allowable speed before Warps come in.
|
||||||
|
*
|
||||||
|
* 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. */
|
/** @brief Reads a Song from an .SM file. */
|
||||||
namespace SMLoader
|
namespace SMLoader
|
||||||
{
|
{
|
||||||
@@ -25,6 +32,17 @@ namespace SMLoader
|
|||||||
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
||||||
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
const RString &sPath, const RString &sParam );
|
||||||
|
void ProcessAttacks( Song &out, MsdFile::value_t sParams );
|
||||||
|
void ProcessInstrumentTracks( Song &out, const RString &sParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+484
-389
@@ -12,12 +12,379 @@
|
|||||||
#include "Song.h"
|
#include "Song.h"
|
||||||
#include "SongManager.h"
|
#include "SongManager.h"
|
||||||
#include "Steps.h"
|
#include "Steps.h"
|
||||||
|
#include "Attack.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A custom .edit file can only be so big before we have to reject it.
|
* @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
|
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);
|
||||||
|
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);
|
||||||
|
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, 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, 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( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true );
|
||||||
|
// XXX: Remove Negatives Bug?
|
||||||
|
new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat);
|
||||||
|
new_seg.m_fStopSeconds = 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;
|
||||||
|
split( sParam, ",", arrayMultiplierExpressions );
|
||||||
|
|
||||||
|
for( unsigned f=0; f<arrayMultiplierExpressions.size(); f++ )
|
||||||
|
{
|
||||||
|
vector<RString> arrayMultiplierValues;
|
||||||
|
split( arrayMultiplierExpressions[f], "=", arrayMultiplierValues );
|
||||||
|
if( arrayMultiplierValues.size() != 2 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #MULTIPLIER value \"%s\" (must have exactly one '='), ignored.",
|
||||||
|
arrayMultiplierExpressions[f].c_str() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float fComboBeat = RowToBeat( arrayMultiplierValues[0], iRowsPerBeat );
|
||||||
|
const int iCombos = StringToInt( arrayMultiplierValues[1] );
|
||||||
|
ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos );
|
||||||
|
out.AddComboSegment( new_seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMALoader::ProcessBeatsPerMeasure( TimingData &out, const RString sParam )
|
||||||
|
{
|
||||||
|
vector<RString> vs1;
|
||||||
|
split( sParam, ",", vs1 );
|
||||||
|
|
||||||
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
|
{
|
||||||
|
vector<RString> vs2;
|
||||||
|
split( *s1, "=", vs2 );
|
||||||
|
|
||||||
|
if( vs2.size() < 2 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid beats per measure change with %i values.", (int)vs2.size() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = StringToFloat( vs2[0] );
|
||||||
|
|
||||||
|
TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), 4 );
|
||||||
|
|
||||||
|
if( fBeat < 0 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( seg.m_iNumerator < 1 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.AddTimeSignatureSegment( seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float BeatToSeconds(float fromBeat, RString toSomething)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam )
|
||||||
|
{
|
||||||
|
vector<RString> vs1;
|
||||||
|
split( sParam, ",", vs1 );
|
||||||
|
|
||||||
|
FOREACH_CONST( RString, vs1, s1 )
|
||||||
|
{
|
||||||
|
vector<RString> vs2;
|
||||||
|
split( *s1, "=", vs2 );
|
||||||
|
|
||||||
|
if( RowToBeat(vs2[0], iRowsPerBeat) == 0 && vs2.size() == 2 ) // First one always seems to have 2.
|
||||||
|
{
|
||||||
|
vs2.push_back("0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vs2.size() < 3 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = RowToBeat( vs2[0], iRowsPerBeat );
|
||||||
|
|
||||||
|
unsigned short tmp = ( (vs2[2].find("s") || vs2[2].find("S") )
|
||||||
|
? 1 : 0);
|
||||||
|
|
||||||
|
SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] ), tmp);
|
||||||
|
|
||||||
|
if( fBeat < 0 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( seg.m_fWait < 0 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, fWait %f.", fBeat, seg.m_fWait );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.AddSpeedSegment( seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
void SMALoader::LoadFromSMATokens(
|
||||||
RString sStepsType,
|
RString sStepsType,
|
||||||
RString sDescription,
|
RString sDescription,
|
||||||
@@ -28,73 +395,9 @@ void SMALoader::LoadFromSMATokens(
|
|||||||
Steps &out
|
Steps &out
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// we're loading from disk, so this is by definition already saved:
|
SMLoader::LoadFromSMTokens( sStepsType, sDescription,
|
||||||
out.SetSavedToDisk( true );
|
sDifficulty, sMeter, sRadarValues,
|
||||||
|
sNoteData, out );
|
||||||
Trim( sStepsType );
|
|
||||||
Trim( sDescription );
|
|
||||||
Trim( sDifficulty );
|
|
||||||
Trim( sNoteData );
|
|
||||||
|
|
||||||
// LOG->Trace( "Steps::LoadFromSMTokens()" );
|
|
||||||
|
|
||||||
// insert stepstype hacks from GameManager.cpp here? -aj
|
|
||||||
out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType );
|
|
||||||
out.SetDescription( sDescription );
|
|
||||||
out.SetCredit( sDescription ); // this is often used for both.
|
|
||||||
out.SetDifficulty( StringToDifficulty(sDifficulty) );
|
|
||||||
|
|
||||||
sDescription.MakeLower();
|
|
||||||
|
|
||||||
// Handle hacks that originated back when StepMania didn't have
|
|
||||||
// Difficulty_Challenge. (At least v1.64, possibly v3.0 final...)
|
|
||||||
if( out.GetDifficulty() == Difficulty_Hard )
|
|
||||||
{
|
|
||||||
// HACK: SMANIAC used to be Difficulty_Hard with a special description.
|
|
||||||
if( sDescription == "smaniac" )
|
|
||||||
out.SetDifficulty( Difficulty_Challenge );
|
|
||||||
|
|
||||||
// HACK: CHALLENGE used to be Difficulty_Hard with a special description.
|
|
||||||
if( sDescription == "challenge" )
|
|
||||||
out.SetDifficulty( Difficulty_Challenge );
|
|
||||||
}
|
|
||||||
|
|
||||||
out.SetMeter( StringToInt(sMeter) );
|
|
||||||
vector<RString> saValues;
|
|
||||||
split( sRadarValues, ",", saValues, true );
|
|
||||||
int categories = NUM_RadarCategory - 1; // Fakes aren't counted in the radar values.
|
|
||||||
if( saValues.size() == (unsigned)categories * NUM_PLAYERS )
|
|
||||||
{
|
|
||||||
RadarValues v[NUM_PLAYERS];
|
|
||||||
FOREACH_PlayerNumber( pn )
|
|
||||||
{
|
|
||||||
// Can't use the foreach anymore due to flexible radar lines.
|
|
||||||
for( RadarCategory rc = (RadarCategory)0; rc < categories;
|
|
||||||
enum_add<RadarCategory>( rc, 1 ) )
|
|
||||||
{
|
|
||||||
v[pn][rc] = StringToFloat( saValues[pn*categories + rc] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.SetCachedRadarValues( v );
|
|
||||||
}
|
|
||||||
|
|
||||||
out.SetSMNoteData( sNoteData );
|
|
||||||
|
|
||||||
out.TidyUpData();
|
|
||||||
}
|
|
||||||
|
|
||||||
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. There can be only one!" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ASSERT( aFileNames.size() == 1 );
|
|
||||||
return LoadFromSMAFile( sPath + aFileNames[0], out );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMALoader::TidyUpData( Song &song, bool bFromCache )
|
void SMALoader::TidyUpData( Song &song, bool bFromCache )
|
||||||
@@ -113,8 +416,12 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.m_Timing.m_sFile = sPath;
|
out.m_SongTiming.m_sFile = sPath; // songs still have their fallback timing.
|
||||||
LoadTimingFromSMAFile( msd, out.m_Timing );
|
|
||||||
|
int state = SMA_GETTING_SONG_INFO;
|
||||||
|
Steps* pNewNotes = NULL;
|
||||||
|
TimingData stepsTiming;
|
||||||
|
int iRowsPerBeat = -1; // Start with an invalid value: needed for checking.
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
||||||
{
|
{
|
||||||
@@ -168,19 +475,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
|
|
||||||
else if( sValueName=="INSTRUMENTTRACK" )
|
else if( sValueName=="INSTRUMENTTRACK" )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
SMLoader::ProcessInstrumentTracks( out, sParams[1] );
|
||||||
split( sParams[1], ",", vs1 );
|
|
||||||
FOREACH_CONST( RString, vs1, s )
|
|
||||||
{
|
|
||||||
vector<RString> vs2;
|
|
||||||
split( *s, "=", vs2 );
|
|
||||||
if( vs2.size() >= 2 )
|
|
||||||
{
|
|
||||||
InstrumentTrack it = StringToInstrumentTrack( vs2[0] );
|
|
||||||
if( it != InstrumentTrack_Invalid )
|
|
||||||
out.m_sInstrumentTrackFile[it] = vs2[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="MUSICLENGTH" )
|
else if( sValueName=="MUSICLENGTH" )
|
||||||
@@ -202,7 +497,8 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
}
|
}
|
||||||
else if( sValueName=="LASTBEAT" )
|
else if( sValueName=="LASTBEAT" )
|
||||||
{
|
{
|
||||||
; }
|
;
|
||||||
|
}
|
||||||
else if( sValueName=="SONGFILENAME" )
|
else if( sValueName=="SONGFILENAME" )
|
||||||
{
|
{
|
||||||
;
|
;
|
||||||
@@ -226,6 +522,11 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
//else if( sValueName=="SAMPLEPATH" )
|
//else if( sValueName=="SAMPLEPATH" )
|
||||||
//out.m_sMusicSamplePath = sParams[1];
|
//out.m_sMusicSamplePath = sParams[1];
|
||||||
|
|
||||||
|
else if( sValueName=="LISTSORT" )
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
else if( sValueName=="DISPLAYBPM" )
|
else if( sValueName=="DISPLAYBPM" )
|
||||||
{
|
{
|
||||||
// #DISPLAYBPM:[xxx][xxx:xxx]|[*];
|
// #DISPLAYBPM:[xxx][xxx:xxx]|[*];
|
||||||
@@ -242,6 +543,41 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="SMAVERSION" )
|
||||||
|
{
|
||||||
|
; // ignore it.
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="ROWSPERBEAT" )
|
||||||
|
{
|
||||||
|
/* This value is used to help translate the timings
|
||||||
|
* the SMA format uses. Starting with the second
|
||||||
|
* appearance, it delimits NoteData. Right now, this
|
||||||
|
* value doesn't seem to be editable in SMA. When it
|
||||||
|
* becomes so, make adjustments to this code. */
|
||||||
|
if( iRowsPerBeat < 0 )
|
||||||
|
{
|
||||||
|
vector<RString> arrayBeatChangeExpressions;
|
||||||
|
split( sParams[1], ",", arrayBeatChangeExpressions );
|
||||||
|
|
||||||
|
vector<RString> arrayBeatChangeValues;
|
||||||
|
split( arrayBeatChangeExpressions[0], "=", arrayBeatChangeValues );
|
||||||
|
iRowsPerBeat = StringToInt(arrayBeatChangeValues[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = SMA_GETTING_STEP_INFO;
|
||||||
|
pNewNotes = new Steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="BEATSPERMEASURE" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessBeatsPerMeasure( timing, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
else if( sValueName=="SELECTABLE" )
|
else if( sValueName=="SELECTABLE" )
|
||||||
{
|
{
|
||||||
if(sParams[1].EqualsNoCase("YES"))
|
if(sParams[1].EqualsNoCase("YES"))
|
||||||
@@ -265,27 +601,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
|
|
||||||
else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" )
|
else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" )
|
||||||
{
|
{
|
||||||
BackgroundLayer iLayer = BACKGROUND_LAYER_1;
|
SMLoader::ProcessBGChanges( out, sValueName, sPath, sParams[1]);
|
||||||
if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 )
|
|
||||||
enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2
|
|
||||||
|
|
||||||
bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer;
|
|
||||||
if( !bValid )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vector<RString> aBGChangeExpressions;
|
|
||||||
split( sParams[1], ",", aBGChangeExpressions );
|
|
||||||
|
|
||||||
for( unsigned b=0; b<aBGChangeExpressions.size(); b++ )
|
|
||||||
{
|
|
||||||
BackgroundChange change;
|
|
||||||
if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) )
|
|
||||||
out.AddBackgroundChange( iLayer, change );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="FGCHANGES" )
|
else if( sValueName=="FGCHANGES" )
|
||||||
@@ -301,6 +617,65 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="OFFSET" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="BPMS" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessBPMs( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessStops( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="DELAYS" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessDelays( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="TICKCOUNT" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessTickcounts( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="SPEED" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessSpeeds( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="MULTIPLIER" )
|
||||||
|
{
|
||||||
|
ProcessMultipliers( pNewNotes->m_Timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="FAKES" )
|
||||||
|
{
|
||||||
|
TimingData &timing = (state == SMA_GETTING_STEP_INFO
|
||||||
|
? pNewNotes->m_Timing : out.m_SongTiming);
|
||||||
|
ProcessFakes( timing, iRowsPerBeat, sParams[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="METERTYPE" )
|
||||||
|
{
|
||||||
|
; // We don't use this...yet.
|
||||||
|
}
|
||||||
|
|
||||||
else if( sValueName=="KEYSOUNDS" )
|
else if( sValueName=="KEYSOUNDS" )
|
||||||
{
|
{
|
||||||
split( sParams[1], ",", out.m_vsKeysoundFile );
|
split( sParams[1], ",", out.m_vsKeysoundFile );
|
||||||
@@ -309,47 +684,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
// Attacks loaded from file
|
// Attacks loaded from file
|
||||||
else if( sValueName=="ATTACKS" )
|
else if( sValueName=="ATTACKS" )
|
||||||
{
|
{
|
||||||
// Build the RString vector here so we can write it to file again later
|
SMLoader::ProcessAttacks( out, sParams );
|
||||||
for( unsigned s=1; s < sParams.params.size(); ++s )
|
|
||||||
out.m_sAttackString.push_back( sParams[s] );
|
|
||||||
|
|
||||||
Attack attack;
|
|
||||||
float end = -9999;
|
|
||||||
|
|
||||||
for( unsigned j=1; j < sParams.params.size(); ++j )
|
|
||||||
{
|
|
||||||
vector<RString> sBits;
|
|
||||||
split( sParams[j], "=", sBits, false );
|
|
||||||
|
|
||||||
// Need an identifer and a value for this to work
|
|
||||||
if( sBits.size() < 2 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TrimLeft( sBits[0] );
|
|
||||||
TrimRight( sBits[0] );
|
|
||||||
|
|
||||||
if( !sBits[0].CompareNoCase("TIME") )
|
|
||||||
attack.fStartSecond = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("LEN") )
|
|
||||||
attack.fSecsRemaining = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("END") )
|
|
||||||
end = strtof( sBits[1], NULL );
|
|
||||||
else if( !sBits[0].CompareNoCase("MODS") )
|
|
||||||
{
|
|
||||||
attack.sModifiers = sBits[1];
|
|
||||||
|
|
||||||
if( end != -9999 )
|
|
||||||
{
|
|
||||||
attack.fSecsRemaining = end - attack.fStartSecond;
|
|
||||||
end = -9999;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( attack.fSecsRemaining < 0.0f )
|
|
||||||
attack.fSecsRemaining = 0.0f;
|
|
||||||
|
|
||||||
out.m_Attacks.push_back( attack );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
|
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
|
||||||
@@ -360,7 +695,6 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Steps* pNewNotes = new Steps;
|
|
||||||
LoadFromSMATokens(
|
LoadFromSMATokens(
|
||||||
sParams[1],
|
sParams[1],
|
||||||
sParams[2],
|
sParams[2],
|
||||||
@@ -372,16 +706,13 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out )
|
|||||||
|
|
||||||
out.AddSteps( pNewNotes );
|
out.AddSteps( pNewNotes );
|
||||||
}
|
}
|
||||||
/*
|
else if( sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" )
|
||||||
* We used to check for timing data in this section. That has
|
|
||||||
* since been moved to a dedicated function.
|
|
||||||
*/
|
|
||||||
else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="DELAYS" || sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" || sValueName=="TICKCOUNTS" )
|
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() );
|
LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() );
|
||||||
}
|
}
|
||||||
|
TidyUpData(out, false);
|
||||||
|
out.TidyUpData();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,236 +721,6 @@ void SMALoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
|||||||
GetDirListing( sPath + RString("*.sma"), out );
|
GetDirListing( sPath + RString("*.sma"), out );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMALoader::LoadTimingFromFile( const RString &fn, TimingData &out )
|
|
||||||
{
|
|
||||||
MsdFile msd;
|
|
||||||
if( !msd.ReadFile( fn, true ) ) // unescape
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", fn, "couldn't be loaded: %s", msd.GetError().c_str() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.m_sFile = fn;
|
|
||||||
LoadTimingFromSMAFile( msd, out );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMALoader::LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out )
|
|
||||||
{
|
|
||||||
out.m_fBeat0OffsetInSeconds = 0;
|
|
||||||
out.m_BPMSegments.clear();
|
|
||||||
out.m_StopSegments.clear();
|
|
||||||
out.m_WarpSegments.clear();
|
|
||||||
out.m_vTimeSignatureSegments.clear();
|
|
||||||
|
|
||||||
vector<WarpSegment> arrayWarpsFromNegativeBPMs;
|
|
||||||
//vector<WarpSegment> arrayWarpsFromNegativeStops;
|
|
||||||
int rowsPerMeasure = 0;
|
|
||||||
bool encountered = false;
|
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
|
||||||
{
|
|
||||||
const MsdFile::value_t &sParams = msd.GetValue(i);
|
|
||||||
RString sValueName = sParams[0];
|
|
||||||
sValueName.MakeUpper();
|
|
||||||
|
|
||||||
if( sValueName=="ROWSPERBEAT")
|
|
||||||
{
|
|
||||||
if( encountered )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
encountered = true;
|
|
||||||
rowsPerMeasure = StringToInt( sParams[1] );
|
|
||||||
}
|
|
||||||
else if( sValueName=="BEATSPERMEASURE" )
|
|
||||||
{
|
|
||||||
TimeSignatureSegment new_seg;
|
|
||||||
new_seg.m_iStartRow = 0;
|
|
||||||
new_seg.m_iNumerator = StringToInt( sParams[1] );
|
|
||||||
new_seg.m_iDenominator = 4;
|
|
||||||
out.AddTimeSignatureSegment( new_seg );
|
|
||||||
}
|
|
||||||
else if( sValueName=="OFFSET" )
|
|
||||||
{
|
|
||||||
out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
|
||||||
}
|
|
||||||
else if( sValueName=="STOPS" )
|
|
||||||
{
|
|
||||||
vector<RString> arrayFreezeExpressions;
|
|
||||||
split( sParams[1], ",", arrayFreezeExpressions );
|
|
||||||
|
|
||||||
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 #%s value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
sValueName.c_str(), arrayFreezeExpressions[f].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float fFreezeBeat = 0;
|
|
||||||
RString beat = arrayFreezeValues[0];
|
|
||||||
if( beat.Right(0).MakeUpper() == "R" )
|
|
||||||
{
|
|
||||||
beat = beat.Left(beat.size()-1);
|
|
||||||
fFreezeBeat = StringToFloat( beat ) / rowsPerMeasure;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fFreezeBeat = StringToFloat(beat);
|
|
||||||
}
|
|
||||||
|
|
||||||
//float fFreezeBeat = StringToFloat( arrayBPMChangeValues[0] );
|
|
||||||
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
|
||||||
StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
|
|
||||||
// XXX: Remove Negatives Bug?
|
|
||||||
new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat);
|
|
||||||
new_seg.m_fStopSeconds = fFreezeSeconds;
|
|
||||||
|
|
||||||
if(fFreezeSeconds > 0.0f)
|
|
||||||
{
|
|
||||||
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
|
|
||||||
out.AddStopSegment( new_seg );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// negative stops (hi JS!) -aj
|
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
|
||||||
{
|
|
||||||
// LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
|
|
||||||
out.AddStopSegment( new_seg );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if( sValueName=="BPMS" )
|
|
||||||
{
|
|
||||||
vector<RString> arrayBPMChangeExpressions;
|
|
||||||
split( sParams[1], ",", arrayBPMChangeExpressions );
|
|
||||||
|
|
||||||
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 #%s value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float fBeat = 0;
|
|
||||||
RString beat = arrayBPMChangeValues[0];
|
|
||||||
if( beat.Right(0).MakeUpper() == "R" )
|
|
||||||
{
|
|
||||||
beat = beat.Left(beat.size()-1);
|
|
||||||
fBeat = StringToFloat( beat ) / rowsPerMeasure;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fBeat = StringToFloat(beat);
|
|
||||||
}
|
|
||||||
|
|
||||||
//float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
|
||||||
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
|
||||||
// XXX: Remove Negatives Bug?
|
|
||||||
BPMSegment new_seg;
|
|
||||||
new_seg.m_iStartRow = BeatToNoteRow(fBeat);
|
|
||||||
new_seg.SetBPM( fNewBPM );
|
|
||||||
|
|
||||||
// convert negative BPMs into Warp segments
|
|
||||||
if( fNewBPM < 0.0f )
|
|
||||||
{
|
|
||||||
vector<RString> arrayNextBPMChangeValues;
|
|
||||||
// get next bpm in sequence
|
|
||||||
if((b+1) < arrayBPMChangeExpressions.size())
|
|
||||||
{
|
|
||||||
split( arrayBPMChangeExpressions[b+1], "=", arrayNextBPMChangeValues );
|
|
||||||
const float fNextPositiveBeat = StringToFloat( arrayNextBPMChangeValues[0] );
|
|
||||||
const float fNextPositiveBPM = StringToFloat( arrayNextBPMChangeValues[1] );
|
|
||||||
|
|
||||||
// tJumpPos = (tPosBPS-abs(negBPS)) + (gPosBPMPosition - fNegPosition)
|
|
||||||
float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat);
|
|
||||||
//float fWarpLengthBeats = fNextPositiveBeat + fDeltaBeat;
|
|
||||||
WarpSegment wsTemp(BeatToNoteRow(fBeat),fDeltaBeat);
|
|
||||||
arrayWarpsFromNegativeBPMs.push_back(wsTemp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==NotesLoSM negbpm==\nfnextposbeat = %f, fnextposbpm = %f,\nfdelta = %f, fwarpto = %f",
|
|
||||||
fNextPositiveBeat,
|
|
||||||
fNextPositiveBPM,
|
|
||||||
fDeltaBeat,
|
|
||||||
fWarpToBeat
|
|
||||||
) );
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==Negative/Subtractive BPM in NotesLoader==\nNegBPM has noterow = %i, BPM = %f\nNextBPM @ noterow %i\nDelta value = %i noterows\nThis warp will have us end up at noterow %i",
|
|
||||||
BeatToNoteRow(fBeat), fNewBPM,
|
|
||||||
BeatToNoteRow(fNextPositiveBeat),
|
|
||||||
BeatToNoteRow(fDeltaBeat),
|
|
||||||
BeatToNoteRow(fWarpToBeat))
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
//float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat);
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==NotesLoader Delta as NoteRows==\nfDeltaBeat = %f (beat)\nfDeltaBeat = (NextBPMSeg %f - abs(fBPS %f)) + (nextStartRow %i - thisRow %i)",
|
|
||||||
fDeltaBeat,(fNextPositiveBPM/60.0f),abs(fNewBPM/60.0f),BeatToNoteRow(fNextPositiveBeat),BeatToNoteRow(fBeat))
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// last BPM is a negative one? ugh. -aj (MAX_NOTE_ROW exists btw)
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fNewBPM > 0.0f)
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out.m_bHasNegativeBpms = true;
|
|
||||||
// only add Negative BPMs in quirks mode -aj
|
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
else
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Note: Even though it is possible to have Negative BPMs and Stops in
|
|
||||||
// a song along with Warps, we should not support files that contain
|
|
||||||
// both styles of warp tricks (Negatives vs. #WARPS).
|
|
||||||
// If Warps have been populated from Negative BPMs, then go through that
|
|
||||||
// instead of using the data in the Warps tag. This should be above,
|
|
||||||
// but it breaks compiling so...
|
|
||||||
if(arrayWarpsFromNegativeBPMs.size() > 0)
|
|
||||||
{
|
|
||||||
// zomg we already have some warps...
|
|
||||||
for( unsigned j=0; j<arrayWarpsFromNegativeBPMs.size(); j++ )
|
|
||||||
{
|
|
||||||
out.AddWarpSegment( arrayWarpsFromNegativeBPMs[j] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// warp sorting will need to take place.
|
|
||||||
//sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong )
|
||||||
{
|
{
|
||||||
LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() );
|
||||||
@@ -702,7 +803,7 @@ bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
|
|||||||
if( !bAddStepsToSong )
|
if( !bAddStepsToSong )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Steps* pNewNotes = new Steps;
|
Steps* pNewNotes = pSong->CreateSteps();
|
||||||
LoadFromSMATokens(
|
LoadFromSMATokens(
|
||||||
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
|
||||||
*pNewNotes);
|
*pNewNotes);
|
||||||
@@ -730,12 +831,6 @@ bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMALoader::LoadFromBGChangesString( BackgroundChange &change,
|
|
||||||
const RString &sBGChangeExpression )
|
|
||||||
{
|
|
||||||
return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
|
* @author Aldo Fregoso, Jason Felds (c) 2009-2011
|
||||||
|
|||||||
+22
-2
@@ -9,6 +9,16 @@ class Song;
|
|||||||
class Steps;
|
class Steps;
|
||||||
class TimingData;
|
class TimingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The various states while parsing a .sma file.
|
||||||
|
*/
|
||||||
|
enum SMALoadingStates
|
||||||
|
{
|
||||||
|
SMA_GETTING_SONG_INFO, /**< Retrieving song information. */
|
||||||
|
SMA_GETTING_STEP_INFO, /**< Retrieving step information. */
|
||||||
|
NUM_SMALoadingStates /**< The number of states used. */
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief Reads a Song from a .SMA file. */
|
/** @brief Reads a Song from a .SMA file. */
|
||||||
namespace SMALoader
|
namespace SMALoader
|
||||||
{
|
{
|
||||||
@@ -25,12 +35,22 @@ namespace SMALoader
|
|||||||
|
|
||||||
bool LoadFromSMAFile( const RString &sPath, Song &out );
|
bool LoadFromSMAFile( const RString &sPath, Song &out );
|
||||||
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
void GetApplicableFiles( const RString &sPath, vector<RString> &out );
|
||||||
bool LoadTimingFromFile( const RString &fn, TimingData &out );
|
|
||||||
void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out );
|
|
||||||
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot );
|
||||||
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong );
|
||||||
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression );
|
||||||
|
|
||||||
|
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 );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+287
-551
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,6 @@ enum SSCLoadingStates
|
|||||||
{
|
{
|
||||||
GETTING_SONG_INFO, /**< Retrieving song information. */
|
GETTING_SONG_INFO, /**< Retrieving song information. */
|
||||||
GETTING_STEP_INFO, /**< Retrieving step information. */
|
GETTING_STEP_INFO, /**< Retrieving step information. */
|
||||||
GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */
|
|
||||||
GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */
|
|
||||||
NUM_SSCLoadingStates /**< The number of states used. */
|
NUM_SSCLoadingStates /**< The number of states used. */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,6 +23,8 @@ enum SSCLoadingStates
|
|||||||
const float VERSION_RADAR_FAKE = 0.53f;
|
const float VERSION_RADAR_FAKE = 0.53f;
|
||||||
/** @brief The version where WarpSegments started to be utilized. */
|
/** @brief The version where WarpSegments started to be utilized. */
|
||||||
const float VERSION_WARP_SEGMENT = 0.56f;
|
const float VERSION_WARP_SEGMENT = 0.56f;
|
||||||
|
/** @brief The version that formally introduced Split Timing. */
|
||||||
|
const float VERSION_SPLIT_TIMING = 0.7f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
||||||
@@ -75,6 +75,13 @@ namespace SSCLoader
|
|||||||
* @param bFromCache a flag to determine if this song is loaded from a cache file.
|
* @param bFromCache a flag to determine if this song is loaded from a cache file.
|
||||||
*/
|
*/
|
||||||
void TidyUpData( Song &song, bool bFromCache );
|
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 );
|
||||||
|
void ProcessFakes( TimingData &, const RString );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
|
|||||||
+11
-11
@@ -350,10 +350,10 @@ bool NotesWriterDWI::Write( RString sPath, const Song &out )
|
|||||||
/* Write transliterations, if we have them, since DWI doesn't support UTF-8. */
|
/* Write transliterations, if we have them, since DWI doesn't support UTF-8. */
|
||||||
f.PutLine( ssprintf("#TITLE:%s;", DwiEscape(out.GetTranslitFullTitle()).c_str()) );
|
f.PutLine( ssprintf("#TITLE:%s;", DwiEscape(out.GetTranslitFullTitle()).c_str()) );
|
||||||
f.PutLine( ssprintf("#ARTIST:%s;", DwiEscape(out.GetTranslitArtist()).c_str()) );
|
f.PutLine( ssprintf("#ARTIST:%s;", DwiEscape(out.GetTranslitArtist()).c_str()) );
|
||||||
ASSERT( out.m_Timing.m_BPMSegments[0].m_iStartRow == 0 );
|
ASSERT( out.m_SongTiming.m_BPMSegments[0].m_iStartRow == 0 );
|
||||||
f.PutLine( ssprintf("#FILE:%s;", DwiEscape(out.m_sMusicFile).c_str()) );
|
f.PutLine( ssprintf("#FILE:%s;", DwiEscape(out.m_sMusicFile).c_str()) );
|
||||||
f.PutLine( ssprintf("#BPM:%.3f;", out.m_Timing.m_BPMSegments[0].GetBPM()) );
|
f.PutLine( ssprintf("#BPM:%.3f;", out.m_SongTiming.m_BPMSegments[0].GetBPM()) );
|
||||||
f.PutLine( ssprintf("#GAP:%ld;", -lrintf( out.m_Timing.m_fBeat0OffsetInSeconds*1000 )) );
|
f.PutLine( ssprintf("#GAP:%ld;", -lrintf( out.m_SongTiming.m_fBeat0OffsetInSeconds*1000 )) );
|
||||||
f.PutLine( ssprintf("#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds) );
|
f.PutLine( ssprintf("#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds) );
|
||||||
f.PutLine( ssprintf("#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds) );
|
f.PutLine( ssprintf("#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds) );
|
||||||
if( out.m_sCDTitleFile.size() )
|
if( out.m_sCDTitleFile.size() )
|
||||||
@@ -374,29 +374,29 @@ bool NotesWriterDWI::Write( RString sPath, const Song &out )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !out.m_Timing.m_StopSegments.empty() )
|
if( !out.m_SongTiming.m_StopSegments.empty() )
|
||||||
{
|
{
|
||||||
f.Write( "#FREEZE:" );
|
f.Write( "#FREEZE:" );
|
||||||
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
|
for( unsigned i=0; i<out.m_SongTiming.m_StopSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
|
const StopSegment &fs = out.m_SongTiming.m_StopSegments[i];
|
||||||
f.Write( ssprintf("%.3f=%.3f", fs.m_iStartRow * 4.0f / ROWS_PER_BEAT,
|
f.Write( ssprintf("%.3f=%.3f", fs.m_iStartRow * 4.0f / ROWS_PER_BEAT,
|
||||||
roundf(fs.m_fStopSeconds*1000)) );
|
roundf(fs.m_fStopSeconds*1000)) );
|
||||||
if( i != out.m_Timing.m_StopSegments.size()-1 )
|
if( i != out.m_SongTiming.m_StopSegments.size()-1 )
|
||||||
f.Write( "," );
|
f.Write( "," );
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( out.m_Timing.m_BPMSegments.size() > 1)
|
if( out.m_SongTiming.m_BPMSegments.size() > 1)
|
||||||
{
|
{
|
||||||
f.Write( "#CHANGEBPM:" );
|
f.Write( "#CHANGEBPM:" );
|
||||||
for( unsigned i=1; i<out.m_Timing.m_BPMSegments.size(); i++ )
|
for( unsigned i=1; i<out.m_SongTiming.m_BPMSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
|
const BPMSegment &bs = out.m_SongTiming.m_BPMSegments[i];
|
||||||
f.Write( ssprintf("%.3f=%.3f", bs.m_iStartRow * 4.0f / ROWS_PER_BEAT, bs.GetBPM() ) );
|
f.Write( ssprintf("%.3f=%.3f", bs.m_iStartRow * 4.0f / ROWS_PER_BEAT, bs.GetBPM() ) );
|
||||||
if( i != out.m_Timing.m_BPMSegments.size()-1 )
|
if( i != out.m_SongTiming.m_BPMSegments.size()-1 )
|
||||||
f.Write( "," );
|
f.Write( "," );
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ bool NotesWriterJson::WriteSong( const RString &sFile, const Song &out, bool bWr
|
|||||||
root["LyricsFile"] = out.m_sLyricsFile;
|
root["LyricsFile"] = out.m_sLyricsFile;
|
||||||
root["CDTitle"] = out.m_sCDTitleFile;
|
root["CDTitle"] = out.m_sCDTitleFile;
|
||||||
root["Music"] = out.m_sMusicFile;
|
root["Music"] = out.m_sMusicFile;
|
||||||
root["Offset"] = out.m_Timing.m_fBeat0OffsetInSeconds;
|
root["Offset"] = out.m_SongTiming.m_fBeat0OffsetInSeconds;
|
||||||
root["SampleStart"] = out.m_fMusicSampleStartSeconds;
|
root["SampleStart"] = out.m_fMusicSampleStartSeconds;
|
||||||
root["SampleLength"] = out.m_fMusicSampleLengthSeconds;
|
root["SampleLength"] = out.m_fMusicSampleLengthSeconds;
|
||||||
if( out.m_SelectionDisplay == Song::SHOW_ALWAYS )
|
if( out.m_SelectionDisplay == Song::SHOW_ALWAYS )
|
||||||
@@ -161,7 +161,7 @@ bool NotesWriterJson::WriteSong( const RString &sFile, const Song &out, bool bWr
|
|||||||
root["SpecifiedBpmMax"] = out.m_fSpecifiedBPMMax;
|
root["SpecifiedBpmMax"] = out.m_fSpecifiedBPMMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serialize( out.m_Timing, root["TimingData"] );
|
Serialize( out.m_SongTiming, root["TimingData"] );
|
||||||
JsonUtil::SerializeVectorObjects( out.m_LyricSegments, Serialize, root["LyricSegments"] );
|
JsonUtil::SerializeVectorObjects( out.m_LyricSegments, Serialize, root["LyricSegments"] );
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
+36
-76
@@ -48,7 +48,7 @@ static RString BackgroundChangeToString( const BackgroundChange &bgc )
|
|||||||
* @brief Write out the common tags for .SM files.
|
* @brief Write out the common tags for .SM files.
|
||||||
* @param f the file in question.
|
* @param f the file in question.
|
||||||
* @param out the Song in question. */
|
* @param out the Song in question. */
|
||||||
static void WriteGlobalTags( RageFile &f, const Song &out )
|
static void WriteGlobalTags( RageFile &f, Song &out )
|
||||||
{
|
{
|
||||||
f.PutLine( ssprintf( "#TITLE:%s;", SmEscape(out.m_sMainTitle).c_str() ) );
|
f.PutLine( ssprintf( "#TITLE:%s;", SmEscape(out.m_sMainTitle).c_str() ) );
|
||||||
f.PutLine( ssprintf( "#SUBTITLE:%s;", SmEscape(out.m_sSubTitle).c_str() ) );
|
f.PutLine( ssprintf( "#SUBTITLE:%s;", SmEscape(out.m_sSubTitle).c_str() ) );
|
||||||
@@ -63,20 +63,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
f.PutLine( ssprintf( "#LYRICSPATH:%s;", SmEscape(out.m_sLyricsFile).c_str() ) );
|
f.PutLine( ssprintf( "#LYRICSPATH:%s;", SmEscape(out.m_sLyricsFile).c_str() ) );
|
||||||
f.PutLine( ssprintf( "#CDTITLE:%s;", SmEscape(out.m_sCDTitleFile).c_str() ) );
|
f.PutLine( ssprintf( "#CDTITLE:%s;", SmEscape(out.m_sCDTitleFile).c_str() ) );
|
||||||
f.PutLine( ssprintf( "#MUSIC:%s;", SmEscape(out.m_sMusicFile).c_str() ) );
|
f.PutLine( ssprintf( "#MUSIC:%s;", SmEscape(out.m_sMusicFile).c_str() ) );
|
||||||
|
f.PutLine( ssprintf( "#OFFSET:%.3f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) );
|
||||||
{
|
|
||||||
vector<RString> vs;
|
|
||||||
FOREACH_ENUM( InstrumentTrack, it )
|
|
||||||
if( out.HasInstrumentTrack(it) )
|
|
||||||
vs.push_back( InstrumentTrackToString(it) +
|
|
||||||
"=" + out.m_sInstrumentTrackFile[it] );
|
|
||||||
if( !vs.empty() )
|
|
||||||
{
|
|
||||||
RString s = join( ",", vs );
|
|
||||||
f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.PutLine( ssprintf( "#OFFSET:%.3f;", out.m_Timing.m_fBeat0OffsetInSeconds ) );
|
|
||||||
f.PutLine( ssprintf( "#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds ) );
|
f.PutLine( ssprintf( "#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds ) );
|
||||||
f.PutLine( ssprintf( "#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds ) );
|
f.PutLine( ssprintf( "#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds ) );
|
||||||
if( out.m_fSpecifiedLastBeat > 0 )
|
if( out.m_fSpecifiedLastBeat > 0 )
|
||||||
@@ -111,79 +98,52 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
|
|
||||||
|
|
||||||
f.Write( "#BPMS:" );
|
f.Write( "#BPMS:" );
|
||||||
for( unsigned i=0; i<out.m_Timing.m_BPMSegments.size(); i++ )
|
for( unsigned i=0; i<out.m_SongTiming.m_BPMSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
|
const BPMSegment &bs = out.m_SongTiming.m_BPMSegments[i];
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.3f=%.3f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
|
f.PutLine( ssprintf( "%.3f=%.3f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
|
||||||
if( i != out.m_Timing.m_BPMSegments.size()-1 )
|
if( i != out.m_SongTiming.m_BPMSegments.size()-1 )
|
||||||
f.Write( "," );
|
f.Write( "," );
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
|
|
||||||
f.Write( "#STOPS:" );
|
unsigned wSize = out.m_SongTiming.m_WarpSegments.size();
|
||||||
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
|
if( wSize > 0 )
|
||||||
{
|
{
|
||||||
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
|
for( unsigned i=0; i < wSize; i++ )
|
||||||
|
{
|
||||||
|
int iRow = out.m_SongTiming.m_WarpSegments[i].m_iStartRow;
|
||||||
|
float fBPS = 60 / out.m_SongTiming.GetBPMAtRow(iRow);
|
||||||
|
float fSkip = fBPS * out.m_SongTiming.m_WarpSegments[i].m_fLengthBeats;
|
||||||
|
StopSegment ss;
|
||||||
|
ss.m_iStartRow = iRow;
|
||||||
|
ss.m_fStopSeconds = -fSkip;
|
||||||
|
ss.m_bDelay = false; // Best to be sure.
|
||||||
|
out.m_SongTiming.AddStopSegment( ss );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Write( "#STOPS:" );
|
||||||
|
for( unsigned i=0; i<out.m_SongTiming.m_StopSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const StopSegment &fs = out.m_SongTiming.m_StopSegments[i];
|
||||||
|
int iRow = fs.m_iStartRow;
|
||||||
|
float fBeat = NoteRowToBeat(!fs.m_bDelay ? iRow : iRow - 1);
|
||||||
|
|
||||||
if(!fs.m_bDelay)
|
if(!fs.m_bDelay)
|
||||||
{
|
{
|
||||||
f.PutLine( ssprintf( "%.3f=%.3f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
f.PutLine( ssprintf( "%.3f=%.3f", fBeat, fs.m_fStopSeconds ) );
|
||||||
if( i != out.m_Timing.m_StopSegments.size()-1 )
|
if( i != out.m_SongTiming.m_StopSegments.size()-1 )
|
||||||
f.Write( "," );
|
f.Write( "," );
|
||||||
}
|
if( fs.m_fStopSeconds < 0 )
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
f.Write( "#ATTACKS:" );
|
|
||||||
for( unsigned j = 0; j < out.m_Attacks.size(); j++ )
|
|
||||||
{
|
{
|
||||||
const Attack &a = out.m_Attacks[j];
|
out.m_SongTiming.m_StopSegments.erase(
|
||||||
f.Write( ssprintf( "TIME=%.2f:LEN=%.2f:MODS=%s",
|
out.m_SongTiming.m_StopSegments.begin()+i,
|
||||||
a.fStartSecond, a.fSecsRemaining, a.sModifiers.c_str() ) );
|
out.m_SongTiming.m_StopSegments.begin()+i+1 );
|
||||||
|
i--;
|
||||||
if( j+1 < out.m_Attacks.size() )
|
|
||||||
f.Write( ":" );
|
|
||||||
f.PutLine( "" );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
f.Write( "#DELAYS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
|
|
||||||
|
|
||||||
if( fs.m_bDelay )
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf( "%.3f=%.3f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
|
||||||
if( i != out.m_Timing.m_StopSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_vTimeSignatureSegments.empty() );
|
|
||||||
f.Write( "#TIMESIGNATURES:" );
|
|
||||||
FOREACH_CONST( TimeSignatureSegment, out.m_Timing.m_vTimeSignatureSegments, iter )
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf( "%.3f=%d=%d", NoteRowToBeat(iter->m_iStartRow),
|
|
||||||
iter->m_iNumerator, iter->m_iDenominator ) );
|
|
||||||
vector<TimeSignatureSegment>::const_iterator iter2 = iter;
|
|
||||||
iter2++;
|
|
||||||
if( iter2 != out.m_Timing.m_vTimeSignatureSegments.end() )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_TickcountSegments.empty() );
|
|
||||||
f.Write( "#TICKCOUNTS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_TickcountSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const TickcountSegment &ts = out.m_Timing.m_TickcountSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.3f=%d", NoteRowToBeat(ts.m_iStartRow), ts.m_iTicks ) );
|
|
||||||
if( i != out.m_Timing.m_TickcountSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
|
|
||||||
@@ -277,8 +237,8 @@ static RString GetSMNotesTag( const Song &song, const Steps &in )
|
|||||||
lines.push_back( ssprintf( " %d:", in.GetMeter() ) );
|
lines.push_back( ssprintf( " %d:", in.GetMeter() ) );
|
||||||
|
|
||||||
vector<RString> asRadarValues;
|
vector<RString> asRadarValues;
|
||||||
// SM files don't use fakes for radar data. Keep it that way.
|
// OpenITG simfiles use 11 radar categories.
|
||||||
int categories = NUM_RadarCategory - 1;
|
int categories = 11;
|
||||||
FOREACH_PlayerNumber( pn )
|
FOREACH_PlayerNumber( pn )
|
||||||
{
|
{
|
||||||
const RadarValues &rv = in.GetRadarValues( pn );
|
const RadarValues &rv = in.GetRadarValues( pn );
|
||||||
@@ -300,7 +260,7 @@ static RString GetSMNotesTag( const Song &song, const Steps &in )
|
|||||||
return JoinLineList( lines );
|
return JoinLineList( lines );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotesWriterSM::Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave )
|
bool NotesWriterSM::Write( RString sPath, Song &out, const vector<Steps*>& vpStepsToSave )
|
||||||
{
|
{
|
||||||
int flags = RageFile::WRITE;
|
int flags = RageFile::WRITE;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ namespace NotesWriterSM
|
|||||||
* @param sPath the path to write the file.
|
* @param sPath the path to write the file.
|
||||||
* @param out the Song to be written out.
|
* @param out the Song to be written out.
|
||||||
* @return its success or failure. */
|
* @return its success or failure. */
|
||||||
bool Write( RString sPath, const Song &out, const vector<Steps*>& vpStepsToSave );
|
bool Write( RString sPath, Song &out, const vector<Steps*>& vpStepsToSave );
|
||||||
/**
|
/**
|
||||||
* @brief Get some contents about the edit file first.
|
* @brief Get some contents about the edit file first.
|
||||||
* @param pSong the Song in question.
|
* @param pSong the Song in question.
|
||||||
|
|||||||
+129
-129
@@ -42,7 +42,128 @@ static RString BackgroundChangeToString( const BackgroundChange &bgc )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write out the common tags for .SM files.
|
* @brief Turn a vector of lines into a single line joined by newline characters.
|
||||||
|
* @param lines the list of lines to join.
|
||||||
|
* @return the joined lines. */
|
||||||
|
static RString JoinLineList( vector<RString> &lines )
|
||||||
|
{
|
||||||
|
for( unsigned i = 0; i < lines.size(); ++i )
|
||||||
|
TrimRight( lines[i] );
|
||||||
|
|
||||||
|
// Skip leading blanks.
|
||||||
|
unsigned j = 0;
|
||||||
|
while( j < lines.size() && lines.size() == 0 )
|
||||||
|
++j;
|
||||||
|
|
||||||
|
return join( "\r\n", lines.begin()+j, lines.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A utility class to write timing tags more easily!
|
||||||
|
struct TimingTagWriter {
|
||||||
|
|
||||||
|
vector<RString> *m_pvsLines;
|
||||||
|
RString m_sNext;
|
||||||
|
|
||||||
|
TimingTagWriter( vector<RString> *pvsLines ): m_pvsLines (pvsLines) { }
|
||||||
|
|
||||||
|
void Write( const int row, const char *value )
|
||||||
|
{
|
||||||
|
m_pvsLines->push_back( m_sNext + ssprintf( "%.6f=%s", NoteRowToBeat(row), value ) );
|
||||||
|
m_sNext = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write( const int row, const float value ) { Write( row, ssprintf( "%.6f", value ) ); }
|
||||||
|
void Write( const int row, const int value ) { Write( row, ssprintf( "%d", value ) ); }
|
||||||
|
void Write( const int row, const int a, const int b ) { Write( row, ssprintf( "%d=%d", a, b ) ); }
|
||||||
|
void Write( const int row, const float a, const float b ) { Write( row, ssprintf( "%.6f=%.6f", a, b) ); }
|
||||||
|
void Write( const int row, const float a, const float b, const unsigned short c )
|
||||||
|
{ Write( row, ssprintf( "%.6f=%.6f=%hd", a, b, c) ); }
|
||||||
|
|
||||||
|
void Init( const RString sTag ) { m_sNext = "#" + sTag + ":"; }
|
||||||
|
void Finish( ) { m_pvsLines->push_back( ( m_sNext != "," ? m_sNext : "" ) + ";" ); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static void GetTimingTags( vector<RString> &lines, TimingData timing, bool bIsSong = false )
|
||||||
|
{
|
||||||
|
TimingTagWriter w ( &lines );
|
||||||
|
|
||||||
|
timing.TidyUpData();
|
||||||
|
|
||||||
|
w.Init( "BPMS" );
|
||||||
|
FOREACH_CONST( BPMSegment, timing.m_BPMSegments, bs )
|
||||||
|
w.Write( bs->m_iStartRow, bs->GetBPM() );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
w.Init( "STOPS" );
|
||||||
|
FOREACH_CONST( StopSegment, timing.m_StopSegments, ss )
|
||||||
|
if( !ss->m_bDelay )
|
||||||
|
w.Write( ss->m_iStartRow, ss->m_fStopSeconds );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
w.Init( "DELAYS" );
|
||||||
|
FOREACH_CONST( StopSegment, timing.m_StopSegments, ss )
|
||||||
|
if( ss->m_bDelay )
|
||||||
|
w.Write( ss->m_iStartRow, ss->m_fStopSeconds );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
w.Init( "WARPS" );
|
||||||
|
FOREACH_CONST( WarpSegment, timing.m_WarpSegments, ws )
|
||||||
|
w.Write( ws->m_iStartRow, ws->m_fLengthBeats );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
ASSERT( !timing.m_vTimeSignatureSegments.empty() );
|
||||||
|
w.Init( "TIMESIGNATURES" );
|
||||||
|
FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter )
|
||||||
|
w.Write( iter->m_iStartRow, iter->m_iNumerator, iter->m_iDenominator );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
ASSERT( !timing.m_TickcountSegments.empty() );
|
||||||
|
w.Init( "TICKCOUNTS" );
|
||||||
|
FOREACH_CONST( TickcountSegment, timing.m_TickcountSegments, ts )
|
||||||
|
w.Write( ts->m_iStartRow, ts->m_iTicks );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
ASSERT( !timing.m_ComboSegments.empty() );
|
||||||
|
w.Init( "COMBOS" );
|
||||||
|
FOREACH_CONST( ComboSegment, timing.m_ComboSegments, cs )
|
||||||
|
w.Write( cs->m_iStartRow, cs->m_iCombo );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
// Song Timing should only have the initial value.
|
||||||
|
w.Init( "SPEEDS" );
|
||||||
|
FOREACH_CONST( SpeedSegment, timing.m_SpeedSegments, ss )
|
||||||
|
w.Write( ss->m_iStartRow, ss->m_fPercent, ss->m_fWait, ss->m_usMode );
|
||||||
|
w.Finish();
|
||||||
|
|
||||||
|
if( !bIsSong )
|
||||||
|
{
|
||||||
|
w.Init( "FAKES" );
|
||||||
|
FOREACH_CONST( FakeSegment, timing.m_FakeSegments, fs )
|
||||||
|
w.Write( fs->m_iStartRow, fs->m_fLengthBeats );
|
||||||
|
w.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Init( "LABELS" );
|
||||||
|
FOREACH_CONST( LabelSegment, timing.m_LabelSegments, ls )
|
||||||
|
w.Write( ls->m_iStartRow, ls->m_sLabel.c_str() );
|
||||||
|
w.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteTimingTags( RageFile &f, const TimingData &timing, bool bIsSong = false )
|
||||||
|
{
|
||||||
|
|
||||||
|
vector<RString> lines;
|
||||||
|
|
||||||
|
GetTimingTags( lines, timing, bIsSong );
|
||||||
|
|
||||||
|
f.PutLine( JoinLineList( lines ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write out the common tags for .SSC files.
|
||||||
* @param f the file in question.
|
* @param f the file in question.
|
||||||
* @param out the Song in question. */
|
* @param out the Song in question. */
|
||||||
static void WriteGlobalTags( RageFile &f, const Song &out )
|
static void WriteGlobalTags( RageFile &f, const Song &out )
|
||||||
@@ -74,7 +195,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" );
|
f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_Timing.m_fBeat0OffsetInSeconds ) );
|
f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) );
|
||||||
f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) );
|
f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) );
|
||||||
f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) );
|
f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) );
|
||||||
if( out.m_fSpecifiedLastBeat > 0 )
|
if( out.m_fSpecifiedLastBeat > 0 )
|
||||||
@@ -106,105 +227,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Write( "#BPMS:" );
|
WriteTimingTags( f, out.m_SongTiming, true );
|
||||||
for( unsigned i=0; i<out.m_Timing.m_BPMSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
|
|
||||||
if( i != out.m_Timing.m_BPMSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
f.Write( "#STOPS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
|
|
||||||
|
|
||||||
if(!fs.m_bDelay)
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
|
||||||
if( i != out.m_Timing.m_StopSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
f.Write( "#DELAYS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
|
|
||||||
|
|
||||||
if( fs.m_bDelay )
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
|
||||||
if( i != out.m_Timing.m_StopSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
|
|
||||||
f.Write( "#WARPS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_WarpSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const WarpSegment &ws = out.m_Timing.m_WarpSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(ws.m_iStartRow), ws.m_fEndBeat ) );
|
|
||||||
if( i != out.m_Timing.m_WarpSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_vTimeSignatureSegments.empty() );
|
|
||||||
f.Write( "#TIMESIGNATURES:" );
|
|
||||||
FOREACH_CONST( TimeSignatureSegment, out.m_Timing.m_vTimeSignatureSegments, iter )
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf( "%.6f=%d=%d", NoteRowToBeat(iter->m_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) );
|
|
||||||
vector<TimeSignatureSegment>::const_iterator iter2 = iter;
|
|
||||||
iter2++;
|
|
||||||
if( iter2 != out.m_Timing.m_vTimeSignatureSegments.end() )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_TickcountSegments.empty() );
|
|
||||||
f.Write( "#TICKCOUNTS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_TickcountSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const TickcountSegment &ts = out.m_Timing.m_TickcountSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%d", NoteRowToBeat(ts.m_iStartRow), ts.m_iTicks ) );
|
|
||||||
if( i != out.m_Timing.m_TickcountSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_ComboSegments.empty() );
|
|
||||||
f.Write( "#COMBOS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_ComboSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const ComboSegment &cs = out.m_Timing.m_ComboSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%d", NoteRowToBeat(cs.m_iStartRow), cs.m_iCombo ) );
|
|
||||||
if( i != out.m_Timing.m_ComboSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
f.Write( "#LABELS:" );
|
|
||||||
for( unsigned i=0; i<out.m_Timing.m_LabelSegments.size(); i++ )
|
|
||||||
{
|
|
||||||
const LabelSegment &ls = out.m_Timing.m_LabelSegments[i];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%s", NoteRowToBeat(ls.m_iStartRow), ls.m_sLabel.c_str() ) );
|
|
||||||
if( i != out.m_Timing.m_LabelSegments.size()-1 )
|
|
||||||
f.Write( "," );
|
|
||||||
}
|
|
||||||
f.PutLine( ";" );
|
|
||||||
|
|
||||||
FOREACH_BackgroundLayer( b )
|
FOREACH_BackgroundLayer( b )
|
||||||
{
|
{
|
||||||
@@ -258,23 +281,6 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Turn a vector of lines into a single line joined by newline characters.
|
|
||||||
* @param lines the list of lines to join.
|
|
||||||
* @return the joined lines. */
|
|
||||||
static RString JoinLineList( vector<RString> &lines )
|
|
||||||
{
|
|
||||||
for( unsigned i = 0; i < lines.size(); ++i )
|
|
||||||
TrimRight( lines[i] );
|
|
||||||
|
|
||||||
// Skip leading blanks.
|
|
||||||
unsigned j = 0;
|
|
||||||
while( j < lines.size() && lines.size() == 0 )
|
|
||||||
++j;
|
|
||||||
|
|
||||||
return join( "\r\n", lines.begin()+j, lines.end() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the individual batches of NoteData.
|
* @brief Retrieve the individual batches of NoteData.
|
||||||
* @param song the Song in question.
|
* @param song the Song in question.
|
||||||
@@ -307,18 +313,11 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa
|
|||||||
|
|
||||||
lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) );
|
lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) );
|
||||||
|
|
||||||
/*
|
GetTimingTags( lines, in.m_Timing );
|
||||||
* TODO: Remove this block, transplant above code
|
|
||||||
* below for Split Timing. -Wolfman2000 */
|
// For now, attacks are NOT in use for the step.
|
||||||
lines.push_back( "#BPMS:;" );
|
|
||||||
lines.push_back( "#STOPS:;" );
|
|
||||||
lines.push_back( "#DELAYS:;" );
|
|
||||||
lines.push_back( "#WARPS:;" );
|
|
||||||
lines.push_back( "#LABELS:;" );
|
|
||||||
lines.push_back( "#TIMESIGNATURES:;" );
|
|
||||||
lines.push_back( "#TICKCOUNTS:;" );
|
|
||||||
lines.push_back( "#ATTACKS:;" );
|
lines.push_back( "#ATTACKS:;" );
|
||||||
lines.push_back( "#COMBOS:;" );
|
lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) );
|
||||||
|
|
||||||
RString sNoteData;
|
RString sNoteData;
|
||||||
in.GetSMNoteData( sNoteData );
|
in.GetSMNoteData( sNoteData );
|
||||||
@@ -350,6 +349,7 @@ bool NotesWriterSSC::Write( RString sPath, const Song &out, const vector<Steps*>
|
|||||||
}
|
}
|
||||||
|
|
||||||
WriteGlobalTags( f, out );
|
WriteGlobalTags( f, out );
|
||||||
|
|
||||||
if( bSavingCache )
|
if( bSavingCache )
|
||||||
{
|
{
|
||||||
f.PutLine( ssprintf( "// cache tags:" ) );
|
f.PutLine( ssprintf( "// cache tags:" ) );
|
||||||
|
|||||||
+44
-33
@@ -506,7 +506,7 @@ void Player::Load()
|
|||||||
|
|
||||||
m_LastTapNoteScore = TNS_None;
|
m_LastTapNoteScore = TNS_None;
|
||||||
// The editor can start playing in the middle of the song.
|
// The editor can start playing in the middle of the song.
|
||||||
const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
const int iNoteRow = BeatToNoteRowNotRounded( m_pPlayerState->m_Position.m_fSongBeat );
|
||||||
m_iFirstUncrossedRow = iNoteRow - 1;
|
m_iFirstUncrossedRow = iNoteRow - 1;
|
||||||
m_pJudgedRows->Reset( iNoteRow );
|
m_pJudgedRows->Reset( iNoteRow );
|
||||||
|
|
||||||
@@ -541,6 +541,8 @@ void Player::Load()
|
|||||||
if( GAMESTATE->m_pCurGame->m_bAllowHopos )
|
if( GAMESTATE->m_pCurGame->m_bAllowHopos )
|
||||||
NoteDataUtil::SetHopoPossibleFlags( pSong, m_NoteData );
|
NoteDataUtil::SetHopoPossibleFlags( pSong, m_NoteData );
|
||||||
|
|
||||||
|
m_Timing = &GAMESTATE->m_pCurSteps[pn]->m_Timing;
|
||||||
|
|
||||||
switch( GAMESTATE->m_PlayMode )
|
switch( GAMESTATE->m_PlayMode )
|
||||||
{
|
{
|
||||||
case PLAY_MODE_RAVE:
|
case PLAY_MODE_RAVE:
|
||||||
@@ -693,7 +695,7 @@ void Player::Update( float fDeltaTime )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fSongBeat = GAMESTATE->m_fSongBeat;
|
const float fSongBeat = m_pPlayerState->m_Position.m_fSongBeat;
|
||||||
const int iSongRow = BeatToNoteRow( fSongBeat );
|
const int iSongRow = BeatToNoteRow( fSongBeat );
|
||||||
|
|
||||||
// Optimization: Don't spend time processing the things below that won't show
|
// Optimization: Don't spend time processing the things below that won't show
|
||||||
@@ -795,7 +797,7 @@ void Player::Update( float fDeltaTime )
|
|||||||
|
|
||||||
// Check for a strum miss
|
// Check for a strum miss
|
||||||
if( m_pPlayerState->m_fLastStrumMusicSeconds != -1 &&
|
if( m_pPlayerState->m_fLastStrumMusicSeconds != -1 &&
|
||||||
m_pPlayerState->m_fLastStrumMusicSeconds + g_fTimingWindowStrum < GAMESTATE->m_fMusicSeconds )
|
m_pPlayerState->m_fLastStrumMusicSeconds + g_fTimingWindowStrum < m_pPlayerState->m_Position.m_fMusicSeconds )
|
||||||
{
|
{
|
||||||
DoStrumMiss();
|
DoStrumMiss();
|
||||||
}
|
}
|
||||||
@@ -917,12 +919,12 @@ void Player::Update( float fDeltaTime )
|
|||||||
/* We want to send the crossed row message exactly when we cross the row--not
|
/* We want to send the crossed row message exactly when we cross the row--not
|
||||||
* .5 before the row. Use a very slow song (around 2 BPM) as a test case: without
|
* .5 before the row. Use a very slow song (around 2 BPM) as a test case: without
|
||||||
* rounding, autoplay steps early. -glenn */
|
* rounding, autoplay steps early. -glenn */
|
||||||
const int iRowNow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
const int iRowNow = BeatToNoteRowNotRounded( m_pPlayerState->m_Position.m_fSongBeat );
|
||||||
if( iRowNow >= 0 )
|
if( iRowNow >= 0 )
|
||||||
{
|
{
|
||||||
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
||||||
{
|
{
|
||||||
if(GAMESTATE->m_bDelay)
|
if(m_pPlayerState->m_Position.m_bDelay)
|
||||||
{
|
{
|
||||||
if( !m_bDelay )
|
if( !m_bDelay )
|
||||||
m_bDelay = true;
|
m_bDelay = true;
|
||||||
@@ -1528,7 +1530,7 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool
|
|||||||
// Is this the row we want?
|
// Is this the row we want?
|
||||||
do {
|
do {
|
||||||
const TapNote &tn = begin->second;
|
const TapNote &tn = begin->second;
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( begin->first ) )
|
if( m_Timing->IsWarpAtRow( begin->first ) || m_Timing->IsFakeAtRow( begin->first ) )
|
||||||
break;
|
break;
|
||||||
if( tn.type == TapNote::empty )
|
if( tn.type == TapNote::empty )
|
||||||
break;
|
break;
|
||||||
@@ -1579,7 +1581,7 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b
|
|||||||
++iter;
|
++iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) )
|
if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) )
|
||||||
{
|
{
|
||||||
++iter;
|
++iter;
|
||||||
continue;
|
continue;
|
||||||
@@ -1650,7 +1652,7 @@ void Player::Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle hammer-ons and pull-offs
|
// Handle hammer-ons and pull-offs
|
||||||
const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago();
|
const float fPositionSeconds = m_pPlayerState->m_Position.m_fMusicSeconds - tm.Ago();
|
||||||
int iHopoCol = -1;
|
int iHopoCol = -1;
|
||||||
bool bDoHopo =
|
bool bDoHopo =
|
||||||
m_pPlayerState->m_fLastHopoNoteMusicSeconds != -1 &&
|
m_pPlayerState->m_fLastHopoNoteMusicSeconds != -1 &&
|
||||||
@@ -1703,7 +1705,7 @@ void Player::Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
|
|||||||
// Check if this fret breaks all active holds.
|
// Check if this fret breaks all active holds.
|
||||||
if( !bRelease )
|
if( !bRelease )
|
||||||
{
|
{
|
||||||
const float fSongBeat = GAMESTATE->m_fSongBeat;
|
const float fSongBeat = m_pPlayerState->m_Position.m_fSongBeat;
|
||||||
const int iSongRow = BeatToNoteRow( fSongBeat );
|
const int iSongRow = BeatToNoteRow( fSongBeat );
|
||||||
|
|
||||||
int iMaxHoldCol = -1;
|
int iMaxHoldCol = -1;
|
||||||
@@ -1745,7 +1747,7 @@ void Player::Strum( int col, int row, const RageTimer &tm, bool bHeld, bool bRel
|
|||||||
DoStrumMiss();
|
DoStrumMiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pPlayerState->m_fLastStrumMusicSeconds = GAMESTATE->m_fMusicSeconds;
|
m_pPlayerState->m_fLastStrumMusicSeconds = m_pPlayerState->m_Position.m_fMusicSeconds;
|
||||||
|
|
||||||
StepStrumHopo( col, row, tm, bHeld, bRelease, ButtonType_StrumFretsChanged );
|
StepStrumHopo( col, row, tm, bHeld, bRelease, ButtonType_StrumFretsChanged );
|
||||||
}
|
}
|
||||||
@@ -1794,7 +1796,7 @@ void Player::ScoreAllActiveHoldsLetGo()
|
|||||||
{
|
{
|
||||||
if( PENALIZE_TAP_SCORE_NONE )
|
if( PENALIZE_TAP_SCORE_NONE )
|
||||||
{
|
{
|
||||||
const float fSongBeat = GAMESTATE->m_fSongBeat;
|
const float fSongBeat = m_pPlayerState->m_Position.m_fSongBeat;
|
||||||
const int iSongRow = BeatToNoteRow( fSongBeat );
|
const int iSongRow = BeatToNoteRow( fSongBeat );
|
||||||
|
|
||||||
// Score all active holds to NotHeld
|
// Score all active holds to NotHeld
|
||||||
@@ -1857,8 +1859,8 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
|
|
||||||
// Do everything that depends on a RageTimer here;
|
// Do everything that depends on a RageTimer here;
|
||||||
// set your breakpoints somewhere after this block.
|
// set your breakpoints somewhere after this block.
|
||||||
const float fLastBeatUpdate = GAMESTATE->m_LastBeatUpdate.Ago();
|
const float fLastBeatUpdate = m_pPlayerState->m_Position.m_LastBeatUpdate.Ago();
|
||||||
const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago();
|
const float fPositionSeconds = m_pPlayerState->m_Position.m_fMusicSeconds - tm.Ago();
|
||||||
const float fTimeSinceStep = tm.Ago();
|
const float fTimeSinceStep = tm.Ago();
|
||||||
|
|
||||||
switch( pbt )
|
switch( pbt )
|
||||||
@@ -1873,7 +1875,16 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float fSongBeat = GAMESTATE->m_pCurSong ? GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds ) : GAMESTATE->m_fSongBeat;
|
float fSongBeat = m_pPlayerState->m_Position.m_fSongBeat;
|
||||||
|
|
||||||
|
if( GAMESTATE->m_pCurSong )
|
||||||
|
{
|
||||||
|
fSongBeat = GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds );
|
||||||
|
|
||||||
|
if( GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber] )
|
||||||
|
fSongBeat = m_Timing->GetBeatFromElapsedTime( fPositionSeconds );
|
||||||
|
}
|
||||||
|
|
||||||
const int iSongRow = row == -1 ? BeatToNoteRow( fSongBeat ) : row;
|
const int iSongRow = row == -1 ? BeatToNoteRow( fSongBeat ) : row;
|
||||||
|
|
||||||
if( col != -1 && !bRelease )
|
if( col != -1 && !bRelease )
|
||||||
@@ -2011,8 +2022,8 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
* "jack hammers." Hmm.
|
* "jack hammers." Hmm.
|
||||||
*/
|
*/
|
||||||
const int iStepSearchRows = max(
|
const int iStepSearchRows = max(
|
||||||
BeatToNoteRow( GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds + StepSearchDistance ) ) - iSongRow,
|
BeatToNoteRow( m_Timing->GetBeatFromElapsedTime( m_pPlayerState->m_Position.m_fMusicSeconds + StepSearchDistance ) ) - iSongRow,
|
||||||
iSongRow - BeatToNoteRow( GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds - StepSearchDistance ) )
|
iSongRow - BeatToNoteRow( m_Timing->GetBeatFromElapsedTime( m_pPlayerState->m_Position.m_fMusicSeconds - StepSearchDistance ) )
|
||||||
) + ROWS_PER_BEAT;
|
) + ROWS_PER_BEAT;
|
||||||
int iRowOfOverlappingNoteOrRow = row;
|
int iRowOfOverlappingNoteOrRow = row;
|
||||||
if( row == -1 )
|
if( row == -1 )
|
||||||
@@ -2039,7 +2050,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
float fNoteOffset = 0.0f;
|
float fNoteOffset = 0.0f;
|
||||||
// we need this later if we are autosyncing
|
// we need this later if we are autosyncing
|
||||||
const float fStepBeat = NoteRowToBeat( iRowOfOverlappingNoteOrRow );
|
const float fStepBeat = NoteRowToBeat( iRowOfOverlappingNoteOrRow );
|
||||||
const float fStepSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat(fStepBeat);
|
const float fStepSeconds = m_Timing->GetElapsedTimeFromBeat(fStepBeat);
|
||||||
|
|
||||||
if( row == -1 )
|
if( row == -1 )
|
||||||
{
|
{
|
||||||
@@ -2048,7 +2059,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
|
|
||||||
/* GAMESTATE->m_fMusicSeconds is the music time as of GAMESTATE->m_LastBeatUpdate. Figure
|
/* GAMESTATE->m_fMusicSeconds is the music time as of GAMESTATE->m_LastBeatUpdate. Figure
|
||||||
* out what the music time is as of now. */
|
* out what the music time is as of now. */
|
||||||
const float fCurrentMusicSeconds = GAMESTATE->m_fMusicSeconds + (fLastBeatUpdate*GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate);
|
const float fCurrentMusicSeconds = m_pPlayerState->m_Position.m_fMusicSeconds + (fLastBeatUpdate*GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate);
|
||||||
|
|
||||||
// ... which means it happened at this point in the music:
|
// ... which means it happened at this point in the music:
|
||||||
const float fMusicSeconds = fCurrentMusicSeconds - fTimeSinceStep * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
const float fMusicSeconds = fCurrentMusicSeconds - fTimeSinceStep * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
||||||
@@ -2089,7 +2100,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
// Stepped too close to mine?
|
// Stepped too close to mine?
|
||||||
if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) &&
|
if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) &&
|
||||||
fSecondsFromExact <= GetWindowSeconds(TW_Mine) &&
|
fSecondsFromExact <= GetWindowSeconds(TW_Mine) &&
|
||||||
!GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iSongRow) )
|
!m_Timing->IsWarpAtRow(iSongRow) && !m_Timing->IsFakeAtRow(iSongRow))
|
||||||
score = TNS_HitMine;
|
score = TNS_HitMine;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2557,14 +2568,14 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
{
|
{
|
||||||
//LOG->Trace( "Steps::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
|
//LOG->Trace( "Steps::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
|
||||||
int iMissIfOlderThanThisRow;
|
int iMissIfOlderThanThisRow;
|
||||||
const float fEarliestTime = GAMESTATE->m_fMusicSeconds - fMissIfOlderThanSeconds;
|
const float fEarliestTime = m_pPlayerState->m_Position.m_fMusicSeconds - fMissIfOlderThanSeconds;
|
||||||
{
|
{
|
||||||
bool bFreeze, bDelay;
|
bool bFreeze, bDelay;
|
||||||
float fMissIfOlderThanThisBeat;
|
float fMissIfOlderThanThisBeat;
|
||||||
float fThrowAway;
|
float fThrowAway;
|
||||||
int iWarpBeginRow;
|
int iWarpBeginRow;
|
||||||
float fWarpLength;
|
float fWarpLength;
|
||||||
GAMESTATE->m_pCurSong->m_Timing.GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay, iWarpBeginRow, fWarpLength );
|
m_Timing->GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay, iWarpBeginRow, fWarpLength );
|
||||||
|
|
||||||
iMissIfOlderThanThisRow = BeatToNoteRow( fMissIfOlderThanThisBeat );
|
iMissIfOlderThanThisRow = BeatToNoteRow( fMissIfOlderThanThisBeat );
|
||||||
if( bFreeze || bDelay )
|
if( bFreeze || bDelay )
|
||||||
@@ -2586,8 +2597,8 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
if( !NeedsTapJudging(tn) )
|
if( !NeedsTapJudging(tn) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Ignore all notes that are skipped via WARPS.
|
// Ignore all notes in WarpSegments or FakeSegments.
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) )
|
if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( tn.type == TapNote::mine )
|
if( tn.type == TapNote::mine )
|
||||||
@@ -2610,7 +2621,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
|
|
||||||
void Player::UpdateJudgedRows()
|
void Player::UpdateJudgedRows()
|
||||||
{
|
{
|
||||||
const int iEndRow = BeatToNoteRow( GAMESTATE->m_fSongBeat );
|
const int iEndRow = BeatToNoteRow( m_pPlayerState->m_Position.m_fSongBeat );
|
||||||
bool bAllJudged = true;
|
bool bAllJudged = true;
|
||||||
const bool bSeparately = GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately;
|
const bool bSeparately = GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately;
|
||||||
|
|
||||||
@@ -2621,8 +2632,8 @@ void Player::UpdateJudgedRows()
|
|||||||
{
|
{
|
||||||
int iRow = iter.Row();
|
int iRow = iter.Row();
|
||||||
|
|
||||||
// If row is within a warp section, ignore it. -aj
|
// Do not judge arrows in WarpSegments or FakeSegments
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iRow) )
|
if( m_Timing->IsWarpAtRow(iRow) || m_Timing->IsFakeAtRow(iRow) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( iLastSeenRow != iRow )
|
if( iLastSeenRow != iRow )
|
||||||
@@ -2843,13 +2854,13 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now )
|
|||||||
int iCheckpointFrequencyRows = ROWS_PER_BEAT/2;
|
int iCheckpointFrequencyRows = ROWS_PER_BEAT/2;
|
||||||
if( CHECKPOINTS_USE_TICKCOUNTS )
|
if( CHECKPOINTS_USE_TICKCOUNTS )
|
||||||
{
|
{
|
||||||
int tickCurrent = GAMESTATE->m_pCurSong->m_Timing.GetTickcountAtRow( iLastRowCrossed );
|
int tickCurrent = m_Timing->GetTickcountAtRow( iLastRowCrossed );
|
||||||
// There are some charts that don't want tickcounts involved at all.
|
// There are some charts that don't want tickcounts involved at all.
|
||||||
iCheckpointFrequencyRows = (tickCurrent > 0 ? ROWS_PER_BEAT / tickCurrent : 0);
|
iCheckpointFrequencyRows = (tickCurrent > 0 ? ROWS_PER_BEAT / tickCurrent : 0);
|
||||||
}
|
}
|
||||||
else if( CHECKPOINTS_USE_TIME_SIGNATURES )
|
else if( CHECKPOINTS_USE_TIME_SIGNATURES )
|
||||||
{
|
{
|
||||||
TimeSignatureSegment tSignature = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) );
|
TimeSignatureSegment tSignature = m_Timing->GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) );
|
||||||
|
|
||||||
// Most songs are in 4/4 time. The frequency for checking tick counts should reflect that.
|
// Most songs are in 4/4 time. The frequency for checking tick counts should reflect that.
|
||||||
iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.m_iDenominator / (tSignature.m_iNumerator * 4);
|
iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.m_iDenominator / (tSignature.m_iNumerator * 4);
|
||||||
@@ -2956,8 +2967,8 @@ void Player::HandleTapRowScore( unsigned row )
|
|||||||
bNoCheating = false;
|
bNoCheating = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Warp hackery. -aj
|
// Do not score rows in WarpSegments or FakeSegments
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( row ) )
|
if( m_Timing->IsWarpAtRow( row ) || m_Timing->IsFakeAtRow( row ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( GAMESTATE->m_bDemonstrationOrJukebox )
|
if( GAMESTATE->m_bDemonstrationOrJukebox )
|
||||||
@@ -3060,8 +3071,8 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH
|
|||||||
bNoCheating = false;
|
bNoCheating = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// More warp hackery. -aj
|
// WarpSegments and FakeSegments aren't judged in any way.
|
||||||
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iRow ) )
|
if( m_Timing->IsWarpAtRow( iRow ) || m_Timing->IsFakeAtRow( iRow ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// don't accumulate combo if AutoPlay is on.
|
// don't accumulate combo if AutoPlay is on.
|
||||||
@@ -3257,7 +3268,7 @@ void Player::SetCombo( int iCombo, int iMisses )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bPastBeginning = GAMESTATE->m_fMusicSeconds > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds * PERCENT_UNTIL_COLOR_COMBO;
|
bPastBeginning = m_pPlayerState->m_Position.m_fMusicSeconds > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds * PERCENT_UNTIL_COLOR_COMBO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_bSendJudgmentAndComboMessages )
|
if( m_bSendJudgmentAndComboMessages )
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "ScreenMessage.h"
|
#include "ScreenMessage.h"
|
||||||
#include "ThemeMetric.h"
|
#include "ThemeMetric.h"
|
||||||
#include "InputEventPlus.h"
|
#include "InputEventPlus.h"
|
||||||
|
#include "TimingData.h"
|
||||||
|
|
||||||
class ScoreDisplay;
|
class ScoreDisplay;
|
||||||
class LifeMeter;
|
class LifeMeter;
|
||||||
@@ -147,6 +148,7 @@ protected:
|
|||||||
PlayerState *m_pPlayerState;
|
PlayerState *m_pPlayerState;
|
||||||
/** @brief The player's present stage stats. */
|
/** @brief The player's present stage stats. */
|
||||||
PlayerStageStats *m_pPlayerStageStats;
|
PlayerStageStats *m_pPlayerStageStats;
|
||||||
|
TimingData *m_Timing;
|
||||||
float m_fNoteFieldHeight;
|
float m_fNoteFieldHeight;
|
||||||
|
|
||||||
bool m_bPaused;
|
bool m_bPaused;
|
||||||
|
|||||||
@@ -680,7 +680,7 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const
|
|||||||
|
|
||||||
bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerNumber pn ) const
|
bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerNumber pn ) const
|
||||||
{
|
{
|
||||||
if( m_fTimeSpacing && pSong->HasSignificantBpmChangesOrStops() )
|
if( m_fTimeSpacing && pSteps->HasSignificantTimingChanges() )
|
||||||
return true;
|
return true;
|
||||||
const RadarValues &rv = pSteps->GetRadarValues( pn );
|
const RadarValues &rv = pSteps->GetRadarValues( pn );
|
||||||
if( m_bTransforms[TRANSFORM_NOHOLDS] && rv[RadarCategory_Holds]>0 )
|
if( m_bTransforms[TRANSFORM_NOHOLDS] && rv[RadarCategory_Holds]>0 )
|
||||||
|
|||||||
+2
-1
@@ -35,8 +35,9 @@ public:
|
|||||||
m_fPassmark(0), m_SpeedfPassmark(1.0f),
|
m_fPassmark(0), m_SpeedfPassmark(1.0f),
|
||||||
m_fRandomSpeed(0), m_SpeedfRandomSpeed(1.0f),
|
m_fRandomSpeed(0), m_SpeedfRandomSpeed(1.0f),
|
||||||
m_bMuteOnError(false), m_FailType(FAIL_IMMEDIATE),
|
m_bMuteOnError(false), m_FailType(FAIL_IMMEDIATE),
|
||||||
m_ScoreDisplay(SCORING_ADD), m_sNoteSkin("")
|
m_ScoreDisplay(SCORING_ADD)
|
||||||
{
|
{
|
||||||
|
m_sNoteSkin = "";
|
||||||
ZERO( m_fAccels ); ONE( m_SpeedfAccels );
|
ZERO( m_fAccels ); ONE( m_SpeedfAccels );
|
||||||
ZERO( m_fEffects ); ONE( m_SpeedfEffects );
|
ZERO( m_fEffects ); ONE( m_SpeedfEffects );
|
||||||
ZERO( m_fAppearances ); ONE( m_SpeedfAppearances );
|
ZERO( m_fAppearances ); ONE( m_SpeedfAppearances );
|
||||||
|
|||||||
+9
-3
@@ -69,8 +69,8 @@ void PlayerState::Update( float fDelta )
|
|||||||
|
|
||||||
bool bCurrentlyEnabled =
|
bool bCurrentlyEnabled =
|
||||||
attack.bGlobal ||
|
attack.bGlobal ||
|
||||||
( attack.fStartSecond < GAMESTATE->m_fMusicSeconds &&
|
( attack.fStartSecond < m_Position.m_fMusicSeconds &&
|
||||||
GAMESTATE->m_fMusicSeconds < attack.fStartSecond+attack.fSecsRemaining );
|
m_Position.m_fMusicSeconds < attack.fStartSecond+attack.fSecsRemaining );
|
||||||
|
|
||||||
if( m_ActiveAttacks[s].bOn == bCurrentlyEnabled )
|
if( m_ActiveAttacks[s].bOn == bCurrentlyEnabled )
|
||||||
continue; // OK
|
continue; // OK
|
||||||
@@ -116,7 +116,7 @@ void PlayerState::LaunchAttack( const Attack& a )
|
|||||||
* so Player::Update knows to apply attack transforms correctly. (yuck) */
|
* so Player::Update knows to apply attack transforms correctly. (yuck) */
|
||||||
m_ModsToApply.push_back( attack );
|
m_ModsToApply.push_back( attack );
|
||||||
if( attack.fStartSecond == -1 )
|
if( attack.fStartSecond == -1 )
|
||||||
attack.fStartSecond = GAMESTATE->m_fMusicSeconds;
|
attack.fStartSecond = m_Position.m_fMusicSeconds;
|
||||||
m_ActiveAttacks.push_back( attack );
|
m_ActiveAttacks.push_back( attack );
|
||||||
|
|
||||||
RebuildPlayerOptionsFromActiveAttacks();
|
RebuildPlayerOptionsFromActiveAttacks();
|
||||||
@@ -197,6 +197,11 @@ class LunaPlayerState: public Luna<PlayerState>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DEFINE_METHOD( GetPlayerNumber, m_PlayerNumber );
|
DEFINE_METHOD( GetPlayerNumber, m_PlayerNumber );
|
||||||
|
static int GetSongPosition( T* p, lua_State *L )
|
||||||
|
{
|
||||||
|
p->m_Position.PushSelf(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
DEFINE_METHOD( GetMultiPlayerNumber, m_mp );
|
DEFINE_METHOD( GetMultiPlayerNumber, m_mp );
|
||||||
DEFINE_METHOD( GetPlayerController, m_PlayerController );
|
DEFINE_METHOD( GetPlayerController, m_PlayerController );
|
||||||
static int SetPlayerOptions( T* p, lua_State *L )
|
static int SetPlayerOptions( T* p, lua_State *L )
|
||||||
@@ -246,6 +251,7 @@ public:
|
|||||||
ADD_METHOD( GetPlayerOptionsArray );
|
ADD_METHOD( GetPlayerOptionsArray );
|
||||||
ADD_METHOD( GetPlayerOptionsString );
|
ADD_METHOD( GetPlayerOptionsString );
|
||||||
ADD_METHOD( GetCurrentPlayerOptions );
|
ADD_METHOD( GetCurrentPlayerOptions );
|
||||||
|
ADD_METHOD( GetSongPosition );
|
||||||
ADD_METHOD( GetHealthState );
|
ADD_METHOD( GetHealthState );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#ifndef PlayerState_H
|
#ifndef PlayerState_H
|
||||||
#define PlayerState_H
|
#define PlayerState_H
|
||||||
|
|
||||||
|
#include "SongPosition.h"
|
||||||
#include "Attack.h"
|
#include "Attack.h"
|
||||||
#include "ModsGroup.h"
|
#include "ModsGroup.h"
|
||||||
#include "PlayerNumber.h"
|
#include "PlayerNumber.h"
|
||||||
@@ -38,6 +39,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
MultiPlayer m_mp;
|
MultiPlayer m_mp;
|
||||||
|
|
||||||
|
// Music statistics:
|
||||||
|
SongPosition m_Position;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Change the PlayerOptions to their default.
|
* @brief Change the PlayerOptions to their default.
|
||||||
* @param l the level of mods to reset.
|
* @param l the level of mods to reset.
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumH
|
|||||||
|
|
||||||
if( iNumBreakCombo == 0 )
|
if( iNumBreakCombo == 0 )
|
||||||
{
|
{
|
||||||
TimingData td = GAMESTATE->m_pCurSong->m_Timing;
|
TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing;
|
||||||
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo );
|
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo );
|
||||||
m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier;
|
m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier;
|
||||||
}
|
}
|
||||||
@@ -463,7 +463,7 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn
|
|||||||
if ( tns >= m_MinScoreToContinueCombo )
|
if ( tns >= m_MinScoreToContinueCombo )
|
||||||
{
|
{
|
||||||
m_pPlayerStageStats->m_iCurMissCombo = 0;
|
m_pPlayerStageStats->m_iCurMissCombo = 0;
|
||||||
TimingData td = GAMESTATE->m_pCurSong->m_Timing;
|
TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing;
|
||||||
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo );
|
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo );
|
||||||
m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier;
|
m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier;
|
||||||
}
|
}
|
||||||
|
|||||||
+414
-196
File diff suppressed because it is too large
Load Diff
+43
-5
@@ -86,6 +86,7 @@ enum EditButton
|
|||||||
EDIT_BUTTON_SNAP_PREV,
|
EDIT_BUTTON_SNAP_PREV,
|
||||||
|
|
||||||
EDIT_BUTTON_OPEN_EDIT_MENU,
|
EDIT_BUTTON_OPEN_EDIT_MENU,
|
||||||
|
EDIT_BUTTON_OPEN_TIMING_MENU,
|
||||||
EDIT_BUTTON_OPEN_AREA_MENU,
|
EDIT_BUTTON_OPEN_AREA_MENU,
|
||||||
EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU,
|
EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU,
|
||||||
EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU,
|
EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU,
|
||||||
@@ -138,6 +139,8 @@ enum EditButton
|
|||||||
|
|
||||||
EDIT_BUTTON_SWITCH_PLAYERS, /**< Allow entering notes for a different Player. */
|
EDIT_BUTTON_SWITCH_PLAYERS, /**< Allow entering notes for a different Player. */
|
||||||
|
|
||||||
|
EDIT_BUTTON_SWITCH_TIMINGS, /**< Allow switching between Song and Step TimingData. */
|
||||||
|
|
||||||
NUM_EditButton, // leave this at the end
|
NUM_EditButton, // leave this at the end
|
||||||
EditButton_Invalid
|
EditButton_Invalid
|
||||||
};
|
};
|
||||||
@@ -232,6 +235,9 @@ protected:
|
|||||||
|
|
||||||
void DoHelp();
|
void DoHelp();
|
||||||
|
|
||||||
|
/** @brief Display the TimingData menu for editing song and step timing. */
|
||||||
|
void DisplayTimingMenu();
|
||||||
|
|
||||||
EditState m_EditState;
|
EditState m_EditState;
|
||||||
|
|
||||||
Song* m_pSong;
|
Song* m_pSong;
|
||||||
@@ -275,14 +281,22 @@ protected:
|
|||||||
/** @brief Has the NoteData been changed such that a user should be prompted to save? */
|
/** @brief Has the NoteData been changed such that a user should be prompted to save? */
|
||||||
bool m_bDirty;
|
bool m_bDirty;
|
||||||
|
|
||||||
|
/** @brief The sound that is played when a note is added. */
|
||||||
RageSound m_soundAddNote;
|
RageSound m_soundAddNote;
|
||||||
|
/** @brief The sound that is played when a note is removed. */
|
||||||
RageSound m_soundRemoveNote;
|
RageSound m_soundRemoveNote;
|
||||||
RageSound m_soundChangeLine;
|
RageSound m_soundChangeLine;
|
||||||
RageSound m_soundChangeSnap;
|
RageSound m_soundChangeSnap;
|
||||||
RageSound m_soundMarker;
|
RageSound m_soundMarker;
|
||||||
RageSound m_soundValueIncrease;
|
RageSound m_soundValueIncrease;
|
||||||
RageSound m_soundValueDecrease;
|
RageSound m_soundValueDecrease;
|
||||||
|
/** @brief The sound that is played when switching players for Routine. */
|
||||||
|
RageSound m_soundSwitchPlayer;
|
||||||
|
/** @brief The sound that is played when switching song/step timing. */
|
||||||
|
RageSound m_soundSwitchTiming;
|
||||||
|
/** @brief The sound that is played when switching to a different chart. */
|
||||||
RageSound m_soundSwitchSteps;
|
RageSound m_soundSwitchSteps;
|
||||||
|
/** @brief The sound that is played when the chart is saved. */
|
||||||
RageSound m_soundSave;
|
RageSound m_soundSave;
|
||||||
|
|
||||||
// used for reverting
|
// used for reverting
|
||||||
@@ -459,7 +473,6 @@ public:
|
|||||||
main_title_transliteration,
|
main_title_transliteration,
|
||||||
sub_title_transliteration,
|
sub_title_transliteration,
|
||||||
artist_transliteration,
|
artist_transliteration,
|
||||||
beat_0_offset,
|
|
||||||
last_beat_hint,
|
last_beat_hint,
|
||||||
preview_start,
|
preview_start,
|
||||||
preview_length,
|
preview_length,
|
||||||
@@ -472,16 +485,21 @@ public:
|
|||||||
|
|
||||||
enum TimingDataInformationChoice
|
enum TimingDataInformationChoice
|
||||||
{
|
{
|
||||||
|
beat_0_offset,
|
||||||
bpm,
|
bpm,
|
||||||
stop,
|
stop,
|
||||||
delay,
|
delay,
|
||||||
// time_signature,
|
time_signature,
|
||||||
time_signature_numerator,
|
label,
|
||||||
time_signature_denominator,
|
|
||||||
tickcount,
|
tickcount,
|
||||||
combo,
|
combo,
|
||||||
label,
|
|
||||||
warp,
|
warp,
|
||||||
|
// speed,
|
||||||
|
speed_percent,
|
||||||
|
speed_wait,
|
||||||
|
speed_mode,
|
||||||
|
fake,
|
||||||
|
erase_step_timing,
|
||||||
NUM_TIMING_DATA_INFORMATION_CHOICES
|
NUM_TIMING_DATA_INFORMATION_CHOICES
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -515,6 +533,18 @@ public:
|
|||||||
NUM_BGCHANGE_CHOICES
|
NUM_BGCHANGE_CHOICES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SpeedSegmentModes
|
||||||
|
{
|
||||||
|
SSMODE_Beats,
|
||||||
|
SSMODE_Seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Take care of any background changes that the user wants.
|
||||||
|
*
|
||||||
|
* It is important that this is only called in Song Timing mode.
|
||||||
|
* @param c the Background Change style requested.
|
||||||
|
* @param iAnswers the other settings involving the change. */
|
||||||
void HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAnswers );
|
void HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAnswers );
|
||||||
|
|
||||||
enum CourseAttackChoice
|
enum CourseAttackChoice
|
||||||
@@ -544,6 +574,14 @@ public:
|
|||||||
|
|
||||||
void MakeFilteredMenuDef( const MenuDef* pDef, MenuDef &menu );
|
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.
|
||||||
|
* @return the proper TimingData. */
|
||||||
|
TimingData & GetAppropriateTiming() const;
|
||||||
|
void SetBeat(float fBeat);
|
||||||
|
float GetBeat();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ void ScreenEditMenu::MenuStart( const InputEventPlus &input )
|
|||||||
case EditMenuAction_Create:
|
case EditMenuAction_Create:
|
||||||
ASSERT( !pSteps );
|
ASSERT( !pSteps );
|
||||||
{
|
{
|
||||||
pSteps = new Steps;
|
pSteps = pSong->CreateSteps();
|
||||||
|
|
||||||
switch( m_Selector.EDIT_MODE )
|
switch( m_Selector.EDIT_MODE )
|
||||||
{
|
{
|
||||||
|
|||||||
+17
-17
@@ -1325,7 +1325,7 @@ void ScreenGameplay::StartPlayingSong( float fMinTimeToNotes, float fMinTimeToMu
|
|||||||
|
|
||||||
{
|
{
|
||||||
const float fFirstBeat = GAMESTATE->m_pCurSong->m_fFirstBeat;
|
const float fFirstBeat = GAMESTATE->m_pCurSong->m_fFirstBeat;
|
||||||
const float fFirstSecond = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat( fFirstBeat );
|
const float fFirstSecond = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( fFirstBeat );
|
||||||
float fStartDelay = fMinTimeToNotes - fFirstSecond;
|
float fStartDelay = fMinTimeToNotes - fFirstSecond;
|
||||||
fStartDelay = max( fStartDelay, fMinTimeToMusic );
|
fStartDelay = max( fStartDelay, fMinTimeToMusic );
|
||||||
p.m_StartSecond = -fStartDelay;
|
p.m_StartSecond = -fStartDelay;
|
||||||
@@ -1347,10 +1347,10 @@ void ScreenGameplay::StartPlayingSong( float fMinTimeToNotes, float fMinTimeToMu
|
|||||||
m_pSoundMusic->Pause( true );
|
m_pSoundMusic->Pause( true );
|
||||||
|
|
||||||
/* Make sure GAMESTATE->m_fMusicSeconds is set up. */
|
/* Make sure GAMESTATE->m_fMusicSeconds is set up. */
|
||||||
GAMESTATE->m_fMusicSeconds = -5000;
|
GAMESTATE->m_Position.m_fMusicSeconds = -5000;
|
||||||
UpdateSongPosition(0);
|
UpdateSongPosition(0);
|
||||||
|
|
||||||
ASSERT( GAMESTATE->m_fMusicSeconds > -4000 ); /* make sure the "fake timer" code doesn't trigger */
|
ASSERT( GAMESTATE->m_Position.m_fMusicSeconds > -4000 ); /* make sure the "fake timer" code doesn't trigger */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1405,7 +1405,7 @@ void ScreenGameplay::PlayAnnouncer( RString type, float fSeconds )
|
|||||||
if( m_DancingState != STATE_DANCING )
|
if( m_DancingState != STATE_DANCING )
|
||||||
return;
|
return;
|
||||||
if( GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes
|
if( GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes
|
||||||
GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat )
|
GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( m_fTimeSinceLastDancingComment < fSeconds )
|
if( m_fTimeSinceLastDancingComment < fSeconds )
|
||||||
@@ -1423,7 +1423,7 @@ void ScreenGameplay::UpdateSongPosition( float fDeltaTime )
|
|||||||
RageTimer tm;
|
RageTimer tm;
|
||||||
const float fSeconds = m_pSoundMusic->GetPositionSeconds( NULL, &tm );
|
const float fSeconds = m_pSoundMusic->GetPositionSeconds( NULL, &tm );
|
||||||
const float fAdjust = SOUND->GetFrameTimingAdjustment( fDeltaTime );
|
const float fAdjust = SOUND->GetFrameTimingAdjustment( fDeltaTime );
|
||||||
GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, GAMESTATE->m_pCurSong->m_Timing, tm+fAdjust );
|
GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, GAMESTATE->m_pCurSong->m_SongTiming, tm+fAdjust, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenGameplay::BeginScreen()
|
void ScreenGameplay::BeginScreen()
|
||||||
@@ -1480,7 +1480,7 @@ bool ScreenGameplay::AllAreFailing()
|
|||||||
|
|
||||||
void ScreenGameplay::GetMusicEndTiming( float &fSecondsToStartFadingOutMusic, float &fSecondsToStartTransitioningOut )
|
void ScreenGameplay::GetMusicEndTiming( float &fSecondsToStartFadingOutMusic, float &fSecondsToStartTransitioningOut )
|
||||||
{
|
{
|
||||||
float fLastStepSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
|
float fLastStepSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
|
||||||
fLastStepSeconds += Player::GetMaxStepDistanceSeconds();
|
fLastStepSeconds += Player::GetMaxStepDistanceSeconds();
|
||||||
|
|
||||||
float fTransitionLength;
|
float fTransitionLength;
|
||||||
@@ -1687,7 +1687,7 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
|
|
||||||
// update fGameplaySeconds
|
// update fGameplaySeconds
|
||||||
STATSMAN->m_CurStageStats.m_fGameplaySeconds += fUnscaledDeltaTime;
|
STATSMAN->m_CurStageStats.m_fGameplaySeconds += fUnscaledDeltaTime;
|
||||||
if( GAMESTATE->m_fSongBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat && GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
|
if( GAMESTATE->m_Position.m_fSongBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat && GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
|
||||||
{
|
{
|
||||||
STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime;
|
STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime;
|
||||||
|
|
||||||
@@ -1707,7 +1707,7 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
if( bAllReallyFailed )
|
if( bAllReallyFailed )
|
||||||
fSecondsToStartTransitioningOut += BEGIN_FAILED_DELAY;
|
fSecondsToStartTransitioningOut += BEGIN_FAILED_DELAY;
|
||||||
|
|
||||||
if( GAMESTATE->m_fMusicSeconds >= fSecondsToStartTransitioningOut && !m_NextSong.IsTransitioning() )
|
if( GAMESTATE->m_Position.m_fMusicSeconds >= fSecondsToStartTransitioningOut && !m_NextSong.IsTransitioning() )
|
||||||
this->PostScreenMessage( SM_NotesEnded, 0 );
|
this->PostScreenMessage( SM_NotesEnded, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1843,8 +1843,8 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
|
|
||||||
float ScreenGameplay::GetHasteRate()
|
float ScreenGameplay::GetHasteRate()
|
||||||
{
|
{
|
||||||
if( GAMESTATE->m_fMusicSeconds < GAMESTATE->m_fLastHasteUpdateMusicSeconds || // new song
|
if( GAMESTATE->m_Position.m_fMusicSeconds < GAMESTATE->m_fLastHasteUpdateMusicSeconds || // new song
|
||||||
GAMESTATE->m_fMusicSeconds > GAMESTATE->m_fLastHasteUpdateMusicSeconds + 4 )
|
GAMESTATE->m_Position.m_fMusicSeconds > GAMESTATE->m_fLastHasteUpdateMusicSeconds + 4 )
|
||||||
{
|
{
|
||||||
bool bAnyPlayerHitAllNotes = false;
|
bool bAnyPlayerHitAllNotes = false;
|
||||||
FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi )
|
FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi )
|
||||||
@@ -1865,7 +1865,7 @@ float ScreenGameplay::GetHasteRate()
|
|||||||
GAMESTATE->m_fHasteRate += 0.1f;
|
GAMESTATE->m_fHasteRate += 0.1f;
|
||||||
CLAMP( GAMESTATE->m_fHasteRate, -1.0f, +1.0f );
|
CLAMP( GAMESTATE->m_fHasteRate, -1.0f, +1.0f );
|
||||||
|
|
||||||
GAMESTATE->m_fLastHasteUpdateMusicSeconds = GAMESTATE->m_fMusicSeconds;
|
GAMESTATE->m_fLastHasteUpdateMusicSeconds = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the life meter is less than half full, push the haste rate down to let
|
/* If the life meter is less than half full, push the haste rate down to let
|
||||||
@@ -1914,7 +1914,7 @@ void ScreenGameplay::UpdateLights()
|
|||||||
ZERO( bBlinkGameButton );
|
ZERO( bBlinkGameButton );
|
||||||
bool bCrossedABeat = false;
|
bool bCrossedABeat = false;
|
||||||
{
|
{
|
||||||
const float fSongBeat = GAMESTATE->m_fLightSongBeat;
|
const float fSongBeat = GAMESTATE->m_Position.m_fLightSongBeat;
|
||||||
const int iSongRow = BeatToNoteRowNotRounded( fSongBeat );
|
const int iSongRow = BeatToNoteRowNotRounded( fSongBeat );
|
||||||
|
|
||||||
static int iRowLastCrossed = 0;
|
static int iRowLastCrossed = 0;
|
||||||
@@ -1968,7 +1968,7 @@ void ScreenGameplay::UpdateLights()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Before the first beat of the song, all cabinet lights solid on (except for menu buttons).
|
// Before the first beat of the song, all cabinet lights solid on (except for menu buttons).
|
||||||
bool bOverrideCabinetBlink = (GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat);
|
bool bOverrideCabinetBlink = (GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat);
|
||||||
FOREACH_CabinetLight( cl )
|
FOREACH_CabinetLight( cl )
|
||||||
bBlinkCabinetLight[cl] |= bOverrideCabinetBlink;
|
bBlinkCabinetLight[cl] |= bOverrideCabinetBlink;
|
||||||
|
|
||||||
@@ -1994,8 +1994,8 @@ void ScreenGameplay::SendCrossedMessages()
|
|||||||
{
|
{
|
||||||
static int iRowLastCrossed = 0;
|
static int iRowLastCrossed = 0;
|
||||||
|
|
||||||
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
|
float fPositionSeconds = GAMESTATE->m_Position.m_fMusicSeconds;
|
||||||
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
|
float fSongBeat = GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds );
|
||||||
|
|
||||||
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
||||||
iRowNow = max( 0, iRowNow );
|
iRowNow = max( 0, iRowNow );
|
||||||
@@ -2032,8 +2032,8 @@ void ScreenGameplay::SendCrossedMessages()
|
|||||||
{
|
{
|
||||||
float fNoteWillCrossInSeconds = MESSAGE_SPACING_SECONDS * i;
|
float fNoteWillCrossInSeconds = MESSAGE_SPACING_SECONDS * i;
|
||||||
|
|
||||||
float fPositionSeconds = GAMESTATE->m_fMusicSeconds + fNoteWillCrossInSeconds;
|
float fPositionSeconds = GAMESTATE->m_Position.m_fMusicSeconds + fNoteWillCrossInSeconds;
|
||||||
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
|
float fSongBeat = GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds );
|
||||||
|
|
||||||
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
||||||
iRowNow = max( 0, iRowNow );
|
iRowNow = max( 0, iRowNow );
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ void ScreenHowToPlay::Step()
|
|||||||
#define ST_JUMPUD (ST_UP | ST_DOWN)
|
#define ST_JUMPUD (ST_UP | ST_DOWN)
|
||||||
|
|
||||||
int iStep = 0;
|
int iStep = 0;
|
||||||
const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat + 0.6f );
|
const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.6f );
|
||||||
// if we want to miss from here on out, don't process steps.
|
// if we want to miss from here on out, don't process steps.
|
||||||
if( m_iW2s < m_iNumW2s && m_NoteData.IsThereATapAtRow( iNoteRow ) )
|
if( m_iW2s < m_iNumW2s && m_NoteData.IsThereATapAtRow( iNoteRow ) )
|
||||||
{
|
{
|
||||||
@@ -229,10 +229,10 @@ void ScreenHowToPlay::Step()
|
|||||||
m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f );
|
m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f );
|
||||||
|
|
||||||
m_pmCharacter->StopTweening();
|
m_pmCharacter->StopTweening();
|
||||||
m_pmCharacter->BeginTweening( GAMESTATE->m_fCurBPS /8, TWEEN_LINEAR );
|
m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /8, TWEEN_LINEAR );
|
||||||
m_pmCharacter->SetRotationY( 90 );
|
m_pmCharacter->SetRotationY( 90 );
|
||||||
m_pmCharacter->BeginTweening( (1/(GAMESTATE->m_fCurBPS * 2) ) ); //sleep between jump-frames
|
m_pmCharacter->BeginTweening( (1/(GAMESTATE->m_Position.m_fCurBPS * 2) ) ); //sleep between jump-frames
|
||||||
m_pmCharacter->BeginTweening( GAMESTATE->m_fCurBPS /6, TWEEN_LINEAR );
|
m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR );
|
||||||
m_pmCharacter->SetRotationY( 0 );
|
m_pmCharacter->SetRotationY( 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -243,11 +243,11 @@ void ScreenHowToPlay::Update( float fDelta )
|
|||||||
{
|
{
|
||||||
if( GAMESTATE->m_pCurSong != NULL )
|
if( GAMESTATE->m_pCurSong != NULL )
|
||||||
{
|
{
|
||||||
GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_Timing );
|
GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_SongTiming );
|
||||||
m_fFakeSecondsIntoSong += fDelta;
|
m_fFakeSecondsIntoSong += fDelta;
|
||||||
|
|
||||||
static int iLastNoteRowCounted = 0;
|
static int iLastNoteRowCounted = 0;
|
||||||
int iCurNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
int iCurNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat );
|
||||||
|
|
||||||
if( iCurNoteRow != iLastNoteRowCounted &&m_NoteData.IsThereATapAtRow(iCurNoteRow) )
|
if( iCurNoteRow != iLastNoteRowCounted &&m_NoteData.IsThereATapAtRow(iCurNoteRow) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ void ScreenNameEntry::ScrollingText::Init( const RString &sName, const vector<fl
|
|||||||
|
|
||||||
void ScreenNameEntry::ScrollingText::DrawPrimitives()
|
void ScreenNameEntry::ScrollingText::DrawPrimitives()
|
||||||
{
|
{
|
||||||
const float fFakeBeat = GAMESTATE->m_fSongBeat;
|
const float fFakeBeat = GAMESTATE->m_Position.m_fSongBeat;
|
||||||
const size_t iClosestIndex = lrintf( fFakeBeat ) % CHARS_CHOICES.size();
|
const size_t iClosestIndex = lrintf( fFakeBeat ) % CHARS_CHOICES.size();
|
||||||
const float fClosestYOffset = GetClosestCharYOffset( fFakeBeat );
|
const float fClosestYOffset = GetClosestCharYOffset( fFakeBeat );
|
||||||
|
|
||||||
@@ -325,7 +325,7 @@ void ScreenNameEntry::Update( float fDelta )
|
|||||||
SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("name entry") );
|
SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("name entry") );
|
||||||
|
|
||||||
m_fFakeBeat += fDelta * FAKE_BEATS_PER_SEC;
|
m_fFakeBeat += fDelta * FAKE_BEATS_PER_SEC;
|
||||||
GAMESTATE->m_fSongBeat = m_fFakeBeat;
|
GAMESTATE->m_Position.m_fSongBeat = m_fFakeBeat;
|
||||||
|
|
||||||
ScreenWithMenuElements::Update(fDelta);
|
ScreenWithMenuElements::Update(fDelta);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1764,7 +1764,7 @@ void ScreenSelectMusic::AfterMusicChange()
|
|||||||
case SampleMusicPreviewMode_LastSong: // fall through
|
case SampleMusicPreviewMode_LastSong: // fall through
|
||||||
// play the sample music
|
// play the sample music
|
||||||
m_sSampleMusicToPlay = pSong->GetMusicPath();
|
m_sSampleMusicToPlay = pSong->GetMusicPath();
|
||||||
m_pSampleMusicTimingData = &pSong->m_Timing;
|
m_pSampleMusicTimingData = &pSong->m_SongTiming;
|
||||||
m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds;
|
m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds;
|
||||||
m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds;
|
m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input )
|
|||||||
}
|
}
|
||||||
if( GAMESTATE->m_pCurSong != NULL )
|
if( GAMESTATE->m_pCurSong != NULL )
|
||||||
{
|
{
|
||||||
BPMSegment& seg = GAMESTATE->m_pCurSong->GetBPMSegmentAtBeat( GAMESTATE->m_fSongBeat );
|
BPMSegment& seg = GAMESTATE->m_pCurSong->m_SongTiming.GetBPMSegmentAtBeat( GAMESTATE->m_Position.m_fSongBeat );
|
||||||
seg.m_fBPS += fDelta;
|
seg.m_fBPS += fDelta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input )
|
|||||||
|
|
||||||
case ChangeSongOffset:
|
case ChangeSongOffset:
|
||||||
if( GAMESTATE->m_pCurSong != NULL )
|
if( GAMESTATE->m_pCurSong != NULL )
|
||||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fDelta;
|
GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fDelta;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-54
@@ -41,7 +41,7 @@
|
|||||||
* @brief The internal version of the cache for StepMania.
|
* @brief The internal version of the cache for StepMania.
|
||||||
*
|
*
|
||||||
* Increment this value to invalidate the current cache. */
|
* Increment this value to invalidate the current cache. */
|
||||||
const int FILE_CACHE_VERSION = 171;
|
const int FILE_CACHE_VERSION = 174;
|
||||||
|
|
||||||
/** @brief How long does a song sample last by default? */
|
/** @brief How long does a song sample last by default? */
|
||||||
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
|
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
|
||||||
@@ -145,6 +145,18 @@ void Song::AddLyricSegment( LyricSegment seg )
|
|||||||
m_LyricSegments.push_back( seg );
|
m_LyricSegments.push_back( seg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Steps *Song::CreateSteps()
|
||||||
|
{
|
||||||
|
Steps *pSteps = new Steps;
|
||||||
|
InitSteps( pSteps );
|
||||||
|
return pSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Song::InitSteps(Steps *pSteps)
|
||||||
|
{
|
||||||
|
pSteps->m_Timing = m_SongTiming;
|
||||||
|
}
|
||||||
|
|
||||||
void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
|
void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
|
||||||
{
|
{
|
||||||
if( m_DisplayBPMType == DISPLAY_BPM_SPECIFIED )
|
if( m_DisplayBPMType == DISPLAY_BPM_SPECIFIED )
|
||||||
@@ -155,7 +167,7 @@ void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
float fMinBPM, fMaxBPM;
|
float fMinBPM, fMaxBPM;
|
||||||
m_Timing.GetActualBPM( fMinBPM, fMaxBPM );
|
m_SongTiming.GetActualBPM( fMinBPM, fMaxBPM );
|
||||||
AddTo.Add( fMinBPM );
|
AddTo.Add( fMinBPM );
|
||||||
AddTo.Add( fMaxBPM );
|
AddTo.Add( fMaxBPM );
|
||||||
}
|
}
|
||||||
@@ -460,6 +472,13 @@ void Song::TidyUpData()
|
|||||||
m_fMusicLengthSeconds = 0;
|
m_fMusicLengthSeconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_SongTiming.TidyUpData();
|
||||||
|
|
||||||
|
FOREACH( Steps *, m_vpSteps, s )
|
||||||
|
{
|
||||||
|
(*s)->m_Timing.TidyUpData();
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate these before we autogen notes, so the new notes can inherit
|
/* Generate these before we autogen notes, so the new notes can inherit
|
||||||
* their source's values. */
|
* their source's values. */
|
||||||
ReCalculateRadarValuesAndLastBeat();
|
ReCalculateRadarValuesAndLastBeat();
|
||||||
@@ -476,29 +495,18 @@ void Song::TidyUpData()
|
|||||||
m_sArtist = "Unknown artist";
|
m_sArtist = "Unknown artist";
|
||||||
TranslateTitles();
|
TranslateTitles();
|
||||||
|
|
||||||
if( m_Timing.m_BPMSegments.empty() )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", m_sSongDir + m_sSongFileName, "has no BPM segments, default provided." );
|
|
||||||
|
|
||||||
m_Timing.AddBPMSegment( BPMSegment(0, 60) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the first BPM segment starts at beat 0.
|
|
||||||
if( m_Timing.m_BPMSegments[0].m_iStartRow != 0 )
|
|
||||||
m_Timing.m_BPMSegments[0].m_iStartRow = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if( m_fMusicSampleStartSeconds == -1 ||
|
if( m_fMusicSampleStartSeconds == -1 ||
|
||||||
m_fMusicSampleStartSeconds == 0 ||
|
m_fMusicSampleStartSeconds == 0 ||
|
||||||
m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds )
|
m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds )
|
||||||
{
|
{
|
||||||
m_fMusicSampleStartSeconds = this->GetElapsedTimeFromBeat( 100 );
|
const TimingData &timing = this->m_SongTiming;
|
||||||
|
m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( 100 );
|
||||||
|
|
||||||
if( m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds )
|
if( m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds )
|
||||||
{
|
{
|
||||||
int iBeat = lrintf( m_fLastBeat/2 );
|
int iBeat = lrintf( m_fLastBeat/2 );
|
||||||
iBeat -= iBeat%4;
|
iBeat -= iBeat%4;
|
||||||
m_fMusicSampleStartSeconds = this->GetElapsedTimeFromBeat( (float)iBeat );
|
m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( (float)iBeat );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,38 +785,6 @@ void Song::TidyUpData()
|
|||||||
m_sSongFileName += ".ssc";
|
m_sSongFileName += ".ssc";
|
||||||
} while(0);
|
} while(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no time signature specified, assume 4/4 time for the whole song.
|
|
||||||
if( m_Timing.m_vTimeSignatureSegments.empty() )
|
|
||||||
{
|
|
||||||
TimeSignatureSegment seg(0, 4, 4);
|
|
||||||
m_Timing.m_vTimeSignatureSegments.push_back( seg );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Likewise, if no tickcount signature is specified, assume 2 ticks
|
|
||||||
* per beat for the entire song. The default of 2 is chosen more
|
|
||||||
* for compatibility with the Pump Pro series than anything else.
|
|
||||||
*/
|
|
||||||
if( m_Timing.m_TickcountSegments.empty() )
|
|
||||||
{
|
|
||||||
TickcountSegment seg(0, 2);
|
|
||||||
m_Timing.m_TickcountSegments.push_back( seg );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Have a default combo segment of one just in case.
|
|
||||||
if( m_Timing.m_ComboSegments.empty() )
|
|
||||||
{
|
|
||||||
ComboSegment seg(0, 1);
|
|
||||||
m_Timing.m_ComboSegments.push_back( seg );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Have a default label segment just in case.
|
|
||||||
if( m_Timing.m_LabelSegments.empty() )
|
|
||||||
{
|
|
||||||
LabelSegment seg(0, "Song Start");
|
|
||||||
m_Timing.m_LabelSegments.push_back( seg );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Song::TranslateTitles()
|
void Song::TranslateTitles()
|
||||||
@@ -857,8 +833,8 @@ void Song::ReCalculateRadarValuesAndLastBeat()
|
|||||||
if( tempNoteData.GetLastRow() == 0 )
|
if( tempNoteData.GetLastRow() == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fFirstBeat = min( fFirstBeat, tempNoteData.GetFirstBeat() );
|
fFirstBeat = min( fFirstBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())) );
|
||||||
fLastBeat = max( fLastBeat, tempNoteData.GetLastBeat() );
|
fLastBeat = max( fLastBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())) );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fFirstBeat = fFirstBeat;
|
m_fFirstBeat = fFirstBeat;
|
||||||
@@ -888,6 +864,12 @@ void Song::Save()
|
|||||||
ReCalculateRadarValuesAndLastBeat();
|
ReCalculateRadarValuesAndLastBeat();
|
||||||
TranslateTitles();
|
TranslateTitles();
|
||||||
|
|
||||||
|
// TODO: Figure out a better way to save to Song's timing data.
|
||||||
|
if( m_vpSteps.size() == 1 )
|
||||||
|
{
|
||||||
|
m_SongTiming = m_vpSteps[0]->m_Timing;
|
||||||
|
}
|
||||||
|
|
||||||
// Save the new files. These calls make backups on their own.
|
// Save the new files. These calls make backups on their own.
|
||||||
if( !SaveToSSCFile(GetSongFilePath(), false) )
|
if( !SaveToSSCFile(GetSongFilePath(), false) )
|
||||||
return;
|
return;
|
||||||
@@ -1453,7 +1435,7 @@ bool Song::IsEditAlreadyLoaded( Steps* pSteps ) const
|
|||||||
|
|
||||||
bool Song::HasSignificantBpmChangesOrStops() const
|
bool Song::HasSignificantBpmChangesOrStops() const
|
||||||
{
|
{
|
||||||
if( m_Timing.HasStops() )
|
if( m_SongTiming.HasStops() )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Don't consider BPM changes that only are only for maintaining sync as
|
// Don't consider BPM changes that only are only for maintaining sync as
|
||||||
@@ -1463,7 +1445,7 @@ bool Song::HasSignificantBpmChangesOrStops() const
|
|||||||
if( m_fSpecifiedBPMMin != m_fSpecifiedBPMMax )
|
if( m_fSpecifiedBPMMin != m_fSpecifiedBPMMax )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if( m_Timing.HasBpmChanges() )
|
else if( m_SongTiming.HasBpmChanges() )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1473,7 +1455,8 @@ bool Song::HasSignificantBpmChangesOrStops() const
|
|||||||
|
|
||||||
float Song::GetStepsSeconds() const
|
float Song::GetStepsSeconds() const
|
||||||
{
|
{
|
||||||
return GetElapsedTimeFromBeat( m_fLastBeat ) - GetElapsedTimeFromBeat( m_fFirstBeat );
|
const TimingData &timing = this->m_SongTiming;
|
||||||
|
return timing.GetElapsedTimeFromBeat( m_fLastBeat ) - timing.GetElapsedTimeFromBeat( m_fFirstBeat );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Song::IsLong() const
|
bool Song::IsLong() const
|
||||||
@@ -1556,7 +1539,7 @@ public:
|
|||||||
}
|
}
|
||||||
static int GetTimingData( T* p, lua_State *L )
|
static int GetTimingData( T* p, lua_State *L )
|
||||||
{
|
{
|
||||||
p->m_Timing.PushSelf(L);
|
p->m_SongTiming.PushSelf(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// has functions
|
// has functions
|
||||||
|
|||||||
+37
-3
@@ -8,16 +8,16 @@
|
|||||||
#include "RageUtil_AutoPtr.h"
|
#include "RageUtil_AutoPtr.h"
|
||||||
#include "RageUtil_CachedObject.h"
|
#include "RageUtil_CachedObject.h"
|
||||||
#include "RageTypes.h"
|
#include "RageTypes.h"
|
||||||
|
#include "Steps.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
class Steps;
|
|
||||||
class Style;
|
class Style;
|
||||||
class StepsID;
|
class StepsID;
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
struct BackgroundChange;
|
struct BackgroundChange;
|
||||||
|
|
||||||
/** @brief The version of the .ssc file format. */
|
/** @brief The version of the .ssc file format. */
|
||||||
const static float STEPFILE_VERSION_NUMBER = 0.59f;
|
const static float STEPFILE_VERSION_NUMBER = 0.7f;
|
||||||
|
|
||||||
/** @brief How many edits for this song can each profile have? */
|
/** @brief How many edits for this song can each profile have? */
|
||||||
const int MAX_EDITS_PER_SONG_PER_PROFILE = 5;
|
const int MAX_EDITS_PER_SONG_PER_PROFILE = 5;
|
||||||
@@ -285,7 +285,10 @@ public:
|
|||||||
bool Matches(RString sGroup, RString sSong) const;
|
bool Matches(RString sGroup, RString sSong) const;
|
||||||
|
|
||||||
/** @brief The Song's TimingData. */
|
/** @brief The Song's TimingData. */
|
||||||
TimingData m_Timing;
|
TimingData m_SongTiming;
|
||||||
|
|
||||||
|
/** @brief The initial offset of a song. */
|
||||||
|
float m_fBeat0OffsetInSeconds;
|
||||||
|
|
||||||
typedef vector<BackgroundChange> VBackgroundChange;
|
typedef vector<BackgroundChange> VBackgroundChange;
|
||||||
private:
|
private:
|
||||||
@@ -317,9 +320,11 @@ public:
|
|||||||
* This must be sorted before gameplay. */
|
* This must be sorted before gameplay. */
|
||||||
vector<LyricSegment> m_LyricSegments;
|
vector<LyricSegment> m_LyricSegments;
|
||||||
|
|
||||||
|
/* [splittiming]
|
||||||
void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); }
|
void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); }
|
||||||
void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); }
|
void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); }
|
||||||
void AddWarpSegment( const WarpSegment &seg ) { m_Timing.AddWarpSegment( seg ); }
|
void AddWarpSegment( const WarpSegment &seg ) { m_Timing.AddWarpSegment( seg ); }
|
||||||
|
*/
|
||||||
void AddBackgroundChange( BackgroundLayer blLayer, BackgroundChange seg );
|
void AddBackgroundChange( BackgroundLayer blLayer, BackgroundChange seg );
|
||||||
void AddForegroundChange( BackgroundChange seg );
|
void AddForegroundChange( BackgroundChange seg );
|
||||||
void AddLyricSegment( LyricSegment seg );
|
void AddLyricSegment( LyricSegment seg );
|
||||||
@@ -327,18 +332,47 @@ public:
|
|||||||
void GetDisplayBpms( DisplayBpms &AddTo ) const;
|
void GetDisplayBpms( DisplayBpms &AddTo ) const;
|
||||||
const BackgroundChange &GetBackgroundAtBeat( BackgroundLayer iLayer, float fBeat ) const;
|
const BackgroundChange &GetBackgroundAtBeat( BackgroundLayer iLayer, float fBeat ) const;
|
||||||
|
|
||||||
|
/* [splittiming]
|
||||||
float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); }
|
float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); }
|
||||||
void SetBPMAtBeat( float fBeat, float fBPM ) { m_Timing.SetBPMAtBeat( fBeat, fBPM ); }
|
void SetBPMAtBeat( float fBeat, float fBPM ) { m_Timing.SetBPMAtBeat( fBeat, fBPM ); }
|
||||||
BPMSegment& GetBPMSegmentAtBeat( float fBeat ) { return m_Timing.GetBPMSegmentAtBeat( fBeat ); }
|
BPMSegment& GetBPMSegmentAtBeat( float fBeat ) { return m_Timing.GetBPMSegmentAtBeat( fBeat ); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
Steps *CreateSteps();
|
||||||
|
void InitSteps(Steps *pSteps);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the beat based on the specified time.
|
* @brief Retrieve the beat based on the specified time.
|
||||||
* @param fElapsedTime the amount of time since the Song started.
|
* @param fElapsedTime the amount of time since the Song started.
|
||||||
* @return the appropriate beat. */
|
* @return the appropriate beat. */
|
||||||
|
/* [splittiming]
|
||||||
|
float SongGetBeatFromElapsedTime( float fElapsedTime ) const
|
||||||
|
{
|
||||||
|
return m_SongTiming.GetBeatFromElapsedTime( fElapsedTime );
|
||||||
|
}
|
||||||
|
float StepsGetBeatFromElapsedTime( float fElapsedTime, const Steps &steps ) const
|
||||||
|
{
|
||||||
|
return steps.m_Timing.GetBeatFromElapsedTime( fElapsedTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
float SongGetElapsedTimeFromBeat( float fBeat ) const
|
||||||
|
{
|
||||||
|
return m_SongTiming.GetElapsedTimeFromBeat( fBeat );
|
||||||
|
}
|
||||||
|
float StepsGetElapsedTimeFromBeat( float fBeat, const Steps &steps ) const
|
||||||
|
{
|
||||||
|
return steps.m_Timing.GetElapsedTimeFromBeat( fBeat );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* [splittiming]
|
||||||
float GetBeatFromElapsedTime( float fElapsedTime ) const
|
float GetBeatFromElapsedTime( float fElapsedTime ) const
|
||||||
{
|
{
|
||||||
return m_Timing.GetBeatFromElapsedTime( fElapsedTime );
|
return m_Timing.GetBeatFromElapsedTime( fElapsedTime );
|
||||||
}
|
}
|
||||||
float GetElapsedTimeFromBeat( float fBeat ) const { return m_Timing.GetElapsedTimeFromBeat( fBeat ); }
|
float GetElapsedTimeFromBeat( float fBeat ) const { return m_Timing.GetElapsedTimeFromBeat( fBeat ); }
|
||||||
|
*/
|
||||||
|
|
||||||
bool HasSignificantBpmChangesOrStops() const;
|
bool HasSignificantBpmChangesOrStops() const;
|
||||||
float GetStepsSeconds() const;
|
float GetStepsSeconds() const;
|
||||||
bool IsLong() const;
|
bool IsLong() const;
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "SongPosition.h"
|
||||||
|
|
||||||
|
static Preference<float> g_fVisualDelaySeconds( "VisualDelaySeconds", 0.0f );
|
||||||
|
|
||||||
|
void SongPosition::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( !timestamp.IsZero() )
|
||||||
|
m_LastBeatUpdate = timestamp;
|
||||||
|
else
|
||||||
|
m_LastBeatUpdate.Touch();
|
||||||
|
|
||||||
|
// xxx testing: only do this on monotune survivor
|
||||||
|
/*
|
||||||
|
if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" )
|
||||||
|
LOG->Trace( ssprintf("[GameState::UpdateSongPosition] cur BPS = %f, fPositionSeconds = %f",m_fCurBPS,fPositionSeconds) );
|
||||||
|
*/
|
||||||
|
|
||||||
|
timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay, m_iWarpBeginRow, m_fWarpDestination );
|
||||||
|
|
||||||
|
// "Crash reason : -243478.890625 -48695.773438"
|
||||||
|
ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds is less than -2000!", m_fSongBeat, fPositionSeconds) );
|
||||||
|
|
||||||
|
m_fMusicSeconds = fPositionSeconds;
|
||||||
|
|
||||||
|
m_fLightSongBeat = timing.GetBeatFromElapsedTime( fPositionSeconds + g_fLightsAheadSeconds );
|
||||||
|
|
||||||
|
m_fSongBeatNoOffset = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds );
|
||||||
|
|
||||||
|
/*
|
||||||
|
// xxx testing: only do this on monotune survivor
|
||||||
|
if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" )
|
||||||
|
{
|
||||||
|
// and only do it in the known negative bpm region. HACKITY HACK
|
||||||
|
if(m_fSongBeat >= 445.490f && m_fSongBeat <= 453.72f)
|
||||||
|
{
|
||||||
|
LOG->Trace( ssprintf("fPositionSeconds = %f",fPositionSeconds) );
|
||||||
|
LOG->Trace( ssprintf("Song beat: %f (%f seconds), BPS = %f (%f BPM)",m_fSongBeat,m_fMusicSecondsVisible,m_fCurBPS,m_fCurBPS*60.0f) );
|
||||||
|
//LOG->Trace( ssprintf("Music seconds visible %f = fPositionSeconds %f - g_fVisualDelaySeconds %f", m_fMusicSecondsVisible,fPositionSeconds,g_fVisualDelaySeconds.Get()) );
|
||||||
|
}
|
||||||
|
else if(m_fSongBeat == 445.500f)
|
||||||
|
{
|
||||||
|
LOG->Trace( ssprintf("[beat 445.500] fPositionSeconds = %f",fPositionSeconds) );
|
||||||
|
LOG->Trace( ssprintf("Song beat: %f (%f seconds), BPS = %f (%f BPM)",m_fSongBeat,m_fMusicSecondsVisible,m_fCurBPS,m_fCurBPS*60.0f) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
m_fMusicSecondsVisible = fPositionSeconds - g_fVisualDelaySeconds.Get();
|
||||||
|
float fThrowAway, fThrowAway2;
|
||||||
|
bool bThrowAway;
|
||||||
|
int iThrowAway;
|
||||||
|
timing.GetBeatAndBPSFromElapsedTime( m_fMusicSecondsVisible, m_fSongBeatVisible, fThrowAway, bThrowAway, bThrowAway, iThrowAway, fThrowAway2 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongPosition::Reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
m_fMusicSecondsVisible = 0;
|
||||||
|
m_fSongBeatVisible = 0;
|
||||||
|
|
||||||
|
m_fMusicSeconds = 0; // MUSIC_SECONDS_INVALID;
|
||||||
|
// todo: move me to FOREACH_EnabledPlayer( p ) after [NUM_PLAYERS]ing
|
||||||
|
m_fSongBeat = 0;
|
||||||
|
m_fSongBeatNoOffset = 0;
|
||||||
|
m_fCurBPS = 10;
|
||||||
|
//m_bStop = false;
|
||||||
|
m_bFreeze = false;
|
||||||
|
m_bDelay = false;
|
||||||
|
m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj
|
||||||
|
m_fWarpDestination = -1; // Set when a warp is encountered. also see above. -aj
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//lua start
|
||||||
|
#include "LuaBinding.h"
|
||||||
|
class LunaSongPosition: public Luna<SongPosition>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DEFINE_METHOD( GetMusicSecondsVisible, m_fMusicSecondsVisible );
|
||||||
|
DEFINE_METHOD( GetSongBeatVisible, m_fSongBeatVisible );
|
||||||
|
DEFINE_METHOD( GetMusicSeconds, m_fMusicSeconds );
|
||||||
|
DEFINE_METHOD( GetSongBeat, m_fSongBeat );
|
||||||
|
DEFINE_METHOD( GetSongBeatNoOffset, m_fSongBeatNoOffset );
|
||||||
|
DEFINE_METHOD( GetCurBPS, m_fCurBPS );
|
||||||
|
DEFINE_METHOD( GetFreeze, m_bFreeze );
|
||||||
|
DEFINE_METHOD( GetDelay, m_bDelay );
|
||||||
|
DEFINE_METHOD( GetWarpBeginRow, m_iWarpBeginRow );
|
||||||
|
DEFINE_METHOD( GetWarpDestination, m_fWarpDestination );
|
||||||
|
|
||||||
|
LunaSongPosition()
|
||||||
|
{
|
||||||
|
ADD_METHOD( GetMusicSecondsVisible );
|
||||||
|
ADD_METHOD( GetSongBeatVisible );
|
||||||
|
ADD_METHOD( GetMusicSeconds );
|
||||||
|
ADD_METHOD( GetSongBeat );
|
||||||
|
ADD_METHOD( GetSongBeatNoOffset );
|
||||||
|
ADD_METHOD( GetCurBPS );
|
||||||
|
ADD_METHOD( GetFreeze );
|
||||||
|
ADD_METHOD( GetDelay );
|
||||||
|
ADD_METHOD( GetWarpBeginRow );
|
||||||
|
ADD_METHOD( GetWarpDestination );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUA_REGISTER_CLASS( SongPosition );
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @author Thai Pangsakulyanont (c) 2011
|
||||||
|
* @section LICENSE
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||||
|
* whom the Software is furnished to do so, provided that the above
|
||||||
|
* copyright notice(s) and this permission notice appear in all copies of
|
||||||
|
* the Software and that both the above copyright notice(s) and this
|
||||||
|
* permission notice appear in supporting documentation.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||||
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||||
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||||
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||||
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#ifndef SONGPOSITION_H
|
||||||
|
#define SONGPOSITION_H
|
||||||
|
|
||||||
|
#include "GameConstantsAndTypes.h"
|
||||||
|
#include "RageTimer.h"
|
||||||
|
#include "LightsManager.h"
|
||||||
|
#include "MessageManager.h"
|
||||||
|
#include "TimingData.h"
|
||||||
|
//XXX: where does this come from? might need another include
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
class SongPosition
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Arcade - the current stage (one song).
|
||||||
|
// Oni/Endless - a single song in a course.
|
||||||
|
// Let a lot of classes access this info here so they don't have to keep their own copies.
|
||||||
|
float m_fMusicSeconds; // time into the current song, not scaled by music rate
|
||||||
|
float m_fSongBeat;
|
||||||
|
float m_fSongBeatNoOffset;
|
||||||
|
float m_fCurBPS;
|
||||||
|
float m_fLightSongBeat; // g_fLightsFalloffSeconds ahead
|
||||||
|
//bool m_bStop; // in the middle of a stop (freeze or delay)
|
||||||
|
/** @brief A flag to determine if we're in the middle of a freeze/stop. */
|
||||||
|
bool m_bFreeze;
|
||||||
|
/** @brief A flag to determine if we're in the middle of a delay (Pump style stop). */
|
||||||
|
bool m_bDelay;
|
||||||
|
/** @brief The row used to start a warp. */
|
||||||
|
int m_iWarpBeginRow;
|
||||||
|
/** @brief The beat to warp to afterwards. */
|
||||||
|
float m_fWarpDestination;
|
||||||
|
RageTimer m_LastBeatUpdate; // time of last m_fSongBeat, etc. update
|
||||||
|
float m_fMusicSecondsVisible;
|
||||||
|
float m_fSongBeatVisible;
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
void UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp = RageZeroTimer );
|
||||||
|
|
||||||
|
// Lua
|
||||||
|
void PushSelf( lua_State *L );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @author Thai Pangsakulyanont (c) 2011
|
||||||
|
* @section LICENSE
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||||
|
* whom the Software is furnished to do so, provided that the above
|
||||||
|
* copyright notice(s) and this permission notice appear in all copies of
|
||||||
|
* the Software and that both the above copyright notice(s) and this
|
||||||
|
* permission notice appear in supporting documentation.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||||
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||||
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||||
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||||
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
@@ -44,7 +44,7 @@ void SoundEffectControl::Update( float fDeltaTime )
|
|||||||
|
|
||||||
if( LOCK_TO_HOLD )
|
if( LOCK_TO_HOLD )
|
||||||
{
|
{
|
||||||
int iRow = BeatToNoteRow( GAMESTATE->m_fSongBeat );
|
int iRow = BeatToNoteRow( GAMESTATE->m_Position.m_fSongBeat );
|
||||||
int iHoldsHeld, iHoldsLetGo;
|
int iHoldsHeld, iHoldsLetGo;
|
||||||
HoldsBeingHeld( iRow, iHoldsHeld, iHoldsLetGo );
|
HoldsBeingHeld( iRow, iHoldsHeld, iHoldsLetGo );
|
||||||
|
|
||||||
|
|||||||
@@ -1444,6 +1444,14 @@
|
|||||||
RelativePath="SongOptions.h"
|
RelativePath="SongOptions.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\SongPosition.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\SongPosition.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="SongUtil.cpp"
|
RelativePath="SongUtil.cpp"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ void Steps::AutogenFrom( const Steps *parent_, StepsType ntTo )
|
|||||||
{
|
{
|
||||||
parent = parent_;
|
parent = parent_;
|
||||||
m_StepsType = ntTo;
|
m_StepsType = ntTo;
|
||||||
|
m_Timing = parent->m_Timing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds ) // pSource does not have to be of the same StepsType
|
void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds ) // pSource does not have to be of the same StepsType
|
||||||
@@ -348,6 +349,7 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds
|
|||||||
pSource->GetNoteData( noteData );
|
pSource->GetNoteData( noteData );
|
||||||
noteData.SetNumTracks( GAMEMAN->GetStepsTypeInfo(ntTo).iNumTracks );
|
noteData.SetNumTracks( GAMEMAN->GetStepsTypeInfo(ntTo).iNumTracks );
|
||||||
parent = NULL;
|
parent = NULL;
|
||||||
|
m_Timing = pSource->m_Timing;
|
||||||
this->SetNoteData( noteData );
|
this->SetNoteData( noteData );
|
||||||
this->SetDescription( pSource->GetDescription() );
|
this->SetDescription( pSource->GetDescription() );
|
||||||
this->SetDifficulty( pSource->GetDifficulty() );
|
this->SetDifficulty( pSource->GetDifficulty() );
|
||||||
@@ -400,6 +402,21 @@ void Steps::SetMeter( int meter )
|
|||||||
m_iMeter = meter;
|
m_iMeter = meter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Steps::HasSignificantTimingChanges() const
|
||||||
|
{
|
||||||
|
if( m_Timing.HasStops() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* TODO: Deal with DisplayBPM here...if possible?
|
||||||
|
* Song's version may still be useful. */
|
||||||
|
|
||||||
|
else if( m_Timing.HasBpmChanges() || m_Timing.HasWarps() || m_Timing.HasSpeedChanges() )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] )
|
void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] )
|
||||||
{
|
{
|
||||||
DeAutogen();
|
DeAutogen();
|
||||||
@@ -424,6 +441,8 @@ public:
|
|||||||
DEFINE_METHOD( IsAnEdit, IsAnEdit() )
|
DEFINE_METHOD( IsAnEdit, IsAnEdit() )
|
||||||
DEFINE_METHOD( IsAPlayerEdit, IsAPlayerEdit() )
|
DEFINE_METHOD( IsAPlayerEdit, IsAPlayerEdit() )
|
||||||
|
|
||||||
|
static int HasSignificantTimingChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSignificantTimingChanges()); return 1; }
|
||||||
|
|
||||||
static int GetRadarValues( T* p, lua_State *L )
|
static int GetRadarValues( T* p, lua_State *L )
|
||||||
{
|
{
|
||||||
PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1);
|
PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1);
|
||||||
@@ -432,6 +451,12 @@ public:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetTimingData( T* p, lua_State *L )
|
||||||
|
{
|
||||||
|
p->m_Timing.PushSelf(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int GetHash( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHash() ); return 1; }
|
static int GetHash( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHash() ); return 1; }
|
||||||
|
|
||||||
// untested
|
// untested
|
||||||
@@ -443,6 +468,7 @@ public:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LunaSteps()
|
LunaSteps()
|
||||||
{
|
{
|
||||||
ADD_METHOD( GetAuthorCredit );
|
ADD_METHOD( GetAuthorCredit );
|
||||||
@@ -452,7 +478,9 @@ public:
|
|||||||
ADD_METHOD( GetFilename );
|
ADD_METHOD( GetFilename );
|
||||||
ADD_METHOD( GetHash );
|
ADD_METHOD( GetHash );
|
||||||
ADD_METHOD( GetMeter );
|
ADD_METHOD( GetMeter );
|
||||||
|
ADD_METHOD( HasSignificantTimingChanges );
|
||||||
ADD_METHOD( GetRadarValues );
|
ADD_METHOD( GetRadarValues );
|
||||||
|
ADD_METHOD( GetTimingData );
|
||||||
//ADD_METHOD( GetSMNoteData );
|
//ADD_METHOD( GetSMNoteData );
|
||||||
ADD_METHOD( GetStepsType );
|
ADD_METHOD( GetStepsType );
|
||||||
ADD_METHOD( IsAnEdit );
|
ADD_METHOD( IsAnEdit );
|
||||||
|
|||||||
+10
@@ -8,6 +8,8 @@
|
|||||||
#include "Difficulty.h"
|
#include "Difficulty.h"
|
||||||
#include "RageUtil_AutoPtr.h"
|
#include "RageUtil_AutoPtr.h"
|
||||||
#include "RageUtil_CachedObject.h"
|
#include "RageUtil_CachedObject.h"
|
||||||
|
#include "TimingData.h"
|
||||||
|
|
||||||
class Profile;
|
class Profile;
|
||||||
class NoteData;
|
class NoteData;
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
@@ -116,6 +118,14 @@ public:
|
|||||||
void TidyUpData();
|
void TidyUpData();
|
||||||
void CalculateRadarValues( float fMusicLengthSeconds );
|
void CalculateRadarValues( float fMusicLengthSeconds );
|
||||||
|
|
||||||
|
/** @brief Timing data */
|
||||||
|
TimingData m_Timing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determine if the Steps have any major timing changes during gameplay.
|
||||||
|
* @return true if it does, or false otherwise. */
|
||||||
|
bool HasSignificantTimingChanges() const;
|
||||||
|
|
||||||
// Lua
|
// Lua
|
||||||
void PushSelf( lua_State *L );
|
void PushSelf( lua_State *L );
|
||||||
|
|
||||||
|
|||||||
+348
-21
@@ -8,10 +8,16 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
|
||||||
TimingData::TimingData()
|
TimingData::TimingData() :
|
||||||
|
m_fBeat0OffsetInSeconds(0),
|
||||||
|
m_bHasNegativeBpms(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TimingData::TimingData(float fOffset) :
|
||||||
|
m_fBeat0OffsetInSeconds(fOffset),
|
||||||
|
m_bHasNegativeBpms(false)
|
||||||
{
|
{
|
||||||
m_fBeat0OffsetInSeconds = 0;
|
|
||||||
m_bHasNegativeBpms = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const
|
void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const
|
||||||
@@ -62,6 +68,16 @@ void TimingData::AddLabelSegment( const LabelSegment &seg )
|
|||||||
m_LabelSegments.insert( upper_bound(m_LabelSegments.begin(), m_LabelSegments.end(), seg), seg );
|
m_LabelSegments.insert( upper_bound(m_LabelSegments.begin(), m_LabelSegments.end(), seg), seg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimingData::AddSpeedSegment( const SpeedSegment &seg )
|
||||||
|
{
|
||||||
|
m_SpeedSegments.insert( upper_bound(m_SpeedSegments.begin(), m_SpeedSegments.end(), seg), seg );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimingData::AddFakeSegment( const FakeSegment &seg )
|
||||||
|
{
|
||||||
|
m_FakeSegments.insert( upper_bound(m_FakeSegments.begin(), m_FakeSegments.end(), seg), seg );
|
||||||
|
}
|
||||||
|
|
||||||
/* Change an existing BPM segment, merge identical segments together or insert a new one. */
|
/* Change an existing BPM segment, merge identical segments together or insert a new one. */
|
||||||
void TimingData::SetBPMAtRow( int iNoteRow, float fBPM )
|
void TimingData::SetBPMAtRow( int iNoteRow, float fBPM )
|
||||||
{
|
{
|
||||||
@@ -160,7 +176,7 @@ void TimingData::SetWarpAtRow( int iRow, float fNew )
|
|||||||
for( i=0; i<m_WarpSegments.size(); i++ )
|
for( i=0; i<m_WarpSegments.size(); i++ )
|
||||||
if( m_WarpSegments[i].m_iStartRow == iRow )
|
if( m_WarpSegments[i].m_iStartRow == iRow )
|
||||||
break;
|
break;
|
||||||
bool valid = iRow > 0 && NoteRowToBeat(iRow) < fNew;
|
bool valid = iRow > 0 && fNew > 0;
|
||||||
if( i == m_WarpSegments.size() )
|
if( i == m_WarpSegments.size() )
|
||||||
{
|
{
|
||||||
if( valid )
|
if( valid )
|
||||||
@@ -172,7 +188,7 @@ void TimingData::SetWarpAtRow( int iRow, float fNew )
|
|||||||
{
|
{
|
||||||
if( valid )
|
if( valid )
|
||||||
{
|
{
|
||||||
m_WarpSegments[i].m_fEndBeat = fNew;
|
m_WarpSegments[i].m_fLengthBeats = fNew;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 );
|
m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 );
|
||||||
@@ -244,6 +260,86 @@ void TimingData::SetLabelAtRow( int iRow, const RString sLabel )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimingData::SetSpeedAtRow( int iRow, float fPercent, float fWait, unsigned short usMode )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i = 0; i < m_SpeedSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
if( m_SpeedSegments[i].m_iStartRow >= iRow)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i == m_SpeedSegments.size() || m_SpeedSegments[i].m_iStartRow != iRow )
|
||||||
|
{
|
||||||
|
// the core mod itself matters the most for comparisons.
|
||||||
|
if( i == 0 || m_SpeedSegments[i-1].m_fPercent != fPercent )
|
||||||
|
AddSpeedSegment( SpeedSegment(iRow, fPercent, fWait, usMode) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The others aren't compared: only the mod itself matters.
|
||||||
|
if( i > 0 && m_SpeedSegments[i-1].m_fPercent == fPercent )
|
||||||
|
m_SpeedSegments.erase( m_SpeedSegments.begin()+i,
|
||||||
|
m_SpeedSegments.begin()+i+1 );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_SpeedSegments[i].m_fPercent = fPercent;
|
||||||
|
m_SpeedSegments[i].m_fWait = fWait;
|
||||||
|
m_SpeedSegments[i].m_usMode = usMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimingData::SetFakeAtRow( int iRow, float fNew )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i=0; i<m_FakeSegments.size(); i++ )
|
||||||
|
if( m_FakeSegments[i].m_iStartRow == iRow )
|
||||||
|
break;
|
||||||
|
bool valid = iRow > 0 && fNew > 0;
|
||||||
|
if( i == m_FakeSegments.size() )
|
||||||
|
{
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
AddFakeSegment( FakeSegment(iRow, fNew) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
m_FakeSegments[i].m_fLengthBeats = fNew;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_FakeSegments.erase( m_FakeSegments.begin()+i, m_FakeSegments.begin()+i+1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimingData::SetSpeedPercentAtRow( int iRow, float fPercent )
|
||||||
|
{
|
||||||
|
SetSpeedAtRow( iRow,
|
||||||
|
fPercent,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_fWait,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_usMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimingData::SetSpeedWaitAtRow( int iRow, float fWait )
|
||||||
|
{
|
||||||
|
SetSpeedAtRow( iRow,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_fPercent,
|
||||||
|
fWait,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_usMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimingData::SetSpeedModeAtRow( int iRow, unsigned short usMode )
|
||||||
|
{
|
||||||
|
SetSpeedAtRow( iRow,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_fPercent,
|
||||||
|
GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).m_fWait,
|
||||||
|
usMode );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float TimingData::GetStopAtRow( int iNoteRow, bool bDelay ) const
|
float TimingData::GetStopAtRow( int iNoteRow, bool bDelay ) const
|
||||||
{
|
{
|
||||||
for( unsigned i=0; i<m_StopSegments.size(); i++ )
|
for( unsigned i=0; i<m_StopSegments.size(); i++ )
|
||||||
@@ -283,7 +379,34 @@ float TimingData::GetWarpAtRow( int iWarpRow ) const
|
|||||||
{
|
{
|
||||||
if( m_WarpSegments[i].m_iStartRow == iWarpRow )
|
if( m_WarpSegments[i].m_iStartRow == iWarpRow )
|
||||||
{
|
{
|
||||||
return m_WarpSegments[i].m_fEndBeat;
|
return m_WarpSegments[i].m_fLengthBeats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TimingData::GetSpeedPercentAtRow( int iRow )
|
||||||
|
{
|
||||||
|
return GetSpeedSegmentAtRow( iRow ).m_fPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TimingData::GetSpeedWaitAtRow( int iRow )
|
||||||
|
{
|
||||||
|
return GetSpeedSegmentAtRow( iRow ).m_fWait;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short TimingData::GetSpeedModeAtRow( int iRow )
|
||||||
|
{
|
||||||
|
return GetSpeedSegmentAtRow( iRow ).m_usMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TimingData::GetFakeAtRow( int iFakeRow ) const
|
||||||
|
{
|
||||||
|
for( unsigned i=0; i<m_FakeSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
if( m_FakeSegments[i].m_iStartRow == iFakeRow )
|
||||||
|
{
|
||||||
|
return m_FakeSegments[i].m_fLengthBeats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -371,6 +494,18 @@ int TimingData::GetWarpSegmentIndexAtRow( int iNoteRow ) const
|
|||||||
return static_cast<int>(i);
|
return static_cast<int>(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TimingData::GetFakeSegmentIndexAtRow( int iNoteRow ) const
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i=0; i<m_FakeSegments.size()-1; i++ )
|
||||||
|
{
|
||||||
|
const FakeSegment& s = m_FakeSegments[i+1];
|
||||||
|
if( s.m_iStartRow > iNoteRow )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
bool TimingData::IsWarpAtRow( int iNoteRow ) const
|
bool TimingData::IsWarpAtRow( int iNoteRow ) const
|
||||||
{
|
{
|
||||||
if( m_WarpSegments.empty() )
|
if( m_WarpSegments.empty() )
|
||||||
@@ -378,7 +513,7 @@ bool TimingData::IsWarpAtRow( int iNoteRow ) const
|
|||||||
|
|
||||||
int i = GetWarpSegmentIndexAtRow( iNoteRow );
|
int i = GetWarpSegmentIndexAtRow( iNoteRow );
|
||||||
const WarpSegment& s = m_WarpSegments[i];
|
const WarpSegment& s = m_WarpSegments[i];
|
||||||
if( s.m_iStartRow <= iNoteRow && iNoteRow < BeatToNoteRow(s.m_fEndBeat) )
|
if( s.m_iStartRow <= iNoteRow && iNoteRow < (s.m_iStartRow + BeatToNoteRow(s.m_fLengthBeats) ) )
|
||||||
{
|
{
|
||||||
if( m_StopSegments.empty() )
|
if( m_StopSegments.empty() )
|
||||||
{
|
{
|
||||||
@@ -393,6 +528,20 @@ bool TimingData::IsWarpAtRow( int iNoteRow ) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TimingData::IsFakeAtRow( int iNoteRow ) const
|
||||||
|
{
|
||||||
|
if( m_FakeSegments.empty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int i = GetFakeSegmentIndexAtRow( iNoteRow );
|
||||||
|
const FakeSegment& s = m_FakeSegments[i];
|
||||||
|
if( s.m_iStartRow <= iNoteRow && iNoteRow < ( s.m_iStartRow + BeatToNoteRow(s.m_fLengthBeats) ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const
|
int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -426,6 +575,15 @@ int TimingData::GetLabelSegmentIndexAtRow( int iRow ) const
|
|||||||
return static_cast<int>(i);
|
return static_cast<int>(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TimingData::GetSpeedSegmentIndexAtRow( int iRow ) const
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i=0; i < m_SpeedSegments.size() - 1; i++ )
|
||||||
|
if( m_SpeedSegments[i+1].m_iStartRow > iRow )
|
||||||
|
break;
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow )
|
BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow )
|
||||||
{
|
{
|
||||||
static BPMSegment empty;
|
static BPMSegment empty;
|
||||||
@@ -445,6 +603,15 @@ TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtRow( int iRow )
|
|||||||
return m_vTimeSignatureSegments[i];
|
return m_vTimeSignatureSegments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpeedSegment& TimingData::GetSpeedSegmentAtRow( int iRow )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i=0; i<m_SpeedSegments.size()-1; i++ )
|
||||||
|
if( m_SpeedSegments[i+1].m_iStartRow > iRow )
|
||||||
|
break;
|
||||||
|
return m_SpeedSegments[i];
|
||||||
|
}
|
||||||
|
|
||||||
int TimingData::GetTimeSignatureNumeratorAtRow( int iRow )
|
int TimingData::GetTimeSignatureNumeratorAtRow( int iRow )
|
||||||
{
|
{
|
||||||
return GetTimeSignatureSegmentAtRow( iRow ).m_iNumerator;
|
return GetTimeSignatureSegmentAtRow( iRow ).m_iNumerator;
|
||||||
@@ -493,6 +660,16 @@ WarpSegment& TimingData::GetWarpSegmentAtRow( int iRow )
|
|||||||
return m_WarpSegments[i];
|
return m_WarpSegments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FakeSegment& TimingData::GetFakeSegmentAtRow( int iRow )
|
||||||
|
{
|
||||||
|
static FakeSegment empty;
|
||||||
|
if( m_FakeSegments.empty() )
|
||||||
|
return empty;
|
||||||
|
|
||||||
|
int i = GetFakeSegmentIndexAtRow( iRow );
|
||||||
|
return m_FakeSegments[i];
|
||||||
|
}
|
||||||
|
|
||||||
int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const
|
int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -652,16 +829,19 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FOUND_WARP:
|
case FOUND_WARP:
|
||||||
bIsWarping = true;
|
|
||||||
if( itWS->m_fEndBeat > fWarpDestination )
|
|
||||||
{
|
{
|
||||||
fWarpDestination = itWS->m_fEndBeat;
|
bIsWarping = true;
|
||||||
|
float fWarpSum = itWS->m_fLengthBeats + NoteRowToBeat( itWS->m_iStartRow );
|
||||||
|
if( fWarpSum > fWarpDestination )
|
||||||
|
{
|
||||||
|
fWarpDestination = fWarpSum;
|
||||||
}
|
}
|
||||||
iWarpBeginOut = iEventRow;
|
iWarpBeginOut = iEventRow;
|
||||||
fWarpDestinationOut = fWarpDestination;
|
fWarpDestinationOut = fWarpDestination;
|
||||||
itWS ++;
|
itWS ++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
iLastRow = iEventRow;
|
iLastRow = iEventRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,14 +924,17 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const
|
|||||||
case FOUND_MARKER:
|
case FOUND_MARKER:
|
||||||
return fLastTime;
|
return fLastTime;
|
||||||
case FOUND_WARP:
|
case FOUND_WARP:
|
||||||
bIsWarping = true;
|
|
||||||
if( itWS->m_fEndBeat > fWarpDestination )
|
|
||||||
{
|
{
|
||||||
fWarpDestination = itWS->m_fEndBeat;
|
bIsWarping = true;
|
||||||
|
float fWarpSum = itWS->m_fLengthBeats + NoteRowToBeat( itWS->m_iStartRow );
|
||||||
|
if( fWarpSum > fWarpDestination )
|
||||||
|
{
|
||||||
|
fWarpDestination = fWarpSum;
|
||||||
}
|
}
|
||||||
itWS ++;
|
itWS ++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
iLastRow = iEventRow;
|
iLastRow = iEventRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,13 +973,13 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool
|
|||||||
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
const int iSegStartRow = m_WarpSegments[i].m_iStartRow;
|
const int iSegStartRow = m_WarpSegments[i].m_iStartRow;
|
||||||
const int iSegEndRow = BeatToNoteRow( m_WarpSegments[i].m_fEndBeat );
|
const int iSegEndRow = iSegStartRow + BeatToNoteRow( m_WarpSegments[i].m_fLengthBeats );
|
||||||
if( iSegEndRow >= iStartIndex )
|
if( iSegEndRow >= iStartIndex )
|
||||||
{
|
{
|
||||||
if( iSegEndRow > iEndIndex )
|
if( iSegEndRow > iEndIndex )
|
||||||
m_WarpSegments[i].m_fEndBeat += NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
|
m_WarpSegments[i].m_fLengthBeats += NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
|
||||||
else
|
else
|
||||||
m_WarpSegments[i].m_fEndBeat = NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale) + iStartIndex);
|
m_WarpSegments[i].m_fLengthBeats = NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale));
|
||||||
}
|
}
|
||||||
if( iSegStartRow < iStartIndex )
|
if( iSegStartRow < iStartIndex )
|
||||||
continue;
|
continue;
|
||||||
@@ -839,6 +1022,36 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool
|
|||||||
m_LabelSegments[i].m_iStartRow = lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex;
|
m_LabelSegments[i].m_iStartRow = lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ( unsigned i = 0; i < m_SpeedSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const int iSegStart = m_SpeedSegments[i].m_iStartRow;
|
||||||
|
if( iSegStart < iStartIndex )
|
||||||
|
continue;
|
||||||
|
else if( iSegStart > iEndIndex )
|
||||||
|
m_SpeedSegments[i].m_iStartRow += lrintf( (iEndIndex - iStartIndex) * (fScale - 1) );
|
||||||
|
else
|
||||||
|
m_SpeedSegments[i].m_iStartRow = lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_FakeSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const int iSegStartRow = m_FakeSegments[i].m_iStartRow;
|
||||||
|
const int iSegEndRow = iSegStartRow + BeatToNoteRow( m_FakeSegments[i].m_fLengthBeats );
|
||||||
|
if( iSegEndRow >= iStartIndex )
|
||||||
|
{
|
||||||
|
if( iSegEndRow > iEndIndex )
|
||||||
|
m_FakeSegments[i].m_fLengthBeats += NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
|
||||||
|
else
|
||||||
|
m_FakeSegments[i].m_fLengthBeats = NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale));
|
||||||
|
}
|
||||||
|
if( iSegStartRow < iStartIndex )
|
||||||
|
continue;
|
||||||
|
else if( iSegStartRow > iEndIndex )
|
||||||
|
m_FakeSegments[i].m_iStartRow += lrintf((iEndIndex - iStartIndex) * (fScale - 1));
|
||||||
|
else
|
||||||
|
m_FakeSegments[i].m_iStartRow = lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex;
|
||||||
|
}
|
||||||
|
|
||||||
// adjust BPM changes to preserve timing
|
// adjust BPM changes to preserve timing
|
||||||
if( bAdjustBPM )
|
if( bAdjustBPM )
|
||||||
{
|
{
|
||||||
@@ -886,8 +1099,6 @@ void TimingData::InsertRows( int iStartRow, int iRowsToAdd )
|
|||||||
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
WarpSegment &warp = m_WarpSegments[i];
|
WarpSegment &warp = m_WarpSegments[i];
|
||||||
if( BeatToNoteRow(warp.m_fEndBeat) >= iStartRow )
|
|
||||||
warp.m_fEndBeat += NoteRowToBeat(iRowsToAdd);
|
|
||||||
if( warp.m_iStartRow < iStartRow )
|
if( warp.m_iStartRow < iStartRow )
|
||||||
continue;
|
continue;
|
||||||
warp.m_iStartRow += iRowsToAdd;
|
warp.m_iStartRow += iRowsToAdd;
|
||||||
@@ -924,6 +1135,22 @@ void TimingData::InsertRows( int iStartRow, int iRowsToAdd )
|
|||||||
labl.m_iStartRow += iRowsToAdd;
|
labl.m_iStartRow += iRowsToAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_SpeedSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
SpeedSegment &sped = m_SpeedSegments[i];
|
||||||
|
if( sped.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
sped.m_iStartRow += iRowsToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_FakeSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
FakeSegment &fake = m_FakeSegments[i];
|
||||||
|
if( fake.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
fake.m_iStartRow += iRowsToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
if( iStartRow == 0 )
|
if( iStartRow == 0 )
|
||||||
{
|
{
|
||||||
/* If we're shifting up at the beginning, we just shifted up the first
|
/* If we're shifting up at the beginning, we just shifted up the first
|
||||||
@@ -985,9 +1212,6 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete )
|
|||||||
{
|
{
|
||||||
WarpSegment &warp = m_WarpSegments[i];
|
WarpSegment &warp = m_WarpSegments[i];
|
||||||
|
|
||||||
if( BeatToNoteRow(warp.m_fEndBeat) >= iStartRow )
|
|
||||||
warp.m_fEndBeat = max( NoteRowToBeat(iStartRow), warp.m_fEndBeat - NoteRowToBeat(iRowsToDelete) );
|
|
||||||
|
|
||||||
if( warp.m_iStartRow < iStartRow )
|
if( warp.m_iStartRow < iStartRow )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1081,9 +1305,98 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete )
|
|||||||
labl.m_iStartRow -= iRowsToDelete;
|
labl.m_iStartRow -= iRowsToDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_SpeedSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
SpeedSegment &sped = m_SpeedSegments[i];
|
||||||
|
|
||||||
|
if( sped.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( sped.m_iStartRow < iStartRow+iRowsToDelete )
|
||||||
|
{
|
||||||
|
m_SpeedSegments.erase( m_SpeedSegments.begin()+i, m_SpeedSegments.begin()+i+1 );
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sped.m_iStartRow -= iRowsToDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_FakeSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
FakeSegment &fake = m_FakeSegments[i];
|
||||||
|
|
||||||
|
if( fake.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( fake.m_iStartRow < iStartRow+iRowsToDelete )
|
||||||
|
{
|
||||||
|
m_FakeSegments.erase( m_FakeSegments.begin()+i, m_FakeSegments.begin()+i+1 );
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fake.m_iStartRow -= iRowsToDelete;
|
||||||
|
}
|
||||||
|
|
||||||
this->SetBPMAtRow( iStartRow, fNewBPM );
|
this->SetBPMAtRow( iStartRow, fNewBPM );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimingData::TidyUpData()
|
||||||
|
{
|
||||||
|
// If there are no BPM segments, provide a default.
|
||||||
|
if( m_BPMSegments.empty() )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", m_sFile, "has no BPM segments, default provided." );
|
||||||
|
|
||||||
|
AddBPMSegment( BPMSegment(0, 60) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the first BPM segment starts at beat 0.
|
||||||
|
if( m_BPMSegments[0].m_iStartRow != 0 )
|
||||||
|
m_BPMSegments[0].m_iStartRow = 0;
|
||||||
|
|
||||||
|
// If no time signature specified, assume 4/4 time for the whole song.
|
||||||
|
if( m_vTimeSignatureSegments.empty() )
|
||||||
|
{
|
||||||
|
TimeSignatureSegment seg(0, 4, 4);
|
||||||
|
m_vTimeSignatureSegments.push_back( seg );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Likewise, if no tickcount signature is specified, assume 2 ticks
|
||||||
|
//per beat for the entire song. The default of 2 is chosen more
|
||||||
|
//for compatibility with the Pump Pro series than anything else.
|
||||||
|
if( m_TickcountSegments.empty() )
|
||||||
|
{
|
||||||
|
TickcountSegment seg(0, 2);
|
||||||
|
m_TickcountSegments.push_back( seg );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have a default combo segment of one just in case.
|
||||||
|
if( m_ComboSegments.empty() )
|
||||||
|
{
|
||||||
|
ComboSegment seg(0, 1);
|
||||||
|
m_ComboSegments.push_back( seg );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have a default label segment just in case.
|
||||||
|
if( m_LabelSegments.empty() )
|
||||||
|
{
|
||||||
|
LabelSegment seg(0, "Song Start");
|
||||||
|
m_LabelSegments.push_back( seg );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always be sure there is a starting speed.
|
||||||
|
if( m_SpeedSegments.empty() )
|
||||||
|
{
|
||||||
|
SpeedSegment seg(0, 1, 0);
|
||||||
|
m_SpeedSegments.push_back( seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool TimingData::HasBpmChanges() const
|
bool TimingData::HasBpmChanges() const
|
||||||
{
|
{
|
||||||
return m_BPMSegments.size()>1;
|
return m_BPMSegments.size()>1;
|
||||||
@@ -1099,6 +1412,16 @@ bool TimingData::HasWarps() const
|
|||||||
return m_WarpSegments.size()>0;
|
return m_WarpSegments.size()>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TimingData::HasFakes() const
|
||||||
|
{
|
||||||
|
return m_FakeSegments.size()>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimingData::HasSpeedChanges() const
|
||||||
|
{
|
||||||
|
return m_SpeedSegments.size()>1;
|
||||||
|
}
|
||||||
|
|
||||||
void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const
|
void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const
|
||||||
{
|
{
|
||||||
iMeasureIndexOut = 0;
|
iMeasureIndexOut = 0;
|
||||||
@@ -1145,6 +1468,8 @@ public:
|
|||||||
static int HasStops( T* p, lua_State *L ) { lua_pushboolean(L, p->HasStops()); return 1; }
|
static int HasStops( T* p, lua_State *L ) { lua_pushboolean(L, p->HasStops()); return 1; }
|
||||||
static int HasBPMChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBpmChanges()); return 1; }
|
static int HasBPMChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBpmChanges()); return 1; }
|
||||||
static int HasWarps( T* p, lua_State *L ) { lua_pushboolean(L, p->HasWarps()); return 1; }
|
static int HasWarps( T* p, lua_State *L ) { lua_pushboolean(L, p->HasWarps()); return 1; }
|
||||||
|
static int HasFakes( T* p, lua_State *L ) { lua_pushboolean(L, p->HasFakes()); return 1; }
|
||||||
|
static int HasSpeedChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSpeedChanges()); return 1; }
|
||||||
static int GetStops( T* p, lua_State *L )
|
static int GetStops( T* p, lua_State *L )
|
||||||
{
|
{
|
||||||
vector<RString> vStops;
|
vector<RString> vStops;
|
||||||
@@ -1232,6 +1557,8 @@ public:
|
|||||||
ADD_METHOD( HasStops );
|
ADD_METHOD( HasStops );
|
||||||
ADD_METHOD( HasBPMChanges );
|
ADD_METHOD( HasBPMChanges );
|
||||||
ADD_METHOD( HasWarps );
|
ADD_METHOD( HasWarps );
|
||||||
|
ADD_METHOD( HasFakes );
|
||||||
|
ADD_METHOD( HasSpeedChanges );
|
||||||
ADD_METHOD( GetStops );
|
ADD_METHOD( GetStops );
|
||||||
ADD_METHOD( GetDelays );
|
ADD_METHOD( GetDelays );
|
||||||
ADD_METHOD( GetBPMs );
|
ADD_METHOD( GetBPMs );
|
||||||
|
|||||||
+470
-18
@@ -313,8 +313,8 @@ struct TimeSignatureSegment
|
|||||||
*
|
*
|
||||||
* A warp segment is used to replicate the effects of Negative BPMs without
|
* A warp segment is used to replicate the effects of Negative BPMs without
|
||||||
* abusing negative BPMs. Negative BPMs should be converted to warp segments.
|
* abusing negative BPMs. Negative BPMs should be converted to warp segments.
|
||||||
* WarpAt=WarpTo is the format, where both are in beats. (Technically they're
|
* WarpAt=WarpToRelative is the format, where both are in beats.
|
||||||
* both rows though.) */
|
* (Technically they're both rows though.) */
|
||||||
struct WarpSegment
|
struct WarpSegment
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -322,45 +322,45 @@ struct WarpSegment
|
|||||||
*
|
*
|
||||||
* It is best to override the values as soon as possible.
|
* It is best to override the values as soon as possible.
|
||||||
*/
|
*/
|
||||||
WarpSegment() : m_iStartRow(-1), m_fEndBeat(-1) { }
|
WarpSegment() : m_iStartRow(-1), m_fLengthBeats(-1) { }
|
||||||
/**
|
/**
|
||||||
* @brief Create a Warp Segment with the specified starting row and row to warp to.
|
* @brief Create a Warp Segment with the specified starting row and row to warp to.
|
||||||
* @param s the starting row of this segment.
|
* @param s the starting row of this segment.
|
||||||
* @param r the row to warp to.
|
* @param r the number of rows to jump ahead.
|
||||||
*/
|
*/
|
||||||
WarpSegment( int s, int r ): m_iStartRow(max(0, (s < r ? s : r))),
|
WarpSegment( int s, int r ): m_iStartRow(s),
|
||||||
m_fEndBeat(max(0, NoteRowToBeat((r > s ? r : s)))) {}
|
m_fLengthBeats(NoteRowToBeat(r)) {}
|
||||||
/**
|
/**
|
||||||
* @brief Creates a Warp Segment with the specified starting row and beat to warp to.
|
* @brief Creates a Warp Segment with the specified starting row and beat to warp to.
|
||||||
* @param s the starting row of this segment.
|
* @param s the starting row of this segment.
|
||||||
* @param b the beat to warp to.
|
* @param b the number of beats to jump ahead.
|
||||||
*/
|
*/
|
||||||
WarpSegment( int s, float b ): m_iStartRow(max(0, s)),
|
WarpSegment( int s, float b ): m_iStartRow(max(0, s)),
|
||||||
m_fEndBeat(max(0, b)) {}
|
m_fLengthBeats(max(0, b)) {}
|
||||||
/**
|
/**
|
||||||
* @brief Create a Warp Segment with the specified starting beat and row to warp to.
|
* @brief Create a Warp Segment with the specified starting beat and row to warp to.
|
||||||
* @param s the starting beat in this segment.
|
* @param s the starting beat in this segment.
|
||||||
* @param r the row to warp to.
|
* @param r the number of rows to jump ahead.
|
||||||
*/
|
*/
|
||||||
WarpSegment( float s, int r ):
|
WarpSegment( float s, int r ):
|
||||||
m_iStartRow(max(0, BeatToNoteRow(s))),
|
m_iStartRow(max(0, BeatToNoteRow(s))),
|
||||||
m_fEndBeat(max(0, NoteRowToBeat(r))) {}
|
m_fLengthBeats(max(0, NoteRowToBeat(r))) {}
|
||||||
/**
|
/**
|
||||||
* @brief Creates a Warp Segment with the specified starting beat and beat to warp to.
|
* @brief Creates a Warp Segment with the specified starting beat and beat to warp to.
|
||||||
* @param s the starting beat of this segment.
|
* @param s the starting beat of this segment.
|
||||||
* @param b the beat to warp to.
|
* @param b the number of beats to jump ahead.
|
||||||
*/
|
*/
|
||||||
WarpSegment( float s, float b ):
|
WarpSegment( float s, float b ):
|
||||||
m_iStartRow(max(0, BeatToNoteRow((s < b ? s : b)))),
|
m_iStartRow(BeatToNoteRow(s)),
|
||||||
m_fEndBeat(max(0, (b > s ? b : s))) {}
|
m_fLengthBeats(b) {}
|
||||||
/**
|
/**
|
||||||
* @brief The row in which the WarpSegment activates.
|
* @brief The row in which the WarpSegment activates.
|
||||||
*/
|
*/
|
||||||
int m_iStartRow;
|
int m_iStartRow;
|
||||||
/**
|
/**
|
||||||
* @brief The beat to warp to.
|
* @brief The number of beats to warp ahead by.
|
||||||
*/
|
*/
|
||||||
float m_fEndBeat;
|
float m_fLengthBeats;
|
||||||
/**
|
/**
|
||||||
* @brief Compares two WarpSegments to see if they are equal to each other.
|
* @brief Compares two WarpSegments to see if they are equal to each other.
|
||||||
* @param other the other WarpSegment to compare to.
|
* @param other the other WarpSegment to compare to.
|
||||||
@@ -369,7 +369,7 @@ struct WarpSegment
|
|||||||
bool operator==( const WarpSegment &other ) const
|
bool operator==( const WarpSegment &other ) const
|
||||||
{
|
{
|
||||||
COMPARE( m_iStartRow );
|
COMPARE( m_iStartRow );
|
||||||
COMPARE( m_fEndBeat );
|
COMPARE( m_fLengthBeats );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -386,7 +386,7 @@ struct WarpSegment
|
|||||||
bool operator<( const WarpSegment &other ) const
|
bool operator<( const WarpSegment &other ) const
|
||||||
{
|
{
|
||||||
return m_iStartRow < other.m_iStartRow ||
|
return m_iStartRow < other.m_iStartRow ||
|
||||||
( m_iStartRow == other.m_iStartRow && m_fEndBeat < other.m_fEndBeat );
|
( m_iStartRow == other.m_iStartRow && m_fLengthBeats < other.m_fLengthBeats );
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Compares two WarpSegments to see if one is less than or equal to the other.
|
* @brief Compares two WarpSegments to see if one is less than or equal to the other.
|
||||||
@@ -508,7 +508,7 @@ struct ComboSegment
|
|||||||
* @param t the amount the combo increases on a succesful hit.
|
* @param t the amount the combo increases on a succesful hit.
|
||||||
*/
|
*/
|
||||||
ComboSegment( int s, int t ): m_iStartRow(max(0, s)),
|
ComboSegment( int s, int t ): m_iStartRow(max(0, s)),
|
||||||
m_iCombo(max(1,t)) {}
|
m_iCombo(max(0,t)) {}
|
||||||
/**
|
/**
|
||||||
* @brief The row in which the ComboSegment activates.
|
* @brief The row in which the ComboSegment activates.
|
||||||
*/
|
*/
|
||||||
@@ -647,6 +647,243 @@ struct LabelSegment
|
|||||||
bool operator>=( const LabelSegment &other ) const { return !operator<(other); }
|
bool operator>=( const LabelSegment &other ) const { return !operator<(other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Identifies when the arrow scroll changes.
|
||||||
|
*
|
||||||
|
* SpeedSegments take a Player's scrolling BPM (Step's BPM * speed mod),
|
||||||
|
* and then multiplies it with the percentage value. No matter the player's
|
||||||
|
* speed mod, the ratio will be the same. Unlike forced attacks, these
|
||||||
|
* cannot be turned off at a set time: reset it by setting the precentage
|
||||||
|
* back to 1.
|
||||||
|
*
|
||||||
|
* These were inspired by the Pump It Up series. */
|
||||||
|
struct SpeedSegment
|
||||||
|
{
|
||||||
|
/** @brief Sets up the SpeedSegment with default values. */
|
||||||
|
SpeedSegment(): m_iStartRow(0),
|
||||||
|
m_fPercent(1), m_fWait(0), m_usMode(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param i The row this activates.
|
||||||
|
* @param p The percentage to use. */
|
||||||
|
SpeedSegment(int i, float p): m_iStartRow(0),
|
||||||
|
m_fPercent(p), m_fWait(0), m_usMode(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param r The beat this activates.
|
||||||
|
* @param p The percentage to use. */
|
||||||
|
SpeedSegment(float r, float p): m_iStartRow(BeatToNoteRow(r)),
|
||||||
|
m_fPercent(p), m_fWait(0), m_usMode(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param i The row this activates.
|
||||||
|
* @param p The percentage to use.
|
||||||
|
* @param w The number of beats to wait. */
|
||||||
|
SpeedSegment(int i, float p, float w): m_iStartRow(i),
|
||||||
|
m_fPercent(p), m_fWait(w), m_usMode(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param r The beat this activates.
|
||||||
|
* @param p The percentage to use.
|
||||||
|
* @param w The number of beats to wait. */
|
||||||
|
SpeedSegment(float r, float p, float w): m_iStartRow(BeatToNoteRow(r)),
|
||||||
|
m_fPercent(p), m_fWait(w), m_usMode(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param i The row this activates.
|
||||||
|
* @param p The percentage to use.
|
||||||
|
* @param w The number of beats/seconds to wait.
|
||||||
|
* @param k The mode used for the wait variable. */
|
||||||
|
SpeedSegment(int i, float p, float w, unsigned short k): m_iStartRow(i),
|
||||||
|
m_fPercent(p), m_fWait(w), m_usMode(k) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets up the SpeedSegment with specified values.
|
||||||
|
* @param r The beat this activates.
|
||||||
|
* @param p The percentage to use.
|
||||||
|
* @param w The number of beats/seconds to wait.
|
||||||
|
* @param k The mode used for the wait variable.*/
|
||||||
|
SpeedSegment(float r, float p, float w, unsigned short k): m_iStartRow(BeatToNoteRow(r)),
|
||||||
|
m_fPercent(p), m_fWait(w), m_usMode(k) {}
|
||||||
|
|
||||||
|
/** @brief The row in which the ComboSegment activates. */
|
||||||
|
int m_iStartRow;
|
||||||
|
/** @brief The percentage to use when multiplying the Player's BPM. */
|
||||||
|
float m_fPercent;
|
||||||
|
/**
|
||||||
|
* @brief The number of beats or seconds to wait for the change to take place.
|
||||||
|
*
|
||||||
|
* A value of 0 means this is immediate. */
|
||||||
|
float m_fWait;
|
||||||
|
/**
|
||||||
|
* @brief The mode that this segment uses for the math.
|
||||||
|
*
|
||||||
|
* 0: beats
|
||||||
|
* 1: seconds
|
||||||
|
* other
|
||||||
|
*/
|
||||||
|
unsigned short m_usMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if they are equal to each other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the equality of the two segments.
|
||||||
|
*/
|
||||||
|
bool operator==( const SpeedSegment &other ) const
|
||||||
|
{
|
||||||
|
COMPARE( m_iStartRow );
|
||||||
|
COMPARE( m_fPercent );
|
||||||
|
COMPARE( m_usMode );
|
||||||
|
COMPARE( m_fWait );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if they are not equal to each other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the inequality of the two segments.
|
||||||
|
*/
|
||||||
|
bool operator!=( const SpeedSegment &other ) const { return !operator==(other); }
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if one is less than the other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is less than the second.
|
||||||
|
*/
|
||||||
|
bool operator<( const SpeedSegment &other ) const { return m_iStartRow < other.m_iStartRow; }
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if one is less than or equal to the other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is less or equal to than the second.
|
||||||
|
*/
|
||||||
|
bool operator<=( const SpeedSegment &other ) const
|
||||||
|
{
|
||||||
|
return ( operator<(other) || operator==(other) );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if one is greater than the other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is greater than the second.
|
||||||
|
*/
|
||||||
|
bool operator>( const SpeedSegment &other ) const { return !operator<=(other); }
|
||||||
|
/**
|
||||||
|
* @brief Compares two SpeedSegments to see if one is greater than or equal to the other.
|
||||||
|
* @param other the other SpeedSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is greater than or equal to the second.
|
||||||
|
*/
|
||||||
|
bool operator>=( const SpeedSegment &other ) const { return !operator<(other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Identifies when a whole region of arrows is to be ignored.
|
||||||
|
*
|
||||||
|
* FakeSegments are similar to the Fake Tap Notes in that the contents
|
||||||
|
* inside are neither for nor against the player. They can be useful for
|
||||||
|
* mission modes, in conjunction with WarpSegments, or perhaps other
|
||||||
|
* uses not thought up at the time of this comment. Unlike the Warp
|
||||||
|
* Segments, these are not magically jumped over: instead, these are
|
||||||
|
* drawn normally.
|
||||||
|
*
|
||||||
|
* These were inspired by the Pump It Up series. */
|
||||||
|
struct FakeSegment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Create a simple Fake Segment with default values.
|
||||||
|
*
|
||||||
|
* It is best to override the values as soon as possible.
|
||||||
|
*/
|
||||||
|
FakeSegment() : m_iStartRow(-1), m_fLengthBeats(-1) { }
|
||||||
|
/**
|
||||||
|
* @brief Create a Fake Segment with the specified values.
|
||||||
|
* @param s the starting row of this segment.
|
||||||
|
* @param r the number of rows this segment lasts.
|
||||||
|
*/
|
||||||
|
FakeSegment( int s, int r ): m_iStartRow(s),
|
||||||
|
m_fLengthBeats(NoteRowToBeat(r)) {}
|
||||||
|
/**
|
||||||
|
* @brief Creates a Fake Segment with the specified values.
|
||||||
|
* @param s the starting row of this segment.
|
||||||
|
* @param b the number of beats this segment lasts.
|
||||||
|
*/
|
||||||
|
FakeSegment( int s, float b ): m_iStartRow(max(0, s)),
|
||||||
|
m_fLengthBeats(max(0, b)) {}
|
||||||
|
/**
|
||||||
|
* @brief Create a Fake Segment with the specified values.
|
||||||
|
* @param s the starting beat in this segment.
|
||||||
|
* @param r the number of rows this segment lasts.
|
||||||
|
*/
|
||||||
|
FakeSegment( float s, int r ):
|
||||||
|
m_iStartRow(max(0, BeatToNoteRow(s))),
|
||||||
|
m_fLengthBeats(max(0, NoteRowToBeat(r))) {}
|
||||||
|
/**
|
||||||
|
* @brief Creates a Fake Segment with the specified values.
|
||||||
|
* @param s the starting beat of this segment.
|
||||||
|
* @param b the number of beats this segment lasts.
|
||||||
|
*/
|
||||||
|
FakeSegment( float s, float b ):
|
||||||
|
m_iStartRow(BeatToNoteRow(s)),
|
||||||
|
m_fLengthBeats(b) {}
|
||||||
|
/**
|
||||||
|
* @brief The row in which the FakeSegment activates.
|
||||||
|
*/
|
||||||
|
int m_iStartRow;
|
||||||
|
/**
|
||||||
|
* @brief The number of beats the FakeSegment is alive for.
|
||||||
|
*/
|
||||||
|
float m_fLengthBeats;
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if they are equal to each other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the equality of the two segments.
|
||||||
|
*/
|
||||||
|
bool operator==( const FakeSegment &other ) const
|
||||||
|
{
|
||||||
|
COMPARE( m_iStartRow );
|
||||||
|
COMPARE( m_fLengthBeats );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if they are not equal to each other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the inequality of the two segments.
|
||||||
|
*/
|
||||||
|
bool operator!=( const FakeSegment &other ) const { return !operator==(other); }
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if one is less than the other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is less than the second.
|
||||||
|
*/
|
||||||
|
bool operator<( const FakeSegment &other ) const
|
||||||
|
{
|
||||||
|
return m_iStartRow < other.m_iStartRow ||
|
||||||
|
( m_iStartRow == other.m_iStartRow && m_fLengthBeats < other.m_fLengthBeats );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if one is less than or equal to the other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is less or equal to than the second.
|
||||||
|
*/
|
||||||
|
bool operator<=( const FakeSegment &other ) const
|
||||||
|
{
|
||||||
|
return ( operator<(other) || operator==(other) );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if one is greater than the other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is greater than the second.
|
||||||
|
*/
|
||||||
|
bool operator>( const FakeSegment &other ) const { return !operator<=(other); }
|
||||||
|
/**
|
||||||
|
* @brief Compares two FakeSegments to see if one is greater than or equal to the other.
|
||||||
|
* @param other the other FakeSegment to compare to.
|
||||||
|
* @return the truth/falsehood of if the first is greater than or equal to the second.
|
||||||
|
*/
|
||||||
|
bool operator>=( const FakeSegment &other ) const { return !operator<(other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Holds data for translating beats<->seconds.
|
* @brief Holds data for translating beats<->seconds.
|
||||||
@@ -658,6 +895,10 @@ public:
|
|||||||
* @brief Sets up initial timing data.
|
* @brief Sets up initial timing data.
|
||||||
*/
|
*/
|
||||||
TimingData();
|
TimingData();
|
||||||
|
/**
|
||||||
|
* @brief Sets up initial timing data with a defined offset.
|
||||||
|
* @param fOffset the offset from the 0th beat. */
|
||||||
|
TimingData(float fOffset);
|
||||||
/**
|
/**
|
||||||
* @brief Gets the actual BPM of the song.
|
* @brief Gets the actual BPM of the song.
|
||||||
* @param fMinBPMOut the minimium specified BPM.
|
* @param fMinBPMOut the minimium specified BPM.
|
||||||
@@ -1234,6 +1475,193 @@ public:
|
|||||||
*/
|
*/
|
||||||
float GetNextLabelSegmentBeatAtBeat( float fBeat ) const { return GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); }
|
float GetNextLabelSegmentBeatAtBeat( float fBeat ) const { return GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's percent at the given row.
|
||||||
|
* @param iNoteRow the row in question.
|
||||||
|
* @return the percent.
|
||||||
|
*/
|
||||||
|
float GetSpeedPercentAtRow( int iNoteRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's percent at the given beat.
|
||||||
|
* @param fBeat the beat in question.
|
||||||
|
* @return the percent.
|
||||||
|
*/
|
||||||
|
float GetSpeedPercentAtBeat( float fBeat ) { return GetSpeedPercentAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's wait at the given row.
|
||||||
|
* @param iNoteRow the row in question.
|
||||||
|
* @return the wait.
|
||||||
|
*/
|
||||||
|
float GetSpeedWaitAtRow( int iNoteRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's wait at the given beat.
|
||||||
|
* @param fBeat the beat in question.
|
||||||
|
* @return the wait.
|
||||||
|
*/
|
||||||
|
float GetSpeedWaitAtBeat( float fBeat ) { return GetSpeedWaitAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's mode at the given row.
|
||||||
|
* @param iNoteRow the row in question.
|
||||||
|
* @return the mode.
|
||||||
|
*/
|
||||||
|
unsigned short GetSpeedModeAtRow( int iNoteRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Speed's mode at the given beat.
|
||||||
|
* @param fBeat the beat in question.
|
||||||
|
* @return the mode.
|
||||||
|
*/
|
||||||
|
unsigned short GetSpeedModeAtBeat( float fBeat ) { return GetSpeedModeAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
/**
|
||||||
|
* @brief Set the row to have the new Speed.
|
||||||
|
* @param iNoteRow the row to have the new Speed.
|
||||||
|
* @param fPercent the percent.
|
||||||
|
* @param fWait the wait.
|
||||||
|
* @param usMode the mode.
|
||||||
|
*/
|
||||||
|
void SetSpeedAtRow( int iNoteRow, float fPercent, float fWait, unsigned short usMode );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to have the new Speed.
|
||||||
|
* @param fBeat the beat to have the new Speed.
|
||||||
|
* @param fPercent the percent.
|
||||||
|
* @param fWait the wait.
|
||||||
|
* @param usMode the mode.
|
||||||
|
*/
|
||||||
|
void SetSpeedAtBeat( float fBeat, float fPercent, float fWait, unsigned short usMode ) { SetSpeedAtRow( BeatToNoteRow(fBeat), fPercent, fWait, usMode ); }
|
||||||
|
/**
|
||||||
|
* @brief Set the row to have the new Speed percent.
|
||||||
|
* @param iNoteRow the row to have the new Speed percent.
|
||||||
|
* @param fPercent the percent.
|
||||||
|
*/
|
||||||
|
void SetSpeedPercentAtRow( int iNoteRow, float fPercent );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to have the new Speed percent.
|
||||||
|
* @param fBeat the beat to have the new Speed percent.
|
||||||
|
* @param fPercent the percent.
|
||||||
|
*/
|
||||||
|
void SetSpeedPercentAtBeat( float fBeat, float fPercent ) { SetSpeedPercentAtRow( BeatToNoteRow(fBeat), fPercent); }
|
||||||
|
/**
|
||||||
|
* @brief Set the row to have the new Speed wait.
|
||||||
|
* @param iNoteRow the row to have the new Speed wait.
|
||||||
|
* @param fWait the wait.
|
||||||
|
*/
|
||||||
|
void SetSpeedWaitAtRow( int iNoteRow, float fWait );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to have the new Speed wait.
|
||||||
|
* @param fBeat the beat to have the new Speed wait.
|
||||||
|
* @param fWait the wait.
|
||||||
|
*/
|
||||||
|
void SetSpeedWaitAtBeat( float fBeat, float fWait ) { SetSpeedWaitAtRow( BeatToNoteRow(fBeat), fWait); }
|
||||||
|
/**
|
||||||
|
* @brief Set the row to have the new Speed mode.
|
||||||
|
* @param iNoteRow the row to have the new Speed mode.
|
||||||
|
* @param usMode the mode.
|
||||||
|
*/
|
||||||
|
void SetSpeedModeAtRow( int iNoteRow, unsigned short usMode );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to have the new Speed mode.
|
||||||
|
* @param fBeat the beat to have the new Speed mode.
|
||||||
|
* @param usMode the mode.
|
||||||
|
*/
|
||||||
|
void SetSpeedModeAtBeat( float fBeat, unsigned short usMode ) { SetSpeedModeAtRow( BeatToNoteRow(fBeat), usMode); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the SpeedSegment at the specified row.
|
||||||
|
* @param iNoteRow the row that has a SpeedSegment.
|
||||||
|
* @return the SpeedSegment in question.
|
||||||
|
*/
|
||||||
|
SpeedSegment& GetSpeedSegmentAtRow( int iNoteRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the SpeedSegment at the specified beat.
|
||||||
|
* @param fBeat the beat that has a SpeedSegment.
|
||||||
|
* @return the SpeedSegment in question.
|
||||||
|
*/
|
||||||
|
SpeedSegment& GetSpeedSegmentAtBeat( float fBeat ) { return GetSpeedSegmentAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the SpeedSegments at the specified row.
|
||||||
|
* @param iNoteRow the row that has a SpeedSegment.
|
||||||
|
* @return the SpeedSegment's index in question.
|
||||||
|
*/
|
||||||
|
int GetSpeedSegmentIndexAtRow( int iNoteRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the SpeedSegments at the specified beat.
|
||||||
|
* @param fBeat the beat that has a SpeedSegment.
|
||||||
|
* @return the SpeedSegment's index in question.
|
||||||
|
*/
|
||||||
|
int GetSpeedSegmentIndexAtBeat( float fBeat ) const { return GetSpeedSegmentIndexAtRow( BeatToNoteRow(fBeat) ); }
|
||||||
|
/**
|
||||||
|
* @brief Add the SpeedSegment to the TimingData.
|
||||||
|
* @param seg the new SpeedSegment.
|
||||||
|
*/
|
||||||
|
void AddSpeedSegment( const SpeedSegment &seg );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determine when the fakes end.
|
||||||
|
* @param iRow The row you start on.
|
||||||
|
* @return the time when the fakes end.
|
||||||
|
*/
|
||||||
|
float GetFakeAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Determine when the fakes end.
|
||||||
|
* @param fBeat The beat you start on.
|
||||||
|
* @return the time when the fakes end.
|
||||||
|
*/
|
||||||
|
float GetFakeAtBeat( float fBeat ) const { return GetFakeAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to indicate when the FakeSegment ends.
|
||||||
|
* @param iRow The row to start on.
|
||||||
|
* @param fNew The destination beat.
|
||||||
|
*/
|
||||||
|
void SetFakeAtRow( int iRow, float fNew );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to indicate when the FakeSegment ends.
|
||||||
|
* @param fBeat The beat to start on.
|
||||||
|
* @param fNew The destination beat.
|
||||||
|
*/
|
||||||
|
void SetFakeAtBeat( float fBeat, float fNew ) { SetFakeAtRow( BeatToNoteRow( fBeat ), fNew ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the FakeSegment at the specified row.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return the FakeSegment in question.
|
||||||
|
*/
|
||||||
|
FakeSegment& GetFakeSegmentAtRow( int iRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the FakeSegment at the specified beat.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return the FakeSegment in question.
|
||||||
|
*/
|
||||||
|
FakeSegment& GetFakeSegmentAtBeat( float fBeat ) { return GetFakeSegmentAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the FakeSegment at the specified row.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return the index in question.
|
||||||
|
*/
|
||||||
|
int GetFakeSegmentIndexAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the FakeSegment at the specified beat.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return the index in question.
|
||||||
|
*/
|
||||||
|
int GetFakeSegmentIndexAtBeat( float fBeat ) const { return GetFakeSegmentIndexAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Checks if the row is inside a fake.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return true if the row is inside a fake, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsFakeAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Checks if the beat is inside a fake.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return true if the row is inside a fake, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsFakeAtBeat( float fBeat ) const { return IsFakeAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Add the FakeSegment to the TimingData.
|
||||||
|
* @param seg the new FakeSegment.
|
||||||
|
*/
|
||||||
|
void AddFakeSegment( const FakeSegment &seg );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor );
|
void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor );
|
||||||
|
|
||||||
void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const;
|
void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const;
|
||||||
@@ -1276,6 +1704,14 @@ public:
|
|||||||
* @return true if there is at least one warp, false otherwise.
|
* @return true if there is at least one warp, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool HasWarps() const;
|
bool HasWarps() const;
|
||||||
|
/**
|
||||||
|
* @brief View the TimingData to see if there is at least one fake segment involved.
|
||||||
|
* @return true if there is at least one fake segment, false otherwise. */
|
||||||
|
bool HasFakes() const;
|
||||||
|
/**
|
||||||
|
* @brief View the TimingData to see if a song changes its speed scrolling at any point.
|
||||||
|
* @return true if there is at least one change, false otherwise. */
|
||||||
|
bool HasSpeedChanges() const;
|
||||||
/**
|
/**
|
||||||
* @brief Compare two sets of timing data to see if they are equal.
|
* @brief Compare two sets of timing data to see if they are equal.
|
||||||
* @param other the other TimingData.
|
* @param other the other TimingData.
|
||||||
@@ -1301,8 +1737,15 @@ public:
|
|||||||
COMPARE( m_ComboSegments.size() );
|
COMPARE( m_ComboSegments.size() );
|
||||||
for( unsigned i=0; i<m_ComboSegments.size(); i++ )
|
for( unsigned i=0; i<m_ComboSegments.size(); i++ )
|
||||||
COMPARE( m_ComboSegments[i] );
|
COMPARE( m_ComboSegments[i] );
|
||||||
|
COMPARE( m_LabelSegments.size() );
|
||||||
for( unsigned i=0; i<m_LabelSegments.size(); i++ )
|
for( unsigned i=0; i<m_LabelSegments.size(); i++ )
|
||||||
COMPARE( m_LabelSegments[i] );
|
COMPARE( m_LabelSegments[i] );
|
||||||
|
COMPARE( m_SpeedSegments.size() );
|
||||||
|
for( unsigned i=0; i<m_SpeedSegments.size(); i++ )
|
||||||
|
COMPARE( m_SpeedSegments[i] );
|
||||||
|
COMPARE( m_FakeSegments.size() );
|
||||||
|
for( unsigned i=0; i<m_FakeSegments.size(); i++ )
|
||||||
|
COMPARE( m_FakeSegments[i] );
|
||||||
COMPARE( m_fBeat0OffsetInSeconds );
|
COMPARE( m_fBeat0OffsetInSeconds );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1317,6 +1760,11 @@ public:
|
|||||||
void InsertRows( int iStartRow, int iRowsToAdd );
|
void InsertRows( int iStartRow, int iRowsToAdd );
|
||||||
void DeleteRows( int iStartRow, int iRowsToDelete );
|
void DeleteRows( int iStartRow, int iRowsToDelete );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tidy up the timing data, e.g. provide default BPMs, labels, tickcounts.
|
||||||
|
*/
|
||||||
|
void TidyUpData();
|
||||||
|
|
||||||
// Lua
|
// Lua
|
||||||
void PushSelf( lua_State *L );
|
void PushSelf( lua_State *L );
|
||||||
/**
|
/**
|
||||||
@@ -1354,6 +1802,10 @@ public:
|
|||||||
* @brief The collection of LabelSegments.
|
* @brief The collection of LabelSegments.
|
||||||
*/
|
*/
|
||||||
vector<LabelSegment> m_LabelSegments;
|
vector<LabelSegment> m_LabelSegments;
|
||||||
|
/** @brief The collection of SpeedSegments. */
|
||||||
|
vector<SpeedSegment> m_SpeedSegments;
|
||||||
|
/** @brief The collection of FakeSegments. */
|
||||||
|
vector<FakeSegment> m_FakeSegments;
|
||||||
/**
|
/**
|
||||||
* @brief The initial offset of a song.
|
* @brief The initial offset of a song.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user