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/README.md b/README.md
index b4d4bcc9..93b36034 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ Also, the command `.\cne test` uses the source assets folder instead of the expo
## Codename Engine
Codename Engine is a new Friday Night Funkin' Engine aimed at simplifying modding, along with extensiblity and ease of use.
-Make sure to read the wiki and join the Discord server linked there!
-#### It includes many new features, as seen [here](FEATURES.md)
+### Before making issues or need help with something, check our website [HERE](https://fnf-cne-devs.github.io/) (it contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more)!!!
+#### The Engine includes many new features, as seen [here](FEATURES.md)
#### Wanna see the new features added in the most recent update? Click [here](PATCHNOTES.md)
## How to download
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 a5bc8d41..359a8eea 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 2abd3409..f27cdcbd 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 9a9596d9..c498cb57 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 d12f2a0d..5981b647 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 c81dc67d..a0fab601 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 38f9abf9..d02f5a41 100644
--- a/assets/data/characters/tankman.xml
+++ b/assets/data/characters/tankman.xml
@@ -1,10 +1,10 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/assets/data/config/credits.xml b/assets/data/config/credits.xml
deleted file mode 100644
index 4f300fcb..00000000
--- a/assets/data/config/credits.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/assets/data/config/options.xml b/assets/data/config/options.xml
deleted file mode 100644
index 888288d7..00000000
--- a/assets/data/config/options.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/assets/data/scripts/pixel.hx b/assets/data/scripts/pixel.hx
index 88bb5af5..26d18251 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/titlescreen/titlescreen.xml b/assets/data/titlescreen/titlescreen.xml
index f16c8b62..323e9ef1 100644
--- a/assets/data/titlescreen/titlescreen.xml
+++ b/assets/data/titlescreen/titlescreen.xml
@@ -7,7 +7,7 @@
-
+
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/shaders/engine/editorBlur.frag b/assets/shaders/engine/editorBlur.frag
index 59b91c72..85754b99 100644
--- a/assets/shaders/engine/editorBlur.frag
+++ b/assets/shaders/engine/editorBlur.frag
@@ -3,19 +3,17 @@
// Used for editors
-int steps = 16;
-int stepsInside = 2;
-float strength = 0.0075;
+const int steps = 16;
+const int stepsInside = 2;
+const float strength = 0.0075;
+
vec4 getColor(vec2 pos) {
- vec2 ps = (pos);
- ps = clamp(ps, vec2(0.0), 1.0 - (1.0 / openfl_TextureSize.xy));
- return flixel_texture2D(bitmap, (ps));
+ pos = clamp(pos, vec2(0.0), vec2(1.0));//1.0 - (1.0 / openfl_TextureSize.xy));
+ return flixel_texture2D(bitmap, pos);
}
+
void main() {
- // vec2 camPos = getCamPos(openfl_TextureCoordv);
vec2 camPos = openfl_TextureCoordv;
- if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0)
- return;
vec4 color = getColor(camPos);
float fsteps = float(steps);
diff --git a/assets/shaders/engine/editorBlurFast.frag b/assets/shaders/engine/editorBlurFast.frag
index 43fa6ed2..db476ae8 100644
--- a/assets/shaders/engine/editorBlurFast.frag
+++ b/assets/shaders/engine/editorBlurFast.frag
@@ -2,53 +2,29 @@
// Used for editors (faster)
-//#define iResolution _camSize
-#define getTexture textureCam
-
-#define iResolution openfl_TextureSize
-//#define getTexture flixel_texture2D
-
-float uBlur = 0.015;
-float uBrightness = 0.6;
+const float uBlur = 0.015;
+const float uBrightness = 0.6;
vec4 getColor(vec2 pos) {
- vec2 ps = (pos);
- ps = clamp(ps, vec2(0.0), vec2(1.0));//1.0 - (1.0 / iResolution.xy));
- return flixel_texture2D(bitmap, (ps));
+ pos = clamp(pos, vec2(0.0), vec2(1.0));//1.0 - (1.0 / openfl_TextureSize.xy));
+ return flixel_texture2D(bitmap, pos);
}
-
-/*vec2 fixvec2(float x, float y) { // makes an uv the same across sizes
- vec2 val = vec2(x, y);
- val.xy *= vec2(1280.0, 720.0);
- val.xy /= iResolution.xy;
- return val;
-}
-vec2 fixvec2(vec2 uv) { // makes an uv the same across sizes
- vec2 val = uv;
- val.xy *= vec2(1280.0, 720.0);
- val.xy /= iResolution.xy;
- return val;
-}*/
+uniform sampler2D noiseTexture;
+uniform vec2 noiseTextureSize;
vec2 random(vec2 p) {
- p = vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));
- return fract(sin(p)*4375.5);
+ p *= openfl_TextureSize;
+ return texture2D(noiseTexture, p / noiseTextureSize).rg - vec2(0.5);
}
void main() {
- vec2 camPos = (openfl_TextureCoordv);
- //vec2 camPos = openfl_TextureCoordv;
- if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0)
- return;
+ vec2 camPos = openfl_TextureCoordv;
+ vec2 blur = vec2(uBlur) * vec2(1.0, openfl_TextureSize.x / openfl_TextureSize.y);
- //vec4 color = getColor(camPos);
-
- vec2 blur = vec2(uBlur) * vec2(1.0, iResolution.x / iResolution.y);
-
- vec4 a = getColor(camPos+(random(camPos)*blur - blur / 2.0)) * uBrightness;
- a += getColor(camPos+(random(camPos+0.1)*blur - blur / 2.0)) * uBrightness;
- //a += getColor(camPos+(random(camPos+0.2)*blur - blur / 2.0)) * uBrightness;
- //a += getColor(camPos+(random(camPos+0.3)*blur - blur / 2.0)) * uBrightness;
- gl_FragColor = a / 2.0;
+ vec4 a = getColor(camPos+random(camPos)*blur);
+ a += getColor(camPos+random(camPos+0.1)*blur);
+ //a += getColor(camPos+random(camPos+0.2)*blur);
+ //a += getColor(camPos+random(camPos+0.3)*blur);
+ gl_FragColor = (a / 2.0) * uBrightness;
}
\ No newline at end of file
diff --git a/assets/shaders/noise128.png b/assets/shaders/noise128.png
new file mode 100644
index 00000000..682cb32a
Binary files /dev/null and b/assets/shaders/noise128.png differ
diff --git a/assets/shaders/noise256.png b/assets/shaders/noise256.png
new file mode 100644
index 00000000..fd2a1410
Binary files /dev/null and b/assets/shaders/noise256.png differ
diff --git a/assets/shaders/noise512.png b/assets/shaders/noise512.png
new file mode 100644
index 00000000..d50270af
Binary files /dev/null and b/assets/shaders/noise512.png differ
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/commandline/commands/Setup.hx b/commandline/commands/Setup.hx
index 87927075..3d85705d 100644
--- a/commandline/commands/Setup.hx
+++ b/commandline/commands/Setup.hx
@@ -18,11 +18,32 @@ class Setup {
FileSystem.deleteDirectory(path);
}
+ public static function addMissingFolders(path:String):String {
+ #if sys
+ var folders:Array = path.split("/");
+ var currentPath:String = "";
+
+ for (folder in folders) {
+ currentPath += folder + "/";
+ if (!FileSystem.exists(currentPath))
+ FileSystem.createDirectory(currentPath);
+ }
+ #end
+ return path;
+ }
+
public static function main(args:Array) {
- var args = ArgParser.parse(args, ["s" => "silent-progress", "S" => "silent-progress", "silent" => "silent-progress"]);
+ var args = ArgParser.parse(args, [
+ "s" => "silent-progress",
+ "S" => "silent-progress",
+ "silent" => "silent-progress",
+ "f" => "fast",
+ "F" => "fast"
+ ]);
var CHECK_VSTUDIO = !args.existsOption("no-vscheck");
var REINSTALL_ALL = args.existsOption("reinstall");
var SILENT = args.existsOption("silent-progress");
+ var FAST = args.existsOption("fast");
// TODO: add only install missing libs
// to prevent messing with currently installed libs
@@ -138,6 +159,11 @@ class Setup {
var commandSuffix = " --always";
if (SILENT) commandSuffix += " --quiet";
+ function command(cmd:String) {
+ Sys.println(cmd); // TODO: ansi color
+ Sys.command(cmd);
+ }
+
for(event in events) {
switch(event.type) {
case INSTALL:
@@ -148,10 +174,23 @@ class Setup {
switch(lib.type) {
case "lib":
prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}"...');
- Sys.command('haxelib$commandPrefix install ${lib.name} ${lib.version != null ? " " + lib.version : " "}');
+ command('haxelib$commandPrefix install ${lib.name} ${lib.version != null ? " " + lib.version : " "}');
case "git":
prettyPrint((lib.global == "true" ? "Globally installing" : "Locally installing") + ' "${lib.name}" from git url "${lib.url}"');
- Sys.command('haxelib$commandPrefix git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}');
+ if(FAST) {
+ var oldcwd = Sys.getCwd();
+ var newCwd = oldcwd + "/.haxelib/" + lib.name + "/";
+ var newCwdGit = newCwd + "git/";
+ addMissingFolders(newCwdGit);
+ Sys.setCwd(newCwd);
+ File.saveContent(".current", "git");
+ if(FileSystem.exists(newCwdGit)) recursiveDelete(newCwdGit);
+ command('git clone ${lib.url} ${lib.name} --depth 1${lib.ref != null ? " --branch " + lib.ref : ""} --progress');
+ FileSystem.rename(newCwd + lib.name, newCwdGit);
+ Sys.setCwd(oldcwd);
+ } else {
+ command('haxelib$commandPrefix git ${lib.name} ${lib.url}${lib.ref != null ? ' ${lib.ref}' : ''}');
+ }
default:
prettyPrint('Cannot resolve library of type "${lib.type}"');
}
@@ -192,7 +231,7 @@ class Setup {
for(line in cmd.lines) {
final line = StringTools.replace(line, "$PLATFORM", platform);
//Sys.println(line);
- Sys.command(line);
+ command(line);
}
Sys.setCwd(oldCwd);
case PRINT:
diff --git a/libs.xml b/libs.xml
index b824cbcb..c024b95c 100644
--- a/libs.xml
+++ b/libs.xml
@@ -20,6 +20,8 @@
+
+
diff --git a/project.xml b/project.xml
index 24538c29..c42c312c 100644
--- a/project.xml
+++ b/project.xml
@@ -118,9 +118,6 @@
-
-
-
@@ -134,11 +131,14 @@
-
+
-
+
+
+
+
@@ -173,6 +173,8 @@
+
+
diff --git a/source/StringTools.hx b/source/StringTools.hx
index 0b495af1..2eac4b10 100644
--- a/source/StringTools.hx
+++ b/source/StringTools.hx
@@ -230,6 +230,8 @@ class StringTools {
return (cast s).startsWith(start);
#elseif lua
return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start);
+ #elseif cpp
+ return untyped s.__StartsWith(start);
#else
return (s.length >= start.length && s.indexOf(start, 0) == 0);
#end
@@ -255,6 +257,8 @@ class StringTools {
return (cast s).endsWith(end);
#elseif lua
return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end);
+ #elseif cpp
+ return untyped s.__EndsWith(end);
#else
var elen = end.length;
var slen = s.length;
diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx
index a3a0a5f9..6a1da437 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;
@@ -56,6 +56,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public var animEnabled:Bool = true;
public var zoomFactorEnabled:Bool = true;
+ public var globalCurFrame(get, set):Int;
+
/**
* ODD interval -> asynced; EVEN interval -> synced
*/
@@ -142,7 +144,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public function beatHit(curBeat:Int)
{
if(!animEnabled) return;
- 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
@@ -392,4 +394,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 eca2968c..604f8d1d 100644
--- a/source/funkin/backend/MusicBeatState.hx
+++ b/source/funkin/backend/MusicBeatState.hx
@@ -164,10 +164,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)
@@ -232,7 +258,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) {
@@ -260,11 +286,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 aebafb20..cee1ad5b 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
*/
@@ -221,7 +225,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) {
@@ -239,7 +243,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() {
@@ -254,19 +258,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 2d17e592..ed673088 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.
- */
- inline public static 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,31 +59,33 @@ class Paths
inline static public function ps1(key:String, ?library:String)
return getPath('data/$key.ps1', library);
- static public 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);
inline static public function soundRandom(key:String, min:Int, max:Int, ?library:String)
return sound(key + FlxG.random.int(min, max), library);
- inline static public 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);
}
- static public 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,9 +109,9 @@ class Paths
return scriptPath;
}
- static public function chart(song:String, ?difficulty:String = "normal"):String
+ static public function chart(song:String, ?difficulty:String):String
{
- difficulty = difficulty.toLowerCase();
+ difficulty = (difficulty != null ? difficulty : Flags.DEFAULT_DIFFICULTY).toLowerCase();
song = song.toLowerCase();
return getPath('songs/$song/charts/$difficulty.json', null);
@@ -160,33 +156,33 @@ class Paths
return getPath('models/$key.awd');
}
- inline static public 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));
- inline static public 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');
- inline static public 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));
- inline static public 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');
- inline static public 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));
- inline static public 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');
inline static public function getAssetsRoot():String
- return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : './assets';
+ 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)
@@ -194,7 +190,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);
}
@@ -206,10 +202,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');
@@ -220,18 +217,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 de4d9621..48ee9d8a 100644
--- a/source/funkin/backend/chart/Chart.hx
+++ b/source/funkin/backend/chart/Chart.hx
@@ -12,11 +12,6 @@ import sys.FileSystem;
using StringTools;
final class Chart {
- /**
- * Default background colors for songs without bg color
- */
- public inline static var defaultColor:FlxColor = 0xFF9271FD;
-
public static final version:String = "1.6.0";
public static function loadEventsJson(songName:String) {
@@ -32,7 +27,9 @@ final 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');
@@ -52,19 +49,19 @@ final 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)];
@@ -88,7 +85,9 @@ final 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: [],
@@ -97,8 +96,8 @@ final 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)
};
@@ -202,7 +201,8 @@ final 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;
@@ -220,11 +220,11 @@ final 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 186e15ca..e84540b0 100644
--- a/source/funkin/backend/chart/ChartData.hx
+++ b/source/funkin/backend/chart/ChartData.hx
@@ -20,7 +20,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;
@@ -28,6 +28,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 0d066a61..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,10 +132,10 @@ class FNFLegacyParser {
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
sectionNote[1] += 4;
- swagSection.sectionNotes.push(sectionNote);
+ swagSection.sectionNotes.push(sectionNote);
}
}
-
+
return {song: base};
}
@@ -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/chart/PsychParser.hx b/source/funkin/backend/chart/PsychParser.hx
index 2d5a8b7b..5fb420d3 100644
--- a/source/funkin/backend/chart/PsychParser.hx
+++ b/source/funkin/backend/chart/PsychParser.hx
@@ -32,7 +32,7 @@ class PsychParser {
for (note in strumLine.notes) {
var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
var swagSection:SwagSection = base.notes[section];
-
+
if (section >= 0 && section < base.notes.length) {
var sectionNote:Array = [
note.time, // TIME
@@ -47,7 +47,7 @@ class PsychParser {
swagSection.sectionNotes.push(sectionNote);
}
}
-
+
var groupedEvents:Array> = [];
var __last:Array = null;
var __lastTime:Float = Math.NaN;
@@ -106,7 +106,7 @@ class PsychParser {
for (psychEvent in psychEvents)
for (i in 1...3) // Turn both vals into strings
- if (!(psychEvent[i] is String))
+ if (!(psychEvent[i] is String))
psychEvent[i] = Std.string(psychEvent[i]);
base.events.push([events[0].time, psychEvents]);
diff --git a/source/funkin/backend/scripting/Script.hx b/source/funkin/backend/scripting/Script.hx
index a0433ba3..12bf14c0 100644
--- a/source/funkin/backend/scripting/Script.hx
+++ b/source/funkin/backend/scripting/Script.hx
@@ -19,89 +19,134 @@ 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,
];
}
+
+ /**
+ * 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 31ae18c6..f77ed9ec 100644
--- a/source/funkin/backend/scripting/events/AmountEvent.hx
+++ b/source/funkin/backend/scripting/events/AmountEvent.hx
@@ -5,9 +5,4 @@ final class AmountEvent extends CancellableEvent {
* Amount
*/
public var amount:Null;
-
- /**
- * Shows whether or not psych users complained about this class
- */
- public var psychUsersComplained:Bool = true;
}
\ 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 87%
rename from source/funkin/backend/scripting/events/NoteHitEvent.hx
rename to source/funkin/backend/scripting/events/note/NoteHitEvent.hx
index 4bac078e..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
*/
@@ -123,6 +133,13 @@ final class NoteHitEvent extends CancellableEvent {
@:dox(hide)
public function cancelDeletion() {preventDeletion();}
+ /**
+ * Forces the note to be deleted.
+ **/
+ public function forceDeletion() {
+ deleteNote = true;
+ }
+
/**
* Prevents the vocals volume from being set to 1 after pressing the note.
*/
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 93d480c6..0166e08e 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 2ccee499..03a6b48c 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,13 +14,129 @@ 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";
- public static var CHARTER_ADVANCED_SETTINGS:Bool = false;
+ 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;
- // Internal stuff
+ 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/Logs.hx b/source/funkin/backend/system/Logs.hx
index ce590882..755d86f8 100644
--- a/source/funkin/backend/system/Logs.hx
+++ b/source/funkin/backend/system/Logs.hx
@@ -11,8 +11,7 @@ final class Logs {
public static var nativeTrace = Log.trace;
public static function init() {
-
- Log.trace = function(v : Dynamic, ?infos : Null) {
+ Log.trace = function(v:Dynamic, ?infos:Null) {
var data = [
logText('${infos.fileName}:${infos.lineNumber}: ', CYAN),
logText(Std.string(v))
@@ -28,22 +27,48 @@ final class Logs {
__showInConsole(prepareColoredTrace(data, TRACE));
};
- LogFrontEnd.onLogs = function(Data, Style, FireOnce) {
+ LogFrontEnd.onLogs = function(data, style, fireOnce) {
var prefix = "[FLIXEL]";
var color:ConsoleColor = LIGHTGRAY;
var level:Level = INFO;
- if (Style == LogStyle.CONSOLE) {prefix = "> "; color = WHITE; level = INFO; } else
- if (Style == LogStyle.ERROR) {prefix = "[FLIXEL]"; color = RED; level = ERROR; } else
- if (Style == LogStyle.NORMAL) {prefix = "[FLIXEL]"; color = WHITE; level = INFO; } else
- if (Style == LogStyle.NOTICE) {prefix = "[FLIXEL]"; color = GREEN; level = VERBOSE;} else
- if (Style == LogStyle.WARNING) {prefix = "[FLIXEL]"; color = YELLOW; level = WARNING;}
+ if (style == LogStyle.CONSOLE) // cant place a switch here as these arent inline values - Nex
+ {
+ prefix = "> ";
+ color = WHITE;
+ level = INFO;
+ }
+ else if (style == LogStyle.ERROR)
+ {
+ prefix = "[FLIXEL]";
+ color = RED;
+ level = ERROR;
+ }
+ else if (style == LogStyle.NORMAL)
+ {
+ prefix = "[FLIXEL]";
+ color = WHITE;
+ level = INFO;
+ }
+ else if (style == LogStyle.NOTICE)
+ {
+ prefix = "[FLIXEL]";
+ color = GREEN;
+ level = VERBOSE;
+ }
+ else if (style == LogStyle.WARNING)
+ {
+ prefix = "[FLIXEL]";
+ color = YELLOW;
+ level = WARNING;
+ }
- var d:Dynamic = Data;
+ var d:Dynamic = data;
if (!(d is Array))
d = [d];
var a:Array = d;
var strs = [for(e in a) Std.string(e)];
- for(e in strs) {
+ for(e in strs)
+ {
Logs.trace('$prefix $e', level, color);
}
};
@@ -55,12 +80,18 @@ final class Logs {
logText('[ '),
logText('${Std.string(time.getHours()).addZeros(2)}:${Std.string(time.getMinutes()).addZeros(2)}:${Std.string(time.getSeconds()).addZeros(2)}', DARKMAGENTA),
logText(' |'),
- switch(level) {
- case WARNING: logText(' WARNING ', DARKYELLOW);
- case ERROR: logText(' ERROR ', DARKRED);
- case TRACE: logText(' TRACE ', GRAY);
- case VERBOSE: logText(' VERBOSE ', DARKMAGENTA);
- default: logText(' INFORMATION ', CYAN);
+ switch (level)
+ {
+ case WARNING:
+ logText(' WARNING ', DARKYELLOW);
+ case ERROR:
+ logText(' ERROR ', DARKRED);
+ case TRACE:
+ logText(' TRACE ', GRAY);
+ case VERBOSE:
+ logText(' VERBOSE ', DARKMAGENTA);
+ default:
+ logText(' INFORMATION ', CYAN);
},
logText('] ')
];
@@ -77,7 +108,7 @@ final class Logs {
}
public static function __showInConsole(text:Array) {
- #if sys
+ #if (sys && !mobile)
while(__showing) {
Sys.sleep(0.05);
}
@@ -89,20 +120,30 @@ final class Logs {
NativeAPI.setConsoleColors();
Sys.print("\r\n");
__showing = false;
+ #elseif mobile
+ while(__showing) {
+ Sys.sleep(0.05);
+ }
+ __showing = true;
+ @:privateAccess
+ Sys.print([for(t in text) t.text].join(""));
+ __showing = false;
#else
@:privateAccess
nativeTrace([for(t in text) t.text].join(""));
#end
}
- public static function traceColored(text:Array, level:Level = INFO) {
+ public static function traceColored(text:Array, level:Level = INFO)
__showInConsole(prepareColoredTrace(text, level));
- }
+
public static function trace(text:String, level:Level = INFO, color:ConsoleColor = LIGHTGRAY) {
- traceColored([{
- text: text,
- color: color
- }], level);
+ traceColored([
+ {
+ text: text,
+ color: color
+ }
+ ], level);
}
}
@@ -113,7 +154,8 @@ enum abstract Level(Int) {
var TRACE = 3;
var VERBOSE = 4;
}
+
typedef LogText = {
var text:String;
var color:ConsoleColor;
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/system/Main.hx b/source/funkin/backend/system/Main.hx
index ee70213d..5617484f 100644
--- a/source/funkin/backend/system/Main.hx
+++ b/source/funkin/backend/system/Main.hx
@@ -30,10 +30,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;
@@ -123,6 +119,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
@@ -145,7 +144,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;
@@ -171,13 +170,22 @@ class Main extends Sprite
initTransition();
}
- public static function refreshAssets() {
- FlxSoundTray.volumeChangeSFX = Paths.sound('menu/volume');
- FlxSoundTray.volumeUpChangeSFX = null;
- FlxSoundTray.volumeDownChangeSFX = null;
+ public static function refreshAssets() @:privateAccess {
+ WindowUtils.resetTitle();
- if (FlxG.game.soundTray != null)
- FlxG.game.soundTray.text.setTextFormat(new TextFormat(Paths.font("vcr.ttf")));
+ var game = FlxG.game;
+ var daSndTray = Type.createInstance(game._customSoundTray = funkin.menus.ui.FunkinSoundTray, []);
+ var index:Int = game.numChildren - 1;
+
+ 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 7a354081..1ea04d22 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
@@ -55,9 +57,9 @@ class MainState extends FlxState {
}
#end
- Main.refreshAssets();
- ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
Flags.load();
+ ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder); // Loads global.hx
+ Main.refreshAssets();
DiscordUtil.init();
EventsData.reloadEvents();
ControlsUtil.loadCustomControls();
@@ -73,6 +75,8 @@ class MainState extends FlxState {
betaWarningShown = true;
}
+ #if sys
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
+ #end
}
}
\ No newline at end of file
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/framerate/FlixelInfo.hx b/source/funkin/backend/system/framerate/FlixelInfo.hx
index 259b7f8f..297fcde7 100644
--- a/source/funkin/backend/system/framerate/FlixelInfo.hx
+++ b/source/funkin/backend/system/framerate/FlixelInfo.hx
@@ -1,5 +1,7 @@
package funkin.backend.system.framerate;
+import funkin.backend.scripting.ModState;
+
class FlixelInfo extends FramerateCategory {
public function new() {
super("Flixel Info");
@@ -14,7 +16,12 @@ class FlixelInfo extends FramerateCategory {
for(_ in FlxG.bitmap._cache.keys())
c++;
- _text = 'State: ${Type.getClassName(Type.getClass(FlxG.state))}';
+ if((FlxG.state is ModState)) {
+ var state:ModState = cast FlxG.state;
+ _text = "Mod State: " + state.scriptName;
+ } else {
+ _text = 'State: ${Type.getClassName(Type.getClass(FlxG.state))}';
+ }
_text += '\nObject Count: ${FlxG.state.members.length}';
_text += '\nCamera Count: ${FlxG.cameras.list.length}';
_text += '\nBitmaps Count: ${c}';
@@ -22,9 +29,9 @@ class FlixelInfo extends FramerateCategory {
_text += '\nFlxG.game Childs Count: ${FlxG.game.numChildren}';
// _text += '\nCached objects count: ${cachedObjects}';
#if FLX_POINT_POOL
- var points = flixel.math.FlxPoint.FlxBasePoint.pool;
+ //var points = flixel.math.FlxPoint.FlxBasePoint.pool;
//_text += '\nPoint Count: ${points._count} | +${points.made} | -${points.gotten} | ${points.balance} | >${points.putted}';
- _text += '\nPoint Count: ${points._count}';
+ //_text += '\nPoint Count: ${points._count}';
#end
}
diff --git a/source/funkin/backend/system/github/GitHub.hx b/source/funkin/backend/system/github/GitHub.hx
index 6129a2d9..ce7e61dc 100644
--- a/source/funkin/backend/system/github/GitHub.hx
+++ b/source/funkin/backend/system/github/GitHub.hx
@@ -4,6 +4,7 @@ import haxe.Exception;
#if GITHUB_API
import haxe.Json;
#end
+import haxe.Exception;
// TODO: Document further and perhaps make this a Haxelib.
class GitHub {
@@ -82,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'));
@@ -105,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 535f6118..37c0f197 100644
--- a/source/funkin/backend/system/macros/BuildInfo.hx
+++ b/source/funkin/backend/system/macros/BuildInfo.hx
@@ -6,13 +6,21 @@ using StringTools;
class BuildInfo {
public static function printBuildInfo() {
if(haxe.macro.Context.defined("display")) return;
- var haxeVersion = haxe.macro.Context.definedValue("haxe");
- Sys.println('--- BUILD INFO ---');
+ var haxeVersion = haxe.macro.Context.definedValue("haxe").trim();
+ Sys.println('[ BUILD INFO ]');
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";
@@ -20,24 +28,27 @@ class BuildInfo {
var options = sys.io.File.getContent(exportPath);
for(option in options.split("\n")) {
if(option.startsWith("haxe=")) {
- lastBuiltWith = option.substr(5);
+ lastBuiltWith = option.substr(5).trim();
break;
}
}
- 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 html5 "HTML5"
+ #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/macros/HashLinkFixer.hx b/source/funkin/backend/system/macros/HashLinkFixer.hx
index 046929e8..697d3c01 100644
--- a/source/funkin/backend/system/macros/HashLinkFixer.hx
+++ b/source/funkin/backend/system/macros/HashLinkFixer.hx
@@ -42,26 +42,12 @@ class HashLinkFixer {
var cl = clRef.get();
if (cl.isAbstract || cl.isExtern || cl.isInterface) return fields;
- if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith("_HSX") && !cl.name.endsWith("_HSC") && !cl.name.endsWith("_HLFHelper")) {
- var metas = cl.meta.get();
-
+ if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith("_HSX") && !cl.name.endsWith("_HSC")) {
if(cl.params.length > 0)
return fields;
- if(cl.module == "EReg") return fields; // private typedef in same class
- if(cl.module == "hl.Format") return fields; // enum in same class
-
var definedFields = [];
- var helperClass = macro class {
-
- };
-
- helperClass.pos = cl.pos;
-
- var module = cl.module + "_HLFHelper";
- var hcClassName = cl.name + "_HLFHelper";
-
for(f in fields.copy()) {
if (f == null)
continue;
@@ -70,10 +56,12 @@ class HashLinkFixer {
if(definedFields.contains(f.name)) continue; // no duplicate fields
+ var hlNativeMeta = null;
var hasHlNative = false;
for(m in f.meta)
if (m.name == ":hlNative") {
hasHlNative = true;
+ hlNativeMeta = m;
break;
}
@@ -92,16 +80,39 @@ class HashLinkFixer {
var overrideExpr:Expr;
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
+ var printer = new haxe.macro.Printer();
+ if(cl.module == "hl.Gc" && fun.ret == null) returns = false; // fix since they dont explicitly set :Void
+ if(cl.module == "hl.Format" && fun.ret == null) returns = false; // fix since they dont explicitly set :Void
+
var name = 'hlf_${f.name}';
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
- var funcExpr:Expr = returns ? {
- //macro return $i{name}($a{arguments});
- macro return @:privateAccess $i{hcClassName}.$name($a{arguments});
- } : {
- macro @:privateAccess $i{hcClassName}.$name($a{arguments});
- };
+ var funcExpr:Expr = macro @:privateAccess $i{name}($a{arguments});
+ if(returns) funcExpr = macro return $funcExpr;
+
+ var cleanMeta = f.meta.copy().filter(function(m) return m.name != ":hlNative");
+ var hasBareMeta = hlNativeMeta.params.length == 0;
+
+ var meta = f.meta.copy();
+ switch hlNativeMeta {
+ case {params: []}:
+ meta = [{name: ":hlNative", params: [macro "std", macro $v{f.name}], pos: Context.currentPos()}].concat(cleanMeta);
+ case {params: [_.expr => EConst(CString(name))]}:
+ meta = [{name: ":hlNative", params: [macro "std", macro $v{name}], pos: Context.currentPos()}].concat(cleanMeta);
+ case {params: [_.expr => EConst(CFloat(version))]}:
+ var curVersion = Context.definedValue("hl_ver");
+ if(curVersion == null) curVersion = "";
+ if(version > curVersion) {
+ meta = cleanMeta;
+ if(f.meta.filter((m) -> m.name == ":noExpr").length > 0)
+ Context.error("Missing function body", f.pos);
+ funcExpr = fun.expr; // restore to default behaviour
+ } else {
+ meta = [{name: ":hlNative", params: [macro "std", macro $v{f.name}], pos: Context.currentPos()}].concat(cleanMeta);
+ }
+ default:
+ }
var fiel:Field = {
name: name,
@@ -109,50 +120,32 @@ class HashLinkFixer {
kind: FFun({
ret: fun.ret,
params: fun.params.copy(),
- expr: fun.expr,
+ expr: funcExpr,
args: fun.args.copy()
}),
- access: f.access.copy(),
- meta: f.meta.copy()
+ access: f.access.copy().filter(function(a) return a != APublic && a != APrivate).concat([APrivate]),
+ meta: meta
};
- helperClass.fields.push(fiel);
+ fields.push(fiel);
definedFields.push(f.name);
+ // Remove meta from original function
for(m in f.meta.copy())
if (m.name == ":hlNative") {
f.meta.remove(m);
}
- fun.expr = funcExpr;
default:
}
}
- helperClass.pack = cl.pack.copy();
- helperClass.pos = cl.pos;
- helperClass.name = hcClassName;
-
- if(definedFields.length > 0) {
+ /*if(definedFields.length > 0) {
trace(cl.module);
- /*for(m in metas.copy()) {
- trace(" " + m.name);
- if(m.name == ":coreApi") {
- metas.remove(m);
- }
- }*/
-
- var imports = Context.getLocalImports().copy();
- Context.defineModule(module, [helperClass], imports);
-
- Context.getLocalImports().push({
- path: [for(m in module.split(".")) {
- name: m,
- pos: Context.currentPos()
- }],
- mode: INormal
- });
- }
+ var printer = new haxe.macro.Printer();
+ for(field in fields) if(field.name.startsWith("hlf_"))
+ Sys.println(printer.printField(field));
+ }*/
}
return fields;
diff --git a/source/funkin/backend/system/updating/AsyncUpdater.hx b/source/funkin/backend/system/updating/AsyncUpdater.hx
index ac31b044..36b79ad4 100644
--- a/source/funkin/backend/system/updating/AsyncUpdater.hx
+++ b/source/funkin/backend/system/updating/AsyncUpdater.hx
@@ -99,7 +99,7 @@ class AsyncUpdater {
progress.files = files.length;
progress.step = DOWNLOADING_ASSETS;
trace('starting assets download');
- doFile([for(e in files) e], fileNames.copy(), function() {
+ doFile(files.copy(), fileNames.copy(), function() {
progress.curFile = -1;
progress.curFileName = null;
progress.files = 1;
diff --git a/source/funkin/backend/system/updating/UpdateScreen.hx b/source/funkin/backend/system/updating/UpdateScreen.hx
index d7da6539..51af11ab 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 7236a18e..f4214029 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -122,11 +122,15 @@ final 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
}
/**
@@ -139,11 +143,15 @@ final 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
}
/**
@@ -155,11 +163,15 @@ final 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
}
/**
@@ -171,11 +183,15 @@ final 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
}
/**
@@ -393,7 +409,7 @@ final 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:Float = 1, Looped:Bool = true, DefaultBPM:Int = 102, ?Group:FlxSoundGroup) {
+ @:noUsing public static function playMusic(path:String, Persist:Bool = false, Volume:Float = 1, Looped:Bool = true, DefaultBPM:Float = 102, ?Group:FlxSoundGroup) {
Conductor.reset();
FlxG.sound.playMusic(path, Volume, Looped, Group);
if (FlxG.sound.music != null) {
@@ -404,17 +420,17 @@ final 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"]).getDefault(DefaultBPM);
@@ -762,7 +778,14 @@ final class CoolUtil
* @param url
*/
@:noUsing public static inline function openURL(url:String) {
+ #if linux
+ // generally `xdg-open` should work in every distro
+ var cmd = Sys.command("xdg-open", [url]);
+ // run old command JUST IN CASE it fails, which it shouldn't
+ if (cmd != 0) cmd = Sys.command("/usr/bin/xdg-open", [url]);
+ #else
FlxG.openURL(url);
+ #end
}
/**
diff --git a/source/funkin/backend/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx
index 0aed4952..0d8dbc1c 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 @@ final 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
}
@@ -525,7 +525,7 @@ typedef DPresence =
var ?button1Url:String; /* max 512 bytes */
var ?button2Label:String; /* max 32 bytes */
var ?button2Url:String; /* max 512 bytes */
- var ?activityType:ActivityType;
+ var ?activityType:#if DISCORD_RPC ActivityType #else Dynamic #end;
var ?streamUrl:String; /* max 512 bytes */
}
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 20337df6..82167fe6 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/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx
index e646aba1..9a85bcc9 100644
--- a/source/funkin/backend/utils/MemoryUtil.hx
+++ b/source/funkin/backend/utils/MemoryUtil.hx
@@ -140,14 +140,16 @@ final class MemoryUtil {
reg.match(process.stdout.readAll().toString());
if (process.exitCode() == 0) return reg.matched(1);
#elseif linux
- var process = new HiddenProcess("sudo", ["dmidecode", "--type", "17"]);
+ /*var process = new HiddenProcess("sudo", ["dmidecode", "--type", "17"]);
if (process.exitCode() != 0) return "Unknown";
var lines = process.stdout.readAll().toString().split("\n");
for (line in lines) {
if (line.startsWith("Type:")) {
return line.substring("Type:".length).trim();
}
- }
+ }*/
+ // TODO: sort of unsafe? also requires users to use `sudo`
+ // when launching the engine through the CLI, REIMPLEMENT LATER.
#end
return "Unknown";
}
diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx
index 8ff95a6b..d3c6fcc4 100644
--- a/source/funkin/backend/utils/XMLUtil.hx
+++ b/source/funkin/backend/utils/XMLUtil.hx
@@ -147,6 +147,8 @@ final 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 fd2a3f1e..be097756 100644
--- a/source/funkin/editors/character/CharacterEditor.hx
+++ b/source/funkin/editors/character/CharacterEditor.hx
@@ -362,7 +362,7 @@ class CharacterEditor extends UIState {
}
animationText.text = '"${character.getAnimName()}"';
- if (Options.characterDragging)
+ if (Options.characterDragging)
handleMouseOffsets();
super.update(elapsed);
diff --git a/source/funkin/editors/charter/ChartCreationScreen.hx b/source/funkin/editors/charter/ChartCreationScreen.hx
index 3909869d..3a4eba1a 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",
@@ -333,7 +333,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 597ef7ae..4d408800 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -1325,7 +1325,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;
@@ -1382,7 +1382,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();
@@ -1398,7 +1398,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();
@@ -1408,7 +1408,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(_);
@@ -1416,20 +1416,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',
}));
}
@@ -1437,7 +1437,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(_);
@@ -1446,7 +1446,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
@@ -1775,7 +1775,7 @@ class Charter extends UIState {
changeNoteSustain(-1);
function _note_selectall(_) {
- selection = [for (note in notesGroup.members) note];
+ selection = cast notesGroup.members.copy();
}
function _note_selectmeasure(_) {
diff --git a/source/funkin/editors/charter/CharterEventScreen.hx b/source/funkin/editors/charter/CharterEventScreen.hx
index 60df5d9a..35c0dd1c 100644
--- a/source/funkin/editors/charter/CharterEventScreen.hx
+++ b/source/funkin/editors/charter/CharterEventScreen.hx
@@ -164,7 +164,11 @@ class CharterEventScreen extends UISubstateWindow {
colorWheel;
case TDropDown(options):
addLabel();
- var dropdown = new UIDropDown(eventName.x, y, 320, 32, options, Std.int(Math.abs(options.indexOf(cast value))));
+ var optionIndex = options.indexOf(cast value);
+ if(optionIndex < 0) {
+ optionIndex = 0;
+ }
+ var dropdown = new UIDropDown(eventName.x, y, 320, 32, options, optionIndex);
paramsPanel.add(dropdown); paramsFields.push(dropdown);
dropdown;
case TCharacter:
diff --git a/source/funkin/editors/charter/CharterMetaDataScreen.hx b/source/funkin/editors/charter/CharterMetaDataScreen.hx
index 660e3d89..0ab7900c 100644
--- a/source/funkin/editors/charter/CharterMetaDataScreen.hx
+++ b/source/funkin/editors/charter/CharterMetaDataScreen.hx
@@ -129,7 +129,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 24fe55f4..a3e0910d 100644
--- a/source/funkin/editors/charter/CharterSelection.hx
+++ b/source/funkin/editors/charter/CharterSelection.hx
@@ -109,9 +109,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
var option = new EditorIconOption(creation.meta.name, "Press ACCEPT to choose a difficulty to edit.", creation.meta.icon, function() {
@@ -147,7 +147,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
curSong.difficulties.push(name);
diff --git a/source/funkin/editors/charter/CharterStrumlineScreen.hx b/source/funkin/editors/charter/CharterStrumlineScreen.hx
index 702afd9b..42d543c9 100644
--- a/source/funkin/editors/charter/CharterStrumlineScreen.hx
+++ b/source/funkin/editors/charter/CharterStrumlineScreen.hx
@@ -48,7 +48,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
if (creatingStrumLine)
strumLine = {
- characters: ["dad"],
+ characters: [Flags.DEFAULT_OPPONENT],
type: OPPONENT,
notes: [],
position: "dad",
@@ -256,7 +256,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 80549cf7..d6d526e5 100644
--- a/source/funkin/editors/charter/SongCreationScreen.hx
+++ b/source/funkin/editors/charter/SongCreationScreen.hx
@@ -80,7 +80,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;
@@ -90,7 +92,7 @@ class SongCreationScreen extends UISubstateWindow {
"Inst Audio File $* Required$",
[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;
@@ -211,7 +213,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/editors/ui/UISubstateWindow.hx b/source/funkin/editors/ui/UISubstateWindow.hx
index 736c5472..be975868 100644
--- a/source/funkin/editors/ui/UISubstateWindow.hx
+++ b/source/funkin/editors/ui/UISubstateWindow.hx
@@ -1,5 +1,8 @@
package funkin.editors.ui;
+import openfl.display.ShaderParameter;
+import openfl.display.ShaderInput;
+import openfl.filters.ShaderFilter;
import flixel.tweens.FlxTween;
import funkin.backend.shaders.CustomShader;
import openfl.filters.ShaderFilter;
@@ -7,7 +10,17 @@ import openfl.filters.ShaderFilter;
// TODO: make UIWarningSubstate extend this
class UISubstateWindow extends MusicBeatSubstate {
var camShaders:Array = [];
- var blurShader:CustomShader = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast");
+ var blurShader:CustomShader = {
+ var _ = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast");
+ if(!Options.intensiveBlur) {
+ var noiseTexture:ShaderInput = _.data.noiseTexture;
+ noiseTexture.input = Assets.getBitmapData("assets/shaders/noise256.png");
+ noiseTexture.wrap = REPEAT;
+ var noiseTextureSize:ShaderParameter = _.data.noiseTextureSize;
+ noiseTextureSize.value = [noiseTexture.input.width, noiseTexture.input.height];
+ }
+ _;
+ };
var titleSpr:UIText;
var messageSpr:UIText;
diff --git a/source/funkin/editors/ui/UIWarningSubstate.hx b/source/funkin/editors/ui/UIWarningSubstate.hx
index 718980f0..1440c0bc 100644
--- a/source/funkin/editors/ui/UIWarningSubstate.hx
+++ b/source/funkin/editors/ui/UIWarningSubstate.hx
@@ -1,5 +1,8 @@
package funkin.editors.ui;
+import openfl.display.ShaderParameter;
+import openfl.display.ShaderInput;
+import openfl.filters.ShaderFilter;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import funkin.backend.shaders.CustomShader;
@@ -7,7 +10,17 @@ import openfl.filters.ShaderFilter;
class UIWarningSubstate extends MusicBeatSubstate {
var camShaders:Array = [];
- var blurShader:CustomShader = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast");
+ var blurShader:CustomShader = {
+ var _ = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast");
+ if(!Options.intensiveBlur) {
+ var noiseTexture:ShaderInput = _.data.noiseTexture;
+ noiseTexture.input = Assets.getBitmapData("assets/shaders/noise256.png");
+ noiseTexture.wrap = REPEAT;
+ var noiseTextureSize:ShaderParameter = _.data.noiseTextureSize;
+ noiseTextureSize.value = [noiseTexture.input.width, noiseTexture.input.height];
+ }
+ _;
+ };
var title:String;
var message:String;
diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx
index 84bc5094..ff6ae27e 100644
--- a/source/funkin/game/Character.hx
+++ b/source/funkin/game/Character.hx
@@ -12,13 +12,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;
@@ -36,8 +34,8 @@ using StringTools;
@:allow(funkin.game.PlayState)
class Character extends FunkinSprite implements IBeatReceiver implements IOffsetCompatible implements IPrePostDraw {
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;
@@ -68,12 +66,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;
@@ -130,7 +128,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;
}
@@ -156,6 +154,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)
@@ -182,6 +185,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]);
@@ -234,6 +240,9 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public var ghostDraw:Bool = false;
public override function draw() {
+ var e = EventManager.get(DrawEvent).recycle();
+ script.call("draw", [e]);
+
preDraw();
super.draw();
postDraw();
@@ -242,6 +251,8 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if (debugHitbox) drawHitbox();
if (debugCamera) drawCamera();
}
+
+ script.call("postDraw", [e]);
}
public var debugHitbox:Bool = false;
@@ -353,15 +364,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
@:noCompletion var __reverseTrailProcedure:Bool = false;
- // When using trails on characters you should do `trail.beforeCache = char.beforeTrailCache;`
+ // When using trails on characters you should do `trail.beforeCache = char.beforeTrailCache;` and `trail.afterCache = char.afterTrailCache;`
public dynamic function beforeTrailCache()
if (isFlippedOffsets()) {
flipX = !flipX;
scale.x *= -1;
__reverseTrailProcedure = true;
}
-
- // When using trails on characters you should do `trail.afterCache = char.afterTrailCache;`
+
public dynamic function afterTrailCache()
if (__reverseTrailProcedure) {
flipX = !flipX;
@@ -540,6 +550,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);
@@ -557,8 +570,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) {
@@ -595,7 +606,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;
@@ -618,4 +629,4 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
list.push(CoolUtil.getFilename(path));
return list;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx
index 9b8d01e5..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,20 +37,16 @@ class GameOverSubstate extends MusicBeatSubstate
public var lossSFX:FlxSound;
- public function new(x:Float, y:Float, character:String = null, 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;
-
- characterName = character;
- if (characterName == null)
- characterName = Character.FALLBACK_DEAD_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()
@@ -60,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);
@@ -131,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);
}
}
@@ -202,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 1c7bb59d..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);
@@ -90,14 +90,12 @@ class HealthIcon extends FlxSprite
if (animation.curAnim != null) {
var i:Int = -1;
var oldKey:Int = -1;
- for(k=>icon in healthSteps) {
- if (k > oldKey && k < health * 100) {
- oldKey = k;
- i = icon;
- }
+ for (k=>icon in healthSteps) if (k > oldKey && k <= health * 100) {
+ oldKey = k;
+ 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 5cc35051..f7cac647 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 8c611581..8213a900 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 f3962944..01b50108 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) {
@@ -702,15 +742,15 @@ class PlayState extends MusicBeatState
// HUD INITIALIZATION & CAMERA INITIALIZATION
#if REGION
var event = EventManager.get(AmountEvent).recycle(null);
- if (!scripts.event("onPreGenerateStrums", event).cancelled) {
+ 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;
@@ -739,10 +779,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);
@@ -779,7 +820,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 = " (Chart Playtesting)";
SaveWarning.showWarning = Charter.undos.unsaved;
@@ -804,7 +845,7 @@ class PlayState extends MusicBeatState
__updateNote_event = EventManager.get(NoteUpdateEvent);
- scripts.call("postCreate");
+ gameAndCharsCall("postCreate", null, "gamePostCreate");
}
/**
@@ -835,7 +876,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() {
@@ -868,7 +909,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;
@@ -881,14 +922,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],
@@ -931,12 +972,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;
@@ -963,7 +1004,7 @@ class PlayState extends MusicBeatState
updateDiscordPresence();
- scripts.call("onStartSong");
+ gameAndCharsCall("onStartSong");
}
public override function destroy() {
@@ -1010,11 +1051,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
@@ -1044,7 +1089,7 @@ class PlayState extends MusicBeatState
@: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;
@@ -1064,13 +1109,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)
@@ -1104,7 +1149,7 @@ class PlayState extends MusicBeatState
inst.resume();
vocals.resume();
}
- scripts.call("onFocus");
+ gameAndCharsCall("onFocus");
updateDiscordPresence();
super.onFocus();
}
@@ -1117,7 +1162,7 @@ class PlayState extends MusicBeatState
inst.pause();
vocals.pause();
}
- scripts.call("onFocusLost");
+ gameAndCharsCall("onFocusLost");
updateDiscordPresence();
super.onFocusLost();
}
@@ -1136,14 +1181,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;
@@ -1151,7 +1196,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());
@@ -1208,7 +1253,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);
@@ -1267,8 +1312,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();
@@ -1287,7 +1333,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;
}
@@ -1312,7 +1358,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);
}
@@ -1357,10 +1403,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":
@@ -1420,11 +1468,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 : Character.FALLBACK_DEAD_CHARACTER),
+ deathCharID.getDefault(charToUse != null ? charToUse.gameOverCharacter : Flags.DEFAULT_GAMEOVER_CHARACTER),
charToUse != null ? charToUse.isPlayer : true,
gameOverSong.getDefault(this.gameOverSong),
lossSFX.getDefault(this.lossSFX),
@@ -1449,7 +1497,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);
}
/**
@@ -1457,7 +1505,7 @@ class PlayState extends MusicBeatState
*/
public function endSong():Void
{
- scripts.call("onSongEnd");
+ gameAndCharsCall("onSongEnd");
canPause = false;
inst.volume = 0;
vocals.volume = 0;
@@ -1578,7 +1626,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;
@@ -1662,11 +1710,13 @@ class PlayState extends MusicBeatState
var event:NoteHitEvent;
if (strumLine != null && !strumLine.cpu)
- event = scripts.event("onPlayerHit", 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 = scripts.event("onDadHit", 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) {
@@ -1681,7 +1731,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;
}
}
@@ -1711,7 +1762,7 @@ class PlayState extends MusicBeatState
}
}
- if (event.deleteNote && !note.isSustainNote) strumLine.deleteNote(note);
+ if (event.deleteNote) strumLine.deleteNote(note);
}
public function displayRating(myRating:String, ?evt:NoteHitEvent = null):Void {
@@ -1740,14 +1791,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;
@@ -1769,6 +1818,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}'));
@@ -1820,14 +1870,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();
@@ -1915,7 +1966,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;
@@ -1935,7 +1987,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 7d8f9211..7da89aad 100644
--- a/source/funkin/game/SplashGroup.hx
+++ b/source/funkin/game/SplashGroup.hx
@@ -43,7 +43,7 @@ class SplashGroup extends FlxTypedGroup {
Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR);
valid = false;
}
- maxSize = 8;
+ maxSize = Flags.MAX_SPLASHES;
}
var _scale:Float = 1.0;
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 e3f0ad4c..7ce0f48c 100644
--- a/source/funkin/game/Stage.hx
+++ b/source/funkin/game/Stage.hx
@@ -8,8 +8,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;
@@ -106,8 +105,8 @@ class Stage extends FlxBasic implements IBeatReceiver {
}
if (PlayState.instance == state) {
- event = EventManager.get(StageXMLEvent).recycle(this, xml, elems);
- elems = PlayState.instance.scripts.event("onStageXMLParsed", event).elems;
+ event = EventManager.get(StageXMLEvent).recycle(this, stageXML, elems);
+ elems = PlayState.instance.gameAndCharsEvent("onStageXMLParsed", event).elems;
}
if(onXMLLoaded != null) {
elems = onXMLLoaded(xml, elems);
@@ -163,7 +162,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
}
if(PlayState.instance == state) {
- 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(onNodeLoaded != null) {
sprite = onNodeLoaded(node, sprite);
@@ -213,7 +212,6 @@ class Stage extends FlxBasic implements IBeatReceiver {
if(onXMLPostLoaded != null) {
elems = onXMLPostLoaded(xml, elems);
}
-
}
public static function getDefaultPos(name:String):StageCharPosInfo {
diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx
index d1b8fa1a..2477d60c 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 b3b16c8e..d7ebd934 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;
@@ -89,7 +95,7 @@ class DialogueCutscene extends Cutscene {
musicVolume: node.has.musicVolume ? (volume = Std.parseFloat(node.att.speed).getDefault(0.8)) : null,
changeMusic: node.has.changeMusic ? FlxG.sound.load(Paths.music(node.att.changeMusic), volume, true) : null,
playSound: node.has.playSound ? FlxG.sound.load(Paths.sound(node.att.playSound)) : null,
- nextSound: node.has.nextSound ? FlxG.sound.load(Paths.music(node.att.nextSound)) : null,
+ nextSound: node.has.nextSound ? FlxG.sound.load(Paths.sound(node.att.nextSound)) : null,
textSound: null
};
@@ -110,22 +116,21 @@ class DialogueCutscene extends Cutscene {
next(true);
} catch(e) {
- Logs.trace('Error while loading dialogue at ${dialoguePath}: ${e.toString()}', ERROR);
- 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();
@@ -138,8 +143,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) {
@@ -154,7 +159,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)
@@ -167,8 +172,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) {
@@ -178,7 +183,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() {
@@ -193,8 +198,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;
@@ -215,4 +218,4 @@ typedef DialogueLine = {
var nextSound:FlxSound;
var textSound:FlxSound;
var changeDefAnim:String;
-}
\ No newline at end of file
+}
diff --git a/source/funkin/game/cutscenes/ScriptedCutscene.hx b/source/funkin/game/cutscenes/ScriptedCutscene.hx
index b305cca0..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.trace('Could not find script for scripted cutscene at ${scriptPath}', ERROR, RED);
- 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 a948344d..b445b611 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.trace('Couldn\'t load dialogue box "$name": ${e.toString()}', ERROR);
+ 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 d53bcbd9..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.trace('Failed to load dialogue character $name: ${message}', ERROR);
+ 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 d436138f..30e3c4fd 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('This engine is still in a *${Main.releaseCycle}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue',
+ disclaimer.applyMarkup('This engine is still in a *${Flags.RELEASE_CYCLE}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue',
[
new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*")
]
diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx
index c1670dfd..afb142ea 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;
@@ -458,7 +459,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 cd40bc90..5f580868 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()
{
@@ -72,7 +73,7 @@ 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')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n');
+ versionText = new FunkinText(5, FlxG.height - 2, 0, '${Flags.VERSION_MESSAGE}\n${Flags.COMMIT_MESSAGE}\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n');
versionText.y -= versionText.height;
versionText.scrollFactor.set();
add(versionText);
@@ -158,7 +159,7 @@ class MainMenuState extends MusicBeatState
var event = event("onSelectItem", EventManager.get(NameEvent).recycle(daChoice));
if (event.cancelled) return;
- switch (daChoice)
+ switch (event.name)
{
case 'story mode': FlxG.switchState(new StoryMenuState());
case 'freeplay': FlxG.switchState(new FreeplayState());
diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx
index 7101486c..1ab70f33 100644
--- a/source/funkin/menus/PauseSubState.hx
+++ b/source/funkin/menus/PauseSubState.hx
@@ -5,15 +5,16 @@ import flixel.text.FlxText;
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;
import funkin.menus.StoryMenuState;
import funkin.options.OptionsMenu;
import funkin.options.keybinds.KeybindsOptions;
+import funkin.options.TreeMenu;
class PauseSubState extends MusicBeatSubstate
{
@@ -21,19 +22,22 @@ class PauseSubState extends MusicBeatSubstate
var grpMenuShit:FlxTypedGroup;
- 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;
@@ -135,13 +139,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();
@@ -153,9 +155,10 @@ class PauseSubState extends MusicBeatSubstate
persistentDraw = false;
openSubState(new KeybindsOptions());
case "Change Options":
+ TreeMenu.lastState = PlayState;
FlxG.switchState(new OptionsMenu());
case "Exit to charter":
- FlxG.switchState(new funkin.editors.charter.Charter(PlayState.SONG.meta.name, PlayState.difficulty, false));
+ FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, false));
case "Exit to menu":
if (PlayState.chartingMode && Charter.undos.unsaved)
game.saveWarn(false);
@@ -206,4 +209,4 @@ class PauseSubState extends MusicBeatSubstate
item.alpha = 0.6;
}
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx
index 1ed7fa5b..8cc0c431 100644
--- a/source/funkin/menus/StoryMenuState.hx
+++ b/source/funkin/menus/StoryMenuState.hx
@@ -6,15 +6,20 @@ 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
+ public var scoreMessage:String = "WEEK SCORE:{0}";
+
public var scoreText:FlxText;
public var tracklist:FlxText;
public var weekTitle:FlxText;
@@ -23,18 +28,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