mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2025-04-12 06:54:41 -04:00
Merge d2e59cf4d0
into d31ef12363
This commit is contained in:
commit
439955a434
3 changed files with 173 additions and 2 deletions
source/funkin
|
@ -145,6 +145,64 @@ class SongDataUtils
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of notes whose note data is mirrored.
|
||||
* Does not mutate the original array.
|
||||
*
|
||||
* @param flip Flip the notes if the notes given are in both strumlines, so that result isn't inverted when mirrored.
|
||||
* @param mirrorX Mirror along the X axis, aka the directions of the notes.
|
||||
* @param mirrorY Mirror along the Y axis, aka the time of the notes. If mirror X is true it won't mirror along Y.
|
||||
*/
|
||||
public static function mirrorNotes(notes:Array<SongNoteData>, ?strumlineSize:Int = 4, flip:Bool = false, mirrorX:Bool = true,
|
||||
mirrorY:Bool = true):Array<SongNoteData>
|
||||
{
|
||||
|
||||
var minTime = notes[0].time;
|
||||
var maxTime = notes[0].time;
|
||||
var minStrumline = notes[0].data;
|
||||
var maxStrumline = notes[0].data;
|
||||
for (note in notes)
|
||||
{
|
||||
// Find the maximum and minimum time and strumline positions
|
||||
// I wish there was a better way of doing this
|
||||
if (flip)
|
||||
{
|
||||
if (note.data < minStrumline) minStrumline = note.data;
|
||||
else if (note.data > maxStrumline) maxStrumline = note.data;
|
||||
}
|
||||
if (note.time < minTime) minTime = note.time;
|
||||
else if (note.time > maxTime) maxTime = note.time;
|
||||
}
|
||||
|
||||
var timeDiff = minTime + (maxTime - minTime) / 2;
|
||||
if (flip && minStrumline < strumlineSize && strumlineSize < maxStrumline)
|
||||
{
|
||||
// Flip the notes if one of the notes is on the other strum
|
||||
// Otherwise they'll be inverted when mirrored
|
||||
notes = flipNotes(notes);
|
||||
}
|
||||
|
||||
return notes.map(function(note:SongNoteData):SongNoteData {
|
||||
var newData = note.data;
|
||||
var newTime = note.time;
|
||||
|
||||
if (mirrorX)
|
||||
{
|
||||
if (newData < strumlineSize) newData = strumlineSize - 1 - newData;
|
||||
else
|
||||
newData = strumlineSize + strumlineSize * 2 - 1 - newData;
|
||||
}
|
||||
// No need to do this if both are true, otherwise the note positions don't actually change and we waste our time
|
||||
if (mirrorY && !mirrorX)
|
||||
{
|
||||
if (newTime < timeDiff) newTime += (timeDiff - newTime) * 2;
|
||||
else if (newTime > timeDiff) newTime -= (newTime - timeDiff) * 2;
|
||||
}
|
||||
|
||||
return new SongNoteData(newTime, newData, note.length, note.kind);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of notes to be used as the clipboard data.
|
||||
*
|
||||
|
|
|
@ -53,6 +53,7 @@ import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
|
|||
import funkin.ui.debug.charting.commands.DeselectItemsCommand;
|
||||
import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand;
|
||||
import funkin.ui.debug.charting.commands.FlipNotesCommand;
|
||||
import funkin.ui.debug.charting.commands.MirrorNotesCommand;
|
||||
import funkin.ui.debug.charting.commands.InvertSelectedItemsCommand;
|
||||
import funkin.ui.debug.charting.commands.MoveEventsCommand;
|
||||
import funkin.ui.debug.charting.commands.MoveItemsCommand;
|
||||
|
@ -3399,7 +3400,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
{
|
||||
currentScrollEase = scrollPositionInPixels;
|
||||
|
||||
if (FlxG.keys.pressed.ALT)
|
||||
if (FlxG.keys.pressed.ALT && !FlxG.keys.pressed.CONTROL)
|
||||
{
|
||||
// If middle mouse panning during song playback, we move ONLY the playhead, without scrolling. Neat!
|
||||
|
||||
|
@ -5389,7 +5390,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
function handleFileKeybinds():Void
|
||||
{
|
||||
// CTRL + N = New Chart
|
||||
if (pressingControl() && FlxG.keys.justPressed.N && !isHaxeUIDialogOpen)
|
||||
if (pressingControl()
|
||||
&& FlxG.keys.justPressed.N
|
||||
&& !isHaxeUIDialogOpen
|
||||
&& !FlxG.keys.pressed.SHIFT
|
||||
&& !FlxG.keys.pressed.ALT)
|
||||
{
|
||||
this.openWelcomeDialog(true);
|
||||
}
|
||||
|
@ -5522,6 +5527,17 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
performCommand(new FlipNotesCommand(currentNoteSelection));
|
||||
}
|
||||
|
||||
// CTRL + SHIFT + M = Mirror Notes along X axis
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.M)
|
||||
{
|
||||
performCommand(new MirrorNotesCommand(currentNoteSelection, true, false, true, false));
|
||||
}
|
||||
// CTRL + ALT + M = Mirror Notes along the Y axis
|
||||
else if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.justPressed.M)
|
||||
{
|
||||
performCommand(new MirrorNotesCommand(currentNoteSelection, true, false, false, true));
|
||||
}
|
||||
|
||||
// CTRL + A = Select All Notes
|
||||
if (pressingControl() && FlxG.keys.justPressed.A)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package funkin.ui.debug.charting.commands;
|
||||
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
|
||||
/**
|
||||
* Command that mirrors a given array of notes on either or strumline individually,
|
||||
* along either the X (note direction) axis or Y (note time) axis.
|
||||
* Flip middle will only work when the given notes are in both strumlines - it's incompatible with individually mirroring the selection.
|
||||
*/
|
||||
@:nullSafety
|
||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||
class MirrorNotesCommand implements ChartEditorCommand
|
||||
{
|
||||
var notes:Array<SongNoteData> = [];
|
||||
var mirroredNotes:Array<SongNoteData> = [];
|
||||
var mirrorX:Bool = true;
|
||||
var mirrorY:Bool = true;
|
||||
|
||||
public function new(notes:Array<SongNoteData>, mirrorIndividually:Bool = true, flipMiddle:Bool = false, mirrorX:Bool = true, mirrorY:Bool = true)
|
||||
{
|
||||
this.notes = notes;
|
||||
this.mirrorX = mirrorX;
|
||||
this.mirrorY = mirrorY;
|
||||
if (mirrorIndividually)
|
||||
{
|
||||
var playerNotes:Array<SongNoteData> = [];
|
||||
var opponentNotes:Array<SongNoteData> = [];
|
||||
// Sort the selection by the strumline positions and then mirror each individually
|
||||
for (note in notes)
|
||||
{
|
||||
if (note.data < ChartEditorState.STRUMLINE_SIZE)
|
||||
{
|
||||
playerNotes.push(note);
|
||||
}
|
||||
else if (note.data >= ChartEditorState.STRUMLINE_SIZE)
|
||||
{
|
||||
opponentNotes.push(note);
|
||||
}
|
||||
}
|
||||
if (playerNotes.length > 0)
|
||||
{
|
||||
this.mirroredNotes = mirroredNotes.concat(SongDataUtils.mirrorNotes(playerNotes, ChartEditorState.STRUMLINE_SIZE, flipMiddle, mirrorX, mirrorY));
|
||||
}
|
||||
if (opponentNotes.length > 0)
|
||||
{
|
||||
this.mirroredNotes = mirroredNotes.concat(SongDataUtils.mirrorNotes(opponentNotes, ChartEditorState.STRUMLINE_SIZE, flipMiddle, mirrorX, mirrorY));
|
||||
}
|
||||
}
|
||||
else
|
||||
this.mirroredNotes = SongDataUtils.mirrorNotes(notes, ChartEditorState.STRUMLINE_SIZE, flipMiddle, mirrorX, mirrorY);
|
||||
}
|
||||
|
||||
public function execute(state:ChartEditorState):Void
|
||||
{
|
||||
// Delete the notes.
|
||||
state.currentSongChartNoteData = SongDataUtils.subtractNotes(state.currentSongChartNoteData, notes);
|
||||
|
||||
// Add the flipped notes.
|
||||
state.currentSongChartNoteData = state.currentSongChartNoteData.concat(mirroredNotes);
|
||||
|
||||
state.currentNoteSelection = mirroredNotes;
|
||||
state.currentEventSelection = [];
|
||||
|
||||
state.saveDataDirty = true;
|
||||
state.noteDisplayDirty = true;
|
||||
state.notePreviewDirty = true;
|
||||
state.sortChartData();
|
||||
}
|
||||
|
||||
public function undo(state:ChartEditorState):Void
|
||||
{
|
||||
state.currentSongChartNoteData = SongDataUtils.subtractNotes(state.currentSongChartNoteData, mirroredNotes);
|
||||
state.currentSongChartNoteData = state.currentSongChartNoteData.concat(notes);
|
||||
|
||||
state.currentNoteSelection = notes;
|
||||
state.currentEventSelection = [];
|
||||
|
||||
state.saveDataDirty = true;
|
||||
state.noteDisplayDirty = true;
|
||||
state.notePreviewDirty = true;
|
||||
|
||||
state.sortChartData();
|
||||
}
|
||||
|
||||
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||
{
|
||||
// This command is undoable. Add to the history if we actually performed an action.
|
||||
return (notes.length > 0 && mirrorX || !mirrorX && mirrorY && notes.length > 1);
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
var len:Int = notes.length;
|
||||
return 'Mirror ${(notes.length > 1) ? '$len Notes' : 'Note'} on ${(mirrorX) ? 'X' : (mirrorY) ? 'Y' : 'huh?'} Axis';
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue