void PlayerState::RemoveActiveAttacks( AttackLevel al ) { for( unsigned s=0; s<m_ActiveAttacks.size(); s++ ) { if( al != NUM_ATTACK_LEVELS && al != m_ActiveAttacks[s].level ) continue; m_ActiveAttacks.erase( m_ActiveAttacks.begin()+s, m_ActiveAttacks.begin()+s+1 ); --s; } RebuildPlayerOptionsFromActiveAttacks(); }
void PlayerState::Update( float fDelta ) { // TRICKY: GAMESTATE->Update is run before any of the Screen update's, // so we'll clear these flags here and let them get turned on later m_bAttackBeganThisUpdate = false; m_bAttackEndedThisUpdate = false; bool bRebuildPlayerOptions = false; // See if any delayed attacks are starting or ending. for( unsigned s=0; s<m_ActiveAttacks.size(); s++ ) { Attack &attack = m_ActiveAttacks[s]; // You must add sattack by calling GameState::LaunchAttack, // or else the sentinel value won't be // converted into the current music time. ASSERT( attack.fStartSecond != ATTACK_STARTS_NOW ); bool bCurrentlyEnabled = attack.bGlobal || ( attack.fStartSecond < m_Position.m_fMusicSeconds && m_Position.m_fMusicSeconds < attack.fStartSecond+attack.fSecsRemaining ); if( m_ActiveAttacks[s].bOn == bCurrentlyEnabled ) continue; // OK if( m_ActiveAttacks[s].bOn && !bCurrentlyEnabled ) m_bAttackEndedThisUpdate = true; else if( !m_ActiveAttacks[s].bOn && bCurrentlyEnabled ) m_bAttackBeganThisUpdate = true; bRebuildPlayerOptions = true; m_ActiveAttacks[s].bOn = bCurrentlyEnabled; } if( bRebuildPlayerOptions ) RebuildPlayerOptionsFromActiveAttacks(); // Update after enabling attacks, so we approach the new state. m_PlayerOptions.Update( fDelta ); if( m_fSecondsUntilAttacksPhasedOut > 0 ) m_fSecondsUntilAttacksPhasedOut = max( 0, m_fSecondsUntilAttacksPhasedOut - fDelta ); }
/* This is called to launch an attack, or to queue an attack if a.fStartSecond * is set. This is also called by GameState::Update when activating a queued attack. */ void PlayerState::LaunchAttack( const Attack& a ) { LOG->Trace( "Launch attack '%s' against P%d at %f", a.sModifiers.c_str(), m_PlayerNumber+1, a.fStartSecond ); Attack attack = a; /* If fStartSecond is the sentinel, it means "launch as soon as possible". For m_ActiveAttacks, * mark the real time it's starting (now), so Update() can know when the attack * started so it can be removed later. For m_ModsToApply, leave the sentinel in, * so Player::Update knows to apply attack transforms correctly. (yuck) */ m_ModsToApply.push_back( attack ); if( attack.fStartSecond == ATTACK_STARTS_NOW ) attack.fStartSecond = m_Position.m_fMusicSeconds; m_ActiveAttacks.push_back( attack ); RebuildPlayerOptionsFromActiveAttacks(); }
void PlayerState::Update( float fDelta ) { // TRICKY: GAMESTATE->Update is run before any of the Screen update's, // so we'll clear these flags here and let them get turned on later m_bAttackBeganThisUpdate = false; m_bAttackEndedThisUpdate = false; bool bRebuildPlayerOptions = false; /* See if any delayed attacks are starting or ending. */ for( unsigned s=0; s<m_ActiveAttacks.size(); s++ ) { Attack &attack = m_ActiveAttacks[s]; // -1 is the "starts now" sentinel value. You must add the attack // by calling GameState::LaunchAttack, or else the -1 won't be // converted into the current music time. ASSERT( attack.fStartSecond != -1 ); bool bCurrentlyEnabled = attack.bGlobal || ( attack.fStartSecond < GAMESTATE->m_fMusicSeconds && GAMESTATE->m_fMusicSeconds < attack.fStartSecond+attack.fSecsRemaining ); if( m_ActiveAttacks[s].bOn == bCurrentlyEnabled ) continue; /* OK */ if( m_ActiveAttacks[s].bOn && !bCurrentlyEnabled ) m_bAttackEndedThisUpdate = true; else if( !m_ActiveAttacks[s].bOn && bCurrentlyEnabled ) m_bAttackBeganThisUpdate = true; bRebuildPlayerOptions = true; m_ActiveAttacks[s].bOn = bCurrentlyEnabled; } if( bRebuildPlayerOptions ) RebuildPlayerOptionsFromActiveAttacks(); /* Update after enabling attacks, so we appraoch the new state. */ m_PlayerOptions.Update( fDelta ); if( m_fSecondsUntilAttacksPhasedOut > 0 ) m_fSecondsUntilAttacksPhasedOut = max( 0, m_fSecondsUntilAttacksPhasedOut - fDelta ); /* XXX m_fWrappedMidiNote = -1; if( m_fUpcomingMidiNote != -1 ) { m_fWrappedMidiNote = PitchDetectionTest::WrapToNearestOctave( PitchDetectionTest::s_ms.fMidiNote, m_fUpcomingMidiNote ); } else { Steps *pSteps = GAMESTATE->m_pCurSteps[m_PlayerNumber]; if( pSteps ) { const RadarValues &rv = pSteps->GetRadarValues(PLAYER_1); float fMinMidiNote = rv.m_Values.v.fMinMidiNote; float fMaxMidiNote = rv.m_Values.v.fMaxMidiNote; if( fMinMidiNote != -1 && fMaxMidiNote != -1 ) m_fWrappedMidiNote = PitchDetectionTest::WrapToNearestOctave( PitchDetectionTest::s_ms.fMidiNote, (fMinMidiNote+fMaxMidiNote)/2 ); } } */ }