diff --git a/Project.xml b/Project.xml
index 7f35ae53..bb3a0e4b 100644
--- a/Project.xml
+++ b/Project.xml
@@ -160,4 +160,7 @@
+
+
+
diff --git a/buildnumber.txt b/buildnumber.txt
index a0ce7199..6ea72f04 100644
--- a/buildnumber.txt
+++ b/buildnumber.txt
@@ -1 +1 @@
-1016
\ No newline at end of file
+1032
\ No newline at end of file
diff --git a/source/funkin/mods/ModsFolder.hx b/source/funkin/mods/ModsFolder.hx
index 410feef8..8a65d4b4 100644
--- a/source/funkin/mods/ModsFolder.hx
+++ b/source/funkin/mods/ModsFolder.hx
@@ -1,9 +1,11 @@
package funkin.mods;
+import flixel.util.FlxSignal.FlxTypedSignal;
import openfl.utils.Assets;
import openfl.utils.AssetManifest;
import openfl.utils.AssetLibrary;
import flixel.graphics.FlxGraphic;
+import flixel.util.FlxSignal.FlxTypedSignal;
#if MOD_SUPPORT
import sys.FileSystem;
@@ -16,13 +18,11 @@ import haxe.io.Path;
using StringTools;
class ModsFolder {
- #if MOD_SUPPORT
/**
- * Last time the folder was modified.
+ * INTERNAL - Only use when editing source mods!!
*/
- public static var lastFolderEditTime:Date = null;
- #end
-
+ @:dox(hide) public static var onModSwitch:FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
+
/**
* Current mod folder. Will affect `Paths`.
*/
@@ -49,6 +49,8 @@ class ModsFolder {
* @param force Whenever the mod should be reloaded if it has already been loaded
*/
public static function loadMod(mod:String, force:Bool = false) {
+ if (mod == null) return null; // may be loading base game
+
if (FileSystem.exists('${modsPath}$mod.zip')) {
var e = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force);
loadedMods.push(mod);
@@ -60,6 +62,23 @@ class ModsFolder {
}
}
+ /**
+ * Switches mod - unloads all the other mods, then load this one.
+ * @param libName
+ */
+ public static function switchMod(mod:String) {
+ for(m in loadedMods)
+ unloadMod(m);
+
+ loadMod(ModsFolder.currentModFolder = mod);
+ onModSwitch.dispatch(ModsFolder.currentModFolder);
+ FlxG.resetState();
+ }
+
+ public static function unloadMod(mod:String) {
+ Assets.unloadLibrary('mods/$mod');
+ }
+
public static function prepareLibrary(libName:String, force:Bool = false) {
if (Assets.hasLibrary(libName)) {
if (force)
diff --git a/source/funkin/scripting/GlobalScript.hx b/source/funkin/scripting/GlobalScript.hx
new file mode 100644
index 00000000..70e2a076
--- /dev/null
+++ b/source/funkin/scripting/GlobalScript.hx
@@ -0,0 +1,100 @@
+package funkin.scripting;
+
+import flixel.FlxG;
+import flixel.FlxState;
+import funkin.mods.ModsFolder;
+#if GLOBAL_SCRIPT
+/**
+ * Class for THE Global Script, aka script that runs in the background at all times.
+ */
+class GlobalScript {
+ public static var script:Script;
+
+ public static function init() {
+ #if MOD_SUPPORT
+ ModsFolder.onModSwitch.add(onModSwitch);
+ #end
+ FlxG.signals.focusGained.add(function() {
+ call("focusGained");
+ });
+ FlxG.signals.focusLost.add(function() {
+ call("focusLost");
+ });
+ FlxG.signals.gameResized.add(function(w:Int, h:Int) {
+ call("gameResized", [w, h]);
+ });
+ FlxG.signals.postDraw.add(function() {
+ call("postDraw");
+ });
+ FlxG.signals.postGameReset.add(function() {
+ call("postGameReset");
+ });
+ FlxG.signals.postGameStart.add(function() {
+ });
+ FlxG.signals.postStateSwitch.add(function() {
+ call("postStateSwitch");
+ });
+ FlxG.signals.postUpdate.add(function() {
+ call("postUpdate", [FlxG.elapsed]);
+ call("updatePost", [FlxG.elapsed]);
+ if (FlxG.keys.justPressed.F5) {
+ if (script != null && !(script is DummyScript)) {
+ Logs.trace('Reloading global script...', WARNING, YELLOW);
+ script.reload();
+ Logs.trace('Global script successfully reloaded.', WARNING, GREEN);
+ } else {
+ Logs.trace('Loading global script...', WARNING, YELLOW);
+ onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
+ if (script is DummyScript)
+ Logs.trace('Global script not found. Are you sure "data/global.hx" exists?', ERROR, RED);
+ else
+ Logs.trace('Global script successfully loaded.', WARNING, GREEN);
+ }
+ }
+ });
+ FlxG.signals.preDraw.add(function() {
+ call("preDraw");
+ });
+ FlxG.signals.preGameReset.add(function() {
+ call("preGameReset");
+ });
+ FlxG.signals.preGameStart.add(function() {
+ call("preGameStart");
+ });
+ FlxG.signals.preStateCreate.add(function(state:FlxState) {
+ call("preStateCreate", [state]);
+ });
+ FlxG.signals.preStateSwitch.add(function() {
+ call("preStateSwitch", []);
+ });
+ FlxG.signals.preUpdate.add(function() {
+ call("preUpdate", [FlxG.elapsed]);
+ call("update", [FlxG.elapsed]);
+ });
+
+ onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end);
+ }
+
+ public static function call(name:String, ?args:Array) {
+ if (script == null) return;
+ script.call(name, args);
+ }
+ public static function onModSwitch(newMod:String) {
+ trace(newMod);
+ if (script != null) {
+ script.destroy();
+ script = null;
+ }
+ script = Script.create(Paths.script('data/global'));
+ script.load();
+ }
+
+ public static function beatHit(curBeat:Int) {
+ call("beatHit", [curBeat]);
+ }
+
+ public static function stepHit(curStep:Int) {
+ call("stepHit", [curStep]);
+ }
+}
+#end
\ No newline at end of file
diff --git a/source/funkin/system/Logs.hx b/source/funkin/system/Logs.hx
index 041318aa..ddca2582 100644
--- a/source/funkin/system/Logs.hx
+++ b/source/funkin/system/Logs.hx
@@ -9,10 +9,6 @@ import funkin.windows.WindowsAPI.ConsoleColor;
class Logs {
private static var __showing:Bool = false;
public static function init() {
- __showInConsole([
- logText("Hello, World! ", CYAN),
- logText("I am..."),
- logText("COLORED!!", RED)]);
Log.trace = function(v : Dynamic, ?infos : Null) {
__showInConsole(prepareColoredTrace([
diff --git a/source/funkin/system/Main.hx b/source/funkin/system/Main.hx
index adb56996..3fe29a33 100644
--- a/source/funkin/system/Main.hx
+++ b/source/funkin/system/Main.hx
@@ -106,13 +106,15 @@ class Main extends Sprite
public function loadGameSettings() {
-
+ Logs.init();
+
// TODO: Mod switching
ModsFolder.init();
- ModsFolder.loadMod("introMod");
- ModsFolder.currentModFolder = "introMod";
-
- Logs.init();
+ ModsFolder.switchMod("introMod");
+
+ #if GLOBAL_SCRIPT
+ funkin.scripting.GlobalScript.init();
+ #end
#if sys
if (Sys.args().contains("-livereload")) {
diff --git a/source/scripting/GlobalScript.hx b/source/scripting/GlobalScript.hx
new file mode 100644
index 00000000..b2b04c5c
--- /dev/null
+++ b/source/scripting/GlobalScript.hx
@@ -0,0 +1,87 @@
+package scripting;
+
+import flixel.FlxState;
+/**
+ * A global script is a special kind of script that runs on everywhere on your mod: menus, game, etc...
+ *
+ * To create one, go to data and create a script named "global", then press F5 in game.
+ *
+ * All flixel signals are automatically binded, as shown below.
+ */
+interface GlobalScript {
+ /**
+ * Called whenever the game gains focus.
+ */
+ public function focusGained():Void;
+ /**
+ * Called whenever the game loses focus.
+ */
+ public function focusLost():Void;
+ /**
+ * Called whenever the game loses focus.
+ * @param width Width of the game
+ * @param height Height of the game
+ */
+ public function gameResized(width:Int, height:Int):Void;
+
+ /**
+ * Called after the screen has been drawn.
+ */
+ public function postDraw():Void;
+
+ /**
+ * Called after the game has been reset.
+ */
+ public function postGameReset():Void;
+
+ /**
+ * Called after the game has been started.
+ */
+ public function postGameStart():Void;
+
+ /**
+ * Called after the state has been switched.
+ */
+ public function postStateSwitch():Void;
+
+ /**
+ * Called after the game has been updated.
+ *
+ * Aliases: `postUpdate`
+ *
+ * @param elapsed Time elapsed since last frame
+ */
+ public function updatePost(elapsed:Float):Void;
+
+ /**
+ * Called before the game draws on screen.
+ */
+ public function preDraw():Void;
+
+ /**
+ * Called before the game resets.
+ */
+ public function preGameReset():Void;
+
+ /**
+ * Called before the game starts.
+ */
+ public function preGameStart():Void;
+
+ /**
+ * Called before the state creates.
+ */
+ public function preStateCreate(state:FlxState):Void;
+
+ /**
+ * Called before the state switches.
+ */
+ public function preStateSwitch():Void;
+
+ /**
+ * Called before the game updates.
+ *
+ * Aliases: `preUpdate`
+ */
+ public function update(elapsed:Float):Void;
+}
\ No newline at end of file