HyperShuffle implementation

Also add it to _fallback
This commit is contained in:
tertu marybig
2022-06-23 11:09:40 -07:00
committed by teejusb
parent 7d88febd51
commit 9b348090a7
10 changed files with 171 additions and 8 deletions
+1
View File
@@ -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'/>
+1
View File
@@ -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 />
+1
View File
@@ -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
+2 -1
View File
@@ -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
View File
@@ -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);
}
+1
View File
@@ -107,6 +107,7 @@ namespace NoteDataUtil
shuffle,
soft_shuffle,
super_shuffle,
hyper_shuffle,
stomp,
swap_up_down,
NUM_TRACK_MAPPINGS
+4
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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 );
+1
View File
@@ -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