diff --git a/stepmania/NEWS b/stepmania/NEWS index 9f26e23b5d..2fdeefc3b2 100644 --- a/stepmania/NEWS +++ b/stepmania/NEWS @@ -1,4 +1,5 @@ ----------------------- Version 3.01 --------------------------- +CHANGE: Simplified NoteSkin format. Old NoteSkins will need to be updated. NEW FEATURE: AutoSync status now shown during gameplay with icon NEW FEATURE: added autogen icon to select music NEW FEATURE: toggle for easter eggs in Machine Options diff --git a/stepmania/src/BGAnimationLayer.cpp b/stepmania/src/BGAnimationLayer.cpp index 8c92733490..9d31b75630 100644 --- a/stepmania/src/BGAnimationLayer.cpp +++ b/stepmania/src/BGAnimationLayer.cpp @@ -496,10 +496,26 @@ void BGAnimationLayer::Update( float fDeltaTime ) { m_Sprites[i].SetX( m_Sprites[i].GetX() + fDeltaTime * PARTICLE_VELOCITY * m_vHeadings[i].x ); m_Sprites[i].SetY( m_Sprites[i].GetY() + fDeltaTime * PARTICLE_VELOCITY * m_vHeadings[i].y ); - if( HitGuardRailLeft(&m_Sprites[i]) ) m_vHeadings[i].x *= -1; - if( HitGuardRailRight(&m_Sprites[i]) ) m_vHeadings[i].x *= -1; - if( HitGuardRailTop(&m_Sprites[i]) ) m_vHeadings[i].y *= -1; - if( HitGuardRailBottom(&m_Sprites[i]) ) m_vHeadings[i].y *= -1; + if( HitGuardRailLeft(&m_Sprites[i]) ) + { + m_vHeadings[i].x *= -1; + m_Sprites[i].SetX( GetGuardRailLeft(&m_Sprites[i]) ); + } + if( HitGuardRailRight(&m_Sprites[i]) ) + { + m_vHeadings[i].x *= -1; + m_Sprites[i].SetX( GetGuardRailRight(&m_Sprites[i]) ); + } + if( HitGuardRailTop(&m_Sprites[i]) ) + { + m_vHeadings[i].y *= -1; + m_Sprites[i].SetY( GetGuardRailTop(&m_Sprites[i]) ); + } + if( HitGuardRailBottom(&m_Sprites[i]) ) + { + m_vHeadings[i].y *= -1; + m_Sprites[i].SetY( GetGuardRailBottom(&m_Sprites[i]) ); + } } break; case EFFECT_TILE_STILL: diff --git a/stepmania/src/Combo.cpp b/stepmania/src/Combo.cpp index e74a3dabab..c29e08f855 100644 --- a/stepmania/src/Combo.cpp +++ b/stepmania/src/Combo.cpp @@ -55,6 +55,22 @@ void Combo::UpdateScore( TapNoteScore score, int iNumNotesInThisRow ) return; } + // combo of marvelous/perfect + switch( score ) + { + case TNS_MARVELOUS: + case TNS_PERFECT: + m_iCurComboOfPerfects += iNumNotesInThisRow; + + if( (m_iCurComboOfPerfects>=150) && (m_iCurComboOfPerfects%150)==0 && !GAMESTATE->m_bDemonstration ) + SCREENMAN->SendMessageToTopScreen( SM_BeginToasty, 0 ); + break; + default: + m_iCurComboOfPerfects = 0; + break; + } + + // combo of marvelous/perfect/great switch( score ) { case TNS_MARVELOUS: @@ -65,18 +81,6 @@ void Combo::UpdateScore( TapNoteScore score, int iNumNotesInThisRow ) m_iCurCombo += iNumNotesInThisRow; // continue combo - switch( score ) - { - case TNS_MARVELOUS: - case TNS_PERFECT: - m_iCurComboOfPerfects += iNumNotesInThisRow; - break; - } - - if( (m_iCurComboOfPerfects>=150) && (m_iCurComboOfPerfects%150)==0 && !GAMESTATE->m_bDemonstration ) - SCREENMAN->SendMessageToTopScreen( SM_BeginToasty, 0 ); - - #define CROSSED( i ) (iOldComboSendMessageToTopScreen( SM_100Combo, 0 ); diff --git a/stepmania/src/Judgement.cpp b/stepmania/src/Judgement.cpp index cf63f8a403..096c5e961a 100644 --- a/stepmania/src/Judgement.cpp +++ b/stepmania/src/Judgement.cpp @@ -23,7 +23,7 @@ const float JUDGEMENT_DISPLAY_TIME = 0.8f; Judgement::Judgement() { m_fDisplayCountdown = 0; - m_sprJudgement.Load( THEME->GetPathTo("Graphics","gameplay judgement") ); + m_sprJudgement.Load( THEME->GetPathTo("Graphics","gameplay judgement 1x6") ); m_sprJudgement.StopAnimating(); m_sprJudgement.TurnShadowOn(); this->AddChild( &m_sprJudgement ); diff --git a/stepmania/src/NoteDisplay.cpp b/stepmania/src/NoteDisplay.cpp index 49be94bce2..3b31523ec3 100644 --- a/stepmania/src/NoteDisplay.cpp +++ b/stepmania/src/NoteDisplay.cpp @@ -25,17 +25,18 @@ #include "RageDisplay.h" -bool g_bDrawHoldHeadForTapsOnSameRow, g_bDrawTapOnTopOfHoldHead, g_bDrawTapOnTopOfHoldTail; // cache +// cache +bool g_bDrawHoldHeadForTapsOnSameRow, g_bDrawTapOnTopOfHoldHead, g_bDrawTapOnTopOfHoldTail; +float g_fTapAnimationLengthInBeats; +float g_bAllowVivid; NoteDisplay::NoteDisplay() { g_bDrawHoldHeadForTapsOnSameRow = GAMEMAN->GetMetricB( "NoteDisplay", "DrawHoldHeadForTapsOnSameRow" ); g_bDrawTapOnTopOfHoldHead = GAMEMAN->GetMetricB( "NoteDisplay", "DrawTapOnTopOfHoldHead" ); g_bDrawTapOnTopOfHoldTail = GAMEMAN->GetMetricB( "NoteDisplay", "DrawTapOnTopOfHoldTail" ); - - // the owner of the NoteDisplay must call load on the gray and color parts -// m_sprHoldParts.Load( THEME->GetPathTo(GRAPHIC_COLOR_ARROW_GRAY_PART) ); -// m_sprTapParts.Load( THEME->GetPathTo(GRAPHIC_COLOR_ARROW_COLOR_PART) ); + g_fTapAnimationLengthInBeats = GAMEMAN->GetMetricF( "NoteDisplay", "TapAnimationLengthInBeats" ); + g_bAllowVivid = GAMEMAN->GetMetricB( "NoteDisplay", "AllowVivid" ); } @@ -43,154 +44,65 @@ void NoteDisplay::Load( int iColNum, PlayerNumber pn ) { m_PlayerNumber = pn; - CString sTapPartsPath = GAMEMAN->GetPathTo(iColNum, "tap parts"); - m_sprTapParts.Load( sTapPartsPath ); - if( m_sprTapParts.GetNumStates() % 2 != 0 ) - RageException::Throw( "Tap Parts '%s' must have an even number of frames.", sTapPartsPath.GetString() ); - m_sprTapParts.StopAnimating(); - m_sprTapParts.TurnShadowOff(); + CString sTapPath = GAMEMAN->GetPathTo(iColNum, "tap"); + m_sprTap.Load( sTapPath ); + m_sprTap.StopAnimating(); + m_sprTap.TurnShadowOff(); - CString sHoldPartsPath = GAMEMAN->GetPathTo(iColNum, "hold parts"); + CString sHoldPartsPath = GAMEMAN->GetPathTo(iColNum, "hold parts 4x2"); m_sprHoldParts.Load( sHoldPartsPath ); if( m_sprHoldParts.GetTexture()->GetFramesWide() != 4 || m_sprHoldParts.GetTexture()->GetFramesHigh() != 2 ) RageException::Throw( "Hold Parts '%s' must have 4x2 frames.", sHoldPartsPath.GetString() ); m_sprHoldParts.StopAnimating(); m_sprHoldParts.TurnShadowOff(); - - m_colorTapTweens.clear(); - const CString sColorsFilePath = GAMEMAN->GetPathTo( iColNum, "Tap.colors" ); - FILE* fp = fopen( sColorsFilePath, "r" ); - if( fp == NULL ) - RageException::Throw( "Couldn't open .colors file '%s'", sColorsFilePath.GetString() ); - - bool bSuccess; - do - { - RageColor color; - int retval = fscanf( fp, "%f,%f,%f,%f\n", &color.r, &color.g, &color.b, &color.a ); - bSuccess = (retval == 4); - if( bSuccess ) - m_colorTapTweens.push_back( color ); - } while( bSuccess ); - - if( m_colorTapTweens.empty() ) - m_colorTapTweens.push_back( RageColor(1,1,1,1) ); - - fclose( fp ); return; } -int NoteDisplay::GetTapGrayFrameNo( const float fNoteBeat ) +int NoteDisplay::GetTapFrameNo( const float fNoteBeat ) { - const int iNumGrayPartFrames = m_sprTapParts.GetNumStates()/2; + const int iNumFrames = m_sprTap.GetNumStates(); + + float fSongBeat = GAMESTATE->m_fSongBeat; + float fPercentIntoMeasure = fmodf( fSongBeat, g_fTapAnimationLengthInBeats ) / g_fTapAnimationLengthInBeats; + fPercentIntoMeasure += 1/(iNumFrames*2.f); // fudge factor so that the "full white" frame shows when the arrow overlaps the receptors + int iSongBeatFrameContrib = fPercentIntoMeasure * iNumFrames; + + float fBeatFraction = fmodf( fNoteBeat, 1.0f ); + fBeatFraction = froundf( fBeatFraction, 0.25f ); + int iBeatFractionContrib = fBeatFraction * iNumFrames; + + g_bAllowVivid = GAMEMAN->GetMetricB( "NoteDisplay", "AllowVivid" ); + + int iFrameNo; + if( g_bAllowVivid && GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_ColorType == PlayerOptions::COLOR_VIVID ) + iFrameNo = (iSongBeatFrameContrib + iBeatFractionContrib) % iNumFrames; + else + iFrameNo = (iSongBeatFrameContrib) % iNumFrames; - const float fSongBeat = GAMESTATE->m_fSongBeat; - const float fPercentIntoBeat = fSongBeat - (int)fSongBeat; - int iFrameNo = int(fPercentIntoBeat * iNumGrayPartFrames) % iNumGrayPartFrames; if( iFrameNo < 0 ) - iFrameNo += iNumGrayPartFrames; + iFrameNo += iNumFrames; - return iFrameNo * 2; + return iFrameNo; } -int NoteDisplay::GetTapColorFrameNo( const float fNoteBeat ) -{ - return GetTapGrayFrameNo(fNoteBeat) + 1; -} - -void NoteDisplay::GetTapEdgeColors( const float fNoteBeat, RageColor &colorLeadingOut, RageColor &colorTrailingOut ) -{ -// Chris: If EZ2 doesn't use a color part, leave that part of the NoteSkin graphic empty -// -// Andy: -// if (GAMESTATE->m_CurGame == GAME_EZ2) +// if( ct == PlayerOptions::COLOR_NOTE ) // { -// return; // Get out of this, as it breaks EZ2, and besides, Ez2 doesn't use COLOR ARROWS +// RageColor color = GetNoteColorFromBeat( fNoteBeat ); +// colorLeadingOut = color; +// colorTrailingOut = color; +// +// // add a little bit of white so the note doesn't look so plain +// colorLeadingOut.r += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); +// colorLeadingOut.g += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); +// colorLeadingOut.b += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); +// colorTrailingOut.r += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); +// colorTrailingOut.g += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); +// colorTrailingOut.b += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); +// return; // } - //////////////////////////////////////////////////////////// - // ADDED 2-14-2002 - BrianB - // - // This section has been added for the different arrow - // display types: - // - // Note: Each note has a different color, but does not tween - // Flat: Each note has the same color, and does tween - // Plain: Each note has the same color, but does not tween - // - //////////////////////////////////////////////////////////// - - const PlayerOptions::ColorType ct = GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_ColorType; - const float fNotePercentIntoBeat = fNoteBeat - (int)fNoteBeat; - const float fSongBeat = GAMESTATE->m_fSongBeat; - float fPercentThroughColors = fmodf( fSongBeat, (float)BEATS_PER_MEASURE ) / BEATS_PER_MEASURE; - - switch( ct ) - { - case PlayerOptions::COLOR_VIVID: - case PlayerOptions::COLOR_NOTE: - fPercentThroughColors += fNotePercentIntoBeat; - break; - } - if( fPercentThroughColors < 0 ) - fPercentThroughColors += 1; - else - fPercentThroughColors -= (int)fPercentThroughColors; - - - - float fPercentThroughColorsLeading=0.f; // fill these in below - float fPercentThroughColorsTrailing=0.f; - switch( ct ) - { - case PlayerOptions::COLOR_VIVID: - case PlayerOptions::COLOR_NOTE: - case PlayerOptions::COLOR_FLAT: - // use different edge colors so that the arrows look more colorful - fPercentThroughColorsLeading = fPercentThroughColors; - fPercentThroughColorsTrailing = fmodf( fPercentThroughColors + 0.20f, 1 ); - break; - case PlayerOptions::COLOR_PLAIN: - // use same colors for both edges, making it look "plain" - fPercentThroughColorsLeading = fPercentThroughColors; - fPercentThroughColorsTrailing = fPercentThroughColors; - break; - default: - ASSERT(0); - } - - - if( ct == PlayerOptions::COLOR_NOTE ) - { - RageColor color = GetNoteColorFromBeat( fNoteBeat ); - colorLeadingOut = color; - colorTrailingOut = color; - - // add a little bit of white so the note doesn't look so plain - colorLeadingOut.r += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); - colorLeadingOut.g += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); - colorLeadingOut.b += 0.3f * fabsf( fPercentThroughColorsLeading - 0.5f ); - colorTrailingOut.r += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); - colorTrailingOut.g += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); - colorTrailingOut.b += 0.3f * fabsf( fPercentThroughColorsTrailing - 0.5f ); - return; - } - - float fLeadingColorIndex = fPercentThroughColorsLeading * m_colorTapTweens.size(); - float fTrailingColorIndex = fPercentThroughColorsTrailing* m_colorTapTweens.size(); - - float fLeadingColorWeightOf2 = fLeadingColorIndex - int(fLeadingColorIndex); - int iLeadingColor1 = int(fLeadingColorIndex); - int iLeadingColor2 = (iLeadingColor1 + 1) % m_colorTapTweens.size(); - colorLeadingOut = m_colorTapTweens[iLeadingColor1] * (1-fLeadingColorWeightOf2) + m_colorTapTweens[iLeadingColor2] * fLeadingColorWeightOf2; - - float fTrailingColorWeightOf2 = fTrailingColorIndex - int(fTrailingColorIndex); - int iTrailingColor1 = int(fTrailingColorIndex); - int iTrailingColor2 = (iTrailingColor1 + 1) % m_colorTapTweens.size(); - colorTrailingOut = m_colorTapTweens[iTrailingColor1] * (1-fTrailingColorWeightOf2) + m_colorTapTweens[iTrailingColor2] * fTrailingColorWeightOf2; -} void NoteDisplay::DrawHold( const HoldNote& hn, const bool bActive, const float fLife, const float fPercentFadeToFail, bool bDrawGlowOnly ) { @@ -221,7 +133,7 @@ void NoteDisplay::DrawHold( const HoldNote& hn, const bool bActive, const float const float fYBodyTop = g_bDrawTapOnTopOfHoldHead ? fYHeadBottom : fYHead; // middle of head const float fYBodyBottom = fYTailTop; // top of tail - const int fYStep = 8; // draw a segment every 8 pixels // this requires that the texture dimensions be a multiple of 8 + const int fYStep = fFrameHeight/4.f; // 4 segments per frame DISPLAY->SetTexture( m_sprHoldParts.GetTexture() ); DISPLAY->SetBlendModeNormal(); @@ -428,24 +340,9 @@ void NoteDisplay::DrawTap( const int iCol, const float fBeat, const bool bOnSame const float fXPos = ArrowGetXPos( m_PlayerNumber, iCol, fYPos ); const float fAlpha = ArrowGetAlpha( m_PlayerNumber, fYPos, fPercentFadeToFail ); const float fGlow = ArrowGetGlow( m_PlayerNumber, fYPos, fPercentFadeToFail ); - const int iGrayPartFrameNo = GetTapGrayFrameNo( fBeat ); - const int iColorPartFrameNo = GetTapColorFrameNo( fBeat ); + const int iTapFrameNo = GetTapFrameNo( fBeat ); const float fColorScale = SCALE(fLife,0,1,0.2f,1); - - RageColor colorGrayPart = RageColor(fColorScale,fColorScale,fColorScale,1); - RageColor colorLeadingEdge; - RageColor colorTrailingEdge; - GetTapEdgeColors( fBeat, colorLeadingEdge, colorTrailingEdge ); - colorGrayPart.a *= fAlpha; - colorLeadingEdge.a *= fAlpha; - colorTrailingEdge.a *= fAlpha; - - colorLeadingEdge.r *= fColorScale; - colorLeadingEdge.g *= fColorScale; - colorLeadingEdge.b *= fColorScale; - colorTrailingEdge.r *= fColorScale; - colorTrailingEdge.g *= fColorScale; - colorTrailingEdge.b *= fColorScale; + RageColor color = RageColor(fColorScale,fColorScale,fColorScale,fAlpha); if( bOnSameRowAsHoldStart && g_bDrawHoldHeadForTapsOnSameRow ) { @@ -453,7 +350,7 @@ void NoteDisplay::DrawTap( const int iCol, const float fBeat, const bool bOnSame // draw hold head // m_sprHoldParts.SetXY( fXPos, fYPos ); - m_sprHoldParts.SetDiffuse( colorGrayPart ); + m_sprHoldParts.SetDiffuse( color ); m_sprHoldParts.SetGlow( RageColor(1,1,1,fGlow) ); m_sprHoldParts.StopUsingCustomCoords(); m_sprHoldParts.SetState( 0 ); @@ -461,23 +358,11 @@ void NoteDisplay::DrawTap( const int iCol, const float fBeat, const bool bOnSame } else { - m_sprTapParts.SetXY( fXPos, fYPos ); - m_sprTapParts.SetRotation( fRotation ); - m_sprTapParts.SetGlow( RageColor(1,1,1,fGlow) ); - - // - // draw gray part - // - m_sprTapParts.SetState( iGrayPartFrameNo ); - m_sprTapParts.SetDiffuse( colorGrayPart ); - m_sprTapParts.Draw(); - - // - // draw color part - // - m_sprTapParts.SetState( iColorPartFrameNo ); - m_sprTapParts.SetDiffuseTopEdge( colorLeadingEdge ); - m_sprTapParts.SetDiffuseBottomEdge( colorTrailingEdge ); - m_sprTapParts.Draw(); + m_sprTap.SetXY( fXPos, fYPos ); + m_sprTap.SetRotation( fRotation ); + m_sprTap.SetGlow( RageColor(1,1,1,fGlow) ); + m_sprTap.SetDiffuse( color ); + m_sprTap.SetState( iTapFrameNo ); + m_sprTap.Draw(); } } \ No newline at end of file diff --git a/stepmania/src/NoteDisplay.h b/stepmania/src/NoteDisplay.h index ad4bb27055..5f32f3547f 100644 --- a/stepmania/src/NoteDisplay.h +++ b/stepmania/src/NoteDisplay.h @@ -28,16 +28,12 @@ public: void DrawHold( const HoldNote& hn, const bool bActive, const float fLife, const float fPercentFadeToFail, bool bDrawGlowOnly = false ); protected: - int GetTapGrayFrameNo( const float fNoteBeat ); - int GetTapColorFrameNo( const float fNoteBeat ); - void GetTapEdgeColors( const float fNoteBeat, RageColor &colorLeadingOut, RageColor &colorTrailingOut ); + int GetTapFrameNo( const float fNoteBeat ); PlayerNumber m_PlayerNumber; // to look up PlayerOptions - Sprite m_sprTapParts; // for now, must be an even number of frames - Sprite m_sprHoldParts; // for now, must be 8 frames - - vector m_colorTapTweens; + Sprite m_sprTap; + Sprite m_sprHoldParts; }; #endif diff --git a/stepmania/src/PlayerOptions.cpp b/stepmania/src/PlayerOptions.cpp index 9329979829..f1426dbded 100644 --- a/stepmania/src/PlayerOptions.cpp +++ b/stepmania/src/PlayerOptions.cpp @@ -111,7 +111,6 @@ CString PlayerOptions::GetString() case COLOR_VIVID: break; case COLOR_NOTE: sReturn += "Note, "; break; case COLOR_FLAT: sReturn += "Flat, "; break; - case COLOR_PLAIN: sReturn += "Plain, "; break; default: ASSERT(0); // invalid COLOR }; @@ -168,7 +167,6 @@ void PlayerOptions::FromString( CString sOptions ) else if( sBit == "reverse" ) m_bReverseScroll = true; else if( sBit == "note" ) m_ColorType = COLOR_NOTE; else if( sBit == "flat" ) m_ColorType = COLOR_FLAT; - else if( sBit == "plain" ) m_ColorType = COLOR_PLAIN; else if( sBit == "noholds" ) m_bHoldNotes = false; else if( sBit == "nofreeze" ) m_bHoldNotes = false; else if( sBit == "dark" ) m_bDark = true; diff --git a/stepmania/src/PlayerOptions.h b/stepmania/src/PlayerOptions.h index 46a072049b..a12bab8e77 100644 --- a/stepmania/src/PlayerOptions.h +++ b/stepmania/src/PlayerOptions.h @@ -33,7 +33,7 @@ struct PlayerOptions TurnType m_TurnType; bool m_bLittle; bool m_bReverseScroll; - enum ColorType { COLOR_VIVID=0, COLOR_NOTE, COLOR_FLAT, COLOR_PLAIN, NUM_COLOR_TYPES }; + enum ColorType { COLOR_VIVID=0, COLOR_NOTE, COLOR_FLAT, NUM_COLOR_TYPES }; ColorType m_ColorType; bool m_bHoldNotes; bool m_bDark; diff --git a/stepmania/src/ScreenPlayerOptions.cpp b/stepmania/src/ScreenPlayerOptions.cpp index 30df04e7ab..30985683c5 100644 --- a/stepmania/src/ScreenPlayerOptions.cpp +++ b/stepmania/src/ScreenPlayerOptions.cpp @@ -41,7 +41,7 @@ OptionRowData g_PlayerOptionsLines[NUM_PLAYER_OPTIONS_LINES] = { { "Turn", 6, {"OFF","MIRROR","LEFT","RIGHT","SHUFFLE","SUPER SHUFFLE"} }, { "Little", 2, {"OFF","ON"} }, { "Scroll", 2, {"STANDARD","REVERSE"} }, - { "Color", 4, {"VIVID","NOTE","FLAT","PLAIN"} }, + { "Color", 3, {"VIVID","NOTE","FLAT"} }, { "Holds", 2, {"OFF","ON"} }, { "Dark", 2, {"OFF","ON"} }, };