simplify TapAttack storage:

store attack info in TapNote
  in the SMNoteData string, store the attack params inline (like with keysounds)
play keysounds when hit
  still doesn't play keysounds on a miss
  still doesn't play autoKeysounds
This commit is contained in:
Chris Danford
2004-10-23 23:41:49 +00:00
parent 056b85f83e
commit 3ac1dba044
23 changed files with 395 additions and 499 deletions
+18 -2
View File
@@ -14,10 +14,26 @@ struct Attack
bool bOn; // for GAMESTATE
bool bGlobal; // true for song-wide course mods
void MakeBlank() { sModifier=""; fStartSecond = -1; bOn = false; bGlobal = false; }
Attack() { MakeBlank(); }
Attack(
AttackLevel level_,
float fStartSecond_,
float fSecsRemaining_,
CString sModifier_,
bool bOn_,
bool bGlobal_ )
{
level = level_;
fStartSecond = fStartSecond_;
fSecsRemaining = fSecsRemaining_;
sModifier = sModifier_;
bOn = bOn_;
bGlobal = bGlobal_;
}
void GetAttackBeats( const Song *song, PlayerNumber pn, float &fStartBeat, float &fEndBeat ) const;
bool IsBlank() { return sModifier.empty(); }
void MakeBlank() { sModifier=""; }
Attack() { fStartSecond = -1; bOn = false; bGlobal = false; }
bool operator== ( const Attack &rhs ) const;
bool ContainsTransformOrTurn() const;
};
+7 -5
View File
@@ -1207,18 +1207,20 @@ void GameState::SetNoteSkinForBeatRange( PlayerNumber pn, CString sNoteSkin, flo
/* 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 GameState::LaunchAttack( PlayerNumber target, Attack a )
void GameState::LaunchAttack( PlayerNumber target, const Attack& a )
{
LOG->Trace( "Launch attack '%s' against P%d at %f", a.sModifier.c_str(), target+1, a.fStartSecond );
Attack attack = a;
/* If fStartSecond is -1, 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 -1 in, so Player::Update
* knows to apply attack transforms correctly. (yuck) */
m_ModsToApply[target].push_back( a );
if( a.fStartSecond == -1 )
a.fStartSecond = this->m_fMusicSeconds;
m_ActiveAttacks[target].push_back( a );
m_ModsToApply[target].push_back( attack );
if( attack.fStartSecond == -1 )
attack.fStartSecond = this->m_fMusicSeconds;
m_ActiveAttacks[target].push_back( attack );
this->RebuildPlayerOptionsFromActiveAttacks( target );
}
+1 -1
View File
@@ -198,7 +198,7 @@ public:
bool m_bAttackBeganThisUpdate[NUM_PLAYERS]; // flag for other objects to watch (play sounds)
bool m_bAttackEndedThisUpdate[NUM_PLAYERS]; // flag for other objects to watch (play sounds)
void GetUndisplayedBeats( PlayerNumber pn, float TotalSeconds, float &StartBeat, float &EndBeat ) const; // only meaningful when a NoteField is in use
void LaunchAttack( PlayerNumber target, Attack aa );
void LaunchAttack( PlayerNumber target, const Attack& a );
void RebuildPlayerOptionsFromActiveAttacks( PlayerNumber pn );
void RemoveAllActiveAttacks(); // called on end of song
void RemoveActiveAttacksForPlayer( PlayerNumber pn, AttackLevel al=NUM_ATTACK_LEVELS /*all*/ );
+13 -79
View File
@@ -77,20 +77,11 @@ void NoteData::CopyRange( const NoteData& from, int iFromIndexBegin, int iFromIn
for( int t=0; t<GetNumTracks(); t++ )
{
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( From, t, from, iFromIndexBegin, iFromIndexEnd )
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( From, t, iFrom, iFromIndexBegin, iFromIndexEnd )
{
int to = iToIndexBegin + from - iFromIndexBegin;
TapNote tn = From.GetTapNote( t, from );
if( tn.type == TapNote::attack )
{
Attack attack = From.GetAttackAt( t, from );
To.SetTapAttackNote( t, to, attack );
}
else
{
To.SetTapNote( t, to, tn );
}
int iTo = iToIndexBegin + iFrom - iFromIndexBegin;
TapNote tn = From.GetTapNote( t, iFrom );
To.SetTapNote( t, iTo, tn );
}
}
@@ -110,7 +101,6 @@ void NoteData::CopyAll( const NoteData& from )
for( int c=0; c<GetNumTracks(); c++ )
m_TapNotes[c] = from.m_TapNotes[c];
m_HoldNotes = from.m_HoldNotes;
m_AttackMap = from.m_AttackMap;
}
bool NoteData::IsRowEmpty( int index ) const
@@ -264,72 +254,18 @@ int NoteData::GetMatchingHoldNote( const HoldNote &hn ) const
}
void NoteData::SetTapAttackNote( int track, int row, Attack attack )
void NoteData::SetTapAttackNote( int track, int row, CString sModifiers, float fDurationSeconds )
{
PruneUnusedAttacksFromMap();
// find first unused attack index
for( unsigned i=0; i<MAX_NUM_ATTACKS; i++ )
{
if( m_AttackMap.find(i) == m_AttackMap.end() ) // this index is free to use
{
m_AttackMap[i] = attack;
TapNote tn;
tn.Set(
TapNote::attack,
TapNote::original,
true,
(uint8_t)i,
false,
0 );
SetTapNote( track, row, tn );
return;
}
}
// TODO: need to increase MAX_NUM_ATTACKS or handle "no more room" case
ASSERT(0);
TapNote tn(
TapNote::attack,
TapNote::original,
sModifiers,
fDurationSeconds,
false,
0 );
SetTapNote( track, row, tn );
}
void NoteData::PruneUnusedAttacksFromMap()
{
// Add all used AttackNote index values to a map.
set<unsigned> setUsedIndices;
for( int t=0; t<GetNumTracks(); t++ )
{
FOREACH_NONEMPTY_ROW_IN_TRACK( *this, t, r )
{
TapNote tn = GetTapNote(t, r);
if( tn.type == TapNote::attack )
setUsedIndices.insert( tn.attackIndex );
}
}
// Remove all items from m_AttackMap that don't have corresponding
// TapNotes in use.
for( unsigned i=0; i<MAX_NUM_ATTACKS; i++ )
{
bool bInAttackMap = m_AttackMap.find(i) != m_AttackMap.end();
bool bActuallyUsed = setUsedIndices.find(i) != setUsedIndices.end();
if( bActuallyUsed && !bInAttackMap )
ASSERT(0); // something earlier than us didn't enforce consistency
if( bInAttackMap && !bActuallyUsed )
m_AttackMap.erase( i );
}
}
const Attack& NoteData::GetAttackAt( int track, int row )
{
TapNote tn = GetTapNote(track, row);
ASSERT( tn.type == TapNote::attack ); // don't call this if the TapNote here isn't an attack
map<unsigned,Attack>::iterator iter = m_AttackMap.find( tn.attackIndex );
ASSERT( iter != m_AttackMap.end() );
return iter->second;
}
int NoteData::GetFirstRow() const
{
int iEarliestRowFoundSoFar = -1;
@@ -718,8 +654,6 @@ void NoteData::LoadTransformed( const NoteData& original, int iNewNumTracks, con
}
Convert4sToHoldNotes();
m_AttackMap = Original.GetAttackMap();
}
void NoteData::PadTapNotes(int rows)
+4 -12
View File
@@ -26,8 +26,6 @@ class NoteData
vector<HoldNote> m_HoldNotes;
map<unsigned,Attack> m_AttackMap;
/* Pad m_TapNotes so it includes the row "rows". */
void PadTapNotes(int rows);
@@ -44,10 +42,6 @@ public:
int GetNumTracks() const;
void SetNumTracks( int iNewNumTracks );
// TODO: Think of better accessors
const map<unsigned,Attack>& GetAttackMap() const { return m_AttackMap; }
map<unsigned,Attack>& GetAttackMap() { return m_AttackMap; }
/* Return the note at the given track and row. Row may be out of
* range; pretend the song goes on with TAP_EMPTYs indefinitely. */
inline TapNote GetTapNote(unsigned track, int row) const
@@ -74,8 +68,8 @@ public:
bool GetNextTapNoteRowForTrack( int track, int &rowInOut ) const;
bool GetNextTapNoteRowForAllTracks( int &rowInOut ) const;
void MoveTapNoteTrack(int dest, int src);
void SetTapNote(int track, int row, TapNote t);
void MoveTapNoteTrack( int dest, int src );
void SetTapNote( int track, int row, TapNote tn );
void ClearRange( int iNoteIndexBegin, int iNoteIndexEnd );
void ClearAll();
@@ -112,10 +106,8 @@ public:
const HoldNote &GetHoldNote( int index ) const { ASSERT( index < (int) m_HoldNotes.size() ); return m_HoldNotes[index]; }
int GetMatchingHoldNote( const HoldNote &hn ) const;
void SetTapAttackNote( int track, int row, Attack attack );
void PruneUnusedAttacksFromMap(); // slow
const Attack& GetAttackAt( int track, int row );
// remove Attacks with SetTapNote(TAP_EMPTY)
// remove me
void SetTapAttackNote( int track, int row, CString sModifiers, float fDurationSeconds );
//
// statistics
+177 -227
View File
@@ -45,248 +45,205 @@ NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMe
return nt;
}
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData, CString sSMAttackData )
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData )
{
//
// Load note data
//
/* Clear notes, but keep the same number of tracks. */
int iNumTracks = out.GetNumTracks();
out.Init();
out.SetNumTracks( iNumTracks );
// strip comments out of sSMNoteData
while( sSMNoteData.Find("//") != -1 )
{
//
// Load note data
//
/* Clear notes, but keep the same number of tracks. */
int iNumTracks = out.GetNumTracks();
out.Init();
out.SetNumTracks( iNumTracks );
// strip comments out of sSMNoteData
while( sSMNoteData.Find("//") != -1 )
{
int iIndexCommentStart = sSMNoteData.Find("//");
int iIndexCommentEnd = sSMNoteData.Find("\n", iIndexCommentStart);
if( iIndexCommentEnd == -1 ) // comment doesn't have an end?
sSMNoteData.erase( iIndexCommentStart, 2 );
else
sSMNoteData.erase( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart );
}
CStringArray asMeasures;
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
{
CString &sMeasureString = asMeasures[m];
TrimLeft(sMeasureString);
TrimRight(sMeasureString);
CStringArray asMeasureLines;
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
for( unsigned l=0; l<asMeasureLines.size(); l++ )
{
CString &sMeasureLine = asMeasureLines[l];
TrimLeft(sMeasureLine);
TrimRight(sMeasureLine);
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
// if( m_iNumTracks != sMeasureLine.GetLength() )
// RageException::Throw( "Actual number of note columns (%d) is different from the StepsType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
const char *p = sMeasureLine;
int iTrack = 0;
while( *p )
{
TapNote tn;
char ch = *p;
switch( ch )
{
case '0': tn = TAP_EMPTY; break;
case '1': tn = TAP_ORIGINAL_TAP; break;
case '2': tn = TAP_ORIGINAL_HOLD_HEAD; break;
case '3': tn = TAP_ORIGINAL_HOLD_TAIL; break;
// case 'm':
// Don't be loose with the definition. Use only 'M' since
// that's what we've been writing to disk. -Chris
case 'M': tn = TAP_ORIGINAL_MINE; break;
default:
if( ch >= 'a' && ch <= 'z' )
{
tn.Set(
TapNote::attack,
TapNote::original,
true,
ch - 'a',
false,
0 );
}
else
{
/* Invalid data. We don't want to assert, since there might
* simply be invalid data in an .SM, and we don't want to die
* due to invalid data. We should probably check for this when
* we load SM data for the first time ... */
// ASSERT(0);
tn = TAP_EMPTY;
}
break;
}
p++;
// look for optional keysound index (e.g. "[123]")
if( *p == '[' )
{
p++;
unsigned uKeysoundIndex = 0;
if( 1 == sscanf( p, "%u]", &uKeysoundIndex ) ) // not fatal if this fails due to malformed data
{
tn.bKeysound = true;
tn.keysoundIndex = (uint16_t)uKeysoundIndex;
}
// skip past the ']'
while( *p )
{
if( *p == ']' )
{
p++;
break;
}
p++;
}
}
out.SetTapNote( iTrack, iIndex, tn );
iTrack++;
}
}
}
out.Convert2sAnd3sToHoldNotes();
int iIndexCommentStart = sSMNoteData.Find("//");
int iIndexCommentEnd = sSMNoteData.Find("\n", iIndexCommentStart);
if( iIndexCommentEnd == -1 ) // comment doesn't have an end?
sSMNoteData.erase( iIndexCommentStart, 2 );
else
sSMNoteData.erase( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart );
}
CStringArray asMeasures;
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
{
//
// Load attack data
//
CStringArray asLines;
split( sSMAttackData, ",", asLines, true );
CString &sMeasureString = asMeasures[m];
TrimLeft(sMeasureString);
TrimRight(sMeasureString);
for( unsigned i=0; i<asLines.size(); i++ )
CStringArray asMeasureLines;
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
for( unsigned l=0; l<asMeasureLines.size(); l++ )
{
CString& sLine = asLines[i];
TrimLeft( sLine );
TrimRight( sLine );
CString &sMeasureLine = asMeasureLines[l];
TrimLeft(sMeasureLine);
TrimRight(sMeasureLine);
if( sLine.empty() )
continue; // skip
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
CStringArray asBits;
split( sLine, "=", asBits, true );
// if( m_iNumTracks != sMeasureLine.GetLength() )
// RageException::Throw( "Actual number of note columns (%d) is different from the StepsType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
if( asBits.size() < 3 )
continue;
if( asBits[0].empty() )
continue;
int attack_index = asBits[0][0] - 'a';
Attack attack;
attack.level = ATTACK_LEVEL_1;
attack.sModifier = asBits[1];
attack.sModifier.Replace( '.', ',' ); // we couldn't use comma here because the map item separator is a comma
attack.fSecsRemaining = strtof( asBits[2], NULL );
out.GetAttackMap()[attack_index] = attack;
}
}
}
void NoteDataUtil::GetSMNoteDataString( const NoteData &in_, CString &notes_out, CString &attacks_out )
{
{
//
// Get note data
//
NoteData in;
in.To2sAnd3s( in_ );
float fLastBeat = in.GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
CString &sRet = notes_out;
sRet = "";
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
if( m )
sRet.append( 1, ',' );
NoteType nt = GetSmallestNoteTypeForMeasure( in, m );
int iRowSpacing;
if( nt == NOTE_TYPE_INVALID )
iRowSpacing = 1;
else
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
sRet += ssprintf(" // measure %d\n", m+1);
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
const char *p = sMeasureLine;
int iTrack = 0;
while( *p )
{
for( int t=0; t<in.GetNumTracks(); t++ )
TapNote tn;
char ch = *p;
switch( ch )
{
TapNote tn = in.GetTapNote(t, r);
char c;
switch( tn.type )
{
case TapNote::empty: c = '0'; break;
case TapNote::tap: c = '1'; break;
case TapNote::hold_head: c = '2'; break;
case TapNote::hold_tail: c = '3'; break;
case TapNote::mine: c = 'M'; break;
case TapNote::attack: c = 'a' + (char)tn.attackIndex ; break;
default:
ASSERT(0);
c = '0';
break;
}
sRet.append(1, c);
if( tn.bKeysound )
{
sRet.append( ssprintf("[%u]",tn.keysoundIndex) );
}
case '0': tn = TAP_EMPTY; break;
case '1': tn = TAP_ORIGINAL_TAP; break;
case '2': tn = TAP_ORIGINAL_HOLD_HEAD; break;
case '3': tn = TAP_ORIGINAL_HOLD_TAIL; break;
// case 'm':
// Don't be loose with the definition. Use only 'M' since
// that's what we've been writing to disk. -Chris
case 'M': tn = TAP_ORIGINAL_MINE; break;
case 'A': tn = TAP_ORIGINAL_ATTACK; break;
default:
/* Invalid data. We don't want to assert, since there might
* simply be invalid data in an .SM, and we don't want to die
* due to invalid data. We should probably check for this when
* we load SM data for the first time ... */
// ASSERT(0);
tn = TAP_EMPTY;
break;
}
sRet.append(1, '\n');
p++;
// look for optional attack info (e.g. "{tipsy,50% drunk:15.2}")
if( *p == '{' )
{
p++;
// TODO: this buffer could overflow
char szModifiers[256] = "";
float fDurationSeconds = 0;
if( 2 == sscanf( p, "%[^:]:%f}", szModifiers, &fDurationSeconds ) ) // not fatal if this fails due to malformed data
{
tn.type = TapNote::attack;
tn.sAttackModifiers = szModifiers;
tn.fAttackDurationSeconds = fDurationSeconds;
}
// skip past the '}'
while( *p )
{
if( *p == '}' )
{
p++;
break;
}
p++;
}
}
// look for optional keysound index (e.g. "[123]")
if( *p == '[' )
{
p++;
int iKeysoundIndex = 0;
if( 1 == sscanf( p, "%d]", &iKeysoundIndex ) ) // not fatal if this fails due to malformed data
{
tn.bKeysound = true;
tn.iKeysoundIndex = iKeysoundIndex;
}
// skip past the ']'
while( *p )
{
if( *p == ']' )
{
p++;
break;
}
p++;
}
}
out.SetTapNote( iTrack, iIndex, tn );
iTrack++;
}
}
}
out.Convert2sAnd3sToHoldNotes();
}
void NoteDataUtil::GetSMNoteDataString( const NoteData &in_, CString &notes_out )
{
//
// Get note data
//
NoteData in;
in.To2sAnd3s( in_ );
float fLastBeat = in.GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
CString &sRet = notes_out;
sRet = "";
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
//
// Get attack data
//
CStringArray asLines;
if( m )
sRet.append( 1, ',' );
for( map<unsigned,Attack>::const_iterator iter = in_.GetAttackMap().begin();
iter != in_.GetAttackMap().end();
iter++ )
NoteType nt = GetSmallestNoteTypeForMeasure( in, m );
int iRowSpacing;
if( nt == NOTE_TYPE_INVALID )
iRowSpacing = 1;
else
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
sRet += ssprintf(" // measure %d\n", m+1);
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
{
int attackIndex = iter->first;
char ch = 'a' + (char)attackIndex;
Attack attack = iter->second;
attack.sModifier.Replace( ',', '.' ); // comma is the map item separator
for( int t=0; t<in.GetNumTracks(); t++ )
{
TapNote tn = in.GetTapNote(t, r);
char c;
switch( tn.type )
{
case TapNote::empty: c = '0'; break;
case TapNote::tap: c = '1'; break;
case TapNote::hold_head: c = '2'; break;
case TapNote::hold_tail: c = '3'; break;
case TapNote::mine: c = 'M'; break;
case TapNote::attack: c = 'A'; break;
default:
ASSERT(0);
c = '0';
break;
}
sRet.append(1, c);
asLines.push_back( ssprintf("%c=%s=%f,\n", ch, attack.sModifier.c_str(), attack.fSecsRemaining) );
if( tn.type == TapNote::attack )
{
sRet.append( ssprintf("{%s:%.2f}",tn.sAttackModifiers.c_str(), tn.fAttackDurationSeconds) );
}
if( tn.bKeysound )
{
sRet.append( ssprintf("[%d]",tn.iKeysoundIndex) );
}
}
sRet.append(1, '\n');
}
attacks_out = join( ",", asLines );
}
}
@@ -354,8 +311,6 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o
}
out.Convert4sToHoldNotes();
out.GetAttackMap() = Original.GetAttackMap();
}
void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNewNumTracks )
@@ -1672,12 +1627,7 @@ void NoteDataUtil::AddTapAttacks( NoteData &nd, Song* pSong )
float fBeat = pSong->GetBeatFromElapsedTime( sec );
int iBeat = (int)fBeat;
int iTrack = iBeat % nd.GetNumTracks(); // deterministically calculates track
Attack attack;
attack.fStartSecond = -1;
attack.fSecsRemaining = 15;
attack.sModifier = szAttacks[rand()%ARRAYSIZE(szAttacks)];
attack.level = ATTACK_LEVEL_1;
nd.SetTapAttackNote( iTrack, BeatToNoteRow(fBeat), attack );
nd.SetTapAttackNote( iTrack, BeatToNoteRow(fBeat), szAttacks[rand()%ARRAYSIZE(szAttacks)], 15 );
}
}
+2 -2
View File
@@ -17,8 +17,8 @@ struct RadarValues;
namespace NoteDataUtil
{
NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex );
void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData, CString sSMAttackData );
void GetSMNoteDataString( const NoteData &in, CString &notes_out, CString &attacks_out );
void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData );
void GetSMNoteDataString( const NoteData &in, CString &notes_out );
void LoadTransformedSlidingWindow( const NoteData &in, NoteData &out, int iNewNumTracks );
void LoadOverlapped( const NoteData &in, NoteData &out, int iNewNumTracks );
void LoadTransformedLights( const NoteData &in, NoteData &out, int iNewNumTracks );
+1 -2
View File
@@ -621,9 +621,8 @@ void NoteField::DrawPrimitives()
NoteDisplayCols *nd = CurDisplay->second;
if( bIsAttack )
{
const Attack& attack = GetAttackAt( c, i );
Sprite sprite;
sprite.Load( THEME->GetPathToG("NoteField attack "+attack.sModifier) );
sprite.Load( THEME->GetPathToG("NoteField attack "+tn.sAttackModifiers) );
float fBeat = NoteRowToBeat(i);
SearchForBeat( CurDisplay, NextDisplay, fBeat );
NoteDisplayCols *nd = CurDisplay->second;
+9 -8
View File
@@ -1,14 +1,15 @@
#include "global.h"
#include "NoteTypes.h"
TapNote TAP_EMPTY = { TapNote::empty, TapNote::original, 0 };
TapNote TAP_ORIGINAL_TAP = { TapNote::tap, TapNote::original, 0 };
TapNote TAP_ORIGINAL_HOLD_HEAD = { TapNote::hold_head, TapNote::original, 0 }; // '2'
TapNote TAP_ORIGINAL_HOLD_TAIL = { TapNote::hold_tail, TapNote::original, 0 }; // '3'
TapNote TAP_ORIGINAL_HOLD = { TapNote::hold, TapNote::original, 0 }; // '4'
TapNote TAP_ORIGINAL_MINE = { TapNote::mine, TapNote::original, 0 };
TapNote TAP_ADDITION_TAP = { TapNote::tap, TapNote::addition, 0 };
TapNote TAP_ADDITION_MINE = { TapNote::mine, TapNote::addition, 0 };
TapNote TAP_EMPTY ( TapNote::empty, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_TAP ( TapNote::tap, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_HOLD_HEAD ( TapNote::hold_head, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_HOLD_TAIL ( TapNote::hold_tail, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_HOLD ( TapNote::hold, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_MINE ( TapNote::mine, TapNote::original, "", 0, false, 0 );
TapNote TAP_ORIGINAL_ATTACK ( TapNote::attack, TapNote::original, "", 0, false, 0 );
TapNote TAP_ADDITION_TAP ( TapNote::tap, TapNote::addition, "", 0, false, 0 );
TapNote TAP_ADDITION_MINE ( TapNote::mine, TapNote::addition, "", 0, false, 0 );
float NoteTypeToBeat( NoteType nt )
{
+21 -23
View File
@@ -4,15 +4,14 @@
struct TapNote
{
enum Type {
empty,
empty, // no note here
tap,
hold_head, // graded like a TAP_TAP
hold_tail, /* In 2sand3s mode, holds are deleted and TAP_HOLD_END is added: */
hold, /* In 4s mode, holds and TAP_HOLD_HEAD are deleted and TAP_HOLD is added: */
mine, // don't step!
attack,
};
unsigned type : 3; // no unsigned enum support in VC++
} type;
enum Source {
original, // part of the original NoteData
addition, // additional note added by a transform
@@ -27,44 +26,42 @@ struct TapNote
// then this is triggered automatically to keep the sound going
// 2 - if we're NOT [anything else], we ignore this.
// Equivalent to all 4s aside from the first one.
};
unsigned source : 2; // only valid if type!=empty
} source;
bool bAttack : 1; // true if this note causes an attack when hit
bool bKeysound : 1; // true if this note plays a keysound when hit
// CAREFUL: small fields grouped together for alignment.
// Only valid if type == attack.
CString sAttackModifiers;
float fAttackDurationSeconds;
uint8_t attackIndex; // index into NoteData's vector of attacks
// Only valid if bAttack.
uint16_t keysoundIndex; // index into Song's vector of keysound files.
bool bKeysound; // true if this note plays a keysound when hit
int iKeysoundIndex; // index into Song's vector of keysound files.
// Only valid if bKeysound.
// Some songs have > 256 keysounds.
void Set(
TapNote() {}
TapNote(
Type type_,
Source source_,
bool bAttack_,
uint8_t attackIndex_,
CString sAttackModifiers_,
float fAttackDurationSeconds_,
bool bKeysound_,
uint16_t keysoundIndex_ )
int iKeysoundIndex_ )
{
type = type_;
source = source_;
bAttack = bAttack_;
attackIndex = attackIndex_;
sAttackModifiers = sAttackModifiers_;
fAttackDurationSeconds = fAttackDurationSeconds_;
bKeysound = bKeysound_;
keysoundIndex = keysoundIndex_;
iKeysoundIndex = iKeysoundIndex_;
}
bool operator==( const TapNote &other )
{
#define COMPARE(x) if(x!=other.x) return false;
COMPARE(type);
COMPARE(source);
COMPARE(bAttack);
COMPARE(sAttackModifiers);
COMPARE(fAttackDurationSeconds);
COMPARE(bKeysound);
COMPARE(attackIndex);
COMPARE(keysoundIndex);
COMPARE(iKeysoundIndex);
#undef COMPARE
return true;
}
@@ -78,6 +75,7 @@ extern TapNote TAP_ORIGINAL_HOLD_HEAD; // '2'
extern TapNote TAP_ORIGINAL_HOLD_TAIL; // '3'
extern TapNote TAP_ORIGINAL_HOLD; // '4'
extern TapNote TAP_ORIGINAL_MINE; // 'M'
extern TapNote TAP_ORIGINAL_ATTACK; // 'A'
extern TapNote TAP_ADDITION_TAP;
extern TapNote TAP_ADDITION_MINE;
+39 -35
View File
@@ -65,6 +65,7 @@ enum BmsTrack
BMS_P2_TURN,
BMS_P2_KEY6,
BMS_P2_KEY7,
BMS_AUTO_KEYSOUND,
NUM_BMS_TRACKS,
BMS_TRACK_INVALID,
};
@@ -83,22 +84,23 @@ static bool ConvertRawTrackToTapNote( int iRawTrack, BmsTrack &bmsTrackOut, bool
switch( iRawTrack )
{
case 11: bmsTrackOut = BMS_P1_KEY1; break;
case 12: bmsTrackOut = BMS_P1_KEY2; break;
case 13: bmsTrackOut = BMS_P1_KEY3; break;
case 14: bmsTrackOut = BMS_P1_KEY4; break;
case 15: bmsTrackOut = BMS_P1_KEY5; break;
case 16: bmsTrackOut = BMS_P1_TURN; break;
case 18: bmsTrackOut = BMS_P1_KEY6; break;
case 19: bmsTrackOut = BMS_P1_KEY7; break;
case 21: bmsTrackOut = BMS_P2_KEY1; break;
case 22: bmsTrackOut = BMS_P2_KEY2; break;
case 23: bmsTrackOut = BMS_P2_KEY3; break;
case 24: bmsTrackOut = BMS_P2_KEY4; break;
case 25: bmsTrackOut = BMS_P2_KEY5; break;
case 26: bmsTrackOut = BMS_P2_TURN; break;
case 28: bmsTrackOut = BMS_P2_KEY6; break;
case 29: bmsTrackOut = BMS_P2_KEY7; break;
case 1: bmsTrackOut = BMS_AUTO_KEYSOUND; break;
case 11: bmsTrackOut = BMS_P1_KEY1; break;
case 12: bmsTrackOut = BMS_P1_KEY2; break;
case 13: bmsTrackOut = BMS_P1_KEY3; break;
case 14: bmsTrackOut = BMS_P1_KEY4; break;
case 15: bmsTrackOut = BMS_P1_KEY5; break;
case 16: bmsTrackOut = BMS_P1_TURN; break;
case 18: bmsTrackOut = BMS_P1_KEY6; break;
case 19: bmsTrackOut = BMS_P1_KEY7; break;
case 21: bmsTrackOut = BMS_P2_KEY1; break;
case 22: bmsTrackOut = BMS_P2_KEY2; break;
case 23: bmsTrackOut = BMS_P2_KEY3; break;
case 24: bmsTrackOut = BMS_P2_KEY4; break;
case 25: bmsTrackOut = BMS_P2_KEY5; break;
case 26: bmsTrackOut = BMS_P2_TURN; break;
case 28: bmsTrackOut = BMS_P2_KEY6; break;
case 29: bmsTrackOut = BMS_P2_KEY7; break;
default: // unknown track
return false;
}
@@ -176,7 +178,7 @@ static StepsType DetermineStepsType( int iPlayer, const NoteData &nd )
}
}
bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CString,unsigned> &mapWavIdToKeysoundIndex )
bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CString,int> &mapWavIdToKeysoundIndex )
{
LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() );
@@ -185,19 +187,19 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CSt
// BMS player code. Fill in below and use to determine StepsType.
int iPlayer = -1;
NoteData* pNoteData = new NoteData;
pNoteData->SetNumTracks( NUM_BMS_TRACKS );
NoteData ndNotes;
ndNotes.SetNumTracks( NUM_BMS_TRACKS );
RageFile file;
if( !file.Open(sPath) )
RageException::Throw( "Failed to open \"%s\" for reading: %s", sPath.c_str(), file.GetError().c_str() );
while( !file.AtEOF() )
{
CString line;
if( file.GetLine( line ) == -1 )
{
LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), file.GetError().c_str() );
delete pNoteData;
return false;
}
@@ -276,11 +278,11 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CSt
if( sNoteId != "00" )
{
TapNote tn = TAP_ORIGINAL_TAP;
map<CString,unsigned>::const_iterator it = mapWavIdToKeysoundIndex.find(sNoteId);
map<CString,int>::const_iterator it = mapWavIdToKeysoundIndex.find(sNoteId);
if( it != mapWavIdToKeysoundIndex.end() )
{
tn.bKeysound = true;
tn.keysoundIndex = (uint16_t)it->second;
tn.iKeysoundIndex = it->second;
}
vTapNotes.push_back( tn );
}
@@ -304,22 +306,27 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CSt
bool bIsHold;
if( ConvertRawTrackToTapNote(iRawTrackNum, bmsTrack, bIsHold) )
{
TapNote tn = vTapNotes[j];
tn.type = bIsHold ? TapNote::hold_head : TapNote::tap;
pNoteData->SetTapNote(bmsTrack, iNoteIndex, tn);
if( bmsTrack == BMS_AUTO_KEYSOUND )
{
}
else
{
TapNote tn = vTapNotes[j];
tn.type = bIsHold ? TapNote::hold_head : TapNote::tap;
ndNotes.SetTapNote( bmsTrack, iNoteIndex, tn );
}
}
}
}
}
}
out.m_StepsType = DetermineStepsType( iPlayer, *pNoteData );
out.m_StepsType = DetermineStepsType( iPlayer, ndNotes );
// we're done reading in all of the BMS values
if( out.m_StepsType == STEPS_TYPE_INVALID )
{
LOG->Warn( "Couldn't determine note type of file '%s'", sPath.c_str() );
delete pNoteData;
return false;
}
@@ -425,14 +432,11 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map<CSt
ASSERT(0);
}
NoteData* pNoteData2 = new NoteData;
pNoteData2->SetNumTracks( iNumNewTracks );
pNoteData2->LoadTransformed( *pNoteData, iNumNewTracks, iTransformNewToOld );
NoteData noteData2;
noteData2.SetNumTracks( iNumNewTracks );
noteData2.LoadTransformed( ndNotes, iNumNewTracks, iTransformNewToOld );
out.SetNoteData(*pNoteData2);
delete pNoteData;
delete pNoteData2;
out.SetNoteData( noteData2 );
out.TidyUpData();
@@ -460,7 +464,7 @@ bool BMSLoader::LoadFromDir( CString sDir, Song &out )
// This maps from a BMS wav ID (e.g. "1A") to an entry in the Song's
// keysound vector. Fill this in below while parsing the song data.
map<CString,unsigned> mapWavIdToKeysoundIndex;
map<CString,int> mapWavIdToKeysoundIndex;
CString sPath = out.GetSongDir() + arrayBMSFileNames[0];
+1 -1
View File
@@ -9,7 +9,7 @@ class Steps;
class BMSLoader: public NotesLoader
{
bool LoadFromBMSFile( const CString &sPath, Steps &out1, const map<CString,unsigned> &mapWavIdToKeysoundIndex );
bool LoadFromBMSFile( const CString &sPath, Steps &out1, const map<CString,int> &mapWavIdToKeysoundIndex );
void SlideDuplicateDifficulties( Song &p );
+6 -11
View File
@@ -17,16 +17,12 @@ void SMLoader::LoadFromSMTokens(
CString sMeter,
CString sRadarValues,
CString sNoteData,
CString sAttackData,
Steps &out
)
{
TrimLeft(sStepsType);
TrimRight(sStepsType);
TrimLeft(sDescription);
TrimRight(sDescription);
TrimLeft(sDifficulty);
TrimRight(sDifficulty);
TrimLeft(sStepsType); TrimRight(sStepsType);
TrimLeft(sDescription); TrimRight(sDescription);
TrimLeft(sDifficulty); TrimRight(sDifficulty);
// LOG->Trace( "Steps::LoadFromSMTokens()" );
@@ -55,7 +51,7 @@ void SMLoader::LoadFromSMTokens(
out.SetRadarValues( v );
}
out.SetSMNoteData(sNoteData, sAttackData);
out.SetSMNoteData(sNoteData);
out.TidyUpData();
}
@@ -363,8 +359,7 @@ bool SMLoader::LoadFromSMFile( CString sPath, Song &out )
sParams[3],
sParams[4],
sParams[5],
sParams[6],
(iNumParams>=8)?sParams[7]:CString(""),
sParams[6],
*pNewNotes );
out.AddSteps( pNewNotes );
@@ -462,7 +457,7 @@ bool SMLoader::LoadEdit( CString sEditFilePath, ProfileSlot slot )
}
LoadFromSMTokens(
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], (iNumParams>=8)?sParams[7]:CString(""),
sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6],
*pNewNotes);
pNewNotes->SetLoadedFromProfile( slot );
-1
View File
@@ -18,7 +18,6 @@ class SMLoader: public NotesLoader
CString sMeter,
CString sRadarValues,
CString sNoteData,
CString sAttackData,
Steps &out);
bool FromCache;
+14 -14
View File
@@ -9,20 +9,20 @@
#include "RageFile.h"
/* Output is an angle bracket expression without angle brackets, eg. "468". */
CString NotesWriterDWI::NotesToDWIString( const TapNote cNoteCols[6] )
CString NotesWriterDWI::NotesToDWIString( const TapNote tnCols[6] )
{
const char dirs[] = { '4', 'C', '2', '8', 'D', '6' };
CString taps, holds, ret;
for( int col = 0; col < 6; ++col )
{
switch( cNoteCols[col].type )
switch( tnCols[col].type )
{
case TapNote::empty:
case TapNote::mine:
continue;
}
if( cNoteCols[col].type == TapNote::hold_head )
if( tnCols[col].type == TapNote::hold_head )
holds += dirs[col];
else
taps += dirs[col];
@@ -81,21 +81,21 @@ CString NotesWriterDWI::NotesToDWIString( const TapNote cNoteCols[6] )
return '0';*/
}
CString NotesWriterDWI::NotesToDWIString( TapNote cNoteCol1, TapNote cNoteCol2, TapNote cNoteCol3, TapNote cNoteCol4, TapNote cNoteCol5, TapNote cNoteCol6 )
CString NotesWriterDWI::NotesToDWIString( TapNote tnCol1, TapNote tnCol2, TapNote tnCol3, TapNote tnCol4, TapNote tnCol5, TapNote tnCol6 )
{
TapNote cNoteCols[6];
cNoteCols[0] = cNoteCol1;
cNoteCols[1] = cNoteCol2;
cNoteCols[2] = cNoteCol3;
cNoteCols[3] = cNoteCol4;
cNoteCols[4] = cNoteCol5;
cNoteCols[5] = cNoteCol6;
return NotesToDWIString( cNoteCols );
TapNote tnCols[6];
tnCols[0] = tnCol1;
tnCols[1] = tnCol2;
tnCols[2] = tnCol3;
tnCols[3] = tnCol4;
tnCols[4] = tnCol5;
tnCols[5] = tnCol6;
return NotesToDWIString( tnCols );
}
CString NotesWriterDWI::NotesToDWIString( TapNote cNoteCol1, TapNote cNoteCol2, TapNote cNoteCol3, TapNote cNoteCol4 )
CString NotesWriterDWI::NotesToDWIString( TapNote tnCol1, TapNote tnCol2, TapNote tnCol3, TapNote tnCol4 )
{
return NotesToDWIString( cNoteCol1, TAP_EMPTY, cNoteCol2, cNoteCol3, TAP_EMPTY, cNoteCol4 );
return NotesToDWIString( tnCol1, TAP_EMPTY, tnCol2, tnCol3, TAP_EMPTY, tnCol4 );
}
char NotesWriterDWI::OptimizeDWIPair( char c1, char c2 )
+2 -15
View File
@@ -157,26 +157,13 @@ void NotesWriterSM::WriteSMNotesTag( const Song &song, const Steps &in, RageFile
f.Write( ssprintf( " %s:", join(",",asRadarValues).c_str() ) );
CString sNoteData;
CString sAttackData;
in.GetSMNoteData( sNoteData, sAttackData );
in.GetSMNoteData( sNoteData );
vector<CString> lines;
split( sNoteData, "\n", lines, false );
WriteLineList( f, lines, true, true );
if( sAttackData.empty() )
f.PutLine( ";" );
else
{
f.PutLine( ":" );
lines.clear();
split( sAttackData, "\n", lines, false );
WriteLineList( f, lines, true, true );
f.PutLine( ";" );
}
f.PutLine( ";" );
}
bool NotesWriterSM::Write(CString sPath, const Song &out, bool bSavingCache)
+38 -4
View File
@@ -110,7 +110,6 @@ void PlayerMinus::Load(
NoteField* pNoteField )
{
m_iDCState = AS2D_IDLE;
//LOG->Trace( "PlayerMinus::Load()", );
GAMESTATE->ResetNoteSkinsForPlayer( pn );
@@ -251,6 +250,21 @@ void PlayerMinus::Load(
m_soundMine.SetParams( p );
m_soundAttackLaunch.SetParams( p );
m_soundAttackEnding.SetParams( p );
//
// Load keysounds
//
Song* pSong = GAMESTATE->m_pCurSong;
CString sSongDir = pSong->GetSongDir();
m_vKeysounds.clear();
m_vKeysounds.resize( pSong->m_vsKeysoundFile.size() );
for( unsigned i=0; i<m_vKeysounds.size(); i++ )
{
CString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[i];
RageSound& sound = m_vKeysounds[i];
sound.Load( sKeysoundFilePath );
sound.SetParams( p );
}
}
void PlayerMinus::Update( float fDeltaTime )
@@ -684,7 +698,7 @@ void PlayerMinus::Step( int col, RageTimer tm )
const float fSecondsFromPerfect = fabsf( fNoteOffset );
TapNote tn = m_NoteData.GetTapNote(col,iIndexOverlappingNote);
TapNote tn = m_NoteData.GetTapNote( col, iIndexOverlappingNote );
switch( GAMESTATE->m_PlayerController[m_PlayerNumber] )
{
@@ -713,8 +727,16 @@ void PlayerMinus::Step( int col, RageTimer tm )
if( fSecondsFromPerfect <= ADJUSTED_WINDOW(Attack) )
{
m_soundAttackLaunch.Play();
// put attack in effect
Attack attack = m_NoteData.GetAttackAt( col, iIndexOverlappingNote );
Attack attack(
ATTACK_LEVEL_1,
-1, // now
tn.fAttackDurationSeconds,
tn.sAttackModifiers,
true,
false
);
GAMESTATE->LaunchAttack( OPPOSITE_PLAYER[m_PlayerNumber], attack );
// remove all TapAttacks on this row
@@ -801,7 +823,14 @@ void PlayerMinus::Step( int col, RageTimer tm )
score = TNS_NONE; // don't score this as anything
// put attack in effect
Attack attack = m_NoteData.GetAttackAt( col, iIndexOverlappingNote );
Attack attack(
ATTACK_LEVEL_1,
-1, // now
tn.fAttackDurationSeconds,
tn.sAttackModifiers,
true,
false
);
GAMESTATE->LaunchAttack( OPPOSITE_PLAYER[m_PlayerNumber], attack );
// remove all TapAttacks on this row
@@ -857,6 +886,11 @@ void PlayerMinus::Step( int col, RageTimer tm )
if( score != TNS_NONE )
m_NoteData.SetTapNoteOffset(col, iIndexOverlappingNote, -fNoteOffset);
if( score != TNS_NONE && tn.bKeysound )
{
m_vKeysounds[tn.iKeysoundIndex].Play();
}
if( GAMESTATE->m_PlayerController[m_PlayerNumber] == PC_HUMAN &&
score >= TNS_GREAT )
HandleAutosync(fNoteOffset);
+2
View File
@@ -107,6 +107,8 @@ protected:
RageSound m_soundMine;
RageSound m_soundAttackLaunch;
RageSound m_soundAttackEnding;
vector<RageSound> m_vKeysounds;
};
class Player : public PlayerMinus
+2 -7
View File
@@ -1399,14 +1399,9 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{
PlayerOptions poChosen = GAMESTATE->m_PlayerOptions[PLAYER_1];
CString sMods = poChosen.GetString();
const int iSongIndex = BeatToNoteRow( GAMESTATE->m_fSongBeat );
const int row = BeatToNoteRow( GAMESTATE->m_fSongBeat );
Attack attack;
attack.level = ATTACK_LEVEL_1; // does this matter?
attack.fSecsRemaining = g_fLastInsertAttackDurationSeconds;
attack.sModifier = sMods;
m_NoteFieldEdit.SetTapAttackNote( g_iLastInsertAttackTrack, iSongIndex, attack );
m_NoteFieldEdit.SetTapAttackNote( g_iLastInsertAttackTrack, row, sMods, g_fLastInsertAttackDurationSeconds );
GAMESTATE->RestoreSelectedOptions(); // restore the edit and playback options
}
break;
+10 -1
View File
@@ -816,7 +816,16 @@ void ScreenGameplay::SetupSong( PlayerNumber p, int iSongIndex )
const Style* pStyle = GAMESTATE->GetCurrentStyle();
NoteData newNoteData;
pStyle->GetTransformedNoteDataForStyle( p, originalNoteData, newNoteData );
m_Player[p].Load( p, newNoteData, m_pLifeMeter[p], m_pCombinedLifeMeter, m_pPrimaryScoreDisplay[p], m_pSecondaryScoreDisplay[p], m_pInventory[p], m_pPrimaryScoreKeeper[p], m_pSecondaryScoreKeeper[p] );
m_Player[p].Load(
p,
newNoteData,
m_pLifeMeter[p],
m_pCombinedLifeMeter,
m_pPrimaryScoreDisplay[p],
m_pSecondaryScoreDisplay[p],
m_pInventory[p],
m_pPrimaryScoreKeeper[p],
m_pSecondaryScoreKeeper[p] );
// Put course options into effect. Do this after Player::Load so
+4 -4
View File
@@ -324,10 +324,10 @@ void Song::DeleteDuplicateSteps( vector<Steps*> &vSteps )
if( s1->GetMeter() != s2->GetMeter() )
continue;
/* Compare, ignoring whitespace. */
CString sSMNoteData1, sSMAttackData1;
s1->GetSMNoteData( sSMNoteData1, sSMAttackData1 );
CString sSMNoteData2, sSMAttackData2;
s2->GetSMNoteData( sSMNoteData2, sSMAttackData2 );
CString sSMNoteData1;
s1->GetSMNoteData( sSMNoteData1 );
CString sSMNoteData2;
s2->GetSMNoteData( sSMNoteData2 );
if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) )
continue;
+21 -38
View File
@@ -42,14 +42,13 @@ Steps::Steps()
m_iMeter = 0;
notes = NULL;
notes_comp = NULL;
notes_comp = "";
parent = NULL;
}
Steps::~Steps()
{
delete notes;
delete notes_comp;
SAFE_DELETE( notes );
}
void Steps::SetNoteData( const NoteData& noteDataNew )
@@ -58,13 +57,11 @@ void Steps::SetNoteData( const NoteData& noteDataNew )
DeAutogen();
delete notes;
SAFE_DELETE( notes );
notes = new NoteData( noteDataNew );
delete notes_comp;
notes_comp = new CompressedNoteData;
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp->notes, notes_comp->attacks );
m_uHash = GetHashForString( notes_comp->notes );
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp );
m_uHash = GetHashForString( notes_comp );
}
void Steps::GetNoteData( NoteData& noteDataOut ) const
@@ -82,36 +79,29 @@ void Steps::GetNoteData( NoteData& noteDataOut ) const
}
}
void Steps::SetSMNoteData( const CString &notes_comp_, const CString &attacks_comp_ )
void Steps::SetSMNoteData( const CString &notes_comp_ )
{
delete notes;
notes = NULL;
SAFE_DELETE( notes );
if(!notes_comp)
notes_comp = new CompressedNoteData;
notes_comp->notes = notes_comp_;
notes_comp->attacks = attacks_comp_;
m_uHash = GetHashForString( notes_comp->notes );
notes_comp = notes_comp_;
m_uHash = GetHashForString( notes_comp );
}
void Steps::GetSMNoteData( CString &notes_comp_out, CString &attacks_comp_out ) const
void Steps::GetSMNoteData( CString &notes_comp_out ) const
{
if(!notes_comp)
if( !notes_comp.empty() )
{
if(!notes)
if( !notes )
{
/* no data is no data */
notes_comp_out = attacks_comp_out = "";
notes_comp_out = "";
return;
}
notes_comp = new CompressedNoteData;
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp->notes, notes_comp->attacks );
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp );
}
notes_comp_out = notes_comp->notes;
attacks_comp_out = notes_comp->attacks;
notes_comp_out = notes_comp;
}
float Steps::PredictMeter() const
@@ -209,8 +199,7 @@ void Steps::Decompress() const
return;
}
notes_comp = new CompressedNoteData;
pSteps->GetSMNoteData( notes_comp->notes, notes_comp->attacks );
pSteps->GetSMNoteData( notes_comp );
}
if( notes_comp == NULL )
@@ -223,7 +212,7 @@ void Steps::Decompress() const
notes = new NoteData;
notes->SetNumTracks( GameManager::StepsTypeToNumTracks(m_StepsType) );
NoteDataUtil::LoadFromSMNoteDataString(*notes, notes_comp->notes, notes_comp->attacks );
NoteDataUtil::LoadFromSMNoteDataString( *notes, notes_comp );
}
}
@@ -232,22 +221,16 @@ void Steps::Compress() const
if( !m_sFilename.empty() )
{
/* We have a file on disk; clear all data in memory. */
delete notes;
notes = NULL;
delete notes_comp;
notes_comp = NULL;
return;
SAFE_DELETE( notes );
}
if(!notes_comp)
if( notes_comp.empty() )
{
if(!notes) return; /* no data is no data */
notes_comp = new CompressedNoteData;
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp->notes, notes_comp->attacks );
NoteDataUtil::GetSMNoteDataString( *notes, notes_comp );
}
delete notes;
notes = NULL;
SAFE_DELETE( notes );
}
/* Copy our parent's data. This is done when we're being changed from autogen
+3 -7
View File
@@ -49,8 +49,8 @@ public:
void GetNoteData( NoteData& noteDataOut ) const;
void SetNoteData( const NoteData& noteDataNew );
void SetSMNoteData( const CString &notes_comp, const CString &attacks_comp );
void GetSMNoteData( CString &notes_comp_out, CString &attacks_comp_out ) const;
void SetSMNoteData( const CString &notes_comp );
void GetSMNoteData( CString &notes_comp_out ) const;
void TidyUpData();
@@ -63,11 +63,7 @@ protected:
* Call Compress() to force us to only have notes_comp; otherwise, creation of
* these is transparent. */
mutable NoteData *notes;
struct CompressedNoteData
{
CString notes, attacks;
};
mutable CompressedNoteData *notes_comp;
mutable CString notes_comp;
const Steps *Real() const;