mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
Merge branch 'rewrite/master' into bugfix/cut-pico-dadbattle
This commit is contained in:
commit
9fd780e00c
32 changed files with 437 additions and 443 deletions
6
.github/workflows/build-shit.yml
vendored
6
.github/workflows/build-shit.yml
vendored
|
@ -13,8 +13,9 @@ jobs:
|
|||
apt update
|
||||
apt install -y sudo git curl unzip
|
||||
- name: Fix git config on posix runner
|
||||
# this can't be {{ github.workspace }} because that's not docker-aware
|
||||
run: |
|
||||
git config --global --add safe.directory ${{ github.workspace }}
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
- name: Get checkout token
|
||||
uses: actions/create-github-app-token@v1
|
||||
id: app_token
|
||||
|
@ -90,8 +91,9 @@ jobs:
|
|||
runs-on: [self-hosted, macos]
|
||||
steps:
|
||||
- name: Fix git config on posix runner
|
||||
# this can't be {{ github.workspace }} because that's not docker-aware
|
||||
run: |
|
||||
git config --global --add safe.directory ${{ github.workspace }}
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
- name: Get checkout token
|
||||
uses: actions/create-github-app-token@v1
|
||||
id: app_token
|
||||
|
|
|
@ -4,6 +4,7 @@ export
|
|||
# Ignore all JSONS in the images folder (including FlxAnimate JSONs)
|
||||
assets/preload/images
|
||||
assets/shared/images
|
||||
assets/weekend1/images
|
||||
|
||||
# Don't ignore data files
|
||||
# TODO: These don't work.
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
{
|
||||
"props": {
|
||||
"ignoreExtern": true,
|
||||
"format": "^[A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$",
|
||||
"format": "^[a-z][A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$",
|
||||
"tokens": ["INLINE", "NOTINLINE"]
|
||||
},
|
||||
"type": "ConstantName"
|
||||
|
|
|
@ -11,9 +11,11 @@ import openfl.display.Sprite;
|
|||
import openfl.events.Event;
|
||||
import openfl.Lib;
|
||||
import openfl.media.Video;
|
||||
import funkin.util.CLIUtil;
|
||||
import openfl.net.NetStream;
|
||||
|
||||
/**
|
||||
* The main class which initializes HaxeFlixel and starts the game in its initial state.
|
||||
*/
|
||||
class Main extends Sprite
|
||||
{
|
||||
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||
|
@ -76,26 +78,27 @@ class Main extends Sprite
|
|||
var netStream:NetStream;
|
||||
var overlay:Sprite;
|
||||
|
||||
/**
|
||||
* A frame counter displayed at the top left.
|
||||
*/
|
||||
public static var fpsCounter:FPS;
|
||||
|
||||
/**
|
||||
* A RAM counter displayed at the top left.
|
||||
*/
|
||||
public static var memoryCounter:MemoryCounter;
|
||||
|
||||
function setupGame():Void
|
||||
{
|
||||
/**
|
||||
* The `zoom` argument of FlxGame was removed in the dev branch of Flixel,
|
||||
* since it was considered confusing and unintuitive.
|
||||
* If you want to change how the game scales when you resize the window,
|
||||
* you can use `FlxG.scaleMode`.
|
||||
* -Eric
|
||||
*/
|
||||
|
||||
initHaxeUI();
|
||||
|
||||
// addChild gets called by the user settings code.
|
||||
fpsCounter = new FPS(10, 3, 0xFFFFFF);
|
||||
// addChild(fpsCounter); // Handled by Preferences.init
|
||||
|
||||
#if !html5
|
||||
// addChild gets called by the user settings code.
|
||||
// TODO: disabled on HTML5 (todo: find another method that works?)
|
||||
memoryCounter = new MemoryCounter(10, 13, 0xFFFFFF);
|
||||
// addChild(memoryCounter);
|
||||
#end
|
||||
|
||||
// George recommends binding the save before FlxGame is created.
|
||||
|
@ -112,6 +115,8 @@ class Main extends Sprite
|
|||
|
||||
#if hxcpp_debug_server
|
||||
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
|
||||
#else
|
||||
trace('hxcpp_debug_server is disabled! This build does not support debugging.');
|
||||
#end
|
||||
}
|
||||
|
||||
|
|
|
@ -3,34 +3,37 @@ package source; // Yeah, I know...
|
|||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
|
||||
/**
|
||||
* A script which executes after the game is built.
|
||||
*/
|
||||
class Postbuild
|
||||
{
|
||||
static inline final buildTimeFile = '.build_time';
|
||||
static inline final BUILD_TIME_FILE:String = '.build_time';
|
||||
|
||||
static function main()
|
||||
static function main():Void
|
||||
{
|
||||
printBuildTime();
|
||||
}
|
||||
|
||||
static function printBuildTime()
|
||||
static function printBuildTime():Void
|
||||
{
|
||||
// get buildEnd before fs operations since they are blocking
|
||||
var end:Float = Sys.time();
|
||||
if (FileSystem.exists(buildTimeFile))
|
||||
if (FileSystem.exists(BUILD_TIME_FILE))
|
||||
{
|
||||
var fi = File.read(buildTimeFile);
|
||||
var fi:sys.io.FileInput = File.read(BUILD_TIME_FILE);
|
||||
var start:Float = fi.readDouble();
|
||||
fi.close();
|
||||
|
||||
sys.FileSystem.deleteFile(buildTimeFile);
|
||||
sys.FileSystem.deleteFile(BUILD_TIME_FILE);
|
||||
|
||||
var buildTime = roundToTwoDecimals(end - start);
|
||||
var buildTime:Float = roundToTwoDecimals(end - start);
|
||||
|
||||
trace('Build took: ${buildTime} seconds');
|
||||
}
|
||||
}
|
||||
|
||||
private static function roundToTwoDecimals(value:Float):Float
|
||||
static function roundToTwoDecimals(value:Float):Float
|
||||
{
|
||||
return Math.round(value * 100) / 100;
|
||||
}
|
||||
|
|
|
@ -2,20 +2,23 @@ package source; // Yeah, I know...
|
|||
|
||||
import sys.io.File;
|
||||
|
||||
/**
|
||||
* A script which executes before the game is built.
|
||||
*/
|
||||
class Prebuild
|
||||
{
|
||||
static inline final buildTimeFile = '.build_time';
|
||||
static inline final BUILD_TIME_FILE:String = '.build_time';
|
||||
|
||||
static function main()
|
||||
static function main():Void
|
||||
{
|
||||
saveBuildTime();
|
||||
trace('Building...');
|
||||
}
|
||||
|
||||
static function saveBuildTime()
|
||||
static function saveBuildTime():Void
|
||||
{
|
||||
var fo = File.write(buildTimeFile);
|
||||
var now = Sys.time();
|
||||
var fo:sys.io.FileOutput = File.write(BUILD_TIME_FILE);
|
||||
var now:Float = Sys.time();
|
||||
fo.writeDouble(now);
|
||||
fo.close();
|
||||
}
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
package flixel.addons.transition;
|
||||
|
||||
import flixel.FlxSubState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
|
||||
/**
|
||||
* A `FlxSubState` which can perform visual transitions
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* First, extend `FlxTransitionableSubState` as ie, `FooState`.
|
||||
*
|
||||
* Method 1:
|
||||
*
|
||||
* ```haxe
|
||||
* var in:TransitionData = new TransitionData(...); // add your data where "..." is
|
||||
* var out:TransitionData = new TransitionData(...);
|
||||
*
|
||||
* FlxG.switchState(() -> new FooState(in,out));
|
||||
* ```
|
||||
*
|
||||
* Method 2:
|
||||
*
|
||||
* ```haxe
|
||||
* FlxTransitionableSubState.defaultTransIn = new TransitionData(...);
|
||||
* FlxTransitionableSubState.defaultTransOut = new TransitionData(...);
|
||||
*
|
||||
* FlxG.switchState(() -> new FooState());
|
||||
* ```
|
||||
*/
|
||||
class FlxTransitionableSubState extends FlxSubState
|
||||
{
|
||||
// global default transitions for ALL states, used if transIn/transOut are null
|
||||
public static var defaultTransIn(get, set):TransitionData;
|
||||
|
||||
static function get_defaultTransIn():TransitionData
|
||||
{
|
||||
return FlxTransitionableState.defaultTransIn;
|
||||
}
|
||||
|
||||
static function set_defaultTransIn(value:TransitionData):TransitionData
|
||||
{
|
||||
return FlxTransitionableState.defaultTransIn = value;
|
||||
}
|
||||
|
||||
public static var defaultTransOut(get, set):TransitionData;
|
||||
|
||||
static function get_defaultTransOut():TransitionData
|
||||
{
|
||||
return FlxTransitionableState.defaultTransOut;
|
||||
}
|
||||
|
||||
static function set_defaultTransOut(value:TransitionData):TransitionData
|
||||
{
|
||||
return FlxTransitionableState.defaultTransOut = value;
|
||||
}
|
||||
|
||||
public static var skipNextTransIn(get, set):Bool;
|
||||
|
||||
static function get_skipNextTransIn():Bool
|
||||
{
|
||||
return FlxTransitionableState.skipNextTransIn;
|
||||
}
|
||||
|
||||
static function set_skipNextTransIn(value:Bool):Bool
|
||||
{
|
||||
return FlxTransitionableState.skipNextTransIn = value;
|
||||
}
|
||||
|
||||
public static var skipNextTransOut(get, set):Bool;
|
||||
|
||||
static function get_skipNextTransOut():Bool
|
||||
{
|
||||
return FlxTransitionableState.skipNextTransOut;
|
||||
}
|
||||
|
||||
static function set_skipNextTransOut(value:Bool):Bool
|
||||
{
|
||||
return FlxTransitionableState.skipNextTransOut = value;
|
||||
}
|
||||
|
||||
// beginning & ending transitions for THIS state:
|
||||
public var transIn:TransitionData;
|
||||
public var transOut:TransitionData;
|
||||
|
||||
public var hasTransIn(get, never):Bool;
|
||||
public var hasTransOut(get, never):Bool;
|
||||
|
||||
/**
|
||||
* Create a state with the ability to do visual transitions
|
||||
* @param TransIn Plays when the state begins
|
||||
* @param TransOut Plays when the state ends
|
||||
*/
|
||||
public function new(?TransIn:TransitionData, ?TransOut:TransitionData)
|
||||
{
|
||||
transIn = TransIn;
|
||||
transOut = TransOut;
|
||||
|
||||
if (transIn == null && defaultTransIn != null)
|
||||
{
|
||||
transIn = defaultTransIn;
|
||||
}
|
||||
if (transOut == null && defaultTransOut != null)
|
||||
{
|
||||
transOut = defaultTransOut;
|
||||
}
|
||||
super();
|
||||
}
|
||||
|
||||
override function destroy():Void
|
||||
{
|
||||
super.destroy();
|
||||
transIn = null;
|
||||
transOut = null;
|
||||
_onExit = null;
|
||||
}
|
||||
|
||||
override function create():Void
|
||||
{
|
||||
super.create();
|
||||
transitionIn();
|
||||
}
|
||||
|
||||
override function startOutro(onOutroComplete:() -> Void)
|
||||
{
|
||||
if (!hasTransOut) onOutroComplete();
|
||||
else if (!_exiting)
|
||||
{
|
||||
// play the exit transition, and when it's done call FlxG.switchState
|
||||
_exiting = true;
|
||||
transitionOut(onOutroComplete);
|
||||
|
||||
if (skipNextTransOut)
|
||||
{
|
||||
skipNextTransOut = false;
|
||||
finishTransOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the in-transition. Can be called manually at any time.
|
||||
*/
|
||||
public function transitionIn():Void
|
||||
{
|
||||
if (transIn != null && transIn.type != NONE)
|
||||
{
|
||||
if (skipNextTransIn)
|
||||
{
|
||||
skipNextTransIn = false;
|
||||
if (finishTransIn != null)
|
||||
{
|
||||
finishTransIn();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var _trans = createTransition(transIn);
|
||||
|
||||
_trans.setStatus(FULL);
|
||||
openSubState(_trans);
|
||||
|
||||
_trans.finishCallback = finishTransIn;
|
||||
_trans.start(OUT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the out-transition. Can be called manually at any time.
|
||||
*/
|
||||
public function transitionOut(?OnExit:Void->Void):Void
|
||||
{
|
||||
_onExit = OnExit;
|
||||
if (hasTransOut)
|
||||
{
|
||||
var _trans = createTransition(transOut);
|
||||
|
||||
_trans.setStatus(EMPTY);
|
||||
openSubState(_trans);
|
||||
|
||||
_trans.finishCallback = finishTransOut;
|
||||
_trans.start(IN);
|
||||
}
|
||||
else
|
||||
{
|
||||
_onExit();
|
||||
}
|
||||
}
|
||||
|
||||
var transOutFinished:Bool = false;
|
||||
|
||||
var _exiting:Bool = false;
|
||||
var _onExit:Void->Void;
|
||||
|
||||
function get_hasTransIn():Bool
|
||||
{
|
||||
return transIn != null && transIn.type != NONE;
|
||||
}
|
||||
|
||||
function get_hasTransOut():Bool
|
||||
{
|
||||
return transOut != null && transOut.type != NONE;
|
||||
}
|
||||
|
||||
function createTransition(data:TransitionData):Transition
|
||||
{
|
||||
return switch (data.type)
|
||||
{
|
||||
case TILES: new Transition(data);
|
||||
case FADE: new Transition(data);
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
function finishTransIn()
|
||||
{
|
||||
closeSubState();
|
||||
}
|
||||
|
||||
function finishTransOut()
|
||||
{
|
||||
transOutFinished = true;
|
||||
|
||||
if (!_exiting)
|
||||
{
|
||||
closeSubState();
|
||||
}
|
||||
|
||||
if (_onExit != null)
|
||||
{
|
||||
_onExit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ package funkin;
|
|||
import funkin.util.Constants;
|
||||
import flixel.util.FlxSignal;
|
||||
import flixel.math.FlxMath;
|
||||
import funkin.play.song.Song.SongDifficulty;
|
||||
import funkin.data.song.SongData.SongTimeChange;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
|
||||
|
@ -136,6 +135,9 @@ class Conductor
|
|||
return beatLengthMs / timeSignatureNumerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The numerator for the current time signature (the `3` in `3/4`).
|
||||
*/
|
||||
public var timeSignatureNumerator(get, never):Int;
|
||||
|
||||
function get_timeSignatureNumerator():Int
|
||||
|
@ -145,6 +147,9 @@ class Conductor
|
|||
return currentTimeChange.timeSignatureNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* The denominator for the current time signature (the `4` in `3/4`).
|
||||
*/
|
||||
public var timeSignatureDenominator(get, never):Int;
|
||||
|
||||
function get_timeSignatureDenominator():Int
|
||||
|
@ -245,7 +250,7 @@ class Conductor
|
|||
* WARNING: Avoid this for things like setting the BPM of the title screen music,
|
||||
* you should have a metadata file for it instead.
|
||||
*/
|
||||
public function forceBPM(?bpm:Float = null)
|
||||
public function forceBPM(?bpm:Float):Void
|
||||
{
|
||||
if (bpm != null)
|
||||
{
|
||||
|
@ -253,7 +258,7 @@ class Conductor
|
|||
}
|
||||
else
|
||||
{
|
||||
// trace('[CONDUCTOR] Resetting BPM to default');
|
||||
trace('[CONDUCTOR] Resetting BPM to default');
|
||||
}
|
||||
|
||||
this.bpmOverride = bpm;
|
||||
|
@ -266,7 +271,7 @@ class Conductor
|
|||
* @param songPosition The current position in the song in milliseconds.
|
||||
* Leave blank to use the FlxG.sound.music position.
|
||||
*/
|
||||
public function update(?songPos:Float)
|
||||
public function update(?songPos:Float):Void
|
||||
{
|
||||
if (songPos == null)
|
||||
{
|
||||
|
@ -274,9 +279,9 @@ class Conductor
|
|||
songPos = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0;
|
||||
}
|
||||
|
||||
var oldMeasure = this.currentMeasure;
|
||||
var oldBeat = this.currentBeat;
|
||||
var oldStep = this.currentStep;
|
||||
var oldMeasure:Float = this.currentMeasure;
|
||||
var oldBeat:Float = this.currentBeat;
|
||||
var oldStep:Float = this.currentStep;
|
||||
|
||||
// Set the song position we are at (for purposes of calculating note positions, etc).
|
||||
this.songPosition = songPos;
|
||||
|
@ -338,39 +343,43 @@ class Conductor
|
|||
}
|
||||
}
|
||||
|
||||
public function mapTimeChanges(songTimeChanges:Array<SongTimeChange>)
|
||||
/**
|
||||
* Apply the `SongTimeChange` data from the song metadata to this Conductor.
|
||||
* @param songTimeChanges The SongTimeChanges.
|
||||
*/
|
||||
public function mapTimeChanges(songTimeChanges:Array<SongTimeChange>):Void
|
||||
{
|
||||
timeChanges = [];
|
||||
|
||||
// Sort in place just in case it's out of order.
|
||||
SongDataUtils.sortTimeChanges(songTimeChanges);
|
||||
|
||||
for (currentTimeChange in songTimeChanges)
|
||||
for (songTimeChange in songTimeChanges)
|
||||
{
|
||||
// TODO: Maybe handle this different?
|
||||
// Do we care about BPM at negative timestamps?
|
||||
// Without any custom handling, `currentStepTime` becomes non-zero at `songPosition = 0`.
|
||||
if (currentTimeChange.timeStamp < 0.0) currentTimeChange.timeStamp = 0.0;
|
||||
if (songTimeChange.timeStamp < 0.0) songTimeChange.timeStamp = 0.0;
|
||||
|
||||
if (currentTimeChange.timeStamp <= 0.0)
|
||||
if (songTimeChange.timeStamp <= 0.0)
|
||||
{
|
||||
currentTimeChange.beatTime = 0.0;
|
||||
songTimeChange.beatTime = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate the beat time of this timestamp.
|
||||
currentTimeChange.beatTime = 0.0;
|
||||
songTimeChange.beatTime = 0.0;
|
||||
|
||||
if (currentTimeChange.timeStamp > 0.0 && timeChanges.length > 0)
|
||||
if (songTimeChange.timeStamp > 0.0 && timeChanges.length > 0)
|
||||
{
|
||||
var prevTimeChange:SongTimeChange = timeChanges[timeChanges.length - 1];
|
||||
currentTimeChange.beatTime = FlxMath.roundDecimal(prevTimeChange.beatTime
|
||||
+ ((currentTimeChange.timeStamp - prevTimeChange.timeStamp) * prevTimeChange.bpm / Constants.SECS_PER_MIN / Constants.MS_PER_SEC),
|
||||
songTimeChange.beatTime = FlxMath.roundDecimal(prevTimeChange.beatTime
|
||||
+ ((songTimeChange.timeStamp - prevTimeChange.timeStamp) * prevTimeChange.bpm / Constants.SECS_PER_MIN / Constants.MS_PER_SEC),
|
||||
4);
|
||||
}
|
||||
}
|
||||
|
||||
timeChanges.push(currentTimeChange);
|
||||
timeChanges.push(songTimeChange);
|
||||
}
|
||||
|
||||
if (timeChanges.length > 0)
|
||||
|
@ -384,6 +393,8 @@ class Conductor
|
|||
|
||||
/**
|
||||
* Given a time in milliseconds, return a time in steps.
|
||||
* @param ms The time in milliseconds.
|
||||
* @return The time in steps.
|
||||
*/
|
||||
public function getTimeInSteps(ms:Float):Float
|
||||
{
|
||||
|
@ -413,7 +424,7 @@ class Conductor
|
|||
|
||||
var lastStepLengthMs:Float = ((Constants.SECS_PER_MIN / lastTimeChange.bpm) * Constants.MS_PER_SEC) / timeSignatureNumerator;
|
||||
var resultFractionalStep:Float = (ms - lastTimeChange.timeStamp) / lastStepLengthMs;
|
||||
resultStep += resultFractionalStep; // Math.floor();
|
||||
resultStep += resultFractionalStep;
|
||||
|
||||
return resultStep;
|
||||
}
|
||||
|
@ -421,6 +432,8 @@ class Conductor
|
|||
|
||||
/**
|
||||
* Given a time in steps and fractional steps, return a time in milliseconds.
|
||||
* @param stepTime The time in steps.
|
||||
* @return The time in milliseconds.
|
||||
*/
|
||||
public function getStepTimeInMs(stepTime:Float):Float
|
||||
{
|
||||
|
@ -457,6 +470,8 @@ class Conductor
|
|||
|
||||
/**
|
||||
* Given a time in beats and fractional beats, return a time in milliseconds.
|
||||
* @param beatTime The time in beats.
|
||||
* @return The time in milliseconds.
|
||||
*/
|
||||
public function getBeatTimeInMs(beatTime:Float):Float
|
||||
{
|
||||
|
@ -491,13 +506,16 @@ class Conductor
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add variables of the current Conductor instance to the Flixel debugger.
|
||||
*/
|
||||
public static function watchQuick():Void
|
||||
{
|
||||
FlxG.watch.addQuick("songPosition", Conductor.instance.songPosition);
|
||||
FlxG.watch.addQuick("bpm", Conductor.instance.bpm);
|
||||
FlxG.watch.addQuick("currentMeasureTime", Conductor.instance.currentMeasureTime);
|
||||
FlxG.watch.addQuick("currentBeatTime", Conductor.instance.currentBeatTime);
|
||||
FlxG.watch.addQuick("currentStepTime", Conductor.instance.currentStepTime);
|
||||
FlxG.watch.addQuick('songPosition', Conductor.instance.songPosition);
|
||||
FlxG.watch.addQuick('bpm', Conductor.instance.bpm);
|
||||
FlxG.watch.addQuick('currentMeasureTime', Conductor.instance.currentMeasureTime);
|
||||
FlxG.watch.addQuick('currentBeatTime', Conductor.instance.currentBeatTime);
|
||||
FlxG.watch.addQuick('currentStepTime', Conductor.instance.currentStepTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,6 @@ import flixel.math.FlxRect;
|
|||
import flixel.FlxSprite;
|
||||
import flixel.system.debug.log.LogStyle;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
import funkin.util.macro.MacroUtil;
|
||||
import funkin.util.WindowUtil;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
|
@ -32,7 +31,6 @@ import funkin.ui.title.TitleState;
|
|||
import funkin.util.CLIUtil;
|
||||
import funkin.util.CLIUtil.CLIParams;
|
||||
import funkin.util.TimerUtil;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
import funkin.util.TrackerUtil;
|
||||
#if discord_rpc
|
||||
import Discord.DiscordClient;
|
||||
|
@ -171,8 +169,9 @@ class InitState extends FlxState
|
|||
AlbumRegistry.instance.loadEntries();
|
||||
StageRegistry.instance.loadEntries();
|
||||
|
||||
// TODO: CharacterDataParser doesn't use json2object, so it's way slower than the other parsers.
|
||||
CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry.
|
||||
// TODO: CharacterDataParser doesn't use json2object, so it's way slower than the other parsers and more prone to syntax errors.
|
||||
// Move it to use a BaseRegistry.
|
||||
CharacterDataParser.loadCharacterCache();
|
||||
|
||||
ModuleHandler.buildModuleCallbacks();
|
||||
ModuleHandler.loadModuleCache();
|
||||
|
@ -190,25 +189,35 @@ class InitState extends FlxState
|
|||
*/
|
||||
function startGame():Void
|
||||
{
|
||||
#if SONG // -DSONG=bopeebo
|
||||
#if SONG
|
||||
// -DSONG=bopeebo
|
||||
startSong(defineSong(), defineDifficulty());
|
||||
#elseif LEVEL // -DLEVEL=week1 -DDIFFICULTY=hard
|
||||
#elseif LEVEL
|
||||
// -DLEVEL=week1 -DDIFFICULTY=hard
|
||||
startLevel(defineLevel(), defineDifficulty());
|
||||
#elseif FREEPLAY // -DFREEPLAY
|
||||
#elseif FREEPLAY
|
||||
// -DFREEPLAY
|
||||
FlxG.switchState(() -> new funkin.ui.freeplay.FreeplayState());
|
||||
#elseif DIALOGUE // -DDIALOGUE
|
||||
#elseif DIALOGUE
|
||||
// -DDIALOGUE
|
||||
FlxG.switchState(() -> new funkin.ui.debug.dialogue.ConversationDebugState());
|
||||
#elseif ANIMATE // -DANIMATE
|
||||
#elseif ANIMATE
|
||||
// -DANIMATE
|
||||
FlxG.switchState(() -> new funkin.ui.debug.anim.FlxAnimateTest());
|
||||
#elseif WAVEFORM // -DWAVEFORM
|
||||
#elseif WAVEFORM
|
||||
// -DWAVEFORM
|
||||
FlxG.switchState(() -> new funkin.ui.debug.WaveformTestState());
|
||||
#elseif CHARTING // -DCHARTING
|
||||
#elseif CHARTING
|
||||
// -DCHARTING
|
||||
FlxG.switchState(() -> new funkin.ui.debug.charting.ChartEditorState());
|
||||
#elseif STAGEBUILD // -DSTAGEBUILD
|
||||
#elseif STAGEBUILD
|
||||
// -DSTAGEBUILD
|
||||
FlxG.switchState(() -> new funkin.ui.debug.stage.StageBuilderState());
|
||||
#elseif ANIMDEBUG // -DANIMDEBUG
|
||||
#elseif ANIMDEBUG
|
||||
// -DANIMDEBUG
|
||||
FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState());
|
||||
#elseif LATENCY // -DLATENCY
|
||||
#elseif LATENCY
|
||||
// -DLATENCY
|
||||
FlxG.switchState(() -> new funkin.LatencyState());
|
||||
#else
|
||||
startGameNormally();
|
||||
|
|
|
@ -11,144 +11,144 @@ class Paths
|
|||
{
|
||||
static var currentLevel:String;
|
||||
|
||||
static public function setCurrentLevel(name:String)
|
||||
public static function setCurrentLevel(name:String):Void
|
||||
{
|
||||
currentLevel = name.toLowerCase();
|
||||
}
|
||||
|
||||
public static function stripLibrary(path:String):String
|
||||
{
|
||||
var parts = path.split(':');
|
||||
var parts:Array<String> = path.split(':');
|
||||
if (parts.length < 2) return path;
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
public static function getLibrary(path:String):String
|
||||
{
|
||||
var parts = path.split(':');
|
||||
if (parts.length < 2) return "preload";
|
||||
var parts:Array<String> = path.split(':');
|
||||
if (parts.length < 2) return 'preload';
|
||||
return parts[0];
|
||||
}
|
||||
|
||||
static function getPath(file:String, type:AssetType, library:Null<String>)
|
||||
static function getPath(file:String, type:AssetType, library:Null<String>):String
|
||||
{
|
||||
if (library != null) return getLibraryPath(file, library);
|
||||
|
||||
if (currentLevel != null)
|
||||
{
|
||||
var levelPath = getLibraryPathForce(file, currentLevel);
|
||||
var levelPath:String = getLibraryPathForce(file, currentLevel);
|
||||
if (OpenFlAssets.exists(levelPath, type)) return levelPath;
|
||||
}
|
||||
|
||||
var levelPath = getLibraryPathForce(file, "shared");
|
||||
var levelPath:String = getLibraryPathForce(file, 'shared');
|
||||
if (OpenFlAssets.exists(levelPath, type)) return levelPath;
|
||||
|
||||
return getPreloadPath(file);
|
||||
}
|
||||
|
||||
static public function getLibraryPath(file:String, library = "preload")
|
||||
public static function getLibraryPath(file:String, library = 'preload'):String
|
||||
{
|
||||
return if (library == "preload" || library == "default") getPreloadPath(file); else getLibraryPathForce(file, library);
|
||||
return if (library == 'preload' || library == 'default') getPreloadPath(file); else getLibraryPathForce(file, library);
|
||||
}
|
||||
|
||||
inline static function getLibraryPathForce(file:String, library:String)
|
||||
static inline function getLibraryPathForce(file:String, library:String):String
|
||||
{
|
||||
return '$library:assets/$library/$file';
|
||||
}
|
||||
|
||||
inline static function getPreloadPath(file:String)
|
||||
static inline function getPreloadPath(file:String):String
|
||||
{
|
||||
return 'assets/$file';
|
||||
}
|
||||
|
||||
inline static public function file(file:String, type:AssetType = TEXT, ?library:String)
|
||||
public static function file(file:String, type:AssetType = TEXT, ?library:String):String
|
||||
{
|
||||
return getPath(file, type, library);
|
||||
}
|
||||
|
||||
public static inline function animateAtlas(path:String, ?library:String)
|
||||
public static function animateAtlas(path:String, ?library:String):String
|
||||
{
|
||||
return getLibraryPath('images/$path', library);
|
||||
}
|
||||
|
||||
inline static public function txt(key:String, ?library:String)
|
||||
public static function txt(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('data/$key.txt', TEXT, library);
|
||||
}
|
||||
|
||||
inline static public function frag(key:String, ?library:String)
|
||||
public static function frag(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('shaders/$key.frag', TEXT, library);
|
||||
}
|
||||
|
||||
inline static public function vert(key:String, ?library:String)
|
||||
public static function vert(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('shaders/$key.vert', TEXT, library);
|
||||
}
|
||||
|
||||
inline static public function xml(key:String, ?library:String)
|
||||
public static function xml(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('data/$key.xml', TEXT, library);
|
||||
}
|
||||
|
||||
inline static public function json(key:String, ?library:String)
|
||||
public static function json(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('data/$key.json', TEXT, library);
|
||||
}
|
||||
|
||||
static public function sound(key:String, ?library:String)
|
||||
public static function sound(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('sounds/$key.${Constants.EXT_SOUND}', SOUND, library);
|
||||
}
|
||||
|
||||
inline static public function soundRandom(key:String, min:Int, max:Int, ?library:String)
|
||||
public static function soundRandom(key:String, min:Int, max:Int, ?library:String):String
|
||||
{
|
||||
return sound(key + FlxG.random.int(min, max), library);
|
||||
}
|
||||
|
||||
inline static public function music(key:String, ?library:String)
|
||||
public static function music(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('music/$key.${Constants.EXT_SOUND}', MUSIC, library);
|
||||
}
|
||||
|
||||
inline static public function videos(key:String, ?library:String)
|
||||
public static function videos(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library);
|
||||
}
|
||||
|
||||
inline static public function voices(song:String, ?suffix:String = '')
|
||||
public static function voices(song:String, ?suffix:String = ''):String
|
||||
{
|
||||
if (suffix == null) suffix = ""; // no suffix, for a sorta backwards compatibility with older-ish voice files
|
||||
if (suffix == null) suffix = ''; // no suffix, for a sorta backwards compatibility with older-ish voice files
|
||||
|
||||
return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}';
|
||||
}
|
||||
|
||||
inline static public function inst(song:String, ?suffix:String = '')
|
||||
public static function inst(song:String, ?suffix:String = ''):String
|
||||
{
|
||||
return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix.${Constants.EXT_SOUND}';
|
||||
}
|
||||
|
||||
inline static public function image(key:String, ?library:String)
|
||||
public static function image(key:String, ?library:String):String
|
||||
{
|
||||
return getPath('images/$key.png', IMAGE, library);
|
||||
}
|
||||
|
||||
inline static public function font(key:String)
|
||||
public static function font(key:String):String
|
||||
{
|
||||
return 'assets/fonts/$key';
|
||||
}
|
||||
|
||||
inline static public function ui(key:String, ?library:String)
|
||||
public static function ui(key:String, ?library:String):String
|
||||
{
|
||||
return xml('ui/$key', library);
|
||||
}
|
||||
|
||||
static public function getSparrowAtlas(key:String, ?library:String)
|
||||
public static function getSparrowAtlas(key:String, ?library:String):FlxAtlasFrames
|
||||
{
|
||||
return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library));
|
||||
}
|
||||
|
||||
inline static public function getPackerAtlas(key:String, ?library:String)
|
||||
public static function getPackerAtlas(key:String, ?library:String):FlxAtlasFrames
|
||||
{
|
||||
return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import flixel.util.FlxSignal;
|
|||
*/
|
||||
class PlayerSettings
|
||||
{
|
||||
// TODO: Finish implementation of second player.
|
||||
public static var numPlayers(default, null) = 0;
|
||||
public static var numAvatars(default, null) = 0;
|
||||
public static var player1(default, null):PlayerSettings;
|
||||
|
@ -21,12 +22,21 @@ class PlayerSettings
|
|||
public static var onAvatarAdd(default, null) = new FlxTypedSignal<PlayerSettings->Void>();
|
||||
public static var onAvatarRemove(default, null) = new FlxTypedSignal<PlayerSettings->Void>();
|
||||
|
||||
/**
|
||||
* The player number associated with this settings object.
|
||||
*/
|
||||
public var id(default, null):Int;
|
||||
|
||||
/**
|
||||
* The controls handler for this player.
|
||||
*/
|
||||
public var controls(default, null):Controls;
|
||||
|
||||
/**
|
||||
* Return the PlayerSettings for the given player number, or `null` if that player isn't active.
|
||||
*
|
||||
* @param id The player number this represents.
|
||||
* @return The PlayerSettings for the given player number, or `null` if that player isn't active.
|
||||
*/
|
||||
public static function get(id:Int):Null<PlayerSettings>
|
||||
{
|
||||
|
@ -38,6 +48,9 @@ class PlayerSettings
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the PlayerSettings singletons for each player.
|
||||
*/
|
||||
public static function init():Void
|
||||
{
|
||||
if (player1 == null)
|
||||
|
@ -56,22 +69,30 @@ class PlayerSettings
|
|||
}
|
||||
}
|
||||
|
||||
public static function reset()
|
||||
/**
|
||||
* Forcibly destroy the PlayerSettings singletons for each player.
|
||||
*/
|
||||
public static function reset():Void
|
||||
{
|
||||
player1 = null;
|
||||
player2 = null;
|
||||
numPlayers = 0;
|
||||
}
|
||||
|
||||
static function onGamepadAdded(gamepad:FlxGamepad)
|
||||
/**
|
||||
* Callback invoked when a gamepad is added.
|
||||
* @param gamepad The gamepad that was added.
|
||||
*/
|
||||
static function onGamepadAdded(gamepad:FlxGamepad):Void
|
||||
{
|
||||
// TODO: Make this detect and handle multiple players
|
||||
player1.addGamepad(gamepad);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The player number this represents. This was refactored to START AT `1`.
|
||||
*/
|
||||
private function new(id:Int)
|
||||
function new(id:Int)
|
||||
{
|
||||
trace('loading player settings for id: $id');
|
||||
|
||||
|
@ -83,11 +104,11 @@ class PlayerSettings
|
|||
|
||||
function addKeyboard():Void
|
||||
{
|
||||
var useDefault = true;
|
||||
var useDefault:Bool = true;
|
||||
if (Save.instance.hasControls(id, Keys))
|
||||
{
|
||||
var keyControlData = Save.instance.getControls(id, Keys);
|
||||
trace("keyControlData: " + haxe.Json.stringify(keyControlData));
|
||||
trace('Loading keyboard control scheme from user save');
|
||||
useDefault = false;
|
||||
controls.fromSaveData(keyControlData, Keys);
|
||||
}
|
||||
|
@ -98,7 +119,7 @@ class PlayerSettings
|
|||
|
||||
if (useDefault)
|
||||
{
|
||||
trace("Loading default keyboard control scheme");
|
||||
trace('Loading default keyboard control scheme');
|
||||
controls.setKeyboardScheme(Solo);
|
||||
}
|
||||
|
||||
|
@ -109,13 +130,13 @@ class PlayerSettings
|
|||
* Called after an FlxGamepad has been detected.
|
||||
* @param gamepad The gamepad that was detected.
|
||||
*/
|
||||
function addGamepad(gamepad:FlxGamepad)
|
||||
function addGamepad(gamepad:FlxGamepad):Void
|
||||
{
|
||||
var useDefault = true;
|
||||
if (Save.instance.hasControls(id, Gamepad(gamepad.id)))
|
||||
{
|
||||
var padControlData = Save.instance.getControls(id, Gamepad(gamepad.id));
|
||||
trace("padControlData: " + haxe.Json.stringify(padControlData));
|
||||
trace('Loading gamepad control scheme from user save');
|
||||
useDefault = false;
|
||||
controls.addGamepadWithSaveData(gamepad.id, padControlData);
|
||||
}
|
||||
|
@ -126,7 +147,7 @@ class PlayerSettings
|
|||
|
||||
if (useDefault)
|
||||
{
|
||||
trace("Loading gamepad control scheme");
|
||||
trace('Loading default gamepad control scheme');
|
||||
controls.addDefaultGamepad(gamepad.id);
|
||||
}
|
||||
PreciseInputManager.instance.initializeButtons(controls, gamepad);
|
||||
|
@ -135,12 +156,12 @@ class PlayerSettings
|
|||
/**
|
||||
* Save this player's controls to the game's persistent save.
|
||||
*/
|
||||
public function saveControls()
|
||||
public function saveControls():Void
|
||||
{
|
||||
var keyData = controls.createSaveData(Keys);
|
||||
if (keyData != null)
|
||||
{
|
||||
trace("saving key data: " + haxe.Json.stringify(keyData));
|
||||
trace('Saving keyboard control scheme to user save');
|
||||
Save.instance.setControls(id, Keys, keyData);
|
||||
}
|
||||
|
||||
|
@ -149,7 +170,7 @@ class PlayerSettings
|
|||
var padData = controls.createSaveData(Gamepad(controls.gamepadsAdded[0]));
|
||||
if (padData != null)
|
||||
{
|
||||
trace("saving pad data: " + haxe.Json.stringify(padData));
|
||||
trace('Saving gamepad control scheme to user save');
|
||||
Save.instance.setControls(id, Gamepad(controls.gamepadsAdded[0]), padData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class Preferences
|
|||
|
||||
static function set_naughtyness(value:Bool):Bool
|
||||
{
|
||||
var save = Save.instance;
|
||||
var save:Save = Save.instance;
|
||||
save.options.naughtyness = value;
|
||||
save.flush();
|
||||
return value;
|
||||
|
@ -39,7 +39,7 @@ class Preferences
|
|||
|
||||
static function set_downscroll(value:Bool):Bool
|
||||
{
|
||||
var save = Save.instance;
|
||||
var save:Save = Save.instance;
|
||||
save.options.downscroll = value;
|
||||
save.flush();
|
||||
return value;
|
||||
|
@ -58,7 +58,7 @@ class Preferences
|
|||
|
||||
static function set_flashingLights(value:Bool):Bool
|
||||
{
|
||||
var save = Save.instance;
|
||||
var save:Save = Save.instance;
|
||||
save.options.flashingLights = value;
|
||||
save.flush();
|
||||
return value;
|
||||
|
@ -77,7 +77,7 @@ class Preferences
|
|||
|
||||
static function set_zoomCamera(value:Bool):Bool
|
||||
{
|
||||
var save = Save.instance;
|
||||
var save:Save = Save.instance;
|
||||
save.options.zoomCamera = value;
|
||||
save.flush();
|
||||
return value;
|
||||
|
@ -122,15 +122,20 @@ class Preferences
|
|||
{
|
||||
if (value != Save.instance.options.autoPause) FlxG.autoPause = value;
|
||||
|
||||
var save = Save.instance;
|
||||
var save:Save = Save.instance;
|
||||
save.options.autoPause = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the user's preferences from the save data and apply them.
|
||||
*/
|
||||
public static function init():Void
|
||||
{
|
||||
// Apply the autoPause setting (enables automatic pausing on focus lost).
|
||||
FlxG.autoPause = Preferences.autoPause;
|
||||
// Apply the debugDisplay setting (enables the FPS and RAM display).
|
||||
toggleDebugDisplay(Preferences.debugDisplay);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package funkin;
|
|||
import flash.Lib;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.Sprite;
|
||||
import flixel.system.FlxBasePreloader;
|
||||
import openfl.display.Sprite;
|
||||
|
@ -12,7 +11,8 @@ import openfl.text.TextField;
|
|||
import openfl.text.TextFormat;
|
||||
import flixel.system.FlxAssets;
|
||||
|
||||
@:bitmap("art/preloaderArt.png") class LogoImage extends BitmapData {}
|
||||
@:bitmap('art/preloaderArt.png')
|
||||
class LogoImage extends BitmapData {}
|
||||
|
||||
class Preloader extends FlxBasePreloader
|
||||
{
|
||||
|
|
|
@ -2,11 +2,7 @@ package funkin.play;
|
|||
|
||||
import funkin.audio.FunkinSound;
|
||||
import flixel.addons.display.FlxPieDial;
|
||||
import flixel.addons.display.FlxPieDial;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import flixel.addons.transition.Transition;
|
||||
import flixel.addons.transition.Transition;
|
||||
import flixel.FlxCamera;
|
||||
|
@ -948,8 +944,8 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
var pauseSubState:FlxSubState = new PauseSubState({mode: isChartingMode ? Charting : Standard});
|
||||
|
||||
FlxTransitionableSubState.skipNextTransIn = true;
|
||||
FlxTransitionableSubState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
FlxTransitionableState.skipNextTransOut = true;
|
||||
pauseSubState.camera = camHUD;
|
||||
openSubState(pauseSubState);
|
||||
// boyfriendPos.put(); // TODO: Why is this here?
|
||||
|
@ -1072,8 +1068,8 @@ class PlayState extends MusicBeatSubState
|
|||
isChartingMode: isChartingMode,
|
||||
transparent: persistentDraw
|
||||
});
|
||||
FlxTransitionableSubState.skipNextTransIn = true;
|
||||
FlxTransitionableSubState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
FlxTransitionableState.skipNextTransOut = true;
|
||||
openSubState(gameOverSubState);
|
||||
}
|
||||
|
||||
|
@ -2093,8 +2089,7 @@ class PlayState extends MusicBeatSubState
|
|||
holdNote.handledMiss = true;
|
||||
|
||||
// We dropped a hold note.
|
||||
// Mute vocals and play miss animation, but don't penalize.
|
||||
vocals.opponentVolume = 0;
|
||||
// Play miss animation, but don't penalize.
|
||||
currentStage.getOpponent().playSingAnimation(holdNote.noteData.getDirection(), true);
|
||||
}
|
||||
}
|
||||
|
@ -2668,8 +2663,8 @@ class PlayState extends MusicBeatSubState
|
|||
var pauseSubState:FlxSubState = new PauseSubState({mode: Conversation});
|
||||
|
||||
persistentUpdate = false;
|
||||
FlxTransitionableSubState.skipNextTransIn = true;
|
||||
FlxTransitionableSubState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
FlxTransitionableState.skipNextTransOut = true;
|
||||
pauseSubState.camera = camCutscene;
|
||||
openSubState(pauseSubState);
|
||||
}
|
||||
|
@ -2684,8 +2679,8 @@ class PlayState extends MusicBeatSubState
|
|||
var pauseSubState:FlxSubState = new PauseSubState({mode: Cutscene});
|
||||
|
||||
persistentUpdate = false;
|
||||
FlxTransitionableSubState.skipNextTransIn = true;
|
||||
FlxTransitionableSubState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
FlxTransitionableState.skipNextTransOut = true;
|
||||
pauseSubState.camera = camCutscene;
|
||||
openSubState(pauseSubState);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import flixel.FlxSprite;
|
|||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxSignal;
|
||||
import flixel.util.FlxTimer;
|
||||
#if html5
|
||||
import funkin.graphics.video.FlxVideo;
|
||||
|
@ -28,6 +29,31 @@ class VideoCutscene
|
|||
static var vid:FlxVideoSprite;
|
||||
#end
|
||||
|
||||
/**
|
||||
* Called when the video is started.
|
||||
*/
|
||||
public static final onVideoStarted:FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Called if the video is paused.
|
||||
*/
|
||||
public static final onVideoPaused:FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Called if the video is resumed.
|
||||
*/
|
||||
public static final onVideoResumed:FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Called if the video is restarted. onVideoStarted is not called.
|
||||
*/
|
||||
public static final onVideoRestarted:FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Called when the video is ended or skipped.
|
||||
*/
|
||||
public static final onVideoEnded:FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Play a video cutscene.
|
||||
* TODO: Currently this is hardcoded to start the countdown after the video is done.
|
||||
|
@ -94,6 +120,8 @@ class VideoCutscene
|
|||
PlayState.instance.add(vid);
|
||||
|
||||
PlayState.instance.refresh();
|
||||
|
||||
onVideoStarted.dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -129,6 +157,8 @@ class VideoCutscene
|
|||
vid.y = 0;
|
||||
// vid.scale.set(0.5, 0.5);
|
||||
});
|
||||
|
||||
onVideoStarted.dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -143,6 +173,7 @@ class VideoCutscene
|
|||
if (vid != null)
|
||||
{
|
||||
vid.restartVideo();
|
||||
onVideoRestarted.dispatch();
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -156,6 +187,8 @@ class VideoCutscene
|
|||
// Resume the video if it was paused.
|
||||
vid.resume();
|
||||
}
|
||||
|
||||
onVideoRestarted.dispatch();
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
@ -166,6 +199,7 @@ class VideoCutscene
|
|||
if (vid != null)
|
||||
{
|
||||
vid.pauseVideo();
|
||||
onVideoPaused.dispatch();
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -173,6 +207,45 @@ class VideoCutscene
|
|||
if (vid != null)
|
||||
{
|
||||
vid.pause();
|
||||
onVideoPaused.dispatch();
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function hideVideo():Void
|
||||
{
|
||||
#if html5
|
||||
if (vid != null)
|
||||
{
|
||||
vid.visible = false;
|
||||
blackScreen.visible = false;
|
||||
}
|
||||
#end
|
||||
|
||||
#if hxCodec
|
||||
if (vid != null)
|
||||
{
|
||||
vid.visible = false;
|
||||
blackScreen.visible = false;
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function showVideo():Void
|
||||
{
|
||||
#if html5
|
||||
if (vid != null)
|
||||
{
|
||||
vid.visible = true;
|
||||
blackScreen.visible = false;
|
||||
}
|
||||
#end
|
||||
|
||||
#if hxCodec
|
||||
if (vid != null)
|
||||
{
|
||||
vid.visible = true;
|
||||
blackScreen.visible = false;
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
@ -183,6 +256,7 @@ class VideoCutscene
|
|||
if (vid != null)
|
||||
{
|
||||
vid.resumeVideo();
|
||||
onVideoResumed.dispatch();
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -190,6 +264,7 @@ class VideoCutscene
|
|||
if (vid != null)
|
||||
{
|
||||
vid.resume();
|
||||
onVideoResumed.dispatch();
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
@ -240,6 +315,7 @@ class VideoCutscene
|
|||
{
|
||||
ease: FlxEase.quadInOut,
|
||||
onComplete: function(twn:FlxTween) {
|
||||
onVideoEnded.dispatch();
|
||||
onCutsceneFinish(cutsceneType);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -52,6 +52,11 @@ class ZoomCameraSongEvent extends SongEvent
|
|||
super('ZoomCamera');
|
||||
}
|
||||
|
||||
static final DEFAULT_ZOOM:Float = 1.0;
|
||||
static final DEFAULT_DURATION:Float = 4.0;
|
||||
static final DEFAULT_MODE:String = 'direct';
|
||||
static final DEFAULT_EASE:String = 'linear';
|
||||
|
||||
public override function handleEvent(data:SongEventData):Void
|
||||
{
|
||||
// Does nothing if there is no PlayState camera or stage.
|
||||
|
@ -60,25 +65,20 @@ class ZoomCameraSongEvent extends SongEvent
|
|||
// Does nothing if we are minimal mode.
|
||||
if (PlayState.instance.isMinimalMode) return;
|
||||
|
||||
var zoom:Null<Float> = data.getFloat('zoom');
|
||||
if (zoom == null) zoom = 1.0;
|
||||
var zoom:Float = data.getFloat('zoom') ?? DEFAULT_ZOOM;
|
||||
|
||||
var duration:Null<Float> = data.getFloat('duration');
|
||||
if (duration == null) duration = 4.0;
|
||||
var duration:Float = data.getFloat('duration') ?? DEFAULT_DURATION;
|
||||
|
||||
var mode:Null<String> = data.getString('mode');
|
||||
if (mode == null) mode = 'additive';
|
||||
var mode:String = data.getString('mode') ?? DEFAULT_MODE;
|
||||
var isDirectMode:Bool = mode == 'direct';
|
||||
|
||||
var ease:Null<String> = data.getString('ease');
|
||||
if (ease == null) ease = 'linear';
|
||||
|
||||
var directMode:Bool = mode == 'direct';
|
||||
var ease:String = data.getString('ease') ?? DEFAULT_EASE;
|
||||
|
||||
// If it's a string, check the value.
|
||||
switch (ease)
|
||||
{
|
||||
case 'INSTANT':
|
||||
PlayState.instance.tweenCameraZoom(zoom, 0, directMode);
|
||||
PlayState.instance.tweenCameraZoom(zoom, 0, isDirectMode);
|
||||
default:
|
||||
var durSeconds = Conductor.instance.stepLengthMs * duration / 1000;
|
||||
|
||||
|
@ -89,7 +89,7 @@ class ZoomCameraSongEvent extends SongEvent
|
|||
return;
|
||||
}
|
||||
|
||||
PlayState.instance.tweenCameraZoom(zoom, durSeconds, directMode, easeFunction);
|
||||
PlayState.instance.tweenCameraZoom(zoom, durSeconds, isDirectMode, easeFunction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ class ZoomCameraSongEvent extends SongEvent
|
|||
{
|
||||
name: 'mode',
|
||||
title: 'Mode',
|
||||
defaultValue: 'additive',
|
||||
defaultValue: 'direct',
|
||||
type: SongEventFieldType.ENUM,
|
||||
keys: ['Additive' => 'additive', 'Direct' => 'direct']
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package funkin.ui;
|
||||
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.text.FlxText;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
|
|
|
@ -1013,7 +1013,14 @@ class FreeplayState extends MusicBeatSubState
|
|||
|
||||
// Set the difficulty star count on the right.
|
||||
albumRoll.setDifficultyStars(daSong?.songRating);
|
||||
albumRoll.albumId = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID;
|
||||
|
||||
// Set the album graphic and play the animation if relevant.
|
||||
var newAlbumId:String = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID;
|
||||
if (albumRoll.albumId != newAlbumId)
|
||||
{
|
||||
albumRoll.albumId = newAlbumId;
|
||||
albumRoll.playIntro();
|
||||
}
|
||||
}
|
||||
|
||||
// Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package funkin.ui.mainmenu;
|
||||
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import funkin.ui.debug.DebugMenuSubState;
|
||||
import flixel.FlxObject;
|
||||
import flixel.FlxSprite;
|
||||
|
@ -103,8 +103,8 @@ class MainMenuState extends MusicBeatState
|
|||
persistentDraw = true;
|
||||
persistentUpdate = false;
|
||||
// Freeplay has its own custom transition
|
||||
FlxTransitionableSubState.skipNextTransIn = true;
|
||||
FlxTransitionableSubState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
FlxTransitionableState.skipNextTransOut = true;
|
||||
openSubState(new FreeplayState());
|
||||
});
|
||||
|
||||
|
|
|
@ -453,9 +453,9 @@ class TitleState extends MusicBeatState
|
|||
switch (i + 1)
|
||||
{
|
||||
case 1:
|
||||
createCoolText(['ninjamuffin99', 'phantomArcade', 'kawaisprite', 'evilsk8r']);
|
||||
createCoolText(['The', 'Funkin Crew Inc']);
|
||||
case 3:
|
||||
addMoreText('present');
|
||||
addMoreText('presents');
|
||||
case 4:
|
||||
deleteCoolText();
|
||||
case 5:
|
||||
|
|
|
@ -13,12 +13,24 @@ class MathUtil
|
|||
|
||||
/**
|
||||
* Perform linear interpolation between the base and the target, based on the current framerate.
|
||||
* @param base The starting value, when `progress <= 0`.
|
||||
* @param target The ending value, when `progress >= 1`.
|
||||
* @param ratio Value used to interpolate between `base` and `target`.
|
||||
*
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
public static function coolLerp(base:Float, target:Float, ratio:Float):Float
|
||||
{
|
||||
return base + cameraLerp(ratio) * (target - base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform linear interpolation based on the current framerate.
|
||||
* @param lerp Value used to interpolate between `base` and `target`.
|
||||
*
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
@:deprecated('Use smoothLerp instead')
|
||||
public static function cameraLerp(lerp:Float):Float
|
||||
{
|
||||
return lerp * (FlxG.elapsed / (1 / 60));
|
||||
|
@ -30,26 +42,30 @@ class MathUtil
|
|||
* @param value The value to get the logarithm of.
|
||||
* @return `log_base(value)`
|
||||
*/
|
||||
public static function logBase(base:Float, value:Float)
|
||||
public static function logBase(base:Float, value:Float):Float
|
||||
{
|
||||
return Math.log(value) / Math.log(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `2^x`
|
||||
* Get the base-2 logarithm of a value.
|
||||
* @param x value
|
||||
* @return `2^x`
|
||||
*/
|
||||
public static function exp2(x:Float)
|
||||
public static function exp2(x:Float):Float
|
||||
{
|
||||
return Math.pow(2, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly interpolate between two values.
|
||||
*
|
||||
* @param base The starting value, when `progress <= 0`.
|
||||
* @param target The ending value, when `progress >= 1`.
|
||||
* @param progress Value used to interpolate between `base` and `target`.
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
public static function lerp(base:Float, target:Float, progress:Float)
|
||||
public static function lerp(base:Float, target:Float, progress:Float):Float
|
||||
{
|
||||
return base + progress * (target - base);
|
||||
}
|
||||
|
@ -67,6 +83,7 @@ class MathUtil
|
|||
*/
|
||||
public static function smoothLerp(current:Float, target:Float, elapsed:Float, duration:Float, precision:Float = 1 / 100):Float
|
||||
{
|
||||
// An alternative algorithm which uses a separate half-life value:
|
||||
// var halfLife:Float = -duration / logBase(2, precision);
|
||||
// lerp(current, target, 1 - exp2(-elapsed / halfLife));
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class MemoryUtil
|
|||
public static function buildGCInfo():String
|
||||
{
|
||||
#if cpp
|
||||
var result = "HXCPP-Immix:";
|
||||
var result:String = 'HXCPP-Immix:';
|
||||
result += '\n- Memory Used: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_USAGE)} bytes';
|
||||
result += '\n- Memory Reserved: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_RESERVED)} bytes';
|
||||
result += '\n- Memory Current Pool: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_CURRENT)} bytes';
|
||||
|
@ -35,10 +35,10 @@ class MemoryUtil
|
|||
result += '\n- HXCPP C++11: ${#if HXCPP_CPP11 'Enabled' #else 'Disabled' #end}';
|
||||
result += '\n- Source Annotation: ${#if annotate_source 'Enabled' #else 'Disabled' #end}';
|
||||
#elseif js
|
||||
var result = "JS-MNS:";
|
||||
var result:String = 'JS-MNS:';
|
||||
result += '\n- Memory Used: ${getMemoryUsed()} bytes';
|
||||
#else
|
||||
var result = "Unknown GC";
|
||||
var result:String = 'Unknown GC';
|
||||
#end
|
||||
|
||||
return result;
|
||||
|
@ -66,7 +66,7 @@ class MemoryUtil
|
|||
#if cpp
|
||||
cpp.vm.Gc.enable(true);
|
||||
#else
|
||||
throw "Not implemented!";
|
||||
throw 'Not implemented!';
|
||||
#end
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class MemoryUtil
|
|||
#if cpp
|
||||
cpp.vm.Gc.enable(false);
|
||||
#else
|
||||
throw "Not implemented!";
|
||||
throw 'Not implemented!';
|
||||
#end
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ class MemoryUtil
|
|||
#if cpp
|
||||
cpp.vm.Gc.run(major);
|
||||
#else
|
||||
throw "Not implemented!";
|
||||
throw 'Not implemented!';
|
||||
#end
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ class MemoryUtil
|
|||
#if cpp
|
||||
cpp.vm.Gc.compact();
|
||||
#else
|
||||
throw "Not implemented!";
|
||||
throw 'Not implemented!';
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ class MouseUtil
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the zoom level of the current camera by the mouse wheel scroll value.
|
||||
*/
|
||||
public static function mouseWheelZoom():Void
|
||||
{
|
||||
if (FlxG.mouse.wheel != 0) FlxG.camera.zoom += FlxG.mouse.wheel * (0.1 * FlxG.camera.zoom);
|
||||
|
|
|
@ -16,9 +16,9 @@ class PlatformUtil
|
|||
#if mac
|
||||
return true;
|
||||
#elseif html5
|
||||
return js.Browser.window.navigator.platform.startsWith("Mac")
|
||||
|| js.Browser.window.navigator.platform.startsWith("iPad")
|
||||
|| js.Browser.window.navigator.platform.startsWith("iPhone");
|
||||
return js.Browser.window.navigator.platform.startsWith('Mac')
|
||||
|| js.Browser.window.navigator.platform.startsWith('iPad')
|
||||
|| js.Browser.window.navigator.platform.startsWith('iPhone');
|
||||
#else
|
||||
return false;
|
||||
#end
|
||||
|
@ -27,7 +27,7 @@ class PlatformUtil
|
|||
/**
|
||||
* Detects and returns the current host platform.
|
||||
* Always returns `HTML5` on web, regardless of the computer running that browser.
|
||||
* Returns `null` if the platform could not be detected.
|
||||
* @return The host platform, or `null` if the platform could not be detected.
|
||||
*/
|
||||
public static function detectHostPlatform():Null<HostPlatform>
|
||||
{
|
||||
|
|
|
@ -27,29 +27,53 @@ class SortUtil
|
|||
/**
|
||||
* You can use this function in FlxTypedGroup.sort() to sort FlxObjects by their z-index values.
|
||||
* The value defaults to 0, but by assigning it you can easily rearrange objects as desired.
|
||||
*
|
||||
* @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING`
|
||||
* @param a The first FlxObject to compare.
|
||||
* @param b The second FlxObject to compare.
|
||||
* @return 1 if `a` has a higher z-index, -1 if `b` has a higher z-index.
|
||||
*/
|
||||
public static inline function byZIndex(Order:Int, Obj1:FlxBasic, Obj2:FlxBasic):Int
|
||||
public static inline function byZIndex(order:Int, a:FlxBasic, b:FlxBasic):Int
|
||||
{
|
||||
if (Obj1 == null || Obj2 == null) return 0;
|
||||
return FlxSort.byValues(Order, Obj1.zIndex, Obj2.zIndex);
|
||||
if (a == null || b == null) return 0;
|
||||
return FlxSort.byValues(order, a.zIndex, b.zIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two Notes, returns 1 or -1 based on whether `a` or `b` has an earlier strumtime.
|
||||
*
|
||||
* @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING`
|
||||
* @param a The first Note to compare.
|
||||
* @param b The second Note to compare.
|
||||
* @return 1 if `a` has an earlier strumtime, -1 if `b` has an earlier strumtime.
|
||||
*/
|
||||
public static inline function byStrumtime(order:Int, a:NoteSprite, b:NoteSprite)
|
||||
public static inline function byStrumtime(order:Int, a:NoteSprite, b:NoteSprite):Int
|
||||
{
|
||||
return noteDataByTime(order, a.noteData, b.noteData);
|
||||
}
|
||||
|
||||
public static inline function noteDataByTime(order:Int, a:SongNoteData, b:SongNoteData)
|
||||
/**
|
||||
* Given two Note Data objects, returns 1 or -1 based on whether `a` or `b` has an earlier time.
|
||||
*
|
||||
* @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING`
|
||||
* @param a The first Event to compare.
|
||||
* @param b The second Event to compare.
|
||||
* @return 1 if `a` has an earlier time, -1 if `b` has an earlier time.
|
||||
*/
|
||||
public static inline function noteDataByTime(order:Int, a:SongNoteData, b:SongNoteData):Int
|
||||
{
|
||||
return FlxSort.byValues(order, a.time, b.time);
|
||||
}
|
||||
|
||||
public static inline function eventDataByTime(order:Int, a:SongEventData, b:SongEventData)
|
||||
/**
|
||||
* Given two Event Data objects, returns 1 or -1 based on whether `a` or `b` has an earlier time.
|
||||
*
|
||||
* @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING`
|
||||
* @param a The first Event to compare.
|
||||
* @param b The second Event to compare.
|
||||
* @return 1 if `a` has an earlier time, -1 if `b` has an earlier time.
|
||||
*/
|
||||
public static inline function eventDataByTime(order:Int, a:SongEventData, b:SongEventData):Int
|
||||
{
|
||||
return FlxSort.byValues(order, a.time, b.time);
|
||||
}
|
||||
|
@ -58,8 +82,11 @@ class SortUtil
|
|||
* Given two FlxFrames, sort their names alphabetically.
|
||||
*
|
||||
* @param order Either `FlxSort.ASCENDING` or `FlxSort.DESCENDING`
|
||||
* @param a The first Frame to compare.
|
||||
* @param b The second Frame to compare.
|
||||
* @return 1 if `a` has an earlier time, -1 if `b` has an earlier time.
|
||||
*/
|
||||
public static inline function byFrameName(a:FlxFrame, b:FlxFrame)
|
||||
public static inline function byFrameName(a:FlxFrame, b:FlxFrame):Int
|
||||
{
|
||||
return alphabetically(a.name, b.name);
|
||||
}
|
||||
|
@ -68,6 +95,7 @@ class SortUtil
|
|||
* Sort predicate for sorting strings alphabetically.
|
||||
* @param a The first string to compare.
|
||||
* @param b The second string to compare.
|
||||
* @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal
|
||||
*/
|
||||
public static function alphabetically(a:String, b:String):Int
|
||||
{
|
||||
|
@ -81,9 +109,11 @@ class SortUtil
|
|||
/**
|
||||
* Sort predicate which sorts two strings alphabetically, but prioritizes a specific string first.
|
||||
* Example usage: `array.sort(defaultThenAlphabetical.bind('test'))` will sort the array so that the string 'test' is first.
|
||||
*
|
||||
* @param defaultValue The value to prioritize.
|
||||
* @param a The first string to compare.
|
||||
* @param b The second string to compare.
|
||||
* @param defaultValue The value to prioritize.
|
||||
* @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal
|
||||
*/
|
||||
public static function defaultThenAlphabetically(defaultValue:String, a:String, b:String):Int
|
||||
{
|
||||
|
@ -96,9 +126,11 @@ class SortUtil
|
|||
/**
|
||||
* Sort predicate which sorts two strings alphabetically, but prioritizes a specific string first.
|
||||
* Example usage: `array.sort(defaultsThenAlphabetical.bind(['test']))` will sort the array so that the string 'test' is first.
|
||||
*
|
||||
* @param defaultValues The values to prioritize.
|
||||
* @param a The first string to compare.
|
||||
* @param b The second string to compare.
|
||||
* @param defaultValues The values to prioritize.
|
||||
* @return 1 if `a` comes before `b`, -1 if `b` comes before `a`, 0 if they are equal
|
||||
*/
|
||||
public static function defaultsThenAlphabetically(defaultValues:Array<String>, a:String, b:String):Int
|
||||
{
|
||||
|
|
|
@ -5,23 +5,42 @@ import haxe.Timer;
|
|||
|
||||
class TimerUtil
|
||||
{
|
||||
/**
|
||||
* Store the current time.
|
||||
*/
|
||||
public static function start():Float
|
||||
{
|
||||
return Timer.stamp();
|
||||
}
|
||||
|
||||
private static function took(start:Float, ?end:Float):Float
|
||||
/**
|
||||
* Return the elapsed time.
|
||||
*/
|
||||
static function took(start:Float, ?end:Float):Float
|
||||
{
|
||||
var endOrNow:Float = end != null ? end : Timer.stamp();
|
||||
return endOrNow - start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the elapsed time in seconds as a string.
|
||||
* @param start The start time.
|
||||
* @param end The end time.
|
||||
* @param precision The number of decimal places to round to.
|
||||
* @return The elapsed time in seconds as a string.
|
||||
*/
|
||||
public static function seconds(start:Float, ?end:Float, ?precision = 2):String
|
||||
{
|
||||
var seconds:Float = FloatTools.round(took(start, end), precision);
|
||||
return '${seconds} seconds';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the elapsed time in milliseconds as a string.
|
||||
* @param start The start time.
|
||||
* @param end The end time.
|
||||
* @return The elapsed time in milliseconds as a string.
|
||||
*/
|
||||
public static function ms(start:Float, ?end:Float):String
|
||||
{
|
||||
var seconds:Float = took(start, end);
|
||||
|
|
|
@ -18,7 +18,7 @@ class TrackerUtil
|
|||
public static function initTrackers():Void
|
||||
{
|
||||
#if FLX_DEBUG
|
||||
Tracker.addProfile(new TrackerProfile(Highscore, ["tallies"]));
|
||||
Tracker.addProfile(new TrackerProfile(Highscore, ['tallies']));
|
||||
FlxG.console.registerClass(Highscore);
|
||||
#end
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ class VersionUtil
|
|||
/**
|
||||
* Checks that a given verison number satisisfies a given version rule.
|
||||
* Version rule can be complex, e.g. "1.0.x" or ">=1.0.0,<1.1.0", or anything NPM supports.
|
||||
* @param version The semantic version to validate.
|
||||
* @param versionRule The version rule to validate against.
|
||||
* @return `true` if the version satisfies the rule, `false` otherwise.
|
||||
*/
|
||||
public static function validateVersion(version:thx.semver.Version, versionRule:thx.semver.VersionRule):Bool
|
||||
{
|
||||
|
@ -32,6 +35,9 @@ class VersionUtil
|
|||
/**
|
||||
* Checks that a given verison number satisisfies a given version rule.
|
||||
* Version rule can be complex, e.g. "1.0.x" or ">=1.0.0,<1.1.0", or anything NPM supports.
|
||||
* @param version The semantic version to validate.
|
||||
* @param versionRule The version rule to validate against.
|
||||
* @return `true` if the version satisfies the rule, `false` otherwise.
|
||||
*/
|
||||
public static function validateVersionStr(version:String, versionRule:String):Bool
|
||||
{
|
||||
|
@ -56,7 +62,7 @@ class VersionUtil
|
|||
public static function getVersionFromJSON(input:Null<String>):Null<thx.semver.Version>
|
||||
{
|
||||
if (input == null) return null;
|
||||
var parsed = SerializerUtil.fromJSON(input);
|
||||
var parsed:Dynamic = SerializerUtil.fromJSON(input);
|
||||
if (parsed == null) return null;
|
||||
if (parsed.version == null) return null;
|
||||
var versionStr:String = parsed.version; // Dynamic -> String cast
|
||||
|
@ -64,6 +70,11 @@ class VersionUtil
|
|||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and parse the semantic version from a JSON string.
|
||||
* @param input The JSON string to parse.
|
||||
* @return The semantic version, or null if it could not be parsed.
|
||||
*/
|
||||
public static function parseVersion(input:Dynamic):Null<thx.semver.Version>
|
||||
{
|
||||
if (input == null) return null;
|
||||
|
|
|
@ -24,7 +24,7 @@ class WindowUtil
|
|||
{
|
||||
#if CAN_OPEN_LINKS
|
||||
#if linux
|
||||
Sys.command('/usr/bin/xdg-open', [targetUrl, "&"]);
|
||||
Sys.command('/usr/bin/xdg-open', [targetUrl, '&']);
|
||||
#else
|
||||
// This should work on Windows and HTML5.
|
||||
FlxG.openURL(targetUrl);
|
||||
|
@ -42,7 +42,7 @@ class WindowUtil
|
|||
{
|
||||
#if CAN_OPEN_LINKS
|
||||
#if windows
|
||||
Sys.command('explorer', [targetPath.replace("/", "\\")]);
|
||||
Sys.command('explorer', [targetPath.replace('/', '\\')]);
|
||||
#elseif mac
|
||||
Sys.command('open', [targetPath]);
|
||||
#elseif linux
|
||||
|
@ -61,9 +61,9 @@ class WindowUtil
|
|||
{
|
||||
#if CAN_OPEN_LINKS
|
||||
#if windows
|
||||
Sys.command('explorer', ["/select," + targetPath.replace("/", "\\")]);
|
||||
Sys.command('explorer', ['/select,' + targetPath.replace('/', '\\')]);
|
||||
#elseif mac
|
||||
Sys.command('open', ["-R", targetPath]);
|
||||
Sys.command('open', ['-R', targetPath]);
|
||||
#elseif linux
|
||||
// TODO: unsure of the linux equivalent to opening a folder and then "selecting" a file.
|
||||
Sys.command('open', [targetPath]);
|
||||
|
@ -82,7 +82,7 @@ class WindowUtil
|
|||
* Wires up FlxSignals that happen based on window activity.
|
||||
* For example, we can run a callback when the window is closed.
|
||||
*/
|
||||
public static function initWindowEvents()
|
||||
public static function initWindowEvents():Void
|
||||
{
|
||||
// onUpdate is called every frame just before rendering.
|
||||
|
||||
|
@ -95,7 +95,7 @@ class WindowUtil
|
|||
/**
|
||||
* Turns off that annoying "Report to Microsoft" dialog that pops up when the game crashes.
|
||||
*/
|
||||
public static function disableCrashHandler()
|
||||
public static function disableCrashHandler():Void
|
||||
{
|
||||
#if (cpp && windows)
|
||||
untyped __cpp__('SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);');
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
package haxe.ui.backend.flixel;
|
||||
|
||||
/**
|
||||
* Override HaxeUI to use `MusicBeatState` instead of `FlxState`.
|
||||
*/
|
||||
typedef UIStateBase = funkin.ui.MusicBeatState;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
package haxe.ui.backend.flixel;
|
||||
|
||||
/**
|
||||
* Override HaxeUI to use `MusicBeatSubState` instead of `FlxSubState`.
|
||||
*/
|
||||
typedef UISubStateBase = funkin.ui.MusicBeatSubState;
|
||||
|
|
|
@ -4,27 +4,22 @@
|
|||
<SubTexture name="staticDown0001" x="17" y="0" width="17" height="17" />
|
||||
<SubTexture name="staticUp0001" x="34" y="0" width="17" height="17" />
|
||||
<SubTexture name="staticRight0001" x="51" y="0" width="17" height="17" />
|
||||
|
||||
<SubTexture name="noteLeft0001" x="0" y="17" width="17" height="17" />
|
||||
<SubTexture name="noteDown0001" x="17" y="17" width="17" height="17" />
|
||||
<SubTexture name="noteUp0001" x="34" y="17" width="17" height="17" />
|
||||
<SubTexture name="noteRight0001" x="51" y="17" width="17" height="17" />
|
||||
|
||||
<SubTexture name="pressedLeft0001" x="0" y="17" width="17" height="17" />
|
||||
<SubTexture name="pressedDown0001" x="17" y="17" width="17" height="17" />
|
||||
<SubTexture name="pressedUp0001" x="34" y="17" width="17" height="17" />
|
||||
<SubTexture name="pressedRight0001" x="51" y="17" width="17" height="17" />
|
||||
|
||||
<SubTexture name="pressedLeft0002" x="0" y="34" width="17" height="17" />
|
||||
<SubTexture name="pressedDown0002" x="17" y="34" width="17" height="17" />
|
||||
<SubTexture name="pressedUp0002" x="34" y="34" width="17" height="17" />
|
||||
<SubTexture name="pressedRight0002" x="51" y="34" width="17" height="17" />
|
||||
|
||||
<SubTexture name="confirmLeft0001" x="0" y="51" width="17" height="17" />
|
||||
<SubTexture name="confirmDown0001" x="17" y="51" width="17" height="17" />
|
||||
<SubTexture name="confirmUp0001" x="34" y="51" width="17" height="17" />
|
||||
<SubTexture name="confirmRight0001" x="51" y="51" width="17" height="17" />
|
||||
|
||||
<SubTexture name="confirmLeft0002" x="0" y="68" width="17" height="17" />
|
||||
<SubTexture name="confirmDown0002" x="17" y="68" width="17" height="17" />
|
||||
<SubTexture name="confirmUp0002" x="34" y="68" width="17" height="17" />
|
||||
|
|
Loading…
Reference in a new issue