Split *Options::FromString into FromString and FromOneModString.
Check for invalid mod names when loading a course by checking whether the mod is a valid PlayerOption or a valid SongOption. Previously, SongOption mods were being flagged as errors by PlayerOptions.
This commit is contained in:
@@ -45,7 +45,7 @@ void ActiveAttackList::Refresh()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
PlayerOptions po;
|
PlayerOptions po;
|
||||||
po.FromString( attack.sModifiers, true );
|
po.FromString( attack.sModifiers );
|
||||||
po.GetLocalizedMods( vsThemedMods );
|
po.GetLocalizedMods( vsThemedMods );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -381,7 +381,7 @@ void CatalogXml::Save( LoadingWindow *loading_window )
|
|||||||
{
|
{
|
||||||
PlayerOptions po;
|
PlayerOptions po;
|
||||||
RString s = *iter;
|
RString s = *iter;
|
||||||
po.FromString( s, false );
|
po.FromString( s );
|
||||||
vector<RString> v;
|
vector<RString> v;
|
||||||
po.GetLocalizedMods( v );
|
po.GetLocalizedMods( v );
|
||||||
if( v.empty() )
|
if( v.empty() )
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "RageFileManager.h"
|
#include "RageFileManager.h"
|
||||||
#include "CourseWriterCRS.h"
|
#include "CourseWriterCRS.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
|
#include "CourseUtil.h"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
const int MAX_EDIT_COURSE_SIZE_BYTES = 30*1024; // 30KB
|
const int MAX_EDIT_COURSE_SIZE_BYTES = 30*1024; // 30KB
|
||||||
@@ -130,9 +131,8 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
|
|||||||
attack.fSecsRemaining = 0.0f;
|
attack.fSecsRemaining = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// warn on invalid so we catch bogus mods on load
|
// warn on invalid so we catch typos on load
|
||||||
PlayerOptions po;
|
CourseUtil::WarnOnInvalidMods( attack.sModifiers );
|
||||||
po.FromString( attack.sModifiers, true );
|
|
||||||
|
|
||||||
attacks.push_back( attack );
|
attacks.push_back( attack );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "Foreach.h"
|
#include "Foreach.h"
|
||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
#include "LocalizedString.h"
|
#include "LocalizedString.h"
|
||||||
|
#include "RageLog.h"
|
||||||
|
#include "arch/Dialog/Dialog.h"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -315,6 +317,29 @@ bool CourseUtil::ValidateEditCourseName( const RString &sAnswer, RString &sError
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CourseUtil::WarnOnInvalidMods( RString sMods )
|
||||||
|
{
|
||||||
|
PlayerOptions po;
|
||||||
|
SongOptions so;
|
||||||
|
vector<RString> vs;
|
||||||
|
split( sMods, ",", vs, true );
|
||||||
|
FOREACH_CONST( RString, vs, s )
|
||||||
|
{
|
||||||
|
bool bValid = false;
|
||||||
|
RString sErrorDetail;
|
||||||
|
bValid |= po.FromOneModString( *s, sErrorDetail );
|
||||||
|
bValid |= so.FromOneModString( *s, sErrorDetail );
|
||||||
|
if( !bValid )
|
||||||
|
{
|
||||||
|
RString sFullError = ssprintf("Error processing '%s' in '%s'", (*s).c_str(), sMods.c_str() );
|
||||||
|
if( !sErrorDetail.empty() )
|
||||||
|
sFullError += ": " + sErrorDetail;
|
||||||
|
LOG->UserLog( "", "", "%s", sFullError.c_str() );
|
||||||
|
Dialog::OK( sFullError, "INVALID_PLAYER_OPTION_WARNING" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// CourseID
|
// CourseID
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ namespace CourseUtil
|
|||||||
void AutogenOniFromArtist( const RString &sArtistName, RString sArtistNameTranslit, vector<Song*> aSongs, Difficulty dc, Course &out );
|
void AutogenOniFromArtist( const RString &sArtistName, RString sArtistNameTranslit, vector<Song*> aSongs, Difficulty dc, Course &out );
|
||||||
|
|
||||||
bool ValidateEditCourseName( const RString &sAnswer, RString &sErrorOut );
|
bool ValidateEditCourseName( const RString &sAnswer, RString &sErrorOut );
|
||||||
|
|
||||||
|
void WarnOnInvalidMods( RString sMods );
|
||||||
};
|
};
|
||||||
|
|
||||||
class CourseID
|
class CourseID
|
||||||
|
|||||||
+159
-162
@@ -1,7 +1,6 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "PlayerOptions.h"
|
#include "PlayerOptions.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "RageLog.h"
|
|
||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
#include "NoteSkinManager.h"
|
#include "NoteSkinManager.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
@@ -11,7 +10,6 @@
|
|||||||
#include "Foreach.h"
|
#include "Foreach.h"
|
||||||
#include "Style.h"
|
#include "Style.h"
|
||||||
#include "CommonMetrics.h"
|
#include "CommonMetrics.h"
|
||||||
#include "arch/Dialog/Dialog.h"
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#define ONE( arr ) { for( unsigned Z = 0; Z < ARRAYLEN(arr); ++Z ) arr[Z]=1.0f; }
|
#define ONE( arr ) { for( unsigned Z = 0; Z < ARRAYLEN(arr); ++Z ) arr[Z]=1.0f; }
|
||||||
@@ -232,179 +230,178 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
|
|||||||
|
|
||||||
/* Options are added to the current settings; call Init() beforehand if
|
/* Options are added to the current settings; call Init() beforehand if
|
||||||
* you don't want this. */
|
* you don't want this. */
|
||||||
void PlayerOptions::FromString( const RString &sOptions, bool bWarnOnInvalid )
|
void PlayerOptions::FromString( const RString &sMultipleMods )
|
||||||
|
{
|
||||||
|
RString sTemp = sMultipleMods;
|
||||||
|
vector<RString> vs;
|
||||||
|
split( sTemp, ",", vs, true );
|
||||||
|
RString sThrowAway;
|
||||||
|
FOREACH( RString, vs, s )
|
||||||
|
{
|
||||||
|
FromOneModString( *s, sThrowAway );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut )
|
||||||
{
|
{
|
||||||
ASSERT( NOTESKIN );
|
ASSERT( NOTESKIN );
|
||||||
// Init();
|
|
||||||
RString sTemp = sOptions;
|
|
||||||
sTemp.MakeLower();
|
|
||||||
vector<RString> asBits;
|
|
||||||
split( sTemp, ",", asBits, true );
|
|
||||||
|
|
||||||
FOREACH( RString, asBits, bit )
|
RString sBit = sOneMod;
|
||||||
|
sBit.MakeLower();
|
||||||
|
TrimLeft(sBit);
|
||||||
|
TrimRight(sBit);
|
||||||
|
|
||||||
|
/* "drunk"
|
||||||
|
* "no drunk"
|
||||||
|
* "150% drunk"
|
||||||
|
* "*2 100% drunk": approach at 2x normal speed */
|
||||||
|
|
||||||
|
float level = 1;
|
||||||
|
float speed = 1;
|
||||||
|
vector<RString> asParts;
|
||||||
|
split( sBit, " ", asParts, true );
|
||||||
|
|
||||||
|
FOREACH_CONST( RString, asParts, s )
|
||||||
{
|
{
|
||||||
RString& sBit = *bit;
|
if( *s == "no" )
|
||||||
TrimLeft(sBit);
|
|
||||||
TrimRight(sBit);
|
|
||||||
|
|
||||||
/* "drunk"
|
|
||||||
* "no drunk"
|
|
||||||
* "150% drunk"
|
|
||||||
* "*2 100% drunk": approach at 2x normal speed */
|
|
||||||
|
|
||||||
float level = 1;
|
|
||||||
float speed = 1;
|
|
||||||
vector<RString> asParts;
|
|
||||||
split( sBit, " ", asParts, true );
|
|
||||||
|
|
||||||
FOREACH_CONST( RString, asParts, s )
|
|
||||||
{
|
{
|
||||||
if( *s == "no" )
|
level = 0;
|
||||||
|
}
|
||||||
|
else if( isdigit((*s)[0]) || (*s)[0] == '-' )
|
||||||
|
{
|
||||||
|
/* If the last character is a *, they probably said "123*" when
|
||||||
|
* they meant "*123". */
|
||||||
|
if( s->Right(1) == "*" )
|
||||||
{
|
{
|
||||||
level = 0;
|
/* XXX We know what they want, is there any reason not to handle it? */
|
||||||
|
/* Yes. We should be strict in handling the format. -Chris */
|
||||||
|
sErrorOut = ssprintf("Invalid player options \"%s\"; did you mean '*%d'?", s->c_str(), atoi(*s) );
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else if( isdigit((*s)[0]) || (*s)[0] == '-' )
|
else
|
||||||
{
|
{
|
||||||
/* If the last character is a *, they probably said "123*" when
|
level = StringToFloat( *s ) / 100.0f;
|
||||||
* they meant "*123". */
|
|
||||||
if( s->Right(1) == "*" )
|
|
||||||
{
|
|
||||||
if( bWarnOnInvalid )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "", "", "Invalid player options \"%s\"; did you mean '*%d'?",
|
|
||||||
s->c_str(), atoi(*s) );
|
|
||||||
}
|
|
||||||
// XXX We know what they want, is there any reason not to handle it?
|
|
||||||
speed = StringToFloat( *s );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
level = StringToFloat( *s ) / 100.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( *s[0]=='*' )
|
|
||||||
{
|
|
||||||
sscanf( *s, "*%f", &speed );
|
|
||||||
if( !isfinite(speed) )
|
|
||||||
speed = 1.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( *s[0]=='*' )
|
||||||
|
|
||||||
sBit = asParts.back();
|
|
||||||
|
|
||||||
#define SET_FLOAT( opt ) { m_ ## opt = level; m_Speed ## opt = speed; }
|
|
||||||
const bool on = (level > 0.5f);
|
|
||||||
|
|
||||||
static Regex mult("^([0-9]+(\\.[0-9]+)?)x$");
|
|
||||||
vector<RString> matches;
|
|
||||||
if( mult.Compare(sBit, matches) )
|
|
||||||
{
|
{
|
||||||
StringConversion::FromString( matches[0], level );
|
sscanf( *s, "*%f", &speed );
|
||||||
SET_FLOAT( fScrollSpeed )
|
if( !isfinite(speed) )
|
||||||
SET_FLOAT( fTimeSpacing )
|
speed = 1.0f;
|
||||||
m_fTimeSpacing = 0;
|
|
||||||
}
|
|
||||||
else if( sscanf( sBit, "c%f", &level ) == 1 )
|
|
||||||
{
|
|
||||||
if( !isfinite(level) || level <= 0.0f )
|
|
||||||
level = 200.0f; // Just pick some value.
|
|
||||||
SET_FLOAT( fScrollBPM )
|
|
||||||
SET_FLOAT( fTimeSpacing )
|
|
||||||
m_fTimeSpacing = 1;
|
|
||||||
}
|
|
||||||
else if( sBit == "clearall" ) Init();
|
|
||||||
else if( sBit == "boost" ) SET_FLOAT( fAccels[ACCEL_BOOST] )
|
|
||||||
else if( sBit == "brake" || sBit == "land" ) SET_FLOAT( fAccels[ACCEL_BRAKE] )
|
|
||||||
else if( sBit == "wave" ) SET_FLOAT( fAccels[ACCEL_WAVE] )
|
|
||||||
else if( sBit == "expand" || sBit == "dwiwave" ) SET_FLOAT( fAccels[ACCEL_EXPAND] )
|
|
||||||
else if( sBit == "boomerang" ) SET_FLOAT( fAccels[ACCEL_BOOMERANG] )
|
|
||||||
else if( sBit == "drunk" ) SET_FLOAT( fEffects[EFFECT_DRUNK] )
|
|
||||||
else if( sBit == "dizzy" ) SET_FLOAT( fEffects[EFFECT_DIZZY] )
|
|
||||||
else if( sBit == "mini" ) SET_FLOAT( fEffects[EFFECT_MINI] )
|
|
||||||
else if( sBit == "tiny" ) SET_FLOAT( fEffects[EFFECT_TINY] )
|
|
||||||
else if( sBit == "flip" ) SET_FLOAT( fEffects[EFFECT_FLIP] )
|
|
||||||
else if( sBit == "invert" ) SET_FLOAT( fEffects[EFFECT_INVERT] )
|
|
||||||
else if( sBit == "tornado" ) SET_FLOAT( fEffects[EFFECT_TORNADO] )
|
|
||||||
else if( sBit == "tipsy" ) SET_FLOAT( fEffects[EFFECT_TIPSY] )
|
|
||||||
else if( sBit == "bumpy" ) SET_FLOAT( fEffects[EFFECT_BUMPY] )
|
|
||||||
else if( sBit == "beat" ) SET_FLOAT( fEffects[EFFECT_BEAT] )
|
|
||||||
else if( sBit == "hidden" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN] )
|
|
||||||
else if( sBit == "hiddenoffset" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN_OFFSET] )
|
|
||||||
else if( sBit == "sudden" ) SET_FLOAT( fAppearances[APPEARANCE_SUDDEN] )
|
|
||||||
else if( sBit == "suddenoffset" ) SET_FLOAT( fAppearances[APPEARANCE_SUDDEN_OFFSET] )
|
|
||||||
else if( sBit == "stealth" ) SET_FLOAT( fAppearances[APPEARANCE_STEALTH] )
|
|
||||||
else if( sBit == "blink" ) SET_FLOAT( fAppearances[APPEARANCE_BLINK] )
|
|
||||||
else if( sBit == "randomvanish" ) SET_FLOAT( fAppearances[APPEARANCE_RANDOMVANISH] )
|
|
||||||
else if( sBit == "turn" && !on ) ZERO( m_bTurns ); /* "no turn" */
|
|
||||||
else if( sBit == "mirror" ) m_bTurns[TURN_MIRROR] = on;
|
|
||||||
else if( sBit == "left" ) m_bTurns[TURN_LEFT] = on;
|
|
||||||
else if( sBit == "right" ) m_bTurns[TURN_RIGHT] = on;
|
|
||||||
else if( sBit == "shuffle" ) m_bTurns[TURN_SHUFFLE] = on;
|
|
||||||
else if( sBit == "supershuffle" ) m_bTurns[TURN_SUPER_SHUFFLE] = on;
|
|
||||||
else if( sBit == "little" ) m_bTransforms[TRANSFORM_LITTLE] = on;
|
|
||||||
else if( sBit == "wide" ) m_bTransforms[TRANSFORM_WIDE] = on;
|
|
||||||
else if( sBit == "big" ) m_bTransforms[TRANSFORM_BIG] = on;
|
|
||||||
else if( sBit == "quick" ) m_bTransforms[TRANSFORM_QUICK] = on;
|
|
||||||
else if( sBit == "bmrize" ) m_bTransforms[TRANSFORM_BMRIZE] = on;
|
|
||||||
else if( sBit == "skippy" ) m_bTransforms[TRANSFORM_SKIPPY] = on;
|
|
||||||
else if( sBit == "mines" ) m_bTransforms[TRANSFORM_MINES] = on;
|
|
||||||
else if( sBit == "echo" ) m_bTransforms[TRANSFORM_ECHO] = on;
|
|
||||||
else if( sBit == "stomp" ) m_bTransforms[TRANSFORM_STOMP] = on;
|
|
||||||
else if( sBit == "planted" ) m_bTransforms[TRANSFORM_PLANTED] = on;
|
|
||||||
else if( sBit == "floored" ) m_bTransforms[TRANSFORM_FLOORED] = on;
|
|
||||||
else if( sBit == "twister" ) m_bTransforms[TRANSFORM_TWISTER] = on;
|
|
||||||
else if( sBit == "nojumps" ) m_bTransforms[TRANSFORM_NOJUMPS] = on;
|
|
||||||
else if( sBit == "nohands" ) m_bTransforms[TRANSFORM_NOHANDS] = on;
|
|
||||||
else if( sBit == "noquads" ) m_bTransforms[TRANSFORM_NOQUADS] = on;
|
|
||||||
else if( sBit == "reverse" ) SET_FLOAT( fScrolls[SCROLL_REVERSE] )
|
|
||||||
else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] )
|
|
||||||
else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] )
|
|
||||||
else if( sBit == "cross" ) SET_FLOAT( fScrolls[SCROLL_CROSS] )
|
|
||||||
else if( sBit == "centered" ) SET_FLOAT( fScrolls[SCROLL_CENTERED] )
|
|
||||||
else if( sBit == "noholds" ) m_bTransforms[TRANSFORM_NOHOLDS] = on;
|
|
||||||
else if( sBit == "norolls" ) m_bTransforms[TRANSFORM_NOROLLS] = on;
|
|
||||||
else if( sBit == "nomines" ) m_bTransforms[TRANSFORM_NOMINES] = on;
|
|
||||||
else if( sBit == "nostretch" ) m_bTransforms[TRANSFORM_NOSTRETCH] = on;
|
|
||||||
else if( sBit == "dark" ) SET_FLOAT( fDark )
|
|
||||||
else if( sBit == "blind" ) SET_FLOAT( fBlind )
|
|
||||||
else if( sBit == "cover" ) SET_FLOAT( fCover )
|
|
||||||
else if( sBit == "passmark" ) SET_FLOAT( fPassmark )
|
|
||||||
else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
|
||||||
else if( sBit == "incoming" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
|
||||||
else if( sBit == "space" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
|
||||||
else if( sBit == "hallway" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
|
||||||
else if( sBit == "distant" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
|
||||||
else if( NOTESKIN && NOTESKIN->DoesNoteSkinExist(sBit) ) m_sNoteSkin = sBit;
|
|
||||||
else if( sBit == "noteskin" && !on ) /* "no noteskin" */ m_sNoteSkin = CommonMetrics::DEFAULT_NOTESKIN_NAME;
|
|
||||||
else if( sBit == "randomspeed" ) SET_FLOAT( fRandomSpeed )
|
|
||||||
else if( sBit == "failarcade" ||
|
|
||||||
sBit == "failimmediate" ) m_FailType = FAIL_IMMEDIATE;
|
|
||||||
else if( sBit == "failendofsong" ||
|
|
||||||
sBit == "failimmediatecontinue" ) m_FailType = FAIL_IMMEDIATE_CONTINUE;
|
|
||||||
else if( sBit == "failatend" ) m_FailType = FAIL_AT_END;
|
|
||||||
else if( sBit == "failoff" ) m_FailType = FAIL_OFF;
|
|
||||||
else if( sBit == "faildefault" )
|
|
||||||
{
|
|
||||||
PlayerOptions po;
|
|
||||||
GAMESTATE->GetDefaultPlayerOptions( po );
|
|
||||||
m_FailType = po.m_FailType;
|
|
||||||
}
|
|
||||||
else if( sBit == "addscore" ) m_ScoreDisplay = SCORING_ADD;
|
|
||||||
else if( sBit == "subtractscore" ) m_ScoreDisplay = SCORING_SUBTRACT;
|
|
||||||
else if( sBit == "averagescore" ) m_ScoreDisplay = SCORING_AVERAGE;
|
|
||||||
else if( sBit == "muteonerror" ) m_bMuteOnError = on;
|
|
||||||
else if( sBit == "random" ) ChooseRandomModifiers();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( bWarnOnInvalid )
|
|
||||||
{
|
|
||||||
RString sWarning = ssprintf( "The options string \"%s\" contains an invalid mod name \"%s\".", sOptions.c_str(), sBit.c_str() );
|
|
||||||
LOG->UserLog( "", "", "%s", sWarning.c_str() );
|
|
||||||
Dialog::OK( sWarning, "INVALID_PLAYER_OPTION_WARNING" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sBit = asParts.back();
|
||||||
|
|
||||||
|
#define SET_FLOAT( opt ) { m_ ## opt = level; m_Speed ## opt = speed; }
|
||||||
|
const bool on = (level > 0.5f);
|
||||||
|
|
||||||
|
static Regex mult("^([0-9]+(\\.[0-9]+)?)x$");
|
||||||
|
vector<RString> matches;
|
||||||
|
if( mult.Compare(sBit, matches) )
|
||||||
|
{
|
||||||
|
StringConversion::FromString( matches[0], level );
|
||||||
|
SET_FLOAT( fScrollSpeed )
|
||||||
|
SET_FLOAT( fTimeSpacing )
|
||||||
|
m_fTimeSpacing = 0;
|
||||||
|
}
|
||||||
|
else if( sscanf( sBit, "c%f", &level ) == 1 )
|
||||||
|
{
|
||||||
|
if( !isfinite(level) || level <= 0.0f )
|
||||||
|
level = 200.0f; // Just pick some value.
|
||||||
|
SET_FLOAT( fScrollBPM )
|
||||||
|
SET_FLOAT( fTimeSpacing )
|
||||||
|
m_fTimeSpacing = 1;
|
||||||
|
}
|
||||||
|
else if( sBit == "clearall" ) Init();
|
||||||
|
else if( sBit == "boost" ) SET_FLOAT( fAccels[ACCEL_BOOST] )
|
||||||
|
else if( sBit == "brake" || sBit == "land" ) SET_FLOAT( fAccels[ACCEL_BRAKE] )
|
||||||
|
else if( sBit == "wave" ) SET_FLOAT( fAccels[ACCEL_WAVE] )
|
||||||
|
else if( sBit == "expand" || sBit == "dwiwave" ) SET_FLOAT( fAccels[ACCEL_EXPAND] )
|
||||||
|
else if( sBit == "boomerang" ) SET_FLOAT( fAccels[ACCEL_BOOMERANG] )
|
||||||
|
else if( sBit == "drunk" ) SET_FLOAT( fEffects[EFFECT_DRUNK] )
|
||||||
|
else if( sBit == "dizzy" ) SET_FLOAT( fEffects[EFFECT_DIZZY] )
|
||||||
|
else if( sBit == "mini" ) SET_FLOAT( fEffects[EFFECT_MINI] )
|
||||||
|
else if( sBit == "tiny" ) SET_FLOAT( fEffects[EFFECT_TINY] )
|
||||||
|
else if( sBit == "flip" ) SET_FLOAT( fEffects[EFFECT_FLIP] )
|
||||||
|
else if( sBit == "invert" ) SET_FLOAT( fEffects[EFFECT_INVERT] )
|
||||||
|
else if( sBit == "tornado" ) SET_FLOAT( fEffects[EFFECT_TORNADO] )
|
||||||
|
else if( sBit == "tipsy" ) SET_FLOAT( fEffects[EFFECT_TIPSY] )
|
||||||
|
else if( sBit == "bumpy" ) SET_FLOAT( fEffects[EFFECT_BUMPY] )
|
||||||
|
else if( sBit == "beat" ) SET_FLOAT( fEffects[EFFECT_BEAT] )
|
||||||
|
else if( sBit == "hidden" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN] )
|
||||||
|
else if( sBit == "hiddenoffset" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN_OFFSET] )
|
||||||
|
else if( sBit == "sudden" ) SET_FLOAT( fAppearances[APPEARANCE_SUDDEN] )
|
||||||
|
else if( sBit == "suddenoffset" ) SET_FLOAT( fAppearances[APPEARANCE_SUDDEN_OFFSET] )
|
||||||
|
else if( sBit == "stealth" ) SET_FLOAT( fAppearances[APPEARANCE_STEALTH] )
|
||||||
|
else if( sBit == "blink" ) SET_FLOAT( fAppearances[APPEARANCE_BLINK] )
|
||||||
|
else if( sBit == "randomvanish" ) SET_FLOAT( fAppearances[APPEARANCE_RANDOMVANISH] )
|
||||||
|
else if( sBit == "turn" && !on ) ZERO( m_bTurns ); /* "no turn" */
|
||||||
|
else if( sBit == "mirror" ) m_bTurns[TURN_MIRROR] = on;
|
||||||
|
else if( sBit == "left" ) m_bTurns[TURN_LEFT] = on;
|
||||||
|
else if( sBit == "right" ) m_bTurns[TURN_RIGHT] = on;
|
||||||
|
else if( sBit == "shuffle" ) m_bTurns[TURN_SHUFFLE] = on;
|
||||||
|
else if( sBit == "supershuffle" ) m_bTurns[TURN_SUPER_SHUFFLE] = on;
|
||||||
|
else if( sBit == "little" ) m_bTransforms[TRANSFORM_LITTLE] = on;
|
||||||
|
else if( sBit == "wide" ) m_bTransforms[TRANSFORM_WIDE] = on;
|
||||||
|
else if( sBit == "big" ) m_bTransforms[TRANSFORM_BIG] = on;
|
||||||
|
else if( sBit == "quick" ) m_bTransforms[TRANSFORM_QUICK] = on;
|
||||||
|
else if( sBit == "bmrize" ) m_bTransforms[TRANSFORM_BMRIZE] = on;
|
||||||
|
else if( sBit == "skippy" ) m_bTransforms[TRANSFORM_SKIPPY] = on;
|
||||||
|
else if( sBit == "mines" ) m_bTransforms[TRANSFORM_MINES] = on;
|
||||||
|
else if( sBit == "echo" ) m_bTransforms[TRANSFORM_ECHO] = on;
|
||||||
|
else if( sBit == "stomp" ) m_bTransforms[TRANSFORM_STOMP] = on;
|
||||||
|
else if( sBit == "planted" ) m_bTransforms[TRANSFORM_PLANTED] = on;
|
||||||
|
else if( sBit == "floored" ) m_bTransforms[TRANSFORM_FLOORED] = on;
|
||||||
|
else if( sBit == "twister" ) m_bTransforms[TRANSFORM_TWISTER] = on;
|
||||||
|
else if( sBit == "nojumps" ) m_bTransforms[TRANSFORM_NOJUMPS] = on;
|
||||||
|
else if( sBit == "nohands" ) m_bTransforms[TRANSFORM_NOHANDS] = on;
|
||||||
|
else if( sBit == "noquads" ) m_bTransforms[TRANSFORM_NOQUADS] = on;
|
||||||
|
else if( sBit == "reverse" ) SET_FLOAT( fScrolls[SCROLL_REVERSE] )
|
||||||
|
else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] )
|
||||||
|
else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] )
|
||||||
|
else if( sBit == "cross" ) SET_FLOAT( fScrolls[SCROLL_CROSS] )
|
||||||
|
else if( sBit == "centered" ) SET_FLOAT( fScrolls[SCROLL_CENTERED] )
|
||||||
|
else if( sBit == "noholds" ) m_bTransforms[TRANSFORM_NOHOLDS] = on;
|
||||||
|
else if( sBit == "norolls" ) m_bTransforms[TRANSFORM_NOROLLS] = on;
|
||||||
|
else if( sBit == "nomines" ) m_bTransforms[TRANSFORM_NOMINES] = on;
|
||||||
|
else if( sBit == "nostretch" ) m_bTransforms[TRANSFORM_NOSTRETCH] = on;
|
||||||
|
else if( sBit == "dark" ) SET_FLOAT( fDark )
|
||||||
|
else if( sBit == "blind" ) SET_FLOAT( fBlind )
|
||||||
|
else if( sBit == "cover" ) SET_FLOAT( fCover )
|
||||||
|
else if( sBit == "passmark" ) SET_FLOAT( fPassmark )
|
||||||
|
else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
||||||
|
else if( sBit == "incoming" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
||||||
|
else if( sBit == "space" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
||||||
|
else if( sBit == "hallway" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
||||||
|
else if( sBit == "distant" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
|
||||||
|
else if( NOTESKIN && NOTESKIN->DoesNoteSkinExist(sBit) ) m_sNoteSkin = sBit;
|
||||||
|
else if( sBit == "noteskin" && !on ) /* "no noteskin" */ m_sNoteSkin = CommonMetrics::DEFAULT_NOTESKIN_NAME;
|
||||||
|
else if( sBit == "randomspeed" ) SET_FLOAT( fRandomSpeed )
|
||||||
|
else if( sBit == "failarcade" ||
|
||||||
|
sBit == "failimmediate" ) m_FailType = FAIL_IMMEDIATE;
|
||||||
|
else if( sBit == "failendofsong" ||
|
||||||
|
sBit == "failimmediatecontinue" ) m_FailType = FAIL_IMMEDIATE_CONTINUE;
|
||||||
|
else if( sBit == "failatend" ) m_FailType = FAIL_AT_END;
|
||||||
|
else if( sBit == "failoff" ) m_FailType = FAIL_OFF;
|
||||||
|
else if( sBit == "faildefault" )
|
||||||
|
{
|
||||||
|
PlayerOptions po;
|
||||||
|
GAMESTATE->GetDefaultPlayerOptions( po );
|
||||||
|
m_FailType = po.m_FailType;
|
||||||
|
}
|
||||||
|
else if( sBit == "addscore" ) m_ScoreDisplay = SCORING_ADD;
|
||||||
|
else if( sBit == "subtractscore" ) m_ScoreDisplay = SCORING_SUBTRACT;
|
||||||
|
else if( sBit == "averagescore" ) m_ScoreDisplay = SCORING_AVERAGE;
|
||||||
|
else if( sBit == "muteonerror" ) m_bMuteOnError = on;
|
||||||
|
else if( sBit == "random" ) ChooseRandomModifiers();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NextFloat( float fValues[], int size )
|
void NextFloat( float fValues[], int size )
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ public:
|
|||||||
void ResetSavedPrefs();
|
void ResetSavedPrefs();
|
||||||
void GetMods( vector<RString> &AddTo, bool bForceNoteSkin = false ) const;
|
void GetMods( vector<RString> &AddTo, bool bForceNoteSkin = false ) const;
|
||||||
void GetLocalizedMods( vector<RString> &AddTo ) const;
|
void GetLocalizedMods( vector<RString> &AddTo ) const;
|
||||||
void FromString( const RString &sOptions, bool bWarnOnInvalid = false );
|
void FromString( const RString &sMultipleMods );
|
||||||
|
bool FromOneModString( const RString &sOneMod, RString &sErrorDetailOut ); // On error, return false and optionally set sErrorDetailOut
|
||||||
void ChooseRandomModifiers();
|
void ChooseRandomModifiers();
|
||||||
bool ContainsTransformOrTurn() const;
|
bool ContainsTransformOrTurn() const;
|
||||||
|
|
||||||
|
|||||||
@@ -132,69 +132,82 @@ RString SongOptions::GetLocalizedString() const
|
|||||||
|
|
||||||
/* Options are added to the current settings; call Init() beforehand if
|
/* Options are added to the current settings; call Init() beforehand if
|
||||||
* you don't want this. */
|
* you don't want this. */
|
||||||
void SongOptions::FromString( const RString &sOptions )
|
void SongOptions::FromString( const RString &sMultipleMods )
|
||||||
{
|
{
|
||||||
// Init();
|
RString sTemp = sMultipleMods;
|
||||||
RString sTemp = sOptions;
|
vector<RString> vs;
|
||||||
sTemp.MakeLower();
|
split( sTemp, ",", vs, true );
|
||||||
vector<RString> asBits;
|
RString sThrowAway;
|
||||||
split( sTemp, ",", asBits, true );
|
FOREACH( RString, vs, s )
|
||||||
|
|
||||||
for( unsigned i=0; i<asBits.size(); i++ )
|
|
||||||
{
|
{
|
||||||
RString& sBit = asBits[i];
|
FromOneModString( *s, sThrowAway );
|
||||||
TrimLeft(sBit);
|
|
||||||
TrimRight(sBit);
|
|
||||||
|
|
||||||
Regex mult("^([0-9]+(\\.[0-9]+)?)xmusic$");
|
|
||||||
vector<RString> matches;
|
|
||||||
if( mult.Compare(sBit, matches) )
|
|
||||||
m_fMusicRate = StringToFloat( matches[0] );
|
|
||||||
|
|
||||||
matches.clear();
|
|
||||||
Regex lives("^([0-9]+) ?(lives|life)$");
|
|
||||||
if( lives.Compare(sBit, matches) )
|
|
||||||
m_iBatteryLives = atoi( matches[0] );
|
|
||||||
|
|
||||||
vector<RString> asParts;
|
|
||||||
split( sBit, " ", asParts, true );
|
|
||||||
bool on = true;
|
|
||||||
if( asParts.size() > 1 )
|
|
||||||
{
|
|
||||||
sBit = asParts[1];
|
|
||||||
|
|
||||||
if( asParts[0] == "no" )
|
|
||||||
on = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( sBit == "norecover" ) m_DrainType = DRAIN_NO_RECOVER;
|
|
||||||
else if( sBit == "suddendeath" ||
|
|
||||||
sBit == "death" ) m_DrainType = DRAIN_SUDDEN_DEATH;
|
|
||||||
else if( sBit == "power-drop" ) m_DrainType = DRAIN_NO_RECOVER;
|
|
||||||
else if( sBit == "normal-drain" ) m_DrainType = DRAIN_NORMAL;
|
|
||||||
|
|
||||||
else if( sBit == "clap" ) m_bAssistClap = on;
|
|
||||||
else if( sBit == "metronome" ) m_bAssistMetronome = on;
|
|
||||||
else if( sBit == "autosync" || sBit == "autosyncsong" )
|
|
||||||
m_AutosyncType = on ? AUTOSYNC_SONG : AUTOSYNC_OFF;
|
|
||||||
else if( sBit == "autosyncmachine" )
|
|
||||||
m_AutosyncType = on ? AUTOSYNC_MACHINE : AUTOSYNC_OFF;
|
|
||||||
else if( sBit == "autosynctempo" )
|
|
||||||
m_AutosyncType = on ? AUTOSYNC_TEMPO : AUTOSYNC_OFF;
|
|
||||||
else if( sBit == "effect" && !on )
|
|
||||||
m_SoundEffectType = SOUNDEFFECT_OFF;
|
|
||||||
else if( sBit == "effectspeed" )
|
|
||||||
m_SoundEffectType = on ? SOUNDEFFECT_SPEED : SOUNDEFFECT_OFF;
|
|
||||||
else if( sBit == "effectpitch" )
|
|
||||||
m_SoundEffectType = on ? SOUNDEFFECT_PITCH : SOUNDEFFECT_OFF;
|
|
||||||
else if( sBit == "savescore" ) m_bSaveScore = on;
|
|
||||||
else if( sBit == "bar" ) m_LifeType = LIFE_BAR;
|
|
||||||
else if( sBit == "battery" ) m_LifeType = LIFE_BATTERY;
|
|
||||||
else if( sBit == "lifetime" ) m_LifeType = LIFE_TIME;
|
|
||||||
else if( sBit == "haste" ) m_fHaste = on? 1.0f:0.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SongOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut )
|
||||||
|
{
|
||||||
|
RString sBit = sOneMod;
|
||||||
|
sBit.MakeLower();
|
||||||
|
TrimLeft(sBit);
|
||||||
|
TrimRight(sBit);
|
||||||
|
|
||||||
|
Regex mult("^([0-9]+(\\.[0-9]+)?)xmusic$");
|
||||||
|
vector<RString> matches;
|
||||||
|
if( mult.Compare(sBit, matches) )
|
||||||
|
{
|
||||||
|
m_fMusicRate = StringToFloat( matches[0] );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches.clear();
|
||||||
|
Regex lives("^([0-9]+) ?(lives|life)$");
|
||||||
|
if( lives.Compare(sBit, matches) )
|
||||||
|
{
|
||||||
|
m_iBatteryLives = atoi( matches[0] );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<RString> asParts;
|
||||||
|
split( sBit, " ", asParts, true );
|
||||||
|
bool on = true;
|
||||||
|
if( asParts.size() > 1 )
|
||||||
|
{
|
||||||
|
sBit = asParts[1];
|
||||||
|
if( asParts[0] == "no" )
|
||||||
|
on = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( sBit == "norecover" ) m_DrainType = DRAIN_NO_RECOVER;
|
||||||
|
else if( sBit == "suddendeath" ||
|
||||||
|
sBit == "death" ) m_DrainType = DRAIN_SUDDEN_DEATH;
|
||||||
|
else if( sBit == "power-drop" ) m_DrainType = DRAIN_NO_RECOVER;
|
||||||
|
else if( sBit == "normal-drain" ) m_DrainType = DRAIN_NORMAL;
|
||||||
|
|
||||||
|
else if( sBit == "clap" ) m_bAssistClap = on;
|
||||||
|
else if( sBit == "metronome" ) m_bAssistMetronome = on;
|
||||||
|
else if( sBit == "autosync" || sBit == "autosyncsong" )
|
||||||
|
m_AutosyncType = on ? AUTOSYNC_SONG : AUTOSYNC_OFF;
|
||||||
|
else if( sBit == "autosyncmachine" )
|
||||||
|
m_AutosyncType = on ? AUTOSYNC_MACHINE : AUTOSYNC_OFF;
|
||||||
|
else if( sBit == "autosynctempo" )
|
||||||
|
m_AutosyncType = on ? AUTOSYNC_TEMPO : AUTOSYNC_OFF;
|
||||||
|
else if( sBit == "effect" && !on )
|
||||||
|
m_SoundEffectType = SOUNDEFFECT_OFF;
|
||||||
|
else if( sBit == "effectspeed" )
|
||||||
|
m_SoundEffectType = on ? SOUNDEFFECT_SPEED : SOUNDEFFECT_OFF;
|
||||||
|
else if( sBit == "effectpitch" )
|
||||||
|
m_SoundEffectType = on ? SOUNDEFFECT_PITCH : SOUNDEFFECT_OFF;
|
||||||
|
else if( sBit == "savescore" ) m_bSaveScore = on;
|
||||||
|
else if( sBit == "bar" ) m_LifeType = LIFE_BAR;
|
||||||
|
else if( sBit == "battery" ) m_LifeType = LIFE_BATTERY;
|
||||||
|
else if( sBit == "lifetime" ) m_LifeType = LIFE_TIME;
|
||||||
|
else if( sBit == "haste" ) m_fHaste = on? 1.0f:0.0f;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool SongOptions::operator==( const SongOptions &other ) const
|
bool SongOptions::operator==( const SongOptions &other ) const
|
||||||
{
|
{
|
||||||
#define COMPARE(x) { if( x != other.x ) return false; }
|
#define COMPARE(x) { if( x != other.x ) return false; }
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
RString GetString() const;
|
RString GetString() const;
|
||||||
RString GetLocalizedString() const;
|
RString GetLocalizedString() const;
|
||||||
void FromString( const RString &sOptions );
|
void FromString( const RString &sOptions );
|
||||||
|
bool FromOneModString( const RString &sOneMod, RString &sErrorDetailOut ); // On error, return false and optionally set sErrorDetailOut
|
||||||
|
|
||||||
bool operator==( const SongOptions &other ) const;
|
bool operator==( const SongOptions &other ) const;
|
||||||
bool operator!=( const SongOptions &other ) const { return !operator==(other); }
|
bool operator!=( const SongOptions &other ) const { return !operator==(other); }
|
||||||
|
|||||||
Reference in New Issue
Block a user