rework tap attack representation

This commit is contained in:
Chris Danford
2003-11-15 23:19:13 +00:00
parent 474b8b9a49
commit 38ec8ca856
6 changed files with 112 additions and 88 deletions
+52 -28
View File
@@ -174,40 +174,66 @@ void NoteData::RemoveHoldNote( int iHoldIndex )
m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1); m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1);
} }
void NoteData::AddAttackNote( AttackNote an ) void NoteData::AddAttackNote( int track, int row, Attack attack )
{ {
m_AttackNotes.push_back(an); PruneUnusedAttacksFromMap();
}
void NoteData::RemoveAttackNote( int index ) // find first unused attack index
{ TapNote tn;
m_AttackNotes.erase( m_AttackNotes.begin()+index ); for( tn = TAP_ATTACK_BEGIN; tn<=TAP_ATTACK_END; tn++ )
}
bool CompareAttackNotes( const AttackNote& an1, const AttackNote& an2 )
{
return an1.fBeat < an2.fBeat;
}
void NoteData::ShuffleAttackNotesOnSameRow()
{
// sort, then shuffle
sort( m_AttackNotes.begin(), m_AttackNotes.end(), CompareAttackNotes );
for( int i=0; i<m_AttackNotes.size(); )
{ {
// Shuffle with other AttackNotes that are on the same row. if( m_AttackMap.find(tn) == m_AttackMap.end() ) // this TapNote value is free to use
// Lame shuffle... goto done_searching;
for( int j=i+1; j<m_AttackNotes.size(); j++ ) }
ASSERT(0);
done_searching:
m_AttackMap[tn] = attack;
SetTapNote( track, row, tn );
}
void NoteData::PruneUnusedAttacksFromMap()
{
// Add all used AttackNote values to a map.
map<TapNote,int> mapAttackToNothing;
int max_row = GetMaxRow();
for( int t=0; t<m_iNumTracks; t++ )
{
for( int r=0; r<=max_row; r++ )
{ {
if( m_AttackNotes[i].fBeat != m_AttackNotes[j].fBeat ) TapNote tn = GetTapNote(t, r);
break; // stop searching if( IsTapAttack( tn ) )
if( rand()%2 ) mapAttackToNothing[tn] = 1;
swap( m_AttackNotes[i].fBeat, m_AttackNotes[j].fBeat ); }
}
// Remove all items from m_AttackMap that don't have corresponding
// TapNotes in use.
for( TapNote tn = TAP_ATTACK_BEGIN; tn<=TAP_ATTACK_END; tn++ )
{
bool bInAttackMap = m_AttackMap.find(tn) != m_AttackMap.end();
bool bActuallyUsed = mapAttackToNothing.find(tn) != mapAttackToNothing.end();
if( bActuallyUsed && !bInAttackMap )
ASSERT( 0 );
if( bInAttackMap && !bActuallyUsed )
{
m_AttackMap.erase( tn );
} }
} }
} }
const Attack& NoteData::GetAttackAt( int track, int row )
{
TapNote tn = GetTapNote(track, row);
ASSERT( IsTapAttack(tn) );
return m_AttackMap[tn];
}
int NoteData::GetFirstRow() const int NoteData::GetFirstRow() const
{ {
return BeatToNoteRow( GetFirstBeat() ); return BeatToNoteRow( GetFirstBeat() );
@@ -677,5 +703,3 @@ int NoteData::GetNumTracksHeldAtRow( int row )
GetTracksHeldAtRow( row, viTracks ); GetTracksHeldAtRow( row, viTracks );
return viTracks.size(); return viTracks.size();
} }
+11 -8
View File
@@ -15,6 +15,8 @@
*/ */
#include "NoteTypes.h" #include "NoteTypes.h"
#include <map>
#include "Attack.h"
class NoteData class NoteData
@@ -25,7 +27,7 @@ class NoteData
vector<HoldNote> m_HoldNotes; vector<HoldNote> m_HoldNotes;
vector<AttackNote> m_AttackNotes; map<TapNote,Attack> m_AttackMap;
/* Pad m_TapNotes so it includes the row "rows". */ /* Pad m_TapNotes so it includes the row "rows". */
void PadTapNotes(int rows); void PadTapNotes(int rows);
@@ -134,20 +136,22 @@ public:
void GetTracksHeldAtRow( int row, vector<int>& viTracksOut ); void GetTracksHeldAtRow( int row, vector<int>& viTracksOut );
int GetNumTracksHeldAtRow( int row ); int GetNumTracksHeldAtRow( int row );
//
// used in edit/record // used in edit/record
//
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
void RemoveHoldNote( int index ); void RemoveHoldNote( int index );
HoldNote &GetHoldNote( int index ) { return m_HoldNotes[index]; } HoldNote &GetHoldNote( int index ) { return m_HoldNotes[index]; }
const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; } const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; }
// used in edit/record void AddAttackNote( int track, int row, Attack attack );
void AddAttackNote( AttackNote an ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath void PruneUnusedAttacksFromMap(); // slow
void RemoveAttackNote( int index ); const Attack& GetAttackAt( int track, int row );
const AttackNote& GetAttackNote( int index ) { return m_AttackNotes[index]; } // remove Attacks with SetTapNote(TAP_EMPTY)
void ShuffleAttackNotesOnSameRow();
//
// statistics // statistics
//
/* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need /* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need
* accuracy.) */ * accuracy.) */
float GetMaxBeat() const { return NoteRowToBeat(GetMaxRow()); } float GetMaxBeat() const { return NoteRowToBeat(GetMaxRow()); }
@@ -164,7 +168,6 @@ public:
/* optimization: for the default of start to end, use the second (faster) */ /* optimization: for the default of start to end, use the second (faster) */
int GetNumHoldNotes( const float fStartBeat, const float fEndBeat = -1 ) const; int GetNumHoldNotes( const float fStartBeat, const float fEndBeat = -1 ) const;
int GetNumHoldNotes() const { return m_HoldNotes.size(); } int GetNumHoldNotes() const { return m_HoldNotes.size(); }
int GetNumAttackNotes() const { return m_AttackNotes.size(); }
// Transformations // Transformations
void LoadTransformed( const NoteData* pOriginal, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track void LoadTransformed( const NoteData* pOriginal, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track
+13 -27
View File
@@ -543,38 +543,24 @@ void NoteField::DrawPrimitives()
bool bIsAddition = (tn == TAP_ADDITION); bool bIsAddition = (tn == TAP_ADDITION);
bool bIsMine = (tn == TAP_MINE); bool bIsMine = (tn == TAP_MINE);
bool bIsAttack = IsTapAttack(tn);
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(i) ); SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(i) );
NoteDisplayCols *nd = CurDisplay->second; NoteDisplayCols *nd = CurDisplay->second;
nd->display[c].DrawTap( c, NoteRowToBeat(i), bHoldNoteBeginsOnThisBeat, bIsAddition, bIsMine, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels ); if( bIsAttack )
}
//
// Draw all AttackNotes in this column
//
for( i=0; i < GetNumAttackNotes(); i++ )
{
const AttackNote& an = GetAttackNote( i );
// If this AttackNote isn't on the screen, skip it
if( an.iTrack != c ||
an.fBeat < fFirstBeatToDraw ||
an.fBeat > fLastBeatToDraw )
continue; // skip
bool bIsInSelectionRange = false;
if( m_fBeginMarker!=-1 && m_fEndMarker!=-1 )
{ {
bIsInSelectionRange = m_fBeginMarker<=an.fBeat && an.fBeat<=m_fEndMarker; const Attack& attack = GetAttackAt( c, i );
Sprite sprite;
sprite.Load( THEME->GetPathToG("NoteField attack "+attack.sModifier) );
float fBeat = NoteRowToBeat(i);
SearchForBeat( CurDisplay, NextDisplay, fBeat );
NoteDisplayCols *nd = CurDisplay->second;
nd->display[c].DrawActor( &sprite, c, fBeat, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels );
}
else
{
nd->display[c].DrawTap( c, NoteRowToBeat(i), bHoldNoteBeginsOnThisBeat, bIsAddition, bIsMine, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels );
} }
Sprite sprite;
sprite.Load( THEME->GetPathToG("NoteField attack "+an.sModifiers) );
SearchForBeat( CurDisplay, NextDisplay, an.fBeat );
NoteDisplayCols *nd = CurDisplay->second;
nd->display[c].DrawActor( &sprite, an.iTrack, an.fBeat, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels );
} }
+5 -9
View File
@@ -70,6 +70,11 @@ static const TapNote TAP_REMOVED_HOLD_TAIL = '\'';
// MD 11/12/03 end // MD 11/12/03 end
// mine note - don't step!
static const TapNote TAP_ATTACK_BEGIN = 'a';
static const TapNote TAP_ATTACK_END = 'z';
inline bool IsTapAttack( TapNote tn ) { return tn>=TAP_ATTACK_BEGIN && tn<=TAP_ATTACK_END; }
enum enum
{ {
@@ -132,15 +137,6 @@ struct HoldNote
float fEndBeat; float fEndBeat;
}; };
struct AttackNote
{
AttackNote( int t, float b, CString m, float d ) { iTrack=t; fBeat=b; sModifiers=m; fDurationSeconds=d; }
int iTrack;
float fBeat;
CString sModifiers;
float fDurationSeconds;
};
inline int BeatToNoteRow( float fBeatNum ) { return int( fBeatNum * ROWS_PER_BEAT + 0.5f); }; // round inline int BeatToNoteRow( float fBeatNum ) { return int( fBeatNum * ROWS_PER_BEAT + 0.5f); }; // round
inline int BeatToNoteRowNotRounded( float fBeatNum ) { return (int)( fBeatNum * ROWS_PER_BEAT ); }; inline int BeatToNoteRowNotRounded( float fBeatNum ) { return (int)( fBeatNum * ROWS_PER_BEAT ); };
+23 -4
View File
@@ -495,6 +495,9 @@ void PlayerMinus::Step( int col, RageTimer tm )
ASSERT( col >= 0 && col <= GetNumTracks() ); ASSERT( col >= 0 && col <= GetNumTracks() );
//
// Check for step on a TapNote
//
int iIndexOverlappingNote = GetClosestNote( col, GAMESTATE->m_fSongBeat, int iIndexOverlappingNote = GetClosestNote( col, GAMESTATE->m_fSongBeat,
StepSearchDistanceForwards * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.m_fMusicRate, StepSearchDistanceForwards * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.m_fMusicRate,
StepSearchDistanceBackwards * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.m_fMusicRate ); StepSearchDistanceBackwards * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.m_fMusicRate );
@@ -557,8 +560,23 @@ void PlayerMinus::Step( int col, RageTimer tm )
} }
if( tn == TAP_MINE ) switch( tn )
{ {
// case TAP_ATTACK:
// // stepped too close to mine?
// if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowAttackSeconds )
// {
// m_soundAttack.Play();
// score = TNS_MISS;
// // put attack in effect
// }
// else
// {
// score = TNS_NONE;
// }
// break;
case TAP_MINE:
// stepped too close to mine? // stepped too close to mine?
if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowMineSeconds ) if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowMineSeconds )
{ {
@@ -575,9 +593,9 @@ void PlayerMinus::Step( int col, RageTimer tm )
{ {
score = TNS_NONE; score = TNS_NONE;
} }
} break;
else // not a mine
{ default: // not a mine
if(GAMESTATE->m_CurGame == GAME_EZ2) if(GAMESTATE->m_CurGame == GAME_EZ2)
{ {
/* 1 is normal. 2 means scoring is half as hard; .5 means it's twice as hard. */ /* 1 is normal. 2 means scoring is half as hard; .5 means it's twice as hard. */
@@ -599,6 +617,7 @@ void PlayerMinus::Step( int col, RageTimer tm )
else if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowBooSeconds ) score = TNS_BOO; else if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowBooSeconds ) score = TNS_BOO;
else score = TNS_NONE; else score = TNS_NONE;
} }
break;
} }
break; break;
} }
+8 -12
View File
@@ -677,17 +677,6 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
} }
} }
// check for to see if the user intended to remove an AttackNote
for( i=0; i<m_NoteFieldEdit.GetNumAttackNotes(); i++ )
{
const AttackNote& an = m_NoteFieldEdit.GetAttackNote(i);
if( an.fBeat == fSongBeat && an.iTrack == iCol )
{
m_NoteFieldEdit.RemoveAttackNote( i );
return;
}
}
if( m_NoteFieldEdit.GetTapNote(iCol, iSongIndex) != TAP_EMPTY ) if( m_NoteFieldEdit.GetTapNote(iCol, iSongIndex) != TAP_EMPTY )
{ {
m_NoteFieldEdit.SetTapNote( iCol, iSongIndex, TAP_EMPTY ); m_NoteFieldEdit.SetTapNote( iCol, iSongIndex, TAP_EMPTY );
@@ -1286,7 +1275,14 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{ {
PlayerOptions poChosen = GAMESTATE->m_PlayerOptions[PLAYER_1]; PlayerOptions poChosen = GAMESTATE->m_PlayerOptions[PLAYER_1];
CString sMods = poChosen.GetString(); CString sMods = poChosen.GetString();
m_NoteFieldEdit.AddAttackNote( AttackNote(g_iLastInsertAttackTrack,GAMESTATE->m_fSongBeat,sMods,g_fLastInsertAttackDurationSeconds) ); const int iSongIndex = BeatToNoteRow( GAMESTATE->m_fSongBeat );
Attack attack;
attack.level = ATTACK_LEVEL_1; // does this matter?
attack.fSecsRemaining = g_fLastInsertAttackDurationSeconds;
attack.sModifier = sMods;
m_NoteFieldEdit.AddAttackNote( g_iLastInsertAttackTrack, iSongIndex, attack );
GAMESTATE->RestoreSelectedOptions(); // restore the edit and playback options GAMESTATE->RestoreSelectedOptions(); // restore the edit and playback options
} }
break; break;