Port OpenITG's M-Mods. Example: m600 to set target BPM of 600, on a 200BPM song this means 3x. Works with custom speed mods. Note: the block in Player.cpp needs to be fixed for these to be usable, do this before releasing PR2.
This commit is contained in:
@@ -68,7 +68,7 @@ local function ParseSpeedModFile(path)
|
|||||||
return mods
|
return mods
|
||||||
else
|
else
|
||||||
-- error; write a fallback mod file and return it
|
-- error; write a fallback mod file and return it
|
||||||
local fallbackString = "0.5x,1x,1.5x,2x,3x,4x,8x,C200,C400"
|
local fallbackString = "0.5x,1x,1.5x,2x,3x,4x,8x,C200,C400,m550"
|
||||||
Trace("[CustomSpeedMods]: Could not read SpeedMods; writing fallback to "..path)
|
Trace("[CustomSpeedMods]: Could not read SpeedMods; writing fallback to "..path)
|
||||||
file:Open(path, 2)
|
file:Open(path, 2)
|
||||||
file:Write(fallbackString)
|
file:Write(fallbackString)
|
||||||
@@ -148,6 +148,7 @@ end
|
|||||||
|
|
||||||
local function SpeedModSort(tab)
|
local function SpeedModSort(tab)
|
||||||
local xMods = {}
|
local xMods = {}
|
||||||
|
local mMods = {}
|
||||||
local cMods = {}
|
local cMods = {}
|
||||||
--local mMods = {}
|
--local mMods = {}
|
||||||
|
|
||||||
@@ -159,10 +160,9 @@ local function SpeedModSort(tab)
|
|||||||
if string.find(tab[i],"C%d") then
|
if string.find(tab[i],"C%d") then
|
||||||
typ = cMods
|
typ = cMods
|
||||||
val = string.gsub(tab[i], "C", "")
|
val = string.gsub(tab[i], "C", "")
|
||||||
elseif string.find(tab[i],"M%d") then
|
elseif string.find(tab[i],"m%d") then
|
||||||
Trace("[CustomSpeedMods] OpenITG's M-Mods are not supported yet in sm-ssc.")
|
typ = mMods
|
||||||
--typ = mMods
|
val = string.gsub(tab[i], "m", "")
|
||||||
--val = string.gsub(tab[i], "M", "")
|
|
||||||
else
|
else
|
||||||
typ = xMods
|
typ = xMods
|
||||||
val = string.gsub(tab[i], "x", "")
|
val = string.gsub(tab[i], "x", "")
|
||||||
@@ -175,7 +175,7 @@ local function SpeedModSort(tab)
|
|||||||
-- sort cMods
|
-- sort cMods
|
||||||
cMods = AnonSort(cMods)
|
cMods = AnonSort(cMods)
|
||||||
-- sort mMods
|
-- sort mMods
|
||||||
--mMods = AnonSort(mMods)
|
mMods = AnonSort(mMods)
|
||||||
local fin = {}
|
local fin = {}
|
||||||
-- convert it back to a string since that's what it expects
|
-- convert it back to a string since that's what it expects
|
||||||
for i=1,#xMods do
|
for i=1,#xMods do
|
||||||
@@ -184,6 +184,9 @@ local function SpeedModSort(tab)
|
|||||||
for i=1,#cMods do
|
for i=1,#cMods do
|
||||||
table.insert(fin, "C"..cMods[i])
|
table.insert(fin, "C"..cMods[i])
|
||||||
end
|
end
|
||||||
|
for i=1,#mMods do
|
||||||
|
table.insert(fin, "m"..mMods[i])
|
||||||
|
end
|
||||||
--for i=1,#mMods do table.insert(fin, "M"..mMods[i]); end;
|
--for i=1,#mMods do table.insert(fin, "M"..mMods[i]); end;
|
||||||
return fin
|
return fin
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -400,7 +400,63 @@ void Player::Init(
|
|||||||
m_soundAttackEnding.Load( THEME->GetPathS(sType,"course attack ending"), true, &SoundParams );
|
m_soundAttackEnding.Load( THEME->GetPathS(sType,"course attack ending"), true, &SoundParams );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// XXX: Fix errors for m-mod support!
|
||||||
|
/*
|
||||||
|
// calculate M-mod speed here, so we can adjust properly on a per-song basis.
|
||||||
|
// XXX: can we find a better location for this?
|
||||||
|
if( m_pPlayerState->m_PlayerOptions.m_fMaxScrollBPM != 0 )
|
||||||
|
{
|
||||||
|
DisplayBpms bpms;
|
||||||
|
|
||||||
|
if( GAMESTATE->IsCourseMode() )
|
||||||
|
{
|
||||||
|
ASSERT( GAMESTATE->m_pCurTrail[pn] );
|
||||||
|
GAMESTATE->m_pCurTrail[pn]->GetDisplayBpms( bpms );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT( GAMESTATE->m_pCurSong );
|
||||||
|
GAMESTATE->m_pCurSong->GetDisplayBpms( bpms );
|
||||||
|
}
|
||||||
|
|
||||||
|
float fMaxBPM = 0;
|
||||||
|
|
||||||
|
// all BPMs are listed and available, so try them first.
|
||||||
|
// get the maximum listed value for the song or course.
|
||||||
|
// if the BPMs are < 0, reset and get the actual values.
|
||||||
|
if( !bpms.IsSecret() )
|
||||||
|
{
|
||||||
|
fMaxBPM = bpms.GetMax();
|
||||||
|
fMaxBPM = max( 0, fMaxBPM );
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can't rely on the displayed BPMs, so manually calculate.
|
||||||
|
if( fMaxBPM == 0 )
|
||||||
|
{
|
||||||
|
float fThrowAway = 0;
|
||||||
|
|
||||||
|
if( GAMESTATE->IsCourseMode() )
|
||||||
|
{
|
||||||
|
FOREACH_CONST( TrailEntry, GAMESTATE->m_pCurTrail[pn]->m_vEntries, e )
|
||||||
|
{
|
||||||
|
float fMaxForEntry;
|
||||||
|
e->pSong->m_Timing.GetActualBPM( fThrowAway, fMaxForEntry );
|
||||||
|
fMaxBPM = max( fMaxForEntry, fMaxBPM );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GAMESTATE->m_pCurSong->m_Timing.GetActualBPM( fThrowAway, fMaxBPM );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT( fMaxBPM > 0 );
|
||||||
|
|
||||||
|
// set an X-mod equal to Mnum / fMaxBPM (e.g. M600 with 150 becomes 4x)
|
||||||
|
m_pPlayerState->m_StoredPlayerOptions.m_fScrollSpeed =
|
||||||
|
( m_pPlayerState->m_StoredPlayerOptions.m_fMaxScrollBPM / fMaxBPM );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
float fBalance = GameSoundManager::GetPlayerBalance( pn );
|
float fBalance = GameSoundManager::GetPlayerBalance( pn );
|
||||||
m_soundMine.SetProperty( "Pan", fBalance );
|
m_soundMine.SetProperty( "Pan", fBalance );
|
||||||
|
|||||||
+43
-6
@@ -26,6 +26,7 @@ ThemeMetric<float> RANDOM_SUDDEN_CHANCE ( "PlayerOptions", "RandomSuddenChance"
|
|||||||
void PlayerOptions::Init()
|
void PlayerOptions::Init()
|
||||||
{
|
{
|
||||||
m_bSetScrollSpeed = false;
|
m_bSetScrollSpeed = false;
|
||||||
|
m_fMaxScrollBPM = 0; m_SpeedfMaxScrollBPM = 1.0f;
|
||||||
m_fTimeSpacing = 0; m_SpeedfTimeSpacing = 1.0f;
|
m_fTimeSpacing = 0; m_SpeedfTimeSpacing = 1.0f;
|
||||||
m_fScrollSpeed = 1.0f; m_SpeedfScrollSpeed = 1.0f;
|
m_fScrollSpeed = 1.0f; m_SpeedfScrollSpeed = 1.0f;
|
||||||
m_fScrollBPM = 200; m_SpeedfScrollBPM = 1.0f;
|
m_fScrollBPM = 200; m_SpeedfScrollBPM = 1.0f;
|
||||||
@@ -60,6 +61,7 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds )
|
|||||||
|
|
||||||
APPROACH( fTimeSpacing );
|
APPROACH( fTimeSpacing );
|
||||||
APPROACH( fScrollSpeed );
|
APPROACH( fScrollSpeed );
|
||||||
|
APPROACH( fMaxScrollBPM );
|
||||||
fapproach( m_fScrollBPM, other.m_fScrollBPM, fDeltaSeconds * other.m_SpeedfScrollBPM*150 );
|
fapproach( m_fScrollBPM, other.m_fScrollBPM, fDeltaSeconds * other.m_SpeedfScrollBPM*150 );
|
||||||
for( int i=0; i<NUM_ACCELS; i++ )
|
for( int i=0; i<NUM_ACCELS; i++ )
|
||||||
APPROACH( fAccels[i] );
|
APPROACH( fAccels[i] );
|
||||||
@@ -116,6 +118,11 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
|
|||||||
|
|
||||||
if( !m_fTimeSpacing )
|
if( !m_fTimeSpacing )
|
||||||
{
|
{
|
||||||
|
if( m_fMaxScrollBPM )
|
||||||
|
{
|
||||||
|
RString s = ssprintf( "m%.0f", m_fMaxScrollBPM );
|
||||||
|
AddTo.push_back( s );
|
||||||
|
}
|
||||||
if( m_bSetScrollSpeed || m_fScrollSpeed != 1 )
|
if( m_bSetScrollSpeed || m_fScrollSpeed != 1 )
|
||||||
{
|
{
|
||||||
/* -> 1.00 */
|
/* -> 1.00 */
|
||||||
@@ -332,6 +339,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
|
|||||||
SET_FLOAT( fScrollSpeed )
|
SET_FLOAT( fScrollSpeed )
|
||||||
SET_FLOAT( fTimeSpacing )
|
SET_FLOAT( fTimeSpacing )
|
||||||
m_fTimeSpacing = 0;
|
m_fTimeSpacing = 0;
|
||||||
|
m_fMaxScrollBPM = 0;
|
||||||
}
|
}
|
||||||
else if( sscanf( sBit, "c%f", &level ) == 1 )
|
else if( sscanf( sBit, "c%f", &level ) == 1 )
|
||||||
{
|
{
|
||||||
@@ -340,17 +348,18 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
|
|||||||
SET_FLOAT( fScrollBPM )
|
SET_FLOAT( fScrollBPM )
|
||||||
SET_FLOAT( fTimeSpacing )
|
SET_FLOAT( fTimeSpacing )
|
||||||
m_fTimeSpacing = 1;
|
m_fTimeSpacing = 1;
|
||||||
|
m_fMaxScrollBPM = 0;
|
||||||
}
|
}
|
||||||
/* Port M-Mods from OpenITG, starting from r537 */
|
// oITG's m-mods
|
||||||
// Midiman
|
// XXX: will not properly tween, I don't think.
|
||||||
else if( sscanf( sBit, "m%f", &level ) == 1 )
|
else if( sscanf( sBit, "m%f", &level ) == 1 )
|
||||||
{
|
{
|
||||||
if( !isfinite(level) || level <= 0.0f )
|
if( !isfinite(level) || level <= 0.0f )
|
||||||
level = 200.0f; // Just pick some value.
|
level = 200.0f;
|
||||||
SET_FLOAT( fScrollBPM )
|
SET_FLOAT( fMaxScrollBPM )
|
||||||
SET_FLOAT( fTimeSpacing )
|
m_fTimeSpacing = 0;
|
||||||
m_fTimeSpacing = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sBit == "clearall" ) Init();
|
else if( sBit == "clearall" ) Init();
|
||||||
else if( sBit == "boost" ) SET_FLOAT( fAccels[ACCEL_BOOST] )
|
else if( sBit == "boost" ) SET_FLOAT( fAccels[ACCEL_BOOST] )
|
||||||
else if( sBit == "brake" || sBit == "land" ) SET_FLOAT( fAccels[ACCEL_BRAKE] )
|
else if( sBit == "brake" || sBit == "land" ) SET_FLOAT( fAccels[ACCEL_BRAKE] )
|
||||||
@@ -650,6 +659,7 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const
|
|||||||
COMPARE(m_fTimeSpacing);
|
COMPARE(m_fTimeSpacing);
|
||||||
COMPARE(m_fScrollSpeed);
|
COMPARE(m_fScrollSpeed);
|
||||||
COMPARE(m_fScrollBPM);
|
COMPARE(m_fScrollBPM);
|
||||||
|
COMPARE(m_fMaxScrollBPM);
|
||||||
COMPARE(m_fRandomSpeed);
|
COMPARE(m_fRandomSpeed);
|
||||||
COMPARE(m_FailType);
|
COMPARE(m_FailType);
|
||||||
COMPARE(m_bMuteOnError);
|
COMPARE(m_bMuteOnError);
|
||||||
@@ -717,6 +727,31 @@ bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerN
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( m_fCover ) return true;
|
if( m_fCover ) return true;
|
||||||
|
|
||||||
|
// M-mods make songs with indefinite BPMs easier because
|
||||||
|
// they ensure that the song has a scrollable speed.
|
||||||
|
if( m_fMaxScrollBPM != 0 )
|
||||||
|
{
|
||||||
|
// BPM display is obfuscated
|
||||||
|
// if( pSong->m_DisplayBPMType == DISPLAY_BPM_RANDOM )
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
DisplayBpms bpms;
|
||||||
|
if( GAMESTATE->IsCourseMode() )
|
||||||
|
{
|
||||||
|
Trail *pTrail = GAMESTATE->m_pCurCourse->GetTrail( GAMESTATE->GetCurrentStyle()->m_StepsType );
|
||||||
|
pTrail->GetDisplayBpms( bpms );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GAMESTATE->m_pCurSong->GetDisplayBpms( bpms );
|
||||||
|
}
|
||||||
|
pSong->GetDisplayBpms( bpms );
|
||||||
|
|
||||||
|
// maximum BPM is obfuscated, so M-mods will set a playable speed.
|
||||||
|
if( bpms.GetMax() <= 0 )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if( m_fPlayerAutoPlay ) return true;
|
if( m_fPlayerAutoPlay ) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -788,6 +823,7 @@ RString PlayerOptions::GetSavedPrefsString() const
|
|||||||
SAVE( m_fTimeSpacing );
|
SAVE( m_fTimeSpacing );
|
||||||
SAVE( m_fScrollSpeed );
|
SAVE( m_fScrollSpeed );
|
||||||
SAVE( m_fScrollBPM );
|
SAVE( m_fScrollBPM );
|
||||||
|
SAVE( m_fMaxScrollBPM );
|
||||||
SAVE( m_fScrolls[SCROLL_REVERSE] );
|
SAVE( m_fScrolls[SCROLL_REVERSE] );
|
||||||
SAVE( m_fPerspectiveTilt );
|
SAVE( m_fPerspectiveTilt );
|
||||||
SAVE( m_bTransforms[TRANSFORM_NOHOLDS] );
|
SAVE( m_bTransforms[TRANSFORM_NOHOLDS] );
|
||||||
@@ -816,6 +852,7 @@ void PlayerOptions::ResetPrefs( ResetPrefsType type )
|
|||||||
CPY( m_fTimeSpacing );
|
CPY( m_fTimeSpacing );
|
||||||
CPY( m_fScrollSpeed );
|
CPY( m_fScrollSpeed );
|
||||||
CPY( m_fScrollBPM );
|
CPY( m_fScrollBPM );
|
||||||
|
CPY( m_fMaxScrollBPM );
|
||||||
break;
|
break;
|
||||||
case saved_prefs_invalid_for_course:
|
case saved_prefs_invalid_for_course:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ public:
|
|||||||
* PlayerOptions::Approach approaches. */
|
* PlayerOptions::Approach approaches. */
|
||||||
bool m_bSetScrollSpeed; // true if the scroll speed was set by FromString
|
bool m_bSetScrollSpeed; // true if the scroll speed was set by FromString
|
||||||
float m_fTimeSpacing, m_SpeedfTimeSpacing; // instead of Beat spacing (CMods, mMods)
|
float m_fTimeSpacing, m_SpeedfTimeSpacing; // instead of Beat spacing (CMods, mMods)
|
||||||
|
float m_fMaxScrollBPM, m_SpeedfMaxScrollBPM;
|
||||||
float m_fScrollSpeed, m_SpeedfScrollSpeed; // used if !m_bTimeSpacing (xMods)
|
float m_fScrollSpeed, m_SpeedfScrollSpeed; // used if !m_bTimeSpacing (xMods)
|
||||||
float m_fScrollBPM, m_SpeedfScrollBPM; // used if m_bTimeSpacing (CMod)
|
float m_fScrollBPM, m_SpeedfScrollBPM; // used if m_bTimeSpacing (CMod)
|
||||||
float m_fAccels[NUM_ACCELS], m_SpeedfAccels[NUM_ACCELS];
|
float m_fAccels[NUM_ACCELS], m_SpeedfAccels[NUM_ACCELS];
|
||||||
|
|||||||
Reference in New Issue
Block a user