diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 4f1084dc..1efcfcfa 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -38,12 +38,12 @@ jobs:
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
- name: Uploading artifact (entire build)
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: Codename Engine
path: CodenameEngine.tar.gz
# - name: Uploading artifact (executable)
- # uses: actions/upload-artifact@v2
+ # uses: actions/upload-artifact@v4
# with:
# name: Update-Linux
# path: export/release/linux/bin/CodenameEngine
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index c11a793f..cdd60670 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -35,12 +35,12 @@ jobs:
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
- name: Uploading artifact (entire build)
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: Codename Engine
path: CodenameEngine.tar.gz
# - name: Uploading artifact (executable)
- # uses: actions/upload-artifact@v2
+ # uses: actions/upload-artifact@v4
# with:
# name: Update-Mac
# path: export/release/macos/bin/CodenameEngine
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 3ec71f90..2986be18 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -33,12 +33,12 @@ jobs:
run: |
haxelib run lime build windows
- name: Uploading artifact (entire build)
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: Codename Engine
path: export/release/windows/bin
# - name: Uploading artifact (executable)
- # uses: actions/upload-artifact@v2
+ # uses: actions/upload-artifact@v4
# with:
# name: Update-Windows
# path: export/release/windows/bin/CodenameEngine.exe
diff --git a/BETAMESSAGE.md b/BETAMESSAGE.md
index 38685be3..cf86b374 100644
--- a/BETAMESSAGE.md
+++ b/BETAMESSAGE.md
@@ -35,7 +35,7 @@ Shoutout to the people who stuck with us throughout the alpha and supported us!
- ### New Features
- Opponent & Co-op modes
- New volume change SFX (no more loud flixel beep, customizable)
- - New FPS counter allowing you to see advanced info by pressing F3.
+ - New FPS counter allowing you to see advanced info by pressing F3 (infos can be selected and copied too when in advanced).
- (Windows) FNF is no longer blurry on 125-150% DPI
- FNF auto fixes audio on state change when you plug in/out your headphones.
- FNF auto applies dark titlebar
diff --git a/FEATURES.md b/FEATURES.md
index 9d53fcaf..caa85417 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -17,7 +17,7 @@ _**QOL = Quality of Life**_
- Usage of [flxanimate](https://github.com/Dot-Stuff/flxanimate) on big sprites, such as Girlfriend to save memory.
- You can further optimize it on certain stages by enabling `Low Memory Mode` in `Options > Appearance`.
- New volume change SFX (no more loud flixel beep, customizable)
-- New FPS counter allowing you to see advanced info by pressing F3.
+- New FPS counter allowing you to see advanced info by pressing F3 (infos can be selected and copied too when in advanced).
- Simple but advanced modding system (press TAB on main menu)
- **Windows only:**
- (Windows) FNF is no longer blurry on 125-150% DPI
diff --git a/README.md b/README.md
index 604cd9c2..b4d4bcc9 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,8 @@ Make sure to read the wiki and join the Discord server linked there!
Latest builds for the engine can be found in the [Actions](https://github.com/YoshiCrafter29/CodenameEngine/actions) tab.
In the future (when the engine won't be a WIP anymore) we're gonna also publish the engine on platforms like Gamebanana; stay tuned!
+If you don't have a github account please go onto https://fnf-cne-devs.github.io/ and click the download button for the respective operating system.
+
How to build
@@ -76,7 +78,7 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
- Steal code from Codename Engine for another different project that is not Codename Engine related (Codename Engine mods excluded) without properly crediting
- Release the entire Codename Engine on platforms (Mods that use Codename Engine as source are fine, if it's specified even better)
- #### *If you need more info or feel like asking to do something which is not listed here, ask us directly on our discord (linked in the wiki)!*
+ #### *If you need more info or feel like asking to do something which is not listed here, ask us directly on our discord (linked on the website)!*
diff --git a/art/flashFiles/Editor_Icons.fla b/art/flashFiles/Editor_Icons.fla
new file mode 100644
index 00000000..6ad80d3d
Binary files /dev/null and b/art/flashFiles/Editor_Icons.fla differ
diff --git a/art/generateDoc.bat b/art/generateDoc.bat
index 5159ca88..e2d35e4f 100644
--- a/art/generateDoc.bat
+++ b/art/generateDoc.bat
@@ -1,7 +1,8 @@
@ECHO OFF
cd ..
echo Building Game...
-lime build windows --haxeflag="--macro include('scripting')" --haxeflag="-xml docs/doc.xml"
-echo Generating Documentation...
-haxelib run dox -i docs --include funkin --include scripting
-echo Done!
\ No newline at end of file
+lime build windows --haxeflag="--macro include('scripting')" --haxeflag="-xml docs/doc.xml" -D DOCUMENTATION --no-output
+echo art
+
+echo Generated the api xml file at docs/doc.xml
+echo Please put this in FNF-CNE-Devs.github.io/api-generator/api/doc.xml
\ No newline at end of file
diff --git a/assets/data/characters/bf-car.xml b/assets/data/characters/bf-car.xml
index b4c9b24c..bd276ca8 100644
--- a/assets/data/characters/bf-car.xml
+++ b/assets/data/characters/bf-car.xml
@@ -1,12 +1,18 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/da.xml b/assets/data/characters/da.xml
index 2ef057ba..f176be02 100644
--- a/assets/data/characters/da.xml
+++ b/assets/data/characters/da.xml
@@ -1,8 +1,13 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/dad.xml b/assets/data/characters/dad.xml
index 1b1e0f04..39319727 100644
--- a/assets/data/characters/dad.xml
+++ b/assets/data/characters/dad.xml
@@ -1,8 +1,13 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/mom-car.xml b/assets/data/characters/mom-car.xml
index fa7c18dd..e511498f 100644
--- a/assets/data/characters/mom-car.xml
+++ b/assets/data/characters/mom-car.xml
@@ -1,10 +1,16 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/characters/mom.xml b/assets/data/characters/mom.xml
index 4781ede4..43d52076 100644
--- a/assets/data/characters/mom.xml
+++ b/assets/data/characters/mom.xml
@@ -1,10 +1,16 @@
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/data/config/credits.xml b/assets/data/config/credits.xml
index 56a5cafd..4f300fcb 100644
--- a/assets/data/config/credits.xml
+++ b/assets/data/config/credits.xml
@@ -3,5 +3,5 @@
diff --git a/assets/data/config/menuItems.txt b/assets/data/config/menuItems.txt
index 6fc72f13..a8ec55b1 100644
--- a/assets/data/config/menuItems.txt
+++ b/assets/data/config/menuItems.txt
@@ -1,4 +1,4 @@
story mode
freeplay
options
-donate
\ No newline at end of file
+credits
\ No newline at end of file
diff --git a/assets/data/scripts/pixel.hx b/assets/data/scripts/pixel.hx
index cc8239cf..8f1887c8 100644
--- a/assets/data/scripts/pixel.hx
+++ b/assets/data/scripts/pixel.hx
@@ -1,3 +1,4 @@
+//
import funkin.game.HudCamera;
import funkin.backend.scripting.events.NoteHitEvent;
@@ -162,16 +163,18 @@ function postUpdate(elapsed) {
if (enableCameraHacks) {
for(p in strumLines)
p.notes.forEach(function(n) {
+ if(n.isSustainNote) return; // hacky fix for hold
n.y -= n.y % daPixelZoom;
n.x -= n.x % daPixelZoom;
});
}
+ var zoom = 1 / daPixelZoom / Math.min(FlxG.scaleMode.scale.x, FlxG.scaleMode.scale.y);
for(e in pixellyCameras) {
if (!e.exists) continue;
- e.zoom = 1 / daPixelZoom / Math.min(FlxG.scaleMode.scale.x, FlxG.scaleMode.scale.y);
+ e.zoom = zoom;
}
for(e in pixellyShaders) {
- e.pixelZoom = 1 / daPixelZoom / Math.min(FlxG.scaleMode.scale.x, FlxG.scaleMode.scale.y);
+ e.pixelZoom = zoom;
}
}
\ No newline at end of file
diff --git a/assets/data/scripts/week6-pause.hx b/assets/data/scripts/week6-pause.hx
index b382af35..6a4455cd 100644
--- a/assets/data/scripts/week6-pause.hx
+++ b/assets/data/scripts/week6-pause.hx
@@ -73,7 +73,8 @@ function confText(text) {
}
function destroy() {
- FlxG.cameras.remove(pauseCam);
+ if(FlxG.cameras.list.contains(pauseCam))
+ FlxG.cameras.remove(pauseCam);
}
var canDoShit = true;
diff --git a/assets/data/stages/limo.hx b/assets/data/stages/limo.hx
index 0116d55a..d9a58d3c 100644
--- a/assets/data/stages/limo.hx
+++ b/assets/data/stages/limo.hx
@@ -1,39 +1,43 @@
var fastCarCanDrive:Bool = true;
-function create() {
+function create()
resetFastCar();
-}
-function update(elapsed:Float) {
+
+function update(elapsed:Float)
+{
if (!fastCarCanDrive && fastCar.x > 2000) {
resetFastCar();
fastCarCanDrive = true;
}
+ var offset = Math.sin(curBeatFloat / 4) * Math.cos(curBeatFloat / 16) * 85;
+
// back limo drive
if (Options.lowMemoryMode) {
- bgLimo.frameOffset.x = Math.sin(curBeatFloat / 4) * Math.cos(curBeatFloat / 16) * 85;
+ bgLimo.frameOffset.x = offset;
} else {
for(e in [bgLimo, dancer1, dancer2, dancer3, dancer4, dancer5]) {
- e.frameOffset.x = Math.sin(curBeatFloat / 4) * Math.cos(curBeatFloat / 16) * 85;
+ e.frameOffset.x = offset;
}
}
}
-function beatHit(curBeat:Int) {
+function beatHit(curBeat:Int)
if (FlxG.random.bool(10) && fastCarCanDrive)
fastCarDrive();
-}
-
-function resetFastCar() {
+function resetFastCar()
+{
fastCar.x = -12600;
fastCar.y = FlxG.random.int(140, 250);
fastCar.velocity.x = 0;
+ fastCar.moves = false;
fastCarCanDrive = true;
}
function fastCarDrive()
{
FlxG.sound.play(Paths.soundRandom('carPass', 0, 1), 0.7);
- fastCar.velocity.x = (FlxG.random.int(170, 220) / FlxG.elapsed) * 3;
+ fastCar.velocity.x = FlxG.random.int(170, 220) * 60 * 3;
+ fastCar.moves = true;
fastCarCanDrive = false;
}
\ No newline at end of file
diff --git a/assets/data/stages/philly.hx b/assets/data/stages/philly.hx
index 989b29b5..6b120b51 100644
--- a/assets/data/stages/philly.hx
+++ b/assets/data/stages/philly.hx
@@ -1,3 +1,4 @@
+//
import funkin.game.PlayState;
// phillyTrain is automatically added by Stage.hx
diff --git a/assets/data/stages/school-evil.hx b/assets/data/stages/school-evil.hx
index af086dab..c29dbeea 100644
--- a/assets/data/stages/school-evil.hx
+++ b/assets/data/stages/school-evil.hx
@@ -1,5 +1,4 @@
function create() {
- importScript("data/scripts/pixel");
isSpooky = true;
// Make transition work between school types
diff --git a/assets/data/stages/school-evil.xml b/assets/data/stages/school-evil.xml
index 568b3aad..48ee14b7 100644
--- a/assets/data/stages/school-evil.xml
+++ b/assets/data/stages/school-evil.xml
@@ -1,5 +1,6 @@
+
\ No newline at end of file
diff --git a/assets/data/stages/school.hx b/assets/data/stages/school.hx
index 5cba9421..dc55a69d 100644
--- a/assets/data/stages/school.hx
+++ b/assets/data/stages/school.hx
@@ -1,5 +1,5 @@
+//
function create() {
- importScript("data/scripts/pixel");
if (PlayState.SONG.meta.name.toLowerCase() == "roses") {
bgGirls.animation.remove("danceLeft");
bgGirls.animation.remove("danceRight");
diff --git a/assets/data/stages/school.xml b/assets/data/stages/school.xml
index dabf463b..7a2740ad 100644
--- a/assets/data/stages/school.xml
+++ b/assets/data/stages/school.xml
@@ -1,5 +1,7 @@
+
+
diff --git a/assets/images/characters/mom.xml b/assets/images/characters/mom.xml
index 67eeb6b7..51132b97 100644
--- a/assets/images/characters/mom.xml
+++ b/assets/images/characters/mom.xml
@@ -15,8 +15,9 @@
-
-
+
+
diff --git a/assets/images/editors/icons.png b/assets/images/editors/icons.png
index 41dee63c..cccc10f9 100644
Binary files a/assets/images/editors/icons.png and b/assets/images/editors/icons.png differ
diff --git a/assets/images/menus/mainmenu/credits.png b/assets/images/menus/mainmenu/credits.png
new file mode 100644
index 00000000..cb1d9863
Binary files /dev/null and b/assets/images/menus/mainmenu/credits.png differ
diff --git a/assets/images/menus/mainmenu/credits.xml b/assets/images/menus/mainmenu/credits.xml
new file mode 100644
index 00000000..c3c2385e
--- /dev/null
+++ b/assets/images/menus/mainmenu/credits.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/images/menus/mainmenu/donate.png b/assets/images/menus/mainmenu/donate.png
index e4a42749..cf6a6d11 100644
Binary files a/assets/images/menus/mainmenu/donate.png and b/assets/images/menus/mainmenu/donate.png differ
diff --git a/assets/images/menus/mainmenu/freeplay.png b/assets/images/menus/mainmenu/freeplay.png
index a34eed2e..361ddfa7 100644
Binary files a/assets/images/menus/mainmenu/freeplay.png and b/assets/images/menus/mainmenu/freeplay.png differ
diff --git a/assets/images/menus/mainmenu/freeplay.xml b/assets/images/menus/mainmenu/freeplay.xml
index 4c288a07..f66f748f 100644
--- a/assets/images/menus/mainmenu/freeplay.xml
+++ b/assets/images/menus/mainmenu/freeplay.xml
@@ -1,17 +1,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/images/menus/mainmenu/options.png b/assets/images/menus/mainmenu/options.png
index ebe1f86f..20688ecc 100644
Binary files a/assets/images/menus/mainmenu/options.png and b/assets/images/menus/mainmenu/options.png differ
diff --git a/assets/images/menus/mainmenu/story mode.png b/assets/images/menus/mainmenu/story mode.png
index 162f403d..466fa338 100644
Binary files a/assets/images/menus/mainmenu/story mode.png and b/assets/images/menus/mainmenu/story mode.png differ
diff --git a/assets/shaders/engine/editorBlur.frag b/assets/shaders/engine/editorBlur.frag
index 937aa028..59b91c72 100644
--- a/assets/shaders/engine/editorBlur.frag
+++ b/assets/shaders/engine/editorBlur.frag
@@ -18,17 +18,17 @@ void main() {
return;
vec4 color = getColor(camPos);
- float fsteps = steps;
- for(float inside = 1.0; inside < stepsInside+1.0; inside++) {
+ float fsteps = float(steps);
+ for(float inside = 1.0; inside < float(stepsInside)+1.0; inside++) {
for(int i = 0; i < steps; i++) {
- float fi = i;
+ float fi = float(i);
color += getColor(camPos + vec2(
- strength * (inside / stepsInside) * cos(fi / fsteps * (PI * 2.0)),
- strength * (inside / stepsInside) * sin(fi / fsteps * (PI * 2.0))
+ strength * (inside / float(stepsInside)) * cos(fi / fsteps * (PI * 2.0)),
+ strength * (inside / float(stepsInside)) * sin(fi / fsteps * (PI * 2.0))
));
}
}
- color /= steps * stepsInside;
+ color /= vec4(steps * stepsInside);
gl_FragColor = color;
-}
\ No newline at end of file
+}
diff --git a/assets/videos/guns-cutscene.mp4 b/assets/videos/guns-cutscene.mp4
deleted file mode 100644
index cfc7500a..00000000
Binary files a/assets/videos/guns-cutscene.mp4 and /dev/null differ
diff --git a/assets/videos/stress-cutscene.mp4 b/assets/videos/stress-cutscene.mp4
deleted file mode 100644
index 036a54d1..00000000
Binary files a/assets/videos/stress-cutscene.mp4 and /dev/null differ
diff --git a/assets/videos/ugh-cutscene.mp4 b/assets/videos/ugh-cutscene.mp4
deleted file mode 100644
index 8f30a8c7..00000000
Binary files a/assets/videos/ugh-cutscene.mp4 and /dev/null differ
diff --git a/commandline/Main.hx b/commandline/Main.hx
index 8c2f9301..1b5b01b8 100644
--- a/commandline/Main.hx
+++ b/commandline/Main.hx
@@ -12,7 +12,7 @@ class Main {
{
names: ["setup"],
doc: "Setups (or updates) all libraries required for the engine.",
- func: Update.main,
+ func: Setup.main,
dDoc: [
"Usage: setup",
"",
diff --git a/commandline/commands/Update.hx b/commandline/commands/Setup.hx
similarity index 97%
rename from commandline/commands/Update.hx
rename to commandline/commands/Setup.hx
index 2513f747..7671c6f4 100644
--- a/commandline/commands/Update.hx
+++ b/commandline/commands/Setup.hx
@@ -6,7 +6,7 @@ import sys.io.File;
import sys.io.Process;
import sys.FileSystem;
-class Update {
+class Setup {
private static function recursiveDelete(path:String) {
for(file in FileSystem.readDirectory(path)) {
var p = '$path/$file';
@@ -54,10 +54,10 @@ class Update {
case "lib" | "git" | "custom":
var lib:Library = {
name: libNode.att.name,
- type: libNode.name
+ type: libNode.name,
+ skipDeps: libNode.has.skipDeps ? libNode.att.skipDeps == "true" : false,
};
if (libNode.has.global) lib.global = libNode.att.global;
- if (libNode.has.skipDeps) lib.skipDeps = libNode.att.skipDeps;
switch (lib.type) {
case "lib":
if (libNode.has.version) lib.version = libNode.att.version;
@@ -139,7 +139,7 @@ class Update {
case INSTALL:
var lib:Library = event.data;
var globalSuffix:Null = lib.global == "true" ? " --global" : "";
- var skipDeps = lib.skipDeps == "true" ? " --skip-dependencies" : "";
+ var skipDeps = lib.skipDeps ? " --skip-dependencies" : "";
var commandPrefix = commandSuffix + globalSuffix + skipDeps;// + " --no-timeout";
switch(lib.type) {
case "lib":
@@ -278,8 +278,8 @@ class Update {
typedef Library = {
var name:String;
var type:String;
+ var skipDeps:Bool;
var ?global:String;
- var ?skipDeps:String;
var ?recursive:String;
var ?version:String;
var ?ref:String;
diff --git a/project.xml b/project.xml
index 017d8ba8..fc5f5474 100644
--- a/project.xml
+++ b/project.xml
@@ -153,6 +153,8 @@
+
+
@@ -201,6 +203,7 @@
+
diff --git a/source/funkin/backend/FlxAnimate.hx b/source/funkin/backend/FlxAnimate.hx
index c2b6e8c6..e22cb867 100644
--- a/source/funkin/backend/FlxAnimate.hx
+++ b/source/funkin/backend/FlxAnimate.hx
@@ -15,7 +15,7 @@ class FlxAnimate extends flxanimate.FlxAnimate {
for (camera in cameras)
{
rMatrix.identity();
- rMatrix.translate(-limb.offset.x, -limb.offset.y);
+ limb.prepareMatrix(rMatrix, FlxFrameAngle.ANGLE_0, _checkFlipX() != camera.flipX, _checkFlipY() != camera.flipY);
rMatrix.concat(_rMatrix);
if (!camera.visible || !camera.exists || !limbOnScreen(limb, _rMatrix, camera))
return;
diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx
index 4a42326d..09cf8f7b 100644
--- a/source/funkin/backend/FunkinSprite.hx
+++ b/source/funkin/backend/FunkinSprite.hx
@@ -96,6 +96,13 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
super.update(elapsed);
if (animateAtlas != null)
animateAtlas.update(elapsed);
+
+ // hate how it looks like but hey at least its optimized and fast - Nex
+ if (!debugMode && isAnimFinished()) {
+ var name = getAnimName() + '-loop';
+ if (hasAnimation(name))
+ playAnim(name, null, lastAnimContext);
+ }
}
public function loadSprite(path:String, Unique:Bool = false, Key:String = null)
@@ -287,11 +294,16 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
#if REGION
public var lastAnimContext:PlayAnimContext = DANCE;
- public function playAnim(AnimName:String, Force:Bool = false, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0):Void
+ public function playAnim(AnimName:String, ?Force:Null, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0):Void
{
if (AnimName == null)
return;
+ if (Force == null) {
+ var anim = animDatas.get(AnimName);
+ Force = anim != null && anim.forced;
+ }
+
if (animateAtlas != null)
{
@:privateAccess
@@ -328,6 +340,10 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
}
+ public inline function isAnimReversed():Bool {
+ return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
+ }
+
public inline function removeAnimation(name:String) {
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
diff --git a/source/funkin/backend/chart/EventsData.hx b/source/funkin/backend/chart/EventsData.hx
index eff3fd8e..64b8ce93 100644
--- a/source/funkin/backend/chart/EventsData.hx
+++ b/source/funkin/backend/chart/EventsData.hx
@@ -69,7 +69,11 @@ class EventsData {
hscriptInterp.variables.set("String", TString);
hscriptInterp.variables.set("StrumLine", TStrumLine);
hscriptInterp.variables.set("ColorWheel", TColorWheel);
- hscriptInterp.variables.set("DropDown", Reflect.makeVarArgs((args) -> {return args.length > 0 ? TDropDown([for (arg in args) Std.string(arg)]) : TDropDown(["null"]);}));
+ hscriptInterp.variables.set("DropDown", Reflect.makeVarArgs(function(args:Array):EventParamType {
+ var flatArgs = CoolUtil.deepFlatten(args);
+ if(flatArgs.length == 0) return TDropDown(["null"]);
+ return TDropDown([for (arg in flatArgs) Std.string(arg)]);
+ }));
hscriptInterp.variables.set("Character", TCharacter);
hscriptInterp.variables.set("Stage", TStage);
@@ -77,11 +81,12 @@ class EventsData {
hscriptParser.allowJSON = hscriptParser.allowMetadata = false;
for (file in Paths.getFolderContent('data/events/', true, BOTH)) {
- if (Path.extension(file) != "json" && Path.extension(file) != "pack") continue;
- var eventName:String = Path.withoutExtension(Path.withoutDirectory(file));
+ var ext = Path.extension(file);
+ if (ext != "json" && ext != "pack") continue;
+ var eventName:String = CoolUtil.getFilename(file);
var fileTxt:String = Assets.getText(file);
- if (Path.extension(file) == "pack") {
+ if (ext == "pack") {
var arr = fileTxt.split("________PACKSEP________");
eventName = Path.withoutExtension(arr[0]);
fileTxt = arr[2];
@@ -93,13 +98,17 @@ class EventsData {
eventsParams.set(eventName, []);
try {
- var data:Dynamic = Json.parse(fileTxt);
+ var data:EventInfoFile = cast Json.parse(fileTxt);
if (data == null || data.params == null) continue;
var finalParams:Array = [];
- for (paramData in cast(data.params, Array)) {
+ for (paramData in data.params) {
try {
- finalParams.push({name: paramData.name, type: hscriptInterp.expr(hscriptParser.parseString(paramData.type)), defValue: paramData.defaultValue});
+ finalParams.push({
+ name: paramData.name,
+ type: hscriptInterp.expr(hscriptParser.parseString(paramData.type)),
+ defValue: paramData.defaultValue
+ });
} catch (e) {trace('Error parsing event param ${paramData.name} - ${eventName}: $e'); finalParams.push(null);}
}
eventsParams.set(eventName, finalParams);
@@ -110,6 +119,14 @@ class EventsData {
}
}
+typedef EventInfoFile = {
+ var params:Array<{
+ var name:String;
+ var type:String;
+ var defaultValue:Dynamic;
+ }>;
+}
+
typedef EventInfo = {
var params:Array;
var paramValues:Array;
diff --git a/source/funkin/backend/scripting/EventManager.hx b/source/funkin/backend/scripting/EventManager.hx
index 84e7d33f..ab47bb5d 100644
--- a/source/funkin/backend/scripting/EventManager.hx
+++ b/source/funkin/backend/scripting/EventManager.hx
@@ -14,8 +14,9 @@ class EventManager {
var index = eventKeys.indexOf(c);
if (index < 0) {
eventKeys.push(c);
- eventValues.push(Type.createInstance(c, []));
- return cast eventValues.last();
+ var ret;
+ eventValues.push(ret = Type.createInstance(c, []));
+ return cast ret;
}
return cast eventValues[index];
diff --git a/source/funkin/backend/scripting/HScript.hx b/source/funkin/backend/scripting/HScript.hx
index f2638f82..c19c82fc 100644
--- a/source/funkin/backend/scripting/HScript.hx
+++ b/source/funkin/backend/scripting/HScript.hx
@@ -64,7 +64,7 @@ class HScript extends Script {
}
private function importFailedCallback(cl:Array):Bool {
- if(_importFailedCallback(cl, "") || _importFailedCallback(cl, "source/")) {
+ if(_importFailedCallback(cl, "source/") || _importFailedCallback(cl, "")) {
return true;
}
return false;
diff --git a/source/funkin/backend/scripting/ModState.hx b/source/funkin/backend/scripting/ModState.hx
index adc0a42c..94a6ac7b 100644
--- a/source/funkin/backend/scripting/ModState.hx
+++ b/source/funkin/backend/scripting/ModState.hx
@@ -1,10 +1,38 @@
package funkin.backend.scripting;
class ModState extends MusicBeatState {
+
+ /**
+ * Name of HScript file in assets/data/states.
+ */
public static var lastName:String = null;
- public function new(stateName:String) {
- if (stateName != null)
- lastName = stateName;
+ /**
+ * Last Optional extra data.
+ */
+ public static var lastData:Dynamic = null;
+
+ /**
+ * Optional extra data.
+ */
+ public var data:Dynamic = null;
+
+ /**
+ * ModState Constructor.
+ * Inherits from MusicBeatState and allows the execution of an HScript from assets/data/states passed via parameters.
+ *
+ * @param _stateName Name or path to a HScript file from assets/data/states.
+ * @param _data Optional extra Dynamic data passed from a previous state (JSON suggested).
+ */
+ public function new(_stateName:String, ?_data:Dynamic) {
+ if(_stateName != null && _stateName != lastName) {
+ lastName = _stateName;
+ lastData = null;
+ }
+
+ if(_data != null)
+ lastData = _data;
+
+ data = lastData;
super(true, lastName);
}
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/ModSubState.hx b/source/funkin/backend/scripting/ModSubState.hx
index 5f06072c..acd90f62 100644
--- a/source/funkin/backend/scripting/ModSubState.hx
+++ b/source/funkin/backend/scripting/ModSubState.hx
@@ -1,10 +1,38 @@
package funkin.backend.scripting;
class ModSubState extends MusicBeatSubstate {
+
+ /**
+ * Name of HScript file in assets/data/states.
+ */
public static var lastName:String = null;
- public function new(stateName:String) {
- if (stateName != null)
- lastName = stateName;
+ /**
+ * Last Optional extra data.
+ */
+ public static var lastData:Dynamic = null;
+
+ /**
+ * Optional extra data.
+ */
+ public var data:Dynamic = null;
+
+ /**
+ * ModSubState Constructor.
+ * Inherits from MusicBeatSubstate and allows the execution of an HScript from assets/data/states passed via parameters.
+ *
+ * @param _stateName Name or path to a HScript file from assets/data/states.
+ * @param _data Optional extra Dynamic data passed from a previous state (JSON suggested).
+ */
+ public function new(_stateName:String, ?_data:Dynamic) {
+ if(_stateName != null && _stateName != lastName) {
+ lastName = _stateName;
+ lastData = null;
+ }
+
+ if(_data != null)
+ lastData = _data;
+
+ data = lastData;
super(true, lastName);
}
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/Script.hx b/source/funkin/backend/scripting/Script.hx
index b70f5766..d9aaea5a 100644
--- a/source/funkin/backend/scripting/Script.hx
+++ b/source/funkin/backend/scripting/Script.hx
@@ -288,7 +288,7 @@ class Script extends FlxBasic implements IFlxDestroyable {
public function get(variable:String):Dynamic {return null;}
/**
- * Gets the variable `variable` from the script's variables.
+ * Sets the variable `variable` from the script's variables.
* @param variable Name of the variable.
* @return Variable (or null if it doesn't exists)
*/
diff --git a/source/funkin/backend/scripting/events/DirectionAnimEvent.hx b/source/funkin/backend/scripting/events/DirectionAnimEvent.hx
index a23626f4..dce2eaff 100644
--- a/source/funkin/backend/scripting/events/DirectionAnimEvent.hx
+++ b/source/funkin/backend/scripting/events/DirectionAnimEvent.hx
@@ -26,7 +26,7 @@ final class DirectionAnimEvent extends CancellableEvent {
**/
public var frame:Int;
/**
- Force the animation to replay even if it's already playing.
+ Force the animation to replay even if it's already playing (if it's null it will be forced based on the sprite's data xml, if it has one).
**/
- public var force:Bool = true;
+ public var force:Null;
}
diff --git a/source/funkin/backend/scripting/events/NoteHitEvent.hx b/source/funkin/backend/scripting/events/NoteHitEvent.hx
index d5f64dc3..4bac078e 100644
--- a/source/funkin/backend/scripting/events/NoteHitEvent.hx
+++ b/source/funkin/backend/scripting/events/NoteHitEvent.hx
@@ -100,9 +100,9 @@ final class NoteHitEvent extends CancellableEvent {
*/
public var ratingAntialiasing:Bool = true;
/**
- * Whenever the animation should be forced to play.
+ * Whenever the animation should be forced to play (if it's null it will be forced based on the sprite's data xml, if it has one).
*/
- public var forceAnim:Bool = true;
+ public var forceAnim:Null = true;
/**
* Prevents the default sing animation from being played.
diff --git a/source/funkin/backend/scripting/events/NoteMissEvent.hx b/source/funkin/backend/scripting/events/NoteMissEvent.hx
index e9475bb0..72f87ddd 100644
--- a/source/funkin/backend/scripting/events/NoteMissEvent.hx
+++ b/source/funkin/backend/scripting/events/NoteMissEvent.hx
@@ -29,9 +29,9 @@ final class NoteMissEvent extends CancellableEvent {
public var gfSadAnim:String;
public var forceGfAnim:Bool;
/**
- * Whenever the animation should be forced to play.
+ * Whenever the animation should be forced to play (if it's null it will be forced based on the sprite's data xml, if it has one).
*/
- public var forceAnim:Bool;
+ public var forceAnim:Null;
/**
* Suffix of the animation. "miss" for miss notes, "-alt" for alt notes, "" for normal ones.
*/
diff --git a/source/funkin/backend/scripting/events/PlayAnimEvent.hx b/source/funkin/backend/scripting/events/PlayAnimEvent.hx
index a555c3ed..f51c8243 100644
--- a/source/funkin/backend/scripting/events/PlayAnimEvent.hx
+++ b/source/funkin/backend/scripting/events/PlayAnimEvent.hx
@@ -7,9 +7,9 @@ final class PlayAnimEvent extends CancellableEvent {
public var animName:String;
/**
- Whenever the animation will be forced or not.
+ Whenever the animation will be forced or not (if it's null it will be forced based on the sprite's data xml, if it has one).
**/
- public var force:Bool;
+ public var force:Null;
/**
Whenever the animation will play in reverse or not
diff --git a/source/funkin/backend/scripting/events/SplashShowEvent.hx b/source/funkin/backend/scripting/events/SplashShowEvent.hx
new file mode 100644
index 00000000..46504d44
--- /dev/null
+++ b/source/funkin/backend/scripting/events/SplashShowEvent.hx
@@ -0,0 +1,23 @@
+package funkin.backend.scripting.events;
+
+import funkin.game.SplashGroup;
+import funkin.game.Strum;
+
+final class SplashShowEvent extends CancellableEvent {
+ /**
+ Splash name/type
+ **/
+ public var splashName:String;
+ /**
+ Splash that is shown
+ **/
+ public var splash:FunkinSprite;
+ /**
+ Strum that the splash is shown on
+ **/
+ public var strum:Strum;
+ /**
+ Splash group that the splash is from
+ **/
+ public var group:SplashGroup;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/shaders/FunkinShader.hx b/source/funkin/backend/shaders/FunkinShader.hx
index b676ae45..0b282ffb 100644
--- a/source/funkin/backend/shaders/FunkinShader.hx
+++ b/source/funkin/backend/shaders/FunkinShader.hx
@@ -438,34 +438,33 @@ uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
-vec4 flixel_texture2D(sampler2D bitmap, vec2 coord)
-{
- vec4 color = texture2D(bitmap, coord);
- if (!hasTransform)
- {
+vec4 applyFlixelEffects(vec4 color) {
+ if(!hasTransform) {
return color;
}
- if (color.a == 0.0)
- {
+ if(color.a == 0.0) {
return vec4(0.0, 0.0, 0.0, 0.0);
}
- if (!hasColorTransform)
- {
+ if(!hasColorTransform) {
return color * openfl_Alphav;
}
- color = vec4(color.rgb / color.a, color.a);
+ color.rgb = color.rgb / color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
- if (color.a > 0.0)
- {
+ if(color.a > 0.0) {
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
return vec4(0.0, 0.0, 0.0, 0.0);
}
+vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
+ vec4 color = texture2D(bitmap, coord);
+ return applyFlixelEffects(color);
+}
+
uniform vec4 _camSize;
float map(float value, float min1, float max1, float min2, float max2) {
@@ -484,9 +483,7 @@ vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
- public static final fragBody:String = "vec4 color = flixel_texture2D (bitmap, openfl_TextureCoordv);
- gl_FragColor = color;
-";
+ public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);";
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
@@ -500,16 +497,26 @@ varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
-uniform vec2 openfl_TextureSize;";
+uniform vec2 openfl_TextureSize;
+
+attribute float alpha;
+attribute vec4 colorMultiplier;
+attribute vec4 colorOffset;
+uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
-if (openfl_HasColorTransform) {
-
+if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
+}
+openfl_Alphav = openfl_Alpha * alpha;
+
+if(hasColorTransform) {
+ openfl_ColorOffsetv = colorOffset / 255.0;
+ openfl_ColorMultiplierv = colorMultiplier;
}
gl_Position = openfl_Matrix * openfl_Position;";
@@ -517,31 +524,14 @@ gl_Position = openfl_Matrix * openfl_Position;";
public static final defaultVertexSource:String = "#pragma header
-attribute float alpha;
-attribute vec4 colorMultiplier;
-attribute vec4 colorOffset;
-uniform bool hasColorTransform;
-
-void main(void)
-{
+void main(void) {
#pragma body
-
- openfl_Alphav = openfl_Alpha * alpha;
-
- if (hasColorTransform)
- {
- openfl_ColorOffsetv = colorOffset / 255.0;
- openfl_ColorMultiplierv = colorMultiplier;
- }
}";
-
- // TODO: camera stuff
public static final defaultFragmentSource:String = "#pragma header
-void main(void)
-{
- gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
+void main(void) {
+ #pragma body
}";
}
diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx
new file mode 100644
index 00000000..fed62113
--- /dev/null
+++ b/source/funkin/backend/system/Flags.hx
@@ -0,0 +1,63 @@
+package funkin.backend.system;
+
+import lime.utils.AssetLibrary;
+import lime.utils.AssetType;
+
+import funkin.backend.assets.IModsAssetLibrary;
+import funkin.backend.assets.ScriptedAssetLibrary;
+
+/**
+ * A class that reads the `flags.ini` file, allowing to read settable Flags (customs too).
+ */
+@:build(funkin.backend.system.macros.FlagMacro.build())
+class Flags {
+ public static var SONGS_LIST_MOD_MODE:Allow<"prepend", "override", "append"> = "override";
+ public static var WEEKS_LIST_MOD_MODE:Allow<"prepend", "override", "append"> = "override";
+
+ // Internal stuff
+
+ @:bypass public static var customFlags:Map = [];
+
+ public static function load() {
+ var flags:Map = [];
+
+ final flagsPath = Paths.getPath("flags.ini");
+
+ for(lib in Paths.assetsTree.libraries) {
+ if(lib.exists(flagsPath, AssetType.TEXT)) {
+ var data:String = lib.getAsset(flagsPath, AssetType.TEXT);
+ var trimmed:String;
+ var splitContent = [for(e in data.split("\n")) if ((trimmed = e.trim()) != "") trimmed];
+
+ for(line in splitContent) {
+ if (line.startsWith(";")) continue;
+ if (line.startsWith("#")) continue;
+ if (line.startsWith("//")) continue;
+ if(line.length == 0) continue;
+ if(line.charAt(0) == "[" && line.charAt(line.length-1) == "]") continue;
+
+ var index = line.indexOf("=");
+ if(index == -1) continue;
+ var name = line.substr(0, index).trim();
+ var value = line.substr(index+1).trim();
+
+ if (value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code)
+ value = value.substr(1, value.length - 2);
+
+ if (value.length == 0 || name.length == 0)
+ continue;
+
+ if(!flags.exists(name))
+ flags[name] = value;
+ }
+ }
+ }
+
+ customFlags = [];
+ reset();
+ for(name=>value in flags)
+ if(!parse(name, value)) {
+ customFlags.set(name, value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx
index 17b3587f..3d2358c2 100644
--- a/source/funkin/backend/system/MainState.hx
+++ b/source/funkin/backend/system/MainState.hx
@@ -8,6 +8,7 @@ import funkin.backend.assets.ModsFolder;
import funkin.backend.chart.EventsData;
import funkin.menus.BetaWarningState;
import funkin.menus.TitleState;
+import funkin.backend.system.framerate.Framerate;
/**
* Simple state used for loading the game
@@ -57,10 +58,14 @@ class MainState extends FlxState {
ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
TranslationUtil.findAllLanguages();
TranslationUtil.setLanguage();
+ Flags.load();
DiscordUtil.init();
EventsData.reloadEvents();
TitleState.initialized = false;
+ if(Framerate.isLoaded)
+ Framerate.instance.reload();
+
if (betaWarningShown)
FlxG.switchState(new TitleState());
else {
diff --git a/source/funkin/backend/system/framerate/CodenameBuildField.hx b/source/funkin/backend/system/framerate/CodenameBuildField.hx
index 3175a01e..5519f4d8 100644
--- a/source/funkin/backend/system/framerate/CodenameBuildField.hx
+++ b/source/funkin/backend/system/framerate/CodenameBuildField.hx
@@ -9,6 +9,9 @@ class CodenameBuildField extends TextField {
defaultTextFormat = Framerate.textFormat;
autoSize = LEFT;
multiline = wordWrap = false;
- text = 'Codename Engine ${Main.releaseCycle}\nCommit ${GitCommitMacro.commitNumber} (${GitCommitMacro.commitHash})';
+ reload();
}
+
+ public function reload()
+ text = 'Codename Engine ${Main.releaseCycle}\nCommit ${GitCommitMacro.commitNumber} (${GitCommitMacro.commitHash})';
}
diff --git a/source/funkin/backend/system/framerate/Framerate.hx b/source/funkin/backend/system/framerate/Framerate.hx
index 8faa09ee..7e8e3f8e 100644
--- a/source/funkin/backend/system/framerate/Framerate.hx
+++ b/source/funkin/backend/system/framerate/Framerate.hx
@@ -82,6 +82,16 @@ class Framerate extends Sprite {
#end
}
+ public function reload() {
+ for(c in categories)
+ c.reload();
+ #if SHOW_BUILD_ON_FPS
+ codenameBuildField.reload();
+ #end
+ memoryCounter.reload();
+ fpsCounter.reload();
+ }
+
private function __addCategory(category:FramerateCategory) {
categories.push(category);
__addToList(category);
@@ -115,9 +125,16 @@ class Framerate extends Sprite {
bgSprite.scaleX = width;
bgSprite.scaleY = height;
- var y:Float = height + 4;
+ var selectable = debugMode == 2;
+ { // idk i tried to make it more lookable:sob: - Nex
+ memoryCounter.memoryText.selectable = memoryCounter.memoryPeakText.selectable =
+ fpsCounter.fpsNum.selectable = fpsCounter.fpsLabel.selectable =
+ #if SHOW_BUILD_ON_FPS codenameBuildField.selectable = #end selectable;
+ }
+ var y:Float = height + 4;
for(c in categories) {
+ c.title.selectable = c.text.selectable = selectable;
c.alpha = debugAlpha;
c.x = FlxMath.lerp(-c.width - offset.x, 0, debugAlpha);
c.y = y;
diff --git a/source/funkin/backend/system/framerate/FramerateCategory.hx b/source/funkin/backend/system/framerate/FramerateCategory.hx
index f1125eb4..db89137f 100644
--- a/source/funkin/backend/system/framerate/FramerateCategory.hx
+++ b/source/funkin/backend/system/framerate/FramerateCategory.hx
@@ -29,6 +29,7 @@ class FramerateCategory extends Sprite {
label.x = 0;
label.y = 0;
label.defaultTextFormat = new TextFormat(Framerate.fontName, label == this.title ? 18 : 12, -1);
+ label.selectable = false;
addChild(label);
}
this.title.text = title;
@@ -39,6 +40,8 @@ class FramerateCategory extends Sprite {
this.text.y = this.title.y + this.title.height + 2;
}
+ public function reload() {}
+
public override function __enterFrame(t:Int) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
@@ -49,4 +52,4 @@ class FramerateCategory extends Sprite {
bgSprite.scaleX = width;
bgSprite.scaleY = height;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/system/framerate/FramerateCounter.hx b/source/funkin/backend/system/framerate/FramerateCounter.hx
index e07a2e02..d6ff4b67 100644
--- a/source/funkin/backend/system/framerate/FramerateCounter.hx
+++ b/source/funkin/backend/system/framerate/FramerateCounter.hx
@@ -1,28 +1,17 @@
package funkin.backend.system.framerate;
-import haxe.ds.Vector;
import openfl.display.Sprite;
import openfl.text.TextField;
import openfl.text.TextFormat;
-inline final FRAME_TIME_HISTORY = 20;
-
class FramerateCounter extends Sprite {
public var fpsNum:TextField;
public var fpsLabel:TextField;
-
- public var fpsHistoryIndex:Int = 0;
- public var fpsHistory:Vector;
+ public var lastFPS:Float = 0;
public function new() {
super();
- fpsHistory = new Vector(FRAME_TIME_HISTORY);
- // Initialize to 60 FPS, so that the initial estimation until we get enough data is always reasonable.
- for(i in 0...FRAME_TIME_HISTORY) {
- fpsHistory[i] = 1000.0 / 60.0;
- }
-
fpsNum = new TextField();
fpsLabel = new TextField();
@@ -33,29 +22,20 @@ class FramerateCounter extends Sprite {
label.text = "FPS";
label.multiline = label.wordWrap = false;
label.defaultTextFormat = new TextFormat(Framerate.fontName, label == fpsNum ? 18 : 12, -1);
+ label.selectable = false;
addChild(label);
}
}
+ public function reload() {}
+
public override function __enterFrame(t:Int) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
- // todo use gpu time
- fpsHistory[fpsHistoryIndex] = FlxG.elapsed * 1000;
- fpsHistoryIndex = (fpsHistoryIndex + 1) % FRAME_TIME_HISTORY;
-
- // Calculate average CPU time.
- // Code based on Godot's FPS counter.
- var cpuTime = 0.0;
- for(i in 0...FRAME_TIME_HISTORY) {
- cpuTime += fpsHistory[i];
- }
- cpuTime /= FRAME_TIME_HISTORY;
- cpuTime = Math.max(0.01, cpuTime); // Prevent unrealistically low values.
-
- fpsNum.text = Std.string(Math.floor(1000.0 / cpuTime));
+ lastFPS = CoolUtil.fpsLerp(lastFPS, FlxG.elapsed == 0 ? 0 : (1 / FlxG.elapsed), 0.25);
+ fpsNum.text = Std.string(Math.floor(lastFPS));
fpsLabel.x = fpsNum.x + fpsNum.width;
fpsLabel.y = (fpsNum.y + fpsNum.height) - fpsLabel.height;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/system/framerate/MemoryCounter.hx b/source/funkin/backend/system/framerate/MemoryCounter.hx
index 33efff59..1c26a27d 100644
--- a/source/funkin/backend/system/framerate/MemoryCounter.hx
+++ b/source/funkin/backend/system/framerate/MemoryCounter.hx
@@ -24,11 +24,14 @@ class MemoryCounter extends Sprite {
label.text = "FPS";
label.multiline = label.wordWrap = false;
label.defaultTextFormat = new TextFormat(Framerate.fontName, 12, -1);
+ label.selectable = false;
addChild(label);
}
memoryPeakText.alpha = 0.5;
}
+ public function reload() {}
+
public override function __enterFrame(t:Int) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
@@ -40,4 +43,4 @@ class MemoryCounter extends Sprite {
memoryPeakText.x = memoryText.x + memoryText.width;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/system/macros/EventMacro.hx b/source/funkin/backend/system/macros/EventMacro.hx
index 810ff1fd..7219a528 100644
--- a/source/funkin/backend/system/macros/EventMacro.hx
+++ b/source/funkin/backend/system/macros/EventMacro.hx
@@ -75,34 +75,13 @@ class EventMacro {
// add a "set this" expr for each variable
for(v in values) {
var name = v.name;
- exprs.push({
- pos: Context.currentPos(),
- expr: EBinop(OpAssign, {
- pos: Context.currentPos(),
- expr: EField({
- pos: Context.currentPos(),
- expr: EConst(CIdent("this"))
- }, name)
- }, {
- pos: Context.currentPos(),
- expr: EConst(CIdent(name))
- })
- });
+ exprs.push(macro this.$name = $i{name});
}
// add a "set this" expr to reset each private/hidden variables
for(v in hiddenValues) {
var name = v.name;
- exprs.push({
- pos: Context.currentPos(),
- expr: EBinop(OpAssign, {
- pos: Context.currentPos(),
- expr: EField({
- pos: Context.currentPos(),
- expr: EConst(CIdent("this"))
- }, name)
- }, v.expr)
- });
+ exprs.push(macro this.$name = ${v.expr});
}
exprs.push(macro return this);
diff --git a/source/funkin/backend/system/macros/FlagMacro.macro.hx b/source/funkin/backend/system/macros/FlagMacro.macro.hx
new file mode 100644
index 00000000..477512c0
--- /dev/null
+++ b/source/funkin/backend/system/macros/FlagMacro.macro.hx
@@ -0,0 +1,211 @@
+package funkin.backend.system.macros;
+
+import haxe.macro.Context;
+import haxe.macro.Expr;
+
+using StringTools;
+
+using haxe.macro.Tools;
+
+class FlagMacro {
+ public static function build():Array {
+ var fields = Context.getBuildFields();
+
+ var clRef = Context.getLocalClass();
+ if (clRef == null)
+ return fields;
+
+ var cl = clRef.get();
+
+ var resetExprs:Array = [];
+ var parserExprs:Array = [];
+
+ for (field in fields) {
+ var skip = false;
+ for(meta in field.meta) {
+ if(meta.name == ":bypass") {
+ skip = true;
+ break;
+ }
+ }
+
+ if(skip) continue;
+
+ switch (field.kind) {
+ case FVar(type, expr):
+ 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)
+ Context.error('Flag ' + field.name + ' must have a type', field.pos);
+ }
+
+ var parser:Expr = null;
+ var customCheck:Expr = null;
+
+ switch(type) {
+ case macro: Array:
+ field.kind = FVar(macro: Array, expr);
+ parser = macro value.split(",").map((e) -> e.trim());
+ case macro: Array:
+ parser = macro value.split(",");
+ case macro: Array:
+ parser = macro value.split(",").map((e) -> {
+ e = e.trim();
+ e == "true" || e == "t" || e == "1";
+ });
+ case macro: Int:
+ parser = macro Std.parseInt(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}):
+ final NONE = 0;
+ final STRING = 1;
+ final INT = 2;
+ var chosenType = NONE;
+
+ var values:Array = [];
+
+ for(param in params) {
+ switch(param) {
+ case TPExpr(e):
+ switch(e.expr) {
+ case EConst(CString(s, kind)):
+ if(chosenType != NONE && chosenType != STRING)
+ Context.error("Flag " + field.name + " Allow<> can only have one type", field.pos);
+ chosenType = STRING;
+
+ values.push(s);
+ case EConst(CInt(num)):
+ if(chosenType != NONE && chosenType != INT)
+ Context.error("Flag " + field.name + " Allow<> can only have one type", field.pos);
+ chosenType = INT;
+
+ values.push(num);
+ default:
+ Context.error("Flag " + field.name + " Allow<> unknown type", field.pos);
+ }
+ default:
+ Context.error("Flag " + field.name + " Unknown type when using Allow<>", field.pos);
+ }
+ }
+
+ var didFind = false;
+ for(v in values) {
+ switch(expr.expr) {
+ case EConst(CString(s, kind)):
+ if(v == s)
+ didFind = true;
+ case EConst(CInt(num)):
+ if(v == num)
+ didFind = true;
+ default:
+ }
+ }
+ if(!didFind)
+ Context.error("Flag " + field.name + "'s Allow<> must have a default value that is allowed, " + expr.toString() + " is not allowed", field.pos);
+
+ if(chosenType == NONE)
+ Context.error("Flag " + field.name + "'s Allow<> must have atleast one value", field.pos);
+
+ var errorMessage = 'Flag ${field.name} must be one of ${values.join(", ")}';
+
+ var checkExpr = macro value == $v{values.shift()};
+ for(v in values)
+ checkExpr = macro $checkExpr || value == $v{v};
+
+ if(chosenType == STRING) {
+ parser = macro value;
+ field.kind = FVar(macro: String, expr);
+ }
+ else if(chosenType == INT) {
+ parser = macro Std.parseInt(value);
+ field.kind = FVar(macro: Int, expr);
+ } else {
+ field.kind = FVar(macro: Any, expr);
+ }
+
+ customCheck = macro @:mergeBlock {
+ if(name == $v{field.name}) {
+ if($checkExpr)
+ $i{field.name} = $parser;
+ else
+ throw $v{errorMessage};
+ return true;
+ }
+ }
+
+ case TPath({name: "Array", pack: []}):
+ Context.error("Flag " + field.name + " cannot be an Array that isnt a String or Bool or TrimmedString", field.pos);
+ case TPath({name: "Map", pack: []}):
+ Context.error("Flag " + field.name + " cannot be a Map", field.pos);
+ default:
+ Context.error("Flag " + field.name + " must be either a Bool, Int, String, Array, Array or Array", field.pos);
+ }
+
+ if(parser == null) {
+ Context.error("Flag " + field.name + " must be either a Bool, Int, String, Array, Array or Array", field.pos);
+ continue;
+ }
+
+ resetExprs.push(macro $i{field.name} = ${expr});
+
+ // parse(name: String, value: String)
+
+ if(customCheck != null) {
+ parserExprs.push(customCheck);
+ } else {
+ parserExprs.push(macro @:mergeBlock {
+ if(name == $v{field.name}) {
+ $i{field.name} = $parser;
+ return true;
+ }
+ });
+ }
+ default:
+ // nothing
+ }
+ }
+
+ fields.push({
+ name: "reset",
+ access: [APublic, AStatic],
+ kind: FFun({
+ args: [],
+ expr: macro $b{resetExprs},
+ ret: macro: Void
+ }),
+ pos: Context.currentPos(),
+ doc: null,
+ meta: []
+ });
+
+ fields.push({
+ name: "parse",
+ access: [APublic, AStatic],
+ kind: FFun({
+ args: [{name: "name", type: macro: String}, {name: "value", type: macro: String}],
+ expr: macro {
+ @:mergeBlock $b{parserExprs};
+
+ return false;
+ },
+ ret: macro: Bool
+ }),
+ pos: Context.currentPos(),
+ doc: null,
+ meta: []
+ });
+
+ //var printer = new haxe.macro.Printer();
+ //trace(printer.printField(fields[fields.length - 2]));
+ //trace(printer.printField(fields[fields.length - 1]));
+
+ return fields;
+ }
+}
\ No newline at end of file
diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx
index 437d05c8..fc0a69c5 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -741,7 +741,7 @@ class CoolUtil
*/
@:noUsing public static inline function openURL(url:String) {
#if linux
- Sys.command('/usr/bin/xdg-open', [url, "&"]);
+ Sys.command('/usr/bin/xdg-open', [url]);
#else
FlxG.openURL(url);
#end
@@ -848,6 +848,104 @@ class CoolUtil
var file = new haxe.io.Path(file);
return file.file;
}
+
+ /**
+ * Converts a string of "1..3,5,7..9,8..5" into an array of numbers like [1,2,3,5,7,8,9,8,7,6,5]
+ * @param input String to parse
+ * @return Array of numbers
+ */
+ public static function parseNumberRange(input:String):Array {
+ var result:Array = [];
+ var parts:Array = input.split(",");
+
+ for (part in parts) {
+ part = part.trim();
+ var idx = part.indexOf("..");
+ if (idx != -1) {
+ var start = Std.parseInt(part.substring(0, idx).trim());
+ var end = Std.parseInt(part.substring(idx + 2).trim());
+
+ if(start == null || end == null) {
+ continue;
+ }
+
+ if (start < end) {
+ for (j in start...end + 1) {
+ result.push(j);
+ }
+ } else {
+ for (j in end...start + 1) {
+ result.push(start + end - j);
+ }
+ }
+ } else {
+ var num = Std.parseInt(part);
+ if (num != null) {
+ result.push(num);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of numbers into a string of ranges.
+ * Example: [1,2,3,5,7,8,9,8,7,6,5] -> "1..3,5,7..9,8..5"
+ * @param numbers Array of numbers
+ * @return String representing the ranges
+ */
+ public static function formatNumberRange(numbers:Array, seperator:String = ","):String {
+ if (numbers.length == 0) return "";
+
+ var result:Array = [];
+ var i = 0;
+
+ while (i < numbers.length) {
+ var start = numbers[i];
+ var end = start;
+ var direction = 0; // 0: no sequence, 1: increasing, -1: decreasing
+
+ if (i + 1 < numbers.length) { // detect direction of sequence
+ if (numbers[i + 1] == end + 1) {
+ direction = 1;
+ } else if (numbers[i + 1] == end - 1) {
+ direction = -1;
+ }
+ }
+
+ if(direction != 0) {
+ while (i + 1 < numbers.length && (numbers[i + 1] == end + direction)) {
+ end = numbers[i + 1];
+ i++;
+ }
+ }
+
+ if (start == end) { // no direction
+ result.push('${start}');
+ } else if (start + direction == end) { // 1 step increment
+ result.push('${start},${end}');
+ } else { // store as range
+ result.push('${start}..${end}');
+ }
+
+ i++;
+ }
+
+ return result.join(seperator);
+ }
+
+ public static function deepFlatten(arr:Array, ?result:Array):Array {
+ if(arr == null) return [];
+ if(result == null) result = [];
+ for (e in arr) {
+ if (Std.isOfType(e, Array)) {
+ deepFlatten(e, result);
+ } else {
+ result.push(e);
+ }
+ }
+ return result;
+ }
}
/**
@@ -860,4 +958,4 @@ enum abstract CoolSfx(Int) from Int {
var CHECKED = 3;
var UNCHECKED = 4;
var WARNING = 5;
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/utils/FunkinParentDisabler.hx b/source/funkin/backend/utils/FunkinParentDisabler.hx
index 07e71a2a..8e9554cc 100644
--- a/source/funkin/backend/utils/FunkinParentDisabler.hx
+++ b/source/funkin/backend/utils/FunkinParentDisabler.hx
@@ -32,8 +32,8 @@ class FunkinParentDisabler extends FlxBasic {
FlxTimer.globalManager._timers = [];
// cameras
- __cameras = [for(c in FlxG.cameras.list) if (c.active) c];
- for(c in __cameras) c.active = false;
+ __cameras = [for(c in FlxG.cameras.list) if (!c.paused) c];
+ for(c in __cameras) c.paused = true;
// sounds
__sounds = [for(s in FlxG.sound.list) if (s.playing) s];
@@ -41,9 +41,6 @@ class FunkinParentDisabler extends FlxBasic {
}
}
- public override function update(elapsed:Float) {
- @:privateAccess for(c in __cameras) c.updateFlashSpritePosition();
- }
public override function draw() {}
public function reset() {
@@ -63,7 +60,7 @@ class FunkinParentDisabler extends FlxBasic {
for(t in __tweens) FlxTween.globalManager._tweens.push(t);
for(t in __timers) FlxTimer.globalManager._timers.push(t);
}
- for(c in __cameras) c.active = true;
+ for(c in __cameras) c.paused = false;
for(s in __sounds) s.play();
}
}
diff --git a/source/funkin/backend/utils/IniUtil.hx b/source/funkin/backend/utils/IniUtil.hx
index 1777ffb8..5f13640b 100644
--- a/source/funkin/backend/utils/IniUtil.hx
+++ b/source/funkin/backend/utils/IniUtil.hx
@@ -29,7 +29,7 @@ class IniUtil {
var name = line.substr(0, index).trim();
var value = line.substr(index+1).trim();
- if (value.startsWith("\"") && value.endsWith("\""))
+ if (value.length > 1 && value.charCodeAt(0) == '"'.code && value.charCodeAt(value.length-1) == '"'.code)
value = value.substr(1, value.length - 2);
if (value.length == 0 || name.length == 0)
diff --git a/source/funkin/backend/utils/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx
index cc8fb9d2..6c27629e 100644
--- a/source/funkin/backend/utils/MemoryUtil.hx
+++ b/source/funkin/backend/utils/MemoryUtil.hx
@@ -117,7 +117,17 @@ class MemoryUtil {
22 => "DDR2 FB-DIMM",
24 => "DDR3",
25 => "FBD2",
- 26 => "DDR4"
+ 26 => "DDR4",
+ 27 => "LPDDR",
+ 28 => "LPDDR2",
+ 29 => "LPDDR3",
+ 30 => "LPDDR4",
+ 31 => "Logical Non-volatile device",
+ 32 => "HBM",
+ 33 => "HBM2",
+ 34 => "DDR5",
+ 35 => "LPDDR5",
+ 36 => "HBM3",
];
var memoryOutput:Int = -1;
diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx
index feb7c780..0bdd3622 100644
--- a/source/funkin/backend/utils/XMLUtil.hx
+++ b/source/funkin/backend/utils/XMLUtil.hx
@@ -4,6 +4,7 @@ import flixel.util.FlxColor;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.FunkinSprite.XMLAnimType;
import funkin.backend.FunkinSprite;
+import funkin.game.Character;
import funkin.backend.system.ErrorCode;
import funkin.backend.system.interfaces.IOffsetCompatible;
import haxe.xml.Access;
@@ -170,8 +171,7 @@ class XMLUtil {
animType: spr.spriteAnimType,
x: 0,
y: 0,
- indices: [for(i in 0...spr.frames.frames.length) i],
- forced: (node.has.forced && node.att.forced == "true") || (!node.has.forced && spr.spriteAnimType == BEAT)
+ indices: [for(i in 0...spr.frames.frames.length) i]
});
}
}
@@ -197,8 +197,7 @@ class XMLUtil {
animType: animType,
x: 0,
y: 0,
- indices: [],
- forced: false,
+ indices: []
};
if (anim.has.name) animData.name = anim.att.name;
@@ -209,14 +208,7 @@ class XMLUtil {
if (anim.has.y) animData.y = Std.parseFloat(anim.att.y).getDefault(animData.y);
if (anim.has.loop) animData.loop = anim.att.loop == "true";
if (anim.has.forced) animData.forced = anim.att.forced == "true";
- if (anim.has.indices) {
- var indicesSplit = anim.att.indices.split(",");
- for(indice in indicesSplit) {
- var i = Std.parseInt(indice.trim());
- if (i != null)
- animData.indices.push(i);
- }
- }
+ if (anim.has.indices) animData.indices = CoolUtil.parseNumberRange(anim.att.indices);
return animData;
}
@@ -261,24 +253,28 @@ class XMLUtil {
if (sprite is FunkinSprite) {
var xmlSpr = cast(sprite, FunkinSprite);
+ var name = animData.name;
switch(animData.animType) {
case BEAT:
xmlSpr.beatAnims.push({
- name: animData.name,
- forced: animData.forced.getDefault(false)
+ name: name,
+ forced: animData.forced.getDefault(defaultForcedCheck(name, xmlSpr))
});
case LOOP:
- xmlSpr.playAnim(animData.name, animData.forced.getDefault(false));
+ xmlSpr.playAnim(name, animData.forced.getDefault(defaultForcedCheck(name, xmlSpr)));
default:
// nothing
}
- xmlSpr.animDatas.set(animData.name, animData);
+ xmlSpr.animDatas.set(name, animData);
}
return OK;
}
return MISSING_PROPERTY;
}
+ public static inline function defaultForcedCheck(animName:String, sprite:FunkinSprite):Bool
+ return sprite is Character && (animName.startsWith("idle") || animName.startsWith("danceLeft") || animName.startsWith("danceRight")) ? false : sprite.spriteAnimType == BEAT;
+
public static inline function fixXMLText(text:String) {
var v:String;
return [for(l in text.split("\n")) if ((v = l.trim()) != "") v].join("\n");
diff --git a/source/funkin/editors/EditorPicker.hx b/source/funkin/editors/EditorPicker.hx
index 1d9768e3..45505fea 100644
--- a/source/funkin/editors/EditorPicker.hx
+++ b/source/funkin/editors/EditorPicker.hx
@@ -33,6 +33,14 @@ class EditorPicker extends MusicBeatSubstate {
state: UIDebugState
},
#end
+ {
+ name: "Wiki",
+ iconID: 5,
+ state: null,
+ onClick: function() {
+ CoolUtil.openURL("https://fnf-cne-devs.github.io/");
+ }
+ },
{
name: "Debug Options",
id: "debugOptions",
@@ -102,7 +110,9 @@ class EditorPicker extends MusicBeatSubstate {
}
if (controls.ACCEPT || FlxG.mouse.justReleased) {
- if (options[curSelected].state != null) {
+ if(options[curSelected].onClick != null)
+ options[curSelected].onClick();
+ else if (options[curSelected].state != null) {
selected = true;
CoolUtil.playMenuSFX(CONFIRM);
@@ -154,6 +164,7 @@ typedef Editor = {
var id:String;
var iconID:Int;
var state:Class;
+ var ?onClick:Void->Void;
}
class EditorPickerOption extends FlxTypedSpriteGroup {
@@ -170,7 +181,6 @@ class EditorPickerOption extends FlxTypedSpriteGroup {
public function new(name:String, iconID:Int, height:Float) {
super();
-
FlxG.mouse.visible = true;
iconSpr = new FlxSprite();
iconSpr.loadGraphic(Paths.image('editors/icons'), true, 128, 128);
diff --git a/source/funkin/editors/character/CharacterAnimScreen.hx b/source/funkin/editors/character/CharacterAnimScreen.hx
index 9968a11e..0d9f30da 100644
--- a/source/funkin/editors/character/CharacterAnimScreen.hx
+++ b/source/funkin/editors/character/CharacterAnimScreen.hx
@@ -72,7 +72,7 @@ class CharacterAnimScreen extends UISubstateWindow {
addLabelOn(loopedCheckbox, translate("looping"));
loopedCheckbox.x += 8; loopedCheckbox.y += 6;
- indicesTextBox = new UITextBox(nameTextBox.x, nameTextBox.y + 32 + 40, animData.indices.join(", "), 270);
+ indicesTextBox = new UITextBox(nameTextBox.x, nameTextBox.y + 32 + 40, CoolUtil.formatNumberRange(animData.indices, ", "), 270);
add(indicesTextBox);
addLabelOn(indicesTextBox, translate("indices"));
@@ -112,14 +112,8 @@ class CharacterAnimScreen extends UISubstateWindow {
animType: NONE,
x: offsetXStepper.value,
y: offsetYStepper.value,
- indices: []
+ indices: CoolUtil.parseNumberRange(indicesTextBox.label.text)
};
- var indicesSplit = indicesTextBox.label.text.split(",");
- for(indice in indicesSplit) {
- var i = Std.parseInt(indice.trim());
- if (i != null)
- animData.indices.push(i);
- }
if (onSave != null) onSave(animData);
}
diff --git a/source/funkin/editors/character/CharacterInfoScreen.hx b/source/funkin/editors/character/CharacterInfoScreen.hx
index dfc3f655..1997a5cd 100644
--- a/source/funkin/editors/character/CharacterInfoScreen.hx
+++ b/source/funkin/editors/character/CharacterInfoScreen.hx
@@ -195,8 +195,10 @@ class CharacterInfoScreen extends UISubstateWindow {
var offset:FlxPoint = character.getAnimOffset(anim.name);
animXml.set("x", Std.string(offset.x));
animXml.set("y", Std.string(offset.y));
+ offset.put();
+
if (anim.indices.length > 0)
- animXml.set("indices", anim.indices.join(","));
+ animXml.set("indices", CoolUtil.formatNumberRange(anim.indices));
xml.addChild(animXml);
}
diff --git a/source/funkin/editors/charter/SongCreationScreen.hx b/source/funkin/editors/charter/SongCreationScreen.hx
index b1d7e5a1..0f2b78ab 100644
--- a/source/funkin/editors/charter/SongCreationScreen.hx
+++ b/source/funkin/editors/charter/SongCreationScreen.hx
@@ -86,8 +86,6 @@ class SongCreationScreen extends UISubstateWindow {
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
songDataGroup.add(stepsPerBeatStepper);
- var voicesUIText:UIText = null;
-
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
@@ -105,10 +103,13 @@ class SongCreationScreen extends UISubstateWindow {
});
songDataGroup.add(voicesExplorer);
- voicesUIText = addLabelOn(voicesExplorer, "");
+ /*voicesUIText = addLabelOn(voicesExplorer, "");
voicesUIText.applyMarkup(
translate("voicesAudio"),
- [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
+ [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);*/
+
+ addLabelOn(voicesExplorer, "Vocal Audio File");
+
var menuTitle:UIText;
menuDataGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, translateMeta("menusData"), 28));
diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx
index 50d82f88..d043c040 100644
--- a/source/funkin/game/Character.hx
+++ b/source/funkin/game/Character.hx
@@ -218,7 +218,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
/**
* Like `playSingAnimUnsafe` but checks if the character has the animation with the suffix part, otherwise it plays the animation without the suffix part.
*/
- public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, Force:Bool = true, Reversed:Bool = false, Frame:Int = 0)
+ public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, ?Force:Null = null, Reversed:Bool = false, Frame:Int = 0)
{
var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
script.call("onPlaySingAnim", [event]);
@@ -235,7 +235,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
playAnim(event.animName, event.force, event.context, event.reversed, event.frame);
}
- public override function playAnim(AnimName:String, Force:Bool = false, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
+ public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context);
script.call("onPlayAnim", [event]);
if (event.cancelled) return;
@@ -306,6 +306,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public inline function buildCharacter(xml:Access) {
this.xml = xml; // Modders wassup :D
sprite = curCharacter;
+ spriteAnimType = BEAT;
if (xml.x.exists("isPlayer")) playerOffsets = (xml.x.get("isPlayer") == "true");
if (xml.x.exists("x")) globalOffset.x = Std.parseFloat(xml.x.get("x"));
@@ -396,7 +397,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
offset.putWeak();
if (anim.indices.length > 0)
- animXml.set("indices", anim.indices.join(","));
+ animXml.set("indices", CoolUtil.formatNumberRange(anim.indices));
xml.addChild(animXml);
}
diff --git a/source/funkin/game/NoteGroup.hx b/source/funkin/game/NoteGroup.hx
index 98b6477e..9c974a13 100644
--- a/source/funkin/game/NoteGroup.hx
+++ b/source/funkin/game/NoteGroup.hx
@@ -34,10 +34,16 @@ class NoteGroup extends FlxTypedGroup {
return FlxSort.byValues(FlxSort.DESCENDING, n1.strumTime, n2.strumTime);
});
}
+
+ @:dox(hide) public var __forcedSongPos:Null = null;
+
+ @:dox(hide) private inline function __getSongPos()
+ return __forcedSongPos == null ? Conductor.songPosition : __forcedSongPos;
+
public override function update(elapsed:Float) {
i = length-1;
__loopSprite = null;
- __time = Conductor.songPosition;
+ __time = __getSongPos();
while(i >= 0) {
__loopSprite = members[i--];
if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.active) {
@@ -58,7 +64,7 @@ class NoteGroup extends FlxTypedGroup {
i = length-1;
__loopSprite = null;
- __time = Conductor.songPosition;
+ __time = __getSongPos();
while(i >= 0) {
__loopSprite = members[i--];
if (__loopSprite == null || !__loopSprite.exists || !__loopSprite.visible)
@@ -81,7 +87,7 @@ class NoteGroup extends FlxTypedGroup {
public override function forEach(noteFunc:Note->Void, recursive:Bool = false) {
i = length-1;
__loopSprite = null;
- __time = Conductor.songPosition;
+ __time = __getSongPos();
var oldCur = __currentlyLooping;
__currentlyLooping = true;
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index bac69c8b..346b701e 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -242,7 +242,7 @@ class PlayState extends MusicBeatState
/**
* Current stage name
*/
- public var curStage:String = "";
+ public var curStage(get, set):String;
/**
* Interval at which Girlfriend dances.
@@ -362,7 +362,7 @@ class PlayState extends MusicBeatState
* Speed at which the game camera zoom lerps to.
*/
public var camGameZoomLerp:Float = 0.05;
-
+
/**
* Camera zoom at which the hud lerps to.
*/
@@ -525,6 +525,14 @@ class PlayState extends MusicBeatState
return this.maxHealth = v;
}
+ private inline function get_curStage()
+ return stage == null ? "" : stage.stageName;
+
+ private inline function set_curStage(name:String) {
+ if (stage != null) stage.stageName = name;
+ return name;
+ }
+
@:dox(hide) override public function create()
{
Note.__customNoteTypeExists = [];
@@ -653,10 +661,12 @@ class PlayState extends MusicBeatState
chars.push(char);
}
- var strOffset:Float = strumLine.strumLinePos == null ? (strumLine.type == 1 ? 0.75 : 0.25) : strumLine.strumLinePos;
- var startingPos:FlxPoint = strumLine.strumPos == null ?
- FlxPoint.get((FlxG.width * strOffset) - ((Note.swagWidth * (strumLine.strumScale == null ? 1 : strumLine.strumScale)) * 2), this.strumLine.y) :
- FlxPoint.get(strumLine.strumPos[0] == 0 ? ((FlxG.width * strOffset) - ((Note.swagWidth * (strumLine.strumScale == null ? 1 : strumLine.strumScale)) * 2)) : strumLine.strumPos[0], strumLine.strumPos[1]);
+ var strOffset:Float = strumLine.strumLinePos != null ? strumLine.strumLinePos : (strumLine.type == 1 ? 0.75 : 0.25);
+ var strScale:Float = strumLine.strumScale != null ? strumLine.strumScale : 1;
+ var strXPos:Float = (FlxG.width * strOffset) - (Note.swagWidth * strScale * 2);
+ var startingPos:FlxPoint = strumLine.strumPos != null ?
+ FlxPoint.get(strumLine.strumPos[0] == 0 ? strXPos : strumLine.strumPos[0], strumLine.strumPos[1]) :
+ FlxPoint.get(strXPos, this.strumLine.y);
var strLine = new StrumLine(chars,
startingPos,
strumLine.strumScale == null ? 1 : strumLine.strumScale,
@@ -1261,7 +1271,7 @@ class PlayState extends MusicBeatState
if (Conductor.songPosition >= 0)
startSong();
}
- } else {
+ } else if (FlxG.sound.music != null) {
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));
@@ -1924,7 +1934,7 @@ class PlayState extends MusicBeatState
}
}
-class ComboRating {
+final class ComboRating {
public var percent:Float;
public var rating:String;
public var color:FlxColor;
diff --git a/source/funkin/game/SplashHandler.hx b/source/funkin/game/SplashHandler.hx
index 1776bdb8..31a06234 100644
--- a/source/funkin/game/SplashHandler.hx
+++ b/source/funkin/game/SplashHandler.hx
@@ -1,5 +1,7 @@
package funkin.game;
+import funkin.backend.scripting.events.SplashShowEvent;
+
class SplashHandler extends FlxTypedGroup {
/**
* Map containing all of the splashes group.
@@ -40,10 +42,10 @@ class SplashHandler extends FlxTypedGroup {
var __grp:SplashGroup;
public function showSplash(name:String, strum:Strum) {
__grp = getSplashGroup(name);
- var event = funkin.backend.scripting.EventManager.get(funkin.backend.scripting.events.DynamicEvent).recycle(__grp.showOnStrum(strum), strum);
+ var event = EventManager.get(SplashShowEvent).recycle(name, __grp.showOnStrum(strum), strum, __grp);
event = PlayState.instance.scripts.event("onSplashShown", event);
if (!event.cancelled)
- add(event.value1);
+ add(event.splash);
// max 8 rendered splashes
while(members.length > 8)
diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx
index 2e3dd050..90f3c748 100644
--- a/source/funkin/game/Stage.hx
+++ b/source/funkin/game/Stage.hx
@@ -2,6 +2,7 @@ package funkin.game;
import flixel.FlxState;
import flixel.math.FlxPoint;
+import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.events.StageNodeEvent;
import funkin.backend.scripting.events.StageXMLEvent;
@@ -12,18 +13,22 @@ import haxe.xml.Access;
using StringTools;
class Stage extends FlxBasic implements IBeatReceiver {
+ public var stageName:String = "";
public var stageXML:Access;
public var stagePath:String;
public var stageSprites:Map = [];
public var stageScript:Script;
public var state:FlxState;
public var characterPoses:Map = [];
+ public var xmlImportedScripts:Array = [];
private var spritesParentFolder = "";
- public function getSprite(name:String) {
+ public function getSprite(name:String)
return stageSprites[name];
- }
+
+ public function setStagesSprites(script:Script)
+ for (k=>e in stageSprites) script.set(k, e);
public function new(stage:String, ?state:FlxState) {
super();
@@ -33,11 +38,8 @@ class Stage extends FlxBasic implements IBeatReceiver {
this.state = state;
stagePath = Paths.xml('stages/$stage');
- try {
- if (Assets.exists(stagePath)) stageXML = new Access(Xml.parse(Assets.getText(stagePath)).firstElement());
- } catch(e) {
- Logs.error('Couldn\'t load stage "$stage": ${e.message}');
- }
+ try if (Assets.exists(stagePath)) stageXML = new Access(Xml.parse(Assets.getText(stagePath)).firstElement())
+ catch(e) Logs.error('Couldn\'t load stage "$stage": ${e.message}');
if (PlayState.instance != null) {
stageScript = Script.create(Paths.script('data/stages/$stage'));
@@ -45,13 +47,15 @@ class Stage extends FlxBasic implements IBeatReceiver {
stageScript.load();
}
+ var event = null;
if (stageXML != null) {
+ stageName = stageXML.getAtt("name").getDefault(stage);
+
if (PlayState.instance != null) {
var parsed:Null;
if(stageXML.has.startCamPosX && (parsed = Std.parseFloat(stageXML.att.startCamPosX)) != null) PlayState.instance.camFollow.x = parsed;
if(stageXML.has.startCamPosY && (parsed = Std.parseFloat(stageXML.att.startCamPosY)) != null) PlayState.instance.camFollow.y = parsed;
if(stageXML.has.zoom && (parsed = Std.parseFloat(stageXML.att.zoom)) != null) PlayState.instance.defaultCamZoom = parsed;
- PlayState.instance.curStage = stageXML.has.name ? stageXML.att.name : stage;
}
if (stageXML.has.folder) {
spritesParentFolder = stageXML.att.folder;
@@ -60,16 +64,13 @@ class Stage extends FlxBasic implements IBeatReceiver {
var elems = [];
for(node in stageXML.elements) {
- if (node.name == "high-memory" && !Options.lowMemoryMode)
- for(e in node.elements)
- elems.push(e);
- else
- elems.push(node);
+ if (node.name == "high-memory" && !Options.lowMemoryMode) for(e in node.elements) __pushNcheckNode(elems, e);
+ else __pushNcheckNode(elems, node);
}
if (PlayState.instance != null) {
- var event = PlayState.instance.scripts.event("onStageXMLParsed", EventManager.get(StageXMLEvent).recycle(this, stageXML, elems));
- elems = event.elems;
+ event = EventManager.get(StageXMLEvent).recycle(this, stageXML, elems);
+ elems = PlayState.instance.scripts.event("onStageXMLParsed", event).elems;
}
for(node in elems) {
@@ -86,7 +87,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
state.add(spr);
spr;
case "box" | "solid":
- if ( !node.has.name || !node.has.width || !node.has.height) continue;
+ if (!node.has.name || !node.has.width || !node.has.height) continue;
var spr = new FlxSprite(
(node.has.x) ? Std.parseFloat(node.att.x).getDefault(0) : 0,
@@ -134,6 +135,9 @@ class Stage extends FlxBasic implements IBeatReceiver {
);
PlayState.instance.add(PlayState.instance.comboGroup);
PlayState.instance.comboGroup;
+ case "use-extension" | "extension" | "ext":
+ if (__shouldLoadBefore(node) || XMLImportedScriptInfo.prepareInfos(node, this) == null) continue;
+ null;
default: null;
}
@@ -173,11 +177,37 @@ class Stage extends FlxBasic implements IBeatReceiver {
});
if (PlayState.instance == null) return;
- for(k=>e in stageSprites) {
- stageScript.set(k, e);
+
+ setStagesSprites(stageScript);
+
+ // i know this for gets run twice under, but its better like this in case a script modifies the short lived ones, i dont wanna save them in an array; more dynamic like this - Nex
+ for (info in xmlImportedScripts) if (info.importStageSprites) {
+ var script = info.getScript();
+ if (script != null) setStagesSprites(script);
+ }
+
+ // idk lemme check anyways just in case scripts did smth - Nex
+ if (event != null) PlayState.instance.scripts.event("onPostStageCreation", event);
+
+ // shortlived scripts destroy when the stage finishes setting up - Nex
+ for (info in xmlImportedScripts) if (info.shortLived) {
+ var script = info.getScript();
+ if (script == null) continue;
+
+ PlayState.instance.scripts.remove(script);
+ script.destroy();
}
}
+ @:dox(hide) private function __pushNcheckNode(array:Array, node:Access) {
+ array.push(node);
+ if ((node.name == "use-extension" || node.name == "extension" || node.name == "ext") && __shouldLoadBefore(node))
+ XMLImportedScriptInfo.prepareInfos(node, this);
+ }
+
+ @:dox(hide) private static inline function __shouldLoadBefore(node:Access):Bool
+ return node.getAtt("loadBefore") != "false";
+
public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo):StageCharPos {
var charPos = new StageCharPos();
charPos.visible = charPos.active = false;
@@ -287,4 +317,45 @@ typedef StageCharPosInfo = {
var y:Float;
var flip:Bool;
var scroll:Float;
+}
+
+class XMLImportedScriptInfo {
+ public var path:String;
+ public var shortLived:Bool = false;
+ public var loadBefore:Bool = true;
+ public var importStageSprites:Bool = false;
+
+ public function new(path:String)
+ this.path = path;
+
+ public function getScript():Script
+ return PlayState.instance == null ? null : PlayState.instance.scripts.getByPath(path);
+
+ public static function prepareInfos(node:Access, ?stage:Stage):XMLImportedScriptInfo {
+ if (!node.has.script || PlayState.instance == null) return null;
+
+ var folder = node.getAtt("folder").getDefault("data/scripts/");
+ if (!folder.endsWith("/")) folder += "/";
+
+ var path = Paths.script(folder + node.getAtt("script"));
+ var daScript = Script.create(path);
+ if (daScript is DummyScript) {
+ var msg = 'Script Extension at ${path} does not exist';
+ if (stage != null) msg += ' through stage "${stage.stageName}"';
+ Logs.trace(msg + ".", ERROR);
+ return null;
+ }
+
+ var infos = new XMLImportedScriptInfo(daScript.path);
+ infos.shortLived = node.getAtt("isShortLived") == "true";
+ infos.importStageSprites = node.getAtt("importStageSprites") == "true";
+ @:privateAccess infos.loadBefore = Stage.__shouldLoadBefore(node);
+
+ if (stage != null) stage.xmlImportedScripts.push(infos);
+ PlayState.instance.scripts.add(daScript);
+ daScript.set("scriptInfo", infos);
+ daScript.load();
+
+ return infos;
+ }
}
\ No newline at end of file
diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx
index dd952d19..cca45b51 100644
--- a/source/funkin/game/StrumLine.hx
+++ b/source/funkin/game/StrumLine.hx
@@ -152,7 +152,10 @@ class StrumLine extends FlxTypedGroup {
var scrollSpeed = strumLine.scrollSpeed;
if(scrollSpeed == null) if (PlayState.instance != null) scrollSpeed = PlayState.instance.scrollSpeed;
if(scrollSpeed == null) scrollSpeed = 1;
- notes.limit = 1500 / scrollSpeed;
+
+ // TODOD: Make this work by accounting zoom and scrollspeed changes - Nex
+ /*var limit = FlxG.height / 0.45;
+ notes.limit = limit / scrollSpeed;*/
}
public override function update(elapsed:Float) {
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
index be917a80..9484e9fc 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
@@ -94,7 +94,7 @@ class DialogueBox extends FunkinSprite {
dialogueBoxScript.call("postCreate");
}
- public override function playAnim(AnimName:String, Force:Bool = false, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
+ public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context);
dialogueBoxScript.call("onPlayAnim", [event]);
if(event.cancelled) return;
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
index 8263272f..e075bef9 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
@@ -61,7 +61,7 @@ class DialogueCharacter extends FunkinSprite {
dialogueCharScript.call("postCreate");
}
- public override function playAnim(AnimName:String, Force:Bool = false, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
+ public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context);
dialogueCharScript.call("playAnim", [event]);
if(event.cancelled) return;
diff --git a/source/funkin/import.hx b/source/funkin/import.hx
index a83d7c8a..20059ad2 100644
--- a/source/funkin/import.hx
+++ b/source/funkin/import.hx
@@ -23,6 +23,8 @@ import flixel.math.FlxMath;
import flixel.tweens.FlxEase;
import flixel.util.FlxDestroyUtil;
+import funkin.backend.system.Flags;
+
import funkin.menus.ui.Alphabet;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx
index fb85e1fb..dfa2a32f 100644
--- a/source/funkin/menus/FreeplayState.hx
+++ b/source/funkin/menus/FreeplayState.hx
@@ -465,8 +465,17 @@ class FreeplaySonglist {
public static function get(useTxt:Bool = true) {
var songList = new FreeplaySonglist();
- if (songList.getSongsFromSource(MODS, useTxt))
- songList.getSongsFromSource(SOURCE, useTxt);
+ switch(Flags.SONGS_LIST_MOD_MODE) {
+ case 'prepend':
+ songList.getSongsFromSource(MODS, useTxt);
+ songList.getSongsFromSource(SOURCE, useTxt);
+ case 'append':
+ songList.getSongsFromSource(SOURCE, useTxt);
+ songList.getSongsFromSource(MODS, useTxt);
+ default /*case 'override'*/:
+ if (songList.getSongsFromSource(MODS, useTxt))
+ songList.getSongsFromSource(SOURCE, useTxt);
+ }
return songList;
}
diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx
index ab643c99..509a9d82 100644
--- a/source/funkin/menus/MainMenuState.hx
+++ b/source/funkin/menus/MainMenuState.hx
@@ -167,7 +167,7 @@ class MainMenuState extends MusicBeatState
{
case 'story mode': FlxG.switchState(new StoryMenuState());
case 'freeplay': FlxG.switchState(new FreeplayState());
- case 'donate': FlxG.switchState(new CreditsMain());
+ case 'donate', 'credits': FlxG.switchState(new CreditsMain()); // kept donate for not breaking scripts, if you dont want donate to bring you to the credits menu, thats easy softcodable - Nex
case 'options': FlxG.switchState(new OptionsMenu());
}
});
diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx
index 094eb07b..1cd7b809 100644
--- a/source/funkin/menus/PauseSubState.hx
+++ b/source/funkin/menus/PauseSubState.hx
@@ -8,6 +8,7 @@ import funkin.backend.scripting.Script;
import funkin.backend.scripting.events.MenuChangeEvent;
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;
@@ -169,6 +170,9 @@ class PauseSubState extends MusicBeatSubstate
PlayState.resetSongInfos();
if (Charter.instance != null) Charter.instance.__clearStatics();
+ // prevents certain notes to disappear early when exiting - Nex
+ game.strumLines.forEachAlive(function(grp) grp.notes.__forcedSongPos = Conductor.songPosition);
+
CoolUtil.playMenuSong();
FlxG.switchState(PlayState.isStoryMode ? new StoryMenuState() : new FreeplayState());
}
diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx
index 7e5cc9a8..36baa263 100644
--- a/source/funkin/menus/StoryMenuState.hx
+++ b/source/funkin/menus/StoryMenuState.hx
@@ -210,14 +210,24 @@ class StoryMenuState extends MusicBeatState {
}
}
- intendedScore = FunkinSave.getWeekHighscore(weeks[curWeek].name, weeks[curWeek].difficulties[curDifficulty]).score;
+ intendedScore = FunkinSave.getWeekHighscore(weeks[curWeek].id, weeks[curWeek].difficulties[curDifficulty]).score;
}
public function loadXMLs() {
// CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
var weeks:Array = [];
- if (getWeeksFromSource(weeks, MODS))
- getWeeksFromSource(weeks, SOURCE);
+
+ switch(Flags.WEEKS_LIST_MOD_MODE) {
+ case 'prepend':
+ getWeeksFromSource(weeks, MODS);
+ getWeeksFromSource(weeks, SOURCE);
+ case 'append':
+ getWeeksFromSource(weeks, SOURCE);
+ getWeeksFromSource(weeks, MODS);
+ default /*case 'override'*/:
+ if (getWeeksFromSource(weeks, MODS))
+ getWeeksFromSource(weeks, SOURCE);
+ }
for(k=>weekName in weeks) {
var week:Access = null;
@@ -355,8 +365,8 @@ class StoryMenuState extends MusicBeatState {
}
typedef WeekData = {
- var name:String;
- var id:String;
+ var name:String; // name SHOULD NOT be used for loading week highscores, its just the name on the right side of the week, remember that next time!! - Nex
+ var id:String; // id IS instead for saving and loading!! - Nex
var sprite:String;
var chars:Array;
var songs:Array;
diff --git a/source/funkin/menus/credits/CreditsMain.hx b/source/funkin/menus/credits/CreditsMain.hx
index 841af11e..813e6296 100644
--- a/source/funkin/menus/credits/CreditsMain.hx
+++ b/source/funkin/menus/credits/CreditsMain.hx
@@ -5,9 +5,11 @@ import funkin.options.OptionsScreen;
import funkin.options.TreeMenu;
import funkin.options.type.*;
import haxe.xml.Access;
+import flixel.util.FlxColor;
class CreditsMain extends TreeMenu {
var bg:FlxSprite;
+ var items:Array = [];
public override function create() {
bg = new FlxSprite(-80).loadGraphic(Paths.image('menus/menuBGBlue'));
@@ -19,7 +21,6 @@ class CreditsMain extends TreeMenu {
bg.antialiasing = true;
add(bg);
- var selectables:Array = [];
var xmlPath = Paths.xml('config/credits');
for(source in [funkin.backend.assets.AssetSource.SOURCE, funkin.backend.assets.AssetSource.MODS]) {
if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT", source)) {
@@ -32,17 +33,18 @@ class CreditsMain extends TreeMenu {
if (access != null)
for(c in parseCreditsFromXML(access, source))
- selectables.push(c);
+ items.push(c);
}
}
- selectables.push(new TextOption("Codename Engine >", TU.translate("credits.selectCodename"), function() {
+
+ items.push(new TextOption("Codename Engine >", TU.translate("credits.selectCodename"), function() {
optionsTree.add(Type.createInstance(CreditsCodename, []));
}));
- selectables.push(new TextOption("Friday Night Funkin'", TU.translate("credits.selectBase"), function() {
+ items.push(new TextOption("Friday Night Funkin'", TU.translate("credits.selectBase"), function() {
CoolUtil.openURL("https://ninja-muffin24.itch.io/funkin");
}));
- main = new OptionsScreen(TU.translate("credits.name"), TU.translate("credits.madePossible"), selectables);
+ main = new OptionsScreen(TU.translate("credits.name"), TU.translate("credits.madePossible"), items);
super.create();
DiscordUtil.call("onMenuLoaded", ["Credits Menu"]);
@@ -69,11 +71,13 @@ class CreditsMain extends TreeMenu {
html_url: 'https://github.com/$username',
avatar_url: 'https://github.com/$username.png'
};
-
- credsMenus.push(new GithubIconOption(user, desc, null,
+ var opt:GithubIconOption = new GithubIconOption(user, desc, null,
node.has.customName ? node.att.customName : null, node.has.size ? Std.parseInt(node.att.size) : 96,
node.has.portrait ? node.att.portrait.toLowerCase() == "false" ? false : true : true
- ));
+ );
+ if (node.has.color)
+ @:privateAccess opt.__text.color = FlxColor.fromString(node.att.color);
+ credsMenus.push(opt);
} else {
if (!node.has.name) {
Logs.warn("A credit node requires a name attribute.", "CreditsMain");
@@ -83,11 +87,14 @@ class CreditsMain extends TreeMenu {
switch(node.name) {
case "credit":
- credsMenus.push(new PortraitOption(name, desc, function() if(node.has.url) CoolUtil.openURL(node.att.url),
+ var opt:PortraitOption = new PortraitOption(name, desc, function() if(node.has.url) CoolUtil.openURL(node.att.url),
node.has.icon && Paths.assetsTree.existsSpecific(Paths.image('credits/${node.att.icon}'), "IMAGE", source) ?
FlxG.bitmap.add(Paths.image('credits/${node.att.icon}')) : null, node.has.size ? Std.parseInt(node.att.size) : 96,
node.has.portrait ? node.att.portrait.toLowerCase() == "false" ? false : true : true
- ));
+ );
+ if (node.has.color)
+ @:privateAccess opt.__text.color = FlxColor.fromString(node.att.color);
+ credsMenus.push(opt);
case "menu":
credsMenus.push(new TextOption(name + " >", desc, function() {
@@ -99,4 +106,4 @@ class CreditsMain extends TreeMenu {
return credsMenus;
}
-}
\ No newline at end of file
+}
diff --git a/source/hscript/Config.hx b/source/hscript/Config.hx
index dcfcc10e..98fc7f7a 100644
--- a/source/hscript/Config.hx
+++ b/source/hscript/Config.hx
@@ -3,19 +3,23 @@ package hscript;
class Config {
// Runs support for custom classes in these
public static final ALLOWED_CUSTOM_CLASSES = [
+ #if !DOCUMENTATION
"flixel",
"funkin",
+ #end
];
// Runs support for abstract support in these
public static final ALLOWED_ABSTRACT_AND_ENUM = [
+ #if !DOCUMENTATION
"flixel",
"openfl",
"haxe.xml",
"haxe.CallStack",
"funkin",
+ #end
];
// Incase any of your files fail