diff --git a/src/Background.cpp b/src/Background.cpp index d744865542..2636e5d1c0 100644 --- a/src/Background.cpp +++ b/src/Background.cpp @@ -702,7 +702,8 @@ void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMus float fBeat, fBPS; bool bFreeze; - pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze ); + int iThrowAway1, iThrowAway2; + pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze, iThrowAway1, iThrowAway2 ); /* Calls to Update() should *not* be scaled by music rate; fCurrentTime is. Undo it. */ const float fRate = GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; @@ -850,7 +851,7 @@ void BackgroundImpl::GetLoadedBackgroundChanges( vector *pBack bool BackgroundImpl::IsDangerAllVisible() { - /* The players are never in danger in FAIL_OFF. */ + // The players are never in danger in FAIL_OFF. FOREACH_PlayerNumber( p ) if( GAMESTATE->GetPlayerFailType(GAMESTATE->m_pPlayerState[p]) == PlayerOptions::FAIL_OFF ) return false; diff --git a/src/GameState.cpp b/src/GameState.cpp index 2e3e8aa4c0..a9ea2bfc8d 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -240,7 +240,6 @@ void GameState::ResetPlayer( PlayerNumber pn ) m_pPlayerState[pn]->m_PlayerOptions.Assign( ModsLevel_Preferred, po ); } -//static Preference g_bMultiplayer( "Multiplayer", false ); void GameState::Reset() { m_MasterPlayerNumber = PLAYER_INVALID; // must initialize for UnjoinPlayer @@ -895,8 +894,8 @@ void GameState::ResetMusicStatistics() //m_bStop = false; m_bFreeze = false; m_bDelay = false; - //m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj - //m_iWarpEndRow = -1; // Set when a warp is encountered. also see above. -aj + m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj + m_iWarpEndRow = -1; // Set when a warp is encountered. also see above. -aj m_fMusicSecondsVisible = 0; m_fSongBeatVisible = 0; Actor::SetBGMTime( 0, 0, 0, 0 ); @@ -951,8 +950,10 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti m_LastBeatUpdate.Touch(); // xxx testing: only do this on monotune survivor + /* if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" ) LOG->Trace( ssprintf("[GameState::UpdateSongPosition] cur BPS = %f, fPositionSeconds = %f",m_fCurBPS,fPositionSeconds) ); + */ //timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay, m_iWarpBeginRow, m_iWarpEndRow ); timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay ); diff --git a/src/GameState.h b/src/GameState.h index 2fd0e4ea1f..62e2767406 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -184,7 +184,7 @@ public: //bool m_bStop; // in the middle of a stop (freeze or delay) bool m_bFreeze; // in the middle of a freeze bool m_bDelay; // in the middle of a delay - //int m_iWarpToRow, m_iWarpFromRow; // used for warping + int m_iWarpBeginRow, m_iWarpEndRow; // used for warping RageTimer m_LastBeatUpdate; // time of last m_fSongBeat, etc. update BroadcastOnChange m_bGameplayLeadIn; diff --git a/src/Player.cpp b/src/Player.cpp index a8b75a7205..f89923c9c9 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -135,7 +135,7 @@ ThemeMetric CHECKPOINTS_USE_TIME_SIGNATURES ( "Player", "CheckpointsUseTim ThemeMetric CHECKPOINTS_FLASH_ON_HOLD ( "Player", "CheckpointsFlashOnHold" ); // sm-ssc addition ThemeMetric IMMEDIATE_HOLD_LET_GO ( "Player", "ImmediateHoldLetGo" ); ThemeMetric REQUIRE_STEP_ON_HOLD_HEADS ( "Player", "RequireStepOnHoldHeads" ); -//ThemeMetric REQUIRE_STEP_ON_TAP_NOTES ( "Player", "RequireStepOnTapNotes" ); // parastar stuff; leave in though +//ThemeMetric HOLD_TRIGGERS_TAP_NOTES ( "Player", "HoldTriggersTapNotes" ); // parastar stuff; leave in though ThemeMetric ROLL_BODY_INCREMENTS_COMBO ( "Player", "RollBodyIncrementsCombo" ); ThemeMetric CHECKPOINTS_TAPS_SEPARATE_JUDGMENT ( "Player", "CheckpointsTapsSeparateJudgment" ); ThemeMetric SCORE_MISSED_HOLDS_AND_ROLLS ( "Player", "ScoreMissedHoldsAndRolls" ); // sm-ssc addition @@ -355,6 +355,9 @@ void Player::Init( m_pActorWithComboPosition = &*m_sprCombo; this->AddChild( m_sprCombo ); + // todo: allow for judgments to be loaded per-column a la pop'n? + // see how HoldJudgments are handled below for an example, though + // it would need more work. -aj m_sprJudgment.Load( THEME->GetPathG(sType,"judgment") ); m_sprJudgment->SetName( "Judgment" ); m_pActorWithJudgmentPosition = &*m_sprJudgment; @@ -481,6 +484,9 @@ void Player::Load() { // ugly, ugly, ugly. Works only w/ dance. // Why does this work only with dance? - Steve + // it has to do with there only being four cases. This is a lame + // workaround, but since only DDR has ever really implemented those + // modes, it's stayed like this. -aj StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; NoteDataUtil::TransformNoteData( m_NoteData, m_pPlayerState->m_PlayerOptions.GetStage(), st ); @@ -675,7 +681,6 @@ void Player::Update( float fDeltaTime ) // Update Y positions { - // todo: unhardcode hold judgment cmds -aj for( int c=0; cGetCurrentStyle()->m_iColsPerPlayer; c++ ) { float fPercentReverse = m_pPlayerState->m_PlayerOptions.GetCurrent().GetReversePercentForColumn(c); @@ -749,7 +754,7 @@ void Player::Update( float fDeltaTime ) GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( col, m_pPlayerState->m_PlayerNumber ); bool bIsHoldingButton = INPUTMAPPER->IsBeingPressed( GameI ); - + if( m_vAlterMap.size() > 0 ) // alternate input is being used { for( unsigned int i=0; i < m_vAlterMap.size(); ++i ) @@ -767,7 +772,6 @@ void Player::Update( float fDeltaTime ) m_pNoteField->SetPressed( col ); } - // handle Autoplay for rolls if( m_pPlayerState->m_PlayerController != PC_HUMAN ) { @@ -821,8 +825,8 @@ void Player::Update( float fDeltaTime ) TrackRowTapNote trtn = { iTrack, iRow, &tn }; /* All holds must be of the same subType because fLife is handled - * in different ways depending on the SubType. Handle Rolls one at a time - * and don't mix with holds. */ + * in different ways depending on the SubType. Handle Rolls one at + * a time and don't mix with holds. */ switch( tn.subType ) { DEFAULT_FAIL( tn.subType ); @@ -901,7 +905,7 @@ void Player::Update( float fDeltaTime ) ApplyWaitingTransforms(); } -/* Update a group of holds with shared scoring/life. All of these holds will have the same start row. */ +// Update a group of holds with shared scoring/life. All of these holds will have the same start row. void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector &vTN ) { ASSERT( !vTN.empty() ); @@ -2321,7 +2325,8 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) bool bFreeze, bDelay; float fMissIfOlderThanThisBeat; float fThrowAway; - GAMESTATE->m_pCurSong->m_Timing.GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay ); + int iWarpBeginRow, iWarpEndRow; + GAMESTATE->m_pCurSong->m_Timing.GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay, iWarpBeginRow, iWarpEndRow ); iMissIfOlderThanThisRow = BeatToNoteRow( fMissIfOlderThanThisBeat ); if( bFreeze || bDelay ) @@ -2356,6 +2361,11 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) } else { + // warp hackery: don't score notes within the warp region. + // (Only useful when QuirksMode is enabled.) -aj + if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() <= GAMESTATE->m_iWarpEndRow ) + continue; + tn.result.tns = TNS_Miss; } } @@ -2367,7 +2377,6 @@ void Player::UpdateJudgedRows() bool bAllJudged = true; const bool bSeparately = GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately; - // todo: modify function for warps? -aj { NoteData::all_tracks_iterator iter = *m_pIterUnjudgedRows; int iLastSeenRow = -1; @@ -2375,16 +2384,14 @@ void Player::UpdateJudgedRows() { int iRow = iter.Row(); - // if row is in a skip section, ignore it? -aj - //if(iRow) - //{ - // // stuff!! - //} - if( iLastSeenRow != iRow ) { iLastSeenRow = iRow; + // if row is within a warp section, ignore it. -aj + if(iRow >= GAMESTATE->m_iWarpBeginRow && iRow <= GAMESTATE->m_iWarpEndRow) + continue; + // crossed a nonempty row if( !NoteDataWithScoring::IsRowCompletelyJudged(m_NoteData, iRow) ) { @@ -2526,7 +2533,7 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) int iLastSeenRow = -1; for( ; !iter.IsAtEnd() && iter.Row() <= iLastRowCrossed; ++iter ) { - /* Apply InitialHoldLife. */ + // Apply InitialHoldLife. TapNote &tn = *iter; int iRow = iter.Row(); int iTrack = iter.Track(); @@ -2630,7 +2637,7 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) { TimeSignatureSegment tSignature = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) ); - // Most songs are in 4/4 time. The frequency for checking tick counts should reflect that. + // Most songs are in 4/4 time. The frequency for checking tick counts should reflect that. iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.m_iDenominator / (tSignature.m_iNumerator * 4); } @@ -2744,6 +2751,10 @@ void Player::HandleTapRowScore( unsigned row ) bNoCheating = false; #endif + // more warp hackery. -aj + if(row >= (unsigned)GAMESTATE->m_iWarpBeginRow && row <= (unsigned)GAMESTATE->m_iWarpEndRow) + return; + if( GAMESTATE->m_bDemonstrationOrJukebox ) bNoCheating = false; // don't accumulate points if AutoPlay is on. diff --git a/src/Song.cpp b/src/Song.cpp index dacfe5a4ef..1499880dab 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -34,7 +34,7 @@ #include #include -const int FILE_CACHE_VERSION = 159; // increment this to invalidate cache +const int FILE_CACHE_VERSION = 160; // increment this to invalidate cache const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; diff --git a/src/TimingData.cpp b/src/TimingData.cpp index aa7783e1cb..9d85f8eba2 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -11,6 +11,7 @@ TimingData::TimingData() { m_fBeat0OffsetInSeconds = 0; + m_bHasNegativeBpms = false; } void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const @@ -41,12 +42,10 @@ void TimingData::AddTimeSignatureSegment( const TimeSignatureSegment &seg ) m_vTimeSignatureSegments.insert( upper_bound(m_vTimeSignatureSegments.begin(), m_vTimeSignatureSegments.end(), seg), seg ); } -/* void TimingData::AddWarpSegment( const WarpSegment &seg ) { m_WarpSegments.insert( upper_bound(m_WarpSegments.begin(), m_WarpSegments.end(), seg), seg ); } -*/ /* Change an existing BPM segment, merge identical segments together or insert a new one. */ void TimingData::SetBPMAtRow( int iNoteRow, float fBPM ) @@ -110,6 +109,13 @@ void TimingData::SetDelayAtRow( int iRow, float fSeconds ) SetStopAtRow(iRow,fSeconds,true); } +/* +void TimingData::SetWarpAtRow( int iRowAt, int iRowTo ) +{ + // todo: code this -aj +} +*/ + float TimingData::GetStopAtRow( int iNoteRow, bool &bDelayOut ) const { bDelayOut = false; // not a delay by default @@ -125,6 +131,18 @@ float TimingData::GetStopAtRow( int iNoteRow, bool &bDelayOut ) const return 0; } +int TimingData::GetWarpToRow( int iWarpBeginRow ) const +{ + for( unsigned i=0; im_fGlobalOffsetSeconds; - GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut, bDelayOut ); + GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut, bDelayOut, iWarpBeginOut, iWarpEndOut ); } -//, int &iWarpOut -void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut ) const +void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, int &iWarpEndOut ) const { // LOG->Trace( "GetBeatAndBPSFromElapsedTime( fElapsedTime = %f )", fElapsedTime ); const float fTime = fElapsedTime; @@ -254,18 +271,18 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float if( (fFreezeStartSecond >= fElapsedTime && !bIsDelay) || (fFreezeStartSecond > fElapsedTime && bIsDelay) ) { - /* The time lies within the stop. */ + // The time lies within the stop. fBeatOut = NoteRowToBeat(m_StopSegments[j].m_iStartRow); fBPSOut = fBPS; bFreezeOut = !bIsDelay; bDelayOut = bIsDelay; - //bWarpOut = false; + //iWarpBeginOut = -1; + //iWarpEndOut = -1; return; } } // by this point we should have the warps in their own place. - /* for( unsigned j=0; j= m_WarpSegments[j].m_iStartRow ) @@ -273,12 +290,18 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float if( !bIsLastBPMSegment && m_WarpSegments[j].m_iStartRow > iStartRowNextSegment ) continue; + // this warp lies within this BPMSegment. + iWarpBeginOut = m_WarpSegments[j].m_iStartRow; + iWarpEndOut = m_WarpSegments[j].m_iEndRow; + // this warp lies within this BPMSegment, and these are wrong + // huh? -aj + /* const int iRowsBeatsSinceStartOfSegment = m_WarpSegments[j].m_iStartRow - iStartRowThisSegment; const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment); const float fWarpStartSecond = fBeatsSinceStartOfSegment / fBPS; + */ } - */ const float fBeatsInThisSegment = fStartBeatNextSegment - fStartBeatThisSegment; const float fSecondsInThisSegment = fBeatsInThisSegment / fBPS; @@ -291,17 +314,17 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float */ if( bIsLastBPMSegment || fElapsedTime <= fSecondsInThisSegment ) { - // this BPMSegment IS the current segment + // this BPMSegment IS the current segment. fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS; fBPSOut = fBPS; bFreezeOut = false; bDelayOut = false; - //bWarpOut = false; - + //iWarpBeginOut; + //iWarpEndOut; return; } - // this BPMSegment is NOT the current segment + // this BPMSegment is NOT the current segment. fElapsedTime -= fSecondsInThisSegment; // xxx: negative testing /* @@ -317,13 +340,13 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float // If we get here, something has gone wrong. Is everything sorted? vector vBPMS = m_BPMSegments; vector vSS = m_StopSegments; - //vector vWS = m_WarpSegments; + vector vWS = m_WarpSegments; sort( vBPMS.begin(), vBPMS.end() ); sort( vSS.begin(), vSS.end() ); - //sort( vWS.begin(), vWS.end() ); + sort( vWS.begin(), vWS.end() ); ASSERT_M( vBPMS == m_BPMSegments, "The BPM segments were not sorted!" ); ASSERT_M( vSS == m_StopSegments, "The Stop segments were not sorted!" ); - //ASSERT_M( vWS == m_WarpSegments, "The Warp segments were not sorted!" ); + ASSERT_M( vWS == m_WarpSegments, "The Warp segments were not sorted!" ); FAIL_M( ssprintf("Failed to find the appropriate segment for elapsed time %f.", fTime) ); } @@ -375,7 +398,9 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const /* for( unsigned i=0; i0; } -/* bool TimingData::HasWarps() const { return m_WarpSegments.size()>0; } -*/ void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const { @@ -515,7 +538,7 @@ void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, i vector::const_iterator next = iter; next++; int iSegmentEndRow = (next == m_vTimeSignatureSegments.end()) ? INT_MAX : next->m_iStartRow; - + int iRowsPerMeasureThisSegment = iter->GetNoteRowsPerMeasure(); if( iNoteRow >= iter->m_iStartRow ) @@ -614,6 +637,7 @@ public: LuaHelpers::CreateTableFromArray(fBPMs, L); return 1; } + static int HasNegativeBPMs( T* p, lua_State *L ) { lua_pushboolean(L, p->m_bHasNegativeBpms); return 1; } // formerly in Song.cpp in sm-ssc private beta 1.x: static int GetBPMAtBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBPMAtBeat(FArg(1))); return 1; } static int GetBeatFromElapsedTime( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBeatFromElapsedTime(FArg(1))); return 1; } @@ -628,6 +652,7 @@ public: ADD_METHOD( GetBPMs ); ADD_METHOD( GetBPMsAndTimes ); ADD_METHOD( GetActualBPM ); + ADD_METHOD( HasNegativeBPMs ); // formerly in Song.cpp in sm-ssc private beta 1.x: ADD_METHOD( GetBPMAtBeat ); ADD_METHOD( GetBeatFromElapsedTime ); diff --git a/src/TimingData.h b/src/TimingData.h index 06a11b695c..ef0d537dfb 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -86,9 +86,9 @@ struct TimeSignatureSegment }; /* A warp segment is used to replicate the effects of Negative BPMs without - * ausing negative BPMs. Negative BPMs should be converted to warp segments. - * WarpAt=WarpTo is the format, where both are in beats. */ -/* + * abusing negative BPMs. Negative BPMs should be converted to warp segments. + * WarpAt=WarpTo is the format, where both are in beats. (Technically they're + * both rows though.) */ struct WarpSegment { WarpSegment() : m_iStartRow(-1), m_iEndRow(-1) { } @@ -105,7 +105,6 @@ struct WarpSegment bool operator!=( const WarpSegment &other ) const { return !operator==(other); } bool operator<( const WarpSegment &other ) const { return m_iStartRow < other.m_iStartRow; } }; -*/ class TimingData { @@ -121,40 +120,43 @@ public: void SetStopAtBeat( float fBeat, float fSeconds ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds ); } void SetStopAtBeat( float fBeat, float fSeconds, bool bDelay ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds, bDelay ); } // (sm-ssc) float GetStopAtRow( int iNoteRow, bool &bDelayOut ) const; + int GetWarpToRow( int iWarpBeginRow ) const; void SetDelayAtRow( int iNoteRow, float fSeconds ); // sm-ssc void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ); void AddBPMSegment( const BPMSegment &seg ); void AddStopSegment( const StopSegment &seg ); void AddTimeSignatureSegment( const TimeSignatureSegment &seg ); - //void AddWarpSegment( const WarpSegment &seg ); + void AddWarpSegment( const WarpSegment &seg ); int GetBPMSegmentIndexAtBeat( float fBeat ); const TimeSignatureSegment& GetTimeSignatureSegmentAtBeat( float fBeat ) const; BPMSegment& GetBPMSegmentAtBeat( float fBeat ); void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const; - void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut ) const; + void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, int &iWarpEndOut ) const; float GetBeatFromElapsedTime( float fElapsedTime ) const // shortcut for places that care only about the beat { float fBeat, fThrowAway; bool bThrowAway, bThrowAway2; - GetBeatAndBPSFromElapsedTime( fElapsedTime, fBeat, fThrowAway, bThrowAway, bThrowAway2 ); + int iThrowAway, iThrowAway2; + GetBeatAndBPSFromElapsedTime( fElapsedTime, fBeat, fThrowAway, bThrowAway, bThrowAway2, iThrowAway, iThrowAway2 ); return fBeat; } float GetElapsedTimeFromBeat( float fBeat ) const; - void GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut ) const; + void GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, int &iWarpEndOut ) const; float GetBeatFromElapsedTimeNoOffset( float fElapsedTime ) const // shortcut for places that care only about the beat { float fBeat, fThrowAway; bool bThrowAway, bThrowAway2; - GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeat, fThrowAway, bThrowAway, bThrowAway2 ); + int iThrowAway, iThrowAway2; + GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeat, fThrowAway, bThrowAway, bThrowAway2, iThrowAway, iThrowAway2 ); return fBeat; } float GetElapsedTimeFromBeatNoOffset( float fBeat ) const; bool HasBpmChanges() const; bool HasStops() const; - // bool HasWarps() const; + bool HasWarps() const; bool operator==( const TimingData &other ) { @@ -164,11 +166,9 @@ public: COMPARE( m_StopSegments.size() ); for( unsigned i=0; i m_BPMSegments; // this must be sorted before gameplay vector m_StopSegments; // this must be sorted before gameplay vector m_vTimeSignatureSegments; // this must be sorted before gameplay - // vector m_vWarpSegments; // this must be sorted before gameplay + vector m_WarpSegments; // this must be sorted before gameplay float m_fBeat0OffsetInSeconds; + bool m_bHasNegativeBpms; // only used for Lua bindings in Song (to be moved to TimingData later) }; #undef COMPARE