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: