From e60ac1395daf1434d4707509719e32f1c152311d Mon Sep 17 00:00:00 2001 From: sigatrev Date: Fri, 5 Sep 2014 22:30:33 -0500 Subject: [PATCH 1/3] expose tap notes for judgment message allow themes access to as much information as possible on judgments --- Docs/Luadoc/Lua.xml | 27 +++++++ Docs/Luadoc/LuaDocumentation.xml | 69 ++++++++++++++++ src/NoteTypes.cpp | 130 ++++++++++++++++++++++++------- src/NoteTypes.h | 37 +++++---- src/Player.cpp | 70 +++++++++++------ src/Player.h | 6 +- 6 files changed, 272 insertions(+), 67 deletions(-) diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index cca7e62894..9573dfd079 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1638,6 +1638,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 4dbeb7bbc1..8c212b20a0 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -4634,6 +4634,75 @@ save yourself some time, copy this for undocumented things: Returns true if the Style needs to be zoomed out with two players. + + + Returns the of the Tap Note. + + + Returns the of the Tap Note. + + + Returns the of the Tap Note. + + + Returns the of the Tap Note. + + + Returns the of the Tap Note. Relevant for routine steps. + + + Returns the Attack Modifiers of the Tap Note. + + + Returns the Attack Duration of the Tap Note in seconds. + + + Returns the Keysound Index of the Tap Note. + + + Returns the Hold Duration of the Tap Note in beats. + + + Returns the of the Tap Note. + + + + + Returns the of the Tap Note. + + + Returns the TapNotOffset of the Tap Note. + + + Returns true if the Tap Note was judged with a result that would stop it from drawing. + + + + + Returns the of the Hold Note. + + + Returns the life of the Hold Note. + + + Returns the amount of time the hold has overlapped the target. + + + Returns the last beat the Hold Note was held. + + + Returns the number of checkpoints hit. + + + Returns the number of checkpoints missed. + + + Returns true if the note was initiated and is being held. + + + Returns true if the note was initiated. + + Loads the TextBanner from the specified metrics group. diff --git a/src/NoteTypes.cpp b/src/NoteTypes.cpp index b164ab7663..851a981dfe 100644 --- a/src/NoteTypes.cpp +++ b/src/NoteTypes.cpp @@ -5,47 +5,47 @@ #include "XmlFile.h" #include "LocalizedString.h" -TapNote TAP_EMPTY ( TapNoteType_Empty, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_TAP ( TapNoteType_Tap, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_LIFT ( TapNoteType_Lift, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_HOLD_HEAD ( TapNoteType_HoldHead, TapNoteSubType_Hold, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_ROLL_HEAD ( TapNoteType_HoldHead, TapNoteSubType_Roll, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_MINE ( TapNoteType_Mine, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_ATTACK ( TapNoteType_Attack, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_AUTO_KEYSOUND ( TapNoteType_AutoKeysound,TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ORIGINAL_FAKE ( TapNoteType_Fake, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_EMPTY ( TapNoteType_Empty, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_TAP ( TapNoteType_Tap, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_LIFT ( TapNoteType_Lift, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_HOLD_HEAD ( TapNoteType_HoldHead, TapNoteSubType_Hold, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_ROLL_HEAD ( TapNoteType_HoldHead, TapNoteSubType_Roll, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_MINE ( TapNoteType_Mine, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_ATTACK ( TapNoteType_Attack, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_AUTO_KEYSOUND ( TapNoteType_AutoKeysound,TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); +TapNote TAP_ORIGINAL_FAKE ( TapNoteType_Fake, TapNoteSubType_Invalid, TapNoteSource_Original, "", 0, -1 ); //TapNote TAP_ORIGINAL_MINE_HEAD ( TapNoteType_HoldHead, TapNoteSubType_Mine, TapNoteSource_Original, "", 0, -1 ); -TapNote TAP_ADDITION_TAP ( TapNoteType_Tap, TapNoteSubType_Invalid, TapNoteSource_Addition, "", 0, -1 ); -TapNote TAP_ADDITION_MINE ( TapNoteType_Mine, TapNoteSubType_Invalid, TapNoteSource_Addition, "", 0, -1 ); +TapNote TAP_ADDITION_TAP ( TapNoteType_Tap, TapNoteSubType_Invalid, TapNoteSource_Addition, "", 0, -1 ); +TapNote TAP_ADDITION_MINE ( TapNoteType_Mine, TapNoteSubType_Invalid, TapNoteSource_Addition, "", 0, -1 ); static const char *TapNoteTypeNames[] = { - "Empty", - "Tap", - "HoldHead", - "HoldTail", - "Mine", - "Lift", - "Attack", - "AutoKeySound", - "Fake", + "Empty", + "Tap", + "HoldHead", + "HoldTail", + "Mine", + "Lift", + "Attack", + "AutoKeySound", + "Fake", }; XToString( TapNoteType ); XToLocalizedString( TapNoteType ); LuaXType( TapNoteType ); static const char *TapNoteSubTypeNames[] = { - "Hold", - "Roll", - //"Mine", + "Hold", + "Roll", + //"Mine", }; XToString( TapNoteSubType ); XToLocalizedString( TapNoteSubType ); LuaXType( TapNoteSubType ); static const char *TapNoteSourceNames[] = { - "Original", - "Addition", + "Original", + "Addition", }; XToString( TapNoteSource ); XToLocalizedString( TapNoteSource ); @@ -127,7 +127,7 @@ static const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE; * @return the quantized NoteType. */ NoteType GetNoteType( int row ) { - if( row % (ROWS_PER_MEASURE/4) == 0) return NOTE_TYPE_4TH; + if( row % (ROWS_PER_MEASURE/4) == 0) return NOTE_TYPE_4TH; else if( row % (ROWS_PER_MEASURE/8) == 0) return NOTE_TYPE_8TH; else if( row % (ROWS_PER_MEASURE/12) == 0) return NOTE_TYPE_12TH; else if( row % (ROWS_PER_MEASURE/16) == 0) return NOTE_TYPE_16TH; @@ -200,6 +200,84 @@ float HoldNoteResult::GetLastHeldBeat() const return NoteRowToBeat(iLastHeldRow); } +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the TapNoteResult. */ +class LunaTapNoteResult: public Luna +{ +public: + DEFINE_METHOD(GetTapNoteScore, tns); + DEFINE_METHOD(GetTapNoteOffset, fTapNoteOffset); + DEFINE_METHOD(GetHidden, bHidden); + + LunaTapNoteResult() + { + ADD_METHOD( GetTapNoteScore ); + ADD_METHOD( GetTapNoteOffset ); + ADD_METHOD( GetHidden ); + } +}; +LUA_REGISTER_CLASS( TapNoteResult ) + +/** @brief Allow Lua to have access to the HoldNoteResult. */ +class LunaHoldNoteResult: public Luna +{ +public: + DEFINE_METHOD(GetHoldNoteScore, hns); + DEFINE_METHOD(GetLife, fLife); + DEFINE_METHOD(GetOverlappedTime, fOverlappedTime); + DEFINE_METHOD(GetLastHeldBeat, GetLastHeldBeat() ); + DEFINE_METHOD(GetCheckpointsHit, iCheckpointsHit ); + DEFINE_METHOD(GetCheckpointsMissed, iCheckpointsMissed ); + DEFINE_METHOD(GetHeld, bHeld ); + DEFINE_METHOD(GetActive, bActive ); + + LunaHoldNoteResult() + { + ADD_METHOD( GetHoldNoteScore ); + ADD_METHOD( GetLife ); + ADD_METHOD( GetOverlappedTime ); + ADD_METHOD( GetLastHeldBeat ); + ADD_METHOD( GetCheckpointsHit ); + ADD_METHOD( GetCheckpointsMissed ); + ADD_METHOD( GetHeld ); + ADD_METHOD( GetActive ); + } +}; +LUA_REGISTER_CLASS( HoldNoteResult ) + +/** @brief Allow Lua to have access to the TapNote. */ +class LunaTapNote: public Luna +{ +public: + DEFINE_METHOD( GetTapNoteType, type ); + DEFINE_METHOD( GetTapNoteSubType, subType ); + DEFINE_METHOD( GetTapNoteSource, source ); + DEFINE_METHOD( GetPlayerNumber, pn ); + DEFINE_METHOD( GetAttackModifiers, sAttackModifiers ); + DEFINE_METHOD( GetAttackDuration, fAttackDurationSeconds ); + DEFINE_METHOD( GetKeysoundIndex, iKeysoundIndex ); + static int GetHoldDuration( T* p, lua_State* L ) { lua_pushnumber(L, NoteRowToBeat(p->iDuration)); return 1; } + static int GetTapNoteResult( T* p, lua_State* L ) { p->result.PushSelf(L); return 1; } + static int GetHoldNoteResult( T* p, lua_State* L ) { p->HoldResult.PushSelf(L); return 1; } + + LunaTapNote() + { + ADD_METHOD( GetTapNoteType ); + ADD_METHOD( GetTapNoteSubType ); + ADD_METHOD( GetTapNoteSource ); + ADD_METHOD( GetTapNoteResult ); + ADD_METHOD( GetPlayerNumber ); + ADD_METHOD( GetAttackModifiers ); + ADD_METHOD( GetAttackDuration ); + ADD_METHOD( GetKeysoundIndex ); + ADD_METHOD( GetHoldDuration ); + ADD_METHOD( GetHoldNoteResult ); + } +}; +LUA_REGISTER_CLASS( TapNote ) + /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/NoteTypes.h b/src/NoteTypes.h index 4cabac1e9c..bd9304828d 100644 --- a/src/NoteTypes.h +++ b/src/NoteTypes.h @@ -31,6 +31,9 @@ struct TapNoteResult // XML XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); + + // Lua + void PushSelf( lua_State *L ); }; /** @brief The result of holding (or letting go of) a hold note. */ struct HoldNoteResult @@ -73,6 +76,9 @@ struct HoldNoteResult // XML XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); + + // Lua + void PushSelf( lua_State *L ); }; /** @brief What is the TapNote's core type? */ @@ -87,8 +93,8 @@ enum TapNoteType TapNoteType_Attack, /**< Hitting this note causes an attack to take place. */ TapNoteType_AutoKeysound, /**< A special sound is played when this note crosses the target area. */ TapNoteType_Fake, /**< This arrow can't be scored for or against the player. */ - NUM_TapNoteType, - TapNoteType_Invalid + NUM_TapNoteType, + TapNoteType_Invalid }; const RString& TapNoteTypeToString( TapNoteType tnt ); const RString& TapNoteTypeToLocalizedString( TapNoteType tnt ); @@ -97,11 +103,11 @@ LuaDeclareType( TapNoteType ); /** @brief The list of a TapNote's sub types. */ enum TapNoteSubType { - TapNoteSubType_Hold, /**< The start of a traditional hold note. */ - TapNoteSubType_Roll, /**< The start of a roll note that must be hit repeatedly. */ - //TapNoteSubType_Mine, - NUM_TapNoteSubType, - TapNoteSubType_Invalid + TapNoteSubType_Hold, /**< The start of a traditional hold note. */ + TapNoteSubType_Roll, /**< The start of a roll note that must be hit repeatedly. */ + //TapNoteSubType_Mine, + NUM_TapNoteSubType, + TapNoteSubType_Invalid }; const RString& TapNoteSubTypeToString( TapNoteSubType tnst ); const RString& TapNoteSubTypeToLocalizedString( TapNoteSubType tnst ); @@ -110,10 +116,10 @@ LuaDeclareType( TapNoteSubType ); /** @brief The different places a TapNote could come from. */ enum TapNoteSource { - TapNoteSource_Original, /**< This note is part of the original NoteData. */ - TapNoteSource_Addition, /**< This note is additional note added by a transform. */ - NUM_TapNoteSource, - TapNoteSource_Invalid + TapNoteSource_Original, /**< This note is part of the original NoteData. */ + TapNoteSource_Addition, /**< This note is additional note added by a transform. */ + NUM_TapNoteSource, + TapNoteSource_Invalid }; const RString& TapNoteSourceToString( TapNoteSource tns ); const RString& TapNoteSourceToLocalizedString( TapNoteSource tns ); @@ -145,11 +151,14 @@ struct TapNote // also used for hold_head only: int iDuration; HoldNoteResult HoldResult; - + // XML XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); + // Lua + void PushSelf( lua_State *L ); + TapNote(): type(TapNoteType_Empty), subType(TapNoteSubType_Invalid), source(TapNoteSource_Original), result(), pn(PLAYER_INVALID), bHopoPossible(false), sAttackModifiers(""), fAttackDurationSeconds(0), @@ -301,7 +310,7 @@ inline float NoteRowToBeat( int iRow ) { return iRow / (float)ROWS_PER_BEAT; } * @brief Convert the note row to note row (returns itself). * @param row the row to convert. */ -static inline int ToNoteRow(int row) { return row; } +static inline int ToNoteRow(int row) { return row; } /** * @brief Convert the beat to note row. @@ -313,7 +322,7 @@ static inline int ToNoteRow(float beat) { return BeatToNoteRow(beat); } * @brief Convert the note row to beat. * @param row the row to convert. */ -static inline float ToBeat(int row) { return NoteRowToBeat(row); } +static inline float ToBeat(int row) { return NoteRowToBeat(row); } /** * @brief Convert the beat row to beat (return itself). diff --git a/src/Player.cpp b/src/Player.cpp index 9c4b6786f3..5bbcdf14b1 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -1464,7 +1464,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorTrace("tap note scoring time."); TapNote &tn = *vTN[0].pTN; - SetHoldJudgment( tn.result.tns, tn.HoldResult.hns, iFirstTrackWithMaxEndRow ); + SetHoldJudgment( tn, iFirstTrackWithMaxEndRow ); HandleHoldScore( tn ); //LOG->Trace("hold result = %s",StringConversion::ToString(tn.HoldResult.hns).c_str()); } @@ -1914,7 +1914,6 @@ void Player::DoTapScoreNone() SendComboMessages( iOldCombo, iOldMissCombo ); - if( m_pLifeMeter ) m_pLifeMeter->HandleTapScoreNone(); // TODO: Remove use of PlayerNumber @@ -1924,7 +1923,7 @@ void Player::DoTapScoreNone() if( PENALIZE_TAP_SCORE_NONE ) { - SetJudgment( TNS_Miss, -1, 0 ); + SetJudgment( BeatToNoteRow( m_pPlayerState->m_Position.m_fSongBeat ), -1, TAP_EMPTY, TNS_Miss, 0 ); // the ScoreKeeper will subtract points later. } } @@ -1960,7 +1959,7 @@ void Player::ScoreAllActiveHoldsLetGo() tn.HoldResult.hns = HNS_LetGo; tn.HoldResult.fLife = 0; - SetHoldJudgment( tn.result.tns, tn.HoldResult.hns, iTrack ); + SetHoldJudgment( tn, iTrack ); HandleHoldScore( tn ); } } @@ -2796,24 +2795,15 @@ void Player::UpdateJudgedRows() if (tn.type == TapNoteType_Empty || tn.type == TapNoteType_Mine || tn.type == TapNoteType_AutoKeysound) continue; - SetJudgment( tn.result.tns, iTrack, tn.result.fTapNoteOffset ); + SetJudgment( iRow, iTrack, tn ); } } else { - vector viColsWithTaps; - for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) - { - const TapNote &tn = m_NoteData.GetTapNote( iTrack, iRow ); - if (tn.type == TapNoteType_Tap || tn.type == TapNoteType_Lift || - ( tn.type == TapNoteType_HoldHead && REQUIRE_STEP_ON_HOLD_HEADS ) ) - { - viColsWithTaps.push_back( iTrack ); - }; - } - SetJudgment( lastTNR.tns, m_NoteData.GetFirstTrackWithTapOrHoldHead(iRow), lastTNR.fTapNoteOffset, viColsWithTaps ); + SetJudgment( iRow, m_NoteData.GetFirstTrackWithTapOrHoldHead(iRow), NoteDataWithScoring::LastTapNoteWithResult( m_NoteData, iRow ) ); } HandleTapRowScore( iRow ); + HandleTapRowScore( iRow ); } } } @@ -3245,7 +3235,7 @@ void Player::HandleHoldCheckpoint(int iRow, ChangeLife( iNumHoldsMissedThisRow == 0? TNS_CheckpointHit:TNS_CheckpointMiss ); - SetJudgment( iNumHoldsMissedThisRow == 0? TNS_CheckpointHit:TNS_CheckpointMiss, viColsWithHold[0], 0 ); + SetJudgment( iRow, viColsWithHold[0], TAP_EMPTY, iNumHoldsMissedThisRow == 0? TNS_CheckpointHit:TNS_CheckpointMiss, 0 ); } void Player::HandleHoldScore( const TapNote &tn ) @@ -3330,7 +3320,7 @@ void Player::SetMineJudgment( TapNoteScore tns , int iTrack ) } } -void Player::SetJudgment( TapNoteScore tns, int iTrack, float fTapNoteOffset, vector viCols ) +void Player::SetJudgment( int iRow, int iTrack, const TapNote &tn, TapNoteScore tns, float fTapNoteOffset ) { if( m_bSendJudgmentAndComboMessages ) { @@ -3340,17 +3330,44 @@ void Player::SetJudgment( TapNoteScore tns, int iTrack, float fTapNoteOffset, ve msg.SetParam( "FirstTrack", iTrack ); msg.SetParam( "TapNoteScore", tns ); msg.SetParam( "Early", fTapNoteOffset < 0.0f ); - msg.SetParam( "TapNoteOffset", fTapNoteOffset ); - msg.SetParam( "Tracks" , viCols ); + msg.SetParam( "TapNoteOffset", tn.result.fTapNoteOffset ); + + Lua* L= LUA->Get(); + lua_createtable( L, 0, m_NoteData.GetNumTracks() ); // TapNotes this row + lua_createtable( L, 0, m_NoteData.GetNumTracks() ); // HoldHeads of tracks held at this row. + + for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) + { + NoteData::iterator tn = m_NoteData.FindTapNote(iTrack, iRow); + if( tn != m_NoteData.end(iTrack) ) + { + tn->second.PushSelf(L); + lua_rawseti(L, -3, iTrack + 1); + } + else + { + int iHeadRow; + if( m_NoteData.IsHoldNoteAtRow( iTrack, iRow, &iHeadRow ) ) + { + NoteData::iterator hold = m_NoteData.FindTapNote(iTrack, iHeadRow); + hold->second.PushSelf(L); + lua_rawseti(L, -2, iTrack + 1); + } + } + } + msg.SetParamFromStack( L, "Holds" ); + msg.SetParamFromStack( L, "Notes" ); + + LUA->Release( L ); MESSAGEMAN->Broadcast( msg ); } } -void Player::SetHoldJudgment( TapNoteScore tns, HoldNoteScore hns, int iTrack ) +void Player::SetHoldJudgment( TapNote &tn, int iTrack ) { ASSERT( iTrack < (int)m_vpHoldJudgment.size() ); if( m_vpHoldJudgment[iTrack] ) - m_vpHoldJudgment[iTrack]->SetHoldJudgment( hns ); + m_vpHoldJudgment[iTrack]->SetHoldJudgment( tn.HoldResult.hns ); if( m_bSendJudgmentAndComboMessages ) { @@ -3359,8 +3376,13 @@ void Player::SetHoldJudgment( TapNoteScore tns, HoldNoteScore hns, int iTrack ) msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp ); msg.SetParam( "FirstTrack", iTrack ); msg.SetParam( "NumTracks", (int)m_vpHoldJudgment.size() ); - msg.SetParam( "TapNoteScore", tns ); - msg.SetParam( "HoldNoteScore", hns ); + msg.SetParam( "TapNoteScore", tn.result.tns ); + msg.SetParam( "HoldNoteScore", tn.HoldResult.hns ); + + Lua* L = LUA->Get(); + tn.PushSelf(L); + msg.SetParamFromStack( L, "TapNote" ); + MESSAGEMAN->Broadcast( msg ); } } diff --git a/src/Player.h b/src/Player.h index a4b8b486f5..9d75b98235 100644 --- a/src/Player.h +++ b/src/Player.h @@ -132,9 +132,9 @@ protected: void PlayKeysound( const TapNote &tn, TapNoteScore score ); void SetMineJudgment( TapNoteScore tns , int iTrack ); - void SetJudgment( TapNoteScore tns, int iFirstTrack, float fTapNoteOffset ) { vector viCols (1,iFirstTrack); SetJudgment( tns, iFirstTrack, fTapNoteOffset, viCols ); } - void SetJudgment( TapNoteScore tns, int iFirstTrack, float fTapNoteOffset, vector viCols ); // -1 if no track as in TNS_Miss - void SetHoldJudgment( TapNoteScore tns, HoldNoteScore hns, int iTrack ); + void SetJudgment( int iRow, int iFirstTrack, const TapNote &tn ) { SetJudgment( iRow, iFirstTrack, tn, tn.result.tns, tn.result.fTapNoteOffset ); } + void SetJudgment( int iRow, int iFirstTrack, const TapNote &tn, TapNoteScore tns, float fTapNoteOffset ); // -1 if no track as in TNS_Miss + void SetHoldJudgment( TapNote &tn, int iTrack ); void SetCombo( int iCombo, int iMisses ); void ChangeLife( TapNoteScore tns ); From ec23dcb5039d39be87152d4a39c553954226538b Mon Sep 17 00:00:00 2001 From: sigatrev Date: Sat, 6 Sep 2014 15:40:46 -0500 Subject: [PATCH 2/3] fix major typo oops... --- src/Player.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Player.cpp b/src/Player.cpp index 5bbcdf14b1..ea07357e20 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -2803,7 +2803,6 @@ void Player::UpdateJudgedRows() SetJudgment( iRow, m_NoteData.GetFirstTrackWithTapOrHoldHead(iRow), NoteDataWithScoring::LastTapNoteWithResult( m_NoteData, iRow ) ); } HandleTapRowScore( iRow ); - HandleTapRowScore( iRow ); } } } From bcb258911498bc92c19d11efa7778982826625ee Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Wed, 10 Sep 2014 02:44:49 -0600 Subject: [PATCH 3/3] Fixed endless courses to make them repick on repeats and not crash after repeating. --- src/Course.cpp | 8 +++-- src/GameState.cpp | 5 ++++ src/GameState.h | 2 ++ src/ScreenGameplay.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/Course.cpp b/src/Course.cpp index 73528353e0..8b291d7b6a 100644 --- a/src/Course.cpp +++ b/src/Course.cpp @@ -404,6 +404,9 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) trail.Init(); // XXX: Why are beginner and challenge excluded here? -Wolfman2000 + // No idea, probably an obsolete design decision from ITG, removing + // exclusion here, but there's some other area that prevents it too. -Kyz + /* switch( cd ) { case Difficulty_Beginner: @@ -412,6 +415,7 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) return false; default: break; } + */ // Construct a new Trail, add it to the cache, then return it. // Different seed for each course, but the same for the whole round: @@ -848,9 +852,9 @@ bool Course::CourseHasBestOrWorst() const { FOREACH_CONST( CourseEntry, m_vEntries, e ) { - if( e->iChooseIndex == SongSort_MostPlays && e->iChooseIndex != -1 ) + if( e->songSort == SongSort_MostPlays && e->iChooseIndex != -1 ) return true; - if( e->iChooseIndex == SongSort_FewestPlays && e->iChooseIndex != -1 ) + if( e->songSort == SongSort_FewestPlays && e->iChooseIndex != -1 ) return true; } diff --git a/src/GameState.cpp b/src/GameState.cpp index eb993a701e..370cdb6ef3 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -2109,6 +2109,11 @@ Difficulty GameState::GetHardestStepsDifficulty() const return dc; } +void GameState::SetNewStageSeed() +{ + m_iStageSeed= rand(); +} + bool GameState::IsEventMode() const { return m_bTemporaryEventMode || PREFSMAN->m_bEventMode; diff --git a/src/GameState.h b/src/GameState.h index 3b6bf60345..3c463e0e69 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -117,6 +117,8 @@ public: int m_iGameSeed, m_iStageSeed; RString m_sStageGUID; + void SetNewStageSeed(); + /** * @brief Determine if a second player can join in at this time. * @return true if a player can still enter the game, false otherwise. */ diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index aff5d2b36a..2c1a96e36e 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -2618,6 +2618,72 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) pi->m_pLifeMeter->OnSongEnded(); } + // If this is a repeating course, and we're at the end of it, repick and + // add new songs to the players' step and song queues. + if(GAMESTATE->IsCourseMode() && GAMESTATE->m_pCurCourse && + GAMESTATE->m_pCurCourse->m_bRepeat && + GAMESTATE->GetCourseSongIndex() >= (int)m_apSongsQueue.size()-1) + { + Course* course= GAMESTATE->m_pCurCourse; + ASSERT(course != NULL); + // Need to store these so they can be used to refetch the players' + // trails after they're invalidated. + vector trail_sts; + vector trail_cds; + FOREACH_EnabledPlayerInfo(m_vPlayerInfo, pi) + { + Trail* trail= GAMESTATE->m_pCurTrail[pi->GetStepsAndTrailIndex()]; + ASSERT(trail != NULL); + trail_sts.push_back(trail->m_StepsType); + trail_cds.push_back(trail->m_CourseDifficulty); + } + // Set a new stage seed so the order will be different. + GAMESTATE->SetNewStageSeed(); + course->InvalidateTrailCache(); + course->RegenerateNonFixedTrails(); + size_t info_id= 0; // Can't use the player number in the playerinfo + // because it won't match up in 2-player. + FOREACH_EnabledPlayerInfo(m_vPlayerInfo, pi) + { + Trail* trail= course->GetTrail(trail_sts[info_id], trail_cds[info_id]); + ASSERT(trail != NULL); + GAMESTATE->m_pCurTrail[pi->m_pn].Set(trail); + ++info_id; + } + PlayerNumber master_pn = GAMESTATE->GetMasterPlayerNumber(); + Trail *master_trail= GAMESTATE->m_pCurTrail[master_pn]; + ASSERT(master_trail != NULL); + FOREACH_CONST(TrailEntry, master_trail->m_vEntries, entry) + { + ASSERT(entry->pSong != NULL); + m_apSongsQueue.push_back(entry->pSong); + STATSMAN->m_CurStageStats.m_vpPossibleSongs.push_back(entry->pSong); + } + FOREACH_EnabledPlayerInfo(m_vPlayerInfo, pi) + { + Trail* trail= GAMESTATE->m_pCurTrail[pi->GetStepsAndTrailIndex()]; + ASSERT(trail != NULL); + FOREACH_CONST(TrailEntry, trail->m_vEntries, entry) + { + ASSERT(entry->pSteps != NULL); + pi->m_vpStepsQueue.push_back(entry->pSteps); + AttackArray a; + entry->GetAttackArray(a); + pi->m_asModifiersQueue.push_back(a); + pi->GetPlayerStageStats()->m_vpPossibleSteps.push_back(entry->pSteps); + } + // In a survival course, override stored mods + if(course->GetCourseType() == COURSE_TYPE_SURVIVAL && + SURVIVAL_MOD_OVERRIDE) + { + pi->GetPlayerState()->m_PlayerOptions.FromString(ModsLevel_Stage, + "clearall," + CommonMetrics::DEFAULT_NOTESKIN_NAME.GetValue() + + "," + CommonMetrics::DEFAULT_MODIFIERS.GetValue()); + pi->GetPlayerState()->RebuildPlayerOptionsFromActiveAttacks(); + } + } + } + GAMESTATE->m_bLoadingNextSong = true; MESSAGEMAN->Broadcast( "BeforeLoadingNextCourseSong" ); m_NextSong.Reset();