2022-03-08 08:13:53 +00:00
|
|
|
package funkin;
|
2020-10-10 02:39:52 +00:00
|
|
|
|
2022-03-21 04:19:05 +00:00
|
|
|
import flixel.FlxState;
|
|
|
|
import flixel.FlxSubState;
|
2022-04-18 23:36:09 +00:00
|
|
|
import flixel.addons.ui.FlxUIState;
|
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.Conductor.BPMChangeEvent;
|
|
|
|
import funkin.modding.PolymodHandler;
|
2022-03-13 18:36:03 +00:00
|
|
|
import funkin.modding.events.ScriptEvent;
|
|
|
|
import funkin.modding.module.ModuleHandler;
|
2022-04-19 00:39:41 +00:00
|
|
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
|
|
|
import funkin.play.stage.StageData.StageDataParser;
|
2022-04-18 23:36:09 +00:00
|
|
|
import funkin.util.SortUtil;
|
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.
|
|
|
|
*/
|
2020-10-12 03:52:21 +00:00
|
|
|
class MusicBeatState extends FlxUIState
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2020-10-13 08:07:04 +00:00
|
|
|
private var curStep:Int = 0;
|
|
|
|
private var curBeat:Int = 0;
|
2020-10-28 08:24:56 +00:00
|
|
|
private var controls(get, never):Controls;
|
2022-02-18 21:29:29 +00:00
|
|
|
private var lastBeatHitTime:Float = 0;
|
2020-10-28 08:24:56 +00:00
|
|
|
|
|
|
|
inline function get_controls():Controls
|
|
|
|
return PlayerSettings.player1.controls;
|
2020-10-13 08:07:04 +00:00
|
|
|
|
2022-03-13 18:36:03 +00:00
|
|
|
public var leftWatermarkText:FlxText = null;
|
|
|
|
public var rightWatermarkText:FlxText = null;
|
|
|
|
|
2022-03-21 04:19:05 +00:00
|
|
|
public function new()
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
|
|
|
|
initCallbacks();
|
|
|
|
}
|
|
|
|
|
|
|
|
function initCallbacks()
|
|
|
|
{
|
|
|
|
subStateOpened.add(onOpenSubstateComplete);
|
|
|
|
subStateClosed.add(onCloseSubstateComplete);
|
|
|
|
}
|
|
|
|
|
2020-10-10 02:39:52 +00:00
|
|
|
override function create()
|
|
|
|
{
|
2022-03-13 18:36:03 +00:00
|
|
|
super.create();
|
|
|
|
|
|
|
|
createWatermarkText();
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|
|
|
|
|
2020-10-10 03:22:07 +00:00
|
|
|
override function update(elapsed:Float)
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2022-03-13 18:36:03 +00:00
|
|
|
super.update(elapsed);
|
|
|
|
|
2022-03-21 04:19:05 +00:00
|
|
|
// This can now be used in EVERY STATE YAY!
|
|
|
|
if (FlxG.keys.justPressed.F5)
|
|
|
|
debug_refreshModules();
|
|
|
|
|
2021-04-01 23:39:03 +00:00
|
|
|
// everyStep();
|
2021-02-12 00:58:11 +00:00
|
|
|
var oldStep:Int = curStep;
|
2020-10-10 03:22:07 +00:00
|
|
|
|
2020-10-16 11:03:10 +00:00
|
|
|
updateCurStep();
|
2020-11-21 10:43:04 +00:00
|
|
|
updateBeat();
|
2020-10-13 08:07:04 +00:00
|
|
|
|
2021-03-17 17:33:26 +00:00
|
|
|
if (oldStep != curStep && curStep >= 0)
|
2021-02-12 00:58:11 +00:00
|
|
|
stepHit();
|
|
|
|
|
2022-04-18 23:36:09 +00:00
|
|
|
FlxG.watch.addQuick("songPos", Conductor.songPosition);
|
|
|
|
|
2022-03-13 18:36:03 +00:00
|
|
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
add(leftWatermarkText);
|
|
|
|
add(rightWatermarkText);
|
|
|
|
}
|
|
|
|
|
|
|
|
function dispatchEvent(event:ScriptEvent)
|
|
|
|
{
|
|
|
|
ModuleHandler.callEvent(event);
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 04:19:05 +00:00
|
|
|
function debug_refreshModules()
|
|
|
|
{
|
2022-04-18 23:36:09 +00:00
|
|
|
PolymodHandler.forceReloadAssets();
|
2022-03-21 04:19:05 +00:00
|
|
|
|
2022-03-27 02:18:26 +00:00
|
|
|
// Restart the current state, so old data is cleared.
|
2022-03-21 04:19:05 +00:00
|
|
|
FlxG.resetState();
|
|
|
|
}
|
|
|
|
|
2020-11-21 10:43:04 +00:00
|
|
|
private function updateBeat():Void
|
|
|
|
{
|
2021-02-11 22:06:26 +00:00
|
|
|
curBeat = Math.floor(curStep / 4);
|
2020-11-21 10:43:04 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 11:03:10 +00:00
|
|
|
private function updateCurStep():Void
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2021-02-11 22:06:26 +00:00
|
|
|
var lastChange:BPMChangeEvent = {
|
|
|
|
stepTime: 0,
|
|
|
|
songTime: 0,
|
|
|
|
bpm: 0
|
|
|
|
}
|
|
|
|
for (i in 0...Conductor.bpmChangeMap.length)
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2021-02-11 22:06:26 +00:00
|
|
|
if (Conductor.songPosition >= Conductor.bpmChangeMap[i].songTime)
|
|
|
|
lastChange = Conductor.bpmChangeMap[i];
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|
|
|
|
|
2021-02-11 22:06:26 +00:00
|
|
|
curStep = lastChange.stepTime + Math.floor((Conductor.songPosition - lastChange.songTime) / Conductor.stepCrochet);
|
2020-10-16 11:03:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-30 01:56:04 +00:00
|
|
|
public function stepHit():Bool
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2022-03-30 01:56:04 +00:00
|
|
|
var event = new SongTimeScriptEvent(ScriptEvent.SONG_STEP_HIT, curBeat, curStep);
|
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-12 02:19:27 +00:00
|
|
|
if (curStep % 4 == 0)
|
2020-10-10 03:22:07 +00:00
|
|
|
beatHit();
|
2022-03-30 01:56:04 +00:00
|
|
|
|
|
|
|
return true;
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|
|
|
|
|
2022-03-30 01:56:04 +00:00
|
|
|
public function beatHit():Bool
|
2020-10-10 02:39:52 +00:00
|
|
|
{
|
2022-03-30 01:56:04 +00:00
|
|
|
var event = new SongTimeScriptEvent(ScriptEvent.SONG_BEAT_HIT, curBeat, curStep);
|
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-18 21:29:29 +00:00
|
|
|
lastBeatHitTime = Conductor.songPosition;
|
2022-03-30 01:56:04 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|
2022-03-21 04:19:05 +00:00
|
|
|
|
|
|
|
override function switchTo(nextState:FlxState):Bool
|
|
|
|
{
|
|
|
|
var event = new StateChangeScriptEvent(ScriptEvent.STATE_CHANGE_BEGIN, nextState, true);
|
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return super.switchTo(nextState);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override function openSubState(targetSubstate:FlxSubState):Void
|
|
|
|
{
|
|
|
|
var event = new SubStateScriptEvent(ScriptEvent.SUBSTATE_OPEN_BEGIN, targetSubstate, true);
|
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
super.openSubState(targetSubstate);
|
|
|
|
}
|
|
|
|
|
|
|
|
function onOpenSubstateComplete(targetState:FlxSubState):Void
|
|
|
|
{
|
|
|
|
dispatchEvent(new SubStateScriptEvent(ScriptEvent.SUBSTATE_OPEN_END, targetState, true));
|
|
|
|
}
|
|
|
|
|
|
|
|
public override function closeSubState():Void
|
|
|
|
{
|
|
|
|
var event = new SubStateScriptEvent(ScriptEvent.SUBSTATE_CLOSE_BEGIN, this.subState, true);
|
|
|
|
|
|
|
|
dispatchEvent(event);
|
|
|
|
|
|
|
|
if (event.eventCanceled)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
super.closeSubState();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCloseSubstateComplete(targetState:FlxSubState):Void
|
|
|
|
{
|
|
|
|
dispatchEvent(new SubStateScriptEvent(ScriptEvent.SUBSTATE_CLOSE_END, targetState, true));
|
|
|
|
}
|
2020-10-10 02:39:52 +00:00
|
|
|
}
|