mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-08-20 07:25:59 +00:00
Merge remote-tracking branch 'origin/rewrite/master' into bugfix/senpai-naughty
This commit is contained in:
commit
b8504c8e3a
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -2,6 +2,9 @@
|
|||
path = assets
|
||||
url = https://github.com/FunkinCrew/Funkin-history-rewrite-assets
|
||||
branch = master
|
||||
update = merge
|
||||
[submodule "art"]
|
||||
path = art
|
||||
url = https://github.com/FunkinCrew/Funkin-history-rewrite-art
|
||||
branch = master
|
||||
update = merge
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.3.0" company="ninjamuffin99" />
|
||||
<!--Switch Export with Unique ApplicationID and Icon-->
|
||||
<set name="APP_ID" value="0x0100f6c013bbc000" />
|
||||
<!--The flixel preloader is not accurate in Chrome. You can use it regularly if you embed the swf into a html file
|
||||
or you can set the actual size of your file manually at "FlxPreloaderBase-onUpdate-bytesTotal"-->
|
||||
<!-- <app preloader="Preloader" resizable="true" /> -->
|
||||
<app preloader="Preloader" />
|
||||
<app preloader="funkin.Preloader" />
|
||||
<!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2-->
|
||||
<set name="SWF_VERSION" value="11.8" />
|
||||
<!-- ____________________________ Window Settings ___________________________ -->
|
||||
|
@ -165,7 +162,10 @@
|
|||
<icon path="art/iconOG.png" />
|
||||
<haxedef name="CAN_OPEN_LINKS" unless="switch" />
|
||||
<haxedef name="CAN_CHEAT" if="switch debug" />
|
||||
<!-- I don't -->
|
||||
<haxedef name="haxeui_no_mouse_reset" />
|
||||
<!-- Clicking outside a dialog should deselect the current focused component. -->
|
||||
<haxedef name="haxeui_focus_out_on_click" />
|
||||
<!-- Skip the Intro -->
|
||||
<section if="debug">
|
||||
<!-- Starts the game at the specified week, at the first song -->
|
||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit c4543111e7a31d7bde0e0fdc56636646abb8c963
|
||||
Subproject commit 482ef76582208a484a2f6450ce5ad9e278db08f8
|
2
hmm.json
2
hmm.json
|
@ -56,7 +56,7 @@
|
|||
"name": "haxeui-flixel",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "9bd0b9e0fea40b8e06a89aac4949512d95064609",
|
||||
"ref": "95c7d66e779626eabd6f48a1cd7aa7f9a503a7f3",
|
||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@ package;
|
|||
import flixel.FlxGame;
|
||||
import flixel.FlxState;
|
||||
import funkin.util.logging.CrashHandler;
|
||||
import funkin.MemoryCounter;
|
||||
import funkin.ui.debug.MemoryCounter;
|
||||
import funkin.save.Save;
|
||||
import haxe.ui.Toolkit;
|
||||
import openfl.display.FPS;
|
||||
|
@ -11,6 +11,7 @@ import openfl.display.Sprite;
|
|||
import openfl.events.Event;
|
||||
import openfl.Lib;
|
||||
import openfl.media.Video;
|
||||
import funkin.util.CLIUtil;
|
||||
import openfl.net.NetStream;
|
||||
|
||||
class Main extends Sprite
|
||||
|
@ -110,5 +111,6 @@ class Main extends Sprite
|
|||
Toolkit.init();
|
||||
Toolkit.theme = 'dark'; // don't be cringe
|
||||
Toolkit.autoScale = false;
|
||||
funkin.input.Cursor.registerHaxeUICursors();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ 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;
|
||||
|
||||
/**
|
||||
* A core class which handles musical timing throughout the game,
|
||||
|
@ -257,6 +258,9 @@ class Conductor
|
|||
{
|
||||
timeChanges = [];
|
||||
|
||||
// Sort in place just in case it's out of order.
|
||||
SongDataUtils.sortTimeChanges(songTimeChanges);
|
||||
|
||||
for (currentTimeChange in songTimeChanges)
|
||||
{
|
||||
// TODO: Maybe handle this different?
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxState;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.system.FlxAssets.FlxGraphicAsset;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.shaderslmfao.ScreenWipeShader;
|
||||
import haxe.format.JsonParser;
|
||||
import lime.math.Rectangle;
|
||||
import lime.utils.Assets;
|
||||
import openfl.filters.ShaderFilter;
|
||||
|
||||
class CoolUtil
|
||||
{
|
||||
public static function coolBaseLog(base:Float, fin:Float):Float
|
||||
{
|
||||
return Math.log(fin) / Math.log(base);
|
||||
}
|
||||
|
||||
public static function coolTextFile(path:String):Array<String>
|
||||
{
|
||||
var daList:Array<String> = [];
|
||||
|
||||
var swagArray:Array<String> = Assets.getText(path).trim().split('\n');
|
||||
|
||||
for (item in swagArray)
|
||||
{
|
||||
// comment support in the quick lil text formats??? using //
|
||||
if (!item.trim().startsWith('//')) daList.push(item);
|
||||
}
|
||||
|
||||
for (i in 0...daList.length)
|
||||
{
|
||||
daList[i] = daList[i].trim();
|
||||
}
|
||||
|
||||
return daList;
|
||||
}
|
||||
|
||||
public static function numberArray(max:Int, ?min = 0):Array<Int>
|
||||
{
|
||||
var dumbArray:Array<Int> = [];
|
||||
for (i in min...max)
|
||||
{
|
||||
dumbArray.push(i);
|
||||
}
|
||||
return dumbArray;
|
||||
}
|
||||
|
||||
static var oldCamPos:FlxPoint = new FlxPoint();
|
||||
static var oldMousePos:FlxPoint = new FlxPoint();
|
||||
|
||||
/**
|
||||
* Used to be for general camera middle click dragging, now generalized for any click and drag type shit!
|
||||
* Listen I don't make the rules here
|
||||
* @param target what you want to be dragged, defaults to CAMERA SCROLL
|
||||
* @param jusPres the "justPressed", should be a button of some sort
|
||||
* @param pressed the "pressed", which should be the same button as `jusPres`
|
||||
*/
|
||||
public static function mouseCamDrag(?target:FlxPoint, ?jusPres:Bool, ?pressed:Bool):Void
|
||||
{
|
||||
if (target == null) target = FlxG.camera.scroll;
|
||||
|
||||
if (jusPres == null) jusPres = FlxG.mouse.justPressedMiddle;
|
||||
|
||||
if (pressed == null) pressed = FlxG.mouse.pressedMiddle;
|
||||
|
||||
if (jusPres)
|
||||
{
|
||||
oldCamPos.set(target.x, target.y);
|
||||
oldMousePos.set(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||
}
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
target.x = oldCamPos.x - (FlxG.mouse.screenX - oldMousePos.x);
|
||||
target.y = oldCamPos.y - (FlxG.mouse.screenY - oldMousePos.y);
|
||||
}
|
||||
}
|
||||
|
||||
public static function mouseWheelZoom():Void
|
||||
{
|
||||
if (FlxG.mouse.wheel != 0) FlxG.camera.zoom += FlxG.mouse.wheel * (0.1 * FlxG.camera.zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
Lerps camera, but accountsfor framerate shit?
|
||||
Right now it's simply for use to change the followLerp variable of a camera during update
|
||||
TODO LATER MAYBE:
|
||||
Actually make and modify the scroll and lerp shit in it's own function
|
||||
instead of solely relying on changing the lerp on the fly
|
||||
*/
|
||||
public static function camLerpShit(lerp:Float):Float
|
||||
{
|
||||
return lerp * (FlxG.elapsed / (1 / 60));
|
||||
}
|
||||
|
||||
public static function coolSwitchState(state:FlxState, transitionTex:String = "shaderTransitionStuff/coolDots", time:Float = 2)
|
||||
{
|
||||
var screenShit:FlxSprite = new FlxSprite().loadGraphic(Paths.image("shaderTransitionStuff/coolDots"));
|
||||
var screenWipeShit:ScreenWipeShader = new ScreenWipeShader();
|
||||
|
||||
screenWipeShit.funnyShit.input = screenShit.pixels;
|
||||
FlxTween.tween(screenWipeShit, {daAlphaShit: 1}, time,
|
||||
{
|
||||
ease: FlxEase.quadInOut,
|
||||
onComplete: function(twn) {
|
||||
screenShit.destroy();
|
||||
FlxG.switchState(new MainMenuState());
|
||||
}
|
||||
});
|
||||
FlxG.camera.setFilters([new ShaderFilter(screenWipeShit)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* frame dependant lerp kinda lol
|
||||
*/
|
||||
public static function coolLerp(base:Float, target:Float, ratio:Float):Float
|
||||
{
|
||||
return base + camLerpShit(ratio) * (target - base);
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.text.FlxTypeText;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.play.PlayState;
|
||||
|
||||
/**
|
||||
* Handles dialog boxes and text, like the ones in Week 6.
|
||||
*/
|
||||
class DialogueBox extends FlxSpriteGroup
|
||||
{
|
||||
var box:FlxSprite;
|
||||
|
||||
var curCharacter:String = '';
|
||||
|
||||
var dialogue:Alphabet;
|
||||
var dialogueList:Array<String> = [];
|
||||
|
||||
// SECOND DIALOGUE FOR THE PIXEL SHIT INSTEAD???
|
||||
var swagDialogue:FlxTypeText;
|
||||
|
||||
var dropText:FlxText;
|
||||
|
||||
public var finishThing:Void->Void;
|
||||
|
||||
var portraitLeft:FlxSprite;
|
||||
var portraitRight:FlxSprite;
|
||||
|
||||
var handSelect:FlxSprite;
|
||||
var bgFade:FlxSprite;
|
||||
|
||||
public function new(talkingRight:Bool = true, ?dialogueList:Array<String>)
|
||||
{
|
||||
super();
|
||||
|
||||
switch (PlayState.instance.currentSong.id.toLowerCase())
|
||||
{
|
||||
case 'senpai':
|
||||
FlxG.sound.playMusic(Paths.music('Lunchbox'), 0);
|
||||
FlxG.sound.music.fadeIn(1, 0, 0.8);
|
||||
case 'thorns':
|
||||
FlxG.sound.playMusic(Paths.music('LunchboxScary'), 0);
|
||||
FlxG.sound.music.fadeIn(1, 0, 0.8);
|
||||
}
|
||||
|
||||
bgFade = new FlxSprite(-200, -200).makeGraphic(Std.int(FlxG.width * 1.3), Std.int(FlxG.height * 1.3), 0xFFB3DFD8);
|
||||
bgFade.scrollFactor.set();
|
||||
bgFade.alpha = 0;
|
||||
add(bgFade);
|
||||
|
||||
new FlxTimer().start(0.83, function(tmr:FlxTimer) {
|
||||
bgFade.alpha += (1 / 5) * 0.7;
|
||||
if (bgFade.alpha > 0.7) bgFade.alpha = 0.7;
|
||||
}, 5);
|
||||
|
||||
portraitLeft = new FlxSprite(-20, 40);
|
||||
portraitLeft.frames = Paths.getSparrowAtlas('weeb/senpaiPortrait');
|
||||
portraitLeft.animation.addByPrefix('enter', 'Senpai Portrait Enter', 24, false);
|
||||
portraitLeft.setGraphicSize(Std.int(portraitLeft.width * Constants.PIXEL_ART_SCALE * 0.9));
|
||||
portraitLeft.updateHitbox();
|
||||
portraitLeft.scrollFactor.set();
|
||||
add(portraitLeft);
|
||||
portraitLeft.visible = false;
|
||||
|
||||
portraitRight = new FlxSprite(0, 40);
|
||||
portraitRight.frames = Paths.getSparrowAtlas('weeb/bfPortrait');
|
||||
portraitRight.animation.addByPrefix('enter', 'Boyfriend portrait enter', 24, false);
|
||||
portraitRight.setGraphicSize(Std.int(portraitRight.width * Constants.PIXEL_ART_SCALE * 0.9));
|
||||
portraitRight.updateHitbox();
|
||||
portraitRight.scrollFactor.set();
|
||||
add(portraitRight);
|
||||
portraitRight.visible = false;
|
||||
|
||||
box = new FlxSprite(-20, 45);
|
||||
|
||||
var hasDialog:Bool = false;
|
||||
switch (PlayState.instance.currentSong.id.toLowerCase())
|
||||
{
|
||||
case 'senpai':
|
||||
hasDialog = true;
|
||||
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-pixel');
|
||||
box.animation.addByPrefix('normalOpen', 'Text Box Appear', 24, false);
|
||||
box.animation.addByIndices('normal', 'Text Box Appear', [4], '', 24);
|
||||
case 'roses':
|
||||
hasDialog = true;
|
||||
FlxG.sound.play(Paths.sound('ANGRY_TEXT_BOX'));
|
||||
|
||||
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-senpaiMad');
|
||||
box.animation.addByPrefix('normalOpen', 'SENPAI ANGRY IMPACT SPEECH', 24, false);
|
||||
box.animation.addByIndices('normal', 'SENPAI ANGRY IMPACT SPEECH', [4], '', 24);
|
||||
|
||||
case 'thorns':
|
||||
hasDialog = true;
|
||||
box.frames = Paths.getSparrowAtlas('weeb/pixelUI/dialogueBox-evil');
|
||||
box.animation.addByPrefix('normalOpen', 'Spirit Textbox spawn', 24, false);
|
||||
box.animation.addByIndices('normal', 'Spirit Textbox spawn', [11], '', 24);
|
||||
|
||||
var face:FlxSprite = new FlxSprite(320, 170).loadGraphic(Paths.image('weeb/spiritFaceForward'));
|
||||
face.setGraphicSize(Std.int(face.width * 6));
|
||||
add(face);
|
||||
}
|
||||
|
||||
this.dialogueList = dialogueList;
|
||||
|
||||
if (!hasDialog) return;
|
||||
|
||||
box.animation.play('normalOpen');
|
||||
box.setGraphicSize(Std.int(box.width * Constants.PIXEL_ART_SCALE * 0.9));
|
||||
box.updateHitbox();
|
||||
add(box);
|
||||
|
||||
box.screenCenter(X);
|
||||
portraitLeft.screenCenter(X);
|
||||
|
||||
handSelect = new FlxSprite(1042, 590).loadGraphic(Paths.image('weeb/pixelUI/hand_textbox'));
|
||||
handSelect.setGraphicSize(Std.int(handSelect.width * Constants.PIXEL_ART_SCALE * 0.9));
|
||||
handSelect.updateHitbox();
|
||||
handSelect.visible = false;
|
||||
add(handSelect);
|
||||
|
||||
if (!talkingRight)
|
||||
{
|
||||
// box.flipX = true;
|
||||
}
|
||||
|
||||
dropText = new FlxText(242, 502, Std.int(FlxG.width * 0.6), '', 32);
|
||||
dropText.font = 'Pixel Arial 11 Bold';
|
||||
dropText.color = 0xFFD89494;
|
||||
add(dropText);
|
||||
|
||||
swagDialogue = new FlxTypeText(240, 500, Std.int(FlxG.width * 0.6), '', 32);
|
||||
swagDialogue.font = 'Pixel Arial 11 Bold';
|
||||
swagDialogue.color = 0xFF3F2021;
|
||||
swagDialogue.sounds = [FlxG.sound.load(Paths.sound('pixelText'), 0.6)];
|
||||
add(swagDialogue);
|
||||
|
||||
dialogue = new Alphabet(0, 80, '', false, true);
|
||||
// dialogue.x = 90;
|
||||
// add(dialogue);
|
||||
}
|
||||
|
||||
var dialogueOpened:Bool = false;
|
||||
var dialogueStarted:Bool = false;
|
||||
var dialogueEnded:Bool = false;
|
||||
|
||||
override function update(elapsed:Float):Void
|
||||
{
|
||||
// HARD CODING CUZ IM STUPDI
|
||||
if (PlayState.instance.currentSong.id.toLowerCase() == 'roses') portraitLeft.visible = false;
|
||||
if (PlayState.instance.currentSong.id.toLowerCase() == 'thorns')
|
||||
{
|
||||
portraitLeft.color = FlxColor.BLACK;
|
||||
swagDialogue.color = FlxColor.WHITE;
|
||||
dropText.color = FlxColor.BLACK;
|
||||
}
|
||||
|
||||
dropText.text = swagDialogue.text;
|
||||
|
||||
if (box.animation.curAnim != null)
|
||||
{
|
||||
if (box.animation.curAnim.name == 'normalOpen' && box.animation.curAnim.finished)
|
||||
{
|
||||
box.animation.play('normal');
|
||||
dialogueOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (dialogueOpened && !dialogueStarted)
|
||||
{
|
||||
startDialogue();
|
||||
dialogueStarted = true;
|
||||
}
|
||||
|
||||
if (FlxG.keys.justPressed.ANY && dialogueEnded)
|
||||
{
|
||||
remove(dialogue);
|
||||
|
||||
FlxG.sound.play(Paths.sound('clickText'), 0.8);
|
||||
|
||||
if (dialogueList[1] == null && dialogueList[0] != null)
|
||||
{
|
||||
if (!isEnding)
|
||||
{
|
||||
isEnding = true;
|
||||
|
||||
if (PlayState.instance.currentSong.id.toLowerCase() == 'senpai'
|
||||
|| PlayState.instance.currentSong.id.toLowerCase() == 'thorns') FlxG.sound.music.fadeOut(2.2, 0);
|
||||
|
||||
new FlxTimer().start(0.2, function(tmr:FlxTimer) {
|
||||
box.alpha -= 1 / 5;
|
||||
bgFade.alpha -= 1 / 5 * 0.7;
|
||||
portraitLeft.visible = false;
|
||||
portraitRight.visible = false;
|
||||
swagDialogue.alpha -= 1 / 5;
|
||||
handSelect.alpha -= 1 / 5;
|
||||
dropText.alpha = swagDialogue.alpha;
|
||||
}, 5);
|
||||
|
||||
new FlxTimer().start(1.2, function(tmr:FlxTimer) {
|
||||
finishThing();
|
||||
kill();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dialogueList.remove(dialogueList[0]);
|
||||
startDialogue();
|
||||
}
|
||||
}
|
||||
else if (FlxG.keys.justPressed.ANY && dialogueStarted) swagDialogue.skip();
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
var isEnding:Bool = false;
|
||||
|
||||
function startDialogue():Void
|
||||
{
|
||||
cleanDialog();
|
||||
// var theDialog:Alphabet = new Alphabet(0, 70, dialogueList[0], false, true);
|
||||
// dialogue = theDialog;
|
||||
// add(theDialog);
|
||||
|
||||
// swagDialogue.text = ;
|
||||
swagDialogue.resetText(dialogueList[0]);
|
||||
swagDialogue.start(0.04);
|
||||
swagDialogue.completeCallback = function() {
|
||||
trace('dialogue finish');
|
||||
handSelect.visible = true;
|
||||
dialogueEnded = true;
|
||||
};
|
||||
handSelect.visible = false;
|
||||
dialogueEnded = false;
|
||||
|
||||
switch (curCharacter)
|
||||
{
|
||||
case 'dad':
|
||||
portraitRight.visible = false;
|
||||
if (!portraitLeft.visible)
|
||||
{
|
||||
portraitLeft.visible = true;
|
||||
portraitLeft.animation.play('enter');
|
||||
}
|
||||
case 'bf':
|
||||
portraitLeft.visible = false;
|
||||
if (!portraitRight.visible)
|
||||
{
|
||||
portraitRight.visible = true;
|
||||
portraitRight.animation.play('enter');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanDialog():Void
|
||||
{
|
||||
var splitName:Array<String> = dialogueList[0].split(':');
|
||||
curCharacter = splitName[1];
|
||||
dialogueList[0] = dialogueList[0].substr(splitName[1].length + 2).trim();
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.tile.FlxDrawBaseItem;
|
||||
import openfl.display.MovieClip;
|
||||
|
||||
class FlxSwf extends FlxSprite
|
||||
{
|
||||
public var swf:MovieClip;
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
override function draw()
|
||||
{
|
||||
for (camera in cameras)
|
||||
{
|
||||
if (!camera.visible || !camera.exists) continue;
|
||||
|
||||
getScreenPosition(_point, camera).subtractPoint(offset);
|
||||
// assume no render blit for now
|
||||
// use camera.canvas
|
||||
// camera.canvas.graphics.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FlxDrawSwfItem extends FlxDrawBaseItem<FlxDrawSwfItem>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
type = FlxDrawItemType.TILES;
|
||||
}
|
||||
|
||||
override function render(camera:FlxCamera)
|
||||
{
|
||||
super.render(camera);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
package funkin;
|
||||
|
||||
/**
|
||||
* A core class which handles tracking score and combo for the current song.
|
||||
*/
|
||||
class Highscore
|
||||
{
|
||||
public static var tallies:Tallies = new Tallies();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package funkin;
|
||||
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
import flixel.FlxState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
|
||||
|
@ -10,7 +12,7 @@ import flixel.math.FlxRect;
|
|||
import flixel.FlxSprite;
|
||||
import flixel.system.debug.log.LogStyle;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
import funkin.util.macro.MacroUtil;
|
||||
import funkin.util.WindowUtil;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
|
@ -26,11 +28,15 @@ import funkin.play.stage.StageData.StageDataParser;
|
|||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.ui.title.TitleState;
|
||||
import funkin.util.CLIUtil;
|
||||
import funkin.util.CLIUtil.CLIParams;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
#if discord_rpc
|
||||
import Discord.DiscordClient;
|
||||
#end
|
||||
|
||||
/**
|
||||
* A core class which performs initialization of the game.
|
||||
* The initialization state has several functions:
|
||||
* - Calls code to set up the game, including loading saves and parsing game data.
|
||||
* - Chooses whether to start via debug or via launching normally.
|
||||
|
@ -228,13 +234,13 @@ class InitState extends FlxState
|
|||
#elseif FREEPLAY // -DFREEPLAY
|
||||
FlxG.switchState(new FreeplayState());
|
||||
#elseif ANIMATE // -DANIMATE
|
||||
FlxG.switchState(new funkin.ui.animDebugShit.FlxAnimateTest());
|
||||
FlxG.switchState(new funkin.ui.debug.anim.FlxAnimateTest());
|
||||
#elseif CHARTING // -DCHARTING
|
||||
FlxG.switchState(new funkin.ui.debug.charting.ChartEditorState());
|
||||
#elseif STAGEBUILD // -DSTAGEBUILD
|
||||
FlxG.switchState(new funkin.ui.stageBullshit.StageBuilderState());
|
||||
FlxG.switchState(new funkin.ui.debug.stage.StageBuilderState());
|
||||
#elseif ANIMDEBUG // -DANIMDEBUG
|
||||
FlxG.switchState(new funkin.ui.animDebugShit.DebugBoundingState());
|
||||
FlxG.switchState(new funkin.ui.debug.anim.DebugBoundingState());
|
||||
#elseif LATENCY // -DLATENCY
|
||||
FlxG.switchState(new funkin.LatencyState());
|
||||
#else
|
||||
|
@ -247,8 +253,21 @@ class InitState extends FlxState
|
|||
*/
|
||||
function startGameNormally():Void
|
||||
{
|
||||
FlxG.sound.cache(Paths.music('freakyMenu/freakyMenu'));
|
||||
FlxG.switchState(new TitleState());
|
||||
var params:CLIParams = CLIUtil.processArgs();
|
||||
trace('Command line args: ${params}');
|
||||
|
||||
if (params.chart.shouldLoadChart)
|
||||
{
|
||||
FlxG.switchState(new ChartEditorState(
|
||||
{
|
||||
fnfcTargetPath: params.chart.chartPath,
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.sound.cache(Paths.music('freakyMenu/freakyMenu'));
|
||||
FlxG.switchState(new TitleState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
|
||||
class MenuCharacter extends FlxSprite
|
||||
{
|
||||
public var character:String;
|
||||
|
||||
public function new(x:Float, character:String = 'bf')
|
||||
{
|
||||
super(x);
|
||||
|
||||
this.character = character;
|
||||
|
||||
var suffix:String = character;
|
||||
|
||||
if (character != "darnell" && character != "nene") suffix = "characters";
|
||||
|
||||
var tex = Paths.getSparrowAtlas('campaign_menu_UI_' + suffix);
|
||||
frames = tex;
|
||||
|
||||
trace(character);
|
||||
|
||||
animation.addByPrefix('bf', "BF idle dance white", 24);
|
||||
animation.addByPrefix('bfConfirm', 'BF HEY!!', 24, false);
|
||||
animation.addByPrefix('gf', "GF Dancing Beat WHITE", 24);
|
||||
animation.addByPrefix('dad', "Dad idle dance BLACK LINE", 24);
|
||||
animation.addByPrefix('spooky', "spooky dance idle BLACK LINES", 24);
|
||||
animation.addByPrefix('pico', "Pico Idle Dance", 24);
|
||||
animation.addByPrefix('mom', "Mom Idle BLACK LINES", 24);
|
||||
animation.addByPrefix('parents-christmas', "Parent Christmas Idle", 24);
|
||||
animation.addByPrefix('senpai', "SENPAI idle Black Lines", 24);
|
||||
animation.addByPrefix('tankman', "Tankman Menu BLACK", 24);
|
||||
animation.addByPrefix('darnell', "Darnell Black Lines To Scale", 24);
|
||||
animation.addByPrefix('nene', "Nene Black Lines To Scale", 24);
|
||||
// Parent Christmas Idle
|
||||
|
||||
animation.play(character);
|
||||
updateHitbox();
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import haxe.io.Path;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
|
||||
class NoteSplash extends FlxSprite
|
||||
{
|
||||
public function new(x:Float, y:Float, noteData:Int = 0):Void
|
||||
{
|
||||
super(x, y);
|
||||
|
||||
animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false);
|
||||
animation.addByPrefix('note1-0', 'note impact 1 blue', 24, false);
|
||||
animation.addByPrefix('note2-0', 'note impact 1 green', 24, false);
|
||||
animation.addByPrefix('note3-0', 'note impact 1 red', 24, false);
|
||||
animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false);
|
||||
animation.addByPrefix('note1-1', 'note impact 2 blue', 24, false);
|
||||
animation.addByPrefix('note2-1', 'note impact 2 green', 24, false);
|
||||
animation.addByPrefix('note3-1', 'note impact 2 red', 24, false);
|
||||
|
||||
setupNoteSplash(x, y, noteData);
|
||||
|
||||
// alpha = 0.75;
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
if (animation.finished)
|
||||
{
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
public static function buildSplashFrames(force:Bool = false):FlxAtlasFrames
|
||||
{
|
||||
// static variables inside functions are a cool of Haxe 4.3.0.
|
||||
static var splashFrames:FlxAtlasFrames = null;
|
||||
|
||||
if (splashFrames != null && !force) return splashFrames;
|
||||
|
||||
splashFrames = Paths.getSparrowAtlas('noteSplashes');
|
||||
|
||||
splashFrames.parent.persist = true;
|
||||
|
||||
return splashFrames;
|
||||
}
|
||||
|
||||
public function setupNoteSplash(x:Float, y:Float, noteData:Int = 0)
|
||||
{
|
||||
setPosition(x, y);
|
||||
alpha = 0.6;
|
||||
|
||||
animation.play('note' + noteData + '-' + FlxG.random.int(0, 1), true);
|
||||
animation.curAnim.frameRate = 24 + FlxG.random.int(-2, 2);
|
||||
animation.finishCallback = function(name) {
|
||||
kill();
|
||||
};
|
||||
updateHitbox();
|
||||
|
||||
offset.set(width * 0.3, height * 0.3);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
class Options
|
||||
{
|
||||
public static var masterVolume:Float = 1;
|
||||
}
|
|
@ -4,6 +4,9 @@ import flixel.graphics.frames.FlxAtlasFrames;
|
|||
import openfl.utils.AssetType;
|
||||
import openfl.utils.Assets as OpenFlAssets;
|
||||
|
||||
/**
|
||||
* A core class which handles determining asset paths.
|
||||
*/
|
||||
class Paths
|
||||
{
|
||||
static var currentLevel:String;
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package funkin;
|
||||
|
||||
import funkin.save.Save;
|
||||
import funkin.Controls;
|
||||
import funkin.input.Controls;
|
||||
import flixel.FlxCamera;
|
||||
import funkin.input.PreciseInputManager;
|
||||
import flixel.input.actions.FlxActionInput;
|
||||
import flixel.input.gamepad.FlxGamepad;
|
||||
import flixel.util.FlxSignal;
|
||||
|
||||
// import ui.DeviceManager;
|
||||
// import props.Player;
|
||||
/**
|
||||
* A core class which represents the current player(s) and their controls and other configuration.
|
||||
*/
|
||||
class PlayerSettings
|
||||
{
|
||||
public static var numPlayers(default, null) = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@ package funkin;
|
|||
import funkin.save.Save;
|
||||
|
||||
/**
|
||||
* A store of user-configurable, globally relevant values.
|
||||
* A core class which provides a store of user-configurable, globally relevant values.
|
||||
*/
|
||||
class Preferences
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package;
|
||||
package funkin;
|
||||
|
||||
import flash.Lib;
|
||||
import flash.display.Bitmap;
|
||||
|
@ -7,6 +7,7 @@ import flash.display.BlendMode;
|
|||
import flash.display.Sprite;
|
||||
import flixel.system.FlxBasePreloader;
|
||||
import openfl.display.Sprite;
|
||||
import funkin.util.CLIUtil;
|
||||
|
||||
@:bitmap("art/preloaderArt.png") class LogoImage extends BitmapData {}
|
||||
|
||||
|
@ -15,6 +16,8 @@ class Preloader extends FlxBasePreloader
|
|||
public function new(MinDisplayTime:Float = 0, ?AllowedURLs:Array<String>)
|
||||
{
|
||||
super(MinDisplayTime, AllowedURLs);
|
||||
|
||||
CLIUtil.resetWorkingDir(); // Bug fix for drag-and-drop.
|
||||
}
|
||||
|
||||
var logo:Sprite;
|
|
@ -1,27 +0,0 @@
|
|||
package funkin;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.sound.FlxSound;
|
||||
|
||||
class TankCutscene extends FlxSprite
|
||||
{
|
||||
public var startSyncAudio:FlxSound;
|
||||
|
||||
public function new(x:Float, y:Float)
|
||||
{
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
var startedPlayingSound:Bool = false;
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
if (animation.curAnim.curFrame >= 1 && !startedPlayingSound)
|
||||
{
|
||||
startSyncAudio.play();
|
||||
startedPlayingSound = true;
|
||||
}
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package funkin;
|
||||
package funkin.api.discord;
|
||||
|
||||
import Sys.sleep;
|
||||
#if discord_rpc
|
|
@ -241,15 +241,3 @@ class NGUtil
|
|||
}
|
||||
#end
|
||||
}
|
||||
|
||||
enum ConnectionResult
|
||||
{
|
||||
/** Log in successful */
|
||||
Success;
|
||||
|
||||
/** Could not login */
|
||||
Fail(msg:String);
|
||||
|
||||
/** User cancelled the login */
|
||||
Cancelled;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package funkin;
|
||||
package funkin.api.newgrounds;
|
||||
|
||||
#if newgrounds
|
||||
import flixel.util.FlxSignal;
|
|
@ -6,4 +6,4 @@ This package contains two main classes:
|
|||
such as retrieving achievement status.
|
||||
- `NGUnsafe` contains sensitive utility functions for interacting with the Newgrounds API.
|
||||
- This includes any functions which scripts should not be able to use,
|
||||
such as writing high scores or posting achievements.
|
||||
such as writing high scores or posting achievements.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.audiovis;
|
||||
package funkin.audio.visualize;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
|
@ -1,12 +1,13 @@
|
|||
package funkin.audiovis;
|
||||
package funkin.audio.visualize;
|
||||
|
||||
import funkin.audiovis.dsp.FFT;
|
||||
import funkin.audio.visualize.dsp.FFT;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.plugin.taskManager.FlxTask;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.sound.FlxSound;
|
||||
import funkin.util.MathUtil;
|
||||
|
||||
using Lambda;
|
||||
|
||||
|
@ -86,7 +87,7 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
|
|||
for (i in 0...group.members.length)
|
||||
{
|
||||
var getSliceShit = function(s:Int) {
|
||||
var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, CoolUtil.coolBaseLog(10, freqShit[0].length));
|
||||
var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, MathUtil.logBase(10, freqShit[0].length));
|
||||
return Math.round(Math.pow(10, powShit));
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ import flixel.math.FlxMath;
|
|||
import flixel.math.FlxPoint;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.audiovis.VisShit;
|
||||
import funkin.audio.visualize.VisShit;
|
||||
import funkin.graphics.rendering.MeshRender;
|
||||
import lime.utils.Int16Array;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.audiovis;
|
||||
package funkin.audio.visualize;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||
|
@ -8,8 +8,8 @@ import flixel.math.FlxVector;
|
|||
import flixel.sound.FlxSound;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.audio.visualize.PolygonSpectogram.VISTYPE;
|
||||
import funkin.audiovis.VisShit.CurAudioInfo;
|
||||
import funkin.audiovis.dsp.FFT;
|
||||
import funkin.audio.visualize.VisShit.CurAudioInfo;
|
||||
import funkin.audio.visualize.dsp.FFT;
|
||||
import haxe.Timer;
|
||||
import lime.system.ThreadPool;
|
||||
import lime.utils.Int16Array;
|
|
@ -1,11 +1,12 @@
|
|||
package funkin.audiovis;
|
||||
package funkin.audio.visualize;
|
||||
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.sound.FlxSound;
|
||||
import funkin.audiovis.dsp.FFT;
|
||||
import funkin.audio.visualize.dsp.FFT;
|
||||
import haxe.Timer;
|
||||
import lime.system.ThreadPool;
|
||||
import lime.utils.Int16Array;
|
||||
import funkin.util.MathUtil;
|
||||
|
||||
using Lambda;
|
||||
|
||||
|
@ -42,7 +43,7 @@ class VisShit
|
|||
// helpers, note that spectrum indexes suppose non-negative frequencies
|
||||
final binSize = fs / fftN;
|
||||
final indexToFreq = function(k:Int) {
|
||||
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, CoolUtil.coolBaseLog(10, halfN)); // 4.3 is almost the log of 20Khz or so. Close enuf lol
|
||||
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, MathUtil.logBase(10, halfN)); // 4.3 is almost the log of 20Khz or so. Close enuf lol
|
||||
|
||||
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.audiovis.dsp;
|
||||
package funkin.audio.visualize.dsp;
|
||||
|
||||
/**
|
||||
Complex number representation.
|
|
@ -1,9 +1,9 @@
|
|||
package funkin.audiovis.dsp;
|
||||
package funkin.audio.visualize.dsp;
|
||||
|
||||
import funkin.audiovis.dsp.Complex;
|
||||
import funkin.audio.visualize.dsp.Complex;
|
||||
|
||||
using funkin.audiovis.dsp.OffsetArray;
|
||||
using funkin.audiovis.dsp.Signal;
|
||||
using funkin.audio.visualize.dsp.OffsetArray;
|
||||
using funkin.audio.visualize.dsp.Signal;
|
||||
|
||||
// these are only used for testing, down in FFT.main()
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.audiovis.dsp;
|
||||
package funkin.audio.visualize.dsp;
|
||||
|
||||
/**
|
||||
A view into an Array with an indexing offset.
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.audiovis.dsp;
|
||||
package funkin.audio.visualize.dsp;
|
||||
|
||||
using Lambda;
|
||||
|
|
@ -104,6 +104,22 @@ class DataParse
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser which outputs a `Either<Float, Array<Float>>`.
|
||||
*/
|
||||
public static function eitherFloatOrFloats(json:Json, name:String):Null<Either<Float, Array<Float>>>
|
||||
{
|
||||
switch (json.value)
|
||||
{
|
||||
case JNumber(f):
|
||||
return Either.Left(Std.parseFloat(f));
|
||||
case JArray(fields):
|
||||
return Either.Right(fields.map((field) -> cast Tools.getValue(field)));
|
||||
default:
|
||||
throw 'Expected property $name to be one or multiple floats, but it was ${json.value}.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser which outputs a `Either<Float, LegacyScrollSpeeds>`.
|
||||
* Used by the FNF legacy JSON importer.
|
||||
|
|
|
@ -3,11 +3,14 @@ package funkin.data;
|
|||
import funkin.util.SerializerUtil;
|
||||
import thx.semver.Version;
|
||||
import thx.semver.VersionRule;
|
||||
import haxe.ds.Either;
|
||||
|
||||
/**
|
||||
* `json2object` has an annotation `@:jcustomwrite` which allows for custom serialization of values to be written to JSON.
|
||||
*
|
||||
* Functions must be of the signature `(T) -> String`, where `T` is the type of the property.
|
||||
*
|
||||
* NOTE: Result must include quotation marks if the value is a string! json2object will not add them for you!
|
||||
*/
|
||||
class DataWrite
|
||||
{
|
||||
|
@ -23,11 +26,12 @@ class DataWrite
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* `@:jcustomwrite(funkin.data.DataWrite.semverVersion)`
|
||||
*/
|
||||
public static function semverVersion(value:Version):String
|
||||
{
|
||||
return value.toString();
|
||||
return '"${value.toString()}"';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,6 +39,22 @@ class DataWrite
|
|||
*/
|
||||
public static function semverVersionRule(value:VersionRule):String
|
||||
{
|
||||
return value.toString();
|
||||
return '"${value.toString()}"';
|
||||
}
|
||||
|
||||
/**
|
||||
* `@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)`
|
||||
*/
|
||||
public static function eitherFloatOrFloats(value:Null<Either<Float, Array<Float>>>):String
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case null:
|
||||
return '${1.0}';
|
||||
case Left(inner):
|
||||
return '$inner';
|
||||
case Right(inner):
|
||||
return dynamicValue(inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,10 @@ typedef UnnamedAnimationData =
|
|||
* The prefix for the frames of the animation as defined by the XML file.
|
||||
* This will may or may not differ from the `name` of the animation,
|
||||
* depending on how your animator organized their FLA or whatever.
|
||||
*
|
||||
* NOTE: For Sparrow animations, this is not optional, but for Packer animations it is.
|
||||
*/
|
||||
@:optional
|
||||
var prefix:String;
|
||||
|
||||
/**
|
||||
|
|
|
@ -208,25 +208,32 @@ typedef SongEventSchemaField =
|
|||
type:SongEventFieldType,
|
||||
|
||||
/**
|
||||
* Used for ENUM values.
|
||||
* Used only for ENUM values.
|
||||
* The key is the display name and the value is the actual value.
|
||||
*/
|
||||
?keys:Map<String, Dynamic>,
|
||||
|
||||
/**
|
||||
* Used for INTEGER and FLOAT values.
|
||||
* The minimum value that can be entered.
|
||||
* @default No minimum
|
||||
*/
|
||||
?min:Float,
|
||||
|
||||
/**
|
||||
* Used for INTEGER and FLOAT values.
|
||||
* The maximum value that can be entered.
|
||||
* @default No maximum
|
||||
*/
|
||||
?max:Float,
|
||||
|
||||
/**
|
||||
* Used for INTEGER and FLOAT values.
|
||||
* The step value that will be used when incrementing/decrementing the value.
|
||||
* @default `0.1`
|
||||
*/
|
||||
?step:Float,
|
||||
|
||||
/**
|
||||
* An optional default value for the field.
|
||||
*/
|
||||
|
|
|
@ -15,8 +15,6 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData>
|
|||
|
||||
public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
||||
|
||||
public static final DEFAULT_NOTE_STYLE_ID:String = "funkin";
|
||||
|
||||
public static final instance:NoteStyleRegistry = new NoteStyleRegistry();
|
||||
|
||||
public function new()
|
||||
|
@ -26,7 +24,7 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData>
|
|||
|
||||
public function fetchDefault():NoteStyle
|
||||
{
|
||||
return fetchEntry(DEFAULT_NOTE_STYLE_ID);
|
||||
return fetchEntry(Constants.DEFAULT_NOTE_STYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package funkin.data.song;
|
||||
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import thx.semver.Version;
|
||||
|
||||
/**
|
||||
* Data containing information about a song.
|
||||
* It should contain all the data needed to display a song in the Freeplay menu, or to load the assets required to play its chart.
|
||||
* Data which is only necessary in-game should be stored in the SongChartData.
|
||||
*/
|
||||
@:nullSafety
|
||||
class SongMetadata
|
||||
{
|
||||
|
@ -35,13 +39,11 @@ class SongMetadata
|
|||
*/
|
||||
public var playData:SongPlayData;
|
||||
|
||||
// @:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
|
||||
@:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
|
||||
public var generatedBy:String;
|
||||
|
||||
// @:default(funkin.data.song.SongData.SongTimeFormat.MILLISECONDS)
|
||||
public var timeFormat:SongTimeFormat;
|
||||
|
||||
// @:default(funkin.data.song.SongData.SongTimeChange.DEFAULT_SONGTIMECHANGES)
|
||||
public var timeChanges:Array<SongTimeChange>;
|
||||
|
||||
/**
|
||||
|
@ -64,7 +66,7 @@ class SongMetadata
|
|||
this.playData.difficulties = [];
|
||||
this.playData.characters = new SongCharacterData('bf', 'gf', 'dad');
|
||||
this.playData.stage = 'mainStage';
|
||||
this.playData.noteSkin = 'funkin';
|
||||
this.playData.noteStyle = Constants.DEFAULT_NOTE_STYLE;
|
||||
this.generatedBy = SongRegistry.DEFAULT_GENERATEDBY;
|
||||
// Variation ID.
|
||||
this.variation = (variation == null) ? Constants.DEFAULT_VARIATION : variation;
|
||||
|
@ -298,23 +300,27 @@ class SongPlayData
|
|||
|
||||
/**
|
||||
* The note style used by this song.
|
||||
* TODO: Rename to `noteStyle`? Renaming values is a breaking change to the metadata format.
|
||||
*/
|
||||
public var noteSkin:String;
|
||||
public var noteStyle:String;
|
||||
|
||||
/**
|
||||
* The difficulty rating for this song as displayed in Freeplay.
|
||||
* TODO: Adding this is a non-breaking change to the metadata format.
|
||||
* The difficulty ratings for this song as displayed in Freeplay.
|
||||
* Key is a difficulty ID or `default`.
|
||||
*/
|
||||
// public var rating:Int;
|
||||
@:default(['default' => 1])
|
||||
public var ratings:Map<String, Int>;
|
||||
|
||||
/**
|
||||
* The album ID for the album to display in Freeplay.
|
||||
* TODO: Adding this is a non-breaking change to the metadata format.
|
||||
* If `null`, display no album.
|
||||
*/
|
||||
// public var album:String;
|
||||
@:optional
|
||||
public var album:Null<String>;
|
||||
|
||||
public function new() {}
|
||||
public function new()
|
||||
{
|
||||
ratings = new Map<String, Int>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a string representation suitable for debugging.
|
||||
|
@ -528,12 +534,22 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
|||
|
||||
public inline function getInt(key:String):Null<Int>
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
if (this.value == null) return null;
|
||||
var result = Reflect.field(this.value, key);
|
||||
if (result == null) return null;
|
||||
if (Std.isOfType(result, Int)) return result;
|
||||
if (Std.isOfType(result, String)) return Std.parseInt(cast result);
|
||||
return cast result;
|
||||
}
|
||||
|
||||
public inline function getFloat(key:String):Null<Float>
|
||||
{
|
||||
return this.value == null ? null : cast Reflect.field(this.value, key);
|
||||
if (this.value == null) return null;
|
||||
var result = Reflect.field(this.value, key);
|
||||
if (result == null) return null;
|
||||
if (Std.isOfType(result, Float)) return result;
|
||||
if (Std.isOfType(result, String)) return Std.parseFloat(cast result);
|
||||
return cast result;
|
||||
}
|
||||
|
||||
public inline function getString(key:String):String
|
||||
|
|
|
@ -3,6 +3,7 @@ package funkin.data.song;
|
|||
import flixel.util.FlxSort;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongData.SongTimeChange;
|
||||
import funkin.util.ClipboardUtil;
|
||||
import funkin.util.SerializerUtil;
|
||||
|
||||
|
@ -163,6 +164,18 @@ class SongDataUtils
|
|||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort an array of notes by strum time.
|
||||
*/
|
||||
public static function sortTimeChanges(timeChanges:Array<SongTimeChange>, desc:Bool = false):Array<SongTimeChange>
|
||||
{
|
||||
// TODO: Modifies the array in place. Is this okay?
|
||||
timeChanges.sort(function(a:SongTimeChange, b:SongTimeChange):Int {
|
||||
return FlxSort.byValues(desc ? FlxSort.DESCENDING : FlxSort.ASCENDING, a.timeStamp, b.timeStamp);
|
||||
});
|
||||
return timeChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize note and event data and write it to the clipboard.
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@ package funkin.data.song;
|
|||
|
||||
import funkin.data.song.SongData;
|
||||
import funkin.data.song.migrator.SongData_v2_0_0.SongMetadata_v2_0_0;
|
||||
import funkin.data.song.migrator.SongData_v2_1_0.SongMetadata_v2_1_0;
|
||||
import funkin.data.song.SongData.SongChartData;
|
||||
import funkin.data.song.SongData.SongMetadata;
|
||||
import funkin.play.song.ScriptedSong;
|
||||
|
@ -18,9 +19,9 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
* Handle breaking changes by incrementing this value
|
||||
* and adding migration to the `migrateStageData()` function.
|
||||
*/
|
||||
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.1.0";
|
||||
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.0";
|
||||
|
||||
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.1.x";
|
||||
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
|
||||
|
||||
public static final SONG_CHART_DATA_VERSION:thx.semver.Version = "2.0.0";
|
||||
|
||||
|
@ -165,6 +166,10 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
{
|
||||
return parseEntryMetadata(id, variation);
|
||||
}
|
||||
else if (VersionUtil.validateVersion(version, "2.1.x"))
|
||||
{
|
||||
return parseEntryMetadata_v2_1_0(id, variation);
|
||||
}
|
||||
else if (VersionUtil.validateVersion(version, "2.0.x"))
|
||||
{
|
||||
return parseEntryMetadata_v2_0_0(id, variation);
|
||||
|
@ -182,6 +187,10 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
{
|
||||
return parseEntryMetadataRaw(contents, fileName);
|
||||
}
|
||||
else if (VersionUtil.validateVersion(version, "2.1.x"))
|
||||
{
|
||||
return parseEntryMetadataRaw_v2_1_0(contents, fileName);
|
||||
}
|
||||
else if (VersionUtil.validateVersion(version, "2.0.x"))
|
||||
{
|
||||
return parseEntryMetadataRaw_v2_0_0(contents, fileName);
|
||||
|
@ -192,12 +201,12 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
}
|
||||
}
|
||||
|
||||
function parseEntryMetadata_v2_0_0(id:String, ?variation:String):Null<SongMetadata>
|
||||
function parseEntryMetadata_v2_1_0(id:String, ?variation:String):Null<SongMetadata>
|
||||
{
|
||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||
|
||||
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
||||
switch (loadEntryMetadataFile(id))
|
||||
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
||||
switch (loadEntryMetadataFile(id, variation))
|
||||
{
|
||||
case {fileName: fileName, contents: contents}:
|
||||
parser.fromJson(contents, fileName);
|
||||
|
@ -209,6 +218,39 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
|||
printErrors(parser.errors, id);
|
||||
return null;
|
||||
}
|
||||
return cleanMetadata(parser.value.migrate(), variation);
|
||||
}
|
||||
|
||||
function parseEntryMetadata_v2_0_0(id:String, ?variation:String):Null<SongMetadata>
|
||||
{
|
||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||
|
||||
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
||||
switch (loadEntryMetadataFile(id, variation))
|
||||
{
|
||||
case {fileName: fileName, contents: contents}:
|
||||
parser.fromJson(contents, fileName);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
if (parser.errors.length > 0)
|
||||
{
|
||||
printErrors(parser.errors, id);
|
||||
return null;
|
||||
}
|
||||
return cleanMetadata(parser.value.migrate(), variation);
|
||||
}
|
||||
|
||||
function parseEntryMetadataRaw_v2_1_0(contents:String, ?fileName:String = 'raw'):Null<SongMetadata>
|
||||
{
|
||||
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
||||
parser.fromJson(contents, fileName);
|
||||
|
||||
if (parser.errors.length > 0)
|
||||
{
|
||||
printErrors(parser.errors, fileName);
|
||||
return null;
|
||||
}
|
||||
return parser.value.migrate();
|
||||
}
|
||||
|
||||
|
|
84
source/funkin/data/song/importer/ChartManifestData.hx
Normal file
84
source/funkin/data/song/importer/ChartManifestData.hx
Normal file
|
@ -0,0 +1,84 @@
|
|||
package funkin.data.song.importer;
|
||||
|
||||
/**
|
||||
* A helper JSON blob found in `.fnfc` files.
|
||||
*/
|
||||
class ChartManifestData
|
||||
{
|
||||
/**
|
||||
* The current semantic version of the chart manifest data.
|
||||
*/
|
||||
public static final CHART_MANIFEST_DATA_VERSION:thx.semver.Version = "1.0.0";
|
||||
|
||||
@:default(funkin.data.song.importer.ChartManifestData.CHART_MANIFEST_DATA_VERSION)
|
||||
@:jcustomparse(funkin.data.DataParse.semverVersion)
|
||||
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
|
||||
public var version:thx.semver.Version;
|
||||
|
||||
/**
|
||||
* The internal song ID for this chart.
|
||||
* The metadata and chart data file names are derived from this.
|
||||
*/
|
||||
public var songId:String;
|
||||
|
||||
public function new(songId:String)
|
||||
{
|
||||
this.version = CHART_MANIFEST_DATA_VERSION;
|
||||
this.songId = songId;
|
||||
}
|
||||
|
||||
public function getMetadataFileName(?variation:String):String
|
||||
{
|
||||
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
|
||||
|
||||
return '$songId-metadata${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_DATA}';
|
||||
}
|
||||
|
||||
public function getChartDataFileName(?variation:String):String
|
||||
{
|
||||
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
|
||||
|
||||
return '$songId-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_DATA}';
|
||||
}
|
||||
|
||||
public function getInstFileName(?variation:String):String
|
||||
{
|
||||
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
|
||||
|
||||
return 'Inst${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
|
||||
}
|
||||
|
||||
public function getVocalsFileName(charId:String, ?variation:String):String
|
||||
{
|
||||
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
|
||||
|
||||
return 'Voices-$charId${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this ChartManifestData into a JSON string.
|
||||
* @return The JSON string.
|
||||
*/
|
||||
public function serialize(pretty:Bool = true):String
|
||||
{
|
||||
var writer = new json2object.JsonWriter<ChartManifestData>();
|
||||
return writer.write(this, pretty ? ' ' : null);
|
||||
}
|
||||
|
||||
public static function deserialize(contents:String):Null<ChartManifestData>
|
||||
{
|
||||
var parser = new json2object.JsonParser<ChartManifestData>();
|
||||
parser.fromJson(contents, 'manifest.json');
|
||||
|
||||
if (parser.errors.length > 0)
|
||||
{
|
||||
trace('[ChartManifest] Failed to parse chart file manifest');
|
||||
|
||||
for (error in parser.errors)
|
||||
DataError.printError(error);
|
||||
|
||||
return null;
|
||||
}
|
||||
return parser.value;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ import funkin.data.song.migrator.SongData_v2_0_0.SongMetadata_v2_0_0;
|
|||
import funkin.data.song.migrator.SongData_v2_0_0.SongPlayData_v2_0_0;
|
||||
import funkin.data.song.migrator.SongData_v2_0_0.SongPlayableChar_v2_0_0;
|
||||
|
||||
using funkin.data.song.migrator.SongDataMigrator; // Does this even work lol?
|
||||
|
||||
/**
|
||||
* This class contains functions to migrate older data formats to the current one.
|
||||
*
|
||||
|
@ -15,6 +17,48 @@ import funkin.data.song.migrator.SongData_v2_0_0.SongPlayableChar_v2_0_0;
|
|||
*/
|
||||
class SongDataMigrator
|
||||
{
|
||||
public static overload extern inline function migrate(input:SongData_v2_1_0.SongMetadata_v2_1_0):SongMetadata
|
||||
{
|
||||
return migrate_SongMetadata_v2_1_0(input);
|
||||
}
|
||||
|
||||
public static function migrate_SongMetadata_v2_1_0(input:SongData_v2_1_0.SongMetadata_v2_1_0):SongMetadata
|
||||
{
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, input.variation);
|
||||
result.version = SongRegistry.SONG_METADATA_VERSION;
|
||||
result.timeFormat = input.timeFormat;
|
||||
result.divisions = input.divisions;
|
||||
result.timeChanges = input.timeChanges;
|
||||
result.looped = input.looped;
|
||||
result.playData = input.playData.migrate();
|
||||
result.generatedBy = input.generatedBy;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static overload extern inline function migrate(input:SongData_v2_1_0.SongPlayData_v2_1_0):SongPlayData
|
||||
{
|
||||
return migrate_SongPlayData_v2_1_0(input);
|
||||
}
|
||||
|
||||
public static function migrate_SongPlayData_v2_1_0(input:SongData_v2_1_0.SongPlayData_v2_1_0):SongPlayData
|
||||
{
|
||||
var result:SongPlayData = new SongPlayData();
|
||||
result.songVariations = input.songVariations;
|
||||
result.difficulties = input.difficulties;
|
||||
result.stage = input.stage;
|
||||
result.characters = input.characters;
|
||||
|
||||
// Renamed
|
||||
result.noteStyle = input.noteSkin;
|
||||
|
||||
// Added
|
||||
result.ratings = ['default' => 1];
|
||||
result.album = null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static overload extern inline function migrate(input:SongData_v2_0_0.SongMetadata_v2_0_0):SongMetadata
|
||||
{
|
||||
return migrate_SongMetadata_v2_0_0(input);
|
||||
|
@ -23,12 +67,12 @@ class SongDataMigrator
|
|||
public static function migrate_SongMetadata_v2_0_0(input:SongData_v2_0_0.SongMetadata_v2_0_0):SongMetadata
|
||||
{
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, input.variation);
|
||||
result.version = input.version;
|
||||
result.version = SongRegistry.SONG_METADATA_VERSION;
|
||||
result.timeFormat = input.timeFormat;
|
||||
result.divisions = input.divisions;
|
||||
result.timeChanges = input.timeChanges;
|
||||
result.looped = input.looped;
|
||||
result.playData = migrate_SongPlayData_v2_0_0(input.playData);
|
||||
result.playData = input.playData.migrate();
|
||||
result.generatedBy = input.generatedBy;
|
||||
|
||||
return result;
|
||||
|
@ -45,7 +89,13 @@ class SongDataMigrator
|
|||
result.songVariations = input.songVariations;
|
||||
result.difficulties = input.difficulties;
|
||||
result.stage = input.stage;
|
||||
result.noteSkin = input.noteSkin;
|
||||
|
||||
// Added
|
||||
result.ratings = ['default' => 1];
|
||||
result.album = null;
|
||||
|
||||
// Renamed
|
||||
result.noteStyle = input.noteSkin;
|
||||
|
||||
// Fetch the first playable character and migrate it.
|
||||
var firstCharKey:Null<String> = input.playableChars.size() == 0 ? null : input.playableChars.keys().array()[0];
|
||||
|
|
|
@ -42,6 +42,7 @@ class SongMetadata_v2_0_0
|
|||
@:default(false)
|
||||
public var looped:Bool;
|
||||
|
||||
@:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
|
||||
public var generatedBy:String;
|
||||
|
||||
public var timeFormat:SongData.SongTimeFormat;
|
||||
|
@ -70,6 +71,13 @@ class SongPlayData_v2_0_0
|
|||
*/
|
||||
public var playableChars:Map<String, SongPlayableChar_v2_0_0>;
|
||||
|
||||
/**
|
||||
* In metadata version `v2.2.0`, this was renamed to `noteStyle`.
|
||||
*/
|
||||
public var noteSkin:String;
|
||||
|
||||
// In 2.2.0, the ratings value was added.
|
||||
// In 2.2.0, the album value was added.
|
||||
// ==========
|
||||
// UNMODIFIED VALUES
|
||||
// ==========
|
||||
|
@ -77,7 +85,6 @@ class SongPlayData_v2_0_0
|
|||
public var difficulties:Array<String>;
|
||||
|
||||
public var stage:String;
|
||||
public var noteSkin:String;
|
||||
|
||||
public function new() {}
|
||||
|
||||
|
|
108
source/funkin/data/song/migrator/SongData_v2_1_0.hx
Normal file
108
source/funkin/data/song/migrator/SongData_v2_1_0.hx
Normal file
|
@ -0,0 +1,108 @@
|
|||
package funkin.data.song.migrator;
|
||||
|
||||
import funkin.data.song.SongData;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import thx.semver.Version;
|
||||
|
||||
@:nullSafety
|
||||
class SongMetadata_v2_1_0
|
||||
{
|
||||
// ==========
|
||||
// MODIFIED VALUES
|
||||
// ===========
|
||||
|
||||
/**
|
||||
* In metadata `v2.2.0`, `SongPlayData` was refactored.
|
||||
*/
|
||||
public var playData:SongPlayData_v2_1_0;
|
||||
|
||||
// ==========
|
||||
// UNMODIFIED VALUES
|
||||
// ==========
|
||||
@:jcustomparse(funkin.data.DataParse.semverVersion)
|
||||
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
|
||||
public var version:Version;
|
||||
|
||||
@:default("Unknown")
|
||||
public var songName:String;
|
||||
|
||||
@:default("Unknown")
|
||||
public var artist:String;
|
||||
|
||||
@:optional
|
||||
@:default(96)
|
||||
public var divisions:Null<Int>; // Optional field
|
||||
|
||||
@:optional
|
||||
@:default(false)
|
||||
public var looped:Bool;
|
||||
|
||||
@:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
|
||||
public var generatedBy:String;
|
||||
|
||||
public var timeFormat:SongData.SongTimeFormat;
|
||||
|
||||
public var timeChanges:Array<SongData.SongTimeChange>;
|
||||
|
||||
/**
|
||||
* Defaults to `Constants.DEFAULT_VARIATION`. Populated later.
|
||||
*/
|
||||
@:jignored
|
||||
public var variation:String;
|
||||
|
||||
public function new(songName:String, artist:String, ?variation:String)
|
||||
{
|
||||
this.version = SongRegistry.SONG_METADATA_VERSION;
|
||||
this.songName = songName;
|
||||
this.artist = artist;
|
||||
this.timeFormat = 'ms';
|
||||
this.divisions = null;
|
||||
this.timeChanges = [new SongTimeChange(0, 100)];
|
||||
this.looped = false;
|
||||
this.playData = new SongPlayData_v2_1_0();
|
||||
this.playData.songVariations = [];
|
||||
this.playData.difficulties = [];
|
||||
this.playData.characters = new SongCharacterData('bf', 'gf', 'dad');
|
||||
this.playData.stage = 'mainStage';
|
||||
this.playData.noteSkin = 'funkin';
|
||||
this.generatedBy = SongRegistry.DEFAULT_GENERATEDBY;
|
||||
// Variation ID.
|
||||
this.variation = (variation == null) ? Constants.DEFAULT_VARIATION : variation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a string representation suitable for debugging.
|
||||
*/
|
||||
public function toString():String
|
||||
{
|
||||
return 'SongMetadata[LEGACY:v2.1.0](${this.songName} by ${this.artist}, variation ${this.variation})';
|
||||
}
|
||||
}
|
||||
|
||||
class SongPlayData_v2_1_0
|
||||
{
|
||||
/**
|
||||
* In `v2.2.0`, this value was renamed to `noteStyle`.
|
||||
*/
|
||||
public var noteSkin:String;
|
||||
|
||||
// In 2.2.0, the ratings value was added.
|
||||
// In 2.2.0, the album value was added.
|
||||
// ==========
|
||||
// UNMODIFIED VALUES
|
||||
// ==========
|
||||
public var songVariations:Array<String>;
|
||||
public var difficulties:Array<String>;
|
||||
public var characters:SongData.SongCharacterData;
|
||||
public var stage:String;
|
||||
|
||||
public function new() {}
|
||||
|
||||
/**
|
||||
* Produces a string representation suitable for debugging.
|
||||
*/
|
||||
public function toString():String
|
||||
{
|
||||
return 'SongPlayData[LEGACY:v2.1.0](${this.songVariations}, ${this.difficulties})';
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import openfl.display.ShaderParameter;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import funkin.Paths;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxColor;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import funkin.Paths;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import funkin.Paths;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import funkin.Paths;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxColor;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxColor;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.shaderslmfao;
|
||||
package funkin.graphics.shaders;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import openfl.Assets;
|
|
@ -12,6 +12,7 @@ using Lambda;
|
|||
using StringTools;
|
||||
using funkin.util.tools.ArraySortTools;
|
||||
using funkin.util.tools.ArrayTools;
|
||||
using funkin.util.tools.DynamicTools;
|
||||
using funkin.util.tools.FloatTools;
|
||||
using funkin.util.tools.Int64Tools;
|
||||
using funkin.util.tools.IntTools;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
package funkin;
|
||||
package funkin.input;
|
||||
|
||||
import flixel.input.gamepad.FlxGamepad;
|
||||
import flixel.util.FlxDirectionFlags;
|
||||
|
@ -23,96 +22,14 @@ import flixel.util.FlxTimer;
|
|||
import lime.ui.Haptic;
|
||||
|
||||
/**
|
||||
* Since, in many cases multiple actions should use similar keys, we don't want the
|
||||
* rebinding UI to list every action. ActionBinders are what the user percieves as
|
||||
* an input so, for instance, they can't set jump-press and jump-release to different keys.
|
||||
*/
|
||||
enum Control
|
||||
{
|
||||
// List notes in order from left to right on gameplay screen.
|
||||
NOTE_LEFT;
|
||||
NOTE_DOWN;
|
||||
NOTE_UP;
|
||||
NOTE_RIGHT;
|
||||
UI_UP;
|
||||
UI_LEFT;
|
||||
UI_RIGHT;
|
||||
UI_DOWN;
|
||||
RESET;
|
||||
ACCEPT;
|
||||
BACK;
|
||||
PAUSE;
|
||||
CUTSCENE_ADVANCE;
|
||||
CUTSCENE_SKIP;
|
||||
VOLUME_UP;
|
||||
VOLUME_DOWN;
|
||||
VOLUME_MUTE;
|
||||
#if CAN_CHEAT
|
||||
CHEAT;
|
||||
#end
|
||||
}
|
||||
|
||||
enum
|
||||
abstract Action(String) to String from String
|
||||
{
|
||||
var UI_UP = "ui_up";
|
||||
var UI_LEFT = "ui_left";
|
||||
var UI_RIGHT = "ui_right";
|
||||
var UI_DOWN = "ui_down";
|
||||
var UI_UP_P = "ui_up-press";
|
||||
var UI_LEFT_P = "ui_left-press";
|
||||
var UI_RIGHT_P = "ui_right-press";
|
||||
var UI_DOWN_P = "ui_down-press";
|
||||
var UI_UP_R = "ui_up-release";
|
||||
var UI_LEFT_R = "ui_left-release";
|
||||
var UI_RIGHT_R = "ui_right-release";
|
||||
var UI_DOWN_R = "ui_down-release";
|
||||
var NOTE_UP = "note_up";
|
||||
var NOTE_LEFT = "note_left";
|
||||
var NOTE_RIGHT = "note_right";
|
||||
var NOTE_DOWN = "note_down";
|
||||
var NOTE_UP_P = "note_up-press";
|
||||
var NOTE_LEFT_P = "note_left-press";
|
||||
var NOTE_RIGHT_P = "note_right-press";
|
||||
var NOTE_DOWN_P = "note_down-press";
|
||||
var NOTE_UP_R = "note_up-release";
|
||||
var NOTE_LEFT_R = "note_left-release";
|
||||
var NOTE_RIGHT_R = "note_right-release";
|
||||
var NOTE_DOWN_R = "note_down-release";
|
||||
var ACCEPT = "accept";
|
||||
var BACK = "back";
|
||||
var PAUSE = "pause";
|
||||
var CUTSCENE_ADVANCE = "cutscene_advance";
|
||||
var CUTSCENE_SKIP = "cutscene_skip";
|
||||
var VOLUME_UP = "volume_up";
|
||||
var VOLUME_DOWN = "volume_down";
|
||||
var VOLUME_MUTE = "volume_mute";
|
||||
var RESET = "reset";
|
||||
#if CAN_CHEAT
|
||||
var CHEAT = "cheat";
|
||||
#end
|
||||
}
|
||||
|
||||
enum Device
|
||||
{
|
||||
Keys;
|
||||
Gamepad(id:Int);
|
||||
}
|
||||
|
||||
enum KeyboardScheme
|
||||
{
|
||||
Solo;
|
||||
Duo(first:Bool);
|
||||
None;
|
||||
Custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of actions that a player would invoke via some input device.
|
||||
* Uses FlxActions to funnel various inputs to a single action.
|
||||
* A core class which handles receiving player input and interpreting it into game actions.
|
||||
*/
|
||||
class Controls extends FlxActionSet
|
||||
{
|
||||
/**
|
||||
* A list of actions that a player would invoke via some input device.
|
||||
* Uses FlxActions to funnel various inputs to a single action.
|
||||
*/
|
||||
var _ui_up = new FlxActionDigital(Action.UI_UP);
|
||||
var _ui_left = new FlxActionDigital(Action.UI_LEFT);
|
||||
var _ui_right = new FlxActionDigital(Action.UI_RIGHT);
|
||||
|
@ -1241,3 +1158,88 @@ class FlxActionInputDigitalAndroid extends FlxActionInputDigital
|
|||
}
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
* Since, in many cases multiple actions should use similar keys, we don't want the
|
||||
* rebinding UI to list every action. ActionBinders are what the user percieves as
|
||||
* an input so, for instance, they can't set jump-press and jump-release to different keys.
|
||||
*/
|
||||
enum Control
|
||||
{
|
||||
// List notes in order from left to right on gameplay screen.
|
||||
NOTE_LEFT;
|
||||
NOTE_DOWN;
|
||||
NOTE_UP;
|
||||
NOTE_RIGHT;
|
||||
UI_UP;
|
||||
UI_LEFT;
|
||||
UI_RIGHT;
|
||||
UI_DOWN;
|
||||
RESET;
|
||||
ACCEPT;
|
||||
BACK;
|
||||
PAUSE;
|
||||
CUTSCENE_ADVANCE;
|
||||
CUTSCENE_SKIP;
|
||||
VOLUME_UP;
|
||||
VOLUME_DOWN;
|
||||
VOLUME_MUTE;
|
||||
#if CAN_CHEAT
|
||||
CHEAT;
|
||||
#end
|
||||
}
|
||||
|
||||
enum
|
||||
abstract Action(String) to String from String
|
||||
{
|
||||
var UI_UP = "ui_up";
|
||||
var UI_LEFT = "ui_left";
|
||||
var UI_RIGHT = "ui_right";
|
||||
var UI_DOWN = "ui_down";
|
||||
var UI_UP_P = "ui_up-press";
|
||||
var UI_LEFT_P = "ui_left-press";
|
||||
var UI_RIGHT_P = "ui_right-press";
|
||||
var UI_DOWN_P = "ui_down-press";
|
||||
var UI_UP_R = "ui_up-release";
|
||||
var UI_LEFT_R = "ui_left-release";
|
||||
var UI_RIGHT_R = "ui_right-release";
|
||||
var UI_DOWN_R = "ui_down-release";
|
||||
var NOTE_UP = "note_up";
|
||||
var NOTE_LEFT = "note_left";
|
||||
var NOTE_RIGHT = "note_right";
|
||||
var NOTE_DOWN = "note_down";
|
||||
var NOTE_UP_P = "note_up-press";
|
||||
var NOTE_LEFT_P = "note_left-press";
|
||||
var NOTE_RIGHT_P = "note_right-press";
|
||||
var NOTE_DOWN_P = "note_down-press";
|
||||
var NOTE_UP_R = "note_up-release";
|
||||
var NOTE_LEFT_R = "note_left-release";
|
||||
var NOTE_RIGHT_R = "note_right-release";
|
||||
var NOTE_DOWN_R = "note_down-release";
|
||||
var ACCEPT = "accept";
|
||||
var BACK = "back";
|
||||
var PAUSE = "pause";
|
||||
var CUTSCENE_ADVANCE = "cutscene_advance";
|
||||
var CUTSCENE_SKIP = "cutscene_skip";
|
||||
var VOLUME_UP = "volume_up";
|
||||
var VOLUME_DOWN = "volume_down";
|
||||
var VOLUME_MUTE = "volume_mute";
|
||||
var RESET = "reset";
|
||||
#if CAN_CHEAT
|
||||
var CHEAT = "cheat";
|
||||
#end
|
||||
}
|
||||
|
||||
enum Device
|
||||
{
|
||||
Keys;
|
||||
Gamepad(id:Int);
|
||||
}
|
||||
|
||||
enum KeyboardScheme
|
||||
{
|
||||
Solo;
|
||||
Duo(first:Bool);
|
||||
None;
|
||||
Custom;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.input;
|
||||
|
||||
import haxe.ui.backend.flixel.CursorHelper;
|
||||
import openfl.utils.Assets;
|
||||
import lime.app.Future;
|
||||
import openfl.display.BitmapData;
|
||||
|
@ -33,7 +34,7 @@ class Cursor
|
|||
Cursor.cursorMode = null;
|
||||
}
|
||||
|
||||
static final CURSOR_DEFAULT_PARAMS:CursorParams =
|
||||
public static final CURSOR_DEFAULT_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-default.png",
|
||||
scale: 1.0,
|
||||
|
@ -42,7 +43,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorDefault:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_CROSS_PARAMS:CursorParams =
|
||||
public static final CURSOR_CROSS_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-cross.png",
|
||||
scale: 1.0,
|
||||
|
@ -51,7 +52,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorCross:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_ERASER_PARAMS:CursorParams =
|
||||
public static final CURSOR_ERASER_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-eraser.png",
|
||||
scale: 1.0,
|
||||
|
@ -60,7 +61,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorEraser:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_GRABBING_PARAMS:CursorParams =
|
||||
public static final CURSOR_GRABBING_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-grabbing.png",
|
||||
scale: 1.0,
|
||||
|
@ -69,7 +70,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorGrabbing:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_HOURGLASS_PARAMS:CursorParams =
|
||||
public static final CURSOR_HOURGLASS_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-hourglass.png",
|
||||
scale: 1.0,
|
||||
|
@ -78,7 +79,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorHourglass:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_POINTER_PARAMS:CursorParams =
|
||||
public static final CURSOR_POINTER_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-pointer.png",
|
||||
scale: 1.0,
|
||||
|
@ -87,7 +88,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorPointer:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_TEXT_PARAMS:CursorParams =
|
||||
public static final CURSOR_TEXT_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-text.png",
|
||||
scale: 0.2,
|
||||
|
@ -96,7 +97,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorText:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_TEXT_VERTICAL_PARAMS:CursorParams =
|
||||
public static final CURSOR_TEXT_VERTICAL_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-text-vertical.png",
|
||||
scale: 0.2,
|
||||
|
@ -105,7 +106,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorTextVertical:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_ZOOM_IN_PARAMS:CursorParams =
|
||||
public static final CURSOR_ZOOM_IN_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-zoom-in.png",
|
||||
scale: 1.0,
|
||||
|
@ -114,7 +115,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorZoomIn:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_ZOOM_OUT_PARAMS:CursorParams =
|
||||
public static final CURSOR_ZOOM_OUT_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-zoom-out.png",
|
||||
scale: 1.0,
|
||||
|
@ -123,7 +124,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorZoomOut:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_CROSSHAIR_PARAMS:CursorParams =
|
||||
public static final CURSOR_CROSSHAIR_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-crosshair.png",
|
||||
scale: 1.0,
|
||||
|
@ -132,7 +133,7 @@ class Cursor
|
|||
};
|
||||
static var assetCursorCrosshair:Null<BitmapData> = null;
|
||||
|
||||
static final CURSOR_CELL_PARAMS:CursorParams =
|
||||
public static final CURSOR_CELL_PARAMS:CursorParams =
|
||||
{
|
||||
graphic: "assets/images/cursor/cursor-cell.png",
|
||||
scale: 1.0,
|
||||
|
@ -500,6 +501,28 @@ class Cursor
|
|||
{
|
||||
trace("Failed to load cursor graphic for cursor mode " + cursorMode + ": " + error);
|
||||
}
|
||||
|
||||
public static function registerHaxeUICursors():Void
|
||||
{
|
||||
CursorHelper.useCustomCursors = true;
|
||||
registerHaxeUICursor('default', CURSOR_DEFAULT_PARAMS);
|
||||
registerHaxeUICursor('cross', CURSOR_CROSS_PARAMS);
|
||||
registerHaxeUICursor('eraser', CURSOR_ERASER_PARAMS);
|
||||
registerHaxeUICursor('grabbing', CURSOR_GRABBING_PARAMS);
|
||||
registerHaxeUICursor('hourglass', CURSOR_HOURGLASS_PARAMS);
|
||||
registerHaxeUICursor('pointer', CURSOR_POINTER_PARAMS);
|
||||
registerHaxeUICursor('text', CURSOR_TEXT_PARAMS);
|
||||
registerHaxeUICursor('text-vertical', CURSOR_TEXT_VERTICAL_PARAMS);
|
||||
registerHaxeUICursor('zoom-in', CURSOR_ZOOM_IN_PARAMS);
|
||||
registerHaxeUICursor('zoom-out', CURSOR_ZOOM_OUT_PARAMS);
|
||||
registerHaxeUICursor('crosshair', CURSOR_CROSSHAIR_PARAMS);
|
||||
registerHaxeUICursor('cell', CURSOR_CELL_PARAMS);
|
||||
}
|
||||
|
||||
public static function registerHaxeUICursor(id:String, params:CursorParams):Void
|
||||
{
|
||||
CursorHelper.registerCursor(id, params.graphic, params.scale, params.offsetX, params.offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
|
||||
|
|
|
@ -108,8 +108,7 @@ class TurboKeyHandler extends FlxBasic
|
|||
* @param repeatDelay How long to wait between repeats.
|
||||
* @return A TurboKeyHandler
|
||||
*/
|
||||
public static overload inline extern function build(inputKeys:Array<FlxKey>, ?delay:Float = DEFAULT_DELAY,
|
||||
?interval:Float = DEFAULT_INTERVAL):TurboKeyHandler
|
||||
public static overload inline extern function build(inputKeys:Array<FlxKey>, ?delay:Float = DEFAULT_DELAY, ?interval:Float = DEFAULT_INTERVAL):TurboKeyHandler
|
||||
{
|
||||
return new TurboKeyHandler(inputKeys, delay, interval);
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ package funkin.modding.base;
|
|||
* Create a scripted class that extends MusicBeatState to use this.
|
||||
*/
|
||||
@:hscriptClass
|
||||
class ScriptedMusicBeatState extends funkin.MusicBeatState implements HScriptedClass {}
|
||||
class ScriptedMusicBeatState extends funkin.ui.MusicBeatState implements HScriptedClass {}
|
||||
|
|
|
@ -5,4 +5,4 @@ package funkin.modding.base;
|
|||
* Create a scripted class that extends MusicBeatSubState to use this.
|
||||
*/
|
||||
@:hscriptClass
|
||||
class ScriptedMusicBeatSubState extends funkin.MusicBeatSubState implements HScriptedClass {}
|
||||
class ScriptedMusicBeatSubState extends funkin.ui.MusicBeatSubState implements HScriptedClass {}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
package funkin.play;
|
||||
|
||||
import funkin.play.character.BaseCharacter;
|
||||
import flixel.FlxSprite;
|
||||
|
||||
class Fighter extends BaseCharacter
|
||||
{
|
||||
public function new(?x:Float = 0, ?y:Float = 0, ?char:String = "pico-fighter")
|
||||
{
|
||||
super(char, Custom);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
animation.finishCallback = function(anim:String) {
|
||||
switch anim
|
||||
{
|
||||
case "punch low" | "punch high" | "block" | 'dodge':
|
||||
dance(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public var actions:Array<ACTIONS> = [PUNCH, BLOCK, DODGE];
|
||||
|
||||
public function doSomething(?forceAction:ACTIONS)
|
||||
{
|
||||
var daAction:ACTIONS = FlxG.random.getObject(actions);
|
||||
|
||||
if (forceAction != null) daAction = forceAction;
|
||||
|
||||
switch (daAction)
|
||||
{
|
||||
case PUNCH:
|
||||
punch();
|
||||
case BLOCK:
|
||||
block();
|
||||
case DODGE:
|
||||
dodge();
|
||||
}
|
||||
}
|
||||
|
||||
public var curAction:ACTIONS = DODGE;
|
||||
|
||||
function dodge()
|
||||
{
|
||||
playAnimation('dodge');
|
||||
curAction = DODGE;
|
||||
}
|
||||
|
||||
public function block()
|
||||
{
|
||||
playAnimation('block');
|
||||
curAction = BLOCK;
|
||||
}
|
||||
|
||||
public function punch()
|
||||
{
|
||||
curAction = PUNCH;
|
||||
playAnimation('punch ' + (FlxG.random.bool() ? "low" : "high"));
|
||||
}
|
||||
}
|
||||
|
||||
enum ACTIONS
|
||||
{
|
||||
DODGE;
|
||||
BLOCK;
|
||||
PUNCH;
|
||||
}
|
|
@ -7,9 +7,11 @@ import flixel.sound.FlxSound;
|
|||
import funkin.ui.story.StoryMenuState;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.modding.events.ScriptEventDispatcher;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.ui.freeplay.FreeplayState;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package funkin;
|
||||
package funkin.play;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.ui.MusicBeatState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
|
||||
class GitarooPause extends MusicBeatState
|
||||
{
|
|
@ -1,9 +1,10 @@
|
|||
package funkin;
|
||||
package funkin.play;
|
||||
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
|
@ -11,6 +12,7 @@ import flixel.tweens.FlxTween;
|
|||
import flixel.util.FlxColor;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.ui.Alphabet;
|
||||
|
||||
class PauseSubState extends MusicBeatSubState
|
||||
{
|
||||
|
@ -231,11 +233,11 @@ class PauseSubState extends MusicBeatSubState
|
|||
|
||||
if (PlayStatePlaylist.isStoryMode)
|
||||
{
|
||||
openSubState(new funkin.ui.StickerSubState(null, STORY));
|
||||
openSubState(new funkin.ui.transition.StickerSubState(null, STORY));
|
||||
}
|
||||
else
|
||||
{
|
||||
openSubState(new funkin.ui.StickerSubState(null, FREEPLAY));
|
||||
openSubState(new funkin.ui.transition.StickerSubState(null, FREEPLAY));
|
||||
}
|
||||
|
||||
case 'Exit to Chart Editor':
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.play;
|
||||
|
||||
import funkin.ui.SwagCamera;
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
import haxe.Int64;
|
||||
|
@ -16,19 +17,24 @@ import flixel.FlxState;
|
|||
import flixel.FlxSubState;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import flixel.math.FlxMath;
|
||||
import funkin.play.components.ComboMilestone;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.play.components.HealthIcon;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.ui.FlxBar;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.api.newgrounds.NGio;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.VoicesGroup;
|
||||
import funkin.save.Save;
|
||||
import funkin.Highscore.Tallies;
|
||||
import funkin.input.PreciseInputManager;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import funkin.modding.events.ScriptEventDispatcher;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
|
@ -42,7 +48,6 @@ import funkin.play.notes.NoteDirection;
|
|||
import funkin.play.notes.Strumline;
|
||||
import funkin.play.notes.SustainTrail;
|
||||
import funkin.play.scoring.Scoring;
|
||||
import funkin.NoteSplash;
|
||||
import funkin.play.song.Song;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
|
@ -50,9 +55,10 @@ import funkin.data.song.SongData.SongNoteData;
|
|||
import funkin.data.song.SongData.SongCharacterData;
|
||||
import funkin.play.stage.Stage;
|
||||
import funkin.play.stage.StageData.StageDataParser;
|
||||
import funkin.ui.PopUpStuff;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
import funkin.ui.stageBuildShit.StageOffsetSubState;
|
||||
import funkin.ui.transition.LoadingState;
|
||||
import funkin.play.components.PopUpStuff;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
import funkin.ui.debug.stage.StageOffsetSubState;
|
||||
import funkin.ui.story.StoryMenuState;
|
||||
import funkin.util.SerializerUtil;
|
||||
import funkin.util.SortUtil;
|
||||
|
@ -510,8 +516,6 @@ class PlayState extends MusicBeatSubState
|
|||
}
|
||||
instance = this;
|
||||
|
||||
NoteSplash.buildSplashFrames();
|
||||
|
||||
if (!assertChartExists()) return;
|
||||
|
||||
if (false)
|
||||
|
@ -700,6 +704,8 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (!overrideMusic)
|
||||
{
|
||||
// Stop the vocals if they already exist.
|
||||
if (vocals != null) vocals.stop();
|
||||
vocals = currentChart.buildVocals();
|
||||
|
||||
if (vocals.members.length == 0)
|
||||
|
@ -1471,7 +1477,7 @@ class PlayState extends MusicBeatSubState
|
|||
{
|
||||
case 'school': 'pixel';
|
||||
case 'schoolEvil': 'pixel';
|
||||
default: 'funkin';
|
||||
default: Constants.DEFAULT_NOTE_STYLE;
|
||||
}
|
||||
var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId);
|
||||
if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault();
|
||||
|
@ -1554,6 +1560,8 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (!overrideMusic)
|
||||
{
|
||||
// Stop the vocals if they already exist.
|
||||
if (vocals != null) vocals.stop();
|
||||
vocals = currentChart.buildVocals();
|
||||
|
||||
if (vocals.members.length == 0)
|
||||
|
@ -2392,8 +2400,8 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
#if sys
|
||||
// spitter for ravy, teehee!!
|
||||
|
||||
var output = SerializerUtil.toJSON(inputSpitter);
|
||||
var writer = new json2object.JsonWriter<Array<ScoreInput>>();
|
||||
var output = writer.write(inputSpitter, ' ');
|
||||
sys.io.File.saveContent("./scores.json", output);
|
||||
#end
|
||||
|
||||
|
|
|
@ -8,16 +8,18 @@ import flixel.graphics.frames.FlxAtlasFrames;
|
|||
import flixel.graphics.frames.FlxBitmapFont;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.text.FlxBitmapText;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
import funkin.ui.freeplay.FreeplayState;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxGradient;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.shaderslmfao.LeftMaskShader;
|
||||
import funkin.ui.TallyCounter;
|
||||
import funkin.graphics.shaders.LeftMaskShader;
|
||||
import funkin.play.components.TallyCounter;
|
||||
import flxanimate.FlxAnimate.Settings;
|
||||
|
||||
class ResultState extends MusicBeatSubState
|
||||
|
|
|
@ -58,7 +58,7 @@ class BaseCharacter extends Bopper
|
|||
*/
|
||||
public var dropNoteCounts(default, null):Array<Int>;
|
||||
|
||||
@:allow(funkin.ui.animDebugShit.DebugBoundingState)
|
||||
@:allow(funkin.ui.debug.anim.DebugBoundingState)
|
||||
final _data:CharacterData;
|
||||
final singTimeSec:Float;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package funkin;
|
||||
package funkin.play.components;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.play;
|
||||
package funkin.play.components;
|
||||
|
||||
import funkin.play.character.CharacterData;
|
||||
import flixel.FlxSprite;
|
||||
|
@ -6,6 +6,7 @@ import flixel.math.FlxMath;
|
|||
import flixel.math.FlxPoint;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import openfl.utils.Assets;
|
||||
import funkin.util.MathUtil;
|
||||
|
||||
/**
|
||||
* This is a rework of the health icon with the following changes:
|
||||
|
@ -201,19 +202,19 @@ class HealthIcon extends FlxSprite
|
|||
if (this.width > this.height)
|
||||
{
|
||||
// Apply linear interpolation while accounting for frame rate.
|
||||
var targetSize:Int = Std.int(CoolUtil.coolLerp(this.width, HEALTH_ICON_SIZE * this.size.x, 0.15));
|
||||
var targetSize:Int = Std.int(MathUtil.coolLerp(this.width, HEALTH_ICON_SIZE * this.size.x, 0.15));
|
||||
|
||||
setGraphicSize(targetSize, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetSize:Int = Std.int(CoolUtil.coolLerp(this.height, HEALTH_ICON_SIZE * this.size.y, 0.15));
|
||||
var targetSize:Int = Std.int(MathUtil.coolLerp(this.height, HEALTH_ICON_SIZE * this.size.y, 0.15));
|
||||
|
||||
setGraphicSize(0, targetSize);
|
||||
}
|
||||
|
||||
// Lerp the health icon back to its normal angle.
|
||||
this.angle = CoolUtil.coolLerp(this.angle, 0, 0.15);
|
||||
this.angle = MathUtil.coolLerp(this.angle, 0, 0.15);
|
||||
|
||||
this.updateHitbox();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.ui;
|
||||
package funkin.play.components;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.ui;
|
||||
package funkin.play.components;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
|
@ -8,7 +8,7 @@ import flixel.tweens.FlxEase;
|
|||
import flixel.tweens.FlxTween;
|
||||
|
||||
/**
|
||||
* Similar to ComboCounter, but it's not!
|
||||
* Numerical counters used next to each judgement in the Results screen.
|
||||
*/
|
||||
class TallyCounter extends FlxTypedSpriteGroup<FlxSprite>
|
||||
{
|
|
@ -4,6 +4,7 @@ import flixel.FlxState;
|
|||
import funkin.modding.events.ScriptEventDispatcher;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.ui.MusicBeatState;
|
||||
|
||||
/**
|
||||
* A state with displays a conversation with no background.
|
||||
|
|
|
@ -12,7 +12,7 @@ import funkin.play.notes.NoteSplash;
|
|||
import funkin.play.notes.NoteSprite;
|
||||
import funkin.play.notes.SustainTrail;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
import funkin.util.SortUtil;
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@ import flixel.FlxSprite;
|
|||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.graphics.tile.FlxDrawTrianglesItem;
|
||||
import flixel.math.FlxMath;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
|
||||
/**
|
||||
* This is based heavily on the `FlxStrip` class. It uses `drawTriangles()` to clip a sustain note
|
||||
|
|
|
@ -96,11 +96,13 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
if (_data != null && _data.playData != null)
|
||||
{
|
||||
for (vari in _data.playData.songVariations)
|
||||
{
|
||||
variations.push(vari);
|
||||
}
|
||||
|
||||
for (meta in fetchVariationMetadata(id))
|
||||
_metadata.set(meta.variation, meta);
|
||||
var variMeta = fetchVariationMetadata(id, vari);
|
||||
if (variMeta != null) _metadata.set(variMeta.variation, variMeta);
|
||||
}
|
||||
}
|
||||
|
||||
if (_metadata.size() == 0)
|
||||
{
|
||||
|
@ -178,7 +180,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
difficulty.generatedBy = metadata.generatedBy;
|
||||
|
||||
difficulty.stage = metadata.playData.stage;
|
||||
difficulty.noteStyle = metadata.playData.noteSkin;
|
||||
difficulty.noteStyle = metadata.playData.noteStyle;
|
||||
|
||||
difficulties.set(diffId, difficulty);
|
||||
|
||||
|
@ -337,17 +339,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
return SongRegistry.instance.parseEntryMetadataWithMigration(id, Constants.DEFAULT_VARIATION, version);
|
||||
}
|
||||
|
||||
function fetchVariationMetadata(id:String):Array<SongMetadata>
|
||||
function fetchVariationMetadata(id:String, vari:String):Null<SongMetadata>
|
||||
{
|
||||
var result:Array<SongMetadata> = [];
|
||||
for (vari in variations)
|
||||
{
|
||||
var version:Null<thx.semver.Version> = SongRegistry.instance.fetchEntryMetadataVersion(id, vari);
|
||||
if (version == null) continue;
|
||||
var meta:Null<SongMetadata> = SongRegistry.instance.parseEntryMetadataWithMigration(id, vari, version);
|
||||
if (meta != null) result.push(meta);
|
||||
}
|
||||
return result;
|
||||
var version:Null<thx.semver.Version> = SongRegistry.instance.fetchEntryMetadataVersion(id, vari);
|
||||
if (version == null) return null;
|
||||
var meta:Null<SongMetadata> = SongRegistry.instance.parseEntryMetadataWithMigration(id, vari, version);
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
return globalOffsets = value;
|
||||
}
|
||||
|
||||
@:allow(funkin.ui.animDebugShit.DebugBoundingState)
|
||||
@:allow(funkin.ui.debug.anim.DebugBoundingState)
|
||||
var animOffsets(default, set):Array<Float> = [0, 0];
|
||||
|
||||
public var originalPosition:FlxPoint = new FlxPoint(0, 0);
|
||||
|
|
|
@ -177,13 +177,13 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
continue;
|
||||
}
|
||||
|
||||
if (Std.isOfType(dataProp.scale, Array))
|
||||
switch (dataProp.scale)
|
||||
{
|
||||
propSprite.scale.set(dataProp.scale[0], dataProp.scale[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
propSprite.scale.set(dataProp.scale);
|
||||
case Left(value):
|
||||
propSprite.scale.set(value);
|
||||
|
||||
case Right(values):
|
||||
propSprite.scale.set(values[0], values[1]);
|
||||
}
|
||||
propSprite.updateHitbox();
|
||||
|
||||
|
@ -195,8 +195,15 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
// If pixel, disable antialiasing.
|
||||
propSprite.antialiasing = !dataProp.isPixel;
|
||||
|
||||
propSprite.scrollFactor.x = dataProp.scroll[0];
|
||||
propSprite.scrollFactor.y = dataProp.scroll[1];
|
||||
switch (dataProp.scroll)
|
||||
{
|
||||
case Left(value):
|
||||
propSprite.scrollFactor.x = value;
|
||||
propSprite.scrollFactor.y = value;
|
||||
case Right(values):
|
||||
propSprite.scrollFactor.x = values[0];
|
||||
propSprite.scrollFactor.y = values[1];
|
||||
}
|
||||
|
||||
propSprite.zIndex = dataProp.zIndex;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package funkin.play.stage;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import funkin.play.stage.ScriptedStage;
|
||||
import funkin.play.stage.Stage;
|
||||
import funkin.util.VersionUtil;
|
||||
|
@ -157,15 +156,26 @@ class StageDataParser
|
|||
return rawJson;
|
||||
}
|
||||
|
||||
static function migrateStageData(rawJson:String, stageId:String)
|
||||
static function migrateStageData(rawJson:String, stageId:String):Null<StageData>
|
||||
{
|
||||
// If you update the stage data format in a breaking way,
|
||||
// handle migration here by checking the `version` value.
|
||||
|
||||
try
|
||||
{
|
||||
var stageData:StageData = cast Json.parse(rawJson);
|
||||
return stageData;
|
||||
var parser = new json2object.JsonParser<StageData>();
|
||||
parser.fromJson(rawJson, '$stageId.json');
|
||||
|
||||
if (parser.errors.length > 0)
|
||||
{
|
||||
trace('[STAGE] Failed to parse stage data');
|
||||
|
||||
for (error in parser.errors)
|
||||
funkin.data.DataError.printError(error);
|
||||
|
||||
return null;
|
||||
}
|
||||
return parser.value;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
|
@ -269,24 +279,29 @@ class StageDataParser
|
|||
inputProp.danceEvery = DEFAULT_DANCEEVERY;
|
||||
}
|
||||
|
||||
if (inputProp.scale == null)
|
||||
{
|
||||
inputProp.scale = DEFAULT_SCALE;
|
||||
}
|
||||
|
||||
if (inputProp.animType == null)
|
||||
{
|
||||
inputProp.animType = DEFAULT_ANIMTYPE;
|
||||
}
|
||||
|
||||
if (Std.isOfType(inputProp.scale, Float))
|
||||
switch (inputProp.scale)
|
||||
{
|
||||
inputProp.scale = [inputProp.scale, inputProp.scale];
|
||||
case null:
|
||||
inputProp.scale = Right([DEFAULT_SCALE, DEFAULT_SCALE]);
|
||||
case Left(value):
|
||||
inputProp.scale = Right([value, value]);
|
||||
case Right(_):
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (inputProp.scroll == null)
|
||||
switch (inputProp.scroll)
|
||||
{
|
||||
inputProp.scroll = DEFAULT_SCROLL;
|
||||
case null:
|
||||
inputProp.scroll = Right(DEFAULT_SCROLL);
|
||||
case Left(value):
|
||||
inputProp.scroll = Right([value, value]);
|
||||
case Right(_):
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (inputProp.alpha == null)
|
||||
|
@ -294,11 +309,6 @@ class StageDataParser
|
|||
inputProp.alpha = DEFAULT_ALPHA;
|
||||
}
|
||||
|
||||
if (Std.isOfType(inputProp.scroll, Float))
|
||||
{
|
||||
inputProp.scroll = [inputProp.scroll, inputProp.scroll];
|
||||
}
|
||||
|
||||
if (inputProp.animations == null)
|
||||
{
|
||||
inputProp.animations = [];
|
||||
|
@ -392,23 +402,39 @@ class StageDataParser
|
|||
}
|
||||
}
|
||||
|
||||
typedef StageData =
|
||||
class StageData
|
||||
{
|
||||
/**
|
||||
* The sematic version number of the stage data JSON format.
|
||||
* Supports fancy comparisons like NPM does it's neat.
|
||||
*/
|
||||
var version:String;
|
||||
public var version:String;
|
||||
|
||||
var name:String;
|
||||
var cameraZoom:Null<Float>;
|
||||
var props:Array<StageDataProp>;
|
||||
var characters:
|
||||
{
|
||||
bf:StageDataCharacter,
|
||||
dad:StageDataCharacter,
|
||||
gf:StageDataCharacter,
|
||||
};
|
||||
public var name:String;
|
||||
public var cameraZoom:Null<Float>;
|
||||
public var props:Array<StageDataProp>;
|
||||
public var characters:StageDataCharacters;
|
||||
|
||||
public function new()
|
||||
{
|
||||
this.version = StageDataParser.STAGE_DATA_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this StageData into a JSON string.
|
||||
*/
|
||||
public function serialize(pretty:Bool = true):String
|
||||
{
|
||||
var writer = new json2object.JsonWriter<StageData>();
|
||||
return writer.write(this, pretty ? ' ' : null);
|
||||
}
|
||||
}
|
||||
|
||||
typedef StageDataCharacters =
|
||||
{
|
||||
var bf:StageDataCharacter;
|
||||
var dad:StageDataCharacter;
|
||||
var gf:StageDataCharacter;
|
||||
};
|
||||
|
||||
typedef StageDataProp =
|
||||
|
@ -417,6 +443,7 @@ typedef StageDataProp =
|
|||
* The name of the prop for later lookup by scripts.
|
||||
* Optional; if unspecified, the prop can't be referenced by scripts.
|
||||
*/
|
||||
@:optional
|
||||
var name:String;
|
||||
|
||||
/**
|
||||
|
@ -435,27 +462,35 @@ typedef StageDataProp =
|
|||
* This is just like CSS, it isn't hard.
|
||||
* @default 0
|
||||
*/
|
||||
var zIndex:Null<Int>;
|
||||
@:optional
|
||||
@:default(0)
|
||||
var zIndex:Int;
|
||||
|
||||
/**
|
||||
* If set to true, anti-aliasing will be forcibly disabled on the sprite.
|
||||
* This prevents blurry images on pixel-art levels.
|
||||
* @default false
|
||||
*/
|
||||
var isPixel:Null<Bool>;
|
||||
@:optional
|
||||
@:default(false)
|
||||
var isPixel:Bool;
|
||||
|
||||
/**
|
||||
* Either the scale of the prop as a float, or the [w, h] scale as an array of two floats.
|
||||
* Pro tip: On pixel-art levels, save the sprite small and set this value to 6 or so to save memory.
|
||||
* @default 1
|
||||
*/
|
||||
var scale:OneOfTwo<Float, Array<Float>>;
|
||||
@:jcustomparse(funkin.data.DataParse.eitherFloatOrFloats)
|
||||
@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)
|
||||
@:optional
|
||||
var scale:haxe.ds.Either<Float, Array<Float>>;
|
||||
|
||||
/**
|
||||
* The alpha of the prop, as a float.
|
||||
* @default 1.0
|
||||
*/
|
||||
var alpha:Null<Float>;
|
||||
@:optional
|
||||
@:default(1.0)
|
||||
var alpha:Float;
|
||||
|
||||
/**
|
||||
* If not zero, this prop will play an animation every X beats of the song.
|
||||
|
@ -464,7 +499,9 @@ typedef StageDataProp =
|
|||
*
|
||||
* @default 0
|
||||
*/
|
||||
var danceEvery:Null<Int>;
|
||||
@:default(0)
|
||||
@:optional
|
||||
var danceEvery:Int;
|
||||
|
||||
/**
|
||||
* How much the prop scrolls relative to the camera. Used to create a parallax effect.
|
||||
|
@ -474,25 +511,32 @@ typedef StageDataProp =
|
|||
* [0, 0] means the prop is not moved.
|
||||
* @default [0, 0]
|
||||
*/
|
||||
var scroll:OneOfTwo<Float, Array<Float>>;
|
||||
@:jcustomparse(funkin.data.DataParse.eitherFloatOrFloats)
|
||||
@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)
|
||||
@:optional
|
||||
var scroll:haxe.ds.Either<Float, Array<Float>>;
|
||||
|
||||
/**
|
||||
* An optional array of animations which the prop can play.
|
||||
* @default Prop has no animations.
|
||||
*/
|
||||
@:optional
|
||||
var animations:Array<AnimationData>;
|
||||
|
||||
/**
|
||||
* If animations are used, this is the name of the animation to play first.
|
||||
* @default Don't play an animation.
|
||||
*/
|
||||
var startingAnimation:String;
|
||||
@:optional
|
||||
var startingAnimation:Null<String>;
|
||||
|
||||
/**
|
||||
* The animation type to use.
|
||||
* Options: "sparrow", "packer"
|
||||
* @default "sparrow"
|
||||
*/
|
||||
@:default("sparrow")
|
||||
@:optional
|
||||
var animType:String;
|
||||
};
|
||||
|
||||
|
@ -503,16 +547,22 @@ typedef StageDataCharacter =
|
|||
* Again, just like CSS.
|
||||
* @default 0
|
||||
*/
|
||||
?zIndex:Int,
|
||||
@:optional
|
||||
@:default(0)
|
||||
var zIndex:Int;
|
||||
|
||||
/**
|
||||
* The position to render the character at.
|
||||
*/
|
||||
position:Array<Float>,
|
||||
@:optional
|
||||
@:default([0, 0])
|
||||
var position:Array<Float>;
|
||||
|
||||
/**
|
||||
* The camera offsets to apply when focusing on the character on this stage.
|
||||
* @default [-100, -100] for BF, [100, -100] for DAD/OPPONENT, [0, 0] for GF
|
||||
*/
|
||||
cameraOffsets:Array<Float>,
|
||||
@:optional
|
||||
@:default([0, 0])
|
||||
var cameraOffsets:Array<Float>;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ package funkin.save;
|
|||
import flixel.util.FlxSave;
|
||||
import funkin.save.migrator.SaveDataMigrator;
|
||||
import thx.semver.Version;
|
||||
import funkin.Controls.Device;
|
||||
import funkin.input.Controls.Device;
|
||||
import funkin.save.migrator.RawSaveData_v1_0_0;
|
||||
|
||||
@:nullSafety
|
||||
|
|
|
@ -13,8 +13,7 @@ class SaveDataMigrator
|
|||
*/
|
||||
public static function migrate(inputData:Dynamic):Save
|
||||
{
|
||||
// This deserializes directly into a `Version` object, not a `String`.
|
||||
var version:Null<Version> = inputData?.version ?? null;
|
||||
var version:Null<thx.semver.Version> = VersionUtil.parseVersion(inputData?.version ?? null);
|
||||
|
||||
if (version == null)
|
||||
{
|
||||
|
@ -24,7 +23,7 @@ class SaveDataMigrator
|
|||
}
|
||||
else
|
||||
{
|
||||
if (VersionUtil.validateVersionStr(version, Save.SAVE_DATA_VERSION_RULE))
|
||||
if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE))
|
||||
{
|
||||
// Simply cast the structured data.
|
||||
var save:Save = inputData;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package funkin;
|
||||
package funkin.ui;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.util.MathUtil;
|
||||
|
||||
/**
|
||||
* Loosley based on FlxTypeText lolol
|
||||
|
@ -151,7 +152,6 @@ class Alphabet extends FlxSpriteGroup
|
|||
if (AlphaCharacter.alphabet.indexOf(splitWords[loopNum].toLowerCase()) != -1
|
||||
|| isNumber
|
||||
|| isSymbol) // if (AlphaCharacter.alphabet.contains(splitWords[loopNum].toLowerCase()) || isNumber || isSymbol)
|
||||
|
||||
{
|
||||
if (lastSprite != null && !xPosResetted)
|
||||
{
|
||||
|
@ -220,8 +220,8 @@ class Alphabet extends FlxSpriteGroup
|
|||
{
|
||||
var scaledY = FlxMath.remapToRange(targetY, 0, 1, 0, 1.3);
|
||||
|
||||
y = CoolUtil.coolLerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16);
|
||||
x = CoolUtil.coolLerp(x, (targetY * 20) + 90, 0.16);
|
||||
y = MathUtil.coolLerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16);
|
||||
x = MathUtil.coolLerp(x, (targetY * 20) + 90, 0.16);
|
||||
}
|
||||
|
||||
super.update(elapsed);
|
|
@ -38,7 +38,7 @@ class AtlasMenuList extends MenuTypedList<AtlasMenuItem>
|
|||
/**
|
||||
* A menu list item which uses single texture atlas.
|
||||
*/
|
||||
class AtlasMenuItem extends MenuItem
|
||||
class AtlasMenuItem extends MenuListItem
|
||||
{
|
||||
var atlas:FlxAtlasFrames;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package funkin;
|
||||
package funkin.ui;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import funkin.util.MathUtil;
|
||||
import flixel.util.FlxColor;
|
||||
|
||||
class MenuItem extends FlxSpriteGroup
|
||||
|
@ -44,7 +45,7 @@ class MenuItem extends FlxSpriteGroup
|
|||
override function update(elapsed:Float)
|
||||
{
|
||||
super.update(elapsed);
|
||||
y = CoolUtil.coolLerp(y, (targetY * 120) + 480, 0.17);
|
||||
y = MathUtil.coolLerp(y, (targetY * 120) + 480, 0.17);
|
||||
|
||||
if (isFlashing) flashingInt += 1;
|
||||
|
|
@ -6,7 +6,7 @@ import flixel.group.FlxGroup;
|
|||
import flixel.math.FlxPoint;
|
||||
import flixel.util.FlxSignal;
|
||||
|
||||
class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
|
||||
class MenuTypedList<T:MenuListItem> extends FlxTypedGroup<T>
|
||||
{
|
||||
public var selectedIndex(default, null) = 0;
|
||||
public var selectedItem(get, never):T;
|
||||
|
@ -206,7 +206,7 @@ class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
|
|||
}
|
||||
}
|
||||
|
||||
class MenuItem extends FlxSprite
|
||||
class MenuListItem extends FlxSprite
|
||||
{
|
||||
public var callback:Void->Void;
|
||||
public var name:String;
|
||||
|
@ -261,7 +261,7 @@ class MenuItem extends FlxSprite
|
|||
}
|
||||
}
|
||||
|
||||
class MenuTypedItem<T:FlxSprite> extends MenuItem
|
||||
class MenuTypedItem<T:FlxSprite> extends MenuListItem
|
||||
{
|
||||
public var label(default, set):T;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package funkin;
|
||||
package funkin.ui;
|
||||
|
||||
import funkin.modding.IScriptedClass.IEventHandler;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import flixel.FlxState;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
|
@ -11,6 +12,7 @@ import funkin.modding.PolymodHandler;
|
|||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.util.SortUtil;
|
||||
import funkin.input.Controls;
|
||||
|
||||
/**
|
||||
* MusicBeatState actually represents the core utility FlxState of the game.
|
||||
|
@ -56,27 +58,45 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
Conductor.stepHit.remove(this.stepHit);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
function handleControls():Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
|
||||
|
||||
// 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);
|
||||
if (!isHaxeUIFocused)
|
||||
{
|
||||
// Rebindable volume keys.
|
||||
if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
|
||||
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
|
||||
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFunctionControls():Void
|
||||
{
|
||||
// Emergency exit button.
|
||||
if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState());
|
||||
|
||||
// This can now be used in EVERY STATE YAY!
|
||||
if (FlxG.keys.justPressed.F5) debug_refreshModules();
|
||||
}
|
||||
|
||||
function handleQuickWatch():Void
|
||||
{
|
||||
// Display Conductor info in the watch window.
|
||||
FlxG.watch.addQuick("songPosition", Conductor.songPosition);
|
||||
FlxG.watch.addQuick("bpm", Conductor.bpm);
|
||||
FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime);
|
||||
FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime);
|
||||
FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
handleControls();
|
||||
handleFunctionControls();
|
||||
handleQuickWatch();
|
||||
|
||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package funkin;
|
||||
package funkin.ui;
|
||||
|
||||
import flixel.addons.transition.FlxTransitionableSubState;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.text.FlxText;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.modding.IScriptedClass.IEventHandler;
|
||||
|
@ -10,6 +11,7 @@ import funkin.modding.module.ModuleHandler;
|
|||
import funkin.modding.PolymodHandler;
|
||||
import funkin.util.SortUtil;
|
||||
import flixel.util.FlxSort;
|
||||
import funkin.input.Controls;
|
||||
|
||||
/**
|
||||
* MusicBeatSubState reincorporates the functionality of MusicBeatState into an FlxSubState.
|
|
@ -1,8 +1,9 @@
|
|||
package funkin;
|
||||
package funkin.ui;
|
||||
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.util.MathUtil;
|
||||
|
||||
class SwagCamera extends FlxCamera
|
||||
{
|
||||
|
@ -92,10 +93,10 @@ class SwagCamera extends FlxCamera
|
|||
else
|
||||
{
|
||||
// THIS THE PART THAT ACTUALLY MATTERS LOL
|
||||
scroll.x = CoolUtil.coolLerp(scroll.x, _scrollTarget.x, followLerp);
|
||||
scroll.y = CoolUtil.coolLerp(scroll.y, _scrollTarget.y, followLerp);
|
||||
// scroll.x += (_scrollTarget.x - scroll.x) * CoolUtil.camLerpShit(followLerp);
|
||||
// scroll.y += (_scrollTarget.y - scroll.y) * CoolUtil.camLerpShit(followLerp);
|
||||
scroll.x = MathUtil.coolLerp(scroll.x, _scrollTarget.x, followLerp);
|
||||
scroll.y = MathUtil.coolLerp(scroll.y, _scrollTarget.y, followLerp);
|
||||
// scroll.x += (_scrollTarget.x - scroll.x) * MathUtil.cameraLerp(followLerp);
|
||||
// scroll.y += (_scrollTarget.y - scroll.y) * MathUtil.cameraLerp(followLerp);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@ package funkin.ui.debug;
|
|||
import flixel.math.FlxPoint;
|
||||
import flixel.FlxObject;
|
||||
import flixel.FlxSprite;
|
||||
import funkin.MusicBeatSubState;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import funkin.ui.TextMenuList;
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
|
||||
class DebugMenuSubState extends MusicBeatSubState
|
||||
{
|
||||
|
@ -85,13 +86,13 @@ class DebugMenuSubState extends MusicBeatSubState
|
|||
|
||||
function openAnimationEditor()
|
||||
{
|
||||
FlxG.switchState(new funkin.ui.animDebugShit.DebugBoundingState());
|
||||
FlxG.switchState(new funkin.ui.debug.anim.DebugBoundingState());
|
||||
trace('Animation Editor');
|
||||
}
|
||||
|
||||
function testStickers()
|
||||
{
|
||||
openSubState(new funkin.ui.StickerSubState());
|
||||
openSubState(new funkin.ui.transition.StickerSubState());
|
||||
trace('opened stickers');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package funkin;
|
||||
package funkin.ui.debug;
|
||||
|
||||
import openfl.text.TextFormat;
|
||||
import openfl.system.System;
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.ui.animDebugShit;
|
||||
package funkin.ui.debug.anim;
|
||||
|
||||
import funkin.util.SerializerUtil;
|
||||
import funkin.play.character.CharacterData;
|
||||
|
@ -15,6 +15,7 @@ import flixel.math.FlxPoint;
|
|||
import flixel.sound.FlxSound;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.util.MouseUtil;
|
||||
import flixel.util.FlxSpriteUtil;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
|
@ -25,6 +26,7 @@ import haxe.ui.components.DropDown;
|
|||
import haxe.ui.core.Component;
|
||||
import haxe.ui.events.ItemEvent;
|
||||
import haxe.ui.events.UIEvent;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import lime.utils.Assets as LimeAssets;
|
||||
import openfl.Assets;
|
||||
import openfl.events.Event;
|
||||
|
@ -32,6 +34,7 @@ import openfl.events.IOErrorEvent;
|
|||
import openfl.geom.Rectangle;
|
||||
import openfl.net.FileReference;
|
||||
import openfl.net.URLLoader;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import openfl.net.URLRequest;
|
||||
import openfl.utils.ByteArray;
|
||||
import funkin.input.Cursor;
|
||||
|
@ -363,8 +366,8 @@ class DebugBoundingState extends FlxState
|
|||
|
||||
if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState());
|
||||
|
||||
CoolUtil.mouseCamDrag();
|
||||
CoolUtil.mouseWheelZoom();
|
||||
MouseUtil.mouseCamDrag();
|
||||
MouseUtil.mouseWheelZoom();
|
||||
|
||||
// bg.scale.x = FlxG.camera.zoom;
|
||||
// bg.scale.y = FlxG.camera.zoom;
|
|
@ -1,7 +1,8 @@
|
|||
package funkin.ui.animDebugShit;
|
||||
package funkin.ui.debug.anim;
|
||||
|
||||
import flixel.FlxG;
|
||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||
import funkin.ui.MusicBeatState;
|
||||
|
||||
/**
|
||||
* A simple test of FlxAnimate.
|
|
@ -16,6 +16,7 @@ import flixel.tweens.FlxEase;
|
|||
import flixel.tweens.FlxTween;
|
||||
import flixel.tweens.misc.VarTween;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.ui.mainmenu.MainMenuState;
|
||||
import flixel.util.FlxSort;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.visualize.PolygonSpectogram;
|
||||
|
@ -31,7 +32,7 @@ import funkin.input.TurboKeyHandler;
|
|||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.play.character.BaseCharacter.CharacterType;
|
||||
import funkin.play.character.CharacterData;
|
||||
import funkin.play.HealthIcon;
|
||||
import funkin.play.components.HealthIcon;
|
||||
import funkin.play.notes.NoteSprite;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.song.Song;
|
||||
|
@ -90,6 +91,7 @@ import haxe.ui.core.Component;
|
|||
import haxe.ui.core.Screen;
|
||||
import haxe.ui.events.DragEvent;
|
||||
import haxe.ui.events.UIEvent;
|
||||
import haxe.ui.focus.FocusManager;
|
||||
import haxe.ui.notifications.NotificationManager;
|
||||
import haxe.ui.notifications.NotificationType;
|
||||
import openfl.display.BitmapData;
|
||||
|
@ -547,22 +549,14 @@ class ChartEditorState extends HaxeUIState
|
|||
// HaxeUI
|
||||
|
||||
/**
|
||||
* Whether the user's mouse cursor is hovering over a SOLID component of the HaxeUI.
|
||||
* If so, ignore mouse events underneath as well as certain key events.
|
||||
* Whether the user is focused on an input in the Haxe UI, and inputs are being fed into it.
|
||||
* If the user clicks off the input, focus will leave.
|
||||
*/
|
||||
var isCursorOverHaxeUI(get, never):Bool;
|
||||
var isHaxeUIFocused(get, never):Bool;
|
||||
|
||||
function get_isCursorOverHaxeUI():Bool
|
||||
function get_isHaxeUIFocused():Bool
|
||||
{
|
||||
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
|
||||
}
|
||||
|
||||
var isCursorOverHaxeUIButton(get, never):Bool;
|
||||
|
||||
function get_isCursorOverHaxeUIButton():Bool
|
||||
{
|
||||
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Button)
|
||||
|| Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Link);
|
||||
return FocusManager.instance.focus != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1046,17 +1040,17 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
function get_currentSongNoteStyle():String
|
||||
{
|
||||
if (currentSongMetadata.playData.noteSkin == null)
|
||||
if (currentSongMetadata.playData.noteStyle == null)
|
||||
{
|
||||
// Initialize to the default value if not set.
|
||||
currentSongMetadata.playData.noteSkin = 'funkin';
|
||||
currentSongMetadata.playData.noteStyle = Constants.DEFAULT_NOTE_STYLE;
|
||||
}
|
||||
return currentSongMetadata.playData.noteSkin;
|
||||
return currentSongMetadata.playData.noteStyle;
|
||||
}
|
||||
|
||||
function set_currentSongNoteStyle(value:String):String
|
||||
{
|
||||
return currentSongMetadata.playData.noteSkin = value;
|
||||
return currentSongMetadata.playData.noteStyle = value;
|
||||
}
|
||||
|
||||
var currentSongStage(get, set):String;
|
||||
|
@ -1326,10 +1320,22 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
// ==============================
|
||||
|
||||
public function new()
|
||||
/**
|
||||
* The params which were passed in when the Chart Editor was initialized.
|
||||
*/
|
||||
var params:Null<ChartEditorParams>;
|
||||
|
||||
/**
|
||||
* The current file path which the chart editor is working with.
|
||||
*/
|
||||
public var currentWorkingFilePath:Null<String>;
|
||||
|
||||
public function new(?params:ChartEditorParams)
|
||||
{
|
||||
// Load the HaxeUI XML file.
|
||||
super(CHART_EDITOR_LAYOUT);
|
||||
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public override function dispatchEvent(event:ScriptEvent):Void
|
||||
|
@ -1410,7 +1416,33 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
refresh();
|
||||
|
||||
this.openWelcomeDialog(false);
|
||||
if (params != null && params.fnfcTargetPath != null)
|
||||
{
|
||||
// Chart editor was opened from the command line. Open the FNFC file now!
|
||||
if (ChartEditorImportExportHandler.loadFromFNFCPath(this, params.fnfcTargetPath))
|
||||
{
|
||||
// Don't open the welcome dialog!
|
||||
|
||||
#if !mac
|
||||
NotificationManager.instance.addNotification(
|
||||
{
|
||||
title: 'Success',
|
||||
body: 'Loaded chart (${params.fnfcTargetPath})',
|
||||
type: NotificationType.Success,
|
||||
expiryMs: Constants.NOTIFICATION_DISMISS_TIME
|
||||
});
|
||||
#end
|
||||
}
|
||||
else
|
||||
{
|
||||
// Song failed to load, open the Welcome dialog so we aren't in a broken state.
|
||||
ChartEditorDialogHandler.openWelcomeDialog(this, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChartEditorDialogHandler.openWelcomeDialog(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
override function destroy():Void
|
||||
|
@ -1772,11 +1804,15 @@ class ChartEditorState extends HaxeUIState
|
|||
noteSnapQuantIndex++;
|
||||
if (noteSnapQuantIndex >= SNAP_QUANTS.length) noteSnapQuantIndex = 0;
|
||||
});
|
||||
addUIRightClickListener('playbarNoteSnap', function(_) {
|
||||
noteSnapQuantIndex--;
|
||||
if (noteSnapQuantIndex < 0) noteSnapQuantIndex = SNAP_QUANTS.length - 1;
|
||||
});
|
||||
|
||||
// Add functionality to the menu items.
|
||||
|
||||
addUIClickListener('menubarItemNewChart', _ -> this.openWelcomeDialog(true));
|
||||
addUIClickListener('menubarItemOpenChart', _ -> this.openBrowseWizard(true));
|
||||
addUIClickListener('menubarItemOpenChart', _ -> this.openBrowseFNFC(true));
|
||||
addUIClickListener('menubarItemSaveChartAs', _ -> this.exportAllSongData());
|
||||
addUIClickListener('menubarItemLoadInst', _ -> this.openUploadInstDialog(true));
|
||||
addUIClickListener('menubarItemImportChart', _ -> this.openImportChartDialog('legacy', true));
|
||||
|
@ -1918,7 +1954,7 @@ class ChartEditorState extends HaxeUIState
|
|||
addUIChangeListener('menubarItemVolumeVocals', function(event:UIEvent) {
|
||||
var volume:Float = (event?.value ?? 0) / 100.0;
|
||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.volume = volume;
|
||||
vocalsVolumeLabel.text = 'Vocals - ${Std.int(event.value)}%';
|
||||
vocalsVolumeLabel.text = 'Voices - ${Std.int(event.value)}%';
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2499,8 +2535,8 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
function handleScrollKeybinds():Void
|
||||
{
|
||||
// Don't scroll when the cursor is over the UI, unless a playbar button (the << >> ones) is pressed.
|
||||
if (isCursorOverHaxeUI && playbarButtonPressed == null) return;
|
||||
// Don't scroll when the user is interacting with the UI, unless a playbar button (the << >> ones) is pressed.
|
||||
if (isHaxeUIFocused && playbarButtonPressed == null) return;
|
||||
|
||||
var scrollAmount:Float = 0; // Amount to scroll the grid.
|
||||
var playheadAmount:Float = 0; // Amount to scroll the playhead relative to the grid.
|
||||
|
@ -2699,7 +2735,7 @@ class ChartEditorState extends HaxeUIState
|
|||
if (FlxG.mouse.justReleased) FlxG.sound.play(Paths.sound("chartingSounds/ClickUp"));
|
||||
|
||||
// Note: If a menu is open in HaxeUI, don't handle cursor behavior.
|
||||
var shouldHandleCursor:Bool = !isCursorOverHaxeUI
|
||||
var shouldHandleCursor:Bool = !isHaxeUIFocused
|
||||
|| (selectionBoxStartPos != null)
|
||||
|| (dragTargetNote != null || dragTargetEvent != null);
|
||||
var eventColumn:Int = (STRUMLINE_SIZE * 2 + 1) - 1;
|
||||
|
@ -3259,14 +3295,14 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
// Create an event and place it in the chart.
|
||||
// TODO: Figure out configuring event data.
|
||||
var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData);
|
||||
var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData.clone());
|
||||
|
||||
performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a note and place it in the chart.
|
||||
var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind);
|
||||
var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind.clone());
|
||||
|
||||
performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL));
|
||||
|
||||
|
@ -3786,7 +3822,7 @@ class ChartEditorState extends HaxeUIState
|
|||
// CTRL + O = Open Chart
|
||||
if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.O)
|
||||
{
|
||||
this.openBrowseWizard(true);
|
||||
this.openBrowseFNFC(true);
|
||||
}
|
||||
|
||||
// CTRL + SHIFT + S = Save As
|
||||
|
@ -3802,6 +3838,16 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
}
|
||||
|
||||
@:nullSafety(Off)
|
||||
function quitChartEditor():Void
|
||||
{
|
||||
autoSave();
|
||||
stopWelcomeMusic();
|
||||
// TODO: PR Flixel to make onComplete nullable.
|
||||
if (audioInstTrack != null) audioInstTrack.onComplete = null;
|
||||
FlxG.switchState(new MainMenuState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keybinds for edit menu items.
|
||||
*/
|
||||
|
@ -3921,7 +3967,7 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
function handleTestKeybinds():Void
|
||||
{
|
||||
if (!isHaxeUIDialogOpen && !isCursorOverHaxeUI && FlxG.keys.justPressed.ENTER)
|
||||
if (!isHaxeUIDialogOpen && !isHaxeUIFocused && FlxG.keys.justPressed.ENTER)
|
||||
{
|
||||
var minimal = FlxG.keys.pressed.SHIFT;
|
||||
this.hideAllToolboxes();
|
||||
|
@ -3938,8 +3984,10 @@ class ChartEditorState extends HaxeUIState
|
|||
if (FlxG.keys.justPressed.F1) this.openUserGuideDialog();
|
||||
}
|
||||
|
||||
function handleQuickWatch():Void
|
||||
override function handleQuickWatch():Void
|
||||
{
|
||||
super.handleQuickWatch();
|
||||
|
||||
FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
|
||||
FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
|
||||
|
||||
|
@ -4093,16 +4141,6 @@ class ChartEditorState extends HaxeUIState
|
|||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user presses the Quit button.
|
||||
*/
|
||||
function quitChartEditor():Void
|
||||
{
|
||||
autoSave();
|
||||
stopWelcomeMusic();
|
||||
FlxG.switchState(new MainMenuState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the window is closed while we are in the chart editor.
|
||||
* @param exitCode The exit code of the window.
|
||||
|
@ -4576,7 +4614,7 @@ class ChartEditorState extends HaxeUIState
|
|||
if (inputStage != null) inputStage.value = currentSongMetadata.playData.stage;
|
||||
|
||||
var inputNoteStyle:Null<DropDown> = toolbox.findComponent('inputNoteStyle', DropDown);
|
||||
if (inputNoteStyle != null) inputNoteStyle.value = currentSongMetadata.playData.noteSkin;
|
||||
if (inputNoteStyle != null) inputNoteStyle.value = currentSongMetadata.playData.noteStyle;
|
||||
|
||||
var inputBPM:Null<NumberStepper> = toolbox.findComponent('inputBPM', NumberStepper);
|
||||
if (inputBPM != null) inputBPM.value = currentSongMetadata.timeChanges[0].bpm;
|
||||
|
@ -4720,6 +4758,14 @@ enum ChartEditorLiveInputStyle
|
|||
WASD;
|
||||
}
|
||||
|
||||
typedef ChartEditorParams =
|
||||
{
|
||||
/**
|
||||
* If non-null, load this song immediately instead of the welcome screen.
|
||||
*/
|
||||
var ?fnfcTargetPath:String;
|
||||
};
|
||||
|
||||
/**
|
||||
* Available themes for the chart editor state.
|
||||
*/
|
||||
|
|
|
@ -134,21 +134,25 @@ class ChartEditorEventSprite extends FlxSprite
|
|||
|
||||
function set_eventData(value:Null<SongEventData>):Null<SongEventData>
|
||||
{
|
||||
this.eventData = value;
|
||||
|
||||
if (this.eventData == null)
|
||||
if (value == null)
|
||||
{
|
||||
this.eventData = null;
|
||||
// Disown parent. MAKE SURE TO REVIVE BEFORE REUSING
|
||||
this.kill();
|
||||
this.visible = false;
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.visible = true;
|
||||
// Only play the animation if the event type has changed.
|
||||
// if (this.eventData == null || this.eventData.event != value.event)
|
||||
playAnimation(value.event);
|
||||
this.eventData = value;
|
||||
// Update the position to match the note data.
|
||||
updateEventPosition();
|
||||
return this.eventData;
|
||||
}
|
||||
|
||||
this.visible = true;
|
||||
playAnimation(this.eventData.event);
|
||||
// Update the position to match the note data.
|
||||
updateEventPosition();
|
||||
|
||||
return this.eventData;
|
||||
}
|
||||
|
||||
public function updateEventPosition(?origin:FlxObject)
|
||||
|
|
|
@ -258,7 +258,7 @@ class ChartEditorAudioHandler
|
|||
{
|
||||
var data:Null<Bytes> = state.audioVocalTrackData.get(key);
|
||||
if (data == null) continue;
|
||||
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Vocals-${key}.ogg', data));
|
||||
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Voices-${key}.ogg', data));
|
||||
}
|
||||
|
||||
return zipEntries;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue