mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-22 09:59:25 +00:00
Merge branch 'rewrite/master' into bugfix/controller-overflow
This commit is contained in:
commit
2a7f9a0880
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit b282f3431c15b719222196813da98ab70839d3e5
|
Subproject commit e56184c0851e822136e3d254a51c89d54022938d
|
|
@ -273,7 +273,7 @@ class SongDataUtils
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter a list of notes to only include notes whose data is within the given range.
|
* Filter a list of notes to only include notes whose data is within the given range, inclusive.
|
||||||
*/
|
*/
|
||||||
public static function getNotesInDataRange(notes:Array<SongNoteData>, start:Int, end:Int):Array<SongNoteData>
|
public static function getNotesInDataRange(notes:Array<SongNoteData>, start:Int, end:Int):Array<SongNoteData>
|
||||||
{
|
{
|
||||||
|
|
|
@ -176,6 +176,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
difficulty.generatedBy = metadata.generatedBy;
|
difficulty.generatedBy = metadata.generatedBy;
|
||||||
difficulty.offsets = metadata.offsets;
|
difficulty.offsets = metadata.offsets;
|
||||||
|
|
||||||
|
difficulty.difficultyRating = metadata.playData.ratings.get(diffId) ?? 0;
|
||||||
|
difficulty.album = metadata.playData.album;
|
||||||
|
|
||||||
difficulty.stage = metadata.playData.stage;
|
difficulty.stage = metadata.playData.stage;
|
||||||
difficulty.noteStyle = metadata.playData.noteStyle;
|
difficulty.noteStyle = metadata.playData.noteStyle;
|
||||||
|
|
||||||
|
@ -405,6 +408,9 @@ class SongDifficulty
|
||||||
|
|
||||||
public var scrollSpeed:Float = Constants.DEFAULT_SCROLLSPEED;
|
public var scrollSpeed:Float = Constants.DEFAULT_SCROLLSPEED;
|
||||||
|
|
||||||
|
public var difficultyRating:Int = 0;
|
||||||
|
public var album:Null<String> = null;
|
||||||
|
|
||||||
public function new(song:Song, diffId:String, variation:String)
|
public function new(song:Song, diffId:String, variation:String)
|
||||||
{
|
{
|
||||||
this.song = song;
|
this.song = song;
|
||||||
|
|
|
@ -274,4 +274,5 @@ enum abstract AtlasFont(String) from String to String
|
||||||
{
|
{
|
||||||
var DEFAULT = "default";
|
var DEFAULT = "default";
|
||||||
var BOLD = "bold";
|
var BOLD = "bold";
|
||||||
|
var FREEPLAY_CLEAR = "freeplay-clear";
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ import funkin.ui.debug.charting.commands.AddNotesCommand;
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
||||||
import funkin.ui.debug.charting.commands.CutItemsCommand;
|
import funkin.ui.debug.charting.commands.CutItemsCommand;
|
||||||
|
import funkin.ui.debug.charting.commands.CopyItemsCommand;
|
||||||
import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
|
import funkin.ui.debug.charting.commands.DeselectAllItemsCommand;
|
||||||
import funkin.ui.debug.charting.commands.DeselectItemsCommand;
|
import funkin.ui.debug.charting.commands.DeselectItemsCommand;
|
||||||
import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand;
|
import funkin.ui.debug.charting.commands.ExtendNoteLengthCommand;
|
||||||
|
@ -106,6 +107,7 @@ import haxe.ui.components.Slider;
|
||||||
import haxe.ui.components.TextField;
|
import haxe.ui.components.TextField;
|
||||||
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
import haxe.ui.containers.dialogs.CollapsibleDialog;
|
||||||
import haxe.ui.containers.Frame;
|
import haxe.ui.containers.Frame;
|
||||||
|
import haxe.ui.containers.Box;
|
||||||
import haxe.ui.containers.menus.Menu;
|
import haxe.ui.containers.menus.Menu;
|
||||||
import haxe.ui.containers.menus.MenuBar;
|
import haxe.ui.containers.menus.MenuBar;
|
||||||
import haxe.ui.containers.menus.MenuItem;
|
import haxe.ui.containers.menus.MenuItem;
|
||||||
|
@ -193,10 +195,40 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
public static final PLAYBAR_HEIGHT:Int = 48;
|
public static final PLAYBAR_HEIGHT:Int = 48;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the note selection buttons above the grid.
|
||||||
|
*/
|
||||||
|
public static final NOTE_SELECT_BUTTON_HEIGHT:Int = 24;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of padding between the menu bar and the chart grid when fully scrolled up.
|
* The amount of padding between the menu bar and the chart grid when fully scrolled up.
|
||||||
*/
|
*/
|
||||||
public static final GRID_TOP_PAD:Int = 8;
|
public static final GRID_TOP_PAD:Int = NOTE_SELECT_BUTTON_HEIGHT + 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial vertical position of the chart grid.
|
||||||
|
*/
|
||||||
|
public static final GRID_INITIAL_Y_POS:Int = MENU_BAR_HEIGHT + GRID_TOP_PAD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The X position of the note preview area.
|
||||||
|
*/
|
||||||
|
public static final NOTE_PREVIEW_X_POS:Int = 350;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Y position of the note preview area.
|
||||||
|
*/
|
||||||
|
public static final NOTE_PREVIEW_Y_POS:Int = GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT - 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The X position of the note grid.
|
||||||
|
*/
|
||||||
|
public static var GRID_X_POS(get, never):Float;
|
||||||
|
|
||||||
|
static function get_GRID_X_POS():Float
|
||||||
|
{
|
||||||
|
return FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
// Background color tint.
|
// Background color tint.
|
||||||
|
@ -341,21 +373,21 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
if (isViewDownscroll)
|
if (isViewDownscroll)
|
||||||
{
|
{
|
||||||
gridTiledSprite.y = -scrollPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD);
|
gridTiledSprite.y = -scrollPositionInPixels + (GRID_INITIAL_Y_POS);
|
||||||
measureTicks.y = gridTiledSprite.y;
|
measureTicks.y = gridTiledSprite.y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gridTiledSprite.y = -scrollPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD);
|
gridTiledSprite.y = -scrollPositionInPixels + (GRID_INITIAL_Y_POS);
|
||||||
measureTicks.y = gridTiledSprite.y;
|
measureTicks.y = gridTiledSprite.y;
|
||||||
|
|
||||||
if (audioVisGroup != null && audioVisGroup.playerVis != null)
|
if (audioVisGroup != null && audioVisGroup.playerVis != null)
|
||||||
{
|
{
|
||||||
audioVisGroup.playerVis.y = Math.max(gridTiledSprite.y, MENU_BAR_HEIGHT);
|
audioVisGroup.playerVis.y = Math.max(gridTiledSprite.y, GRID_INITIAL_Y_POS);
|
||||||
}
|
}
|
||||||
if (audioVisGroup != null && audioVisGroup.opponentVis != null)
|
if (audioVisGroup != null && audioVisGroup.opponentVis != null)
|
||||||
{
|
{
|
||||||
audioVisGroup.opponentVis.y = Math.max(gridTiledSprite.y, MENU_BAR_HEIGHT);
|
audioVisGroup.opponentVis.y = Math.max(gridTiledSprite.y, GRID_INITIAL_Y_POS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,7 +459,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
this.playheadPositionInPixels = value;
|
this.playheadPositionInPixels = value;
|
||||||
|
|
||||||
// Move the playhead sprite to the correct position.
|
// Move the playhead sprite to the correct position.
|
||||||
gridPlayhead.y = this.playheadPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD);
|
gridPlayhead.y = this.playheadPositionInPixels + GRID_INITIAL_Y_POS;
|
||||||
|
|
||||||
return this.playheadPositionInPixels;
|
return this.playheadPositionInPixels;
|
||||||
}
|
}
|
||||||
|
@ -1677,6 +1709,24 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
var playbarEnd:Button;
|
var playbarEnd:Button;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button above the grid that selects all notes on the opponent's side.
|
||||||
|
* Constructed manually and added to the layout so we can control its position.
|
||||||
|
*/
|
||||||
|
var buttonSelectOpponent:Button;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button above the grid that selects all notes on the player's side.
|
||||||
|
* Constructed manually and added to the layout so we can control its position.
|
||||||
|
*/
|
||||||
|
var buttonSelectPlayer:Button;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button above the grid that selects all song events.
|
||||||
|
* Constructed manually and added to the layout so we can control its position.
|
||||||
|
*/
|
||||||
|
var buttonSelectEvent:Button;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RENDER OBJECTS
|
* RENDER OBJECTS
|
||||||
*/
|
*/
|
||||||
|
@ -2112,8 +2162,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (gridBitmap == null) throw 'ERROR: Tried to build grid, but gridBitmap is null! Check ChartEditorThemeHandler.updateTheme().';
|
if (gridBitmap == null) throw 'ERROR: Tried to build grid, but gridBitmap is null! Check ChartEditorThemeHandler.updateTheme().';
|
||||||
|
|
||||||
gridTiledSprite = new FlxTiledSprite(gridBitmap, gridBitmap.width, 1000, false, true);
|
gridTiledSprite = new FlxTiledSprite(gridBitmap, gridBitmap.width, 1000, false, true);
|
||||||
gridTiledSprite.x = FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE; // Center the grid.
|
gridTiledSprite.x = GRID_X_POS; // Center the grid.
|
||||||
gridTiledSprite.y = MENU_BAR_HEIGHT + GRID_TOP_PAD; // Push down to account for the menu bar.
|
gridTiledSprite.y = GRID_INITIAL_Y_POS; // Push down to account for the menu bar.
|
||||||
add(gridTiledSprite);
|
add(gridTiledSprite);
|
||||||
gridTiledSprite.zIndex = 10;
|
gridTiledSprite.zIndex = 10;
|
||||||
|
|
||||||
|
@ -2144,9 +2194,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
add(gridPlayhead);
|
add(gridPlayhead);
|
||||||
gridPlayhead.zIndex = 30;
|
gridPlayhead.zIndex = 30;
|
||||||
|
|
||||||
var playheadWidth:Int = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + (PLAYHEAD_SCROLL_AREA_WIDTH);
|
var playheadWidth:Int = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + (PLAYHEAD_SCROLL_AREA_WIDTH * 2);
|
||||||
var playheadBaseYPos:Float = MENU_BAR_HEIGHT + GRID_TOP_PAD;
|
var playheadBaseYPos:Float = GRID_INITIAL_Y_POS;
|
||||||
gridPlayhead.setPosition(gridTiledSprite.x, playheadBaseYPos);
|
gridPlayhead.setPosition(GRID_X_POS, playheadBaseYPos);
|
||||||
var playheadSprite:FlxSprite = new FlxSprite().makeGraphic(playheadWidth, PLAYHEAD_HEIGHT, PLAYHEAD_COLOR);
|
var playheadSprite:FlxSprite = new FlxSprite().makeGraphic(playheadWidth, PLAYHEAD_HEIGHT, PLAYHEAD_COLOR);
|
||||||
playheadSprite.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
playheadSprite.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
||||||
playheadSprite.y = 0;
|
playheadSprite.y = 0;
|
||||||
|
@ -2188,10 +2238,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
function buildNotePreview():Void
|
function buildNotePreview():Void
|
||||||
{
|
{
|
||||||
var height:Int = FlxG.height - MENU_BAR_HEIGHT - GRID_TOP_PAD - PLAYBAR_HEIGHT - GRID_TOP_PAD - GRID_TOP_PAD;
|
var playbarHeightWithPad = PLAYBAR_HEIGHT + 10;
|
||||||
notePreview = new ChartEditorNotePreview(height);
|
var notePreviewHeight:Int = FlxG.height - NOTE_PREVIEW_Y_POS - playbarHeightWithPad;
|
||||||
notePreview.x = 320;
|
notePreview = new ChartEditorNotePreview(notePreviewHeight);
|
||||||
notePreview.y = MENU_BAR_HEIGHT + GRID_TOP_PAD;
|
notePreview.x = NOTE_PREVIEW_X_POS;
|
||||||
|
notePreview.y = NOTE_PREVIEW_Y_POS;
|
||||||
add(notePreview);
|
add(notePreview);
|
||||||
|
|
||||||
if (notePreviewViewport == null) throw 'ERROR: Tried to build note preview, but notePreviewViewport is null! Check ChartEditorThemeHandler.updateTheme().';
|
if (notePreviewViewport == null) throw 'ERROR: Tried to build note preview, but notePreviewViewport is null! Check ChartEditorThemeHandler.updateTheme().';
|
||||||
|
@ -2377,6 +2428,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
add(playbarHeadLayout);
|
add(playbarHeadLayout);
|
||||||
|
|
||||||
|
// Little text that shows up when you copy something.
|
||||||
txtCopyNotif = new FlxText(0, 0, 0, '', 24);
|
txtCopyNotif = new FlxText(0, 0, 0, '', 24);
|
||||||
txtCopyNotif.setBorderStyle(OUTLINE, 0xFF074809, 1);
|
txtCopyNotif.setBorderStyle(OUTLINE, 0xFF074809, 1);
|
||||||
txtCopyNotif.color = 0xFF52FF77;
|
txtCopyNotif.color = 0xFF52FF77;
|
||||||
|
@ -2401,6 +2453,77 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
this.openCharacterDropdown(CharacterType.BF, true);
|
this.openCharacterDropdown(CharacterType.BF, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
buttonSelectOpponent = new Button();
|
||||||
|
buttonSelectOpponent.allowFocus = false;
|
||||||
|
buttonSelectOpponent.text = "Opponent"; // Default text.
|
||||||
|
buttonSelectOpponent.x = GRID_X_POS;
|
||||||
|
buttonSelectOpponent.y = GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT - 8;
|
||||||
|
buttonSelectOpponent.width = GRID_SIZE * 4;
|
||||||
|
buttonSelectOpponent.height = NOTE_SELECT_BUTTON_HEIGHT;
|
||||||
|
buttonSelectOpponent.tooltip = "Click to set selection to all notes on this side.\nShift-click to add all notes on this side to selection.";
|
||||||
|
buttonSelectOpponent.zIndex = 110;
|
||||||
|
add(buttonSelectOpponent);
|
||||||
|
|
||||||
|
buttonSelectOpponent.onClick = (_) -> {
|
||||||
|
var notesToSelect:Array<SongNoteData> = currentSongChartNoteData;
|
||||||
|
notesToSelect = SongDataUtils.getNotesInDataRange(notesToSelect, STRUMLINE_SIZE, STRUMLINE_SIZE * 2 - 1);
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
performCommand(new SelectItemsCommand(notesToSelect, []));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
performCommand(new SetItemSelectionCommand(notesToSelect, []));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonSelectPlayer = new Button();
|
||||||
|
buttonSelectPlayer.allowFocus = false;
|
||||||
|
buttonSelectPlayer.text = "Player"; // Default text.
|
||||||
|
buttonSelectPlayer.x = buttonSelectOpponent.x + buttonSelectOpponent.width;
|
||||||
|
buttonSelectPlayer.y = buttonSelectOpponent.y;
|
||||||
|
buttonSelectPlayer.width = GRID_SIZE * 4;
|
||||||
|
buttonSelectPlayer.height = NOTE_SELECT_BUTTON_HEIGHT;
|
||||||
|
buttonSelectPlayer.tooltip = "Click to set selection to all notes on this side.\nShift-click to add all notes on this side to selection.";
|
||||||
|
buttonSelectPlayer.zIndex = 110;
|
||||||
|
add(buttonSelectPlayer);
|
||||||
|
|
||||||
|
buttonSelectPlayer.onClick = (_) -> {
|
||||||
|
var notesToSelect:Array<SongNoteData> = currentSongChartNoteData;
|
||||||
|
notesToSelect = SongDataUtils.getNotesInDataRange(notesToSelect, 0, STRUMLINE_SIZE - 1);
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
performCommand(new SelectItemsCommand(notesToSelect, []));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
performCommand(new SetItemSelectionCommand(notesToSelect, []));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonSelectEvent = new Button();
|
||||||
|
buttonSelectEvent.allowFocus = false;
|
||||||
|
buttonSelectEvent.icon = Paths.image('ui/chart-editor/events/Default');
|
||||||
|
buttonSelectEvent.iconPosition = "top";
|
||||||
|
buttonSelectEvent.x = buttonSelectPlayer.x + buttonSelectPlayer.width;
|
||||||
|
buttonSelectEvent.y = buttonSelectPlayer.y;
|
||||||
|
buttonSelectEvent.width = GRID_SIZE;
|
||||||
|
buttonSelectEvent.height = NOTE_SELECT_BUTTON_HEIGHT;
|
||||||
|
buttonSelectEvent.tooltip = "Click to set selection to all events.\nShift-click to add all events to selection.";
|
||||||
|
buttonSelectEvent.zIndex = 110;
|
||||||
|
add(buttonSelectEvent);
|
||||||
|
|
||||||
|
buttonSelectEvent.onClick = (_) -> {
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
performCommand(new SelectItemsCommand([], currentSongChartEventData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
performCommand(new SetItemSelectionCommand([], currentSongChartEventData));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2527,11 +2650,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
menubarItemFlipNotes.onClick = _ -> performCommand(new FlipNotesCommand(currentNoteSelection));
|
menubarItemFlipNotes.onClick = _ -> performCommand(new FlipNotesCommand(currentNoteSelection));
|
||||||
|
|
||||||
menubarItemSelectAll.onClick = _ -> performCommand(new SelectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
menubarItemSelectAllNotes.onClick = _ -> performCommand(new SelectAllItemsCommand(true, false));
|
||||||
|
|
||||||
menubarItemSelectInverse.onClick = _ -> performCommand(new InvertSelectedItemsCommand(currentNoteSelection, currentEventSelection));
|
menubarItemSelectAllEvents.onClick = _ -> performCommand(new SelectAllItemsCommand(false, true));
|
||||||
|
|
||||||
menubarItemSelectNone.onClick = _ -> performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
menubarItemSelectInverse.onClick = _ -> performCommand(new InvertSelectedItemsCommand());
|
||||||
|
|
||||||
|
menubarItemSelectNone.onClick = _ -> performCommand(new DeselectAllItemsCommand());
|
||||||
|
|
||||||
menubarItemPlaytestFull.onClick = _ -> testSongInPlayState(false);
|
menubarItemPlaytestFull.onClick = _ -> testSongInPlayState(false);
|
||||||
menubarItemPlaytestMinimal.onClick = _ -> testSongInPlayState(true);
|
menubarItemPlaytestMinimal.onClick = _ -> testSongInPlayState(true);
|
||||||
|
@ -3047,7 +3172,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
if (holdNoteSprite == null || holdNoteSprite.noteData == null || !holdNoteSprite.exists || !holdNoteSprite.visible) continue;
|
if (holdNoteSprite == null || holdNoteSprite.noteData == null || !holdNoteSprite.exists || !holdNoteSprite.visible) continue;
|
||||||
|
|
||||||
if (!holdNoteSprite.isHoldNoteVisible(FlxG.height - MENU_BAR_HEIGHT, GRID_TOP_PAD))
|
if (!holdNoteSprite.isHoldNoteVisible(FlxG.height - PLAYBAR_HEIGHT, MENU_BAR_HEIGHT))
|
||||||
{
|
{
|
||||||
holdNoteSprite.kill();
|
holdNoteSprite.kill();
|
||||||
}
|
}
|
||||||
|
@ -3083,7 +3208,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Resolve an issue where dragging an event too far would cause it to be hidden.
|
// Resolve an issue where dragging an event too far would cause it to be hidden.
|
||||||
var isSelectedAndDragged = currentEventSelection.fastContains(eventSprite.eventData) && (dragTargetCurrentStep != 0);
|
var isSelectedAndDragged = currentEventSelection.fastContains(eventSprite.eventData) && (dragTargetCurrentStep != 0);
|
||||||
|
|
||||||
if ((eventSprite.isEventVisible(FlxG.height - MENU_BAR_HEIGHT, GRID_TOP_PAD)
|
if ((eventSprite.isEventVisible(FlxG.height - PLAYBAR_HEIGHT, MENU_BAR_HEIGHT)
|
||||||
&& currentSongChartEventData.fastContains(eventSprite.eventData))
|
&& currentSongChartEventData.fastContains(eventSprite.eventData))
|
||||||
|| isSelectedAndDragged)
|
|| isSelectedAndDragged)
|
||||||
{
|
{
|
||||||
|
@ -3631,7 +3756,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
// Clicked on the playhead scroll area.
|
// Clicked on the playhead scroll area.
|
||||||
// Move the playhead to the cursor position.
|
// Move the playhead to the cursor position.
|
||||||
this.playheadPositionInPixels = FlxG.mouse.screenY - MENU_BAR_HEIGHT - GRID_TOP_PAD;
|
this.playheadPositionInPixels = FlxG.mouse.screenY - (GRID_INITIAL_Y_POS);
|
||||||
moveSongToScrollPosition();
|
moveSongToScrollPosition();
|
||||||
|
|
||||||
// Cursor should be a grabby hand.
|
// Cursor should be a grabby hand.
|
||||||
|
@ -3724,7 +3849,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set the selection.
|
// Set the selection.
|
||||||
performCommand(new SetItemSelectionCommand(notesToSelect, eventsToSelect, currentNoteSelection, currentEventSelection));
|
performCommand(new SetItemSelectionCommand(notesToSelect, eventsToSelect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3737,7 +3862,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||||
if (shouldDeselect)
|
if (shouldDeselect)
|
||||||
{
|
{
|
||||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new DeselectAllItemsCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3842,12 +3967,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (highlightedNote != null && highlightedNote.noteData != null)
|
if (highlightedNote != null && highlightedNote.noteData != null)
|
||||||
{
|
{
|
||||||
// Click a note to select it.
|
// Click a note to select it.
|
||||||
performCommand(new SetItemSelectionCommand([highlightedNote.noteData], [], currentNoteSelection, currentEventSelection));
|
performCommand(new SetItemSelectionCommand([highlightedNote.noteData], []));
|
||||||
}
|
}
|
||||||
else if (highlightedEvent != null && highlightedEvent.eventData != null)
|
else if (highlightedEvent != null && highlightedEvent.eventData != null)
|
||||||
{
|
{
|
||||||
// Click an event to select it.
|
// Click an event to select it.
|
||||||
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData], currentNoteSelection, currentEventSelection));
|
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3855,7 +3980,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||||
if (shouldDeselect)
|
if (shouldDeselect)
|
||||||
{
|
{
|
||||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new DeselectAllItemsCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3870,7 +3995,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
var shouldDeselect:Bool = !wasCursorOverHaxeUI && (currentNoteSelection.length > 0 || currentEventSelection.length > 0);
|
||||||
if (shouldDeselect)
|
if (shouldDeselect)
|
||||||
{
|
{
|
||||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new DeselectAllItemsCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4111,7 +4236,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If you click an unselected note, and aren't holding Control, deselect everything else.
|
// If you click an unselected note, and aren't holding Control, deselect everything else.
|
||||||
performCommand(new SetItemSelectionCommand([highlightedNote.noteData], [], currentNoteSelection, currentEventSelection));
|
performCommand(new SetItemSelectionCommand([highlightedNote.noteData], []));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (highlightedEvent != null && highlightedEvent.eventData != null)
|
else if (highlightedEvent != null && highlightedEvent.eventData != null)
|
||||||
|
@ -4124,7 +4249,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If you click an unselected event, and aren't holding Control, deselect everything else.
|
// If you click an unselected event, and aren't holding Control, deselect everything else.
|
||||||
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData], currentNoteSelection, currentEventSelection));
|
performCommand(new SetItemSelectionCommand([], [highlightedEvent.eventData]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4425,7 +4550,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
if (currentSongMetadata.playData.characters.player != charPlayer.charId)
|
if (currentSongMetadata.playData.characters.player != charPlayer.charId)
|
||||||
{
|
{
|
||||||
if (healthIconBF != null) healthIconBF.characterId = currentSongMetadata.playData.characters.player;
|
if (healthIconBF != null)
|
||||||
|
{
|
||||||
|
healthIconBF.characterId = currentSongMetadata.playData.characters.player;
|
||||||
|
}
|
||||||
|
|
||||||
charPlayer.loadCharacter(currentSongMetadata.playData.characters.player);
|
charPlayer.loadCharacter(currentSongMetadata.playData.characters.player);
|
||||||
charPlayer.characterType = CharacterType.BF;
|
charPlayer.characterType = CharacterType.BF;
|
||||||
|
@ -4461,7 +4589,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
if (currentSongMetadata.playData.characters.opponent != charPlayer.charId)
|
if (currentSongMetadata.playData.characters.opponent != charPlayer.charId)
|
||||||
{
|
{
|
||||||
if (healthIconDad != null) healthIconDad.characterId = currentSongMetadata.playData.characters.opponent;
|
if (healthIconDad != null)
|
||||||
|
{
|
||||||
|
healthIconDad.characterId = currentSongMetadata.playData.characters.opponent;
|
||||||
|
}
|
||||||
|
|
||||||
charPlayer.loadCharacter(currentSongMetadata.playData.characters.opponent);
|
charPlayer.loadCharacter(currentSongMetadata.playData.characters.opponent);
|
||||||
charPlayer.characterType = CharacterType.DAD;
|
charPlayer.characterType = CharacterType.DAD;
|
||||||
|
@ -4479,6 +4610,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSelectionButtons():Void
|
||||||
|
{
|
||||||
|
// Make sure buttons are never nudged out of the correct spot.
|
||||||
|
// TODO: Why do these even move in the first place? The camera never moves, LOL.
|
||||||
|
buttonSelectOpponent.y = GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT - 2;
|
||||||
|
buttonSelectPlayer.y = GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT - 2;
|
||||||
|
buttonSelectEvent.y = GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT - 2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles display elements for the playbar at the bottom.
|
* Handles display elements for the playbar at the bottom.
|
||||||
*/
|
*/
|
||||||
|
@ -4587,11 +4727,19 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
healthIconBF.size *= 0.5; // Make the icon smaller in Chart Editor.
|
healthIconBF.size *= 0.5; // Make the icon smaller in Chart Editor.
|
||||||
healthIconBF.flipX = !healthIconBF.flipX; // BF faces the other way.
|
healthIconBF.flipX = !healthIconBF.flipX; // BF faces the other way.
|
||||||
}
|
}
|
||||||
|
if (buttonSelectPlayer != null)
|
||||||
|
{
|
||||||
|
buttonSelectPlayer.text = charDataBF?.name ?? 'Player';
|
||||||
|
}
|
||||||
if (healthIconDad != null)
|
if (healthIconDad != null)
|
||||||
{
|
{
|
||||||
healthIconDad.configure(charDataDad?.healthIcon);
|
healthIconDad.configure(charDataDad?.healthIcon);
|
||||||
healthIconDad.size *= 0.5; // Make the icon smaller in Chart Editor.
|
healthIconDad.size *= 0.5; // Make the icon smaller in Chart Editor.
|
||||||
}
|
}
|
||||||
|
if (buttonSelectOpponent != null)
|
||||||
|
{
|
||||||
|
buttonSelectOpponent.text = charDataDad?.name ?? 'Opponent';
|
||||||
|
}
|
||||||
healthIconsDirty = false;
|
healthIconsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4599,15 +4747,19 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (healthIconBF != null)
|
if (healthIconBF != null)
|
||||||
{
|
{
|
||||||
// Base X position to the right of the grid.
|
// Base X position to the right of the grid.
|
||||||
healthIconBF.x = (gridTiledSprite == null) ? (0) : (gridTiledSprite.x + gridTiledSprite.width + 45 - (healthIconBF.width / 2));
|
var xOffset = 45 - (healthIconBF.width / 2);
|
||||||
healthIconBF.y = (gridTiledSprite == null) ? (0) : (MENU_BAR_HEIGHT + GRID_TOP_PAD + 30 - (healthIconBF.height / 2));
|
healthIconBF.x = (gridTiledSprite == null) ? (0) : (GRID_X_POS + gridTiledSprite.width + xOffset);
|
||||||
|
var yOffset = 30 - (healthIconBF.height / 2);
|
||||||
|
healthIconBF.y = (gridTiledSprite == null) ? (0) : (GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT) + yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visibly center the Dad health icon.
|
// Visibly center the Dad health icon.
|
||||||
if (healthIconDad != null)
|
if (healthIconDad != null)
|
||||||
{
|
{
|
||||||
healthIconDad.x = (gridTiledSprite == null) ? (0) : (gridTiledSprite.x - 75 - (healthIconDad.width / 2));
|
var xOffset = 45 + (healthIconDad.width / 2);
|
||||||
healthIconDad.y = (gridTiledSprite == null) ? (0) : (MENU_BAR_HEIGHT + GRID_TOP_PAD + 30 - (healthIconDad.height / 2));
|
healthIconDad.x = (gridTiledSprite == null) ? (0) : (GRID_X_POS - xOffset);
|
||||||
|
var yOffset = 30 - (healthIconDad.height / 2);
|
||||||
|
healthIconDad.y = (gridTiledSprite == null) ? (0) : (GRID_INITIAL_Y_POS - NOTE_SELECT_BUTTON_HEIGHT) + yOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4689,54 +4841,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// CTRL + C = Copy
|
// CTRL + C = Copy
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.C)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.C)
|
||||||
{
|
{
|
||||||
if (currentNoteSelection.length > 0)
|
performCommand(new CopyItemsCommand(currentNoteSelection, currentEventSelection));
|
||||||
{
|
|
||||||
txtCopyNotif.visible = true;
|
|
||||||
txtCopyNotif.text = "Copied " + currentNoteSelection.length + " notes to clipboard";
|
|
||||||
txtCopyNotif.x = FlxG.mouse.x - (txtCopyNotif.width / 2);
|
|
||||||
txtCopyNotif.y = FlxG.mouse.y - 16;
|
|
||||||
FlxTween.tween(txtCopyNotif, {y: txtCopyNotif.y - 32}, 0.5,
|
|
||||||
{
|
|
||||||
type: FlxTween.ONESHOT,
|
|
||||||
ease: FlxEase.quadOut,
|
|
||||||
onComplete: function(_) {
|
|
||||||
txtCopyNotif.visible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (note in renderedNotes.members)
|
|
||||||
{
|
|
||||||
if (isNoteSelected(note.noteData))
|
|
||||||
{
|
|
||||||
FlxTween.globalManager.cancelTweensOf(note);
|
|
||||||
FlxTween.globalManager.cancelTweensOf(note.scale);
|
|
||||||
note.playNoteAnimation();
|
|
||||||
var prevX:Float = note.scale.x;
|
|
||||||
var prevY:Float = note.scale.y;
|
|
||||||
|
|
||||||
note.scale.x *= 1.2;
|
|
||||||
note.scale.y *= 1.2;
|
|
||||||
|
|
||||||
note.angle = FlxG.random.bool() ? -10 : 10;
|
|
||||||
FlxTween.tween(note, {"angle": 0}, 0.8, {ease: FlxEase.elasticOut});
|
|
||||||
|
|
||||||
FlxTween.tween(note.scale, {"y": prevX, "x": prevY}, 0.7,
|
|
||||||
{
|
|
||||||
ease: FlxEase.elasticOut,
|
|
||||||
onComplete: function(_) {
|
|
||||||
note.playNoteAnimation();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't need a command for this since we can't undo it.
|
|
||||||
SongDataUtils.writeItemsToClipboard(
|
|
||||||
{
|
|
||||||
notes: SongDataUtils.buildNoteClipboard(currentNoteSelection),
|
|
||||||
events: SongDataUtils.buildEventClipboard(currentEventSelection),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL + X = Cut
|
// CTRL + X = Cut
|
||||||
|
@ -4797,25 +4902,50 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
performCommand(new FlipNotesCommand(currentNoteSelection));
|
performCommand(new FlipNotesCommand(currentNoteSelection));
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL + A = Select All
|
// CTRL + A = Select All Notes
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.A)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.A)
|
||||||
{
|
{
|
||||||
// Select all items.
|
// Select all items.
|
||||||
performCommand(new SelectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
if (FlxG.keys.pressed.ALT)
|
||||||
|
{
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
// CTRL + ALT + SHIFT + A = Append All Events to Selection
|
||||||
|
performCommand(new SelectItemsCommand([], currentSongChartEventData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// CTRL + ALT + A = Set Selection to All Events
|
||||||
|
performCommand(new SelectAllItemsCommand(false, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FlxG.keys.pressed.SHIFT)
|
||||||
|
{
|
||||||
|
// CTRL + SHIFT + A = Append All Notes to Selection
|
||||||
|
performCommand(new SelectItemsCommand(currentSongChartNoteData, []));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// CTRL + A = Set Selection to All Notes
|
||||||
|
performCommand(new SelectAllItemsCommand(true, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL + I = Select Inverse
|
// CTRL + I = Select Inverse
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.I)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.I)
|
||||||
{
|
{
|
||||||
// Select unselected items and deselect selected items.
|
// Select unselected items and deselect selected items.
|
||||||
performCommand(new InvertSelectedItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new InvertSelectedItemsCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL + D = Select None
|
// CTRL + D = Select None
|
||||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.D)
|
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.D)
|
||||||
{
|
{
|
||||||
// Deselect all items.
|
// Deselect all items.
|
||||||
performCommand(new DeselectAllItemsCommand(currentNoteSelection, currentEventSelection));
|
performCommand(new DeselectAllItemsCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4979,13 +5109,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
* Perform (or redo) a command, then add it to the undo stack.
|
* Perform (or redo) a command, then add it to the undo stack.
|
||||||
*
|
*
|
||||||
* @param command The command to perform.
|
* @param command The command to perform.
|
||||||
* @param purgeRedoStack If true, the redo stack will be cleared.
|
* @param purgeRedoStack If `true`, the redo stack will be cleared after performing the command.
|
||||||
*/
|
*/
|
||||||
function performCommand(command:ChartEditorCommand, purgeRedoStack:Bool = true):Void
|
function performCommand(command:ChartEditorCommand, purgeRedoStack:Bool = true):Void
|
||||||
{
|
{
|
||||||
command.execute(this);
|
command.execute(this);
|
||||||
undoHistory.push(command);
|
if (command.shouldAddToHistory(this))
|
||||||
commandHistoryDirty = true;
|
{
|
||||||
|
undoHistory.push(command);
|
||||||
|
commandHistoryDirty = true;
|
||||||
|
}
|
||||||
if (purgeRedoStack) redoHistory = [];
|
if (purgeRedoStack) redoHistory = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4996,6 +5129,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
function undoCommand(command:ChartEditorCommand):Void
|
function undoCommand(command:ChartEditorCommand):Void
|
||||||
{
|
{
|
||||||
command.undo(this);
|
command.undo(this);
|
||||||
|
// Note, if we are undoing a command, it should already be in the history,
|
||||||
|
// therefore we don't need to check `shouldAddToHistory(state)`
|
||||||
redoHistory.push(command);
|
redoHistory.push(command);
|
||||||
commandHistoryDirty = true;
|
commandHistoryDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -5333,6 +5468,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
if (displayAutosavePopup)
|
if (displayAutosavePopup)
|
||||||
{
|
{
|
||||||
displayAutosavePopup = false;
|
displayAutosavePopup = false;
|
||||||
|
#if sys
|
||||||
Toolkit.callLater(() -> {
|
Toolkit.callLater(() -> {
|
||||||
var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]);
|
var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]);
|
||||||
this.infoWithActions('Auto-Save', 'Chart auto-saved to ${absoluteBackupsPath}.', [
|
this.infoWithActions('Auto-Save', 'Chart auto-saved to ${absoluteBackupsPath}.', [
|
||||||
|
@ -5342,6 +5478,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
// TODO: No auto-save on HTML5?
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
moveSongToScrollPosition();
|
moveSongToScrollPosition();
|
||||||
|
@ -5644,6 +5783,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
@:privateAccess
|
@:privateAccess
|
||||||
ChartEditorNoteSprite.noteFrameCollection = null;
|
ChartEditorNoteSprite.noteFrameCollection = null;
|
||||||
|
|
||||||
|
// Stop the music.
|
||||||
|
welcomeMusic.destroy();
|
||||||
|
audioInstTrack.destroy();
|
||||||
|
audioVocalTrackGroup.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyCanQuickSave():Void
|
function applyCanQuickSave():Void
|
||||||
|
|
|
@ -59,6 +59,12 @@ class AddEventsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = events.length;
|
var len:Int = events.length;
|
||||||
|
|
|
@ -59,6 +59,12 @@ class AddNotesCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
if (notes.length == 1)
|
if (notes.length == 1)
|
||||||
|
|
|
@ -64,6 +64,12 @@ class ChangeStartingBPMCommand implements ChartEditorCommand
|
||||||
Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges);
|
Conductor.instance.mapTimeChanges(state.currentSongMetadata.timeChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (targetBPM != previousBPM);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Change Starting BPM to ${targetBPM}';
|
return 'Change Starting BPM to ${targetBPM}';
|
||||||
|
|
|
@ -6,6 +6,8 @@ package funkin.ui.debug.charting.commands;
|
||||||
*
|
*
|
||||||
* To make a functionality compatible with the undo/redo history, create a new class
|
* To make a functionality compatible with the undo/redo history, create a new class
|
||||||
* that implements ChartEditorCommand, then call `ChartEditorState.performCommand(new Command())`
|
* that implements ChartEditorCommand, then call `ChartEditorState.performCommand(new Command())`
|
||||||
|
*
|
||||||
|
* NOTE: Make the constructor very simple, as it may be called without executing by the command palette.
|
||||||
*/
|
*/
|
||||||
interface ChartEditorCommand
|
interface ChartEditorCommand
|
||||||
{
|
{
|
||||||
|
@ -22,6 +24,15 @@ interface ChartEditorCommand
|
||||||
*/
|
*/
|
||||||
public function undo(state:ChartEditorState):Void;
|
public function undo(state:ChartEditorState):Void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether or not this command should be appended to the in the undo/redo history.
|
||||||
|
* Generally this should be true, it should only be false if the command is minor and non-destructive,
|
||||||
|
* like copying to the clipboard.
|
||||||
|
*
|
||||||
|
* Called after `execute()` is performed.
|
||||||
|
*/
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a short description of the action (for the UI).
|
* Get a short description of the action (for the UI).
|
||||||
* For example, return `Add Left Note` to display `Undo Add Left Note` in the menu.
|
* For example, return `Add Left Note` to display `Undo Add Left Note` in the menu.
|
||||||
|
|
144
source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx
Normal file
144
source/funkin/ui/debug/charting/commands/CopyItemsCommand.hx
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
package funkin.ui.debug.charting.commands;
|
||||||
|
|
||||||
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
|
import funkin.data.song.SongData.SongEventData;
|
||||||
|
import funkin.data.song.SongDataUtils;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command that copies a given set of notes and song events to the clipboard,
|
||||||
|
* without deleting them from the chart editor.
|
||||||
|
*/
|
||||||
|
@:nullSafety
|
||||||
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
|
class CopyItemsCommand implements ChartEditorCommand
|
||||||
|
{
|
||||||
|
var notes:Array<SongNoteData>;
|
||||||
|
var events:Array<SongEventData>;
|
||||||
|
|
||||||
|
public function new(notes:Array<SongNoteData>, events:Array<SongEventData>)
|
||||||
|
{
|
||||||
|
this.notes = notes;
|
||||||
|
this.events = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(state:ChartEditorState):Void
|
||||||
|
{
|
||||||
|
// Calculate a single time offset for all the notes and events.
|
||||||
|
var timeOffset:Null<Int> = state.currentNoteSelection.length > 0 ? Std.int(state.currentNoteSelection[0].time) : null;
|
||||||
|
if (state.currentEventSelection.length > 0)
|
||||||
|
{
|
||||||
|
if (timeOffset == null || state.currentEventSelection[0].time < timeOffset)
|
||||||
|
{
|
||||||
|
timeOffset = Std.int(state.currentEventSelection[0].time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SongDataUtils.writeItemsToClipboard(
|
||||||
|
{
|
||||||
|
notes: SongDataUtils.buildNoteClipboard(state.currentNoteSelection, timeOffset),
|
||||||
|
events: SongDataUtils.buildEventClipboard(state.currentEventSelection, timeOffset),
|
||||||
|
});
|
||||||
|
|
||||||
|
performVisuals(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function performVisuals(state:ChartEditorState):Void
|
||||||
|
{
|
||||||
|
if (state.currentNoteSelection.length > 0)
|
||||||
|
{
|
||||||
|
// Display the "Copied Notes" text.
|
||||||
|
if (state.txtCopyNotif != null)
|
||||||
|
{
|
||||||
|
state.txtCopyNotif.visible = true;
|
||||||
|
state.txtCopyNotif.text = "Copied " + state.currentNoteSelection.length + " notes to clipboard";
|
||||||
|
state.txtCopyNotif.x = FlxG.mouse.x - (state.txtCopyNotif.width / 2);
|
||||||
|
state.txtCopyNotif.y = FlxG.mouse.y - 16;
|
||||||
|
FlxTween.tween(state.txtCopyNotif, {y: state.txtCopyNotif.y - 32}, 0.5,
|
||||||
|
{
|
||||||
|
type: FlxTween.ONESHOT,
|
||||||
|
ease: FlxEase.quadOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
state.txtCopyNotif.visible = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wiggle the notes.
|
||||||
|
for (note in state.renderedNotes.members)
|
||||||
|
{
|
||||||
|
if (state.isNoteSelected(note.noteData))
|
||||||
|
{
|
||||||
|
FlxTween.globalManager.cancelTweensOf(note);
|
||||||
|
FlxTween.globalManager.cancelTweensOf(note.scale);
|
||||||
|
note.playNoteAnimation();
|
||||||
|
var prevX:Float = note.scale.x;
|
||||||
|
var prevY:Float = note.scale.y;
|
||||||
|
|
||||||
|
note.scale.x *= 1.2;
|
||||||
|
note.scale.y *= 1.2;
|
||||||
|
|
||||||
|
note.angle = FlxG.random.bool() ? -10 : 10;
|
||||||
|
FlxTween.tween(note, {"angle": 0}, 0.8, {ease: FlxEase.elasticOut});
|
||||||
|
|
||||||
|
FlxTween.tween(note.scale, {"y": prevX, "x": prevY}, 0.7,
|
||||||
|
{
|
||||||
|
ease: FlxEase.elasticOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
note.playNoteAnimation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wiggle the events.
|
||||||
|
for (event in state.renderedEvents.members)
|
||||||
|
{
|
||||||
|
if (state.isEventSelected(event.eventData))
|
||||||
|
{
|
||||||
|
FlxTween.globalManager.cancelTweensOf(event);
|
||||||
|
FlxTween.globalManager.cancelTweensOf(event.scale);
|
||||||
|
event.playAnimation();
|
||||||
|
var prevX:Float = event.scale.x;
|
||||||
|
var prevY:Float = event.scale.y;
|
||||||
|
|
||||||
|
event.scale.x *= 1.2;
|
||||||
|
event.scale.y *= 1.2;
|
||||||
|
|
||||||
|
event.angle = FlxG.random.bool() ? -10 : 10;
|
||||||
|
FlxTween.tween(event, {"angle": 0}, 0.8, {ease: FlxEase.elasticOut});
|
||||||
|
|
||||||
|
FlxTween.tween(event.scale, {"y": prevX, "x": prevY}, 0.7,
|
||||||
|
{
|
||||||
|
ease: FlxEase.elasticOut,
|
||||||
|
onComplete: function(_) {
|
||||||
|
event.playAnimation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function undo(state:ChartEditorState):Void
|
||||||
|
{
|
||||||
|
// This command is not undoable. Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is not undoable. Don't add it to the history.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String
|
||||||
|
{
|
||||||
|
var len:Int = notes.length + events.length;
|
||||||
|
|
||||||
|
if (notes.length == 0) return 'Copy $len Events to Clipboard';
|
||||||
|
else if (events.length == 0) return 'Copy $len Notes to Clipboard';
|
||||||
|
else
|
||||||
|
return 'Copy $len Items to Clipboard';
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,12 @@ class CutItemsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Always add it to the history.
|
||||||
|
return (notes.length > 0 || events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = notes.length + events.length;
|
var len:Int = notes.length + events.length;
|
||||||
|
|
|
@ -10,17 +10,16 @@ import funkin.data.song.SongData.SongEventData;
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class DeselectAllItemsCommand implements ChartEditorCommand
|
class DeselectAllItemsCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
var previousNoteSelection:Array<SongNoteData>;
|
var previousNoteSelection:Array<SongNoteData> = [];
|
||||||
var previousEventSelection:Array<SongEventData>;
|
var previousEventSelection:Array<SongEventData> = [];
|
||||||
|
|
||||||
public function new(?previousNoteSelection:Array<SongNoteData>, ?previousEventSelection:Array<SongEventData>)
|
public function new() {}
|
||||||
{
|
|
||||||
this.previousNoteSelection = previousNoteSelection == null ? [] : previousNoteSelection;
|
|
||||||
this.previousEventSelection = previousEventSelection == null ? [] : previousEventSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
|
this.previousNoteSelection = state.currentNoteSelection;
|
||||||
|
this.previousEventSelection = state.currentEventSelection;
|
||||||
|
|
||||||
state.currentNoteSelection = [];
|
state.currentNoteSelection = [];
|
||||||
state.currentEventSelection = [];
|
state.currentEventSelection = [];
|
||||||
|
|
||||||
|
@ -35,6 +34,12 @@ class DeselectAllItemsCommand implements ChartEditorCommand
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (previousNoteSelection.length > 0 || previousEventSelection.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Deselect All Items';
|
return 'Deselect All Items';
|
||||||
|
|
|
@ -45,16 +45,27 @@ class DeselectItemsCommand implements ChartEditorCommand
|
||||||
state.notePreviewDirty = true;
|
state.notePreviewDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (notes.length > 0 || events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var noteCount = notes.length + events.length;
|
var isPlural = (notes.length + events.length) > 1;
|
||||||
|
var notesOnly = (notes.length > 0 && events.length == 0);
|
||||||
|
var eventsOnly = (notes.length == 0 && events.length > 0);
|
||||||
|
|
||||||
if (noteCount == 1)
|
if (notesOnly)
|
||||||
{
|
{
|
||||||
var dir:String = notes[0].getDirectionName();
|
return 'Deselect ${notes.length} ${isPlural ? 'Notes' : 'Note'}';
|
||||||
return 'Deselect $dir Items';
|
}
|
||||||
|
else if (eventsOnly)
|
||||||
|
{
|
||||||
|
return 'Deselect ${events.length} ${isPlural ? 'Events' : 'Event'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Deselect ${noteCount} Items';
|
return 'Deselect ${notes.length + events.length} Items';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,12 @@ class ExtendNoteLengthCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (oldLength != newLength);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Extend Note Length';
|
return 'Extend Note Length';
|
||||||
|
|
|
@ -51,6 +51,12 @@ class FlipNotesCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = notes.length;
|
var len:Int = notes.length;
|
||||||
|
|
|
@ -12,19 +12,19 @@ import funkin.data.song.SongDataUtils;
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class InvertSelectedItemsCommand implements ChartEditorCommand
|
class InvertSelectedItemsCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
var previousNoteSelection:Array<SongNoteData>;
|
var previousNoteSelection:Array<SongNoteData> = [];
|
||||||
var previousEventSelection:Array<SongEventData>;
|
var previousEventSelection:Array<SongEventData> = [];
|
||||||
|
|
||||||
public function new(?previousNoteSelection:Array<SongNoteData>, ?previousEventSelection:Array<SongEventData>)
|
public function new() {}
|
||||||
{
|
|
||||||
this.previousNoteSelection = previousNoteSelection == null ? [] : previousNoteSelection;
|
|
||||||
this.previousEventSelection = previousEventSelection == null ? [] : previousEventSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
|
this.previousNoteSelection = state.currentNoteSelection;
|
||||||
|
this.previousEventSelection = state.currentEventSelection;
|
||||||
|
|
||||||
state.currentNoteSelection = SongDataUtils.subtractNotes(state.currentSongChartNoteData, previousNoteSelection);
|
state.currentNoteSelection = SongDataUtils.subtractNotes(state.currentSongChartNoteData, previousNoteSelection);
|
||||||
state.currentEventSelection = SongDataUtils.subtractEvents(state.currentSongChartEventData, previousEventSelection);
|
state.currentEventSelection = SongDataUtils.subtractEvents(state.currentSongChartEventData, previousEventSelection);
|
||||||
|
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,12 @@ class InvertSelectedItemsCommand implements ChartEditorCommand
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (previousNoteSelection.length > 0 || previousEventSelection.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Invert Selected Items';
|
return 'Invert Selected Items';
|
||||||
|
|
|
@ -65,6 +65,12 @@ class MoveEventsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = events.length;
|
var len:Int = events.length;
|
||||||
|
|
|
@ -88,6 +88,12 @@ class MoveItemsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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 || events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = notes.length + events.length;
|
var len:Int = notes.length + events.length;
|
||||||
|
|
|
@ -67,6 +67,12 @@ class MoveNotesCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = notes.length;
|
var len:Int = notes.length;
|
||||||
|
|
|
@ -71,6 +71,12 @@ class PasteItemsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (addedNotes.length > 0 || addedEvents.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var currentClipboard:SongClipboardItems = SongDataUtils.readItemsFromClipboard();
|
var currentClipboard:SongClipboardItems = SongDataUtils.readItemsFromClipboard();
|
||||||
|
|
|
@ -48,6 +48,12 @@ class RemoveEventsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
state.sortChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
if (events.length == 1 && events[0] != null)
|
if (events.length == 1 && events[0] != null)
|
||||||
|
|
|
@ -62,6 +62,12 @@ class RemoveItemsCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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 || events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Remove ${notes.length + events.length} Items';
|
return 'Remove ${notes.length + events.length} Items';
|
||||||
|
|
|
@ -50,6 +50,12 @@ class RemoveNotesCommand implements ChartEditorCommand
|
||||||
state.sortChartData();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
if (notes.length == 1 && notes[0] != null)
|
if (notes.length == 1 && notes[0] != null)
|
||||||
|
|
|
@ -10,19 +10,25 @@ import funkin.data.song.SongData.SongEventData;
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class SelectAllItemsCommand implements ChartEditorCommand
|
class SelectAllItemsCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
var previousNoteSelection:Array<SongNoteData>;
|
var shouldSelectNotes:Bool;
|
||||||
var previousEventSelection:Array<SongEventData>;
|
var shouldSelectEvents:Bool;
|
||||||
|
|
||||||
public function new(?previousNoteSelection:Array<SongNoteData>, ?previousEventSelection:Array<SongEventData>)
|
var previousNoteSelection:Array<SongNoteData> = [];
|
||||||
|
var previousEventSelection:Array<SongEventData> = [];
|
||||||
|
|
||||||
|
public function new(shouldSelectNotes:Bool, shouldSelectEvents:Bool)
|
||||||
{
|
{
|
||||||
this.previousNoteSelection = previousNoteSelection == null ? [] : previousNoteSelection;
|
this.shouldSelectNotes = shouldSelectNotes;
|
||||||
this.previousEventSelection = previousEventSelection == null ? [] : previousEventSelection;
|
this.shouldSelectEvents = shouldSelectEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
state.currentNoteSelection = state.currentSongChartNoteData;
|
this.previousNoteSelection = state.currentNoteSelection;
|
||||||
state.currentEventSelection = state.currentSongChartEventData;
|
this.previousEventSelection = state.currentEventSelection;
|
||||||
|
|
||||||
|
state.currentNoteSelection = shouldSelectNotes ? state.currentSongChartNoteData : [];
|
||||||
|
state.currentEventSelection = shouldSelectEvents ? state.currentSongChartEventData : [];
|
||||||
|
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -35,8 +41,29 @@ class SelectAllItemsCommand implements ChartEditorCommand
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (state.currentNoteSelection.length > 0 || state.currentEventSelection.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Select All Items';
|
if (shouldSelectNotes && !shouldSelectEvents)
|
||||||
|
{
|
||||||
|
return 'Select All Notes';
|
||||||
|
}
|
||||||
|
else if (shouldSelectEvents && !shouldSelectNotes)
|
||||||
|
{
|
||||||
|
return 'Select All Events';
|
||||||
|
}
|
||||||
|
else if (shouldSelectNotes && shouldSelectEvents)
|
||||||
|
{
|
||||||
|
return 'Select All Notes and Events';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 'Select Nothing (Huh?)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ class SelectItemsCommand implements ChartEditorCommand
|
||||||
var notes:Array<SongNoteData>;
|
var notes:Array<SongNoteData>;
|
||||||
var events:Array<SongEventData>;
|
var events:Array<SongEventData>;
|
||||||
|
|
||||||
public function new(notes:Array<SongNoteData>, events:Array<SongEventData>)
|
public function new(?notes:Array<SongNoteData>, ?events:Array<SongEventData>)
|
||||||
{
|
{
|
||||||
this.notes = notes;
|
this.notes = notes ?? [];
|
||||||
this.events = events;
|
this.events = events ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
|
@ -72,6 +72,12 @@ class SelectItemsCommand implements ChartEditorCommand
|
||||||
state.notePreviewDirty = true;
|
state.notePreviewDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// This command is undoable. Add to the history if we actually performed an action.
|
||||||
|
return (notes.length > 0 || events.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
var len:Int = notes.length + events.length;
|
var len:Int = notes.length + events.length;
|
||||||
|
|
|
@ -13,20 +13,20 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
var notes:Array<SongNoteData>;
|
var notes:Array<SongNoteData>;
|
||||||
var events:Array<SongEventData>;
|
var events:Array<SongEventData>;
|
||||||
var previousNoteSelection:Array<SongNoteData>;
|
var previousNoteSelection:Array<SongNoteData> = [];
|
||||||
var previousEventSelection:Array<SongEventData>;
|
var previousEventSelection:Array<SongEventData> = [];
|
||||||
|
|
||||||
public function new(notes:Array<SongNoteData>, events:Array<SongEventData>, previousNoteSelection:Array<SongNoteData>,
|
public function new(notes:Array<SongNoteData>, events:Array<SongEventData>)
|
||||||
previousEventSelection:Array<SongEventData>)
|
|
||||||
{
|
{
|
||||||
this.notes = notes;
|
this.notes = notes;
|
||||||
this.events = events;
|
this.events = events;
|
||||||
this.previousNoteSelection = previousNoteSelection == null ? [] : previousNoteSelection;
|
|
||||||
this.previousEventSelection = previousEventSelection == null ? [] : previousEventSelection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(state:ChartEditorState):Void
|
public function execute(state:ChartEditorState):Void
|
||||||
{
|
{
|
||||||
|
this.previousNoteSelection = state.currentNoteSelection;
|
||||||
|
this.previousEventSelection = state.currentEventSelection;
|
||||||
|
|
||||||
state.currentNoteSelection = notes;
|
state.currentNoteSelection = notes;
|
||||||
state.currentEventSelection = events;
|
state.currentEventSelection = events;
|
||||||
|
|
||||||
|
@ -67,8 +67,14 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
state.noteDisplayDirty = true;
|
state.noteDisplayDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// Add to the history if we actually performed an action.
|
||||||
|
return (state.currentNoteSelection != previousNoteSelection && state.currentEventSelection != previousEventSelection);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Select ${notes.length} Items';
|
return 'Select ${notes.length + events.length} Items';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,12 @@ class SwitchDifficultyCommand implements ChartEditorCommand
|
||||||
state.notePreviewDirty = true;
|
state.notePreviewDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToHistory(state:ChartEditorState):Bool
|
||||||
|
{
|
||||||
|
// Add to the history if we actually performed an action.
|
||||||
|
return (prevVariation != newVariation || prevDifficulty != newDifficulty);
|
||||||
|
}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'Switch Difficulty';
|
return 'Switch Difficulty';
|
||||||
|
|
|
@ -119,8 +119,10 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
return DEFAULT_EVENT;
|
return DEFAULT_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function playAnimation(name:String):Void
|
public function playAnimation(?name:String):Void
|
||||||
{
|
{
|
||||||
|
if (name == null) name = eventData?.event ?? DEFAULT_EVENT;
|
||||||
|
|
||||||
var correctedName = correctAnimationName(name);
|
var correctedName = correctAnimationName(name);
|
||||||
this.animation.play(correctedName);
|
this.animation.play(correctedName);
|
||||||
refresh();
|
refresh();
|
||||||
|
|
|
@ -70,9 +70,9 @@ class ChartEditorNotePreview extends FlxSprite
|
||||||
* @param event The data for the event.
|
* @param event The data for the event.
|
||||||
* @param songLengthInMs The total length of the song in milliseconds.
|
* @param songLengthInMs The total length of the song in milliseconds.
|
||||||
*/
|
*/
|
||||||
public function addEvent(event:SongEventData, songLengthInMs:Int):Void
|
public function addEvent(event:SongEventData, songLengthInMs:Int, ?isSelection:Bool = false):Void
|
||||||
{
|
{
|
||||||
drawNote(-1, false, Std.int(event.time), songLengthInMs);
|
drawNote(-1, false, Std.int(event.time), songLengthInMs, isSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,6 +114,19 @@ class ChartEditorNotePreview extends FlxSprite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an array of selected events to the preview.
|
||||||
|
* @param events The data for the events.
|
||||||
|
* @param songLengthInMs The total length of the song in milliseconds.
|
||||||
|
*/
|
||||||
|
public function addSelectedEvents(events:Array<SongEventData>, songLengthInMs:Int):Void
|
||||||
|
{
|
||||||
|
for (event in events)
|
||||||
|
{
|
||||||
|
addEvent(event, songLengthInMs, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a note on the preview.
|
* Draws a note on the preview.
|
||||||
* @param dir Note data.
|
* @param dir Note data.
|
||||||
|
|
|
@ -188,17 +188,19 @@ class ChartEditorAudioHandler
|
||||||
state.audioVisGroup.playerVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195;
|
state.audioVisGroup.playerVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195;
|
||||||
state.audioVisGroup.playerVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
state.audioVisGroup.playerVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
||||||
state.audioVisGroup.playerVis.detail = 1;
|
state.audioVisGroup.playerVis.detail = 1;
|
||||||
|
state.audioVisGroup.playerVis.y = Math.max(state.gridTiledSprite?.y ?? 0.0, ChartEditorState.GRID_INITIAL_Y_POS);
|
||||||
|
|
||||||
state.audioVocalTrackGroup.playerVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
state.audioVocalTrackGroup.playerVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||||
return true;
|
return true;
|
||||||
case DAD:
|
case DAD:
|
||||||
state.audioVocalTrackGroup.addOpponentVoice(vocalTrack);
|
state.audioVocalTrackGroup.addOpponentVoice(vocalTrack);
|
||||||
state.audioVisGroup.addOpponentVis(vocalTrack);
|
state.audioVisGroup.addOpponentVis(vocalTrack);
|
||||||
state.audioVisGroup.opponentVis.x = 405;
|
state.audioVisGroup.opponentVis.x = 435;
|
||||||
|
|
||||||
state.audioVisGroup.opponentVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195;
|
state.audioVisGroup.opponentVis.realtimeVisLenght = Conductor.instance.getStepTimeInMs(16) * 0.00195;
|
||||||
state.audioVisGroup.opponentVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
state.audioVisGroup.opponentVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
||||||
state.audioVisGroup.opponentVis.detail = 1;
|
state.audioVisGroup.opponentVis.detail = 1;
|
||||||
|
state.audioVisGroup.opponentVis.y = Math.max(state.gridTiledSprite?.y ?? 0.0, ChartEditorState.GRID_INITIAL_Y_POS);
|
||||||
|
|
||||||
state.audioVocalTrackGroup.opponentVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
state.audioVocalTrackGroup.opponentVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ package funkin.ui.debug.charting.handlers;
|
||||||
|
|
||||||
import funkin.util.PlatformUtil;
|
import funkin.util.PlatformUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles modifying the shortcut text of menu items based on the current platform.
|
||||||
|
* On MacOS, `Ctrl`, `Alt`, and `Shift` are replaced with `⌘` (or `^`), `⌥`, and `⇧`, respectively.
|
||||||
|
*/
|
||||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||||
class ChartEditorShortcutHandler
|
class ChartEditorShortcutHandler
|
||||||
{
|
{
|
||||||
|
@ -18,7 +22,8 @@ class ChartEditorShortcutHandler
|
||||||
state.menubarItemCopy.shortcutText = ctrlOrCmd('C');
|
state.menubarItemCopy.shortcutText = ctrlOrCmd('C');
|
||||||
state.menubarItemPaste.shortcutText = ctrlOrCmd('V');
|
state.menubarItemPaste.shortcutText = ctrlOrCmd('V');
|
||||||
|
|
||||||
state.menubarItemSelectAll.shortcutText = ctrlOrCmd('A');
|
state.menubarItemSelectAllNotes.shortcutText = ctrlOrCmd('A');
|
||||||
|
state.menubarItemSelectAllEvents.shortcutText = ctrlOrCmd(alt('A'));
|
||||||
state.menubarItemSelectInverse.shortcutText = ctrlOrCmd('I');
|
state.menubarItemSelectInverse.shortcutText = ctrlOrCmd('I');
|
||||||
state.menubarItemSelectNone.shortcutText = ctrlOrCmd('D');
|
state.menubarItemSelectNone.shortcutText = ctrlOrCmd('D');
|
||||||
state.menubarItemSelectBeforeCursor.shortcutText = shift('Home');
|
state.menubarItemSelectBeforeCursor.shortcutText = shift('Home');
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package funkin.ui.freeplay;
|
package funkin.ui.freeplay;
|
||||||
|
|
||||||
import funkin.input.Controls;
|
|
||||||
import flash.text.TextField;
|
import flash.text.TextField;
|
||||||
import flixel.addons.display.FlxGridOverlay;
|
import flixel.addons.display.FlxGridOverlay;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
|
@ -23,33 +22,35 @@ import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSpriteUtil;
|
import flixel.util.FlxSpriteUtil;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.input.Controls.Control;
|
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.level.LevelRegistry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
import funkin.graphics.shaders.AngleMask;
|
import funkin.graphics.shaders.AngleMask;
|
||||||
import funkin.graphics.shaders.HSVShader;
|
import funkin.graphics.shaders.HSVShader;
|
||||||
import funkin.graphics.shaders.PureColor;
|
import funkin.graphics.shaders.PureColor;
|
||||||
import funkin.util.MathUtil;
|
|
||||||
import funkin.graphics.shaders.StrokeShader;
|
import funkin.graphics.shaders.StrokeShader;
|
||||||
|
import funkin.input.Controls;
|
||||||
|
import funkin.input.Controls.Control;
|
||||||
import funkin.play.components.HealthIcon;
|
import funkin.play.components.HealthIcon;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.play.PlayStatePlaylist;
|
import funkin.play.PlayStatePlaylist;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
import funkin.save.Save.SaveScoreData;
|
import funkin.save.Save.SaveScoreData;
|
||||||
|
import funkin.ui.AtlasText;
|
||||||
import funkin.ui.freeplay.BGScrollingText;
|
import funkin.ui.freeplay.BGScrollingText;
|
||||||
import funkin.ui.freeplay.DifficultyStars;
|
import funkin.ui.freeplay.DifficultyStars;
|
||||||
import funkin.ui.freeplay.DJBoyfriend;
|
import funkin.ui.freeplay.DJBoyfriend;
|
||||||
import funkin.ui.freeplay.FreeplayScore;
|
import funkin.ui.freeplay.FreeplayScore;
|
||||||
import funkin.ui.freeplay.LetterSort;
|
import funkin.ui.freeplay.LetterSort;
|
||||||
import funkin.ui.freeplay.SongMenuItem;
|
import funkin.ui.freeplay.SongMenuItem;
|
||||||
|
import funkin.ui.mainmenu.MainMenuState;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import funkin.ui.mainmenu.MainMenuState;
|
|
||||||
import funkin.ui.transition.LoadingState;
|
import funkin.ui.transition.LoadingState;
|
||||||
import funkin.ui.transition.StickerSubState;
|
import funkin.ui.transition.StickerSubState;
|
||||||
import funkin.util.MathUtil;
|
import funkin.util.MathUtil;
|
||||||
|
import funkin.util.MathUtil;
|
||||||
import lime.app.Future;
|
import lime.app.Future;
|
||||||
import lime.utils.Assets;
|
import lime.utils.Assets;
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
var currentDifficulty:String = Constants.DEFAULT_DIFFICULTY;
|
var currentDifficulty:String = Constants.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
var fp:FreeplayScore;
|
var fp:FreeplayScore;
|
||||||
var txtCompletion:FlxText;
|
var txtCompletion:AtlasText;
|
||||||
var lerpCompletion:Float = 0;
|
var lerpCompletion:Float = 0;
|
||||||
var intendedCompletion:Float = 0;
|
var intendedCompletion:Float = 0;
|
||||||
var lerpScore:Float = 0;
|
var lerpScore:Float = 0;
|
||||||
|
@ -87,6 +88,8 @@ class FreeplayState extends MusicBeatSubState
|
||||||
var grpCapsules:FlxTypedGroup<SongMenuItem>;
|
var grpCapsules:FlxTypedGroup<SongMenuItem>;
|
||||||
var curCapsule:SongMenuItem;
|
var curCapsule:SongMenuItem;
|
||||||
var curPlaying:Bool = false;
|
var curPlaying:Bool = false;
|
||||||
|
var ostName:FlxText;
|
||||||
|
var difficultyStars:DifficultyStars;
|
||||||
|
|
||||||
var dj:DJBoyfriend;
|
var dj:DJBoyfriend;
|
||||||
|
|
||||||
|
@ -150,15 +153,10 @@ class FreeplayState extends MusicBeatSubState
|
||||||
for (songId in LevelRegistry.instance.parseEntryData(levelId).songs)
|
for (songId in LevelRegistry.instance.parseEntryData(levelId).songs)
|
||||||
{
|
{
|
||||||
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
||||||
var songBaseDifficulty:SongDifficulty = song.getDifficulty(Constants.DEFAULT_DIFFICULTY);
|
|
||||||
|
|
||||||
var songName = songBaseDifficulty.songName;
|
songs.push(new FreeplaySongData(levelId, songId, song));
|
||||||
var songOpponent = songBaseDifficulty.characters.opponent;
|
|
||||||
var songDifficulties = song.listDifficulties();
|
|
||||||
|
|
||||||
songs.push(new FreeplaySongData(songId, songName, levelId, songOpponent, songDifficulties));
|
for (difficulty in song.listDifficulties())
|
||||||
|
|
||||||
for (difficulty in songDifficulties)
|
|
||||||
{
|
{
|
||||||
diffIdsTotal.pushUnique(difficulty);
|
diffIdsTotal.pushUnique(difficulty);
|
||||||
}
|
}
|
||||||
|
@ -334,6 +332,8 @@ class FreeplayState extends MusicBeatSubState
|
||||||
if (diffSprite.difficultyId == currentDifficulty) diffSprite.visible = true;
|
if (diffSprite.difficultyId == currentDifficulty) diffSprite.visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This is an AtlasSprite because we use an animation to bring it into view.
|
||||||
|
// TODO: Add the ability to select the album graphic.
|
||||||
var albumArt:FlxAtlasSprite = new FlxAtlasSprite(640, 360, Paths.animateAtlas("freeplay/albumRoll"));
|
var albumArt:FlxAtlasSprite = new FlxAtlasSprite(640, 360, Paths.animateAtlas("freeplay/albumRoll"));
|
||||||
albumArt.visible = false;
|
albumArt.visible = false;
|
||||||
add(albumArt);
|
add(albumArt);
|
||||||
|
@ -347,7 +347,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
|
|
||||||
var albumTitle:FlxSprite = new FlxSprite(947, 491).loadGraphic(Paths.image('freeplay/albumTitle-fnfvol1'));
|
var albumTitle:FlxSprite = new FlxSprite(947, 491).loadGraphic(Paths.image('freeplay/albumTitle-fnfvol1'));
|
||||||
var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite'));
|
var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite'));
|
||||||
var difficultyStars:DifficultyStars = new DifficultyStars(140, 39);
|
difficultyStars = new DifficultyStars(140, 39);
|
||||||
|
|
||||||
difficultyStars.stars.visible = false;
|
difficultyStars.stars.visible = false;
|
||||||
albumTitle.visible = false;
|
albumTitle.visible = false;
|
||||||
|
@ -382,11 +382,16 @@ class FreeplayState extends MusicBeatSubState
|
||||||
add(overhangStuff);
|
add(overhangStuff);
|
||||||
FlxTween.tween(overhangStuff, {y: 0}, 0.3, {ease: FlxEase.quartOut});
|
FlxTween.tween(overhangStuff, {y: 0}, 0.3, {ease: FlxEase.quartOut});
|
||||||
|
|
||||||
var fnfFreeplay:FlxText = new FlxText(0, 12, 0, "FREEPLAY", 48);
|
var fnfFreeplay:FlxText = new FlxText(8, 8, 0, "FREEPLAY", 48);
|
||||||
fnfFreeplay.font = "VCR OSD Mono";
|
fnfFreeplay.font = "VCR OSD Mono";
|
||||||
fnfFreeplay.visible = false;
|
fnfFreeplay.visible = false;
|
||||||
|
|
||||||
exitMovers.set([overhangStuff, fnfFreeplay],
|
ostName = new FlxText(8, 8, FlxG.width - 8 - 8, "OFFICIAL OST", 48);
|
||||||
|
ostName.font = "VCR OSD Mono";
|
||||||
|
ostName.alignment = RIGHT;
|
||||||
|
ostName.visible = false;
|
||||||
|
|
||||||
|
exitMovers.set([overhangStuff, fnfFreeplay, ostName],
|
||||||
{
|
{
|
||||||
y: -overhangStuff.height,
|
y: -overhangStuff.height,
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -397,8 +402,9 @@ class FreeplayState extends MusicBeatSubState
|
||||||
var sillyStroke = new StrokeShader(0xFFFFFFFF, 2, 2);
|
var sillyStroke = new StrokeShader(0xFFFFFFFF, 2, 2);
|
||||||
fnfFreeplay.shader = sillyStroke;
|
fnfFreeplay.shader = sillyStroke;
|
||||||
add(fnfFreeplay);
|
add(fnfFreeplay);
|
||||||
|
add(ostName);
|
||||||
|
|
||||||
var fnfHighscoreSpr:FlxSprite = new FlxSprite(890, 70);
|
var fnfHighscoreSpr:FlxSprite = new FlxSprite(860, 70);
|
||||||
fnfHighscoreSpr.frames = Paths.getSparrowAtlas('freeplay/highscore');
|
fnfHighscoreSpr.frames = Paths.getSparrowAtlas('freeplay/highscore');
|
||||||
fnfHighscoreSpr.animation.addByPrefix("highscore", "highscore", 24, false);
|
fnfHighscoreSpr.animation.addByPrefix("highscore", "highscore", 24, false);
|
||||||
fnfHighscoreSpr.visible = false;
|
fnfHighscoreSpr.visible = false;
|
||||||
|
@ -415,8 +421,10 @@ class FreeplayState extends MusicBeatSubState
|
||||||
fp.visible = false;
|
fp.visible = false;
|
||||||
add(fp);
|
add(fp);
|
||||||
|
|
||||||
txtCompletion = new FlxText(1200, 77, 0, "0", 32);
|
var clearBoxSprite:FlxSprite = new FlxSprite(1165, 65).loadGraphic(Paths.image('freeplay/clearBox'));
|
||||||
txtCompletion.font = "VCR OSD Mono";
|
add(clearBoxSprite);
|
||||||
|
|
||||||
|
txtCompletion = new AtlasText(1185, 87, "69", AtlasFont.FREEPLAY_CLEAR);
|
||||||
txtCompletion.visible = false;
|
txtCompletion.visible = false;
|
||||||
add(txtCompletion);
|
add(txtCompletion);
|
||||||
|
|
||||||
|
@ -485,6 +493,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
new FlxTimer().start(1 / 24, function(handShit) {
|
new FlxTimer().start(1 / 24, function(handShit) {
|
||||||
fnfHighscoreSpr.visible = true;
|
fnfHighscoreSpr.visible = true;
|
||||||
fnfFreeplay.visible = true;
|
fnfFreeplay.visible = true;
|
||||||
|
ostName.visible = true;
|
||||||
fp.visible = true;
|
fp.visible = true;
|
||||||
fp.updateScore(0);
|
fp.updateScore(0);
|
||||||
|
|
||||||
|
@ -674,9 +683,32 @@ class FreeplayState extends MusicBeatSubState
|
||||||
lerpScore = MathUtil.coolLerp(lerpScore, intendedScore, 0.2);
|
lerpScore = MathUtil.coolLerp(lerpScore, intendedScore, 0.2);
|
||||||
lerpCompletion = MathUtil.coolLerp(lerpCompletion, intendedCompletion, 0.9);
|
lerpCompletion = MathUtil.coolLerp(lerpCompletion, intendedCompletion, 0.9);
|
||||||
|
|
||||||
|
if (Math.isNaN(lerpScore))
|
||||||
|
{
|
||||||
|
lerpScore = intendedScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.isNaN(lerpCompletion))
|
||||||
|
{
|
||||||
|
lerpCompletion = intendedCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
fp.updateScore(Std.int(lerpScore));
|
fp.updateScore(Std.int(lerpScore));
|
||||||
|
|
||||||
txtCompletion.text = Math.floor(lerpCompletion * 100) + "%";
|
txtCompletion.text = '${Math.floor(lerpCompletion * 100)}';
|
||||||
|
|
||||||
|
// Right align the completion percentage
|
||||||
|
switch (txtCompletion.text.length)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
txtCompletion.x = 1185 - 10;
|
||||||
|
case 2:
|
||||||
|
txtCompletion.x = 1185;
|
||||||
|
case 1:
|
||||||
|
txtCompletion.x = 1185 + 24;
|
||||||
|
default:
|
||||||
|
txtCompletion.x = 1185;
|
||||||
|
}
|
||||||
|
|
||||||
handleInputs(elapsed);
|
handleInputs(elapsed);
|
||||||
}
|
}
|
||||||
|
@ -913,6 +945,11 @@ class FreeplayState extends MusicBeatSubState
|
||||||
intendedCompletion = 0.0;
|
intendedCompletion = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intendedCompletion == Math.POSITIVE_INFINITY || intendedCompletion == Math.NEGATIVE_INFINITY || Math.isNaN(intendedCompletion))
|
||||||
|
{
|
||||||
|
intendedCompletion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
grpDifficulties.group.forEach(function(diffSprite) {
|
grpDifficulties.group.forEach(function(diffSprite) {
|
||||||
diffSprite.visible = false;
|
diffSprite.visible = false;
|
||||||
});
|
});
|
||||||
|
@ -938,6 +975,27 @@ class FreeplayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (change != 0)
|
||||||
|
{
|
||||||
|
// Update the song capsules to reflect the new difficulty info.
|
||||||
|
for (songCapsule in grpCapsules.members)
|
||||||
|
{
|
||||||
|
if (songCapsule == null) continue;
|
||||||
|
if (songCapsule.songData != null)
|
||||||
|
{
|
||||||
|
songCapsule.songData.currentDifficulty = currentDifficulty;
|
||||||
|
songCapsule.init(null, null, songCapsule.songData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
songCapsule.init(null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the difficulty star count on the right.
|
||||||
|
difficultyStars.difficulty = daSong.songRating;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String)
|
// Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String)
|
||||||
|
@ -1046,6 +1104,10 @@ class FreeplayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
currentDifficulty = rememberedDifficulty;
|
currentDifficulty = rememberedDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the difficulty star count on the right.
|
||||||
|
var daSong = songs[curSelected];
|
||||||
|
difficultyStars.difficulty = daSong?.songRating ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeSelection(change:Int = 0)
|
function changeSelection(change:Int = 0)
|
||||||
|
@ -1176,19 +1238,47 @@ class FreeplaySongData
|
||||||
{
|
{
|
||||||
public var isFav:Bool = false;
|
public var isFav:Bool = false;
|
||||||
|
|
||||||
public var songId:String = "";
|
var song:Song;
|
||||||
public var songName:String = "";
|
|
||||||
public var levelId:String = "";
|
|
||||||
public var songCharacter:String = "";
|
|
||||||
public var songDifficulties:Array<String> = [];
|
|
||||||
|
|
||||||
public function new(songId:String, songName:String, levelId:String, songCharacter:String, songDifficulties:Array<String>)
|
public var levelId(default, null):String = "";
|
||||||
|
public var songId(default, null):String = "";
|
||||||
|
|
||||||
|
public var songDifficulties(default, null):Array<String> = [];
|
||||||
|
|
||||||
|
public var songName(default, null):String = "";
|
||||||
|
public var songCharacter(default, null):String = "";
|
||||||
|
public var songRating(default, null):Int = 0;
|
||||||
|
|
||||||
|
public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
|
function set_currentDifficulty(value:String):String
|
||||||
|
{
|
||||||
|
if (currentDifficulty == value) return value;
|
||||||
|
|
||||||
|
currentDifficulty = value;
|
||||||
|
updateValues();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new(levelId:String, songId:String, song:Song)
|
||||||
{
|
{
|
||||||
this.songId = songId;
|
|
||||||
this.songName = songName;
|
|
||||||
this.levelId = levelId;
|
this.levelId = levelId;
|
||||||
this.songCharacter = songCharacter;
|
this.songId = songId;
|
||||||
this.songDifficulties = songDifficulties;
|
this.song = song;
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateValues():Void
|
||||||
|
{
|
||||||
|
this.songDifficulties = song.listDifficulties();
|
||||||
|
if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
|
var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty);
|
||||||
|
if (songDifficulty == null) return;
|
||||||
|
this.songName = songDifficulty.songName;
|
||||||
|
this.songCharacter = songDifficulty.characters.opponent;
|
||||||
|
this.songRating = songDifficulty.difficultyRating;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,6 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
|
|
||||||
var ranks:Array<String> = ["fail", "average", "great", "excellent", "perfect"];
|
var ranks:Array<String> = ["fail", "average", "great", "excellent", "perfect"];
|
||||||
|
|
||||||
// lol...
|
|
||||||
var diffRanks:Array<String> = [
|
|
||||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "14", "15"
|
|
||||||
];
|
|
||||||
|
|
||||||
public var targetPos:FlxPoint = new FlxPoint();
|
public var targetPos:FlxPoint = new FlxPoint();
|
||||||
public var doLerp:Bool = false;
|
public var doLerp:Bool = false;
|
||||||
public var doJumpIn:Bool = false;
|
public var doJumpIn:Bool = false;
|
||||||
|
@ -47,10 +42,12 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
public var doJumpOut:Bool = false;
|
public var doJumpOut:Bool = false;
|
||||||
|
|
||||||
public var onConfirm:Void->Void;
|
public var onConfirm:Void->Void;
|
||||||
public var diffGrayscale:Grayscale;
|
public var grayscaleShader:Grayscale;
|
||||||
|
|
||||||
public var hsvShader(default, set):HSVShader;
|
public var hsvShader(default, set):HSVShader;
|
||||||
|
|
||||||
|
var diffRatingSprite:FlxSprite;
|
||||||
|
|
||||||
public function new(x:Float, y:Float)
|
public function new(x:Float, y:Float)
|
||||||
{
|
{
|
||||||
super(x, y);
|
super(x, y);
|
||||||
|
@ -75,26 +72,30 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
add(ranking);
|
add(ranking);
|
||||||
grpHide.add(ranking);
|
grpHide.add(ranking);
|
||||||
|
|
||||||
diffGrayscale = new Grayscale(1);
|
|
||||||
|
|
||||||
var diffRank = new FlxSprite(145, 90).loadGraphic(Paths.image("freeplay/diffRankings/diff" + FlxG.random.getObject(diffRanks)));
|
|
||||||
diffRank.shader = diffGrayscale;
|
|
||||||
diffRank.visible = false;
|
|
||||||
add(diffRank);
|
|
||||||
diffRank.origin.set(capsule.origin.x - diffRank.x, capsule.origin.y - diffRank.y);
|
|
||||||
grpHide.add(diffRank);
|
|
||||||
|
|
||||||
switch (rank)
|
switch (rank)
|
||||||
{
|
{
|
||||||
case "perfect":
|
case "perfect":
|
||||||
ranking.x -= 10;
|
ranking.x -= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grayscaleShader = new Grayscale(1);
|
||||||
|
|
||||||
|
diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image("freeplay/diffRatings/diff00"));
|
||||||
|
diffRatingSprite.shader = grayscaleShader;
|
||||||
|
diffRatingSprite.visible = false;
|
||||||
|
add(diffRatingSprite);
|
||||||
|
diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y);
|
||||||
|
grpHide.add(diffRatingSprite);
|
||||||
|
|
||||||
songText = new CapsuleText(capsule.width * 0.26, 45, 'Random', Std.int(40 * realScaled));
|
songText = new CapsuleText(capsule.width * 0.26, 45, 'Random', Std.int(40 * realScaled));
|
||||||
add(songText);
|
add(songText);
|
||||||
grpHide.add(songText);
|
grpHide.add(songText);
|
||||||
|
|
||||||
pixelIcon = new FlxSprite(155, 15);
|
// TODO: Use value from metadata instead of random.
|
||||||
|
updateDifficultyRating(FlxG.random.int(0, 15));
|
||||||
|
|
||||||
|
pixelIcon = new FlxSprite(160, 35);
|
||||||
|
|
||||||
pixelIcon.makeGraphic(32, 32, 0x00000000);
|
pixelIcon.makeGraphic(32, 32, 0x00000000);
|
||||||
pixelIcon.antialiasing = false;
|
pixelIcon.antialiasing = false;
|
||||||
pixelIcon.active = false;
|
pixelIcon.active = false;
|
||||||
|
@ -113,6 +114,12 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
setVisibleGrp(false);
|
setVisibleGrp(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDifficultyRating(newRating:Int)
|
||||||
|
{
|
||||||
|
var ratingPadded:String = newRating < 10 ? '0$newRating' : '$newRating';
|
||||||
|
diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}'));
|
||||||
|
}
|
||||||
|
|
||||||
function set_hsvShader(value:HSVShader):HSVShader
|
function set_hsvShader(value:HSVShader):HSVShader
|
||||||
{
|
{
|
||||||
this.hsvShader = value;
|
this.hsvShader = value;
|
||||||
|
@ -149,16 +156,17 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
updateSelected();
|
updateSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init(x:Float, y:Float, songData:Null<FreeplaySongData>)
|
public function init(?x:Float, ?y:Float, songData:Null<FreeplaySongData>)
|
||||||
{
|
{
|
||||||
this.x = x;
|
if (x != null) this.x = x;
|
||||||
this.y = y;
|
if (y != null) this.y = y;
|
||||||
this.songData = songData;
|
this.songData = songData;
|
||||||
|
|
||||||
// Update capsule text.
|
// Update capsule text.
|
||||||
songText.text = songData?.songName ?? 'Random';
|
songText.text = songData?.songName ?? 'Random';
|
||||||
// Update capsule character.
|
// Update capsule character.
|
||||||
if (songData?.songCharacter != null) setCharacter(songData.songCharacter);
|
if (songData?.songCharacter != null) setCharacter(songData.songCharacter);
|
||||||
|
updateDifficultyRating(songData?.songRating ?? 0);
|
||||||
// Update opacity, offsets, etc.
|
// Update opacity, offsets, etc.
|
||||||
updateSelected();
|
updateSelected();
|
||||||
}
|
}
|
||||||
|
@ -200,7 +208,14 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
|
|
||||||
pixelIcon.loadGraphic(Paths.image(charPath));
|
pixelIcon.loadGraphic(Paths.image(charPath));
|
||||||
pixelIcon.scale.x = pixelIcon.scale.y = 2;
|
pixelIcon.scale.x = pixelIcon.scale.y = 2;
|
||||||
pixelIcon.origin.x = 100;
|
|
||||||
|
switch (char)
|
||||||
|
{
|
||||||
|
case "parents-christmas":
|
||||||
|
pixelIcon.origin.x = 140;
|
||||||
|
default:
|
||||||
|
pixelIcon.origin.x = 100;
|
||||||
|
}
|
||||||
// pixelIcon.origin.x = capsule.origin.x;
|
// pixelIcon.origin.x = capsule.origin.x;
|
||||||
// pixelIcon.offset.x -= pixelIcon.origin.x;
|
// pixelIcon.offset.x -= pixelIcon.origin.x;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +351,7 @@ class SongMenuItem extends FlxSpriteGroup
|
||||||
|
|
||||||
function updateSelected():Void
|
function updateSelected():Void
|
||||||
{
|
{
|
||||||
diffGrayscale.setAmount(this.selected ? 0 : 0.8);
|
grayscaleShader.setAmount(this.selected ? 0 : 0.8);
|
||||||
songText.alpha = this.selected ? 1 : 0.6;
|
songText.alpha = this.selected ? 1 : 0.6;
|
||||||
songText.blurredText.visible = this.selected ? true : false;
|
songText.blurredText.visible = this.selected ? true : false;
|
||||||
capsule.offset.x = this.selected ? 0 : -5;
|
capsule.offset.x = this.selected ? 0 : -5;
|
||||||
|
|
Loading…
Reference in a new issue