diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index 2e64038f0b..b50b979df1 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -424,12 +424,34 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float return fPixelOffsetFromCenter; } -float ArrowEffects::GetRotation( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead ) +float ArrowEffects::GetRotationX( const PlayerState *pPlayerState, float fYOffset ) +{ + const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; + float fRotation = 0; + if( fEffects[PlayerOptions::EFFECT_ROLL] != 0 ) + { + fRotation = fEffects[PlayerOptions::EFFECT_ROLL] * fYOffset/2; + } + return fRotation; +} + +float ArrowEffects::GetRotationY( const PlayerState *pPlayerState, float fYOffset ) +{ + const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; + float fRotation = 0; + if( fEffects[PlayerOptions::EFFECT_TWIRL] != 0 ) + { + fRotation = fEffects[PlayerOptions::EFFECT_TWIRL] * fYOffset/2; + } + return fRotation; +} + +float ArrowEffects::GetRotationZ( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead ) { const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; float fRotation = 0; if( fEffects[PlayerOptions::EFFECT_CONFUSION] != 0 ) - fRotation += ReceptorGetRotation( pPlayerState ); + fRotation += ReceptorGetRotationZ( pPlayerState ); // Doesn't affect hold heads, unlike confusion if( fEffects[PlayerOptions::EFFECT_DIZZY] != 0 && !bIsHoldHead ) @@ -444,7 +466,7 @@ float ArrowEffects::GetRotation( const PlayerState* pPlayerState, float fNoteBea return fRotation; } -float ArrowEffects::ReceptorGetRotation( const PlayerState* pPlayerState ) +float ArrowEffects::ReceptorGetRotationZ( const PlayerState* pPlayerState ) { const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; float fRotation = 0; @@ -626,7 +648,10 @@ float ArrowEffects::GetZPos( const PlayerState* pPlayerState, int iCol, float fY bool ArrowEffects::NeedZBuffer( const PlayerState* pPlayerState ) { const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; - if( fEffects[PlayerOptions::EFFECT_BUMPY] != 0 ) + // We also need to use the Z buffer if twirl is in play, because of + // hold modulation. -vyhd (OpenITG r623) + if( fEffects[PlayerOptions::EFFECT_BUMPY] != 0 || + fEffects[PlayerOptions::EFFECT_TWIRL] != 0 ) return true; return false; diff --git a/src/ArrowEffects.h b/src/ArrowEffects.h index 5de2872827..d27eebd831 100644 --- a/src/ArrowEffects.h +++ b/src/ArrowEffects.h @@ -31,9 +31,13 @@ public: // fRotation is Z rotation of an arrow. This will depend on the column of // the arrow and possibly the Arrow effect and the fYOffset (in the case of // EFFECT_DIZZY). - static float GetRotation( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead ); - static float ReceptorGetRotation( const PlayerState* pPlayerState ); + static float GetRotationZ( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead ); + static float ReceptorGetRotationZ( const PlayerState* pPlayerState ); + // Due to the handling logic for holds on Twirl, we need to use an offset instead. + // It's more intuitive for Roll to be based off offset, so use an offset there too. + static float GetRotationX( const PlayerState* pPlayerState, float fYOffset ); + static float GetRotationY( const PlayerState *pPlayerState, float fYOffset ); // 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/GhostArrowRow.cpp b/src/GhostArrowRow.cpp index 6dee088190..7e80021393 100644 --- a/src/GhostArrowRow.cpp +++ b/src/GhostArrowRow.cpp @@ -51,7 +51,7 @@ void GhostArrowRow::Update( float fDeltaTime ) m_Ghost[c]->SetY( fY ); m_Ghost[c]->SetZ( fZ ); - const float fRotation = ArrowEffects::ReceptorGetRotation( m_pPlayerState ); + const float fRotation = ArrowEffects::ReceptorGetRotationZ( m_pPlayerState ); m_Ghost[c]->SetRotationZ( fRotation ); const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); diff --git a/src/NoteDisplay.cpp b/src/NoteDisplay.cpp index d1e32e8a10..c8cfa778f1 100644 --- a/src/NoteDisplay.cpp +++ b/src/NoteDisplay.cpp @@ -12,6 +12,7 @@ #include "NoteTypes.h" #include "LuaBinding.h" #include "Foreach.h" +#include "RageMath.h" const RString& NoteNotePartToString( NotePart i ); #define FOREACH_NotePart( i ) FOREACH_ENUM( NotePart, i ) @@ -444,9 +445,21 @@ void NoteDisplay::DrawHoldPart( vector &vpSpr, int iCol, int fYStep, fl float fX = ArrowEffects::GetXPos( m_pPlayerState, iCol, fYOffset ); - const float fXLeft = fX - fScaledFrameWidth/2; + // XXX: Actor rotations use degrees, RageFastCos/Sin use radians. Convert here. + const float fRotationY = ArrowEffects::GetRotationY( m_pPlayerState, fYOffset ) * PI/180; + + // if we're rotating, we need to modify the X and Z coords for the outer edges. + const float fRotOffsetX = fFrameWidth/2 * RageFastCos(fRotationY); + const float fRotOffsetZ = fFrameWidth/2 * RageFastSin(fRotationY); + + //const float fXLeft = fX - (fScaledFrameWidth/2); + const float fXLeft = fX - fRotOffsetX; const float fXCenter = fX; - const float fXRight = fX + fScaledFrameWidth/2; + //const float fXRight = fX + (fScaledFrameWidth/2); + const float fXRight = fX + fRotOffsetX; + const float fZLeft = fZ - fRotOffsetZ; + const float fZRight = fZ + fRotOffsetZ; + const float fDistFromTop = fY - fYTop; float fTexCoordTop = SCALE( fDistFromTop, 0, fFrameHeight, rect.top, rect.bottom ); fTexCoordTop += fAddToTexCoord; @@ -457,9 +470,9 @@ void NoteDisplay::DrawHoldPart( vector &vpSpr, int iCol, int fYStep, fl if( fAlpha > 0 ) bAllAreTransparent = false; - queue.v[0].p = RageVector3(fXLeft, fY, fZ); queue.v[0].c = color; queue.v[0].t = RageVector2(fTexCoordLeft, fTexCoordTop); + queue.v[0].p = RageVector3(fXLeft, fY, fZLeft); queue.v[0].c = color; queue.v[0].t = RageVector2(fTexCoordLeft, fTexCoordTop); queue.v[1].p = RageVector3(fXCenter, fY, fZ); queue.v[1].c = color; queue.v[1].t = RageVector2(fTexCoordCenter, fTexCoordTop); - queue.v[2].p = RageVector3(fXRight, fY, fZ); queue.v[2].c = color; queue.v[2].t = RageVector2(fTexCoordRight, fTexCoordTop); + queue.v[2].p = RageVector3(fXRight, fY, fZRight); queue.v[2].c = color; queue.v[2].t = RageVector2(fTexCoordRight, fTexCoordTop); queue.v+=3; if( queue.Free() < 3 || bLast ) @@ -666,12 +679,18 @@ void NoteDisplay::DrawActor( const TapNote& tn, Actor* pActor, NotePart part, in const float fGlow = ArrowEffects::GetGlow( m_pPlayerState, iCol, fYOffset, fPercentFadeToFail, m_fYReverseOffsetPixels, fDrawDistanceBeforeTargetsPixels, fFadeInPercentOfDrawFar ); const RageColor diffuse = RageColor(fColorScale,fColorScale,fColorScale,fAlpha); const RageColor glow = RageColor(1,1,1,fGlow); + float fRotationX = 0; + float fRotationY = 0; float fRotationZ = 0; - fRotationZ = ArrowEffects::GetRotation( m_pPlayerState, fBeat, tn.type == tn.hold_head ); + fRotationX = ArrowEffects::GetRotationX( m_pPlayerState, fYOffset ); + fRotationY = ArrowEffects::GetRotationY( m_pPlayerState, fYOffset ); + fRotationZ = ArrowEffects::GetRotationZ( m_pPlayerState, fBeat, tn.type == tn.hold_head ); if( tn.type != tn.hold_head ) fColorScale *= ArrowEffects::GetBrightness( m_pPlayerState, fBeat ); + pActor->SetRotationX( fRotationX ); + pActor->SetRotationY( fRotationY ); pActor->SetRotationZ( fRotationZ ); pActor->SetXY( fX, fY ); pActor->SetZ( fZ ); diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index c5bef2cd70..2b4053b6b6 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -105,7 +105,7 @@ RString PlayerOptions::GetString( bool bForceNoteSkin ) const void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const { - RString sReturn; + //RString sReturn; if( !m_fTimeSpacing ) { @@ -134,35 +134,37 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fAccels[ACCEL_BOOST], "Boost" ); AddPart( AddTo, m_fAccels[ACCEL_BRAKE], "Brake" ); - AddPart( AddTo, m_fAccels[ACCEL_WAVE], "Wave" ); - AddPart( AddTo, m_fAccels[ACCEL_EXPAND], "Expand" ); + AddPart( AddTo, m_fAccels[ACCEL_WAVE], "Wave" ); + AddPart( AddTo, m_fAccels[ACCEL_EXPAND], "Expand" ); AddPart( AddTo, m_fAccels[ACCEL_BOOMERANG], "Boomerang" ); - AddPart( AddTo, m_fEffects[EFFECT_DRUNK], "Drunk" ); - AddPart( AddTo, m_fEffects[EFFECT_DIZZY], "Dizzy" ); + AddPart( AddTo, m_fEffects[EFFECT_DRUNK], "Drunk" ); + AddPart( AddTo, m_fEffects[EFFECT_DIZZY], "Dizzy" ); AddPart( AddTo, m_fEffects[EFFECT_CONFUSION], "Confusion" ); - AddPart( AddTo, m_fEffects[EFFECT_MINI], "Mini" ); - AddPart( AddTo, m_fEffects[EFFECT_TINY], "Tiny" ); - AddPart( AddTo, m_fEffects[EFFECT_FLIP], "Flip" ); - AddPart( AddTo, m_fEffects[EFFECT_INVERT], "Invert" ); + AddPart( AddTo, m_fEffects[EFFECT_MINI], "Mini" ); + AddPart( AddTo, m_fEffects[EFFECT_TINY], "Tiny" ); + AddPart( AddTo, m_fEffects[EFFECT_FLIP], "Flip" ); + AddPart( AddTo, m_fEffects[EFFECT_INVERT], "Invert" ); AddPart( AddTo, m_fEffects[EFFECT_TORNADO], "Tornado" ); - AddPart( AddTo, m_fEffects[EFFECT_TIPSY], "Tipsy" ); - AddPart( AddTo, m_fEffects[EFFECT_BUMPY], "Bumpy" ); - AddPart( AddTo, m_fEffects[EFFECT_BEAT], "Beat" ); - AddPart( AddTo, m_fEffects[EFFECT_XMODE], "XMode" ); + AddPart( AddTo, m_fEffects[EFFECT_TIPSY], "Tipsy" ); + AddPart( AddTo, m_fEffects[EFFECT_BUMPY], "Bumpy" ); + AddPart( AddTo, m_fEffects[EFFECT_BEAT], "Beat" ); + AddPart( AddTo, m_fEffects[EFFECT_XMODE], "XMode" ); + AddPart( AddTo, m_fEffects[EFFECT_TWIRL], "Twirl" ); + AddPart( AddTo, m_fEffects[EFFECT_ROLL], "Roll" ); - AddPart( AddTo, m_fAppearances[APPEARANCE_HIDDEN], "Hidden" ); + AddPart( AddTo, m_fAppearances[APPEARANCE_HIDDEN], "Hidden" ); AddPart( AddTo, m_fAppearances[APPEARANCE_HIDDEN_OFFSET], "HiddenOffset" ); - AddPart( AddTo, m_fAppearances[APPEARANCE_SUDDEN], "Sudden" ); + AddPart( AddTo, m_fAppearances[APPEARANCE_SUDDEN], "Sudden" ); AddPart( AddTo, m_fAppearances[APPEARANCE_SUDDEN_OFFSET], "SuddenOffset" ); AddPart( AddTo, m_fAppearances[APPEARANCE_STEALTH], "Stealth" ); - AddPart( AddTo, m_fAppearances[APPEARANCE_BLINK], "Blink" ); + AddPart( AddTo, m_fAppearances[APPEARANCE_BLINK], "Blink" ); AddPart( AddTo, m_fAppearances[APPEARANCE_RANDOMVANISH], "RandomVanish" ); AddPart( AddTo, m_fScrolls[SCROLL_REVERSE], "Reverse" ); - AddPart( AddTo, m_fScrolls[SCROLL_SPLIT], "Split" ); + AddPart( AddTo, m_fScrolls[SCROLL_SPLIT], "Split" ); AddPart( AddTo, m_fScrolls[SCROLL_ALTERNATE], "Alternate" ); - AddPart( AddTo, m_fScrolls[SCROLL_CROSS], "Cross" ); + AddPart( AddTo, m_fScrolls[SCROLL_CROSS], "Cross" ); AddPart( AddTo, m_fScrolls[SCROLL_CENTERED], "Centered" ); AddPart( AddTo, m_fDark, "Dark" ); @@ -179,10 +181,10 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fRandomSpeed, "RandomSpeed" ); if( m_bTurns[TURN_MIRROR] ) AddTo.push_back( "Mirror" ); - if( m_bTurns[TURN_LEFT] ) AddTo.push_back( "Left" ); - if( m_bTurns[TURN_RIGHT] ) AddTo.push_back( "Right" ); + if( m_bTurns[TURN_LEFT] ) AddTo.push_back( "Left" ); + if( m_bTurns[TURN_RIGHT] ) AddTo.push_back( "Right" ); if( m_bTurns[TURN_SHUFFLE] ) AddTo.push_back( "Shuffle" ); - if( m_bTurns[TURN_SOFT_SHUFFLE] ) AddTo.push_back( "SoftShuffle" ); + if( m_bTurns[TURN_SOFT_SHUFFLE] ) AddTo.push_back( "SoftShuffle" ); if( m_bTurns[TURN_SUPER_SHUFFLE] ) AddTo.push_back( "SuperShuffle" ); if( m_bTransforms[TRANSFORM_NOHOLDS] ) AddTo.push_back( "NoHolds" ); @@ -190,7 +192,7 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const if( m_bTransforms[TRANSFORM_NOMINES] ) AddTo.push_back( "NoMines" ); if( m_bTransforms[TRANSFORM_LITTLE] ) AddTo.push_back( "Little" ); if( m_bTransforms[TRANSFORM_WIDE] ) AddTo.push_back( "Wide" ); - if( m_bTransforms[TRANSFORM_BIG] ) AddTo.push_back( "Big" ); + if( m_bTransforms[TRANSFORM_BIG] ) AddTo.push_back( "Big" ); if( m_bTransforms[TRANSFORM_QUICK] ) AddTo.push_back( "Quick" ); if( m_bTransforms[TRANSFORM_BMRIZE] ) AddTo.push_back( "BMRize" ); if( m_bTransforms[TRANSFORM_SKIPPY] ) AddTo.push_back( "Skippy" ); @@ -355,6 +357,8 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut else if( sBit == "bumpy" ) SET_FLOAT( fEffects[EFFECT_BUMPY] ) else if( sBit == "beat" ) SET_FLOAT( fEffects[EFFECT_BEAT] ) else if( sBit == "xmode" ) SET_FLOAT( fEffects[EFFECT_XMODE] ) + else if( sBit == "twirl" ) SET_FLOAT( fEffects[EFFECT_TWIRL] ) + else if( sBit == "roll" ) SET_FLOAT( fEffects[EFFECT_ROLL] ) else if( sBit == "hidden" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN] ) else if( sBit == "hiddenoffset" ) SET_FLOAT( fAppearances[APPEARANCE_HIDDEN_OFFSET] ) else if( sBit == "sudden" ) SET_FLOAT( fAppearances[APPEARANCE_SUDDEN] ) diff --git a/src/PlayerOptions.h b/src/PlayerOptions.h index 17cc756bc9..8557ba43cf 100644 --- a/src/PlayerOptions.h +++ b/src/PlayerOptions.h @@ -59,6 +59,8 @@ public: EFFECT_BUMPY, EFFECT_BEAT, EFFECT_XMODE, + EFFECT_TWIRL, + EFFECT_ROLL, NUM_EFFECTS }; enum Appearance { diff --git a/src/ReceptorArrowRow.cpp b/src/ReceptorArrowRow.cpp index d6a024fc62..0fe67aba0c 100644 --- a/src/ReceptorArrowRow.cpp +++ b/src/ReceptorArrowRow.cpp @@ -56,7 +56,7 @@ void ReceptorArrowRow::Update( float fDeltaTime ) m_ReceptorArrow[c]->SetY( fY ); m_ReceptorArrow[c]->SetZ( fZ ); - const float fRotation = ArrowEffects::ReceptorGetRotation( m_pPlayerState ); + const float fRotation = ArrowEffects::ReceptorGetRotationZ( m_pPlayerState ); m_ReceptorArrow[c]->SetRotationZ( fRotation ); const float fZoom = ArrowEffects::GetZoom( m_pPlayerState );