fix "transform mods that last for a whole song in a course get applied twice"

fix "impossible to get 100% on a course that uses AddMines" by calculating RadarValues after applying mods
Trail::GetRadarValues needs to do caching.  Performance is bad.
This commit is contained in:
Chris Danford
2004-07-23 04:45:48 +00:00
parent 23cedc1b83
commit 27ece3ecbf
11 changed files with 154 additions and 59 deletions
+21 -1
View File
@@ -3,9 +3,12 @@
#include "GameState.h" #include "GameState.h"
#include "RageUtil.h" #include "RageUtil.h"
#include "song.h" #include "song.h"
#include "Foreach.h"
void Attack::GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBeat, float &fEndBeat ) const void Attack::GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBeat, float &fEndBeat ) const
{ {
ASSERT( song );
if( fStartSecond >= 0 ) if( fStartSecond >= 0 )
{ {
CHECKPOINT; CHECKPOINT;
@@ -19,7 +22,7 @@ void Attack::GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBea
ASSERT( GAMESTATE->m_pCurSong ); ASSERT( GAMESTATE->m_pCurSong );
/* We're setting this effect on the fly. If it's an arrow-changing effect /* We're setting this effect on the fly. If it's an arrow-changing effect
* (transform or note skin), apply it in the future, past what's currently on * (transform or note skin), apply it in the future, after what's currently on
* screen, so new arrows will scroll on screen with this effect. */ * screen, so new arrows will scroll on screen with this effect. */
GAMESTATE->GetUndisplayedBeats( pn, fSecsRemaining, fStartBeat, fEndBeat ); GAMESTATE->GetUndisplayedBeats( pn, fSecsRemaining, fStartBeat, fEndBeat );
} }
@@ -39,6 +42,23 @@ bool Attack::operator== ( const Attack &rhs ) const
EQUAL(bGlobal); EQUAL(bGlobal);
} }
bool Attack::ContainsTransformOrTurn() const
{
PlayerOptions po;
po.FromString( sModifier );
return po.ContainsTransformOrTurn();
}
bool AttackArray::ContainsTransformOrTurn() const
{
FOREACH_CONST( Attack, *this, a )
{
if( a->ContainsTransformOrTurn() )
return true;
}
return false;
}
/* /*
* (c) 2003-2004 Chris Danford * (c) 2003-2004 Chris Danford
* All rights reserved. * All rights reserved.
+6 -1
View File
@@ -19,8 +19,13 @@ struct Attack
void MakeBlank() { sModifier=""; } void MakeBlank() { sModifier=""; }
Attack() { fStartSecond = -1; bOn = false; bGlobal = false; } Attack() { fStartSecond = -1; bOn = false; bGlobal = false; }
bool operator== ( const Attack &rhs ) const; bool operator== ( const Attack &rhs ) const;
bool ContainsTransformOrTurn() const;
};
struct AttackArray : public vector<Attack>
{
bool ContainsTransformOrTurn() const;
}; };
typedef vector<Attack> AttackArray;
#endif #endif
+17
View File
@@ -6,6 +6,7 @@
#include "song.h" #include "song.h"
#include "GameState.h" #include "GameState.h"
#include "RadarValues.h" #include "RadarValues.h"
#include "Foreach.h"
NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex ) NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex )
{ {
@@ -1551,6 +1552,22 @@ void NoteDataUtil::ConvertAdditionsToRegular( NoteData &in )
in.SetTapNote(t,r,TAP_TAP); in.SetTapNote(t,r,TAP_TAP);
} }
void NoteDataUtil::TransformNoteData( NoteData &nd, const AttackArray &aa, StepsType st, Song* pSong )
{
FOREACH_CONST( Attack, aa, a )
{
PlayerOptions po;
po.FromString( a->sModifier );
if( po.ContainsTransformOrTurn() )
{
float fStartBeat, fEndBeat;
a->GetAttackBeats( pSong, PLAYER_INVALID, fStartBeat, fEndBeat );
NoteDataUtil::TransformNoteData( nd, po, st, fStartBeat, fEndBeat );
}
}
}
void NoteDataUtil::TransformNoteData( NoteData &nd, const PlayerOptions &po, StepsType st, float fStartBeat, float fEndBeat ) void NoteDataUtil::TransformNoteData( NoteData &nd, const PlayerOptions &po, StepsType st, float fStartBeat, float fEndBeat )
{ {
if( po.m_bTurns[PlayerOptions::TURN_MIRROR] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::mirror, fStartBeat, fEndBeat ); if( po.m_bTurns[PlayerOptions::TURN_MIRROR] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::mirror, fStartBeat, fEndBeat );
+1
View File
@@ -84,6 +84,7 @@ namespace NoteDataUtil
// True if no notes in row that aren't true in the mask // True if no notes in row that aren't true in the mask
bool RowPassesValidMask( NoteData &in, int row, const bool bValidMask[] ); bool RowPassesValidMask( NoteData &in, int row, const bool bValidMask[] );
void TransformNoteData( NoteData &nd, const AttackArray &aa, StepsType st, Song* pSong );
void TransformNoteData( NoteData &nd, const PlayerOptions &po, StepsType st, float fStartBeat = 0, float fEndBeat = 99999 ); void TransformNoteData( NoteData &nd, const PlayerOptions &po, StepsType st, float fStartBeat = 0, float fEndBeat = 99999 );
void AddTapAttacks( NoteData &nd, Song* pSong ); void AddTapAttacks( NoteData &nd, Song* pSong );
+19 -3
View File
@@ -179,7 +179,6 @@ CString PlayerOptions::GetString() const
* you don't want this. */ * you don't want this. */
void PlayerOptions::FromString( CString sOptions ) void PlayerOptions::FromString( CString sOptions )
{ {
ASSERT( GAMESTATE->m_pPosition );
ASSERT( NOTESKIN ); ASSERT( NOTESKIN );
// Init(); // Init();
sOptions.MakeLower(); sOptions.MakeLower();
@@ -299,11 +298,13 @@ void PlayerOptions::FromString( CString sOptions )
else if( sBit == "space" ) { m_fSkew = level; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } else if( sBit == "space" ) { m_fSkew = level; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
else if( sBit == "hallway" ) { m_fSkew = 0; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } else if( sBit == "hallway" ) { m_fSkew = 0; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
else if( sBit == "distant" ) { m_fSkew = 0; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } else if( sBit == "distant" ) { m_fSkew = 0; m_fPerspectiveTilt = +level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
else if( GAMESTATE->m_pPosition->IsValidModeForAnyStyle(sBit) ) else if( GAMESTATE->m_pPosition && GAMESTATE->m_pPosition->IsValidModeForAnyStyle(sBit) )
// The only time we'll be in this function and NOTESKIN isn't created is
// when calculating RadarValues for courses with transform mods.
m_sPositioning = sBit; m_sPositioning = sBit;
else if( sBit == "nopositioning" ) else if( sBit == "nopositioning" )
m_sPositioning = ""; m_sPositioning = "";
else if( NOTESKIN->DoesNoteSkinExist(sBit) ) else if( NOTESKIN && NOTESKIN->DoesNoteSkinExist(sBit) )
m_sNoteSkin = sBit; m_sNoteSkin = sBit;
else if( sBit == "noteskin" && !on ) /* "no noteskin" */ else if( sBit == "noteskin" && !on ) /* "no noteskin" */
m_sNoteSkin = "default"; m_sNoteSkin = "default";
@@ -620,6 +621,21 @@ CString PlayerOptions::GetThemedString() const
return join( ", ", asThemedMods ); return join( ", ", asThemedMods );
} }
bool PlayerOptions::ContainsTransformOrTurn() const
{
for( int i=0; i<NUM_TRANSFORMS; i++ )
{
if( m_bTransforms[i] )
return true;
}
for( int i=0; i<NUM_TURNS; i++ )
{
if( m_bTurns[i] )
return true;
}
return false;
}
/* /*
* (c) 2001-2004 Chris Danford, Glenn Maynard * (c) 2001-2004 Chris Danford, Glenn Maynard
* All rights reserved. * All rights reserved.
+1
View File
@@ -20,6 +20,7 @@ struct PlayerOptions
CString GetThemedString() const; CString GetThemedString() const;
void FromString( CString sOptions ); void FromString( CString sOptions );
void ChooseRandomMofifiers(); void ChooseRandomMofifiers();
bool ContainsTransformOrTurn() const;
bool operator==( const PlayerOptions &other ) const; bool operator==( const PlayerOptions &other ) const;
bool operator!=( const PlayerOptions &other ) const { return !operator==(other); } bool operator!=( const PlayerOptions &other ) const { return !operator==(other); }
+18 -23
View File
@@ -28,42 +28,37 @@ ScoreKeeperMAX2::ScoreKeeperMAX2( const vector<Song*>& apSongs, const vector<Ste
{ {
Song* pSong = apSongs[i]; Song* pSong = apSongs[i];
Steps* pSteps = apSteps[i]; Steps* pSteps = apSteps[i];
NoteData notedata; const AttackArray &aa = asModifiers[i];
pSteps->GetNoteData( &notedata ); NoteData ndTemp;
pSteps->GetNoteData( &ndTemp );
/* We might have been given lots of songs; don't keep them in memory uncompressed. */ /* We might have been given lots of songs; don't keep them in memory uncompressed. */
pSteps->Compress(); pSteps->Compress();
const Style* pStyle = GAMESTATE->GetCurrentStyle(); const Style* pStyle = GAMESTATE->GetCurrentStyle();
NoteData playerNoteData; NoteData nd;
pStyle->GetTransformedNoteDataForStyle( pn_, &notedata, &playerNoteData ); pStyle->GetTransformedNoteDataForStyle( pn_, &ndTemp, &nd );
/* Apply transforms to find out how the notes will really look. /* Compute RadarValues before applying any user-selected mods. Apply
* Course mods and count them in the "pre" RadarValues because they're
* forced and not chosen by the user.
*/
NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong );
RadarValues rvPre;
NoteDataUtil::GetRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre );
/* Apply user transforms to find out how the notes will really look.
* *
* XXX: This is brittle: if we end up combining mods for a song differently * XXX: This is brittle: if we end up combining mods for a song differently
* than ScreenGameplay, we'll end up with the wrong data. We should probably * than ScreenGameplay, we'll end up with the wrong data. We should probably
* have eg. GAMESTATE->GetOptionsForCourse(po,so,pn) to get options based on * have eg. GAMESTATE->GetOptionsForCourse(po,so,pn) to get options based on
* the last call to StoreSelectedOptions and the modifiers list, but that'd * the last call to StoreSelectedOptions and the modifiers list, but that'd
* mean moving the queues in ScreenGameplay to GameState ... */ * mean moving the queues in ScreenGameplay to GameState ... */
NoteData playerNoteDataPostModifiers(playerNoteData); NoteDataUtil::TransformNoteData( nd, GAMESTATE->m_PlayerOptions[pn_], pSteps->m_StepsType );
NoteDataUtil::TransformNoteData( playerNoteDataPostModifiers, GAMESTATE->m_PlayerOptions[pn_], GAMESTATE->GetCurrentStyle()->m_StepsType ); RadarValues rvPost;
NoteDataUtil::GetRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPost );
for( unsigned j=0; j < asModifiers[i].size(); j++ ) iTotalPossibleDancePoints += this->GetPossibleDancePoints( rvPre, rvPost );
{
const Attack &mod = asModifiers[i][j];
PlayerOptions po;
po.FromString( mod.sModifier );
float fStartBeat, fEndBeat;
mod.GetAttackBeats( pSong, m_PlayerNumber, fStartBeat, fEndBeat );
NoteDataUtil::TransformNoteData( playerNoteDataPostModifiers, po, GAMESTATE->GetCurrentStyle()->m_StepsType, fStartBeat, fEndBeat );
}
RadarValues radarValuesPostModifiers;
NoteDataUtil::GetRadarValues( playerNoteDataPostModifiers, pSong->m_fMusicLengthSeconds, radarValuesPostModifiers );
iTotalPossibleDancePoints += this->GetPossibleDancePoints( pSteps->GetRadarValues(), radarValuesPostModifiers );
} }
g_CurStageStats.iPossibleDancePoints[pn_] = iTotalPossibleDancePoints; g_CurStageStats.iPossibleDancePoints[pn_] = iTotalPossibleDancePoints;
+30 -23
View File
@@ -231,7 +231,7 @@ void ScreenGameplay::Init()
g_CurStageStats.iMeter[p] = m_vpStepsQueue[p][0]->GetMeter(); g_CurStageStats.iMeter[p] = m_vpStepsQueue[p][0]->GetMeter();
/* Record combo rollover. */ /* Record combo rollover. */
g_CurStageStats.UpdateComboList( (PlayerNumber)p, 0, true ); g_CurStageStats.UpdateComboList( p, 0, true );
} }
if( GAMESTATE->IsExtraStage() ) if( GAMESTATE->IsExtraStage() )
@@ -251,7 +251,7 @@ void ScreenGameplay::Init()
{ {
case PrefsManager::SCORING_MAX2: case PrefsManager::SCORING_MAX2:
case PrefsManager::SCORING_5TH: case PrefsManager::SCORING_5TH:
m_pPrimaryScoreKeeper[p] = new ScoreKeeperMAX2( m_apSongsQueue, m_vpStepsQueue[p], m_asModifiersQueue[p], (PlayerNumber)p ); m_pPrimaryScoreKeeper[p] = new ScoreKeeperMAX2( m_apSongsQueue, m_vpStepsQueue[p], m_asModifiersQueue[p], p );
break; break;
default: ASSERT(0); default: ASSERT(0);
} }
@@ -259,7 +259,7 @@ void ScreenGameplay::Init()
switch( GAMESTATE->m_PlayMode ) switch( GAMESTATE->m_PlayMode )
{ {
case PLAY_MODE_RAVE: case PLAY_MODE_RAVE:
m_pSecondaryScoreKeeper[p] = new ScoreKeeperRave( (PlayerNumber)p ); m_pSecondaryScoreKeeper[p] = new ScoreKeeperRave( p );
break; break;
} }
} }
@@ -412,7 +412,7 @@ void ScreenGameplay::Init()
ASSERT(0); ASSERT(0);
} }
m_pLifeMeter[p]->Load( (PlayerNumber)p ); m_pLifeMeter[p]->Load( p );
m_pLifeMeter[p]->SetName( ssprintf("LifeP%d",p+1) ); m_pLifeMeter[p]->SetName( ssprintf("LifeP%d",p+1) );
SET_XY( *m_pLifeMeter[p] ); SET_XY( *m_pLifeMeter[p] );
this->AddChild( m_pLifeMeter[p] ); this->AddChild( m_pLifeMeter[p] );
@@ -469,7 +469,7 @@ void ScreenGameplay::Init()
ASSERT(0); ASSERT(0);
} }
m_pPrimaryScoreDisplay[p]->Init( (PlayerNumber)p ); m_pPrimaryScoreDisplay[p]->Init( p );
m_pPrimaryScoreDisplay[p]->SetName( ssprintf("ScoreP%d",p+1) ); m_pPrimaryScoreDisplay[p]->SetName( ssprintf("ScoreP%d",p+1) );
SET_XY( *m_pPrimaryScoreDisplay[p] ); SET_XY( *m_pPrimaryScoreDisplay[p] );
if( GAMESTATE->m_PlayMode != PLAY_MODE_RAVE || SHOW_SCORE_IN_RAVE ) /* XXX: ugly */ if( GAMESTATE->m_PlayMode != PLAY_MODE_RAVE || SHOW_SCORE_IN_RAVE ) /* XXX: ugly */
@@ -488,7 +488,7 @@ void ScreenGameplay::Init()
if( m_pSecondaryScoreDisplay[p] ) if( m_pSecondaryScoreDisplay[p] )
{ {
m_pSecondaryScoreDisplay[p]->Init( (PlayerNumber)p ); m_pSecondaryScoreDisplay[p]->Init( p );
m_pSecondaryScoreDisplay[p]->SetName( ssprintf("SecondaryScoreP%d",p+1) ); m_pSecondaryScoreDisplay[p]->SetName( ssprintf("SecondaryScoreP%d",p+1) );
SET_XY( *m_pSecondaryScoreDisplay[p] ); SET_XY( *m_pSecondaryScoreDisplay[p] );
this->AddChild( m_pSecondaryScoreDisplay[p] ); this->AddChild( m_pSecondaryScoreDisplay[p] );
@@ -576,7 +576,6 @@ void ScreenGameplay::Init()
m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() ); m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() );
this->AddChild( &m_textSongOptions ); this->AddChild( &m_textSongOptions );
{
FOREACH_EnabledPlayer( pn ) FOREACH_EnabledPlayer( pn )
{ {
m_ActiveAttackList[pn].LoadFromFont( THEME->GetPathF(m_sName,"ActiveAttackList") ); m_ActiveAttackList[pn].LoadFromFont( THEME->GetPathF(m_sName,"ActiveAttackList") );
@@ -585,7 +584,6 @@ void ScreenGameplay::Init()
SET_XY( m_ActiveAttackList[pn] ); SET_XY( m_ActiveAttackList[pn] );
this->AddChild( &m_ActiveAttackList[pn] ); this->AddChild( &m_ActiveAttackList[pn] );
} }
}
@@ -629,7 +627,7 @@ void ScreenGameplay::Init()
// { // {
// case PLAY_MODE_BATTLE: // case PLAY_MODE_BATTLE:
// m_pInventory[p] = new Inventory; // m_pInventory[p] = new Inventory;
// m_pInventory[p]->Load( (PlayerNumber)p ); // m_pInventory[p]->Load( p );
// this->AddChild( m_pInventory[p] ); // this->AddChild( m_pInventory[p] );
// break; // break;
// } // }
@@ -770,14 +768,31 @@ bool ScreenGameplay::IsLastSong()
return GAMESTATE->GetCourseSongIndex()+1 == (int)m_apSongsQueue.size(); // GetCourseSongIndex() is 0-based but size() is not return GAMESTATE->GetCourseSongIndex()+1 == (int)m_apSongsQueue.size(); // GetCourseSongIndex() is 0-based but size() is not
} }
void ScreenGameplay::SetupSong( int p, int iSongIndex ) void ScreenGameplay::SetupSong( PlayerNumber p, int iSongIndex )
{ {
/* This is the first beat that can be changed without it being visible. Until /* This is the first beat that can be changed without it being visible. Until
* we draw for the first time, any beat can be changed. */ * we draw for the first time, any beat can be changed. */
GAMESTATE->m_fLastDrawnBeat[p] = -100; GAMESTATE->m_fLastDrawnBeat[p] = -100;
GAMESTATE->m_pCurSteps[p] = m_vpStepsQueue[p][iSongIndex]; GAMESTATE->m_pCurSteps[p] = m_vpStepsQueue[p][iSongIndex];
// Put course options into effect. /* Load new NoteData into Player. Do this before
* RebuildPlayerOptionsFromActiveAttacks or else transform mods will get
* propogated to GAMESTATE->m_PlayerOptions too early and be double-applied
* to the NoteData:
* once in Player::Load, then again in Player::ApplyActiveAttacks. This
* is very bad for transforms like AddMines.
*/
NoteData pOriginalNoteData;
GAMESTATE->m_pCurSteps[p]->GetNoteData( &pOriginalNoteData );
const Style* pStyle = GAMESTATE->GetCurrentStyle();
NoteData pNewNoteData;
pStyle->GetTransformedNoteDataForStyle( p, &pOriginalNoteData, &pNewNoteData );
m_Player[p].Load( p, &pNewNoteData, m_pLifeMeter[p], m_pCombinedLifeMeter, m_pPrimaryScoreDisplay[p], m_pSecondaryScoreDisplay[p], m_pInventory[p], m_pPrimaryScoreKeeper[p], m_pSecondaryScoreKeeper[p] );
// Put course options into effect. Do this after Player::Load so
// that mods aren't double-applied.
GAMESTATE->m_ModsToApply[p].clear(); GAMESTATE->m_ModsToApply[p].clear();
for( unsigned i=0; i<m_asModifiersQueue[p][iSongIndex].size(); ++i ) for( unsigned i=0; i<m_asModifiersQueue[p][iSongIndex].size(); ++i )
{ {
@@ -785,24 +800,16 @@ void ScreenGameplay::SetupSong( int p, int iSongIndex )
if( a.fStartSecond == 0 ) if( a.fStartSecond == 0 )
a.fStartSecond = -1; // now a.fStartSecond = -1; // now
GAMESTATE->LaunchAttack( (PlayerNumber)p, a ); GAMESTATE->LaunchAttack( p, a );
GAMESTATE->m_SongOptions.FromString( a.sModifier ); GAMESTATE->m_SongOptions.FromString( a.sModifier );
} }
/* Update attack bOn flags. */ /* Update attack bOn flags. */
GAMESTATE->Update(0); GAMESTATE->Update(0);
GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( (PlayerNumber)p ); GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( p );
/* Hack: Course modifiers that are set to start immediately shouldn't tween on. */ /* Hack: Course modifiers that are set to start immediately shouldn't tween on. */
GAMESTATE->m_CurrentPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p]; GAMESTATE->m_CurrentPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p];
NoteData pOriginalNoteData;
GAMESTATE->m_pCurSteps[p]->GetNoteData( &pOriginalNoteData );
const Style* pStyle = GAMESTATE->GetCurrentStyle();
NoteData pNewNoteData;
pStyle->GetTransformedNoteDataForStyle( (PlayerNumber)p, &pOriginalNoteData, &pNewNoteData );
m_Player[p].Load( (PlayerNumber)p, &pNewNoteData, m_pLifeMeter[p], m_pCombinedLifeMeter, m_pPrimaryScoreDisplay[p], m_pSecondaryScoreDisplay[p], m_pInventory[p], m_pPrimaryScoreKeeper[p], m_pSecondaryScoreKeeper[p] );
} }
static int GetMaxSongsPlayed() static int GetMaxSongsPlayed()
@@ -1371,7 +1378,7 @@ void ScreenGameplay::Update( float fDeltaTime )
FOREACH_CpuPlayer(p) FOREACH_CpuPlayer(p)
{ {
SOUND->PlayOnceFromDir( THEME->GetPathS(m_sName,"oni die") ); SOUND->PlayOnceFromDir( THEME->GetPathS(m_sName,"oni die") );
ShowOniGameOver((PlayerNumber)p); ShowOniGameOver( p );
m_Player[p].Init(); // remove all notes and scoring m_Player[p].Init(); // remove all notes and scoring
m_Player[p].FadeToFail(); // tell the NoteField to fade to white m_Player[p].FadeToFail(); // tell the NoteField to fade to white
} }
@@ -1980,7 +1987,7 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM )
/* Mark failure. This hasn't been done yet if m_bTwoPlayerRecovery is set. */ /* Mark failure. This hasn't been done yet if m_bTwoPlayerRecovery is set. */
if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF && if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF &&
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsFailing()) || (m_pLifeMeter[p] && m_pLifeMeter[p]->IsFailing()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsFailing((PlayerNumber)p)) ) (m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsFailing(p)) )
g_CurStageStats.bFailed[p] = true; g_CurStageStats.bFailed[p] = true;
if( !g_CurStageStats.bFailed[p] ) if( !g_CurStageStats.bFailed[p] )
+1 -1
View File
@@ -68,7 +68,7 @@ protected:
void TweenOffScreen(); void TweenOffScreen();
bool IsLastSong(); bool IsLastSong();
void SetupSong( int p, int iSongIndex ); void SetupSong( PlayerNumber p, int iSongIndex );
void LoadNextSong(); void LoadNextSong();
void LoadCourseSongNumber( int SongNumber ); void LoadCourseSongNumber( int SongNumber );
float StartPlayingSong(float MinTimeToNotes, float MinTimeToMusic); float StartPlayingSong(float MinTimeToNotes, float MinTimeToMusic);
+32
View File
@@ -3,6 +3,9 @@
#include "Foreach.h" #include "Foreach.h"
#include "Steps.h" #include "Steps.h"
#include "song.h" #include "song.h"
#include "PlayerOptions.h"
#include "NoteData.h"
#include "NoteDataUtil.h"
void TrailEntry::GetAttackArray( AttackArray &out ) const void TrailEntry::GetAttackArray( AttackArray &out ) const
{ {
@@ -35,6 +38,17 @@ bool TrailEntry::operator== ( const TrailEntry &rhs ) const
EQUAL(dc); EQUAL(dc);
} }
bool TrailEntry::ContainsTransformOrTurn() const
{
PlayerOptions po;
po.FromString( Modifiers );
if( po.ContainsTransformOrTurn() )
return true;
if( Attacks.ContainsTransformOrTurn() )
return true;
return false;
}
RadarValues Trail::GetRadarValues() const RadarValues Trail::GetRadarValues() const
{ {
RadarValues rv; RadarValues rv;
@@ -43,8 +57,26 @@ RadarValues Trail::GetRadarValues() const
{ {
const Steps *pSteps = e->pSteps; const Steps *pSteps = e->pSteps;
ASSERT( pSteps ); ASSERT( pSteps );
if( e->ContainsTransformOrTurn() )
{
NoteData nd;
pSteps->GetNoteData( &nd );
RadarValues rv_orig;
NoteDataUtil::GetRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv_orig );
PlayerOptions po;
po.FromString( e->Modifiers );
if( po.ContainsTransformOrTurn() )
NoteDataUtil::TransformNoteData( nd, po, pSteps->m_StepsType );
NoteDataUtil::TransformNoteData( nd, e->Attacks, pSteps->m_StepsType, e->pSong );
RadarValues rv2;
NoteDataUtil::GetRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv2 );
rv += rv2;
}
else
{
rv += pSteps->GetRadarValues(); rv += pSteps->GetRadarValues();
} }
}
return rv; return rv;
} }
+1
View File
@@ -35,6 +35,7 @@ struct TrailEntry
Difficulty dc; Difficulty dc;
bool operator== ( const TrailEntry &rhs ) const; bool operator== ( const TrailEntry &rhs ) const;
bool operator!= ( const TrailEntry &rhs ) const { return !(*this==rhs); } bool operator!= ( const TrailEntry &rhs ) const { return !(*this==rhs); }
bool ContainsTransformOrTurn() const;
}; };
class Trail class Trail