2023-11-07 09:04:22 +00:00
|
|
|
package funkin.ui;
|
2020-10-10 02:39:52 +00:00
|
|
|
|
2023-06-16 21:37:56 +00:00
|
|
|
import funkin.modding.IScriptedClass.IEventHandler;
|
2023-11-07 09:04:22 +00:00
|
|
|
import funkin.ui.mainmenu.MainMenuState;
|
2022-03-21 04:19:05 +00:00
|
|
|
import flixel.FlxState;
|
|
|
|
import flixel.FlxSubState;
|
2023-07-26 20:52:58 +00:00
|
|
|
import flixel.addons.transition.FlxTransitionableState;
|
2022-03-13 18:36:03 +00:00
|
|
|
import flixel.text.FlxText;
|
2022-04-18 23:36:09 +00:00
|
|
|
import flixel.util.FlxColor;
|
|
|
|
import flixel.util.FlxSort;
|
|
|
|
import funkin.modding.PolymodHandler;
|
2022-03-13 18:36:03 +00:00
|
|
|
import funkin.modding.events.ScriptEvent;
|
|
|
|
import funkin.modding.module.ModuleHandler;
|
2022-04-18 23:36:09 +00:00
|
|
|
import funkin.util.SortUtil;
|
2023-10-31 19:30:47 +00:00
|
|
|
import funkin.input.Controls;
|
2020-10-10 02:39:52 +00:00
|
|
|
|
2022-03-21 04:19:05 +00:00
|
|
|
/**
|
|
|
|
* MusicBeatState actually represents the core utility FlxState of the game.
|
|
|
|
* It includes functionality for event handling, as well as maintaining BPM-based update events.
|
|
|
|
*/
|
2023-07-26 20:52:58 +00:00
|
|
|
class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2023-01-23 03:25:45 +00:00
|
|
|
var controls(get, never):Controls;
|
|
|
|
|
|
|
|
inline function get_controls():Controls
|
|
|
|
return PlayerSettings.player1.controls;
|
|
|
|
|
|
|
|
public var leftWatermarkText:FlxText = null;
|
|
|
|
public var rightWatermarkText:FlxText = null;
|
|
|
|
|
|
|
|
public function new()
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
|
|
|
|
initCallbacks();
|
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
function initCallbacks()
|
|
|
|
{
|
2023-06-09 19:44:29 +00:00
|
|
|
subStateOpened.add(onOpenSubStateComplete);
|
|
|
|
subStateClosed.add(onCloseSubStateComplete);
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
2022-09-07 23:07:08 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
override function create()
|
|
|
|
{
|
|
|
|
super.create();
|
|
|
|
|
|
|
|
createWatermarkText();
|
|
|
|
|
|
|
|
Conductor.beatHit.add(this.beatHit);
|
|
|
|
Conductor.stepHit.add(this.stepHit);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override function destroy():Void
|
|
|
|
{
|
|
|
|
super.destroy();
|
|
|
|
Conductor.beatHit.remove(this.beatHit);
|
|
|
|
Conductor.stepHit.remove(this.stepHit);
|
|
|
|
}
|
2022-03-13 18:36:03 +00:00
|
|
|
|
2023-10-27 05:42:05 +00:00
|
|
|
function handleControls():Void
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
2023-10-27 05:42:05 +00:00
|
|
|
var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
|
|
|
|
|
|
|
|
if (!isHaxeUIFocused)
|
|
|
|
{
|
|
|
|
// Rebindable volume keys.
|
|
|
|
if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
|
|
|
|
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
|
|
|
|
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
|
|
|
|
}
|
|
|
|
}
|
2023-07-08 05:03:46 +00:00
|
|
|
|
2023-10-27 05:42:05 +00:00
|
|
|
function handleFunctionControls():Void
|
|
|
|
{
|
2023-01-23 03:25:45 +00:00
|
|
|
// Emergency exit button.
|
|
|
|
if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState());
|
2022-03-13 18:36:03 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
// This can now be used in EVERY STATE YAY!
|
|
|
|
if (FlxG.keys.justPressed.F5) debug_refreshModules();
|
2023-10-27 05:42:05 +00:00
|
|
|
}
|
2022-03-13 18:36:03 +00:00
|
|
|
|
2023-10-27 05:42:05 +00:00
|
|
|
function handleQuickWatch():Void
|
|
|
|
{
|
2023-01-23 03:25:45 +00:00
|
|
|
// Display Conductor info in the watch window.
|
2023-07-02 20:17:04 +00:00
|
|
|
FlxG.watch.addQuick("songPosition", Conductor.songPosition);
|
2023-12-08 06:15:22 +00:00
|
|
|
FlxG.watch.addQuick("songPositionNoOffset", Conductor.songPosition + Conductor.instrumentalOffset);
|
2023-12-05 07:44:57 +00:00
|
|
|
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
2023-01-23 03:25:45 +00:00
|
|
|
FlxG.watch.addQuick("bpm", Conductor.bpm);
|
2023-07-02 20:17:04 +00:00
|
|
|
FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime);
|
|
|
|
FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime);
|
|
|
|
FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime);
|
2023-10-27 05:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override function update(elapsed:Float)
|
|
|
|
{
|
|
|
|
super.update(elapsed);
|
|
|
|
|
|
|
|
handleControls();
|
|
|
|
handleFunctionControls();
|
|
|
|
handleQuickWatch();
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
function createWatermarkText()
|
|
|
|
{
|
|
|
|
// Both have an xPos of 0, but a width equal to the full screen.
|
|
|
|
// The rightWatermarkText is right aligned, which puts the text in the correct spot.
|
|
|
|
leftWatermarkText = new FlxText(0, FlxG.height - 18, FlxG.width, '', 12);
|
|
|
|
rightWatermarkText = new FlxText(0, FlxG.height - 18, FlxG.width, '', 12);
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
// 100,000 should be good enough.
|
|
|
|
leftWatermarkText.zIndex = 100000;
|
|
|
|
rightWatermarkText.zIndex = 100000;
|
|
|
|
leftWatermarkText.scrollFactor.set(0, 0);
|
|
|
|
rightWatermarkText.scrollFactor.set(0, 0);
|
|
|
|
leftWatermarkText.setFormat("VCR OSD Mono", 16, FlxColor.WHITE, LEFT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
|
|
|
|
rightWatermarkText.setFormat("VCR OSD Mono", 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
add(leftWatermarkText);
|
|
|
|
add(rightWatermarkText);
|
|
|
|
}
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-06-16 21:37:56 +00:00
|
|
|
public function dispatchEvent(event:ScriptEvent)
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
|
|
|
ModuleHandler.callEvent(event);
|
|
|
|
}
|
2020-10-10 02:39:52 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
function debug_refreshModules()
|
|
|
|
{
|
|
|
|
PolymodHandler.forceReloadAssets();
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-07-14 00:27:45 +00:00
|
|
|
this.destroy();
|
|
|
|
|
|
|
|
// Create a new instance of the current state, so old data is cleared.
|
2023-01-23 03:25:45 +00:00
|
|
|
FlxG.resetState();
|
|
|
|
}
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
public function stepHit():Bool
|
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
var event = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.currentBeat, Conductor.currentStep);
|
2022-03-30 01:56:04 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
dispatchEvent(event);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
if (event.eventCanceled) return false;
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
public function beatHit():Bool
|
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
var event = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.currentBeat, Conductor.currentStep);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
dispatchEvent(event);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
if (event.eventCanceled) return false;
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
/**
|
|
|
|
* Refreshes the state, by redoing the render order of all sprites.
|
|
|
|
* It does this based on the `zIndex` of each prop.
|
|
|
|
*/
|
|
|
|
public function refresh()
|
|
|
|
{
|
|
|
|
sort(SortUtil.byZIndex, FlxSort.ASCENDING);
|
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-05-25 22:33:39 +00:00
|
|
|
override function startOutro(onComplete:() -> Void):Void
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
var event = new StateChangeScriptEvent(STATE_CHANGE_BEGIN, null, true);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
dispatchEvent(event);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-05-25 22:33:39 +00:00
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onComplete();
|
|
|
|
}
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-06-09 19:44:29 +00:00
|
|
|
public override function openSubState(targetSubState:FlxSubState):Void
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
var event = new SubStateScriptEvent(SUBSTATE_OPEN_BEGIN, targetSubState, true);
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2023-01-23 03:25:45 +00:00
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled) return;
|
|
|
|
|
2023-06-09 19:44:29 +00:00
|
|
|
super.openSubState(targetSubState);
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
|
|
|
|
2023-06-09 19:44:29 +00:00
|
|
|
function onOpenSubStateComplete(targetState:FlxSubState):Void
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
dispatchEvent(new SubStateScriptEvent(SUBSTATE_OPEN_END, targetState, true));
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public override function closeSubState():Void
|
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
var event = new SubStateScriptEvent(SUBSTATE_CLOSE_BEGIN, this.subState, true);
|
2023-01-23 03:25:45 +00:00
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled) return;
|
|
|
|
|
|
|
|
super.closeSubState();
|
|
|
|
}
|
|
|
|
|
2023-06-09 19:44:29 +00:00
|
|
|
function onCloseSubStateComplete(targetState:FlxSubState):Void
|
2023-01-23 03:25:45 +00:00
|
|
|
{
|
2023-10-26 09:46:22 +00:00
|
|
|
dispatchEvent(new SubStateScriptEvent(SUBSTATE_CLOSE_END, targetState, true));
|
2023-01-23 03:25:45 +00:00
|
|
|
}
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|