diff --git a/.vscode/launch.json b/.vscode/launch.json
index 15d3b4b7c..4afcd170e 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,19 +1,17 @@
{
"version": "0.2.0",
"configurations": [
- {
- "name": "HTML5 Debug",
- "type": "chrome",
- "request": "launch",
- "url": "http://127.0.0.1:3001",
- "sourceMaps": true,
- "webRoot": "${workspaceFolder}",
- "preLaunchTask": "debug: html"
- },
{
+ // Launch in native/CPP
"name": "Lime",
"type": "lime",
"request": "launch"
+ },
+ {
+ // Evaluate macros with debugging enabled
+ "name": "Haxe Eval",
+ "type": "haxe-eval",
+ "request": "launch"
}
]
-}
\ No newline at end of file
+}
diff --git a/Project.xml b/Project.xml
index 938b96ed4..1382f5f71 100644
--- a/Project.xml
+++ b/Project.xml
@@ -2,7 +2,7 @@
-
+
@@ -24,10 +24,10 @@
-
+
-
+
@@ -37,78 +37,79 @@
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
@@ -119,26 +120,27 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
+
+
@@ -179,52 +181,57 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
-
+
-
+
@@ -232,8 +239,8 @@
-
-
+
+
+
\ No newline at end of file
diff --git a/example_mods/introMod/_polymod_icon.png b/example_mods/introMod/_polymod_icon.png
new file mode 100644
index 000000000..2828bd554
Binary files /dev/null and b/example_mods/introMod/_polymod_icon.png differ
diff --git a/example_mods/introMod/_polymod_meta.json b/example_mods/introMod/_polymod_meta.json
new file mode 100644
index 000000000..ccd7405d8
--- /dev/null
+++ b/example_mods/introMod/_polymod_meta.json
@@ -0,0 +1,8 @@
+{
+ "title": "Intro Mod",
+ "description": "An introductory mod.",
+ "author": "MasterEric",
+ "api_version": "0.1.0",
+ "mod_version": "1.0.0",
+ "license": "Apache-2.0"
+}
diff --git a/example_mods/introMod/assets/preload/data/introText.txt b/example_mods/introMod/data/introText.txt
similarity index 100%
rename from example_mods/introMod/assets/preload/data/introText.txt
rename to example_mods/introMod/data/introText.txt
diff --git a/example_mods/introMod/assets/preload/images/gfDanceTitle.png b/example_mods/introMod/images/gfDanceTitle.png
similarity index 100%
rename from example_mods/introMod/assets/preload/images/gfDanceTitle.png
rename to example_mods/introMod/images/gfDanceTitle.png
diff --git a/example_mods/testing123/_polymod_meta.json b/example_mods/testing123/_polymod_meta.json
index e74efc4f3..0c134dd9f 100644
--- a/example_mods/testing123/_polymod_meta.json
+++ b/example_mods/testing123/_polymod_meta.json
@@ -1,8 +1,8 @@
-{
- "title": "Testing123",
- "description": "Newgrounds? More like OLDGROUNDS lol.",
- "author": "MasterEric",
- "api_version": "0.1.0",
- "mod_version": "1.0.0",
- "license": "Apache-2.0"
-}
+{
+ "title": "Testing123",
+ "description": "Newgrounds? More like OLDGROUNDS lol.",
+ "author": "MasterEric",
+ "api_version": "0.1.0",
+ "mod_version": "1.0.0",
+ "license": "Apache-2.0"
+}
diff --git a/source/BGSprite.hx b/source/BGSprite.hx
deleted file mode 100644
index 45894efa6..000000000
--- a/source/BGSprite.hx
+++ /dev/null
@@ -1,64 +0,0 @@
-package;
-
-import flixel.FlxSprite;
-
-class BGSprite extends FlxSprite
-{
- /**
- Cool lil utility thing just so that it can easy do antialiasing and scrollfactor bullshit
- */
- public var idleAnim:String;
-
- /**
- * NOTE: loadOldWay param is just for current backward compatibility! Will be moved later!
- */
- public function new(image:String, x:Float = 0, y:Float = 0, parX:Float = 1, parY:Float = 1, ?daAnimations:Array, ?loopingAnim:Bool = false,
- ?loadOldWay:Bool = true)
- {
- super(x, y);
-
- if (loadOldWay)
- {
- if (daAnimations != null)
- {
- setupSparrow(image, daAnimations, loopingAnim);
- }
- else
- {
- justLoadImage(image);
- }
- }
-
- scrollFactor.set(parX, parY);
- antialiasing = true;
- }
-
- public function setupSparrow(image:String, daAnimations:Array, ?loopingAnim:Bool = false)
- {
- frames = Paths.getSparrowAtlas(image);
- for (anims in daAnimations)
- {
- var daLoop:Bool = loopingAnim;
- if (loopingAnim == null)
- daLoop = false;
-
- animation.addByPrefix(anims, anims, 24, daLoop);
- animation.play(anims);
-
- if (idleAnim == null)
- idleAnim = anims;
- }
- }
-
- public function justLoadImage(image:String)
- {
- loadGraphic(Paths.image(image));
- active = false;
- }
-
- public function dance():Void
- {
- if (idleAnim != null)
- animation.play(idleAnim);
- }
-}
diff --git a/source/BackgroundDancer.hx b/source/BackgroundDancer.hx
deleted file mode 100644
index 43a68c145..000000000
--- a/source/BackgroundDancer.hx
+++ /dev/null
@@ -1,31 +0,0 @@
-package;
-
-import flixel.FlxSprite;
-import flixel.graphics.frames.FlxAtlasFrames;
-
-class BackgroundDancer extends FlxSprite
-{
- public function new(x:Float, y:Float)
- {
- super(x, y);
-
- frames = Paths.getSparrowAtlas("limo/limoDancer");
- animation.addByIndices('danceLeft', 'bg dancer sketch PINK', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false);
- animation.addByIndices('danceRight', 'bg dancer sketch PINK', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false);
- animation.play('danceLeft');
- animation.finish();
- antialiasing = true;
- }
-
- var danceDir:Bool = false;
-
- public function dance():Void
- {
- danceDir = !danceDir;
-
- if (danceDir)
- animation.play('danceRight', true);
- else
- animation.play('danceLeft', true);
- }
-}
diff --git a/source/BackgroundGirls.hx b/source/BackgroundGirls.hx
deleted file mode 100644
index 1a6030362..000000000
--- a/source/BackgroundGirls.hx
+++ /dev/null
@@ -1,41 +0,0 @@
-package;
-
-import flixel.FlxSprite;
-import flixel.graphics.frames.FlxAtlasFrames;
-
-class BackgroundGirls extends FlxSprite
-{
- public function new(x:Float, y:Float)
- {
- super(x, y);
-
- // BG fangirls dissuaded
- frames = Paths.getSparrowAtlas('weeb/bgFreaks');
-
- animation.addByIndices('danceLeft', 'BG girls group', CoolUtil.numberArray(14), "", 24, false);
- animation.addByIndices('danceRight', 'BG girls group', CoolUtil.numberArray(30, 15), "", 24, false);
-
- animation.play('danceLeft');
- animation.finish();
- }
-
- var danceDir:Bool = false;
-
- public function getScared():Void
- {
- animation.addByIndices('danceLeft', 'BG fangirls dissuaded', CoolUtil.numberArray(14), "", 24, false);
- animation.addByIndices('danceRight', 'BG fangirls dissuaded', CoolUtil.numberArray(30, 15), "", 24, false);
- dance();
- animation.finish();
- }
-
- public function dance():Void
- {
- danceDir = !danceDir;
-
- if (danceDir)
- animation.play('danceRight', true);
- else
- animation.play('danceLeft', true);
- }
-}
diff --git a/source/Main.hx b/source/Main.hx
index 5edf6f82a..fb2a01a69 100644
--- a/source/Main.hx
+++ b/source/Main.hx
@@ -1,5 +1,7 @@
package;
+import funkin.InitState;
+import funkin.MemoryCounter;
import flixel.FlxGame;
import flixel.FlxState;
import openfl.Lib;
@@ -42,9 +44,9 @@ class Main extends Sprite
// A design similar to that of Minecraft resource packs would be intuitive.
// 3. The interface should save (to the save file) and output an ordered array of mod IDs.
// 4. Replace the call to PolymodHandler.loadAllMods() with a call to PolymodHandler.loadModsById(ids:Array).
- modding.PolymodHandler.loadAllMods();
+ funkin.modding.PolymodHandler.loadAllMods();
- i18n.FireTongueHandler.init();
+ funkin.i18n.FireTongueHandler.init();
if (stage != null)
{
@@ -98,9 +100,11 @@ class Main extends Sprite
#if debug
fpsCounter = new FPS(10, 3, 0xFFFFFF);
addChild(fpsCounter);
+ #if !html5
memoryCounter = new MemoryCounter(10, 13, 0xFFFFFF);
addChild(memoryCounter);
#end
+ #end
/*
video = new Video();
diff --git a/Preloader.hx b/source/Preloader.hx
similarity index 100%
rename from Preloader.hx
rename to source/Preloader.hx
diff --git a/source/TankmenBG.hx b/source/TankmenBG.hx
deleted file mode 100644
index b889b5a93..000000000
--- a/source/TankmenBG.hx
+++ /dev/null
@@ -1,89 +0,0 @@
-package;
-
-import flixel.FlxSprite;
-import haxe.display.Display.Package;
-
-class TankmenBG extends FlxSprite
-{
- public static var animationNotes:Array = [];
-
- public var strumTime:Float = 0;
- public var goingRight:Bool = false;
- public var tankSpeed:Float = 0.7;
-
- public var endingOffset:Float;
-
- public function new(x:Float, y:Float, isGoingRight:Bool)
- {
- super(x, y);
-
- // makeGraphic(200, 200);
-
- frames = Paths.getSparrowAtlas('tankmanKilled1');
- antialiasing = true;
- animation.addByPrefix('run', 'tankman running', 24, true);
- animation.addByPrefix('shot', 'John Shot ' + FlxG.random.int(1, 2), 24, false);
-
- animation.play('run');
- animation.curAnim.curFrame = FlxG.random.int(0, animation.curAnim.numFrames - 1);
-
- updateHitbox();
-
- setGraphicSize(Std.int(width * 0.8));
- updateHitbox();
- }
-
- public function resetShit(x:Float, y:Float, isGoingRight:Bool)
- {
- setPosition(x, y);
- goingRight = isGoingRight;
- endingOffset = FlxG.random.float(50, 200);
- tankSpeed = FlxG.random.float(0.6, 1);
-
- if (goingRight)
- flipX = true;
- }
-
- override function update(elapsed:Float)
- {
- super.update(elapsed);
-
- if (x >= FlxG.width * 1.2 || x <= FlxG.width * -0.5)
- visible = false;
- else
- visible = true;
-
- if (animation.curAnim.name == 'run')
- {
- var endDirection:Float = (FlxG.width * 0.74) + endingOffset;
-
- if (goingRight)
- {
- endDirection = (FlxG.width * 0.02) - endingOffset;
-
- x = (endDirection + (Conductor.songPosition - strumTime) * tankSpeed);
- }
- else
- {
- x = (endDirection - (Conductor.songPosition - strumTime) * tankSpeed);
- }
- }
-
- if (Conductor.songPosition > strumTime)
- {
- // kill();
- animation.play('shot');
-
- if (goingRight)
- {
- offset.y = 200;
- offset.x = 300;
- }
- }
-
- if (animation.curAnim.name == 'shot' && animation.curAnim.curFrame >= animation.curAnim.frames.length - 1)
- {
- kill();
- }
- }
-}
diff --git a/source/Alphabet.hx b/source/funkin/Alphabet.hx
similarity index 99%
rename from source/Alphabet.hx
rename to source/funkin/Alphabet.hx
index 5caaccbf4..018882e0c 100644
--- a/source/Alphabet.hx
+++ b/source/funkin/Alphabet.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
diff --git a/source/Boyfriend.hx b/source/funkin/Boyfriend.hx
similarity index 98%
rename from source/Boyfriend.hx
rename to source/funkin/Boyfriend.hx
index d407ae8ab..12bf7553e 100644
--- a/source/Boyfriend.hx
+++ b/source/funkin/Boyfriend.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
diff --git a/source/ButtonRemapSubstate.hx b/source/funkin/ButtonRemapSubstate.hx
similarity index 88%
rename from source/ButtonRemapSubstate.hx
rename to source/funkin/ButtonRemapSubstate.hx
index 64ff07948..35c7a1476 100644
--- a/source/ButtonRemapSubstate.hx
+++ b/source/funkin/ButtonRemapSubstate.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSubState;
diff --git a/source/Character.hx b/source/funkin/Character.hx
similarity index 96%
rename from source/Character.hx
rename to source/funkin/Character.hx
index 0c1eb4118..5c266078a 100644
--- a/source/Character.hx
+++ b/source/funkin/Character.hx
@@ -1,11 +1,14 @@
-package;
+package funkin;
-import Section.SwagSection;
+import funkin.Note.NoteData;
+import funkin.SongLoad.SwagSong;
+import funkin.Section.SwagSection;
import flixel.FlxSprite;
import flixel.animation.FlxBaseAnimation;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.util.FlxSort;
import haxe.io.Path;
+import funkin.play.PlayState;
using StringTools;
@@ -19,7 +22,7 @@ class Character extends FlxSprite
public var holdTimer:Float = 0;
- public var animationNotes:Array = [];
+ public var animationNotes:Array = [];
public function new(x:Float, y:Float, ?character:String = "bf", ?isPlayer:Bool = false)
{
@@ -267,6 +270,8 @@ class Character extends FlxSprite
quickAnimAdd('singLEFTmiss', 'BF NOTE LEFT MISS');
quickAnimAdd('singRIGHTmiss', 'BF NOTE RIGHT MISS');
quickAnimAdd('singDOWNmiss', 'BF NOTE DOWN MISS');
+ quickAnimAdd('preAttack', 'bf pre attack');
+ quickAnimAdd('attack', 'boyfriend attack');
quickAnimAdd('hey', 'BF HEY');
quickAnimAdd('firstDeath', "BF dies");
@@ -582,27 +587,25 @@ class Character extends FlxSprite
public function loadMappedAnims()
{
- var swagshit = SongLoad.loadFromJson('picospeaker', 'stress');
+ var swagshit:SwagSong = SongLoad.loadFromJson('stress', 'stress');
- var notes = swagshit.extraNotes.get('picospeaker');
+ var notes:Array = swagshit.noteMap.get('picospeaker');
for (section in notes)
{
- for (idk in section.sectionNotes)
+ for (noteData in section.sectionNotes)
{
- animationNotes.push(idk);
+ animationNotes.push(noteData);
}
}
- TankmenBG.animationNotes = animationNotes;
-
trace(animationNotes);
animationNotes.sort(sortAnims);
}
- function sortAnims(val1:Array, val2:Array):Int
+ function sortAnims(val1:NoteData, val2:NoteData):Int
{
- return FlxSort.byValues(FlxSort.ASCENDING, val1[0], val2[0]);
+ return FlxSort.byValues(FlxSort.ASCENDING, val1.strumTime, val2.strumTime);
}
function quickAnimAdd(name:String, prefix:String)
@@ -657,13 +660,13 @@ class Character extends FlxSprite
// for pico??
if (animationNotes.length > 0)
{
- if (Conductor.songPosition > animationNotes[0][0])
+ if (Conductor.songPosition > animationNotes[0].strumTime)
{
- trace('played shoot anim' + animationNotes[0][1]);
+ trace('played shoot anim' + animationNotes[0].noteData);
var shootAnim:Int = 1;
- if (animationNotes[0][1] >= 2)
+ if ((cast animationNotes[0].noteData) >= 2)
shootAnim = 3;
shootAnim += FlxG.random.int(0, 1);
@@ -689,6 +692,8 @@ class Character extends FlxSprite
*/
public function dance()
{
+ if (animation == null)
+ return;
if (!debugMode)
{
switch (curCharacter)
@@ -723,6 +728,8 @@ class Character extends FlxSprite
public function playAnim(AnimName:String, Force:Bool = false, Reversed:Bool = false, Frame:Int = 0):Void
{
+ if (animation == null)
+ return;
animation.play(AnimName, Force, Reversed, Frame);
var daOffset = animOffsets.get(AnimName);
diff --git a/source/ComboCounter.hx b/source/funkin/ComboCounter.hx
similarity index 99%
rename from source/ComboCounter.hx
rename to source/funkin/ComboCounter.hx
index a7f9c921f..a5f8b71b5 100644
--- a/source/ComboCounter.hx
+++ b/source/funkin/ComboCounter.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
diff --git a/source/Conductor.hx b/source/funkin/Conductor.hx
similarity index 96%
rename from source/Conductor.hx
rename to source/funkin/Conductor.hx
index a1a010ef7..765686740 100644
--- a/source/Conductor.hx
+++ b/source/funkin/Conductor.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import SongLoad.SwagSong;
+import funkin.SongLoad.SwagSong;
/**
* ...
diff --git a/source/Controls.hx b/source/funkin/Controls.hx
similarity index 99%
rename from source/Controls.hx
rename to source/funkin/Controls.hx
index 82a44af0f..31b2933f2 100644
--- a/source/Controls.hx
+++ b/source/funkin/Controls.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxObject;
import flixel.input.FlxInput;
diff --git a/source/CoolUtil.hx b/source/funkin/CoolUtil.hx
similarity index 97%
rename from source/CoolUtil.hx
rename to source/funkin/CoolUtil.hx
index d548ab7b8..60e12f343 100644
--- a/source/CoolUtil.hx
+++ b/source/funkin/CoolUtil.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.FlxState;
@@ -15,7 +15,8 @@ import haxe.format.JsonParser;
import lime.math.Rectangle;
import lime.utils.Assets;
import openfl.filters.ShaderFilter;
-import shaderslmfao.ScreenWipeShader;
+import funkin.play.PlayState;
+import funkin.shaderslmfao.ScreenWipeShader;
using StringTools;
diff --git a/source/CutsceneAnimTestState.hx b/source/funkin/CutsceneAnimTestState.hx
similarity index 99%
rename from source/CutsceneAnimTestState.hx
rename to source/funkin/CutsceneAnimTestState.hx
index eddbfe62e..ae2a0b80f 100644
--- a/source/CutsceneAnimTestState.hx
+++ b/source/funkin/CutsceneAnimTestState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.FlxState;
diff --git a/source/CutsceneCharacter.hx b/source/funkin/CutsceneCharacter.hx
similarity index 99%
rename from source/CutsceneCharacter.hx
rename to source/funkin/CutsceneCharacter.hx
index c85d53b92..cf2caa870 100644
--- a/source/CutsceneCharacter.hx
+++ b/source/funkin/CutsceneCharacter.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
diff --git a/source/DialogueBox.hx b/source/funkin/DialogueBox.hx
similarity index 99%
rename from source/DialogueBox.hx
rename to source/funkin/DialogueBox.hx
index 75b9ea30d..cc582cc84 100644
--- a/source/DialogueBox.hx
+++ b/source/funkin/DialogueBox.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.addons.text.FlxTypeText;
@@ -8,6 +8,7 @@ import flixel.input.FlxKeyManager;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
+import funkin.play.PlayState;
using StringTools;
diff --git a/source/Discord.hx b/source/funkin/Discord.hx
similarity index 94%
rename from source/Discord.hx
rename to source/funkin/Discord.hx
index 04e9ebfa1..34fce44ed 100644
--- a/source/Discord.hx
+++ b/source/funkin/Discord.hx
@@ -1,92 +1,92 @@
-package;
-
-import Sys.sleep;
-
-using StringTools;
-
-#if discord_rpc
-import discord_rpc.DiscordRpc;
-#end
-
-class DiscordClient
-{
- #if discord_rpc
- public function new()
- {
- trace("Discord Client starting...");
- DiscordRpc.start({
- clientID: "814588678700924999",
- onReady: onReady,
- onError: onError,
- onDisconnected: onDisconnected
- });
- trace("Discord Client started.");
-
- while (true)
- {
- DiscordRpc.process();
- sleep(2);
- // trace("Discord Client Update");
- }
-
- DiscordRpc.shutdown();
- }
-
- public static function shutdown()
- {
- DiscordRpc.shutdown();
- }
-
- static function onReady()
- {
- DiscordRpc.presence({
- details: "In the Menus",
- state: null,
- largeImageKey: 'icon',
- largeImageText: "Friday Night Funkin'"
- });
- }
-
- static function onError(_code:Int, _message:String)
- {
- trace('Error! $_code : $_message');
- }
-
- static function onDisconnected(_code:Int, _message:String)
- {
- trace('Disconnected! $_code : $_message');
- }
-
- public static function initialize()
- {
- var DiscordDaemon = sys.thread.Thread.create(() ->
- {
- new DiscordClient();
- });
- trace("Discord Client initialized");
- }
-
- public static function changePresence(details:String, state:Null, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
- {
- var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
-
- if (endTimestamp > 0)
- {
- endTimestamp = startTimestamp + endTimestamp;
- }
-
- DiscordRpc.presence({
- details: details,
- state: state,
- largeImageKey: 'icon',
- largeImageText: "Friday Night Funkin'",
- smallImageKey: smallImageKey,
- // Obtained times are in milliseconds so they are divided so Discord can use it
- startTimestamp: Std.int(startTimestamp / 1000),
- endTimestamp: Std.int(endTimestamp / 1000)
- });
-
- // trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp');
- }
- #end
-}
+package funkin;
+
+import Sys.sleep;
+
+using StringTools;
+
+#if discord_rpc
+import discord_rpc.DiscordRpc;
+#end
+
+class DiscordClient
+{
+ #if discord_rpc
+ public function new()
+ {
+ trace("Discord Client starting...");
+ DiscordRpc.start({
+ clientID: "814588678700924999",
+ onReady: onReady,
+ onError: onError,
+ onDisconnected: onDisconnected
+ });
+ trace("Discord Client started.");
+
+ while (true)
+ {
+ DiscordRpc.process();
+ sleep(2);
+ // trace("Discord Client Update");
+ }
+
+ DiscordRpc.shutdown();
+ }
+
+ public static function shutdown()
+ {
+ DiscordRpc.shutdown();
+ }
+
+ static function onReady()
+ {
+ DiscordRpc.presence({
+ details: "In the Menus",
+ state: null,
+ largeImageKey: 'icon',
+ largeImageText: "Friday Night Funkin'"
+ });
+ }
+
+ static function onError(_code:Int, _message:String)
+ {
+ trace('Error! $_code : $_message');
+ }
+
+ static function onDisconnected(_code:Int, _message:String)
+ {
+ trace('Disconnected! $_code : $_message');
+ }
+
+ public static function initialize()
+ {
+ var DiscordDaemon = sys.thread.Thread.create(() ->
+ {
+ new DiscordClient();
+ });
+ trace("Discord Client initialized");
+ }
+
+ public static function changePresence(details:String, state:Null, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
+ {
+ var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
+
+ if (endTimestamp > 0)
+ {
+ endTimestamp = startTimestamp + endTimestamp;
+ }
+
+ DiscordRpc.presence({
+ details: details,
+ state: state,
+ largeImageKey: 'icon',
+ largeImageText: "Friday Night Funkin'",
+ smallImageKey: smallImageKey,
+ // Obtained times are in milliseconds so they are divided so Discord can use it
+ startTimestamp: Std.int(startTimestamp / 1000),
+ endTimestamp: Std.int(endTimestamp / 1000)
+ });
+
+ // trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp');
+ }
+ #end
+}
diff --git a/source/FlxSwf.hx b/source/funkin/FlxSwf.hx
similarity index 97%
rename from source/FlxSwf.hx
rename to source/funkin/FlxSwf.hx
index 48d0eff11..87d106c0e 100644
--- a/source/FlxSwf.hx
+++ b/source/funkin/FlxSwf.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxCamera;
import flixel.FlxSprite;
diff --git a/source/FlxVideo.hx b/source/funkin/FlxVideo.hx
similarity index 98%
rename from source/FlxVideo.hx
rename to source/funkin/FlxVideo.hx
index 7b9fa5702..82e7c366c 100644
--- a/source/FlxVideo.hx
+++ b/source/funkin/FlxVideo.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxBasic;
import flixel.FlxSprite;
diff --git a/source/FreeplayState.hx b/source/funkin/FreeplayState.hx
similarity index 97%
rename from source/FreeplayState.hx
rename to source/funkin/FreeplayState.hx
index 719178bfd..c309ec5e0 100644
--- a/source/FreeplayState.hx
+++ b/source/funkin/FreeplayState.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Controls.Control;
+import funkin.Controls.Control;
import flash.text.TextField;
import flixel.FlxCamera;
import flixel.FlxGame;
@@ -21,15 +21,16 @@ import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxSpriteUtil;
import flixel.util.FlxTimer;
-import freeplayStuff.BGScrollingText;
-import freeplayStuff.DJBoyfriend;
-import freeplayStuff.FreeplayScore;
-import freeplayStuff.SongMenuItem;
+import funkin.freeplayStuff.BGScrollingText;
+import funkin.freeplayStuff.DJBoyfriend;
+import funkin.freeplayStuff.FreeplayScore;
+import funkin.freeplayStuff.SongMenuItem;
import lime.app.Future;
import lime.utils.Assets;
-import shaderslmfao.AngleMask;
-import shaderslmfao.PureColor;
-import shaderslmfao.StrokeShader;
+import funkin.shaderslmfao.AngleMask;
+import funkin.shaderslmfao.PureColor;
+import funkin.shaderslmfao.StrokeShader;
+import funkin.play.PlayState;
using StringTools;
@@ -78,6 +79,7 @@ class FreeplayState extends MusicBeatSubstate
#if debug
isDebug = true;
addSong('Test', 1, 'bf-pixel');
+ addSong('Pyro', 4, 'bf');
#end
var initSonglist = CoolUtil.coolTextFile(Paths.txt('freeplaySonglist'));
@@ -517,10 +519,7 @@ class FreeplayState extends MusicBeatSubstate
if (controls.BACK)
{
FlxG.sound.play(Paths.sound('cancelMenu'));
-
- close();
-
- // FlxG.switchState(new MainMenuState());
+ FlxG.switchState(new MainMenuState());
}
if (accepted)
diff --git a/source/GameOverSubstate.hx b/source/funkin/GameOverSubstate.hx
similarity index 96%
rename from source/GameOverSubstate.hx
rename to source/funkin/GameOverSubstate.hx
index 469a2a609..f35d5f094 100644
--- a/source/GameOverSubstate.hx
+++ b/source/funkin/GameOverSubstate.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxObject;
import flixel.FlxSubState;
@@ -6,8 +6,9 @@ import flixel.math.FlxPoint;
import flixel.system.FlxSound;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
-import haxe.display.Display.Package;
-import ui.PreferencesMenu;
+import haxe.display.Display;
+import funkin.ui.PreferencesMenu;
+import funkin.play.PlayState;
class GameOverSubstate extends MusicBeatSubstate
{
@@ -24,7 +25,7 @@ class GameOverSubstate extends MusicBeatSubstate
gameOverMusic = new FlxSound();
FlxG.sound.list.add(gameOverMusic);
- var daStage = PlayState.curStage;
+ var daStage = PlayState.curStageId;
var daBf:String = '';
switch (daStage)
{
diff --git a/source/GitarooPause.hx b/source/funkin/GitarooPause.hx
similarity index 97%
rename from source/GitarooPause.hx
rename to source/funkin/GitarooPause.hx
index 61d431de1..d22620a46 100644
--- a/source/GitarooPause.hx
+++ b/source/funkin/GitarooPause.hx
@@ -1,7 +1,8 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
+import funkin.play.PlayState;
class GitarooPause extends MusicBeatState
{
diff --git a/source/HealthIcon.hx b/source/funkin/HealthIcon.hx
similarity index 97%
rename from source/HealthIcon.hx
rename to source/funkin/HealthIcon.hx
index a11251de7..e3b48a153 100644
--- a/source/HealthIcon.hx
+++ b/source/funkin/HealthIcon.hx
@@ -1,7 +1,8 @@
-package;
+package funkin;
import flixel.FlxSprite;
import openfl.utils.Assets;
+import funkin.play.PlayState;
using StringTools;
diff --git a/source/Highscore.hx b/source/funkin/Highscore.hx
similarity index 99%
rename from source/Highscore.hx
rename to source/funkin/Highscore.hx
index 9618114de..45a115075 100644
--- a/source/Highscore.hx
+++ b/source/funkin/Highscore.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
class Highscore
{
diff --git a/source/InitState.hx b/source/funkin/InitState.hx
similarity index 87%
rename from source/InitState.hx
rename to source/funkin/InitState.hx
index 9526720b0..812df1b51 100644
--- a/source/InitState.hx
+++ b/source/funkin/InitState.hx
@@ -1,7 +1,7 @@
-package;
+package funkin;
-#if !(macro)
-import charting.ChartingState;
+import funkin.play.stage.StageData;
+import funkin.charting.ChartingState;
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.transition.TransitionData;
@@ -10,9 +10,11 @@ import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.util.FlxColor;
import openfl.display.BitmapData;
-import play.PicoFight;
-import ui.PreferencesMenu;
-import ui.stageBuildShit.StageBuilderState;
+import funkin.play.PicoFight;
+import funkin.ui.PreferencesMenu;
+import funkin.ui.stageBuildShit.StageBuilderState;
+import funkin.util.macro.MacroUtil;
+import funkin.play.PlayState;
using StringTools;
@@ -29,12 +31,17 @@ import sys.io.File;
import sys.thread.Thread;
#end
+/**
+ * Initializes the game state using custom defines.
+ * Only used in Debug builds.
+ */
class InitState extends FlxTransitionableState
{
override public function create():Void
{
+ trace('This is a debug build, loading InitState...');
#if android
- FlxG.android.preventDefaultKeys = [FlxAndroidKey.BACK];
+ FlxG.android.preventDefaultKeys = [flixel.input.android.FlxAndroidKey.BACK];
#end
#if newgrounds
NGio.init();
@@ -113,6 +120,8 @@ class InitState extends FlxTransitionableState
// FlxTransitionableState.skipNextTransOut = true;
FlxTransitionableState.skipNextTransIn = true;
+ StageDataParser.loadStageCache();
+
#if song
var song = getSong();
@@ -191,21 +200,12 @@ class InitState extends FlxTransitionableState
LoadingState.loadAndSwitchState(new PlayState());
}
}
-#end
function getWeek()
- return Std.parseInt(getDefine("week"));
+ return Std.parseInt(MacroUtil.getDefine("week"));
function getSong()
- return getDefine("song");
+ return MacroUtil.getDefine("song");
function getDif()
- return Std.parseInt(getDefine("dif", "1"));
-
-macro function getDefine(key:String, defaultValue:String = null):haxe.macro.Expr
-{
- var value = haxe.macro.Context.definedValue(key);
- if (value == null)
- value = defaultValue;
- return macro $v{value};
-}
+ return Std.parseInt(MacroUtil.getDefine("dif", "1"));
diff --git a/source/InputFormatter.hx b/source/funkin/InputFormatter.hx
similarity index 99%
rename from source/InputFormatter.hx
rename to source/funkin/InputFormatter.hx
index 30c10ae44..b2d3f596a 100644
--- a/source/InputFormatter.hx
+++ b/source/funkin/InputFormatter.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Controls;
+import funkin.Controls;
import flixel.input.gamepad.FlxGamepad;
import flixel.input.gamepad.FlxGamepadInputID;
import flixel.input.keyboard.FlxKey;
diff --git a/source/LatencyState.hx b/source/funkin/LatencyState.hx
similarity index 98%
rename from source/LatencyState.hx
rename to source/funkin/LatencyState.hx
index e4214577d..4e0ca07af 100644
--- a/source/LatencyState.hx
+++ b/source/funkin/LatencyState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.FlxState;
diff --git a/source/LoadingState.hx b/source/funkin/LoadingState.hx
similarity index 97%
rename from source/LoadingState.hx
rename to source/funkin/LoadingState.hx
index 016377ecb..3b9d88b4f 100644
--- a/source/LoadingState.hx
+++ b/source/funkin/LoadingState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.FlxState;
@@ -12,6 +12,7 @@ import lime.utils.AssetLibrary;
import lime.utils.AssetManifest;
import lime.utils.Assets as LimeAssets;
import openfl.utils.Assets;
+import funkin.play.PlayState;
class LoadingState extends MusicBeatState
{
@@ -187,7 +188,14 @@ class LoadingState extends MusicBeatState
static function getNextState(target:FlxState, stopMusic = false):FlxState
{
- Paths.setCurrentLevel("week" + PlayState.storyWeek);
+ if (PlayState.storyWeek == 0)
+ {
+ Paths.setCurrentLevel('tutorial');
+ }
+ else
+ {
+ Paths.setCurrentLevel("week" + PlayState.storyWeek);
+ }
#if NO_PRELOAD_ALL
var loaded = isSoundLoaded(getSongPath())
&& (!PlayState.SONG.needsVoices || isSoundLoaded(getVocalPath()))
diff --git a/source/MainMenuState.hx b/source/funkin/MainMenuState.hx
similarity index 96%
rename from source/MainMenuState.hx
rename to source/funkin/MainMenuState.hx
index 5a7dc505a..f85c2a3c3 100644
--- a/source/MainMenuState.hx
+++ b/source/funkin/MainMenuState.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import NGio;
+import funkin.NGio;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
@@ -17,12 +17,12 @@ import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import lime.app.Application;
import openfl.filters.ShaderFilter;
-import shaderslmfao.ScreenWipeShader;
-import ui.AtlasMenuList;
-import ui.MenuList;
-import ui.OptionsState;
-import ui.PreferencesMenu;
-import ui.Prompt;
+import funkin.shaderslmfao.ScreenWipeShader;
+import funkin.ui.AtlasMenuList;
+import funkin.ui.MenuList;
+import funkin.ui.OptionsState;
+import funkin.ui.PreferencesMenu;
+import funkin.ui.Prompt;
using StringTools;
@@ -31,7 +31,7 @@ import Discord.DiscordClient;
#end
#if newgrounds
import io.newgrounds.NG;
-import ui.NgPrompt;
+import funkin.ui.NgPrompt;
#end
class MainMenuState extends MusicBeatState
diff --git a/source/MemoryCounter.hx b/source/funkin/MemoryCounter.hx
similarity index 98%
rename from source/MemoryCounter.hx
rename to source/funkin/MemoryCounter.hx
index 2772ada77..8ce1f47f8 100644
--- a/source/MemoryCounter.hx
+++ b/source/funkin/MemoryCounter.hx
@@ -1,3 +1,5 @@
+package funkin;
+
import openfl.text.TextFormat;
import openfl.system.System;
import openfl.text.TextField;
diff --git a/source/MenuCharacter.hx b/source/funkin/MenuCharacter.hx
similarity index 98%
rename from source/MenuCharacter.hx
rename to source/funkin/MenuCharacter.hx
index 5403478e1..14cc4e05f 100644
--- a/source/MenuCharacter.hx
+++ b/source/funkin/MenuCharacter.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
diff --git a/source/MenuItem.hx b/source/funkin/MenuItem.hx
similarity index 98%
rename from source/MenuItem.hx
rename to source/funkin/MenuItem.hx
index 98b08f87d..de03c5b69 100644
--- a/source/MenuItem.hx
+++ b/source/funkin/MenuItem.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
diff --git a/source/MusicBeatState.hx b/source/funkin/MusicBeatState.hx
similarity index 96%
rename from source/MusicBeatState.hx
rename to source/funkin/MusicBeatState.hx
index 5a5d1e18f..570c0c677 100644
--- a/source/MusicBeatState.hx
+++ b/source/funkin/MusicBeatState.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Conductor.BPMChangeEvent;
+import funkin.Conductor.BPMChangeEvent;
import flixel.FlxGame;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.ui.FlxUIState;
diff --git a/source/MusicBeatSubstate.hx b/source/funkin/MusicBeatSubstate.hx
similarity index 95%
rename from source/MusicBeatSubstate.hx
rename to source/funkin/MusicBeatSubstate.hx
index add132693..8374848e4 100644
--- a/source/MusicBeatSubstate.hx
+++ b/source/funkin/MusicBeatSubstate.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Conductor.BPMChangeEvent;
+import funkin.Conductor.BPMChangeEvent;
import flixel.FlxSubState;
class MusicBeatSubstate extends FlxSubState
diff --git a/source/NGio.hx b/source/funkin/NGio.hx
similarity index 99%
rename from source/NGio.hx
rename to source/funkin/NGio.hx
index 2b30865bb..b0b429f6c 100644
--- a/source/NGio.hx
+++ b/source/funkin/NGio.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
#if newgrounds
import flixel.util.FlxSignal;
diff --git a/source/Note.hx b/source/funkin/Note.hx
similarity index 76%
rename from source/Note.hx
rename to source/funkin/Note.hx
index 1cb0b6a4e..290fea0b6 100644
--- a/source/Note.hx
+++ b/source/funkin/Note.hx
@@ -1,19 +1,13 @@
-package;
+package funkin;
import flixel.FlxSprite;
-import flixel.graphics.frames.FlxAtlasFrames;
import flixel.math.FlxMath;
-import flixel.util.FlxColor;
-import flixel.util.FlxTimer;
-import shaderslmfao.ColorSwap;
-import ui.PreferencesMenu;
+import funkin.shaderslmfao.ColorSwap;
+import funkin.ui.PreferencesMenu;
+import funkin.play.PlayState;
using StringTools;
-#if polymod
-import polymod.format.ParseRules.TargetSignatureElement;
-#end
-
class Note extends FlxSprite
{
public var data = new NoteData();
@@ -43,29 +37,41 @@ class Note extends FlxSprite
public var isSustainNote:Bool = false;
public var colorSwap:ColorSwap;
-
+
/** the lowercase name of the note, for anim control, i.e. left right up down */
public var dirName(get, never):String;
- inline function get_dirName() return data.dirName;
-
+
+ inline function get_dirName()
+ return data.dirName;
+
/** the uppercase name of the note, for anim control, i.e. left right up down */
public var dirNameUpper(get, never):String;
- inline function get_dirNameUpper() return data.dirNameUpper;
-
+
+ inline function get_dirNameUpper()
+ return data.dirNameUpper;
+
/** the lowercase name of the note's color, for anim control, i.e. purple blue green red */
public var colorName(get, never):String;
- inline function get_colorName() return data.colorName;
-
+
+ inline function get_colorName()
+ return data.colorName;
+
/** the lowercase name of the note's color, for anim control, i.e. purple blue green red */
public var colorNameUpper(get, never):String;
- inline function get_colorNameUpper() return data.colorNameUpper;
-
+
+ inline function get_colorNameUpper()
+ return data.colorNameUpper;
+
public var highStakes(get, never):Bool;
- inline function get_highStakes() return data.highStakes;
-
+
+ inline function get_highStakes()
+ return data.highStakes;
+
public var lowStakes(get, never):Bool;
- inline function get_lowStakes() return data.lowStakes;
-
+
+ inline function get_lowStakes()
+ return data.lowStakes;
+
public static var swagWidth:Float = 160 * 0.7;
public static var PURP_NOTE:Int = 0;
public static var GREEN_NOTE:Int = 2;
@@ -103,8 +109,9 @@ class Note extends FlxSprite
data.noteData = noteData;
- var daStage:String = PlayState.curStage;
+ var daStage:String = PlayState.curStageId;
+ // TODO: Make this logic more generic
switch (daStage)
{
case 'school' | 'schoolEvil':
@@ -187,7 +194,7 @@ class Note extends FlxSprite
x -= width / 2;
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
x += 30;
if (prevNote.isSustainNote)
@@ -263,7 +270,7 @@ class Note extends FlxSprite
alpha = 0.3;
}
}
-
+
static public function fromData(data:NoteData, prevNote:Note, isSustainNote = false)
{
return new Note(data.strumTime, data.noteData, prevNote, isSustainNote);
@@ -276,101 +283,133 @@ typedef RawNoteData =
var noteData:NoteType;
var sustainLength:Float;
var altNote:Bool;
+ var noteKind:NoteKind;
}
@:forward
abstract NoteData(RawNoteData)
{
- public function new (strumTime = 0.0, noteData:NoteType = 0, sustainLength = 0.0, altNote = false)
+ public function new(strumTime = 0.0, noteData:NoteType = 0, sustainLength = 0.0, altNote = false, noteKind = NORMAL)
{
- this =
- { strumTime : strumTime
- , noteData : noteData
- , sustainLength : sustainLength
- , altNote : altNote
+ this = {
+ strumTime: strumTime,
+ noteData: noteData,
+ sustainLength: sustainLength,
+ altNote: altNote,
+ noteKind: noteKind
}
}
-
+
public var note(get, never):NoteType;
- inline function get_note() return this.noteData.value;
-
+
+ inline function get_note()
+ return this.noteData.value;
+
public var int(get, never):Int;
- inline function get_int() return this.noteData.int;
-
+
+ inline function get_int()
+ return this.noteData.int;
+
public var dir(get, never):NoteDir;
- inline function get_dir() return this.noteData.value;
-
+
+ inline function get_dir()
+ return this.noteData.value;
+
public var dirName(get, never):String;
- inline function get_dirName() return dir.name;
-
+
+ inline function get_dirName()
+ return dir.name;
+
public var dirNameUpper(get, never):String;
- inline function get_dirNameUpper() return dir.nameUpper;
-
+
+ inline function get_dirNameUpper()
+ return dir.nameUpper;
+
public var color(get, never):NoteColor;
- inline function get_color() return this.noteData.value;
-
+
+ inline function get_color()
+ return this.noteData.value;
+
public var colorName(get, never):String;
- inline function get_colorName() return color.name;
-
+
+ inline function get_colorName()
+ return color.name;
+
public var colorNameUpper(get, never):String;
- inline function get_colorNameUpper() return color.nameUpper;
-
+
+ inline function get_colorNameUpper()
+ return color.nameUpper;
+
public var highStakes(get, never):Bool;
- inline function get_highStakes() return this.noteData.highStakes;
-
+
+ inline function get_highStakes()
+ return this.noteData.highStakes;
+
public var lowStakes(get, never):Bool;
- inline function get_lowStakes() return this.noteData.lowStakes;
+
+ inline function get_lowStakes()
+ return this.noteData.lowStakes;
}
enum abstract NoteType(Int) from Int to Int
{
// public var raw(get, never):Int;
// inline function get_raw() return this;
-
public var int(get, never):Int;
- inline function get_int() return this < 0 ? -this : this % 4;
-
+
+ inline function get_int()
+ return this < 0 ? -this : this % 4;
+
public var value(get, never):NoteType;
- inline function get_value() return int;
-
+
+ inline function get_value()
+ return int;
+
public var highStakes(get, never):Bool;
- inline function get_highStakes() return this > 3;
-
+
+ inline function get_highStakes()
+ return this > 3;
+
public var lowStakes(get, never):Bool;
- inline function get_lowStakes() return this < 0;
+
+ inline function get_lowStakes()
+ return this < 0;
}
@:forward
enum abstract NoteDir(NoteType) from Int to Int from NoteType
{
- var LEFT = 0;
- var DOWN = 1;
- var UP = 2;
+ var LEFT = 0;
+ var DOWN = 1;
+ var UP = 2;
var RIGHT = 3;
-
var value(get, never):NoteDir;
- inline function get_value() return this.value;
-
+
+ inline function get_value()
+ return this.value;
+
public var name(get, never):String;
+
function get_name()
{
- return switch(value)
+ return switch (value)
{
- case LEFT : "left" ;
- case DOWN : "down" ;
- case UP : "up" ;
+ case LEFT: "left";
+ case DOWN: "down";
+ case UP: "up";
case RIGHT: "right";
}
}
-
+
public var nameUpper(get, never):String;
+
function get_nameUpper()
{
- return switch(value)
+ return switch (value)
{
- case LEFT : "LEFT" ;
- case DOWN : "DOWN" ;
- case UP : "UP" ;
+ case LEFT: "LEFT";
+ case DOWN: "DOWN";
+ case UP: "UP";
case RIGHT: "RIGHT";
}
}
@@ -380,34 +419,47 @@ enum abstract NoteDir(NoteType) from Int to Int from NoteType
enum abstract NoteColor(NoteType) from Int to Int from NoteType
{
var PURPLE = 0;
- var BLUE = 1;
- var GREEN = 2;
- var RED = 3;
-
+ var BLUE = 1;
+ var GREEN = 2;
+ var RED = 3;
var value(get, never):NoteColor;
- inline function get_value() return this.value;
-
+
+ inline function get_value()
+ return this.value;
+
public var name(get, never):String;
+
function get_name()
{
- return switch(value)
+ return switch (value)
{
case PURPLE: "purple";
- case BLUE : "blue" ;
- case GREEN : "green" ;
- case RED : "red" ;
+ case BLUE: "blue";
+ case GREEN: "green";
+ case RED: "red";
}
}
-
+
public var nameUpper(get, never):String;
+
function get_nameUpper()
{
- return switch(value)
+ return switch (value)
{
case PURPLE: "PURPLE";
- case BLUE : "BLUE" ;
- case GREEN : "GREEN" ;
- case RED : "RED" ;
+ case BLUE: "BLUE";
+ case GREEN: "GREEN";
+ case RED: "RED";
}
}
-}
\ No newline at end of file
+}
+
+enum abstract NoteKind(String) from String to String
+{
+ var NORMAL = "normal";
+ var PYRO_LIGHT = "pyro_light";
+ var PYRO_KICK = "pyro_kick";
+ var PYRO_TOSS = "pyro_toss";
+ var PYRO_COCK = "pyro_cock"; // lol
+ var PYRO_SHOOT = "pyro_shoot";
+}
diff --git a/source/NoteSplash.hx b/source/funkin/NoteSplash.hx
similarity index 94%
rename from source/NoteSplash.hx
rename to source/funkin/NoteSplash.hx
index b23daefe6..3e4d3a3b5 100644
--- a/source/NoteSplash.hx
+++ b/source/funkin/NoteSplash.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import haxe.io.Path;
@@ -34,7 +34,8 @@ class NoteSplash extends FlxSprite
animation.play('note' + noteData + '-' + FlxG.random.int(0, 1), true);
animation.curAnim.frameRate = 24 + FlxG.random.int(-2, 2);
- animation.finishCallback = function(name){
+ animation.finishCallback = function(name)
+ {
kill();
};
updateHitbox();
diff --git a/source/Options.hx b/source/funkin/Options.hx
similarity index 79%
rename from source/Options.hx
rename to source/funkin/Options.hx
index f392a8b1e..7edaa25af 100644
--- a/source/Options.hx
+++ b/source/funkin/Options.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
class Options
{
diff --git a/source/OutdatedSubState.hx b/source/funkin/OutdatedSubState.hx
similarity index 96%
rename from source/OutdatedSubState.hx
rename to source/funkin/OutdatedSubState.hx
index 1af9eb614..32792032e 100644
--- a/source/OutdatedSubState.hx
+++ b/source/funkin/OutdatedSubState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.FlxSubState;
@@ -6,6 +6,7 @@ import flixel.text.FlxText;
import flixel.util.FlxColor;
import lime.app.Application;
+#if newgrounds
class OutdatedSubState extends MusicBeatState
{
public static var leftState:Bool = false;
@@ -42,3 +43,4 @@ class OutdatedSubState extends MusicBeatState
super.update(elapsed);
}
}
+#end
diff --git a/source/Paths.hx b/source/funkin/Paths.hx
similarity index 99%
rename from source/Paths.hx
rename to source/funkin/Paths.hx
index e1b42b901..03a90ff9a 100644
--- a/source/Paths.hx
+++ b/source/funkin/Paths.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.graphics.frames.FlxAtlasFrames;
import openfl.utils.AssetType;
diff --git a/source/PauseSubState.hx b/source/funkin/PauseSubState.hx
similarity index 98%
rename from source/PauseSubState.hx
rename to source/funkin/PauseSubState.hx
index f2ee9c60f..14cbb63a8 100644
--- a/source/PauseSubState.hx
+++ b/source/funkin/PauseSubState.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Controls.Control;
+import funkin.Controls.Control;
import flixel.FlxSprite;
import flixel.FlxSubState;
import flixel.addons.transition.FlxTransitionableState;
@@ -11,6 +11,7 @@ import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
+import funkin.play.PlayState;
class PauseSubState extends MusicBeatSubstate
{
diff --git a/source/PlayerSettings.hx b/source/funkin/PlayerSettings.hx
similarity index 99%
rename from source/PlayerSettings.hx
rename to source/funkin/PlayerSettings.hx
index 1b9681579..ab5d9e689 100644
--- a/source/PlayerSettings.hx
+++ b/source/funkin/PlayerSettings.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Controls;
+import funkin.Controls;
import flixel.FlxCamera;
import flixel.input.actions.FlxActionInput;
import flixel.input.gamepad.FlxGamepad;
diff --git a/source/Section.hx b/source/funkin/Section.hx
similarity index 92%
rename from source/Section.hx
rename to source/funkin/Section.hx
index e1fc84f5e..cc0931acb 100644
--- a/source/Section.hx
+++ b/source/funkin/Section.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import Note.NoteData;
+import funkin.Note.NoteData;
typedef SwagSection =
{
diff --git a/source/SongLoad.hx b/source/funkin/SongLoad.hx
similarity index 95%
rename from source/SongLoad.hx
rename to source/funkin/SongLoad.hx
index c5d694220..770795602 100644
--- a/source/SongLoad.hx
+++ b/source/funkin/SongLoad.hx
@@ -1,7 +1,7 @@
-package;
+package funkin;
-import Note.NoteData;
-import Section.SwagSection;
+import funkin.Note.NoteData;
+import funkin.Section.SwagSection;
import haxe.Json;
import haxe.format.JsonParser;
import lime.utils.Assets;
@@ -48,7 +48,7 @@ class SongLoad
public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong
{
- var rawJson = Assets.getText(Paths.json(folder.toLowerCase() + '/' + jsonInput.toLowerCase())).trim();
+ var rawJson = Assets.getText(Paths.json('songs/${folder.toLowerCase()}/${jsonInput.toLowerCase()}')).trim();
while (!rawJson.endsWith("}"))
{
@@ -174,6 +174,8 @@ class SongLoad
for (sectionIndex => section in noteStuff)
{
+ if (section == null || section.sectionNotes == null)
+ continue;
for (noteIndex => noteDataArray in section.sectionNotes)
{
var arrayDipshit:Array = cast noteDataArray; // crackhead
@@ -188,6 +190,10 @@ class SongLoad
noteStuff[sectionIndex].sectionNotes[noteIndex].noteData = arrayDipshit[1];
noteStuff[sectionIndex].sectionNotes[noteIndex].sustainLength = arrayDipshit[2];
noteStuff[sectionIndex].sectionNotes[noteIndex].altNote = arrayDipshit[3];
+ if (arrayDipshit.length >= 5)
+ {
+ noteStuff[sectionIndex].sectionNotes[noteIndex].noteKind = arrayDipshit[4];
+ }
}
else if (noteDataArray != null)
{
diff --git a/source/StoryMenuState.hx b/source/funkin/StoryMenuState.hx
similarity index 98%
rename from source/StoryMenuState.hx
rename to source/funkin/StoryMenuState.hx
index 8ff7d1370..00e482a8a 100644
--- a/source/StoryMenuState.hx
+++ b/source/funkin/StoryMenuState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
#if discord_rpc
import Discord.DiscordClient;
@@ -14,6 +14,7 @@ import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import lime.net.curl.CURLCode;
+import funkin.play.PlayState;
using StringTools;
@@ -21,7 +22,7 @@ class StoryMenuState extends MusicBeatState
{
var scoreText:FlxText;
- var weekData:Array = [
+ var weekData:Array> = [
['Tutorial'],
['Bopeebo', 'Fresh', 'Dadbattle'],
['Spookeez', 'South', "Monster"],
@@ -430,11 +431,10 @@ class StoryMenuState extends MusicBeatState
// grpWeekCharacters.members[0].updateHitbox();
}
- var stringThing:Array = weekData[curWeek];
-
- for (i in stringThing)
+ var trackNames:Array = weekData[curWeek];
+ for (i in trackNames)
{
- txtTracklist.text += "\n" + i;
+ txtTracklist.text += '\n${i}';
}
txtTracklist.text = txtTracklist.text.toUpperCase();
diff --git a/source/SwagCamera.hx b/source/funkin/SwagCamera.hx
similarity index 99%
rename from source/SwagCamera.hx
rename to source/funkin/SwagCamera.hx
index 4903b0e07..7184601b9 100644
--- a/source/SwagCamera.hx
+++ b/source/funkin/SwagCamera.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxCamera;
import flixel.FlxSprite;
diff --git a/source/TankCutscene.hx b/source/funkin/TankCutscene.hx
similarity index 96%
rename from source/TankCutscene.hx
rename to source/funkin/TankCutscene.hx
index a8a18321c..a144b16fe 100644
--- a/source/TankCutscene.hx
+++ b/source/funkin/TankCutscene.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import flixel.FlxSprite;
import flixel.system.FlxSound;
diff --git a/source/TitleState.hx b/source/funkin/TitleState.hx
similarity index 97%
rename from source/TitleState.hx
rename to source/funkin/TitleState.hx
index e3feea22d..f54bfbd3c 100644
--- a/source/TitleState.hx
+++ b/source/funkin/TitleState.hx
@@ -1,6 +1,6 @@
-package;
+package funkin;
-import audiovis.SpectogramSprite;
+import funkin.audiovis.SpectogramSprite;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
@@ -29,10 +29,10 @@ import openfl.events.NetStatusEvent;
import openfl.media.Video;
import openfl.net.NetConnection;
import openfl.net.NetStream;
-import shaderslmfao.BuildingShaders;
-import shaderslmfao.ColorSwap;
-import shaderslmfao.TitleOutline;
-import ui.PreferencesMenu;
+import funkin.shaderslmfao.BuildingShaders;
+import funkin.shaderslmfao.ColorSwap;
+import funkin.shaderslmfao.TitleOutline;
+import funkin.ui.PreferencesMenu;
using StringTools;
@@ -351,17 +351,6 @@ class TitleState extends MusicBeatState
FlxG.switchState(new CutsceneAnimTestState());
#end
- /*
- if (FlxG.keys.justPressed.R)
- {
- #if polymod
- polymod.Polymod.init({modRoot: "mods", dirs: ['introMod']});
- trace('reinitialized');
- #end
- }
-
- */
-
if (FlxG.sound.music != null)
Conductor.songPosition = FlxG.sound.music.time;
if (FlxG.keys.justPressed.F)
diff --git a/source/VideoState.hx b/source/funkin/VideoState.hx
similarity index 99%
rename from source/VideoState.hx
rename to source/funkin/VideoState.hx
index 5130cc223..d5954ccda 100644
--- a/source/VideoState.hx
+++ b/source/funkin/VideoState.hx
@@ -1,4 +1,4 @@
-package;
+package funkin;
import openfl.display.Sprite;
import openfl.events.AsyncErrorEvent;
diff --git a/source/VoicesGroup.hx b/source/funkin/VoicesGroup.hx
similarity index 99%
rename from source/VoicesGroup.hx
rename to source/funkin/VoicesGroup.hx
index 86f22d1d8..ae34bb0c6 100644
--- a/source/VoicesGroup.hx
+++ b/source/funkin/VoicesGroup.hx
@@ -1,3 +1,5 @@
+package funkin;
+
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.system.FlxSound;
diff --git a/source/animate/AnimTestStage.hx b/source/funkin/animate/AnimTestStage.hx
similarity index 96%
rename from source/animate/AnimTestStage.hx
rename to source/funkin/animate/AnimTestStage.hx
index eb7a2b38b..26e1fceb2 100644
--- a/source/animate/AnimTestStage.hx
+++ b/source/funkin/animate/AnimTestStage.hx
@@ -1,4 +1,4 @@
-package animate;
+package funkin.animate;
import flixel.FlxSprite;
import flixel.FlxState;
diff --git a/source/animate/AnimateTimeline.hx b/source/funkin/animate/AnimateTimeline.hx
similarity index 94%
rename from source/animate/AnimateTimeline.hx
rename to source/funkin/animate/AnimateTimeline.hx
index 70fc3f5a7..27f70f7ae 100644
--- a/source/animate/AnimateTimeline.hx
+++ b/source/funkin/animate/AnimateTimeline.hx
@@ -1,7 +1,5 @@
-package animate;
+package funkin.animate;
-// import animate.FlxSymbol.Parsed;
-// import animate.FlxSymbol.Timeline;
import flixel.FlxCamera;
import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
diff --git a/source/animate/FlxAnimate.hx b/source/funkin/animate/FlxAnimate.hx
similarity index 97%
rename from source/animate/FlxAnimate.hx
rename to source/funkin/animate/FlxAnimate.hx
index 60408697a..607776275 100644
--- a/source/animate/FlxAnimate.hx
+++ b/source/funkin/animate/FlxAnimate.hx
@@ -1,10 +1,8 @@
-package animate;
+package funkin.animate;
-// import animateAtlasPlayer.assets.AssetManager;
-// import animateAtlasPlayer.core.Animation;
-import animate.ParseAnimate.AnimJson;
-import animate.ParseAnimate.Sprite;
-import animate.ParseAnimate.Spritemap;
+import funkin.animate.ParseAnimate.AnimJson;
+import funkin.animate.ParseAnimate.Sprite;
+import funkin.animate.ParseAnimate.Spritemap;
import flixel.FlxCamera;
import flixel.FlxSprite;
import flixel.graphics.FlxGraphic;
diff --git a/source/animate/FlxSymbol.hx b/source/funkin/animate/FlxSymbol.hx
similarity index 84%
rename from source/animate/FlxSymbol.hx
rename to source/funkin/animate/FlxSymbol.hx
index bb995057b..3e2fffd84 100644
--- a/source/animate/FlxSymbol.hx
+++ b/source/funkin/animate/FlxSymbol.hx
@@ -1,12 +1,12 @@
-package animate;
+package funkin.animate;
-import animate.ParseAnimate.AnimJson;
-import animate.ParseAnimate.Animation;
-import animate.ParseAnimate.Frame;
-import animate.ParseAnimate.Sprite;
-import animate.ParseAnimate.Spritemap;
-import animate.ParseAnimate.SymbolDictionary;
-import animate.ParseAnimate.Timeline;
+import funkin.animate.ParseAnimate.AnimJson;
+import funkin.animate.ParseAnimate.Animation;
+import funkin.animate.ParseAnimate.Frame;
+import funkin.animate.ParseAnimate.Sprite;
+import funkin.animate.ParseAnimate.Spritemap;
+import funkin.animate.ParseAnimate.SymbolDictionary;
+import funkin.animate.ParseAnimate.Timeline;
import flixel.FlxCamera;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxFrame.FlxFrameAngle;
diff --git a/source/animate/ParseAnimate.hx b/source/funkin/animate/ParseAnimate.hx
similarity index 99%
rename from source/animate/ParseAnimate.hx
rename to source/funkin/animate/ParseAnimate.hx
index 673cbcce1..a9902fa6d 100644
--- a/source/animate/ParseAnimate.hx
+++ b/source/funkin/animate/ParseAnimate.hx
@@ -1,10 +1,9 @@
-package animate;
+package funkin.animate;
import haxe.format.JsonParser;
import openfl.Assets;
import openfl.geom.Matrix3D;
import openfl.geom.Matrix;
-import sys.io.File;
/**
* Generally designed / written in a way that can be easily taken out of FNF and used elsewhere
diff --git a/source/animate/TimelineFrame.hx b/source/funkin/animate/TimelineFrame.hx
similarity index 94%
rename from source/animate/TimelineFrame.hx
rename to source/funkin/animate/TimelineFrame.hx
index 629e91f62..dbd5bfc7a 100644
--- a/source/animate/TimelineFrame.hx
+++ b/source/funkin/animate/TimelineFrame.hx
@@ -1,6 +1,6 @@
-package animate;
+package funkin.animate;
-import animate.FlxSymbol.Frame;
+import funkin.animate.ParseAnimate.Frame;
import flixel.FlxSprite;
import flixel.input.mouse.FlxMouseEventManager;
import flixel.util.FlxColor;
diff --git a/source/audiovis/ABotVis.hx b/source/funkin/audiovis/ABotVis.hx
similarity index 97%
rename from source/audiovis/ABotVis.hx
rename to source/funkin/audiovis/ABotVis.hx
index c6411c4d8..a05238e9f 100644
--- a/source/audiovis/ABotVis.hx
+++ b/source/funkin/audiovis/ABotVis.hx
@@ -1,13 +1,13 @@
-package audiovis;
+package funkin.audiovis;
-import audiovis.dsp.FFT;
+import funkin.audiovis.dsp.FFT;
import flixel.FlxSprite;
import flixel.addons.plugin.taskManager.FlxTask;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
import flixel.math.FlxMath;
import flixel.system.FlxSound;
-import ui.PreferencesMenu.CheckboxThingie;
+import funkin.ui.PreferencesMenu.CheckboxThingie;
using Lambda;
diff --git a/source/audiovis/PolygonSpectogram.hx b/source/funkin/audiovis/PolygonSpectogram.hx
similarity index 96%
rename from source/audiovis/PolygonSpectogram.hx
rename to source/funkin/audiovis/PolygonSpectogram.hx
index 31409c45f..d8af4e07d 100644
--- a/source/audiovis/PolygonSpectogram.hx
+++ b/source/funkin/audiovis/PolygonSpectogram.hx
@@ -1,12 +1,12 @@
-package audiovis;
+package funkin.audiovis;
-import audiovis.VisShit.CurAudioInfo;
+import funkin.audiovis.VisShit.CurAudioInfo;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.system.FlxSound;
import flixel.util.FlxColor;
import lime.utils.Int16Array;
-import rendering.MeshRender;
+import funkin.rendering.MeshRender;
class PolygonSpectogram extends MeshRender
{
diff --git a/source/audiovis/SpectogramSprite.hx b/source/funkin/audiovis/SpectogramSprite.hx
similarity index 98%
rename from source/audiovis/SpectogramSprite.hx
rename to source/funkin/audiovis/SpectogramSprite.hx
index 394bfadf6..b3cb6ff62 100644
--- a/source/audiovis/SpectogramSprite.hx
+++ b/source/funkin/audiovis/SpectogramSprite.hx
@@ -1,8 +1,8 @@
-package audiovis;
+package funkin.audiovis;
-import audiovis.PolygonSpectogram.VISTYPE;
-import audiovis.VisShit.CurAudioInfo;
-import audiovis.dsp.FFT;
+import funkin.audiovis.PolygonSpectogram.VISTYPE;
+import funkin.audiovis.VisShit.CurAudioInfo;
+import funkin.audiovis.dsp.FFT;
import flixel.FlxSprite;
import flixel.group.FlxGroup;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
diff --git a/source/audiovis/VisShit.hx b/source/funkin/audiovis/VisShit.hx
similarity index 98%
rename from source/audiovis/VisShit.hx
rename to source/funkin/audiovis/VisShit.hx
index 819a76e59..232d060a5 100644
--- a/source/audiovis/VisShit.hx
+++ b/source/funkin/audiovis/VisShit.hx
@@ -1,6 +1,6 @@
-package audiovis;
+package funkin.audiovis;
-import audiovis.dsp.FFT;
+import funkin.audiovis.dsp.FFT;
import flixel.math.FlxMath;
import flixel.system.FlxSound;
import lime.utils.Int16Array;
diff --git a/source/audiovis/dsp/Complex.hx b/source/funkin/audiovis/dsp/Complex.hx
similarity index 98%
rename from source/audiovis/dsp/Complex.hx
rename to source/funkin/audiovis/dsp/Complex.hx
index 8dc8c9b7a..eeff9679f 100644
--- a/source/audiovis/dsp/Complex.hx
+++ b/source/funkin/audiovis/dsp/Complex.hx
@@ -1,4 +1,4 @@
-package audiovis.dsp;
+package funkin.audiovis.dsp;
/**
Complex number representation.
diff --git a/source/audiovis/dsp/FFT.hx b/source/funkin/audiovis/dsp/FFT.hx
similarity index 97%
rename from source/audiovis/dsp/FFT.hx
rename to source/funkin/audiovis/dsp/FFT.hx
index d46c8ffa1..7929c0f0a 100644
--- a/source/audiovis/dsp/FFT.hx
+++ b/source/funkin/audiovis/dsp/FFT.hx
@@ -1,9 +1,9 @@
-package audiovis.dsp;
+package funkin.audiovis.dsp;
-import audiovis.dsp.Complex;
+import funkin.audiovis.dsp.Complex;
-using audiovis.dsp.OffsetArray;
-using audiovis.dsp.Signal;
+using funkin.audiovis.dsp.OffsetArray;
+using funkin.audiovis.dsp.Signal;
// these are only used for testing, down in FFT.main()
diff --git a/source/audiovis/dsp/OffsetArray.hx b/source/funkin/audiovis/dsp/OffsetArray.hx
similarity index 98%
rename from source/audiovis/dsp/OffsetArray.hx
rename to source/funkin/audiovis/dsp/OffsetArray.hx
index ec5ddf539..db06ce40f 100644
--- a/source/audiovis/dsp/OffsetArray.hx
+++ b/source/funkin/audiovis/dsp/OffsetArray.hx
@@ -1,4 +1,4 @@
-package audiovis.dsp;
+package funkin.audiovis.dsp;
/**
A view into an Array with an indexing offset.
diff --git a/source/audiovis/dsp/Signal.hx b/source/funkin/audiovis/dsp/Signal.hx
similarity index 98%
rename from source/audiovis/dsp/Signal.hx
rename to source/funkin/audiovis/dsp/Signal.hx
index 7c5631c21..aeb6c3f91 100644
--- a/source/audiovis/dsp/Signal.hx
+++ b/source/funkin/audiovis/dsp/Signal.hx
@@ -1,4 +1,4 @@
-package audiovis.dsp;
+package funkin.audiovis.dsp;
using Lambda;
diff --git a/source/charting/ChartingState.hx b/source/funkin/charting/ChartingState.hx
similarity index 99%
rename from source/charting/ChartingState.hx
rename to source/funkin/charting/ChartingState.hx
index ab098e1ac..fd7b739de 100644
--- a/source/charting/ChartingState.hx
+++ b/source/funkin/charting/ChartingState.hx
@@ -1,12 +1,12 @@
-package charting;
+package funkin.charting;
-import Conductor.BPMChangeEvent;
-import Note.NoteData;
-import Section.SwagSection;
-import SongLoad.SwagSong;
-import audiovis.ABotVis;
-import audiovis.PolygonSpectogram;
-import audiovis.SpectogramSprite;
+import funkin.Conductor.BPMChangeEvent;
+import funkin.Note.NoteData;
+import funkin.Section.SwagSection;
+import funkin.SongLoad.SwagSong;
+import funkin.audiovis.ABotVis;
+import funkin.audiovis.PolygonSpectogram;
+import funkin.audiovis.SpectogramSprite;
import flixel.FlxSprite;
import flixel.addons.display.FlxGridOverlay;
import flixel.addons.transition.FlxTransitionableState;
@@ -29,7 +29,8 @@ import lime.utils.Assets;
import openfl.events.Event;
import openfl.events.IOErrorEvent;
import openfl.net.FileReference;
-import rendering.MeshRender;
+import funkin.rendering.MeshRender;
+import funkin.play.PlayState;
using Lambda;
using StringTools;
diff --git a/source/freeplayStuff/BGScrollingText.hx b/source/funkin/freeplayStuff/BGScrollingText.hx
similarity index 98%
rename from source/freeplayStuff/BGScrollingText.hx
rename to source/funkin/freeplayStuff/BGScrollingText.hx
index f25b8c82e..39837e031 100644
--- a/source/freeplayStuff/BGScrollingText.hx
+++ b/source/funkin/freeplayStuff/BGScrollingText.hx
@@ -1,4 +1,4 @@
-package freeplayStuff;
+package funkin.freeplayStuff;
import flixel.FlxObject;
import flixel.group.FlxGroup.FlxTypedGroup;
diff --git a/source/freeplayStuff/DJBoyfriend.hx b/source/funkin/freeplayStuff/DJBoyfriend.hx
similarity index 97%
rename from source/freeplayStuff/DJBoyfriend.hx
rename to source/funkin/freeplayStuff/DJBoyfriend.hx
index 25c725b11..8ea52370d 100644
--- a/source/freeplayStuff/DJBoyfriend.hx
+++ b/source/funkin/freeplayStuff/DJBoyfriend.hx
@@ -1,4 +1,4 @@
-package freeplayStuff;
+package funkin.freeplayStuff;
import flixel.FlxSprite;
import flixel.util.FlxSignal;
diff --git a/source/freeplayStuff/FreeplayScore.hx b/source/funkin/freeplayStuff/FreeplayScore.hx
similarity index 96%
rename from source/freeplayStuff/FreeplayScore.hx
rename to source/funkin/freeplayStuff/FreeplayScore.hx
index 315f881ea..cef363cd0 100644
--- a/source/freeplayStuff/FreeplayScore.hx
+++ b/source/funkin/freeplayStuff/FreeplayScore.hx
@@ -1,4 +1,4 @@
-package freeplayStuff;
+package funkin.freeplayStuff;
import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
@@ -11,6 +11,8 @@ class FreeplayScore extends FlxTypedSpriteGroup
function set_scoreShit(val):Int
{
+ if (group == null || group.members == null)
+ return val;
var loopNum:Int = group.members.length - 1;
var dumbNumb = Std.parseInt(Std.string(val));
var prevNum:ScoreNum;
diff --git a/source/freeplayStuff/SongMenuItem.hx b/source/funkin/freeplayStuff/SongMenuItem.hx
similarity index 98%
rename from source/freeplayStuff/SongMenuItem.hx
rename to source/funkin/freeplayStuff/SongMenuItem.hx
index cf9935ee2..7eb862bef 100644
--- a/source/freeplayStuff/SongMenuItem.hx
+++ b/source/funkin/freeplayStuff/SongMenuItem.hx
@@ -1,4 +1,4 @@
-package freeplayStuff;
+package funkin.freeplayStuff;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
diff --git a/source/i18n/FireTongueHandler.hx b/source/funkin/i18n/FireTongueHandler.hx
similarity index 99%
rename from source/i18n/FireTongueHandler.hx
rename to source/funkin/i18n/FireTongueHandler.hx
index 53a16059d..fdb13e41c 100644
--- a/source/i18n/FireTongueHandler.hx
+++ b/source/funkin/i18n/FireTongueHandler.hx
@@ -1,4 +1,4 @@
-package i18n;
+package funkin.i18n;
import firetongue.FireTongue;
diff --git a/source/funkin/i18n/README.md b/source/funkin/i18n/README.md
new file mode 100644
index 000000000..d55a8f41c
--- /dev/null
+++ b/source/funkin/i18n/README.md
@@ -0,0 +1,3 @@
+# i18n
+
+This package contains functions used for internationalization (i18n).
diff --git a/source/import.hx b/source/funkin/import.hx
similarity index 88%
rename from source/import.hx
rename to source/funkin/import.hx
index 13736ea5e..67be91c51 100644
--- a/source/import.hx
+++ b/source/funkin/import.hx
@@ -1,6 +1,6 @@
#if !macro
// Only import these when we aren't in a macro.
-import Paths;
+import funkin.Paths;
import flixel.FlxG; // This one in particular causes a compile error if you're using macros.
#end
diff --git a/source/modding/IHook.hx b/source/funkin/modding/IHook.hx
similarity index 92%
rename from source/modding/IHook.hx
rename to source/funkin/modding/IHook.hx
index a1a75d08d..fdcf9da27 100644
--- a/source/modding/IHook.hx
+++ b/source/funkin/modding/IHook.hx
@@ -1,13 +1,13 @@
-package modding;
-
-import polymod.hscript.HScriptable;
-
-/**
- * Add this interface to a class to make it a scriptable object.
- * Functions annotated with @:hscript will call the relevant script.
- */
-@:hscript({
- // ALL of these values are added to ALL scripts in the child classes.
- context: [FlxG, FlxSprite, Math, Paths, Std]
-})
-interface IHook extends HScriptable {}
+package funkin.modding;
+
+import polymod.hscript.HScriptable;
+
+/**
+ * Add this interface to a class to make it a scriptable object.
+ * Functions annotated with @:hscript will call the relevant script.
+ */
+@:hscript({
+ // ALL of these values are added to ALL scripts in the child classes.
+ context: [FlxG, FlxSprite, Math, Paths, Std]
+})
+interface IHook extends HScriptable {}
diff --git a/source/funkin/modding/PolymodErrorHandler.hx b/source/funkin/modding/PolymodErrorHandler.hx
new file mode 100644
index 000000000..c0616dfb5
--- /dev/null
+++ b/source/funkin/modding/PolymodErrorHandler.hx
@@ -0,0 +1,71 @@
+package funkin.modding;
+
+import polymod.Polymod;
+
+class PolymodErrorHandler
+{
+ /**
+ * Show a popup with the given text.
+ * This displays a system popup, it WILL interrupt the game.
+ * Make sure to only use this when it's important, like when there's a script error.
+ *
+ * @param name The name at the top of the popup.
+ * @param desc The body text of the popup.
+ */
+ public static function showAlert(name:String, desc:String):Void
+ {
+ lime.app.Application.current.window.alert(desc, name);
+ }
+
+ public static function onPolymodError(error:PolymodError):Void
+ {
+ // Perform an action based on the error code.
+ switch (error.code)
+ {
+ case MOD_LOAD_PREPARE:
+ logInfo('[POLYMOD]: ${error.message}');
+ case MOD_LOAD_DONE:
+ logInfo('[POLYMOD]: ${error.message}');
+ case MISSING_ICON:
+ logWarn('[POLYMOD]: A mod is missing an icon. Please add one.');
+ case SCRIPT_PARSE_ERROR:
+ // A syntax error when parsing a script.
+ logError('[POLYMOD]: ${error.message}');
+ showAlert('Polymod Script Parsing Error', error.message);
+ case SCRIPT_EXCEPTION:
+ // A runtime error when running a script.
+ logError('[POLYMOD]: ${error.message}');
+ showAlert('Polymod Script Execution Error', error.message);
+ case SCRIPT_CLASS_NOT_FOUND:
+ // A scripted class tried to reference an unknown superclass.
+ logError('[POLYMOD]: ${error.message}');
+ showAlert('Polymod Script Parsing Error', error.message);
+ default:
+ // Log the message based on its severity.
+ switch (error.severity)
+ {
+ case NOTICE:
+ logInfo('[POLYMOD]: ${error.message}');
+ case WARNING:
+ logWarn('[POLYMOD]: ${error.message}');
+ case ERROR:
+ logError('[POLYMOD]: ${error.message}');
+ }
+ }
+ }
+
+ static function logInfo(message:String):Void
+ {
+ trace('[INFO ] ${message}');
+ }
+
+ static function logError(message:String):Void
+ {
+ trace('[ERROR] ${message}');
+ }
+
+ static function logWarn(message:String):Void
+ {
+ trace('[WARN ] ${message}');
+ }
+}
diff --git a/source/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx
similarity index 69%
rename from source/modding/PolymodHandler.hx
rename to source/funkin/modding/PolymodHandler.hx
index de4438b54..1f6d149cb 100644
--- a/source/modding/PolymodHandler.hx
+++ b/source/funkin/modding/PolymodHandler.hx
@@ -1,202 +1,168 @@
-package modding;
-
-#if polymod
-import polymod.Polymod.ModMetadata;
-import polymod.Polymod;
-import polymod.backends.OpenFLBackend;
-import polymod.backends.PolymodAssets.PolymodAssetType;
-import polymod.format.ParseRules.LinesParseFormat;
-import polymod.format.ParseRules.TextFileFormat;
-#end
-
-class PolymodHandler
-{
- /**
- * The API version that mods should comply with.
- * Format this with Semantic Versioning; ...
- * Bug fixes increment the patch version, new features increment the minor version.
- * Changes that break old mods increment the major version.
- */
- static final API_VERSION = "0.1.0";
-
- /**
- * Where relative to the executable that mods are located.
- */
- static final MOD_FOLDER = "mods";
-
- /**
- * Loads the game with ALL mods enabled with Polymod.
- */
- public static function loadAllMods()
- {
- #if polymod
- trace("Initializing Polymod (using all mods)...");
- loadModsById(getAllModIds());
- #else
- trace("Polymod not initialized; not supported on this platform.");
- #end
- }
-
- /**
- * Loads the game without any mods enabled with Polymod.
- */
- public static function loadNoMods()
- {
- // We still need to configure the debug print calls etc.
- #if polymod
- trace("Initializing Polymod (using no mods)...");
- loadModsById([]);
- #else
- trace("Polymod not initialized; not supported on this platform.");
- #end
- }
-
- public static function loadModsById(ids:Array)
- {
- #if polymod
- if (ids.length == 0)
- {
- trace('You attempted to load zero mods.');
- }
- else
- {
- trace('Attempting to load ${ids.length} mods...');
- }
- var loadedModList = polymod.Polymod.init({
- // Root directory for all mods.
- modRoot: MOD_FOLDER,
- // The directories for one or more mods to load.
- dirs: ids,
- // Framework being used to load assets.
- framework: OPENFL,
- // The current version of our API.
- apiVersion: API_VERSION,
- // Call this function any time an error occurs.
- errorCallback: onPolymodError,
- // Enforce semantic version patterns for each mod.
- // modVersions: null,
- // A map telling Polymod what the asset type is for unfamiliar file extensions.
- // extensionMap: [],
-
- frameworkParams: buildFrameworkParams(),
-
- // List of filenames to ignore in mods. Use the default list to ignore the metadata file, etc.
- ignoredFiles: Polymod.getDefaultIgnoreList(),
-
- // Parsing rules for various data formats.
- parseRules: buildParseRules(),
- });
-
- if (loadedModList == null)
- {
- trace('[POLYMOD] An error occurred! Failed when loading mods!');
- }
- else
- {
- if (loadedModList.length == 0)
- {
- trace('[POLYMOD] Mod loading complete. We loaded no mods / ${ids.length} mods.');
- }
- else
- {
- trace('[POLYMOD] Mod loading complete. We loaded ${loadedModList.length} / ${ids.length} mods.');
- }
- }
-
- for (mod in loadedModList)
- trace(' * ${mod.title} v${mod.modVersion} [${mod.id}]');
-
- #if debug
- var fileList = Polymod.listModFiles("IMAGE");
- trace('[POLYMOD] Installed mods have replaced ${fileList.length} images.');
- for (item in fileList)
- trace(' * $item');
-
- fileList = Polymod.listModFiles("TEXT");
- trace('[POLYMOD] Installed mods have replaced ${fileList.length} text files.');
- for (item in fileList)
- trace(' * $item');
-
- fileList = Polymod.listModFiles("MUSIC");
- trace('[POLYMOD] Installed mods have replaced ${fileList.length} music files.');
- for (item in fileList)
- trace(' * $item');
-
- fileList = Polymod.listModFiles("SOUND");
- trace('[POLYMOD] Installed mods have replaced ${fileList.length} sound files.');
- for (item in fileList)
- trace(' * $item');
- #end
- #else
- trace("[POLYMOD] Mods are not supported on this platform.");
- #end
- }
-
- #if polymod
- static function buildParseRules():polymod.format.ParseRules
- {
- var output = polymod.format.ParseRules.getDefault();
- // Ensure TXT files have merge support.
- output.addType("txt", TextFileFormat.LINES);
- // Ensure script files have merge support.
- output.addType("hscript", TextFileFormat.PLAINTEXT);
-
- // You can specify the format of a specific file, with file extension.
- // output.addFile("data/introText.txt", TextFileFormat.LINES)
- return output;
- }
-
- static inline function buildFrameworkParams():polymod.Polymod.FrameworkParams
- {
- return {
- assetLibraryPaths: [
- "songs" => "./songs", "shared" => "./", "tutorial" => "./tutorial", "scripts" => "./scripts", "week1" => "./week1", "week2" => "./week2",
- "week3" => "./week3", "week4" => "./week4", "week5" => "./week5", "week6" => "./week6", "week7" => "./week7", "week8" => "./week8",
- ]
- }
- }
-
- static function onPolymodError(error:PolymodError):Void
- {
- // Perform an action based on the error code.
- switch (error.code)
- {
- case MOD_LOAD_PREPARE:
- trace('[POLYMOD] ${error.message}');
- case MOD_LOAD_DONE:
- trace('[POLYMOD] ${error.message}');
- case MISSING_ICON:
- trace('[POLYMOD] A mod is missing an icon. Please add one.');
- default:
- // Log the message based on its severity.
- switch (error.severity)
- {
- case NOTICE:
- trace('[POLYMOD] ${error.message}');
- case WARNING:
- trace('[POLYMOD] ${error.message}');
- case ERROR:
- trace('[POLYMOD] ${error.message}');
- }
- }
- }
- #end
-
- public static function getAllMods()
- {
- #if polymod
- trace('Scanning the mods folder...');
- var modMetadata = Polymod.scan(MOD_FOLDER);
- trace('Found ${modMetadata.length} mods when scanning.');
- return modMetadata;
- #else
- return new Array();
- #end
- }
-
- public static function getAllModIds():Array
- {
- var modIds = [for (i in getAllMods()) i.id];
- return modIds;
- }
-}
+package funkin.modding;
+
+import polymod.Polymod.ModMetadata;
+import polymod.Polymod;
+import polymod.backends.OpenFLBackend;
+import polymod.backends.PolymodAssets.PolymodAssetType;
+import polymod.format.ParseRules.LinesParseFormat;
+import polymod.format.ParseRules.TextFileFormat;
+
+class PolymodHandler
+{
+ /**
+ * The API version that mods should comply with.
+ * Format this with Semantic Versioning; ...
+ * Bug fixes increment the patch version, new features increment the minor version.
+ * Changes that break old mods increment the major version.
+ */
+ static final API_VERSION = "0.1.0";
+
+ /**
+ * Where relative to the executable that mods are located.
+ */
+ static final MOD_FOLDER = "mods";
+
+ /**
+ * Loads the game with ALL mods enabled with Polymod.
+ */
+ public static function loadAllMods()
+ {
+ trace("Initializing Polymod (using all mods)...");
+ loadModsById(getAllModIds());
+ }
+
+ /**
+ * Loads the game without any mods enabled with Polymod.
+ */
+ public static function loadNoMods()
+ {
+ // We still need to configure the debug print calls etc.
+ trace("Initializing Polymod (using no mods)...");
+ loadModsById([]);
+ }
+
+ public static function loadModsById(ids:Array)
+ {
+ if (ids.length == 0)
+ {
+ trace('You attempted to load zero mods.');
+ }
+ else
+ {
+ trace('Attempting to load ${ids.length} mods...');
+ }
+ var loadedModList = polymod.Polymod.init({
+ // Root directory for all mods.
+ modRoot: MOD_FOLDER,
+ // The directories for one or more mods to load.
+ dirs: ids,
+ // Framework being used to load assets.
+ framework: OPENFL,
+ // The current version of our API.
+ apiVersion: API_VERSION,
+ // Call this function any time an error occurs.
+ errorCallback: PolymodErrorHandler.onPolymodError,
+ // Enforce semantic version patterns for each mod.
+ // modVersions: null,
+ // A map telling Polymod what the asset type is for unfamiliar file extensions.
+ // extensionMap: [],
+
+ frameworkParams: buildFrameworkParams(),
+
+ // List of filenames to ignore in mods. Use the default list to ignore the metadata file, etc.
+ ignoredFiles: Polymod.getDefaultIgnoreList(),
+
+ // Parsing rules for various data formats.
+ parseRules: buildParseRules(),
+
+ // Parse hxc files and register the scripted classes in them.
+ useScriptedClasses: true,
+ });
+
+ if (loadedModList == null)
+ {
+ trace('[POLYMOD] An error occurred! Failed when loading mods!');
+ }
+ else
+ {
+ if (loadedModList.length == 0)
+ {
+ trace('[POLYMOD] Mod loading complete. We loaded no mods / ${ids.length} mods.');
+ }
+ else
+ {
+ trace('[POLYMOD] Mod loading complete. We loaded ${loadedModList.length} / ${ids.length} mods.');
+ }
+ }
+
+ for (mod in loadedModList)
+ {
+ trace(' * ${mod.title} v${mod.modVersion} [${mod.id}]');
+ }
+
+ #if debug
+ var fileList = Polymod.listModFiles(PolymodAssetType.IMAGE);
+ trace('[POLYMOD] Installed mods have replaced ${fileList.length} images.');
+ for (item in fileList)
+ trace(' * $item');
+
+ fileList = Polymod.listModFiles(PolymodAssetType.TEXT);
+ trace('[POLYMOD] Installed mods have replaced ${fileList.length} text files.');
+ for (item in fileList)
+ trace(' * $item');
+
+ fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_MUSIC);
+ trace('[POLYMOD] Installed mods have replaced ${fileList.length} music files.');
+ for (item in fileList)
+ trace(' * $item');
+
+ fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_SOUND);
+ trace('[POLYMOD] Installed mods have replaced ${fileList.length} sound files.');
+ for (item in fileList)
+ trace(' * $item');
+
+ fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_GENERIC);
+ trace('[POLYMOD] Installed mods have replaced ${fileList.length} generic audio files.');
+ for (item in fileList)
+ trace(' * $item');
+ #end
+ }
+
+ static function buildParseRules():polymod.format.ParseRules
+ {
+ var output = polymod.format.ParseRules.getDefault();
+ // Ensure TXT files have merge support.
+ output.addType("txt", TextFileFormat.LINES);
+ // Ensure script files have merge support.
+ output.addType("hscript", TextFileFormat.PLAINTEXT);
+ output.addType("hxs", TextFileFormat.PLAINTEXT);
+
+ // You can specify the format of a specific file, with file extension.
+ // output.addFile("data/introText.txt", TextFileFormat.LINES)
+ return output;
+ }
+
+ static inline function buildFrameworkParams():polymod.Polymod.FrameworkParams
+ {
+ return {
+ assetLibraryPaths: [
+ "songs" => "songs", "shared" => "", "tutorial" => "tutorial", "scripts" => "scripts", "week1" => "week1", "week2" => "week2",
+ "week3" => "week3", "week4" => "week4", "week5" => "week5", "week6" => "week6", "week7" => "week7", "week8" => "week8",
+ ]
+ }
+ }
+
+ public static function getAllMods():Array
+ {
+ trace('Scanning the mods folder...');
+ var modMetadata = Polymod.scan(MOD_FOLDER);
+ trace('Found ${modMetadata.length} mods when scanning.');
+ return modMetadata;
+ }
+
+ public static function getAllModIds():Array
+ {
+ var modIds = [for (i in getAllMods()) i.id];
+ return modIds;
+ }
+}
diff --git a/source/funkin/modding/base/README.md b/source/funkin/modding/base/README.md
new file mode 100644
index 000000000..ebcea06f3
--- /dev/null
+++ b/source/funkin/modding/base/README.md
@@ -0,0 +1,5 @@
+# modding.base
+
+This package is used to allow modders to create scripted classes which extend these base classes.
+For example, one script can extend FlxSprite and another can call `ScriptedFlxSprite.init('ClassName')`.
+Most of these scripted class stubs are not used by the game itself, so this package has been explicitly marked to be ignored by DCE.
diff --git a/source/funkin/modding/base/ScriptedFlxSprite.hx b/source/funkin/modding/base/ScriptedFlxSprite.hx
new file mode 100644
index 000000000..9bccdc778
--- /dev/null
+++ b/source/funkin/modding/base/ScriptedFlxSprite.hx
@@ -0,0 +1,10 @@
+package funkin.modding.base;
+
+import flixel.FlxSprite;
+import funkin.modding.IHook;
+
+@:hscriptClass
+class ScriptedFlxSprite extends FlxSprite implements IHook
+{
+ // No body needed for this class, it's magic ;)
+}
diff --git a/source/funkin/modding/base/ScriptedFlxSpriteGroup.hx b/source/funkin/modding/base/ScriptedFlxSpriteGroup.hx
new file mode 100644
index 000000000..a60dfdad3
--- /dev/null
+++ b/source/funkin/modding/base/ScriptedFlxSpriteGroup.hx
@@ -0,0 +1,10 @@
+package funkin.modding.base;
+
+import flixel.group.FlxSpriteGroup;
+import funkin.modding.IHook;
+
+@:hscriptClass
+class ScriptedFlxSpriteGroup extends FlxSpriteGroup implements IHook
+{
+ // No body needed for this class, it's magic ;)
+}
diff --git a/source/play/Fighter.hx b/source/funkin/play/Fighter.hx
similarity index 97%
rename from source/play/Fighter.hx
rename to source/funkin/play/Fighter.hx
index cde3c1f30..fa17b6bd7 100644
--- a/source/play/Fighter.hx
+++ b/source/funkin/play/Fighter.hx
@@ -1,4 +1,4 @@
-package play;
+package funkin.play;
import flixel.FlxSprite;
diff --git a/source/play/PicoFight.hx b/source/funkin/play/PicoFight.hx
similarity index 98%
rename from source/play/PicoFight.hx
rename to source/funkin/play/PicoFight.hx
index 576d8b4f8..1ef8a1fa2 100644
--- a/source/play/PicoFight.hx
+++ b/source/funkin/play/PicoFight.hx
@@ -1,7 +1,7 @@
-package play;
+package funkin.play;
-import Note.NoteData;
-import audiovis.PolygonSpectogram;
+import funkin.Note.NoteData;
+import funkin.audiovis.PolygonSpectogram;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.addons.effects.FlxTrail;
diff --git a/source/PlayState.hx b/source/funkin/play/PlayState.hx
similarity index 76%
rename from source/PlayState.hx
rename to source/funkin/play/PlayState.hx
index 345db7912..fa7a482be 100644
--- a/source/PlayState.hx
+++ b/source/funkin/play/PlayState.hx
@@ -1,22 +1,15 @@
-package;
+package funkin.play;
-import Note;
-import Section.SwagSection;
-import SongLoad.SwagSong;
-import charting.ChartingState;
import flixel.FlxCamera;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.FlxSubState;
-import flixel.addons.effects.FlxTrail;
import flixel.addons.transition.FlxTransitionableState;
import flixel.group.FlxGroup;
-import flixel.math.FlxAngle;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
-import flixel.system.FlxSound;
import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
@@ -24,14 +17,18 @@ import flixel.ui.FlxBar;
import flixel.util.FlxColor;
import flixel.util.FlxSort;
import flixel.util.FlxTimer;
+import funkin.Note;
+import funkin.Section.SwagSection;
+import funkin.SongLoad.SwagSong;
+import funkin.charting.ChartingState;
+import funkin.play.stage.Stage;
+import funkin.play.stage.StageData;
+import funkin.shaderslmfao.ColorSwap;
+import funkin.ui.PopUpStuff;
+import funkin.ui.PreferencesMenu;
import haxe.Json;
import lime.ui.Haptic;
import lime.utils.Assets;
-import shaderslmfao.BuildingShaders;
-import shaderslmfao.ColorSwap;
-import shaderslmfao.OverlayBlend;
-import ui.PopUpStuff;
-import ui.PreferencesMenu;
using StringTools;
@@ -41,7 +38,8 @@ import Discord.DiscordClient;
class PlayState extends MusicBeatState
{
- public static var curStage:String = '';
+ // TODO: Reorganize these variables (maybe there should be a separate class like Conductor just to hold them?)
+ public static var curStageId:String = '';
public static var SONG:SwagSong;
public static var isStoryMode:Bool = false;
public static var storyWeek:Int = 0;
@@ -51,8 +49,6 @@ class PlayState extends MusicBeatState
public static var practiceMode:Bool = false;
public static var needsReset:Bool = false;
- var halloweenLevel:Bool = false;
-
private var vocals:VoicesGroup;
private var vocalsFinished:Bool = false;
@@ -75,6 +71,11 @@ class PlayState extends MusicBeatState
private var strumLineNotes:FlxTypedGroup;
+ /**
+ * The currently active PlayState.
+ */
+ public static var instance:PlayState = null;
+
/**
* Strumline for player
*/
@@ -84,7 +85,9 @@ class PlayState extends MusicBeatState
private var curSong:String = "";
private var gfSpeed:Int = 1;
- private var health:Float = 1;
+
+ public static var health:Float = 1;
+
private var healthDisplay:Float = 1;
private var combo:Int = 0;
@@ -103,32 +106,6 @@ class PlayState extends MusicBeatState
public static var seenCutscene:Bool = false;
- var halloweenBG:FlxSprite;
- var isHalloween:Bool = false;
-
- var phillyCityLights:FlxTypedGroup;
- var phillyTrain:FlxSprite;
- var trainSound:FlxSound;
-
- var foregroundSprites:FlxTypedGroup;
-
- var limo:FlxSprite;
- var grpLimoDancers:FlxTypedGroup;
- var fastCar:FlxSprite;
-
- var upperBoppers:FlxSprite;
- var bottomBoppers:FlxSprite;
- var santa:FlxSprite;
-
- var bgGirls:BackgroundGirls;
- var wiggleShit:WiggleEffect = new WiggleEffect();
-
- var tankmanRun:FlxTypedGroup;
- var gfCutsceneLayer:FlxGroup;
- var bfTankCutsceneLayer:FlxGroup;
- var tankWatchtower:BGSprite;
- var tankGround:BGSprite;
-
var talking:Bool = true;
var songScore:Int = 0;
var scoreTxt:FlxText;
@@ -157,14 +134,18 @@ class PlayState extends MusicBeatState
#end
var camPos:FlxPoint;
- var lightFadeShader:BuildingShaders;
var comboPopUps:PopUpStuff;
override public function create()
{
+ instance = this;
+
initCameras();
+ // Starting health.
+ health = 1;
+
persistentUpdate = true;
persistentDraw = true;
@@ -174,28 +155,24 @@ class PlayState extends MusicBeatState
Conductor.mapBPMChanges(SONG);
Conductor.changeBPM(SONG.bpm);
- foregroundSprites = new FlxTypedGroup();
-
// dialogue init shit, just for week 5 really (for now...?)
switch (SONG.song.toLowerCase())
{
case 'senpai':
- dialogue = CoolUtil.coolTextFile(Paths.txt('senpai/senpaiDialogue'));
+ dialogue = CoolUtil.coolTextFile(Paths.txt('songs/senpai/senpaiDialogue'));
case 'roses':
- dialogue = CoolUtil.coolTextFile(Paths.txt('roses/rosesDialogue'));
+ dialogue = CoolUtil.coolTextFile(Paths.txt('songs/roses/rosesDialogue'));
case 'thorns':
- dialogue = CoolUtil.coolTextFile(Paths.txt('thorns/thornsDialogue'));
+ dialogue = CoolUtil.coolTextFile(Paths.txt('songs/thorns/thornsDialogue'));
}
#if discord_rpc
initDiscord();
#end
- initStageBullshit();
+ initStage();
initCharacters();
- add(foregroundSprites);
-
if (dialogue != null)
{
doof = new DialogueBox(false, dialogue);
@@ -384,316 +361,35 @@ class PlayState extends MusicBeatState
FlxG.cameras.add(camHUD, false);
}
- // a lot of this stage code will be cleaned up more when the stage load shit is more fleshed out! For now it's still a lot of hardcoded shit!!
- function initStageBullshit()
+ function initStage()
{
+ // TODO: Move stageId to the song file.
switch (SONG.song.toLowerCase())
{
case 'spookeez' | 'monster' | 'south':
- curStage = "spooky";
- halloweenLevel = true;
-
- var hallowTex = Paths.getSparrowAtlas('halloween_bg');
-
- halloweenBG = new FlxSprite(-200, -100);
- halloweenBG.frames = hallowTex;
- halloweenBG.animation.addByPrefix('idle', 'halloweem bg0');
- halloweenBG.animation.addByPrefix('lightning', 'halloweem bg lightning strike', 24, false);
- halloweenBG.animation.play('idle');
- halloweenBG.antialiasing = true;
- add(halloweenBG);
-
- isHalloween = true;
+ curStageId = "spookyMansion";
case 'pico' | 'blammed' | 'philly':
- curStage = 'philly';
-
- var bg:FlxSprite = new FlxSprite(-100).loadGraphic(Paths.image('philly/sky'));
- bg.scrollFactor.set(0.1, 0.1);
- add(bg);
-
- var city:FlxSprite = new FlxSprite(-10).loadGraphic(Paths.image('philly/city'));
- city.scrollFactor.set(0.3, 0.3);
- city.setGraphicSize(Std.int(city.width * 0.85));
- city.updateHitbox();
- add(city);
-
- lightFadeShader = new BuildingShaders();
- phillyCityLights = new FlxTypedGroup();
-
- add(phillyCityLights);
-
- for (i in 0...5)
- {
- var light:FlxSprite = new FlxSprite(city.x).loadGraphic(Paths.image('philly/win' + i));
- light.scrollFactor.set(0.3, 0.3);
- light.visible = false;
- light.setGraphicSize(Std.int(light.width * 0.85));
- light.updateHitbox();
- light.antialiasing = true;
- light.shader = lightFadeShader.shader;
- phillyCityLights.add(light);
- }
-
- var streetBehind:FlxSprite = new FlxSprite(-40, 50).loadGraphic(Paths.image('philly/behindTrain'));
- add(streetBehind);
-
- phillyTrain = new FlxSprite(2000, 360).loadGraphic(Paths.image('philly/train'));
- add(phillyTrain);
-
- trainSound = new FlxSound().loadEmbedded(Paths.sound('train_passes'));
- FlxG.sound.list.add(trainSound);
-
- // var cityLights:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.win0.png);
-
- var street:FlxSprite = new FlxSprite(-40, streetBehind.y).loadGraphic(Paths.image('philly/street'));
- add(street);
+ curStageId = 'phillyTrain';
case "milf" | 'satin-panties' | 'high':
- curStage = 'limo';
- defaultCamZoom *= 0.90;
-
- var skyBG:FlxSprite = new FlxSprite(-120, -50).loadGraphic(Paths.image('limo/limoSunset'));
-
- var overlayShader:OverlayBlend = new OverlayBlend();
- var sunOverlay:FlxSprite = new FlxSprite().loadGraphic(Paths.image('limo/limoOverlay'));
- sunOverlay.setGraphicSize(Std.int(sunOverlay.width * 2));
- sunOverlay.updateHitbox();
- overlayShader.funnyShit.input = sunOverlay.pixels;
- skyBG.shader = overlayShader;
-
- skyBG.scrollFactor.set(0.1, 0.1);
- add(skyBG);
-
- var bgLimo:FlxSprite = new FlxSprite(-200, 480);
- bgLimo.frames = Paths.getSparrowAtlas('limo/bgLimo');
- bgLimo.animation.addByPrefix('drive', "background limo pink", 24);
- bgLimo.animation.play('drive');
- bgLimo.scrollFactor.set(0.4, 0.4);
- add(bgLimo);
-
- grpLimoDancers = new FlxTypedGroup();
- add(grpLimoDancers);
-
- for (i in 0...5)
- {
- var dancer:BackgroundDancer = new BackgroundDancer((370 * i) + 130, bgLimo.y - 400);
- dancer.scrollFactor.set(0.4, 0.4);
- grpLimoDancers.add(dancer);
- }
-
- var overlayShit:FlxSprite = new FlxSprite(-500, -600).loadGraphic(Paths.image('limo/limoOverlay'));
- overlayShit.alpha = 0.5;
- // add(overlayShit);
- // var shaderBullshit = new BlendModeEffect(new OverlayShader(), FlxColor.RED);
- // FlxG.camera.setFilters([new ShaderFilter(cast shaderBullshit.shader)]);
- // overlayShit.shader = shaderBullshit;
-
- limo = new FlxSprite(-120, 550);
- limo.frames = Paths.getSparrowAtlas('limo/limoDrive');
- limo.animation.addByPrefix('drive', "Limo stage", 24);
- limo.animation.play('drive');
- limo.antialiasing = true;
-
- fastCar = new FlxSprite(-300, 160).loadGraphic(Paths.image('limo/fastCarLol'));
- // add(limo);
+ curStageId = 'limoRide';
case "cocoa" | 'eggnog':
- curStage = 'mall';
-
- defaultCamZoom *= 0.80;
-
- var bg:FlxSprite = new FlxSprite(-1000, -500).loadGraphic(Paths.image('christmas/bgWalls'));
- bg.antialiasing = true;
- bg.scrollFactor.set(0.2, 0.2);
- bg.active = false;
- bg.setGraphicSize(Std.int(bg.width * 0.8));
- bg.updateHitbox();
- add(bg);
-
- upperBoppers = new FlxSprite(-240, -90);
- upperBoppers.frames = Paths.getSparrowAtlas('christmas/upperBop');
- upperBoppers.animation.addByPrefix('bop', "Upper Crowd Bob", 24, false);
- upperBoppers.antialiasing = true;
- upperBoppers.scrollFactor.set(0.33, 0.33);
- upperBoppers.setGraphicSize(Std.int(upperBoppers.width * 0.85));
- upperBoppers.updateHitbox();
- add(upperBoppers);
-
- var bgEscalator:FlxSprite = new FlxSprite(-1100, -600).loadGraphic(Paths.image('christmas/bgEscalator'));
- bgEscalator.antialiasing = true;
- bgEscalator.scrollFactor.set(0.3, 0.3);
- bgEscalator.active = false;
- bgEscalator.setGraphicSize(Std.int(bgEscalator.width * 0.9));
- bgEscalator.updateHitbox();
- add(bgEscalator);
-
- var tree:FlxSprite = new FlxSprite(370, -250).loadGraphic(Paths.image('christmas/christmasTree'));
- tree.antialiasing = true;
- tree.scrollFactor.set(0.40, 0.40);
- add(tree);
-
- bottomBoppers = new FlxSprite(-300, 140);
- bottomBoppers.frames = Paths.getSparrowAtlas('christmas/bottomBop');
- bottomBoppers.animation.addByPrefix('bop', 'Bottom Level Boppers', 24, false);
- bottomBoppers.antialiasing = true;
- bottomBoppers.scrollFactor.set(0.9, 0.9);
- bottomBoppers.setGraphicSize(Std.int(bottomBoppers.width * 1));
- bottomBoppers.updateHitbox();
- add(bottomBoppers);
-
- var fgSnow:FlxSprite = new FlxSprite(-600, 700).loadGraphic(Paths.image('christmas/fgSnow'));
- fgSnow.active = false;
- fgSnow.antialiasing = true;
- add(fgSnow);
-
- santa = new FlxSprite(-840, 150);
- santa.frames = Paths.getSparrowAtlas('christmas/santa');
- santa.animation.addByPrefix('idle', 'santa idle in fear', 24, false);
- santa.antialiasing = true;
- add(santa);
+ curStageId = 'mallXmas';
case 'winter-horrorland':
- loadStage('mallEvil');
+ curStageId = 'mallEvil';
+ case 'pyro':
+ curStageId = 'pyro';
case 'senpai' | 'roses':
- curStage = 'school';
-
- // defaultCamZoom *= 0.9;
-
- var bgSky = new FlxSprite().loadGraphic(Paths.image('weeb/weebSky'));
- bgSky.scrollFactor.set(0.1, 0.1);
- add(bgSky);
-
- var repositionShit = -200;
-
- var bgSchool:FlxSprite = new FlxSprite(repositionShit, 0).loadGraphic(Paths.image('weeb/weebSchool'));
- bgSchool.scrollFactor.set(0.6, 0.90);
- add(bgSchool);
-
- var bgStreet:FlxSprite = new FlxSprite(repositionShit).loadGraphic(Paths.image('weeb/weebStreet'));
- bgStreet.scrollFactor.set(0.95, 0.95);
- add(bgStreet);
-
- var fgTrees:FlxSprite = new FlxSprite(repositionShit + 170, 130).loadGraphic(Paths.image('weeb/weebTreesBack'));
- fgTrees.scrollFactor.set(0.9, 0.9);
- add(fgTrees);
-
- var bgTrees:FlxSprite = new FlxSprite(repositionShit - 380, -800);
- var treetex = Paths.getPackerAtlas('weeb/weebTrees');
- bgTrees.frames = treetex;
- bgTrees.animation.add('treeLoop', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], 12);
- bgTrees.animation.play('treeLoop');
- bgTrees.scrollFactor.set(0.85, 0.85);
- add(bgTrees);
-
- var treeLeaves:FlxSprite = new FlxSprite(repositionShit, -40);
- treeLeaves.frames = Paths.getSparrowAtlas('weeb/petals');
- treeLeaves.animation.addByPrefix('leaves', 'PETALS ALL', 24, true);
- treeLeaves.animation.play('leaves');
- treeLeaves.scrollFactor.set(0.85, 0.85);
- add(treeLeaves);
-
- var widShit = Std.int(bgSky.width * 6);
-
- bgSky.setGraphicSize(widShit);
- bgSchool.setGraphicSize(widShit);
- bgStreet.setGraphicSize(widShit);
- bgTrees.setGraphicSize(Std.int(widShit * 1.4));
- fgTrees.setGraphicSize(Std.int(widShit * 0.8));
- treeLeaves.setGraphicSize(widShit);
-
- fgTrees.updateHitbox();
- bgSky.updateHitbox();
- bgSchool.updateHitbox();
- bgStreet.updateHitbox();
- bgTrees.updateHitbox();
- treeLeaves.updateHitbox();
-
- bgGirls = new BackgroundGirls(-100, 190);
- bgGirls.scrollFactor.set(0.9, 0.9);
-
- if (SONG.song.toLowerCase() == 'roses')
- {
- bgGirls.getScared();
- }
-
- bgGirls.setGraphicSize(Std.int(bgGirls.width * daPixelZoom));
- bgGirls.updateHitbox();
- add(bgGirls);
- case 'thorns':
- // loadStage('schoolEvil');
- curStage = 'schoolEvil';
-
- var schoolBG:FlxSprite = new FlxSprite(-200, 0).loadGraphic(Paths.image('weeb/evilSchoolBG'));
- wiggleShit.waveAmplitude = 0.017;
- wiggleShit.waveSpeed = 2;
- wiggleShit.waveFrequency = 4;
- schoolBG.shader = wiggleShit.shader;
- schoolBG.setGraphicSize(Std.int(schoolBG.width * 6));
- schoolBG.updateHitbox();
- // schoolBG.scale.set(6, 6);
- add(schoolBG);
-
- schoolBG.scrollFactor.set(0.7, 1);
-
- var schoolFront:FlxSprite = new FlxSprite(-250, schoolBG.y + 20).loadGraphic(Paths.image('weeb/evilSchoolFG'));
-
- schoolFront.shader = wiggleShit.shader;
-
- schoolFront.setGraphicSize(Std.int(schoolFront.width * 6));
- schoolFront.updateHitbox();
- add(schoolFront);
-
- case 'guns' | 'stress' | 'ugh':
- loadStage('tank');
-
- // this goes after tankSky and before tankMountains in stage file
- // need to accomodate for the velocity thing!
- var tankSky:BGSprite = new BGSprite('tankClouds', FlxG.random.int(-700, -100), FlxG.random.int(-20, 20), 0.1, 0.1);
- tankSky.active = true;
- tankSky.velocity.x = FlxG.random.float(5, 15);
- add(tankSky);
-
- tankWatchtower = new BGSprite('tankWatchtower', 100, 50, 0.5, 0.5, ['watchtower gradient color']);
- add(tankWatchtower);
-
- tankGround = new BGSprite('tankRolling', 300, 300, 0.5, 0.5, ['BG tank w lighting'], true);
- add(tankGround);
- // tankGround.active = false;
-
- tankmanRun = new FlxTypedGroup();
- add(tankmanRun);
-
- var tankGround:BGSprite = new BGSprite('tankGround', -420, -150);
- tankGround.setGraphicSize(Std.int(tankGround.width * 1.15));
- tankGround.updateHitbox();
- add(tankGround);
-
- moveTank();
-
- // smokeLeft.screenCenter();
-
- var fgTank0:BGSprite = new BGSprite('tank0', -500, 650, 1.7, 1.5, ['fg']);
- foregroundSprites.add(fgTank0);
-
- var fgTank1:BGSprite = new BGSprite('tank1', -300, 750, 2, 0.2, ['fg']);
- foregroundSprites.add(fgTank1);
-
- // just called 'foreground' just cuz small inconsistency no bbiggei
- var fgTank2:BGSprite = new BGSprite('tank2', 450, 940, 1.5, 1.5, ['foreground']);
- foregroundSprites.add(fgTank2);
-
- var fgTank4:BGSprite = new BGSprite('tank4', 1300, 900, 1.5, 1.5, ['fg']);
- foregroundSprites.add(fgTank4);
-
- var fgTank5:BGSprite = new BGSprite('tank5', 1620, 700, 1.5, 1.5, ['fg']);
- foregroundSprites.add(fgTank5);
-
- var fgTank3:BGSprite = new BGSprite('tank3', 1300, 1200, 3.5, 2.5, ['fg']);
- foregroundSprites.add(fgTank3);
-
+ curStageId = 'school';
case "darnell":
- loadStage('phillyStreets');
-
+ curStageId = 'phillyStreets';
+ case 'thorns':
+ curStageId = 'schoolEvil';
+ case 'guns' | 'stress' | 'ugh':
+ curStageId = 'tankmanBattlefield';
default:
- loadStage('stage');
+ curStageId = "mainStage";
}
+ loadStage(curStageId);
}
function initCharacters()
@@ -701,15 +397,15 @@ class PlayState extends MusicBeatState
// all dis is shitty, redo later for stage shit
var gfVersion:String = 'gf';
- switch (curStage)
+ switch (curStageId)
{
- case 'limo':
+ case 'limoRide':
gfVersion = 'gf-car';
- case 'mall' | 'mallEvil':
+ case 'mallXmas' | 'mallEvil':
gfVersion = 'gf-christmas';
case 'school' | 'schoolEvil':
gfVersion = 'gf-pixel';
- case 'tank':
+ case 'tankmanBattlefield':
gfVersion = 'gf-tankmen';
}
@@ -729,23 +425,6 @@ class PlayState extends MusicBeatState
case 'pico-speaker':
gf.x -= 50;
gf.y -= 200;
-
- var tempTankman:TankmenBG = new TankmenBG(20, 500, true);
- tempTankman.strumTime = 10;
- tempTankman.resetShit(20, 600, true);
- tankmanRun.add(tempTankman);
-
- for (i in 0...TankmenBG.animationNotes.length)
- {
- if (FlxG.random.bool(16))
- {
- var tankman:TankmenBG = tankmanRun.recycle(TankmenBG);
- // new TankmenBG(500, 200 + FlxG.random.int(50, 100), TankmenBG.animationNotes[i][1] < 2);
- tankman.strumTime = TankmenBG.animationNotes[i][0];
- tankman.resetShit(500, 200 + FlxG.random.int(50, 100), TankmenBG.animationNotes[i][1] < 2);
- tankmanRun.add(tankman);
- }
- }
}
dad = new Character(100, 100, SONG.player2);
@@ -790,37 +469,8 @@ class PlayState extends MusicBeatState
boyfriend = new Boyfriend(770, 450, SONG.player1);
// REPOSITIONING PER STAGE
- switch (curStage)
+ switch (curStageId)
{
- case 'limo':
- boyfriend.y -= 220;
- boyfriend.x += 260;
-
- resetFastCar();
- add(fastCar);
- case 'mall':
- boyfriend.x += 200;
- case 'mallEvil':
- boyfriend.x += 320;
- dad.y -= 80;
- case 'school':
- boyfriend.x += 200;
- boyfriend.y += 220;
- gf.x += 180;
- gf.y += 300;
- case 'schoolEvil':
- // trailArea.scrollFactor.set();
-
- var evilTrail = new FlxTrail(dad, null, 4, 24, 0.3, 0.069);
- // evilTrail.changeValuesEnabled(false, false, false, false);
- // evilTrail.changeGraphic()
- add(evilTrail);
- // evilTrail.scrollFactor.set(1.1, 1.1);
-
- boyfriend.x += 200;
- boyfriend.y += 220;
- gf.x += 180;
- gf.y += 300;
case "tank":
gf.y += 10;
gf.x -= 30;
@@ -834,24 +484,25 @@ class PlayState extends MusicBeatState
gf.x -= 170;
gf.y -= 75;
}
- case 'stage' | 'phillyStreets':
- dad.y = 870 - dad.height;
}
- add(gf);
+ if (curStage != null)
+ {
+ // We're using Eric's stage handler.
+ // Characters get added to the stage, not the main scene.
+ curStage.addCharacter(gf, GF);
+ curStage.addCharacter(boyfriend, BF);
+ curStage.addCharacter(dad, DAD);
- gfCutsceneLayer = new FlxGroup();
- add(gfCutsceneLayer);
-
- bfTankCutsceneLayer = new FlxGroup();
- add(bfTankCutsceneLayer);
-
- // Shitty layering but whatev it works LOL
- if (curStage == 'limo')
- add(limo);
-
- add(dad);
- add(boyfriend);
+ // Redo z-indexes.
+ curStage.refresh();
+ }
+ else
+ {
+ add(gf);
+ add(dad);
+ add(boyfriend);
+ }
}
function ughIntro()
@@ -862,6 +513,7 @@ class PlayState extends MusicBeatState
blackShit.scrollFactor.set();
add(blackShit);
+ #if html5
var vid:FlxVideo = new FlxVideo('music/ughCutscene.mp4');
vid.finishCallback = function()
{
@@ -870,6 +522,12 @@ class PlayState extends MusicBeatState
startCountdown();
cameraMovement();
};
+ #else
+ remove(blackShit);
+ FlxTween.tween(FlxG.camera, {zoom: defaultCamZoom}, (Conductor.crochet / 1000) * 5, {ease: FlxEase.quadInOut});
+ startCountdown();
+ cameraMovement();
+ #end
FlxG.camera.zoom = defaultCamZoom * 1.2;
@@ -940,43 +598,59 @@ class PlayState extends MusicBeatState
});*/
}
- function loadStage(path:String)
+ /**
+ * Removes any references to the current stage, then clears the stage cache,
+ * then reloads all the stages.
+ *
+ * This is useful for when you want to edit a stage without reloading the whole game.
+ * Reloading works on both the JSON and the HXC, if applicable.
+ *
+ * Call this by pressing F5 on a debug build.
+ */
+ function debug_refreshStages()
{
- curStage = path;
-
- var json = Assets.getText(Paths.file('data/stagedata/' + curStage + 'Stage.json'));
-
- var parsed:StageData = cast Json.parse(json);
-
- defaultCamZoom *= parsed.camZoom;
-
- for (prop in parsed.propsBackground)
+ // Remove the current stage. If the stage gets deleted while it's still in use,
+ // it'll probably crash the game or something.
+ if (this.curStage != null)
{
- var funnyProp:BGSprite = new BGSprite(prop.path, prop.x, prop.y, prop.scrollX, prop.scrollY, null, false, false);
-
- if (prop.animBullshit != null)
- funnyProp.setupSparrow(prop.path, prop.animBullshit.anims, prop.animBullshit.isLooping);
- else
- funnyProp.justLoadImage(prop.path);
-
- if (prop.updateHitbox != null && !prop.updateHitbox)
- {
- funnyProp.scale.set(prop.scaleX, prop.scaleY);
- }
- else
- {
- funnyProp.setGraphicSize(Std.int(funnyProp.width * prop.scaleX), Std.int(funnyProp.height * prop.scaleY));
- funnyProp.updateHitbox();
- }
-
- if (prop.antialiasing != null)
- funnyProp.antialiasing = prop.antialiasing;
-
- funnyProp.scrollFactor.set(prop.scrollX, prop.scrollY);
- add(funnyProp);
+ remove(curStage);
+ curStage.kill();
+ curStage = null;
}
- trace(parsed.propsBackground);
+ // Forcibly reload scripts so that scripted stages can be edited.
+ polymod.hscript.PolymodScriptClass.clearScriptClasses();
+ polymod.hscript.PolymodScriptClass.registerAllScriptClasses();
+
+ // Reload the stages in cache. This might cause a lag spike but who cares this is a debug utility.
+ StageDataParser.loadStageCache();
+
+ // Reload the level. This should use new data from the assets folder.
+ LoadingState.loadAndSwitchState(new PlayState());
+ }
+
+ public var curStage:Stage;
+
+ /**
+ * Loads stage data from cache, assembles the props,
+ * and adds it to the state.
+ * @param id
+ */
+ function loadStage(id:String)
+ {
+ curStage = StageDataParser.fetchStage(id);
+
+ if (curStage != null)
+ {
+ // Actually create and position the sprites.
+ curStage.buildStage();
+
+ // Apply camera zoom.
+ defaultCamZoom *= curStage.camZoom;
+
+ // Add the stage to the scene.
+ this.add(curStage);
+ }
}
function gunsIntro()
@@ -987,6 +661,7 @@ class PlayState extends MusicBeatState
blackShit.scrollFactor.set();
add(blackShit);
+ #if html5
var vid:FlxVideo = new FlxVideo('music/gunsCutscene.mp4');
vid.finishCallback = function()
{
@@ -996,6 +671,13 @@ class PlayState extends MusicBeatState
startCountdown();
cameraMovement();
};
+ #else
+ remove(blackShit);
+
+ FlxTween.tween(FlxG.camera, {zoom: defaultCamZoom}, (Conductor.crochet / 1000) * 5, {ease: FlxEase.quadInOut});
+ startCountdown();
+ cameraMovement();
+ #end
/* camFollow.setPosition(camPos.x, camPos.y);
@@ -1061,6 +743,7 @@ class PlayState extends MusicBeatState
blackShit.scrollFactor.set();
add(blackShit);
+ #if html5
var vid:FlxVideo = new FlxVideo('music/stressCutscene.mp4');
vid.finishCallback = function()
{
@@ -1070,6 +753,13 @@ class PlayState extends MusicBeatState
startCountdown();
cameraMovement();
};
+ #else
+ remove(blackShit);
+
+ FlxTween.tween(FlxG.camera, {zoom: defaultCamZoom}, (Conductor.crochet / 1000) * 5, {ease: FlxEase.quadInOut});
+ startCountdown();
+ cameraMovement();
+ #end
/* camHUD.visible = false;
@@ -1451,10 +1141,17 @@ class PlayState extends MusicBeatState
gf.dance();
if (swagCounter % 2 == 0)
{
- if (!boyfriend.animation.curAnim.name.startsWith("sing"))
- boyfriend.playAnim('idle');
- if (!dad.animation.curAnim.name.startsWith("sing"))
- dad.dance();
+ if (boyfriend.animation != null)
+ {
+ if (!boyfriend.animation.curAnim.name.startsWith("sing"))
+ boyfriend.playAnim('idle');
+ }
+
+ if (dad.animation != null)
+ {
+ if (!dad.animation.curAnim.name.startsWith("sing"))
+ dad.dance();
+ }
}
else if (dad.curCharacter == 'spooky' && !dad.animation.curAnim.name.startsWith("sing"))
dad.dance();
@@ -1464,7 +1161,7 @@ class PlayState extends MusicBeatState
var introSprPaths:Array = ["ready", "set", "go"];
var altSuffix:String = "";
- if (curStage.startsWith("school"))
+ if (curStageId.startsWith("school"))
{
altSuffix = '-pixel';
introSprPaths = ['weeb/pixelUI/ready-pixel', 'weeb/pixelUI/set-pixel', 'weeb/pixelUI/date-pixel'];
@@ -1500,7 +1197,7 @@ class PlayState extends MusicBeatState
var spr:FlxSprite = new FlxSprite().loadGraphic(Paths.image(path));
spr.scrollFactor.set();
- if (curStage.startsWith('school'))
+ if (curStageId.startsWith('school'))
spr.setGraphicSize(Std.int(spr.width * daPixelZoom));
spr.updateHitbox();
@@ -1603,7 +1300,7 @@ class PlayState extends MusicBeatState
var gottaHitNote:Bool = section.mustHitSection;
- if (songNotes.highStakes)
+ if (songNotes.highStakes) // noteData > 3
gottaHitNote = !section.mustHitSection;
var oldNote:Note;
@@ -1613,8 +1310,10 @@ class PlayState extends MusicBeatState
oldNote = null;
var swagNote:Note = new Note(daStrumTime, daNoteData, oldNote);
+ // swagNote.data = songNotes;
swagNote.data.sustainLength = songNotes.sustainLength;
swagNote.data.altNote = songNotes.altNote;
+
swagNote.scrollFactor.set(0, 0);
var susLength:Float = swagNote.data.sustainLength;
@@ -1673,7 +1372,7 @@ class PlayState extends MusicBeatState
babyArrow.shader = colorswap.shader;
colorswap.update(Note.arrowColors[i]);
- switch (curStage)
+ switch (curStageId)
{
case 'school' | 'schoolEvil':
babyArrow.loadGraphic(Paths.image('weeb/pixelUI/arrows-pixels'), true, 17, 17);
@@ -1872,9 +1571,13 @@ class PlayState extends MusicBeatState
FlxG.sound.music.pause();
vocals.pause();
+ curStage.resetStage();
+
FlxG.sound.music.time = 0;
+
regenNoteData(); // loads the note data from start
health = 1;
+ songScore = 0;
restartCountdownTimer();
needsReset = false;
@@ -1943,31 +1646,8 @@ class PlayState extends MusicBeatState
// Conductor.lastSongPos = FlxG.sound.music.time;
}
- switch (curStage)
- {
- case 'philly':
- if (trainMoving)
- {
- trainFrameTiming += elapsed;
-
- if (trainFrameTiming >= 1 / 24)
- {
- updateTrainPos();
- trainFrameTiming = 0;
- }
- }
-
- lightFadeShader.update((Conductor.crochet / 1000) * FlxG.elapsed * 1.5);
- // phillyCityLights.members[curLight].alpha -= (Conductor.crochet / 1000) * FlxG.elapsed;
-
- case 'tank':
- moveTank();
- }
-
super.update(elapsed); // idk if there's a particular reason why some code is before super.update(), and some is after. Prob nothing too much to worry about.
- wiggleShit.update(elapsed);
-
var androidPause:Bool = false;
#if android
@@ -1980,11 +1660,11 @@ class PlayState extends MusicBeatState
persistentDraw = true;
paused = true;
- // 1 / 1000 chance for Gitaroo Man easter egg
- // can this please move to dying it's kinda fucked up that pausing has a 1/1000 chance ur forced to restart
- if (FlxG.random.bool(0.1))
+ // There is a 1/1000 change to use a special pause menu.
+ // This prevents the player from resuming, but that's the point.
+ // It's a reference to Gitaroo Man, which doesn't let you pause the game.
+ if (FlxG.random.bool(1 / 1000))
{
- // gitaroo man easter egg
FlxG.switchState(new GitarooPause());
}
else
@@ -2014,7 +1694,10 @@ class PlayState extends MusicBeatState
scoreTxt.text = "Score:" + songScore;
if (FlxG.keys.justPressed.EIGHT)
- FlxG.switchState(new ui.animDebugShit.DebugBoundingState());
+ FlxG.switchState(new funkin.ui.animDebugShit.DebugBoundingState());
+
+ if (FlxG.keys.justPressed.F5)
+ debug_refreshStages();
if (FlxG.keys.justPressed.NINE)
iconP1.swapOldIcon();
@@ -2243,9 +1926,16 @@ class PlayState extends MusicBeatState
}
else if (daNote.tooLate || daNote.wasGoodHit)
{
+ // TODO: Why the hell is the noteMiss logic in two different places?
if (daNote.tooLate)
{
- health -= 0.0775;
+ if (curStage != null)
+ {
+ curStage.onNoteMiss(daNote);
+ }
+
+ // lose less health on sustain notes!
+ health -= 0.0775 * (daNote.isSustainNote ? 0.2 : 1); // if it's sustain, multiply it by 0.2 (not checked for balence yet), else keep it same (multiply by 1)
vocals.volume = 0;
killCombo();
}
@@ -2262,6 +1952,12 @@ class PlayState extends MusicBeatState
if (!inCutscene)
keyShit();
+
+ if (curStage != null)
+ {
+ // We're using Eric's stage handler.
+ curStage.onUpdate(elapsed);
+ }
}
function applyClipRect(daNote:Note):Void
@@ -2451,6 +2147,12 @@ class PlayState extends MusicBeatState
health += healthMulti;
+ // TODO: Redo note hit logic to make sure this always gets called
+ if (curStage != null)
+ {
+ curStage.onNoteHit(daNote);
+ }
+
if (isSick)
{
var noteSplash:NoteSplash = grpNoteSplashes.recycle(NoteSplash);
@@ -2498,11 +2200,11 @@ class PlayState extends MusicBeatState
{
camFollow.setPosition(boyfriend.getMidpoint().x - 100, boyfriend.getMidpoint().y - 100);
- switch (curStage)
+ switch (curStageId)
{
case 'limo':
camFollow.x = boyfriend.getMidpoint().x - 300;
- case 'mall':
+ case 'mallXmas':
camFollow.y = boyfriend.getMidpoint().y - 200;
case 'school' | 'schoolEvil':
camFollow.x = boyfriend.getMidpoint().x - 200;
@@ -2684,7 +2386,7 @@ class PlayState extends MusicBeatState
if (!holdArray[spr.ID])
spr.animation.play('static');
- if (spr.animation.curAnim.name == 'confirm' && !curStage.startsWith('school'))
+ if (spr.animation.curAnim.name == 'confirm' && !curStageId.startsWith('school'))
{
spr.centerOffsets();
spr.offset.x -= 13;
@@ -2695,11 +2397,31 @@ class PlayState extends MusicBeatState
});
}
- override function switchTo(nextState:FlxState):Bool
+ function performCleanup()
{
+ // Uncache the song.
openfl.utils.Assets.cache.clear(Paths.inst(SONG.song));
openfl.utils.Assets.cache.clear(Paths.voices(SONG.song));
+ // Remove reference to stage and remove sprites from it to save memory.
+ if (curStage != null)
+ {
+ remove(curStage);
+ curStage.kill();
+ curStage = null;
+ }
+
+ // Clear the static reference to this state.
+ instance = null;
+ }
+
+ /**
+ * This function is called before switching to a new FlxState.
+ */
+ override function switchTo(nextState:FlxState):Bool
+ {
+ performCleanup();
+
return super.switchTo(nextState);
}
@@ -2786,112 +2508,6 @@ class PlayState extends MusicBeatState
FlxG.camera.focusOn(camFollow.getPosition());
}
- var fastCarCanDrive:Bool = true;
-
- function resetFastCar():Void
- {
- fastCar.x = -12600;
- fastCar.y = FlxG.random.int(140, 250);
- fastCar.velocity.x = 0;
- 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;
- fastCarCanDrive = false;
- new FlxTimer().start(2, function(tmr:FlxTimer)
- {
- resetFastCar();
- });
- }
-
- function moveTank():Void
- {
- if (!inCutscene)
- {
- var daAngleOffset:Float = 1;
- tankAngle += FlxG.elapsed * tankSpeed;
- tankGround.angle = tankAngle - 90 + 15;
-
- tankGround.x = tankX + Math.cos(FlxAngle.asRadians((tankAngle * daAngleOffset) + 180)) * 1500;
- tankGround.y = 1300 + Math.sin(FlxAngle.asRadians((tankAngle * daAngleOffset) + 180)) * 1100;
- }
- }
-
- var tankResetShit:Bool = false;
- var tankMoving:Bool = false;
- var tankAngle:Float = FlxG.random.int(-90, 45);
- var tankSpeed:Float = FlxG.random.float(5, 7);
- var tankX:Float = 400;
-
- var trainMoving:Bool = false;
- var trainFrameTiming:Float = 0;
-
- var trainCars:Int = 8;
- var trainFinishing:Bool = false;
- var trainCooldown:Int = 0;
-
- function trainStart():Void
- {
- trainMoving = true;
- trainSound.play(true);
- }
-
- var startedMoving:Bool = false;
-
- function updateTrainPos():Void
- {
- if (trainSound.time >= 4700)
- {
- startedMoving = true;
- gf.playAnim('hairBlow');
- }
-
- if (startedMoving)
- {
- phillyTrain.x -= 400;
-
- if (phillyTrain.x < -2000 && !trainFinishing)
- {
- phillyTrain.x = -1150;
- trainCars -= 1;
-
- if (trainCars <= 0)
- trainFinishing = true;
- }
-
- if (phillyTrain.x < -4000 && trainFinishing)
- trainReset();
- }
- }
-
- function trainReset():Void
- {
- gf.playAnim('hairFall');
- phillyTrain.x = FlxG.width + 200;
- trainMoving = false;
- // trainSound.stop();
- // trainSound.time = 0;
- trainCars = 8;
- trainFinishing = false;
- startedMoving = false;
- }
-
- function lightningStrikeShit():Void
- {
- FlxG.sound.play(Paths.soundRandom('thunder_', 1, 2));
- halloweenBG.animation.play('lightning');
-
- lightningStrikeBeat = curBeat;
- lightningOffset = FlxG.random.int(8, 24);
-
- boyfriend.playAnim('scared', true);
- gf.playAnim('scared', true);
- }
-
override function stepHit()
{
super.stepHit();
@@ -2901,10 +2517,13 @@ class PlayState extends MusicBeatState
{
resyncVocals();
}
- }
- var lightningStrikeBeat:Int = 0;
- var lightningOffset:Int = 8;
+ if (curStage != null)
+ {
+ // We're using Eric's stage handler. The stage should know that a beat has been hit.
+ curStage.onStepHit(curBeat);
+ }
+ }
override function beatHit()
{
@@ -2975,9 +2594,9 @@ class PlayState extends MusicBeatState
if (curBeat % 2 == 0)
{
- if (!boyfriend.animation.curAnim.name.startsWith("sing"))
+ if (boyfriend.animation != null && !boyfriend.animation.curAnim.name.startsWith("sing"))
boyfriend.playAnim('idle');
- if (!dad.animation.curAnim.name.startsWith("sing"))
+ if (dad.animation != null && !dad.animation.curAnim.name.startsWith("sing"))
dad.dance();
}
else if (dad.curCharacter == 'spooky')
@@ -2997,61 +2616,10 @@ class PlayState extends MusicBeatState
dad.playAnim('cheer', true);
}
- foregroundSprites.forEach(function(spr:BGSprite)
+ if (curStage != null)
{
- spr.dance();
- });
-
- // boppin friends
- switch (curStage)
- {
- case 'school':
- bgGirls.dance();
-
- case 'mall':
- upperBoppers.animation.play('bop', true);
- bottomBoppers.animation.play('bop', true);
- santa.animation.play('idle', true);
-
- case 'limo':
- grpLimoDancers.forEach(function(dancer:BackgroundDancer)
- {
- dancer.dance();
- });
-
- if (FlxG.random.bool(10) && fastCarCanDrive)
- fastCarDrive();
- case "philly":
- if (!trainMoving)
- trainCooldown += 1;
-
- if (curBeat % 4 == 0)
- {
- lightFadeShader.reset();
-
- phillyCityLights.forEach(function(light:FlxSprite)
- {
- light.visible = false;
- });
-
- curLight = FlxG.random.int(0, phillyCityLights.length - 1);
-
- phillyCityLights.members[curLight].visible = true;
- // phillyCityLights.members[curLight].alpha = 1;
- }
-
- if (curBeat % 8 == 4 && FlxG.random.bool(30) && !trainMoving && trainCooldown > 8)
- {
- trainCooldown = FlxG.random.int(-4, 0);
- trainStart();
- }
- case 'tank':
- tankWatchtower.dance();
- }
-
- if (isHalloween && FlxG.random.bool(10) && curBeat > lightningStrikeBeat + lightningOffset)
- {
- lightningStrikeShit();
+ // We're using Eric's stage handler. The stage should know that a beat has been hit.
+ curStage.onBeatHit(curBeat);
}
}
diff --git a/source/funkin/play/character/Character.hx b/source/funkin/play/character/Character.hx
new file mode 100644
index 000000000..c5ae1014a
--- /dev/null
+++ b/source/funkin/play/character/Character.hx
@@ -0,0 +1,9 @@
+package funkin.play.character;
+
+enum CharacterType
+{
+ BF;
+ GF;
+ DAD;
+ OTHER;
+}
diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx
new file mode 100644
index 000000000..3105847b2
--- /dev/null
+++ b/source/funkin/play/stage/Bopper.hx
@@ -0,0 +1,119 @@
+package funkin.play.stage;
+
+import flixel.FlxSprite;
+
+/**
+ * A Bopper is a stage prop which plays a dance animation.
+ * Y'know, a thingie that bops. A bopper.
+ */
+class Bopper extends FlxSprite
+{
+ /**
+ * The bopper plays the dance animation once every `danceEvery` beats.
+ */
+ public var danceEvery:Int = 1;
+
+ /**
+ * Whether the bopper should dance left and right.
+ * - If true, alternate playing `danceLeft` and `danceRight`.
+ * - If false, play `idle` every time.
+ *
+ * You can manually set this value, or you can leave it as `null` to determine it automatically.
+ */
+ public var shouldAlternate:Null = null;
+
+ /**
+ * Set this value to define an additional horizontal offset to this sprite's position.
+ */
+ public var xOffset:Float = 0;
+
+ override function set_x(value:Float):Float
+ {
+ this.x = value + this.xOffset;
+ return value;
+ }
+
+ public var idleSuffix(default, set):String = "";
+
+ function set_idleSuffix(value:String):String
+ {
+ this.idleSuffix = value;
+ this.dance();
+ return value;
+ }
+
+ /**
+ * Set this value to define an additional vertical offset to this sprite's position.
+ */
+ public var yOffset:Float = 0;
+
+ override function set_y(value:Float):Float
+ {
+ this.y = value + this.yOffset;
+ return value;
+ }
+
+ /**
+ * Whether to play `danceRight` next iteration.
+ * Only used when `shouldAlternate` is true.
+ */
+ var hasDanced:Bool = false;
+
+ public function new(danceEvery:Int = 1)
+ {
+ super();
+ this.danceEvery = danceEvery;
+ }
+
+ function update_shouldAlternate():Void
+ {
+ if (this.animation.getByName('danceLeft') != null)
+ {
+ this.shouldAlternate = true;
+ }
+ }
+
+ /**
+ * Called once every beat of the song.
+ */
+ public function onBeatHit(curBeat:Int):Void
+ {
+ if (curBeat % danceEvery == 0)
+ {
+ dance();
+ }
+ }
+
+ /**
+ * Called every `danceEvery` beats of the song.
+ */
+ public function dance():Void
+ {
+ if (this.animation == null)
+ {
+ return;
+ }
+
+ if (shouldAlternate == null)
+ {
+ update_shouldAlternate();
+ }
+
+ if (shouldAlternate)
+ {
+ if (hasDanced)
+ {
+ this.animation.play('danceRight$idleSuffix');
+ }
+ else
+ {
+ this.animation.play('danceLeft$idleSuffix');
+ }
+ hasDanced = !hasDanced;
+ }
+ else
+ {
+ this.animation.play('idle$idleSuffix');
+ }
+ }
+}
diff --git a/source/funkin/play/stage/ScriptedBopper.hx b/source/funkin/play/stage/ScriptedBopper.hx
new file mode 100644
index 000000000..a344b0428
--- /dev/null
+++ b/source/funkin/play/stage/ScriptedBopper.hx
@@ -0,0 +1,10 @@
+package funkin.play.stage;
+
+import funkin.modding.IHook;
+
+@:hscriptClass
+@:keep
+class ScriptedBopper extends Bopper implements IHook
+{
+ // No body needed for this class, it's magic ;)
+}
diff --git a/source/funkin/play/stage/ScriptedStage.hx b/source/funkin/play/stage/ScriptedStage.hx
new file mode 100644
index 000000000..114afb1d5
--- /dev/null
+++ b/source/funkin/play/stage/ScriptedStage.hx
@@ -0,0 +1,9 @@
+package funkin.play.stage;
+
+import funkin.modding.IHook;
+
+@:hscriptClass
+class ScriptedStage extends Stage implements IHook
+{
+ // No body needed for this class, it's magic ;)
+}
diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx
new file mode 100644
index 000000000..502e8ed76
--- /dev/null
+++ b/source/funkin/play/stage/Stage.hx
@@ -0,0 +1,402 @@
+package funkin.play.stage;
+
+import flixel.FlxSprite;
+import flixel.group.FlxSpriteGroup;
+import flixel.math.FlxPoint;
+import flixel.util.FlxSort;
+import funkin.modding.IHook;
+import funkin.play.character.Character.CharacterType;
+import funkin.play.stage.StageData.StageDataParser;
+import funkin.util.SortUtil;
+
+/**
+ * A Stage is a group of objects rendered in the PlayState.
+ *
+ * A Stage is comprised of one or more props, each of which is a FlxSprite.
+ */
+class Stage extends FlxSpriteGroup implements IHook
+{
+ public final stageId:String;
+ public final stageName:String;
+
+ final _data:StageData;
+
+ public var camZoom:Float = 1.0;
+
+ var namedProps:Map = new Map();
+ var characters:Map = new Map();
+ var boppers:Array = new Array();
+
+ /**
+ * The Stage elements get initialized at the beginning of the game.
+ * They're used to cache the data needed to build the stage,
+ * then accessed and fleshed out when the stage needs to be built.
+ *
+ * @param stageId
+ */
+ public function new(stageId:String)
+ {
+ super();
+
+ this.stageId = stageId;
+ _data = StageDataParser.parseStageData(this.stageId);
+ if (_data == null)
+ {
+ throw 'Could not find stage data for stageId: $stageId';
+ }
+ else
+ {
+ this.stageName = _data.name;
+ }
+ }
+
+ /**
+ * The default stage construction routine. Called when the stage is going to be played in.
+ * Instantiates each prop and adds it to the stage, while setting its parameters.
+ */
+ public function buildStage()
+ {
+ trace('Building stage for display: ${this.stageId}');
+
+ this.camZoom = _data.cameraZoom;
+ // this.scrollFactor = new FlxPoint(1, 1);
+
+ for (dataProp in _data.props)
+ {
+ trace(' Placing prop: ${dataProp.name} (${dataProp.assetPath})');
+
+ var isAnimated = dataProp.animations.length > 0;
+
+ var propSprite:FlxSprite;
+ if (dataProp.danceEvery != 0)
+ {
+ propSprite = new Bopper(dataProp.danceEvery);
+ }
+ else
+ {
+ propSprite = new FlxSprite();
+ }
+
+ if (isAnimated)
+ {
+ // Initalize sprite frames.
+ switch (dataProp.animType)
+ {
+ case "packer":
+ propSprite.frames = Paths.getPackerAtlas(dataProp.assetPath);
+ default: // "sparrow"
+ propSprite.frames = Paths.getSparrowAtlas(dataProp.assetPath);
+ }
+ }
+ else
+ {
+ // Initalize static sprite.
+ propSprite.loadGraphic(Paths.image(dataProp.assetPath));
+
+ // Disables calls to update() for a performance boost.
+ propSprite.active = false;
+ }
+
+ if (propSprite.frames == null || propSprite.frames.numFrames == 0)
+ {
+ trace(' ERROR: Could not build texture for prop.');
+ continue;
+ }
+
+ if (Std.isOfType(dataProp.scale, Array))
+ {
+ propSprite.scale.set(dataProp.scale[0], dataProp.scale[1]);
+ }
+ else
+ {
+ propSprite.scale.set(dataProp.scale);
+ }
+ propSprite.updateHitbox();
+
+ propSprite.x = dataProp.position[0];
+ propSprite.y = dataProp.position[1];
+
+ // If pixel, disable antialiasing.
+ propSprite.antialiasing = !dataProp.isPixel;
+
+ propSprite.scrollFactor.x = dataProp.scroll[0];
+ propSprite.scrollFactor.y = dataProp.scroll[1];
+
+ propSprite.zIndex = dataProp.zIndex;
+
+ switch (dataProp.animType)
+ {
+ case "packer":
+ for (propAnim in dataProp.animations)
+ {
+ propSprite.animation.add(propAnim.name, propAnim.frameIndices);
+ }
+ default: // "sparrow"
+ for (propAnim in dataProp.animations)
+ {
+ if (propAnim.frameIndices.length == 0)
+ {
+ propSprite.animation.addByPrefix(propAnim.name, propAnim.prefix, propAnim.frameRate, propAnim.loop, propAnim.flipX,
+ propAnim.flipY);
+ }
+ else
+ {
+ propSprite.animation.addByIndices(propAnim.name, propAnim.prefix, propAnim.frameIndices, "", propAnim.frameRate, propAnim.loop,
+ propAnim.flipX, propAnim.flipY);
+ }
+ }
+ }
+
+ if (dataProp.startingAnimation != null)
+ {
+ propSprite.animation.play(dataProp.startingAnimation);
+ }
+
+ if (Std.isOfType(propSprite, Bopper))
+ {
+ addBopper(cast propSprite, dataProp.name);
+ }
+ else
+ {
+ addProp(propSprite, dataProp.name);
+ }
+ trace(' Prop placed.');
+ }
+
+ this.refresh();
+ }
+
+ /**
+ * Add a sprite to the stage.
+ * @param prop The sprite to add.
+ * @param name (Optional) A unique name for the sprite.
+ * You can call `getNamedProp(name)` to retrieve it later.
+ */
+ public function addProp(prop:FlxSprite, ?name:String = null)
+ {
+ if (name != null)
+ {
+ namedProps.set(name, prop);
+ }
+ this.add(prop);
+ }
+
+ /**
+ * Add a sprite to the stage which animates to the beat of the song.
+ */
+ public function addBopper(bopper:Bopper, ?name:String = null)
+ {
+ boppers.push(bopper);
+ this.addProp(bopper, name);
+ }
+
+ /**
+ * Refreshes the stage, by redoing the render order of all props.
+ * It does this based on the `zIndex` of each prop.
+ */
+ public function refresh()
+ {
+ sort(SortUtil.byZIndex, FlxSort.ASCENDING);
+ trace('Stage sorted by z-index');
+ }
+
+ /**
+ * Resets the stage and it's props (needs to be overridden with your own logic!)
+ */
+ public function resetStage()
+ {
+ // Override me in your script to reset stage shit however you please!
+ // also note: maybe add some default behaviour to reset stage stuff?
+ }
+
+ /**
+ * A function that should get called every frame.
+ */
+ public function onUpdate(elapsed:Float):Void
+ {
+ // Override me in your scripted stage to perform custom behavior!
+ }
+
+ /**
+ * A function that gets called when the player hits a note.
+ */
+ public function onNoteHit(note:Note):Void
+ {
+ // Override me in your scripted stage to perform custom behavior!
+ }
+
+ /**
+ * A function that gets called when the player hits a note.
+ */
+ public function onNoteMiss(note:Note):Void
+ {
+ // Override me in your scripted stage to perform custom behavior!
+ }
+
+ /**
+ * Adjusts the position and other properties of the soon-to-be child of this sprite group.
+ * Private helper to avoid duplicate code in `add()` and `insert()`.
+ *
+ * @param Sprite The sprite or sprite group that is about to be added or inserted into the group.
+ */
+ override function preAdd(Sprite:FlxSprite):Void
+ {
+ var sprite:FlxSprite = cast Sprite;
+ sprite.x += x;
+ sprite.y += y;
+ sprite.alpha *= alpha;
+ // Don't override scroll factors.
+ // sprite.scrollFactor.copyFrom(scrollFactor);
+ sprite.cameras = _cameras; // _cameras instead of cameras because get_cameras() will not return null
+
+ if (clipRect != null)
+ clipRectTransform(sprite, clipRect);
+ }
+
+ /**
+ * A function that gets called once per step in the song.
+ * @param curStep The current step number.
+ */
+ public function onStepHit(curStep:Int):Void
+ {
+ // Override me in your scripted stage to perform custom behavior!
+ }
+
+ /**
+ * A function that gets called once per beat in the song (once every four steps).
+ * @param curStep The current beat number.
+ */
+ public function onBeatHit(curBeat:Int):Void
+ {
+ // Override me in your scripted stage to perform custom behavior!
+ // Make sure to call super.onBeatHit(curBeat) if you want to keep the boppers dancing.
+
+ for (bopper in boppers)
+ {
+ bopper.onBeatHit(curBeat);
+ }
+ }
+
+ /**
+ * Used by the PlayState to add a character to the stage.
+ */
+ public function addCharacter(character:Character, charType:CharacterType)
+ {
+ // Apply position and z-index.
+ switch (charType)
+ {
+ case BF:
+ this.characters.set("bf", character);
+ character.zIndex = _data.characters.bf.zIndex;
+ character.x = _data.characters.bf.position[0];
+ character.y = _data.characters.bf.position[1];
+ case GF:
+ this.characters.set("gf", character);
+ character.zIndex = _data.characters.gf.zIndex;
+ character.x = _data.characters.gf.position[0];
+ character.y = _data.characters.gf.position[1];
+ case DAD:
+ this.characters.set("dad", character);
+ character.zIndex = _data.characters.dad.zIndex;
+ character.x = _data.characters.dad.position[0];
+ character.y = _data.characters.dad.position[1];
+ default:
+ this.characters.set(character.curCharacter, character);
+ }
+
+ // Add the character to the scene.
+ this.add(character);
+ }
+
+ /**
+ * Retrieves a given character from the stage.
+ */
+ public function getCharacter(id:String):Character
+ {
+ return this.characters.get(id);
+ }
+
+ public function getBoyfriend():Character
+ {
+ return getCharacter('bf');
+ }
+
+ public function getGirlfriend():Character
+ {
+ return getCharacter('gf');
+ }
+
+ public function getDad():Character
+ {
+ return getCharacter('dad');
+ }
+
+ /**
+ * Retrieve a specific prop by the name assigned in the JSON file.
+ * @param name The name of the prop to retrieve.
+ * @return The corresponding FlxSprite.
+ */
+ public function getNamedProp(name:String):FlxSprite
+ {
+ return this.namedProps.get(name);
+ }
+
+ /**
+ * Retrieve a list of all the asset paths required to load the stage.
+ * Override this in a scripted class to ensure that all necessary assets are loaded!
+ *
+ * @return An array of file names.
+ */
+ public function fetchAssetPaths():Array
+ {
+ var result:Array = [];
+ for (dataProp in _data.props)
+ {
+ result.push(Paths.image(dataProp.assetPath));
+ }
+ return result;
+ }
+
+ /**
+ * Perform cleanup for when you are leaving the level.
+ */
+ public override function kill()
+ {
+ super.kill();
+
+ for (prop in this.namedProps)
+ {
+ prop.destroy();
+ }
+ namedProps.clear();
+
+ for (char in this.characters)
+ {
+ char.destroy();
+ }
+ characters.clear();
+
+ for (bopper in boppers)
+ {
+ bopper.destroy();
+ }
+ boppers = [];
+
+ for (sprite in this.group)
+ {
+ sprite.destroy();
+ }
+ group.clear();
+ }
+
+ /**
+ * Perform cleanup for when you are destroying the stage
+ * and removing all its data from cache.
+ *
+ * Call this ONLY when you are performing a hard cache clear.
+ */
+ public override function destroy()
+ {
+ super.destroy();
+ }
+}
diff --git a/source/funkin/play/stage/StageData.hx b/source/funkin/play/stage/StageData.hx
new file mode 100644
index 000000000..2e9058a87
--- /dev/null
+++ b/source/funkin/play/stage/StageData.hx
@@ -0,0 +1,509 @@
+package funkin.play.stage;
+
+import openfl.Assets;
+import funkin.util.assets.DataAssets;
+import haxe.Json;
+import flixel.util.typeLimit.OneOfTwo;
+
+using StringTools;
+
+/**
+ * Contains utilities for loading and parsing stage data.
+ */
+class StageDataParser
+{
+ /**
+ * The current version string for the stage data format.
+ * Handle breaking changes by incrementing this value
+ * and adding migration to the `migrateStageData()` function.
+ */
+ public static final STAGE_DATA_VERSION:String = "1.0";
+
+ static final stageCache:Map = new Map();
+
+ static final DEFAULT_STAGE_ID = 'UNKNOWN';
+
+ /**
+ * Parses and preloads the game's stage data and scripts when the game starts.
+ *
+ * If you want to force stages to be reloaded, you can just call this function again.
+ */
+ public static function loadStageCache():Void
+ {
+ // Clear any stages that are cached if there were any.
+ clearStageCache();
+ trace("[STAGEDATA] Loading stage cache...");
+
+ //
+ // SCRIPTED STAGES
+ //
+ var scriptedStageClassNames:Array = ScriptedStage.listScriptClasses();
+ trace(' Instantiating ${scriptedStageClassNames.length} scripted stages...');
+ for (stageCls in scriptedStageClassNames)
+ {
+ var stage:Stage = ScriptedStage.init(stageCls, DEFAULT_STAGE_ID);
+ if (stage != null)
+ {
+ trace(' Loaded scripted stage: ${stage.stageName}');
+ // Disable the rendering logic for stage until it's loaded.
+ // Note that kill() =/= destroy()
+ stage.kill();
+
+ // Then store it.
+ stageCache.set(stage.stageId, stage);
+ }
+ else
+ {
+ trace(' Failed to instantiate scripted stage class: ${stageCls}');
+ }
+ }
+
+ //
+ // UNSCRIPTED STAGES
+ //
+ var stageIdList:Array = DataAssets.listDataFilesInPath('stages/');
+ var unscriptedStageIds:Array = stageIdList.filter(function(stageId:String):Bool
+ {
+ return !stageCache.exists(stageId);
+ });
+ trace(' Instantiating ${unscriptedStageIds.length} non-scripted stages...');
+ for (stageId in unscriptedStageIds)
+ {
+ var stage:Stage;
+ try
+ {
+ stage = new Stage(stageId);
+ if (stage != null)
+ {
+ trace(' Loaded stage data: ${stage.stageName}');
+ stageCache.set(stageId, stage);
+ }
+ }
+ catch (e)
+ {
+ // Assume error was already logged.
+ continue;
+ }
+ }
+
+ trace(' Successfully loaded ${Lambda.count(stageCache)} stages.');
+ }
+
+ public static function fetchStage(stageId:String):Null
+ {
+ if (stageCache.exists(stageId))
+ {
+ trace('[STAGEDATA] Successfully fetch stage: ${stageId}');
+ var stage:Stage = stageCache.get(stageId);
+ stage.revive();
+ return stage;
+ }
+ else
+ {
+ trace('[STAGEDATA] Failed to fetch stage, not found in cache: ${stageId}');
+ return null;
+ }
+ }
+
+ static function clearStageCache():Void
+ {
+ if (stageCache != null)
+ {
+ for (stage in stageCache)
+ {
+ stage.destroy();
+ }
+ stageCache.clear();
+ }
+ }
+
+ /**
+ * Load a stage's JSON file, parse its data, and return it.
+ *
+ * @param stageId The stage to load.
+ * @return The stage data, or null if validation failed.
+ */
+ public static function parseStageData(stageId:String):Null
+ {
+ var rawJson:String = loadStageFile(stageId);
+
+ var stageData:StageData = migrateStageData(rawJson, stageId);
+
+ return validateStageData(stageId, stageData);
+ }
+
+ static function loadStageFile(stagePath:String):String
+ {
+ var stageFilePath:String = Paths.json('stages/${stagePath}');
+ var rawJson = Assets.getText(stageFilePath).trim();
+
+ while (!rawJson.endsWith("}"))
+ {
+ rawJson = rawJson.substr(0, rawJson.length - 1);
+ }
+
+ return rawJson;
+ }
+
+ static function migrateStageData(rawJson:String, stageId:String)
+ {
+ // If you update the stage data format in a breaking way,
+ // handle migration here by checking the `version` value.
+
+ try
+ {
+ var stageData:StageData = cast Json.parse(rawJson);
+ return stageData;
+ }
+ catch (e)
+ {
+ trace(' Error parsing data for stage: ${stageId}');
+ trace(' ${e}');
+ return null;
+ }
+ }
+
+ static final DEFAULT_NAME:String = "Untitled Stage";
+ static final DEFAULT_CAMERAZOOM:Float = 1.0;
+ static final DEFAULT_ZINDEX:Int = 0;
+ static final DEFAULT_DANCEEVERY:Int = 0;
+ static final DEFAULT_SCALE:Float = 1.0;
+ static final DEFAULT_ISPIXEL:Bool = false;
+ static final DEFAULT_POSITION:Array = [0, 0];
+ static final DEFAULT_SCROLL:Array = [0, 0];
+ static final DEFAULT_FRAMEINDICES:Array = [];
+ static final DEFAULT_ANIMTYPE:String = "sparrow";
+
+ static final DEFAULT_CHARACTER_DATA:StageDataCharacter = {
+ zIndex: DEFAULT_ZINDEX,
+ position: DEFAULT_POSITION,
+ }
+
+ /**
+ * Set unspecified parameters to their defaults.
+ * If the parameter is mandatory, print an error message.
+ * @param id
+ * @param input
+ * @return The validated stage data
+ */
+ static function validateStageData(id:String, input:StageData):Null
+ {
+ if (input == null)
+ {
+ trace('[STAGEDATA] ERROR: Could not parse stage data for "${id}".');
+ return null;
+ }
+
+ if (input.version != STAGE_DATA_VERSION)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing version');
+ return null;
+ }
+
+ if (input.name == null)
+ {
+ trace('[STAGEDATA] WARN: Stage data for "$id" missing name');
+ input.name = DEFAULT_NAME;
+ }
+
+ if (input.cameraZoom == null)
+ {
+ input.cameraZoom = DEFAULT_CAMERAZOOM;
+ }
+
+ if (input.props == null || input.props.length == 0)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing props');
+ return null;
+ }
+
+ for (inputProp in input.props)
+ {
+ // It's fine for inputProp.name to be null
+
+ if (inputProp.assetPath == null)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing assetPath for prop "${inputProp.name}"');
+ return null;
+ }
+
+ if (inputProp.position == null)
+ {
+ inputProp.position = DEFAULT_POSITION;
+ }
+
+ if (inputProp.zIndex == null)
+ {
+ inputProp.zIndex = DEFAULT_ZINDEX;
+ }
+
+ if (inputProp.isPixel == null)
+ {
+ inputProp.isPixel = DEFAULT_ISPIXEL;
+ }
+
+ if (inputProp.danceEvery == null)
+ {
+ inputProp.danceEvery = DEFAULT_DANCEEVERY;
+ }
+
+ if (inputProp.scale == null)
+ {
+ inputProp.scale = DEFAULT_SCALE;
+ }
+
+ if (inputProp.animType == null)
+ {
+ inputProp.animType = DEFAULT_ANIMTYPE;
+ }
+
+ if (Std.isOfType(inputProp.scale, Float))
+ {
+ inputProp.scale = [inputProp.scale, inputProp.scale];
+ }
+
+ if (inputProp.scroll == null)
+ {
+ inputProp.scroll = DEFAULT_SCROLL;
+ }
+
+ if (Std.isOfType(inputProp.scroll, Float))
+ {
+ inputProp.scroll = [inputProp.scroll, inputProp.scroll];
+ }
+
+ if (inputProp.animations == null)
+ {
+ inputProp.animations = [];
+ }
+
+ if (inputProp.animations.length == 0 && inputProp.startingAnimation != null)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing animations for prop "${inputProp.name}"');
+ return null;
+ }
+
+ for (inputAnimation in inputProp.animations)
+ {
+ if (inputAnimation.name == null)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing animation name for prop "${inputProp.name}"');
+ return null;
+ }
+
+ if (inputAnimation.frameRate == null)
+ {
+ inputAnimation.frameRate = 24;
+ }
+
+ if (inputAnimation.frameIndices == null)
+ {
+ inputAnimation.frameIndices = DEFAULT_FRAMEINDICES;
+ }
+
+ if (inputAnimation.loop == null)
+ {
+ inputAnimation.loop = true;
+ }
+
+ if (inputAnimation.flipX == null)
+ {
+ inputAnimation.flipX = false;
+ }
+
+ if (inputAnimation.flipY == null)
+ {
+ inputAnimation.flipY = false;
+ }
+ }
+ }
+
+ if (input.characters == null)
+ {
+ trace('[STAGEDATA] ERROR: Could not load stage data for "$id": missing characters');
+ return null;
+ }
+
+ if (input.characters.bf == null)
+ {
+ input.characters.bf = DEFAULT_CHARACTER_DATA;
+ }
+ if (input.characters.dad == null)
+ {
+ input.characters.dad = DEFAULT_CHARACTER_DATA;
+ }
+ if (input.characters.gf == null)
+ {
+ input.characters.gf = DEFAULT_CHARACTER_DATA;
+ }
+
+ for (inputCharacter in [input.characters.bf, input.characters.dad, input.characters.gf])
+ {
+ if (inputCharacter.zIndex == null)
+ {
+ inputCharacter.zIndex = 0;
+ }
+ if (inputCharacter.position == null || inputCharacter.position.length != 2)
+ {
+ inputCharacter.position = [0, 0];
+ }
+ }
+
+ // All good!
+ return input;
+ }
+}
+
+typedef StageData =
+{
+ // Uses semantic versioning.
+ var version:String;
+ var name:String;
+ var cameraZoom:Null;
+ var props:Array;
+ var characters:
+ {
+ bf:StageDataCharacter,
+ dad:StageDataCharacter,
+ gf:StageDataCharacter,
+ };
+};
+
+typedef StageDataProp =
+{
+ /**
+ * The name of the prop for later lookup by scripts.
+ * Optional; if unspecified, the prop can't be referenced by scripts.
+ */
+ var name:String;
+
+ /**
+ * The asset used to display the prop.
+ */
+ var assetPath:String;
+
+ /**
+ * The position of the prop as an [x, y] array of two floats.
+ */
+ var position:Array;
+
+ /**
+ * A number determining the stack order of the prop, relative to other props and the characters in the stage.
+ * Props with lower numbers render below those with higher numbers.
+ * This is just like CSS, it isn't hard.
+ * @default 0
+ */
+ var zIndex:Null;
+
+ /**
+ * If set to true, anti-aliasing will be forcibly disabled on the sprite.
+ * This prevents blurry images on pixel-art levels.
+ * @default false
+ */
+ var isPixel:Null;
+
+ /**
+ * Either the scale of the prop as a float, or the [w, h] scale as an array of two floats.
+ * Pro tip: On pixel-art levels, save the sprite small and set this value to 6 or so to save memory.
+ * @default 1
+ */
+ var scale:OneOfTwo>;
+
+ /**
+ * If not zero, this prop will play an animation every X beats of the song.
+ * This requires animations to be defined. If `danceLeft` and `danceRight` are defined,
+ * they will alternated between, otherwise the `idle` animation will be used.
+ *
+ * @default 0
+ */
+ var danceEvery:Null;
+
+ /**
+ * How much the prop scrolls relative to the camera. Used to create a parallax effect.
+ * Represented as a float or as an [x, y] array of two floats.
+ * [1, 1] means the prop moves 1:1 with the camera.
+ * [0.5, 0.5] means the prop half as much as the camera.
+ * [0, 0] means the prop is not moved.
+ * @default [0, 0]
+ */
+ var scroll:OneOfTwo>;
+
+ /**
+ * An optional array of animations which the prop can play.
+ * @default Prop has no animations.
+ */
+ var animations:Array;
+
+ /**
+ * If animations are used, this is the name of the animation to play first.
+ * @default Don't play an animation.
+ */
+ var startingAnimation:String;
+
+ /**
+ * The animation type to use.
+ * Options: "sparrow", "packer"
+ * @default "sparrow"
+ */
+ var animType:String;
+};
+
+typedef StageDataPropAnimation =
+{
+ /**
+ * The name of the animation.
+ */
+ var name:String;
+
+ /**
+ * The common beginning of image names in atlas for this animation's frames.
+ * For example, if the frames are named "test0001.png", "test0002.png", etc., use "test".
+ */
+ var prefix:String;
+
+ /**
+ * If you want this animation to use only certain frames of an animation with a given prefix,
+ * select them here.
+ * @example [0, 1, 2, 3] (use only the first four frames)
+ * @default [] (all frames)
+ */
+ var frameIndices:Array;
+
+ /**
+ * The speed of the animation in frames per second.
+ * @default 24
+ */
+ var frameRate:Null;
+
+ /**
+ * Whether the animation should loop.
+ * @default false
+ */
+ var loop:Null;
+
+ /**
+ * Whether to flip the sprite horizontally while animating.
+ * @default false
+ */
+ var flipX:Null;
+
+ /**
+ * Whether to flip the sprite vertically while animating.
+ * @default false
+ */
+ var flipY:Null;
+};
+
+typedef StageDataCharacter =
+{
+ /**
+ * A number determining the stack order of the character, relative to props and other characters in the stage.
+ * Again, just like CSS.
+ * @default 0
+ */
+ zIndex:Null,
+
+ /**
+ * The position to render the character at.
+ */ position:Array
+};
diff --git a/source/rendering/MeshRender.hx b/source/funkin/rendering/MeshRender.hx
similarity index 98%
rename from source/rendering/MeshRender.hx
rename to source/funkin/rendering/MeshRender.hx
index d981a1303..2865b1a3d 100644
--- a/source/rendering/MeshRender.hx
+++ b/source/funkin/rendering/MeshRender.hx
@@ -1,4 +1,4 @@
-package rendering;
+package funkin.rendering;
import flixel.FlxStrip;
import flixel.util.FlxColor;
diff --git a/source/shaderslmfao/AngleMask.hx b/source/funkin/shaderslmfao/AngleMask.hx
similarity index 96%
rename from source/shaderslmfao/AngleMask.hx
rename to source/funkin/shaderslmfao/AngleMask.hx
index 2b276de05..1f16d63ca 100644
--- a/source/shaderslmfao/AngleMask.hx
+++ b/source/funkin/shaderslmfao/AngleMask.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
diff --git a/source/BlendModeEffect.hx b/source/funkin/shaderslmfao/BlendModeEffect.hx
similarity index 96%
rename from source/BlendModeEffect.hx
rename to source/funkin/shaderslmfao/BlendModeEffect.hx
index 1c9038be7..bc242b3e3 100644
--- a/source/BlendModeEffect.hx
+++ b/source/funkin/shaderslmfao/BlendModeEffect.hx
@@ -1,4 +1,4 @@
-package;
+package funkin.shaderslmfao;
import flixel.util.FlxColor;
import openfl.display.ShaderParameter;
diff --git a/source/shaderslmfao/BuildingShaders.hx b/source/funkin/shaderslmfao/BuildingShaders.hx
similarity index 96%
rename from source/shaderslmfao/BuildingShaders.hx
rename to source/funkin/shaderslmfao/BuildingShaders.hx
index a89a3b0df..62b9b0154 100644
--- a/source/shaderslmfao/BuildingShaders.hx
+++ b/source/funkin/shaderslmfao/BuildingShaders.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
diff --git a/source/shaderslmfao/ColorSwap.hx b/source/funkin/shaderslmfao/ColorSwap.hx
similarity index 99%
rename from source/shaderslmfao/ColorSwap.hx
rename to source/funkin/shaderslmfao/ColorSwap.hx
index e24ac1095..0738789be 100644
--- a/source/shaderslmfao/ColorSwap.hx
+++ b/source/funkin/shaderslmfao/ColorSwap.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
diff --git a/source/shaderslmfao/MultiplyShader.hx b/source/funkin/shaderslmfao/MultiplyShader.hx
similarity index 95%
rename from source/shaderslmfao/MultiplyShader.hx
rename to source/funkin/shaderslmfao/MultiplyShader.hx
index e86820ba1..27ae60d3b 100644
--- a/source/shaderslmfao/MultiplyShader.hx
+++ b/source/funkin/shaderslmfao/MultiplyShader.hx
@@ -1,4 +1,4 @@
-package;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
@@ -28,4 +28,4 @@ class MultiplyShader extends FlxShader
{
super();
}
-}
\ No newline at end of file
+}
diff --git a/source/shaderslmfao/OverlayBlend.hx b/source/funkin/shaderslmfao/OverlayBlend.hx
similarity index 97%
rename from source/shaderslmfao/OverlayBlend.hx
rename to source/funkin/shaderslmfao/OverlayBlend.hx
index cf8996346..162726f69 100644
--- a/source/shaderslmfao/OverlayBlend.hx
+++ b/source/funkin/shaderslmfao/OverlayBlend.hx
@@ -1,8 +1,9 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.math.FlxPoint;
import flixel.system.FlxAssets.FlxShader;
+@:keep
class OverlayBlend extends FlxShader
{
// these r copypaste
diff --git a/source/shaderslmfao/PureColor.hx b/source/funkin/shaderslmfao/PureColor.hx
similarity index 96%
rename from source/shaderslmfao/PureColor.hx
rename to source/funkin/shaderslmfao/PureColor.hx
index 774df767a..3546e7fda 100644
--- a/source/shaderslmfao/PureColor.hx
+++ b/source/funkin/shaderslmfao/PureColor.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
diff --git a/source/shaderslmfao/ScreenWipeShader.hx b/source/funkin/shaderslmfao/ScreenWipeShader.hx
similarity index 98%
rename from source/shaderslmfao/ScreenWipeShader.hx
rename to source/funkin/shaderslmfao/ScreenWipeShader.hx
index 5264f7c33..37e6d604d 100644
--- a/source/shaderslmfao/ScreenWipeShader.hx
+++ b/source/funkin/shaderslmfao/ScreenWipeShader.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
diff --git a/source/shaderslmfao/StrokeShader.hx b/source/funkin/shaderslmfao/StrokeShader.hx
similarity index 98%
rename from source/shaderslmfao/StrokeShader.hx
rename to source/funkin/shaderslmfao/StrokeShader.hx
index a6ba1ccad..575ff9419 100644
--- a/source/shaderslmfao/StrokeShader.hx
+++ b/source/funkin/shaderslmfao/StrokeShader.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
diff --git a/source/shaderslmfao/TitleOutline.hx b/source/funkin/shaderslmfao/TitleOutline.hx
similarity index 98%
rename from source/shaderslmfao/TitleOutline.hx
rename to source/funkin/shaderslmfao/TitleOutline.hx
index c8d002d85..cabab767d 100644
--- a/source/shaderslmfao/TitleOutline.hx
+++ b/source/funkin/shaderslmfao/TitleOutline.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.math.FlxPoint;
import flixel.system.FlxAssets.FlxShader;
diff --git a/source/shaderslmfao/WaveShader.hx b/source/funkin/shaderslmfao/WaveShader.hx
similarity index 91%
rename from source/shaderslmfao/WaveShader.hx
rename to source/funkin/shaderslmfao/WaveShader.hx
index 9e7be1adf..14aa2b7b1 100644
--- a/source/shaderslmfao/WaveShader.hx
+++ b/source/funkin/shaderslmfao/WaveShader.hx
@@ -1,4 +1,4 @@
-package shaderslmfao;
+package funkin.shaderslmfao;
import flixel.system.FlxAssets.FlxShader;
diff --git a/source/WiggleEffect.hx b/source/funkin/shaderslmfao/WiggleEffect.hx
similarity index 91%
rename from source/WiggleEffect.hx
rename to source/funkin/shaderslmfao/WiggleEffect.hx
index d11bf6e7a..bae55c6b1 100644
--- a/source/WiggleEffect.hx
+++ b/source/funkin/shaderslmfao/WiggleEffect.hx
@@ -1,4 +1,4 @@
-package;
+package funkin.shaderslmfao;
// STOLEN FROM HAXEFLIXEL DEMO LOL
import flixel.system.FlxAssets.FlxShader;
@@ -20,9 +20,13 @@ class WiggleEffect
public var waveFrequency(default, set):Float = 0;
public var waveAmplitude(default, set):Float = 0;
- public function new():Void
+ public function new(speed:Float, freq:Float, amplitude:Float, ?effect:WiggleEffectType = DREAMY):Void
{
shader.uTime.value = [0];
+ this.waveSpeed = speed;
+ this.waveFrequency = freq;
+ this.waveAmplitude = amplitude;
+ this.effectType = effect;
}
public function update(elapsed:Float):Void
@@ -57,6 +61,11 @@ class WiggleEffect
shader.uWaveAmplitude.value = [waveAmplitude];
return v;
}
+
+ function toString()
+ {
+ return 'WiggleEffect(${shader.uTime.value[0]})';
+ }
}
class WiggleShader extends FlxShader
diff --git a/source/ui/AtlasMenuList.hx b/source/funkin/ui/AtlasMenuList.hx
similarity index 86%
rename from source/ui/AtlasMenuList.hx
rename to source/funkin/ui/AtlasMenuList.hx
index 68232da5c..7a217a44c 100644
--- a/source/ui/AtlasMenuList.hx
+++ b/source/funkin/ui/AtlasMenuList.hx
@@ -1,7 +1,6 @@
-package ui;
-
-import ui.MenuList;
+package funkin.ui;
+import funkin.ui.MenuList;
import flixel.graphics.frames.FlxAtlasFrames;
typedef AtlasAsset = flixel.util.typeLimit.OneOfTwo;
@@ -9,24 +8,24 @@ typedef AtlasAsset = flixel.util.typeLimit.OneOfTwo;
class AtlasMenuList extends MenuTypedList
{
public var atlas:FlxAtlasFrames;
-
- public function new (atlas, navControls:NavControls = Vertical, ?wrapMode)
+
+ public function new(atlas, navControls:NavControls = Vertical, ?wrapMode)
{
super(navControls, wrapMode);
-
+
if (Std.is(atlas, String))
this.atlas = Paths.getSparrowAtlas(cast atlas);
else
this.atlas = cast atlas;
}
-
+
public function createItem(x = 0.0, y = 0.0, name, callback, fireInstantly = false)
{
var item = new AtlasMenuItem(x, y, name, atlas, callback);
item.fireInstantly = fireInstantly;
return addItem(name, item);
}
-
+
override function destroy()
{
super.destroy();
@@ -35,47 +34,48 @@ class AtlasMenuList extends MenuTypedList
}
class AtlasMenuItem extends MenuItem
-{
+{
var atlas:FlxAtlasFrames;
- public function new (x = 0.0, y = 0.0, name:String, atlas:FlxAtlasFrames, callback)
+
+ public function new(x = 0.0, y = 0.0, name:String, atlas:FlxAtlasFrames, callback)
{
this.atlas = atlas;
super(x, y, name, callback);
}
-
+
override function setData(name:String, ?callback:Void->Void)
{
frames = atlas;
animation.addByPrefix('idle', '$name idle', 24);
animation.addByPrefix('selected', '$name selected', 24);
-
+
super.setData(name, callback);
}
-
+
function changeAnim(animName:String)
{
animation.play(animName);
updateHitbox();
}
-
+
override function idle()
{
changeAnim('idle');
}
-
+
override function select()
{
changeAnim('selected');
}
-
+
override function get_selected()
{
return animation.curAnim != null && animation.curAnim.name == "selected";
}
-
+
override function destroy()
{
super.destroy();
atlas = null;
}
-}
\ No newline at end of file
+}
diff --git a/source/ui/AtlasText.hx b/source/funkin/ui/AtlasText.hx
similarity index 80%
rename from source/ui/AtlasText.hx
rename to source/funkin/ui/AtlasText.hx
index 9ac6ae059..6df5f9e22 100644
--- a/source/ui/AtlasText.hx
+++ b/source/funkin/ui/AtlasText.hx
@@ -1,4 +1,4 @@
-package ui;
+package funkin.ui;
import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup;
@@ -8,7 +8,7 @@ import flixel.util.FlxStringUtil;
@:forward
abstract BoldText(AtlasText) from AtlasText to AtlasText
{
- inline public function new (x = 0.0, y = 0.0, text:String)
+ inline public function new(x = 0.0, y = 0.0, text:String)
{
this = new AtlasText(x, y, text, Bold);
}
@@ -21,58 +21,67 @@ class AtlasText extends FlxTypedSpriteGroup
{
static var fonts = new Map();
static var casesAllowed = new Map();
+
public var text(default, set):String = "";
-
+
var font:AtlasFontData;
-
+
public var atlas(get, never):FlxAtlasFrames;
- inline function get_atlas() return font.atlas;
+
+ inline function get_atlas()
+ return font.atlas;
+
public var caseAllowed(get, never):Case;
- inline function get_caseAllowed() return font.caseAllowed;
+
+ inline function get_caseAllowed()
+ return font.caseAllowed;
+
public var maxHeight(get, never):Float;
- inline function get_maxHeight() return font.maxHeight;
-
- public function new (x = 0.0, y = 0.0, text:String, fontName:AtlasFont = Default)
+
+ inline function get_maxHeight()
+ return font.maxHeight;
+
+ public function new(x = 0.0, y = 0.0, text:String, fontName:AtlasFont = Default)
{
if (!fonts.exists(fontName))
fonts[fontName] = new AtlasFontData(fontName);
font = fonts[fontName];
-
+
super(x, y);
-
+
this.text = text;
}
-
+
function set_text(value:String)
{
if (value == null)
value = "";
-
+
var caseValue = restrictCase(value);
var caseText = restrictCase(this.text);
-
+
this.text = value;
if (caseText == caseValue)
return value; // cancel redraw
-
+
if (caseValue.indexOf(caseText) == 0)
{
// new text is just old text with additions at the end, append the difference
appendTextCased(caseValue.substr(caseText.length));
return this.text;
}
-
+
value = caseValue;
-
+
group.kill();
-
+
if (value == "")
return this.text;
-
+
appendTextCased(caseValue);
return this.text;
}
-
+
/**
* Adds new characters, without needing to redraw the previous characters
* @param text The text to add.
@@ -82,27 +91,27 @@ class AtlasText extends FlxTypedSpriteGroup
{
if (text == null)
throw "cannot append null";
-
+
if (text == "")
return;
-
+
this.text = this.text + text;
}
-
+
/**
* Converts all characters to fit the font's `allowedCase`.
* @param text
*/
function restrictCase(text:String)
{
- return switch(caseAllowed)
+ return switch (caseAllowed)
{
case Both: text;
case Upper: text.toUpperCase();
case Lower: text.toLowerCase();
}
}
-
+
/**
* Adds new text on top of the existing text. Helper for other methods; DOESN'T CHANGE `this.text`.
* @param text The text to add, assumed to match the font's `caseAllowed`.
@@ -121,58 +130,58 @@ class AtlasText extends FlxTypedSpriteGroup
xPos = lastChar.x + lastChar.width - x;
yPos = lastChar.y + lastChar.height - maxHeight - y;
}
-
+
var splitValues = text.split("");
for (i in 0...splitValues.length)
{
- switch(splitValues[i])
+ switch (splitValues[i])
{
case " ":
- {
- xPos += 40;
- }
- case "\n":
- {
- xPos = 0;
- yPos += maxHeight;
- }
- case char:
- {
- var charSprite:AtlasChar;
- if (group.members.length <= charCount)
- charSprite = new AtlasChar(atlas, char);
- else
{
- charSprite = group.members[charCount];
- charSprite.revive();
- charSprite.char = char;
- charSprite.alpha = 1;//gets multiplied when added
+ xPos += 40;
+ }
+ case "\n":
+ {
+ xPos = 0;
+ yPos += maxHeight;
+ }
+ case char:
+ {
+ var charSprite:AtlasChar;
+ if (group.members.length <= charCount)
+ charSprite = new AtlasChar(atlas, char);
+ else
+ {
+ charSprite = group.members[charCount];
+ charSprite.revive();
+ charSprite.char = char;
+ charSprite.alpha = 1; // gets multiplied when added
+ }
+ charSprite.x = xPos;
+ charSprite.y = yPos + maxHeight - charSprite.height;
+ add(charSprite);
+
+ xPos += charSprite.width;
+ charCount++;
}
- charSprite.x = xPos;
- charSprite.y = yPos + maxHeight - charSprite.height;
- add(charSprite);
-
- xPos += charSprite.width;
- charCount++;
- }
}
}
}
-
+
override function toString()
{
- return "InputItem, " + FlxStringUtil.getDebugString(
- [ LabelValuePair.weak("x", x)
- , LabelValuePair.weak("y", y)
- , LabelValuePair.weak("text", text)
- ]
- );
+ return "InputItem, " + FlxStringUtil.getDebugString([
+ LabelValuePair.weak("x", x),
+ LabelValuePair.weak("y", y),
+ LabelValuePair.weak("text", text)
+ ]);
}
}
class AtlasChar extends FlxSprite
{
public var char(default, set):String;
+
public function new(x = 0.0, y = 0.0, atlas:FlxAtlasFrames, char:String)
{
super(x, y);
@@ -180,7 +189,7 @@ class AtlasChar extends FlxSprite
this.char = char;
antialiasing = true;
}
-
+
function set_char(value:String)
{
if (this.char != value)
@@ -230,31 +239,31 @@ private class AtlasFontData
{
static public var upperChar = ~/^[A-Z]\d+$/;
static public var lowerChar = ~/^[a-z]\d+$/;
-
+
public var atlas:FlxAtlasFrames;
public var maxHeight:Float = 0.0;
public var caseAllowed:Case = Both;
-
- public function new (name:AtlasFont)
+
+ public function new(name:AtlasFont)
{
atlas = Paths.getSparrowAtlas("fonts/" + name.getName().toLowerCase());
atlas.parent.destroyOnNoUse = false;
atlas.parent.persist = true;
-
+
var containsUpper = false;
var containsLower = false;
-
+
for (frame in atlas.frames)
{
maxHeight = Math.max(maxHeight, frame.frame.height);
-
+
if (!containsUpper)
containsUpper = upperChar.match(frame.name);
-
+
if (!containsLower)
containsLower = lowerChar.match(frame.name);
}
-
+
if (containsUpper != containsLower)
caseAllowed = containsUpper ? Upper : Lower;
}
@@ -271,4 +280,4 @@ enum AtlasFont
{
Default;
Bold;
-}
\ No newline at end of file
+}
diff --git a/source/ui/ColorsMenu.hx b/source/funkin/ui/ColorsMenu.hx
similarity index 94%
rename from source/ui/ColorsMenu.hx
rename to source/funkin/ui/ColorsMenu.hx
index cef364c2c..84739058b 100644
--- a/source/ui/ColorsMenu.hx
+++ b/source/funkin/ui/ColorsMenu.hx
@@ -1,11 +1,12 @@
-package ui;
+package funkin.ui;
import flixel.addons.effects.chainable.FlxEffectSprite;
import flixel.addons.effects.chainable.FlxOutlineEffect;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.util.FlxColor;
+import funkin.ui.OptionsState.Page;
-class ColorsMenu extends ui.OptionsState.Page
+class ColorsMenu extends Page
{
var curSelected:Int = 0;
diff --git a/source/ui/ControlsMenu.hx b/source/funkin/ui/ControlsMenu.hx
similarity index 97%
rename from source/ui/ControlsMenu.hx
rename to source/funkin/ui/ControlsMenu.hx
index 7b8d129cf..fb4144b5b 100644
--- a/source/ui/ControlsMenu.hx
+++ b/source/funkin/ui/ControlsMenu.hx
@@ -1,6 +1,6 @@
-package ui;
+package funkin.ui;
-import Controls;
+import funkin.Controls;
import flixel.FlxCamera;
import flixel.FlxObject;
import flixel.FlxSprite;
@@ -8,11 +8,11 @@ import flixel.group.FlxGroup;
import flixel.input.actions.FlxActionInput;
import flixel.input.gamepad.FlxGamepadInputID;
import flixel.input.keyboard.FlxKey;
-import ui.AtlasText;
-import ui.MenuList;
-import ui.TextMenuList;
+import funkin.ui.AtlasText;
+import funkin.ui.MenuList;
+import funkin.ui.TextMenuList;
-class ControlsMenu extends ui.OptionsState.Page
+class ControlsMenu extends funkin.ui.OptionsState.Page
{
inline static public var COLUMNS = 2;
static var controlList = Control.createAll();
diff --git a/source/ui/MenuList.hx b/source/funkin/ui/MenuList.hx
similarity index 99%
rename from source/ui/MenuList.hx
rename to source/funkin/ui/MenuList.hx
index e8bc63cc3..347415f70 100644
--- a/source/ui/MenuList.hx
+++ b/source/funkin/ui/MenuList.hx
@@ -1,4 +1,4 @@
-package ui;
+package funkin.ui;
import flixel.FlxSprite;
import flixel.effects.FlxFlicker;
diff --git a/source/ui/ModMenu.hx b/source/funkin/ui/ModMenu.hx
similarity index 71%
rename from source/ui/ModMenu.hx
rename to source/funkin/ui/ModMenu.hx
index bd87d290d..3d195e861 100644
--- a/source/ui/ModMenu.hx
+++ b/source/funkin/ui/ModMenu.hx
@@ -1,16 +1,17 @@
-package ui;
+package funkin.ui;
+import funkin.modding.PolymodHandler;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import polymod.Polymod;
-import sys.FileSystem;
+import funkin.ui.OptionsState.Page;
-class ModMenu extends ui.OptionsState.Page
+class ModMenu extends Page
{
var grpMods:FlxTypedGroup;
- var enabledMods:Array = [];
- var modFolders:Array = [];
+ var enabledMods:Array = [];
+ var detectedMods:Array = [];
var curSelected:Int = 0;
@@ -62,10 +63,10 @@ class ModMenu extends ui.OptionsState.Page
{
curSelected += change;
- if (curSelected >= modFolders.length)
+ if (curSelected >= detectedMods.length)
curSelected = 0;
if (curSelected < 0)
- curSelected = modFolders.length - 1;
+ curSelected = detectedMods.length - 1;
for (txt in 0...grpMods.length)
{
@@ -80,8 +81,6 @@ class ModMenu extends ui.OptionsState.Page
organizeByY();
}
- inline static var MOD_PATH = "./mods";
-
private function refreshModList():Void
{
while (grpMods.members.length > 0)
@@ -90,36 +89,17 @@ class ModMenu extends ui.OptionsState.Page
}
#if desktop
- var modList = [];
- modFolders = [];
+ detectedMods = PolymodHandler.getAllMods();
- trace("mods path:" + FileSystem.absolutePath(MOD_PATH));
- if (!FileSystem.exists(MOD_PATH))
+ trace('ModMenu: Detected ${detectedMods.length} mods');
+
+ for (index in 0...detectedMods.length)
{
- FlxG.log.warn("missing mods folder, expected: " + FileSystem.absolutePath(MOD_PATH));
- return;
- }
-
- for (file in FileSystem.readDirectory(MOD_PATH))
- {
- if (FileSystem.isDirectory(MOD_PATH + file))
- modFolders.push(file);
- }
-
- enabledMods = [];
-
- modList = Polymod.scan(MOD_PATH);
-
- trace(modList);
-
- var loopNum:Int = 0;
- for (i in modFolders)
- {
- var txt:ModMenuItem = new ModMenuItem(0, 10 + (40 * loopNum), 0, i, 32);
- txt.text = i;
+ var modMetadata:ModMetadata = detectedMods[index];
+ var modName:String = modMetadata.title;
+ var txt:ModMenuItem = new ModMenuItem(0, 10 + (40 * index), 0, modName, 32);
+ txt.text = modName;
grpMods.add(txt);
-
- loopNum++;
}
#end
}
diff --git a/source/ui/NgPrompt.hx b/source/funkin/ui/NgPrompt.hx
similarity index 52%
rename from source/ui/NgPrompt.hx
rename to source/funkin/ui/NgPrompt.hx
index 4bf75997f..716880b11 100644
--- a/source/ui/NgPrompt.hx
+++ b/source/funkin/ui/NgPrompt.hx
@@ -1,80 +1,77 @@
-package ui;
+package funkin.ui;
-import NGio;
-import ui.Prompt;
+#if newgrounds
+import funkin.NGio;
+import funkin.ui.Prompt;
class NgPrompt extends Prompt
{
- public function new (text:String, style:ButtonStyle = Yes_No)
+ public function new(text:String, style:ButtonStyle = Yes_No)
{
super(text, style);
}
-
+
static public function showLogin()
{
return showLoginPrompt(true);
}
-
+
static public function showSavedSessionFailed()
{
return showLoginPrompt(false);
}
-
+
static function showLoginPrompt(fromUi:Bool)
{
var prompt = new NgPrompt("Talking to server...", None);
- prompt.openCallback = NGio.login.bind
- (
- function popupLauncher(openPassportUrl)
+ prompt.openCallback = NGio.login.bind(function popupLauncher(openPassportUrl)
+ {
+ var choiceMsg = fromUi ? #if web "Log in to Newgrounds?" #else null #end // User-input needed to allow popups
+ : "Your session has expired.\n Please login again.";
+
+ if (choiceMsg != null)
{
- var choiceMsg = fromUi
- ? #if web "Log in to Newgrounds?" #else null #end // User-input needed to allow popups
- : "Your session has expired.\n Please login again.";
-
- if (choiceMsg != null)
+ prompt.setText(choiceMsg);
+ prompt.setButtons(Yes_No);
+ #if web
+ prompt.buttons.getItem("yes").fireInstantly = true;
+ #end
+ prompt.onYes = function()
{
- prompt.setText(choiceMsg);
- prompt.setButtons(Yes_No);
- #if web
- prompt.buttons.getItem("yes").fireInstantly = true;
- #end
- prompt.onYes = function()
- {
- prompt.setText("Connecting..." #if web + "\n(check your popup blocker)" #end);
- prompt.setButtons(None);
- openPassportUrl();
- };
- prompt.onNo = function()
- {
- prompt.close();
- prompt = null;
- NGio.cancelLogin();
- };
- }
- else
- {
- prompt.setText("Connecting...");
+ prompt.setText("Connecting..." #if web + "\n(check your popup blocker)" #end);
+ prompt.setButtons(None);
openPassportUrl();
- }
- },
- function onLoginComplete(result:ConnectionResult)
- {
- switch (result)
+ };
+ prompt.onNo = function()
{
- case Success:
+ prompt.close();
+ prompt = null;
+ NGio.cancelLogin();
+ };
+ }
+ else
+ {
+ prompt.setText("Connecting...");
+ openPassportUrl();
+ }
+ }, function onLoginComplete(result:ConnectionResult)
+ {
+ switch (result)
+ {
+ case Success:
{
prompt.setText("Login Successful");
prompt.setButtons(Ok);
prompt.onYes = prompt.close;
}
- case Fail(msg):
+ case Fail(msg):
{
trace("Login Error:" + msg);
prompt.setText("Login failed");
prompt.setButtons(Ok);
prompt.onYes = prompt.close;
}
- case Cancelled:
+ case Cancelled:
{
if (prompt != null)
{
@@ -85,13 +82,12 @@ class NgPrompt extends Prompt
else
trace("Login cancelled via prompt");
}
- }
}
- );
-
+ });
+
return prompt;
}
-
+
static public function showLogout()
{
var user = io.newgrounds.NG.core.user.name;
@@ -104,4 +100,5 @@ class NgPrompt extends Prompt
prompt.onNo = prompt.close;
return prompt;
}
-}
\ No newline at end of file
+}
+#end
diff --git a/source/ui/OptionsState.hx b/source/funkin/ui/OptionsState.hx
similarity index 98%
rename from source/ui/OptionsState.hx
rename to source/funkin/ui/OptionsState.hx
index 816834933..1b6d03e93 100644
--- a/source/ui/OptionsState.hx
+++ b/source/funkin/ui/OptionsState.hx
@@ -1,11 +1,11 @@
-package ui;
+package funkin.ui;
import flixel.FlxSprite;
import flixel.FlxSubState;
import flixel.addons.transition.FlxTransitionableState;
import flixel.group.FlxGroup;
import flixel.util.FlxSignal;
-import i18n.FireTongueHandler.t;
+import funkin.i18n.FireTongueHandler.t;
// typedef OptionsState = OptionsMenu_old;
// class OptionsState_new extends MusicBeatState
@@ -33,9 +33,7 @@ class OptionsState extends MusicBeatState
var controls = addPage(Controls, new ControlsMenu());
// var colors = addPage(Colors, new ColorsMenu());
- #if polymod
var mods = addPage(Mods, new ModMenu());
- #end
if (options.hasMultipleOptions())
{
@@ -43,10 +41,7 @@ class OptionsState extends MusicBeatState
controls.onExit.add(switchPage.bind(Options));
// colors.onExit.add(switchPage.bind(Options));
preferences.onExit.add(switchPage.bind(Options));
-
- #if polymod
mods.onExit.add(switchPage.bind(Options));
- #end
}
else
{
@@ -180,9 +175,7 @@ class OptionsMenu extends Page
createItem(t("PREFERENCES"), function() switchPage(Preferences));
createItem(t("CONTROLS"), function() switchPage(Controls));
// createItem(t("COLORS"), function() switchPage(Colors));
- #if polymod
createItem(t("MODS"), function() switchPage(Mods));
- #end
#if CAN_OPEN_LINKS
if (showDonate)
diff --git a/source/ui/PopUpStuff.hx b/source/funkin/ui/PopUpStuff.hx
similarity index 93%
rename from source/ui/PopUpStuff.hx
rename to source/funkin/ui/PopUpStuff.hx
index eeef727f1..02f08687d 100644
--- a/source/ui/PopUpStuff.hx
+++ b/source/funkin/ui/PopUpStuff.hx
@@ -1,8 +1,9 @@
-package ui;
+package funkin.ui;
import flixel.FlxSprite;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.tweens.FlxTween;
+import funkin.play.PlayState;
using StringTools;
@@ -21,7 +22,7 @@ class PopUpStuff extends FlxTypedGroup
var rating:FlxSprite = new FlxSprite();
var ratingPath:String = daRating;
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
ratingPath = "weeb/pixelUI/" + ratingPath + "-pixel";
rating.loadGraphic(Paths.image(ratingPath));
@@ -39,7 +40,7 @@ class PopUpStuff extends FlxTypedGroup
add(rating);
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
{
rating.setGraphicSize(Std.int(rating.width * PlayState.daPixelZoom * 0.7));
}
@@ -68,7 +69,7 @@ class PopUpStuff extends FlxTypedGroup
var pixelShitPart1:String = "";
var pixelShitPart2:String = '';
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
{
pixelShitPart1 = 'weeb/pixelUI/';
pixelShitPart2 = '-pixel';
@@ -89,7 +90,7 @@ class PopUpStuff extends FlxTypedGroup
add(comboSpr);
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
{
comboSpr.setGraphicSize(Std.int(comboSpr.width * PlayState.daPixelZoom * 0.7));
}
@@ -128,7 +129,7 @@ class PopUpStuff extends FlxTypedGroup
var numScore:FlxSprite = new FlxSprite().loadGraphic(Paths.image(pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2));
numScore.y = comboSpr.y;
- if (PlayState.curStage.startsWith('school'))
+ if (PlayState.curStageId.startsWith('school'))
{
numScore.setGraphicSize(Std.int(numScore.width * PlayState.daPixelZoom));
}
diff --git a/source/ui/PreferencesMenu.hx b/source/funkin/ui/PreferencesMenu.hx
similarity index 96%
rename from source/ui/PreferencesMenu.hx
rename to source/funkin/ui/PreferencesMenu.hx
index d77aff357..6fcf7b57a 100644
--- a/source/ui/PreferencesMenu.hx
+++ b/source/funkin/ui/PreferencesMenu.hx
@@ -1,14 +1,13 @@
-package ui;
+package funkin.ui;
import flixel.FlxCamera;
import flixel.FlxObject;
import flixel.FlxSprite;
-import flixel.group.FlxGroup;
-import flixel.util.FlxColor;
-import ui.AtlasText.AtlasFont;
-import ui.TextMenuList.TextMenuItem;
+import funkin.ui.AtlasText.AtlasFont;
+import funkin.ui.TextMenuList.TextMenuItem;
+import funkin.ui.OptionsState.Page;
-class PreferencesMenu extends ui.OptionsState.Page
+class PreferencesMenu extends Page
{
public static var preferences:Map = new Map();
diff --git a/source/ui/Prompt.hx b/source/funkin/ui/Prompt.hx
similarity index 97%
rename from source/ui/Prompt.hx
rename to source/funkin/ui/Prompt.hx
index acd584e97..1679d3886 100644
--- a/source/ui/Prompt.hx
+++ b/source/funkin/ui/Prompt.hx
@@ -1,11 +1,11 @@
-package ui;
+package funkin.ui;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.text.FlxText;
import flixel.util.FlxColor;
-import ui.AtlasText;
-import ui.MenuList;
+import funkin.ui.AtlasText;
+import funkin.ui.MenuList;
class Prompt extends flixel.FlxSubState
{
diff --git a/source/ui/TextMenuList.hx b/source/funkin/ui/TextMenuList.hx
similarity index 94%
rename from source/ui/TextMenuList.hx
rename to source/funkin/ui/TextMenuList.hx
index c507ae864..ae3ed7bff 100644
--- a/source/ui/TextMenuList.hx
+++ b/source/funkin/ui/TextMenuList.hx
@@ -1,7 +1,7 @@
-package ui;
+package funkin.ui;
-import ui.AtlasText;
-import ui.MenuList;
+import funkin.ui.AtlasText;
+import funkin.ui.MenuList;
class TextMenuList extends MenuTypedList
{
diff --git a/source/ui/animDebugShit/DebugBoundingState.hx b/source/funkin/ui/animDebugShit/DebugBoundingState.hx
similarity index 99%
rename from source/ui/animDebugShit/DebugBoundingState.hx
rename to source/funkin/ui/animDebugShit/DebugBoundingState.hx
index 5a2b1535d..9f49f5cc0 100644
--- a/source/ui/animDebugShit/DebugBoundingState.hx
+++ b/source/funkin/ui/animDebugShit/DebugBoundingState.hx
@@ -1,4 +1,4 @@
-package ui.animDebugShit;
+package funkin.ui.animDebugShit;
import flixel.FlxCamera;
import flixel.FlxSprite;
diff --git a/source/ui/stageBuildShit/CharStage.hx b/source/funkin/ui/stageBuildShit/CharStage.hx
similarity index 80%
rename from source/ui/stageBuildShit/CharStage.hx
rename to source/funkin/ui/stageBuildShit/CharStage.hx
index a0e1ed062..740c8de3b 100644
--- a/source/ui/stageBuildShit/CharStage.hx
+++ b/source/funkin/ui/stageBuildShit/CharStage.hx
@@ -1,4 +1,4 @@
-package ui.stageBuildShit;
+package funkin.ui.stageBuildShit;
class CharStage extends SprStage
{
diff --git a/source/ui/stageBuildShit/SprStage.hx b/source/funkin/ui/stageBuildShit/SprStage.hx
similarity index 96%
rename from source/ui/stageBuildShit/SprStage.hx
rename to source/funkin/ui/stageBuildShit/SprStage.hx
index 5011355f0..95eba9325 100644
--- a/source/ui/stageBuildShit/SprStage.hx
+++ b/source/funkin/ui/stageBuildShit/SprStage.hx
@@ -1,4 +1,4 @@
-package ui.stageBuildShit;
+package funkin.ui.stageBuildShit;
import flixel.FlxSprite;
import flixel.input.mouse.FlxMouseEventManager;
diff --git a/source/ui/stageBuildShit/StageBuilderState.hx b/source/funkin/ui/stageBuildShit/StageBuilderState.hx
similarity index 99%
rename from source/ui/stageBuildShit/StageBuilderState.hx
rename to source/funkin/ui/stageBuildShit/StageBuilderState.hx
index 1ca1f6145..5ebb6df57 100644
--- a/source/ui/stageBuildShit/StageBuilderState.hx
+++ b/source/funkin/ui/stageBuildShit/StageBuilderState.hx
@@ -1,4 +1,4 @@
-package ui.stageBuildShit;
+package funkin.ui.stageBuildShit;
import flixel.FlxCamera;
import flixel.FlxSprite;
diff --git a/source/ui/stageBuildShit/StagetoolBar.hx b/source/funkin/ui/stageBuildShit/StagetoolBar.hx
similarity index 91%
rename from source/ui/stageBuildShit/StagetoolBar.hx
rename to source/funkin/ui/stageBuildShit/StagetoolBar.hx
index 74337d64d..521881c9c 100644
--- a/source/ui/stageBuildShit/StagetoolBar.hx
+++ b/source/funkin/ui/stageBuildShit/StagetoolBar.hx
@@ -1,4 +1,4 @@
-package ui.stageBuildShit;
+package funkin.ui.stageBuildShit;
import flixel.group.FlxGroup;
diff --git a/source/util/SortUtil.hx b/source/funkin/util/SortUtil.hx
similarity index 65%
rename from source/util/SortUtil.hx
rename to source/funkin/util/SortUtil.hx
index 0cac21ac8..29f64fb0d 100644
--- a/source/util/SortUtil.hx
+++ b/source/funkin/util/SortUtil.hx
@@ -1,8 +1,10 @@
-package util;
+package funkin.util;
+#if !macro
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.util.FlxSort;
import flixel.FlxObject;
+#end
class SortUtil
{
@@ -14,13 +16,4 @@ class SortUtil
{
return FlxSort.byValues(Order, Obj1.zIndex, Obj2.zIndex);
}
-
- /**
- * Sorts the element in an FlxTypedGroup by their z-index values.
- * @param group The group to sort.
- */
- public static inline function sortByZIndex(group:FlxTypedGroup)
- {
- group.sort(byZIndex, FlxSort.ASCENDING);
- }
}
diff --git a/source/funkin/util/assets/DataAssets.hx b/source/funkin/util/assets/DataAssets.hx
new file mode 100644
index 000000000..d00703068
--- /dev/null
+++ b/source/funkin/util/assets/DataAssets.hx
@@ -0,0 +1,30 @@
+package funkin.util.assets;
+
+using StringTools;
+
+class DataAssets
+{
+ static function buildDataPath(path:String):String
+ {
+ return 'assets/data/${path}';
+ }
+
+ public static function listDataFilesInPath(path:String, ?ext:String = '.json'):Array
+ {
+ var textAssets = openfl.utils.Assets.list();
+ var queryPath = buildDataPath(path);
+
+ var results:Array = [];
+ for (textPath in textAssets)
+ {
+ if (textPath.startsWith(queryPath) && textPath.endsWith(ext))
+ {
+ var pathNoSuffix = textPath.substring(0, textPath.length - ext.length);
+ var pathNoPrefix = pathNoSuffix.substring(queryPath.length);
+ results.push(pathNoPrefix);
+ }
+ }
+
+ return results;
+ }
+}
diff --git a/source/util/macro/FlxMacro.hx b/source/funkin/util/macro/FlxMacro.hx
similarity index 97%
rename from source/util/macro/FlxMacro.hx
rename to source/funkin/util/macro/FlxMacro.hx
index f66be4a32..adbee3319 100644
--- a/source/util/macro/FlxMacro.hx
+++ b/source/funkin/util/macro/FlxMacro.hx
@@ -1,4 +1,4 @@
-package util.macro;
+package funkin.util.macro;
#if macro
class FlxMacro
diff --git a/source/funkin/util/macro/MacroUtil.hx b/source/funkin/util/macro/MacroUtil.hx
new file mode 100644
index 000000000..ebf5bd5ec
--- /dev/null
+++ b/source/funkin/util/macro/MacroUtil.hx
@@ -0,0 +1,12 @@
+package funkin.util.macro;
+
+class MacroUtil
+{
+ public static macro function getDefine(key:String, defaultValue:String = null):haxe.macro.Expr
+ {
+ var value = haxe.macro.Context.definedValue(key);
+ if (value == null)
+ value = defaultValue;
+ return macro $v{value};
+ }
+}
diff --git a/source/play/stage/Stage.hx b/source/play/stage/Stage.hx
deleted file mode 100644
index b612a97d0..000000000
--- a/source/play/stage/Stage.hx
+++ /dev/null
@@ -1,9 +0,0 @@
-package play.stage;
-
-import flixel.FlxObject;
-import flixel.group.FlxGroup.FlxTypedGroup;
-
-/**
- * A Stage is a group of objects.
- */
-class Stage extends FlxTypedGroup {}