From e15e0e68be2e6ca6bada1418bc5e7348d1a80e83 Mon Sep 17 00:00:00 2001 From: MrThatKid Date: Sat, 13 May 2017 11:34:34 -0700 Subject: [PATCH] Add nITG's various path shape & other modifiers - V2 (#1435) * Implemented nITG's Square modifiers Modifiers added: Square SquareOffset SquarePeriod SquareZ SquareZOffset SquareZPeriod * Implemented nITG's BumpyX Modifiers Also fixes up some tiny bits pertaining to the square modifiers. Modifiers Added: BumpyX BumpyXPeriod BumpyXOffset * Implemented nITG's TornadoZ Modifiers Modifiers Added: TornadoZ TornadoZPeriod TornadoZOffset Another commit is needed to update fallback's metrics * Update fallback's metrics to accommodate TornadoX * Implemented nITG's Parabola Modifiers Modifiers Added: ParabolaX ParabolaY ParabolaZ * Implemented nITG's Sawtooth Modifiers Modifiers Added: Sawtooth SawtoothPeriod SawtoothZ SawtoothZPeriod * Implemented nITG's Zigzag Modifiers Modifiers Added: Zigzag ZigzagPeriod ZigzagOffset ZigzagZ ZigzagZPeriod ZigzagZOffset * Implemented nITG's ModTimer modifiers Modifiers Added: ModTimer (Lua method name is ModTimerSetting (takes enums. Ex: 'ModTimerType_Song'). Can be activated with mod strings 'modtimer(song/beat/game/default)' ) ModTimerOffset ModTimerMult * Remove Log use from ArrowEffects::GetTime() * Accidentally removed a CPY(m_BatteryLives) * Implemented nITG's DrunkZ modifiers Modifiers added: drunkz drunkzspeed drunkzoffset drunkzperiod Another commit is needed to update fallback's metrics * Update fallback's metrics to accommodate DrunkZ * Implemented nITG's BeatY & BeatZ Modifers Modifiers Added: beaty beatyoffset beatyperiod beatymult beatz beatzoffset beatzperiod beatzmult Another commit is needed to update fallback's metrics * Updated fallback's metrics to accommodate ... the new Beat modifiers. * Implemented nITG's Digital Modifiers Modifers Added: digital digitalsteps digitalperiod digitaloffset digitalz digitalzsteps digitalzperiod digitalzoffset * Removed duplicate zbuffer check. * Updated Luadocs with the new modifiers * Removed accidental duplicate Mini from Luadocs * Split up long modifier lines. Hopefully, this makes it a bit easier to read. * Remove accidental commit to root of repo. * Split up long modifier lines Hopefully, this makes it easier to read. * Redid Square functions to not use FastSin This implementation is based off of 5.2's square_wave function from ModValue. * Redid zigzag functions to not use FastSin This implementation is based off of 5.2's triangle_wave function from ModValue. * Moved square & zigzag calculation to RageMath. New RageMath functions: RageSquare RageTriangle * Made Square & Digital have the same period... as Zigzag and Sawtooth. * Deduplicate tornado calculations. * Fixed typo in UpdateTornado, and moved UpdateTornado logic to ArrowEffects::Init because it doesn't depend on anything that changes every frame. Tornado metrics are also loaded in ArrowEffects::Init. * Deduplicated Beat mod update logic. The logic is now placed into a function called UpdateBeat. The m_fBeatFactor members are now a 1D array, similar to m_MaxTornado and m_MinTornado. --- Docs/Luadoc/Lua.xml | 56 ++++- Docs/Luadoc/LuaDocumentation.xml | 54 ++++- Themes/_fallback/metrics.ini | 27 ++- src/ArrowEffects.cpp | 392 ++++++++++++++++++++++++------- src/ArrowEffects.h | 7 +- src/Player.cpp | 2 +- src/PlayerOptions.cpp | 259 +++++++++++++++++++- src/PlayerOptions.h | 64 +++++ src/RageMath.cpp | 34 +++ src/RageMath.h | 3 + 10 files changed, 801 insertions(+), 97 deletions(-) diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index c2bfc66c43..61d9ddbb88 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1114,9 +1114,17 @@ - + + + + + + + + + @@ -1127,6 +1135,9 @@ + + + @@ -1138,6 +1149,14 @@ + + + + + + + + @@ -1145,6 +1164,10 @@ + + + + @@ -1164,6 +1187,9 @@ + + + @@ -1186,6 +1212,9 @@ + + + @@ -1196,6 +1225,10 @@ + + + + @@ -1204,6 +1237,12 @@ + + + + + + @@ -1218,6 +1257,9 @@ + + + @@ -1227,6 +1269,12 @@ + + + + + + @@ -2316,6 +2364,12 @@ + + + + + + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 4772e2fffb..7df4afe1b5 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -3432,9 +3432,17 @@ save yourself some time, copy this for undocumented things: - + + + + + + + + + @@ -3445,6 +3453,9 @@ save yourself some time, copy this for undocumented things: + + + If the player has a CMod set, returns the value of that CMod and its associated approach speed. Returns nil otherwise.
@@ -3460,6 +3471,14 @@ save yourself some time, copy this for undocumented things: + + + + + + + + If the player is using Distant (zero skew and positive tilt), returns the value of tilt and its approach_speed.
@@ -3472,6 +3491,10 @@ save yourself some time, copy this for undocumented things: + + + + @@ -3510,6 +3533,13 @@ save yourself some time, copy this for undocumented things: + + Sets the effect clock of certain modifiers for the player, if the optional argument is provided. Returns the that was previously set.
+ Can also be set through strings in PlayerOptions::FromString().
+ String Examples: 'ModTimerSong', 'modtimerbeat', etc. +
+ + MaxScrollBPM is one of the variables for controlling the speed mod.
Use CMod, XMod, or MMod to set the speed mod unless you have a good reason not to.
@@ -3557,6 +3587,9 @@ save yourself some time, copy this for undocumented things: If the player is using Overhead (0 tilt, 0 skew), returns true.
If true is passed, sets the tilt and skew to 0.
+ + + @@ -3567,6 +3600,10 @@ save yourself some time, copy this for undocumented things: + + + + ScrollBPM is one of the variables for controlling the speed mod.
Use CMod, XMod, or MMod to set the speed mod unless you have a good reason not to.
@@ -3593,6 +3630,12 @@ save yourself some time, copy this for undocumented things: If the optional second argument is passed, sets the approach_speed for skew and tilt to it.
+ + + + + + @@ -3614,6 +3657,9 @@ save yourself some time, copy this for undocumented things: + + + @@ -3629,6 +3675,12 @@ save yourself some time, copy this for undocumented things: If the optional second argument is passed, sets the speed at which the transition occurs.
+ + + + + +
diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 66bdb563a4..010f165d24 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -210,16 +210,33 @@ TipsyArrowMagnitude=0.4 TipsyOffsetTimerFrequency=1.2 TipsyOffsetColumnFrequency=2 TipsyOffsetArrowMagnitude=0.4 -TornadoPositionScaleToLow=-1 -TornadoPositionScaleToHigh=1 -TornadoOffsetFrequency=6 -TornadoOffsetScaleFromLow=-1 -TornadoOffsetScaleFromHigh=1 +TornadoXPositionScaleToLow=-1 +TornadoXPositionScaleToHigh=1 +TornadoXOffsetFrequency=6 +TornadoXOffsetScaleFromLow=-1 +TornadoXOffsetScaleFromHigh=1 +TornadoYPositionScaleToLow=-1 +TornadoYPositionScaleToHigh=1 +TornadoYOffsetFrequency=6 +TornadoYOffsetScaleFromLow=-1 +TornadoYOffsetScaleFromHigh=1 +TornadoZPositionScaleToLow=-1 +TornadoZPositionScaleToHigh=1 +TornadoZOffsetFrequency=6 +TornadoZOffsetScaleFromLow=-1 +TornadoZOffsetScaleFromHigh=1 DrunkColumnFrequency=0.2 DrunkOffsetFrequency=10 DrunkArrowMagnitude=0.5 +DrunkZColumnFrequency=0.2 +DrunkZOffsetFrequency=10 +DrunkZArrowMagnitude=0.5 BeatOffsetHeight=15 BeatPIHeight=2 +BeatYOffsetHeight=15 +BeatYPIHeight=2 +BeatZOffsetHeight=15 +BeatZPIHeight=2 MiniPercentBase=0.5 MiniPercentGate=1 TinyPercentBase=0.5 diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index 3a959cabee..7ce69ba93d 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -14,6 +14,8 @@ #include "ThemeMetric.h" #include +static char const dimension_names[4]= "XYZ"; + static ThemeMetric ARROW_SPACING( "ArrowEffects", "ArrowSpacing" ); static ThemeMetric QUANTIZE_ARROW_Y( "ArrowEffects", "QuantizeArrowYPosition"); static ThemeMetric HIDDEN_SUDDEN_PAST_RECEPTOR( "ArrowEffects", "DrawHiddenNotesAfterReceptor"); @@ -46,16 +48,34 @@ static ThemeMetric TIPSY_ARROW_MAGNITUDE( "ArrowEffects", "TipsyArrowMagn static ThemeMetric TIPSY_OFFSET_TIMER_FREQUENCY( "ArrowEffects", "TipsyOffsetTimerFrequency" ); static ThemeMetric TIPSY_OFFSET_COLUMN_FREQUENCY( "ArrowEffects", "TipsyOffsetColumnFrequency" ); static ThemeMetric TIPSY_OFFSET_ARROW_MAGNITUDE( "ArrowEffects", "TipsyOffsetArrowMagnitude" ); -static ThemeMetric TORNADO_POSITION_SCALE_TO_LOW( "ArrowEffects", "TornadoPositionScaleToLow" ); -static ThemeMetric TORNADO_POSITION_SCALE_TO_HIGH( "ArrowEffects", "TornadoPositionScaleToHigh" ); -static ThemeMetric TORNADO_OFFSET_FREQUENCY( "ArrowEffects", "TornadoOffsetFrequency" ); -static ThemeMetric TORNADO_OFFSET_SCALE_FROM_LOW( "ArrowEffects", "TornadoOffsetScaleFromLow" ); -static ThemeMetric TORNADO_OFFSET_SCALE_FROM_HIGH( "ArrowEffects", "TornadoOffsetScaleFromHigh" ); + +static RString TPSTL_NAME(size_t i) { return ssprintf("Tornado%cPositionScaleToLow", dimension_names[i]); } +static ThemeMetric1D TORNADO_POSITION_SCALE_TO_LOW("ArrowEffects", TPSTL_NAME, 3); +static RString TPSTH_NAME(size_t i) { return ssprintf("Tornado%cPositionScaleToHigh", dimension_names[i]); } +static ThemeMetric1D TORNADO_POSITION_SCALE_TO_HIGH("ArrowEffects", TPSTH_NAME, 3); +static RString TOF_NAME(size_t i) { return ssprintf("Tornado%cOffsetFrequency", dimension_names[i]); } +static ThemeMetric1D TORNADO_OFFSET_FREQUENCY("ArrowEffects", TOF_NAME, 3); +static RString TOSFL_NAME(size_t i) { return ssprintf("Tornado%cOffsetScaleFromLow", dimension_names[i]); } +static ThemeMetric1D TORNADO_OFFSET_SCALE_FROM_LOW("ArrowEffects", TOSFL_NAME, 3); +static RString TOSFH_NAME(size_t i) { return ssprintf("Tornado%cOffsetScaleFromHigh", dimension_names[i]); } +static ThemeMetric1D TORNADO_OFFSET_SCALE_FROM_HIGH("ArrowEffects", TOSFH_NAME, 3); + static ThemeMetric DRUNK_COLUMN_FREQUENCY( "ArrowEffects", "DrunkColumnFrequency" ); static ThemeMetric DRUNK_OFFSET_FREQUENCY( "ArrowEffects", "DrunkOffsetFrequency" ); static ThemeMetric DRUNK_ARROW_MAGNITUDE( "ArrowEffects", "DrunkArrowMagnitude" ); + +static ThemeMetric DRUNK_Z_COLUMN_FREQUENCY( "ArrowEffects", "DrunkZColumnFrequency" ); +static ThemeMetric DRUNK_Z_OFFSET_FREQUENCY( "ArrowEffects", "DrunkZOffsetFrequency" ); +static ThemeMetric DRUNK_Z_ARROW_MAGNITUDE( "ArrowEffects", "DrunkZArrowMagnitude" ); + static ThemeMetric BEAT_OFFSET_HEIGHT( "ArrowEffects", "BeatOffsetHeight" ); static ThemeMetric BEAT_PI_HEIGHT( "ArrowEffects", "BeatPIHeight" ); + +static ThemeMetric BEAT_Y_OFFSET_HEIGHT( "ArrowEffects", "BeatYOffsetHeight" ); +static ThemeMetric BEAT_Y_PI_HEIGHT( "ArrowEffects", "BeatYPIHeight" ); +static ThemeMetric BEAT_Z_OFFSET_HEIGHT( "ArrowEffects", "BeatZOffsetHeight" ); +static ThemeMetric BEAT_Z_PI_HEIGHT( "ArrowEffects", "BeatZPIHeight" ); + static ThemeMetric TINY_PERCENT_BASE( "ArrowEffects", "TinyPercentBase" ); static ThemeMetric TINY_PERCENT_GATE( "ArrowEffects", "TinyPercentGate" ); static ThemeMetric DIZZY_HOLD_HEADS( "ArrowEffects", "DizzyHoldHeads" ); @@ -69,21 +89,166 @@ static float GetNoteFieldHeight() return SCREEN_HEIGHT + fabsf(curr_options->m_fPerspectiveTilt)*200; } +float ArrowEffects::GetTime() +{ + float mult = 1.f + curr_options->m_fModTimerMult; + float offset = curr_options->m_fModTimerOffset; + ModTimerType modtimer = curr_options->m_ModTimerType; + switch(modtimer) + { + case ModTimerType_Default: + case ModTimerType_Game: + return (RageTimer::GetTimeSinceStartFast()+offset)*mult; + case ModTimerType_Beat: + return (GAMESTATE->m_Position.m_fSongBeatVisible+offset)*mult; + case ModTimerType_Song: + return (GAMESTATE->m_Position.m_fMusicSeconds+offset)*mult; + default: + return RageTimer::GetTimeSinceStartFast()+offset; + } +} + namespace { struct PerPlayerData { - float m_fMinTornadoX[MAX_COLS_PER_PLAYER]; - float m_fMaxTornadoX[MAX_COLS_PER_PLAYER]; + float m_MinTornado[3][MAX_COLS_PER_PLAYER]; + float m_MaxTornado[3][MAX_COLS_PER_PLAYER]; float m_fInvertDistance[MAX_COLS_PER_PLAYER]; float m_tipsy_result[MAX_COLS_PER_PLAYER]; float m_tipsy_offset_result[MAX_COLS_PER_PLAYER]; - float m_fBeatFactor; + float m_fBeatFactor[3]; float m_fExpandSeconds; + + // m_prev_style is for checking whether ArrowEffects::Init needs to be + // called. Finding all the placed ArrowEffects is used and making sure + // they all call Init after changing style is non-trivial and more likely + // to cause bugs. -Kyz + Style const* m_prev_style; }; PerPlayerData g_EffectData[NUM_PLAYERS]; + int const dim_x= 0; + int const dim_y= 1; + int const dim_z= 2; + + float tornado_position_scale_to_low[3]; + float tornado_position_scale_to_high[3]; + float tornado_offset_frequency[3]; + float tornado_offset_scale_from_low[3]; + float tornado_offset_scale_from_high[3]; }; +static float CalculateTornadoOffsetFromMagnitude(int dimension, int col_id, + float magnitude, float effect_offset, float period, + const Style::ColumnInfo* pCols, float field_zoom, + PerPlayerData& data, float y_offset) +{ + float const real_pixel_offset= pCols[col_id].fXOffset * field_zoom; + float const position_between= SCALE(real_pixel_offset, + data.m_MinTornado[dimension][col_id] * field_zoom, + data.m_MaxTornado[dimension][col_id] * field_zoom, + tornado_position_scale_to_low[dimension], + tornado_position_scale_to_high[dimension]); + float rads= acosf(position_between); + float frequency= tornado_offset_frequency[dimension]; + rads+= (y_offset + effect_offset) * ((period * frequency) + frequency) / SCREEN_HEIGHT; + float const adjusted_pixel_offset= SCALE(RageFastCos(rads), + tornado_offset_scale_from_low[dimension], + tornado_offset_scale_from_high[dimension], + data.m_MinTornado[dimension][col_id] * field_zoom, + data.m_MaxTornado[dimension][col_id] * field_zoom); + return (adjusted_pixel_offset - real_pixel_offset) * magnitude; +} + +static void UpdateBeat(int dimension, PerPlayerData &data, const SongPosition &position, float beat_offset, float beat_mult) +{ + float fAccelTime = 0.2f, fTotalTime = 0.5f; + float fBeat = ((position.m_fSongBeatVisible + fAccelTime + beat_offset) * (beat_mult+1)); + + const bool bEvenBeat = ( int(fBeat) % 2 ) != 0; + + data.m_fBeatFactor[dimension] = 0; + if( fBeat < 0 ) + return; + + // -100.2 -> -0.2 -> 0.2 + fBeat -= truncf( fBeat ); + fBeat += 1; + fBeat -= truncf( fBeat ); + + if( fBeat >= fTotalTime ) + return; + + if( fBeat < fAccelTime ) + { + data.m_fBeatFactor[dimension] = SCALE( fBeat, 0.0f, fAccelTime, 0.0f, 1.0f); + data.m_fBeatFactor[dimension] *= data.m_fBeatFactor[dimension]; + } else /* fBeat < fTotalTime */ { + data.m_fBeatFactor[dimension] = SCALE( fBeat, fAccelTime, fTotalTime, 1.0f, 0.0f); + data.m_fBeatFactor[dimension] = 1 - (1-data.m_fBeatFactor[dimension]) * (1-data.m_fBeatFactor[dimension]); + } + + if( bEvenBeat ) + data.m_fBeatFactor[dimension] *= -1; + data.m_fBeatFactor[dimension] *= 20.0f; +} + + +void ArrowEffects::Init(PlayerNumber pn) +{ + const Style* pStyle = GAMESTATE->GetCurrentStyle(pn); + const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn]; + PerPlayerData &data = g_EffectData[pn]; + // Init tornado limits. + // This used to run every frame, but it doesn't actually depend on anything + // that changes every frame. In openitg, it runs for every note. -Kyz + + // TRICKY: Tornado is very unplayable in doubles, so use a smaller + // tornado width if there are many columns + + /* the wide_field check makes an assumption for dance mode. + * perhaps check if we are actually playing on singles without, + * say more than 6 columns. That would exclude IIDX, pop'n, and + * techno-8, all of which would be very hectic. + * certain non-singles modes (like halfdoubles 6cols) + * could possibly have tornado enabled. + * let's also take default resolution (640x480) into mind. -aj */ + bool wide_field= pStyle->m_iColsPerPlayer > 4; + int max_player_col= pStyle->m_iColsPerPlayer-1; + for(int dimension= 0; dimension < 3; ++dimension) + { + int width= 3; + // wide_field only matters for x, which is dimension 0. -Kyz + if(dimension == 0 && wide_field) + { + width= 2; + } + for(int col_id= 0; col_id <= max_player_col; ++col_id) + { + int start_col= col_id - width; + int end_col= col_id + width; + CLAMP(start_col, 0, max_player_col); + CLAMP(end_col, 0, max_player_col); + data.m_MinTornado[dimension][col_id]= FLT_MAX; + data.m_MaxTornado[dimension][col_id]= FLT_MIN; + for(int i= start_col; i <= end_col; ++i) + { + // Using the x offset when the dimension might be y or z feels so + // wrong, but it provides min and max values when otherwise the + // limits would just be zero, which would make it do nothing. -Kyz + data.m_MinTornado[dimension][col_id] = min(pCols[i].fXOffset, data.m_MinTornado[dimension][col_id]); + data.m_MaxTornado[dimension][col_id] = max(pCols[i].fXOffset, data.m_MaxTornado[dimension][col_id]); + } + } + + tornado_position_scale_to_low[dimension]= TORNADO_POSITION_SCALE_TO_LOW.GetValue(dimension); + tornado_position_scale_to_high[dimension]= TORNADO_POSITION_SCALE_TO_HIGH.GetValue(dimension); + tornado_offset_frequency[dimension]= TORNADO_OFFSET_FREQUENCY.GetValue(dimension); + tornado_offset_scale_from_low[dimension]= TORNADO_OFFSET_SCALE_FROM_LOW.GetValue(dimension); + tornado_offset_scale_from_high[dimension]= TORNADO_OFFSET_SCALE_FROM_HIGH.GetValue(dimension); + } +} + void ArrowEffects::Update() { static float fLastTime = 0; @@ -101,42 +266,17 @@ void ArrowEffects::Update() PerPlayerData &data = g_EffectData[pn]; + if(pStyle != data.m_prev_style) + { + Init(pn); + data.m_prev_style= pStyle; + } + if( !position.m_bFreeze || !position.m_bDelay ) { data.m_fExpandSeconds += fTime - fLastTime; data.m_fExpandSeconds = fmodf( data.m_fExpandSeconds, (PI*2)/(accels[PlayerOptions::ACCEL_EXPAND_PERIOD]+1) ); } - - // Update Tornado - for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum ) - { - // TRICKY: Tornado is very unplayable in doubles, so use a smaller - // tornado width if there are many columns - - /* the below makes an assumption for dance mode. - * perhaps check if we are actually playing on singles without, - * say more than 6 columns. That would exclude IIDX, pop'n, and - * techno-8, all of which would be very hectic. - * certain non-singles modes (like halfdoubles 6cols) - * could possibly have tornado enabled. - * let's also take default resolution (640x480) into mind. -aj */ - bool bWideField = pStyle->m_iColsPerPlayer > 4; - int iTornadoWidth = bWideField ? 2 : 3; - - int iStartCol = iColNum - iTornadoWidth; - int iEndCol = iColNum + iTornadoWidth; - CLAMP( iStartCol, 0, pStyle->m_iColsPerPlayer-1 ); - CLAMP( iEndCol, 0, pStyle->m_iColsPerPlayer-1 ); - - data.m_fMinTornadoX[iColNum] = FLT_MAX; - data.m_fMaxTornadoX[iColNum] = FLT_MIN; - - for( int i=iStartCol; i<=iEndCol; i++ ) - { - data.m_fMinTornadoX[iColNum] = min( data.m_fMinTornadoX[iColNum], pCols[i].fXOffset * field_zoom ); - data.m_fMaxTornadoX[iColNum] = max( data.m_fMaxTornadoX[iColNum], pCols[i].fXOffset * field_zoom); - } - } // Update Invert for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum ) @@ -185,7 +325,7 @@ void ArrowEffects::Update() // Update Tipsy if(effects[PlayerOptions::EFFECT_TIPSY] != 0) { - const float time= RageTimer::GetTimeSinceStartFast(); + const float time= ArrowEffects::GetTime(); const float time_times_timer= time * ((effects[PlayerOptions::EFFECT_TIPSY_SPEED] * TIPSY_TIMER_FREQUENCY) + TIPSY_TIMER_FREQUENCY); const float arrow_times_mag= ARROW_SIZE * TIPSY_ARROW_MAGNITUDE; const float time_times_offset_timer= time * @@ -211,37 +351,13 @@ void ArrowEffects::Update() } // Update Beat - do { - float fAccelTime = 0.2f, fTotalTime = 0.5f; - float fBeat = ((position.m_fSongBeatVisible + fAccelTime + effects[PlayerOptions::EFFECT_BEAT_OFFSET]) * (effects[PlayerOptions::EFFECT_BEAT_MULT]+1)); + UpdateBeat(dim_x, data, position, effects[PlayerOptions::EFFECT_BEAT_OFFSET], effects[PlayerOptions::EFFECT_BEAT_MULT]); - const bool bEvenBeat = ( int(fBeat) % 2 ) != 0; + // Update BeatY + UpdateBeat(dim_y, data, position, effects[PlayerOptions::EFFECT_BEAT_Y_OFFSET], effects[PlayerOptions::EFFECT_BEAT_Y_MULT]); - data.m_fBeatFactor = 0; - if( fBeat < 0 ) - break; - - // -100.2 -> -0.2 -> 0.2 - fBeat -= truncf( fBeat ); - fBeat += 1; - fBeat -= truncf( fBeat ); - - if( fBeat >= fTotalTime ) - break; - - if( fBeat < fAccelTime ) - { - data.m_fBeatFactor = SCALE( fBeat, 0.0f, fAccelTime, 0.0f, 1.0f); - data.m_fBeatFactor *= data.m_fBeatFactor; - } else /* fBeat < fTotalTime */ { - data.m_fBeatFactor = SCALE( fBeat, fAccelTime, fTotalTime, 1.0f, 0.0f); - data.m_fBeatFactor = 1 - (1-data.m_fBeatFactor) * (1-data.m_fBeatFactor); - } - - if( bEvenBeat ) - data.m_fBeatFactor *= -1; - data.m_fBeatFactor *= 20.0f; - } while( false ); + // Update BeatZ + UpdateBeat(dim_z, data, position, effects[PlayerOptions::EFFECT_BEAT_Z_OFFSET], effects[PlayerOptions::EFFECT_BEAT_Z_MULT]); } fLastTime = fTime; } @@ -337,7 +453,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float } const float* fAccels = curr_options->m_fAccels; - //const float* fEffects = curr_options->m_fEffects; + const float* fEffects = curr_options->m_fEffects; float fYAdjust = 0; // fill this in depending on PlayerOptions @@ -362,6 +478,9 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float } if( fAccels[PlayerOptions::ACCEL_WAVE] != 0 ) fYAdjust += fAccels[PlayerOptions::ACCEL_WAVE] * WAVE_MOD_MAGNITUDE *RageFastSin( fYOffset/((fAccels[PlayerOptions::ACCEL_WAVE_PERIOD]*WAVE_MOD_HEIGHT)+WAVE_MOD_HEIGHT) ); + + if( fEffects[PlayerOptions::EFFECT_PARABOLA_Y] != 0 ) + fYAdjust += fEffects[PlayerOptions::EFFECT_PARABOLA_Y] * (fYOffset/ARROW_SIZE) * (fYOffset/ARROW_SIZE); fYOffset += fYAdjust; @@ -449,6 +568,12 @@ float ArrowEffects::GetYPos(int iCol, float fYOffset, float fYReverseOffsetPixel PerPlayerData& data= g_EffectData[curr_options->m_pn]; f+= fEffects[PlayerOptions::EFFECT_TIPSY] * data.m_tipsy_result[iCol]; + if( fEffects[PlayerOptions::EFFECT_BEAT_Y] != 0 ) + { + const float fShift = data.m_fBeatFactor[dim_y]*RageFastSin( fYOffset / ((fEffects[PlayerOptions::EFFECT_BEAT_Y_PERIOD]*BEAT_Y_OFFSET_HEIGHT)+BEAT_Y_OFFSET_HEIGHT) + PI/BEAT_Y_PI_HEIGHT ); + f += fEffects[PlayerOptions::EFFECT_BEAT_Y] * fShift; + } + // In beware's DDR Extreme-focused fork of StepMania 3.9, this value is // floored, making arrows show on integer Y coordinates. Supposedly it makes // the arrows look better, but testing needs to be done. @@ -466,6 +591,8 @@ float ArrowEffects::GetYOffsetFromYPos(int iCol, float YPos, float fYReverseOffs // TODO: Don't index by PlayerNumber. PerPlayerData& data= g_EffectData[curr_options->m_pn]; f+= fEffects[PlayerOptions::EFFECT_TIPSY] * data.m_tipsy_offset_result[iCol]; + + f+= fEffects[PlayerOptions::EFFECT_PARABOLA_Y] * (YPos/ARROW_SIZE) * (YPos/ARROW_SIZE); float fShift, fScale; ArrowGetReverseShiftAndScale(iCol, fYReverseOffsetPixels, fShift, fScale); @@ -490,22 +617,21 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float if( fEffects[PlayerOptions::EFFECT_TORNADO] != 0 ) { - const float fRealPixelOffset = pCols[iColNum].fXOffset * pPlayerState->m_NotefieldZoom; - const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum], - TORNADO_POSITION_SCALE_TO_LOW, TORNADO_POSITION_SCALE_TO_HIGH ); - float fRads = acosf( fPositionBetween ); - fRads += (fYOffset + fEffects[PlayerOptions::EFFECT_TORNADO_OFFSET]) * ((fEffects[PlayerOptions::EFFECT_TORNADO_PERIOD] * TORNADO_OFFSET_FREQUENCY) + TORNADO_OFFSET_FREQUENCY) / SCREEN_HEIGHT; - - const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), TORNADO_OFFSET_SCALE_FROM_LOW, TORNADO_OFFSET_SCALE_FROM_HIGH, - data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum] ); - - fPixelOffsetFromCenter += (fAdjustedPixelOffset - fRealPixelOffset) * fEffects[PlayerOptions::EFFECT_TORNADO]; + fPixelOffsetFromCenter += CalculateTornadoOffsetFromMagnitude(dim_x, + iColNum, fEffects[PlayerOptions::EFFECT_TORNADO], + fEffects[PlayerOptions::EFFECT_TORNADO_OFFSET], + fEffects[PlayerOptions::EFFECT_TORNADO_PERIOD], + pCols, pPlayerState->m_NotefieldZoom, data, fYOffset); } + + if( fEffects[PlayerOptions::EFFECT_BUMPY_X] != 0 ) + fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_BUMPY_X] * 40*RageFastSin( (fYOffset+(100.0f*(fEffects[PlayerOptions::EFFECT_BUMPY_X_OFFSET])))/((fEffects[PlayerOptions::EFFECT_BUMPY_X_PERIOD]*16.0f)+16.0f) ); if( fEffects[PlayerOptions::EFFECT_DRUNK] != 0 ) fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_DRUNK] * - ( RageFastCos( RageTimer::GetTimeSinceStartFast()*(1+fEffects[PlayerOptions::EFFECT_DRUNK_SPEED]) + iColNum*((fEffects[PlayerOptions::EFFECT_DRUNK_OFFSET]*DRUNK_COLUMN_FREQUENCY)+DRUNK_COLUMN_FREQUENCY) + ( RageFastCos( GetTime()*(1+fEffects[PlayerOptions::EFFECT_DRUNK_SPEED]) + iColNum*((fEffects[PlayerOptions::EFFECT_DRUNK_OFFSET]*DRUNK_COLUMN_FREQUENCY)+DRUNK_COLUMN_FREQUENCY) + fYOffset*((fEffects[PlayerOptions::EFFECT_DRUNK_PERIOD]*DRUNK_OFFSET_FREQUENCY)+DRUNK_OFFSET_FREQUENCY)/SCREEN_HEIGHT) * ARROW_SIZE*DRUNK_ARROW_MAGNITUDE ); + if( fEffects[PlayerOptions::EFFECT_FLIP] != 0 ) { const int iFirstCol = 0; @@ -521,9 +647,39 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float if( fEffects[PlayerOptions::EFFECT_BEAT] != 0 ) { - const float fShift = data.m_fBeatFactor*RageFastSin( fYOffset / ((fEffects[PlayerOptions::EFFECT_BEAT_PERIOD]*BEAT_OFFSET_HEIGHT)+BEAT_OFFSET_HEIGHT) + PI/BEAT_PI_HEIGHT ); + const float fShift = data.m_fBeatFactor[dim_x]*RageFastSin( fYOffset / ((fEffects[PlayerOptions::EFFECT_BEAT_PERIOD]*BEAT_OFFSET_HEIGHT)+BEAT_OFFSET_HEIGHT) + PI/BEAT_PI_HEIGHT ); fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_BEAT] * fShift; } + + if( fEffects[PlayerOptions::EFFECT_ZIGZAG] != 0 ) + { + float fResult = RageTriangle( (PI * (1/(fEffects[PlayerOptions::EFFECT_ZIGZAG_PERIOD]+1)) * + ((fYOffset+(100.0f*(fEffects[PlayerOptions::EFFECT_ZIGZAG_OFFSET])))/ARROW_SIZE) ) ); + + fPixelOffsetFromCenter += (fEffects[PlayerOptions::EFFECT_ZIGZAG]*ARROW_SIZE/2) * fResult; + } + + if( fEffects[PlayerOptions::EFFECT_SAWTOOTH] != 0 ) + fPixelOffsetFromCenter += (fEffects[PlayerOptions::EFFECT_SAWTOOTH]*ARROW_SIZE) * + ((0.5f / (fEffects[PlayerOptions::EFFECT_SAWTOOTH_PERIOD]+1) * fYOffset) / ARROW_SIZE - + floor((0.5f / (fEffects[PlayerOptions::EFFECT_SAWTOOTH_PERIOD]+1) * fYOffset) / ARROW_SIZE) ); + + if( fEffects[PlayerOptions::EFFECT_PARABOLA_X] != 0 ) + fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_PARABOLA_X] * (fYOffset/ARROW_SIZE) * (fYOffset/ARROW_SIZE); + + if( fEffects[PlayerOptions::EFFECT_DIGITAL] != 0 ) + fPixelOffsetFromCenter += (fEffects[PlayerOptions::EFFECT_DIGITAL] * ARROW_SIZE * 0.5f) * + round((fEffects[PlayerOptions::EFFECT_DIGITAL_STEPS]+1) * RageFastSin( + (PI * (fYOffset + (1.0f * (fEffects[PlayerOptions::EFFECT_DIGITAL_OFFSET]) ) ) / + (ARROW_SIZE + (fEffects[PlayerOptions::EFFECT_DIGITAL_PERIOD] * ARROW_SIZE)) ) ) )/(fEffects[PlayerOptions::EFFECT_DIGITAL_STEPS]+1); + + if( fEffects[PlayerOptions::EFFECT_SQUARE] != 0 ) + { + float fResult = RageSquare( (PI * (fYOffset+(1.0f*(fEffects[PlayerOptions::EFFECT_SQUARE_OFFSET]))) / + (ARROW_SIZE+(fEffects[PlayerOptions::EFFECT_SQUARE_PERIOD]*ARROW_SIZE))) ); + + fPixelOffsetFromCenter += (fEffects[PlayerOptions::EFFECT_SQUARE] * ARROW_SIZE * 0.5f) * fResult; + } if( fEffects[PlayerOptions::EFFECT_XMODE] != 0 ) { @@ -791,7 +947,7 @@ float ArrowGetPercentVisible(float fYPosWithoutReverse) fVisibleAdjust -= fAppearances[PlayerOptions::APPEARANCE_STEALTH]; if( fAppearances[PlayerOptions::APPEARANCE_BLINK] != 0 ) { - float f = RageFastSin(RageTimer::GetTimeSinceStartFast()*10); + float f = RageFastSin(ArrowEffects::GetTime()*10); f = Quantize( f, BLINK_MOD_FREQUENCY ); fVisibleAdjust += SCALE( f, 0, 1, -1, 0 ); } @@ -853,13 +1009,67 @@ float ArrowEffects::GetBrightness( const PlayerState* pPlayerState, float fNoteB } -float ArrowEffects::GetZPos(int iCol, float fYOffset) +float ArrowEffects::GetZPos( const PlayerState* pPlayerState, int iCol, float fYOffset) { float fZPos=0; const float* fEffects = curr_options->m_fEffects; + const Style* pStyle = GAMESTATE->GetCurrentStyle(pPlayerState->m_PlayerNumber); + + // TODO: Don't index by PlayerNumber. + const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pPlayerState->m_PlayerNumber]; + PerPlayerData &data = g_EffectData[pPlayerState->m_PlayerNumber]; + if( fEffects[PlayerOptions::EFFECT_TORNADO_Z] != 0 ) + { + fZPos += CalculateTornadoOffsetFromMagnitude(dim_z, iCol, + fEffects[PlayerOptions::EFFECT_TORNADO_Z], + fEffects[PlayerOptions::EFFECT_TORNADO_Z_OFFSET], + fEffects[PlayerOptions::EFFECT_TORNADO_Z_PERIOD], + pCols, pPlayerState->m_NotefieldZoom, data, fYOffset); + } + if( fEffects[PlayerOptions::EFFECT_BUMPY] != 0 ) fZPos += fEffects[PlayerOptions::EFFECT_BUMPY] * 40*RageFastSin( (fYOffset+(100.0f*fEffects[PlayerOptions::EFFECT_BUMPY_OFFSET]) )/((fEffects[PlayerOptions::EFFECT_BUMPY_PERIOD]*16.0f)+16.0f) ); + + if( fEffects[PlayerOptions::EFFECT_ZIGZAG_Z] != 0 ) + { + float fResult = RageTriangle( (PI * (1/(fEffects[PlayerOptions::EFFECT_ZIGZAG_Z_PERIOD]+1)) * + ((fYOffset+(100.0f*(fEffects[PlayerOptions::EFFECT_ZIGZAG_Z_OFFSET])))/ARROW_SIZE) ) ); + + fZPos += (fEffects[PlayerOptions::EFFECT_ZIGZAG_Z]*ARROW_SIZE/2) * fResult; + } + + if( fEffects[PlayerOptions::EFFECT_SAWTOOTH_Z] != 0 ) + fZPos += (fEffects[PlayerOptions::EFFECT_SAWTOOTH_Z]*ARROW_SIZE) * + ((0.5f/(fEffects[PlayerOptions::EFFECT_SAWTOOTH_Z_PERIOD]+1)*fYOffset)/ARROW_SIZE - + floor((0.5f/(fEffects[PlayerOptions::EFFECT_SAWTOOTH_Z_PERIOD]+1)*fYOffset)/ARROW_SIZE)); + + if( fEffects[PlayerOptions::EFFECT_PARABOLA_Z] != 0 ) + fZPos += fEffects[PlayerOptions::EFFECT_PARABOLA_Z] * (fYOffset/ARROW_SIZE) * (fYOffset/ARROW_SIZE); + + if( fEffects[PlayerOptions::EFFECT_DRUNK_Z] != 0 ) + fZPos += fEffects[PlayerOptions::EFFECT_DRUNK_Z] * + ( RageFastCos( GetTime()*(1+fEffects[PlayerOptions::EFFECT_DRUNK_Z_SPEED]) + iCol*((fEffects[PlayerOptions::EFFECT_DRUNK_Z_OFFSET]*DRUNK_Z_COLUMN_FREQUENCY)+DRUNK_Z_COLUMN_FREQUENCY) + + fYOffset*((fEffects[PlayerOptions::EFFECT_DRUNK_Z_PERIOD]*DRUNK_Z_OFFSET_FREQUENCY)+DRUNK_Z_OFFSET_FREQUENCY)/SCREEN_HEIGHT) * ARROW_SIZE*DRUNK_Z_ARROW_MAGNITUDE ); + + if( fEffects[PlayerOptions::EFFECT_BEAT_Z] != 0 ) + { + const float fShift = data.m_fBeatFactor[dim_z]*RageFastSin( fYOffset / ((fEffects[PlayerOptions::EFFECT_BEAT_Z_PERIOD]*BEAT_Z_OFFSET_HEIGHT)+BEAT_Z_OFFSET_HEIGHT) + PI/BEAT_Z_PI_HEIGHT ); + fZPos += fEffects[PlayerOptions::EFFECT_BEAT_Z] * fShift; + } + + if( fEffects[PlayerOptions::EFFECT_DIGITAL_Z] != 0 ) + fZPos += (fEffects[PlayerOptions::EFFECT_DIGITAL_Z] * ARROW_SIZE * 0.5f) * + round((fEffects[PlayerOptions::EFFECT_DIGITAL_Z_STEPS]+1) * RageFastSin( + (PI * (fYOffset + (1.0f * (fEffects[PlayerOptions::EFFECT_DIGITAL_Z_OFFSET]) ) ) / + (ARROW_SIZE + (fEffects[PlayerOptions::EFFECT_DIGITAL_Z_PERIOD] * ARROW_SIZE)) )))/(fEffects[PlayerOptions::EFFECT_DIGITAL_Z_STEPS]+1); + + if( fEffects[PlayerOptions::EFFECT_SQUARE_Z] != 0 ) + { + float fResult = RageSquare( (PI * (fYOffset+(1.0f*(fEffects[PlayerOptions::EFFECT_SQUARE_Z_OFFSET]))) / + (ARROW_SIZE+(fEffects[PlayerOptions::EFFECT_SQUARE_Z_PERIOD]*ARROW_SIZE))) ); + fZPos += (fEffects[PlayerOptions::EFFECT_SQUARE_Z] * ARROW_SIZE * 0.5f) * fResult; + } return fZPos; } @@ -874,6 +1084,18 @@ bool ArrowEffects::NeedZBuffer() { return true; } + if( fEffects[PlayerOptions::EFFECT_BEAT_Z] != 0 || + fEffects[PlayerOptions::EFFECT_DIGITAL_Z] != 0 ) + return true; + if( fEffects[PlayerOptions::EFFECT_ZIGZAG_Z] != 0 || + fEffects[PlayerOptions::EFFECT_SAWTOOTH_Z] != 0 ) + { + return true; + } + if( fEffects[PlayerOptions::EFFECT_PARABOLA_Z] != 0 ) + return true; + if( fEffects[PlayerOptions::EFFECT_SQUARE_Z] != 0 ) + return true; return false; } @@ -1000,7 +1222,7 @@ namespace { PlayerState *ps = Luna::check( L, 1 ); ArrowEffects::SetCurrentOptions(&ps->m_PlayerOptions.GetCurrent()); - lua_pushnumber(L, ArrowEffects::GetZPos(IArg(2)-1, FArg(3))); + lua_pushnumber(L, ArrowEffects::GetZPos( ps, IArg(2)-1, FArg(3))); return 1; } diff --git a/src/ArrowEffects.h b/src/ArrowEffects.h index bb95e54cc1..f5eba27698 100644 --- a/src/ArrowEffects.h +++ b/src/ArrowEffects.h @@ -2,6 +2,7 @@ #define ARROWEFFECTS_H #include "RageTypes.h" +#include "PlayerNumber.h" class PlayerState; class PlayerOptions; @@ -9,6 +10,8 @@ class PlayerOptions; class ArrowEffects { public: + static void Init(PlayerNumber pn); + static float GetTime(); static void Update(); // SetCurrentOptions and the hidden static variable it set exists so that // ArrowEffects doesn't have to reach through the PlayerState to check @@ -31,7 +34,7 @@ public: { ret.x= GetMoveX(col) + GetXPos(player_state, col, y_offset); ret.y= GetMoveY(col) + GetYPos(col, y_offset, y_reverse_offset, with_reverse); - ret.z= GetMoveZ(col) + GetZPos(col, y_offset); + ret.z= GetMoveZ(col) + GetZPos(player_state, col, y_offset); } /** @@ -80,7 +83,7 @@ public: * @param iCol the specific arrow column. * @param fYPos the Y position of the arrow. * @return the Z position. */ - static float GetZPos(int iCol, float fYPos); + static float GetZPos( const PlayerState* pPlayerState, int iCol, float fYPos); // Enable this if any ZPos effects are enabled. static bool NeedZBuffer(); diff --git a/src/Player.cpp b/src/Player.cpp index c48fa625ab..e1c6579d45 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -892,7 +892,7 @@ void Player::Update( float fDeltaTime ) //float fGrayYPos = SCALE( fPercentReverse, 0.f, 1.f, GRAY_ARROWS_Y_STANDARD, GRAY_ARROWS_Y_REVERSE ); float fX = ArrowEffects::GetXPos( m_pPlayerState, c, 0 ); - const float fZ = ArrowEffects::GetZPos(c, 0); + const float fZ = ArrowEffects::GetZPos( m_pPlayerState, c, 0); fX *= ( 1 - fMiniPercent * 0.5f ); m_vpHoldJudgment[c]->SetX( fX ); diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index 7f3753a79a..32eaa443f2 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -30,6 +30,16 @@ XToString( DrainType ); XToLocalizedString( DrainType ); LuaXType( DrainType ); +static const char *ModTimerTypeNames[] = { + "Game", + "Beat", + "Song", + "Default", +}; +XToString( ModTimerType ); +XToLocalizedString( ModTimerType ); +LuaXType( ModTimerType ); + void NextFloat( float fValues[], int size ); void NextBool( bool bValues[], int size ); @@ -51,6 +61,7 @@ void PlayerOptions::Init() { m_LifeType = LifeType_Bar; m_DrainType = DrainType_Normal; + m_ModTimerType = ModTimerType_Default; m_BatteryLives = 4; m_MinTNSToHideNotes= PREFSMAN->m_MinTNSToHideNotes; m_bSetScrollSpeed = false; @@ -72,6 +83,8 @@ void PlayerOptions::Init() m_fSkew = 0; m_SpeedfSkew = 1.0f; m_fPassmark = 0; m_SpeedfPassmark = 1.0f; m_fRandomSpeed = 0; m_SpeedfRandomSpeed = 1.0f; + m_fModTimerMult = 0; m_SpeedfModTimerMult = 1.0f; + m_fModTimerOffset = 0; m_SpeedfModTimerOffset = 1.0f; ZERO( m_bTurns ); ZERO( m_bTransforms ); m_bMuteOnError = false; @@ -91,7 +104,10 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds ) DO_COPY( m_LifeType ); DO_COPY( m_DrainType ); + DO_COPY( m_ModTimerType ); DO_COPY( m_BatteryLives ); + APPROACH( fModTimerMult ); + APPROACH( fModTimerOffset ); APPROACH( fTimeSpacing ); APPROACH( fScrollSpeed ); APPROACH( fMaxScrollBPM ); @@ -210,6 +226,23 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const RString s = ssprintf( "C%.0f", m_fScrollBPM ); AddTo.push_back( s ); } + + switch(m_ModTimerType) + { + case ModTimerType_Game: + AddTo.push_back("ModTimerGame"); + break; + case ModTimerType_Beat: + AddTo.push_back("ModTimerBeat"); + break; + case ModTimerType_Song: + AddTo.push_back("ModTimerSong"); + break; + case ModTimerType_Default: + break; + default: + FAIL_M(ssprintf("Invalid ModTimerType: %i", m_ModTimerType)); + } AddPart( AddTo, m_fAccels[ACCEL_BOOST], "Boost" ); AddPart( AddTo, m_fAccels[ACCEL_BRAKE], "Brake" ); @@ -223,6 +256,10 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fEffects[EFFECT_DRUNK_SPEED], "DrunkSpeed" ); AddPart( AddTo, m_fEffects[EFFECT_DRUNK_OFFSET], "DrunkOffset" ); AddPart( AddTo, m_fEffects[EFFECT_DRUNK_PERIOD], "DrunkPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_DRUNK_Z], "DrunkZ" ); + AddPart( AddTo, m_fEffects[EFFECT_DRUNK_Z_SPEED], "DrunkZSpeed" ); + AddPart( AddTo, m_fEffects[EFFECT_DRUNK_Z_OFFSET], "DrunkZOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_DRUNK_Z_PERIOD], "DrunkZPeriod" ); AddPart( AddTo, m_fEffects[EFFECT_DIZZY], "Dizzy" ); AddPart( AddTo, m_fEffects[EFFECT_CONFUSION], "Confusion" ); AddPart( AddTo, m_fEffects[EFFECT_CONFUSION_OFFSET], "ConfusionOffset" ); @@ -237,16 +274,57 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fEffects[EFFECT_TORNADO], "Tornado" ); AddPart( AddTo, m_fEffects[EFFECT_TORNADO_PERIOD], "TornadoPeriod" ); AddPart( AddTo, m_fEffects[EFFECT_TORNADO_OFFSET], "TornadoOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_TORNADO_Z], "TornadoZ" ); + AddPart( AddTo, m_fEffects[EFFECT_TORNADO_Z_PERIOD], "TornadoZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_TORNADO_Z_OFFSET], "TornadoZOffset" ); AddPart( AddTo, m_fEffects[EFFECT_TIPSY], "Tipsy" ); AddPart( AddTo, m_fEffects[EFFECT_TIPSY_SPEED], "TipsySpeed" ); AddPart( AddTo, m_fEffects[EFFECT_TIPSY_OFFSET], "TipsyOffset" ); AddPart( AddTo, m_fEffects[EFFECT_BUMPY], "Bumpy" ); - AddPart( AddTo, m_fEffects[EFFECT_BUMPY_OFFSET], "BumpyOffset" ); - AddPart( AddTo, m_fEffects[EFFECT_BUMPY_PERIOD], "BumpyPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY_OFFSET], "BumpyOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY_PERIOD], "BumpyPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY_X], "BumpyX" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY_X_OFFSET], "BumpyXOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY_X_PERIOD], "BumpyXPeriod" ); AddPart( AddTo, m_fEffects[EFFECT_BEAT], "Beat" ); AddPart( AddTo, m_fEffects[EFFECT_BEAT_OFFSET], "BeatOffset" ); AddPart( AddTo, m_fEffects[EFFECT_BEAT_PERIOD], "BeatPeriod" ); AddPart( AddTo, m_fEffects[EFFECT_BEAT_MULT], "BeatMult" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Y], "BeatY" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Y_OFFSET], "BeatYOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Y_PERIOD], "BeatYPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Y_MULT], "BeatYMult" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Z], "BeatZ" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Z_OFFSET], "BeatZOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Z_PERIOD], "BeatZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT_Z_MULT], "BeatZMult" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG], "Zigzag" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG_PERIOD], "ZigzagPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG_OFFSET], "ZigzagOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG_Z], "ZigzagZ" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG_Z_PERIOD], "ZigzagZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_ZIGZAG_Z_OFFSET], "ZigzagZOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_SAWTOOTH], "Sawtooth" ); + AddPart( AddTo, m_fEffects[EFFECT_SAWTOOTH_PERIOD], "SawtoothPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_SAWTOOTH_Z], "SawtoothZ" ); + AddPart( AddTo, m_fEffects[EFFECT_SAWTOOTH_Z_PERIOD], "SawtoothZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE], "Square" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE_OFFSET], "SquareOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE_PERIOD], "SquarePeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE_Z], "SquareZ" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE_Z_OFFSET], "SquareZOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_SQUARE_Z_PERIOD], "SquareZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL], "Digital" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_STEPS], "DigitalSteps" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_PERIOD], "DigitalPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_OFFSET], "DigitalOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_Z], "DigitalZ" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_Z_STEPS], "DigitalZSteps" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_Z_PERIOD], "DigitalZPeriod" ); + AddPart( AddTo, m_fEffects[EFFECT_DIGITAL_Z_OFFSET], "DigitalZOffset" ); + AddPart( AddTo, m_fEffects[EFFECT_PARABOLA_X], "ParabolaX" ); + AddPart( AddTo, m_fEffects[EFFECT_PARABOLA_Y], "ParabolaY" ); + AddPart( AddTo, m_fEffects[EFFECT_PARABOLA_Z], "ParabolaZ" ); AddPart( AddTo, m_fEffects[EFFECT_XMODE], "XMode" ); AddPart( AddTo, m_fEffects[EFFECT_TWIRL], "Twirl" ); AddPart( AddTo, m_fEffects[EFFECT_ROLL], "Roll" ); @@ -276,6 +354,9 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fScrolls[SCROLL_CROSS], "Cross" ); AddPart( AddTo, m_fScrolls[SCROLL_CENTERED], "Centered" ); + AddPart( AddTo, m_fModTimerMult, "ModTimerMult" ); + AddPart( AddTo, m_fModTimerOffset, "ModTimerOffset" ); + AddPart( AddTo, m_fDark, "Dark" ); AddPart( AddTo, m_fBlind, "Blind" ); @@ -490,6 +571,15 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut // level is a percentage for every other option, so multiply by 100. -Kyz m_BatteryLives= level * 100.0f; } + else if( sBit.find("modtimer") != sBit.npos) + { + if( sBit == "modtimerdefault" ) { m_ModTimerType= ModTimerType_Default; } + else if( sBit == "modtimersong" ) { m_ModTimerType= ModTimerType_Song; } + else if( sBit == "modtimerbeat" ) { m_ModTimerType= ModTimerType_Beat; } + else if( sBit == "modtimergame" ) { m_ModTimerType= ModTimerType_Game; } + else if( sBit == "modtimermult" ) SET_FLOAT( fModTimerMult ) + else if( sBit == "modtimeroffset" ) SET_FLOAT( fModTimerOffset ) + } else if( sBit == "bar" ) { m_LifeType= LifeType_Bar; } else if( sBit == "battery" ) { m_LifeType= LifeType_Battery; } else if( sBit == "lifetime" ) { m_LifeType= LifeType_Time; } @@ -515,6 +605,10 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut else if( sBit == "drunkspeed" ) SET_FLOAT( fEffects[EFFECT_DRUNK_SPEED] ) else if( sBit == "drunkoffset" ) SET_FLOAT( fEffects[EFFECT_DRUNK_OFFSET] ) else if( sBit == "drunkperiod" ) SET_FLOAT( fEffects[EFFECT_DRUNK_PERIOD] ) + else if( sBit == "drunkz" ) SET_FLOAT( fEffects[EFFECT_DRUNK_Z] ) + else if( sBit == "drunkzspeed" ) SET_FLOAT( fEffects[EFFECT_DRUNK_Z_SPEED] ) + else if( sBit == "drunkzoffset" ) SET_FLOAT( fEffects[EFFECT_DRUNK_Z_OFFSET] ) + else if( sBit == "drunkzperiod" ) SET_FLOAT( fEffects[EFFECT_DRUNK_Z_PERIOD] ) } else if( sBit == "dizzy" ) SET_FLOAT( fEffects[EFFECT_DIZZY] ) else if( sBit.find("confusion") != sBit.npos) @@ -535,6 +629,9 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut if( sBit == "tornado" ) SET_FLOAT( fEffects[EFFECT_TORNADO] ) else if( sBit == "tornadoperiod" ) SET_FLOAT( fEffects[EFFECT_TORNADO_PERIOD] ) else if( sBit == "tornadooffset" ) SET_FLOAT( fEffects[EFFECT_TORNADO_OFFSET] ) + else if( sBit == "tornadoz" ) SET_FLOAT( fEffects[EFFECT_TORNADO_Z] ) + else if( sBit == "tornadozperiod" ) SET_FLOAT( fEffects[EFFECT_TORNADO_Z_PERIOD] ) + else if( sBit == "tornadozoffset" ) SET_FLOAT( fEffects[EFFECT_TORNADO_Z_OFFSET] ) } else if( sBit.find("tipsy") != sBit.npos) { @@ -547,6 +644,9 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut if( sBit == "bumpy" ) SET_FLOAT( fEffects[EFFECT_BUMPY] ) else if( sBit == "bumpyoffset" ) SET_FLOAT( fEffects[EFFECT_BUMPY_OFFSET] ) else if( sBit == "bumpyperiod" ) SET_FLOAT( fEffects[EFFECT_BUMPY_PERIOD] ) + else if( sBit == "bumpyx" ) SET_FLOAT( fEffects[EFFECT_BUMPY_X] ) + else if( sBit == "bumpyxoffset" ) SET_FLOAT( fEffects[EFFECT_BUMPY_X_OFFSET] ) + else if( sBit == "bumpyxperiod" ) SET_FLOAT( fEffects[EFFECT_BUMPY_X_PERIOD] ) } else if( sBit.find("beat") != sBit.npos) { @@ -554,6 +654,56 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut else if( sBit == "beatoffset" ) SET_FLOAT( fEffects[EFFECT_BEAT_OFFSET] ) else if( sBit == "beatperiod" ) SET_FLOAT( fEffects[EFFECT_BEAT_PERIOD] ) else if( sBit == "beatmult" ) SET_FLOAT( fEffects[EFFECT_BEAT_MULT] ) + else if( sBit == "beaty" ) SET_FLOAT( fEffects[EFFECT_BEAT_Y] ) + else if( sBit == "beatyoffset" ) SET_FLOAT( fEffects[EFFECT_BEAT_Y_OFFSET] ) + else if( sBit == "beatyperiod" ) SET_FLOAT( fEffects[EFFECT_BEAT_Y_PERIOD] ) + else if( sBit == "beatymult" ) SET_FLOAT( fEffects[EFFECT_BEAT_Y_MULT] ) + else if( sBit == "beatz" ) SET_FLOAT( fEffects[EFFECT_BEAT_Z] ) + else if( sBit == "beatzoffset" ) SET_FLOAT( fEffects[EFFECT_BEAT_Z_OFFSET] ) + else if( sBit == "beatzperiod" ) SET_FLOAT( fEffects[EFFECT_BEAT_Z_PERIOD] ) + else if( sBit == "beatzmult" ) SET_FLOAT( fEffects[EFFECT_BEAT_Z_MULT] ) + } + else if( sBit.find("digital") != sBit.npos) + { + if( sBit == "digital" ) SET_FLOAT( fEffects[EFFECT_DIGITAL] ) + else if( sBit == "digitalsteps" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_STEPS] ) + else if( sBit == "digitalperiod" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_PERIOD] ) + else if( sBit == "digitaloffset" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_OFFSET] ) + else if( sBit == "digitalz" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_Z] ) + else if( sBit == "digitalzsteps" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_Z_STEPS] ) + else if( sBit == "digitalzperiod" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_Z_PERIOD] ) + else if( sBit == "digitalzoffset" ) SET_FLOAT( fEffects[EFFECT_DIGITAL_Z_OFFSET] ) + } + else if( sBit.find("zigzag") != sBit.npos) + { + if( sBit == "zigzag" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG] ) + else if( sBit == "zigzagperiod" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG_PERIOD] ) + else if( sBit == "zigzagoffset" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG_OFFSET] ) + else if( sBit == "zigzagz" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG_Z] ) + else if( sBit == "zigzagzperiod" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG_Z_PERIOD] ) + else if( sBit == "zigzagzoffset" ) SET_FLOAT( fEffects[EFFECT_ZIGZAG_Z_OFFSET] ) + } + else if( sBit.find("sawtooth") != sBit.npos) + { + if( sBit == "sawtooth" ) SET_FLOAT( fEffects[EFFECT_SAWTOOTH] ) + else if( sBit == "sawtoothperiod" ) SET_FLOAT( fEffects[EFFECT_SAWTOOTH_PERIOD] ) + else if( sBit == "sawtoothz" ) SET_FLOAT( fEffects[EFFECT_SAWTOOTH_Z] ) + else if( sBit == "sawtoothzperiod" ) SET_FLOAT( fEffects[EFFECT_SAWTOOTH_Z_PERIOD] ) + } + else if( sBit.find("square") != sBit.npos) + { + if( sBit == "square" ) SET_FLOAT( fEffects[EFFECT_SQUARE] ) + else if( sBit == "squareoffset" ) SET_FLOAT( fEffects[EFFECT_SQUARE_OFFSET] ) + else if( sBit == "squareperiod" ) SET_FLOAT( fEffects[EFFECT_SQUARE_PERIOD] ) + else if( sBit == "squarez" ) SET_FLOAT( fEffects[EFFECT_SQUARE_Z] ) + else if( sBit == "squarezoffset" ) SET_FLOAT( fEffects[EFFECT_SQUARE_Z_OFFSET] ) + else if( sBit == "squarezperiod" ) SET_FLOAT( fEffects[EFFECT_SQUARE_Z_PERIOD] ) + } + else if( sBit.find("parabola") != sBit.npos) + { + if( sBit == "parabolax" ) SET_FLOAT( fEffects[EFFECT_PARABOLA_X] ) + else if( sBit == "parabolay" ) SET_FLOAT( fEffects[EFFECT_PARABOLA_Y] ) + else if( sBit == "parabolaz" ) SET_FLOAT( fEffects[EFFECT_PARABOLA_Z] ) } else if( sBit == "xmode" ) SET_FLOAT( fEffects[EFFECT_XMODE] ) else if( sBit == "twirl" ) SET_FLOAT( fEffects[EFFECT_TWIRL] ) @@ -861,6 +1011,9 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const #define COMPARE(x) { if( x != other.x ) return false; } COMPARE(m_LifeType); COMPARE(m_DrainType); + COMPARE(m_ModTimerType); + COMPARE(m_fModTimerMult); + COMPARE(m_fModTimerOffset); COMPARE(m_BatteryLives); COMPARE(m_fTimeSpacing); COMPARE(m_fScrollSpeed); @@ -916,6 +1069,9 @@ PlayerOptions& PlayerOptions::operator=(PlayerOptions const& other) #define CPY_SPEED(x) m_ ## x = other.m_ ## x; m_Speed ## x = other.m_Speed ## x; CPY(m_LifeType); CPY(m_DrainType); + CPY(m_ModTimerType); + CPY_SPEED(fModTimerMult); + CPY_SPEED(fModTimerOffset); CPY(m_BatteryLives); CPY_SPEED(fTimeSpacing); CPY_SPEED(fScrollSpeed); @@ -1152,6 +1308,9 @@ void PlayerOptions::ResetPrefs( ResetPrefsType type ) CPY(m_LifeType); CPY(m_DrainType); CPY(m_BatteryLives); + CPY(m_ModTimerType); + CPY(m_fModTimerMult); + CPY(m_fModTimerOffset); CPY(m_MinTNSToHideNotes); CPY( m_fPerspectiveTilt ); @@ -1198,7 +1357,10 @@ public: ENUM_INTERFACE(LifeSetting, LifeType, LifeType); ENUM_INTERFACE(DrainSetting, DrainType, DrainType); + ENUM_INTERFACE(ModTimerSetting, ModTimerType, ModTimerType) INT_INTERFACE(BatteryLives, BatteryLives); + FLOAT_INTERFACE(ModTimerMult, ModTimerMult, true); + FLOAT_INTERFACE(ModTimerOffset, ModTimerOffset, true); FLOAT_INTERFACE(TimeSpacing, TimeSpacing, true); FLOAT_INTERFACE(MaxScrollBPM, MaxScrollBPM, true); FLOAT_INTERFACE(ScrollSpeed, ScrollSpeed, true); @@ -1214,6 +1376,10 @@ public: FLOAT_INTERFACE(DrunkSpeed, Effects[PlayerOptions::EFFECT_DRUNK_SPEED], true); FLOAT_INTERFACE(DrunkOffset, Effects[PlayerOptions::EFFECT_DRUNK_OFFSET], true); FLOAT_INTERFACE(DrunkPeriod, Effects[PlayerOptions::EFFECT_DRUNK_PERIOD], true); + FLOAT_INTERFACE(DrunkZ, Effects[PlayerOptions::EFFECT_DRUNK_Z], true); + FLOAT_INTERFACE(DrunkZSpeed, Effects[PlayerOptions::EFFECT_DRUNK_Z_SPEED], true); + FLOAT_INTERFACE(DrunkZOffset, Effects[PlayerOptions::EFFECT_DRUNK_Z_OFFSET], true); + FLOAT_INTERFACE(DrunkZPeriod, Effects[PlayerOptions::EFFECT_DRUNK_Z_PERIOD], true); FLOAT_INTERFACE(Dizzy, Effects[PlayerOptions::EFFECT_DIZZY], true); FLOAT_INTERFACE(Confusion, Effects[PlayerOptions::EFFECT_CONFUSION], true); FLOAT_INTERFACE(ConfusionOffset, Effects[PlayerOptions::EFFECT_CONFUSION_OFFSET], true); @@ -1228,16 +1394,57 @@ public: FLOAT_INTERFACE(Tornado, Effects[PlayerOptions::EFFECT_TORNADO], true); FLOAT_INTERFACE(TornadoPeriod, Effects[PlayerOptions::EFFECT_TORNADO_PERIOD], true); FLOAT_INTERFACE(TornadoOffset, Effects[PlayerOptions::EFFECT_TORNADO_OFFSET], true); + FLOAT_INTERFACE(TornadoZ, Effects[PlayerOptions::EFFECT_TORNADO_Z], true); + FLOAT_INTERFACE(TornadoZPeriod, Effects[PlayerOptions::EFFECT_TORNADO_Z_PERIOD], true); + FLOAT_INTERFACE(TornadoZOffset, Effects[PlayerOptions::EFFECT_TORNADO_Z_OFFSET], true); FLOAT_INTERFACE(Tipsy, Effects[PlayerOptions::EFFECT_TIPSY], true); FLOAT_INTERFACE(TipsySpeed, Effects[PlayerOptions::EFFECT_TIPSY_SPEED], true); FLOAT_INTERFACE(TipsyOffset, Effects[PlayerOptions::EFFECT_TIPSY_OFFSET], true); FLOAT_INTERFACE(Bumpy, Effects[PlayerOptions::EFFECT_BUMPY], true); FLOAT_INTERFACE(BumpyOffset, Effects[PlayerOptions::EFFECT_BUMPY_OFFSET], true); FLOAT_INTERFACE(BumpyPeriod, Effects[PlayerOptions::EFFECT_BUMPY_PERIOD], true); + FLOAT_INTERFACE(BumpyX, Effects[PlayerOptions::EFFECT_BUMPY_X], true); + FLOAT_INTERFACE(BumpyXOffset, Effects[PlayerOptions::EFFECT_BUMPY_X_OFFSET], true); + FLOAT_INTERFACE(BumpyXPeriod, Effects[PlayerOptions::EFFECT_BUMPY_X_PERIOD], true); FLOAT_INTERFACE(Beat, Effects[PlayerOptions::EFFECT_BEAT], true); FLOAT_INTERFACE(BeatOffset, Effects[PlayerOptions::EFFECT_BEAT_OFFSET], true); FLOAT_INTERFACE(BeatPeriod, Effects[PlayerOptions::EFFECT_BEAT_PERIOD], true); FLOAT_INTERFACE(BeatMult, Effects[PlayerOptions::EFFECT_BEAT_MULT], true); + FLOAT_INTERFACE(BeatY, Effects[PlayerOptions::EFFECT_BEAT_Y], true); + FLOAT_INTERFACE(BeatYOffset, Effects[PlayerOptions::EFFECT_BEAT_Y_OFFSET], true); + FLOAT_INTERFACE(BeatYPeriod, Effects[PlayerOptions::EFFECT_BEAT_Y_PERIOD], true); + FLOAT_INTERFACE(BeatYMult, Effects[PlayerOptions::EFFECT_BEAT_Y_MULT], true); + FLOAT_INTERFACE(BeatZ, Effects[PlayerOptions::EFFECT_BEAT_Z], true); + FLOAT_INTERFACE(BeatZOffset, Effects[PlayerOptions::EFFECT_BEAT_Z_OFFSET], true); + FLOAT_INTERFACE(BeatZPeriod, Effects[PlayerOptions::EFFECT_BEAT_Z_PERIOD], true); + FLOAT_INTERFACE(BeatZMult, Effects[PlayerOptions::EFFECT_BEAT_Z_MULT], true); + FLOAT_INTERFACE(Zigzag, Effects[PlayerOptions::EFFECT_ZIGZAG], true); + FLOAT_INTERFACE(ZigzagPeriod, Effects[PlayerOptions::EFFECT_ZIGZAG_PERIOD], true); + FLOAT_INTERFACE(ZigzagOffset, Effects[PlayerOptions::EFFECT_ZIGZAG_OFFSET], true); + FLOAT_INTERFACE(ZigzagZ, Effects[PlayerOptions::EFFECT_ZIGZAG_Z], true); + FLOAT_INTERFACE(ZigzagZPeriod, Effects[PlayerOptions::EFFECT_ZIGZAG_Z_PERIOD], true); + FLOAT_INTERFACE(ZigzagZOffset, Effects[PlayerOptions::EFFECT_ZIGZAG_Z_OFFSET], true); + FLOAT_INTERFACE(Sawtooth, Effects[PlayerOptions::EFFECT_SAWTOOTH], true); + FLOAT_INTERFACE(SawtoothPeriod, Effects[PlayerOptions::EFFECT_SAWTOOTH_PERIOD], true); + FLOAT_INTERFACE(SawtoothZ, Effects[PlayerOptions::EFFECT_SAWTOOTH_Z], true); + FLOAT_INTERFACE(SawtoothZPeriod, Effects[PlayerOptions::EFFECT_SAWTOOTH_Z_PERIOD], true); + FLOAT_INTERFACE(Square, Effects[PlayerOptions::EFFECT_SQUARE], true); + FLOAT_INTERFACE(SquareOffset, Effects[PlayerOptions::EFFECT_SQUARE_OFFSET], true); + FLOAT_INTERFACE(SquarePeriod, Effects[PlayerOptions::EFFECT_SQUARE_PERIOD], true); + FLOAT_INTERFACE(SquareZ, Effects[PlayerOptions::EFFECT_SQUARE_Z], true); + FLOAT_INTERFACE(SquareZOffset, Effects[PlayerOptions::EFFECT_SQUARE_Z_OFFSET], true); + FLOAT_INTERFACE(SquareZPeriod, Effects[PlayerOptions::EFFECT_SQUARE_Z_PERIOD], true); + FLOAT_INTERFACE(Digital, Effects[PlayerOptions::EFFECT_DIGITAL], true); + FLOAT_INTERFACE(DigitalSteps, Effects[PlayerOptions::EFFECT_DIGITAL_STEPS], true); + FLOAT_INTERFACE(DigitalPeriod, Effects[PlayerOptions::EFFECT_DIGITAL_PERIOD], true); + FLOAT_INTERFACE(DigitalOffset, Effects[PlayerOptions::EFFECT_DIGITAL_OFFSET], true); + FLOAT_INTERFACE(DigitalZ, Effects[PlayerOptions::EFFECT_DIGITAL_Z], true); + FLOAT_INTERFACE(DigitalZSteps, Effects[PlayerOptions::EFFECT_DIGITAL_Z_STEPS], true); + FLOAT_INTERFACE(DigitalZPeriod, Effects[PlayerOptions::EFFECT_DIGITAL_Z_PERIOD], true); + FLOAT_INTERFACE(DigitalZOffset, Effects[PlayerOptions::EFFECT_DIGITAL_Z_OFFSET], true); + FLOAT_INTERFACE(ParabolaX, Effects[PlayerOptions::EFFECT_PARABOLA_X], true); + FLOAT_INTERFACE(ParabolaY, Effects[PlayerOptions::EFFECT_PARABOLA_Y], true); + FLOAT_INTERFACE(ParabolaZ, Effects[PlayerOptions::EFFECT_PARABOLA_Z], 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); @@ -1608,6 +1815,9 @@ public: ADD_METHOD(LifeSetting); ADD_METHOD(DrainSetting); + ADD_METHOD(ModTimerSetting); + ADD_METHOD(ModTimerMult); + ADD_METHOD(ModTimerOffset); ADD_METHOD(BatteryLives); ADD_METHOD(TimeSpacing); ADD_METHOD(MaxScrollBPM); @@ -1624,6 +1834,10 @@ public: ADD_METHOD(DrunkSpeed); ADD_METHOD(DrunkOffset); ADD_METHOD(DrunkPeriod); + ADD_METHOD(DrunkZ); + ADD_METHOD(DrunkZSpeed); + ADD_METHOD(DrunkZOffset); + ADD_METHOD(DrunkZPeriod); ADD_METHOD(Dizzy); ADD_METHOD(Confusion); ADD_METHOD(ConfusionOffset); @@ -1638,16 +1852,57 @@ public: ADD_METHOD(Tornado); ADD_METHOD(TornadoPeriod); ADD_METHOD(TornadoOffset); + ADD_METHOD(TornadoZ); + ADD_METHOD(TornadoZPeriod); + ADD_METHOD(TornadoZOffset); ADD_METHOD(Tipsy); ADD_METHOD(TipsySpeed); ADD_METHOD(TipsyOffset); ADD_METHOD(Bumpy); ADD_METHOD(BumpyOffset); ADD_METHOD(BumpyPeriod); + ADD_METHOD(BumpyX); + ADD_METHOD(BumpyXOffset); + ADD_METHOD(BumpyXPeriod); ADD_METHOD(Beat); ADD_METHOD(BeatOffset); ADD_METHOD(BeatPeriod); ADD_METHOD(BeatMult); + ADD_METHOD(BeatY); + ADD_METHOD(BeatYOffset); + ADD_METHOD(BeatYPeriod); + ADD_METHOD(BeatYMult); + ADD_METHOD(BeatZ); + ADD_METHOD(BeatZOffset); + ADD_METHOD(BeatZPeriod); + ADD_METHOD(BeatZMult); + ADD_METHOD(Zigzag); + ADD_METHOD(ZigzagPeriod); + ADD_METHOD(ZigzagOffset); + ADD_METHOD(ZigzagZ); + ADD_METHOD(ZigzagZPeriod); + ADD_METHOD(ZigzagZOffset); + ADD_METHOD(Sawtooth); + ADD_METHOD(SawtoothPeriod); + ADD_METHOD(SawtoothZ); + ADD_METHOD(SawtoothZPeriod); + ADD_METHOD(Square); + ADD_METHOD(SquareOffset); + ADD_METHOD(SquarePeriod); + ADD_METHOD(SquareZ); + ADD_METHOD(SquareZOffset); + ADD_METHOD(SquareZPeriod); + ADD_METHOD(Digital); + ADD_METHOD(DigitalSteps); + ADD_METHOD(DigitalPeriod); + ADD_METHOD(DigitalOffset); + ADD_METHOD(DigitalZ); + ADD_METHOD(DigitalZSteps); + ADD_METHOD(DigitalZPeriod); + ADD_METHOD(DigitalZOffset); + ADD_METHOD(ParabolaX); + ADD_METHOD(ParabolaY); + ADD_METHOD(ParabolaZ); ADD_METHOD(Xmode); ADD_METHOD(Twirl); ADD_METHOD(Roll); diff --git a/src/PlayerOptions.h b/src/PlayerOptions.h index 383bf24bec..b46ad69189 100644 --- a/src/PlayerOptions.h +++ b/src/PlayerOptions.h @@ -37,6 +37,19 @@ const RString& DrainTypeToString( DrainType cat ); const RString& DrainTypeToLocalizedString( DrainType cat ); LuaDeclareType( DrainType ); +enum ModTimerType +{ + ModTimerType_Game, + ModTimerType_Beat, + ModTimerType_Song, + ModTimerType_Default, + NUM_ModTimerType, + ModTimerType_Invalid +}; +const RString& ModTimerTypeToString( ModTimerType cat ); +const RString& ModTimerTypeToLocalizedString( ModTimerType cat ); +LuaDeclareType( ModTimerType ); + /** @brief Per-player options that are not saved between sessions. */ class PlayerOptions { @@ -46,6 +59,7 @@ public: * * This code was taken from Init() to use proper initialization. */ PlayerOptions(): m_LifeType(LifeType_Bar), m_DrainType(DrainType_Normal), + m_ModTimerType(ModTimerType_Default), m_BatteryLives(4), m_bSetScrollSpeed(false), m_fTimeSpacing(0), m_SpeedfTimeSpacing(1.0f), @@ -62,6 +76,8 @@ public: m_fSkew(0), m_SpeedfSkew(1.0f), m_fPassmark(0), m_SpeedfPassmark(1.0f), m_fRandomSpeed(0), m_SpeedfRandomSpeed(1.0f), + m_fModTimerMult(0), m_SpeedfModTimerMult(1.0f), + m_fModTimerOffset(0), m_SpeedfModTimerOffset(1.0f), m_bMuteOnError(false), m_FailType(FailType_Immediate), m_MinTNSToHideNotes(PREFSMAN->m_MinTNSToHideNotes) { @@ -117,6 +133,10 @@ public: EFFECT_DRUNK_SPEED, EFFECT_DRUNK_OFFSET, EFFECT_DRUNK_PERIOD, + EFFECT_DRUNK_Z, + EFFECT_DRUNK_Z_SPEED, + EFFECT_DRUNK_Z_OFFSET, + EFFECT_DRUNK_Z_PERIOD, EFFECT_DIZZY, EFFECT_CONFUSION, EFFECT_CONFUSION_OFFSET, @@ -131,16 +151,57 @@ public: EFFECT_TORNADO, EFFECT_TORNADO_PERIOD, EFFECT_TORNADO_OFFSET, + EFFECT_TORNADO_Z, + EFFECT_TORNADO_Z_PERIOD, + EFFECT_TORNADO_Z_OFFSET, EFFECT_TIPSY, EFFECT_TIPSY_SPEED, EFFECT_TIPSY_OFFSET, EFFECT_BUMPY, EFFECT_BUMPY_OFFSET, EFFECT_BUMPY_PERIOD, + EFFECT_BUMPY_X, + EFFECT_BUMPY_X_OFFSET, + EFFECT_BUMPY_X_PERIOD, EFFECT_BEAT, EFFECT_BEAT_OFFSET, EFFECT_BEAT_PERIOD, EFFECT_BEAT_MULT, + EFFECT_BEAT_Y, + EFFECT_BEAT_Y_OFFSET, + EFFECT_BEAT_Y_PERIOD, + EFFECT_BEAT_Y_MULT, + EFFECT_BEAT_Z, + EFFECT_BEAT_Z_OFFSET, + EFFECT_BEAT_Z_PERIOD, + EFFECT_BEAT_Z_MULT, + EFFECT_DIGITAL, + EFFECT_DIGITAL_STEPS, + EFFECT_DIGITAL_PERIOD, + EFFECT_DIGITAL_OFFSET, + EFFECT_DIGITAL_Z, + EFFECT_DIGITAL_Z_STEPS, + EFFECT_DIGITAL_Z_PERIOD, + EFFECT_DIGITAL_Z_OFFSET, + EFFECT_ZIGZAG, + EFFECT_ZIGZAG_PERIOD, + EFFECT_ZIGZAG_OFFSET, + EFFECT_ZIGZAG_Z, + EFFECT_ZIGZAG_Z_PERIOD, + EFFECT_ZIGZAG_Z_OFFSET, + EFFECT_SAWTOOTH, + EFFECT_SAWTOOTH_PERIOD, + EFFECT_SAWTOOTH_Z, + EFFECT_SAWTOOTH_Z_PERIOD, + EFFECT_SQUARE, + EFFECT_SQUARE_PERIOD, + EFFECT_SQUARE_OFFSET, + EFFECT_SQUARE_Z, + EFFECT_SQUARE_Z_PERIOD, + EFFECT_SQUARE_Z_OFFSET, + EFFECT_PARABOLA_X, + EFFECT_PARABOLA_Y, + EFFECT_PARABOLA_Z, EFFECT_XMODE, EFFECT_TWIRL, EFFECT_ROLL, @@ -210,6 +271,7 @@ public: LifeType m_LifeType; DrainType m_DrainType; // only used with LifeBar + ModTimerType m_ModTimerType; int m_BatteryLives; /* All floats have a corresponding speed setting, which determines how fast * PlayerOptions::Approach approaches. */ @@ -236,6 +298,8 @@ public: float m_fPassmark, m_SpeedfPassmark; float m_fRandomSpeed, m_SpeedfRandomSpeed; + float m_fModTimerMult, m_SpeedfModTimerMult; + float m_fModTimerOffset, m_SpeedfModTimerOffset; /* The maximum column number is 16.*/ float m_fMovesX[16], m_SpeedfMovesX[16]; float m_fMovesY[16], m_SpeedfMovesY[16]; diff --git a/src/RageMath.cpp b/src/RageMath.cpp index 5e85551cb2..8f112aed91 100644 --- a/src/RageMath.cpp +++ b/src/RageMath.cpp @@ -643,6 +643,40 @@ float RageFastCos( float x ) return RageFastSin( x + 0.5f*PI ); } +float RageSquare( float angle ) +{ + float fAngle = fmod( angle , (PI * 2) ); + //Hack: This ensures the hold notes don't flicker right before they're hit. + if(fAngle < 0.01f) + { + fAngle+= PI * 2; + } + return fAngle >= PI ? -1.0 : 1.0; +} + +float RageTriangle( float angle ) +{ + float fAngle= fmod(angle, PI * 2.0); + if(fAngle < 0.0) + { + fAngle+= PI * 2.0; + } + double result= fAngle * (1 / PI); + if(result < .5) + { + return result * 2.0; + } + else if(result < 1.5) + { + return 1.0 - ((result - .5) * 2.0); + } + else + { + return -4.0 + (result * 2.0); + } + +} + float RageQuadratic::Evaluate( float fT ) const { // optimized (m_fA * fT*fT*fT) + (m_fB * fT*fT) + (m_fC * fT) + m_fD; diff --git a/src/RageMath.h b/src/RageMath.h index 12b91fe556..b9a2022563 100644 --- a/src/RageMath.h +++ b/src/RageMath.h @@ -56,6 +56,9 @@ void RageMatrixTranspose( RageMatrix* pOut, const RageMatrix* pIn ); float RageFastSin( float x ) CONST_FUNCTION; float RageFastCos( float x ) CONST_FUNCTION; +float RageSquare( float x) CONST_FUNCTION; +float RageTriangle( float x) CONST_FUNCTION; + class RageQuadratic { public: