mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-12-04 12:43:16 +00:00
Merge branch 'rewrite/master' of https://github.com/FunkinCrew/funkin-secret into input-offsets
This commit is contained in:
commit
6e691c66c3
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 1f00d24134231433180affecc67a617d54169ffa
|
||||
Subproject commit 75ac8ec2564c9a56e8282b0853091ecd8b4f2dfd
|
|
@ -50,11 +50,13 @@ class InitState extends FlxState
|
|||
*/
|
||||
public override function create():Void
|
||||
{
|
||||
// Setup a bunch of important Flixel stuff.
|
||||
setupShit();
|
||||
|
||||
// loadSaveData(); // Moved to Main.hx
|
||||
// Load player options from save data.
|
||||
// Flixel has already loaded the save data, so we can just use it.
|
||||
Preferences.init();
|
||||
|
||||
// Load controls from save data.
|
||||
PlayerSettings.init();
|
||||
|
||||
|
@ -198,8 +200,13 @@ class InitState extends FlxState
|
|||
//
|
||||
// FLIXEL PLUGINS
|
||||
//
|
||||
// Plugins provide a useful interface for globally active Flixel objects,
|
||||
// that receive update events regardless of the current state.
|
||||
// TODO: Move Module behavior to a Flixel plugin.
|
||||
funkin.util.plugins.EvacuateDebugPlugin.initialize();
|
||||
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
|
||||
funkin.util.plugins.ScreenshotPlugin.initialize();
|
||||
funkin.util.plugins.VolumePlugin.initialize();
|
||||
funkin.util.plugins.WatchPlugin.initialize();
|
||||
|
||||
//
|
||||
|
@ -302,15 +309,11 @@ class InitState extends FlxState
|
|||
return;
|
||||
}
|
||||
|
||||
// Load and cache the song's charts.
|
||||
// TODO: Do this in the loading state.
|
||||
songData.cacheCharts(true);
|
||||
|
||||
LoadingState.loadAndSwitchState(() -> new funkin.play.PlayState(
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: songData,
|
||||
targetDifficulty: difficultyId,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,11 +339,11 @@ class InitState extends FlxState
|
|||
|
||||
var targetSong:funkin.play.song.Song = SongRegistry.instance.fetchEntry(targetSongId);
|
||||
|
||||
LoadingState.loadAndSwitchState(() -> new funkin.play.PlayState(
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: difficultyId,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function defineSong():String
|
||||
|
|
|
@ -20,7 +20,10 @@ class Preferences
|
|||
|
||||
static function set_naughtyness(value:Bool):Bool
|
||||
{
|
||||
return Save.get().options.naughtyness = value;
|
||||
var save = Save.get();
|
||||
save.options.naughtyness = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +39,10 @@ class Preferences
|
|||
|
||||
static function set_downscroll(value:Bool):Bool
|
||||
{
|
||||
return Save.get().options.downscroll = value;
|
||||
var save = Save.get();
|
||||
save.options.downscroll = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +58,10 @@ class Preferences
|
|||
|
||||
static function set_flashingLights(value:Bool):Bool
|
||||
{
|
||||
return Save.get().options.flashingLights = value;
|
||||
var save = Save.get();
|
||||
save.options.flashingLights = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +77,10 @@ class Preferences
|
|||
|
||||
static function set_zoomCamera(value:Bool):Bool
|
||||
{
|
||||
return Save.get().options.zoomCamera = value;
|
||||
var save = Save.get();
|
||||
save.options.zoomCamera = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +101,10 @@ class Preferences
|
|||
toggleDebugDisplay(value);
|
||||
}
|
||||
|
||||
return Save.get().options.debugDisplay = value;
|
||||
var save = Save.get();
|
||||
save.options.debugDisplay = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +122,10 @@ class Preferences
|
|||
{
|
||||
if (value != Save.get().options.autoPause) FlxG.autoPause = value;
|
||||
|
||||
return Save.get().options.autoPause = value;
|
||||
var save = Save.get();
|
||||
save.options.autoPause = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
public static function init():Void
|
||||
|
|
|
@ -8,6 +8,9 @@ import flash.display.Sprite;
|
|||
import flixel.system.FlxBasePreloader;
|
||||
import openfl.display.Sprite;
|
||||
import funkin.util.CLIUtil;
|
||||
import openfl.text.TextField;
|
||||
import openfl.text.TextFormat;
|
||||
import flixel.system.FlxAssets;
|
||||
|
||||
@:bitmap("art/preloaderArt.png") class LogoImage extends BitmapData {}
|
||||
|
||||
|
@ -21,12 +24,26 @@ class Preloader extends FlxBasePreloader
|
|||
}
|
||||
|
||||
var logo:Sprite;
|
||||
var _text:TextField;
|
||||
|
||||
override function create():Void
|
||||
{
|
||||
this._width = Lib.current.stage.stageWidth;
|
||||
this._height = Lib.current.stage.stageHeight;
|
||||
|
||||
_text = new TextField();
|
||||
_text.width = 500;
|
||||
_text.text = "Loading FNF";
|
||||
_text.defaultTextFormat = new TextFormat(FlxAssets.FONT_DEFAULT, 16, 0xFFFFFFFF);
|
||||
_text.embedFonts = true;
|
||||
_text.selectable = false;
|
||||
_text.multiline = false;
|
||||
_text.wordWrap = false;
|
||||
_text.autoSize = LEFT;
|
||||
_text.x = 2;
|
||||
_text.y = 2;
|
||||
addChild(_text);
|
||||
|
||||
var ratio:Float = this._width / 2560; // This allows us to scale assets depending on the size of the screen.
|
||||
|
||||
logo = new Sprite();
|
||||
|
@ -34,27 +51,14 @@ class Preloader extends FlxBasePreloader
|
|||
logo.scaleX = logo.scaleY = ratio;
|
||||
logo.x = ((this._width) / 2) - ((logo.width) / 2);
|
||||
logo.y = (this._height / 2) - ((logo.height) / 2);
|
||||
addChild(logo); // Adds the graphic to the NMEPreloader's buffer.
|
||||
// addChild(logo); // Adds the graphic to the NMEPreloader's buffer.
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
override function update(Percent:Float):Void
|
||||
{
|
||||
if (Percent < 69)
|
||||
{
|
||||
logo.scaleX += Percent / 1920;
|
||||
logo.scaleY += Percent / 1920;
|
||||
logo.x -= Percent * 0.6;
|
||||
logo.y -= Percent / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
logo.scaleX = this._width / 1280;
|
||||
logo.scaleY = this._width / 1280;
|
||||
logo.x = ((this._width) / 2) - ((logo.width) / 2);
|
||||
logo.y = (this._height / 2) - ((logo.height) / 2);
|
||||
}
|
||||
_text.text = "FNF: " + Math.round(Percent * 100) + "%";
|
||||
|
||||
super.update(Percent);
|
||||
}
|
||||
|
|
|
@ -898,20 +898,26 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
|||
/**
|
||||
* The kind of the note.
|
||||
* This can allow the note to include information used for custom behavior.
|
||||
* Defaults to blank or `Constants.DEFAULT_DIFFICULTY`.
|
||||
* Defaults to `null` for no kind.
|
||||
*/
|
||||
@:alias("k")
|
||||
@:default("normal")
|
||||
@:optional
|
||||
public var kind(get, default):String = '';
|
||||
@:isVar
|
||||
public var kind(get, set):Null<String> = null;
|
||||
|
||||
function get_kind():String
|
||||
function get_kind():Null<String>
|
||||
{
|
||||
if (this.kind == null || this.kind == '') return 'normal';
|
||||
if (this.kind == null || this.kind == '') return null;
|
||||
|
||||
return this.kind;
|
||||
}
|
||||
|
||||
function set_kind(value:Null<String>):Null<String>
|
||||
{
|
||||
if (value == '') value = null;
|
||||
return this.kind = value;
|
||||
}
|
||||
|
||||
public function new(time:Float, data:Int, length:Float = 0, kind:String = '')
|
||||
{
|
||||
this.time = time;
|
||||
|
@ -1061,13 +1067,13 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
|
|||
if (this == null) return other == null;
|
||||
if (other == null) return false;
|
||||
|
||||
if (this.kind == '')
|
||||
if (this.kind == null || this.kind == '')
|
||||
{
|
||||
if (other.kind != '' && other.kind != 'normal') return false;
|
||||
if (other.kind != '' && this.kind != null) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other.kind == '' || other.kind != this.kind) return false;
|
||||
if (other.kind == '' || this.kind == null) return false;
|
||||
}
|
||||
|
||||
return this.time == other.time && this.data == other.data && this.length == other.length;
|
||||
|
@ -1082,11 +1088,11 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
|
|||
|
||||
if (this.kind == '')
|
||||
{
|
||||
if (other.kind != '' && other.kind != 'normal') return true;
|
||||
if (other.kind != '') return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other.kind == '' || other.kind != this.kind) return true;
|
||||
if (other.kind == '') return true;
|
||||
}
|
||||
|
||||
return this.time != other.time || this.data != other.data || this.length != other.length;
|
||||
|
|
|
@ -210,14 +210,13 @@ class SongDataUtils
|
|||
*/
|
||||
public static function writeItemsToClipboard(data:SongClipboardItems):Void
|
||||
{
|
||||
var writer = new json2object.JsonWriter<SongClipboardItems>();
|
||||
var ignoreNullOptionals = true;
|
||||
var writer = new json2object.JsonWriter<SongClipboardItems>(ignoreNullOptionals);
|
||||
var dataString:String = writer.write(data, ' ');
|
||||
|
||||
ClipboardUtil.setClipboard(dataString);
|
||||
|
||||
trace('Wrote ' + data.notes.length + ' notes and ' + data.events.length + ' events to clipboard.');
|
||||
|
||||
trace(dataString);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,12 +63,10 @@ class Controls extends FlxActionSet
|
|||
var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU);
|
||||
var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART);
|
||||
var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE);
|
||||
var _screenshot = new FlxActionDigital(Action.SCREENSHOT);
|
||||
var _volume_up = new FlxActionDigital(Action.VOLUME_UP);
|
||||
var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN);
|
||||
var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE);
|
||||
#if CAN_CHEAT
|
||||
var _cheat = new FlxActionDigital(Action.CHEAT);
|
||||
#end
|
||||
|
||||
var byName:Map<String, FlxActionDigital> = new Map<String, FlxActionDigital>();
|
||||
|
||||
|
@ -235,6 +233,11 @@ class Controls extends FlxActionSet
|
|||
inline function get_DEBUG_STAGE()
|
||||
return _debug_stage.check();
|
||||
|
||||
public var SCREENSHOT(get, never):Bool;
|
||||
|
||||
inline function get_SCREENSHOT()
|
||||
return _screenshot.check();
|
||||
|
||||
public var VOLUME_UP(get, never):Bool;
|
||||
|
||||
inline function get_VOLUME_UP()
|
||||
|
@ -255,13 +258,6 @@ class Controls extends FlxActionSet
|
|||
inline function get_RESET()
|
||||
return _reset.check();
|
||||
|
||||
#if CAN_CHEAT
|
||||
public var CHEAT(get, never):Bool;
|
||||
|
||||
inline function get_CHEAT()
|
||||
return _cheat.check();
|
||||
#end
|
||||
|
||||
public function new(name, scheme:KeyboardScheme = null)
|
||||
{
|
||||
super(name);
|
||||
|
@ -295,13 +291,14 @@ class Controls extends FlxActionSet
|
|||
add(_pause);
|
||||
add(_cutscene_advance);
|
||||
add(_cutscene_skip);
|
||||
add(_debug_menu);
|
||||
add(_debug_chart);
|
||||
add(_debug_stage);
|
||||
add(_screenshot);
|
||||
add(_volume_up);
|
||||
add(_volume_down);
|
||||
add(_volume_mute);
|
||||
add(_reset);
|
||||
#if CAN_CHEAT
|
||||
add(_cheat);
|
||||
#end
|
||||
|
||||
for (action in digitalActions)
|
||||
byName[action.name] = action;
|
||||
|
@ -391,12 +388,10 @@ class Controls extends FlxActionSet
|
|||
case DEBUG_MENU: _debug_menu;
|
||||
case DEBUG_CHART: _debug_chart;
|
||||
case DEBUG_STAGE: _debug_stage;
|
||||
case SCREENSHOT: _screenshot;
|
||||
case VOLUME_UP: _volume_up;
|
||||
case VOLUME_DOWN: _volume_down;
|
||||
case VOLUME_MUTE: _volume_mute;
|
||||
#if CAN_CHEAT
|
||||
case CHEAT: _cheat;
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,6 +459,8 @@ class Controls extends FlxActionSet
|
|||
func(_debug_chart, JUST_PRESSED);
|
||||
case DEBUG_STAGE:
|
||||
func(_debug_stage, JUST_PRESSED);
|
||||
case SCREENSHOT:
|
||||
func(_screenshot, JUST_PRESSED);
|
||||
case VOLUME_UP:
|
||||
func(_volume_up, JUST_PRESSED);
|
||||
case VOLUME_DOWN:
|
||||
|
@ -472,10 +469,6 @@ class Controls extends FlxActionSet
|
|||
func(_volume_mute, JUST_PRESSED);
|
||||
case RESET:
|
||||
func(_reset, JUST_PRESSED);
|
||||
#if CAN_CHEAT
|
||||
case CHEAT:
|
||||
func(_cheat, JUST_PRESSED);
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,6 +659,8 @@ class Controls extends FlxActionSet
|
|||
bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
|
||||
bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
|
||||
bindKeys(Control.DEBUG_STAGE, getDefaultKeybinds(scheme, Control.DEBUG_STAGE));
|
||||
bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET));
|
||||
bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT));
|
||||
bindKeys(Control.VOLUME_UP, getDefaultKeybinds(scheme, Control.VOLUME_UP));
|
||||
bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN));
|
||||
bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE));
|
||||
|
@ -693,6 +688,7 @@ class Controls extends FlxActionSet
|
|||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||
case Control.DEBUG_CHART: return [];
|
||||
case Control.DEBUG_STAGE: return [];
|
||||
case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen
|
||||
case Control.VOLUME_UP: return [PLUS, NUMPADPLUS];
|
||||
case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
|
||||
case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
|
||||
|
@ -716,6 +712,7 @@ class Controls extends FlxActionSet
|
|||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||
case Control.DEBUG_CHART: return [];
|
||||
case Control.DEBUG_STAGE: return [];
|
||||
case Control.SCREENSHOT: return [PRINTSCREEN];
|
||||
case Control.VOLUME_UP: return [PLUS];
|
||||
case Control.VOLUME_DOWN: return [MINUS];
|
||||
case Control.VOLUME_MUTE: return [ZERO];
|
||||
|
@ -739,6 +736,7 @@ class Controls extends FlxActionSet
|
|||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||
case Control.DEBUG_CHART: return [];
|
||||
case Control.DEBUG_STAGE: return [];
|
||||
case Control.SCREENSHOT: return [PRINTSCREEN];
|
||||
case Control.VOLUME_UP: return [NUMPADPLUS];
|
||||
case Control.VOLUME_DOWN: return [NUMPADMINUS];
|
||||
case Control.VOLUME_MUTE: return [NUMPADZERO];
|
||||
|
@ -845,6 +843,7 @@ class Controls extends FlxActionSet
|
|||
Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT),
|
||||
Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT),
|
||||
Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
|
||||
// Control.SCREENSHOT => [],
|
||||
// Control.VOLUME_UP => [RIGHT_SHOULDER],
|
||||
// Control.VOLUME_DOWN => [LEFT_SHOULDER],
|
||||
// Control.VOLUME_MUTE => [RIGHT_TRIGGER],
|
||||
|
@ -852,8 +851,7 @@ class Controls extends FlxActionSet
|
|||
Control.CUTSCENE_SKIP => getDefaultGamepadBinds(Control.CUTSCENE_SKIP),
|
||||
// Control.DEBUG_MENU
|
||||
// Control.DEBUG_CHART
|
||||
Control.RESET => getDefaultGamepadBinds(Control.RESET),
|
||||
#if CAN_CHEAT, Control.CHEAT => getDefaultGamepadBinds(Control.CHEAT) #end
|
||||
Control.RESET => getDefaultGamepadBinds(Control.RESET)
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -870,6 +868,7 @@ class Controls extends FlxActionSet
|
|||
case Control.NOTE_LEFT: return [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT];
|
||||
case Control.NOTE_RIGHT: return [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT];
|
||||
case Control.PAUSE: return [START];
|
||||
case Control.SCREENSHOT: return [];
|
||||
case Control.VOLUME_UP: return [];
|
||||
case Control.VOLUME_DOWN: return [];
|
||||
case Control.VOLUME_MUTE: return [];
|
||||
|
@ -878,7 +877,6 @@ class Controls extends FlxActionSet
|
|||
case Control.DEBUG_MENU: return [];
|
||||
case Control.DEBUG_CHART: return [];
|
||||
case Control.RESET: return [RIGHT_SHOULDER];
|
||||
#if CAN_CHEAT, Control.CHEAT: return [X]; #end
|
||||
default:
|
||||
// Fallthrough.
|
||||
}
|
||||
|
@ -1236,6 +1234,8 @@ enum Control
|
|||
// CUTSCENE
|
||||
CUTSCENE_ADVANCE;
|
||||
CUTSCENE_SKIP;
|
||||
// SCREENSHOT
|
||||
SCREENSHOT;
|
||||
// VOLUME
|
||||
VOLUME_UP;
|
||||
VOLUME_DOWN;
|
||||
|
@ -1244,9 +1244,6 @@ enum Control
|
|||
DEBUG_MENU;
|
||||
DEBUG_CHART;
|
||||
DEBUG_STAGE;
|
||||
#if CAN_CHEAT
|
||||
CHEAT;
|
||||
#end
|
||||
}
|
||||
|
||||
enum
|
||||
|
@ -1289,13 +1286,12 @@ abstract Action(String) to String from String
|
|||
var VOLUME_UP = "volume_up";
|
||||
var VOLUME_DOWN = "volume_down";
|
||||
var VOLUME_MUTE = "volume_mute";
|
||||
// SCREENSHOT
|
||||
var SCREENSHOT = "screenshot";
|
||||
// DEBUG
|
||||
var DEBUG_MENU = "debug_menu";
|
||||
var DEBUG_CHART = "debug_chart";
|
||||
var DEBUG_STAGE = "debug_stage";
|
||||
#if CAN_CHEAT
|
||||
var CHEAT = "cheat";
|
||||
#end
|
||||
}
|
||||
|
||||
enum Device
|
||||
|
|
|
@ -123,6 +123,11 @@ typedef PlayStateParams =
|
|||
* and must be loaded externally.
|
||||
*/
|
||||
?overrideMusic:Bool,
|
||||
/**
|
||||
* The initial camera follow point.
|
||||
* Used to persist the position of the `cameraFollowPosition` between levels.
|
||||
*/
|
||||
?cameraFollowPoint:FlxPoint,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,7 +221,7 @@ class PlayState extends MusicBeatSubState
|
|||
* The camera follow point from the last stage.
|
||||
* Used to persist the position of the `cameraFollowPosition` between levels.
|
||||
*/
|
||||
public var previousCameraFollowPoint:FlxSprite = null;
|
||||
public var previousCameraFollowPoint:FlxPoint = null;
|
||||
|
||||
/**
|
||||
* The current camera zoom level.
|
||||
|
@ -354,6 +359,11 @@ class PlayState extends MusicBeatSubState
|
|||
*/
|
||||
var startingSong:Bool = false;
|
||||
|
||||
/**
|
||||
* False if `FlxG.sound.music`
|
||||
*/
|
||||
var musicPausedBySubState:Bool = false;
|
||||
|
||||
/**
|
||||
* False until `create()` has completed.
|
||||
*/
|
||||
|
@ -539,6 +549,7 @@ class PlayState extends MusicBeatSubState
|
|||
isMinimalMode = params.minimalMode ?? false;
|
||||
startTimestamp = params.startTimestamp ?? 0.0;
|
||||
overrideMusic = params.overrideMusic ?? false;
|
||||
previousCameraFollowPoint = params.cameraFollowPoint;
|
||||
|
||||
// Don't do anything else here! Wait until create() when we attach to the camera.
|
||||
}
|
||||
|
@ -697,7 +708,7 @@ class PlayState extends MusicBeatSubState
|
|||
function assertChartExists():Bool
|
||||
{
|
||||
// Returns null if the song failed to load or doesn't have the selected difficulty.
|
||||
if (currentSong == null || currentChart == null)
|
||||
if (currentSong == null || currentChart == null || currentChart.notes == null)
|
||||
{
|
||||
// We have encountered a critical error. Prevent Flixel from trying to run any gameplay logic.
|
||||
criticalFailure = true;
|
||||
|
@ -716,6 +727,10 @@ class PlayState extends MusicBeatSubState
|
|||
{
|
||||
message = 'The was a critical error retrieving data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.';
|
||||
}
|
||||
else if (currentChart.notes == null)
|
||||
{
|
||||
message = 'The was a critical error retrieving note data for this song on "$currentDifficulty" difficulty with variation "$currentVariation". Click OK to return to the main menu.';
|
||||
}
|
||||
|
||||
// Display a popup. This blocks the application until the user clicks OK.
|
||||
lime.app.Application.current.window.alert(message, 'Error loading PlayState');
|
||||
|
@ -1042,6 +1057,7 @@ class PlayState extends MusicBeatSubState
|
|||
// Pause the music.
|
||||
if (FlxG.sound.music != null)
|
||||
{
|
||||
musicPausedBySubState = FlxG.sound.music.playing;
|
||||
FlxG.sound.music.pause();
|
||||
if (vocals != null) vocals.pause();
|
||||
}
|
||||
|
@ -1049,7 +1065,6 @@ class PlayState extends MusicBeatSubState
|
|||
// Pause the countdown.
|
||||
Countdown.pauseCountdown();
|
||||
}
|
||||
else {}
|
||||
|
||||
super.openSubState(subState);
|
||||
}
|
||||
|
@ -1069,7 +1084,10 @@ class PlayState extends MusicBeatSubState
|
|||
if (event.eventCanceled) return;
|
||||
|
||||
// Resume
|
||||
FlxG.sound.music.play(FlxG.sound.music.time);
|
||||
if (musicPausedBySubState)
|
||||
{
|
||||
FlxG.sound.music.play(FlxG.sound.music.time);
|
||||
}
|
||||
|
||||
if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals();
|
||||
|
||||
|
@ -2613,38 +2631,25 @@ class PlayState extends MusicBeatSubState
|
|||
FlxG.sound.play(Paths.sound('Lights_Shut_off'), function() {
|
||||
// no camFollow so it centers on horror tree
|
||||
var targetSong:Song = SongRegistry.instance.fetchEntry(targetSongId);
|
||||
// Load and cache the song's charts.
|
||||
// TODO: Do this in the loading state.
|
||||
targetSong.cacheCharts(true);
|
||||
|
||||
LoadingState.loadAndSwitchState(() -> {
|
||||
var nextPlayState:PlayState = new PlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: PlayStatePlaylist.campaignDifficulty,
|
||||
targetVariation: currentVariation,
|
||||
});
|
||||
nextPlayState.previousCameraFollowPoint = new FlxSprite(cameraFollowPoint.x, cameraFollowPoint.y);
|
||||
return nextPlayState;
|
||||
});
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: PlayStatePlaylist.campaignDifficulty,
|
||||
targetVariation: currentVariation,
|
||||
cameraFollowPoint: cameraFollowPoint.getPosition(),
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetSong:Song = SongRegistry.instance.fetchEntry(targetSongId);
|
||||
// Load and cache the song's charts.
|
||||
// TODO: Do this in the loading state.
|
||||
targetSong.cacheCharts(true);
|
||||
LoadingState.loadAndSwitchState(() -> {
|
||||
var nextPlayState:PlayState = new PlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: PlayStatePlaylist.campaignDifficulty,
|
||||
targetVariation: currentVariation,
|
||||
});
|
||||
nextPlayState.previousCameraFollowPoint = new FlxSprite(cameraFollowPoint.x, cameraFollowPoint.y);
|
||||
return nextPlayState;
|
||||
});
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: PlayStatePlaylist.campaignDifficulty,
|
||||
targetVariation: currentVariation,
|
||||
cameraFollowPoint: cameraFollowPoint.getPosition(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,9 @@ abstract Save(RawSaveData)
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Modifications will not be saved without calling `Save.flush()`!
|
||||
*/
|
||||
public var options(get, never):SaveDataOptions;
|
||||
|
||||
function get_options():SaveDataOptions
|
||||
|
@ -122,6 +125,9 @@ abstract Save(RawSaveData)
|
|||
return this.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Modifications will not be saved without calling `Save.flush()`!
|
||||
*/
|
||||
public var modOptions(get, never):Map<String, Dynamic>;
|
||||
|
||||
function get_modOptions():Map<String, Dynamic>
|
||||
|
|
|
@ -59,19 +59,6 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
Conductor.stepHit.remove(this.stepHit);
|
||||
}
|
||||
|
||||
function handleControls():Void
|
||||
{
|
||||
var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
|
||||
|
||||
if (!isHaxeUIFocused)
|
||||
{
|
||||
// Rebindable volume keys.
|
||||
if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
|
||||
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
|
||||
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFunctionControls():Void
|
||||
{
|
||||
// Emergency exit button.
|
||||
|
@ -85,8 +72,6 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
{
|
||||
super.update(elapsed);
|
||||
|
||||
handleControls();
|
||||
|
||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,6 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
{
|
||||
super.update(elapsed);
|
||||
|
||||
// Rebindable volume keys.
|
||||
if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
|
||||
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
|
||||
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
|
||||
|
||||
// Emergency exit button.
|
||||
if (FlxG.keys.justPressed.F4) FlxG.switchState(() -> new MainMenuState());
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import funkin.ui.debug.charting.ChartEditorState;
|
|||
import funkin.ui.MusicBeatSubState;
|
||||
import funkin.util.logging.CrashHandler;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import funkin.util.FileUtil;
|
||||
|
||||
class DebugMenuSubState extends MusicBeatSubState
|
||||
{
|
||||
|
@ -121,16 +122,7 @@ class DebugMenuSubState extends MusicBeatSubState
|
|||
#if sys
|
||||
function openLogFolder()
|
||||
{
|
||||
#if windows
|
||||
Sys.command('explorer', [CrashHandler.LOG_FOLDER]);
|
||||
#elseif mac
|
||||
// mac could be fuckie with where the log folder is relative to the game file...
|
||||
// if this comment is still here... it means it has NOT been verified on mac yet!
|
||||
Sys.command('open', [CrashHandler.LOG_FOLDER]);
|
||||
#end
|
||||
|
||||
// TODO: implement linux
|
||||
// some shit with xdg-open :thinking: emoji...
|
||||
FileUtil.openFolder(CrashHandler.LOG_FOLDER);
|
||||
}
|
||||
#end
|
||||
|
||||
|
|
|
@ -162,8 +162,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
public static final CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:String = Paths.ui('chart-editor/toolbox/opponent-preview');
|
||||
public static final CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/metadata');
|
||||
public static final CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT:String = Paths.ui('chart-editor/toolbox/offsets');
|
||||
public static final CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/notedata');
|
||||
public static final CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/eventdata');
|
||||
public static final CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/note-data');
|
||||
public static final CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT:String = Paths.ui('chart-editor/toolbox/event-data');
|
||||
public static final CHART_EDITOR_TOOLBOX_FREEPLAY_LAYOUT:String = Paths.ui('chart-editor/toolbox/freeplay');
|
||||
public static final CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:String = Paths.ui('chart-editor/toolbox/playtest-properties');
|
||||
|
||||
|
@ -538,9 +538,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
// Tools Status
|
||||
|
||||
/**
|
||||
* The note kind to use for notes being placed in the chart. Defaults to `''`.
|
||||
* The note kind to use for notes being placed in the chart. Defaults to `null`.
|
||||
*/
|
||||
var noteKindToPlace:String = '';
|
||||
var noteKindToPlace:Null<String> = null;
|
||||
|
||||
/**
|
||||
* The event type to use for events being placed in the chart. Defaults to `''`.
|
||||
|
@ -2458,11 +2458,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
*/
|
||||
override public function draw():Void
|
||||
{
|
||||
if (selectionBoxStartPos != null)
|
||||
{
|
||||
trace('selectionBoxSprite: ${selectionBoxSprite.visible} ${selectionBoxSprite.exists} ${this.members.contains(selectionBoxSprite)}');
|
||||
}
|
||||
|
||||
super.draw();
|
||||
}
|
||||
|
||||
|
@ -2968,7 +2963,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
menubarItemToggleToolboxDifficulty.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxMetadata.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_METADATA_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxOffsets.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxNotes.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxNoteData.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxEventData.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxFreeplay.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_FREEPLAY_LAYOUT, event.value);
|
||||
menubarItemToggleToolboxPlaytestProperties.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT, event.value);
|
||||
|
@ -5286,6 +5281,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
{
|
||||
FlxG.watch.addQuick('musicTime', audioInstTrack?.time ?? 0.0);
|
||||
|
||||
FlxG.watch.addQuick('noteKindToPlace', noteKindToPlace);
|
||||
FlxG.watch.addQuick('eventKindToPlace', eventKindToPlace);
|
||||
|
||||
FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
|
||||
FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
|
||||
|
||||
|
|
|
@ -59,6 +59,17 @@ class SelectItemsCommand implements ChartEditorCommand
|
|||
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT);
|
||||
}
|
||||
|
||||
// If we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
||||
if (this.events.length == 0 && this.notes.length >= 1)
|
||||
{
|
||||
var noteSelected = this.notes[0];
|
||||
|
||||
state.noteKindToPlace = noteSelected.kind;
|
||||
|
||||
// This code is here to parse note data that's not built as a struct for some reason.
|
||||
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT);
|
||||
}
|
||||
|
||||
state.noteDisplayDirty = true;
|
||||
state.notePreviewDirty = true;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,16 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
|||
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT);
|
||||
}
|
||||
|
||||
// IF we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
||||
if (this.events.length == 0 && this.notes.length >= 1)
|
||||
{
|
||||
var noteSelected = this.notes[0];
|
||||
|
||||
state.noteKindToPlace = noteSelected.kind;
|
||||
|
||||
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT);
|
||||
}
|
||||
|
||||
state.noteDisplayDirty = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import funkin.ui.debug.charting.toolboxes.ChartEditorMetadataToolbox;
|
|||
import funkin.ui.debug.charting.toolboxes.ChartEditorOffsetsToolbox;
|
||||
import funkin.ui.debug.charting.toolboxes.ChartEditorFreeplayToolbox;
|
||||
import funkin.ui.debug.charting.toolboxes.ChartEditorEventDataToolbox;
|
||||
import funkin.ui.debug.charting.toolboxes.ChartEditorNoteDataToolbox;
|
||||
import funkin.ui.debug.charting.toolboxes.ChartEditorDifficultyToolbox;
|
||||
import haxe.ui.containers.Frame;
|
||||
import haxe.ui.containers.Grid;
|
||||
|
@ -79,17 +80,16 @@ class ChartEditorToolboxHandler
|
|||
|
||||
switch (id)
|
||||
{
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:
|
||||
onShowToolboxNoteData(state, toolbox);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT:
|
||||
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT:
|
||||
// TODO: Fix this.
|
||||
// TODO: Make these better.
|
||||
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:
|
||||
onShowToolboxPlaytestProperties(state, toolbox);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_DIFFICULTY_LAYOUT:
|
||||
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT:
|
||||
// TODO: Fix this.
|
||||
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT:
|
||||
cast(toolbox, ChartEditorBaseToolbox).refresh();
|
||||
|
@ -124,10 +124,6 @@ class ChartEditorToolboxHandler
|
|||
|
||||
switch (id)
|
||||
{
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:
|
||||
onHideToolboxNoteData(state, toolbox);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT:
|
||||
onHideToolboxEventData(state, toolbox);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:
|
||||
onHideToolboxPlaytestProperties(state, toolbox);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
||||
|
@ -196,7 +192,7 @@ class ChartEditorToolboxHandler
|
|||
var toolbox:Null<CollapsibleDialog> = null;
|
||||
switch (id)
|
||||
{
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT:
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_NOTE_DATA_LAYOUT:
|
||||
toolbox = buildToolboxNoteDataLayout(state);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT:
|
||||
toolbox = buildToolboxEventDataLayout(state);
|
||||
|
@ -262,58 +258,13 @@ class ChartEditorToolboxHandler
|
|||
|
||||
static function buildToolboxNoteDataLayout(state:ChartEditorState):Null<CollapsibleDialog>
|
||||
{
|
||||
var toolbox:CollapsibleDialog = cast RuntimeComponentBuilder.fromAsset(ChartEditorState.CHART_EDITOR_TOOLBOX_NOTEDATA_LAYOUT);
|
||||
var toolbox:ChartEditorBaseToolbox = ChartEditorNoteDataToolbox.build(state);
|
||||
|
||||
if (toolbox == null) return null;
|
||||
|
||||
// Starting position.
|
||||
toolbox.x = 75;
|
||||
toolbox.y = 100;
|
||||
|
||||
toolbox.onDialogClosed = function(event:DialogEvent) {
|
||||
state.menubarItemToggleToolboxNotes.selected = false;
|
||||
}
|
||||
|
||||
var toolboxNotesNoteKind:Null<DropDown> = toolbox.findComponent('toolboxNotesNoteKind', DropDown);
|
||||
if (toolboxNotesNoteKind == null) throw 'ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Could not find toolboxNotesNoteKind component.';
|
||||
var toolboxNotesCustomKindLabel:Null<Label> = toolbox.findComponent('toolboxNotesCustomKindLabel', Label);
|
||||
if (toolboxNotesCustomKindLabel == null)
|
||||
throw 'ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Could not find toolboxNotesCustomKindLabel component.';
|
||||
var toolboxNotesCustomKind:Null<TextField> = toolbox.findComponent('toolboxNotesCustomKind', TextField);
|
||||
if (toolboxNotesCustomKind == null) throw 'ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Could not find toolboxNotesCustomKind component.';
|
||||
|
||||
toolboxNotesNoteKind.onChange = function(event:UIEvent) {
|
||||
var isCustom:Bool = (event.data.id == '~CUSTOM~');
|
||||
|
||||
if (isCustom)
|
||||
{
|
||||
toolboxNotesCustomKindLabel.hidden = false;
|
||||
toolboxNotesCustomKind.hidden = false;
|
||||
|
||||
state.noteKindToPlace = toolboxNotesCustomKind.text;
|
||||
}
|
||||
else
|
||||
{
|
||||
toolboxNotesCustomKindLabel.hidden = true;
|
||||
toolboxNotesCustomKind.hidden = true;
|
||||
|
||||
state.noteKindToPlace = event.data.id;
|
||||
}
|
||||
}
|
||||
|
||||
toolboxNotesCustomKind.onChange = function(event:UIEvent) {
|
||||
state.noteKindToPlace = toolboxNotesCustomKind.text;
|
||||
}
|
||||
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
static function onShowToolboxNoteData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||
|
||||
static function onHideToolboxNoteData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||
|
||||
static function onHideToolboxEventData(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||
|
||||
static function onShowToolboxPlaytestProperties(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||
|
||||
static function onHideToolboxPlaytestProperties(state:ChartEditorState, toolbox:CollapsibleDialog):Void {}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package funkin.ui.debug.charting.toolboxes;
|
||||
|
||||
import haxe.ui.components.DropDown;
|
||||
import haxe.ui.components.TextField;
|
||||
import haxe.ui.events.UIEvent;
|
||||
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||
|
||||
/**
|
||||
* The toolbox which allows modifying information like Note Kind.
|
||||
*/
|
||||
@:access(funkin.ui.debug.charting.ChartEditorState)
|
||||
@:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/toolboxes/note-data.xml"))
|
||||
class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox
|
||||
{
|
||||
var toolboxNotesNoteKind:DropDown;
|
||||
var toolboxNotesCustomKind:TextField;
|
||||
|
||||
var _initializing:Bool = true;
|
||||
|
||||
public function new(chartEditorState2:ChartEditorState)
|
||||
{
|
||||
super(chartEditorState2);
|
||||
|
||||
initialize();
|
||||
|
||||
this.onDialogClosed = onClose;
|
||||
|
||||
this._initializing = false;
|
||||
}
|
||||
|
||||
function onClose(event:UIEvent)
|
||||
{
|
||||
chartEditorState.menubarItemToggleToolboxNoteData.selected = false;
|
||||
}
|
||||
|
||||
function initialize():Void
|
||||
{
|
||||
toolboxNotesNoteKind.onChange = function(event:UIEvent) {
|
||||
var noteKind:Null<String> = event?.data?.id ?? null;
|
||||
if (noteKind == '') noteKind = null;
|
||||
|
||||
trace('ChartEditorToolboxHandler.buildToolboxNoteDataLayout() - Note kind changed: $noteKind');
|
||||
|
||||
// Edit the note data to place.
|
||||
if (noteKind == '~CUSTOM~')
|
||||
{
|
||||
showCustom();
|
||||
toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
else
|
||||
{
|
||||
hideCustom();
|
||||
chartEditorState.noteKindToPlace = noteKind;
|
||||
toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
|
||||
if (!_initializing && chartEditorState.currentNoteSelection.length > 0)
|
||||
{
|
||||
// Edit the note data of any selected notes.
|
||||
for (note in chartEditorState.currentNoteSelection)
|
||||
{
|
||||
note.kind = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
chartEditorState.saveDataDirty = true;
|
||||
chartEditorState.noteDisplayDirty = true;
|
||||
chartEditorState.notePreviewDirty = true;
|
||||
}
|
||||
};
|
||||
var startingValueNoteKind = ChartEditorDropdowns.populateDropdownWithNoteKinds(toolboxNotesNoteKind, '');
|
||||
toolboxNotesNoteKind.value = startingValueNoteKind;
|
||||
|
||||
toolboxNotesCustomKind.onChange = function(event:UIEvent) {
|
||||
var customKind:Null<String> = event?.target?.text;
|
||||
chartEditorState.noteKindToPlace = customKind;
|
||||
|
||||
if (chartEditorState.currentEventSelection.length > 0)
|
||||
{
|
||||
// Edit the note data of any selected notes.
|
||||
for (note in chartEditorState.currentNoteSelection)
|
||||
{
|
||||
note.kind = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
chartEditorState.saveDataDirty = true;
|
||||
chartEditorState.noteDisplayDirty = true;
|
||||
chartEditorState.notePreviewDirty = true;
|
||||
}
|
||||
};
|
||||
toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
|
||||
public override function refresh():Void
|
||||
{
|
||||
super.refresh();
|
||||
|
||||
toolboxNotesNoteKind.value = ChartEditorDropdowns.lookupNoteKind(chartEditorState.noteKindToPlace);
|
||||
toolboxNotesCustomKind.value = chartEditorState.noteKindToPlace;
|
||||
}
|
||||
|
||||
function showCustom():Void
|
||||
{
|
||||
toolboxNotesCustomKindLabel.hidden = false;
|
||||
toolboxNotesCustomKind.hidden = false;
|
||||
}
|
||||
|
||||
function hideCustom():Void
|
||||
{
|
||||
toolboxNotesCustomKindLabel.hidden = true;
|
||||
toolboxNotesCustomKind.hidden = true;
|
||||
}
|
||||
|
||||
public static function build(chartEditorState:ChartEditorState):ChartEditorNoteDataToolbox
|
||||
{
|
||||
return new ChartEditorNoteDataToolbox(chartEditorState);
|
||||
}
|
||||
}
|
|
@ -108,6 +108,55 @@ class ChartEditorDropdowns
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
static final NOTE_KINDS:Map<String, String> = [
|
||||
// Base
|
||||
"" => "Default",
|
||||
"~CUSTOM~" => "Custom",
|
||||
// Weeks 1-7
|
||||
"mom" => "Mom Sings (Week 5)",
|
||||
"ugh" => "Ugh (Week 7)",
|
||||
"hehPrettyGood" => "Heh, Pretty Good (Week 7)",
|
||||
// Weekend 1
|
||||
"weekend-1-lightcan" => "Light Can (2hot)",
|
||||
"weekend-1-kickcan" => "Kick Can (2hot)",
|
||||
"weekend-1-kneecan" => "Knee Can (2hot)",
|
||||
"weekend-1-cockgun" => "Cock Gun (2hot)",
|
||||
"weekend-1-firegun" => "Fire Gun (2hot)",
|
||||
"weekend-1-punchlow" => "Punch Low (Blazin)",
|
||||
"weekend-1-punchhigh" => "Punch High (Blazin)",
|
||||
"weekend-1-punchlowblocked" => "Punch Low Blocked (Blazin)",
|
||||
"weekend-1-punchhighblocked" => "Punch High Blocked (Blazin)",
|
||||
"weekend-1-dodgelow" => "Dodge Low (Blazin)",
|
||||
"weekend-1-blockhigh" => "Block High (Blazin)",
|
||||
"weekend-1-fakeout" => "Fakeout (Blazin)",
|
||||
];
|
||||
|
||||
public static function populateDropdownWithNoteKinds(dropDown:DropDown, startingKindId:String):DropDownEntry
|
||||
{
|
||||
dropDown.dataSource.clear();
|
||||
|
||||
var returnValue:DropDownEntry = lookupNoteKind('~CUSTOM');
|
||||
|
||||
for (noteKindId in NOTE_KINDS.keys())
|
||||
{
|
||||
var noteKind:String = NOTE_KINDS.get(noteKindId) ?? 'Default';
|
||||
|
||||
var value:DropDownEntry = {id: noteKindId, text: noteKind};
|
||||
if (startingKindId == noteKindId) returnValue = value;
|
||||
|
||||
dropDown.dataSource.add(value);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public static function lookupNoteKind(noteKindId:Null<String>):DropDownEntry
|
||||
{
|
||||
if (noteKindId == null) return lookupNoteKind('');
|
||||
if (!NOTE_KINDS.exists(noteKindId)) return {id: '~CUSTOM~', text: 'Custom'};
|
||||
return {id: noteKindId ?? '', text: NOTE_KINDS.get(noteKindId) ?? 'Default'};
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate a dropdown with a list of song variations.
|
||||
*/
|
||||
|
|
|
@ -1135,18 +1135,14 @@ class FreeplayState extends MusicBeatSubState
|
|||
FlxG.sound.play(Paths.sound('confirmMenu'));
|
||||
dj.confirm();
|
||||
|
||||
// Load and cache the song's charts.
|
||||
// TODO: Do this in the loading state.
|
||||
targetSong.cacheCharts(true);
|
||||
|
||||
new FlxTimer().start(1, function(tmr:FlxTimer) {
|
||||
Paths.setCurrentLevel(cap.songData.levelId);
|
||||
LoadingState.loadAndSwitchState(() -> new PlayState(
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: targetDifficulty,
|
||||
targetVariation: targetVariation,
|
||||
}), true);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,10 @@ class Level implements IRegistryEntry<LevelData>
|
|||
|
||||
if (_data.props.length == 0) return props;
|
||||
|
||||
var hiddenProps:Array<LevelProp> = props.splice(_data.props.length - 1, props.length - 1);
|
||||
for (hiddenProp in hiddenProps)
|
||||
hiddenProp.visible = false;
|
||||
|
||||
for (propIndex in 0..._data.props.length)
|
||||
{
|
||||
var propData = _data.props[propIndex];
|
||||
|
@ -198,6 +202,7 @@ class Level implements IRegistryEntry<LevelData>
|
|||
{
|
||||
existingProp.propData = propData;
|
||||
existingProp.x = propData.offsets[0] + FlxG.width * 0.25 * propIndex;
|
||||
existingProp.visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -554,22 +554,15 @@ class StoryMenuState extends MusicBeatState
|
|||
PlayStatePlaylist.campaignTitle = currentLevel.getTitle();
|
||||
PlayStatePlaylist.campaignDifficulty = currentDifficultyId;
|
||||
|
||||
if (targetSong != null)
|
||||
{
|
||||
// Load and cache the song's charts.
|
||||
// TODO: Do this in the loading state.
|
||||
targetSong.cacheCharts(true);
|
||||
}
|
||||
|
||||
new FlxTimer().start(1, function(tmr:FlxTimer) {
|
||||
FlxTransitionableState.skipNextTransIn = false;
|
||||
FlxTransitionableState.skipNextTransOut = false;
|
||||
|
||||
LoadingState.loadAndSwitchState(() -> new PlayState(
|
||||
LoadingState.loadPlayState(
|
||||
{
|
||||
targetSong: targetSong,
|
||||
targetDifficulty: PlayStatePlaylist.campaignDifficulty,
|
||||
}), true);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -597,7 +590,9 @@ class StoryMenuState extends MusicBeatState
|
|||
{
|
||||
// Both the previous and current level were simple backgrounds.
|
||||
// Fade between colors directly, rather than fading one background out and another in.
|
||||
FlxTween.color(levelBackground, 0.4, previousColor, currentColor);
|
||||
// cancels potential tween in progress, and tweens from there
|
||||
FlxTween.cancelTweensOf(levelBackground);
|
||||
FlxTween.color(levelBackground, 0.9, levelBackground.color, currentColor, {ease: FlxEase.quartOut});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -637,10 +632,10 @@ class StoryMenuState extends MusicBeatState
|
|||
|
||||
function updateProps():Void
|
||||
{
|
||||
for (prop in currentLevel.buildProps(levelProps.members))
|
||||
for (ind => prop in currentLevel.buildProps(levelProps.members))
|
||||
{
|
||||
prop.zIndex = 1000;
|
||||
levelProps.add(prop);
|
||||
if (levelProps.members[ind] != prop) levelProps.replace(levelProps.members[ind], prop) ?? levelProps.add(prop);
|
||||
}
|
||||
|
||||
refresh();
|
||||
|
|
|
@ -9,7 +9,6 @@ import funkin.graphics.shaders.ScreenWipeShader;
|
|||
import funkin.play.PlayState;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import funkin.play.song.Song.SongDifficulty;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import funkin.ui.MusicBeatState;
|
||||
import haxe.io.Path;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
|
@ -27,17 +26,19 @@ class LoadingState extends MusicBeatState
|
|||
inline static var MIN_TIME = 1.0;
|
||||
|
||||
var target:NextState;
|
||||
var stopMusic = false;
|
||||
var playParams:Null<PlayStateParams>;
|
||||
var stopMusic:Bool = false;
|
||||
var callbacks:MultiCallback;
|
||||
var danceLeft = false;
|
||||
var danceLeft:Bool = false;
|
||||
|
||||
var loadBar:FlxSprite;
|
||||
var funkay:FlxSprite;
|
||||
|
||||
function new(target:NextState, stopMusic:Bool)
|
||||
function new(target:NextState, stopMusic:Bool, playParams:Null<PlayStateParams> = null)
|
||||
{
|
||||
super();
|
||||
this.target = target;
|
||||
this.playParams = playParams;
|
||||
this.stopMusic = stopMusic;
|
||||
}
|
||||
|
||||
|
@ -62,10 +63,18 @@ class LoadingState extends MusicBeatState
|
|||
callbacks = new MultiCallback(onLoad);
|
||||
var introComplete = callbacks.add('introComplete');
|
||||
|
||||
if (Std.isOfType(target, PlayState))
|
||||
if (playParams != null)
|
||||
{
|
||||
var targetPlayState:PlayState = cast target;
|
||||
var targetChart:SongDifficulty = targetPlayState.currentChart;
|
||||
// Load and cache the song's charts.
|
||||
if (playParams.targetSong != null)
|
||||
{
|
||||
playParams.targetSong.cacheCharts(true);
|
||||
}
|
||||
|
||||
// Preload the song for the play state.
|
||||
var difficulty:String = playParams.targetDifficulty ?? Constants.DEFAULT_DIFFICULTY;
|
||||
var variation:String = playParams.targetVariation ?? Constants.DEFAULT_VARIATION;
|
||||
var targetChart:SongDifficulty = playParams.targetSong?.getDifficulty(difficulty, variation);
|
||||
var instPath:String = Paths.inst(targetChart.song.id);
|
||||
var voicesPaths:Array<String> = targetChart.buildVoiceList();
|
||||
|
||||
|
@ -172,25 +181,36 @@ class LoadingState extends MusicBeatState
|
|||
return Paths.inst(PlayState.instance.currentSong.id);
|
||||
}
|
||||
|
||||
inline static public function loadAndSwitchState(nextState:NextState, shouldStopMusic = false):Void
|
||||
{
|
||||
FlxG.switchState(getNextState(nextState, shouldStopMusic));
|
||||
}
|
||||
|
||||
static function getNextState(nextState:NextState, shouldStopMusic = false):NextState
|
||||
/**
|
||||
* Starts the transition to a new `PlayState` to start a new song.
|
||||
* First switches to the `LoadingState` if assets need to be loaded.
|
||||
* @param params The parameters for the next `PlayState`.
|
||||
* @param shouldStopMusic Whether to stop the current music while loading.
|
||||
*/
|
||||
public static function loadPlayState(params:PlayStateParams, shouldStopMusic = false):Void
|
||||
{
|
||||
Paths.setCurrentLevel(PlayStatePlaylist.campaignId);
|
||||
var playStateCtor:NextState = () -> new PlayState(params);
|
||||
|
||||
#if NO_PRELOAD_ALL
|
||||
// var loaded = isSoundLoaded(getSongPath())
|
||||
// && (!PlayState.currentSong.needsVoices || isSoundLoaded(getVocalPath()))
|
||||
// && isLibraryLoaded('shared');
|
||||
//
|
||||
if (true) return () -> new LoadingState(nextState, shouldStopMusic);
|
||||
#end
|
||||
if (shouldStopMusic && FlxG.sound.music != null) FlxG.sound.music.stop();
|
||||
// Switch to loading state while we load assets (default on HTML5 target).
|
||||
var loadStateCtor:NextState = () -> new LoadingState(playStateCtor, shouldStopMusic, params);
|
||||
FlxG.switchState(loadStateCtor);
|
||||
#else
|
||||
// All assets preloaded, switch directly to play state (defualt on other targets).
|
||||
if (shouldStopMusic && FlxG.sound.music != null)
|
||||
{
|
||||
FlxG.sound.music.stop();
|
||||
}
|
||||
|
||||
return nextState;
|
||||
// Load and cache the song's charts.
|
||||
if (params?.targetSong != null)
|
||||
{
|
||||
params.targetSong.cacheCharts(true);
|
||||
}
|
||||
|
||||
FlxG.switchState(playStateCtor);
|
||||
#end
|
||||
}
|
||||
|
||||
#if NO_PRELOAD_ALL
|
||||
|
|
|
@ -20,6 +20,7 @@ class FileUtil
|
|||
{
|
||||
public static final FILE_FILTER_FNFC:FileFilter = new FileFilter("Friday Night Funkin' Chart (.fnfc)", "*.fnfc");
|
||||
public static final FILE_FILTER_ZIP:FileFilter = new FileFilter("ZIP Archive (.zip)", "*.zip");
|
||||
public static final FILE_FILTER_PNG:FileFilter = new FileFilter("PNG Image (.png)", "*.png");
|
||||
|
||||
public static final FILE_EXTENSION_INFO_FNFC:FileDialogExtensionInfo =
|
||||
{
|
||||
|
@ -31,6 +32,11 @@ class FileUtil
|
|||
extension: 'zip',
|
||||
label: 'ZIP Archive',
|
||||
};
|
||||
public static final FILE_EXTENSION_INFO_PNG:FileDialogExtensionInfo =
|
||||
{
|
||||
extension: 'png',
|
||||
label: 'PNG Image',
|
||||
};
|
||||
|
||||
/**
|
||||
* Browses for a single file, then calls `onSelect(fileInfo)` when a file is selected.
|
||||
|
@ -639,6 +645,23 @@ class FileUtil
|
|||
};
|
||||
}
|
||||
|
||||
public static function openFolder(pathFolder:String)
|
||||
{
|
||||
#if windows
|
||||
Sys.command('explorer', [pathFolder]);
|
||||
#elseif mac
|
||||
// mac could be fuckie with where the log folder is relative to the game file...
|
||||
// if this comment is still here... it means it has NOT been verified on mac yet!
|
||||
//
|
||||
// FileUtil.hx note: this was originally used to open the logs specifically!
|
||||
// thats why the above comment is there!
|
||||
Sys.command('open', [pathFolder]);
|
||||
#end
|
||||
|
||||
// TODO: implement linux
|
||||
// some shit with xdg-open :thinking: emoji...
|
||||
}
|
||||
|
||||
static function convertTypeFilter(typeFilter:Array<FileFilter>):String
|
||||
{
|
||||
var filter:String = null;
|
||||
|
|
|
@ -5,6 +5,12 @@ package funkin.util;
|
|||
*/
|
||||
class MathUtil
|
||||
{
|
||||
/**
|
||||
* Euler's constant and the base of the natural logarithm.
|
||||
* Math.E is not a constant in Haxe, so we'll just define it ourselves.
|
||||
*/
|
||||
public static final E:Float = 2.71828182845904523536;
|
||||
|
||||
/**
|
||||
* Perform linear interpolation between the base and the target, based on the current framerate.
|
||||
*/
|
||||
|
@ -24,8 +30,44 @@ class MathUtil
|
|||
* @param value The value to get the logarithm of.
|
||||
* @return `log_base(value)`
|
||||
*/
|
||||
public static function logBase(base:Float, value:Float):Float
|
||||
public static function logBase(base:Float, value:Float)
|
||||
{
|
||||
return Math.log(value) / Math.log(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `2^x`
|
||||
*/
|
||||
public static function exp2(x:Float)
|
||||
{
|
||||
return Math.pow(2, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly interpolate between two values.
|
||||
* @param base The starting value, when `progress <= 0`.
|
||||
* @param target The ending value, when `progress >= 1`.
|
||||
* @param progress Value used to interpolate between `base` and `target`.
|
||||
*/
|
||||
public static function lerp(base:Float, target:Float, progress:Float)
|
||||
{
|
||||
return base + progress * (target - base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a framerate-independent linear interpolation between the base value and the target.
|
||||
* @param current The current value.
|
||||
* @param target The target value.
|
||||
* @param elapsed The time elapsed since the last frame.
|
||||
* @param duration The total duration of the interpolation. Nominal duration until remaining distance is less than `precision`.
|
||||
* @param precision The target precision of the interpolation. Defaults to 1% of distance remaining.
|
||||
* @see https://twitter.com/FreyaHolmer/status/1757918211679650262
|
||||
*/
|
||||
public static function smoothLerp(current:Float, target:Float, elapsed:Float, duration:Float, precision:Float = 1 / 100):Float
|
||||
{
|
||||
// var halfLife:Float = -duration / logBase(2, precision);
|
||||
// lerp(current, target, 1 - exp2(-elapsed / halfLife));
|
||||
|
||||
return lerp(current, target, 1 - Math.pow(precision, elapsed / duration));
|
||||
}
|
||||
}
|
||||
|
|
320
source/funkin/util/plugins/ScreenshotPlugin.hx
Normal file
320
source/funkin/util/plugins/ScreenshotPlugin.hx
Normal file
|
@ -0,0 +1,320 @@
|
|||
package funkin.util.plugins;
|
||||
|
||||
import flixel.FlxBasic;
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxState;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxSignal;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
import funkin.input.Cursor;
|
||||
import openfl.display.Bitmap;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.display.PNGEncoderOptions;
|
||||
import openfl.geom.Matrix;
|
||||
import openfl.geom.Rectangle;
|
||||
import openfl.utils.ByteArray;
|
||||
import openfl.events.MouseEvent;
|
||||
|
||||
typedef ScreenshotPluginParams =
|
||||
{
|
||||
hotkeys:Array<FlxKey>,
|
||||
?region:Rectangle,
|
||||
shouldHideMouse:Bool,
|
||||
flashColor:Null<FlxColor>,
|
||||
fancyPreview:Bool,
|
||||
};
|
||||
|
||||
/**
|
||||
* What if `flixel.addons.plugin.screengrab.FlxScreenGrab` but it's better?
|
||||
* TODO: Contribute this upstream.
|
||||
*/
|
||||
class ScreenshotPlugin extends FlxBasic
|
||||
{
|
||||
public static final SCREENSHOT_FOLDER = 'screenshots';
|
||||
|
||||
var _hotkeys:Array<FlxKey>;
|
||||
|
||||
var _region:Null<Rectangle>;
|
||||
|
||||
var _shouldHideMouse:Bool;
|
||||
|
||||
var _flashColor:Null<FlxColor>;
|
||||
|
||||
var _fancyPreview:Bool;
|
||||
|
||||
/**
|
||||
* A signal fired before the screenshot is taken.
|
||||
*/
|
||||
public var onPreScreenshot(default, null):FlxTypedSignal<Void->Void>;
|
||||
|
||||
/**
|
||||
* A signal fired after the screenshot is taken.
|
||||
* @param bitmap The bitmap that was captured.
|
||||
*/
|
||||
public var onPostScreenshot(default, null):FlxTypedSignal<Bitmap->Void>;
|
||||
|
||||
public function new(params:ScreenshotPluginParams)
|
||||
{
|
||||
super();
|
||||
|
||||
_hotkeys = params.hotkeys;
|
||||
_region = params.region ?? null;
|
||||
_shouldHideMouse = params.shouldHideMouse;
|
||||
_flashColor = params.flashColor;
|
||||
_fancyPreview = params.fancyPreview;
|
||||
|
||||
onPreScreenshot = new FlxTypedSignal<Void->Void>();
|
||||
onPostScreenshot = new FlxTypedSignal<Bitmap->Void>();
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
if (hasPressedScreenshot())
|
||||
{
|
||||
capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the screenshot plugin.
|
||||
*/
|
||||
public static function initialize():Void
|
||||
{
|
||||
FlxG.plugins.addPlugin(new ScreenshotPlugin(
|
||||
{
|
||||
flashColor: Preferences.flashingLights ? FlxColor.WHITE : null, // Was originally a black flash.
|
||||
|
||||
// TODO: Add a way to configure screenshots from the options menu.
|
||||
hotkeys: [FlxKey.F3],
|
||||
shouldHideMouse: false,
|
||||
fancyPreview: true,
|
||||
}));
|
||||
}
|
||||
|
||||
public function hasPressedScreenshot():Bool
|
||||
{
|
||||
return PlayerSettings.player1.controls.SCREENSHOT;
|
||||
}
|
||||
|
||||
public function updatePreferences():Void
|
||||
{
|
||||
_flashColor = Preferences.flashingLights ? FlxColor.WHITE : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the region of the screen that should be captured.
|
||||
* You don't need to call this method if you want to capture the entire screen, that's the default behavior.
|
||||
*/
|
||||
public function defineCaptureRegion(x:Int, y:Int, width:Int, height:Int):Void
|
||||
{
|
||||
_region = new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture the game screen as a bitmap.
|
||||
*/
|
||||
public function capture():Void
|
||||
{
|
||||
onPreScreenshot.dispatch();
|
||||
|
||||
var captureRegion = _region != null ? _region : new Rectangle(0, 0, FlxG.stage.stageWidth, FlxG.stage.stageHeight);
|
||||
|
||||
var wasMouseHidden = false;
|
||||
if (_shouldHideMouse && FlxG.mouse.visible)
|
||||
{
|
||||
wasMouseHidden = true;
|
||||
Cursor.hide();
|
||||
}
|
||||
|
||||
// The actual work.
|
||||
// var bitmap = new Bitmap(new BitmapData(Math.floor(captureRegion.width), Math.floor(captureRegion.height), true, 0x00000000)); // Create a transparent empty bitmap.
|
||||
// var drawMatrix = new Matrix(1, 0, 0, 1, -captureRegion.x, -captureRegion.y); // Modifying this will scale or skew the bitmap.
|
||||
// bitmap.bitmapData.draw(FlxG.stage, drawMatrix);
|
||||
var bitmap = new Bitmap(BitmapData.fromImage(FlxG.stage.window.readPixels()));
|
||||
|
||||
if (wasMouseHidden)
|
||||
{
|
||||
Cursor.show();
|
||||
}
|
||||
|
||||
// Save the bitmap to a file.
|
||||
saveScreenshot(bitmap);
|
||||
|
||||
// Show some feedback.
|
||||
showCaptureFeedback();
|
||||
if (_fancyPreview)
|
||||
{
|
||||
showFancyPreview(bitmap);
|
||||
}
|
||||
|
||||
onPostScreenshot.dispatch(bitmap);
|
||||
}
|
||||
|
||||
final CAMERA_FLASH_DURATION = 0.25;
|
||||
|
||||
/**
|
||||
* Visual (and audio?) feedback when a screenshot is taken.
|
||||
*/
|
||||
function showCaptureFeedback():Void
|
||||
{
|
||||
var flashBitmap = new Bitmap(new BitmapData(Std.int(FlxG.stage.width), Std.int(FlxG.stage.height), false, 0xFFFFFFFF));
|
||||
var flashSpr = new Sprite();
|
||||
flashSpr.addChild(flashBitmap);
|
||||
FlxG.stage.addChild(flashSpr);
|
||||
FlxTween.tween(flashSpr, {alpha: 0}, 0.15, {ease: FlxEase.quadOut, onComplete: _ -> FlxG.stage.removeChild(flashSpr)});
|
||||
}
|
||||
|
||||
static final PREVIEW_INITIAL_DELAY = 0.25; // How long before the preview starts fading in.
|
||||
static final PREVIEW_FADE_IN_DURATION = 0.3; // How long the preview takes to fade in.
|
||||
static final PREVIEW_FADE_OUT_DELAY = 1.25; // How long the preview stays on screen.
|
||||
static final PREVIEW_FADE_OUT_DURATION = 0.3; // How long the preview takes to fade out.
|
||||
|
||||
function showFancyPreview(bitmap:Bitmap):Void
|
||||
{
|
||||
// ermmm stealing this??
|
||||
var wasMouseHidden = false;
|
||||
if (!FlxG.mouse.visible)
|
||||
{
|
||||
wasMouseHidden = true;
|
||||
Cursor.show();
|
||||
}
|
||||
|
||||
// so that it doesnt change the alpha when tweening in/out
|
||||
var changingAlpha:Bool = false;
|
||||
|
||||
// fuck it, cursed locally scoped functions, purely because im lazy
|
||||
// (and so we can check changingAlpha, which is locally scoped.... because I'm lazy...)
|
||||
var onHover = function(e:MouseEvent) {
|
||||
if (!changingAlpha) e.target.alpha = 0.6;
|
||||
};
|
||||
|
||||
var onHoverOut = function(e:MouseEvent) {
|
||||
if (!changingAlpha) e.target.alpha = 1;
|
||||
}
|
||||
|
||||
var scale:Float = 0.25;
|
||||
var w:Int = Std.int(bitmap.bitmapData.width * scale);
|
||||
var h:Int = Std.int(bitmap.bitmapData.height * scale);
|
||||
|
||||
var preview:BitmapData = new BitmapData(w, h, true);
|
||||
var matrix:openfl.geom.Matrix = new openfl.geom.Matrix();
|
||||
matrix.scale(scale, scale);
|
||||
preview.draw(bitmap.bitmapData, matrix);
|
||||
|
||||
// used for movement + button stuff
|
||||
var previewSprite = new Sprite();
|
||||
|
||||
previewSprite.buttonMode = true;
|
||||
previewSprite.addEventListener(MouseEvent.MOUSE_DOWN, openScreenshotsFolder);
|
||||
previewSprite.addEventListener(MouseEvent.MOUSE_OVER, onHover);
|
||||
previewSprite.addEventListener(MouseEvent.MOUSE_OUT, onHoverOut);
|
||||
|
||||
FlxG.stage.addChild(previewSprite);
|
||||
|
||||
previewSprite.alpha = 0.0;
|
||||
previewSprite.y -= 10;
|
||||
|
||||
var previewBitmap = new Bitmap(preview);
|
||||
previewSprite.addChild(previewBitmap);
|
||||
|
||||
// Wait to fade in.
|
||||
new FlxTimer().start(PREVIEW_INITIAL_DELAY, function(_) {
|
||||
// Fade in.
|
||||
changingAlpha = true;
|
||||
FlxTween.tween(previewSprite, {alpha: 1.0, y: 0}, PREVIEW_FADE_IN_DURATION,
|
||||
{
|
||||
ease: FlxEase.quartOut,
|
||||
onComplete: function(_) {
|
||||
changingAlpha = false;
|
||||
// Wait to fade out.
|
||||
new FlxTimer().start(PREVIEW_FADE_OUT_DELAY, function(_) {
|
||||
changingAlpha = true;
|
||||
// Fade out.
|
||||
FlxTween.tween(previewSprite, {alpha: 0.0, y: 10}, PREVIEW_FADE_OUT_DURATION,
|
||||
{
|
||||
ease: FlxEase.quartInOut,
|
||||
onComplete: function(_) {
|
||||
if (wasMouseHidden)
|
||||
{
|
||||
Cursor.hide();
|
||||
}
|
||||
|
||||
previewSprite.removeEventListener(MouseEvent.MOUSE_DOWN, openScreenshotsFolder);
|
||||
previewSprite.removeEventListener(MouseEvent.MOUSE_OVER, onHover);
|
||||
previewSprite.removeEventListener(MouseEvent.MOUSE_OUT, onHoverOut);
|
||||
|
||||
FlxG.stage.removeChild(previewSprite);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openScreenshotsFolder(e:MouseEvent):Void
|
||||
{
|
||||
FileUtil.openFolder(SCREENSHOT_FOLDER);
|
||||
}
|
||||
|
||||
static function getCurrentState():FlxState
|
||||
{
|
||||
var state = FlxG.state;
|
||||
while (state.subState != null)
|
||||
{
|
||||
state = state.subState;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static function getScreenshotPath():String
|
||||
{
|
||||
return '$SCREENSHOT_FOLDER/screenshot-${DateUtil.generateTimestamp()}.png';
|
||||
}
|
||||
|
||||
static function makeScreenshotPath():Void
|
||||
{
|
||||
FileUtil.createDirIfNotExists(SCREENSHOT_FOLDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Bitmap to a PNG ByteArray to save to a file.
|
||||
*/
|
||||
static function encodePNG(bitmap:Bitmap):ByteArray
|
||||
{
|
||||
return bitmap.bitmapData.encode(bitmap.bitmapData.rect, new PNGEncoderOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the generated bitmap to a file.
|
||||
* @param bitmap The bitmap to save.
|
||||
*/
|
||||
static function saveScreenshot(bitmap:Bitmap)
|
||||
{
|
||||
makeScreenshotPath();
|
||||
var targetPath:String = getScreenshotPath();
|
||||
|
||||
var pngData = encodePNG(bitmap);
|
||||
|
||||
if (pngData == null)
|
||||
{
|
||||
trace('[WARN] Failed to encode PNG data.');
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Saving screenshot to: ' + targetPath);
|
||||
// TODO: Make this work on browser.
|
||||
FileUtil.writeBytesToPath(targetPath, pngData);
|
||||
}
|
||||
}
|
||||
}
|
34
source/funkin/util/plugins/VolumePlugin.hx
Normal file
34
source/funkin/util/plugins/VolumePlugin.hx
Normal file
|
@ -0,0 +1,34 @@
|
|||
package funkin.util.plugins;
|
||||
|
||||
import flixel.FlxBasic;
|
||||
|
||||
/**
|
||||
* Handles volume control in a way that is compatible with alternate control schemes.
|
||||
*/
|
||||
class VolumePlugin extends FlxBasic
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public static function initialize()
|
||||
{
|
||||
FlxG.plugins.addPlugin(new VolumePlugin());
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
|
||||
|
||||
if (!isHaxeUIFocused)
|
||||
{
|
||||
// Rebindable volume keys.
|
||||
if (PlayerSettings.player1.controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
|
||||
else if (PlayerSettings.player1.controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
|
||||
else if (PlayerSettings.player1.controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue