diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 964eb04199..b10019410c 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -780,6 +780,7 @@ + @@ -1453,6 +1454,20 @@ + + + + + + + + + + + + + + @@ -1777,6 +1792,12 @@ + + + + + + @@ -1832,6 +1853,11 @@ + + + + + @@ -1951,6 +1977,11 @@ + + + + + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 1adcb4b5c3..589d6da91b 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -2335,6 +2335,9 @@ save yourself some time, copy this for undocumented things: Returns the song options as a string. + + Returns the song options for the specified ModsLevel as an object. + Returns how much of the song is through at beat fBeat. @@ -2830,7 +2833,7 @@ save yourself some time, copy this for undocumented things: - Most options fall into one of two types: float or bool.
+ Most options fall into one of four types: float, int, bool, or enum.
Float type options have this interface:
Option(value, approach_speed)
If value is a float, sets the TimeSpacing modifier to value.
@@ -2843,7 +2846,9 @@ save yourself some time, copy this for undocumented things: a,b= options:Boost(5) -- Sets a and b to the previous values, NOT to 5 and .5. Sets the value to 5 and leaves the approach speed at whatever it was.

Setting the approach speed only matters when modifying the PlayerOptions from ModsLevel_Song.
+ Int type options are similar to float in that they return and take a number, but they do not have an approach speed.
Bool type options have an almost identical interface, the difference is that they can not have an approach speed.
+ Enum type options are almost identical to bool type. They take and return an enum value.
For brevity, the functions are only given a description if the option requires careful handling or does not follow the float or bool interfaces.
@@ -4044,6 +4049,36 @@ save yourself some time, copy this for undocumented things: Returns true if the specified song was loaded from AdditionalSongs.
+ + + See the description for PlayerOptions. The functions follow the same design. + + + + + + + + + + + + + + + + + + + + + + + Limited to the range 0 < rate <= 3 because speeds greater than 3 are likely to crash. + + + + Returns the current beats per second. diff --git a/src/AdjustSync.cpp b/src/AdjustSync.cpp index fb88d39475..0234cffbf4 100644 --- a/src/AdjustSync.cpp +++ b/src/AdjustSync.cpp @@ -141,25 +141,22 @@ void AdjustSync::RevertSyncChanges() static LocalizedString AUTOSYNC_CORRECTION_APPLIED ( "AdjustSync", "Autosync: Correction applied." ); static LocalizedString AUTOSYNC_CORRECTION_NOT_APPLIED ( "AdjustSync", "Autosync: Correction NOT applied. Deviation too high." ); -static LocalizedString AUTOSYNC_SONG ( "AdjustSync", "Autosync Song" ); -static LocalizedString AUTOSYNC_MACHINE ( "AdjustSync", "Autosync Machine" ); -static LocalizedString AUTOSYNC_TEMPO ( "AdjustSync", "Autosync Tempo" ); void AdjustSync::HandleAutosync( float fNoteOffBySeconds, float fStepTime ) { if( GAMESTATE->IsCourseMode() ) return; - SongOptions::AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; + AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; switch( type ) { - case SongOptions::AUTOSYNC_OFF: + case AutosyncType_Off: return; - case SongOptions::AUTOSYNC_TEMPO: + case AutosyncType_Tempo: { // We collect all of the data and process it at the end s_vAutosyncTempoData.push_back( make_pair(fStepTime, fNoteOffBySeconds) ); break; } - case SongOptions::AUTOSYNC_MACHINE: - case SongOptions::AUTOSYNC_SONG: + case AutosyncType_Machine: + case AutosyncType_Song: { s_fAutosyncOffset[s_iAutosyncOffsetSample] = fNoteOffBySeconds; ++s_iAutosyncOffsetSample; @@ -179,7 +176,7 @@ void AdjustSync::HandleSongEnd() { if( GAMESTATE->IsCourseMode() ) return; - if( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType == SongOptions::AUTOSYNC_TEMPO ) + if( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType == AutosyncType_Tempo ) { AutosyncTempo(); } @@ -192,25 +189,13 @@ void AdjustSync::AutosyncOffset() const float mean = calc_mean( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT ); const float stddev = calc_stddev( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT ); - RString sAutosyncType; - SongOptions::AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; - switch( type ) - { - case SongOptions::AUTOSYNC_SONG: - sAutosyncType = AUTOSYNC_SONG; - break; - case SongOptions::AUTOSYNC_MACHINE: - sAutosyncType = AUTOSYNC_MACHINE; - break; - default: - FAIL_M(ssprintf("Invalid autosync type: %i", type)); - } + AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; if( stddev < .03f ) // If they stepped with less than .03 error { switch( type ) { - case SongOptions::AUTOSYNC_SONG: + case AutosyncType_Song: { GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += mean; const vector& vpSteps = GAMESTATE->m_pCurSong->GetAllSteps(); @@ -224,7 +209,7 @@ void AdjustSync::AutosyncOffset() } break; } - case SongOptions::AUTOSYNC_MACHINE: + case AutosyncType_Machine: // Step timing is not needed for this operation. PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean ); break; diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp index e3b60582d2..cf399ad2ef 100644 --- a/src/GameCommand.cpp +++ b/src/GameCommand.cpp @@ -805,9 +805,9 @@ void GameCommand::ApplySelf( const vector &vpns ) const // we don't override the user's changes if they back out. if( GAMESTATE->m_PlayMode == PLAY_MODE_ONI && GAMESTATE->m_PlayMode != OldPlayMode && - GAMESTATE->m_SongOptions.GetStage().m_LifeType == SongOptions::LIFE_BAR ) + GAMESTATE->m_SongOptions.GetStage().m_LifeType == LifeType_Bar ) { - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_BATTERY ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, LifeType_Battery ); } } diff --git a/src/GameState.cpp b/src/GameState.cpp index 12554cb666..fd135343d8 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -2366,6 +2366,12 @@ public: LuaHelpers::Push( L, s ); return 1; } + static int GetSongOptionsObject( T* p, lua_State *L ) + { + ModsLevel m = Enum::Check( L, 1 ); + p->m_SongOptions.Get(m).PushSelf(L); + return 1; + } static int GetDefaultSongOptions( T* p, lua_State *L ) { SongOptions so; @@ -2643,6 +2649,7 @@ public: ADD_METHOD( GetPremium ); ADD_METHOD( GetSongOptionsString ); ADD_METHOD( GetSongOptions ); + ADD_METHOD( GetSongOptionsObject ); ADD_METHOD( GetDefaultSongOptions ); ADD_METHOD( ApplyPreferredModifiers ); ADD_METHOD( ApplyStageModifiers ); diff --git a/src/LifeMeter.cpp b/src/LifeMeter.cpp index 1d6fd285fb..2f72d0c953 100644 --- a/src/LifeMeter.cpp +++ b/src/LifeMeter.cpp @@ -4,13 +4,13 @@ #include "LifeMeterBattery.h" #include "LifeMeterTime.h" -LifeMeter *LifeMeter::MakeLifeMeter( SongOptions::LifeType t ) +LifeMeter *LifeMeter::MakeLifeMeter( LifeType t ) { switch( t ) { - case SongOptions::LIFE_BAR: return new LifeMeterBar; - case SongOptions::LIFE_BATTERY: return new LifeMeterBattery; - case SongOptions::LIFE_TIME: return new LifeMeterTime; + case LifeType_Bar: return new LifeMeterBar; + case LifeType_Battery: return new LifeMeterBattery; + case LifeType_Time: return new LifeMeterTime; default: FAIL_M(ssprintf("Unrecognized LifeMeter type: %i", t)); } diff --git a/src/LifeMeter.h b/src/LifeMeter.h index 33a74be67f..1f45c68bea 100644 --- a/src/LifeMeter.h +++ b/src/LifeMeter.h @@ -41,7 +41,7 @@ public: virtual float GetLife() const { return 0; } // for cosmetic use only virtual void UpdateNonstopLifebar() { } - static LifeMeter *MakeLifeMeter( SongOptions::LifeType t ); + static LifeMeter *MakeLifeMeter( LifeType t ); // // Lua diff --git a/src/LifeMeterBar.cpp b/src/LifeMeterBar.cpp index 90a9106228..09f56eea70 100644 --- a/src/LifeMeterBar.cpp +++ b/src/LifeMeterBar.cpp @@ -31,16 +31,16 @@ LifeMeterBar::LifeMeterBar() m_pPlayerState = NULL; - SongOptions::DrainType dtype = GAMESTATE->m_SongOptions.GetStage().m_DrainType; + DrainType dtype = GAMESTATE->m_SongOptions.GetStage().m_DrainType; switch( dtype ) { - case SongOptions::DRAIN_NORMAL: + case DrainType_Normal: m_fLifePercentage = INITIAL_VALUE; break; /* These types only go down, so they always start at full. */ - case SongOptions::DRAIN_NO_RECOVER: - case SongOptions::DRAIN_SUDDEN_DEATH: + case DrainType_NoRecover: + case DrainType_SuddenDeath: m_fLifePercentage = 1.0f; break; default: FAIL_M(ssprintf("Invalid DrainType: %i", dtype)); @@ -132,12 +132,12 @@ void LifeMeterBar::ChangeLife( TapNoteScore score ) switch( GAMESTATE->m_SongOptions.GetSong().m_DrainType ) { DEFAULT_FAIL( GAMESTATE->m_SongOptions.GetSong().m_DrainType ); - case SongOptions::DRAIN_NORMAL: + case DrainType_Normal: break; - case SongOptions::DRAIN_NO_RECOVER: + case DrainType_NoRecover: fDeltaLife = min( fDeltaLife, 0 ); break; - case SongOptions::DRAIN_SUDDEN_DEATH: + case DrainType_SuddenDeath: if( score < MIN_STAY_ALIVE ) fDeltaLife = -1.0f; else @@ -151,10 +151,10 @@ void LifeMeterBar::ChangeLife( TapNoteScore score ) void LifeMeterBar::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) { float fDeltaLife=0.f; - SongOptions::DrainType dtype = GAMESTATE->m_SongOptions.GetSong().m_DrainType; + DrainType dtype = GAMESTATE->m_SongOptions.GetSong().m_DrainType; switch( dtype ) { - case SongOptions::DRAIN_NORMAL: + case DrainType_Normal: switch( score ) { case HNS_Held: fDeltaLife = m_fLifePercentChange.GetValue(SE_Held); break; @@ -166,7 +166,7 @@ void LifeMeterBar::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) if( IsHot() && score == HNS_LetGo ) fDeltaLife = -0.10f; // make it take a while to get back to "hot" break; - case SongOptions::DRAIN_NO_RECOVER: + case DrainType_NoRecover: switch( score ) { case HNS_Held: fDeltaLife = +0.000f; break; @@ -176,7 +176,7 @@ void LifeMeterBar::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) FAIL_M(ssprintf("Invalid HoldNoteScore: %i", score)); } break; - case SongOptions::DRAIN_SUDDEN_DEATH: + case DrainType_SuddenDeath: switch( score ) { case HNS_Held: fDeltaLife = +0; break; @@ -221,14 +221,14 @@ void LifeMeterBar::ChangeLife( float fDeltaLife ) switch( GAMESTATE->m_SongOptions.GetSong().m_DrainType ) { - case SongOptions::DRAIN_NORMAL: - case SongOptions::DRAIN_NO_RECOVER: + case DrainType_Normal: + case DrainType_NoRecover: if( fDeltaLife > 0 ) fDeltaLife *= m_fLifeDifficulty; else fDeltaLife /= m_fLifeDifficulty; break; - case SongOptions::DRAIN_SUDDEN_DEATH: + case DrainType_SuddenDeath: // This should always -1.0f; if( fDeltaLife < 0 ) fDeltaLife = -1.0f; diff --git a/src/LuaBinding.cpp b/src/LuaBinding.cpp index a264675164..0c7aa4dc21 100644 --- a/src/LuaBinding.cpp +++ b/src/LuaBinding.cpp @@ -376,6 +376,25 @@ LuaClass::~LuaClass() LUA->Release( L ); } +void DefaultNilArgs(lua_State* L, int n) +{ + while(lua_gettop(L) < n) + { + lua_pushnil(L); + } +} + +float FArgGTEZero(lua_State* L, int index) +{ + float s= FArg(index); + if(s < 0) + { + luaL_error(L, "Arg must be greater than or equal to zero."); + } + return s; +} + + /* * (c) 2005 Glenn Maynard * All rights reserved. diff --git a/src/LuaBinding.h b/src/LuaBinding.h index 91c0392646..91c27c6dec 100644 --- a/src/LuaBinding.h +++ b/src/LuaBinding.h @@ -170,6 +170,11 @@ public: #define LIST_METHOD( method_name ) \ { #method_name, method_name } +// Explicitly separates the stack into args and return values. +// This way, the stack can safely be used to store the previous values. +void DefaultNilArgs(lua_State* L, int n); +float FArgGTEZero(lua_State* L, int index); + #endif /* diff --git a/src/OptionsBinding.h b/src/OptionsBinding.h new file mode 100644 index 0000000000..67628b541b --- /dev/null +++ b/src/OptionsBinding.h @@ -0,0 +1,95 @@ +/* OptionsBinding - little helpers so that SongOptions and PlayerOptions can more easily have similar interfaces. */ + +// No .cpp file because it's just some #defines, and not in a makefile because it doesn't need to be. +// DefaultNilArgs would be in here, but then there would need to be a .cpp file, and DefaultNilArgs is more widely useful. + +#ifndef OptionsBinding_H +#define OptionsBinding_H + // Functions are designed to combine Get and Set into one, to be less clumsy to use. -Kyz + // If a valid arg is passed, the value is set. + // The previous value is returned. +#define FLOAT_INTERFACE(func_name, member, valid) \ + static int func_name(T* p, lua_State* L) \ + { \ + DefaultNilArgs(L, 2); \ + lua_pushnumber(L, p->m_f ## member); \ + lua_pushnumber(L, p->m_Speedf ## member); \ + if(lua_isnumber(L, 1)) \ + { \ + float v= FArg(1); \ + if(!valid) \ + { \ + luaL_error(L, "Invalid value %f", v); \ + } \ + p->m_f ## member = v; \ + if(p->m_Speedf ## member <= 0.0f) \ + { \ + p->m_Speedf ## member = 1.0f; \ + } \ + } \ + if(lua_isnumber(L, 2)) \ + { \ + p->m_Speedf ## member = FArgGTEZero(L, 2); \ + } \ + return 2; \ + } +#define INT_INTERFACE(func_name, member) \ + static int func_name(T* p, lua_State* L) \ + { \ + DefaultNilArgs(L, 1); \ + lua_pushnumber(L, p->m_i ## member); \ + if(lua_isnumber(L, 1)) \ + { \ + p->m_i ## member = IArg(1); \ + } \ + return 1; \ + } +#define BOOL_INTERFACE(func_name, member) \ + static int func_name(T* p, lua_State* L) \ + { \ + DefaultNilArgs(L, 1); \ + lua_pushboolean(L, p->m_b ## member); \ + if(lua_isboolean(L, 1)) \ + { \ + p->m_b ## member = BArg(1); \ + } \ + return 1; \ + } +#define ENUM_INTERFACE(func_name, member, enum_name) \ + static int func_name(T* p, lua_State* L) \ + { \ + DefaultNilArgs(L, 1); \ + Enum::Push(L, p->m_ ## member); \ + if(!lua_isnil(L, 1)) \ + { \ + p->m_ ## member= Enum::Check(L, 1); \ + } \ + return 1; \ + } + +#endif + +/* + * (c) 2014 Eric Reese + * 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. + */ diff --git a/src/Player.cpp b/src/Player.cpp index 250446001a..f9abacbcd5 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -629,7 +629,7 @@ void Player::Load() // TODO: Remove use of PlayerNumber. PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - bool bOniDead = GAMESTATE->m_SongOptions.GetStage().m_LifeType == SongOptions::LIFE_BATTERY && + bool bOniDead = GAMESTATE->m_SongOptions.GetStage().m_LifeType == LifeType_Battery && (m_pPlayerStageStats == NULL || m_pPlayerStageStats->m_bFailed); /* The editor reuses Players ... so we really need to make sure everything @@ -1782,7 +1782,7 @@ int Player::GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRows bool Player::IsOniDead() const { // If we're playing on oni and we've died, do nothing. - return GAMESTATE->m_SongOptions.GetCurrent().m_LifeType == SongOptions::LIFE_BATTERY && m_pPlayerStageStats && m_pPlayerStageStats->m_bFailed; + return GAMESTATE->m_SongOptions.GetCurrent().m_LifeType == LifeType_Battery && m_pPlayerStageStats && m_pPlayerStageStats->m_bFailed; } void Player::Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ) diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index b5eeadb339..cc354c3b95 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -908,6 +908,7 @@ void PlayerOptions::ResetPrefs( ResetPrefsType type ) // lua start #include "LuaBinding.h" +#include "OptionsBinding.h" /** @brief Allow Lua to have access to PlayerOptions. */ class LunaPlayerOptions: public Luna @@ -930,107 +931,53 @@ public: return 1; } - static float CheckedApproachSpeed(lua_State* L, float s) - { - if(s < 0) - { - luaL_error(L, "Approach speed must be greater than or equal to zero."); - } - return s; - } - - // Explicitly separates the stack into args and return values. - // This way, the stack can safely be used to store the previous values. - static void DefaultNilArgs(lua_State* L, int n) - { - while(lua_gettop(L) < n) - { - lua_pushnil(L); - } - } - - // Functions are designed to combine Get and Set into one, to be less clumsy to use. -Kyz - // If a valid arg is passed, the value is set. - // The previous value is returned. -#define FLOAT_INTERFACE(func_name, member) \ - static int func_name(T* p, lua_State* L) \ - { \ - DefaultNilArgs(L, 2); \ - lua_pushnumber(L, p->m_f ## member); \ - lua_pushnumber(L, p->m_Speedf ## member); \ - if(lua_isnumber(L, 1)) \ - { \ - p->m_f ## member = FArg(1); \ - if(p->m_Speedf ## member <= 0.0f) \ - { \ - p->m_Speedf ## member = 1.0f; \ - } \ - } \ - if(lua_isnumber(L, 2)) \ - { \ - p->m_Speedf ## member = CheckedApproachSpeed(L, FArg(2)); \ - } \ - return 2; \ - } -#define BOOL_INTERFACE(func_name, member) \ - static int func_name(T* p, lua_State* L) \ - { \ - DefaultNilArgs(L, 1); \ - lua_pushboolean(L, p->m_b ## member); \ - if(lua_isboolean(L, 1)) \ - { \ - p->m_b ## member = BArg(1); \ - } \ - return 1; \ - } - // Direct control functions, for themes that can handle it. - FLOAT_INTERFACE(TimeSpacing, TimeSpacing); - FLOAT_INTERFACE(MaxScrollBPM, MaxScrollBPM); - FLOAT_INTERFACE(ScrollSpeed, ScrollSpeed); - FLOAT_INTERFACE(ScrollBPM, ScrollBPM); - FLOAT_INTERFACE(Boost, Accels[PlayerOptions::ACCEL_BOOST]); - FLOAT_INTERFACE(Brake, Accels[PlayerOptions::ACCEL_BRAKE]); - FLOAT_INTERFACE(Wave, Accels[PlayerOptions::ACCEL_WAVE]); - FLOAT_INTERFACE(Expand, Accels[PlayerOptions::ACCEL_EXPAND]); - FLOAT_INTERFACE(Boomerang, Accels[PlayerOptions::ACCEL_BOOMERANG]); - FLOAT_INTERFACE(Drunk, Effects[PlayerOptions::EFFECT_DRUNK]); - FLOAT_INTERFACE(Dizzy, Effects[PlayerOptions::EFFECT_DIZZY]); - FLOAT_INTERFACE(Confusion, Effects[PlayerOptions::EFFECT_CONFUSION]); - FLOAT_INTERFACE(Mini, Effects[PlayerOptions::EFFECT_MINI]); - FLOAT_INTERFACE(Tiny, Effects[PlayerOptions::EFFECT_TINY]); - FLOAT_INTERFACE(Flip, Effects[PlayerOptions::EFFECT_FLIP]); - FLOAT_INTERFACE(Invert, Effects[PlayerOptions::EFFECT_INVERT]); - FLOAT_INTERFACE(Tornado, Effects[PlayerOptions::EFFECT_TORNADO]); - FLOAT_INTERFACE(Tipsy, Effects[PlayerOptions::EFFECT_TIPSY]); - FLOAT_INTERFACE(Bumpy, Effects[PlayerOptions::EFFECT_BUMPY]); - FLOAT_INTERFACE(Beat, Effects[PlayerOptions::EFFECT_BEAT]); - FLOAT_INTERFACE(Xmode, Effects[PlayerOptions::EFFECT_XMODE]); - FLOAT_INTERFACE(Twirl, Effects[PlayerOptions::EFFECT_TWIRL]); - FLOAT_INTERFACE(Roll, Effects[PlayerOptions::EFFECT_ROLL]); - FLOAT_INTERFACE(Hidden, Appearances[PlayerOptions::APPEARANCE_HIDDEN]); - FLOAT_INTERFACE(HiddenOffset, Appearances[PlayerOptions::APPEARANCE_HIDDEN_OFFSET]); - FLOAT_INTERFACE(Sudden, Appearances[PlayerOptions::APPEARANCE_SUDDEN]); - FLOAT_INTERFACE(SuddenOffset, Appearances[PlayerOptions::APPEARANCE_SUDDEN_OFFSET]); - FLOAT_INTERFACE(Stealth, Appearances[PlayerOptions::APPEARANCE_STEALTH]); - FLOAT_INTERFACE(Blink, Appearances[PlayerOptions::APPEARANCE_BLINK]); - FLOAT_INTERFACE(RandomVanish, Appearances[PlayerOptions::APPEARANCE_RANDOMVANISH]); - FLOAT_INTERFACE(Reverse, Scrolls[PlayerOptions::SCROLL_REVERSE]); - FLOAT_INTERFACE(Split, Scrolls[PlayerOptions::SCROLL_SPLIT]); - FLOAT_INTERFACE(Alternate, Scrolls[PlayerOptions::SCROLL_ALTERNATE]); - FLOAT_INTERFACE(Cross, Scrolls[PlayerOptions::SCROLL_CROSS]); - FLOAT_INTERFACE(Centered, Scrolls[PlayerOptions::SCROLL_CENTERED]); - FLOAT_INTERFACE(Dark, Dark); - FLOAT_INTERFACE(Blind, Blind); - FLOAT_INTERFACE(Cover, Cover); - FLOAT_INTERFACE(RandAttack, RandAttack); - FLOAT_INTERFACE(NoAttack, NoAttack); - FLOAT_INTERFACE(PlayerAutoPlay, PlayerAutoPlay); - FLOAT_INTERFACE(Skew, Skew); - FLOAT_INTERFACE(Tilt, PerspectiveTilt); - FLOAT_INTERFACE(Passmark, Passmark); // Passmark is not sanity checked to the [0, 1] range because LifeMeterBar::IsFailing is the only thing that uses it, and it's used in a <= test. Any theme passing a value outside the [0, 1] range probably expects the result they get. -Kyz - FLOAT_INTERFACE(RandomSpeed, RandomSpeed); + FLOAT_INTERFACE(TimeSpacing, TimeSpacing, true); + FLOAT_INTERFACE(MaxScrollBPM, MaxScrollBPM, true); + FLOAT_INTERFACE(ScrollSpeed, ScrollSpeed, true); + FLOAT_INTERFACE(ScrollBPM, ScrollBPM, true); + FLOAT_INTERFACE(Boost, Accels[PlayerOptions::ACCEL_BOOST], true); + FLOAT_INTERFACE(Brake, Accels[PlayerOptions::ACCEL_BRAKE], true); + FLOAT_INTERFACE(Wave, Accels[PlayerOptions::ACCEL_WAVE], true); + FLOAT_INTERFACE(Expand, Accels[PlayerOptions::ACCEL_EXPAND], true); + FLOAT_INTERFACE(Boomerang, Accels[PlayerOptions::ACCEL_BOOMERANG], true); + FLOAT_INTERFACE(Drunk, Effects[PlayerOptions::EFFECT_DRUNK], true); + FLOAT_INTERFACE(Dizzy, Effects[PlayerOptions::EFFECT_DIZZY], true); + FLOAT_INTERFACE(Confusion, Effects[PlayerOptions::EFFECT_CONFUSION], true); + FLOAT_INTERFACE(Mini, Effects[PlayerOptions::EFFECT_MINI], true); + FLOAT_INTERFACE(Tiny, Effects[PlayerOptions::EFFECT_TINY], true); + FLOAT_INTERFACE(Flip, Effects[PlayerOptions::EFFECT_FLIP], true); + FLOAT_INTERFACE(Invert, Effects[PlayerOptions::EFFECT_INVERT], true); + FLOAT_INTERFACE(Tornado, Effects[PlayerOptions::EFFECT_TORNADO], true); + FLOAT_INTERFACE(Tipsy, Effects[PlayerOptions::EFFECT_TIPSY], true); + FLOAT_INTERFACE(Bumpy, Effects[PlayerOptions::EFFECT_BUMPY], true); + FLOAT_INTERFACE(Beat, Effects[PlayerOptions::EFFECT_BEAT], true); + FLOAT_INTERFACE(Xmode, Effects[PlayerOptions::EFFECT_XMODE], true); + FLOAT_INTERFACE(Twirl, Effects[PlayerOptions::EFFECT_TWIRL], true); + FLOAT_INTERFACE(Roll, Effects[PlayerOptions::EFFECT_ROLL], true); + FLOAT_INTERFACE(Hidden, Appearances[PlayerOptions::APPEARANCE_HIDDEN], true); + FLOAT_INTERFACE(HiddenOffset, Appearances[PlayerOptions::APPEARANCE_HIDDEN_OFFSET], true); + FLOAT_INTERFACE(Sudden, Appearances[PlayerOptions::APPEARANCE_SUDDEN], true); + FLOAT_INTERFACE(SuddenOffset, Appearances[PlayerOptions::APPEARANCE_SUDDEN_OFFSET], true); + FLOAT_INTERFACE(Stealth, Appearances[PlayerOptions::APPEARANCE_STEALTH], true); + FLOAT_INTERFACE(Blink, Appearances[PlayerOptions::APPEARANCE_BLINK], true); + FLOAT_INTERFACE(RandomVanish, Appearances[PlayerOptions::APPEARANCE_RANDOMVANISH], true); + FLOAT_INTERFACE(Reverse, Scrolls[PlayerOptions::SCROLL_REVERSE], true); + FLOAT_INTERFACE(Split, Scrolls[PlayerOptions::SCROLL_SPLIT], true); + FLOAT_INTERFACE(Alternate, Scrolls[PlayerOptions::SCROLL_ALTERNATE], true); + FLOAT_INTERFACE(Cross, Scrolls[PlayerOptions::SCROLL_CROSS], true); + FLOAT_INTERFACE(Centered, Scrolls[PlayerOptions::SCROLL_CENTERED], true); + FLOAT_INTERFACE(Dark, Dark, true); + FLOAT_INTERFACE(Blind, Blind, true); + FLOAT_INTERFACE(Cover, Cover, true); + FLOAT_INTERFACE(RandAttack, RandAttack, true); + FLOAT_INTERFACE(NoAttack, NoAttack, true); + FLOAT_INTERFACE(PlayerAutoPlay, PlayerAutoPlay, true); + FLOAT_INTERFACE(Skew, Skew, true); + FLOAT_INTERFACE(Tilt, PerspectiveTilt, true); + FLOAT_INTERFACE(Passmark, Passmark, true); // Passmark is not sanity checked to the [0, 1] range because LifeMeterBar::IsFailing is the only thing that uses it, and it's used in a <= test. Any theme passing a value outside the [0, 1] range probably expects the result they get. -Kyz + FLOAT_INTERFACE(RandomSpeed, RandomSpeed, true); BOOL_INTERFACE(TurnNone, Turns[PlayerOptions::TURN_NONE]); BOOL_INTERFACE(Mirror, Turns[PlayerOptions::TURN_MIRROR]); BOOL_INTERFACE(Backwards, Turns[PlayerOptions::TURN_BACKWARDS]); @@ -1063,9 +1010,7 @@ public: BOOL_INTERFACE(NoQuads, Transforms[PlayerOptions::TRANSFORM_NOQUADS]); BOOL_INTERFACE(NoStretch, Transforms[PlayerOptions::TRANSFORM_NOSTRETCH]); BOOL_INTERFACE(MuteOnError, MuteOnError); - -#undef FLOAT_INTERFACE -#undef BOOL_INTERFACE + ENUM_INTERFACE(FailSetting, FailType, FailType); // NoteSkins static int NoteSkin(T* p, lua_State* L) @@ -1098,17 +1043,6 @@ public: return 2; } - static int FailSetting(T* p, lua_State* L) - { - DefaultNilArgs(L, 1); - Enum::Push(L, p->m_FailType); - if(lua_isstring(L, 1)) - { - p->m_FailType= Enum::Check(L, 1); - } - return 1; - } - static void SetSpeedModApproaches(T* p, float speed) { p->m_SpeedfScrollBPM= speed; @@ -1147,7 +1081,7 @@ public: } if(lua_isnumber(L, 2)) { - SetSpeedModApproaches(p, CheckedApproachSpeed(L, FArg(2))); + SetSpeedModApproaches(p, FArgGTEZero(L, 2)); } return 2; } @@ -1174,7 +1108,7 @@ public: } if(lua_isnumber(L, 2)) { - SetSpeedModApproaches(p, CheckedApproachSpeed(L, FArg(2))); + SetSpeedModApproaches(p, FArgGTEZero(L, 2)); } return 2; } @@ -1206,7 +1140,7 @@ public: } if(lua_isnumber(L, 2)) { - SetSpeedModApproaches(p, CheckedApproachSpeed(L, FArg(2))); + SetSpeedModApproaches(p, FArgGTEZero(L, 2)); } return 2; } @@ -1228,7 +1162,7 @@ public: } if(lua_isnumber(L, 2)) { - SetPerspectiveApproach(p, L, CheckedApproachSpeed(L, FArg(2))); + SetPerspectiveApproach(p, L, FArgGTEZero(L, 2)); } return 1; } @@ -1255,7 +1189,7 @@ public: } if(lua_isnumber(L, 2)) { - SetPerspectiveApproach(p, L, CheckedApproachSpeed(L, FArg(2))); + SetPerspectiveApproach(p, L, FArgGTEZero(L, 2)); } return 2; } @@ -1282,7 +1216,7 @@ public: } if(lua_isnumber(L, 2)) { - SetPerspectiveApproach(p, L, CheckedApproachSpeed(L, FArg(2))); + SetPerspectiveApproach(p, L, FArgGTEZero(L, 2)); } return 2; } @@ -1307,7 +1241,7 @@ public: } if(lua_isnumber(L, 2)) { - SetPerspectiveApproach(p, L, CheckedApproachSpeed(L, FArg(2))); + SetPerspectiveApproach(p, L, FArgGTEZero(L, 2)); } return 2; } @@ -1332,7 +1266,7 @@ public: } if(lua_isnumber(L, 2)) { - SetPerspectiveApproach(p, L, CheckedApproachSpeed(L, FArg(2))); + SetPerspectiveApproach(p, L, FArgGTEZero(L, 2)); } return 2; } diff --git a/src/ScreenDebugOverlay.cpp b/src/ScreenDebugOverlay.cpp index 68204bd00c..3cdfe08a9f 100644 --- a/src/ScreenDebugOverlay.cpp +++ b/src/ScreenDebugOverlay.cpp @@ -647,28 +647,28 @@ class DebugLineAutosync : public IDebugLine virtual RString GetDisplayTitle() { return AUTOSYNC.GetValue(); } virtual RString GetDisplayValue() { - SongOptions::AutosyncType type = GAMESTATE->m_SongOptions.GetSong().m_AutosyncType; + AutosyncType type = GAMESTATE->m_SongOptions.GetSong().m_AutosyncType; switch( type ) { - case SongOptions::AUTOSYNC_OFF: return OFF.GetValue(); break; - case SongOptions::AUTOSYNC_SONG: return SONG.GetValue(); break; - case SongOptions::AUTOSYNC_MACHINE: return MACHINE.GetValue(); break; - case SongOptions::AUTOSYNC_TEMPO: return SYNC_TEMPO.GetValue(); break; + case AutosyncType_Off: return OFF.GetValue(); break; + case AutosyncType_Song: return SONG.GetValue(); break; + case AutosyncType_Machine: return MACHINE.GetValue(); break; + case AutosyncType_Tempo: return SYNC_TEMPO.GetValue(); break; default: FAIL_M(ssprintf("Invalid autosync type: %i", type)); } } virtual Type GetType() const { return IDebugLine::gameplay_only; } - virtual bool IsEnabled() { return GAMESTATE->m_SongOptions.GetSong().m_AutosyncType!=SongOptions::AUTOSYNC_OFF; } + virtual bool IsEnabled() { return GAMESTATE->m_SongOptions.GetSong().m_AutosyncType!=AutosyncType_Off; } virtual void DoAndLog( RString &sMessageOut ) { int as = GAMESTATE->m_SongOptions.GetSong().m_AutosyncType + 1; bool bAllowSongAutosync = !GAMESTATE->IsCourseMode(); if( !bAllowSongAutosync && - ( as == SongOptions::AUTOSYNC_SONG || as == SongOptions::AUTOSYNC_TEMPO ) ) - as = SongOptions::AUTOSYNC_MACHINE; - wrap( as, SongOptions::NUM_AUTOSYNC_TYPES ); - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Song, m_AutosyncType, SongOptions::AutosyncType(as) ); + ( as == AutosyncType_Song || as == AutosyncType_Tempo ) ) + as = AutosyncType_Machine; + wrap( as, NUM_AutosyncType ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Song, m_AutosyncType, AutosyncType(as) ); MESSAGEMAN->Broadcast( Message_AutosyncChanged ); IDebugLine::DoAndLog( sMessageOut ); } diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index efae737af1..ed67500d1b 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -135,7 +135,7 @@ void PlayerInfo::Load( PlayerNumber pn, MultiPlayer mp, bool bShowNoteField, int break; case PLAY_MODE_ONI: case PLAY_MODE_ENDLESS: - if( GAMESTATE->m_SongOptions.GetStage().m_LifeType == SongOptions::LIFE_TIME ) + if( GAMESTATE->m_SongOptions.GetStage().m_LifeType == LifeType_Time ) m_pPrimaryScoreDisplay = new ScoreDisplayLifeTime; else m_pPrimaryScoreDisplay = new ScoreDisplayOni; @@ -570,7 +570,7 @@ void ScreenGameplay::Init() // not 100% sure of that. -freem if( !GAMESTATE->IsPlayerEnabled(pi->m_pn) && SHOW_LIFE_METER_FOR_DISABLED_PLAYERS ) { - if(GAMESTATE->m_SongOptions.GetStage().m_LifeType == SongOptions::LIFE_BAR) + if(GAMESTATE->m_SongOptions.GetStage().m_LifeType == LifeType_Bar) static_cast(pi->m_pLifeMeter)->ChangeLife(-1.0f); } } @@ -1017,9 +1017,9 @@ void ScreenGameplay::SetupSong( int iSongIndex ) RString sType; switch( GAMESTATE->m_SongOptions.GetCurrent().m_SoundEffectType ) { - case SongOptions::SOUNDEFFECT_OFF: sType = "SoundEffectControl_Off"; break; - case SongOptions::SOUNDEFFECT_SPEED: sType = "SoundEffectControl_Speed"; break; - case SongOptions::SOUNDEFFECT_PITCH: sType = "SoundEffectControl_Pitch"; break; + case SoundEffectType_Off: sType = "SoundEffectControl_Off"; break; + case SoundEffectType_Speed: sType = "SoundEffectControl_Speed"; break; + case SoundEffectType_Pitch: sType = "SoundEffectControl_Pitch"; break; default: break; } @@ -1082,7 +1082,7 @@ void ScreenGameplay::LoadNextSong() /* If we're in battery mode, force FailImmediate. We assume in Player::Step * that failed players can't step. */ - if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType == SongOptions::LIFE_BATTERY ) + if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType == LifeType_Battery ) { FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) PO_GROUP_ASSIGN( pi->GetPlayerState()->m_PlayerOptions, ModsLevel_Song, m_FailType, FailType_Immediate ); @@ -1118,10 +1118,10 @@ void ScreenGameplay::LoadNextSong() // reset oni game over graphic SET_XY_AND_ON_COMMAND( pi->m_sprOniGameOver ); - if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType==SongOptions::LIFE_BATTERY && pi->GetPlayerStageStats()->m_bFailed ) // already failed + if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType==LifeType_Battery && pi->GetPlayerStageStats()->m_bFailed ) // already failed pi->ShowOniGameOver(); - if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType==SongOptions::LIFE_BAR && pi->m_pLifeMeter ) + if( GAMESTATE->m_SongOptions.GetCurrent().m_LifeType==LifeType_Bar && pi->m_pLifeMeter ) pi->m_pLifeMeter->UpdateNonstopLifebar(); if( pi->m_pStepsDisplay ) @@ -1634,7 +1634,7 @@ void ScreenGameplay::Update( float fDeltaTime ) PlayerNumber pn = pi->GetStepsAndTrailIndex(); FailType ft = GAMESTATE->GetPlayerFailType( pi->GetPlayerState() ); - SongOptions::LifeType lt = GAMESTATE->m_SongOptions.GetCurrent().m_LifeType; + LifeType lt = GAMESTATE->m_SongOptions.GetCurrent().m_LifeType; if( ft == FailType_Off || ft == FailType_EndOfSong ) continue; @@ -1658,7 +1658,7 @@ void ScreenGameplay::Update( float fDeltaTime ) bool bAllowOniDie = false; switch( lt ) { - case SongOptions::LIFE_BATTERY: + case LifeType_Battery: bAllowOniDie = true; default: break; diff --git a/src/ScreenGameplaySyncMachine.cpp b/src/ScreenGameplaySyncMachine.cpp index 037ced9f97..24456d85bf 100644 --- a/src/ScreenGameplaySyncMachine.cpp +++ b/src/ScreenGameplaySyncMachine.cpp @@ -45,7 +45,7 @@ void ScreenGameplaySyncMachine::Init() ScreenGameplayNormal::Init(); - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_AutosyncType, SongOptions::AUTOSYNC_MACHINE ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_AutosyncType, AutosyncType_Machine ); ClearMessageQueue(); // remove all of the messages set in ScreenGameplay that animate "ready", "here we go", etc. diff --git a/src/ScreenJukebox.cpp b/src/ScreenJukebox.cpp index 6176a50ebe..925e9fb209 100644 --- a/src/ScreenJukebox.cpp +++ b/src/ScreenJukebox.cpp @@ -198,7 +198,7 @@ void ScreenJukebox::Init() PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fPerspectiveTilt, -1.0f ); PO_GROUP_ASSIGN_N( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fEffects, PlayerOptions::EFFECT_TINY, 1.0f ); } - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_BATTERY ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, LifeType_Battery ); } FOREACH_EnabledPlayer( p ) diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index 48e01e7a77..89045a53b2 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -1247,11 +1247,11 @@ bool ScreenSelectMusic::MenuStart( const InputEventPlus &input ) // apply #LIVES if( pCourse->m_iLives != -1 ) { - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_BATTERY ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, LifeType_Battery ); SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_iBatteryLives, pCourse->m_iLives ); } if( pCourse->GetCourseType() == COURSE_TYPE_SURVIVAL) - SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_TIME ); + SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, LifeType_Time ); } else { diff --git a/src/ScreenSyncOverlay.cpp b/src/ScreenSyncOverlay.cpp index b0ba604e4b..be23fc1c08 100644 --- a/src/ScreenSyncOverlay.cpp +++ b/src/ScreenSyncOverlay.cpp @@ -113,13 +113,13 @@ void ScreenSyncOverlay::UpdateText() } } - SongOptions::AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; + AutosyncType type = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType; switch( type ) { - case SongOptions::AUTOSYNC_OFF: break; - case SongOptions::AUTOSYNC_SONG: vs.push_back(AUTO_SYNC_SONG); break; - case SongOptions::AUTOSYNC_MACHINE: vs.push_back(AUTO_SYNC_MACHINE); break; - case SongOptions::AUTOSYNC_TEMPO: vs.push_back(AUTO_SYNC_TEMPO); break; + case AutosyncType_Off: break; + case AutosyncType_Song: vs.push_back(AUTO_SYNC_SONG); break; + case AutosyncType_Machine: vs.push_back(AUTO_SYNC_MACHINE); break; + case AutosyncType_Tempo: vs.push_back(AUTO_SYNC_TEMPO); break; default: FAIL_M(ssprintf("Invalid autosync type: %i", type)); } @@ -134,7 +134,7 @@ void ScreenSyncOverlay::UpdateText() // Update SyncInfo - bool bVisible = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType != SongOptions::AUTOSYNC_OFF; + bool bVisible = GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType != AutosyncType_Off; m_textAdjustments.SetVisible( bVisible ); if( bVisible ) { diff --git a/src/SongOptions.cpp b/src/SongOptions.cpp index 6580f729a0..360b96505e 100644 --- a/src/SongOptions.cpp +++ b/src/SongOptions.cpp @@ -4,10 +4,47 @@ #include "GameState.h" #include "CommonMetrics.h" +static const char *LifeTypeNames[] = { + "Bar", + "Battery", + "Time", +}; +XToString( LifeType ); +XToLocalizedString( LifeType ); +LuaXType( LifeType ); + +static const char *DrainTypeNames[] = { + "Normal", + "NoRecover", + "SuddenDeath", +}; +XToString( DrainType ); +XToLocalizedString( DrainType ); +LuaXType( DrainType ); + +static const char *AutosyncTypeNames[] = { + "Off", + "Song", + "Machine", + "Tempo", +}; +XToString( AutosyncType ); +XToLocalizedString( AutosyncType ); +LuaXType( AutosyncType ); + +static const char *SoundEffectTypeNames[] = { + "Off", + "Speed", + "Pitch", +}; +XToString( SoundEffectType ); +XToLocalizedString( SoundEffectType ); +LuaXType( SoundEffectType ); + void SongOptions::Init() { - m_LifeType = LIFE_BAR; - m_DrainType = DRAIN_NORMAL; + m_LifeType = LifeType_Bar; + m_DrainType = DrainType_Normal; m_iBatteryLives = 4; m_bAssistClap = false; m_bAssistMetronome = false; @@ -15,8 +52,8 @@ void SongOptions::Init() m_SpeedfMusicRate = 1.0f; m_fHaste = 0.0f; m_SpeedfHaste = 1.0f; - m_AutosyncType = AUTOSYNC_OFF; - m_SoundEffectType = SOUNDEFFECT_OFF; + m_AutosyncType = AutosyncType_Off; + m_SoundEffectType = SoundEffectType_Off; m_bStaticBackground = false; m_bRandomBGOnly = false; m_bSaveScore = true; @@ -61,18 +98,18 @@ void SongOptions::GetMods( vector &AddTo ) const { switch( m_LifeType ) { - case LIFE_BAR: + case LifeType_Bar: switch( m_DrainType ) { - case DRAIN_NORMAL: break; - case DRAIN_NO_RECOVER: AddTo.push_back("NoRecover"); break; - case DRAIN_SUDDEN_DEATH: AddTo.push_back("SuddenDeath"); break; + case DrainType_Normal: break; + case DrainType_NoRecover: AddTo.push_back("NoRecover"); break; + case DrainType_SuddenDeath: AddTo.push_back("SuddenDeath"); break; } break; - case LIFE_BATTERY: + case LifeType_Battery: AddTo.push_back( ssprintf( "%dLives", m_iBatteryLives ) ); break; - case LIFE_TIME: + case LifeType_Time: AddTo.push_back( "LifeTime" ); break; default: @@ -92,19 +129,19 @@ void SongOptions::GetMods( vector &AddTo ) const switch( m_AutosyncType ) { - case AUTOSYNC_OFF: break; - case AUTOSYNC_SONG: AddTo.push_back("AutosyncSong"); break; - case AUTOSYNC_MACHINE: AddTo.push_back("AutosyncMachine"); break; - case AUTOSYNC_TEMPO: AddTo.push_back("AutosyncTempo"); break; + case AutosyncType_Off: break; + case AutosyncType_Song: AddTo.push_back("AutosyncSong"); break; + case AutosyncType_Machine: AddTo.push_back("AutosyncMachine"); break; + case AutosyncType_Tempo: AddTo.push_back("AutosyncTempo"); break; default: FAIL_M(ssprintf("Invalid autosync type: %i", m_AutosyncType)); } switch( m_SoundEffectType ) { - case SOUNDEFFECT_OFF: break; - case SOUNDEFFECT_SPEED: AddTo.push_back("EffectSpeed"); break; - case SOUNDEFFECT_PITCH: AddTo.push_back("EffectPitch"); break; + case SoundEffectType_Off: break; + case SoundEffectType_Speed: AddTo.push_back("EffectSpeed"); break; + case SoundEffectType_Pitch: AddTo.push_back("EffectPitch"); break; default: FAIL_M(ssprintf("Invalid sound effect type: %i", m_SoundEffectType)); } @@ -190,26 +227,26 @@ bool SongOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut ) 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; + if( sBit == "norecover" ) m_DrainType = DrainType_NoRecover; + else if( sBit == "suddendeath" || sBit == "death" ) m_DrainType = DrainType_SuddenDeath; + else if( sBit == "power-drop" ) m_DrainType = DrainType_NoRecover; + else if( sBit == "normal-drain" ) m_DrainType = DrainType_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 == "autosync" || sBit == "autosyncsong" ) m_AutosyncType = on ? AutosyncType_Song : AutosyncType_Off; + else if( sBit == "autosyncmachine" ) m_AutosyncType = on ? AutosyncType_Machine : AutosyncType_Off; + else if( sBit == "autosynctempo" ) m_AutosyncType = on ? AutosyncType_Tempo : AutosyncType_Off; + else if( sBit == "effect" && !on ) m_SoundEffectType = SoundEffectType_Off; + else if( sBit == "effectspeed" ) m_SoundEffectType = on ? SoundEffectType_Speed : SoundEffectType_Off; + else if( sBit == "effectpitch" ) m_SoundEffectType = on ? SoundEffectType_Pitch : SoundEffectType_Off; else if( sBit == "staticbg" ) m_bStaticBackground = on; else if( sBit == "randombg" ) m_bRandomBGOnly = on; else if( sBit == "savescore" ) m_bSaveScore = on; else if( sBit == "savereplay" ) m_bSaveReplay = 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 == "bar" ) m_LifeType = LifeType_Bar; + else if( sBit == "battery" ) m_LifeType = LifeType_Battery; + else if( sBit == "lifetime" ) m_LifeType = LifeType_Time; else if( sBit == "haste" ) m_fHaste = on? 1.0f:0.0f; else return false; @@ -237,6 +274,51 @@ bool SongOptions::operator==( const SongOptions &other ) const return true; } +// lua start +#include "LuaBinding.h" +#include "OptionsBinding.h" + +/** @brief Allow Lua to have access to SongOptions. */ +class LunaSongOptions: public Luna +{ +public: + + ENUM_INTERFACE(LifeSetting, LifeType, LifeType); + ENUM_INTERFACE(DrainSetting, DrainType, DrainType); + ENUM_INTERFACE(AutosyncSetting, AutosyncType, AutosyncType); + //ENUM_INTERFACE(SoundEffectSetting, SoundEffectType, SoundEffectType); + // Broken, SoundEffectType_Speed disables rate mod, other settings have no effect. -Kyz + INT_INTERFACE(BatteryLives, BatteryLives); + BOOL_INTERFACE(AssistClap, AssistClap); + BOOL_INTERFACE(AssistMetronome, AssistMetronome); + BOOL_INTERFACE(StaticBackground, StaticBackground); + BOOL_INTERFACE(RandomBGOnly, RandomBGOnly); + BOOL_INTERFACE(SaveScore, SaveScore); + BOOL_INTERFACE(SaveReplay, SaveReplay); + FLOAT_INTERFACE(MusicRate, MusicRate, (v > 0.0f && v <= 3.0f)); // Greater than 3 seems to crash frequently, haven't investigated why. -Kyz + FLOAT_INTERFACE(Haste, Haste, true); + + LunaSongOptions() + { + ADD_METHOD(LifeSetting); + ADD_METHOD(DrainSetting); + ADD_METHOD(AutosyncSetting); + //ADD_METHOD(SoundEffectSetting); + ADD_METHOD(BatteryLives); + ADD_METHOD(AssistClap); + ADD_METHOD(AssistMetronome); + ADD_METHOD(StaticBackground); + ADD_METHOD(RandomBGOnly); + ADD_METHOD(SaveScore); + ADD_METHOD(SaveReplay); + ADD_METHOD(MusicRate); + ADD_METHOD(Haste); + } +}; + +LUA_REGISTER_CLASS( SongOptions ) +// lua end + /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/SongOptions.h b/src/SongOptions.h index 9bb88f4236..9d2c93d911 100644 --- a/src/SongOptions.h +++ b/src/SongOptions.h @@ -3,43 +3,68 @@ #ifndef SONG_OPTIONS_H #define SONG_OPTIONS_H +#include "EnumHelper.h" + +enum LifeType +{ + LifeType_Bar, + LifeType_Battery, + LifeType_Time, + NUM_LifeType, + LifeType_Invalid +}; +const RString& LifeTypeToString( LifeType cat ); +const RString& LifeTypeToLocalizedString( LifeType cat ); +LuaDeclareType( LifeType ); + +enum DrainType +{ + DrainType_Normal, + DrainType_NoRecover, + DrainType_SuddenDeath, + NUM_DrainType, + DrainType_Invalid +}; +const RString& DrainTypeToString( DrainType cat ); +const RString& DrainTypeToLocalizedString( DrainType cat ); +LuaDeclareType( DrainType ); + +enum AutosyncType +{ + AutosyncType_Off, + AutosyncType_Song, + AutosyncType_Machine, + AutosyncType_Tempo, + NUM_AutosyncType, + AutosyncType_Invalid +}; +const RString& AutosyncTypeToString( AutosyncType cat ); +const RString& AutosyncTypeToLocalizedString( AutosyncType cat ); +LuaDeclareType( AutosyncType ); + +enum SoundEffectType +{ + SoundEffectType_Off, + SoundEffectType_Speed, + SoundEffectType_Pitch, + NUM_SoundEffectType, + SoundEffectType_Invalid +}; +const RString& SoundEffectTypeToString( SoundEffectType cat ); +const RString& SoundEffectTypeToLocalizedString( SoundEffectType cat ); +LuaDeclareType( SoundEffectType ); + class SongOptions { public: - enum LifeType - { - LIFE_BAR=0, - LIFE_BATTERY, - LIFE_TIME, - NUM_LIFE_TYPES - }; LifeType m_LifeType; - enum DrainType - { - DRAIN_NORMAL, - DRAIN_NO_RECOVER, - DRAIN_SUDDEN_DEATH - }; DrainType m_DrainType; // only used with LifeBar int m_iBatteryLives; bool m_bAssistClap; bool m_bAssistMetronome; float m_fMusicRate, m_SpeedfMusicRate; float m_fHaste, m_SpeedfHaste; - enum AutosyncType { - AUTOSYNC_OFF, - AUTOSYNC_SONG, - AUTOSYNC_MACHINE, - AUTOSYNC_TEMPO, - NUM_AUTOSYNC_TYPES - }; AutosyncType m_AutosyncType; - enum SoundEffectType { - SOUNDEFFECT_OFF, - SOUNDEFFECT_SPEED, - SOUNDEFFECT_PITCH, - NUM_SOUNDEFFECT - }; SoundEffectType m_SoundEffectType; bool m_bStaticBackground; bool m_bRandomBGOnly; @@ -51,12 +76,12 @@ public: * * This is taken from Init(), but uses the intended * initialization lists. */ - SongOptions(): m_LifeType(LIFE_BAR), m_DrainType(DRAIN_NORMAL), + SongOptions(): m_LifeType(LifeType_Bar), m_DrainType(DrainType_Normal), m_iBatteryLives(4), m_bAssistClap(false), m_bAssistMetronome(false), m_fMusicRate(1.0f), m_SpeedfMusicRate(1.0f), m_fHaste(0.0f), - m_SpeedfHaste(1.0f), m_AutosyncType(AUTOSYNC_OFF), - m_SoundEffectType(SOUNDEFFECT_OFF), + m_SpeedfHaste(1.0f), m_AutosyncType(AutosyncType_Off), + m_SoundEffectType(SoundEffectType_Off), m_bStaticBackground(false), m_bRandomBGOnly(false), m_bSaveScore(true), m_bSaveReplay(false) {}; void Init(); @@ -70,6 +95,9 @@ public: bool operator==( const SongOptions &other ) const; bool operator!=( const SongOptions &other ) const { return !operator==(other); } + + // Lua + void PushSelf( lua_State *L ); }; #endif