diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml
index d523d5514c..7686476a35 100644
--- a/Docs/Luadoc/Lua.xml
+++ b/Docs/Luadoc/Lua.xml
@@ -1641,6 +1641,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml
index b78ceba84d..912176d889 100644
--- a/Docs/Luadoc/LuaDocumentation.xml
+++ b/Docs/Luadoc/LuaDocumentation.xml
@@ -4643,6 +4643,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/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/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..ea07357e20 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,22 +2795,12 @@ 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 );
}
@@ -3245,7 +3234,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 +3319,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 +3329,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 +3375,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 );
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();