diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index e833ab7e51..b5759dae61 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1161,6 +1161,9 @@ + + + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 04a394ac5a..39bbac6690 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -3517,6 +3517,15 @@ save yourself some time, copy this for undocumented things: If the optional second argument is passed, sets the speed at which the transition occurs.
MMods are not tweenable or settable on ScreenGameplay. Use XMods if you need such an effect.
+ + Use 1-16 in place of 'n' to move a specific column. + + + Use 1-16 in place of 'n' to move a specific column. + + + Use 1-16 in place of 'n' to move a specific column. + diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index e5170e0576..c5313daa1d 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -675,6 +675,33 @@ float ArrowEffects::ReceptorGetRotationY( const PlayerState* pPlayerState ) return fRotation; } +float ArrowEffects::GetMoveX(int iCol) +{ + const float* fMoves = curr_options->m_fMovesX; + float f = 0; + if( fMoves[iCol] != 0 ) + f += ARROW_SIZE * fMoves[iCol]; + return f; +} + +float ArrowEffects::GetMoveY(int iCol) +{ + const float* fMoves = curr_options->m_fMovesY; + float f = 0; + if( fMoves[iCol] != 0 ) + f += ARROW_SIZE * fMoves[iCol]; + return f; +} + +float ArrowEffects::GetMoveZ(int iCol) +{ + const float* fMoves = curr_options->m_fMovesZ; + float f = 0; + if( fMoves[iCol] != 0 ) + f += ARROW_SIZE * fMoves[iCol]; + return f; +} + #define CENTER_LINE_Y 160 // from fYOffset == 0 #define FADE_DIST_Y 40 diff --git a/src/ArrowEffects.h b/src/ArrowEffects.h index 9568f19846..bb95e54cc1 100644 --- a/src/ArrowEffects.h +++ b/src/ArrowEffects.h @@ -29,9 +29,9 @@ public: static void GetXYZPos(const PlayerState* player_state, int col, float y_offset, float y_reverse_offset, RageVector3& ret, bool with_reverse= true) { - ret.x= GetXPos(player_state, col, y_offset); - ret.y= GetYPos(col, y_offset, y_reverse_offset, with_reverse); - ret.z= GetZPos(col, y_offset); + 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); } /** @@ -62,6 +62,10 @@ public: static float ReceptorGetRotationX( const PlayerState* pPlayerState); static float ReceptorGetRotationY( const PlayerState* pPlayerState); + + static float GetMoveX(int iCol); + static float GetMoveY(int iCol); + static float GetMoveZ(int iCol); // fXPos is a horizontal position in pixels relative to the center of the field. // This depends on the column of the arrow and possibly the Arrow effect and diff --git a/src/NoteDisplay.cpp b/src/NoteDisplay.cpp index 7f97a7484d..6623895073 100644 --- a/src/NoteDisplay.cpp +++ b/src/NoteDisplay.cpp @@ -884,10 +884,10 @@ void NoteDisplay::DrawHoldPart(vector &vpSpr, switch(column_args.pos_handler->m_spline_mode) { case NCSM_Disabled: - ae_pos.y= fY; + ae_pos.y= fY + ArrowEffects::GetMoveY(column_args.column); break; case NCSM_Offset: - ae_pos.y= fY; + ae_pos.y= fY + ArrowEffects::GetMoveY(column_args.column); column_args.pos_handler->EvalDerivForBeat(column_args.song_beat, cur_beat, sp_pos_forward); RageVec3Normalize(&sp_pos_forward, &sp_pos_forward); break; diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index 35bc19e8f6..859ac76c58 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -76,6 +76,10 @@ void PlayerOptions::Init() ZERO( m_bTransforms ); m_bMuteOnError = false; m_sNoteSkin = ""; + ZERO( m_fMovesX ); ONE( m_SpeedfMovesX ); + ZERO( m_fMovesY ); ONE( m_SpeedfMovesY ); + ZERO( m_fMovesZ ); ONE( m_SpeedfMovesZ ); + } void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds ) @@ -110,6 +114,12 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds ) APPROACH( fSkew ); APPROACH( fPassmark ); APPROACH( fRandomSpeed ); + for( int i=0; i<16; i++) + APPROACH( fMovesX[i] ); + for( int i=0; i<16; i++) + APPROACH( fMovesY[i] ); + for( int i=0; i<16; i++) + APPROACH( fMovesZ[i] ); DO_COPY( m_bSetScrollSpeed ); for( int i=0; i &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fEffects[EFFECT_XMODE], "XMode" ); AddPart( AddTo, m_fEffects[EFFECT_TWIRL], "Twirl" ); AddPart( AddTo, m_fEffects[EFFECT_ROLL], "Roll" ); + + for( int i=0; i<16; i++) + { + RString s = ssprintf( "MoveX%d", i+1 ); + + AddPart( AddTo, m_fMovesX[i], s ); + s = ssprintf( "MoveY%d", i+1 ); + AddPart( AddTo, m_fMovesY[i], s ); + s = ssprintf( "MoveZ%d", i+1 ); + AddPart( AddTo, m_fMovesZ[i], s ); + } AddPart( AddTo, m_fAppearances[APPEARANCE_HIDDEN], "Hidden" ); AddPart( AddTo, m_fAppearances[APPEARANCE_HIDDEN_OFFSET], "HiddenOffset" ); @@ -565,6 +586,20 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut } else if( sBit == "muteonerror" ) m_bMuteOnError = on; else if( sBit == "random" ) ChooseRandomModifiers(); + + else if( sBit.find("move") != sBit.npos) + { + for (int i=0; i<16; i++) + { + RString s = ssprintf( "movex%d", i+1 ); + if( sBit == s) SET_FLOAT( fMovesX[i] ) + s = ssprintf( "movey%d", i+1 ); + if( sBit == s) SET_FLOAT( fMovesY[i] ) + s = ssprintf( "movez%d", i+1 ); + if( sBit == s) SET_FLOAT( fMovesZ[i] ) + } + } + // deprecated mods/left in for compatibility else if( sBit == "converge" ) SET_FLOAT( fScrolls[SCROLL_CENTERED] ) // end of the list @@ -811,6 +846,12 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const COMPARE(m_bTurns[i]); for( int i = 0; i < PlayerOptions::NUM_TRANSFORMS; ++i ) COMPARE(m_bTransforms[i]); + for( int i = 0; i < 16; ++i ) + COMPARE(m_fMovesX[i]); + for( int i = 0; i < 16; ++i ) + COMPARE(m_fMovesY[i]); + for( int i = 0; i < 16; ++i ) + COMPARE(m_fMovesZ[i]); #undef COMPARE return true; } @@ -869,6 +910,18 @@ PlayerOptions& PlayerOptions::operator=(PlayerOptions const& other) { CPY(m_bTransforms[i]); } + for( int i = 0; i < 16; ++i ) + { + CPY(m_fMovesX[i]); + } + for( int i = 0; i < 16; ++i ) + { + CPY(m_fMovesY[i]); + } + for( int i = 0; i < 16; ++i ) + { + CPY(m_fMovesZ[i]); + } #undef CPY #undef CPY_SPEED return *this; @@ -1144,6 +1197,11 @@ public: FLOAT_INTERFACE(Tilt, PerspectiveTilt, true); FLOAT_INTERFACE(Passmark, Passmark, true); // Passmark is not sanity checked to the [0, 1] range because LifeMeterBar::IsFailing is the only thing that uses it, and it's used in a <= test. Any theme passing a value outside the [0, 1] range probably expects the result they get. -Kyz FLOAT_INTERFACE(RandomSpeed, RandomSpeed, true); + + MULTICOL_FLOAT_INTERFACE(MoveX, MovesX, true); + MULTICOL_FLOAT_INTERFACE(MoveY, MovesY, true); + MULTICOL_FLOAT_INTERFACE(MoveZ, MovesZ, true); + BOOL_INTERFACE(TurnNone, Turns[PlayerOptions::TURN_NONE]); BOOL_INTERFACE(Mirror, Turns[PlayerOptions::TURN_MIRROR]); BOOL_INTERFACE(Backwards, Turns[PlayerOptions::TURN_BACKWARDS]); @@ -1567,6 +1625,11 @@ public: ADD_METHOD(NoQuads); ADD_METHOD(NoStretch); ADD_METHOD(MuteOnError); + + ADD_MULTICOL_METHOD(MoveX); + ADD_MULTICOL_METHOD(MoveY); + ADD_MULTICOL_METHOD(MoveZ); + ADD_METHOD(NoteSkin); ADD_METHOD(FailSetting); diff --git a/src/PlayerOptions.h b/src/PlayerOptions.h index cd5ff88615..63074919d1 100644 --- a/src/PlayerOptions.h +++ b/src/PlayerOptions.h @@ -71,6 +71,9 @@ public: ZERO( m_fAppearances ); ONE( m_SpeedfAppearances ); ZERO( m_fScrolls ); ONE( m_SpeedfScrolls ); ZERO( m_bTurns ); ZERO( m_bTransforms ); + ZERO( m_fMovesX ); ONE( m_SpeedfMovesX ); + ZERO( m_fMovesY ); ONE( m_SpeedfMovesY ); + ZERO( m_fMovesZ ); ONE( m_SpeedfMovesZ ); }; void Init(); void Approach( const PlayerOptions& other, float fDeltaSeconds ); @@ -219,6 +222,10 @@ public: float m_fPassmark, m_SpeedfPassmark; float m_fRandomSpeed, m_SpeedfRandomSpeed; + /* The maximum column number is 16.*/ + float m_fMovesX[16], m_SpeedfMovesX[16]; + float m_fMovesY[16], m_SpeedfMovesY[16]; + float m_fMovesZ[16], m_SpeedfMovesZ[16]; bool m_bTurns[NUM_TURNS]; bool m_bTransforms[NUM_TRANSFORMS]; @@ -257,6 +264,41 @@ public: bool IsEasierForCourseAndTrail( Course* pCourse, Trail* pTrail ) const; }; +#define ADD_MULTICOL_METHOD( method_name) \ + ADD_METHOD( method_name##1 ); \ + ADD_METHOD( method_name##2 ); \ + ADD_METHOD( method_name##3 ); \ + ADD_METHOD( method_name##4 ); \ + ADD_METHOD( method_name##5 ); \ + ADD_METHOD( method_name##6 ); \ + ADD_METHOD( method_name##7 ); \ + ADD_METHOD( method_name##8 ); \ + ADD_METHOD( method_name##9 ); \ + ADD_METHOD( method_name##10 ); \ + ADD_METHOD( method_name##11 ); \ + ADD_METHOD( method_name##12 ); \ + ADD_METHOD( method_name##13 ); \ + ADD_METHOD( method_name##14 ); \ + ADD_METHOD( method_name##15 ); \ + ADD_METHOD( method_name##16 ); +#define MULTICOL_FLOAT_INTERFACE(func_name, member, valid) \ + FLOAT_INTERFACE(func_name##1, member[0], valid); \ + FLOAT_INTERFACE(func_name##2, member[1], valid); \ + FLOAT_INTERFACE(func_name##3, member[2], valid); \ + FLOAT_INTERFACE(func_name##4, member[3], valid); \ + FLOAT_INTERFACE(func_name##5, member[4], valid); \ + FLOAT_INTERFACE(func_name##6, member[5], valid); \ + FLOAT_INTERFACE(func_name##7, member[6], valid); \ + FLOAT_INTERFACE(func_name##8, member[7], valid); \ + FLOAT_INTERFACE(func_name##9, member[8], valid); \ + FLOAT_INTERFACE(func_name##10, member[9], valid); \ + FLOAT_INTERFACE(func_name##11, member[10], valid); \ + FLOAT_INTERFACE(func_name##12, member[11], valid); \ + FLOAT_INTERFACE(func_name##13, member[12], valid); \ + FLOAT_INTERFACE(func_name##14, member[13], valid); \ + FLOAT_INTERFACE(func_name##15, member[14], valid); \ + FLOAT_INTERFACE(func_name##16, member[15], valid); + #endif /*