simpler/more consistent attack/mod handling
This commit is contained in:
+15
-56
@@ -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<MAX_SIMULTANEOUS_ATTACKS; s++ )
|
||||
|
||||
@@ -174,23 +174,18 @@ public:
|
||||
float fStartSecond; // -1 = now
|
||||
float fSecsRemaining;
|
||||
CString sModifier;
|
||||
|
||||
void GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBeat, float &fEndBeat ) const;
|
||||
bool IsBlank() { return sModifier.empty(); }
|
||||
void MakeBlank() { sModifier=""; }
|
||||
Attack() { fStartSecond = -1; }
|
||||
};
|
||||
typedef vector<GameState::Attack> 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<TransformToApply_t> m_TransformsToApply[NUM_PLAYERS];
|
||||
vector<Attack> 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
|
||||
|
||||
+25
-29
@@ -332,44 +332,40 @@ void PlayerMinus::Update( float fDeltaTime )
|
||||
|
||||
|
||||
// process transforms that are waiting to be applied
|
||||
for( unsigned j=0; j<GAMESTATE->m_TransformsToApply[m_PlayerNumber].size(); j++ )
|
||||
for( unsigned j=0; j<GAMESTATE->m_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 );
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "RageLog.h"
|
||||
|
||||
|
||||
ScoreKeeperMAX2::ScoreKeeperMAX2( const vector<Steps*>& apNotes_, const CStringArray &asModifiers, PlayerNumber pn_ ):
|
||||
ScoreKeeperMAX2::ScoreKeeperMAX2( const vector<Song*>& apSongs, const vector<Steps*>& apNotes_, const vector<GameState::AttackArray> &asModifiers, PlayerNumber pn_ ):
|
||||
ScoreKeeper(pn_), apNotes(apNotes_)
|
||||
{
|
||||
//
|
||||
@@ -52,11 +52,20 @@ ScoreKeeperMAX2::ScoreKeeperMAX2( const vector<Steps*>& 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 );
|
||||
}
|
||||
|
||||
@@ -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<Steps*>& apNotes, const CStringArray &asModifiers, PlayerNumber pn);
|
||||
ScoreKeeperMAX2( const vector<Song*>& apSongs, const vector<Steps*>& apNotes, const vector<GameState::AttackArray> &asModifiers, PlayerNumber pn);
|
||||
|
||||
// before a song plays (called multiple times if course)
|
||||
void OnNextSong( int iSongInCourseIndex, const Steps* pNotes, const NoteData* pNoteData );
|
||||
|
||||
@@ -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; c<ci.size(); ++c )
|
||||
{
|
||||
m_apNotesQueue[p].push_back( ci[c].pNotes );
|
||||
m_asModifiersQueue[p].push_back( ci[c].Modifiers );
|
||||
GameState::AttackArray a;
|
||||
GetCourseAttackArray( ci[c], a );
|
||||
m_asModifiersQueue[p].push_back( a );
|
||||
}
|
||||
}
|
||||
m_apSongsQueue.clear();
|
||||
@@ -170,7 +184,7 @@ ScreenGameplay::ScreenGameplay( CString sName, bool bDemonstration ) : Screen("S
|
||||
for( int p=0; p<NUM_PLAYERS; p++ )
|
||||
{
|
||||
m_apNotesQueue[p].push_back( GAMESTATE->m_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; i<m_asModifiersQueue[p][iPlaySongIndex].size(); ++i )
|
||||
{
|
||||
GameState::Attack a;
|
||||
a.fSecsRemaining = 10000; /* whole song */
|
||||
a.level = ATTACK_LEVEL_1;
|
||||
|
||||
a.sModifier=m_asModifiersQueue[p][iPlaySongIndex];
|
||||
GAMESTATE->LaunchAttack( (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. */
|
||||
|
||||
|
||||
@@ -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<Song*> m_apSongsQueue; // size may be >1 if playing a course
|
||||
vector<Steps*> 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<GameState::AttackArray> 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
|
||||
|
||||
Reference in New Issue
Block a user