mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-12-02 04:17:07 -05:00
Merge branch 'rewrite/master' of https://github.com/FunkinCrew/Funkin-secret into feature/focusCameraTweening
This commit is contained in:
commit
db80bba100
25 changed files with 1129 additions and 480 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 84b1574294e7a7af21adf1a0e4894c88431ca43d
|
Subproject commit 8b914574fc4724c5fe483f4f9d81081bb1518c12
|
4
hmm.json
4
hmm.json
|
@ -73,8 +73,8 @@
|
||||||
"name": "hxCodec",
|
"name": "hxCodec",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "c8c47e706ad82a423783006ed901b6d93c89a421",
|
"ref": "387e1665d6feb5762358134f168e6ebfe46acec8",
|
||||||
"url": "https://github.com/polybiusproxy/hxCodec"
|
"url": "https://github.com/FunkinCrew/hxCodec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "hxcpp",
|
"name": "hxcpp",
|
||||||
|
|
|
@ -202,6 +202,9 @@ class InitState extends FlxState
|
||||||
// Plugins provide a useful interface for globally active Flixel objects,
|
// Plugins provide a useful interface for globally active Flixel objects,
|
||||||
// that receive update events regardless of the current state.
|
// that receive update events regardless of the current state.
|
||||||
// TODO: Move scripted Module behavior to a Flixel plugin.
|
// TODO: Move scripted Module behavior to a Flixel plugin.
|
||||||
|
#if debug
|
||||||
|
funkin.util.plugins.MemoryGCPlugin.initialize();
|
||||||
|
#end
|
||||||
funkin.util.plugins.EvacuateDebugPlugin.initialize();
|
funkin.util.plugins.EvacuateDebugPlugin.initialize();
|
||||||
funkin.util.plugins.ForceCrashPlugin.initialize();
|
funkin.util.plugins.ForceCrashPlugin.initialize();
|
||||||
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
|
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
|
||||||
|
|
|
@ -25,6 +25,9 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
{
|
{
|
||||||
static final MAX_VOLUME:Float = 1.0;
|
static final MAX_VOLUME:Float = 1.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using `FunkinSound.load` will override a dead instance from here rather than creating a new one, if possible!
|
||||||
|
*/
|
||||||
static var cache(default, null):FlxTypedGroup<FunkinSound> = new FlxTypedGroup<FunkinSound>();
|
static var cache(default, null):FlxTypedGroup<FunkinSound> = new FlxTypedGroup<FunkinSound>();
|
||||||
|
|
||||||
public var muted(default, set):Bool = false;
|
public var muted(default, set):Bool = false;
|
||||||
|
@ -174,10 +177,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
*/
|
*/
|
||||||
override function onFocus():Void
|
override function onFocus():Void
|
||||||
{
|
{
|
||||||
if (!_alreadyPaused && this._shouldPlay)
|
if (!_alreadyPaused)
|
||||||
{
|
{
|
||||||
resume();
|
resume();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Not resuming audio on focus!');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,6 +192,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
*/
|
*/
|
||||||
override function onFocusLost():Void
|
override function onFocusLost():Void
|
||||||
{
|
{
|
||||||
|
trace('Focus lost, pausing audio!');
|
||||||
_alreadyPaused = _paused;
|
_alreadyPaused = _paused;
|
||||||
pause();
|
pause();
|
||||||
}
|
}
|
||||||
|
@ -252,6 +260,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
{
|
{
|
||||||
var sound:FunkinSound = cache.recycle(construct);
|
var sound:FunkinSound = cache.recycle(construct);
|
||||||
|
|
||||||
|
// Load the sound.
|
||||||
|
// Sets `exists = true` as a side effect.
|
||||||
sound.loadEmbedded(embeddedSound, looped, autoDestroy, onComplete);
|
sound.loadEmbedded(embeddedSound, looped, autoDestroy, onComplete);
|
||||||
|
|
||||||
if (embeddedSound is String)
|
if (embeddedSound is String)
|
||||||
|
|
|
@ -80,8 +80,9 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
|
||||||
|
|
||||||
// We have to play, then pause the sound to set the time,
|
// We have to play, then pause the sound to set the time,
|
||||||
// else the sound will restart immediately when played.
|
// else the sound will restart immediately when played.
|
||||||
result.play(true, 0.0);
|
// TODO: Past me experienced that issue but present me didn't? Investigate.
|
||||||
result.pause();
|
// result.play(true, 0.0);
|
||||||
|
// result.pause();
|
||||||
result.time = this.time;
|
result.time = this.time;
|
||||||
|
|
||||||
result.onComplete = function() {
|
result.onComplete = function() {
|
||||||
|
|
|
@ -40,6 +40,32 @@ class FlxVideo extends FlxBasic
|
||||||
netStream.play(videoPath);
|
netStream.play(videoPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pauseVideo():Void
|
||||||
|
{
|
||||||
|
if (netStream != null)
|
||||||
|
{
|
||||||
|
netStream.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resumeVideo():Void
|
||||||
|
{
|
||||||
|
// Resume playing the video.
|
||||||
|
if (netStream != null)
|
||||||
|
{
|
||||||
|
netStream.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restartVideo():Void
|
||||||
|
{
|
||||||
|
// Seek to the beginning of the video.
|
||||||
|
if (netStream != null)
|
||||||
|
{
|
||||||
|
netStream.seek(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function finishVideo():Void
|
public function finishVideo():Void
|
||||||
{
|
{
|
||||||
netStream.dispose();
|
netStream.dispose();
|
||||||
|
|
|
@ -58,12 +58,11 @@ class Controls extends FlxActionSet
|
||||||
var _back = new FlxActionDigital(Action.BACK);
|
var _back = new FlxActionDigital(Action.BACK);
|
||||||
var _pause = new FlxActionDigital(Action.PAUSE);
|
var _pause = new FlxActionDigital(Action.PAUSE);
|
||||||
var _reset = new FlxActionDigital(Action.RESET);
|
var _reset = new FlxActionDigital(Action.RESET);
|
||||||
|
var _screenshot = new FlxActionDigital(Action.SCREENSHOT);
|
||||||
var _cutscene_advance = new FlxActionDigital(Action.CUTSCENE_ADVANCE);
|
var _cutscene_advance = new FlxActionDigital(Action.CUTSCENE_ADVANCE);
|
||||||
var _cutscene_skip = new FlxActionDigital(Action.CUTSCENE_SKIP);
|
|
||||||
var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU);
|
var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU);
|
||||||
var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART);
|
var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART);
|
||||||
var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE);
|
var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE);
|
||||||
var _screenshot = new FlxActionDigital(Action.SCREENSHOT);
|
|
||||||
var _volume_up = new FlxActionDigital(Action.VOLUME_UP);
|
var _volume_up = new FlxActionDigital(Action.VOLUME_UP);
|
||||||
var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN);
|
var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN);
|
||||||
var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE);
|
var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE);
|
||||||
|
@ -208,16 +207,21 @@ class Controls extends FlxActionSet
|
||||||
inline function get_PAUSE()
|
inline function get_PAUSE()
|
||||||
return _pause.check();
|
return _pause.check();
|
||||||
|
|
||||||
|
public var RESET(get, never):Bool;
|
||||||
|
|
||||||
|
inline function get_RESET()
|
||||||
|
return _reset.check();
|
||||||
|
|
||||||
|
public var SCREENSHOT(get, never):Bool;
|
||||||
|
|
||||||
|
inline function get_SCREENSHOT()
|
||||||
|
return _screenshot.check();
|
||||||
|
|
||||||
public var CUTSCENE_ADVANCE(get, never):Bool;
|
public var CUTSCENE_ADVANCE(get, never):Bool;
|
||||||
|
|
||||||
inline function get_CUTSCENE_ADVANCE()
|
inline function get_CUTSCENE_ADVANCE()
|
||||||
return _cutscene_advance.check();
|
return _cutscene_advance.check();
|
||||||
|
|
||||||
public var CUTSCENE_SKIP(get, never):Bool;
|
|
||||||
|
|
||||||
inline function get_CUTSCENE_SKIP()
|
|
||||||
return _cutscene_skip.check();
|
|
||||||
|
|
||||||
public var DEBUG_MENU(get, never):Bool;
|
public var DEBUG_MENU(get, never):Bool;
|
||||||
|
|
||||||
inline function get_DEBUG_MENU()
|
inline function get_DEBUG_MENU()
|
||||||
|
@ -233,11 +237,6 @@ class Controls extends FlxActionSet
|
||||||
inline function get_DEBUG_STAGE()
|
inline function get_DEBUG_STAGE()
|
||||||
return _debug_stage.check();
|
return _debug_stage.check();
|
||||||
|
|
||||||
public var SCREENSHOT(get, never):Bool;
|
|
||||||
|
|
||||||
inline function get_SCREENSHOT()
|
|
||||||
return _screenshot.check();
|
|
||||||
|
|
||||||
public var VOLUME_UP(get, never):Bool;
|
public var VOLUME_UP(get, never):Bool;
|
||||||
|
|
||||||
inline function get_VOLUME_UP()
|
inline function get_VOLUME_UP()
|
||||||
|
@ -253,11 +252,6 @@ class Controls extends FlxActionSet
|
||||||
inline function get_VOLUME_MUTE()
|
inline function get_VOLUME_MUTE()
|
||||||
return _volume_mute.check();
|
return _volume_mute.check();
|
||||||
|
|
||||||
public var RESET(get, never):Bool;
|
|
||||||
|
|
||||||
inline function get_RESET()
|
|
||||||
return _reset.check();
|
|
||||||
|
|
||||||
public function new(name, scheme:KeyboardScheme = null)
|
public function new(name, scheme:KeyboardScheme = null)
|
||||||
{
|
{
|
||||||
super(name);
|
super(name);
|
||||||
|
@ -289,16 +283,15 @@ class Controls extends FlxActionSet
|
||||||
add(_accept);
|
add(_accept);
|
||||||
add(_back);
|
add(_back);
|
||||||
add(_pause);
|
add(_pause);
|
||||||
|
add(_reset);
|
||||||
|
add(_screenshot);
|
||||||
add(_cutscene_advance);
|
add(_cutscene_advance);
|
||||||
add(_cutscene_skip);
|
|
||||||
add(_debug_menu);
|
add(_debug_menu);
|
||||||
add(_debug_chart);
|
add(_debug_chart);
|
||||||
add(_debug_stage);
|
add(_debug_stage);
|
||||||
add(_screenshot);
|
|
||||||
add(_volume_up);
|
add(_volume_up);
|
||||||
add(_volume_down);
|
add(_volume_down);
|
||||||
add(_volume_mute);
|
add(_volume_mute);
|
||||||
add(_reset);
|
|
||||||
|
|
||||||
for (action in digitalActions)
|
for (action in digitalActions)
|
||||||
byName[action.name] = action;
|
byName[action.name] = action;
|
||||||
|
@ -383,12 +376,11 @@ class Controls extends FlxActionSet
|
||||||
case BACK: _back;
|
case BACK: _back;
|
||||||
case PAUSE: _pause;
|
case PAUSE: _pause;
|
||||||
case RESET: _reset;
|
case RESET: _reset;
|
||||||
|
case SCREENSHOT: _screenshot;
|
||||||
case CUTSCENE_ADVANCE: _cutscene_advance;
|
case CUTSCENE_ADVANCE: _cutscene_advance;
|
||||||
case CUTSCENE_SKIP: _cutscene_skip;
|
|
||||||
case DEBUG_MENU: _debug_menu;
|
case DEBUG_MENU: _debug_menu;
|
||||||
case DEBUG_CHART: _debug_chart;
|
case DEBUG_CHART: _debug_chart;
|
||||||
case DEBUG_STAGE: _debug_stage;
|
case DEBUG_STAGE: _debug_stage;
|
||||||
case SCREENSHOT: _screenshot;
|
|
||||||
case VOLUME_UP: _volume_up;
|
case VOLUME_UP: _volume_up;
|
||||||
case VOLUME_DOWN: _volume_down;
|
case VOLUME_DOWN: _volume_down;
|
||||||
case VOLUME_MUTE: _volume_mute;
|
case VOLUME_MUTE: _volume_mute;
|
||||||
|
@ -449,26 +441,24 @@ class Controls extends FlxActionSet
|
||||||
func(_back, JUST_PRESSED);
|
func(_back, JUST_PRESSED);
|
||||||
case PAUSE:
|
case PAUSE:
|
||||||
func(_pause, JUST_PRESSED);
|
func(_pause, JUST_PRESSED);
|
||||||
|
case RESET:
|
||||||
|
func(_reset, JUST_PRESSED);
|
||||||
|
case SCREENSHOT:
|
||||||
|
func(_screenshot, JUST_PRESSED);
|
||||||
case CUTSCENE_ADVANCE:
|
case CUTSCENE_ADVANCE:
|
||||||
func(_cutscene_advance, JUST_PRESSED);
|
func(_cutscene_advance, JUST_PRESSED);
|
||||||
case CUTSCENE_SKIP:
|
|
||||||
func(_cutscene_skip, PRESSED);
|
|
||||||
case DEBUG_MENU:
|
case DEBUG_MENU:
|
||||||
func(_debug_menu, JUST_PRESSED);
|
func(_debug_menu, JUST_PRESSED);
|
||||||
case DEBUG_CHART:
|
case DEBUG_CHART:
|
||||||
func(_debug_chart, JUST_PRESSED);
|
func(_debug_chart, JUST_PRESSED);
|
||||||
case DEBUG_STAGE:
|
case DEBUG_STAGE:
|
||||||
func(_debug_stage, JUST_PRESSED);
|
func(_debug_stage, JUST_PRESSED);
|
||||||
case SCREENSHOT:
|
|
||||||
func(_screenshot, JUST_PRESSED);
|
|
||||||
case VOLUME_UP:
|
case VOLUME_UP:
|
||||||
func(_volume_up, JUST_PRESSED);
|
func(_volume_up, JUST_PRESSED);
|
||||||
case VOLUME_DOWN:
|
case VOLUME_DOWN:
|
||||||
func(_volume_down, JUST_PRESSED);
|
func(_volume_down, JUST_PRESSED);
|
||||||
case VOLUME_MUTE:
|
case VOLUME_MUTE:
|
||||||
func(_volume_mute, JUST_PRESSED);
|
func(_volume_mute, JUST_PRESSED);
|
||||||
case RESET:
|
|
||||||
func(_reset, JUST_PRESSED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,13 +644,12 @@ class Controls extends FlxActionSet
|
||||||
bindKeys(Control.ACCEPT, getDefaultKeybinds(scheme, Control.ACCEPT));
|
bindKeys(Control.ACCEPT, getDefaultKeybinds(scheme, Control.ACCEPT));
|
||||||
bindKeys(Control.BACK, getDefaultKeybinds(scheme, Control.BACK));
|
bindKeys(Control.BACK, getDefaultKeybinds(scheme, Control.BACK));
|
||||||
bindKeys(Control.PAUSE, getDefaultKeybinds(scheme, Control.PAUSE));
|
bindKeys(Control.PAUSE, getDefaultKeybinds(scheme, Control.PAUSE));
|
||||||
|
bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET));
|
||||||
|
bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT));
|
||||||
bindKeys(Control.CUTSCENE_ADVANCE, getDefaultKeybinds(scheme, Control.CUTSCENE_ADVANCE));
|
bindKeys(Control.CUTSCENE_ADVANCE, getDefaultKeybinds(scheme, Control.CUTSCENE_ADVANCE));
|
||||||
bindKeys(Control.CUTSCENE_SKIP, getDefaultKeybinds(scheme, Control.CUTSCENE_SKIP));
|
|
||||||
bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
|
bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
|
||||||
bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
|
bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
|
||||||
bindKeys(Control.DEBUG_STAGE, getDefaultKeybinds(scheme, Control.DEBUG_STAGE));
|
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_UP, getDefaultKeybinds(scheme, Control.VOLUME_UP));
|
||||||
bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN));
|
bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN));
|
||||||
bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE));
|
bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE));
|
||||||
|
@ -683,16 +672,15 @@ class Controls extends FlxActionSet
|
||||||
case Control.ACCEPT: return [Z, SPACE, ENTER];
|
case Control.ACCEPT: return [Z, SPACE, ENTER];
|
||||||
case Control.BACK: return [X, BACKSPACE, ESCAPE];
|
case Control.BACK: return [X, BACKSPACE, ESCAPE];
|
||||||
case Control.PAUSE: return [P, ENTER, ESCAPE];
|
case Control.PAUSE: return [P, ENTER, ESCAPE];
|
||||||
|
case Control.RESET: return [R];
|
||||||
|
case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen
|
||||||
case Control.CUTSCENE_ADVANCE: return [Z, ENTER];
|
case Control.CUTSCENE_ADVANCE: return [Z, ENTER];
|
||||||
case Control.CUTSCENE_SKIP: return [P, ESCAPE];
|
|
||||||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||||
case Control.DEBUG_CHART: return [];
|
case Control.DEBUG_CHART: return [];
|
||||||
case Control.DEBUG_STAGE: 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_UP: return [PLUS, NUMPADPLUS];
|
||||||
case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
|
case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
|
||||||
case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
|
case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
|
||||||
case Control.RESET: return [R];
|
|
||||||
}
|
}
|
||||||
case Duo(true):
|
case Duo(true):
|
||||||
switch (control) {
|
switch (control) {
|
||||||
|
@ -707,16 +695,15 @@ class Controls extends FlxActionSet
|
||||||
case Control.ACCEPT: return [G, Z];
|
case Control.ACCEPT: return [G, Z];
|
||||||
case Control.BACK: return [H, X];
|
case Control.BACK: return [H, X];
|
||||||
case Control.PAUSE: return [ONE];
|
case Control.PAUSE: return [ONE];
|
||||||
|
case Control.RESET: return [R];
|
||||||
|
case Control.SCREENSHOT: return [PRINTSCREEN];
|
||||||
case Control.CUTSCENE_ADVANCE: return [G, Z];
|
case Control.CUTSCENE_ADVANCE: return [G, Z];
|
||||||
case Control.CUTSCENE_SKIP: return [ONE];
|
|
||||||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||||
case Control.DEBUG_CHART: return [];
|
case Control.DEBUG_CHART: return [];
|
||||||
case Control.DEBUG_STAGE: return [];
|
case Control.DEBUG_STAGE: return [];
|
||||||
case Control.SCREENSHOT: return [PRINTSCREEN];
|
|
||||||
case Control.VOLUME_UP: return [PLUS];
|
case Control.VOLUME_UP: return [PLUS];
|
||||||
case Control.VOLUME_DOWN: return [MINUS];
|
case Control.VOLUME_DOWN: return [MINUS];
|
||||||
case Control.VOLUME_MUTE: return [ZERO];
|
case Control.VOLUME_MUTE: return [ZERO];
|
||||||
case Control.RESET: return [R];
|
|
||||||
}
|
}
|
||||||
case Duo(false):
|
case Duo(false):
|
||||||
switch (control) {
|
switch (control) {
|
||||||
|
@ -731,16 +718,15 @@ class Controls extends FlxActionSet
|
||||||
case Control.ACCEPT: return [ENTER];
|
case Control.ACCEPT: return [ENTER];
|
||||||
case Control.BACK: return [ESCAPE];
|
case Control.BACK: return [ESCAPE];
|
||||||
case Control.PAUSE: return [ONE];
|
case Control.PAUSE: return [ONE];
|
||||||
|
case Control.RESET: return [R];
|
||||||
|
case Control.SCREENSHOT: return [PRINTSCREEN];
|
||||||
case Control.CUTSCENE_ADVANCE: return [ENTER];
|
case Control.CUTSCENE_ADVANCE: return [ENTER];
|
||||||
case Control.CUTSCENE_SKIP: return [ONE];
|
|
||||||
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
case Control.DEBUG_MENU: return [GRAVEACCENT];
|
||||||
case Control.DEBUG_CHART: return [];
|
case Control.DEBUG_CHART: return [];
|
||||||
case Control.DEBUG_STAGE: return [];
|
case Control.DEBUG_STAGE: return [];
|
||||||
case Control.SCREENSHOT: return [PRINTSCREEN];
|
|
||||||
case Control.VOLUME_UP: return [NUMPADPLUS];
|
case Control.VOLUME_UP: return [NUMPADPLUS];
|
||||||
case Control.VOLUME_DOWN: return [NUMPADMINUS];
|
case Control.VOLUME_DOWN: return [NUMPADMINUS];
|
||||||
case Control.VOLUME_MUTE: return [NUMPADZERO];
|
case Control.VOLUME_MUTE: return [NUMPADZERO];
|
||||||
case Control.RESET: return [R];
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Fallthrough.
|
// Fallthrough.
|
||||||
|
@ -843,15 +829,14 @@ class Controls extends FlxActionSet
|
||||||
Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT),
|
Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT),
|
||||||
Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT),
|
Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT),
|
||||||
Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
|
Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
|
||||||
|
Control.RESET => getDefaultGamepadBinds(Control.RESET),
|
||||||
// Control.SCREENSHOT => [],
|
// Control.SCREENSHOT => [],
|
||||||
// Control.VOLUME_UP => [RIGHT_SHOULDER],
|
// Control.VOLUME_UP => [RIGHT_SHOULDER],
|
||||||
// Control.VOLUME_DOWN => [LEFT_SHOULDER],
|
// Control.VOLUME_DOWN => [LEFT_SHOULDER],
|
||||||
// Control.VOLUME_MUTE => [RIGHT_TRIGGER],
|
// Control.VOLUME_MUTE => [RIGHT_TRIGGER],
|
||||||
Control.CUTSCENE_ADVANCE => getDefaultGamepadBinds(Control.CUTSCENE_ADVANCE),
|
Control.CUTSCENE_ADVANCE => getDefaultGamepadBinds(Control.CUTSCENE_ADVANCE),
|
||||||
Control.CUTSCENE_SKIP => getDefaultGamepadBinds(Control.CUTSCENE_SKIP),
|
|
||||||
// Control.DEBUG_MENU
|
// Control.DEBUG_MENU
|
||||||
// Control.DEBUG_CHART
|
// Control.DEBUG_CHART
|
||||||
Control.RESET => getDefaultGamepadBinds(Control.RESET)
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,15 +853,14 @@ class Controls extends FlxActionSet
|
||||||
case Control.NOTE_LEFT: return [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT];
|
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.NOTE_RIGHT: return [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT];
|
||||||
case Control.PAUSE: return [START];
|
case Control.PAUSE: return [START];
|
||||||
|
case Control.RESET: return [RIGHT_SHOULDER];
|
||||||
case Control.SCREENSHOT: return [];
|
case Control.SCREENSHOT: return [];
|
||||||
case Control.VOLUME_UP: return [];
|
case Control.VOLUME_UP: return [];
|
||||||
case Control.VOLUME_DOWN: return [];
|
case Control.VOLUME_DOWN: return [];
|
||||||
case Control.VOLUME_MUTE: return [];
|
case Control.VOLUME_MUTE: return [];
|
||||||
case Control.CUTSCENE_ADVANCE: return [A];
|
case Control.CUTSCENE_ADVANCE: return [A];
|
||||||
case Control.CUTSCENE_SKIP: return [START];
|
|
||||||
case Control.DEBUG_MENU: return [];
|
case Control.DEBUG_MENU: return [];
|
||||||
case Control.DEBUG_CHART: return [];
|
case Control.DEBUG_CHART: return [];
|
||||||
case Control.RESET: return [RIGHT_SHOULDER];
|
|
||||||
default:
|
default:
|
||||||
// Fallthrough.
|
// Fallthrough.
|
||||||
}
|
}
|
||||||
|
@ -1228,14 +1212,13 @@ enum Control
|
||||||
UI_RIGHT;
|
UI_RIGHT;
|
||||||
UI_DOWN;
|
UI_DOWN;
|
||||||
RESET;
|
RESET;
|
||||||
|
SCREENSHOT;
|
||||||
ACCEPT;
|
ACCEPT;
|
||||||
BACK;
|
BACK;
|
||||||
PAUSE;
|
PAUSE;
|
||||||
// CUTSCENE
|
// CUTSCENE
|
||||||
CUTSCENE_ADVANCE;
|
CUTSCENE_ADVANCE;
|
||||||
CUTSCENE_SKIP;
|
|
||||||
// SCREENSHOT
|
// SCREENSHOT
|
||||||
SCREENSHOT;
|
|
||||||
// VOLUME
|
// VOLUME
|
||||||
VOLUME_UP;
|
VOLUME_UP;
|
||||||
VOLUME_DOWN;
|
VOLUME_DOWN;
|
||||||
|
@ -1279,15 +1262,14 @@ abstract Action(String) to String from String
|
||||||
var BACK = "back";
|
var BACK = "back";
|
||||||
var PAUSE = "pause";
|
var PAUSE = "pause";
|
||||||
var RESET = "reset";
|
var RESET = "reset";
|
||||||
|
// SCREENSHOT
|
||||||
|
var SCREENSHOT = "screenshot";
|
||||||
// CUTSCENE
|
// CUTSCENE
|
||||||
var CUTSCENE_ADVANCE = "cutscene_advance";
|
var CUTSCENE_ADVANCE = "cutscene_advance";
|
||||||
var CUTSCENE_SKIP = "cutscene_skip";
|
|
||||||
// VOLUME
|
// VOLUME
|
||||||
var VOLUME_UP = "volume_up";
|
var VOLUME_UP = "volume_up";
|
||||||
var VOLUME_DOWN = "volume_down";
|
var VOLUME_DOWN = "volume_down";
|
||||||
var VOLUME_MUTE = "volume_mute";
|
var VOLUME_MUTE = "volume_mute";
|
||||||
// SCREENSHOT
|
|
||||||
var SCREENSHOT = "screenshot";
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
var DEBUG_MENU = "debug_menu";
|
var DEBUG_MENU = "debug_menu";
|
||||||
var DEBUG_CHART = "debug_chart";
|
var DEBUG_CHART = "debug_chart";
|
||||||
|
|
|
@ -1,313 +1,736 @@
|
||||||
package funkin.play;
|
package funkin.play;
|
||||||
|
|
||||||
import funkin.play.PlayStatePlaylist;
|
|
||||||
import flixel.FlxSprite;
|
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.FlxG;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import flixel.util.FlxTimer;
|
||||||
import flixel.sound.FlxSound;
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import flixel.math.FlxMath;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.play.PlayState;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.ui.Alphabet;
|
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
|
import funkin.play.cutscene.VideoCutscene;
|
||||||
|
import funkin.play.PlayState;
|
||||||
|
import funkin.ui.AtlasText;
|
||||||
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import funkin.ui.transition.StickerSubState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for initializing the PauseSubState.
|
||||||
|
*/
|
||||||
|
typedef PauseSubStateParams =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Which mode to start in. Dictates what entries are displayed.
|
||||||
|
*/
|
||||||
|
?mode:PauseMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu displayed when the Play State is paused.
|
||||||
|
*/
|
||||||
class PauseSubState extends MusicBeatSubState
|
class PauseSubState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
var grpMenuShit:FlxTypedGroup<Alphabet>;
|
// ===============
|
||||||
|
// Constants
|
||||||
|
// ===============
|
||||||
|
|
||||||
final pauseOptionsBase:Array<String> = [
|
/**
|
||||||
'Resume',
|
* Pause menu entries for when the game is paused during a song.
|
||||||
'Restart Song',
|
*/
|
||||||
'Change Difficulty',
|
static final PAUSE_MENU_ENTRIES_STANDARD:Array<PauseMenuEntry> = [
|
||||||
'Toggle Practice Mode',
|
{text: 'Resume', callback: resume},
|
||||||
'Exit to Menu'
|
{text: 'Restart Song', callback: restartPlayState},
|
||||||
|
{text: 'Change Difficulty', callback: switchMode.bind(_, Difficulty)},
|
||||||
|
{text: 'Enable Practice Mode', callback: enablePracticeMode, filter: () -> !(PlayState.instance?.isPracticeMode ?? false)},
|
||||||
|
{text: 'Exit to Menu', callback: quitToMenu},
|
||||||
];
|
];
|
||||||
final pauseOptionsCharting:Array<String> = ['Resume', 'Restart Song', 'Exit to Chart Editor'];
|
|
||||||
|
|
||||||
final pauseOptionsDifficultyBase:Array<String> = ['BACK'];
|
/**
|
||||||
|
* Pause menu entries for when the game is paused in the Chart Editor preview.
|
||||||
|
*/
|
||||||
|
static final PAUSE_MENU_ENTRIES_CHARTING:Array<PauseMenuEntry> = [
|
||||||
|
{text: 'Resume', callback: resume},
|
||||||
|
{text: 'Restart Song', callback: restartPlayState},
|
||||||
|
{text: 'Return to Chart Editor', callback: quitToChartEditor},
|
||||||
|
];
|
||||||
|
|
||||||
var pauseOptionsDifficulty:Array<String> = []; // AUTO-POPULATED
|
/**
|
||||||
|
* Pause menu entries for when the user selects "Change Difficulty".
|
||||||
|
*/
|
||||||
|
static final PAUSE_MENU_ENTRIES_DIFFICULTY:Array<PauseMenuEntry> = [
|
||||||
|
{text: 'Back', callback: switchMode.bind(_, Standard)}
|
||||||
|
// Other entries are added dynamically.
|
||||||
|
];
|
||||||
|
|
||||||
var menuItems:Array<String> = [];
|
/**
|
||||||
var curSelected:Int = 0;
|
* Pause menu entries for when the game is paused during a video cutscene.
|
||||||
|
*/
|
||||||
|
static final PAUSE_MENU_ENTRIES_VIDEO_CUTSCENE:Array<PauseMenuEntry> = [
|
||||||
|
{text: 'Resume', callback: resume},
|
||||||
|
{text: 'Restart Cutscene', callback: restartVideoCutscene},
|
||||||
|
{text: 'Skip Cutscene', callback: skipVideoCutscene},
|
||||||
|
{text: 'Exit to Menu', callback: quitToMenu},
|
||||||
|
];
|
||||||
|
|
||||||
var pauseMusic:FlxSound;
|
/**
|
||||||
|
* Pause menu entries for when the game is paused during a conversation.
|
||||||
|
*/
|
||||||
|
static final PAUSE_MENU_ENTRIES_CONVERSATION:Array<PauseMenuEntry> = [
|
||||||
|
{text: 'Resume', callback: resume},
|
||||||
|
{text: 'Restart Dialogue', callback: restartConversation},
|
||||||
|
{text: 'Skip Dialogue', callback: skipConversation},
|
||||||
|
{text: 'Exit to Menu', callback: quitToMenu},
|
||||||
|
];
|
||||||
|
|
||||||
var practiceText:FlxText;
|
/**
|
||||||
|
* Duration for the music to fade in when the pause menu is opened.
|
||||||
|
*/
|
||||||
|
static final MUSIC_FADE_IN_TIME:Float = 5;
|
||||||
|
|
||||||
public var exitingToMenu:Bool = false;
|
/**
|
||||||
|
* The final volume for the music when the pause menu is opened.
|
||||||
|
*/
|
||||||
|
static final MUSIC_FINAL_VOLUME:Float = 0.75;
|
||||||
|
|
||||||
var bg:FlxSprite;
|
/**
|
||||||
var metaDataGrp:FlxTypedGroup<FlxSprite>;
|
* Defines which pause music to use.
|
||||||
|
*/
|
||||||
|
public static var musicSuffix:String = '';
|
||||||
|
|
||||||
var isChartingMode:Bool;
|
/**
|
||||||
|
* Reset the pause configuration to the default.
|
||||||
|
*/
|
||||||
|
public static function reset():Void
|
||||||
|
{
|
||||||
|
musicSuffix = '';
|
||||||
|
}
|
||||||
|
|
||||||
public function new(isChartingMode:Bool = false)
|
// ===============
|
||||||
|
// Status Variables
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disallow input until transitions are complete!
|
||||||
|
* This prevents the pause menu from immediately closing when opened, among other things.
|
||||||
|
*/
|
||||||
|
public var allowInput:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entries currently displayed in the pause menu.
|
||||||
|
*/
|
||||||
|
var currentMenuEntries:Array<PauseMenuEntry>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of `currentMenuEntries` that is currently selected.
|
||||||
|
*/
|
||||||
|
var currentEntry:Int = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mode that the pause menu is currently in.
|
||||||
|
*/
|
||||||
|
var currentMode:PauseMode;
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Graphics Variables
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The semi-transparent black background that appears when the game is paused.
|
||||||
|
*/
|
||||||
|
var background:FunkinSprite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The metadata displayed in the top right.
|
||||||
|
*/
|
||||||
|
var metadata:FlxTypedSpriteGroup<FlxText>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text object that displays the current practice mode status.
|
||||||
|
*/
|
||||||
|
var metadataPractice:FlxText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text object that displays the current death count.
|
||||||
|
*/
|
||||||
|
var metadataDeaths:FlxText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual text objects for the menu entries.
|
||||||
|
*/
|
||||||
|
var menuEntryText:FlxTypedSpriteGroup<AtlasText>;
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Audio Variables
|
||||||
|
// ===============
|
||||||
|
var pauseMusic:FunkinSound;
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Constructor
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
public function new(?params:PauseSubStateParams)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
this.currentMode = params?.mode ?? Standard;
|
||||||
this.isChartingMode = isChartingMode;
|
|
||||||
|
|
||||||
menuItems = this.isChartingMode ? pauseOptionsCharting : pauseOptionsBase;
|
|
||||||
var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation);
|
|
||||||
trace('DIFFICULTIES: ${difficultiesInVariation}');
|
|
||||||
|
|
||||||
pauseOptionsDifficulty = difficultiesInVariation.map(function(item:String):String {
|
|
||||||
return item.toUpperCase();
|
|
||||||
}).concat(pauseOptionsDifficultyBase);
|
|
||||||
|
|
||||||
if (PlayStatePlaylist.campaignId == 'week6')
|
|
||||||
{
|
|
||||||
pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast-pixel'), true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pauseMusic = new FlxSound().loadEmbedded(Paths.music('breakfast'), true, true);
|
|
||||||
}
|
|
||||||
pauseMusic.volume = 0;
|
|
||||||
pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
|
|
||||||
|
|
||||||
FlxG.sound.list.add(pauseMusic);
|
|
||||||
|
|
||||||
bg = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
|
|
||||||
bg.alpha = 0;
|
|
||||||
bg.scrollFactor.set();
|
|
||||||
add(bg);
|
|
||||||
|
|
||||||
metaDataGrp = new FlxTypedGroup<FlxSprite>();
|
|
||||||
add(metaDataGrp);
|
|
||||||
|
|
||||||
var levelInfo:FlxText = new FlxText(20, 15, 0, '', 32);
|
|
||||||
if (PlayState.instance.currentChart != null)
|
|
||||||
{
|
|
||||||
levelInfo.text += '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
|
|
||||||
}
|
|
||||||
levelInfo.scrollFactor.set();
|
|
||||||
levelInfo.setFormat(Paths.font('vcr.ttf'), 32);
|
|
||||||
levelInfo.updateHitbox();
|
|
||||||
metaDataGrp.add(levelInfo);
|
|
||||||
|
|
||||||
var levelDifficulty:FlxText = new FlxText(20, 15 + 32, 0, '', 32);
|
|
||||||
levelDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase();
|
|
||||||
levelDifficulty.scrollFactor.set();
|
|
||||||
levelDifficulty.setFormat(Paths.font('vcr.ttf'), 32);
|
|
||||||
levelDifficulty.updateHitbox();
|
|
||||||
metaDataGrp.add(levelDifficulty);
|
|
||||||
|
|
||||||
var deathCounter:FlxText = new FlxText(20, 15 + 64, 0, '', 32);
|
|
||||||
deathCounter.text = 'Blue balled: ${PlayState.instance.deathCounter}';
|
|
||||||
FlxG.watch.addQuick('totalNotesHit', Highscore.tallies.totalNotesHit);
|
|
||||||
FlxG.watch.addQuick('totalNotes', Highscore.tallies.totalNotes);
|
|
||||||
deathCounter.scrollFactor.set();
|
|
||||||
deathCounter.setFormat(Paths.font('vcr.ttf'), 32);
|
|
||||||
deathCounter.updateHitbox();
|
|
||||||
metaDataGrp.add(deathCounter);
|
|
||||||
|
|
||||||
practiceText = new FlxText(20, 15 + 64 + 32, 0, 'PRACTICE MODE', 32);
|
|
||||||
practiceText.scrollFactor.set();
|
|
||||||
practiceText.setFormat(Paths.font('vcr.ttf'), 32);
|
|
||||||
practiceText.updateHitbox();
|
|
||||||
practiceText.x = FlxG.width - (practiceText.width + 20);
|
|
||||||
practiceText.visible = PlayState.instance.isPracticeMode;
|
|
||||||
metaDataGrp.add(practiceText);
|
|
||||||
|
|
||||||
levelDifficulty.alpha = 0;
|
|
||||||
levelInfo.alpha = 0;
|
|
||||||
deathCounter.alpha = 0;
|
|
||||||
|
|
||||||
levelInfo.x = FlxG.width - (levelInfo.width + 20);
|
|
||||||
levelDifficulty.x = FlxG.width - (levelDifficulty.width + 20);
|
|
||||||
deathCounter.x = FlxG.width - (deathCounter.width + 20);
|
|
||||||
|
|
||||||
FlxTween.tween(bg, {alpha: 0.6}, 0.4, {ease: FlxEase.quartInOut});
|
|
||||||
FlxTween.tween(levelInfo, {alpha: 1, y: 20}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.3});
|
|
||||||
FlxTween.tween(levelDifficulty, {alpha: 1, y: levelDifficulty.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.5});
|
|
||||||
FlxTween.tween(deathCounter, {alpha: 1, y: deathCounter.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: 0.7});
|
|
||||||
|
|
||||||
grpMenuShit = new FlxTypedGroup<Alphabet>();
|
|
||||||
add(grpMenuShit);
|
|
||||||
|
|
||||||
regenMenu();
|
|
||||||
|
|
||||||
// cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function regenMenu():Void
|
// ===============
|
||||||
|
// Lifecycle Functions
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the state is first loaded.
|
||||||
|
*/
|
||||||
|
public override function create():Void
|
||||||
{
|
{
|
||||||
while (grpMenuShit.members.length > 0)
|
super.create();
|
||||||
{
|
|
||||||
grpMenuShit.remove(grpMenuShit.members[0], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in 0...menuItems.length)
|
startPauseMusic();
|
||||||
{
|
|
||||||
var songText:Alphabet = new Alphabet(0, (70 * i) + 30, menuItems[i], true, false);
|
|
||||||
songText.isMenuItem = true;
|
|
||||||
songText.targetY = i;
|
|
||||||
grpMenuShit.add(songText);
|
|
||||||
}
|
|
||||||
|
|
||||||
curSelected = 0;
|
buildBackground();
|
||||||
changeSelection();
|
|
||||||
|
buildMetadata();
|
||||||
|
|
||||||
|
regenerateMenu();
|
||||||
|
|
||||||
|
transitionIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
override function update(elapsed:Float):Void
|
/**
|
||||||
|
* Called every frame.
|
||||||
|
* @param elapsed The time elapsed since the last frame, in seconds.
|
||||||
|
*/
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
if (pauseMusic.volume < 0.5) pauseMusic.volume += 0.01 * elapsed;
|
|
||||||
|
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
|
||||||
handleInputs();
|
handleInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the state is closed.
|
||||||
|
*/
|
||||||
|
public override function destroy():Void
|
||||||
|
{
|
||||||
|
super.destroy();
|
||||||
|
pauseMusic.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Initialization Functions
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play the pause music.
|
||||||
|
*/
|
||||||
|
function startPauseMusic():Void
|
||||||
|
{
|
||||||
|
var pauseMusicPath:String = Paths.music('breakfast$musicSuffix');
|
||||||
|
pauseMusic = FunkinSound.load(pauseMusicPath, true, true);
|
||||||
|
|
||||||
|
if (pauseMusic == null)
|
||||||
|
{
|
||||||
|
FlxG.log.warn('Could not play pause music: ${pauseMusicPath} does not exist!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start playing at a random point in the song.
|
||||||
|
pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
|
||||||
|
pauseMusic.fadeIn(MUSIC_FADE_IN_TIME, 0, MUSIC_FINAL_VOLUME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the semi-transparent black background.
|
||||||
|
*/
|
||||||
|
function buildBackground():Void
|
||||||
|
{
|
||||||
|
// Using state.bgColor causes bugs!
|
||||||
|
background = new FunkinSprite(0, 0);
|
||||||
|
background.makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||||
|
background.alpha = 0.0;
|
||||||
|
background.scrollFactor.set(0, 0);
|
||||||
|
background.updateHitbox();
|
||||||
|
add(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the metadata in the top right.
|
||||||
|
*/
|
||||||
|
function buildMetadata():Void
|
||||||
|
{
|
||||||
|
metadata = new FlxTypedSpriteGroup<FlxText>();
|
||||||
|
metadata.scrollFactor.set(0, 0);
|
||||||
|
add(metadata);
|
||||||
|
|
||||||
|
var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name - Artist');
|
||||||
|
metadataSong.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
|
if (PlayState.instance?.currentChart != null)
|
||||||
|
{
|
||||||
|
metadataSong.text = '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
|
||||||
|
}
|
||||||
|
metadataSong.scrollFactor.set(0, 0);
|
||||||
|
metadata.add(metadataSong);
|
||||||
|
|
||||||
|
var metadataDifficulty:FlxText = new FlxText(20, 15 + 32, FlxG.width - 40, 'Difficulty: ');
|
||||||
|
metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
|
if (PlayState.instance?.currentDifficulty != null)
|
||||||
|
{
|
||||||
|
metadataDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase();
|
||||||
|
}
|
||||||
|
metadataDifficulty.scrollFactor.set(0, 0);
|
||||||
|
metadata.add(metadataDifficulty);
|
||||||
|
|
||||||
|
metadataDeaths = new FlxText(20, 15 + 64, FlxG.width - 40, '${PlayState.instance?.deathCounter} Blue Balls');
|
||||||
|
metadataDeaths.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
|
metadataDeaths.scrollFactor.set(0, 0);
|
||||||
|
metadata.add(metadataDeaths);
|
||||||
|
|
||||||
|
metadataPractice = new FlxText(20, 15 + 96, FlxG.width - 40, 'PRACTICE MODE');
|
||||||
|
metadataPractice.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
|
metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
|
||||||
|
metadataPractice.scrollFactor.set(0, 0);
|
||||||
|
metadata.add(metadataPractice);
|
||||||
|
|
||||||
|
updateMetadataText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform additional animations to transition the pause menu in when it is first displayed.
|
||||||
|
*/
|
||||||
|
function transitionIn():Void
|
||||||
|
{
|
||||||
|
FlxTween.tween(background, {alpha: 0.6}, 0.8, {ease: FlxEase.quartOut});
|
||||||
|
|
||||||
|
// Animate each element a little bit downwards.
|
||||||
|
var delay:Float = 0.1;
|
||||||
|
for (child in metadata.members)
|
||||||
|
{
|
||||||
|
FlxTween.tween(child, {alpha: 1, y: child.y + 5}, 1.8, {ease: FlxEase.quartOut, startDelay: delay});
|
||||||
|
delay += 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new FlxTimer().start(0.2, (_) -> {
|
||||||
|
allowInput = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Input Handling
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process user inputs every frame.
|
||||||
|
*/
|
||||||
function handleInputs():Void
|
function handleInputs():Void
|
||||||
{
|
{
|
||||||
var upP = controls.UI_UP_P;
|
if (!allowInput) return;
|
||||||
var downP = controls.UI_DOWN_P;
|
|
||||||
var accepted = controls.ACCEPT;
|
if (controls.UI_UP_P)
|
||||||
|
{
|
||||||
|
changeSelection(-1);
|
||||||
|
}
|
||||||
|
if (controls.UI_DOWN_P)
|
||||||
|
{
|
||||||
|
changeSelection(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controls.ACCEPT)
|
||||||
|
{
|
||||||
|
currentMenuEntries[currentEntry].callback(this);
|
||||||
|
}
|
||||||
|
else if (controls.PAUSE)
|
||||||
|
{
|
||||||
|
resume(this);
|
||||||
|
}
|
||||||
|
|
||||||
#if (debug || FORCE_DEBUG_VERSION)
|
#if (debug || FORCE_DEBUG_VERSION)
|
||||||
// to pause the game and get screenshots easy, press H on pause menu!
|
// to pause the game and get screenshots easy, press H on pause menu!
|
||||||
if (FlxG.keys.justPressed.H)
|
if (FlxG.keys.justPressed.H)
|
||||||
{
|
{
|
||||||
bg.visible = !bg.visible;
|
var visible = !metadata.visible;
|
||||||
grpMenuShit.visible = !grpMenuShit.visible;
|
|
||||||
metaDataGrp.visible = !metaDataGrp.visible;
|
metadata.visible = visible;
|
||||||
|
menuEntryText.visible = visible;
|
||||||
|
this.bgColor = visible ? 0x99000000 : 0x00000000; // 60% or fully transparent black
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
if (!exitingToMenu)
|
|
||||||
{
|
|
||||||
if (upP)
|
|
||||||
{
|
|
||||||
changeSelection(-1);
|
|
||||||
}
|
|
||||||
if (downP)
|
|
||||||
{
|
|
||||||
changeSelection(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
var androidPause:Bool = false;
|
|
||||||
|
|
||||||
#if android
|
|
||||||
androidPause = FlxG.android.justPressed.BACK;
|
|
||||||
#end
|
|
||||||
|
|
||||||
if (androidPause) close();
|
|
||||||
|
|
||||||
if (accepted)
|
|
||||||
{
|
|
||||||
var daSelected:String = menuItems[curSelected];
|
|
||||||
|
|
||||||
switch (daSelected)
|
|
||||||
{
|
|
||||||
case 'Resume':
|
|
||||||
close();
|
|
||||||
|
|
||||||
case 'Change Difficulty':
|
|
||||||
menuItems = pauseOptionsDifficulty;
|
|
||||||
regenMenu();
|
|
||||||
|
|
||||||
case 'Toggle Practice Mode':
|
|
||||||
PlayState.instance.isPracticeMode = true;
|
|
||||||
practiceText.visible = PlayState.instance.isPracticeMode;
|
|
||||||
|
|
||||||
case 'Restart Song':
|
|
||||||
PlayState.instance.needsReset = true;
|
|
||||||
close();
|
|
||||||
|
|
||||||
case 'Exit to Menu':
|
|
||||||
exitingToMenu = true;
|
|
||||||
PlayState.instance.deathCounter = 0;
|
|
||||||
|
|
||||||
for (item in grpMenuShit.members)
|
|
||||||
{
|
|
||||||
item.targetY = -3;
|
|
||||||
item.alpha = 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlxTransitionableState.skipNextTransIn = true;
|
|
||||||
FlxTransitionableState.skipNextTransOut = true;
|
|
||||||
|
|
||||||
if (PlayStatePlaylist.isStoryMode)
|
|
||||||
{
|
|
||||||
PlayStatePlaylist.reset();
|
|
||||||
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.story.StoryMenuState(sticker)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(null, sticker)));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'Exit to Chart Editor':
|
|
||||||
this.close();
|
|
||||||
if (FlxG.sound.music != null) FlxG.sound.music.pause(); // Don't reset song position!
|
|
||||||
PlayState.instance.close(); // This only works because PlayState is a substate!
|
|
||||||
|
|
||||||
case 'BACK':
|
|
||||||
menuItems = this.isChartingMode ? pauseOptionsCharting : pauseOptionsBase;
|
|
||||||
regenMenu();
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (pauseOptionsDifficulty.contains(daSelected))
|
|
||||||
{
|
|
||||||
PlayState.instance.currentSong = SongRegistry.instance.fetchEntry(PlayState.instance.currentSong.id.toLowerCase());
|
|
||||||
|
|
||||||
// Reset campaign score when changing difficulty
|
|
||||||
// So if you switch difficulty on the last song of a week you get a really low overall score.
|
|
||||||
PlayStatePlaylist.campaignScore = 0;
|
|
||||||
PlayStatePlaylist.campaignDifficulty = daSelected.toLowerCase();
|
|
||||||
PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty;
|
|
||||||
|
|
||||||
PlayState.instance.needsReset = true;
|
|
||||||
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace('[WARN] Unhandled pause menu option: ${daSelected}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.J)
|
|
||||||
{
|
|
||||||
// for reference later!
|
|
||||||
// PlayerSettings.player1.controls.replaceBinding(Control.LEFT, Keys, FlxKey.J, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override function destroy():Void
|
|
||||||
{
|
|
||||||
pauseMusic.destroy();
|
|
||||||
|
|
||||||
super.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the current selection up or down.
|
||||||
|
* @param change The amount to change the selection by, with sign indicating direction.
|
||||||
|
*/
|
||||||
function changeSelection(change:Int = 0):Void
|
function changeSelection(change:Int = 0):Void
|
||||||
{
|
{
|
||||||
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
|
FlxG.sound.play(Paths.sound('scrollMenu'), 0.4);
|
||||||
|
|
||||||
curSelected += change;
|
currentEntry += change;
|
||||||
|
|
||||||
if (curSelected < 0) curSelected = menuItems.length - 1;
|
if (currentEntry < 0) currentEntry = currentMenuEntries.length - 1;
|
||||||
if (curSelected >= menuItems.length) curSelected = 0;
|
if (currentEntry >= currentMenuEntries.length) currentEntry = 0;
|
||||||
|
|
||||||
for (index => item in grpMenuShit.members)
|
for (entryIndex in 0...currentMenuEntries.length)
|
||||||
{
|
{
|
||||||
item.targetY = index - curSelected;
|
var isCurrent:Bool = entryIndex == currentEntry;
|
||||||
|
|
||||||
item.alpha = 0.6;
|
var entry:PauseMenuEntry = currentMenuEntries[entryIndex];
|
||||||
|
var text:AtlasText = entry.sprite;
|
||||||
|
|
||||||
if (item.targetY == 0)
|
// Set the transparency.
|
||||||
{
|
text.alpha = isCurrent ? 1.0 : 0.6;
|
||||||
item.alpha = 1;
|
|
||||||
}
|
// Set the position.
|
||||||
|
var targetX = FlxMath.remapToRange((entryIndex - currentEntry), 0, 1, 0, 1.3) * 20 + 90;
|
||||||
|
var targetY = FlxMath.remapToRange((entryIndex - currentEntry), 0, 1, 0, 1.3) * 120 + (FlxG.height * 0.48);
|
||||||
|
trace(targetY);
|
||||||
|
FlxTween.globalManager.cancelTweensOf(text);
|
||||||
|
FlxTween.tween(text, {x: targetX, y: targetY}, 0.33, {ease: FlxEase.quartOut});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Menu Functions
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the current menu entries and regenerate them based on the current mode.
|
||||||
|
* @param targetMode Optionally specify a mode to switch to before regenerating the menu.
|
||||||
|
*/
|
||||||
|
function regenerateMenu(?targetMode:PauseMode):Void
|
||||||
|
{
|
||||||
|
// If targetMode is null, keep the current mode.
|
||||||
|
if (targetMode == null) targetMode = this.currentMode;
|
||||||
|
|
||||||
|
var previousMode:PauseMode = this.currentMode;
|
||||||
|
this.currentMode = targetMode;
|
||||||
|
|
||||||
|
resetSelection();
|
||||||
|
chooseMenuEntries();
|
||||||
|
clearAndAddMenuEntries();
|
||||||
|
updateMetadataText();
|
||||||
|
changeSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the current selection to the first entry.
|
||||||
|
*/
|
||||||
|
function resetSelection():Void
|
||||||
|
{
|
||||||
|
this.currentEntry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select which menu entries to display based on the current mode.
|
||||||
|
*/
|
||||||
|
function chooseMenuEntries():Void
|
||||||
|
{
|
||||||
|
// Choose the correct menu entries.
|
||||||
|
// NOTE: We clone the arrays to prevent modifications to the arrays from affecting the original.
|
||||||
|
switch (this.currentMode)
|
||||||
|
{
|
||||||
|
case PauseMode.Standard:
|
||||||
|
currentMenuEntries = PAUSE_MENU_ENTRIES_STANDARD.clone();
|
||||||
|
case PauseMode.Charting:
|
||||||
|
currentMenuEntries = PAUSE_MENU_ENTRIES_CHARTING.clone();
|
||||||
|
case PauseMode.Difficulty:
|
||||||
|
// Prepend the difficulties.
|
||||||
|
var entries:Array<PauseMenuEntry> = [];
|
||||||
|
if (PlayState.instance.currentChart != null)
|
||||||
|
{
|
||||||
|
var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation);
|
||||||
|
trace('DIFFICULTIES: ${difficultiesInVariation}');
|
||||||
|
for (difficulty in difficultiesInVariation)
|
||||||
|
{
|
||||||
|
entries.push({text: difficulty.toTitleCase(), callback: (state) -> changeDifficulty(state, difficulty)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the back button.
|
||||||
|
currentMenuEntries = entries.concat(PAUSE_MENU_ENTRIES_DIFFICULTY.clone());
|
||||||
|
case PauseMode.Conversation:
|
||||||
|
currentMenuEntries = PAUSE_MENU_ENTRIES_CONVERSATION.clone();
|
||||||
|
case PauseMode.Cutscene:
|
||||||
|
currentMenuEntries = PAUSE_MENU_ENTRIES_VIDEO_CUTSCENE.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the `menuEntryText` group and render the current menu entries to it.
|
||||||
|
* We first create the `menuEntryText` group if it doesn't already exist.
|
||||||
|
*/
|
||||||
|
function clearAndAddMenuEntries():Void
|
||||||
|
{
|
||||||
|
if (menuEntryText == null)
|
||||||
|
{
|
||||||
|
menuEntryText = new FlxTypedSpriteGroup<AtlasText>();
|
||||||
|
menuEntryText.scrollFactor.set(0, 0);
|
||||||
|
add(menuEntryText);
|
||||||
|
}
|
||||||
|
menuEntryText.clear();
|
||||||
|
|
||||||
|
// Render out the entries depending on the mode.
|
||||||
|
var entryIndex:Int = 0;
|
||||||
|
var toRemove = [];
|
||||||
|
for (entry in currentMenuEntries)
|
||||||
|
{
|
||||||
|
if (entry == null || (entry.filter != null && !entry.filter()))
|
||||||
|
{
|
||||||
|
// Remove entries that should be hidden.
|
||||||
|
toRemove.push(entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle visible entries.
|
||||||
|
var yPos:Float = 70 * entryIndex + 30;
|
||||||
|
var text:AtlasText = new AtlasText(0, yPos, entry.text, AtlasFont.BOLD);
|
||||||
|
text.scrollFactor.set(0, 0);
|
||||||
|
text.alpha = 0;
|
||||||
|
menuEntryText.add(text);
|
||||||
|
|
||||||
|
entry.sprite = text;
|
||||||
|
|
||||||
|
entryIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (entry in toRemove)
|
||||||
|
{
|
||||||
|
currentMenuEntries.remove(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Metadata Functions
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the values for the metadata text in the top right.
|
||||||
|
*/
|
||||||
|
function updateMetadataText():Void
|
||||||
|
{
|
||||||
|
metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
|
||||||
|
|
||||||
|
switch (this.currentMode)
|
||||||
|
{
|
||||||
|
case Standard | Difficulty:
|
||||||
|
metadataDeaths.text = '${PlayState.instance?.deathCounter} Blue Balls';
|
||||||
|
case Charting:
|
||||||
|
metadataDeaths.text = 'Chart Editor Preview';
|
||||||
|
case Conversation:
|
||||||
|
metadataDeaths.text = 'Dialogue Paused';
|
||||||
|
case Cutscene:
|
||||||
|
metadataDeaths.text = 'Video Paused';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// Menu Callbacks
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the pause menu and resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function resume(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
// Resume a paused video if it exists.
|
||||||
|
VideoCutscene.resumeVideo();
|
||||||
|
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the pause menu to the indicated mode.
|
||||||
|
* Create a callback from this using `.bind(_, targetMode)`.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
* @param targetMode The mode to switch to.
|
||||||
|
*/
|
||||||
|
static function switchMode(state:PauseSubState, targetMode:PauseMode):Void
|
||||||
|
{
|
||||||
|
state.regenerateMenu(targetMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the game's difficulty to the indicated difficulty, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
* @param difficulty The difficulty to switch to.
|
||||||
|
*/
|
||||||
|
static function changeDifficulty(state:PauseSubState, difficulty:String):Void
|
||||||
|
{
|
||||||
|
PlayState.instance.currentSong = SongRegistry.instance.fetchEntry(PlayState.instance.currentSong.id.toLowerCase());
|
||||||
|
|
||||||
|
// Reset campaign score when changing difficulty
|
||||||
|
// So if you switch difficulty on the last song of a week you get a really low overall score.
|
||||||
|
PlayStatePlaylist.campaignScore = 0;
|
||||||
|
PlayStatePlaylist.campaignDifficulty = difficulty;
|
||||||
|
PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty;
|
||||||
|
|
||||||
|
PlayState.instance.needsReset = true;
|
||||||
|
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the current level, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function restartPlayState(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
PlayState.instance.needsReset = true;
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force the game into practice mode, then update the pause menu.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function enablePracticeMode(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
if (PlayState.instance == null) return;
|
||||||
|
|
||||||
|
PlayState.instance.isPracticeMode = true;
|
||||||
|
state.regenerateMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the paused video cutscene, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function restartVideoCutscene(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
VideoCutscene.restartVideo();
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip the paused video cutscene, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function skipVideoCutscene(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
VideoCutscene.finishVideo();
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the paused conversation, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function restartConversation(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
if (PlayState.instance?.currentConversation == null) return;
|
||||||
|
|
||||||
|
PlayState.instance.currentConversation.resetConversation();
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip the paused conversation, then resume the game.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function skipConversation(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
if (PlayState.instance?.currentConversation == null) return;
|
||||||
|
|
||||||
|
PlayState.instance.currentConversation.skipConversation();
|
||||||
|
state.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quit the game and return to the main menu.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function quitToMenu(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
state.allowInput = false;
|
||||||
|
|
||||||
|
PlayState.instance.deathCounter = 0;
|
||||||
|
|
||||||
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
|
FlxTransitionableState.skipNextTransOut = true;
|
||||||
|
|
||||||
|
if (PlayStatePlaylist.isStoryMode)
|
||||||
|
{
|
||||||
|
PlayStatePlaylist.reset();
|
||||||
|
state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.story.StoryMenuState(sticker)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(null, sticker)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quit the game and return to the chart editor.
|
||||||
|
* @param state The current PauseSubState.
|
||||||
|
*/
|
||||||
|
static function quitToChartEditor(state:PauseSubState):Void
|
||||||
|
{
|
||||||
|
state.close();
|
||||||
|
if (FlxG.sound.music != null) FlxG.sound.music.pause(); // Don't reset song position!
|
||||||
|
PlayState.instance.close(); // This only works because PlayState is a substate!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which set of options the pause menu should display.
|
||||||
|
*/
|
||||||
|
enum PauseMode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The menu displayed when the player pauses the game during a song.
|
||||||
|
*/
|
||||||
|
Standard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu displayed when the player pauses the game during a song while in charting mode.
|
||||||
|
*/
|
||||||
|
Charting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu displayed when the player moves to change the game's difficulty.
|
||||||
|
*/
|
||||||
|
Difficulty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu displayed when the player pauses the game during a conversation.
|
||||||
|
*/
|
||||||
|
Conversation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu displayed when the player pauses the game during a video cutscene.
|
||||||
|
*/
|
||||||
|
Cutscene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single entry in the pause menu.
|
||||||
|
*/
|
||||||
|
typedef PauseMenuEntry =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The text to display for this entry.
|
||||||
|
* TODO: Implement localization.
|
||||||
|
*/
|
||||||
|
var text:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback to execute when the user selects this entry.
|
||||||
|
*/
|
||||||
|
var callback:PauseSubState->Void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this returns true, the entry will be displayed. If it returns false, the entry will be hidden.
|
||||||
|
*/
|
||||||
|
var ?filter:Void->Bool;
|
||||||
|
|
||||||
|
// Instance-specific properties
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text object currently displaying this entry.
|
||||||
|
*/
|
||||||
|
var ?sprite:AtlasText;
|
||||||
|
};
|
||||||
|
|
|
@ -322,6 +322,11 @@ class PlayState extends MusicBeatSubState
|
||||||
**/
|
**/
|
||||||
var inputReleaseQueue:Array<PreciseInputEvent> = [];
|
var inputReleaseQueue:Array<PreciseInputEvent> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we just unpaused the game, we shouldn't be able to pause again for one frame.
|
||||||
|
*/
|
||||||
|
var justUnpaused:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PRIVATE INSTANCE VARIABLES
|
* PRIVATE INSTANCE VARIABLES
|
||||||
* Private instance variables should be used for information that must be reset or dereferenced
|
* Private instance variables should be used for information that must be reset or dereferenced
|
||||||
|
@ -450,11 +455,6 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
var comboPopUps:PopUpStuff;
|
var comboPopUps:PopUpStuff;
|
||||||
|
|
||||||
/**
|
|
||||||
* The circular sprite that appears while the user is holding down the Skip Cutscene button.
|
|
||||||
*/
|
|
||||||
var skipTimer:FlxPieDial;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PROPERTIES
|
* PROPERTIES
|
||||||
*/
|
*/
|
||||||
|
@ -482,7 +482,7 @@ class PlayState extends MusicBeatSubState
|
||||||
if (!Std.isOfType(this.subState, PauseSubState)) return false;
|
if (!Std.isOfType(this.subState, PauseSubState)) return false;
|
||||||
|
|
||||||
var pauseSubState:PauseSubState = cast this.subState;
|
var pauseSubState:PauseSubState = cast this.subState;
|
||||||
return pauseSubState.exitingToMenu;
|
return !pauseSubState.allowInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -637,16 +637,9 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
// Initialize the judgements and combo meter.
|
// Initialize the judgements and combo meter.
|
||||||
comboPopUps = new PopUpStuff();
|
comboPopUps = new PopUpStuff();
|
||||||
comboPopUps.cameras = [camHUD];
|
comboPopUps.zIndex = 900;
|
||||||
add(comboPopUps);
|
add(comboPopUps);
|
||||||
|
comboPopUps.cameras = [camHUD];
|
||||||
// The little dial that shows up when you hold the Skip Cutscene key.
|
|
||||||
skipTimer = new FlxPieDial(16, 16, 32, FlxColor.WHITE, 36, CIRCLE, true, 24);
|
|
||||||
skipTimer.amount = 0;
|
|
||||||
skipTimer.zIndex = 1000;
|
|
||||||
add(skipTimer);
|
|
||||||
// Renders only in video cutscene mode.
|
|
||||||
skipTimer.cameras = [camCutscene];
|
|
||||||
|
|
||||||
#if discord_rpc
|
#if discord_rpc
|
||||||
// Initialize Discord Rich Presence.
|
// Initialize Discord Rich Presence.
|
||||||
|
@ -763,6 +756,8 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
public override function update(elapsed:Float):Void
|
public override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
|
// TOTAL: 9.42% CPU Time when profiled in VS 2019.
|
||||||
|
|
||||||
if (criticalFailure) return;
|
if (criticalFailure) return;
|
||||||
|
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
@ -787,8 +782,7 @@ class PlayState extends MusicBeatSubState
|
||||||
inputSpitter = [];
|
inputSpitter = [];
|
||||||
|
|
||||||
// Reset music properly.
|
// Reset music properly.
|
||||||
|
FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
|
||||||
FlxG.sound.music.time = Math.max(0, startTimestamp - Conductor.instance.instrumentalOffset);
|
|
||||||
FlxG.sound.music.pause();
|
FlxG.sound.music.pause();
|
||||||
|
|
||||||
if (!overrideMusic)
|
if (!overrideMusic)
|
||||||
|
@ -864,7 +858,7 @@ class PlayState extends MusicBeatSubState
|
||||||
#end
|
#end
|
||||||
|
|
||||||
// Attempt to pause the game.
|
// Attempt to pause the game.
|
||||||
if ((controls.PAUSE || androidPause) && isInCountdown && mayPauseGame)
|
if ((controls.PAUSE || androidPause) && isInCountdown && mayPauseGame && !justUnpaused)
|
||||||
{
|
{
|
||||||
var event = new PauseScriptEvent(FlxG.random.bool(1 / 1000));
|
var event = new PauseScriptEvent(FlxG.random.bool(1 / 1000));
|
||||||
|
|
||||||
|
@ -899,12 +893,12 @@ class PlayState extends MusicBeatSubState
|
||||||
boyfriendPos = currentStage.getBoyfriend().getScreenPosition();
|
boyfriendPos = currentStage.getBoyfriend().getScreenPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pauseSubState:FlxSubState = new PauseSubState(isChartingMode);
|
var pauseSubState:FlxSubState = new PauseSubState({mode: isChartingMode ? Charting : Standard});
|
||||||
|
|
||||||
FlxTransitionableSubState.skipNextTransIn = true;
|
FlxTransitionableSubState.skipNextTransIn = true;
|
||||||
FlxTransitionableSubState.skipNextTransOut = true;
|
FlxTransitionableSubState.skipNextTransOut = true;
|
||||||
openSubState(pauseSubState);
|
|
||||||
pauseSubState.camera = camHUD;
|
pauseSubState.camera = camHUD;
|
||||||
|
openSubState(pauseSubState);
|
||||||
// boyfriendPos.put(); // TODO: Why is this here?
|
// boyfriendPos.put(); // TODO: Why is this here?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,6 +996,8 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
// Moving notes into position is now done by Strumline.update().
|
// Moving notes into position is now done by Strumline.update().
|
||||||
processNotes(elapsed);
|
processNotes(elapsed);
|
||||||
|
|
||||||
|
justUnpaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function processSongEvents():Void
|
function processSongEvents():Void
|
||||||
|
@ -1076,7 +1072,10 @@ class PlayState extends MusicBeatSubState
|
||||||
if (FlxG.sound.music != null)
|
if (FlxG.sound.music != null)
|
||||||
{
|
{
|
||||||
musicPausedBySubState = FlxG.sound.music.playing;
|
musicPausedBySubState = FlxG.sound.music.playing;
|
||||||
FlxG.sound.music.pause();
|
if (musicPausedBySubState)
|
||||||
|
{
|
||||||
|
FlxG.sound.music.pause();
|
||||||
|
}
|
||||||
if (vocals != null) vocals.pause();
|
if (vocals != null) vocals.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,7 +1103,12 @@ class PlayState extends MusicBeatSubState
|
||||||
// Resume
|
// Resume
|
||||||
if (musicPausedBySubState)
|
if (musicPausedBySubState)
|
||||||
{
|
{
|
||||||
FlxG.sound.music.play(FlxG.sound.music.time);
|
FlxG.sound.music.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentConversation != null)
|
||||||
|
{
|
||||||
|
currentConversation.resumeMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals();
|
if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals();
|
||||||
|
@ -1123,6 +1127,8 @@ class PlayState extends MusicBeatSubState
|
||||||
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
|
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
justUnpaused = true;
|
||||||
}
|
}
|
||||||
else if (Std.isOfType(subState, Transition))
|
else if (Std.isOfType(subState, Transition))
|
||||||
{
|
{
|
||||||
|
@ -1283,6 +1289,7 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
var animShit:ComboMilestone = new ComboMilestone(-100, 300, Highscore.tallies.combo);
|
var animShit:ComboMilestone = new ComboMilestone(-100, 300, Highscore.tallies.combo);
|
||||||
animShit.scrollFactor.set(0.6, 0.6);
|
animShit.scrollFactor.set(0.6, 0.6);
|
||||||
|
animShit.zIndex = 1100;
|
||||||
animShit.cameras = [camHUD];
|
animShit.cameras = [camHUD];
|
||||||
add(animShit);
|
add(animShit);
|
||||||
|
|
||||||
|
@ -1304,12 +1311,6 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
public override function destroy():Void
|
public override function destroy():Void
|
||||||
{
|
{
|
||||||
if (currentConversation != null)
|
|
||||||
{
|
|
||||||
remove(currentConversation);
|
|
||||||
currentConversation.kill();
|
|
||||||
}
|
|
||||||
|
|
||||||
performCleanup();
|
performCleanup();
|
||||||
|
|
||||||
super.destroy();
|
super.destroy();
|
||||||
|
@ -1369,18 +1370,21 @@ class PlayState extends MusicBeatSubState
|
||||||
healthBarBG = FunkinSprite.create(0, healthBarYPos, Paths.image('healthBar'));
|
healthBarBG = FunkinSprite.create(0, healthBarYPos, Paths.image('healthBar'));
|
||||||
healthBarBG.screenCenter(X);
|
healthBarBG.screenCenter(X);
|
||||||
healthBarBG.scrollFactor.set(0, 0);
|
healthBarBG.scrollFactor.set(0, 0);
|
||||||
|
healthBarBG.zIndex = 800;
|
||||||
add(healthBarBG);
|
add(healthBarBG);
|
||||||
|
|
||||||
healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), this,
|
healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), this,
|
||||||
'healthLerp', 0, 2);
|
'healthLerp', 0, 2);
|
||||||
healthBar.scrollFactor.set();
|
healthBar.scrollFactor.set();
|
||||||
healthBar.createFilledBar(Constants.COLOR_HEALTH_BAR_RED, Constants.COLOR_HEALTH_BAR_GREEN);
|
healthBar.createFilledBar(Constants.COLOR_HEALTH_BAR_RED, Constants.COLOR_HEALTH_BAR_GREEN);
|
||||||
|
healthBar.zIndex = 801;
|
||||||
add(healthBar);
|
add(healthBar);
|
||||||
|
|
||||||
// The score text below the health bar.
|
// The score text below the health bar.
|
||||||
scoreText = new FlxText(healthBarBG.x + healthBarBG.width - 190, healthBarBG.y + 30, 0, '', 20);
|
scoreText = new FlxText(healthBarBG.x + healthBarBG.width - 190, healthBarBG.y + 30, 0, '', 20);
|
||||||
scoreText.setFormat(Paths.font('vcr.ttf'), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
|
scoreText.setFormat(Paths.font('vcr.ttf'), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
|
||||||
scoreText.scrollFactor.set();
|
scoreText.scrollFactor.set();
|
||||||
|
scoreText.zIndex = 802;
|
||||||
add(scoreText);
|
add(scoreText);
|
||||||
|
|
||||||
// Move the health bar to the HUD camera.
|
// Move the health bar to the HUD camera.
|
||||||
|
@ -1494,6 +1498,7 @@ class PlayState extends MusicBeatSubState
|
||||||
iconP2 = new HealthIcon('dad', 1);
|
iconP2 = new HealthIcon('dad', 1);
|
||||||
iconP2.y = healthBar.y - (iconP2.height / 2);
|
iconP2.y = healthBar.y - (iconP2.height / 2);
|
||||||
dad.initHealthIcon(true); // Apply the character ID here
|
dad.initHealthIcon(true); // Apply the character ID here
|
||||||
|
iconP2.zIndex = 850;
|
||||||
add(iconP2);
|
add(iconP2);
|
||||||
iconP2.cameras = [camHUD];
|
iconP2.cameras = [camHUD];
|
||||||
|
|
||||||
|
@ -1513,6 +1518,7 @@ class PlayState extends MusicBeatSubState
|
||||||
iconP1 = new HealthIcon('bf', 0);
|
iconP1 = new HealthIcon('bf', 0);
|
||||||
iconP1.y = healthBar.y - (iconP1.height / 2);
|
iconP1.y = healthBar.y - (iconP1.height / 2);
|
||||||
boyfriend.initHealthIcon(false); // Apply the character ID here
|
boyfriend.initHealthIcon(false); // Apply the character ID here
|
||||||
|
iconP1.zIndex = 850;
|
||||||
add(iconP1);
|
add(iconP1);
|
||||||
iconP1.cameras = [camHUD];
|
iconP1.cameras = [camHUD];
|
||||||
|
|
||||||
|
@ -1580,13 +1586,13 @@ class PlayState extends MusicBeatSubState
|
||||||
playerStrumline.x = FlxG.width / 2 + Constants.STRUMLINE_X_OFFSET; // Classic style
|
playerStrumline.x = FlxG.width / 2 + Constants.STRUMLINE_X_OFFSET; // Classic style
|
||||||
// playerStrumline.x = FlxG.width - playerStrumline.width - Constants.STRUMLINE_X_OFFSET; // Centered style
|
// playerStrumline.x = FlxG.width - playerStrumline.width - Constants.STRUMLINE_X_OFFSET; // Centered style
|
||||||
playerStrumline.y = Preferences.downscroll ? FlxG.height - playerStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
|
playerStrumline.y = Preferences.downscroll ? FlxG.height - playerStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
|
||||||
playerStrumline.zIndex = 200;
|
playerStrumline.zIndex = 1001;
|
||||||
playerStrumline.cameras = [camHUD];
|
playerStrumline.cameras = [camHUD];
|
||||||
|
|
||||||
// Position the opponent strumline on the left half of the screen
|
// Position the opponent strumline on the left half of the screen
|
||||||
opponentStrumline.x = Constants.STRUMLINE_X_OFFSET;
|
opponentStrumline.x = Constants.STRUMLINE_X_OFFSET;
|
||||||
opponentStrumline.y = Preferences.downscroll ? FlxG.height - opponentStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
|
opponentStrumline.y = Preferences.downscroll ? FlxG.height - opponentStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
|
||||||
opponentStrumline.zIndex = 100;
|
opponentStrumline.zIndex = 1000;
|
||||||
opponentStrumline.cameras = [camHUD];
|
opponentStrumline.cameras = [camHUD];
|
||||||
|
|
||||||
if (!PlayStatePlaylist.isStoryMode)
|
if (!PlayStatePlaylist.isStoryMode)
|
||||||
|
@ -1733,6 +1739,7 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
currentConversation = ConversationRegistry.instance.fetchEntry(conversationId);
|
currentConversation = ConversationRegistry.instance.fetchEntry(conversationId);
|
||||||
if (currentConversation == null) return;
|
if (currentConversation == null) return;
|
||||||
|
if (!currentConversation.alive) currentConversation.revive();
|
||||||
|
|
||||||
currentConversation.completeCallback = onConversationComplete;
|
currentConversation.completeCallback = onConversationComplete;
|
||||||
currentConversation.cameras = [camCutscene];
|
currentConversation.cameras = [camCutscene];
|
||||||
|
@ -1750,8 +1757,13 @@ class PlayState extends MusicBeatSubState
|
||||||
function onConversationComplete():Void
|
function onConversationComplete():Void
|
||||||
{
|
{
|
||||||
isInCutscene = false;
|
isInCutscene = false;
|
||||||
remove(currentConversation);
|
|
||||||
currentConversation = null;
|
if (currentConversation != null)
|
||||||
|
{
|
||||||
|
currentConversation.kill();
|
||||||
|
remove(currentConversation);
|
||||||
|
currentConversation = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (startingSong && !isInCountdown)
|
if (startingSong && !isInCountdown)
|
||||||
{
|
{
|
||||||
|
@ -1776,12 +1788,14 @@ class PlayState extends MusicBeatSubState
|
||||||
FlxG.sound.music.onComplete = endSong.bind(false);
|
FlxG.sound.music.onComplete = endSong.bind(false);
|
||||||
// A negative instrumental offset means the song skips the first few milliseconds of the track.
|
// A negative instrumental offset means the song skips the first few milliseconds of the track.
|
||||||
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
|
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
|
||||||
FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
|
FlxG.sound.music.play(true, startTimestamp - Conductor.instance.instrumentalOffset);
|
||||||
|
|
||||||
|
// I am going insane.
|
||||||
|
FlxG.sound.music.volume = 1.0;
|
||||||
|
FlxG.sound.music.fadeTween.cancel();
|
||||||
|
|
||||||
trace('Playing vocals...');
|
trace('Playing vocals...');
|
||||||
add(vocals);
|
add(vocals);
|
||||||
|
|
||||||
FlxG.sound.music.play(FlxG.sound.music.time);
|
|
||||||
vocals.play();
|
vocals.play();
|
||||||
resyncVocals();
|
resyncVocals();
|
||||||
|
|
||||||
|
@ -2459,58 +2473,43 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function handleCutsceneKeys(elapsed:Float):Void
|
function handleCutsceneKeys(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
|
if (isGamePaused) return;
|
||||||
|
|
||||||
if (currentConversation != null)
|
if (currentConversation != null)
|
||||||
{
|
{
|
||||||
if (controls.CUTSCENE_ADVANCE) currentConversation?.advanceConversation();
|
// Pause/unpause may conflict with advancing the conversation!
|
||||||
|
if (controls.CUTSCENE_ADVANCE && !justUnpaused)
|
||||||
if (controls.CUTSCENE_SKIP)
|
|
||||||
{
|
{
|
||||||
currentConversation?.trySkipConversation(elapsed);
|
currentConversation.advanceConversation();
|
||||||
}
|
}
|
||||||
else
|
else if (controls.PAUSE && !justUnpaused)
|
||||||
{
|
{
|
||||||
currentConversation?.trySkipConversation(-1);
|
currentConversation.pauseMusic();
|
||||||
|
|
||||||
|
var pauseSubState:FlxSubState = new PauseSubState({mode: Conversation});
|
||||||
|
|
||||||
|
persistentUpdate = false;
|
||||||
|
FlxTransitionableSubState.skipNextTransIn = true;
|
||||||
|
FlxTransitionableSubState.skipNextTransOut = true;
|
||||||
|
pauseSubState.camera = camCutscene;
|
||||||
|
openSubState(pauseSubState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (VideoCutscene.isPlaying())
|
else if (VideoCutscene.isPlaying())
|
||||||
{
|
{
|
||||||
// This is a video cutscene.
|
// This is a video cutscene.
|
||||||
|
if (controls.PAUSE && !justUnpaused)
|
||||||
if (controls.CUTSCENE_SKIP)
|
|
||||||
{
|
{
|
||||||
trySkipVideoCutscene(elapsed);
|
VideoCutscene.pauseVideo();
|
||||||
|
|
||||||
|
var pauseSubState:FlxSubState = new PauseSubState({mode: Cutscene});
|
||||||
|
|
||||||
|
persistentUpdate = false;
|
||||||
|
FlxTransitionableSubState.skipNextTransIn = true;
|
||||||
|
FlxTransitionableSubState.skipNextTransOut = true;
|
||||||
|
pauseSubState.camera = camCutscene;
|
||||||
|
openSubState(pauseSubState);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
trySkipVideoCutscene(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle logic for the skip timer.
|
|
||||||
* If the skip button is being held, pass the amount of time elapsed since last game update.
|
|
||||||
* If the skip button has been released, pass a negative number.
|
|
||||||
*/
|
|
||||||
function trySkipVideoCutscene(elapsed:Float):Void
|
|
||||||
{
|
|
||||||
if (skipTimer == null || skipTimer.animation == null) return;
|
|
||||||
|
|
||||||
if (elapsed < 0)
|
|
||||||
{
|
|
||||||
skipHeldTimer = 0.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
skipHeldTimer += elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
skipTimer.visible = skipHeldTimer >= 0.05;
|
|
||||||
skipTimer.amount = Math.min(skipHeldTimer / 1.5, 1.0);
|
|
||||||
|
|
||||||
if (skipHeldTimer >= 1.5)
|
|
||||||
{
|
|
||||||
skipVideoCutscene();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2724,6 +2723,12 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function performCleanup():Void
|
function performCleanup():Void
|
||||||
{
|
{
|
||||||
|
if (currentConversation != null)
|
||||||
|
{
|
||||||
|
remove(currentConversation);
|
||||||
|
currentConversation.kill();
|
||||||
|
}
|
||||||
|
|
||||||
if (currentChart != null)
|
if (currentChart != null)
|
||||||
{
|
{
|
||||||
// TODO: Uncache the song.
|
// TODO: Uncache the song.
|
||||||
|
@ -2740,7 +2745,7 @@ class PlayState extends MusicBeatSubState
|
||||||
FlxG.sound.music.pause();
|
FlxG.sound.music.pause();
|
||||||
if (vocals != null)
|
if (vocals != null)
|
||||||
{
|
{
|
||||||
vocals.pause();
|
vocals.destroy();
|
||||||
remove(vocals);
|
remove(vocals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2755,6 +2760,7 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
|
|
||||||
GameOverSubState.reset();
|
GameOverSubState.reset();
|
||||||
|
PauseSubState.reset();
|
||||||
|
|
||||||
// Clear the static reference to this state.
|
// Clear the static reference to this state.
|
||||||
instance = null;
|
instance = null;
|
||||||
|
|
|
@ -191,7 +191,11 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
_skipTransformChildren = true;
|
_skipTransformChildren = true;
|
||||||
super.kill();
|
super.kill();
|
||||||
_skipTransformChildren = false;
|
_skipTransformChildren = false;
|
||||||
this.mainSprite.kill();
|
if (this.mainSprite != null)
|
||||||
|
{
|
||||||
|
this.mainSprite.kill();
|
||||||
|
this.mainSprite = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@ import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import flixel.util.FlxDirection;
|
||||||
|
|
||||||
class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
{
|
{
|
||||||
|
@ -30,14 +31,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
|
|
||||||
rating.zIndex = 1000;
|
rating.zIndex = 1000;
|
||||||
rating.x = FlxG.width * 0.50;
|
rating.x = FlxG.width * 0.50;
|
||||||
rating.x -= FlxG.camera.scroll.x * 0.2;
|
// rating.x -= FlxG.camera.scroll.x * 0.2;
|
||||||
// make sure rating is visible lol!
|
|
||||||
// if (rating.x < FlxG.camera.scroll.x)
|
|
||||||
// rating.x = FlxG.camera.scroll.x;
|
|
||||||
// else if (rating.x > FlxG.camera.scroll.x + FlxG.camera.width - rating.width)
|
|
||||||
// rating.x = FlxG.camera.scroll.x + FlxG.camera.width - rating.width;
|
|
||||||
|
|
||||||
// FlxG.camera.scroll.y +
|
|
||||||
rating.y = FlxG.camera.height * 0.4 - 60;
|
rating.y = FlxG.camera.height * 0.4 - 60;
|
||||||
rating.acceleration.y = 550;
|
rating.acceleration.y = 550;
|
||||||
rating.velocity.y -= FlxG.random.int(140, 175);
|
rating.velocity.y -= FlxG.random.int(140, 175);
|
||||||
|
@ -91,13 +85,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
var comboSpr:FunkinSprite = FunkinSprite.create(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2));
|
var comboSpr:FunkinSprite = FunkinSprite.create(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2));
|
||||||
comboSpr.y = FlxG.camera.height * 0.4 + 80;
|
comboSpr.y = FlxG.camera.height * 0.4 + 80;
|
||||||
comboSpr.x = FlxG.width * 0.50;
|
comboSpr.x = FlxG.width * 0.50;
|
||||||
comboSpr.x -= FlxG.camera.scroll.x * 0.2;
|
// comboSpr.x -= FlxG.camera.scroll.x * 0.2;
|
||||||
// make sure combo is visible lol!
|
|
||||||
// 194 fits 4 combo digits
|
|
||||||
// if (comboSpr.x < FlxG.camera.scroll.x + 194)
|
|
||||||
// comboSpr.x = FlxG.camera.scroll.x + 194;
|
|
||||||
// else if (comboSpr.x > FlxG.camera.scroll.x + FlxG.camera.width - comboSpr.width)
|
|
||||||
// comboSpr.x = FlxG.camera.scroll.x + FlxG.camera.width - comboSpr.width;
|
|
||||||
|
|
||||||
comboSpr.acceleration.y = 600;
|
comboSpr.acceleration.y = 600;
|
||||||
comboSpr.velocity.y -= 150;
|
comboSpr.velocity.y -= 150;
|
||||||
|
|
|
@ -112,6 +112,7 @@ class VideoCutscene
|
||||||
{
|
{
|
||||||
vid.zIndex = 0;
|
vid.zIndex = 0;
|
||||||
vid.bitmap.onEndReached.add(finishVideo.bind(0.5));
|
vid.bitmap.onEndReached.add(finishVideo.bind(0.5));
|
||||||
|
vid.autoPause = false;
|
||||||
|
|
||||||
vid.cameras = [PlayState.instance.camCutscene];
|
vid.cameras = [PlayState.instance.camCutscene];
|
||||||
|
|
||||||
|
@ -136,6 +137,63 @@ class VideoCutscene
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
public static function restartVideo(resume:Bool = true):Void
|
||||||
|
{
|
||||||
|
#if html5
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
vid.restartVideo();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
#if hxCodec
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
// Seek to the start of the video.
|
||||||
|
vid.bitmap.time = 0;
|
||||||
|
if (resume)
|
||||||
|
{
|
||||||
|
// Resume the video if it was paused.
|
||||||
|
vid.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function pauseVideo():Void
|
||||||
|
{
|
||||||
|
#if html5
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
vid.pauseVideo();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
#if hxCodec
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
vid.pause();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resumeVideo():Void
|
||||||
|
{
|
||||||
|
#if html5
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
vid.resumeVideo();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
#if hxCodec
|
||||||
|
if (vid != null)
|
||||||
|
{
|
||||||
|
vid.resume();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the active video cutscene. Done when the video is finished or when the player skips the cutscene.
|
* Finish the active video cutscene. Done when the video is finished or when the player skips the cutscene.
|
||||||
* @param transitionTime The duration of the transition to the next state. Defaults to 0.5 seconds (this time is always used when cancelling the video).
|
* @param transitionTime The duration of the transition to the next state. Defaults to 0.5 seconds (this time is always used when cancelling the video).
|
||||||
|
|
|
@ -31,10 +31,6 @@ import funkin.data.dialogue.DialogueBoxRegistry;
|
||||||
*/
|
*/
|
||||||
class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<ConversationData>
|
class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<ConversationData>
|
||||||
{
|
{
|
||||||
static final CONVERSATION_SKIP_TIMER:Float = 1.5;
|
|
||||||
|
|
||||||
var skipHeldTimer:Float = 0.0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the conversation.
|
* The ID of the conversation.
|
||||||
*/
|
*/
|
||||||
|
@ -105,8 +101,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
|
|
||||||
var currentDialogueBox:DialogueBox;
|
var currentDialogueBox:DialogueBox;
|
||||||
|
|
||||||
var skipTimer:FlxPieDial;
|
|
||||||
|
|
||||||
public function new(id:String)
|
public function new(id:String)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -124,8 +118,8 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
{
|
{
|
||||||
// Reset the progress in the dialogue.
|
// Reset the progress in the dialogue.
|
||||||
currentDialogueEntry = 0;
|
currentDialogueEntry = 0;
|
||||||
|
currentDialogueLine = 0;
|
||||||
this.state = ConversationState.Start;
|
this.state = ConversationState.Start;
|
||||||
this.alpha = 1.0;
|
|
||||||
|
|
||||||
// Start the dialogue.
|
// Start the dialogue.
|
||||||
dispatchEvent(new DialogueScriptEvent(DIALOGUE_START, this, false));
|
dispatchEvent(new DialogueScriptEvent(DIALOGUE_START, this, false));
|
||||||
|
@ -151,8 +145,31 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
music.play();
|
music.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pauseMusic():Void
|
||||||
|
{
|
||||||
|
if (music != null)
|
||||||
|
{
|
||||||
|
music.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resumeMusic():Void
|
||||||
|
{
|
||||||
|
if (music != null)
|
||||||
|
{
|
||||||
|
music.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setupBackdrop():Void
|
function setupBackdrop():Void
|
||||||
{
|
{
|
||||||
|
if (backdrop != null)
|
||||||
|
{
|
||||||
|
backdrop.destroy();
|
||||||
|
remove(backdrop);
|
||||||
|
backdrop = null;
|
||||||
|
}
|
||||||
|
|
||||||
backdrop = new FunkinSprite(0, 0);
|
backdrop = new FunkinSprite(0, 0);
|
||||||
|
|
||||||
if (_data.backdrop == null) return;
|
if (_data.backdrop == null) return;
|
||||||
|
@ -181,12 +198,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupSkipTimer():Void
|
|
||||||
{
|
|
||||||
add(skipTimer = new FlxPieDial(16, 16, 32, FlxColor.WHITE, 36, CIRCLE, true, 24));
|
|
||||||
skipTimer.amount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override function update(elapsed:Float):Void
|
public override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
@ -199,9 +210,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
var nextSpeakerId:String = currentDialogueEntryData.speaker;
|
var nextSpeakerId:String = currentDialogueEntryData.speaker;
|
||||||
|
|
||||||
// Skip the next steps if the current speaker is already displayed.
|
// Skip the next steps if the current speaker is already displayed.
|
||||||
if (currentSpeaker != null && nextSpeakerId == currentSpeaker.id) return;
|
if ((currentSpeaker != null && currentSpeaker.alive) && nextSpeakerId == currentSpeaker.id) return;
|
||||||
|
|
||||||
var nextSpeaker:Speaker = SpeakerRegistry.instance.fetchEntry(nextSpeakerId);
|
|
||||||
|
|
||||||
if (currentSpeaker != null)
|
if (currentSpeaker != null)
|
||||||
{
|
{
|
||||||
|
@ -210,6 +219,8 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
currentSpeaker = null;
|
currentSpeaker = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nextSpeaker:Speaker = SpeakerRegistry.instance.fetchEntry(nextSpeakerId);
|
||||||
|
|
||||||
if (nextSpeaker == null)
|
if (nextSpeaker == null)
|
||||||
{
|
{
|
||||||
if (nextSpeakerId == null)
|
if (nextSpeakerId == null)
|
||||||
|
@ -222,6 +233,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!nextSpeaker.alive) nextSpeaker.revive();
|
||||||
|
|
||||||
ScriptEventDispatcher.callEvent(nextSpeaker, new ScriptEvent(CREATE, true));
|
ScriptEventDispatcher.callEvent(nextSpeaker, new ScriptEvent(CREATE, true));
|
||||||
|
|
||||||
|
@ -249,8 +261,8 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
{
|
{
|
||||||
var nextDialogueBoxId:String = currentDialogueEntryData?.box;
|
var nextDialogueBoxId:String = currentDialogueEntryData?.box;
|
||||||
|
|
||||||
// Skip the next steps if the current speaker is already displayed.
|
// Skip the next steps if the current dialogue box is already displayed.
|
||||||
if (currentDialogueBox != null && nextDialogueBoxId == currentDialogueBox.id) return;
|
if ((currentDialogueBox != null && currentDialogueBox.alive) && nextDialogueBoxId == currentDialogueBox.id) return;
|
||||||
|
|
||||||
if (currentDialogueBox != null)
|
if (currentDialogueBox != null)
|
||||||
{
|
{
|
||||||
|
@ -266,6 +278,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
trace('Dialogue box could not be retrieved.');
|
trace('Dialogue box could not be retrieved.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!nextDialogueBox.alive) nextDialogueBox.revive();
|
||||||
|
|
||||||
ScriptEventDispatcher.callEvent(nextDialogueBox, new ScriptEvent(CREATE, true));
|
ScriptEventDispatcher.callEvent(nextDialogueBox, new ScriptEvent(CREATE, true));
|
||||||
|
|
||||||
|
@ -347,29 +360,28 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
currentDialogueEntry = 0;
|
currentDialogueEntry = 0;
|
||||||
this.state = ConversationState.Start;
|
this.state = ConversationState.Start;
|
||||||
|
|
||||||
advanceConversation();
|
if (outroTween != null)
|
||||||
}
|
|
||||||
|
|
||||||
public function trySkipConversation(elapsed:Float):Void
|
|
||||||
{
|
|
||||||
if (skipTimer == null || skipTimer.animation == null) return;
|
|
||||||
|
|
||||||
if (elapsed < 0)
|
|
||||||
{
|
{
|
||||||
skipHeldTimer = 0.0;
|
outroTween.cancel();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
skipHeldTimer += elapsed;
|
|
||||||
}
|
}
|
||||||
|
outroTween = null;
|
||||||
|
|
||||||
skipTimer.visible = skipHeldTimer >= 0.05;
|
if (this.music != null) this.music.stop();
|
||||||
skipTimer.amount = Math.min(skipHeldTimer / CONVERSATION_SKIP_TIMER, 1.0);
|
this.music = null;
|
||||||
|
|
||||||
if (skipHeldTimer >= CONVERSATION_SKIP_TIMER)
|
if (currentSpeaker != null) currentSpeaker.kill();
|
||||||
{
|
remove(currentSpeaker);
|
||||||
skipConversation();
|
currentSpeaker = null;
|
||||||
}
|
|
||||||
|
if (currentDialogueBox != null) currentDialogueBox.kill();
|
||||||
|
remove(currentDialogueBox);
|
||||||
|
currentDialogueBox = null;
|
||||||
|
|
||||||
|
if (backdrop != null) backdrop.destroy();
|
||||||
|
remove(backdrop);
|
||||||
|
backdrop = null;
|
||||||
|
|
||||||
|
startConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -383,7 +395,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
dispatchEvent(new DialogueScriptEvent(DIALOGUE_SKIP, this, true));
|
dispatchEvent(new DialogueScriptEvent(DIALOGUE_SKIP, this, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
static var outroTween:FlxTween;
|
var outroTween:FlxTween;
|
||||||
|
|
||||||
public function startOutro():Void
|
public function startOutro():Void
|
||||||
{
|
{
|
||||||
|
@ -411,7 +423,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
|
|
||||||
public function endOutro():Void
|
public function endOutro():Void
|
||||||
{
|
{
|
||||||
outroTween = null;
|
|
||||||
ScriptEventDispatcher.callEvent(this, new ScriptEvent(DESTROY, false));
|
ScriptEventDispatcher.callEvent(this, new ScriptEvent(DESTROY, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +436,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
// Fade in the music and backdrop.
|
// Fade in the music and backdrop.
|
||||||
setupMusic();
|
setupMusic();
|
||||||
setupBackdrop();
|
setupBackdrop();
|
||||||
setupSkipTimer();
|
|
||||||
|
|
||||||
// Advance the conversation.
|
// Advance the conversation.
|
||||||
state = ConversationState.Opening;
|
state = ConversationState.Opening;
|
||||||
|
@ -547,19 +557,25 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
{
|
{
|
||||||
propagateEvent(event);
|
propagateEvent(event);
|
||||||
|
|
||||||
if (outroTween != null) outroTween.cancel(); // Canc
|
if (outroTween != null)
|
||||||
|
{
|
||||||
|
outroTween.cancel();
|
||||||
|
}
|
||||||
outroTween = null;
|
outroTween = null;
|
||||||
|
|
||||||
this.alpha = 0.0;
|
|
||||||
if (this.music != null) this.music.stop();
|
if (this.music != null) this.music.stop();
|
||||||
this.music = null;
|
this.music = null;
|
||||||
|
|
||||||
this.skipTimer = null;
|
|
||||||
if (currentSpeaker != null) currentSpeaker.kill();
|
if (currentSpeaker != null) currentSpeaker.kill();
|
||||||
|
remove(currentSpeaker);
|
||||||
currentSpeaker = null;
|
currentSpeaker = null;
|
||||||
|
|
||||||
if (currentDialogueBox != null) currentDialogueBox.kill();
|
if (currentDialogueBox != null) currentDialogueBox.kill();
|
||||||
|
remove(currentDialogueBox);
|
||||||
currentDialogueBox = null;
|
currentDialogueBox = null;
|
||||||
if (backdrop != null) backdrop.kill();
|
|
||||||
|
if (backdrop != null) backdrop.destroy();
|
||||||
|
remove(backdrop);
|
||||||
backdrop = null;
|
backdrop = null;
|
||||||
|
|
||||||
this.clear();
|
this.clear();
|
||||||
|
@ -578,16 +594,27 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
*/
|
*/
|
||||||
function propagateEvent(event:ScriptEvent):Void
|
function propagateEvent(event:ScriptEvent):Void
|
||||||
{
|
{
|
||||||
if (this.currentDialogueBox != null)
|
if (this.currentDialogueBox != null && this.currentDialogueBox.exists)
|
||||||
{
|
{
|
||||||
ScriptEventDispatcher.callEvent(this.currentDialogueBox, event);
|
ScriptEventDispatcher.callEvent(this.currentDialogueBox, event);
|
||||||
}
|
}
|
||||||
if (this.currentSpeaker != null)
|
if (this.currentSpeaker != null && this.currentSpeaker.exists)
|
||||||
{
|
{
|
||||||
ScriptEventDispatcher.callEvent(this.currentSpeaker, event);
|
ScriptEventDispatcher.callEvent(this.currentSpeaker, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls `kill()` on the group's members and then on the group itself.
|
||||||
|
* You can revive this group later via `revive()` after this.
|
||||||
|
*/
|
||||||
|
public override function revive():Void
|
||||||
|
{
|
||||||
|
super.revive();
|
||||||
|
this.alpha = 1;
|
||||||
|
this.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls `kill()` on the group's members and then on the group itself.
|
* Calls `kill()` on the group's members and then on the group itself.
|
||||||
* You can revive this group later via `revive()` after this.
|
* You can revive this group later via `revive()` after this.
|
||||||
|
@ -599,6 +626,12 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
|
||||||
exists = false;
|
exists = false;
|
||||||
_skipTransformChildren = false;
|
_skipTransformChildren = false;
|
||||||
if (group != null) group.kill();
|
if (group != null) group.kill();
|
||||||
|
|
||||||
|
if (outroTween != null)
|
||||||
|
{
|
||||||
|
outroTween.cancel();
|
||||||
|
outroTween = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function toString():String
|
public override function toString():String
|
||||||
|
|
|
@ -4,10 +4,11 @@ import flixel.FlxSprite;
|
||||||
import funkin.data.IRegistryEntry;
|
import funkin.data.IRegistryEntry;
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
import flixel.graphics.frames.FlxFramesCollection;
|
import flixel.graphics.frames.FlxFramesCollection;
|
||||||
import flixel.text.FlxText;
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.addons.text.FlxTypeText;
|
import flixel.addons.text.FlxTypeText;
|
||||||
import funkin.util.assets.FlxAnimationUtil;
|
import funkin.util.assets.FlxAnimationUtil;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.data.dialogue.DialogueBoxData;
|
import funkin.data.dialogue.DialogueBoxData;
|
||||||
|
@ -111,9 +112,6 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||||
this.y = 0;
|
this.y = 0;
|
||||||
this.alpha = 1;
|
this.alpha = 1;
|
||||||
|
|
||||||
this.boxSprite = new FlxSprite(0, 0);
|
|
||||||
add(this.boxSprite);
|
|
||||||
|
|
||||||
loadSpritesheet();
|
loadSpritesheet();
|
||||||
loadAnimations();
|
loadAnimations();
|
||||||
|
|
||||||
|
@ -122,6 +120,14 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||||
|
|
||||||
function loadSpritesheet():Void
|
function loadSpritesheet():Void
|
||||||
{
|
{
|
||||||
|
if (this.boxSprite != null)
|
||||||
|
{
|
||||||
|
remove(this.boxSprite);
|
||||||
|
this.boxSprite = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boxSprite = new FunkinSprite(0, 0);
|
||||||
|
|
||||||
trace('[DIALOGUE BOX] Loading spritesheet ${_data.assetPath} for ${id}');
|
trace('[DIALOGUE BOX] Loading spritesheet ${_data.assetPath} for ${id}');
|
||||||
|
|
||||||
var tex:FlxFramesCollection = Paths.getSparrowAtlas(_data.assetPath);
|
var tex:FlxFramesCollection = Paths.getSparrowAtlas(_data.assetPath);
|
||||||
|
@ -146,6 +152,8 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||||
this.flipY = _data.flipY;
|
this.flipY = _data.flipY;
|
||||||
this.globalOffsets = _data.offsets;
|
this.globalOffsets = _data.offsets;
|
||||||
this.setScale(_data.scale);
|
this.setScale(_data.scale);
|
||||||
|
|
||||||
|
add(this.boxSprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setText(newText:String):Void
|
public function setText(newText:String):Void
|
||||||
|
@ -190,6 +198,34 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||||
this.boxSprite.updateHitbox();
|
this.boxSprite.updateHitbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls `kill()` on the group's members and then on the group itself.
|
||||||
|
* You can revive this group later via `revive()` after this.
|
||||||
|
*/
|
||||||
|
public override function kill():Void
|
||||||
|
{
|
||||||
|
super.kill();
|
||||||
|
if (this.boxSprite != null)
|
||||||
|
{
|
||||||
|
this.boxSprite.kill();
|
||||||
|
this.boxSprite = null;
|
||||||
|
}
|
||||||
|
if (this.textDisplay != null)
|
||||||
|
{
|
||||||
|
this.textDisplay.kill();
|
||||||
|
this.textDisplay = null;
|
||||||
|
}
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function revive():Void
|
||||||
|
{
|
||||||
|
super.revive();
|
||||||
|
|
||||||
|
this.visible = true;
|
||||||
|
this.alpha = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
function loadAnimations():Void
|
function loadAnimations():Void
|
||||||
{
|
{
|
||||||
trace('[DIALOGUE BOX] Loading ${_data.animations.length} animations for ${id}');
|
trace('[DIALOGUE BOX] Loading ${_data.animations.length} animations for ${id}');
|
||||||
|
@ -246,7 +282,8 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||||
textDisplay.setFormat(_data.text.fontFamily, _data.text.size, FlxColor.fromString(_data.text.color), LEFT, SHADOW,
|
textDisplay.setFormat(_data.text.fontFamily, _data.text.size, FlxColor.fromString(_data.text.color), LEFT, SHADOW,
|
||||||
FlxColor.fromString(_data.text.shadowColor ?? '#00000000'), false);
|
FlxColor.fromString(_data.text.shadowColor ?? '#00000000'), false);
|
||||||
textDisplay.borderSize = _data.text.shadowWidth ?? 2;
|
textDisplay.borderSize = _data.text.shadowWidth ?? 2;
|
||||||
textDisplay.sounds = [FlxG.sound.load(Paths.sound('pixelText'), 0.6)];
|
// TODO: Add an option to configure this.
|
||||||
|
textDisplay.sounds = [FunkinSound.load(Paths.sound('pixelText'), 0.6)];
|
||||||
|
|
||||||
textDisplay.completeCallback = onTypingComplete;
|
textDisplay.completeCallback = onTypingComplete;
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,26 @@ class Speaker extends FlxSprite implements IDialogueScriptedClass implements IRe
|
||||||
loadAnimations();
|
loadAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls `kill()` on the group's members and then on the group itself.
|
||||||
|
* You can revive this group later via `revive()` after this.
|
||||||
|
*/
|
||||||
|
public override function kill():Void
|
||||||
|
{
|
||||||
|
super.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function revive():Void
|
||||||
|
{
|
||||||
|
super.revive();
|
||||||
|
|
||||||
|
this.visible = true;
|
||||||
|
this.alpha = 1.0;
|
||||||
|
|
||||||
|
loadSpritesheet();
|
||||||
|
loadAnimations();
|
||||||
|
}
|
||||||
|
|
||||||
function loadSpritesheet():Void
|
function loadSpritesheet():Void
|
||||||
{
|
{
|
||||||
trace('[SPEAKER] Loading spritesheet ${_data.assetPath} for ${id}');
|
trace('[SPEAKER] Loading spritesheet ${_data.assetPath} for ${id}');
|
||||||
|
|
|
@ -502,11 +502,11 @@ class SongDifficulty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function playInst(volume:Float = 1.0, looped:Bool = false):Void
|
public function playInst(volume:Float = 1.0, looped:Bool = false):Void
|
||||||
{
|
{
|
||||||
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
|
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
|
||||||
|
|
||||||
FlxG.sound.music = FunkinSound.load(Paths.inst(this.song.id, suffix), volume, looped);
|
FlxG.sound.music = FunkinSound.load(Paths.inst(this.song.id, suffix), volume, looped, false, true);
|
||||||
|
|
||||||
// Workaround for a bug where FlxG.sound.music.update() was being called twice.
|
// Workaround for a bug where FlxG.sound.music.update() was being called twice.
|
||||||
FlxG.sound.list.remove(FlxG.sound.music);
|
FlxG.sound.list.remove(FlxG.sound.music);
|
||||||
|
@ -614,9 +614,9 @@ class SongDifficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add player vocals.
|
// Add player vocals.
|
||||||
if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(Assets.getSound(voiceList[0])));
|
if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(voiceList[0]));
|
||||||
// Add opponent vocals.
|
// Add opponent vocals.
|
||||||
if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(Assets.getSound(voiceList[1])));
|
if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(voiceList[1]));
|
||||||
|
|
||||||
// Add additional vocals.
|
// Add additional vocals.
|
||||||
if (voiceList.length > 2)
|
if (voiceList.length > 2)
|
||||||
|
|
|
@ -893,12 +893,6 @@ typedef SaveControlsData =
|
||||||
*/
|
*/
|
||||||
var ?CUTSCENE_ADVANCE:Array<Int>;
|
var ?CUTSCENE_ADVANCE:Array<Int>;
|
||||||
|
|
||||||
/**
|
|
||||||
* Keybind for skipping a cutscene.
|
|
||||||
* @default `Escape`
|
|
||||||
*/
|
|
||||||
var ?CUTSCENE_SKIP:Array<Int>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keybind for increasing volume.
|
* Keybind for increasing volume.
|
||||||
* @default `Plus`
|
* @default `Plus`
|
||||||
|
|
|
@ -35,7 +35,6 @@ typedef SaveControlsData_v1_0_0 =
|
||||||
var ?ACCEPT:Array<Int>;
|
var ?ACCEPT:Array<Int>;
|
||||||
var ?BACK:Array<Int>;
|
var ?BACK:Array<Int>;
|
||||||
var ?CUTSCENE_ADVANCE:Array<Int>;
|
var ?CUTSCENE_ADVANCE:Array<Int>;
|
||||||
var ?CUTSCENE_SKIP:Array<Int>;
|
|
||||||
var ?NOTE_DOWN:Array<Int>;
|
var ?NOTE_DOWN:Array<Int>;
|
||||||
var ?NOTE_LEFT:Array<Int>;
|
var ?NOTE_LEFT:Array<Int>;
|
||||||
var ?NOTE_RIGHT:Array<Int>;
|
var ?NOTE_RIGHT:Array<Int>;
|
||||||
|
|
|
@ -272,7 +272,6 @@ class SaveDataMigrator
|
||||||
ACCEPT: controlsData?.keys?.ACCEPT ?? null,
|
ACCEPT: controlsData?.keys?.ACCEPT ?? null,
|
||||||
BACK: controlsData?.keys?.BACK ?? null,
|
BACK: controlsData?.keys?.BACK ?? null,
|
||||||
CUTSCENE_ADVANCE: controlsData?.keys?.CUTSCENE_ADVANCE ?? null,
|
CUTSCENE_ADVANCE: controlsData?.keys?.CUTSCENE_ADVANCE ?? null,
|
||||||
CUTSCENE_SKIP: controlsData?.keys?.CUTSCENE_SKIP ?? null,
|
|
||||||
NOTE_DOWN: controlsData?.keys?.NOTE_DOWN ?? null,
|
NOTE_DOWN: controlsData?.keys?.NOTE_DOWN ?? null,
|
||||||
NOTE_LEFT: controlsData?.keys?.NOTE_LEFT ?? null,
|
NOTE_LEFT: controlsData?.keys?.NOTE_LEFT ?? null,
|
||||||
NOTE_RIGHT: controlsData?.keys?.NOTE_RIGHT ?? null,
|
NOTE_RIGHT: controlsData?.keys?.NOTE_RIGHT ?? null,
|
||||||
|
@ -293,7 +292,6 @@ class SaveDataMigrator
|
||||||
ACCEPT: controlsData?.pad?.ACCEPT ?? null,
|
ACCEPT: controlsData?.pad?.ACCEPT ?? null,
|
||||||
BACK: controlsData?.pad?.BACK ?? null,
|
BACK: controlsData?.pad?.BACK ?? null,
|
||||||
CUTSCENE_ADVANCE: controlsData?.pad?.CUTSCENE_ADVANCE ?? null,
|
CUTSCENE_ADVANCE: controlsData?.pad?.CUTSCENE_ADVANCE ?? null,
|
||||||
CUTSCENE_SKIP: controlsData?.pad?.CUTSCENE_SKIP ?? null,
|
|
||||||
NOTE_DOWN: controlsData?.pad?.NOTE_DOWN ?? null,
|
NOTE_DOWN: controlsData?.pad?.NOTE_DOWN ?? null,
|
||||||
NOTE_LEFT: controlsData?.pad?.NOTE_LEFT ?? null,
|
NOTE_LEFT: controlsData?.pad?.NOTE_LEFT ?? null,
|
||||||
NOTE_RIGHT: controlsData?.pad?.NOTE_RIGHT ?? null,
|
NOTE_RIGHT: controlsData?.pad?.NOTE_RIGHT ?? null,
|
||||||
|
|
|
@ -51,6 +51,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
|
|
||||||
override function update(elapsed:Float):Void
|
override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
|
// 3.59% CPU Usage (100% is FlxTypedGroup#update() and most of that is updating each member.)
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
|
||||||
// Emergency exit button.
|
// Emergency exit button.
|
||||||
|
@ -61,8 +62,11 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
|
|
||||||
// Display Conductor info in the watch window.
|
// Display Conductor info in the watch window.
|
||||||
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
||||||
|
|
||||||
|
// 0.09% CPU Usage?
|
||||||
Conductor.watchQuick();
|
Conductor.watchQuick();
|
||||||
|
|
||||||
|
// 4.31% CPU Usage
|
||||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2838,12 +2838,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
menuBarItemInputStyleNone.onClick = function(event:UIEvent) {
|
menuBarItemInputStyleNone.onClick = function(event:UIEvent) {
|
||||||
currentLiveInputStyle = None;
|
currentLiveInputStyle = None;
|
||||||
};
|
};
|
||||||
|
menuBarItemInputStyleNone.selected = currentLiveInputStyle == None;
|
||||||
menuBarItemInputStyleNumberKeys.onClick = function(event:UIEvent) {
|
menuBarItemInputStyleNumberKeys.onClick = function(event:UIEvent) {
|
||||||
currentLiveInputStyle = NumberKeys;
|
currentLiveInputStyle = NumberKeys;
|
||||||
};
|
};
|
||||||
|
menuBarItemInputStyleNumberKeys.selected = currentLiveInputStyle == NumberKeys;
|
||||||
menuBarItemInputStyleWASD.onClick = function(event:UIEvent) {
|
menuBarItemInputStyleWASD.onClick = function(event:UIEvent) {
|
||||||
currentLiveInputStyle = WASD;
|
currentLiveInputStyle = WASDKeys;
|
||||||
};
|
};
|
||||||
|
menuBarItemInputStyleWASD.selected = currentLiveInputStyle == WASDKeys;
|
||||||
|
|
||||||
menubarItemAbout.onClick = _ -> this.openAboutDialog();
|
menubarItemAbout.onClick = _ -> this.openAboutDialog();
|
||||||
menubarItemWelcomeDialog.onClick = _ -> this.openWelcomeDialog(true);
|
menubarItemWelcomeDialog.onClick = _ -> this.openWelcomeDialog(true);
|
||||||
|
@ -2942,7 +2945,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
menubarItemPlaybackSpeed.onChange = event -> {
|
menubarItemPlaybackSpeed.onChange = event -> {
|
||||||
var pitch:Float = (event.value.toFloat() * 2.0) / 100.0;
|
var pitch:Float = (event.value.toFloat() * 2.0) / 100.0;
|
||||||
pitch = Math.floor(pitch / 0.25) * 0.25; // Round to nearest 0.25.
|
pitch = Math.floor(pitch / 0.05) * 0.05; // Round to nearest 5%
|
||||||
|
pitch = Math.max(0.05, Math.min(2.0, pitch)); // Clamp to 5% to 200%
|
||||||
#if FLX_PITCH
|
#if FLX_PITCH
|
||||||
if (audioInstTrack != null) audioInstTrack.pitch = pitch;
|
if (audioInstTrack != null) audioInstTrack.pitch = pitch;
|
||||||
audioVocalTrackGroup.pitch = pitch;
|
audioVocalTrackGroup.pitch = pitch;
|
||||||
|
@ -4933,7 +4937,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Place notes at the playhead.
|
// Place notes at the playhead.
|
||||||
switch (currentLiveInputStyle)
|
switch (currentLiveInputStyle)
|
||||||
{
|
{
|
||||||
case ChartEditorLiveInputStyle.WASD:
|
case ChartEditorLiveInputStyle.WASDKeys:
|
||||||
if (FlxG.keys.justPressed.A) placeNoteAtPlayhead(4);
|
if (FlxG.keys.justPressed.A) placeNoteAtPlayhead(4);
|
||||||
if (FlxG.keys.justPressed.S) placeNoteAtPlayhead(5);
|
if (FlxG.keys.justPressed.S) placeNoteAtPlayhead(5);
|
||||||
if (FlxG.keys.justPressed.W) placeNoteAtPlayhead(6);
|
if (FlxG.keys.justPressed.W) placeNoteAtPlayhead(6);
|
||||||
|
@ -5236,6 +5240,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
// Would bind Ctrl+A and Ctrl+D here, but they are already bound to Select All and Select None.
|
// Would bind Ctrl+A and Ctrl+D here, but they are already bound to Select All and Select None.
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Ignoring keybinds for View menu items because we are in live input mode (${currentLiveInputStyle}).');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6125,7 +6133,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Available input modes for the chart editor state.
|
* Available input modes for the chart editor state. Numbers/arrows/WASD available for other keybinds.
|
||||||
*/
|
*/
|
||||||
enum ChartEditorLiveInputStyle
|
enum ChartEditorLiveInputStyle
|
||||||
{
|
{
|
||||||
|
@ -6140,9 +6148,9 @@ enum ChartEditorLiveInputStyle
|
||||||
NumberKeys;
|
NumberKeys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WASD to place notes on opponent's side, arrow keys to place notes on player's side.
|
* WASD to place notes on opponent's side, Arrow keys to place notes on player's side.
|
||||||
*/
|
*/
|
||||||
WASD;
|
WASDKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef ChartEditorParams =
|
typedef ChartEditorParams =
|
||||||
|
|
|
@ -36,11 +36,24 @@ class ConversationDebugState extends MusicBeatState
|
||||||
|
|
||||||
public override function create():Void
|
public override function create():Void
|
||||||
{
|
{
|
||||||
conversation = ConversationRegistry.instance.fetchEntry(conversationId);
|
super.create();
|
||||||
conversation.completeCallback = onConversationComplete;
|
startConversation();
|
||||||
add(conversation);
|
}
|
||||||
|
|
||||||
ScriptEventDispatcher.callEvent(conversation, new ScriptEvent(CREATE, false));
|
function startConversation():Void
|
||||||
|
{
|
||||||
|
if (conversation != null) return;
|
||||||
|
|
||||||
|
conversation = ConversationRegistry.instance.fetchEntry(conversationId);
|
||||||
|
if (conversation == null) return;
|
||||||
|
if (!conversation.alive) conversation.revive();
|
||||||
|
|
||||||
|
conversation.zIndex = 1000;
|
||||||
|
add(conversation);
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
var event:ScriptEvent = new ScriptEvent(CREATE, false);
|
||||||
|
ScriptEventDispatcher.callEvent(conversation, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onConversationComplete():Void
|
function onConversationComplete():Void
|
||||||
|
@ -61,15 +74,17 @@ class ConversationDebugState extends MusicBeatState
|
||||||
|
|
||||||
if (conversation != null)
|
if (conversation != null)
|
||||||
{
|
{
|
||||||
if (controls.CUTSCENE_ADVANCE) conversation.advanceConversation();
|
if (controls.CUTSCENE_ADVANCE)
|
||||||
|
|
||||||
if (controls.CUTSCENE_SKIP)
|
|
||||||
{
|
{
|
||||||
conversation.trySkipConversation(elapsed);
|
conversation.advanceConversation();
|
||||||
}
|
}
|
||||||
else
|
else if (controls.PAUSE)
|
||||||
{
|
{
|
||||||
conversation.trySkipConversation(-1);
|
conversation.kill();
|
||||||
|
remove(conversation);
|
||||||
|
conversation = null;
|
||||||
|
|
||||||
|
FlxG.switchState(() -> new ConversationDebugState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
|
||||||
static var controlGroups:Array<Array<Control>> = [
|
static var controlGroups:Array<Array<Control>> = [
|
||||||
[NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT],
|
[NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT],
|
||||||
[UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK],
|
[UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK],
|
||||||
[CUTSCENE_ADVANCE, CUTSCENE_SKIP],
|
[CUTSCENE_ADVANCE],
|
||||||
[VOLUME_UP, VOLUME_DOWN, VOLUME_MUTE],
|
[VOLUME_UP, VOLUME_DOWN, VOLUME_MUTE],
|
||||||
[DEBUG_MENU, DEBUG_CHART]
|
[DEBUG_MENU, DEBUG_CHART]
|
||||||
];
|
];
|
||||||
|
|
37
source/funkin/util/plugins/MemoryGCPlugin.hx
Normal file
37
source/funkin/util/plugins/MemoryGCPlugin.hx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package funkin.util.plugins;
|
||||||
|
|
||||||
|
import flixel.FlxBasic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plugin which adds functionality to press `Ins` to immediately perform memory garbage collection.
|
||||||
|
*/
|
||||||
|
class MemoryGCPlugin extends FlxBasic
|
||||||
|
{
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initialize():Void
|
||||||
|
{
|
||||||
|
FlxG.plugins.addPlugin(new MemoryGCPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (FlxG.keys.justPressed.INSERT)
|
||||||
|
{
|
||||||
|
var perfStart:Float = Sys.time();
|
||||||
|
funkin.util.MemoryUtil.collect(true);
|
||||||
|
var perfEnd:Float = Sys.time();
|
||||||
|
trace("Memory GC took " + (perfEnd - perfStart) + " seconds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function destroy():Void
|
||||||
|
{
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,10 @@ class WatchPlugin extends FlxBasic
|
||||||
|
|
||||||
FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition);
|
FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition);
|
||||||
FlxG.watch.addQuick("songPositionNoOffset", Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
|
FlxG.watch.addQuick("songPositionNoOffset", Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
|
||||||
|
|
||||||
|
FlxG.watch.addQuick("musicLength", FlxG.sound?.music?.length ?? 0.0);
|
||||||
FlxG.watch.addQuick("musicTime", FlxG.sound?.music?.time ?? 0.0);
|
FlxG.watch.addQuick("musicTime", FlxG.sound?.music?.time ?? 0.0);
|
||||||
|
|
||||||
FlxG.watch.addQuick("bpm", Conductor.instance.bpm);
|
FlxG.watch.addQuick("bpm", Conductor.instance.bpm);
|
||||||
FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime);
|
FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime);
|
||||||
FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime);
|
FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime);
|
||||||
|
|
Loading…
Reference in a new issue