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);
}
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 )
{
m_AttackNotes.erase( m_AttackNotes.begin()+index );
}
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(); )
// find first unused attack index
TapNote tn;
for( tn = TAP_ATTACK_BEGIN; tn<=TAP_ATTACK_END; tn++ )
{
// Shuffle with other AttackNotes that are on the same row.
// Lame shuffle...
for( int j=i+1; j<m_AttackNotes.size(); j++ )
if( m_AttackMap.find(tn) == m_AttackMap.end() ) // this TapNote value is free to use
goto done_searching;
}
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 )
break; // stop searching
if( rand()%2 )
swap( m_AttackNotes[i].fBeat, m_AttackNotes[j].fBeat );
TapNote tn = GetTapNote(t, r);
if( IsTapAttack( tn ) )
mapAttackToNothing[tn] = 1;
}
}
// 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
{
return BeatToNoteRow( GetFirstBeat() );
@@ -677,5 +703,3 @@ int NoteData::GetNumTracksHeldAtRow( int row )
GetTracksHeldAtRow( row, viTracks );
return viTracks.size();
}
+11 -8
View File
@@ -15,6 +15,8 @@
*/
#include "NoteTypes.h"
#include <map>
#include "Attack.h"
class NoteData
@@ -25,7 +27,7 @@ class NoteData
vector<HoldNote> m_HoldNotes;
vector<AttackNote> m_AttackNotes;
map<TapNote,Attack> m_AttackMap;
/* Pad m_TapNotes so it includes the row "rows". */
void PadTapNotes(int rows);
@@ -134,20 +136,22 @@ public:
void GetTracksHeldAtRow( int row, vector<int>& viTracksOut );
int GetNumTracksHeldAtRow( int row );
//
// used in edit/record
//
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
void RemoveHoldNote( int index );
HoldNote &GetHoldNote( int index ) { return m_HoldNotes[index]; }
const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; }
// used in edit/record
void AddAttackNote( AttackNote an ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
void RemoveAttackNote( int index );
const AttackNote& GetAttackNote( int index ) { return m_AttackNotes[index]; }
void ShuffleAttackNotesOnSameRow();
void AddAttackNote( int track, int row, Attack attack );
void PruneUnusedAttacksFromMap(); // slow
const Attack& GetAttackAt( int track, int row );
// remove Attacks with SetTapNote(TAP_EMPTY)
//
// statistics
//
/* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need
* accuracy.) */
float GetMaxBeat() const { return NoteRowToBeat(GetMaxRow()); }
@@ -164,7 +168,6 @@ public:
/* 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 { return m_HoldNotes.size(); }
int GetNumAttackNotes() const { return m_AttackNotes.size(); }
// Transformations
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 bIsMine = (tn == TAP_MINE);
bool bIsAttack = IsTapAttack(tn);
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(i) );
NoteDisplayCols *nd = CurDisplay->second;
nd->display[c].DrawTap( c, NoteRowToBeat(i), bHoldNoteBeginsOnThisBeat, bIsAddition, bIsMine, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, 1, m_fYReverseOffsetPixels );
}
//
// 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 )
if( bIsAttack )
{
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
// 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
{
@@ -132,15 +137,6 @@ struct HoldNote
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 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() );
//
// Check for step on a TapNote
//
int iIndexOverlappingNote = GetClosestNote( col, GAMESTATE->m_fSongBeat,
StepSearchDistanceForwards * 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?
if( fScaledSecondsFromPerfect <= PREFSMAN->m_fJudgeWindowMineSeconds )
{
@@ -575,9 +593,9 @@ void PlayerMinus::Step( int col, RageTimer tm )
{
score = TNS_NONE;
}
}
else // not a mine
{
break;
default: // not a mine
if(GAMESTATE->m_CurGame == GAME_EZ2)
{
/* 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 score = TNS_NONE;
}
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 )
{
m_NoteFieldEdit.SetTapNote( iCol, iSongIndex, TAP_EMPTY );
@@ -1286,7 +1275,14 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{
PlayerOptions poChosen = GAMESTATE->m_PlayerOptions[PLAYER_1];
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
}
break;