From cefc7f6685d5fa3143af689302d9e0c26ab5e1b6 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 25 Oct 2003 07:58:10 +0000 Subject: [PATCH] simpler/more consistent attack/mod handling --- stepmania/src/GameState.cpp | 71 +++++++------------------------ stepmania/src/GameState.h | 13 ++---- stepmania/src/Player.cpp | 54 +++++++++++------------ stepmania/src/ScoreKeeperMAX2.cpp | 19 ++++++--- stepmania/src/ScoreKeeperMAX2.h | 3 +- stepmania/src/ScreenGameplay.cpp | 31 +++++++++----- stepmania/src/ScreenGameplay.h | 3 +- 7 files changed, 82 insertions(+), 112 deletions(-) diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index 594db442e7..83d55d5876 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -157,7 +157,6 @@ void GameState::Update( float fDelta ) m_ActiveAttacks[p][s].fStartSecond = -1; - ActivateAttack( (PlayerNumber)p, s, true ); RebuildPlayerOptions = true; } @@ -628,60 +627,6 @@ void GameState::GetUndisplayedBeats( PlayerNumber pn, float TotalSeconds, float EndBeat = truncf(EndBeat)+1; } -void GameState::ActivateAttack( PlayerNumber target, int slot, bool ActivingDelayedAttack ) -{ - const Attack &a = m_ActiveAttacks[target][slot]; - - enum { QUEUE_FOR_LATER, ACTIVATE_QUEUED_ATTACK, START_IMMEDIATELY } type; - if( ActivingDelayedAttack ) - { - ASSERT( a.fStartSecond < 0 ); - type = ACTIVATE_QUEUED_ATTACK; - } - else if( a.fStartSecond >= 0 ) - type = QUEUE_FOR_LATER; - else - type = START_IMMEDIATELY; - - float StartBeat = 0, EndBeat = 0; - switch( type ) - { - case QUEUE_FOR_LATER: - StartBeat = this->m_pCurSong->GetBeatFromElapsedTime( a.fStartSecond ); - EndBeat = this->m_pCurSong->GetBeatFromElapsedTime( a.fStartSecond+a.fSecsRemaining ); - break; - case START_IMMEDIATELY: - /* 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 - * screen, so new arrows will scroll on screen with this effect. */ - GetUndisplayedBeats( target, a.fSecsRemaining, StartBeat, EndBeat ); - break; - } - - // - // Peek at the effect being applied. - // - PlayerOptions po; - po.FromString( a.sModifier ); - - switch( type ) - { - case QUEUE_FOR_LATER: - case START_IMMEDIATELY: - if( po.m_sNoteSkin != "" ) - { - SetNoteSkinForBeatRange( target, po.m_sNoteSkin, StartBeat, EndBeat ); - LOG->Trace("skin ..."); - } - /* If it's a transform, add it to the list of transforms that should be applied - * by the Player on its next update. */ - if( po.m_Transform != PlayerOptions::TRANSFORM_NONE ) - { - m_TransformsToApply[target].push_back( - TransformToApply_t( po.m_Transform, StartBeat, EndBeat ) ); - } - } -} void GameState::SetNoteSkinForBeatRange( PlayerNumber pn, CString sNoteSkin, float StartBeat, float EndBeat ) { @@ -721,7 +666,7 @@ void GameState::LaunchAttack( PlayerNumber target, Attack a ) if( m_ActiveAttacks[target][s].fSecsRemaining <= 0 ) { m_ActiveAttacks[target][s] = a; - ActivateAttack( target, s, false ); + m_ModsToApply[target].push_back( a ); GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( target ); return; } @@ -731,6 +676,20 @@ void GameState::LaunchAttack( PlayerNumber target, Attack a ) a.sModifier.c_str(), target ); } +void GameState::Attack::GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBeat, float &fEndBeat ) const +{ + if( fStartSecond >= 0 ) + { + fStartBeat = song->GetBeatFromElapsedTime( fStartSecond ); + fEndBeat = song->GetBeatFromElapsedTime( fStartSecond+fSecsRemaining ); + } else { + /* 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 + * screen, so new arrows will scroll on screen with this effect. */ + GAMESTATE->GetUndisplayedBeats( pn, fSecsRemaining, fStartBeat, fEndBeat ); + } +} + void GameState::RemoveActiveAttacksForPlayer( PlayerNumber pn, AttackLevel al ) { for( int s=0; s AttackArray; enum { MAX_SIMULTANEOUS_ATTACKS=16 }; Attack m_ActiveAttacks[NUM_PLAYERS][MAX_SIMULTANEOUS_ATTACKS]; - struct TransformToApply_t - { - PlayerOptions::Transform trans; - float fStartBeat, fEndBeat; - TransformToApply_t( PlayerOptions::Transform trans_, float fStartBeat_, float fEndBeat_ ): - trans(trans_), fStartBeat(fStartBeat_), fEndBeat(fEndBeat_) { } - }; - vector m_TransformsToApply[NUM_PLAYERS]; + vector m_ModsToApply[NUM_PLAYERS]; - void ActivateAttack( PlayerNumber target, int slot, bool ActivingDelayedAttack ); void SetNoteSkinForBeatRange( PlayerNumber pn, CString sNoteSkin, float StartBeat, float EndBeat ); // used in PLAY_MODE_BATTLE diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index 0defe441dd..6c715296ca 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -332,44 +332,40 @@ void PlayerMinus::Update( float fDeltaTime ) // process transforms that are waiting to be applied - for( unsigned j=0; jm_TransformsToApply[m_PlayerNumber].size(); j++ ) + for( unsigned j=0; jm_ModsToApply[m_PlayerNumber].size(); j++ ) { - const GameState::TransformToApply_t &tr = GAMESTATE->m_TransformsToApply[m_PlayerNumber][j]; + const GameState::Attack &mod = GAMESTATE->m_ModsToApply[m_PlayerNumber][j]; + PlayerOptions po; + /* Should this default to "" always? need it blank so we know if mod.sModifier + * changes the note skin. */ + po.m_sNoteSkin = ""; + po.FromString( mod.sModifier ); /* Note that runtime effects like these currently must not change hold * notes. CopyRange below converts through 4s, which means the hold note * array will be reconstructed; if hold notes end up in a different order, * they won't align with this->m_HoldNoteScores. */ - LOG->Trace( "Applying transform from %f to %f", tr.fStartBeat, tr.fEndBeat ); - switch( tr.trans ) - { - case PlayerOptions::TRANSFORM_LITTLE: - NoteDataUtil::Little( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_WIDE: - NoteDataUtil::Wide( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_BIG: - NoteDataUtil::Big( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_QUICK: - NoteDataUtil::Quick( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_SKIPPY: - NoteDataUtil::Skippy( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_MINES: - NoteDataUtil::Mines( *this, tr.fStartBeat, tr.fEndBeat ); - break; - case PlayerOptions::TRANSFORM_NONE: - default: - ASSERT(0); - } + if( po.m_Turn != PlayerOptions::TURN_NONE ) + RageException::Throw("Can't use turns as battle attacks"); + if( !po.m_bHoldNotes ) + RageException::Throw("Can't use NoHolds as a battle attack"); - m_pNoteField->CopyRange( this, BeatToNoteRow(tr.fStartBeat), BeatToNoteRow(tr.fEndBeat), BeatToNoteRow(tr.fStartBeat) ); + float fStartBeat, fEndBeat; + mod.GetAttackBeats( GAMESTATE->m_pCurSong, m_PlayerNumber, fStartBeat, fEndBeat ); + + LOG->Trace( "Applying transform from %f to %f", fStartBeat, fEndBeat ); + if( po.m_sNoteSkin != "" ) + GAMESTATE->SetNoteSkinForBeatRange( m_PlayerNumber, po.m_sNoteSkin, fStartBeat, fEndBeat ); + + NoteDataUtil::TransformNoteData( *this, po, GAMESTATE->GetCurrentStyleDef()->m_StepsType, fStartBeat, fEndBeat ); + m_pNoteField->CopyRange( this, BeatToNoteRow(fStartBeat), BeatToNoteRow(fEndBeat), BeatToNoteRow(fStartBeat) ); } - GAMESTATE->m_TransformsToApply[m_PlayerNumber].clear(); + GAMESTATE->m_ModsToApply[m_PlayerNumber].clear(); + /* Cache any newly-used note skins. Normally, the only new skins cached now are + * when we're adding course modifiers at the start of a song. If this is spending + * time loading skins in the middle of a song, something is wrong. */ + m_pNoteField->CacheAllUsedNoteSkins(); ActorFrame::Update( fDeltaTime ); } diff --git a/stepmania/src/ScoreKeeperMAX2.cpp b/stepmania/src/ScoreKeeperMAX2.cpp index d896c2de90..9eb404e20e 100644 --- a/stepmania/src/ScoreKeeperMAX2.cpp +++ b/stepmania/src/ScoreKeeperMAX2.cpp @@ -25,7 +25,7 @@ #include "RageLog.h" -ScoreKeeperMAX2::ScoreKeeperMAX2( const vector& apNotes_, const CStringArray &asModifiers, PlayerNumber pn_ ): +ScoreKeeperMAX2::ScoreKeeperMAX2( const vector& apSongs, const vector& apNotes_, const vector &asModifiers, PlayerNumber pn_ ): ScoreKeeper(pn_), apNotes(apNotes_) { // @@ -52,11 +52,20 @@ ScoreKeeperMAX2::ScoreKeeperMAX2( const vector& apNotes_, const CStringA * have eg. GAMESTATE->GetOptionsForCourse(po,so,pn) to get options based on * the last call to StoreSelectedOptions and the modifiers list, but that'd * mean moving the queues in ScreenGameplay to GameState ... */ - PlayerOptions ModsForThisSong( GAMESTATE->m_PlayerOptions[pn_] ); - ModsForThisSong.FromString( asModifiers[i] ); - NoteData playerNoteDataPostModifiers(playerNoteData); - NoteDataUtil::TransformNoteData( playerNoteDataPostModifiers, ModsForThisSong, GAMESTATE->GetCurrentStyleDef()->m_StepsType ); + NoteDataUtil::TransformNoteData( playerNoteDataPostModifiers, GAMESTATE->m_PlayerOptions[pn_], GAMESTATE->GetCurrentStyleDef()->m_StepsType ); + + for( unsigned j=0; j < asModifiers[i].size(); j++ ) + { + const GameState::Attack &mod = asModifiers[i][j]; + PlayerOptions po; + po.FromString( mod.sModifier ); + + float fStartBeat, fEndBeat; + mod.GetAttackBeats( apSongs[i], m_PlayerNumber, fStartBeat, fEndBeat ); + + NoteDataUtil::TransformNoteData( playerNoteDataPostModifiers, po, GAMESTATE->GetCurrentStyleDef()->m_StepsType, fStartBeat, fEndBeat ); + } iTotalPossibleDancePoints += this->GetPossibleDancePoints( playerNoteData, playerNoteDataPostModifiers ); } diff --git a/stepmania/src/ScoreKeeperMAX2.h b/stepmania/src/ScoreKeeperMAX2.h index 44feaa745f..327f88cc21 100644 --- a/stepmania/src/ScoreKeeperMAX2.h +++ b/stepmania/src/ScoreKeeperMAX2.h @@ -14,6 +14,7 @@ #include "ScoreKeeper.h" #include "NoteDataWithScoring.h" +#include "GameState.h" class Steps; class ScoreKeeperMAX2: public ScoreKeeper @@ -38,7 +39,7 @@ class ScoreKeeperMAX2: public ScoreKeeper int m_ComboBonusFactor[NUM_TAP_NOTE_SCORES]; public: - ScoreKeeperMAX2( const vector& apNotes, const CStringArray &asModifiers, PlayerNumber pn); + ScoreKeeperMAX2( const vector& apSongs, const vector& apNotes, const vector &asModifiers, PlayerNumber pn); // before a song plays (called multiple times if course) void OnNextSong( int iSongInCourseIndex, const Steps* pNotes, const NoteData* pNoteData ); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 54a90170c0..ef711aeae4 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -81,6 +81,18 @@ const ScreenMessage SM_GoToScreenAfterFail = ScreenMessage(SM_User+31); const ScreenMessage SM_StartHereWeGo = ScreenMessage(SM_User+40); const ScreenMessage SM_StopHereWeGo = ScreenMessage(SM_User+41); +void GetCourseAttackArray( const Course::Info &ci, GameState::AttackArray &out ) +{ + GameState::Attack a; + a.fStartSecond = 0; + a.fSecsRemaining = 10000; /* whole song */ + a.level = ATTACK_LEVEL_1; + a.sModifier = ci.Modifiers; + + out.push_back( a ); +} + + /* XXX: Not using sName yet here until I work out jukebox/demo. */ ScreenGameplay::ScreenGameplay( CString sName, bool bDemonstration ) : Screen("ScreenGameplay") { @@ -157,7 +169,9 @@ ScreenGameplay::ScreenGameplay( CString sName, bool bDemonstration ) : Screen("S for( unsigned c=0; cm_pCurNotes[p] ); - m_asModifiersQueue[p].push_back( "" ); + m_asModifiersQueue[p].push_back( GameState::AttackArray() ); } } @@ -209,7 +223,7 @@ ScreenGameplay::ScreenGameplay( CString sName, bool bDemonstration ) : Screen("S { case PrefsManager::SCORING_MAX2: case PrefsManager::SCORING_5TH: - m_pPrimaryScoreKeeper[p] = new ScoreKeeperMAX2( m_apNotesQueue[p], m_asModifiersQueue[p], (PlayerNumber)p ); + m_pPrimaryScoreKeeper[p] = new ScoreKeeperMAX2( m_apSongsQueue, m_apNotesQueue[p], m_asModifiersQueue[p], (PlayerNumber)p ); break; default: ASSERT(0); } @@ -693,16 +707,11 @@ void ScreenGameplay::LoadNextSong() GAMESTATE->m_pCurNotes[p] = m_apNotesQueue[p][iPlaySongIndex]; // Put courses options into effect. + for( unsigned i=0; iLaunchAttack( (PlayerNumber)p, a ); + GAMESTATE->LaunchAttack( (PlayerNumber)p, m_asModifiersQueue[p][iPlaySongIndex][i] ); + GAMESTATE->m_SongOptions.FromString( m_asModifiersQueue[p][iPlaySongIndex][i].sModifier ); } - GAMESTATE->m_SongOptions.FromString( m_asModifiersQueue[p][iPlaySongIndex] ); - /* Queue course attacks. */ diff --git a/stepmania/src/ScreenGameplay.h b/stepmania/src/ScreenGameplay.h index bfbce49ca0..3229716333 100644 --- a/stepmania/src/ScreenGameplay.h +++ b/stepmania/src/ScreenGameplay.h @@ -28,6 +28,7 @@ class Inventory; #include "LyricDisplay.h" #include "TimingAssist.h" #include "Character.h" +#include "GameState.h" // messages sent by Combo const ScreenMessage SM_PlayToasty = ScreenMessage(SM_User+104); @@ -91,7 +92,7 @@ protected: } m_DancingState; vector m_apSongsQueue; // size may be >1 if playing a course vector m_apNotesQueue[NUM_PLAYERS]; // size may be >1 if playing a course - CStringArray m_asModifiersQueue[NUM_PLAYERS];// size may be >1 if playing a course + vector m_asModifiersQueue[NUM_PLAYERS];// size may be >1 if playing a course bool m_bChangedOffsetOrBPM; float m_fTimeLeftBeforeDancingComment; // this counter is only running while STATE_DANCING