HyperShuffle implementation
Also add it to _fallback
This commit is contained in:
+157
-6
@@ -1855,6 +1855,142 @@ static void GetTrackMapping( StepsType st, NoteDataUtil::TrackMapping tt, int Nu
|
||||
}
|
||||
}
|
||||
|
||||
static void HyperShuffleNotes( NoteData &inout, int iStartIndex, int iEndIndex)
|
||||
{
|
||||
int iNumTracks = inout.GetNumTracks();
|
||||
|
||||
std::vector<int> viHoldEndRows(iNumTracks, -1);
|
||||
|
||||
// A "free track" is a track that is not part of a hold and is therefore
|
||||
// free to be shuffled into.
|
||||
int iFreeTracks = iNumTracks;
|
||||
|
||||
// If this is the first row, there cannot be any active holds yet.
|
||||
if ( iStartIndex != 0 )
|
||||
{
|
||||
// Search for any hold notes that might be present at the first row.
|
||||
// Once the loop below gets going, it keeps track of hold notes itself.
|
||||
for ( int track = 0; track < iNumTracks; track++ )
|
||||
{
|
||||
int iTargetRow = iStartIndex;
|
||||
|
||||
if ( inout.GetPrevTapNoteRowForTrack(track, iTargetRow) )
|
||||
{
|
||||
const TapNote &tn = inout.GetTapNote(track, iTargetRow);
|
||||
|
||||
// Check for a hold that ends on or after this row.
|
||||
if ( tn.type == TapNoteType_HoldHead )
|
||||
{
|
||||
int iHoldEndRow = iTargetRow + tn.iDuration;
|
||||
|
||||
if ( iHoldEndRow >= iStartIndex )
|
||||
{
|
||||
viHoldEndRows[track] = iHoldEndRow;
|
||||
iFreeTracks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stores the list of tracks that can have notes placed into them.
|
||||
// This will be shuffled so that notes can be placed in different tracks.
|
||||
std::vector<int> viTargetTracks;
|
||||
// Stores the list of tap notes that need to be placed.
|
||||
std::vector<TapNote> vtnTargetTaps;
|
||||
viTargetTracks.reserve(iNumTracks);
|
||||
vtnTargetTaps.reserve(iNumTracks);
|
||||
|
||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
||||
{
|
||||
viTargetTracks.clear();
|
||||
vtnTargetTaps.clear();
|
||||
int iActualTaps = 0;
|
||||
|
||||
for( int track=0; track<iNumTracks; track++ )
|
||||
{
|
||||
int iHoldEndRow = viHoldEndRows[track];
|
||||
|
||||
// Check if this track is actually still occupied by a hold.
|
||||
if(iHoldEndRow != -1)
|
||||
{
|
||||
if (r > iHoldEndRow)
|
||||
{
|
||||
iHoldEndRow = -1;
|
||||
viHoldEndRows[track] = iHoldEndRow;
|
||||
iFreeTracks++;
|
||||
}
|
||||
}
|
||||
|
||||
const TapNote tn1 = inout.GetTapNote(track, r);
|
||||
switch( tn1.type )
|
||||
{
|
||||
case TapNoteType_HoldTail:
|
||||
ASSERT_M(0, ssprintf("Saw a HoldTail during HyperShuffleNotes (row %d, track %d)", r, track));
|
||||
|
||||
// If asserts are off, treat this HoldTail as if it were an empty note.
|
||||
// If they aren't off, this code can't be reached.
|
||||
inout.SetTapNote(track, r, TAP_EMPTY);
|
||||
|
||||
// Fallthrough
|
||||
case TapNoteType_Empty:
|
||||
// Empty tap notes don't get directly placed in the shuffle table.
|
||||
// Instead, if they aren't in a hold, they get added to the list
|
||||
// of selectable tracks. Later on, new empty tap notes will be
|
||||
// created to pad the list of taps out to the required number.
|
||||
if( iHoldEndRow == -1 )
|
||||
viTargetTracks.push_back(track);
|
||||
break;
|
||||
case TapNoteType_AutoKeysound:
|
||||
case TapNoteType_Tap:
|
||||
case TapNoteType_Lift:
|
||||
case TapNoteType_Mine:
|
||||
case TapNoteType_Attack:
|
||||
case TapNoteType_Fake:
|
||||
case TapNoteType_HoldHead:
|
||||
vtnTargetTaps.push_back(tn1);
|
||||
iActualTaps++;
|
||||
|
||||
if (iHoldEndRow == -1 )
|
||||
viTargetTracks.push_back(track);
|
||||
else
|
||||
{
|
||||
// This track won't be part of the shuffle table, so if it
|
||||
// is not cleared now it will not get cleared later.
|
||||
inout.SetTapNote(track, r, TAP_EMPTY);
|
||||
}
|
||||
break;
|
||||
case TapNoteType_Invalid:
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Do the padding described above.
|
||||
for(int i = iActualTaps; i < iFreeTracks; i++)
|
||||
vtnTargetTaps.push_back(TAP_EMPTY);
|
||||
|
||||
std::random_shuffle(viTargetTracks.begin(), viTargetTracks.end(), g_RandomNumberGenerator);
|
||||
|
||||
// Go through the tracks in their shuffled order and drop tap notes.
|
||||
for(int i = 0; i < viTargetTracks.size(); i++)
|
||||
{
|
||||
const int targetTrack = viTargetTracks[i];
|
||||
const TapNote current_tn = vtnTargetTaps[i];
|
||||
inout.SetTapNote(targetTrack, r, current_tn);
|
||||
|
||||
// If it's a hold, mark this track occupied by a hold until its end.
|
||||
if( current_tn.type == TapNoteType_HoldHead )
|
||||
{
|
||||
ASSERT_M(viHoldEndRows[targetTrack] == -1,
|
||||
ssprintf("Tried to insert a hold into another hold (row %d, track %d)", r, targetTrack));
|
||||
iFreeTracks--;
|
||||
viHoldEndRows[targetTrack] = r + current_tn.iDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SuperShuffleTaps( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||
{
|
||||
/*
|
||||
@@ -1935,14 +2071,28 @@ static void SuperShuffleTaps( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||
|
||||
void NoteDataUtil::Turn( NoteData &inout, StepsType st, TrackMapping tt, int iStartIndex, int iEndIndex )
|
||||
{
|
||||
int iTakeFromTrack[MAX_NOTE_TRACKS]; // New track "t" will take from old track iTakeFromTrack[t]
|
||||
GetTrackMapping( st, tt, inout.GetNumTracks(), iTakeFromTrack );
|
||||
|
||||
NoteData tempNoteData;
|
||||
tempNoteData.LoadTransformed( inout, inout.GetNumTracks(), iTakeFromTrack );
|
||||
|
||||
if( tt == super_shuffle )
|
||||
SuperShuffleTaps( tempNoteData, iStartIndex, iEndIndex );
|
||||
if( tt == hyper_shuffle )
|
||||
{
|
||||
// HyperShuffle doesn't require a column transformation beforehand, so there's no point
|
||||
// in wasting time doing that.
|
||||
tempNoteData.CopyAll(inout);
|
||||
HyperShuffleNotes( tempNoteData, iStartIndex, iEndIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate how the columns should be rearranged, and then do it.
|
||||
int iTakeFromTrack[MAX_NOTE_TRACKS]; // New track "t" will take from old track iTakeFromTrack[t]
|
||||
GetTrackMapping( st, tt, inout.GetNumTracks(), iTakeFromTrack );
|
||||
|
||||
tempNoteData.LoadTransformed( inout, inout.GetNumTracks(), iTakeFromTrack );
|
||||
|
||||
// SuperShuffle doesn't affect holds, it instead relies on a regular shuffle to do them first.
|
||||
// Then it SuperShuffles everything else.
|
||||
if( tt == super_shuffle )
|
||||
SuperShuffleTaps( tempNoteData, iStartIndex, iEndIndex );
|
||||
}
|
||||
|
||||
inout.CopyAll( tempNoteData );
|
||||
inout.RevalidateATIs(vector<int>(), false);
|
||||
@@ -2785,6 +2935,7 @@ void NoteDataUtil::TransformNoteData( NoteData &nd, TimingData const& timing_dat
|
||||
if( po.m_bTurns[PlayerOptions::TURN_SHUFFLE] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::shuffle, iStartIndex, iEndIndex );
|
||||
if( po.m_bTurns[PlayerOptions::TURN_SOFT_SHUFFLE] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::soft_shuffle, iStartIndex, iEndIndex );
|
||||
if( po.m_bTurns[PlayerOptions::TURN_SUPER_SHUFFLE] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::super_shuffle, iStartIndex, iEndIndex );
|
||||
if( po.m_bTurns[PlayerOptions::TURN_HYPER_SHUFFLE] ) NoteDataUtil::Turn( nd, st, NoteDataUtil::hyper_shuffle, iStartIndex, iEndIndex );
|
||||
|
||||
nd.RevalidateATIs(vector<int>(), false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user