HyperShuffle implementation
Also add it to _fallback
This commit is contained in:
@@ -1289,6 +1289,7 @@
|
||||
<Function name='Hidden'/>
|
||||
<Function name='HiddenOffset'/>
|
||||
<Function name='HoldRolls'/>
|
||||
<Function name='HyperShuffle'/>
|
||||
<Function name='Incoming'/>
|
||||
<Function name='Invert'/>
|
||||
<Function name='IsEasierForCourseAndTrail'/>
|
||||
|
||||
@@ -4125,6 +4125,7 @@ a,b = options:Boost(5)
|
||||
<Function name='Hidden' return='float, float' arguments='float value, float approach_speed'> </Function>
|
||||
<Function name='HiddenOffset' return='float, float' arguments='float value, float approach_speed'> </Function>
|
||||
<Function name='HoldRolls' return='bool' arguments='bool value'> </Function>
|
||||
<Function name='HyperShuffle' return='bool' arguments='bool value'> </Function>
|
||||
<Function name='Incoming' return='float, float' arguments='float value, float approach_speed'>
|
||||
If the player is using Incoming ((positive skew and negative tilt) or (negative skew and positive tilt)), returns the value of skew and its approach_speed.<br />
|
||||
Returns nil otherwise.<br />
|
||||
|
||||
@@ -892,6 +892,7 @@ SuddenDeath=Sudden Death
|
||||
SuddenOffset=Sudden Offset
|
||||
SuperShuffle=Cement Mixer
|
||||
SoftShuffle=Soft Shuffle
|
||||
HyperShuffle=Hyper Shuffle
|
||||
Swap Sides=Swap Sides
|
||||
Swap Up/Down=Swap Up/Down
|
||||
Sync Machine=Sync Machine
|
||||
|
||||
@@ -2464,7 +2464,7 @@ Appearance,4="mod,blink;name,Blink"
|
||||
# Appearance,5="mod,blink;name,Blink"
|
||||
# Appearance,6="mod,randomvanish;name,R.Vanish"
|
||||
|
||||
Turn="7;selectmultiple"
|
||||
Turn="8;selectmultiple"
|
||||
TurnDefault="mod,no turn"
|
||||
Turn,1="mod,mirror;name,Mirror"
|
||||
Turn,2="mod,backwards;name,Backwards"
|
||||
@@ -2473,6 +2473,7 @@ Turn,4="mod,right;name,Right"
|
||||
Turn,5="mod,shuffle;name,Shuffle"
|
||||
Turn,6="mod,supershuffle;name,SuperShuffle"
|
||||
Turn,7="mod,softshuffle;name,SoftShuffle"
|
||||
Turn,8="mod,hypershuffle;name,HyperShuffle"
|
||||
|
||||
# Turn="6"
|
||||
# TurnDefault="mod,no turn"
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ namespace NoteDataUtil
|
||||
shuffle,
|
||||
soft_shuffle,
|
||||
super_shuffle,
|
||||
hyper_shuffle,
|
||||
stomp,
|
||||
swap_up_down,
|
||||
NUM_TRACK_MAPPINGS
|
||||
|
||||
@@ -492,6 +492,7 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
|
||||
if( m_bTurns[TURN_SHUFFLE] ) AddTo.push_back( "Shuffle" );
|
||||
if( m_bTurns[TURN_SOFT_SHUFFLE] ) AddTo.push_back( "SoftShuffle" );
|
||||
if( m_bTurns[TURN_SUPER_SHUFFLE] ) AddTo.push_back( "SuperShuffle" );
|
||||
if( m_bTurns[TURN_HYPER_SHUFFLE] ) AddTo.push_back( "HyperShuffle" );
|
||||
|
||||
if( m_bTransforms[TRANSFORM_NOHOLDS] ) AddTo.push_back( "NoHolds" );
|
||||
if( m_bTransforms[TRANSFORM_NOROLLS] ) AddTo.push_back( "NoRolls" );
|
||||
@@ -1027,6 +1028,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
|
||||
else if( sBit == "shuffle" ) m_bTurns[TURN_SHUFFLE] = on;
|
||||
else if( sBit == "softshuffle" ) m_bTurns[TURN_SOFT_SHUFFLE] = on;
|
||||
else if( sBit == "supershuffle" ) m_bTurns[TURN_SUPER_SHUFFLE] = on;
|
||||
else if( sBit == "hypershuffle" ) m_bTurns[TURN_HYPER_SHUFFLE] = on;
|
||||
else if( sBit == "little" ) m_bTransforms[TRANSFORM_LITTLE] = on;
|
||||
else if( sBit == "wide" ) m_bTransforms[TRANSFORM_WIDE] = on;
|
||||
else if( sBit == "big" ) m_bTransforms[TRANSFORM_BIG] = on;
|
||||
@@ -2009,6 +2011,7 @@ public:
|
||||
BOOL_INTERFACE(Shuffle, Turns[PlayerOptions::TURN_SHUFFLE]);
|
||||
BOOL_INTERFACE(SoftShuffle, Turns[PlayerOptions::TURN_SOFT_SHUFFLE]);
|
||||
BOOL_INTERFACE(SuperShuffle, Turns[PlayerOptions::TURN_SUPER_SHUFFLE]);
|
||||
BOOL_INTERFACE(HyperShuffle, Turns[PlayerOptions::TURN_HYPER_SHUFFLE]);
|
||||
BOOL_INTERFACE(NoHolds, Transforms[PlayerOptions::TRANSFORM_NOHOLDS]);
|
||||
BOOL_INTERFACE(NoRolls, Transforms[PlayerOptions::TRANSFORM_NOROLLS]);
|
||||
BOOL_INTERFACE(NoMines, Transforms[PlayerOptions::TRANSFORM_NOMINES]);
|
||||
@@ -2554,6 +2557,7 @@ public:
|
||||
ADD_METHOD(Shuffle);
|
||||
ADD_METHOD(SoftShuffle);
|
||||
ADD_METHOD(SuperShuffle);
|
||||
ADD_METHOD(HyperShuffle);
|
||||
ADD_METHOD(NoHolds);
|
||||
ADD_METHOD(NoRolls);
|
||||
ADD_METHOD(NoMines);
|
||||
|
||||
@@ -292,6 +292,7 @@ public:
|
||||
TURN_SHUFFLE, /**< Some of the arrow columns are changed throughout the whole song. */
|
||||
TURN_SOFT_SHUFFLE, /**< Only shuffle arrow columns on an axis of symmetry. */
|
||||
TURN_SUPER_SHUFFLE, /**< Every arrow is placed on a random column. */
|
||||
TURN_HYPER_SHUFFLE, /**< Every arrow is placed on a random column, but more fairly than SuperShuffle. */
|
||||
NUM_TURNS
|
||||
};
|
||||
enum Transform {
|
||||
|
||||
+2
-1
@@ -842,7 +842,7 @@ static MenuDef g_AlterMenu(
|
||||
EditMode_Practice, true, true, 0,
|
||||
"4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
|
||||
MenuRowDef(ScreenEdit::turn, "Turn", true,
|
||||
EditMode_Practice, true, true, 0, "Left","Right","Mirror","Backwards","Shuffle","SuperShuffle" ),
|
||||
EditMode_Practice, true, true, 0, "Left","Right","Mirror","Backwards","Shuffle","SuperShuffle","HyperShuffle" ),
|
||||
MenuRowDef(ScreenEdit::transform, "Transform", true,
|
||||
EditMode_Practice, true, true, 0, "NoHolds","NoMines","Little","Wide",
|
||||
"Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored",
|
||||
@@ -5167,6 +5167,7 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector<int> &ans
|
||||
case turn_backwards: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::backwards ); break;
|
||||
case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break;
|
||||
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break;
|
||||
case hyper_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::hyper_shuffle ); break;
|
||||
}
|
||||
|
||||
HandleAreaMenuChoice( paste_at_begin_marker, false );
|
||||
|
||||
@@ -487,6 +487,7 @@ public:
|
||||
turn_backwards, /**< Turn the notes as if you were facing away from the machine. */
|
||||
shuffle, /**< Replace one column with another column. */
|
||||
super_shuffle, /**< Replace each note individually. */
|
||||
hyper_shuffle, /**< Replace each note individually but more fairly. */
|
||||
NUM_TURN_TYPES
|
||||
};
|
||||
enum TransformType
|
||||
|
||||
Reference in New Issue
Block a user