diff --git a/.gitattributes b/.gitattributes
index f2b8f594..4afc5728 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7,4 +7,9 @@ pages/** linguist-vendored
# Include HScript files as Haxe
*.hxs linguist-language=Haxe
*.hsc linguist-language=Haxe
-*.hscript linguist-language=Haxe
\ No newline at end of file
+*.hscript linguist-language=Haxe
+
+# Include Shader files as GLSL
+*.frag linguist-language=GLSL
+*.vert linguist-language=GLSL
+*.glsl linguist-language=GLSL
\ No newline at end of file
diff --git a/assets/data/characters/bf-car.xml b/assets/data/characters/bf-car.xml
index bd276ca8..b73d5a12 100644
--- a/assets/data/characters/bf-car.xml
+++ b/assets/data/characters/bf-car.xml
@@ -10,9 +10,9 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/bf-christmas.xml b/assets/data/characters/bf-christmas.xml
index 88feb049..1289abdc 100644
--- a/assets/data/characters/bf-christmas.xml
+++ b/assets/data/characters/bf-christmas.xml
@@ -1,13 +1,13 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/bf-holding-gf.xml b/assets/data/characters/bf-holding-gf.xml
index 390504bc..9053ec5c 100644
--- a/assets/data/characters/bf-holding-gf.xml
+++ b/assets/data/characters/bf-holding-gf.xml
@@ -1,13 +1,13 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/bf-pixel.xml b/assets/data/characters/bf-pixel.xml
index b1c668a3..621ec9e0 100644
--- a/assets/data/characters/bf-pixel.xml
+++ b/assets/data/characters/bf-pixel.xml
@@ -1,15 +1,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/bf.xml b/assets/data/characters/bf.xml
index 245fbffd..96f90b81 100644
--- a/assets/data/characters/bf.xml
+++ b/assets/data/characters/bf.xml
@@ -1,18 +1,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/dad.xml b/assets/data/characters/dad.xml
index 39319727..3c8da4c2 100644
--- a/assets/data/characters/dad.xml
+++ b/assets/data/characters/dad.xml
@@ -1,13 +1,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/gf-car.xml b/assets/data/characters/gf-car.xml
index 72ca5814..02fe7e1b 100644
--- a/assets/data/characters/gf-car.xml
+++ b/assets/data/characters/gf-car.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/assets/data/characters/gf-christmas.xml b/assets/data/characters/gf-christmas.xml
index 1a995a2a..d9a05715 100644
--- a/assets/data/characters/gf-christmas.xml
+++ b/assets/data/characters/gf-christmas.xml
@@ -1,14 +1,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/gf-pixel.xml b/assets/data/characters/gf-pixel.xml
index 73aa39e9..eefc4cba 100644
--- a/assets/data/characters/gf-pixel.xml
+++ b/assets/data/characters/gf-pixel.xml
@@ -1,5 +1,5 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/assets/data/characters/gf-tankmen.xml b/assets/data/characters/gf-tankmen.xml
index 7ba7df0a..a332b124 100644
--- a/assets/data/characters/gf-tankmen.xml
+++ b/assets/data/characters/gf-tankmen.xml
@@ -1,7 +1,7 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/assets/data/characters/gf.xml b/assets/data/characters/gf.xml
index 911d2073..54a8ad59 100644
--- a/assets/data/characters/gf.xml
+++ b/assets/data/characters/gf.xml
@@ -1,14 +1,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/mom-car.xml b/assets/data/characters/mom-car.xml
index e511498f..ff23aa88 100644
--- a/assets/data/characters/mom-car.xml
+++ b/assets/data/characters/mom-car.xml
@@ -1,16 +1,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/mom.xml b/assets/data/characters/mom.xml
index 43d52076..88cbc3c9 100644
--- a/assets/data/characters/mom.xml
+++ b/assets/data/characters/mom.xml
@@ -1,16 +1,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/monster-christmas.xml b/assets/data/characters/monster-christmas.xml
index 61bae9ee..73eeed57 100644
--- a/assets/data/characters/monster-christmas.xml
+++ b/assets/data/characters/monster-christmas.xml
@@ -1,8 +1,8 @@
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/assets/data/characters/monster.xml b/assets/data/characters/monster.xml
index df8d70bd..0da80ca9 100644
--- a/assets/data/characters/monster.xml
+++ b/assets/data/characters/monster.xml
@@ -1,8 +1,8 @@
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/assets/data/characters/parents-christmas.xml b/assets/data/characters/parents-christmas.xml
index 991fff09..4371389f 100644
--- a/assets/data/characters/parents-christmas.xml
+++ b/assets/data/characters/parents-christmas.xml
@@ -1,12 +1,25 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/pico-speakers.xml b/assets/data/characters/pico-speakers.xml
index ffb35177..36ec2528 100644
--- a/assets/data/characters/pico-speakers.xml
+++ b/assets/data/characters/pico-speakers.xml
@@ -1,16 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/pico.xml b/assets/data/characters/pico.xml
index 74e9baed..e5685dd8 100644
--- a/assets/data/characters/pico.xml
+++ b/assets/data/characters/pico.xml
@@ -1,16 +1,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/senpai-angry.xml b/assets/data/characters/senpai-angry.xml
index c1203449..b9450a24 100644
--- a/assets/data/characters/senpai-angry.xml
+++ b/assets/data/characters/senpai-angry.xml
@@ -1,8 +1,8 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/assets/data/characters/senpai.xml b/assets/data/characters/senpai.xml
index f243b2e5..762afb67 100644
--- a/assets/data/characters/senpai.xml
+++ b/assets/data/characters/senpai.xml
@@ -1,10 +1,9 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/spirit.xml b/assets/data/characters/spirit.xml
index d1ee5dc9..9885a662 100644
--- a/assets/data/characters/spirit.xml
+++ b/assets/data/characters/spirit.xml
@@ -1,10 +1,8 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/assets/data/characters/spooky.xml b/assets/data/characters/spooky.xml
index 2a434f21..f60758e4 100644
--- a/assets/data/characters/spooky.xml
+++ b/assets/data/characters/spooky.xml
@@ -1,9 +1,9 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/assets/data/characters/tankman.xml b/assets/data/characters/tankman.xml
index 092e0368..c06aa6c4 100644
--- a/assets/data/characters/tankman.xml
+++ b/assets/data/characters/tankman.xml
@@ -1,10 +1,10 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/assets/data/scripts/pixel.hx b/assets/data/scripts/pixel.hx
index 8f1887c8..22c4e611 100644
--- a/assets/data/scripts/pixel.hx
+++ b/assets/data/scripts/pixel.hx
@@ -12,7 +12,7 @@ public var enablePauseMenu = true;
public var isSpooky = false;
var oldStageQuality = FlxG.game.stage.quality;
-static var daPixelZoom = 6;
+public var daPixelZoom = PlayState.daPixelZoom;
/**
* UI
diff --git a/assets/data/scripts/week6-pause.hx b/assets/data/scripts/week6-pause.hx
index 6a4455cd..f5fa3394 100644
--- a/assets/data/scripts/week6-pause.hx
+++ b/assets/data/scripts/week6-pause.hx
@@ -17,7 +17,7 @@ function create(event) {
// cancel default pause menu!!
event.cancel();
- event.music = isThorns ? "pixel/LunchboxScary" : "pixel/Lunchbox";
+ event.music = isThorns ? "pixel/LunchboxScary" : "pixel/breakfast";
cameras = [];
diff --git a/assets/data/weeks/characters/bf.xml b/assets/data/weeks/characters/bf.xml
index 20e9176d..1f3fa299 100644
--- a/assets/data/weeks/characters/bf.xml
+++ b/assets/data/weeks/characters/bf.xml
@@ -1,5 +1,5 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/dad.xml b/assets/data/weeks/characters/dad.xml
index dfda66e7..2b1cd842 100644
--- a/assets/data/weeks/characters/dad.xml
+++ b/assets/data/weeks/characters/dad.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/gf.xml b/assets/data/weeks/characters/gf.xml
index 1af08c30..3ac59136 100644
--- a/assets/data/weeks/characters/gf.xml
+++ b/assets/data/weeks/characters/gf.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/mom.xml b/assets/data/weeks/characters/mom.xml
index 338e2825..78682a7d 100644
--- a/assets/data/weeks/characters/mom.xml
+++ b/assets/data/weeks/characters/mom.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/parents-christmas.xml b/assets/data/weeks/characters/parents-christmas.xml
index 44070ced..18f95ffb 100644
--- a/assets/data/weeks/characters/parents-christmas.xml
+++ b/assets/data/weeks/characters/parents-christmas.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/pico-player.xml b/assets/data/weeks/characters/pico-player.xml
new file mode 100644
index 00000000..709ea008
--- /dev/null
+++ b/assets/data/weeks/characters/pico-player.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/pico.xml b/assets/data/weeks/characters/pico.xml
index f4f32242..424a0e44 100644
--- a/assets/data/weeks/characters/pico.xml
+++ b/assets/data/weeks/characters/pico.xml
@@ -1,2 +1,4 @@
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/assets/data/weeks/characters/spooky.xml b/assets/data/weeks/characters/spooky.xml
index 2466bbbb..e4955b1f 100644
--- a/assets/data/weeks/characters/spooky.xml
+++ b/assets/data/weeks/characters/spooky.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/images/characters/senpai.png b/assets/images/characters/senpai.png
index fa5a3293..1c7f8f52 100644
Binary files a/assets/images/characters/senpai.png and b/assets/images/characters/senpai.png differ
diff --git a/assets/images/characters/senpai.xml b/assets/images/characters/senpai.xml
index d8e532e4..fb01b854 100644
--- a/assets/images/characters/senpai.xml
+++ b/assets/images/characters/senpai.xml
@@ -1,159 +1,164 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/images/menus/storymenu/characters/pico.png b/assets/images/menus/storymenu/characters/pico.png
index 46a4e375..bae0afa3 100644
Binary files a/assets/images/menus/storymenu/characters/pico.png and b/assets/images/menus/storymenu/characters/pico.png differ
diff --git a/assets/images/menus/storymenu/characters/pico.xml b/assets/images/menus/storymenu/characters/pico.xml
index 9e6832cd..04cfe8e6 100644
--- a/assets/images/menus/storymenu/characters/pico.xml
+++ b/assets/images/menus/storymenu/characters/pico.xml
@@ -1,19 +1,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/music/pixel/breakfast.mp3 b/assets/music/pixel/breakfast.mp3
new file mode 100644
index 00000000..9868a89f
Binary files /dev/null and b/assets/music/pixel/breakfast.mp3 differ
diff --git a/assets/music/pixel/breakfast.ogg b/assets/music/pixel/breakfast.ogg
new file mode 100644
index 00000000..7227bea6
Binary files /dev/null and b/assets/music/pixel/breakfast.ogg differ
diff --git a/assets/shaders/engine/README.txt b/assets/shaders/engine/README.txt
deleted file mode 100644
index d5534429..00000000
--- a/assets/shaders/engine/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-THOSE SHADERS ARE USED INTERNALLY BY THE ENGINE
-
-MODIFY THEM AT YOUR OWN RISK!! IF IT CRASHES IT AINT MY FAULT
\ No newline at end of file
diff --git a/assets/songs/guns/cutscene.hx b/assets/songs/guns/cutscene.hx
index af4d9be9..f445ad3a 100644
--- a/assets/songs/guns/cutscene.hx
+++ b/assets/songs/guns/cutscene.hx
@@ -1,7 +1,9 @@
import funkin.system.FunkinSprite;
var tankman:FunkinSprite;
-var tankTalk1, distorto:FlxSound;
+var tankTalk, distorto:FlxSound;
+var timers:Array = [];
+var destroyDistorto:Bool = true;
function create() {
FlxTween.tween(FlxG.camera, {zoom: 1}, 0.7, {ease: FlxEase.quadInOut});
@@ -28,29 +30,39 @@ function create() {
tankman.playAnim('tank');
tankTalk.play();
- new FlxTimer().start(4.1, function(ugly:FlxTimer)
+ timer(4.1, function()
{
FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom * 1.4}, 0.4, {ease: FlxEase.quadOut});
FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom * 1.3}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0.45});
game.gf.playAnim('sad', false, "DANCE");
});
- new FlxTimer().start(11, function(tmr:FlxTimer)
- {
- game.remove(tankman);
- tankman.destroy();
-
- game.camHUD.visible = true;
- game.dad.visible = true;
+ timer(11, function() {
+ destroyDistorto = false;
distorto.fadeOut((Conductor.crochet / 1000) * 5, 0);
- FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0});
-
close();
});
}
+function timer(duration:Float, callBack:Void->Void) {
+ timers.push(new FlxTimer().start(duration, function(timer) {
+ timers.remove(timer);
+ callBack();
+ }));
+}
+
function focusOn(char) {
var camPos = char.getCameraPosition();
game.camFollow.setPosition(camPos.x, camPos.y);
camPos.put();
+}
+
+function destroy() {
+ game.remove(tankman);
+ game.camHUD.visible = true;
+ game.dad.visible = true;
+ for(timer in timers) timer.cancel();
+ for(thing in [tankman, tankTalk]) thing.destroy();
+ if(destroyDistorto) distorto.destroy();
+ FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0});
}
\ No newline at end of file
diff --git a/assets/songs/stress/cutscene.hx b/assets/songs/stress/cutscene.hx
index dd55a3da..40951864 100644
--- a/assets/songs/stress/cutscene.hx
+++ b/assets/songs/stress/cutscene.hx
@@ -27,11 +27,6 @@ function create() {
stressCutscene.play();
stressCutscene.onComplete = function() {
- for(spr in [gf, tankman, pico]) {
- spr.destroy();
- game.remove(spr);
- }
- game.camHUD.visible = game.dad.visible = game.gf.visible = true;
close();
};
@@ -59,8 +54,6 @@ function create() {
}
function update(elapsed) {
- if (FlxG.keys.justPressed.F5)
- FlxG.resetState();
switch(step) {
case 0:
lipSync(tankman, 0, 16750);
@@ -133,4 +126,14 @@ function focusOn(char, snap:Bool = false) {
game.camFollow.setPosition(camPos.x, camPos.y);
if(snap) FlxG.camera.snapToTarget();
camPos.put();
+}
+
+function destroy() {
+ game.boyfriend.animation.finishCallback = null;
+ game.camHUD.visible = game.boyfriend.visible = game.dad.visible = game.gf.visible = true;
+ for(thing in [bf, gf, tankman, pico, stressCutscene]) {
+ if(thing == null) continue;
+ if(thing != stressCutscene) game.remove(thing);
+ thing.destroy();
+ }
}
\ No newline at end of file
diff --git a/assets/songs/test/dialogue.hx b/assets/songs/test/dialogue.hx
new file mode 100644
index 00000000..5d3e7fa0
--- /dev/null
+++ b/assets/songs/test/dialogue.hx
@@ -0,0 +1,5 @@
+function next(event)
+ if (!event.playFirst) trace("-");
+
+function postNext(event)
+ trace(curLine.char + " says: " + curLine.text);
\ No newline at end of file
diff --git a/assets/songs/ugh/cutscene.hx b/assets/songs/ugh/cutscene.hx
index f1167d57..f78c6117 100644
--- a/assets/songs/ugh/cutscene.hx
+++ b/assets/songs/ugh/cutscene.hx
@@ -2,6 +2,8 @@ import funkin.system.FunkinSprite;
var tankman:FunkinSprite;
var tankTalk1, tankTalk2, bfBeep, distorto:FlxSound;
+var timers:Array = [];
+var destroyDistorto:Bool = true;
function create() {
FlxTween.tween(FlxG.camera, {zoom: 1}, 0.7, {ease: FlxEase.quadInOut});
@@ -33,35 +35,46 @@ function create() {
tankman.playAnim('1');
tankTalk1.play();
- new FlxTimer().start(3, function(tmr:FlxTimer) {
+ timer(3, function() {
focusOn(game.boyfriend);
- new FlxTimer().start(1.5, function(t) {
+ timer(1.5, function() {
game.boyfriend.playAnim("singUP");
bfBeep.play();
- new FlxTimer().start(1.5, function(t) {
+ timer(1.5, function() {
focusOn(game.dad);
tankTalk2.play();
tankman.playAnim('2');
- new FlxTimer().start(6.1, function(t) {
- game.remove(tankman);
- tankman.destroy();
-
- game.camHUD.visible = true;
- game.dad.visible = true;
+ timer(6.1, function() {
+ destroyDistorto = false;
distorto.fadeOut((Conductor.crochet / 1000) * 5, 0);
-
close();
- }, 1);
- }, 1);
- }, 1);
- }, 1);
+ });
+ });
+ });
+ });
+}
+
+function timer(duration:Float, callBack:Void->Void) {
+ timers.push(new FlxTimer().start(duration, function(timer) {
+ timers.remove(timer);
+ callBack();
+ }));
}
function focusOn(char) {
var camPos = char.getCameraPosition();
game.camFollow.setPosition(camPos.x, camPos.y);
camPos.put();
+}
+
+function destroy() {
+ game.remove(tankman);
+ game.camHUD.visible = true;
+ game.dad.visible = true;
+ for(timer in timers) timer.cancel();
+ for(thing in [tankTalk1, tankTalk2, bfBeep, tankman]) thing.destroy();
+ if(destroyDistorto) distorto.destroy();
}
\ No newline at end of file
diff --git a/libs.xml b/libs.xml
index c7b59da3..e74a0e6b 100644
--- a/libs.xml
+++ b/libs.xml
@@ -20,6 +20,8 @@
+
+
diff --git a/project.xml b/project.xml
index 3d38069a..5ad86277 100644
--- a/project.xml
+++ b/project.xml
@@ -136,9 +136,12 @@
-
+
+
+
+
@@ -175,6 +178,8 @@
+
+
diff --git a/source/StringTools.hx b/source/StringTools.hx
index 40397636..2eac4b10 100644
--- a/source/StringTools.hx
+++ b/source/StringTools.hx
@@ -219,7 +219,7 @@ class StringTools {
If `start` is the empty String `""`, the result is true.
**/
- public static #if (java || python || (js && js_es >= 6) || cpp) inline #end function startsWith(s:String, start:String):Bool {
+ public static #if (java || python || (js && js_es >= 6)) inline #end function startsWith(s:String, start:String):Bool {
#if java
return (cast s : java.NativeString).startsWith(start);
#elseif hl
@@ -244,7 +244,7 @@ class StringTools {
If `end` is the empty String `""`, the result is true.
**/
- public static #if (java || python || (js && js_es >= 6) || cpp) inline #end function endsWith(s:String, end:String):Bool {
+ public static #if (java || python || (js && js_es >= 6)) inline #end function endsWith(s:String, end:String):Bool {
#if java
return (cast s : java.NativeString).endsWith(end);
#elseif hl
diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx
index 267d1581..9e3392dc 100644
--- a/source/funkin/backend/FunkinSprite.hx
+++ b/source/funkin/backend/FunkinSprite.hx
@@ -8,7 +8,7 @@ import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.util.typeLimit.OneOfTwo;
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
-import funkin.backend.scripting.events.PlayAnimContext;
+import funkin.backend.scripting.events.sprite.PlayAnimContext;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.system.interfaces.IOffsetCompatible;
import funkin.backend.utils.XMLUtil.AnimData;
@@ -46,6 +46,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public var debugMode:Bool = false;
public var animDatas:Map = [];
+ public var globalCurFrame(get, set):Int;
+
/**
* ODD interval -> asynced; EVEN interval -> synced
*/
@@ -130,7 +132,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
private var countedBeat = 0;
public function beatHit(curBeat:Int)
{
- if (beatAnims.length > 0 && (curBeat + beatOffset) % beatInterval == 0)
+ if (lastAnimContext != LOCK && beatAnims.length > 0 && (curBeat + beatOffset) % beatInterval == 0)
{
if(skipNegativeBeats && curBeat < 0) return;
// TODO: find a solution without countedBeat
@@ -391,4 +393,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return beatInterval = v;
}
+
+ @:noCompletion private inline function get_globalCurFrame() {
+ return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
+ }
+ @:noCompletion private inline function set_globalCurFrame(val:Int) {
+ return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
+ }
}
diff --git a/source/funkin/backend/MusicBeatState.hx b/source/funkin/backend/MusicBeatState.hx
index 56dc1874..801794ec 100644
--- a/source/funkin/backend/MusicBeatState.hx
+++ b/source/funkin/backend/MusicBeatState.hx
@@ -162,10 +162,36 @@ class MusicBeatState extends FlxState implements IBeatReceiver
persistentUpdate = true;
call("postCreate");
if (!skipTransIn)
- openSubState(new MusicBeatTransition(null));
+ startTransition(null);
skipTransIn = false;
skipTransOut = false;
}
+
+ public function startTransition(?newState:FlxState, skipSubStates:Bool = false):Bool {
+ if (!skipSubStates) {
+ var curCheckingSub:FlxSubState = subState;
+ var found:FlxSubState = null; // always gets the last one - Nex
+
+ while (curCheckingSub != null) {
+ if (curCheckingSub is MusicBeatTransition) {
+ found = null; // avoiding infinite loops - Nex
+ break;
+ }
+
+ if (curCheckingSub is MusicBeatSubstate && cast(curCheckingSub, MusicBeatSubstate).canOpenCustomTransition) found = curCheckingSub;
+ curCheckingSub = curCheckingSub.subState;
+ }
+
+ if (found != null) {
+ found.openSubState(new MusicBeatTransition(newState));
+ return true; // "Started from a substate?"
+ }
+ }
+
+ openSubState(new MusicBeatTransition(newState));
+ return false;
+ }
+
public function call(name:String, ?args:Array, ?defaultVal:Dynamic):Dynamic {
// calls the function on the assigned script
if(stateScripts != null)
@@ -228,7 +254,7 @@ class MusicBeatState extends FlxState implements IBeatReceiver
public override function openSubState(subState:FlxSubState) {
var e = event("onOpenSubState", EventManager.get(StateEvent).recycle(subState));
if (!e.cancelled)
- super.openSubState(subState);
+ super.openSubState(e.substate is FlxSubState ? cast e.substate : subState);
}
public override function onResize(w:Int, h:Int) {
@@ -256,11 +282,9 @@ class MusicBeatState extends FlxState implements IBeatReceiver
if (e.cancelled)
return false;
- if (skipTransOut)
+ if (skipTransOut || (subState is MusicBeatTransition && cast(subState, MusicBeatTransition).newState != null))
return true;
- if (subState is MusicBeatTransition && cast(subState, MusicBeatTransition).newState != null)
- return true;
- openSubState(new MusicBeatTransition(nextState));
+ startTransition(e.substate);
persistentUpdate = false;
return false;
}
diff --git a/source/funkin/backend/MusicBeatSubstate.hx b/source/funkin/backend/MusicBeatSubstate.hx
index b8d26038..d0d0f86f 100644
--- a/source/funkin/backend/MusicBeatSubstate.hx
+++ b/source/funkin/backend/MusicBeatSubstate.hx
@@ -16,6 +16,10 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
private var lastBeat:Float = 0;
private var lastStep:Float = 0;
+ /**
+ * Whether this specifc substate can open custom transitions
+ */
+ public var canOpenCustomTransition:Bool = false;
/**
* Current step
*/
@@ -217,7 +221,7 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
public override function openSubState(subState:FlxSubState) {
var e = event("onOpenSubState", EventManager.get(StateEvent).recycle(subState));
if (!e.cancelled)
- super.openSubState(subState);
+ super.openSubState(e.substate is FlxSubState ? cast e.substate : subState);
}
public override function onResize(w:Int, h:Int) {
@@ -235,7 +239,7 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
var e = event("onStateSwitch", EventManager.get(StateEvent).recycle(nextState));
if (e.cancelled)
return false;
- return super.switchTo(nextState);
+ return super.switchTo(e.substate);
}
public override function onFocus() {
@@ -250,19 +254,14 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
public var parent:FlxState;
- public function onSubstateOpen() {
-
- }
+ public function onSubstateOpen() {}
public override function resetSubState() {
+ super.resetSubState();
if (subState != null && subState is MusicBeatSubstate) {
var subState:MusicBeatSubstate = cast subState;
subState.parent = this;
- super.resetSubState();
- if (subState != null)
- cast(subState, MusicBeatSubstate).onSubstateOpen();
- return;
+ subState.onSubstateOpen();
}
- super.resetSubState();
}
}
diff --git a/source/funkin/backend/assets/Paths.hx b/source/funkin/backend/assets/Paths.hx
index 9ccec02a..5988a7ba 100644
--- a/source/funkin/backend/assets/Paths.hx
+++ b/source/funkin/backend/assets/Paths.hx
@@ -13,12 +13,6 @@ using StringTools;
class Paths
{
- /**
- * Preferred sound extension for the game's audio files.
- * Currently is set to `mp3` for web targets, and `ogg` for other targets.
- */
- public static inline final SOUND_EXT = #if web "mp3" #else "ogg" #end;
-
public static var assetsTree:AssetsLibraryList;
public static var tempFramesCache:Map = [];
@@ -32,8 +26,8 @@ class Paths
public static inline function getPath(file:String, ?library:String)
return library != null ? '$library:assets/$library/$file' : 'assets/$file';
- public static inline function video(key:String, ?ext:String = "mp4")
- return getPath('videos/$key.$ext');
+ public static inline function video(key:String, ?ext:String)
+ return getPath('videos/$key.${ext != null ? ext : Flags.VIDEO_EXT}');
public static inline function ndll(key:String)
return getPath('ndlls/$key.ndll');
@@ -65,30 +59,33 @@ class Paths
public static inline function ps1(key:String, ?library:String)
return getPath('data/$key.ps1', library);
- public static function sound(key:String, ?library:String)
- return getPath('sounds/$key.$SOUND_EXT', library);
+ static public function sound(key:String, ?library:String, ?ext:String)
+ return getPath('sounds/$key.${ext != null ? ext : Flags.SOUND_EXT}', library);
public static inline function soundRandom(key:String, min:Int, max:Int, ?library:String)
return sound(key + FlxG.random.int(min, max), library);
- public static inline function music(key:String, ?library:String)
- return getPath('music/$key.$SOUND_EXT', library);
+ inline static public function music(key:String, ?library:String, ?ext:String)
+ return getPath('music/$key.${ext != null ? ext : Flags.SOUND_EXT}', library);
- inline static public function voices(song:String, difficulty:String = "normal", ?prefix:String = "")
- {
+ inline static public function voices(song:String, ?difficulty:String, ?prefix:String = "", ?ext:String) {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
+ if (ext == null) ext = Flags.SOUND_EXT;
song = song.toLowerCase();
- var diff = getPath('songs/${song}/song/Voices$prefix-${difficulty.toLowerCase()}.$SOUND_EXT', null);
- return OpenFlAssets.exists(diff) ? diff : getPath('songs/${song}/song/Voices$prefix.$SOUND_EXT', null);
+ var diff = getPath('songs/$song/song/Voices$prefix-${difficulty.toLowerCase()}.${ext}', null);
+ return OpenFlAssets.exists(diff) ? diff : getPath('songs/$song/song/Voices$prefix.${ext}', null);
}
- inline static public function inst(song:String, difficulty:String = "normal", ?prefix:String = "")
- {
+ inline static public function inst(song:String, ?difficulty:String, ?prefix:String = "", ?ext:String) {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
+ if (ext == null) ext = Flags.SOUND_EXT;
song = song.toLowerCase();
- var diff = getPath('songs/${song}/song/Inst$prefix-${difficulty.toLowerCase()}.$SOUND_EXT', null);
- return OpenFlAssets.exists(diff) ? diff : getPath('songs/${song}/song/Inst$prefix.$SOUND_EXT', null);
+ var diff = getPath('songs/$song/song/Inst$prefix-${difficulty.toLowerCase()}.${ext}', null);
+ return OpenFlAssets.exists(diff) ? diff : getPath('songs/$song/song/Inst$prefix.${ext}', null);
}
- public static function image(key:String, ?library:String, checkForAtlas:Bool = false, ?ext:String = "png") {
+ static public function image(key:String, ?library:String, checkForAtlas:Bool = false, ?ext:String) {
+ if (ext == null) ext = Flags.IMAGE_EXT;
if (checkForAtlas) {
var atlasPath = getPath('images/$key/spritemap.$ext', library);
var multiplePath = getPath('images/$key/1.$ext', library);
@@ -113,8 +110,9 @@ class Paths
return scriptPath;
}
- public static function chart(song:String, ?difficulty:String = "normal"):String {
- difficulty = difficulty.toLowerCase();
+ static public function chart(song:String, ?difficulty:String):String
+ {
+ difficulty = (difficulty != null ? difficulty : Flags.DEFAULT_DIFFICULTY).toLowerCase();
song = song.toLowerCase();
return getPath('songs/$song/charts/$difficulty.json', null);
@@ -156,33 +154,33 @@ class Paths
return getPath('models/$key.awd');
}
- public static inline function getSparrowAtlas(key:String, ?library:String)
- return FlxAtlasFrames.fromSparrow(image(key, library), file('images/$key.xml', library));
+ inline static public function getSparrowAtlas(key:String, ?library:String, ?ext:String)
+ return FlxAtlasFrames.fromSparrow(image(key, library, ext), file('images/$key.xml', library));
- public static inline function getSparrowAtlasAlt(key:String)
- return FlxAtlasFrames.fromSparrow('$key.png', '$key.xml');
+ inline static public function getSparrowAtlasAlt(key:String, ?ext:String)
+ return FlxAtlasFrames.fromSparrow('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.xml');
- public static inline function getPackerAtlas(key:String, ?library:String)
- return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library));
+ inline static public function getPackerAtlas(key:String, ?library:String, ?ext:String)
+ return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library, ext), file('images/$key.txt', library));
- public static inline function getPackerAtlasAlt(key:String)
- return FlxAtlasFrames.fromSpriteSheetPacker('$key.png', '$key.txt');
+ inline static public function getPackerAtlasAlt(key:String, ?ext:String)
+ return FlxAtlasFrames.fromSpriteSheetPacker('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.txt');
- public static inline function getAsepriteAtlas(key:String, ?library:String)
- return FlxAtlasFrames.fromAseprite(image(key, library), file('images/$key.json', library));
+ inline static public function getAsepriteAtlas(key:String, ?library:String, ?ext:String)
+ return FlxAtlasFrames.fromAseprite(image(key, library, ext), file('images/$key.json', library));
- public static inline function getAsepriteAtlasAlt(key:String)
- return FlxAtlasFrames.fromAseprite('$key.png', '$key.json');
+ inline static public function getAsepriteAtlasAlt(key:String, ?ext:String)
+ return FlxAtlasFrames.fromAseprite('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.json');
- public static inline function getAssetsRoot():String
- return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : './assets';
+ inline static public function getAssetsRoot():String
+ return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : #if (sys && TEST_BUILD) './${Main.pathBack}assets/' #else './assets' #end;
/**
* Gets frames at specified path.
* @param key Path to the frames
* @param library (Additional) library to load the frames from.
*/
- public static function getFrames(key:String, assetsPath:Bool = false, ?library:String) {
+ public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null) {
if (tempFramesCache.exists(key)) {
var frames = tempFramesCache[key];
if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
@@ -190,7 +188,7 @@ class Paths
else
tempFramesCache.remove(key);
}
- return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true));
+ return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
}
@@ -202,10 +200,11 @@ class Paths
* @param SkipAtlasCheck Whenever the atlas check should be skipped.
* @return FlxFramesCollection Frames
*/
- static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false):FlxFramesCollection {
+ static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, ?Ext:String = null):FlxFramesCollection {
var noExt = Path.withoutExtension(path);
+ var ext = Ext != null ? Ext : Flags.IMAGE_EXT;
- if (Assets.exists('$noExt/1.png')) {
+ if (Assets.exists('$noExt/1.${ext}')) {
// MULTIPLE SPRITESHEETS!!
var graphic = FlxG.bitmap.add("flixel/images/logo/default.png", false, '$noExt/mult');
@@ -216,18 +215,18 @@ class Paths
trace("no frames yet for multiple atlases!!");
var cur = 1;
var finalFrames = new MultiFramesCollection(graphic);
- while(Assets.exists('$noExt/$cur.png')) {
- var spr = loadFrames('$noExt/$cur.png');
+ while(Assets.exists('$noExt/$cur.${ext}')) {
+ var spr = loadFrames('$noExt/$cur.${ext}');
finalFrames.addFrames(spr);
cur++;
}
return finalFrames;
} else if (Assets.exists('$noExt.xml')) {
- return Paths.getSparrowAtlasAlt(noExt);
+ return Paths.getSparrowAtlasAlt(noExt, ext);
} else if (Assets.exists('$noExt.txt')) {
- return Paths.getPackerAtlasAlt(noExt);
+ return Paths.getPackerAtlasAlt(noExt, ext);
} else if (Assets.exists('$noExt.json')) {
- return Paths.getAsepriteAtlasAlt(noExt);
+ return Paths.getAsepriteAtlasAlt(noExt, ext);
}
var graph:FlxGraphic = FlxG.bitmap.add(path, Unique, Key);
diff --git a/source/funkin/backend/chart/BaseGameParser.hx b/source/funkin/backend/chart/BaseGameParser.hx
new file mode 100644
index 00000000..84b281aa
--- /dev/null
+++ b/source/funkin/backend/chart/BaseGameParser.hx
@@ -0,0 +1,176 @@
+package funkin.backend.chart;
+
+import funkin.backend.chart.ChartData.ChartMetaData;
+
+// These new structures are kinda a mess to port, i love and hate them at the same time; why the hell are every difficulty in the same file??? - Nex
+class BaseGameParser {
+ public static function parseChart(data:Dynamic, metaData:Dynamic, result:ChartData) {
+ // TO DO
+ }
+
+ public static function parseMeta(data:Dynamic, result:ChartMetaData) {
+ var data:SwagMetadata = data;
+ result.name = data.songName;
+ result.artist = data.artist;
+
+ result.customValues = {};
+ result.customValues.timeChanges = data.timeChanges;
+ var firstTimeChng:SwagTimeChange = data.timeChanges[0];
+ result.bpm = firstTimeChng.bpm;
+ result.beatsPerMeasure = firstTimeChng.b != null ? firstTimeChng.b : Flags.DEFAULT_BEATS_PER_MEASURE;
+
+ result.difficulties = data.playData.difficulties.concat(data.playData.songVariations);
+ Reflect.deleteField(data.playData, "difficulties");
+
+ for (field in Reflect.fields(data.playData))
+ Reflect.setProperty(result.customValues, field, Reflect.getProperty(data.playData, field));
+ }
+
+ public static function encodeMeta(meta:ChartMetaData, ?chart:ChartData):SwagMetadata {
+ var addVars:Dynamic = meta.customValues;
+ var defStage:String = addVars.stage != null ? addVars.stage : Flags.DEFAULT_STAGE;
+ var defChars:SwagCharactersList = addVars.characters != null ? addVars.characters : {player: Flags.DEFAULT_CHARACTER, girlfriend: Flags.DEFAULT_GIRLFRIEND, opponent: Flags.DEFAULT_OPPONENT};
+ var defTimeCh:Array;
+
+ if (addVars.timeChanges != null && addVars.timeChanges.length > 0) {
+ defTimeCh = addVars.timeChanges;
+ defTimeCh[0].bpm = meta.bpm;
+ }
+ else defTimeCh = [{bpm: meta.bpm, t: -1}];
+
+ if (chart != null) {
+ defStage = chart.stage;
+
+ var done:Array = [false, false, false];
+ for (strumLine in chart.strumLines) switch (strumLine.type) {
+ case OPPONENT:
+ if (!done[0]) {
+ done[0] = true;
+ defChars.opponent = strumLine.characters.getDefault([defChars.opponent])[0];
+ }
+ case PLAYER:
+ if (!done[1]) {
+ done[1] = true;
+ defChars.player = strumLine.characters.getDefault([defChars.player])[0];
+ }
+ case ADDITIONAL:
+ if (!done[3]) {
+ done[3] = true;
+ defChars.girlfriend = strumLine.characters.getDefault([defChars.girlfriend])[0];
+ }
+ }
+ }
+
+ var result:SwagMetadata = {
+ songName: meta.name,
+ timeFormat: MILLISECONDS,
+ artist: meta.artist,
+ timeChanges: defTimeCh,
+ looped: false,
+ generatedBy: 'Basegame Chart Importer (Codename Engine)',
+ version: Flags.BASEGAME_SONG_METADATA_VERSION,
+ playData: {
+ stage: defStage,
+ characters: defChars,
+ songVariations: addVars.songVariations != null ? [for (i in 0...addVars.songVariations.length) {meta.difficulties.remove(addVars.songVariations[i]); addVars.songVariations[i];}] : [],
+ difficulties: meta.difficulties,
+ noteStyle: addVars.noteStyle != null ? addVars.noteStyle : Flags.BASEGAME_DEFAULT_NOTE_STYLE,
+ album: addVars.album != null ? addVars.album : Flags.BASEGAME_DEFAULT_ALBUM_ID,
+ previewStart: addVars.previewStart != null ? addVars.previewStart : Flags.BASEGAME_DEFAULT_PREVIEW_START,
+ previewEnd: addVars.previewEnd != null ? addVars.previewEnd : Flags.BASEGAME_DEFAULT_PREVIEW_END
+ },
+ };
+
+ return result;
+ return null;
+ }
+
+ public static function encodeChart(chart:ChartData):NewSwagSong {
+ // TO DO
+ return null;
+ }
+}
+
+// METADATA STRUCTURES
+typedef SwagMetadata =
+{
+ var timeFormat:SwagTimeFormat;
+ var artist:String;
+ var songName:String;
+ var playData:SwagPlayData;
+ var timeChanges:Array;
+ var generatedBy:String;
+ var looped:Bool;
+ var version:String;
+
+ var ?divisions:Int;
+ var ?offsets:SwagSongOffsets;
+}
+
+enum abstract SwagTimeFormat(String) from String to String
+{
+ var TICKS = 'ticks';
+ var FLOAT = 'float';
+ var MILLISECONDS = 'ms';
+}
+
+typedef SwagTimeChange =
+{
+ var ?d:Int; // Time Signature Den
+ var ?n:Int; // Time Signature Num
+ var t:Int; // Time Stamp
+ var ?b:Int; // Beat Time
+ var ?bt:Array; // Beat Tuplets
+ var bpm:Float;
+}
+
+typedef SwagPlayData =
+{
+ var album:String;
+ var previewStart:Float;
+ var previewEnd:Float;
+ var stage:String;
+ var characters:SwagCharactersList;
+ var songVariations:Array;
+ var difficulties:Array;
+ var noteStyle:String;
+}
+
+typedef SwagCharactersList =
+{
+ var player:String;
+ var girlfriend:String;
+ var opponent:String;
+}
+
+typedef SwagSongOffsets =
+{
+ var ?instrumental:Float;
+ var ?altInstrumentals:Dynamic;
+ var ?vocals:Dynamic;
+}
+
+// CHART STRUCTURE
+typedef NewSwagSong =
+{
+ var version:String;
+ var scrollSpeed:Dynamic; // Map
+ var events:Array;
+ var notes:Dynamic; // Map>
+ var generatedBy:String;
+}
+
+typedef SwagEvent =
+{
+ var t:Float; // Time
+ var e:String; // Event Kind
+ var v:Dynamic; // Value (Map)
+}
+
+typedef SwagNote =
+{
+ var t:Float; // Time
+ var d:Int; // Data
+ var l:Float; // Length
+ var k:String; // Kind
+}
\ No newline at end of file
diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx
index 93279d43..f1d1d62b 100644
--- a/source/funkin/backend/chart/Chart.hx
+++ b/source/funkin/backend/chart/Chart.hx
@@ -12,11 +12,6 @@ import sys.FileSystem;
using StringTools;
class Chart {
- /**
- * Default background colors for songs without bg color
- */
- public inline static var defaultColor:FlxColor = 0xFF9271FD;
-
public static function loadEventsJson(songName:String) {
var path = Paths.file('songs/${songName.toLowerCase()}/events.json');
var data:Array = null;
@@ -30,7 +25,9 @@ class Chart {
return data;
}
- public static function loadChartMeta(songName:String, difficulty:String = "normal", fromMods:Bool = true) {
+ public static function loadChartMeta(songName:String, ?difficulty:String, fromMods:Bool = true) {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
+
var metaPath = Paths.file('songs/${songName.toLowerCase()}/meta.json');
var metaDiffPath = Paths.file('songs/${songName.toLowerCase()}/meta-${difficulty.toLowerCase()}.json');
@@ -50,19 +47,19 @@ class Chart {
if (data == null)
data = {
- name: songName,
- bpm: 100
+ name: songName
};
data.setFieldDefault("name", songName);
- data.setFieldDefault("beatsPerMeasure", 4);
- data.setFieldDefault("stepsPerBeat", 4);
+ data.setFieldDefault("bpm", Flags.DEFAULT_BPM);
+ data.setFieldDefault("beatsPerMeasure", Flags.DEFAULT_BEATS_PER_MEASURE);
+ data.setFieldDefault("stepsPerBeat", Flags.DEFAULT_STEPS_PER_BEAT);
data.setFieldDefault("needsVoices", true);
- data.setFieldDefault("icon", "face");
+ data.setFieldDefault("icon", Flags.DEFAULT_HEALTH_ICON);
data.setFieldDefault("difficulties", []);
- data.setFieldDefault("coopAllowed", false);
- data.setFieldDefault("opponentModeAllowed", false);
+ data.setFieldDefault("coopAllowed", Flags.DEFAULT_COOP_ALLOWED);
+ data.setFieldDefault("opponentModeAllowed", Flags.DEFAULT_OPPONENT_MODE_ALLOWED);
data.setFieldDefault("displayName", data.name);
- data.setFieldDefault("parsedColor", data.color.getColorFromDynamic().getDefault(defaultColor));
+ data.setFieldDefault("parsedColor", data.color.getColorFromDynamic().getDefault(Flags.DEFAULT_COLOR));
if (data.difficulties.length <= 0) {
data.difficulties = [for(f in Paths.getFolderContent('songs/${songName.toLowerCase()}/charts/', false, fromMods ? MODS : SOURCE)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
@@ -86,7 +83,9 @@ class Chart {
return data;
}
- public static function parse(songName:String, difficulty:String = "normal"):ChartData {
+ public static function parse(songName:String, ?difficulty:String):ChartData {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
+
var chartPath = Paths.chart(songName, difficulty);
var base:ChartData = {
strumLines: [],
@@ -95,8 +94,8 @@ class Chart {
meta: {
name: null
},
- scrollSpeed: 2,
- stage: "stage",
+ scrollSpeed: Flags.DEFAULT_SCROLL_SPEED,
+ stage: Flags.DEFAULT_STAGE,
codenameChart: true,
fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS)
};
@@ -192,7 +191,8 @@ class Chart {
* @param saveSettings
* @return Filtered chart used for saving.
*/
- public static function save(songFolderPath:String, chart:ChartData, difficulty:String = "normal", ?saveSettings:ChartSaveSettings):ChartData {
+ public static function save(songFolderPath:String, chart:ChartData, ?difficulty:String, ?saveSettings:ChartSaveSettings):ChartData {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
if (saveSettings == null) saveSettings = {};
if (saveSettings.saveMetaInChart == null) saveSettings.saveMetaInChart = true;
@@ -210,11 +210,11 @@ class Chart {
var chartPath = '${songFolderPath}/$saveFolder/${difficulty.trim()}.json';
var metaPath = '${songFolderPath}/meta.json';
- CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? "\t" : null));
+ CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
// idk how null reacts to it so better be sure
if (saveSettings.overrideExistingMeta == true || !FileSystem.exists(metaPath))
- CoolUtil.safeSaveFile(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? "\t" : null));
+ CoolUtil.safeSaveFile(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
#end
return filteredChart;
}
diff --git a/source/funkin/backend/chart/ChartData.hx b/source/funkin/backend/chart/ChartData.hx
index 3f8f3302..425cfc3a 100644
--- a/source/funkin/backend/chart/ChartData.hx
+++ b/source/funkin/backend/chart/ChartData.hx
@@ -19,7 +19,7 @@ typedef ChartMetaData = {
public var ?bpm:Float;
public var ?displayName:String;
public var ?beatsPerMeasure:Float;
- public var ?stepsPerBeat:Float;
+ public var ?stepsPerBeat:Int;
public var ?icon:String;
public var ?color:Dynamic;
public var ?difficulties:Array;
@@ -27,6 +27,7 @@ typedef ChartMetaData = {
public var ?opponentModeAllowed:Bool;
public var ?customValues:Dynamic;
public var ?needsVoices:Bool;
+ public var ?artist:String;
// NOT TO BE EXPORTED
public var ?parsedColor:FlxColor;
diff --git a/source/funkin/backend/chart/FNFLegacyParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx
index a63aa649..e4e60d9b 100644
--- a/source/funkin/backend/chart/FNFLegacyParser.hx
+++ b/source/funkin/backend/chart/FNFLegacyParser.hx
@@ -45,7 +45,7 @@ class FNFLegacyParser {
var camFocusedBF:Bool = false;
var altAnims:Bool = false;
- var beatsPerMeasure:Float = data.beatsPerMeasure.getDefault(4);
+ var beatsPerMeasure:Float = data.beatsPerMeasure.getDefault(Flags.DEFAULT_BEATS_PER_MEASURE);
var curBPM:Float = data.bpm;
var curTime:Float = 0;
var curCrochet:Float = ((60 / curBPM) * 1000);
@@ -132,7 +132,7 @@ class FNFLegacyParser {
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
sectionNote[1] += 4;
- swagSection.sectionNotes.push(sectionNote);
+ swagSection.sectionNotes.push(sectionNote);
}
}
@@ -156,9 +156,9 @@ class FNFLegacyParser {
for (strumLine in chart.strumLines)
switch (strumLine.type) {
case OPPONENT:
- if (base.player2 == null) base.player2 = strumLine.characters.getDefault(["dad"])[0];
+ if (base.player2 == null) base.player2 = strumLine.characters.getDefault([Flags.DEFAULT_OPPONENT])[0];
case PLAYER:
- if (base.player1 == null) base.player1 = strumLine.characters.getDefault(["bf"])[0];
+ if (base.player1 == null) base.player1 = strumLine.characters.getDefault([Flags.DEFAULT_CHARACTER])[0];
case ADDITIONAL: // do nothing
}
@@ -221,7 +221,7 @@ typedef SwagSong =
// ADDITIONAL STUFF THAT MAY NOT BE PRESENT IN CHART
var ?maxHealth:Float;
var ?beatsPerMeasure:Float;
- var ?stepsPerBeat:Float;
+ var ?stepsPerBeat:Int;
}
typedef SwagSection =
diff --git a/source/funkin/backend/scripting/Script.hx b/source/funkin/backend/scripting/Script.hx
index d9aaea5a..48d3c357 100644
--- a/source/funkin/backend/scripting/Script.hx
+++ b/source/funkin/backend/scripting/Script.hx
@@ -19,78 +19,78 @@ class Script extends FlxBasic implements IFlxDestroyable {
public static function getDefaultVariables(?script:Script):Map {
return [
// Haxe related stuff
- "Std" => Std,
- "Math" => Math,
- "Reflect" => Reflect,
- "StringTools" => StringTools,
- "Json" => haxe.Json,
+ "Std" => Std,
+ "Math" => Math,
+ "Reflect" => Reflect,
+ "StringTools" => StringTools,
+ "Json" => haxe.Json,
// OpenFL & Lime related stuff
"Assets" => openfl.utils.Assets,
- "Application" => lime.app.Application,
+ "Application" => lime.app.Application,
"Main" => funkin.backend.system.Main,
"window" => lime.app.Application.current.window,
// Flixel related stuff
- "FlxG" => flixel.FlxG,
- "FlxSprite" => flixel.FlxSprite,
- "FlxBasic" => flixel.FlxBasic,
- "FlxCamera" => flixel.FlxCamera,
- "state" => flixel.FlxG.state,
- "FlxEase" => flixel.tweens.FlxEase,
- "FlxTween" => flixel.tweens.FlxTween,
- "FlxSound" => flixel.sound.FlxSound,
- "FlxAssets" => flixel.system.FlxAssets,
- "FlxMath" => flixel.math.FlxMath,
- "FlxGroup" => flixel.group.FlxGroup,
- "FlxTypedGroup" => flixel.group.FlxGroup.FlxTypedGroup,
+ "state" => flixel.FlxG.state,
+ "FlxG" => flixel.FlxG,
+ "FlxSprite" => flixel.FlxSprite,
+ "FlxBasic" => flixel.FlxBasic,
+ "FlxCamera" => flixel.FlxCamera,
+ "FlxEase" => flixel.tweens.FlxEase,
+ "FlxTween" => flixel.tweens.FlxTween,
+ "FlxSound" => flixel.sound.FlxSound,
+ "FlxAssets" => flixel.system.FlxAssets,
+ "FlxMath" => flixel.math.FlxMath,
+ "FlxGroup" => flixel.group.FlxGroup,
+ "FlxTypedGroup" => flixel.group.FlxGroup.FlxTypedGroup,
"FlxSpriteGroup" => flixel.group.FlxSpriteGroup,
- "FlxTypeText" => flixel.addons.text.FlxTypeText,
- "FlxText" => flixel.text.FlxText,
- "FlxTimer" => flixel.util.FlxTimer,
- "FlxPoint" => CoolUtil.getMacroAbstractClass("flixel.math.FlxPoint"),
- "FlxAxes" => CoolUtil.getMacroAbstractClass("flixel.util.FlxAxes"),
- "FlxColor" => CoolUtil.getMacroAbstractClass("flixel.util.FlxColor"),
+ "FlxTypeText" => flixel.addons.text.FlxTypeText,
+ "FlxText" => flixel.text.FlxText,
+ "FlxTimer" => flixel.util.FlxTimer,
+ "FlxPoint" => CoolUtil.getMacroAbstractClass("flixel.math.FlxPoint"),
+ "FlxAxes" => CoolUtil.getMacroAbstractClass("flixel.util.FlxAxes"),
+ "FlxColor" => CoolUtil.getMacroAbstractClass("flixel.util.FlxColor"),
// Engine related stuff
"engine" => {
- commit: funkin.backend.system.macros.GitCommitMacro.commitNumber,
- hash: funkin.backend.system.macros.GitCommitMacro.commitHash,
+ commit: Flags.COMMIT_NUMBER,
+ hash: Flags.COMMIT_HASH,
build: 2675, // 2675 being the last build num before it was removed
name: "Codename Engine"
},
- "ModState" => funkin.backend.scripting.ModState,
- "ModSubState" => funkin.backend.scripting.ModSubState,
- "PlayState" => funkin.game.PlayState,
- "GameOverSubstate" => funkin.game.GameOverSubstate,
+ "ModState" => funkin.backend.scripting.ModState,
+ "ModSubState" => funkin.backend.scripting.ModSubState,
+ "PlayState" => funkin.game.PlayState,
+ "GameOverSubstate" => funkin.game.GameOverSubstate,
"HealthIcon" => funkin.game.HealthIcon,
- "HudCamera" => funkin.game.HudCamera,
- "Note" => funkin.game.Note,
- "Strum" => funkin.game.Strum,
- "StrumLine" => funkin.game.StrumLine,
- "Character" => funkin.game.Character,
- "Boyfriend" => funkin.game.Character, // for compatibility
- "PauseSubstate" => funkin.menus.PauseSubState,
- "FreeplayState" => funkin.menus.FreeplayState,
- "MainMenuState" => funkin.menus.MainMenuState,
- "PauseSubState" => funkin.menus.PauseSubState,
+ "HudCamera" => funkin.game.HudCamera,
+ "Note" => funkin.game.Note,
+ "Strum" => funkin.game.Strum,
+ "StrumLine" => funkin.game.StrumLine,
+ "Character" => funkin.game.Character,
+ "Boyfriend" => funkin.game.Character, // for compatibility
+ "PauseSubstate" => funkin.menus.PauseSubState,
+ "FreeplayState" => funkin.menus.FreeplayState,
+ "MainMenuState" => funkin.menus.MainMenuState,
+ "PauseSubState" => funkin.menus.PauseSubState,
"StoryMenuState" => funkin.menus.StoryMenuState,
"TitleState" => funkin.menus.TitleState,
- "Options" => funkin.options.Options,
- "Paths" => funkin.backend.assets.Paths,
- "Conductor" => funkin.backend.system.Conductor,
- "FunkinShader" => funkin.backend.shaders.FunkinShader,
- "CustomShader" => funkin.backend.shaders.CustomShader,
+ "Options" => funkin.options.Options,
+ "Paths" => funkin.backend.assets.Paths,
+ "Conductor" => funkin.backend.system.Conductor,
+ "FunkinShader" => funkin.backend.shaders.FunkinShader,
+ "CustomShader" => funkin.backend.shaders.CustomShader,
"FunkinText" => funkin.backend.FunkinText,
"FlxAnimate" => funkin.backend.FlxAnimate,
"FunkinSprite" => funkin.backend.FunkinSprite,
- "Alphabet" => funkin.menus.ui.Alphabet,
+ "Alphabet" => funkin.menus.ui.Alphabet,
- "CoolUtil" => funkin.backend.utils.CoolUtil,
- "IniUtil" => funkin.backend.utils.IniUtil,
- "XMLUtil" => funkin.backend.utils.XMLUtil,
- #if sys "ZipUtil" => funkin.backend.utils.ZipUtil, #end
- "MarkdownUtil" => funkin.backend.utils.MarkdownUtil,
+ "CoolUtil" => funkin.backend.utils.CoolUtil,
+ "IniUtil" => funkin.backend.utils.IniUtil,
+ "XMLUtil" => funkin.backend.utils.XMLUtil,
+ #if sys "ZipUtil" => funkin.backend.utils.ZipUtil, #end
+ "MarkdownUtil" => funkin.backend.utils.MarkdownUtil,
"EngineUtil" => funkin.backend.utils.EngineUtil,
"MemoryUtil" => funkin.backend.utils.MemoryUtil,
"BitmapUtil" => funkin.backend.utils.BitmapUtil,
@@ -101,12 +101,57 @@ class Script extends FlxBasic implements IFlxDestroyable {
#end
];
}
+
+ /**
+ * Used internally to keep backwards compatibility with old scripts.
+ * This gets set on `hscript.Interp.importRedirects`,
+ * if you wanna modify it, please edit `hscript.Interp.importRedirects` directly.
+ **/
+ public static function getDefaultImportRedirects():Map {
+ var redirects:Map = [
+ "funkin.savedata.FunkinSave" => "funkin.backend.utils.FunkinSave"
+ ];
+
+ final events = "funkin.backend.scripting.events.";
+ redirects[events + "CharacterNodeEvent"] = events + "character.CharacterNodeEvent";
+ redirects[events + "CharacterXMLEvent"] = events + "character.CharacterXMLEvent";
+ redirects[events + "DanceEvent"] = events + "character.DanceEvent";
+ redirects[events + "DirectionAnimEvent"] = events + "character.DirectionAnimEvent";
+ redirects[events + "DiscordPresenceUpdateEvent"] = events + "discord.DiscordPresenceUpdateEvent";
+ redirects[events + "GameOverCreationEvent"] = events + "gameover.GameOverCreationEvent";
+ redirects[events + "CamMoveEvent"] = events + "gameplay.CamMoveEvent";
+ redirects[events + "CountdownEvent"] = events + "gameplay.CountdownEvent";
+ redirects[events + "EventGameEvent"] = events + "gameplay.EventGameEvent";
+ redirects[events + "GameOverEvent"] = events + "gameplay.GameOverEvent";
+ redirects[events + "RatingUpdateEvent"] = events + "gameplay.RatingUpdateEvent";
+ redirects[events + "HealthIconChangeEvent"] = events + "healthicon.HealthIconChangeEvent";
+ redirects[events + "FreeplayAlphaUpdateEvent"] = events + "menu.freeplay.FreeplayAlphaUpdateEvent";
+ redirects[events + "FreeplaySongSelectEvent"] = events + "menu.freeplay.FreeplaySongSelectEvent";
+ redirects[events + "MenuChangeEvent"] = events + "menu.MenuChangeEvent";
+ redirects[events + "PauseCreationEvent"] = events + "menu.pause.PauseCreationEvent";
+ redirects[events + "WeekSelectEvent"] = events + "menu.storymenu.WeekSelectEvent";
+ redirects[events + "InputSystemEvent"] = events + "note.InputSystemEvent";
+ redirects[events + "NoteCreationEvent"] = events + "note.NoteCreationEvent";
+ redirects[events + "NoteHitEvent"] = events + "note.NoteHitEvent";
+ redirects[events + "NoteMissEvent"] = events + "note.NoteMissEvent";
+ redirects[events + "NoteUpdateEvent"] = events + "note.NoteUpdateEvent";
+ redirects[events + "SimpleNoteEvent"] = events + "note.SimpleNoteEvent";
+ redirects[events + "StrumCreationEvent"] = events + "note.StrumCreationEvent";
+ redirects[events + "SplashShowEvent"] = events + "splash.SplashShowEvent";
+ redirects[events + "PlayAnimContext"] = events + "sprite.PlayAnimContext";
+ redirects[events + "PlayAnimEvent"] = events + "sprite.PlayAnimEvent";
+ redirects[events + "StageNodeEvent"] = events + "stage.StageNodeEvent";
+ redirects[events + "StageXMLEvent"] = events + "stage.StageXMLEvent";
+
+ return redirects;
+ }
+
public static function getDefaultPreprocessors():Map {
var defines = funkin.backend.system.macros.DefinesMacro.defines;
defines.set("CODENAME_ENGINE", true);
defines.set("CODENAME_VER", Application.current.meta.get('version'));
defines.set("CODENAME_BUILD", 2675); // 2675 being the last build num before it was removed
- defines.set("CODENAME_COMMIT", funkin.backend.system.macros.GitCommitMacro.commitNumber);
+ defines.set("CODENAME_COMMIT", Flags.COMMIT_NUMBER);
return defines;
}
/**
diff --git a/source/funkin/backend/scripting/events/AmountEvent.hx b/source/funkin/backend/scripting/events/AmountEvent.hx
index a27b1f51..f77ed9ec 100644
--- a/source/funkin/backend/scripting/events/AmountEvent.hx
+++ b/source/funkin/backend/scripting/events/AmountEvent.hx
@@ -4,10 +4,5 @@ final class AmountEvent extends CancellableEvent {
/**
* Amount
*/
- public var amount:Int;
-
- /**
- * Shows whether or not psych users complained about this class
- */
- public var psychUsersComplained:Bool = true;
+ public var amount:Null;
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DrawEvent.hx b/source/funkin/backend/scripting/events/DrawEvent.hx
index 94e1aa8b..74788ecd 100644
--- a/source/funkin/backend/scripting/events/DrawEvent.hx
+++ b/source/funkin/backend/scripting/events/DrawEvent.hx
@@ -1,4 +1,5 @@
package funkin.backend.scripting.events;
final class DrawEvent extends CancellableEvent {
+ // temp empty for now - Nex
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/README.md b/source/funkin/backend/scripting/events/README.md
new file mode 100644
index 00000000..193eef72
--- /dev/null
+++ b/source/funkin/backend/scripting/events/README.md
@@ -0,0 +1,7 @@
+## NOTE
+Keep in mind that a certain criteria was used to place events in their corresponding folders which is simply what the events themselves are mostly related to.
+
+For example:
+
+- `GameOverEvent` inside of the `gameplay` folder instead of the `gameover` folder since it gets called in the `PlayState` class (that owns the `gameplay` folder) instead of the `GameOverSubstate` class itself;
+- `NoteHitEvent` gets indeed called by the `PlayState` class but it's also used in the `StrumLine` (For those who didn't really know, Strumlines are the Input Notes) class and since the event's name itself starts with the word `Note` it was more accurate to place it in the `note` folder instead of the `gameplay` folder that `PlayState` owns.
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/StateEvent.hx b/source/funkin/backend/scripting/events/StateEvent.hx
index d3f35783..7426f319 100644
--- a/source/funkin/backend/scripting/events/StateEvent.hx
+++ b/source/funkin/backend/scripting/events/StateEvent.hx
@@ -4,7 +4,7 @@ import flixel.FlxState;
final class StateEvent extends CancellableEvent {
/**
- * Substate that is about to be opened/closed
+ * Substate or State that is about to be opened/closed
*/
- public var substate:FlxState;
+ public var substate:FlxState; // WHY is it named substate :sob: - Nex
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/CharacterNodeEvent.hx b/source/funkin/backend/scripting/events/character/CharacterNodeEvent.hx
similarity index 87%
rename from source/funkin/backend/scripting/events/CharacterNodeEvent.hx
rename to source/funkin/backend/scripting/events/character/CharacterNodeEvent.hx
index 9577a64f..85eb46c8 100644
--- a/source/funkin/backend/scripting/events/CharacterNodeEvent.hx
+++ b/source/funkin/backend/scripting/events/character/CharacterNodeEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.character;
import funkin.game.Character;
import haxe.xml.Access;
diff --git a/source/funkin/backend/scripting/events/CharacterXMLEvent.hx b/source/funkin/backend/scripting/events/character/CharacterXMLEvent.hx
similarity index 70%
rename from source/funkin/backend/scripting/events/CharacterXMLEvent.hx
rename to source/funkin/backend/scripting/events/character/CharacterXMLEvent.hx
index e4f107fd..7375bafd 100644
--- a/source/funkin/backend/scripting/events/CharacterXMLEvent.hx
+++ b/source/funkin/backend/scripting/events/character/CharacterXMLEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.character;
import funkin.game.Character;
import haxe.xml.Access;
@@ -7,7 +7,7 @@ final class CharacterXMLEvent extends CancellableEvent {
/**
* The character instance
*/
- public var character:Character;
+ public var character:Character;
/**
* The xml
diff --git a/source/funkin/backend/scripting/events/DanceEvent.hx b/source/funkin/backend/scripting/events/character/DanceEvent.hx
similarity index 60%
rename from source/funkin/backend/scripting/events/DanceEvent.hx
rename to source/funkin/backend/scripting/events/character/DanceEvent.hx
index b2300f8f..4f7f7154 100644
--- a/source/funkin/backend/scripting/events/DanceEvent.hx
+++ b/source/funkin/backend/scripting/events/character/DanceEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.character;
final class DanceEvent extends CancellableEvent {
public var danced:Bool;
diff --git a/source/funkin/backend/scripting/events/DirectionAnimEvent.hx b/source/funkin/backend/scripting/events/character/DirectionAnimEvent.hx
similarity index 87%
rename from source/funkin/backend/scripting/events/DirectionAnimEvent.hx
rename to source/funkin/backend/scripting/events/character/DirectionAnimEvent.hx
index dce2eaff..2bc027fa 100644
--- a/source/funkin/backend/scripting/events/DirectionAnimEvent.hx
+++ b/source/funkin/backend/scripting/events/character/DirectionAnimEvent.hx
@@ -1,4 +1,6 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.character;
+
+import funkin.backend.scripting.events.sprite.PlayAnimContext;
final class DirectionAnimEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/dialogue/DialogueNextLineEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueNextLineEvent.hx
new file mode 100644
index 00000000..7a5e3eac
--- /dev/null
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueNextLineEvent.hx
@@ -0,0 +1,14 @@
+package funkin.backend.scripting.events.dialogue;
+
+/**
+ * CANCEL this event to prevent continuing with the next dialogue.
+ *
+ * **NOTE**: To access the current, past or next lines, use `curLine`, `lastLine` or also `dialogueLines` in the `DialogueCutscene` class (they're globals and can be accessed at any time as long as the Dialogue Cutscene is active)!
+ */
+final class DialogueNextLineEvent extends CancellableEvent
+{
+ /**
+ * If the dialogue has just been opened.
+ */
+ public var playFirst:Bool = false;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx b/source/funkin/backend/scripting/events/discord/DiscordPresenceUpdateEvent.hx
similarity index 81%
rename from source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx
rename to source/funkin/backend/scripting/events/discord/DiscordPresenceUpdateEvent.hx
index c17cbb68..19884e42 100644
--- a/source/funkin/backend/scripting/events/DiscordPresenceUpdateEvent.hx
+++ b/source/funkin/backend/scripting/events/discord/DiscordPresenceUpdateEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.discord;
final class DiscordPresenceUpdateEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/GameOverCreationEvent.hx b/source/funkin/backend/scripting/events/gameover/GameOverCreationEvent.hx
similarity index 87%
rename from source/funkin/backend/scripting/events/GameOverCreationEvent.hx
rename to source/funkin/backend/scripting/events/gameover/GameOverCreationEvent.hx
index bb9b04c0..39762aeb 100644
--- a/source/funkin/backend/scripting/events/GameOverCreationEvent.hx
+++ b/source/funkin/backend/scripting/events/gameover/GameOverCreationEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameover;
/**
* CANCEL this event to prevent default behaviour!
diff --git a/source/funkin/backend/scripting/events/CamMoveEvent.hx b/source/funkin/backend/scripting/events/gameplay/CamMoveEvent.hx
similarity index 87%
rename from source/funkin/backend/scripting/events/CamMoveEvent.hx
rename to source/funkin/backend/scripting/events/gameplay/CamMoveEvent.hx
index 3dcbda78..06792c48 100644
--- a/source/funkin/backend/scripting/events/CamMoveEvent.hx
+++ b/source/funkin/backend/scripting/events/gameplay/CamMoveEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameplay;
import flixel.math.FlxPoint;
import funkin.game.StrumLine;
diff --git a/source/funkin/backend/scripting/events/CountdownEvent.hx b/source/funkin/backend/scripting/events/gameplay/CountdownEvent.hx
similarity index 95%
rename from source/funkin/backend/scripting/events/CountdownEvent.hx
rename to source/funkin/backend/scripting/events/gameplay/CountdownEvent.hx
index 7c6b4308..a86d8bae 100644
--- a/source/funkin/backend/scripting/events/CountdownEvent.hx
+++ b/source/funkin/backend/scripting/events/gameplay/CountdownEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameplay;
import flixel.sound.FlxSound;
import flixel.tweens.FlxTween;
diff --git a/source/funkin/backend/scripting/events/EventGameEvent.hx b/source/funkin/backend/scripting/events/gameplay/EventGameEvent.hx
similarity index 71%
rename from source/funkin/backend/scripting/events/EventGameEvent.hx
rename to source/funkin/backend/scripting/events/gameplay/EventGameEvent.hx
index 836e44c9..2e063d90 100644
--- a/source/funkin/backend/scripting/events/EventGameEvent.hx
+++ b/source/funkin/backend/scripting/events/gameplay/EventGameEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameplay;
import funkin.backend.chart.ChartData;
diff --git a/source/funkin/backend/scripting/events/GameOverEvent.hx b/source/funkin/backend/scripting/events/gameplay/GameOverEvent.hx
similarity index 94%
rename from source/funkin/backend/scripting/events/GameOverEvent.hx
rename to source/funkin/backend/scripting/events/gameplay/GameOverEvent.hx
index b0e83795..28521f5b 100644
--- a/source/funkin/backend/scripting/events/GameOverEvent.hx
+++ b/source/funkin/backend/scripting/events/gameplay/GameOverEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameplay;
import funkin.game.Character;
diff --git a/source/funkin/backend/scripting/events/RatingUpdateEvent.hx b/source/funkin/backend/scripting/events/gameplay/RatingUpdateEvent.hx
similarity index 78%
rename from source/funkin/backend/scripting/events/RatingUpdateEvent.hx
rename to source/funkin/backend/scripting/events/gameplay/RatingUpdateEvent.hx
index 96ad7e7e..59a3305d 100644
--- a/source/funkin/backend/scripting/events/RatingUpdateEvent.hx
+++ b/source/funkin/backend/scripting/events/gameplay/RatingUpdateEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.gameplay;
final class RatingUpdateEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/HealthIconChangeEvent.hx b/source/funkin/backend/scripting/events/healthicon/HealthIconChangeEvent.hx
similarity index 78%
rename from source/funkin/backend/scripting/events/HealthIconChangeEvent.hx
rename to source/funkin/backend/scripting/events/healthicon/HealthIconChangeEvent.hx
index a98493ef..dbb4cb68 100644
--- a/source/funkin/backend/scripting/events/HealthIconChangeEvent.hx
+++ b/source/funkin/backend/scripting/events/healthicon/HealthIconChangeEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.healthicon;
final class HealthIconChangeEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/MenuChangeEvent.hx b/source/funkin/backend/scripting/events/menu/MenuChangeEvent.hx
similarity index 87%
rename from source/funkin/backend/scripting/events/MenuChangeEvent.hx
rename to source/funkin/backend/scripting/events/menu/MenuChangeEvent.hx
index d74ef2a4..90b03dcf 100644
--- a/source/funkin/backend/scripting/events/MenuChangeEvent.hx
+++ b/source/funkin/backend/scripting/events/menu/MenuChangeEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.menu;
final class MenuChangeEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/FreeplayAlphaUpdateEvent.hx b/source/funkin/backend/scripting/events/menu/freeplay/FreeplayAlphaUpdateEvent.hx
similarity index 90%
rename from source/funkin/backend/scripting/events/FreeplayAlphaUpdateEvent.hx
rename to source/funkin/backend/scripting/events/menu/freeplay/FreeplayAlphaUpdateEvent.hx
index 639645c2..d8ab6f0b 100644
--- a/source/funkin/backend/scripting/events/FreeplayAlphaUpdateEvent.hx
+++ b/source/funkin/backend/scripting/events/menu/freeplay/FreeplayAlphaUpdateEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.menu.freeplay;
final class FreeplayAlphaUpdateEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/FreeplaySongSelectEvent.hx b/source/funkin/backend/scripting/events/menu/freeplay/FreeplaySongSelectEvent.hx
similarity index 86%
rename from source/funkin/backend/scripting/events/FreeplaySongSelectEvent.hx
rename to source/funkin/backend/scripting/events/menu/freeplay/FreeplaySongSelectEvent.hx
index b97847b0..e2ee1fc7 100644
--- a/source/funkin/backend/scripting/events/FreeplaySongSelectEvent.hx
+++ b/source/funkin/backend/scripting/events/menu/freeplay/FreeplaySongSelectEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.menu.freeplay;
final class FreeplaySongSelectEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/PauseCreationEvent.hx b/source/funkin/backend/scripting/events/menu/pause/PauseCreationEvent.hx
similarity index 83%
rename from source/funkin/backend/scripting/events/PauseCreationEvent.hx
rename to source/funkin/backend/scripting/events/menu/pause/PauseCreationEvent.hx
index a02b0e1a..290ac847 100644
--- a/source/funkin/backend/scripting/events/PauseCreationEvent.hx
+++ b/source/funkin/backend/scripting/events/menu/pause/PauseCreationEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.menu.pause;
/**
* CANCEL this event to prevent default behaviour!
diff --git a/source/funkin/backend/scripting/events/WeekSelectEvent.hx b/source/funkin/backend/scripting/events/menu/storymenu/WeekSelectEvent.hx
similarity index 89%
rename from source/funkin/backend/scripting/events/WeekSelectEvent.hx
rename to source/funkin/backend/scripting/events/menu/storymenu/WeekSelectEvent.hx
index e255d361..c9afe956 100644
--- a/source/funkin/backend/scripting/events/WeekSelectEvent.hx
+++ b/source/funkin/backend/scripting/events/menu/storymenu/WeekSelectEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.menu.storymenu;
import funkin.menus.StoryMenuState.WeekData;
diff --git a/source/funkin/backend/scripting/events/InputSystemEvent.hx b/source/funkin/backend/scripting/events/note/InputSystemEvent.hx
similarity index 95%
rename from source/funkin/backend/scripting/events/InputSystemEvent.hx
rename to source/funkin/backend/scripting/events/note/InputSystemEvent.hx
index 3855c31f..06ea39a4 100644
--- a/source/funkin/backend/scripting/events/InputSystemEvent.hx
+++ b/source/funkin/backend/scripting/events/note/InputSystemEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.StrumLine;
diff --git a/source/funkin/backend/scripting/events/NoteCreationEvent.hx b/source/funkin/backend/scripting/events/note/NoteCreationEvent.hx
similarity index 94%
rename from source/funkin/backend/scripting/events/NoteCreationEvent.hx
rename to source/funkin/backend/scripting/events/note/NoteCreationEvent.hx
index 3f7d1890..f070099f 100644
--- a/source/funkin/backend/scripting/events/NoteCreationEvent.hx
+++ b/source/funkin/backend/scripting/events/note/NoteCreationEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Note;
diff --git a/source/funkin/backend/scripting/events/NoteHitEvent.hx b/source/funkin/backend/scripting/events/note/NoteHitEvent.hx
similarity index 89%
rename from source/funkin/backend/scripting/events/NoteHitEvent.hx
rename to source/funkin/backend/scripting/events/note/NoteHitEvent.hx
index 6b761aed..4c4a2053 100644
--- a/source/funkin/backend/scripting/events/NoteHitEvent.hx
+++ b/source/funkin/backend/scripting/events/note/NoteHitEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Character;
import funkin.game.Note;
@@ -24,9 +24,19 @@ final class NoteHitEvent extends CancellableEvent {
*/
public var countScore:Bool = true;
/**
- * Whenever ratings should be shown or not.
+ * Whenever ratings (Rating sprite, Digits sprites and Combo sprite) should be shown or not.
+ *
+ * NOTE: Whether it's `true` use `displayRating` and `displayCombo` (plus `minDigitDisplay` in the PlayState class) to change what's going to pop up!
*/
public var showRating:Null = null;
+ /**
+ * Whenever the Rating sprites should be shown or not.
+ */
+ public var displayRating:Bool;
+ /**
+ * Whenever the Combo sprite should be shown or not (like old Week 7 patches).
+ */
+ public var displayCombo:Bool;
/**
* Note that has been pressed
*/
diff --git a/source/funkin/backend/scripting/events/NoteMissEvent.hx b/source/funkin/backend/scripting/events/note/NoteMissEvent.hx
similarity index 98%
rename from source/funkin/backend/scripting/events/NoteMissEvent.hx
rename to source/funkin/backend/scripting/events/note/NoteMissEvent.hx
index 72f87ddd..9499d612 100644
--- a/source/funkin/backend/scripting/events/NoteMissEvent.hx
+++ b/source/funkin/backend/scripting/events/note/NoteMissEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Character;
import funkin.game.Note;
diff --git a/source/funkin/backend/scripting/events/NoteUpdateEvent.hx b/source/funkin/backend/scripting/events/note/NoteUpdateEvent.hx
similarity index 95%
rename from source/funkin/backend/scripting/events/NoteUpdateEvent.hx
rename to source/funkin/backend/scripting/events/note/NoteUpdateEvent.hx
index 45676ec5..d004fa0e 100644
--- a/source/funkin/backend/scripting/events/NoteUpdateEvent.hx
+++ b/source/funkin/backend/scripting/events/note/NoteUpdateEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Note;
import funkin.game.Strum;
diff --git a/source/funkin/backend/scripting/events/SimpleNoteEvent.hx b/source/funkin/backend/scripting/events/note/SimpleNoteEvent.hx
similarity index 75%
rename from source/funkin/backend/scripting/events/SimpleNoteEvent.hx
rename to source/funkin/backend/scripting/events/note/SimpleNoteEvent.hx
index 3899958b..9d031fcf 100644
--- a/source/funkin/backend/scripting/events/SimpleNoteEvent.hx
+++ b/source/funkin/backend/scripting/events/note/SimpleNoteEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Note;
diff --git a/source/funkin/backend/scripting/events/StrumCreationEvent.hx b/source/funkin/backend/scripting/events/note/StrumCreationEvent.hx
similarity index 94%
rename from source/funkin/backend/scripting/events/StrumCreationEvent.hx
rename to source/funkin/backend/scripting/events/note/StrumCreationEvent.hx
index d591d958..517075c3 100644
--- a/source/funkin/backend/scripting/events/StrumCreationEvent.hx
+++ b/source/funkin/backend/scripting/events/note/StrumCreationEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.note;
import funkin.game.Strum;
diff --git a/source/funkin/backend/scripting/events/shader/ShaderProcessEvent.hx b/source/funkin/backend/scripting/events/shader/ShaderProcessEvent.hx
new file mode 100644
index 00000000..e8c6b746
--- /dev/null
+++ b/source/funkin/backend/scripting/events/shader/ShaderProcessEvent.hx
@@ -0,0 +1,8 @@
+package funkin.backend.scripting.events.shader;
+
+final class ShaderProcessEvent extends CancellableEvent
+{
+ public var source:String;
+
+ public var storageType:String;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/soundtray/SoundTrayShowEvent.hx b/source/funkin/backend/scripting/events/soundtray/SoundTrayShowEvent.hx
new file mode 100644
index 00000000..7d9b29bd
--- /dev/null
+++ b/source/funkin/backend/scripting/events/soundtray/SoundTrayShowEvent.hx
@@ -0,0 +1,6 @@
+package funkin.backend.scripting.events.soundtray;
+
+final class SoundTrayShowEvent extends CancellableEvent
+{
+ public var up:Bool;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/soundtray/SoundTrayTextEvent.hx b/source/funkin/backend/scripting/events/soundtray/SoundTrayTextEvent.hx
new file mode 100644
index 00000000..1010df06
--- /dev/null
+++ b/source/funkin/backend/scripting/events/soundtray/SoundTrayTextEvent.hx
@@ -0,0 +1,12 @@
+package funkin.backend.scripting.events.soundtray;
+
+final class SoundTrayTextEvent extends CancellableEvent
+{
+ public var checkIfNull:Bool;
+
+ public var reloadDefaultTextFormat:Bool;
+
+ public var displayTxt:String;
+
+ public var y:Float;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/SplashShowEvent.hx b/source/funkin/backend/scripting/events/splash/SplashShowEvent.hx
similarity index 89%
rename from source/funkin/backend/scripting/events/SplashShowEvent.hx
rename to source/funkin/backend/scripting/events/splash/SplashShowEvent.hx
index 46504d44..6cdea0ee 100644
--- a/source/funkin/backend/scripting/events/SplashShowEvent.hx
+++ b/source/funkin/backend/scripting/events/splash/SplashShowEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.splash;
import funkin.game.SplashGroup;
import funkin.game.Strum;
diff --git a/source/funkin/backend/scripting/events/PlayAnimContext.hx b/source/funkin/backend/scripting/events/sprite/PlayAnimContext.hx
similarity index 94%
rename from source/funkin/backend/scripting/events/PlayAnimContext.hx
rename to source/funkin/backend/scripting/events/sprite/PlayAnimContext.hx
index f3c9e211..67f8c857 100644
--- a/source/funkin/backend/scripting/events/PlayAnimContext.hx
+++ b/source/funkin/backend/scripting/events/sprite/PlayAnimContext.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.sprite;
/**
Contains all contexts possible for `PlayAnimEvent`.
diff --git a/source/funkin/backend/scripting/events/PlayAnimEvent.hx b/source/funkin/backend/scripting/events/sprite/PlayAnimEvent.hx
similarity index 92%
rename from source/funkin/backend/scripting/events/PlayAnimEvent.hx
rename to source/funkin/backend/scripting/events/sprite/PlayAnimEvent.hx
index f51c8243..0db69a2b 100644
--- a/source/funkin/backend/scripting/events/PlayAnimEvent.hx
+++ b/source/funkin/backend/scripting/events/sprite/PlayAnimEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.sprite;
final class PlayAnimEvent extends CancellableEvent {
/**
diff --git a/source/funkin/backend/scripting/events/StageNodeEvent.hx b/source/funkin/backend/scripting/events/stage/StageNodeEvent.hx
similarity index 89%
rename from source/funkin/backend/scripting/events/StageNodeEvent.hx
rename to source/funkin/backend/scripting/events/stage/StageNodeEvent.hx
index 93465fa6..505e92b8 100644
--- a/source/funkin/backend/scripting/events/StageNodeEvent.hx
+++ b/source/funkin/backend/scripting/events/stage/StageNodeEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.stage;
import funkin.game.Stage;
import haxe.xml.Access;
diff --git a/source/funkin/backend/scripting/events/StageXMLEvent.hx b/source/funkin/backend/scripting/events/stage/StageXMLEvent.hx
similarity index 85%
rename from source/funkin/backend/scripting/events/StageXMLEvent.hx
rename to source/funkin/backend/scripting/events/stage/StageXMLEvent.hx
index 16693d33..9bc6f10b 100644
--- a/source/funkin/backend/scripting/events/StageXMLEvent.hx
+++ b/source/funkin/backend/scripting/events/stage/StageXMLEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.stage;
import funkin.game.Stage;
import haxe.xml.Access;
diff --git a/source/funkin/backend/shaders/CustomShader.hx b/source/funkin/backend/shaders/CustomShader.hx
index f0b5f3e2..67be4761 100644
--- a/source/funkin/backend/shaders/CustomShader.hx
+++ b/source/funkin/backend/shaders/CustomShader.hx
@@ -25,6 +25,10 @@ class CustomShader extends FunkinShader {
var fragCode = Assets.exists(fragShaderPath) ? Assets.getText(fragShaderPath) : null;
var vertCode = Assets.exists(vertShaderPath) ? Assets.getText(vertShaderPath) : null;
+ fileName = name;
+ fragFileName = fragShaderPath;
+ vertFileName = vertShaderPath;
+
path = fragShaderPath+vertShaderPath;
if (fragCode == null && vertCode == null)
diff --git a/source/funkin/backend/shaders/FunkinShader.hx b/source/funkin/backend/shaders/FunkinShader.hx
index 0b282ffb..b7c1be14 100644
--- a/source/funkin/backend/shaders/FunkinShader.hx
+++ b/source/funkin/backend/shaders/FunkinShader.hx
@@ -1,15 +1,17 @@
package funkin.backend.shaders;
+import flixel.system.FlxAssets.FlxShader;
+import flixel.util.FlxSignal.FlxTypedSignal;
import haxe.Exception;
import hscript.IHScriptCustomBehaviour;
-import flixel.system.FlxAssets.FlxShader;
-
import lime.utils.Float32Array;
-
-import openfl.display.ShaderParameterType;
-import openfl.display.ShaderParameter;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
+import openfl.display.ShaderParameter;
+import openfl.display.ShaderParameterType;
+import openfl.display3D._internal.GLProgram;
+import openfl.display3D._internal.GLShader;
+import openfl.utils._internal.Log;
using StringTools;
@:access(openfl.display3D.Context3D)
@@ -18,8 +20,20 @@ using StringTools;
@:access(openfl.display.ShaderParameter)
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
+ private static var FRAGMENT_SHADER = 0;
+ private static var VERTEX_SHADER = 1;
+
+ public var onGLUpdate:FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
+ public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
public var glslVer:String = "120";
+ public var fileName:String = "FunkinShader";
+ public var fragFileName:String = "FunkinShader";
+ public var vertFileName:String = "FunkinShader";
+
+ public var shaderPrefix:String = "";
+ public var fragmentPrefix:String = "";
+ public var vertexPrefix:String = "";
/**
* Creates a new shader from the specified fragment and vertex source.
@@ -38,11 +52,171 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
super();
}
+ static var IMPORT_REGEX = ~/#import\s+<(.*)>/;
+
+ private function processImports(value:String, type:Int):String
+ {
+ while(IMPORT_REGEX.match(value))
+ {
+ var importPath = IMPORT_REGEX.matched(1);
+ var importSource = Assets.getText("assets/shaders/" + importPath);
+ if(importSource == null) {
+ var fileName = type == FRAGMENT_SHADER ? fragFileName : vertFileName;
+ Logs.traceColored([
+ Logs.logText('[Shader] ', RED),
+ Logs.logText('Failed to import shader ${importPath} in ${fileName}', RED),
+ ]);
+ } else {
+ value = value.replace(IMPORT_REGEX.matched(0), importSource);
+ }
+ }
+ return value;
+ }
+
+ static var ERROR_POS_REGEX = ~/(\d+):(\d+): (.*)/g;
+ static var ERROR_REGEX = ~/ERROR: (\d+):(\d+): (.*)/g;
+ static var ERROR_REGEX_2 = ~/(\d+)\((\d+)\) : error ([^:]+): (.*)/g;
+ @:noCompletion private override function __createGLShader(source:String, type:Int):GLShader
+ {
+ var gl = __context.gl;
+
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+ var shaderInfoLog = gl.getShaderInfoLog(shader);
+ var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != "";
+ var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+
+ if (hasInfoLog || compileStatus == 0)
+ {
+ var isVertexShader = type == gl.VERTEX_SHADER;
+ var messageBuf = new StringBuf();
+ messageBuf.add((compileStatus == 0) ? "Error" : "Info");
+ if(isVertexShader) {
+ messageBuf.add(" compiling vertex shader");
+ if(vertFileName != null && vertFileName.length > 0) {
+ messageBuf.add(" (" + vertFileName + ")");
+ }
+ } else {
+ messageBuf.add(" compiling fragment shader");
+ if(fragFileName != null && fragFileName.length > 0) {
+ messageBuf.add(" (" + fragFileName + ")");
+ }
+ }
+ messageBuf.add("\n");
+ var errorPositions = [];
+ var regex = null;
+ var tmp = shaderInfoLog;
+ if(shaderInfoLog.contains(" : error ")) {
+ regex = ERROR_REGEX_2;
+
+ while(regex.match(tmp)) {
+ errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(4)));
+ tmp = regex.matchedRight();
+ }
+ } else if(shaderInfoLog.contains("ERROR: ")) {
+ regex = ERROR_REGEX;
+
+ while(regex.match(tmp)) {
+ errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
+ tmp = regex.matchedRight();
+ }
+ } else {
+ regex = ERROR_POS_REGEX;
+
+ while(regex.match(tmp)) {
+ errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
+ tmp = regex.matchedRight();
+ }
+ }
+ var splitSource = source.split("\n");
+ for(error in errorPositions) {
+ messageBuf.add("ERROR: Line: " + error.line);
+ if(error.column > 0) {
+ messageBuf.add(", Column: " + error.column);
+ }
+ messageBuf.add(", " + error.message);
+ if(error.line < splitSource.length) {
+ messageBuf.add("\nLine: ");
+ messageBuf.add(splitSource[error.line-1].trim());
+ }
+ messageBuf.add("\n\n");
+ }
+ var hasErrorPosition = errorPositions.length > 0;
+ if(hasErrorPosition) {
+ messageBuf.add("Raw shader info log:\n");
+ }
+ messageBuf.add(shaderInfoLog);
+ messageBuf.add("\n");
+ messageBuf.add(source);
+
+ var message = messageBuf.toString();
+ if (compileStatus == 0) Log.error(message);
+ else if (hasInfoLog) Log.debug(message);
+ }
+
+ return shader;
+ }
+
+ @:noCompletion private override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram
+ {
+ var program:GLProgram = null;
+ try
+ {
+ var gl = __context.gl;
+
+ var vertexShader = __createGLShader(vertexSource, gl.VERTEX_SHADER);
+ var fragmentShader = __createGLShader(fragmentSource, gl.FRAGMENT_SHADER);
+
+ program = gl.createProgram();
+
+ // Fix support for drivers that don't draw if attribute 0 is disabled
+ for (param in __paramFloat)
+ {
+ if (param.name.indexOf("Position") > -1 && StringTools.startsWith(param.name, "openfl_"))
+ {
+ gl.bindAttribLocation(program, 0, param.name);
+ break;
+ }
+ }
+
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+
+ if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0)
+ {
+ var messageBuf = new StringBuf();
+ messageBuf.add("Unable to initialize the shader program");
+ messageBuf.add("\n");
+ messageBuf.add(gl.getProgramInfoLog(program));
+ var message = messageBuf.toString();
+ Log.error(message);
+ }
+ }
+ catch (error:Dynamic)
+ {
+ Logs.traceColored([
+ Logs.logText('[Shader] ', BLUE),
+ Logs.logText('Failed to compile shader ${fileName}: ', RED),
+ Logs.logText(Std.string(error))
+ ], TRACE);
+ }
+ return program;
+
+ return program;
+ }
+
+ var glRawFragmentSource:String;
+ var glRawVertexSource:String;
+
@:noCompletion override private function set_glFragmentSource(value:String):String
{
if(value == null)
value = ShaderTemplates.defaultFragmentSource;
+ glRawFragmentSource = value;
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
+ value = processImports(value, FRAGMENT_SHADER);
if (value != __glFragmentSource)
{
__glSourceDirty = true;
@@ -55,7 +229,9 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
{
if(value == null)
value = ShaderTemplates.defaultVertexSource;
+ glRawVertexSource = value;
value = value.replace("#pragma header", ShaderTemplates.vertHeader).replace("#pragma body", ShaderTemplates.vertBody);
+ value = processImports(value, VERTEX_SHADER);
if (value != __glVertexSource)
{
__glSourceDirty = true;
@@ -64,6 +240,11 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
return __glVertexSource = value;
}
+ override function __updateGL():Void {
+ onGLUpdate.dispatch();
+ super.__updateGL();
+ }
+
@:noCompletion private override function __initGL():Void
{
if (__glSourceDirty || __paramBool == null)
@@ -83,23 +264,28 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
if (__context != null && program == null)
{
- var prefix = '#version ${glslVer}\n';
+ var prefixBuf = new StringBuf();
+ prefixBuf.add('#version ${glslVer}\n');
+ prefixBuf.add(shaderPrefix);
var gl = __context.gl;
- prefix += "#ifdef GL_ES
- "
- + (precisionHint == FULL ? "#ifdef GL_FRAGMENT_PRECISION_HIGH
- precision highp float;
- #else
- precision mediump float;
- #endif" : "precision lowp float;")
- + "
- #endif
- ";
+ prefixBuf.add("#ifdef GL_ES\n");
+ if (precisionHint == FULL) {
+ prefixBuf.add("#ifdef GL_FRAGMENT_PRECISION_HIGH\n");
+ prefixBuf.add("precision highp float;\n");
+ prefixBuf.add("#else\n");
+ prefixBuf.add("precision mediump float;\n");
+ prefixBuf.add("#endif\n");
+ } else {
+ prefixBuf.add("precision lowp float;\n");
+ }
+ prefixBuf.add("#endif\n");
- var vertex = prefix + glVertexSource;
- var fragment = prefix + glFragmentSource;
+ var prefix = prefixBuf.toString();
+
+ var vertex = prefix + vertexPrefix + glVertexSource;
+ var fragment = prefix + fragmentPrefix + glFragmentSource;
var id = vertex + fragment;
@@ -110,9 +296,7 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
else
{
program = __context.createProgram(GLSL);
-
program.__glProgram = __createGLProgram(vertex, fragment);
-
__context.__programs.set(id, program);
}
@@ -120,56 +304,35 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
{
glProgram = program.__glProgram;
- for (input in __inputBitmapData)
- {
+ for (input in __inputBitmapData) {
- if (input.__isUniform)
- {
+ if (input.__isUniform) {
input.index = gl.getUniformLocation(glProgram, input.name);
- }
- else
- {
+ } else {
input.index = gl.getAttribLocation(glProgram, input.name);
}
}
- for (parameter in __paramBool)
- {
-
- if (parameter.__isUniform)
- {
+ for (parameter in __paramBool) {
+ if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
- }
- else
- {
+ } else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
- for (parameter in __paramFloat)
- {
-
- if (parameter.__isUniform)
- {
+ for (parameter in __paramFloat) {
+ if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
- }
- else
- {
+ } else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
- for (parameter in __paramInt)
- {
-
- if (parameter.__isUniform)
- {
-
+ for (parameter in __paramInt) {
+ if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
- }
- else
- {
-
+ } else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
@@ -178,8 +341,12 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
}
}
+ var __cancelNextProcessGLData:Bool = false;
@:noCompletion private override function __processGLData(source:String, storageType:String):Void
{
+ onProcessGLData.dispatch(source, storageType);
+ if (__cancelNextProcessGLData != (__cancelNextProcessGLData = false))
+ return;
var lastMatch = 0, position, regex, name, type;
if (storageType == "uniform")
@@ -202,160 +369,146 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
}
var isUniform = (storageType == "uniform");
-
- if (StringTools.startsWith(type, "sampler"))
- {
- var input = new ShaderInput();
- input.name = name;
- @:privateAccess
- input.__isUniform = isUniform;
- __inputBitmapData.push(input);
-
- switch (name)
- {
- case "openfl_Texture":
- __texture = input;
- case "bitmap":
- __bitmap = input;
- default:
- }
-
- Reflect.setField(__data, name, input);
- try{Reflect.setField(this, name, input);} catch(e) {}
- }
- else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null)
- {
- var parameterType:ShaderParameterType = switch (type)
- {
- case "bool": BOOL;
- case "double", "float": FLOAT;
- case "int", "uint": INT;
- case "bvec2": BOOL2;
- case "bvec3": BOOL3;
- case "bvec4": BOOL4;
- case "ivec2", "uvec2": INT2;
- case "ivec3", "uvec3": INT3;
- case "ivec4", "uvec4": INT4;
- case "vec2", "dvec2": FLOAT2;
- case "vec3", "dvec3": FLOAT3;
- case "vec4", "dvec4": FLOAT4;
- case "mat2", "mat2x2": MATRIX2X2;
- case "mat2x3": MATRIX2X3;
- case "mat2x4": MATRIX2X4;
- case "mat3x2": MATRIX3X2;
- case "mat3", "mat3x3": MATRIX3X3;
- case "mat3x4": MATRIX3X4;
- case "mat4x2": MATRIX4X2;
- case "mat4x3": MATRIX4X3;
- case "mat4", "mat4x4": MATRIX4X4;
- default: null;
- }
-
- var length = switch (parameterType)
- {
- case BOOL2, INT2, FLOAT2: 2;
- case BOOL3, INT3, FLOAT3: 3;
- case BOOL4, INT4, FLOAT4, MATRIX2X2: 4;
- case MATRIX3X3: 9;
- case MATRIX4X4: 16;
- default: 1;
- }
-
- var arrayLength = switch (parameterType)
- {
- case MATRIX2X2: 2;
- case MATRIX3X3: 3;
- case MATRIX4X4: 4;
- default: 1;
- }
-
- switch (parameterType)
- {
- case BOOL, BOOL2, BOOL3, BOOL4:
- var parameter = new ShaderParameter();
- parameter.name = name;
- @:privateAccess
- parameter.type = parameterType;
- @:privateAccess
- parameter.__arrayLength = arrayLength;
- @:privateAccess
- parameter.__isBool = true;
- @:privateAccess
- parameter.__isUniform = isUniform;
- @:privateAccess
- parameter.__length = length;
- __paramBool.push(parameter);
-
- if (name == "openfl_HasColorTransform")
- {
- __hasColorTransform = parameter;
- }
-
- Reflect.setField(__data, name, parameter);
- try{Reflect.setField(this, name, parameter);} catch(e) {}
-
- case INT, INT2, INT3, INT4:
- var parameter = new ShaderParameter();
- parameter.name = name;
- @:privateAccess
- parameter.type = parameterType;
- @:privateAccess
- parameter.__arrayLength = arrayLength;
- @:privateAccess
- parameter.__isInt = true;
- @:privateAccess
- parameter.__isUniform = isUniform;
- @:privateAccess
- parameter.__length = length;
- @:privateAccess
- __paramInt.push(parameter);
- Reflect.setField(__data, name, parameter);
- try{Reflect.setField(this, name, parameter);} catch(e) {}
-
- default:
- var parameter = new ShaderParameter();
- parameter.name = name;
- @:privateAccess
- parameter.type = parameterType;
- @:privateAccess
- parameter.__arrayLength = arrayLength;
- #if lime
- @:privateAccess
- if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength);
- #end
- @:privateAccess
- parameter.__isFloat = true;
- @:privateAccess
- parameter.__isUniform = isUniform;
- @:privateAccess
- parameter.__length = length;
- __paramFloat.push(parameter);
-
- if (StringTools.startsWith(name, "openfl_"))
- {
- switch (name)
- {
- case "openfl_Alpha": __alpha = parameter;
- case "openfl_ColorMultiplier": __colorMultiplier = parameter;
- case "openfl_ColorOffset": __colorOffset = parameter;
- case "openfl_Matrix": __matrix = parameter;
- case "openfl_Position": __position = parameter;
- case "openfl_TextureCoord": __textureCoord = parameter;
- case "openfl_TextureSize": __textureSize = parameter;
- default:
- }
- }
-
- Reflect.setField(__data, name, parameter);
- try{Reflect.setField(this, name, parameter);} catch(e) {}
- }
- }
+ registerParameter(name, type, isUniform);
position = regex.matchedPos();
lastMatch = position.pos + position.len;
}
}
+ function registerParameter(name:String, type:String, isUniform:Bool):Void
+ {
+ if (StringTools.startsWith(type, "sampler"))
+ {
+ var input = new ShaderInput();
+ input.name = name;
+ input.__isUniform = isUniform;
+ __inputBitmapData.push(input);
+
+ switch (name)
+ {
+ case "openfl_Texture":
+ __texture = input;
+ case "bitmap":
+ __bitmap = input;
+ default:
+ }
+
+ Reflect.setField(__data, name, input);
+ try{Reflect.setField(this, name, input);} catch(e) {}
+ }
+ else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null)
+ {
+ var parameterType:ShaderParameterType = switch (type)
+ {
+ case "bool": BOOL;
+ case "double", "float": FLOAT;
+ case "int", "uint": INT;
+ case "bvec2": BOOL2;
+ case "bvec3": BOOL3;
+ case "bvec4": BOOL4;
+ case "ivec2", "uvec2": INT2;
+ case "ivec3", "uvec3": INT3;
+ case "ivec4", "uvec4": INT4;
+ case "vec2", "dvec2": FLOAT2;
+ case "vec3", "dvec3": FLOAT3;
+ case "vec4", "dvec4": FLOAT4;
+ case "mat2", "mat2x2": MATRIX2X2;
+ case "mat2x3": MATRIX2X3;
+ case "mat2x4": MATRIX2X4;
+ case "mat3x2": MATRIX3X2;
+ case "mat3", "mat3x3": MATRIX3X3;
+ case "mat3x4": MATRIX3X4;
+ case "mat4x2": MATRIX4X2;
+ case "mat4x3": MATRIX4X3;
+ case "mat4", "mat4x4": MATRIX4X4;
+ default: null;
+ }
+
+ var length = switch (parameterType)
+ {
+ case BOOL2, INT2, FLOAT2: 2;
+ case BOOL3, INT3, FLOAT3: 3;
+ case BOOL4, INT4, FLOAT4, MATRIX2X2: 4;
+ case MATRIX3X3: 9;
+ case MATRIX4X4: 16;
+ default: 1;
+ }
+
+ var arrayLength = switch (parameterType)
+ {
+ case MATRIX2X2: 2;
+ case MATRIX3X3: 3;
+ case MATRIX4X4: 4;
+ default: 1;
+ }
+
+ switch (parameterType)
+ {
+ case BOOL, BOOL2, BOOL3, BOOL4:
+ var parameter = new ShaderParameter();
+ parameter.name = name;
+ parameter.type = parameterType;
+ parameter.__arrayLength = arrayLength;
+ parameter.__isBool = true;
+ parameter.__isUniform = isUniform;
+ parameter.__length = length;
+ __paramBool.push(parameter);
+
+ if (name == "openfl_HasColorTransform")
+ {
+ __hasColorTransform = parameter;
+ }
+
+ Reflect.setField(__data, name, parameter);
+ try{Reflect.setField(this, name, parameter);} catch(e) {}
+
+ case INT, INT2, INT3, INT4:
+ var parameter = new ShaderParameter();
+ parameter.name = name;
+ parameter.type = parameterType;
+ parameter.__arrayLength = arrayLength;
+ parameter.__isInt = true;
+ parameter.__isUniform = isUniform;
+ parameter.__length = length;
+ __paramInt.push(parameter);
+ Reflect.setField(__data, name, parameter);
+ try{Reflect.setField(this, name, parameter);} catch(e) {}
+
+ default:
+ var parameter = new ShaderParameter();
+ parameter.name = name;
+ parameter.type = parameterType;
+ parameter.__arrayLength = arrayLength;
+ #if lime
+ if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength);
+ #end
+ parameter.__isFloat = true;
+ parameter.__isUniform = isUniform;
+ parameter.__length = length;
+ __paramFloat.push(parameter);
+
+ if (StringTools.startsWith(name, "openfl_"))
+ {
+ switch (name)
+ {
+ case "openfl_Alpha": __alpha = parameter;
+ case "openfl_ColorMultiplier": __colorMultiplier = parameter;
+ case "openfl_ColorOffset": __colorOffset = parameter;
+ case "openfl_Matrix": __matrix = parameter;
+ case "openfl_Position": __position = parameter;
+ case "openfl_TextureCoord": __textureCoord = parameter;
+ case "openfl_TextureSize": __textureSize = parameter;
+ default:
+ }
+ }
+
+ Reflect.setField(__data, name, parameter);
+ try{Reflect.setField(this, name, parameter);} catch(e) {}
+ }
+ }
+ }
+
public function hget(name:String):Dynamic {
if (__instanceFields.contains(name) || __instanceFields.contains('get_${name}'))
return Reflect.getProperty(this, name);
@@ -394,7 +547,6 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
var cl:String = Type.getClassName(Type.getClass(field));
// cant do "field is ShaderInput" for some reason
if (cl.startsWith("openfl.display.ShaderParameter")) {
- @:privateAccess
if (field.__length <= 1) {
if ((val is Array))
return field.value = val;
@@ -546,4 +698,16 @@ class ShaderTypeException extends Exception {
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
+}
+
+class ShaderErrorPosition {
+ public var column:Int;
+ public var line:Int;
+ public var message:String;
+
+ public function new(line:String, column:String, message:String) {
+ this.line = Std.parseInt(line);
+ this.column = Std.parseInt(column);
+ this.message = message;
+ }
}
\ No newline at end of file
diff --git a/source/funkin/backend/shaders/ScriptableShader.hx b/source/funkin/backend/shaders/ScriptableShader.hx
new file mode 100644
index 00000000..72a4a150
--- /dev/null
+++ b/source/funkin/backend/shaders/ScriptableShader.hx
@@ -0,0 +1,111 @@
+package funkin.backend.shaders;
+
+import hscript.IHScriptCustomBehaviour;
+import funkin.backend.scripting.events.shader.ShaderProcessEvent;
+import funkin.backend.scripting.ScriptPack;
+import funkin.backend.scripting.Script;
+
+@:structInit
+class FieldInfo {
+ public var get:Void->Dynamic;
+ public var set:Dynamic->Dynamic;
+}
+
+@:access(funkin.backend.shaders.FunkinShader)
+class ScriptableShader extends FlxBasic implements IHScriptCustomBehaviour {
+ private static var __instanceFields = Type.getInstanceFields(ScriptableShader);
+
+ public var shader:FunkinShader;
+ public var script:Script;
+
+ var fields:Map = [];
+
+ public function new(shader:FunkinShader, ?scriptName:String, ?parentScriptPack:ScriptPack) {
+ super();
+
+ if(parentScriptPack == null && PlayState.instance != null)
+ parentScriptPack = PlayState.instance.scripts;
+
+ if(scriptName == null)
+ if((shader is CustomShader)) scriptName = cast(shader, CustomShader).fileName;
+ else throw "Missing name for shader script, please provide a scriptName, or use CustomShader";
+
+ script = Script.create(Paths.script('shaders/$scriptName'));
+ script.setParent(shader);
+ script.set("shader", shader);
+ script.set("registerParameter", shader.registerParameter);
+ script.set("registerField", (name:String, get: Void->Dynamic, set: Dynamic->Dynamic) -> {
+ registerField(name, get, set);
+ });
+ script.set("registerShaderField", (name:String, shaderField:String) -> {
+ var get = () -> shader.hget(shaderField);
+ var set = (value:Dynamic) -> {
+ var val = shader.hset(shaderField, value);
+ script.set(name, val);
+ return val;
+ };
+ registerField(name, get, set);
+ var gg = script.get(name);
+ if(gg != null) {
+ shader.hset(shaderField, gg);
+ }
+ });
+ if(parentScriptPack != null)
+ script.setPublicMap(parentScriptPack.publicVariables);
+ script.load();
+ script.call("create");
+
+ shader.onGLUpdate.add(updateGL);
+ shader.onProcessGLData.add(processGLData);
+ }
+
+ function registerField(name:String, get: Void->Dynamic, set: Dynamic->Dynamic) {
+ fields.set(name, {
+ get: get,
+ set: set
+ });
+ script.set("get_"+name, get);
+ script.set("set_"+name, set);
+ }
+
+ public override function update(elapsed:Float) script.call("update", [elapsed]);
+ public override function draw() script.call("draw", []);
+ public function updateGL() script.call("updateGL", []);
+ public function processGLData(source:String, storageType:String) {
+ var event = EventManager.get(ShaderProcessEvent).recycle(source, storageType);
+ script.call("processGLData", [event]);
+ if(event.cancelled)
+ shader.__cancelNextProcessGLData = true;
+ script.call("processGLDataPost", [event]);
+ }
+
+ public override function destroy() {
+ shader.onGLUpdate.remove(updateGL);
+ shader.onProcessGLData.remove(processGLData);
+ if(script != null) {
+ script.call("destroy");
+ script.destroy();
+ }
+ fields = null;
+ super.destroy();
+ }
+
+ public function hget(name:String):Dynamic {
+ if(fields.exists(name))
+ return fields.get(name).get();
+ if (__instanceFields.contains(name) || __instanceFields.contains('get_${name}'))
+ return Reflect.getProperty(this, name);
+ return shader.hget(name);
+ }
+
+ public function hset(name:String, val:Dynamic):Dynamic {
+ if (fields.exists(name)) {
+ return fields.get(name).set(val);
+ }
+ if (__instanceFields.contains(name) || __instanceFields.contains('set_${name}')) {
+ Reflect.setProperty(this, name, val);
+ return val;
+ }
+ return shader.hset(name, val);
+ }
+}
\ No newline at end of file
diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx
index f9758b94..56dbfcd9 100644
--- a/source/funkin/backend/system/Conductor.hx
+++ b/source/funkin/backend/system/Conductor.hx
@@ -45,7 +45,7 @@ class Conductor
/**
* Number of steps per beat (bottom number in time signature). Defaults to 4.
*/
- public static var stepsPerBeat:Float = 4;
+ public static var stepsPerBeat:Int = 4;
/**
@@ -262,7 +262,7 @@ class Conductor
}
}
- public static function changeBPM(newBpm:Float, beatsPerMeasure:Float = 4, stepsPerBeat:Float = 4)
+ public static function changeBPM(newBpm:Float, beatsPerMeasure:Float = 4, stepsPerBeat:Int = 4)
{
bpm = newBpm;
diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx
index 3b03b561..5a09e333 100644
--- a/source/funkin/backend/system/Flags.hx
+++ b/source/funkin/backend/system/Flags.hx
@@ -2,7 +2,10 @@ package funkin.backend.system;
import lime.utils.AssetLibrary;
import lime.utils.AssetType;
+import flixel.util.FlxColor;
+import lime.app.Application;
+import funkin.backend.system.macros.GitCommitMacro;
import funkin.backend.assets.IModsAssetLibrary;
import funkin.backend.assets.ScriptedAssetLibrary;
@@ -11,6 +14,43 @@ import funkin.backend.assets.ScriptedAssetLibrary;
*/
@:build(funkin.backend.system.macros.FlagMacro.build())
class Flags {
+ // -- Codename's Default Flags --
+ public static var COMMIT_NUMBER:Int = GitCommitMacro.commitNumber;
+ public static var COMMIT_HASH:String = GitCommitMacro.commitHash;
+ public static var COMMIT_MESSAGE:String = 'Commit $COMMIT_NUMBER ($COMMIT_HASH)';
+ @:lazy public static var VERSION_MESSAGE:String = 'Codename Engine v${Application.current.meta.get('version')}';
+
+ public static var REPO_NAME:String = "CodenameEngine";
+ public static var REPO_OWNER:String = "FNF-CNE-Devs";
+ public static var REPO_URL:String = 'https://github.com/$REPO_OWNER/$REPO_NAME';
+
+ // make this empty once you guys are done with the project.
+ // good luck /gen <3 @crowplexus
+ public static var RELEASE_CYCLE:String = "Beta";
+
+ /**
+ * Preferred sound extension for the game's audio files.
+ * Currently is set to `mp3` for web targets, and `ogg` for other targets.
+ */
+ public static var SOUND_EXT:String = #if web "mp3" #else "ogg" #end; // we also support wav
+ public static var VIDEO_EXT:String = "mp4";
+ public static var IMAGE_EXT:String = "png"; // we also support jpg
+
+ public static var DEFAULT_DISCORD_LOGO_KEY:String = "icon";
+ public static var DEFAULT_DISCORD_CLIENT_ID:String = "1027994136193810442";
+ public static var DEFAULT_DISCORD_LOGO_TEXT:String = "Codename Engine";
+
+ @:also(funkin.game.Character.FALLBACK_CHARACTER)
+ public static var DEFAULT_CHARACTER:String = "bf";
+ public static var DEFAULT_GIRLFRIEND:String = "gf";
+ public static var DEFAULT_OPPONENT:String = "dad";
+
+ @:also(funkin.game.PlayState.difficulty)
+ public static var DEFAULT_DIFFICULTY:String = "normal";
+ public static var DEFAULT_STAGE:String = "stage";
+ public static var DEFAULT_SCROLL_SPEED:Float = 2.0;
+ public static var DEFAULT_HEALTH_ICON:String = "face";
+
public static var SONGS_LIST_MOD_MODE:Allow<"prepend", "override", "append"> = "override";
public static var WEEKS_LIST_MOD_MODE:Allow<"prepend", "override", "append"> = "override";
@@ -29,7 +69,89 @@ class Flags {
public static var WHITELISTED_LANGUAGES:Array = [];
// Internal stuff
+ public static var DEFAULT_BPM:Float = 100.0;
+ public static var DEFAULT_BEATS_PER_MEASURE:Float = 4;
+ public static var DEFAULT_STEPS_PER_BEAT:Int = 4;
+ public static var SUPPORTED_CHART_RUNTIME_FORMATS:Array = ["Legacy", "Psych Engine"];
+ public static var SUPPORTED_CHART_FORMATS:Array = ["BaseGame"];
+
+ public static var BASEGAME_SONG_METADATA_VERSION:String = "2.2.2";
+ public static var BASEGAME_SONG_CHART_DATA_VERSION:String = "2.0.0";
+ public static var BASEGAME_DEFAULT_NOTE_STYLE:String = 'funkin';
+ public static var BASEGAME_DEFAULT_ALBUM_ID:String = 'volume1';
+ public static var BASEGAME_DEFAULT_PREVIEW_START:Float = 0;
+ public static var BASEGAME_DEFAULT_PREVIEW_END:Float = 15000;
+
+ /**
+ * Default background colors for songs without bg color
+ */
+ public static var DEFAULT_COLOR:FlxColor = 0xFF9271FD;
+ public static var DEFAULT_COOP_ALLOWED:Bool = false;
+ public static var DEFAULT_OPPONENT_MODE_ALLOWED:Bool = false;
+
+ @:also(funkin.game.PlayState.coopMode)
+ public static var DEFAULT_COOP_MODE:Bool = false; // used in playstate if it doesnt find it
+ @:also(funkin.game.PlayState.opponentMode)
+ public static var DEFAULT_OPPONENT_MODE:Bool = false;
+
+ public static var DEFAULT_NOTE_MS_LIMIT:Float = 1500;
+ public static var DEFAULT_NOTE_SCALE:Float = 0.7;
+
+ @:also(funkin.game.Character.FALLBACK_DEAD_CHARACTER)
+ public static var DEFAULT_GAMEOVER_CHARACTER:String = "bf-dead";
+ public static var DEFAULT_GAMEOVER_SONG:String = "gameOver";
+ public static var DEFAULT_GAMEOVER_LOSS_SFX:String = "gameOverSFX";
+ public static var DEFAULT_GAMEOVER_RETRY_SFX:String = "gameOverEnd";
+
+ public static var DEFAULT_CAM_ZOOM_INTERVAL:Int = 4;
+ public static var DEFAULT_CAM_ZOOM_STRENGTH:Int = 1;
+ public static var DEFAULT_CAM_ZOOM:Float = 1.05; // what zoom level it defaults to
+ public static var DEFAULT_HUD_ZOOM:Float = 1.0;
+ public static var MAX_CAMERA_ZOOM:Float = 1.35;
+
+ public static var DEFAULT_PAUSE_ITEMS:Array = ['Resume', 'Restart Song', 'Change Controls', 'Change Options', 'Exit to menu', "Exit to charter"];
+ public static var DEFAULT_CUTSCENE_PAUSE_ITEMS:Array = ['Resume Cutscene', 'Skip Cutscene', 'Restart Cutscene', 'Exit to menu'];
+ public static var DEFAULT_GITAROO:Bool = true;
+ public static var GITAROO_CHANCE:Float = 0.1;
+ public static var DEFAULT_CAN_ACCESS_DEBUG_MENUS:Bool = true;
+ public static var DEFAULT_MUTE_VOCALS_ON_MISS:Bool = true;
+
+ public static var DEFAULT_MAX_HEALTH:Float = 2.0;
+ public static var DEFAULT_HEALTH:Null = null;//DEFAULT_MAX_HEALTH / 2.0;
+ public static var BOP_ICON_SCALE:Float = 1.2;
+ public static var ICON_OFFSET:Float = 26;
+ public static var ICON_LERP:Float = 0.33;
+
+ public static var CAM_BOP_STRENGTH:Float = 0.015;
+ public static var HUD_BOP_STRENGTH:Float = 0.03;
+ public static var DEFAULT_CAM_ZOOM_LERP:Float = 0.05;
+ public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05;
+
+ public static var MAX_SPLASHES:Int = 8;
+ public static var STUNNED_TIME:Float = 5 / 60;
+
+ @:also(funkin.game.PlayState.daPixelZoom)
+ public static var PIXEL_ART_SCALE:Float = 6.0;
+
+ public static var DEFAULT_COMBO_GROUP_MAX_SIZE:Int = 25;
+
+ public static var DEFAULT_STRUM_AMOUNT:Int = 4;
+ public static var DEFAULT_CAMERA_FOLLOW_SPEED:Float = 0.04;
+
+ public static var VOCAL_OFFSET_VIOLATION_THRESHOLD:Float = 25;
+
+ // Usage: Codename Credits
+ public static var MAIN_DEVS_COLOR:FlxColor = 0xFF9C35D5;
+ public static var MIN_CONTRIBUTIONS_COLOR:FlxColor = 0xFFB4A7DA;
+
+ public static var UNDO_PREFIX:String = "* ";
+ public static var JSON_PRETTY_PRINT:String = "\t";
+ // -- End of Codename's Default Flags --
+
+ /**
+ * Flags that Codename couldn't recognize as it's own defaults (they can only be `string`!).
+ */
@:bypass public static var customFlags:Map = [];
public static function load() {
diff --git a/source/funkin/backend/system/Main.hx b/source/funkin/backend/system/Main.hx
index 7744cc90..ce553d2a 100644
--- a/source/funkin/backend/system/Main.hx
+++ b/source/funkin/backend/system/Main.hx
@@ -29,10 +29,6 @@ import android.os.Build;
class Main extends Sprite
{
- // make this empty once you guys are done with the project.
- // good luck /gen <3 @crowplexus
- public static final releaseCycle:String = "Beta";
-
public static var instance:Main;
public static var modToLoad:String = null;
@@ -128,6 +124,9 @@ class Main extends Sprite
ShaderResizeFix.init();
Logs.init();
Paths.init();
+
+ hscript.Interp.importRedirects = funkin.backend.scripting.Script.getDefaultImportRedirects();
+
#if GLOBAL_SCRIPT
funkin.backend.scripting.GlobalScript.init();
#end
@@ -149,7 +148,7 @@ class Main extends Sprite
Assets.registerLibrary('default', lib);
funkin.options.PlayerSettings.init();
- funkin.savedata.FunkinSave.init();
+ funkin.backend.utils.FunkinSave.init();
Options.load();
FlxG.fixedTimestep = false;
@@ -172,15 +171,22 @@ class Main extends Sprite
initTransition();
}
- public static function refreshAssets() {
+ public static function refreshAssets() @:privateAccess {
WindowUtils.resetTitle();
- FlxSoundTray.volumeChangeSFX = Paths.sound('menu/volume');
- FlxSoundTray.volumeUpChangeSFX = null;
- FlxSoundTray.volumeDownChangeSFX = null;
+ var game = FlxG.game;
+ var daSndTray = Type.createInstance(game._customSoundTray = funkin.menus.ui.FunkinSoundTray, []);
+ var index:Int = game.numChildren - 1;
- if (FlxG.game.soundTray != null)
- FlxG.game.soundTray.text.setTextFormat(new TextFormat(Paths.font("vcr.ttf")));
+ if(game.soundTray != null)
+ {
+ var newIndex:Int = game.getChildIndex(game.soundTray);
+ if(newIndex != -1) index = newIndex;
+ game.removeChild(game.soundTray);
+ game.soundTray.__cleanup();
+ }
+
+ game.addChildAt(game.soundTray = daSndTray, index);
}
public static function initTransition() {
diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx
index 47a3fc33..f2000c9b 100644
--- a/source/funkin/backend/system/MainState.hx
+++ b/source/funkin/backend/system/MainState.hx
@@ -18,8 +18,10 @@ class MainState extends FlxState {
public static var betaWarningShown:Bool = false;
public override function create() {
super.create();
- if (!initiated)
+ if (!initiated) {
Main.loadGameSettings();
+ }
+
initiated = true;
#if sys
@@ -54,11 +56,11 @@ class MainState extends FlxState {
}
#end
- Main.refreshAssets();
- ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
Flags.load();
TranslationUtil.findAllLanguages();
TranslationUtil.setLanguage();
+ ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder); // Loads global.hx
+ Main.refreshAssets();
DiscordUtil.init();
EventsData.reloadEvents();
TitleState.initialized = false;
diff --git a/source/funkin/backend/system/framerate/CodenameBuildField.hx b/source/funkin/backend/system/framerate/CodenameBuildField.hx
index 5519f4d8..aa7a9b7b 100644
--- a/source/funkin/backend/system/framerate/CodenameBuildField.hx
+++ b/source/funkin/backend/system/framerate/CodenameBuildField.hx
@@ -13,5 +13,5 @@ class CodenameBuildField extends TextField {
}
public function reload()
- text = 'Codename Engine ${Main.releaseCycle}\nCommit ${GitCommitMacro.commitNumber} (${GitCommitMacro.commitHash})';
+ text = 'Codename Engine ${Flags.RELEASE_CYCLE}\n${Flags.COMMIT_MESSAGE}';
}
diff --git a/source/funkin/backend/system/github/GitHub.hx b/source/funkin/backend/system/github/GitHub.hx
index 515e2f63..ce7e61dc 100644
--- a/source/funkin/backend/system/github/GitHub.hx
+++ b/source/funkin/backend/system/github/GitHub.hx
@@ -83,7 +83,7 @@ class GitHub {
* @param onError Error Callback
* @return Members List
*/
- public static function getOrganizationMembers(org:String, ?onError:Exception->Void):Array {
+ public static function getOrganizationMembers(org:String, ?onError:Exception->Void):Array {
#if GITHUB_API
try {
var data = Json.parse(HttpUtil.requestText('https://api.github.com/orgs/$org/members'));
@@ -106,7 +106,7 @@ class GitHub {
* @param onError Error Callback
* @return User/Organization
*/
- public static function getUser(user:String, ?onError:Exception->Void):GitHubUser {
+ public static function getUser(user:String, ?onError:Exception->Void):GitHubUser {
#if GITHUB_API
try {
var url = 'https://api.github.com/users/$user';
diff --git a/source/funkin/backend/system/macros/BuildInfo.hx b/source/funkin/backend/system/macros/BuildInfo.hx
index 733d11cd..193d3bb9 100644
--- a/source/funkin/backend/system/macros/BuildInfo.hx
+++ b/source/funkin/backend/system/macros/BuildInfo.hx
@@ -11,8 +11,16 @@ class BuildInfo {
Sys.println('Haxe Version: ${haxeVersion}');
try {
var lastBuiltWith:Null = null;
- var compiling = #if final "final" #elseif debug "debug" #else "release" #end;
- var target = #if windows "windows" #elseif mac "macos" #elseif linux "linux" #elseif android "android" #elseif ios "ios" #elseif html5 "html5" #else "" #end;
+ var compiling = #if final "release" #elseif debug "debug" #else "release" #end;
+ var target = #if hl "hl"
+ #elseif html5 "html5"
+ #elseif ios "ios"
+ #elseif android "android"
+ #elseif windows "windows"
+ #elseif (mac || macos) "macos"
+ #elseif linux "linux"
+ #else ""
+ #end;
if(target == "") throw "Unknown target";
var exportPath = Sys.getCwd() + "/export/" + compiling + "/" + target + "/";
exportPath += "obj/Options.txt";
@@ -25,18 +33,22 @@ class BuildInfo {
}
}
- if(lastBuiltWith != null && lastBuiltWith != haxeVersion)
+ if(lastBuiltWith != null && lastBuiltWith.length > 0 && lastBuiltWith != haxeVersion)
Sys.println('Last Built With Haxe: ${lastBuiltWith} [!!!! MAKE SURE IF YOU SWITCHED VERSIONS YOU DELETE EXPORT FOLDERS !!!!]');
} catch(e) {}
- Sys.println('Target Platform: ${
- #if windows "Windows"
- #elseif mac "Mac"
- #elseif linux "Linux"
- #elseif android "Android"
+ var targetPlatform = #if html5 "Web (HTML5)"
#elseif ios "iOS"
+ #elseif android "Android"
+ #elseif windows "Windows"
+ #elseif (mac || macos) "Mac"
+ #elseif linux "Linux"
#else "Unknown"
- #end
- }');
+ #end;
+
+ if(haxe.macro.Context.defined("hl")) {
+ targetPlatform = "Hashlink (" + targetPlatform + ")";
+ }
+ Sys.println('Target Platform: ' + targetPlatform);
Sys.println('Build Date: ${Date.now().toString()}');
Sys.println('');
}
diff --git a/source/funkin/backend/system/macros/FlagMacro.macro.hx b/source/funkin/backend/system/macros/FlagMacro.macro.hx
index 3f827d7b..d18c10d1 100644
--- a/source/funkin/backend/system/macros/FlagMacro.macro.hx
+++ b/source/funkin/backend/system/macros/FlagMacro.macro.hx
@@ -7,7 +7,18 @@ using StringTools;
using haxe.macro.Tools;
+using funkin.backend.system.macros.FlagMacro;
+
class FlagMacro {
+ private static function hasMeta(meta:Array, name:String):Bool {
+ for(m in meta) {
+ if(m.name == name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static function build():Array {
var fields = Context.getBuildFields();
@@ -21,26 +32,50 @@ class FlagMacro {
var parserExprs:Array = [];
for (field in fields) {
- var skip = false;
- for(meta in field.meta) {
- if(meta.name == ":bypass") {
- skip = true;
- break;
- }
- }
+ var skip = field.meta.hasMeta(":bypass");
+ var hasLazy = field.meta.hasMeta(":lazy");
if(skip) continue;
switch (field.kind) {
case FVar(type, expr):
+ var isNullable = false;
+ switch(type) {
+ case TPath({name: "Null", pack: [], params: [TPType(p)]}):
+ type = p;
+ isNullable = true;
+ default:
+ }
+
+ var alsos:Array = [];
+ for(meta in field.meta) {
+ if(meta.name == ":also") {
+ for(param in meta.params) {
+ switch(param.expr) {
+ case EField(_, _):
+ alsos.push(param);
+ default:
+ Context.error("Invalid :also parameter", param.pos);
+ }
+ }
+ }
+ }
+
if(expr == null)
Context.error('Flag ' + field.name + ' must have a default value', field.pos);
- switch(expr.expr) {
- case EConst(CIdent("true")) | EConst(CIdent("false")):
- type = macro: Bool;
- default:
- if(type == null)
+ if(type == null) {
+ switch(expr.expr) {
+ case EConst(CIdent("true")) | EConst(CIdent("false")):
+ type = macro: Bool;
+ case EConst(CInt(_)):
+ type = macro: Int;
+ case EConst(CFloat(_)):
+ type = macro: Float;
+ case EConst(CString(_)):
+ type = macro: String;
+ default:
Context.error('Flag ' + field.name + ' must have a type', field.pos);
+ }
}
var parser:Expr = null;
@@ -52,7 +87,7 @@ class FlagMacro {
parser = macro value.split(",").map((e) -> e.trim());
case macro: Array:
parser = macro value.split(",");
- case macro: Array:
+ case (macro: Array) | (macro: Array):
parser = macro value.split(",").map((e) -> Std.parseInt(e));
case macro: Array:
parser = macro value.split(",").map((e) -> Std.parseFloat(e));
@@ -61,12 +96,15 @@ class FlagMacro {
e = e.trim();
e == "true" || e == "t" || e == "1";
});
- case macro: Int:
+ case macro: TrimmedString:
+ field.kind = FVar(macro: String, expr);
+ parser = macro value.trim();
+ case macro: String:
+ parser = macro value;
+ case (macro: Int) | (macro: FlxColor):
parser = macro Std.parseInt(value);
case macro: Float:
parser = macro Std.parseFloat(value);
- case macro: String:
- parser = macro value;
case macro: Bool:
parser = macro value == "true" || value == "t" || value == "1";
case TPath({name: "Allow", pack: [], params: params}):
@@ -128,8 +166,7 @@ class FlagMacro {
if(chosenType == STRING) {
parser = macro value;
field.kind = FVar(macro: String, expr);
- }
- else if(chosenType == INT) {
+ } else if(chosenType == INT) {
parser = macro Std.parseInt(value);
field.kind = FVar(macro: Int, expr);
} else {
@@ -147,7 +184,7 @@ class FlagMacro {
}
case TPath({name: "Array", pack: []}):
- Context.error("Flag " + field.name + " cannot be an Array that isnt a String or Bool or TrimmedString", field.pos);
+ Context.error("Flag " + field.name + " cannot be an Array that isnt a String or Bool or TrimmedString or Int or Float", field.pos);
case TPath({name: "Map", pack: []}):
Context.error("Flag " + field.name + " cannot be a Map", field.pos);
default:
@@ -159,6 +196,14 @@ class FlagMacro {
continue;
}
+ if(isNullable) {
+ switch(field.kind) {
+ case FVar(t, e):
+ field.kind = FVar(TPath({name: "Null", pack: [], params: [TPType(t)]}), e);
+ default:
+ }
+ }
+
resetExprs.push(macro $i{field.name} = ${expr});
// parse(name: String, value: String)
@@ -166,16 +211,39 @@ class FlagMacro {
if(customCheck != null) {
parserExprs.push(customCheck);
} else {
- parserExprs.push(macro @:mergeBlock {
- if(name == $v{field.name}) {
- $i{field.name} = $parser;
- return true;
- }
- });
+ var alsoExpr = alsos.length > 0 ? macro @:mergeBlock $b{alsos.map((e) -> return macro $e = val)} : macro {};
+
+ if(isNullable) {
+ parserExprs.push(macro @:mergeBlock {
+ if(name == $v{field.name}) {
+ var val = value == "NULL" ? null : $parser;
+ $i{field.name} = val;
+ $alsoExpr;
+ return true;
+ }
+ });
+ } else {
+ parserExprs.push(macro @:mergeBlock {
+ if(name == $v{field.name}) {
+ var val = $parser;
+ $i{field.name} = val;
+ $alsoExpr;
+ return true;
+ }
+ });
+ }
}
default:
// nothing
}
+
+ if(hasLazy) {
+ switch(field.kind) {
+ case FVar(t, expr):
+ field.kind = FVar(t, null);
+ default:
+ }
+ }
}
fields.push({
@@ -209,6 +277,9 @@ class FlagMacro {
});
//var printer = new haxe.macro.Printer();
+ //for(field in fields) {
+ // trace(printer.printField(field));
+ //}
//trace(printer.printField(fields[fields.length - 2]));
//trace(printer.printField(fields[fields.length - 1]));
diff --git a/source/funkin/backend/system/updating/UpdateScreen.hx b/source/funkin/backend/system/updating/UpdateScreen.hx
index 66d02394..60ed6506 100644
--- a/source/funkin/backend/system/updating/UpdateScreen.hx
+++ b/source/funkin/backend/system/updating/UpdateScreen.hx
@@ -56,7 +56,7 @@ class UpdateScreen extends MusicBeatState {
generalProgress.alignment = CENTER;
add(generalProgress);
- overSound = FlxG.sound.load(Paths.sound('gameOverEnd'));
+ overSound = FlxG.sound.load(Paths.sound(Flags.DEFAULT_GAMEOVER_RETRY_SFX));
updater.execute();
diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx
index 36342c67..f7db98eb 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -153,11 +153,15 @@ class CoolUtil
* @return The attributes through the `FileAttributeWrapper`
*/
@:noUsing public static inline function safeGetAttributes(path:String, useAbsol:Bool = true):FileAttributeWrapper {
+ #if sys
addMissingFolders(Path.directory(path));
var result = NativeAPI.getFileAttributes(path, useAbsol);
if(result.isNothing) Logs.trace('The file where it has been tried to get the attributes from, might be corrupted or inexistent (code: ${result.getValue()})', WARNING);
return result;
+ #else
+ return 0;
+ #end
}
/**
@@ -170,11 +174,15 @@ class CoolUtil
*/
@:noUsing public static inline function safeSetAttributes(path:String, attrib:OneOfThree, useAbsol:Bool = true):Int {
// yes, i'm aware that FileAttribute is also an Int so need to include it too, but at least like this we don't have to make cast sometimes while passing the arguments - Nex
+ #if sys
addMissingFolders(Path.directory(path));
var result = NativeAPI.setFileAttributes(path, attrib, useAbsol);
if(result == 0) Logs.trace('Failed to set attributes to $path with a code of: $result', WARNING);
return result;
+ #else
+ return 0;
+ #end
}
/**
@@ -186,11 +194,15 @@ class CoolUtil
* @return The result code: `0` means that it failed setting
*/
@:noUsing public static inline function safeAddAttributes(path:String, attrib:OneOfTwo, useAbsol:Bool = true):Int {
+ #if sys
addMissingFolders(Path.directory(path));
var result = NativeAPI.addFileAttributes(path, attrib, useAbsol);
if(result == 0) Logs.trace('Failed to add attributes to $path with a code of: $result', WARNING);
return result;
+ #else
+ return 0;
+ #end
}
/**
@@ -202,11 +214,15 @@ class CoolUtil
* @return The result code: `0` means that it failed setting
*/
@:noUsing public static inline function safeRemoveAttributes(path:String, attrib:OneOfTwo, useAbsol:Bool = true):Int {
+ #if sys
addMissingFolders(Path.directory(path));
var result = NativeAPI.removeFileAttributes(path, attrib, useAbsol);
if(result == 0) Logs.trace('Failed to remove attributes to $path with a code of: $result', WARNING);
return result;
+ #else
+ return 0;
+ #end
}
/**
@@ -433,7 +449,7 @@ class CoolUtil
* @param Looped Whenever the music loops (true)
* @param Group A group that this music belongs to (default)
*/
- @:noUsing public static function playMusic(path:String, Persist:Bool = false, Volume:Int = 1, Looped:Bool = true, DefaultBPM:Int = 102, ?Group:FlxSoundGroup) {
+ @:noUsing public static function playMusic(path:String, Persist:Bool = false, Volume:Int = 1, Looped:Bool = true, DefaultBPM:Float = 102, ?Group:FlxSoundGroup) {
Conductor.reset();
FlxG.sound.playMusic(path, Volume, Looped, Group);
if (FlxG.sound.music != null) {
@@ -444,17 +460,17 @@ class CoolUtil
if (Assets.exists(infoPath)) {
var musicInfo = IniUtil.parseAsset(infoPath, [
"BPM" => null,
- "TimeSignature" => "4/4"
+ "TimeSignature" => Flags.DEFAULT_BEATS_PER_MEASURE + "/" + Flags.DEFAULT_STEPS_PER_BEAT
]);
var timeSignParsed:Array> = musicInfo["TimeSignature"] == null ? [] : [for(s in musicInfo["TimeSignature"].split("/")) Std.parseFloat(s)];
- var beatsPerMeasure:Float = 4;
- var stepsPerBeat:Float = 4;
+ var beatsPerMeasure:Float = Flags.DEFAULT_BEATS_PER_MEASURE;
+ var stepsPerBeat:Int = Flags.DEFAULT_STEPS_PER_BEAT;
// Check later, i dont think timeSignParsed can contain null, only nan
if (timeSignParsed.length == 2 && !timeSignParsed.contains(null)) {
- beatsPerMeasure = timeSignParsed[0] == null || timeSignParsed[0] <= 0 ? 4 : cast timeSignParsed[0];
- stepsPerBeat = timeSignParsed[1] == null || timeSignParsed[1] <= 0 ? 4 : cast timeSignParsed[1];
+ beatsPerMeasure = timeSignParsed[0] == null || timeSignParsed[0] <= 0 ? Flags.DEFAULT_BEATS_PER_MEASURE : cast timeSignParsed[0];
+ stepsPerBeat = timeSignParsed[1] == null || timeSignParsed[1] <= 0 ? Flags.DEFAULT_STEPS_PER_BEAT : cast timeSignParsed[1];
}
var bpm:Null = Std.parseFloat(musicInfo["BPM"]).getDefaultFloat(DefaultBPM);
diff --git a/source/funkin/backend/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx
index 20b58da2..42735a9c 100644
--- a/source/funkin/backend/utils/DiscordUtil.hx
+++ b/source/funkin/backend/utils/DiscordUtil.hx
@@ -5,7 +5,7 @@ import flixel.sound.FlxSound;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.scripting.*; // lazy
import funkin.backend.scripting.events.CancellableEvent;
-import funkin.backend.scripting.events.DiscordPresenceUpdateEvent;
+import funkin.backend.scripting.events.discord.*;
import funkin.backend.system.macros.Utils;
import haxe.Json;
import openfl.display.BitmapData;
@@ -86,9 +86,9 @@ class DiscordUtil
if (config == null)
config = {};
- config.logoKey = config.logoKey.getDefault("icon");
- config.logoText = config.logoText.getDefault(Application.current.meta.get('title'));
- config.clientID = config.clientID.getDefault("1027994136193810442");
+ config.logoKey = config.logoKey.getDefault(Flags.DEFAULT_DISCORD_LOGO_KEY);
+ config.logoText = config.logoText.getDefault(Flags.DEFAULT_DISCORD_LOGO_TEXT);
+ config.clientID = config.clientID.getDefault(Flags.DEFAULT_DISCORD_CLIENT_ID);
currentID = config.clientID;
#end
}
diff --git a/source/funkin/savedata/FunkinSave.hx b/source/funkin/backend/utils/FunkinSave.hx
similarity index 99%
rename from source/funkin/savedata/FunkinSave.hx
rename to source/funkin/backend/utils/FunkinSave.hx
index b2df2242..3dbfcf2e 100644
--- a/source/funkin/savedata/FunkinSave.hx
+++ b/source/funkin/backend/utils/FunkinSave.hx
@@ -1,4 +1,4 @@
-package funkin.savedata;
+package funkin.backend.utils;
import flixel.util.FlxSave;
import lime.app.Application;
diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx
index 5448ef11..87b76b35 100644
--- a/source/funkin/backend/utils/XMLUtil.hx
+++ b/source/funkin/backend/utils/XMLUtil.hx
@@ -147,6 +147,8 @@ class XMLUtil {
var graphicSizey:Null = Std.parseInt(node.att.graphicSizey);
if (graphicSizey.isNotNull()) spr.setGraphicSize(0, graphicSizey);
}
+
+ if (node.has.flipX && node.att.flipX == "true") spr.flipX = true;
if (node.has.updateHitbox && node.att.updateHitbox == "true") spr.updateHitbox();
if (node.has.zoomfactor)
diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx
index 9d9e80d9..460767c7 100644
--- a/source/funkin/editors/character/CharacterEditor.hx
+++ b/source/funkin/editors/character/CharacterEditor.hx
@@ -324,7 +324,7 @@ class CharacterEditor extends UIState {
characterBG.scale.set(FlxG.width/characterBG.width, FlxG.height/characterBG.height);
characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom);
- WindowUtils.prefix = undos.unsaved ? "* " : "";
+ WindowUtils.prefix = undos.unsaved ? Flags.UNDO_PREFIX : "";
SaveWarning.showWarning = undos.unsaved;
}
@@ -364,7 +364,7 @@ class CharacterEditor extends UIState {
]);
// clean
- if (charXML.exists("gameOverChar") && character.gameOverCharacter == "bf-dead") charXML.remove("gameOverChar");
+ if (charXML.exists("gameOverChar") && character.gameOverCharacter == Flags.DEFAULT_GAMEOVER_CHARACTER) charXML.remove("gameOverChar");
if (charXML.exists("camx") && character.cameraOffset.x == 0) charXML.remove("camx");
if (charXML.exists("camy") && character.cameraOffset.y == 0) charXML.remove("camy");
if (charXML.exists("holdTime") && character.holdTime == 4) charXML.remove("holdTime");
diff --git a/source/funkin/editors/character/CharacterInfoScreen.hx b/source/funkin/editors/character/CharacterInfoScreen.hx
index 1997a5cd..f993d210 100644
--- a/source/funkin/editors/character/CharacterInfoScreen.hx
+++ b/source/funkin/editors/character/CharacterInfoScreen.hx
@@ -151,7 +151,7 @@ class CharacterInfoScreen extends UISubstateWindow {
@:privateAccess iconSprite.animation.clearAnimations();
var path:String = Paths.image('icons/$icon');
- if (!Assets.exists(path)) path = Paths.image('icons/face');
+ if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
iconSprite.loadGraphic(path, true, 150, 150);
iconSprite.animation.add(icon, [0], 0, false);
diff --git a/source/funkin/editors/charter/ChartCreationScreen.hx b/source/funkin/editors/charter/ChartCreationScreen.hx
index f634bdff..5067d728 100644
--- a/source/funkin/editors/charter/ChartCreationScreen.hx
+++ b/source/funkin/editors/charter/ChartCreationScreen.hx
@@ -73,7 +73,7 @@ class ChartCreationScreen extends UISubstateWindow {
strumLineList.addButton.callback = function() {
strumLineList.add(new StrumLineButton(strumLineList.buttons.length, {
- characters: ["dad"],
+ characters: [Flags.DEFAULT_OPPONENT],
type: 0,
notes: null,
position: "DAD",
@@ -84,7 +84,7 @@ class ChartCreationScreen extends UISubstateWindow {
// DEFAULTS
strumLineList.add(new StrumLineButton(0, {
- characters: ["dad"],
+ characters: [Flags.DEFAULT_OPPONENT],
type: 0,
notes: null,
position: "DAD",
@@ -93,7 +93,7 @@ class ChartCreationScreen extends UISubstateWindow {
scrollSpeed: 1,
}, strumLineList));
strumLineList.add(new StrumLineButton(1, {
- characters: ["bf"],
+ characters: [Flags.DEFAULT_CHARACTER],
type: 1,
notes: null,
position: "BOYFRIEND",
@@ -102,7 +102,7 @@ class ChartCreationScreen extends UISubstateWindow {
scrollSpeed: 1,
}, strumLineList));
strumLineList.add(new StrumLineButton(2, {
- characters: ["gf"],
+ characters: [Flags.DEFAULT_GIRLFRIEND],
type: 2,
notes: null,
position: "GIRLFRIEND",
@@ -334,7 +334,7 @@ class CompactCharacterButton extends UIButton {
char = funkin.game.Character.getIconFromCharName(char);
var image = Paths.image("icons/" + char);
if(!Assets.exists(image))
- image = Paths.image("icons/face");
+ image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
charIcon.loadGraphic(image, true, 150, 150);
charIcon.updateHitbox();
}
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index b7f5aa7a..6852beb6 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -1255,7 +1255,7 @@ class Charter extends UIState {
if (strumLines != null)
strumlineLockButton.button.animation.play(strumLines.draggable ? "1" : "0", true);
- WindowUtils.prefix = undos.unsaved ? "* " : "";
+ WindowUtils.prefix = undos.unsaved ? Flags.UNDO_PREFIX : "";
SaveWarning.showWarning = undos.unsaved;
__firstFrame = false;
@@ -1307,7 +1307,7 @@ class Charter extends UIState {
}
function _file_saveas(_) {
- openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false), null, Options.editorPrettyPrint ? "\t" : null), {
+ openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false), null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null), {
defaultSaveFile: '${__diff.toLowerCase()}.json'
}));
undos.save();
@@ -1323,7 +1323,7 @@ class Charter extends UIState {
}
function _file_saveas_no_events(_) {
- openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false), null, Options.editorPrettyPrint ? "\t" : null), {
+ openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false), null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null), {
defaultSaveFile: '${__diff.toLowerCase()}.json'
}));
undos.save();
@@ -1333,7 +1333,7 @@ class Charter extends UIState {
#if sys
CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/meta.json',
- Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, "\t")
+ Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, Flags.JSON_PRETTY_PRINT)
);
#else
_file_meta_saveas(_);
@@ -1341,20 +1341,20 @@ class Charter extends UIState {
}
function _file_meta_saveas(_) {
- openSubState(new SaveSubstate(Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, "\t"), { // always pretty print meta
+ openSubState(new SaveSubstate(Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, Flags.JSON_PRETTY_PRINT), { // always pretty print meta
defaultSaveFile: 'meta.json'
}));
}
function _file_saveas_fnflegacy(_) {
- openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
- defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
+ openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null), {
+ defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == Flags.DEFAULT_DIFFICULTY ? "" : '-${__diff.toLowerCase()}'}.json',
}));
}
function _file_saveas_psych(_) {
- openSubState(new SaveSubstate(Json.stringify(PsychParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
- defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
+ openSubState(new SaveSubstate(Json.stringify(PsychParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null), {
+ defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == Flags.DEFAULT_DIFFICULTY ? "" : '-${__diff.toLowerCase()}'}.json',
}));
}
@@ -1362,7 +1362,7 @@ class Charter extends UIState {
#if sys
CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json',
- Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null)
+ Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null)
);
#else
_file_events_saveas(_);
@@ -1371,7 +1371,7 @@ class Charter extends UIState {
function _file_events_saveas(_) {
#if sys
- openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null), {
+ openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? Flags.JSON_PRETTY_PRINT : null), {
defaultSaveFile: 'events.json'
}));
#end
diff --git a/source/funkin/editors/charter/CharterMetaDataScreen.hx b/source/funkin/editors/charter/CharterMetaDataScreen.hx
index ab3c0638..0ebd697d 100644
--- a/source/funkin/editors/charter/CharterMetaDataScreen.hx
+++ b/source/funkin/editors/charter/CharterMetaDataScreen.hx
@@ -132,7 +132,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
@:privateAccess iconSprite.animation.clearAnimations();
var path:String = Paths.image('icons/$icon');
- if (!Assets.exists(path)) path = Paths.image('icons/face');
+ if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
iconSprite.loadGraphic(path, true, 150, 150);
iconSprite.animation.add(icon, [0], 0, false);
diff --git a/source/funkin/editors/charter/CharterSelection.hx b/source/funkin/editors/charter/CharterSelection.hx
index 3f3ae6f6..ea404e18 100644
--- a/source/funkin/editors/charter/CharterSelection.hx
+++ b/source/funkin/editors/charter/CharterSelection.hx
@@ -111,9 +111,9 @@ class CharterSelection extends EditorTreeMenu {
sys.FileSystem.createDirectory('$songFolder/charts');
// Save Files
- CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, "\t"));
- if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Paths.SOUND_EXT}', creation.instBytes);
- if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Paths.SOUND_EXT}', creation.voicesBytes);
+ CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, Flags.JSON_PRETTY_PRINT));
+ if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
+ if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
#end
// duplicated code, todo: fix this
@@ -151,7 +151,7 @@ class CharterSelection extends EditorTreeMenu {
var songFolder:String = '${Paths.getAssetsRoot()}/songs/${curSong.name}';
// Save Files
- CoolUtil.safeSaveFile('$songFolder/charts/${name}.json', Json.stringify(data, "\t"));
+ CoolUtil.safeSaveFile('$songFolder/charts/${name}.json', Json.stringify(data, Flags.JSON_PRETTY_PRINT));
// Add to List
// duplicated code, todo: fix this
diff --git a/source/funkin/editors/charter/CharterStrumlineScreen.hx b/source/funkin/editors/charter/CharterStrumlineScreen.hx
index 86305682..52332584 100644
--- a/source/funkin/editors/charter/CharterStrumlineScreen.hx
+++ b/source/funkin/editors/charter/CharterStrumlineScreen.hx
@@ -39,7 +39,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
if (creatingStrumLine)
strumLine = {
- characters: ["dad"],
+ characters: [Flags.DEFAULT_OPPONENT],
type: OPPONENT,
notes: [],
position: "dad",
@@ -205,7 +205,7 @@ class CharacterButton extends UIButton {
char = Character.getIconFromCharName(char);
var image = Paths.image("icons/" + char);
if(!Assets.exists(image))
- image = Paths.image("icons/face");
+ image = Paths.image("icons/" + Flags.DEFAULT_HEALTH_ICON);
charIcon.loadGraphic(image, true, 150, 150);
charIcon.updateHitbox();
}
diff --git a/source/funkin/editors/charter/SongCreationScreen.hx b/source/funkin/editors/charter/SongCreationScreen.hx
index 0f2b78ab..b2a49c85 100644
--- a/source/funkin/editors/charter/SongCreationScreen.hx
+++ b/source/funkin/editors/charter/SongCreationScreen.hx
@@ -86,7 +86,9 @@ class SongCreationScreen extends UISubstateWindow {
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
songDataGroup.add(stepsPerBeatStepper);
- instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Paths.SOUND_EXT, function (res) {
+ var voicesUIText:UIText = null;
+
+ instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
instExplorer.uiElement = audioPlayer;
@@ -96,7 +98,7 @@ class SongCreationScreen extends UISubstateWindow {
translate("instAudio"),
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
- voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, null, null, Paths.SOUND_EXT, function (res) {
+ voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, null, null, Flags.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(voicesExplorer.x + 8, voicesExplorer.y + 8, res);
voicesExplorer.members.push(audioPlayer);
voicesExplorer.uiElement = audioPlayer;
@@ -224,7 +226,7 @@ class SongCreationScreen extends UISubstateWindow {
@:privateAccess iconSprite.animation.clearAnimations();
var path:String = Paths.image('icons/$icon');
- if (!Assets.exists(path)) path = Paths.image('icons/face');
+ if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
iconSprite.loadGraphic(path, true, 150, 150);
iconSprite.animation.add(icon, [0], 0, false);
diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx
index b7598302..56de1058 100644
--- a/source/funkin/game/Character.hx
+++ b/source/funkin/game/Character.hx
@@ -9,13 +9,11 @@ import funkin.backend.FunkinSprite;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
-import funkin.backend.scripting.events.CharacterNodeEvent;
-import funkin.backend.scripting.events.CharacterXMLEvent;
-import funkin.backend.scripting.events.DanceEvent;
-import funkin.backend.scripting.events.DirectionAnimEvent;
-import funkin.backend.scripting.events.PlayAnimContext;
-import funkin.backend.scripting.events.PlayAnimEvent;
+import funkin.backend.scripting.events.CancellableEvent;
+import funkin.backend.scripting.events.character.*;
+import funkin.backend.scripting.events.sprite.*;
import funkin.backend.scripting.events.PointEvent;
+import funkin.backend.scripting.events.DrawEvent;
import funkin.backend.system.Conductor;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.system.interfaces.IOffsetCompatible;
@@ -32,8 +30,8 @@ using StringTools;
@:allow(funkin.game.PlayState)
class Character extends FunkinSprite implements IBeatReceiver implements IOffsetCompatible {
public var isPlayer:Bool = false;
- public var curCharacter:String = 'bf';
- public var sprite:String = 'bf';
+ public var curCharacter:String = Flags.DEFAULT_CHARACTER;
+ public var sprite:String = Flags.DEFAULT_CHARACTER;
public var lastHit:Float = Math.NEGATIVE_INFINITY;
public var holdTime:Float = 4;
@@ -63,12 +61,12 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
@:noCompletion var __switchAnims:Bool = true;
- public function new(x:Float, y:Float, ?character:String = "bf", isPlayer:Bool = false, switchAnims:Bool = true, disableScripts:Bool = false)
+ public function new(x:Float, y:Float, ?character:String, isPlayer:Bool = false, switchAnims:Bool = true, disableScripts:Bool = false)
{
super(x, y);
animOffsets = new Map();
- curCharacter = character;
+ curCharacter = character != null ? character : Flags.DEFAULT_CHARACTER;
this.isPlayer = isPlayer;
__switchAnims = switchAnims;
@@ -128,7 +126,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
scripts.call("update", [elapsed]);
if (stunned) {
__stunnedTime += elapsed;
- if (__stunnedTime > 5 / 60)
+ if (__stunnedTime > Flags.STUNNED_TIME)
stunned = false;
}
@@ -154,6 +152,11 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
}
public function tryDance() {
+ var event = new CancellableEvent();
+ script.call("onTryDance", [event]);
+ if (event.cancelled)
+ return;
+
switch (lastAnimContext) {
case SING | MISS:
if (lastHit + (Conductor.stepCrochet * holdTime) < Conductor.songPosition)
@@ -180,6 +183,9 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
tryDance();
}
+ public override function measureHit(curMeasure:Int)
+ script.call("measureHit", [curMeasure]);
+
public override function stepHit(curStep:Int)
scripts.call("stepHit", [curStep]);
@@ -203,17 +209,24 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
return (isPlayer != playerOffsets) != (flipX != __baseFlipped);
public override function draw() {
- if (isFlippedOffsets()) {
- __reverseDrawProcedure = true;
- flipX = !flipX;
- scale.x *= -1;
+ var e = EventManager.get(DrawEvent).recycle();
+ script.call("draw", [e]);
- super.draw();
+ if(!e.cancelled) {
+ if (isFlippedOffsets()) {
+ __reverseDrawProcedure = true;
+ flipX = !flipX;
+ scale.x *= -1;
- flipX = !flipX;
- scale.x *= -1;
- __reverseDrawProcedure = false;
- } else super.draw();
+ super.draw();
+
+ flipX = !flipX;
+ scale.x *= -1;
+ __reverseDrawProcedure = false;
+ } else super.draw();
+ }
+
+ script.call("postDraw", [e]);
}
public var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];
@@ -464,6 +477,9 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
@:noCompletion private function get_danceInterval()
return beatInterval;
+ public static var FALLBACK_CHARACTER:String = Flags.DEFAULT_CHARACTER;
+ public static var FALLBACK_DEAD_CHARACTER:String = Flags.DEFAULT_GAMEOVER_CHARACTER;
+
private function set_script(script:Script):Script {
if (scripts == null) (scripts = new ScriptPack("Character")).setParent(this);
@@ -481,8 +497,6 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
// ---- end of Backwards compat ----
- public static var FALLBACK_CHARACTER:String = "bf";
- public static var FALLBACK_DEAD_CHARACTER:String = "bf-dead";
public static function getXMLFromCharName(character:OneOfTwo):Access {
var char:Character = null;
if (character is Character) {
@@ -519,7 +533,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
}
public static function getIconFromCharName(?character:String, ?defaultIcon:String = null) {
- if(character == null) return "face";
+ if(character == null) return Flags.DEFAULT_HEALTH_ICON;
if(defaultIcon == null) defaultIcon = character;
var icon:String = defaultIcon;
diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx
index 4351a9dc..a871422f 100644
--- a/source/funkin/game/GameOverSubstate.hx
+++ b/source/funkin/game/GameOverSubstate.hx
@@ -5,7 +5,7 @@ import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.events.CancellableEvent;
-import funkin.backend.scripting.events.GameOverCreationEvent;
+import funkin.backend.scripting.events.gameover.*;
import funkin.backend.system.Conductor;
import funkin.editors.charter.Charter;
import funkin.menus.FreeplayState;
@@ -28,6 +28,7 @@ class GameOverSubstate extends MusicBeatSubstate
public var gameoverScript:Script;
public var game:PlayState = PlayState.instance; // shortcut
+ public static var instance:GameOverSubstate = null;
private var __cancelDefault:Bool = false;
@@ -36,16 +37,16 @@ class GameOverSubstate extends MusicBeatSubstate
public var lossSFX:FlxSound;
- public function new(x:Float, y:Float, character:String = "bf-dead", player:Bool = true, gameOverSong:String = "gameOver", lossSFX:String = "gameOverSFX", retrySFX:String = "gameOverEnd")
+ public function new(x:Float, y:Float, ?character:String, player:Bool = true, ?gameOverSong:String, ?lossSFX:String, ?retrySFX:String)
{
super();
this.x = x;
this.y = y;
- this.characterName = character;
this.player = player;
- this.gameOverSong = gameOverSong;
- this.lossSFXName = lossSFX;
- this.retrySFX = retrySFX;
+ this.characterName = character != null ? character : Flags.DEFAULT_GAMEOVER_CHARACTER;
+ this.gameOverSong = gameOverSong != null ? gameOverSong : Flags.DEFAULT_GAMEOVER_SONG;
+ this.lossSFXName = lossSFX != null ? lossSFX : Flags.DEFAULT_GAMEOVER_LOSS_SFX;
+ this.retrySFX = retrySFX != null ? retrySFX : Flags.DEFAULT_GAMEOVER_RETRY_SFX;
}
public override function create()
@@ -56,7 +57,7 @@ class GameOverSubstate extends MusicBeatSubstate
FlxG.sound.music.stop();
gameoverScript = Script.create(Paths.script(script));
- gameoverScript.setParent(this);
+ gameoverScript.setParent(instance = this);
gameoverScript.load();
var event = EventManager.get(GameOverCreationEvent).recycle(x, y, characterName, player, gameOverSong, gameOverSongBPM, lossSFXName, retrySFX);
@@ -127,7 +128,7 @@ class GameOverSubstate extends MusicBeatSubstate
if (!isEnding && ((!lossSFX.playing) || (character.getAnimName() == "firstDeath" && character.isAnimFinished())) && (FlxG.sound.music == null || !FlxG.sound.music.playing))
{
- CoolUtil.playMusic(Paths.music(gameOverSong), false, 1, true, 100);
+ CoolUtil.playMusic(Paths.music(gameOverSong), false, 1, true, Flags.DEFAULT_BPM);
beatHit(0);
}
}
@@ -198,5 +199,6 @@ class GameOverSubstate extends MusicBeatSubstate
gameoverScript.destroy();
super.destroy();
+ instance = null;
}
}
\ No newline at end of file
diff --git a/source/funkin/game/HealthIcon.hx b/source/funkin/game/HealthIcon.hx
index 07feba62..5d2c8225 100644
--- a/source/funkin/game/HealthIcon.hx
+++ b/source/funkin/game/HealthIcon.hx
@@ -27,7 +27,7 @@ class HealthIcon extends FlxSprite
/**
* current animation state
*/
- public var curAnimState:Int = -1;
+ public var curAnimState:Int = -1;
/**
* Helper for HScript who can't make maps
@@ -48,12 +48,12 @@ class HealthIcon extends FlxSprite
];
}
- public function new(char:String = 'bf', isPlayer:Bool = false)
+ public function new(?char:String, isPlayer:Bool = false)
{
super();
health = 0.5;
this.isPlayer = isPlayer;
- setIcon(char);
+ setIcon(char != null ? char : Flags.DEFAULT_CHARACTER);
scrollFactor.set();
}
@@ -62,7 +62,7 @@ class HealthIcon extends FlxSprite
if(curCharacter != char || this.width != width || this.height != height) {
curCharacter = char;
var path = Paths.image('icons/$char');
- if (!Assets.exists(path)) path = Paths.image('icons/face');
+ if (!Assets.exists(path)) path = Paths.image('icons/' + Flags.DEFAULT_HEALTH_ICON);
loadGraphic(path, true, width, height);
@@ -95,7 +95,7 @@ class HealthIcon extends FlxSprite
i = icon;
}
if (i >= 0 && curAnimState != i) {
- var event = EventManager.get(funkin.backend.scripting.events.HealthIconChangeEvent).recycle(i, this);
+ var event = EventManager.get(funkin.backend.scripting.events.healthicon.HealthIconChangeEvent).recycle(i, this);
funkin.backend.scripting.GlobalScript.event("onHealthIconAnimChange", event);
if (!event.cancelled)
animation.curAnim.curFrame = event.amount;
diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx
index 60aab276..125ec419 100644
--- a/source/funkin/game/Note.hx
+++ b/source/funkin/game/Note.hx
@@ -3,7 +3,7 @@ package funkin.game;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import funkin.backend.chart.ChartData;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.note.NoteCreationEvent;
import funkin.backend.system.Conductor;
using StringTools;
@@ -86,7 +86,7 @@ class Note extends FlxSprite
return PlayState.instance.getNoteType(noteTypeID);
}
- public static var swagWidth:Float = 160 * 0.7;
+ public static var swagWidth:Float = 160 * 0.7; // TODO: remove this
private static var __customNoteTypeExists:Map = [];
@@ -117,11 +117,8 @@ class Note extends FlxSprite
this.isSustainNote = sustain;
this.sustainLength = sustainLength;
this.strumLine = strumLine;
- for(field in Reflect.fields(noteData)) {
- if(!DEFAULT_FIELDS.contains(field)) {
- this.extra.set(field, Reflect.field(noteData, field));
- }
- }
+ for(field in Reflect.fields(noteData)) if(!DEFAULT_FIELDS.contains(field))
+ this.extra.set(field, Reflect.field(noteData, field));
x += 50;
// MAKE SURE ITS DEFINITELY OFF SCREEN?
@@ -132,10 +129,10 @@ class Note extends FlxSprite
var customType = Paths.image('game/notes/${this.noteType}');
var event = EventManager.get(NoteCreationEvent).recycle(this, strumID, this.noteType, noteTypeID, PlayState.instance.strumLines.members.indexOf(strumLine), mustPress,
- (this.noteType != null && customTypePathExists(customType)) ? 'game/notes/${this.noteType}' : 'game/notes/default', @:privateAccess strumLine.strumScale * 0.7, animSuffix);
+ (this.noteType != null && customTypePathExists(customType)) ? 'game/notes/${this.noteType}' : 'game/notes/default', @:privateAccess strumLine.strumScale * Flags.DEFAULT_NOTE_SCALE, animSuffix);
if (PlayState.instance != null)
- event = PlayState.instance.scripts.event("onNoteCreation", event);
+ event = PlayState.instance.gameAndCharsEvent("onNoteCreation", event);
this.animSuffix = event.animSuffix;
if (!event.cancelled) {
@@ -189,7 +186,7 @@ class Note extends FlxSprite
if (PlayState.instance != null) {
PlayState.instance.splashHandler.getSplashGroup(splash);
- PlayState.instance.scripts.event("onPostNoteCreation", event);
+ PlayState.instance.gameAndCharsEvent("onPostNoteCreation", event);
}
}
diff --git a/source/funkin/game/NoteGroup.hx b/source/funkin/game/NoteGroup.hx
index 9c974a13..24c61469 100644
--- a/source/funkin/game/NoteGroup.hx
+++ b/source/funkin/game/NoteGroup.hx
@@ -12,7 +12,7 @@ class NoteGroup extends FlxTypedGroup {
/**
* How many ms it should show a note before it should be hit
**/
- public var limit:Float = 1500;
+ public var limit:Float = Flags.DEFAULT_NOTE_MS_LIMIT;
/**
* Preallocates the members array with nulls, but if theres anything in the array already it clears it
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index d85479cd..f4421e4e 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -18,6 +18,8 @@ import funkin.backend.chart.EventsData;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
+import funkin.backend.scripting.events.gameplay.*;
+import funkin.backend.scripting.events.note.*;
import funkin.backend.scripting.events.*;
import funkin.backend.system.Conductor;
import funkin.backend.system.RotatingSpriteGroup;
@@ -28,7 +30,7 @@ import funkin.game.SplashHandler;
import funkin.game.cutscenes.*;
import funkin.menus.*;
import funkin.menus.StoryMenuState.WeekData;
-import funkin.savedata.FunkinSave;
+import funkin.backend.utils.FunkinSave;
import haxe.io.Path;
using StringTools;
@@ -61,7 +63,7 @@ class PlayState extends MusicBeatState
/**
* The selected difficulty name
*/
- public static var difficulty:String = "normal";
+ public static var difficulty:String = Flags.DEFAULT_DIFFICULTY;
/**
* Whenever the week is coming from the mods folder or not.
*/
@@ -73,11 +75,11 @@ class PlayState extends MusicBeatState
/**
* Whenever the song has been started with opponent mode on.
*/
- public static var opponentMode:Bool = false;
+ public static var opponentMode:Bool = Flags.DEFAULT_OPPONENT_MODE;
/**
* Whenever the song has been started with co-op mode on.
*/
- public static var coopMode:Bool = false;
+ public static var coopMode:Bool = Flags.DEFAULT_COOP_MODE;
/**
* Script Pack of all the scripts being ran.
@@ -96,15 +98,15 @@ class PlayState extends MusicBeatState
/**
* Game Over Song. (assets/music/gameOver.ogg)
*/
- public var gameOverSong:String = "gameOver";
+ public var gameOverSong:String = Flags.DEFAULT_GAMEOVER_SONG;
/**
* Game Over Song. (assets/sounds/gameOverSFX.ogg)
*/
- public var lossSFX:String = "gameOverSFX";
+ public var lossSFX:String = Flags.DEFAULT_GAMEOVER_LOSS_SFX;
/**
* Game Over End SFX, used when retrying. (assets/sounds/gameOverEnd.ogg)
*/
- public var retrySFX:String = "gameOverEnd";
+ public var retrySFX:String = Flags.DEFAULT_GAMEOVER_RETRY_SFX;
/**
* Current Stage.
@@ -209,15 +211,15 @@ class PlayState extends MusicBeatState
/**
* Whenever the vocals should be muted when a note is missed.
*/
- public var muteVocalsOnMiss:Bool = true;
+ public var muteVocalsOnMiss:Bool = Flags.DEFAULT_MUTE_VOCALS_ON_MISS;
/**
* Whenever the player can press 7, 8 or 9 to access the debug menus.
*/
- public var canAccessDebugMenus:Bool = true;
+ public var canAccessDebugMenus:Bool = Flags.DEFAULT_CAN_ACCESS_DEBUG_MENUS;
/**
* Whether or not to show the secret gitaroo pause.
*/
- public var allowGitaroo:Bool = true;
+ public var allowGitaroo:Bool = Flags.DEFAULT_GITAROO;
/**
* Whether or not to bop the icons on beat.
*/
@@ -231,19 +233,23 @@ class PlayState extends MusicBeatState
* Interval of cam zooming (beats).
* For example: if set to 4, the camera will zoom every 4 beats.
*/
- public var camZoomingInterval:Int = 4;
+ public var camZoomingInterval:Int = Flags.DEFAULT_CAM_ZOOM_INTERVAL;
/**
* How strong the cam zooms should be (defaults to 1)
*/
- public var camZoomingStrength:Float = 1;
+ public var camZoomingStrength:Float = Flags.DEFAULT_CAM_ZOOM_STRENGTH;
/**
* Maximum amount of zoom for the camera.
*/
- public var maxCamZoom:Float = 1.35;
+ public var maxCamZoom:Float = Flags.MAX_CAMERA_ZOOM;
/**
* Current song name (lowercase)
*/
public var curSong:String = "";
+ /**
+ * Current song name (lowercase and spaces to dashes)
+ */
+ public var curSongID:String = "";
/**
* Current stage name
*/
@@ -262,7 +268,7 @@ class PlayState extends MusicBeatState
/**
* Maximum health the player can have. Defaults to 2.
*/
- @:isVar public var maxHealth(get, set):Float = 2;
+ @:isVar public var maxHealth(get, set):Float = Flags.DEFAULT_MAX_HEALTH;
/**
* Current combo.
*/
@@ -362,25 +368,25 @@ class PlayState extends MusicBeatState
/**
* Camera zoom at which the game lerps to.
*/
- public var defaultCamZoom:Float = 1.05;
+ public var defaultCamZoom:Float = Flags.DEFAULT_CAM_ZOOM;
/**
* Speed at which the game camera zoom lerps to.
*/
- public var camGameZoomLerp:Float = 0.05;
+ public var camGameZoomLerp:Float = Flags.DEFAULT_CAM_ZOOM_LERP;
/**
* Camera zoom at which the hud lerps to.
*/
- public var defaultHudZoom:Float = 1.0;
+ public var defaultHudZoom:Float = Flags.DEFAULT_HUD_ZOOM;
/**
* Speed at which the hud camera zoom lerps to.
*/
- public var camHUDZoomLerp:Float = 0.05;
+ public var camHUDZoomLerp:Float = Flags.DEFAULT_HUD_ZOOM_LERP;
/**
* Zoom for the pixel assets.
*/
- public static var daPixelZoom:Float = 6;
+ public static var daPixelZoom:Float = Flags.PIXEL_ART_SCALE;
/**
* Whenever the game is currently in a cutscene or not.
@@ -459,6 +465,22 @@ class PlayState extends MusicBeatState
* Group containing all of the combo sprites.
*/
public var comboGroup:RotatingSpriteGroup;
+ /**
+ * Whenever the Rating sprites should be shown or not.
+ *
+ * NOTE: This is just a default value for the final value, the final value can be changed through notes hit events.
+ */
+ public var defaultDisplayRating:Bool = true;
+ /**
+ * Whenever the Combo sprite should be shown or not (like old Week 7 patches).
+ *
+ * NOTE: This is just a default value for the final value, the final value can be changed through notes hit events.
+ */
+ public var defaultDisplayCombo:Bool = false;
+ /**
+ * Minimum Combo Count to display the combo digits. Anything less than 0 means it won't be shown.
+ */
+ public var minDigitDisplay:Int = 10;
/**
* Array containing all of the note types names.
*/
@@ -516,7 +538,7 @@ class PlayState extends MusicBeatState
if (e.percent <= acc && (rating == null || rating.percent < e.percent))
rating = e;
- var event = scripts.event("onRatingUpdate", EventManager.get(RatingUpdateEvent).recycle(rating, curRating));
+ var event = gameAndCharsEvent("onRatingUpdate", EventManager.get(RatingUpdateEvent).recycle(rating, curRating));
if (!event.cancelled)
curRating = event.rating;
}
@@ -538,6 +560,24 @@ class PlayState extends MusicBeatState
return name;
}
+ public inline function callOnCharacters(func:String, ?parameters:Array) {
+ if(strumLines != null) strumLines.forEachAlive(function (strLine:StrumLine) {
+ if (strLine.characters != null) for (character in strLine.characters)
+ if (character != null) character.script.call(func, parameters);
+ });
+ }
+
+ public inline function gameAndCharsCall(func:String, ?parameters:Array, ?charsFunc:String) {
+ scripts.call(func, parameters);
+ callOnCharacters(charsFunc != null ? charsFunc : func, parameters);
+ }
+
+ public inline function gameAndCharsEvent(func:String, ?event:T, ?charsFunc:String):T {
+ scripts.event(func, event);
+ callOnCharacters(charsFunc != null ? charsFunc : func, [event]);
+ return event;
+ }
+
@:dox(hide) override public function create()
{
Note.__customNoteTypeExists = [];
@@ -581,7 +621,7 @@ class PlayState extends MusicBeatState
// CHARACTER INITIALIZATION
#if REGION
comboGroup = new RotatingSpriteGroup(FlxG.width * 0.55, (FlxG.height * 0.5) - 60);
- comboGroup.maxSize = 25;
+ comboGroup.maxSize = Flags.DEFAULT_COMBO_GROUP_MAX_SIZE;
#end
// CAMERA FOLLOW, SCRIPTS & STAGE INITIALIZATION
@@ -589,7 +629,7 @@ class PlayState extends MusicBeatState
camFollow = new FlxObject(0, 0, 2, 2);
add(camFollow);
- if (SONG.stage == null || SONG.stage.trim() == "") SONG.stage = "stage";
+ if (SONG.stage == null || SONG.stage.trim() == "") SONG.stage = Flags.DEFAULT_STAGE;
add(stage = new Stage(SONG.stage));
if (!chartingMode || Options.charterEnablePlaytestScripts) {
@@ -699,16 +739,16 @@ class PlayState extends MusicBeatState
// HUD INITIALIZATION & CAMERA INITIALIZATION
#if REGION
- var event = EventManager.get(AmountEvent).recycle(4);
- if (!scripts.event("onPreGenerateStrums", event).cancelled) {
+ var event = EventManager.get(AmountEvent).recycle(null);
+ if (!gameAndCharsEvent("onPreGenerateStrums", event).cancelled) {
generateStrums(event.amount);
- scripts.event("onPostGenerateStrums", event);
+ gameAndCharsEvent("onPostGenerateStrums", event);
}
for(str in strumLines)
str.generate(str.data, (chartingMode && Charter.startHere) ? Charter.startTime : null);
- FlxG.camera.follow(camFollow, LOCKON, 0.04);
+ FlxG.camera.follow(camFollow, LOCKON, Flags.DEFAULT_CAMERA_FOLLOW_SPEED);
FlxG.camera.zoom = defaultCamZoom;
// camHUD.zoom = defaultHudZoom;
@@ -737,10 +777,11 @@ class PlayState extends MusicBeatState
healthBar.createFilledBar(leftColor, rightColor);
add(healthBar);
- health = maxHealth / 2;
+ if (Flags.DEFAULT_HEALTH != null) health = Flags.DEFAULT_HEALTH;
+ else health = maxHealth / 2;
- iconP1 = new HealthIcon(boyfriend != null ? boyfriend.getIcon() : "face", true);
- iconP2 = new HealthIcon(dad != null ? dad.getIcon() : "face", false);
+ iconP1 = new HealthIcon(boyfriend != null ? boyfriend.getIcon() : Flags.DEFAULT_HEALTH_ICON, true);
+ iconP2 = new HealthIcon(dad != null ? dad.getIcon() : Flags.DEFAULT_HEALTH_ICON, false);
for(icon in [iconP1, iconP2]) {
icon.y = healthBar.y - (icon.height / 2);
add(icon);
@@ -777,7 +818,7 @@ class PlayState extends MusicBeatState
FlxG.sound.load(Paths.sound(s));
if (chartingMode) {
- WindowUtils.prefix = Charter.undos.unsaved ? "* " : "";
+ WindowUtils.prefix = Charter.undos.unsaved ? Flags.UNDO_PREFIX : "";
WindowUtils.suffix = TU.translate("charter.chartPlaytesting");
SaveWarning.showWarning = Charter.undos.unsaved;
@@ -802,7 +843,7 @@ class PlayState extends MusicBeatState
__updateNote_event = EventManager.get(NoteUpdateEvent);
- scripts.call("postCreate");
+ gameAndCharsCall("postCreate", null, "gamePostCreate");
}
/**
@@ -833,7 +874,7 @@ class PlayState extends MusicBeatState
inCutscene = true;
var videoCutscene = Paths.video('$songName-${prefix}cutscene');
- var videoCutsceneAlt = Paths.file('songs/$songName/${prefix}cutscene.mp4');
+ var videoCutsceneAlt = Paths.file('songs/$songName/${prefix}cutscene.${Flags.VIDEO_EXT}');
var dialogue = Paths.file('songs/$songName/${prefix}dialogue.xml');
persistentUpdate = true;
var toCall:Void->Void = function() {
@@ -866,7 +907,7 @@ class PlayState extends MusicBeatState
_startCountdownCalled = true;
inCutscene = false;
- if (scripts.event("onStartCountdown", new CancellableEvent()).cancelled) return;
+ if (gameAndCharsEvent("onStartCountdown", new CancellableEvent()).cancelled) return;
}
startedCountdown = true;
@@ -879,14 +920,14 @@ class PlayState extends MusicBeatState
countdown(swagCounter++);
}, introLength);
}
- scripts.call("onPostStartCountdown");
+ gameAndCharsCall("onPostStartCountdown");
}
/**
* Creates a fake countdown.
*/
public function countdown(swagCounter:Int) {
- var event:CountdownEvent = scripts.event("onCountdown", EventManager.get(CountdownEvent).recycle(
+ var event:CountdownEvent = gameAndCharsEvent("onCountdown", EventManager.get(CountdownEvent).recycle(
swagCounter,
1,
introSounds[swagCounter],
@@ -929,12 +970,12 @@ class PlayState extends MusicBeatState
event.spriteTween = tween;
event.cancelled = false;
- scripts.event("onPostCountdown", event);
+ gameAndCharsEvent("onPostCountdown", event);
}
@:dox(hide) function startSong():Void
{
- scripts.call("onSongStart");
+ gameAndCharsCall("onSongStart");
startingSong = false;
inst.onComplete = endSong;
@@ -961,7 +1002,7 @@ class PlayState extends MusicBeatState
updateDiscordPresence();
- scripts.call("onStartSong");
+ gameAndCharsCall("onStartSong");
}
public override function destroy() {
@@ -1008,11 +1049,15 @@ class PlayState extends MusicBeatState
return FlxSort.byValues(FlxSort.DESCENDING, p1.time, p2.time);
});
- camZoomingInterval = cast songData.meta.beatsPerMeasure.getDefault(4);
+ var beatsPerMeasure:Float = songData.meta.beatsPerMeasure.getDefault(Flags.DEFAULT_BEATS_PER_MEASURE);
+ var stepsPerBeat:Int = songData.meta.stepsPerBeat.getDefault(Flags.DEFAULT_STEPS_PER_BEAT);
- Conductor.changeBPM(songData.meta.bpm, cast songData.meta.beatsPerMeasure.getDefault(4), cast songData.meta.stepsPerBeat.getDefault(4));
+ camZoomingInterval = Std.int(beatsPerMeasure);
+
+ Conductor.changeBPM(songData.meta.bpm, beatsPerMeasure, stepsPerBeat);
curSong = songData.meta.name.toLowerCase();
+ curSongID = curSong.replace(" ", "-");
inst = FlxG.sound.load(Paths.inst(SONG.meta.name, difficulty));
if (SONG.meta.needsVoices != false && Assets.exists(Paths.voices(SONG.meta.name, difficulty))) // null or true
@@ -1032,14 +1077,17 @@ class PlayState extends MusicBeatState
}
@:dox(hide)
- private inline function generateStrums(amount:Int = 4):Void
- for(p in strumLines)
- p.generateStrums(amount);
+ private inline function generateStrums(amount:Null = null):Void {
+ for(p in strumLines) {
+ var kc = amount != null ? amount : Flags.DEFAULT_STRUM_AMOUNT;
+ p.generateStrums(kc);
+ }
+ }
@:dox(hide)
override function openSubState(SubState:FlxSubState)
{
- var event = scripts.event("onSubstateOpen", EventManager.get(StateEvent).recycle(SubState));
+ var event = gameAndCharsEvent("onSubstateOpen", EventManager.get(StateEvent).recycle(SubState));
if (!postCreated)
MusicBeatState.skipTransIn = true;
@@ -1059,13 +1107,13 @@ class PlayState extends MusicBeatState
startTimer.active = false;
}
- super.openSubState(SubState);
+ super.openSubState(event.substate is FlxSubState ? cast event.substate : SubState);
}
@:dox(hide)
override function closeSubState()
{
- var event = scripts.event("onSubstateClose", EventManager.get(StateEvent).recycle(subState));
+ var event = gameAndCharsEvent("onSubstateClose", EventManager.get(StateEvent).recycle(subState));
if (event.cancelled) return;
if (paused)
@@ -1099,7 +1147,7 @@ class PlayState extends MusicBeatState
inst.resume();
vocals.resume();
}
- scripts.call("onFocus");
+ gameAndCharsCall("onFocus");
updateDiscordPresence();
super.onFocus();
}
@@ -1112,7 +1160,7 @@ class PlayState extends MusicBeatState
inst.pause();
vocals.pause();
}
- scripts.call("onFocusLost");
+ gameAndCharsCall("onFocusLost");
updateDiscordPresence();
super.onFocusLost();
}
@@ -1131,14 +1179,14 @@ class PlayState extends MusicBeatState
strumLine.vocals.play();
}
vocals.play();
- scripts.call("onVocalsResync");
+ gameAndCharsCall("onVocalsResync");
}
/**
* Pauses the game.
*/
public function pauseGame() {
- var e = scripts.event("onGamePause", new CancellableEvent());
+ var e = gameAndCharsEvent("onGamePause", new CancellableEvent());
if (e.cancelled) return;
persistentUpdate = false;
@@ -1146,7 +1194,7 @@ class PlayState extends MusicBeatState
paused = true;
// 1 / 1000 chance for Gitaroo Man easter egg
- if (allowGitaroo && FlxG.random.bool(0.1))
+ if (allowGitaroo && FlxG.random.bool(Flags.GITAROO_CHANCE))
{
// gitaroo man easter egg
FlxG.switchState(new GitarooPause());
@@ -1203,7 +1251,7 @@ class PlayState extends MusicBeatState
}
function updateIconPositions() {
- var iconOffset:Int = 26;
+ var iconOffset = Flags.ICON_OFFSET;
var center:Float = healthBar.x + healthBar.width * FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0);
@@ -1266,8 +1314,9 @@ class PlayState extends MusicBeatState
}
if (doIconBop) {
- iconP1.scale.set(lerp(iconP1.scale.x, 1, 0.33), lerp(iconP1.scale.y, 1, 0.33));
- iconP2.scale.set(lerp(iconP2.scale.x, 1, 0.33), lerp(iconP2.scale.y, 1, 0.33));
+ var iconLerp = Flags.ICON_LERP;
+ iconP1.scale.set(lerp(iconP1.scale.x, 1, iconLerp), lerp(iconP1.scale.y, 1, iconLerp));
+ iconP2.scale.set(lerp(iconP2.scale.x, 1, iconLerp), lerp(iconP2.scale.y, 1, iconLerp));
iconP1.updateHitbox();
iconP2.updateHitbox();
@@ -1286,7 +1335,7 @@ class PlayState extends MusicBeatState
var instTime = FlxG.sound.music.time;
var isOffsync = vocals.time != instTime || [for(strumLine in strumLines.members) strumLine.vocals.time != instTime].contains(true);
__vocalOffsetViolation = Math.max(0, __vocalOffsetViolation + (isOffsync ? elapsed : -elapsed / 2));
- if (__vocalOffsetViolation > 25) {
+ if (__vocalOffsetViolation > Flags.VOCAL_OFFSET_VIOLATION_THRESHOLD) {
resyncVocals();
__vocalOffsetViolation = 0;
}
@@ -1311,7 +1360,7 @@ class PlayState extends MusicBeatState
pos.x /= r;
pos.y /= r;
- var event = scripts.event("onCameraMove", EventManager.get(CamMoveEvent).recycle(pos, strumLines.members[curCameraTarget], r));
+ var event = gameAndCharsEvent("onCameraMove", EventManager.get(CamMoveEvent).recycle(pos, strumLines.members[curCameraTarget], r));
if (!event.cancelled)
camFollow.setPosition(pos.x, pos.y);
}
@@ -1356,10 +1405,12 @@ class PlayState extends MusicBeatState
public var scrollSpeedTween:FlxTween = null;
public function executeEvent(event:ChartEvent) @:privateAccess {
- if (event == null) return;
- if (event.params == null) return;
+ if (event == null || event.params == null) return;
- if (scripts.event("onEvent", EventManager.get(EventGameEvent).recycle(event)).cancelled) return;
+ var e = EventManager.get(EventGameEvent).recycle(event);
+ gameAndCharsEvent("onEvent", e);
+ if (e.cancelled) return;
+ var event = e.event;
switch(event.name) {
case "HScript Call":
@@ -1419,11 +1470,11 @@ class PlayState extends MusicBeatState
*/
public function gameOver(?character:Character, ?deathCharID:String, ?gameOverSong:String, ?lossSFX:String, ?retrySFX:String) {
var charToUse:Character = character.getDefault(opponentMode ? dad : boyfriend); // Imma still make it check null later just in case dad or bf are also null for some weird scripts - Nex
- var event:GameOverEvent = scripts.event("onGameOver", EventManager.get(GameOverEvent).recycle(
+ var event:GameOverEvent = gameAndCharsEvent("onGameOver", EventManager.get(GameOverEvent).recycle(
charToUse == null ? 0 : charToUse.x,
charToUse == null ? 0 : charToUse.y,
charToUse,
- deathCharID.getDefault(charToUse != null ? charToUse.gameOverCharacter : "bf-dead"),
+ deathCharID.getDefault(charToUse != null ? charToUse.gameOverCharacter : Flags.DEFAULT_GAMEOVER_CHARACTER),
charToUse != null ? charToUse.isPlayer : true,
gameOverSong.getDefault(this.gameOverSong),
lossSFX.getDefault(this.lossSFX),
@@ -1448,7 +1499,7 @@ class PlayState extends MusicBeatState
openSubState(new GameOverSubstate(event.x, event.y, event.deathCharID, event.isPlayer, event.gameOverSong, event.lossSFX, event.retrySFX));
- scripts.event("onPostGameOver", event);
+ gameAndCharsEvent("onPostGameOver", event);
}
/**
@@ -1456,7 +1507,7 @@ class PlayState extends MusicBeatState
*/
public function endSong():Void
{
- scripts.call("onSongEnd");
+ gameAndCharsCall("onSongEnd");
canPause = false;
inst.volume = 0;
vocals.volume = 0;
@@ -1577,7 +1628,7 @@ class PlayState extends MusicBeatState
var directionID:Null = note == null ? direction : note.strumID;
if (playerID == null || directionID == null || playerID == -1) return;
- var event:NoteMissEvent = scripts.event("onPlayerMiss", EventManager.get(NoteMissEvent).recycle(note, -10, 1, muteVocalsOnMiss, note != null ? -0.0475 : -0.04, Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2), note == null, combo > 5, "sad", true, true, "miss", strumLines.members[playerID].characters, playerID, note != null ? note.noteType : null, directionID, 0));
+ var event:NoteMissEvent = gameAndCharsEvent("onPlayerMiss", EventManager.get(NoteMissEvent).recycle(note, -10, 1, muteVocalsOnMiss, note != null ? -0.0475 : -0.04, Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2), note == null, combo > 5, "sad", true, true, "miss", strumLines.members[playerID].characters, playerID, note != null ? note.noteType : null, directionID, 0));
strumLine.onMiss.dispatch(event);
if (event.cancelled) return;
@@ -1661,13 +1712,13 @@ class PlayState extends MusicBeatState
var event:NoteHitEvent;
if (strumLine != null && !strumLine.cpu)
- event = EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, 0.023, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick");
+ event = EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, 0.023, daRating, Options.splashesEnabled && !note.isSustainNote && daRating == "sick");
else
- event = EventManager.get(NoteHitEvent).recycle(false, false, false, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, daRating, false);
+ event = EventManager.get(NoteHitEvent).recycle(false, false, false, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, daRating, false);
event.deleteNote = !note.isSustainNote; // work around, to allow sustain notes to be deleted
event = scripts.event(strumLine != null && !strumLine.cpu ? "onPlayerHit" : "onDadHit", event);
strumLine.onHit.dispatch(event);
- scripts.event("onNoteHit", event);
+ gameAndCharsEvent("onNoteHit", event);
if (!event.cancelled) {
if (!note.isSustainNote) {
@@ -1682,7 +1733,8 @@ class PlayState extends MusicBeatState
if (event.showRating || (event.showRating == null && event.player))
{
displayCombo(event);
- displayRating(event.rating, event);
+ if (event.displayRating)
+ displayRating(event.rating, event);
ratingNum += 1;
}
}
@@ -1741,14 +1793,12 @@ class PlayState extends MusicBeatState
}
public function displayCombo(?evt:NoteHitEvent = null):Void {
- var hasEvent = evt != null;
- var pre:String = hasEvent ? evt.ratingPrefix : "";
- var suf:String = hasEvent ? evt.ratingSuffix : "";
+ if (minDigitDisplay >= 0 && (combo == 0 || combo >= minDigitDisplay)) {
+ var hasEvent = evt != null;
+ var pre:String = hasEvent ? evt.ratingPrefix : "";
+ var suf:String = hasEvent ? evt.ratingSuffix : "";
- var separatedScore:String = Std.string(combo).addZeros(3);
-
- if (combo == 0 || combo >= 10) {
- if (combo >= 10) {
+ if (evt.displayCombo) {
var comboSpr:FlxSprite = comboGroup.recycleLoop(FlxSprite).loadAnimatedGraphic(Paths.image('${pre}combo${suf}'));
comboSpr.resetSprite(comboGroup.x, comboGroup.y);
comboSpr.acceleration.y = 600;
@@ -1770,6 +1820,7 @@ class PlayState extends MusicBeatState
});
}
+ var separatedScore:String = Std.string(combo).addZeros(3);
for (i in 0...separatedScore.length)
{
var numScore:FlxSprite = comboGroup.recycleLoop(FlxSprite).loadAnimatedGraphic(Paths.image('${pre}num${separatedScore.charAt(i)}${suf}'));
@@ -1821,14 +1872,15 @@ class PlayState extends MusicBeatState
if (camZoomingInterval < 1) camZoomingInterval = 1;
if (Options.camZoomOnBeat && camZooming && FlxG.camera.zoom < maxCamZoom && curBeat % camZoomingInterval == 0)
{
- FlxG.camera.zoom += 0.015 * camZoomingStrength;
- camHUD.zoom += 0.03 * camZoomingStrength;
+ FlxG.camera.zoom += Flags.CAM_BOP_STRENGTH * camZoomingStrength;
+ camHUD.zoom += Flags.HUD_BOP_STRENGTH * camZoomingStrength;
}
if (doIconBop)
{
- iconP1.scale.set(1.2, 1.2);
- iconP2.scale.set(1.2, 1.2);
+ var iconScale = Flags.BOP_ICON_SCALE;
+ iconP1.scale.set(iconScale, iconScale);
+ iconP2.scale.set(iconScale, iconScale);
iconP1.updateHitbox();
iconP2.updateHitbox();
@@ -1916,7 +1968,8 @@ class PlayState extends MusicBeatState
* @param weekData Week Data
* @param difficulty Week Difficulty
*/
- public static function loadWeek(weekData:WeekData, difficulty:String = "normal") {
+ public static function loadWeek(weekData:WeekData, ?difficulty:String) {
+ if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
storyWeek = weekData;
storyPlaylist = [for(e in weekData.songs) e.name];
isStoryMode = true;
@@ -1936,7 +1989,8 @@ class PlayState extends MusicBeatState
* @param opponentMode Whenever opponent mode is on
* @param coopMode Whenever co-op mode is on.
*/
- public static function loadSong(_name:String, _difficulty:String = "normal", _opponentMode:Bool = false, _coopMode:Bool = false) {
+ public static function loadSong(_name:String, ?_difficulty:String, _opponentMode:Bool = false, _coopMode:Bool = false) {
+ if (_difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
isStoryMode = false;
opponentMode = _opponentMode;
chartingMode = false;
diff --git a/source/funkin/game/SplashGroup.hx b/source/funkin/game/SplashGroup.hx
index c8286042..41455ba6 100644
--- a/source/funkin/game/SplashGroup.hx
+++ b/source/funkin/game/SplashGroup.hx
@@ -42,7 +42,7 @@ class SplashGroup extends FlxTypedGroup {
Logs.error('Couldn\'t parse splash data for "${path}": ${e.toString()}');
valid = false;
}
- maxSize = 8;
+ maxSize = Flags.MAX_SPLASHES;
}
function createSplash(imagePath:String) {
diff --git a/source/funkin/game/SplashHandler.hx b/source/funkin/game/SplashHandler.hx
index 31a06234..ad14ad8c 100644
--- a/source/funkin/game/SplashHandler.hx
+++ b/source/funkin/game/SplashHandler.hx
@@ -1,6 +1,6 @@
package funkin.game;
-import funkin.backend.scripting.events.SplashShowEvent;
+import funkin.backend.scripting.events.splash.*;
class SplashHandler extends FlxTypedGroup {
/**
@@ -42,13 +42,15 @@ class SplashHandler extends FlxTypedGroup {
var __grp:SplashGroup;
public function showSplash(name:String, strum:Strum) {
__grp = getSplashGroup(name);
+
var event = EventManager.get(SplashShowEvent).recycle(name, __grp.showOnStrum(strum), strum, __grp);
- event = PlayState.instance.scripts.event("onSplashShown", event);
+ event = PlayState.instance.gameAndCharsEvent("onSplashShown", event);
+
if (!event.cancelled)
add(event.splash);
// max 8 rendered splashes
- while(members.length > 8)
+ while(members.length > Flags.MAX_SPLASHES)
remove(members[0], true);
}
}
\ No newline at end of file
diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx
index 4ab56a26..2d494a9c 100644
--- a/source/funkin/game/Stage.hx
+++ b/source/funkin/game/Stage.hx
@@ -7,8 +7,7 @@ import funkin.backend.utils.XMLUtil.XMLImportedScriptInfo;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
-import funkin.backend.scripting.events.StageNodeEvent;
-import funkin.backend.scripting.events.StageXMLEvent;
+import funkin.backend.scripting.events.stage.*;
import funkin.backend.system.interfaces.IBeatReceiver;
import haxe.io.Path;
import haxe.xml.Access;
@@ -76,7 +75,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
if (PlayState.instance != null) {
event = EventManager.get(StageXMLEvent).recycle(this, stageXML, elems);
- elems = PlayState.instance.scripts.event("onStageXMLParsed", event).elems;
+ elems = PlayState.instance.gameAndCharsEvent("onStageXMLParsed", event).elems;
}
for(node in elems) {
@@ -148,7 +147,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
}
if(PlayState.instance != null) {
- sprite = PlayState.instance.scripts.event("onStageNodeParsed", EventManager.get(StageNodeEvent).recycle(this, node, sprite, node.name)).sprite;
+ sprite = PlayState.instance.gameAndCharsEvent("onStageNodeParsed", EventManager.get(StageNodeEvent).recycle(this, node, sprite, node.name)).sprite;
}
if (sprite != null) {
@@ -193,7 +192,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
}
// idk lemme check anyways just in case scripts did smth - Nex
- if (event != null) PlayState.instance.scripts.event("onPostStageCreation", event);
+ if (event != null) PlayState.instance.gameAndCharsEvent("onPostStageCreation", event);
// shortlived scripts destroy when the stage finishes setting up - Nex
for (info in xmlImportedScripts) if (info.shortLived) {
diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx
index 83d9c855..5417b494 100644
--- a/source/funkin/game/StrumLine.hx
+++ b/source/funkin/game/StrumLine.hx
@@ -5,7 +5,7 @@ import flixel.sound.FlxSound;
import flixel.tweens.FlxTween;
import flixel.util.FlxSignal.FlxTypedSignal;
import funkin.backend.chart.ChartData;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.note.*;
import funkin.backend.system.Conductor;
import funkin.backend.system.Controls;
@@ -153,9 +153,11 @@ class StrumLine extends FlxTypedGroup {
if(scrollSpeed == null) if (PlayState.instance != null) scrollSpeed = PlayState.instance.scrollSpeed;
if(scrollSpeed == null) scrollSpeed = 1;
- // TODOD: Make this work by accounting zoom and scrollspeed changes - Nex
+ // TODO: Make this work by accounting zoom and scrollspeed changes - Nex
/*var limit = FlxG.height / 0.45;
- notes.limit = limit / scrollSpeed;*/
+ notes.limit = limit / scrollSpeed;
+ OR
+ notes.limit = Flags.DEFAULT_NOTE_MS_LIMIT / scrollSpeed;*/
}
public override function update(elapsed:Float) {
@@ -250,7 +252,8 @@ class StrumLine extends FlxTypedGroup {
__justReleased.push(s.__getJustReleased(this));
}
- var event = PlayState.instance.scripts.event("onInputUpdate", EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id));
+ var event = EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id);
+ if (PlayState.instance != null) PlayState.instance.gameAndCharsEvent("onInputUpdate", event);
if (event.cancelled) return;
__pressed = CoolUtil.getDefault(event.pressed, []);
@@ -285,13 +288,14 @@ class StrumLine extends FlxTypedGroup {
forEach(function(str:Strum) {
str.updatePlayerInput(str.__getPressed(this), str.__getJustPressed(this), str.__getJustReleased(this));
});
- PlayState.instance.scripts.call("onPostInputUpdate");
+ PlayState.instance.gameAndCharsCall("onPostInputUpdate");
}
public inline function addHealth(health:Float)
PlayState.instance.health += health * (opponentSide ? -1 : 1);
- public inline function generateStrums(amount:Int = 4) {
+ public inline function generateStrums(amount:Int = -1) {
+ if(amount == -1) amount = Flags.DEFAULT_STRUM_AMOUNT;
for (i in 0...amount)
add(createStrum(i));
}
@@ -319,7 +323,7 @@ class StrumLine extends FlxTypedGroup {
var event = EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix);
event.__doAnimation = !MusicBeatState.skipTransIn && (PlayState.instance != null ? PlayState.instance.introLength > 0 : true);
- event = PlayState.instance.scripts.event("onStrumCreation", event);
+ if (PlayState.instance != null) event = PlayState.instance.gameAndCharsEvent("onStrumCreation", event);
if (!event.cancelled) {
babyArrow.frames = Paths.getFrames(event.sprite);
@@ -329,7 +333,7 @@ class StrumLine extends FlxTypedGroup {
babyArrow.animation.addByPrefix('red', 'arrowRIGHT');
babyArrow.antialiasing = true;
- babyArrow.setGraphicSize(Std.int((babyArrow.width * 0.7) * strumScale));
+ babyArrow.setGraphicSize(Std.int((babyArrow.width * Flags.DEFAULT_NOTE_SCALE) * strumScale));
babyArrow.animation.addByPrefix('static', 'arrow${event.animPrefix.toUpperCase()}');
babyArrow.animation.addByPrefix('pressed', '${event.animPrefix} press', 24, false);
@@ -350,7 +354,7 @@ class StrumLine extends FlxTypedGroup {
insert(i, babyArrow);
- PlayState.instance.scripts.event("onPostStrumCreation", event);
+ if (PlayState.instance != null) PlayState.instance.gameAndCharsEvent("onPostStrumCreation", event);
return babyArrow;
}
diff --git a/source/funkin/game/cutscenes/Cutscene.hx b/source/funkin/game/cutscenes/Cutscene.hx
index cd572812..41f7e233 100644
--- a/source/funkin/game/cutscenes/Cutscene.hx
+++ b/source/funkin/game/cutscenes/Cutscene.hx
@@ -1,18 +1,77 @@
package funkin.game.cutscenes;
+import funkin.backend.scripting.events.NameEvent;
+import funkin.menus.PauseSubState;
+
/**
* Substate made for cutscenes.
*/
class Cutscene extends MusicBeatSubstate {
var __callback:Void->Void;
+ var __pausable:Bool;
var game:PlayState = PlayState.instance;
- public function new(callback:Void->Void) {
- super();
- __callback = callback;
+ public var paused:Bool = false;
+ public var pauseItems:Array;
+ public var skippable(default, set):Bool;
+
+ public function set_skippable(val:Bool):Bool {
+ if(!val) pauseItems.remove('Skip Cutscene');
+ else if(!pauseItems.contains('Skip Cutscene')) pauseItems.insert(1, 'Skip Cutscene');
+ return skippable = val;
}
+
+ public function new(callback:Void->Void, allowPause:Bool = true, canSkip:Bool = true) {
+ super();
+ canOpenCustomTransition = true;
+
+ __callback = callback;
+ __pausable = allowPause;
+
+ pauseItems = Flags.DEFAULT_CUTSCENE_PAUSE_ITEMS;
+ skippable = canSkip;
+ }
+
public override function update(elapsed:Float) {
super.update(elapsed);
+ if (pauseCheck()) pauseCutscene();
+ }
+
+ public function pauseCheck():Bool
+ return controls.PAUSE && __pausable;
+
+ var _before:Array = [false, true];
+ public function pauseCutscene() {
+ _before = [game.persistentUpdate, game.persistentDraw];
+ game.persistentUpdate = persistentUpdate = false;
+ game.persistentDraw = persistentDraw = true;
+ paused = true;
+
+ openSubState(new PauseSubState(pauseItems, selectPauseOption));
+ }
+
+ public override function closeSubState() {
+ if (paused) {
+ game.persistentUpdate = _before[0];
+ game.persistentDraw = _before[1];
+ paused = false;
+ }
+
+ super.closeSubState();
+ }
+
+ public function onSkipCutscene(event:NameEvent) close();
+ public function onRestartCutscene(event:NameEvent) event.name = "Restart Song"; // Making the whole PlayState restart just for precaution - Nex
+ public function onResumeCutscene(event:NameEvent) event.name = "Resume";
+
+ public function selectPauseOption(event:NameEvent) {
+ switch(event.name) {
+ case 'Skip Cutscene': onSkipCutscene(event);
+ case 'Restart Cutscene': onRestartCutscene(event);
+ case 'Resume Cutscene': onResumeCutscene(event);
+ }
+
+ return true;
}
public override function close() {
diff --git a/source/funkin/game/cutscenes/DialogueCutscene.hx b/source/funkin/game/cutscenes/DialogueCutscene.hx
index 6f850007..59c6d83c 100644
--- a/source/funkin/game/cutscenes/DialogueCutscene.hx
+++ b/source/funkin/game/cutscenes/DialogueCutscene.hx
@@ -13,7 +13,7 @@ import haxe.xml.Access;
/**
* Substate made for dialogue cutscenes. To use it in a scripted cutscene, call `startDialogue`.
*/
-class DialogueCutscene extends Cutscene {
+class DialogueCutscene extends ScriptedCutscene {
public var dialoguePath:String;
public var dialogueData:Access;
@@ -28,23 +28,29 @@ class DialogueCutscene extends Cutscene {
public var curMusic:FlxSound = null;
public static var cutscene:DialogueCutscene;
- public var dialogueScript:Script;
+ public var dialogueScript(get, set):Script;
public function set_curLine(val:DialogueLine) {
lastLine = curLine;
return curLine = val;
}
+ // Backwards comapt funcs - Nex
+ public function set_dialogueScript(val:Script) return script = val;
+ public function get_dialogueScript() return script;
+
public function new(dialoguePath:String, callback:Void->Void) {
- super(callback);
- this.dialoguePath = dialoguePath;
+ super(this.dialoguePath = dialoguePath, callback);
+
camera = dialogueCamera = new FlxCamera();
dialogueCamera.bgColor = 0;
FlxG.cameras.add(dialogueCamera, false);
- dialogueScript = Script.create(Paths.script(Path.withoutExtension(dialoguePath), null, dialoguePath.startsWith('assets')));
- dialogueScript.setParent(cutscene = this);
- dialogueScript.load();
+ cutscene = this;
+ }
+
+ public override function onErrorScriptLoading() {
+ Logs.trace('Could not find script for dialogue cutscene at "${scriptPath}"', WARNING, YELLOW);
}
var parentDisabler:FunkinParentDisabler;
@@ -112,22 +118,21 @@ class DialogueCutscene extends Cutscene {
next(true);
} catch(e) {
- Logs.error('Error while loading dialogue at ${dialoguePath}: ${e.toString()}');
- trace(CoolUtil.getLastExceptionStack());
+ var message:String = e.toString();
+ Logs.trace('Error while loading dialogue at ${dialoguePath}: $message', ERROR, RED);
+ dialogueScript.call("loadingError", [message]);
close();
}
+
dialogueScript.call("postCreate");
}
- public override function beatHit(curBeat:Int) {
- super.beatHit(curBeat);
- dialogueScript.call("beatHit", [curBeat]);
+ public override function pauseCheck():Bool {
+ return super.pauseCheck() && !controls.ACCEPT; // Avoids next() and pause() being called at the same time - Nex
}
public override function update(elapsed:Float) {
super.update(elapsed);
- dialogueScript.call("update", [elapsed]);
-
if(controls.ACCEPT) {
if(dialogueBox.dialogueEnded) next();
else dialogueBox.text.skip();
@@ -140,8 +145,8 @@ class DialogueCutscene extends Cutscene {
public var canProceed:Bool = true;
public function next(playFirst:Bool = false) {
- var event = EventManager.get(DynamicEvent).recycle(playFirst);
- dialogueScript.call("next", [playFirst]);
+ var event = EventManager.get(DialogueNextLineEvent).recycle(playFirst);
+ dialogueScript.call("next", [event]);
if(event.cancelled || !canProceed) return;
if ((curLine = dialogueLines.shift()) == null) {
@@ -156,7 +161,7 @@ class DialogueCutscene extends Cutscene {
}
if (curLine.callback != null)
- dialogueScript.call(curLine.callback, [playFirst]);
+ dialogueScript.call(curLine.callback, [event.playFirst]);
for (k=>c in charMap)
if (k != curLine.char)
@@ -169,8 +174,8 @@ class DialogueCutscene extends Cutscene {
dialogueBox.popupChar(char, force);
}
- var finalSuffix:String = playFirst && dialogueBox.hasAnimation(curLine.bubble + "-firstOpen") ? "-firstOpen" : dialogueBox.hasAnimation(curLine.bubble + "-open") ? "-open" : "";
- dialogueBox.playBubbleAnim(curLine.bubble, finalSuffix, curLine.text, curLine.format, curLine.speed, curLine.nextSound, curLine.textSound != null ? [curLine.textSound] : null, finalSuffix == "-firstOpen" || finalSuffix == "-open", !playFirst);
+ var finalSuffix:String = event.playFirst && dialogueBox.hasAnimation(curLine.bubble + "-firstOpen") ? "-firstOpen" : dialogueBox.hasAnimation(curLine.bubble + "-open") ? "-open" : "";
+ dialogueBox.playBubbleAnim(curLine.bubble, finalSuffix, curLine.text, curLine.format, curLine.speed, curLine.nextSound, curLine.textSound != null ? [curLine.textSound] : null, finalSuffix == "-firstOpen" || finalSuffix == "-open", !event.playFirst);
if(curLine.playSound != null) curLine.playSound.play();
if(curLine.changeMusic != null) {
@@ -180,7 +185,7 @@ class DialogueCutscene extends Cutscene {
curMusic.fadeIn(1, 0, curMusic.volume);
} else if(curLine.musicVolume != null && curMusic != null) curMusic.volume = curLine.musicVolume;
- dialogueScript.call("postNext", [playFirst]);
+ dialogueScript.call("postNext", [event]);
}
public override function close() {
@@ -195,8 +200,6 @@ class DialogueCutscene extends Cutscene {
public override function destroy() {
if(curMusic != null && !curMusic.persist) curMusic.destroy();
- dialogueScript.call("destroy");
- dialogueScript.destroy();
super.destroy();
cutscene = null;
diff --git a/source/funkin/game/cutscenes/ScriptedCutscene.hx b/source/funkin/game/cutscenes/ScriptedCutscene.hx
index ae3bdc24..20a01aa2 100644
--- a/source/funkin/game/cutscenes/ScriptedCutscene.hx
+++ b/source/funkin/game/cutscenes/ScriptedCutscene.hx
@@ -1,20 +1,25 @@
package funkin.game.cutscenes;
+import haxe.io.Path;
+import flixel.FlxSubState;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
+import funkin.backend.scripting.events.CancellableEvent;
+import funkin.backend.scripting.events.NameEvent;
+import funkin.backend.scripting.events.StateEvent;
/**
* Substate made for scripted cutscenes.
* To add cutscenes to your songs, add a `cutscene.hx` file in your song's directory (ex: `songs/song/cutscene.hx`)
*/
class ScriptedCutscene extends Cutscene {
+ var scriptPath:String;
var script:Script;
- var scriptPath:String;
public function new(scriptPath:String, callback:Void->Void) {
super(callback);
- script = Script.create(this.scriptPath = scriptPath);
+ script = Script.create(this.scriptPath = Paths.script(Path.withoutExtension(scriptPath), null, scriptPath.startsWith('assets')));
script.setPublicMap(PlayState.instance.scripts.publicVariables);
script.setParent(this);
script.load();
@@ -22,32 +27,91 @@ class ScriptedCutscene extends Cutscene {
public override function create() {
super.create();
- trace("fuck you");
script.call("create");
- if (Std.isOfType(script, DummyScript)) {
- Logs.error('Could not find script for scripted cutscene at ${scriptPath}');
- close();
- }
+
+ if(Std.isOfType(script, DummyScript))
+ onErrorScriptLoading();
}
- public override function update(elapsed:Float) {
+ public function onErrorScriptLoading() {
+ Logs.trace('Could not find script for scripted cutscene at "${scriptPath}"', ERROR, RED);
+ close();
+ }
+
+ public override function pauseCheck():Bool
+ {
+ var shouldClose = super.pauseCheck();
+ script.call("pauseCheck", [shouldClose]);
+ return shouldClose;
+ }
+
+ public override function update(elapsed:Float)
+ {
script.call("update", [elapsed]);
super.update(elapsed);
script.call("postUpdate", [elapsed]);
}
- public override function beatHit(curBeat:Int) {
+ public override function pauseCutscene()
+ {
+ var event = new CancellableEvent();
+ script.call("pauseCutscene", [event]);
+ if(!event.cancelled) super.pauseCutscene();
+ }
+
+ public override function onSkipCutscene(event:NameEvent)
+ {
+ script.call("onSkipCutscene", [event]);
+ if(!event.cancelled) super.onSkipCutscene(event);
+ }
+
+ public override function onRestartCutscene(event:NameEvent)
+ {
+ script.call("onRestartCutscene", [event]);
+ if(!event.cancelled) super.onRestartCutscene(event);
+ }
+
+ public override function onResumeCutscene(event:NameEvent)
+ {
+ script.call("onResumeCutscene", [event]);
+ if(!event.cancelled) super.onResumeCutscene(event);
+ }
+
+ public override function measureHit(curMeasure:Int)
+ {
+ super.measureHit(curMeasure);
+ script.call("measureHit", [curMeasure]);
+ }
+
+ public override function beatHit(curBeat:Int)
+ {
super.beatHit(curBeat);
script.call("beatHit", [curBeat]);
}
- public override function stepHit(curStep:Int) {
+ public override function stepHit(curStep:Int)
+ {
super.stepHit(curStep);
script.call("stepHit", [curStep]);
}
+ public override function openSubState(sub:FlxSubState)
+ {
+ var event = EventManager.get(StateEvent).recycle(sub);
+ script.call("onSubstateClose", [event]);
+ if(!event.cancelled) super.openSubState(event.substate is FlxSubState ? cast event.substate : sub);
+ }
+
+ public override function closeSubState()
+ {
+ var event = EventManager.get(StateEvent).recycle(subState);
+ script.call("onSubstateOpen", [event]);
+ if(!event.cancelled) super.closeSubState();
+ }
+
public override function destroy() {
script.call("destroy");
+ script.destroy();
super.destroy();
}
diff --git a/source/funkin/game/cutscenes/VideoCutscene.hx b/source/funkin/game/cutscenes/VideoCutscene.hx
index f12210eb..9216c340 100644
--- a/source/funkin/game/cutscenes/VideoCutscene.hx
+++ b/source/funkin/game/cutscenes/VideoCutscene.hx
@@ -1,5 +1,6 @@
package funkin.game.cutscenes;
+import flixel.tweens.FlxTween;
import flixel.addons.display.FlxBackdrop;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
@@ -12,7 +13,7 @@ import haxe.xml.Access;
import sys.io.File;
#end
#if VIDEO_CUTSCENES
-import hxvlc.flixel.FlxVideo;
+import hxvlc.flixel.FlxVideoSprite;
#end
/**
@@ -24,22 +25,24 @@ class VideoCutscene extends Cutscene {
var localPath:String;
#if VIDEO_CUTSCENES
- var video:FlxVideo;
- public var skippable:Bool = true;
- #end
+ var video:FlxVideoSprite;
+ final mutex = new sys.thread.Mutex();
+
var cutsceneCamera:FlxCamera;
var text:FunkinText;
var loadingBackdrop:FlxBackdrop;
- var videoReady:Bool = false;
+ private var __loaded:Bool = false;
var bg:FlxSprite;
var subtitle:FunkinText;
public var subtitles:Array = [];
+ var curSubtitle:Int = 0;
+ #end
public function new(path:String, callback:Void->Void) {
- super(callback);
+ super(callback, false);
localPath = Assets.getPath(this.path = path);
}
@@ -48,21 +51,17 @@ class VideoCutscene extends Cutscene {
// TODO: get vlc to stop autoloading those goddamn subtitles (use different file ext??)
+ #if VIDEO_CUTSCENES
cutsceneCamera = new FlxCamera();
cutsceneCamera.bgColor = 0;
FlxG.cameras.add(cutsceneCamera, false);
- #if VIDEO_CUTSCENES
parseSubtitles();
- video = new FlxVideo();
- video.onEndReached.add(function()
- {
- video.dispose();
- FlxG.removeChild(video);
- });
- video.onEndReached.add(close);
- FlxG.addChildBelowMouse(video);
+ add(video = new FlxVideoSprite());
+ video.antialiasing = true;
+ video.autoPause = false; // Imma handle it better inside this class, mainly because of the pause menu - Nex
+ video.bitmap.onEndReached.add(close);
//cover = new FlxSprite(0, FlxG.height * 0.85).makeSolid(FlxG.width + 50, FlxG.height + 50, 0xFF000000);
//cover.scrollFactor.set(0, 0);
@@ -77,41 +76,44 @@ class VideoCutscene extends Cutscene {
subtitle.alignment = CENTER;
subtitle.visible = false;
- if (localPath.startsWith("[ZIP]")) {
- text = new FunkinText(10, 10, Std.int(FlxG.width / 2), "Loading video...");
- text.cameras = [cutsceneCamera];
- text.visible = false;
- @:privateAccess
- text.regenGraphic();
- add(text);
+ text = new FunkinText(10, 10, Std.int(FlxG.width / 2), "Loading video...");
+ text.cameras = [cutsceneCamera];
+ text.visible = false;
+ @:privateAccess
+ text.regenGraphic();
+ add(text);
- loadingBackdrop = new FlxBackdrop(text.graphic, X);
- loadingBackdrop.y = FlxG.height - 20 - loadingBackdrop.height;
- loadingBackdrop.cameras = [cutsceneCamera];
- add(loadingBackdrop);
+ loadingBackdrop = new FlxBackdrop(text.graphic, X);
+ loadingBackdrop.y = FlxG.height - 20 - loadingBackdrop.height;
+ loadingBackdrop.velocity.x = 70;
+ loadingBackdrop.cameras = [cutsceneCamera];
+ add(loadingBackdrop);
- // ZIP PATH: EXPORT
- // TODO: this but better and more ram friendly
- localPath = './.temp/video-${curVideo++}.mp4';
- Main.execAsync(function() {
+ loadingBackdrop.alpha = 0;
+ FlxTween.tween(loadingBackdrop, {alpha: 1}, 0.5, {ease: FlxEase.sineInOut});
+
+ Main.execAsync(function() {
+ if (localPath.startsWith("[ZIP]")) {
+ // ZIP PATH: EXPORT
+ // TODO: this but better and more ram friendly
+ localPath = './.temp/video-${curVideo++}.mp4';
File.saveBytes(localPath, Assets.getBytes(path));
- videoReady = true;
- });
- } else {
- if (video.load(localPath))
- new FlxTimer().start(0.001, function(tmr:FlxTimer) {
- video.play();
- });
- else
- close();
- }
+ }
+
+ if(video.load(localPath)) new FlxTimer().start(0.001, function(_) {mutex.acquire(); onReady(); mutex.release();});
+ else { mutex.acquire(); close(); mutex.release(); }
+ });
+
add(bg);
add(subtitle);
- #end
cameras = [cutsceneCamera];
+ #else
+ close();
+ #end
}
+ #if VIDEO_CUTSCENES
public function parseSubtitles() {
var subtitlesPath = '${Path.withoutExtension(path)}.srt';
@@ -141,27 +143,23 @@ class VideoCutscene extends Cutscene {
}
if (subtitleText.length <= 0) continue; // empty subtitle, skipping
var lastSub = subtitles.last();
- if (lastSub != null && lastSub.subtitle == "" && lastSub.time > beginTime)
+ if (lastSub != null && lastSub.subtitle == "" && lastSub.time >= beginTime)
subtitles.pop(); // remove last subtitle auto reset to prevent bugs
subtitles.push({
- subtitle: subtitleText.join("."),
- time: beginTime * 1000,
- color: 0xFFFFFFFF // todo
+ subtitle: subtitleText.join(""),
+ time: beginTime * 1000
});
subtitles.push({
subtitle: "",
- time: endTime * 1000,
- color: 0xFFFFFFFF
+ time: endTime * 1000
});
}
}
-
- trace(subtitles);
}
public static function splitTime(str:String):Float {
if (str == null || str.trim() == "") return -1;
- var multipliers:Array = [1, 60, 3600, 86400]; // no way a cutscene will last longer than days
+ var multipliers:Array = [1, 60, 3600, 86400, 31536000]; // no way a cutscene will last longer than years
var timeSplit:Array> = [for(e in str.split(":")) Std.parseFloat(e.replace(",", "."))];
var time:Float = 0;
@@ -173,50 +171,62 @@ class VideoCutscene extends Cutscene {
return time;
}
+ public inline function onReady() {
+ FlxTween.cancelTweensOf(loadingBackdrop);
+ FlxTween.tween(loadingBackdrop, {alpha: 0}, 0.7, {ease: FlxEase.sineInOut, onComplete: function(_) {
+ loadingBackdrop.destroy();
+ text.destroy();
+ }});
+
+ __pausable = __loaded = true;
+ video.play();
+ }
+
public override function update(elapsed:Float) {
super.update(elapsed);
- #if VIDEO_CUTSCENES
- if (videoReady) {
- videoReady = false;
- if (video.load(localPath))
- new FlxTimer().start(0.001, function(tmr:FlxTimer) {
- video.play();
- });
- else
- {
- close();
+ if(loadingBackdrop != null) return;
- if (loadingBackdrop != null)
- loadingBackdrop.visible = false;
-
- return;
- }
-
- if (loadingBackdrop != null)
- loadingBackdrop.visible = false;
- }
@:privateAccess
- var time:Int64 = video.time;
+ var time:Int64 = video.bitmap.time;
+ var time:Float = FPHelper.i64ToDouble(time.low, time.high);
- while (subtitles.length > 0 && subtitles[0].time < Math.round(FPHelper.i64ToDouble(time.low, time.high)))
- setSubtitle(subtitles.shift());
+ if(curSubtitle < subtitles.length && subtitles[curSubtitle].time < time) {
+ setSubtitle(subtitles[curSubtitle]);
+ curSubtitle++;
+ }
+ }
- if (loadingBackdrop != null) {
- loadingBackdrop.x -= elapsed * FlxG.width * 0.5;
- }
- if (skippable && video.isPlaying && controls.ACCEPT) {
- video.onEndReached.dispatch();
- }
- #else
- close();
- #end
+ @:dox(hide) override public function onFocus() {
+ if(FlxG.autoPause && !paused) video.resume();
+ super.onFocus();
+ }
+
+ @:dox(hide) override public function onFocusLost() {
+ if(FlxG.autoPause && !paused) video.pause();
+ super.onFocusLost();
+ }
+
+ public override function pauseCutscene() {
+ video.pause();
+ super.pauseCutscene();
+ }
+
+ public override function onResumeCutscene(event) {
+ video.resume();
+ super.onResumeCutscene(event);
+ }
+
+ public override function onRestartCutscene(event) {
+ closeSubState();
+ video.bitmap.position = curSubtitle = 0;
+ setSubtitle({time: -1, subtitle: ""});
+ video.resume();
}
public function setSubtitle(sub:CutsceneSubtitle) {
if (bg.visible = subtitle.visible = (sub.subtitle.length > 0)) {
subtitle.text = sub.subtitle;
- subtitle.color = sub.color;
subtitle.screenCenter(X);
bg.scale.set(subtitle.width + 8, subtitle.height + 8);
bg.updateHitbox();
@@ -228,10 +238,10 @@ class VideoCutscene extends Cutscene {
FlxG.cameras.remove(cutsceneCamera, true);
super.destroy();
}
+ #end
}
typedef CutsceneSubtitle = {
var time:Float; // time in ms
var subtitle:String; // subtitle text
- var color:FlxColor;
}
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
index 936979f9..bafc77a5 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
@@ -3,8 +3,7 @@ package funkin.game.cutscenes.dialogue;
import flixel.addons.text.FlxTypeText;
import flixel.sound.FlxSound;
import funkin.backend.scripting.Script;
-import funkin.backend.scripting.events.PlayAnimContext;
-import funkin.backend.scripting.events.PlayAnimEvent;
+import funkin.backend.scripting.events.sprite.*;
import funkin.backend.scripting.events.dialogue.*;
import haxe.xml.Access;
@@ -87,8 +86,11 @@ class DialogueBox extends FunkinSprite {
}
} catch(e) {
active = false;
- Logs.error('Couldn\'t load dialogue box "$name": ${e.toString()}');
+ var message:String = e.toString();
+ Logs.trace('Couldn\'t load dialogue box "$name": $message', ERROR, RED);
+ dialogueBoxScript.call("loadingError", [message]);
}
+
defaultTextTypeSFX = [FlxG.sound.load(textTypeSFX)];
FlxG.sound.cache(nextSFX);
dialogueBoxScript.call("postCreate");
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
index e075bef9..2c3eec13 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
@@ -2,8 +2,7 @@ package funkin.game.cutscenes.dialogue;
import flixel.tweens.FlxTween;
import funkin.backend.scripting.Script;
-import funkin.backend.scripting.events.PlayAnimContext;
-import funkin.backend.scripting.events.PlayAnimEvent;
+import funkin.backend.scripting.events.sprite.*;
import funkin.backend.scripting.events.dialogue.*;
import haxe.xml.Access;
@@ -54,9 +53,10 @@ class DialogueCharacter extends FunkinSprite {
x = 0; y = 0;
} catch(e) {
var message:String = e.toString();
- Logs.error('Failed to load dialogue character $name: ${message}');
+ Logs.trace('Failed to load dialogue character $name: ${message}', ERROR, RED);
dialogueCharScript.call("loadingError", [message]);
}
+
visible = false;
dialogueCharScript.call("postCreate");
}
diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx
index 68147a00..9d6688e9 100644
--- a/source/funkin/menus/BetaWarningState.hx
+++ b/source/funkin/menus/BetaWarningState.hx
@@ -19,7 +19,7 @@ class BetaWarningState extends MusicBeatState {
disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32);
disclaimer.alignment = CENTER;
- disclaimer.applyMarkup(TU.translate("betaWarning.desc", [Main.releaseCycle]) + "\n\n" + TU.translate("betaWarning.proceed", ["ENTER"]),
+ disclaimer.applyMarkup(TU.translate("betaWarning.desc", [Flags.RELEASE_CYCLE]) + "\n\n" + TU.translate("betaWarning.proceed", ["ENTER"]),
[
new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*")
]
diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx
index bee0eef7..282cd53a 100644
--- a/source/funkin/menus/FreeplayState.hx
+++ b/source/funkin/menus/FreeplayState.hx
@@ -4,9 +4,10 @@ import flixel.text.FlxText;
import flixel.util.FlxColor;
import funkin.backend.chart.Chart;
import funkin.backend.chart.ChartData.ChartMetaData;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.menu.MenuChangeEvent;
+import funkin.backend.scripting.events.menu.freeplay.*;
import funkin.game.HealthIcon;
-import funkin.savedata.FunkinSave;
+import funkin.backend.utils.FunkinSave;
using StringTools;
@@ -463,7 +464,7 @@ class FreeplaySonglist {
if (songsFound.length > 0) {
for(s in songsFound)
- songs.push(Chart.loadChartMeta(s, "normal", source == MODS));
+ songs.push(Chart.loadChartMeta(s, Flags.DEFAULT_DIFFICULTY, source == MODS));
return false;
}
return true;
diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx
index 802b8e46..c6843d87 100644
--- a/source/funkin/menus/MainMenuState.hx
+++ b/source/funkin/menus/MainMenuState.hx
@@ -4,7 +4,8 @@ import flixel.FlxState;
import flixel.effects.FlxFlicker;
import flixel.tweens.FlxTween;
import funkin.backend.FunkinText;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.menu.MenuChangeEvent;
+import funkin.backend.scripting.events.NameEvent;
import funkin.menus.credits.CreditsMain;
import funkin.options.OptionsMenu;
import lime.app.Application;
@@ -24,7 +25,7 @@ class MainMenuState extends MusicBeatState
var camFollow:FlxObject;
var versionText:FunkinText;
- public var canAccessDebugMenus:Bool = true;
+ public var canAccessDebugMenus:Bool = Flags.DEFAULT_CAN_ACCESS_DEBUG_MENUS;
override function create()
{
@@ -73,8 +74,8 @@ class MainMenuState extends MusicBeatState
FlxG.camera.follow(camFollow, null, 0.06);
versionText = new FunkinText(5, FlxG.height - 2, 0, [
- 'Codename Engine v${Application.current.meta.get('version')}',
- TU.translate("mainMenu.commit", [funkin.backend.system.macros.GitCommitMacro.commitNumber, funkin.backend.system.macros.GitCommitMacro.commitHash]),
+ Flags.VERSION_MESSAGE,
+ TU.translate("mainMenu.commit", [Flags.COMMIT_NUMBER, Flags.COMMIT_HASH]),
TU.translate("mainMenu.openMods", [controls.getKeyName(SWITCHMOD)]),
''
].join('\n'));
diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx
index 1f4008a0..dcfb48c0 100644
--- a/source/funkin/menus/PauseSubState.hx
+++ b/source/funkin/menus/PauseSubState.hx
@@ -5,9 +5,9 @@ import funkin.backend.FunkinText;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import funkin.backend.scripting.Script;
-import funkin.backend.scripting.events.MenuChangeEvent;
+import funkin.backend.scripting.events.menu.MenuChangeEvent;
+import funkin.backend.scripting.events.menu.pause.*;
import funkin.backend.scripting.events.NameEvent;
-import funkin.backend.scripting.events.PauseCreationEvent;
import funkin.backend.system.Conductor;
import funkin.backend.utils.FunkinParentDisabler;
import funkin.editors.charter.Charter;
@@ -29,19 +29,22 @@ class PauseSubState extends MusicBeatSubstate
// Change Options -> pause.changeOptions
// Exit to menu -> pause.exitToMenu
// Exit to charter -> pause.exitToCharter
- var menuItems:Array = ['Resume', 'Restart Song', 'Change Controls', 'Change Options', 'Exit to menu', "Exit to charter"];
+ var menuItems:Array;
var curSelected:Int = 0;
var pauseMusic:FlxSound;
public var pauseScript:Script;
+ public var selectCall:NameEvent->Void; // Mainly for extern stuff that aren't scripts - Nex
public var game:PlayState = PlayState.instance; // shortcut
private var __cancelDefault:Bool = false;
- public function new(x:Float = 0, y:Float = 0) {
+ public function new(?items:Array, ?selectCall:NameEvent->Void) {
super();
+ menuItems = items != null ? items : Flags.DEFAULT_PAUSE_ITEMS;
+ this.selectCall = selectCall;
}
var parentDisabler:FunkinParentDisabler;
@@ -150,13 +153,11 @@ class PauseSubState extends MusicBeatSubstate
public function selectOption() {
var event = EventManager.get(NameEvent).recycle(menuItems[curSelected]);
+ if (selectCall != null) selectCall(event);
pauseScript.call("onSelectOption", [event]);
-
if (event.cancelled) return;
- var daSelected:String = event.name;
-
- switch (daSelected)
+ switch (event.name)
{
case "Resume":
close();
diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx
index 56a708f5..b39593cf 100644
--- a/source/funkin/menus/StoryMenuState.hx
+++ b/source/funkin/menus/StoryMenuState.hx
@@ -6,15 +6,21 @@ import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import funkin.backend.FunkinText;
-import funkin.backend.scripting.events.*;
-import funkin.savedata.FunkinSave;
+import funkin.backend.scripting.events.menu.MenuChangeEvent;
+import funkin.backend.scripting.events.menu.storymenu.*;
+import funkin.backend.scripting.events.CancellableEvent;
+import funkin.backend.utils.FunkinSave;
import haxe.io.Path;
import haxe.xml.Access;
class StoryMenuState extends MusicBeatState {
- public var characters:Map = [];
+ public var characters:Map = [];
public var weeks:Array = [];
+ // yes it supports parameters - Nex
+ // To be removed later, when translation branch is merged into public - Neo
+ public var scoreMessage:String = "WEEK SCORE:{0}";
+
public var scoreText:FlxText;
public var tracklist:FlxText;
public var weekTitle:FlxText;
@@ -23,18 +29,21 @@ class StoryMenuState extends MusicBeatState {
public var curWeek:Int = 0;
public var difficultySprites:Map = [];
- public var weekBG:FlxSprite;
public var leftArrow:FlxSprite;
public var rightArrow:FlxSprite;
public var blackBar:FlxSprite;
+ public var weekBG:FlxSprite;
+ public var defColor:String = "#F9CF51";
+ public var interpColor:FlxInterpolateColor;
+
public var lerpScore:Float = 0;
public var intendedScore:Int = 0;
public var canSelect:Bool = true;
public var weekSprites:FlxTypedGroup