add echo, planted, stomp transforms
This commit is contained in:
@@ -1741,8 +1741,8 @@ ExplanationTogetherX=70
|
||||
ExplanationTogetherY=412
|
||||
ExplanationTogetherOnCommand=wrapwidthpixels,1000;horizalign,left;cropright,1;linear,0.5;cropright,0
|
||||
ExplanationZoom=0.5
|
||||
ExplanationP1OnCommand=wrapwidthpixels,600;horizalign,left;cropright,1;linear,0.5;cropright,0
|
||||
ExplanationP2OnCommand=wrapwidthpixels,600;horizalign,right;cropright,1;linear,0.5;cropright,0
|
||||
ExplanationP1OnCommand=wrapwidthpixels,500;horizalign,left;cropright,1;linear,0.5;cropright,0
|
||||
ExplanationP2OnCommand=wrapwidthpixels,500;horizalign,right;cropright,1;linear,0.5;cropright,0
|
||||
ColorSelected=1,1,1,1 // normal
|
||||
ColorNotSelected=0.5,0.5,0.5,1 // grayed
|
||||
NumShownItems=10
|
||||
@@ -2940,7 +2940,7 @@ TurnName,5=SHUFFLE
|
||||
Turn,6=mod,supershuffle
|
||||
TurnName,6=S.SHUFFLE
|
||||
|
||||
Transform=7
|
||||
Transform=10
|
||||
TransformDefault=mod,no transform
|
||||
Transform,1=
|
||||
TransformName,1=OFF
|
||||
@@ -2956,6 +2956,12 @@ Transform,6=mod,skippy
|
||||
TransformName,6=SKIPPY
|
||||
Transform,7=mod,mines
|
||||
TransformName,7=MINES
|
||||
Transform,8=mod,echo
|
||||
TransformName,8=ECHO
|
||||
Transform,9=mod,planted
|
||||
TransformName,9=PLANTED
|
||||
Transform,10=mod,stomp
|
||||
TransformName,10=STOMP
|
||||
|
||||
Scroll=4
|
||||
ScrollDefault=mod,no reverse,no split,no alternate
|
||||
|
||||
@@ -174,15 +174,6 @@ void NoteData::RemoveHoldNote( int iHoldIndex )
|
||||
m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1);
|
||||
}
|
||||
|
||||
bool NoteData::IsThereATapAtRow( int iRow ) const
|
||||
{
|
||||
for( int t=0; t<m_iNumTracks; t++ )
|
||||
if( GetTapNote(t, iRow) != TAP_EMPTY )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int NoteData::GetFirstRow() const
|
||||
{
|
||||
return BeatToNoteRow( GetFirstBeat() );
|
||||
@@ -606,3 +597,18 @@ void NoteData::EliminateAllButOneTap(int row)
|
||||
m_TapNotes[track][row] = TAP_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
int NoteData::GetNumTracksHeldAtRow( int row )
|
||||
{
|
||||
// Optimization opportunity:
|
||||
// Search more efficiently knowing that m_HoldNotes is sorted.
|
||||
int iNumTracksHeld = 0;
|
||||
float fBeat = NoteRowToBeat(row);
|
||||
for( unsigned i=0; i<m_HoldNotes.size(); i++ )
|
||||
{
|
||||
const HoldNote& hn = m_HoldNotes[i];
|
||||
if( fBeat >= hn.fStartBeat && fBeat <= hn.fEndBeat )
|
||||
iNumTracksHeld++;
|
||||
}
|
||||
return iNumTracksHeld;
|
||||
}
|
||||
@@ -98,6 +98,11 @@ public:
|
||||
return t;
|
||||
return -1;
|
||||
}
|
||||
inline bool IsThereATapAtRow( int index ) const
|
||||
{
|
||||
return GetFirstTrackWithTap( index ) != -1;
|
||||
}
|
||||
int GetNumTracksHeldAtRow( int row );
|
||||
|
||||
// used in edit/record
|
||||
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
|
||||
@@ -106,7 +111,6 @@ public:
|
||||
const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; }
|
||||
|
||||
// statistics
|
||||
bool IsThereATapAtRow( int iRow ) const;
|
||||
|
||||
/* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need
|
||||
* accuracy.) */
|
||||
|
||||
@@ -689,6 +689,148 @@ void NoteDataUtil::Mines( NoteData &in, float fStartBeat, float fEndBeat )
|
||||
}
|
||||
}
|
||||
|
||||
void NoteDataUtil::Echo( NoteData &in, float fStartBeat, float fEndBeat )
|
||||
{
|
||||
// add 8th note tap "echos" after all taps
|
||||
int iEchoTrack = -1;
|
||||
|
||||
fStartBeat = froundf( fStartBeat, 0.5 );
|
||||
|
||||
const int first_row = BeatToNoteRow( fStartBeat );
|
||||
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
|
||||
const int rows_per_interval = BeatToNoteRow( 0.5 );
|
||||
|
||||
// window is one beat wide and slides 1/2 a beat at a time
|
||||
for( int r=first_row; r<last_row; r+=rows_per_interval )
|
||||
{
|
||||
int iRowWindowBegin = r;
|
||||
int iRowWindowEnd = r + rows_per_interval*2;
|
||||
float fBeatWindowBegin = NoteRowToBeat(iRowWindowBegin);
|
||||
float fBeatWindowEnd = NoteRowToBeat(iRowWindowEnd);
|
||||
int iRowEcho = r + rows_per_interval;
|
||||
|
||||
int iFirstTapInRow = in.GetFirstTrackWithTap(iRowWindowBegin);
|
||||
if( iFirstTapInRow != -1 )
|
||||
{
|
||||
iEchoTrack = iFirstTapInRow;
|
||||
}
|
||||
|
||||
// don't insert a new note if there's already a tap within this interval
|
||||
bool bTapInMiddle = false;
|
||||
for( int r2=iRowWindowBegin+1; r2<=iRowWindowEnd-1; r2++ )
|
||||
if( in.IsThereATapAtRow(r2) )
|
||||
{
|
||||
bTapInMiddle = true;
|
||||
break;
|
||||
}
|
||||
if( bTapInMiddle )
|
||||
continue;
|
||||
|
||||
// don't insert a new note if there's already a hold headwithin this interval
|
||||
// TODO: Why is this necessary? Isn't there a TAP_TAP at the HoldNote head spot?
|
||||
for( int i=0; i<in.GetNumHoldNotes(); i++ )
|
||||
{
|
||||
int iHoldHeadRow = BeatToNoteRow(in.GetHoldNote(i).fStartBeat);
|
||||
if( iHoldHeadRow >= iRowWindowBegin+1 && iHoldHeadRow <= iRowWindowEnd-1 )
|
||||
{
|
||||
bTapInMiddle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( bTapInMiddle )
|
||||
continue;
|
||||
|
||||
if( iEchoTrack==-1 )
|
||||
continue;
|
||||
|
||||
int iNumTracksHeld = in.GetNumTracksHeldAtRow(iRowEcho);
|
||||
if( iNumTracksHeld >= 2 )
|
||||
continue;
|
||||
|
||||
in.SetTapNote( iEchoTrack, iRowEcho, TAP_ADDITION );
|
||||
}
|
||||
}
|
||||
|
||||
void NoteDataUtil::Planted( NoteData &in, float fStartBeat, float fEndBeat )
|
||||
{
|
||||
// Convert all taps to freezes.
|
||||
const int first_row = BeatToNoteRow( fStartBeat );
|
||||
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
|
||||
for( int r=first_row; r<=last_row; r++ )
|
||||
{
|
||||
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||
{
|
||||
if( in.GetTapNote(t,r) == TAP_TAP )
|
||||
{
|
||||
// search for row of next TAP_TAP
|
||||
for( int r2=r+1; r2<=last_row; r2++ )
|
||||
{
|
||||
if( in.IsThereATapAtRow(r2) )
|
||||
{
|
||||
// If there are two taps in a row on the same track,
|
||||
// don't convert the earlier one to a hold.
|
||||
if( in.GetFirstTrackWithTap(r2) == t )
|
||||
goto dont_add_hold;
|
||||
break; // stop searching
|
||||
}
|
||||
}
|
||||
float fStartBeat = NoteRowToBeat(r);
|
||||
float fEndBeat = NoteRowToBeat(r2);
|
||||
// If the steps end in a tap, convert that tap
|
||||
// to a hold that lasts for at least one beat.
|
||||
if( r2==r+1 )
|
||||
fEndBeat = fStartBeat+1;
|
||||
in.AddHoldNote( HoldNote(t,fStartBeat,fEndBeat) );
|
||||
}
|
||||
dont_add_hold:
|
||||
int blah = 0; // shut compiler up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NoteDataUtil::Stomp( NoteData &in, float fStartBeat, float fEndBeat )
|
||||
{
|
||||
// Make all non jumps with ample space around them into jumps.
|
||||
|
||||
const int first_row = BeatToNoteRow( fStartBeat );
|
||||
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
|
||||
|
||||
for( int r=first_row; r<last_row; r++ )
|
||||
{
|
||||
if( in.GetNumTracksWithTap(r) != 1 )
|
||||
continue; // skip
|
||||
|
||||
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||
{
|
||||
if( in.GetTapNote(t, r) == TAP_TAP ) // there is a tap here
|
||||
{
|
||||
// Look to see if there is enough empty space on either side of the note
|
||||
// to turn this into a jump.
|
||||
int iRowWindowBegin = r - BeatToNoteRow(0.5);
|
||||
int iRowWindowEnd = r + BeatToNoteRow(0.5);
|
||||
|
||||
bool bTapInMiddle = false;
|
||||
for( int r2=iRowWindowBegin+1; r2<=iRowWindowEnd-1; r2++ )
|
||||
if( in.IsThereATapAtRow(r2) && r2 != r ) // don't count the note we're looking around
|
||||
{
|
||||
bTapInMiddle = true;
|
||||
break;
|
||||
}
|
||||
if( bTapInMiddle )
|
||||
continue;
|
||||
|
||||
// don't convert to jump if there's a hold here
|
||||
int iNumTracksHeld = in.GetNumTracksHeldAtRow(r);
|
||||
if( iNumTracksHeld >= 1 )
|
||||
continue;
|
||||
|
||||
// TODO: Make this accurate for StepsTypes other than 4 panel cross.
|
||||
int iOppositeTrack = in.GetNumTracks()-1-t;
|
||||
in.SetTapNote( iOppositeTrack, r, TAP_ADDITION );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NoteDataUtil::SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat )
|
||||
{
|
||||
@@ -984,6 +1126,9 @@ void NoteDataUtil::TransformNoteData( NoteData &nd, const PlayerOptions &po, Ste
|
||||
case PlayerOptions::TRANSFORM_QUICK: NoteDataUtil::Quick(nd, fStartBeat, fEndBeat); break;
|
||||
case PlayerOptions::TRANSFORM_SKIPPY: NoteDataUtil::Skippy(nd, fStartBeat, fEndBeat); break;
|
||||
case PlayerOptions::TRANSFORM_MINES: NoteDataUtil::Mines(nd, fStartBeat, fEndBeat); break;
|
||||
case PlayerOptions::TRANSFORM_ECHO: NoteDataUtil::Echo(nd, fStartBeat, fEndBeat); break;
|
||||
case PlayerOptions::TRANSFORM_PLANTED: NoteDataUtil::Planted(nd, fStartBeat, fEndBeat); break;
|
||||
case PlayerOptions::TRANSFORM_STOMP: NoteDataUtil::Stomp(nd, fStartBeat, fEndBeat); break;
|
||||
default: ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,11 @@ namespace NoteDataUtil
|
||||
void Big( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Quick( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Skippy( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Mines( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bSkippy, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Mines( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Echo( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Planted( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void Stomp( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
|
||||
void SuperShuffleTaps( NoteData &in );
|
||||
|
||||
// change all TAP_ADDITIONs to TAP_TAPs
|
||||
|
||||
@@ -154,6 +154,9 @@ CString PlayerOptions::GetString() const
|
||||
case TRANSFORM_QUICK: sReturn += "Quick, "; break;
|
||||
case TRANSFORM_SKIPPY: sReturn += "Skippy, "; break;
|
||||
case TRANSFORM_MINES: sReturn += "Mines, "; break;
|
||||
case TRANSFORM_ECHO: sReturn += "Echo, "; break;
|
||||
case TRANSFORM_PLANTED: sReturn += "Planted, "; break;
|
||||
case TRANSFORM_STOMP: sReturn += "Stomp, "; break;
|
||||
default: ASSERT(0); // invalid
|
||||
}
|
||||
|
||||
@@ -280,6 +283,9 @@ void PlayerOptions::FromString( CString sOptions )
|
||||
else if( sBit == "quick" ) m_Transform = TRANSFORM_QUICK;
|
||||
else if( sBit == "skippy" ) m_Transform = TRANSFORM_SKIPPY;
|
||||
else if( sBit == "mines" ) m_Transform = TRANSFORM_MINES;
|
||||
else if( sBit == "echo" ) m_Transform = TRANSFORM_ECHO;
|
||||
else if( sBit == "planted" ) m_Transform = TRANSFORM_PLANTED;
|
||||
else if( sBit == "stomp" ) m_Transform = TRANSFORM_STOMP;
|
||||
else if( sBit == "reverse" ) SET_FLOAT( fScrolls[SCROLL_REVERSE] )
|
||||
else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] )
|
||||
else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] )
|
||||
|
||||
@@ -65,6 +65,9 @@ struct PlayerOptions
|
||||
TRANSFORM_QUICK,
|
||||
TRANSFORM_SKIPPY,
|
||||
TRANSFORM_MINES,
|
||||
TRANSFORM_ECHO,
|
||||
TRANSFORM_PLANTED,
|
||||
TRANSFORM_STOMP,
|
||||
NUM_TRANSFORMS
|
||||
};
|
||||
enum Scroll {
|
||||
|
||||
@@ -156,7 +156,7 @@ Menu g_AreaMenu
|
||||
MenuRow( "Clear", true ),
|
||||
MenuRow( "Quantize", true, 0, "4TH","8TH","12TH","16TH","24TH","32ND","48TH","64TH" ),
|
||||
MenuRow( "Turn", true, 0, "Left","Right","Mirror","Shuffle","Super Shuffle" ),
|
||||
MenuRow( "Transform", true, 0, "Little","Wide","Big","Quick","Skippy" ),
|
||||
MenuRow( "Transform", true, 0, "Little","Wide","Big","Quick","Skippy","Mines","Echo","Planted","Stomp" ),
|
||||
MenuRow( "Alter", true, 0, "Backwards","Swap Sides","Copy Left To Right","Copy Right To Left","Clear Left","Clear Right","Collapse To One","Shift Left","Shift Right" ),
|
||||
MenuRow( "Tempo", true, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
|
||||
MenuRow( "Play selection", true ),
|
||||
@@ -1538,6 +1538,10 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
||||
case big: NoteDataUtil::Big( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case quick: NoteDataUtil::Quick( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case skippy: NoteDataUtil::Skippy( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case mines: NoteDataUtil::Mines( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case echo: NoteDataUtil::Echo( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case planted: NoteDataUtil::Planted( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
case stomp: NoteDataUtil::Stomp( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
|
||||
default: ASSERT(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
};
|
||||
void HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers );
|
||||
enum TurnType { left, right, mirror, shuffle, super_shuffle, NUM_TURN_TYPES };
|
||||
enum TransformType { little, wide, big, quick, skippy, NUM_TRANSFORM_TYPES };
|
||||
enum TransformType { little, wide, big, quick, skippy, mines, echo, planted, stomp, NUM_TRANSFORM_TYPES };
|
||||
enum AlterType { backwards, swap_sides, copy_left_to_right, copy_right_to_left, clear_left, clear_right, collapse_to_one, shift_left, shift_right, NUM_ALTER_TYPES };
|
||||
// MD 11/02/03 - added additional tempo adjusts which make "sense"
|
||||
enum TempoType { compress_2x, compress_3_2, compress_4_3, expand_4_3, expand_3_2, expand_2x, NUM_TEMPO_TYPES };
|
||||
|
||||
@@ -210,24 +210,21 @@ void ScreenOptions::Init( InputMode im, OptionRow OptionRows[], int iNumOptionLi
|
||||
}
|
||||
|
||||
// add explanation here so it appears on top
|
||||
for( p=0; p<NUM_PLAYERS; p++ )
|
||||
{
|
||||
m_textExplanation[p].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
|
||||
m_textExplanation[p].SetZoom( EXPLANATION_ZOOM );
|
||||
m_textExplanation[p].SetShadowLength( 0 );
|
||||
m_framePage.AddChild( &m_textExplanation[p] );
|
||||
}
|
||||
switch( m_InputMode )
|
||||
{
|
||||
case INPUTMODE_INDIVIDUAL:
|
||||
for( p=0; p<NUM_PLAYERS; p++ )
|
||||
{
|
||||
m_textExplanation[p].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
|
||||
m_textExplanation[p].SetXY( EXPLANATION_X(p), EXPLANATION_Y(p) );
|
||||
m_textExplanation[p].SetZoom( EXPLANATION_ZOOM );
|
||||
m_textExplanation[p].SetShadowLength( 0 );
|
||||
m_framePage.AddChild( &m_textExplanation[p] );
|
||||
}
|
||||
break;
|
||||
case INPUTMODE_TOGETHER:
|
||||
m_textExplanation[0].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
|
||||
m_textExplanation[0].SetXY( EXPLANATION_TOGETHER_X, EXPLANATION_TOGETHER_Y );
|
||||
m_textExplanation[0].SetZoom( EXPLANATION_ZOOM );
|
||||
m_textExplanation[0].SetShadowLength( 0 );
|
||||
m_framePage.AddChild( &m_textExplanation[0] );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
@@ -891,7 +888,7 @@ void ScreenOptions::ChangeValue( PlayerNumber pn, int iDelta )
|
||||
m_iSelectedOption[p][iCurRow] = iNewSel;
|
||||
UpdateText( (PlayerNumber)p, iCurRow );
|
||||
}
|
||||
OnChange( pn );
|
||||
OnChange( (PlayerNumber)p );
|
||||
}
|
||||
m_SoundChangeCol.Play();
|
||||
}
|
||||
@@ -908,7 +905,7 @@ void ScreenOptions::MenuUp( PlayerNumber pn )
|
||||
m_iCurrentRow[p] = m_iNumOptionRows; // on exit
|
||||
else
|
||||
m_iCurrentRow[p]--;
|
||||
OnChange( pn );
|
||||
OnChange( (PlayerNumber)p );
|
||||
}
|
||||
m_SoundPrevRow.Play();
|
||||
}
|
||||
@@ -925,7 +922,7 @@ void ScreenOptions::MenuDown( PlayerNumber pn )
|
||||
m_iCurrentRow[p] = 0; // on first row
|
||||
else
|
||||
m_iCurrentRow[p]++;
|
||||
OnChange( pn );
|
||||
OnChange( (PlayerNumber)p );
|
||||
}
|
||||
m_SoundNextRow.Play();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user