SM4SVN commits, all code by Chris Danford:

* 57e8159: fix handling of noteskins with an uppercase letter
* 3be4d7e: track W4 full combo
* f8270c6: draw glow using stroke texture
This commit is contained in:
AJ Kelly
2010-03-09 03:22:58 -06:00
parent 4d50f8da6e
commit 8ba30b523c
3 changed files with 102 additions and 77 deletions
+2
View File
@@ -697,7 +697,9 @@ void BitmapText::DrawPrimitives()
for( ; i < iEnd; ++i ) for( ; i < iEnd; ++i )
m_aVertices[i].c = attr.glow; m_aVertices[i].c = attr.glow;
} }
// draw glow using the base texture and the glow texture. Otherwise, glow looks too tame on BitmapText that has a stroke.
DrawChars( false ); DrawChars( false );
DrawChars( true );
} }
} }
+43 -37
View File
@@ -77,15 +77,15 @@ void NoteField::Unload()
void NoteField::CacheNoteSkin( const RString &sNoteSkin_ ) void NoteField::CacheNoteSkin( const RString &sNoteSkin_ )
{ {
RString sNoteSkin = sNoteSkin_; RString sNoteSkinLower = sNoteSkin_;
sNoteSkin.MakeLower(); sNoteSkinLower.MakeLower();
if( m_NoteDisplays.find(sNoteSkin) != m_NoteDisplays.end() ) if( m_NoteDisplays.find(sNoteSkinLower) != m_NoteDisplays.end() )
return; return;
LockNoteSkin l( sNoteSkin ); LockNoteSkin l( sNoteSkinLower );
LOG->Trace("NoteField::CacheNoteSkin: cache %s", sNoteSkin.c_str() ); LOG->Trace("NoteField::CacheNoteSkin: cache %s", sNoteSkinLower.c_str() );
NoteDisplayCols *nd = new NoteDisplayCols( GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer ); NoteDisplayCols *nd = new NoteDisplayCols( GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer );
for( int c=0; c<GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer; c++ ) for( int c=0; c<GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer; c++ )
@@ -93,26 +93,22 @@ void NoteField::CacheNoteSkin( const RString &sNoteSkin_ )
nd->m_ReceptorArrowRow.Load( m_pPlayerState, m_fYReverseOffsetPixels ); nd->m_ReceptorArrowRow.Load( m_pPlayerState, m_fYReverseOffsetPixels );
nd->m_GhostArrowRow.Load( m_pPlayerState, m_fYReverseOffsetPixels ); nd->m_GhostArrowRow.Load( m_pPlayerState, m_fYReverseOffsetPixels );
m_NoteDisplays[ sNoteSkin ] = nd; m_NoteDisplays[ sNoteSkinLower ] = nd;
} }
void NoteField::UncacheNoteSkin( const RString &sNoteSkin_ ) void NoteField::UncacheNoteSkin( const RString &sNoteSkin_ )
{ {
RString sNoteSkin( sNoteSkin_ ); RString sNoteSkinLower = sNoteSkin_;
sNoteSkin.MakeLower(); sNoteSkinLower.MakeLower();
LOG->Trace("NoteField::CacheNoteSkin: release %s", sNoteSkin.c_str() ); LOG->Trace("NoteField::CacheNoteSkin: release %s", sNoteSkinLower.c_str() );
ASSERT_M( m_NoteDisplays.find(sNoteSkin) != m_NoteDisplays.end(), sNoteSkin ); ASSERT_M( m_NoteDisplays.find(sNoteSkinLower) != m_NoteDisplays.end(), sNoteSkinLower );
delete m_NoteDisplays[sNoteSkin]; delete m_NoteDisplays[sNoteSkinLower];
m_NoteDisplays.erase( sNoteSkin ); m_NoteDisplays.erase( sNoteSkinLower );
} }
void NoteField::CacheAllUsedNoteSkins() void NoteField::CacheAllUsedNoteSkins()
{ {
/* Cache all note skins that we might need for the whole song, course or battle
* play, so we don't have to load them later (such as between course songs). */
vector<RString> asSkins;
// If we're in Routine mode, apply our per-player noteskins. // If we're in Routine mode, apply our per-player noteskins.
if( GAMESTATE->GetCurrentStyle()->m_StyleType == StyleType_TwoPlayersSharedSides ) if( GAMESTATE->GetCurrentStyle()->m_StyleType == StyleType_TwoPlayersSharedSides )
{ {
@@ -120,32 +116,43 @@ void NoteField::CacheAllUsedNoteSkins()
GAMESTATE->ApplyStageModifiers( pn, ROUTINE_NOTESKIN.GetValue(pn) ); GAMESTATE->ApplyStageModifiers( pn, ROUTINE_NOTESKIN.GetValue(pn) );
} }
GAMESTATE->GetAllUsedNoteSkins( asSkins ); /* Cache all note skins that we might need for the whole song, course or battle
asSkins.push_back( m_pPlayerState->m_PlayerOptions.GetStage().m_sNoteSkin ); * play, so we don't have to load them later (such as between course songs). */
vector<RString> asSkinsLower;
GAMESTATE->GetAllUsedNoteSkins( asSkinsLower );
asSkinsLower.push_back( m_pPlayerState->m_PlayerOptions.GetStage().m_sNoteSkin );
FOREACH( RString, asSkinsLower, s )
s->MakeLower();
for( unsigned i=0; i < asSkins.size(); ++i ) for( unsigned i=0; i < asSkinsLower.size(); ++i )
CacheNoteSkin( asSkins[i] ); CacheNoteSkin( asSkinsLower[i] );
/* If we're changing note skins in the editor, we can have old note skins /* If we're changing note skins in the editor, we can have old note skins lying
* lying around. Remove them so they don't accumulate. */ * around. Remove them so they don't accumulate. */
set<RString> setNoteSkinsToUnload; set<RString> setNoteSkinsToUnload;
FOREACHM( RString, NoteDisplayCols *, m_NoteDisplays, d ) FOREACHM( RString, NoteDisplayCols *, m_NoteDisplays, d )
{ {
if( find(asSkins.begin(), asSkins.end(), d->first) == asSkins.end() ) bool unused = find(asSkinsLower.begin(), asSkinsLower.end(), d->first) == asSkinsLower.end();
if( unused )
setNoteSkinsToUnload.insert( d->first ); setNoteSkinsToUnload.insert( d->first );
} }
FOREACHS( RString, setNoteSkinsToUnload, s ) FOREACHS( RString, setNoteSkinsToUnload, s )
UncacheNoteSkin( *s ); UncacheNoteSkin( *s );
map<RString, NoteDisplayCols *>::iterator it = m_NoteDisplays.find( m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin ); RString sCurrentNoteSkinLower = m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin;
ASSERT_M( it != m_NoteDisplays.end(), m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin ); sCurrentNoteSkinLower.MakeLower();
map<RString, NoteDisplayCols *>::iterator it = m_NoteDisplays.find( sCurrentNoteSkinLower );
ASSERT_M( it != m_NoteDisplays.end(), sCurrentNoteSkinLower );
m_pCurDisplay = it->second; m_pCurDisplay = it->second;
memset( m_pDisplays, 0, sizeof(m_pDisplays) ); memset( m_pDisplays, 0, sizeof(m_pDisplays) );
FOREACH_EnabledPlayer( pn ) FOREACH_EnabledPlayer( pn )
{ {
const RString& sNoteSkin = GAMESTATE->m_pPlayerState[pn]->m_PlayerOptions.GetCurrent().m_sNoteSkin; RString sNoteSkinLower = GAMESTATE->m_pPlayerState[pn]->m_PlayerOptions.GetCurrent().m_sNoteSkin;
it = m_NoteDisplays.find( sNoteSkin ); sNoteSkinLower.MakeLower();
ASSERT_M( it != m_NoteDisplays.end(), sNoteSkin ); it = m_NoteDisplays.find( sNoteSkinLower );
ASSERT_M( it != m_NoteDisplays.end(), sNoteSkinLower );
m_pDisplays[pn] = it->second; m_pDisplays[pn] = it->second;
} }
} }
@@ -177,16 +184,17 @@ void NoteField::Load(
ssprintf("%d = %d",m_pNoteData->GetNumTracks(), GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer) ); ssprintf("%d = %d",m_pNoteData->GetNumTracks(), GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer) );
// The note skin may have changed at the beginning of a new course song. // The note skin may have changed at the beginning of a new course song.
map<RString, NoteDisplayCols *>::iterator it = m_NoteDisplays.find( m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin ); RString sNoteSkinLower = m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin;
ASSERT_M( it != m_NoteDisplays.end(), sNoteSkinLower.MakeLower();
ssprintf("Player noteskin: %s", m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin.c_str()) ); map<RString, NoteDisplayCols *>::iterator it = m_NoteDisplays.find( sNoteSkinLower );
m_pCurDisplay = it->second; ASSERT_M( it != m_NoteDisplays.end(), sNoteSkinLower );
memset( m_pDisplays, 0, sizeof(m_pDisplays) ); memset( m_pDisplays, 0, sizeof(m_pDisplays) );
FOREACH_EnabledPlayer( pn ) FOREACH_EnabledPlayer( pn )
{ {
const RString& sNoteSkin = GAMESTATE->m_pPlayerState[pn]->m_PlayerOptions.GetCurrent().m_sNoteSkin; RString sNoteSkinLower = GAMESTATE->m_pPlayerState[pn]->m_PlayerOptions.GetCurrent().m_sNoteSkin;
it = m_NoteDisplays.find( sNoteSkin ); sNoteSkinLower.MakeLower();
ASSERT_M( it != m_NoteDisplays.end(), sNoteSkin ); it = m_NoteDisplays.find( sNoteSkinLower );
ASSERT_M( it != m_NoteDisplays.end(), sNoteSkinLower );
m_pDisplays[pn] = it->second; m_pDisplays[pn] = it->second;
} }
} }
@@ -686,9 +694,7 @@ void NoteField::DrawPrimitives()
// todo: add warp text // todo: add warp text
//
// Course mods text // Course mods text
//
const Course *pCourse = GAMESTATE->m_pCurCourse; const Course *pCourse = GAMESTATE->m_pCurCourse;
if( pCourse ) if( pCourse )
{ {
+55 -38
View File
@@ -611,8 +611,7 @@ void Player::Update( float fDeltaTime )
if(m_pPlayerState->m_mp != MultiPlayer_Invalid) if(m_pPlayerState->m_mp != MultiPlayer_Invalid)
{ {
/* /* In multiplayer, it takes too long to run player updates for every player each frame;
* In multiplayer, it takes too long to run player updates for every player each frame;
* with 32 players and three difficulties, we have 96 Players to update. Stagger these * with 32 players and three difficulties, we have 96 Players to update. Stagger these
* updates, by only updating a few players each update; since we don't have screen elements * updates, by only updating a few players each update; since we don't have screen elements
* tightly tied to user actions in this mode, this doesn't degrade gameplay. Run 4 players * tightly tied to user actions in this mode, this doesn't degrade gameplay. Run 4 players
@@ -901,7 +900,7 @@ void Player::Update( float fDeltaTime )
ApplyWaitingTransforms(); 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<TrackRowTapNote> &vTN ) void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTapNote> &vTN )
{ {
ASSERT( !vTN.empty() ); ASSERT( !vTN.empty() );
@@ -1026,9 +1025,10 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTap
if( bInitiatedNote && fLife != 0 ) if( bInitiatedNote && fLife != 0 )
{ {
/* This hold note is not judged and we stepped on its head. Update iLastHeldRow. /* This hold note is not judged and we stepped on its head.
* Do this even if we're a little beyond the end of the hold note, to make sure * Update iLastHeldRow. Do this even if we're a little beyond the end
* iLastHeldRow is clamped to iEndRow if the hold note is held all the way. */ * of the hold note, to make sure iLastHeldRow is clamped to iEndRow
* if the hold note is held all the way. */
FOREACH( TrackRowTapNote, vTN, trtn ) FOREACH( TrackRowTapNote, vTN, trtn )
{ {
TapNote &tn = *trtn->pTN; TapNote &tn = *trtn->pTN;
@@ -1098,8 +1098,9 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTap
m_pSecondaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate ); m_pSecondaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate );
} }
/* check for LetGo. If the head was missed completely, don't count an LetGo. */ // check for LetGo. If the head was missed completely, don't count an LetGo.
/* Why? If you never step on the head, then it will be left as HNS_None, which doesn't seem correct. */ /* Why? If you never step on the head, then it will be left as HNS_None,
* which doesn't seem correct. */
if( IMMEDIATE_HOLD_LET_GO ) if( IMMEDIATE_HOLD_LET_GO )
{ {
if( bInitiatedNote && fLife == 0 ) // the player has not pressed the button for a long time! if( bInitiatedNote && fLife == 0 ) // the player has not pressed the button for a long time!
@@ -1111,9 +1112,9 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTap
{ {
bool bLetGoOfHoldNote = false; bool bLetGoOfHoldNote = false;
/* Score rolls that end with fLife == 0 as LetGo, even if HOLD_CHECKPOINTS is on. /* Score rolls that end with fLife == 0 as LetGo, even if
* Rolls don't have iCheckpointsMissed set, so, unless we check Life == 0, rolls would always be * HOLD_CHECKPOINTS is on. Rolls don't have iCheckpointsMissed set, so,
* scored as Held. */ * unless we check Life == 0, rolls would always be scored as Held. */
bool bAllowHoldCheckpoints; bool bAllowHoldCheckpoints;
switch( subType ) switch( subType )
{ {
@@ -1142,7 +1143,8 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTap
} }
bLetGoOfHoldNote = iCheckpointsMissed > 0 || iCheckpointsHit == 0; bLetGoOfHoldNote = iCheckpointsMissed > 0 || iCheckpointsHit == 0;
// TRICKY: If the hold is so short that it has no checkpoints, then mark it as Held if the head was stepped on. // TRICKY: If the hold is so short that it has no checkpoints,
// then mark it as Held if the head was stepped on.
if( iCheckpointsHit == 0 && iCheckpointsMissed == 0 ) if( iCheckpointsHit == 0 && iCheckpointsMissed == 0 )
bLetGoOfHoldNote = !bSteppedOnHead; bLetGoOfHoldNote = !bSteppedOnHead;
} }
@@ -1387,7 +1389,7 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool
if( !bForward ) if( !bForward )
--begin; --begin;
/* Is this the row we want? */ // Is this the row we want?
do { do {
const TapNote &tn = begin->second; const TapNote &tn = begin->second;
if( tn.type == TapNote::empty ) if( tn.type == TapNote::empty )
@@ -1405,7 +1407,7 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool
return -1; return -1;
} }
/* Find the closest note to fBeat. */ // Find the closest note to fBeat.
int Player::GetClosestNote( int col, int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const int Player::GetClosestNote( int col, int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const
{ {
// Start at iIndexStartLookingAt and search outward. // Start at iIndexStartLookingAt and search outward.
@@ -1460,7 +1462,7 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b
return -1; return -1;
} }
/* Find the closest note to fBeat. */ // Find the closest note to fBeat.
int Player::GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const int Player::GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const
{ {
// Start at iIndexStartLookingAt and search outward. // Start at iIndexStartLookingAt and search outward.
@@ -1504,7 +1506,6 @@ void Player::Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
StepStrumHopo( col, row, tm, bHeld, bRelease, ButtonType_StrumFretsChanged ); StepStrumHopo( col, row, tm, bHeld, bRelease, ButtonType_StrumFretsChanged );
} }
// Handle hammer-ons and pull-offs // Handle hammer-ons and pull-offs
const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago(); const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago();
int iHopoCol = -1; int iHopoCol = -1;
@@ -1556,7 +1557,6 @@ void Player::Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRele
if( bDoHopo ) if( bDoHopo )
Hopo( iHopoCol, row, tm, bHeld, bRelease ); Hopo( iHopoCol, row, tm, bHeld, bRelease );
// Check if this fret breaks all active holds. // Check if this fret breaks all active holds.
if( !bRelease ) if( !bRelease )
{ {
@@ -1683,7 +1683,8 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
if( IsOniDead() ) if( IsOniDead() )
return; return;
// Do everything that depends on a RageTimer here and set your breakpoints somewhere after this block // Do everything that depends on a RageTimer here;
// set your breakpoints somewhere after this block.
const float fLastBeatUpdate = GAMESTATE->m_LastBeatUpdate.Ago(); const float fLastBeatUpdate = GAMESTATE->m_LastBeatUpdate.Ago();
const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago(); const float fPositionSeconds = GAMESTATE->m_fMusicSeconds - tm.Ago();
const float fTimeSinceStep = tm.Ago(); const float fTimeSinceStep = tm.Ago();
@@ -1824,13 +1825,17 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
} }
// Check for step on a TapNote // Check for step on a TapNote
/* XXX: This seems wrong. If a player steps twice quickly and two notes are close together in the same column then /* XXX: This seems wrong. If a player steps twice quickly and two notes are
* it is possible for the two notes to be graded out of order. Two possible fixes: * close together in the same column then it is possible for the two notes
* 1. Adjust the fSongBeat (or the resulting note row) backward by iStepSearchRows and search forward two iStepSearchRows * to be graded out of order.
* lengths, disallowing graded. This doesn't seem right because if a second note has passed, an earlier one should not * Two possible fixes:
* be graded. * 1. Adjust the fSongBeat (or the resulting note row) backward by
* iStepSearchRows and search forward two iStepSearchRows lengths,
* disallowing graded. This doesn't seem right because if a second note has
* passed, an earlier one should not be graded.
* 2. Clamp the distance searched backward to the previous row graded. * 2. Clamp the distance searched backward to the previous row graded.
* Either option would fundamentally change the grading of two quick notes "jack hammers." Hmm. * Either option would fundamentally change the grading of two quick notes
* "jack hammers." Hmm.
*/ */
const int iStepSearchRows = BeatToNoteRow( StepSearchDistance * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate ); const int iStepSearchRows = BeatToNoteRow( StepSearchDistance * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate );
int iRowOfOverlappingNoteOrRow = row; int iRowOfOverlappingNoteOrRow = row;
@@ -1910,7 +1915,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
case TapNote::attack: case TapNote::attack:
if( !bRelease && fSecondsFromExact <= GetWindowSeconds(TW_Attack) && !pTN->result.bHidden ) if( !bRelease && fSecondsFromExact <= GetWindowSeconds(TW_Attack) && !pTN->result.bHidden )
score = TNS_W2; /* sentinel */ score = TNS_W2; // sentinel
break; break;
case TapNote::hold_head: case TapNote::hold_head:
@@ -1937,7 +1942,8 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
case PC_AUTOPLAY: case PC_AUTOPLAY:
score = PlayerAI::GetTapNoteScore( m_pPlayerState ); score = PlayerAI::GetTapNoteScore( m_pPlayerState );
/* XXX: This doesn't make sense. Step should only be called in autoplay for hit notes */ /* XXX: This doesn't make sense.
* Step should only be called in autoplay for hit notes. */
#if 0 #if 0
// GetTapNoteScore always returns TNS_W1 in autoplay. // GetTapNoteScore always returns TNS_W1 in autoplay.
// If the step is far away, don't judge it. // If the step is far away, don't judge it.
@@ -1949,12 +1955,12 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
} }
#endif #endif
// TRICKY: We're asking the AI to judge mines. consider TNS_W4 and below // TRICKY: We're asking the AI to judge mines. Consider TNS_W4 and
// as "mine was hit" and everything else as "mine was avoided" // below as "mine was hit" and everything else as "mine was avoided"
if( pTN->type == TapNote::mine ) if( pTN->type == TapNote::mine )
{ {
// The CPU hits a lot of mines. Only consider hitting the // The CPU hits a lot of mines. Only consider hitting the
// first mine for a row. We know we're the first mine if // first mine for a row. We know we're the first mine if
// there are are no mines to the left of us. // there are are no mines to the left of us.
for( int t=0; t<col; t++ ) for( int t=0; t<col; t++ )
{ {
@@ -1962,7 +1968,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
return; // avoid return; // avoid
} }
// The CPU hits a lot of mines. Make it less likely to hit // The CPU hits a lot of mines. Make it less likely to hit
// mines that don't have a tap note on the same row. // mines that don't have a tap note on the same row.
bool bTapsOnRow = m_NoteData.IsThereATapOrHoldHeadAtRow( iRowOfOverlappingNoteOrRow ); bool bTapsOnRow = m_NoteData.IsThereATapOrHoldHeadAtRow( iRowOfOverlappingNoteOrRow );
TapNoteScore get_to_avoid = bTapsOnRow ? TNS_W3 : TNS_W4; TapNoteScore get_to_avoid = bTapsOnRow ? TNS_W3 : TNS_W4;
@@ -1974,7 +1980,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
} }
if( pTN->type == TapNote::attack && score > TNS_W4 ) if( pTN->type == TapNote::attack && score > TNS_W4 )
score = TNS_W2; /* sentinel */ score = TNS_W2; // sentinel
/* AI will generate misses here. Don't handle a miss like a regular note because /* AI will generate misses here. Don't handle a miss like a regular note because
* we want the judgment animation to appear delayed. Instead, return early if * we want the judgment animation to appear delayed. Instead, return early if
@@ -2107,7 +2113,7 @@ done_checking_hopo:
break; break;
} }
// handle attack notes
if( pTN->type == TapNote::attack && score == TNS_W2 ) if( pTN->type == TapNote::attack && score == TNS_W2 )
{ {
score = TNS_None; // don't score this as anything score = TNS_None; // don't score this as anything
@@ -2178,7 +2184,8 @@ done_checking_hopo:
if( pTN->type != TapNote::mine ) if( pTN->type != TapNote::mine )
{ {
const bool bBlind = (m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind != 0); const bool bBlind = (m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind != 0);
// XXX This is the wrong combo for shared players. STATSMAN->m_CurStageStats.m_Player[pn] might work but could be wrong. // XXX: This is the wrong combo for shared players.
// STATSMAN->m_CurStageStats.m_Player[pn] might work, but could be wrong.
const bool bBright = ( m_pPlayerStageStats && m_pPlayerStageStats->m_iCurCombo > int(BRIGHT_GHOST_COMBO_THRESHOLD) ) || bBlind; const bool bBright = ( m_pPlayerStageStats && m_pPlayerStageStats->m_iCurCombo > int(BRIGHT_GHOST_COMBO_THRESHOLD) ) || bBlind;
if( m_pNoteField ) if( m_pNoteField )
m_pNoteField->DidTapNote( col, bBlind? TNS_W1:score, bBright ); m_pNoteField->DidTapNote( col, bBlind? TNS_W1:score, bBright );
@@ -2359,6 +2366,7 @@ void Player::UpdateJudgedRows()
bool bAllJudged = true; bool bAllJudged = true;
const bool bSeparately = GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately; const bool bSeparately = GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately;
// todo: modify function for warps? -aj
{ {
NoteData::all_tracks_iterator iter = *m_pIterUnjudgedRows; NoteData::all_tracks_iterator iter = *m_pIterUnjudgedRows;
int iLastSeenRow = -1; int iLastSeenRow = -1;
@@ -2366,6 +2374,12 @@ void Player::UpdateJudgedRows()
{ {
int iRow = iter.Row(); int iRow = iter.Row();
// if row is in a skip section, ignore it? -aj
//if(iRow)
//{
// // stuff!!
//}
if( iLastSeenRow != iRow ) if( iLastSeenRow != iRow )
{ {
iLastSeenRow = iRow; iLastSeenRow = iRow;
@@ -2402,6 +2416,7 @@ void Player::UpdateJudgedRows()
} }
} }
// handle mines.
{ {
bAllJudged = true; bAllJudged = true;
set<RageSound *> setSounds; set<RageSound *> setSounds;
@@ -2995,7 +3010,7 @@ void Player::SetCombo( int iCombo, int iMisses )
this->PlayCommand( "ThousandMilestone" ); this->PlayCommand( "ThousandMilestone" );
// don't show a colored combo until 1/4 of the way through the song // don't show a colored combo until 1/4 of the way through the song
bool bPastMidpoint = GAMESTATE->GetCourseSongIndex()>0 || bool bPastBeginning = (!GAMESTATE->IsCourseMode() || GAMESTATE->GetCourseSongIndex()>0) &&
GAMESTATE->m_fMusicSeconds > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds/4; GAMESTATE->m_fMusicSeconds > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds/4;
if( m_bSendJudgmentAndComboMessages ) if( m_bSendJudgmentAndComboMessages )
@@ -3005,12 +3020,14 @@ void Player::SetCombo( int iCombo, int iMisses )
msg.SetParam( "Combo", iCombo ); msg.SetParam( "Combo", iCombo );
if( iMisses ) if( iMisses )
msg.SetParam( "Misses", iMisses ); msg.SetParam( "Misses", iMisses );
if( bPastMidpoint && m_pPlayerStageStats->FullComboOfScore(TNS_W1) ) if( bPastPastBeginning && m_pPlayerStageStats->FullComboOfScore(TNS_W1) )
msg.SetParam( "FullComboW1", true ); msg.SetParam( "FullComboW1", true );
if( bPastMidpoint && m_pPlayerStageStats->FullComboOfScore(TNS_W2) ) if( bPastPastBeginning && m_pPlayerStageStats->FullComboOfScore(TNS_W2) )
msg.SetParam( "FullComboW2", true ); msg.SetParam( "FullComboW2", true );
if( bPastMidpoint && m_pPlayerStageStats->FullComboOfScore(TNS_W3) ) if( bPastPastBeginning && m_pPlayerStageStats->FullComboOfScore(TNS_W3) )
msg.SetParam( "FullComboW3", true ); msg.SetParam( "FullComboW3", true );
if( bPastPastBeginning && m_pPlayerStageStats->FullComboOfScore(TNS_W4) )
msg.SetParam( "FullComboW4", true );
this->HandleMessage( msg ); this->HandleMessage( msg );
} }
} }