From 3ac1dba044e33b074b1ce66ff96b7c0bfad10152 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sat, 23 Oct 2004 23:41:49 +0000 Subject: [PATCH] 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 --- stepmania/src/Attack.h | 20 +- stepmania/src/GameState.cpp | 12 +- stepmania/src/GameState.h | 2 +- stepmania/src/NoteData.cpp | 92 +------ stepmania/src/NoteData.h | 16 +- stepmania/src/NoteDataUtil.cpp | 404 ++++++++++++++----------------- stepmania/src/NoteDataUtil.h | 4 +- stepmania/src/NoteField.cpp | 3 +- stepmania/src/NoteTypes.cpp | 17 +- stepmania/src/NoteTypes.h | 44 ++-- stepmania/src/NotesLoaderBMS.cpp | 74 +++--- stepmania/src/NotesLoaderBMS.h | 2 +- stepmania/src/NotesLoaderSM.cpp | 17 +- stepmania/src/NotesLoaderSM.h | 1 - stepmania/src/NotesWriterDWI.cpp | 28 +-- stepmania/src/NotesWriterSM.cpp | 17 +- stepmania/src/Player.cpp | 42 +++- stepmania/src/Player.h | 2 + stepmania/src/ScreenEdit.cpp | 9 +- stepmania/src/ScreenGameplay.cpp | 11 +- stepmania/src/Song.cpp | 8 +- stepmania/src/Steps.cpp | 59 ++--- stepmania/src/Steps.h | 10 +- 23 files changed, 395 insertions(+), 499 deletions(-) diff --git a/stepmania/src/Attack.h b/stepmania/src/Attack.h index cde8f9e758..0e3cf82ec3 100644 --- a/stepmania/src/Attack.h +++ b/stepmania/src/Attack.h @@ -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; }; diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index fa831bdfa1..979df99ccf 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -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 ); } diff --git a/stepmania/src/GameState.h b/stepmania/src/GameState.h index d6df1d110e..8fc5b2ecfb 100644 --- a/stepmania/src/GameState.h +++ b/stepmania/src/GameState.h @@ -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*/ ); diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index 428620330f..edc9a4c316 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -77,20 +77,11 @@ void NoteData::CopyRange( const NoteData& from, int iFromIndexBegin, int iFromIn for( int t=0; t setUsedIndices; - - for( int t=0; t::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) diff --git a/stepmania/src/NoteData.h b/stepmania/src/NoteData.h index 8982254b21..4749672970 100644 --- a/stepmania/src/NoteData.h +++ b/stepmania/src/NoteData.h @@ -26,8 +26,6 @@ class NoteData vector m_HoldNotes; - map 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& GetAttackMap() const { return m_AttackMap; } - map& 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 diff --git a/stepmania/src/NoteDataUtil.cpp b/stepmania/src/NoteDataUtil.cpp index 9f31bd2931..89050b7fd7 100644 --- a/stepmania/src/NoteDataUtil.cpp +++ b/stepmania/src/NoteDataUtil.cpp @@ -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= '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::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; tGetBeatFromElapsedTime( 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 ); } } diff --git a/stepmania/src/NoteDataUtil.h b/stepmania/src/NoteDataUtil.h index e1ed564573..1ea9b8dad2 100644 --- a/stepmania/src/NoteDataUtil.h +++ b/stepmania/src/NoteDataUtil.h @@ -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 ¬es_out, CString &attacks_out ); + void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData ); + void GetSMNoteDataString( const NoteData &in, CString ¬es_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 ); diff --git a/stepmania/src/NoteField.cpp b/stepmania/src/NoteField.cpp index 01c722f434..9cc20e618c 100644 --- a/stepmania/src/NoteField.cpp +++ b/stepmania/src/NoteField.cpp @@ -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; diff --git a/stepmania/src/NoteTypes.cpp b/stepmania/src/NoteTypes.cpp index dbf5e04f2f..4f34150664 100644 --- a/stepmania/src/NoteTypes.cpp +++ b/stepmania/src/NoteTypes.cpp @@ -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 ) { diff --git a/stepmania/src/NoteTypes.h b/stepmania/src/NoteTypes.h index 8c389b2021..3a233859a0 100644 --- a/stepmania/src/NoteTypes.h +++ b/stepmania/src/NoteTypes.h @@ -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; diff --git a/stepmania/src/NotesLoaderBMS.cpp b/stepmania/src/NotesLoaderBMS.cpp index 50fc6b4a7e..bcee698607 100644 --- a/stepmania/src/NotesLoaderBMS.cpp +++ b/stepmania/src/NotesLoaderBMS.cpp @@ -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 &mapWavIdToKeysoundIndex ) +bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const map &mapWavIdToKeysoundIndex ) { LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() ); @@ -185,19 +187,19 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out, const mapSetNumTracks( 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::const_iterator it = mapWavIdToKeysoundIndex.find(sNoteId); + map::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 mapSetTapNote(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 mapSetNumTracks( 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 mapWavIdToKeysoundIndex; + map mapWavIdToKeysoundIndex; CString sPath = out.GetSongDir() + arrayBMSFileNames[0]; diff --git a/stepmania/src/NotesLoaderBMS.h b/stepmania/src/NotesLoaderBMS.h index d2e2b57be5..795fdf9c5e 100644 --- a/stepmania/src/NotesLoaderBMS.h +++ b/stepmania/src/NotesLoaderBMS.h @@ -9,7 +9,7 @@ class Steps; class BMSLoader: public NotesLoader { - bool LoadFromBMSFile( const CString &sPath, Steps &out1, const map &mapWavIdToKeysoundIndex ); + bool LoadFromBMSFile( const CString &sPath, Steps &out1, const map &mapWavIdToKeysoundIndex ); void SlideDuplicateDifficulties( Song &p ); diff --git a/stepmania/src/NotesLoaderSM.cpp b/stepmania/src/NotesLoaderSM.cpp index b6f59e7f95..d5ec793ddc 100644 --- a/stepmania/src/NotesLoaderSM.cpp +++ b/stepmania/src/NotesLoaderSM.cpp @@ -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 ); diff --git a/stepmania/src/NotesLoaderSM.h b/stepmania/src/NotesLoaderSM.h index 8242a721cf..5a7bea6c33 100644 --- a/stepmania/src/NotesLoaderSM.h +++ b/stepmania/src/NotesLoaderSM.h @@ -18,7 +18,6 @@ class SMLoader: public NotesLoader CString sMeter, CString sRadarValues, CString sNoteData, - CString sAttackData, Steps &out); bool FromCache; diff --git a/stepmania/src/NotesWriterDWI.cpp b/stepmania/src/NotesWriterDWI.cpp index 226651f526..4aca99fbb1 100644 --- a/stepmania/src/NotesWriterDWI.cpp +++ b/stepmania/src/NotesWriterDWI.cpp @@ -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 ) diff --git a/stepmania/src/NotesWriterSM.cpp b/stepmania/src/NotesWriterSM.cpp index 4d4afd0145..5eeff0e1b6 100644 --- a/stepmania/src/NotesWriterSM.cpp +++ b/stepmania/src/NotesWriterSM.cpp @@ -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 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) diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index ef5cea846f..19039dc682 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -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; im_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); diff --git a/stepmania/src/Player.h b/stepmania/src/Player.h index 1cf1f0c254..e607a38a9e 100644 --- a/stepmania/src/Player.h +++ b/stepmania/src/Player.h @@ -107,6 +107,8 @@ protected: RageSound m_soundMine; RageSound m_soundAttackLaunch; RageSound m_soundAttackEnding; + + vector m_vKeysounds; }; class Player : public PlayerMinus diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index d8f3772ddd..ff2418f89c 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -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; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 246de1a424..552786e111 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -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 diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index 90a9685862..b13e4e282a 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -324,10 +324,10 @@ void Song::DeleteDuplicateSteps( vector &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; diff --git a/stepmania/src/Steps.cpp b/stepmania/src/Steps.cpp index f5a0c4c630..4849f8e91a 100644 --- a/stepmania/src/Steps.cpp +++ b/stepmania/src/Steps.cpp @@ -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 ¬es_comp_, const CString &attacks_comp_ ) +void Steps::SetSMNoteData( const CString ¬es_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 ¬es_comp_out, CString &attacks_comp_out ) const +void Steps::GetSMNoteData( CString ¬es_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 diff --git a/stepmania/src/Steps.h b/stepmania/src/Steps.h index 07afb05812..bbe5543b06 100644 --- a/stepmania/src/Steps.h +++ b/stepmania/src/Steps.h @@ -49,8 +49,8 @@ public: void GetNoteData( NoteData& noteDataOut ) const; void SetNoteData( const NoteData& noteDataNew ); - void SetSMNoteData( const CString ¬es_comp, const CString &attacks_comp ); - void GetSMNoteData( CString ¬es_comp_out, CString &attacks_comp_out ) const; + void SetSMNoteData( const CString ¬es_comp ); + void GetSMNoteData( CString ¬es_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;