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:
@@ -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
@@ -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
@@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user