simpler/more consistent attack/mod handling

This commit is contained in:
Glenn Maynard
2003-10-25 07:58:10 +00:00
parent e792d3e4df
commit cefc7f6685
7 changed files with 82 additions and 112 deletions
+15 -56
View File
@@ -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++ )
+4 -9
View File
@@ -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
View File
@@ -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 );
}
+14 -5
View File
@@ -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 );
}
+2 -1
View File
@@ -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 );
+20 -11
View File
@@ -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. */
+2 -1
View File
@@ -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