diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 66cdf2a34b..314da4376c 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -32,6 +32,33 @@ static ThemeMetric FADE_FAIL_TIME( "NoteField", "FadeFailTime" ); static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); } static ThemeMetric1D ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS ); + +inline const TimingData *GetRealTiming(const PlayerState *pPlayerState) +{ + if( GAMESTATE->m_pCurSteps[pPlayerState->m_PlayerNumber] != NULL ) + return &GAMESTATE->m_pCurSteps[pPlayerState->m_PlayerNumber]->m_Timing; + return NULL; +} + +inline const TimingData *GetDisplayedTiming(const PlayerState *pPlayerState) +{ + if( !GAMESTATE->m_bIsEditorStepTiming ) + return &GAMESTATE->m_pCurSong->m_SongTiming; + return GetRealTiming(pPlayerState); +} + +inline const SongPosition *GetRealPosition(const PlayerState *pPlayerState) +{ + return &pPlayerState->m_Position; +} + +inline const SongPosition *GetDisplayedPosition(const PlayerState *pPlayerState) +{ + if( !GAMESTATE->m_bIsEditorStepTiming ) + return &GAMESTATE->m_Position; + return GetRealPosition(pPlayerState); +} + NoteField::NoteField() { m_pNoteData = NULL; @@ -240,7 +267,7 @@ void NoteField::Update( float fDeltaTime ) ActorFrame::Update( fDeltaTime ); // update m_fBoardOffsetPixels, m_fCurrentBeatLastUpdate, m_fYPosCurrentBeatLastUpdate - const float fCurrentBeat = m_pPlayerState->m_Position.m_fSongBeat; + const float fCurrentBeat = GetDisplayedPosition(m_pPlayerState)->m_fSongBeat; bool bTweeningOn = m_sprBoard->GetCurrentDiffuseAlpha() >= 0.98 && m_sprBoard->GetCurrentDiffuseAlpha() < 1.00; // HACK if( !bTweeningOn && m_fCurrentBeatLastUpdate != -1 ) { @@ -444,6 +471,7 @@ static ThemeMetric TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" ); static ThemeMetric COMBO_OFFSETX ( "NoteField", "ComboOffsetX" ); static ThemeMetric LABEL_OFFSETX ( "NoteField", "LabelOffsetX" ); + void NoteField::DrawBPMText( const float fBeat, const float fBPM ) { const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); @@ -606,7 +634,7 @@ void NoteField::DrawBGChangeText( const float fBeat, const RString sNewBGName ) // change this probing to binary search float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceAfterTargetsPixels ) { - float fFirstBeatToDraw = pPlayerState->m_Position.m_fSongBeat-4; // Adjust to balance off performance and showing enough notes. + float fFirstBeatToDraw = GetDisplayedPosition(pPlayerState)->m_fSongBeat-4; // Adjust to balance off performance and showing enough notes. /* In Boomerang, we'll usually have two sections of notes: before and after * the peak. We always start drawing before the peak, and end after it, or @@ -618,7 +646,7 @@ float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistance bBoomerang = (fAccels[PlayerOptions::ACCEL_BOOMERANG] != 0); } - while( fFirstBeatToDraw < pPlayerState->m_Position.m_fSongBeat ) + while( fFirstBeatToDraw < GetDisplayedPosition(pPlayerState)->m_fSongBeat ) { bool bIsPastPeakYOffset; float fPeakYOffset; @@ -640,7 +668,7 @@ float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceB // Probe for last note to draw. Worst case is 0.25x + boost. // Adjust search distance so that notes don't pop onto the screen. float fSearchDistance = 10; - float fLastBeatToDraw = pPlayerState->m_Position.m_fSongBeat+fSearchDistance; + float fLastBeatToDraw = GetDisplayedPosition(pPlayerState)->m_fSongBeat+fSearchDistance; const int NUM_ITERATIONS = 20; @@ -739,12 +767,13 @@ void NoteField::DrawPrimitives() cur->m_ReceptorArrowRow.Draw(); } - Steps *stepChecking = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]; + const TimingData *pTiming = GetDisplayedTiming(m_pPlayerState); // Draw beat bars - if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && stepChecking != NULL ) + if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && pTiming != NULL ) { - const vector &vTimeSignatureSegments = stepChecking->m_Timing.m_vTimeSignatureSegments; + const TimingData &timing = *pTiming; + const vector &vTimeSignatureSegments = timing.m_vTimeSignatureSegments; int iMeasureIndex = 0; FOREACH_CONST( TimeSignatureSegment, vTimeSignatureSegments, iter ) { @@ -783,11 +812,11 @@ void NoteField::DrawPrimitives() } } - if( GAMESTATE->IsEditing() && stepChecking != NULL ) + if( GAMESTATE->IsEditing() && pTiming != NULL ) { ASSERT(GAMESTATE->m_pCurSong); - const TimingData &timing = stepChecking->m_Timing; + const TimingData &timing = *pTiming; // BPM text FOREACH_CONST( BPMSegment, timing.m_BPMSegments, seg ) @@ -1056,7 +1085,7 @@ void NoteField::DrawPrimitives() displayCols->display[c].DrawHold( tn, c, iStartRow, bIsHoldingNote, Result, bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, m_fYReverseOffsetPixels, (float) iDrawDistanceAfterTargetsPixels, (float) iDrawDistanceBeforeTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT ); - bool bNoteIsUpcoming = NoteRowToBeat(iStartRow) > m_pPlayerState->m_Position.m_fSongBeat; + bool bNoteIsUpcoming = NoteRowToBeat(iStartRow) > GetDisplayedPosition(m_pPlayerState)->m_fSongBeat; bAnyUpcomingInThisCol |= bNoteIsUpcoming; } } @@ -1098,7 +1127,7 @@ void NoteField::DrawPrimitives() continue; // skip ASSERT_M( NoteRowToBeat(q) > -2000, ssprintf("%i %i %i, %f %f", q, iLastRowToDraw, - iFirstRowToDraw, m_pPlayerState->m_Position.m_fSongBeat, m_pPlayerState->m_Position.m_fMusicSeconds) ); + iFirstRowToDraw, GetDisplayedPosition(m_pPlayerState)->m_fSongBeat, GetDisplayedPosition(m_pPlayerState)->m_fMusicSeconds) ); // See if there is a hold step that begins on this index. // Only do this if the noteskin cares. @@ -1128,7 +1157,7 @@ void NoteField::DrawPrimitives() m_fYReverseOffsetPixels, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT ); - bool bNoteIsUpcoming = NoteRowToBeat(q) > m_pPlayerState->m_Position.m_fSongBeat; + bool bNoteIsUpcoming = NoteRowToBeat(q) > GetDisplayedPosition(m_pPlayerState)->m_fSongBeat; bAnyUpcomingInThisCol |= bNoteIsUpcoming; } diff --git a/src/NoteField.h b/src/NoteField.h index 560f3cb563..c389676cfb 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -1,6 +1,8 @@ #ifndef NOTE_FIELD_H #define NOTE_FIELD_H +#include "TimingData.h" +#include "SongPosition.h" #include "Sprite.h" #include "ActorFrame.h" #include "BitmapText.h" @@ -65,7 +67,7 @@ protected: void DrawAttackText( const float fBeat, const Attack &attack ); void DrawBGChangeText( const float fBeat, const RString sNewBGName ); float GetWidth() const; - + const NoteData *m_pNoteData; float m_fPercentFadeToFail; // -1 if not fading to fail diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 0a6e8a2a4a..8a69a67040 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -735,10 +735,8 @@ void ScreenEdit::Init() GAMESTATE->m_bGameplayLeadIn.Set( true ); GAMESTATE->m_EditMode = EDIT_MODE.GetValue(); - GAMESTATE->m_Position.m_fSongBeat = 0; - FOREACH_PlayerNumber( p ) - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = 0; - m_fTrailingBeat = GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat; + SetBeat(0); + m_fTrailingBeat = 0; m_iShiftAnchor = -1; m_iStartPlayingAt = -1; @@ -1179,9 +1177,13 @@ void ScreenEdit::DrawPrimitives() // HACK: Draw using the trailing beat PlayerState *pPlayerState = const_cast (m_NoteFieldEdit.GetPlayerState()); - float fSongBeat = pPlayerState->m_Position.m_fSongBeat; // save song beat - float fSongBeatNoOffset = pPlayerState->m_Position.m_fSongBeatNoOffset; - float fSongBeatVisible = pPlayerState->m_Position.m_fSongBeatVisible; + float fPlayerSongBeat = pPlayerState->m_Position.m_fSongBeat; // save song beat + float fPlayerSongBeatNoOffset = pPlayerState->m_Position.m_fSongBeatNoOffset; + float fPlayerSongBeatVisible = pPlayerState->m_Position.m_fSongBeatVisible; + + float fGameSongBeat = GAMESTATE->m_Position.m_fSongBeat; // save song beat + float fGameSongBeatNoOffset = GAMESTATE->m_Position.m_fSongBeatNoOffset; + float fGameSongBeatVisible = GAMESTATE->m_Position.m_fSongBeatVisible; pPlayerState->m_Position.m_fSongBeat = m_fTrailingBeat; // put trailing beat in effect pPlayerState->m_Position.m_fSongBeatNoOffset = m_fTrailingBeat; // put trailing beat in effect @@ -1189,9 +1191,13 @@ void ScreenEdit::DrawPrimitives() ScreenWithMenuElements::DrawPrimitives(); - pPlayerState->m_Position.m_fSongBeat = fSongBeat; // restore real song beat - pPlayerState->m_Position.m_fSongBeatNoOffset = fSongBeatNoOffset; - pPlayerState->m_Position.m_fSongBeatVisible = fSongBeatVisible; + pPlayerState->m_Position.m_fSongBeat = fPlayerSongBeat; // restore real song beat + pPlayerState->m_Position.m_fSongBeatNoOffset = fPlayerSongBeatNoOffset; + pPlayerState->m_Position.m_fSongBeatVisible = fPlayerSongBeatVisible; + + GAMESTATE->m_Position.m_fSongBeat = fGameSongBeat; // restore real song beat + GAMESTATE->m_Position.m_fSongBeatNoOffset = fGameSongBeatNoOffset; + GAMESTATE->m_Position.m_fSongBeatVisible = fGameSongBeatVisible; } @@ -2407,15 +2413,8 @@ void ScreenEdit::TransitionEditState( EditState em ) m_Background.Unload(); m_Foreground.Unload(); - // Restore the cursor position. - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = m_fBeatToReturnTo; - - // Make sure we're snapped. - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = Quantize( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) ); - - /* Playing and recording have lead-ins, which may start before beat 0; - * make sure we don't stay there if we escaped out early. */ - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = max( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat, 0 ); + // Restore the cursor position + Quantize + Clamp + SetBeat( max( 0, Quantize( m_fBeatToReturnTo, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) ) ) ); break; @@ -2532,7 +2531,7 @@ void ScreenEdit::ScrollTo( float fDestinationBeat ) if( fOriginalBeat == fDestinationBeat ) return; - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = fDestinationBeat; + SetBeat(fDestinationBeat); // check to see if they're holding a button for( int n=0; nm_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = m_fTrailingBeat; + SetBeat(m_fTrailingBeat); } else if( SM == SM_LoseFocus ) { @@ -2981,10 +2980,10 @@ void ScreenEdit::OnSnapModeChange() m_soundChangeSnap.Play(); NoteType nt = m_SnapDisplay.GetNoteType(); - int iStepIndex = BeatToNoteRow( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat ); + int iStepIndex = BeatToNoteRow( GetBeat() ); int iElementsPerNoteType = BeatToNoteRow( NoteTypeToBeat(nt) ); int iStepIndexHangover = iStepIndex % iElementsPerNoteType; - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat -= NoteRowToBeat( iStepIndexHangover ); + SetBeat( GetBeat() - NoteRowToBeat( iStepIndexHangover ) ); } @@ -3109,6 +3108,29 @@ TimingData & ScreenEdit::GetAppropriateTiming() const return m_pSong->m_SongTiming; } +inline void ScreenEdit::SetBeat(float fBeat) +{ + if( !GAMESTATE->m_bIsEditorStepTiming ) + { + GAMESTATE->m_Position.m_fSongBeat = fBeat; + GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = m_pSteps->m_Timing.GetBeatFromElapsedTime(m_pSong->m_SongTiming.GetElapsedTimeFromBeat(fBeat)); + } + else + { + GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = fBeat; + GAMESTATE->m_Position.m_fSongBeat = m_pSong->m_SongTiming.GetBeatFromElapsedTime(m_pSteps->m_Timing.GetElapsedTimeFromBeat(fBeat)); + } +} + +inline float ScreenEdit::GetBeat() +{ + if( !GAMESTATE->m_bIsEditorStepTiming ) + { + return GAMESTATE->m_Position.m_fSongBeat; + } + return GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat; +} + void ScreenEdit::DisplayTimingMenu() { g_TimingDataInformation.rows.clear(); @@ -3126,16 +3148,8 @@ void ScreenEdit::DisplayTimingMenu() g_TimingDataInformation.rows.push_back(hl); } - float fBeat; + float fBeat = GetBeat(); TimingData &pTime = GetAppropriateTiming(); - if( !GAMESTATE->m_bIsEditorStepTiming ) - { - fBeat = GAMESTATE->m_Position.m_fSongBeat; - } - else - { - fBeat = GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat; - } // TODO: Better way of guaranteeing that we don't go out of bounds between timings. int posLabel = ScreenEdit::tickcount; diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index f76c56a020..da134f6aa2 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -555,6 +555,9 @@ private: * @brief Retrieve the appropriate TimingData based on GAMESTATE. * @return the proper TimingData. */ TimingData & GetAppropriateTiming() const; + void SetBeat(float fBeat); + float GetBeat(); + }; #endif