diff --git a/.github/ISSUE_TEMPLATE/compiling.md b/.github/ISSUE_TEMPLATE/compiling.md index bd6f439c..4f516469 100644 --- a/.github/ISSUE_TEMPLATE/compiling.md +++ b/.github/ISSUE_TEMPLATE/compiling.md @@ -16,5 +16,5 @@ labels: compiling help [ ] Mac ### Explain your issue -##### Please check first if your issue haven't already been reported yet. -[weed]: <> (MAKE SURE TO ADD A SCREENSHOT OF THE CRASH HANDLER, IF AVAILABLE, AND STEPS TO REPRODUCE THE BUG!) \ No newline at end of file +##### Please check first if your issue haven't already been reported yet, and make sure you ran the `update.bat` file before building. +[weed]: <> (MAKE SURE TO ADD A SCREENSHOT OF THE CRASH HANDLER, IF AVAILABLE, AND STEPS TO REPRODUCE THE BUG!) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5463a51b..08e9b4d2 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -27,7 +27,7 @@ jobs: cache-build-linux - name: Installing/Updating libraries run: | - haxe -cp ./update -D analyzer-optimize -main Update --interp + haxe -cp commandline -D analyzer-optimize --run Main setup - name: Building the game run: | haxelib run lime build linux @@ -70,4 +70,4 @@ jobs: export/release/linux/haxe/ export/release/linux/obj/ restore-keys: | - cache-build-linux \ No newline at end of file + cache-build-linux diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 772db147..65a3fa2e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -27,7 +27,7 @@ jobs: cache-build-mac - name: Installing/Updating libraries run: | - haxe -cp ./update -D analyzer-optimize -main Update --interp + haxe -cp commandline -D analyzer-optimize --run Main setup - name: Building the game run: | haxelib run lime build mac @@ -70,4 +70,4 @@ jobs: export/release/macos/haxe/ export/release/macos/obj/ restore-keys: | - cache-build-mac \ No newline at end of file + cache-build-mac diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 6088d1c2..1c93ad8c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -27,7 +27,7 @@ jobs: cache-build-windows - name: Installing/Updating libraries run: | - haxe -cp ./update -D analyzer-optimize -main Update --interp + haxe -cp commandline -D analyzer-optimize --run Main setup - name: Building the game run: | haxelib run lime build windows @@ -70,4 +70,4 @@ jobs: export/release/windows/haxe/ export/release/windows/obj/ restore-keys: | - cache-build-windows \ No newline at end of file + cache-build-windows diff --git a/.gitignore b/.gitignore index bee4df7e..43d2c37c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ latest/windows/obj/ latest/windows/haxe/ .vscode/* !.vscode/settings.json -.haxelib/ \ No newline at end of file +.haxelib/ +mods/Baldi's Basics in Funkin'/ \ No newline at end of file diff --git a/README.md b/README.md index 6c8f365c..3b8538b9 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Latest builds for the engine can be found in the [Actions](https://github.com/Yo Windows ##### Tested on Windows 10 21H2 -1. Install the [latest version of Haxe](https://haxe.org/download/). +1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/). 2. Download [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) 3. Wait for the Visual Studio Installer to install 4. On the Visual Studio installer screen, go to the "Individual components" tab and only select those options: @@ -63,7 +63,7 @@ Latest builds for the engine can be found in the [Actions](https://github.com/Yo Linux ##### Requires testing -1. Install the [latest version of Haxe](https://haxe.org/download/). +1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/). 2. Install `g++`, if not present already. 3. Download and install [`git-scm`](https://git-scm.com/download/linux). 4. Open a terminal in the Codename Engine source folder, and run `update.sh`. @@ -74,7 +74,7 @@ Latest builds for the engine can be found in the [Actions](https://github.com/Yo MacOS ##### Requires testing -1. Install the [latest version of Haxe](https://haxe.org/download/). +1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/). 2. Install `Xcode` to allow C++ app building. 3. Download and install [`git-scm`](https://git-scm.com/download/mac). 4. Open a terminal in the Codename Engine source folder, and run `update.sh`. diff --git a/assets/images/editors/charter/event-icons.png b/assets/images/editors/charter/event-icons.png deleted file mode 100644 index fee6d3d0..00000000 Binary files a/assets/images/editors/charter/event-icons.png and /dev/null differ diff --git a/assets/images/editors/charter/event-icons/Alt Animation Toggle.png b/assets/images/editors/charter/event-icons/Alt Animation Toggle.png new file mode 100644 index 00000000..f2180276 Binary files /dev/null and b/assets/images/editors/charter/event-icons/Alt Animation Toggle.png differ diff --git a/assets/images/editors/charter/event-icons/BPM Change.png b/assets/images/editors/charter/event-icons/BPM Change.png new file mode 100644 index 00000000..a59fe83a Binary files /dev/null and b/assets/images/editors/charter/event-icons/BPM Change.png differ diff --git a/assets/images/editors/charter/event-icons/Camera Movement.png b/assets/images/editors/charter/event-icons/Camera Movement.png new file mode 100644 index 00000000..c7b117f0 Binary files /dev/null and b/assets/images/editors/charter/event-icons/Camera Movement.png differ diff --git a/assets/images/editors/charter/event-icons/HScript Call.png b/assets/images/editors/charter/event-icons/HScript Call.png new file mode 100644 index 00000000..ab2ff5e1 Binary files /dev/null and b/assets/images/editors/charter/event-icons/HScript Call.png differ diff --git a/assets/images/editors/charter/event-icons/Unknown.png b/assets/images/editors/charter/event-icons/Unknown.png new file mode 100644 index 00000000..ba1116fd Binary files /dev/null and b/assets/images/editors/charter/event-icons/Unknown.png differ diff --git a/commandline/commands/Compiler.hx b/commandline/commands/Compiler.hx index 24ace428..0e0eb692 100644 --- a/commandline/commands/Compiler.hx +++ b/commandline/commands/Compiler.hx @@ -5,13 +5,13 @@ class Compiler { __build(args, ["test", getBuildTarget(), "-D", "TEST_BUILD"]); } public static function build(args:Array) { - __build(args, ["build", "windows", "-D", "TEST_BUILD"]); + __build(args, ["build", getBuildTarget(), "-D", "TEST_BUILD"]); } public static function release(args:Array) { - __build(args, ["build", "windows"]); + __build(args, ["build", getBuildTarget()]); } public static function testRelease(args:Array) { - __build(args, ["test", "windows"]); + __build(args, ["test", getBuildTarget()]); } private static function __build(args:Array, arg:Array) { diff --git a/source/funkin/backend/chart/BaseGameParser.hx b/source/funkin/backend/chart/BaseGameParser.hx index 3c56e069..a8b31b87 100644 --- a/source/funkin/backend/chart/BaseGameParser.hx +++ b/source/funkin/backend/chart/BaseGameParser.hx @@ -55,7 +55,7 @@ class BaseGameParser { if (camFocusedBF != (camFocusedBF = section.mustHitSection)) { result.events.push({ time: curTime, - type: CAM_MOVEMENT, + name: "Camera Movement", params: [camFocusedBF ? 1 : 0] }); } @@ -90,7 +90,7 @@ class BaseGameParser { result.events.push({ time: curTime, - type: BPM_CHANGE, + name: "BPM Change", params: [section.bpm] }); } diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx index 8253a7a8..e950fa9e 100644 --- a/source/funkin/backend/chart/Chart.hx +++ b/source/funkin/backend/chart/Chart.hx @@ -108,6 +108,22 @@ class Chart { */ #if REGION if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) { + // backward compat on events since its caused problems + var eventTypesToString:Map = [ + -1 => "HScript Call", + 0 => "Unknown", + 1 => "Camera Movement", + 2 => "BPM Change", + 3 => "Alt Animation Toggle", + ]; + + for (event in cast(data.events, Array)) { + if (Reflect.hasField(event, "type")) { + event.name = eventTypesToString[event.type]; + event.type = null; + } + } + // codename chart base = data; } else { diff --git a/source/funkin/backend/chart/ChartData.hx b/source/funkin/backend/chart/ChartData.hx index 3dd309e7..e81589e7 100644 --- a/source/funkin/backend/chart/ChartData.hx +++ b/source/funkin/backend/chart/ChartData.hx @@ -48,8 +48,8 @@ typedef ChartNote = { } typedef ChartEvent = { + var name:String; var time:Float; - var type:ChartEventType; var params:Array; } @@ -67,43 +67,4 @@ abstract ChartStrumLineType(Int) from Int to Int { * STRUMLINE IS MARKED AS ADDITIONAL - WILL BE PLAYED AS CPU EVEN IF OPPONENT MODE IS ENABLED */ var ADDITIONAL = 2; -} -@:enum -abstract ChartEventType(Int) from Int to Int { - /** - * CUSTOM EVENT - * Params: - * - Function Name (String) - * - Function Parameters... - */ - var CUSTOM = -1; - /** - * NO EVENT, MADE FOR UNKNOWN EVENTS / EVENTS THAT CANNOT BE PARSED - */ - var NONE = 0; - /** - * CAMERA MOVEMENT EVENT - * Params: - * - Target Strumline ID (Int) - */ - var CAM_MOVEMENT = 1; - /** - * BPM CHANGE EVENT - * Params: - * - Target BPM (Float) - */ - var BPM_CHANGE = 2; - /** - * ALT ANIM TOGGLE - * Params: - * - Strum Line which is going to be toggled (Int) - * - Whenever its going to be toggled or not (Bool) - */ - var ALT_ANIM_TOGGLE = 3; - - /** - * Returns all usable event types. - */ - public static inline function getChartEventTypes():Array - return [CUSTOM, CAM_MOVEMENT, BPM_CHANGE, ALT_ANIM_TOGGLE]; } \ No newline at end of file diff --git a/source/funkin/backend/scripting/events/EventGameEvent.hx b/source/funkin/backend/scripting/events/EventGameEvent.hx new file mode 100644 index 00000000..836e44c9 --- /dev/null +++ b/source/funkin/backend/scripting/events/EventGameEvent.hx @@ -0,0 +1,7 @@ +package funkin.backend.scripting.events; + +import funkin.backend.chart.ChartData; + +final class EventGameEvent extends CancellableEvent { + public var event:ChartEvent; +} \ No newline at end of file diff --git a/source/funkin/backend/scripting/events/StrumCreationEvent.hx b/source/funkin/backend/scripting/events/StrumCreationEvent.hx index 699f88bc..d591d958 100644 --- a/source/funkin/backend/scripting/events/StrumCreationEvent.hx +++ b/source/funkin/backend/scripting/events/StrumCreationEvent.hx @@ -21,6 +21,11 @@ final class StrumCreationEvent extends CancellableEvent { */ public var strumID:Int; + /** + * Animation prefix (`left` = `arrowLEFT`, `left press`, `left confirm`). + */ + public var animPrefix:String; + /** * Sprite path, in case you only want to change the sprite. */ diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx index a35f57c7..d38db2c8 100644 --- a/source/funkin/backend/system/Conductor.hx +++ b/source/funkin/backend/system/Conductor.hx @@ -134,7 +134,7 @@ class Conductor var songTime:Float = 0; var stepTime:Float = 0; - for(e in song.events) if (e.type == BPM_CHANGE && e.params != null && e.params[0] is Float) { + for(e in song.events) if (e.name == "BPM Change" && e.params != null && e.params[0] is Float) { if (e.params[0] == curBPM) continue; var steps = (e.time - songTime) / ((60 / curBPM) * 1000 / 4); stepTime += steps; diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx index 0c03257b..714170f0 100644 --- a/source/funkin/backend/system/MainState.hx +++ b/source/funkin/backend/system/MainState.hx @@ -6,6 +6,7 @@ import sys.FileSystem; import funkin.backend.assets.ModsFolder; import funkin.menus.TitleState; import funkin.menus.BetaWarningState; +import funkin.editors.charter.EventsData; import flixel.FlxState; /** @@ -42,6 +43,7 @@ class MainState extends FlxState { Main.refreshAssets(); ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder); DiscordUtil.reloadJsonData(); + EventsData.reloadEvents(); TitleState.initialized = false; diff --git a/source/funkin/backend/system/framerate/SystemInfo.hx b/source/funkin/backend/system/framerate/SystemInfo.hx index 3c775623..80e35e14 100644 --- a/source/funkin/backend/system/framerate/SystemInfo.hx +++ b/source/funkin/backend/system/framerate/SystemInfo.hx @@ -31,7 +31,7 @@ class SystemInfo extends FramerateCategory { if (process.exitCode() == 0) cpuName = process.stdout.readAll().toString().trim().split(":")[1].trim(); #elseif linux var process = new HiddenProcess("cat", ["/proc/cpuinfo"]); - if (process.exitCode() != 0) return; + if (process.exitCode() != 0) throw 'Could not fetch CPU information'; for (line in process.stdout.readAll().toString().split("\n")) { if (line.indexOf("model name") == 0) { diff --git a/source/funkin/backend/utils/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx index 47f55114..4c0c40c0 100644 --- a/source/funkin/backend/utils/MemoryUtil.hx +++ b/source/funkin/backend/utils/MemoryUtil.hx @@ -128,7 +128,7 @@ class MemoryUtil { reg.match(process.stdout.readAll().toString()); if (process.exitCode() == 0) return reg.matched(1); #elseif linux - var process = HiddenProcess("sudo", ["dmidecode", "--type", "17"]); + var process = new HiddenProcess("sudo", ["dmidecode", "--type", "17"]); if (process.exitCode() != 0) return "Unknown"; var lines = process.stdout.readAll().toString().split("\n"); for (line in lines) { diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index 80759bf3..236a4d74 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -405,8 +405,11 @@ class Charter extends UIState { var instPath:String; public function loadSong() { - if (__reload) + if (__reload) { + EventsData.reloadEvents(); PlayState.loadSong(__song, __diff, false, false); + } + Conductor.setupSong(PlayState.SONG); diff --git a/source/funkin/editors/charter/CharterEvent.hx b/source/funkin/editors/charter/CharterEvent.hx index 0d62361d..6c49081a 100644 --- a/source/funkin/editors/charter/CharterEvent.hx +++ b/source/funkin/editors/charter/CharterEvent.hx @@ -1,76 +1,10 @@ package funkin.editors.charter; import funkin.backend.system.Conductor; -import funkin.backend.chart.ChartData.ChartEventType; import funkin.game.HealthIcon; import funkin.backend.chart.ChartData.ChartEvent; class CharterEvent extends UISliceSprite { - public static function getEventInfo(id:ChartEventType):EventDefineInfo { - return switch(id) { - case CUSTOM: - // hscript - { - name: "HScript Call", - params: [ - { - name: "Function name", - type: TString, - defValue: "myFunc" - }, - { - name: "Function parameters (string)", - type: TArrayOfString, - defValue: [] - } - ] - } - case CAM_MOVEMENT: - { - name: "Camera Movement", - params: [ - { - name: "Camera Target", - type: TStrumLine, - defValue: 0 - } - ] - } - case BPM_CHANGE: - { - name: "BPM Change", - params: [ - { - name: "Target BPM", - type: TFloat(1), - defValue: Conductor.bpm - } - ] - } - case ALT_ANIM_TOGGLE: - { - name: "Alt Animation Toggle", - params: [ - { - name: "Strumline", - type: TStrumLine, - defValue: 0 - }, - { - name: "Enable", - type: TBool, - defValue: true - } - ] - } - default: - { - name: "Unknown", - params: [] - } - }; - } - public var events:Array; public var step:Float; @@ -92,17 +26,19 @@ class CharterEvent extends UISliceSprite { } } - private static function generateDefaultIcon(type:Int) { - var spr = new FlxSprite().loadGraphic(Paths.image('editors/charter/event-icons'), true, 16, 16); - spr.frame = spr.frames.frames[type+1]; - return spr; + private static function generateDefaultIcon(name:String) { + var path:String = Paths.image('editors/charter/event-icons/$name'); + if (!Assets.exists(path)) path = Paths.image('editors/charter/event-icons/Unknown'); + + var spr = new FlxSprite().loadGraphic(path); + return spr; } public static function generateEventIcon(event:ChartEvent) { - return switch(event.type) { + return switch(event.name) { default: - generateDefaultIcon(event.type); - case CAM_MOVEMENT: + generateDefaultIcon(event.name); + case "Camera Movement": // custom icon for camera movement var state = cast(FlxG.state, Charter); if (event.params[0] != null && event.params[0] >= 0 && event.params[0] < state.strumLines.length) { @@ -111,7 +47,7 @@ class CharterEvent extends UISliceSprite { healthIcon.setUnstretchedGraphicSize(32, 32, false); healthIcon; } else - generateDefaultIcon(event.type); + generateDefaultIcon(event.name); } } @@ -136,28 +72,4 @@ class CharterEvent extends UISliceSprite { x = -(bWidth = 37 + (icons.length * 22)); } -} - -typedef EventDefineInfo = { - var name:String; - var params:Array; -} -typedef EventInfo = { - > EventDefineInfo, - var paramValues:Array; -} - -typedef EventParamInfo = { - var name:String; - var type:EventParamType; - var defValue:Dynamic; -} - -enum EventParamType { - TBool; - TInt(?min:Int, ?max:Int, ?step:Float); - TFloat(?min:Int, ?max:Int, ?step:Float, ?precision:Int); - TString; - TArrayOfString; - TStrumLine; } \ No newline at end of file diff --git a/source/funkin/editors/charter/CharterEventGroup.hx b/source/funkin/editors/charter/CharterEventGroup.hx index c631a05a..90719fec 100644 --- a/source/funkin/editors/charter/CharterEventGroup.hx +++ b/source/funkin/editors/charter/CharterEventGroup.hx @@ -1,5 +1,3 @@ package funkin.editors.charter; -class CharterEventGroup extends FlxTypedGroup { - -} \ No newline at end of file +class CharterEventGroup extends FlxTypedGroup {} \ No newline at end of file diff --git a/source/funkin/editors/charter/CharterEventScreen.hx b/source/funkin/editors/charter/CharterEventScreen.hx index b81ee135..8fbc60bd 100644 --- a/source/funkin/editors/charter/CharterEventScreen.hx +++ b/source/funkin/editors/charter/CharterEventScreen.hx @@ -2,6 +2,7 @@ package funkin.editors.charter; import funkin.backend.system.Conductor; import flixel.group.FlxGroup; +import funkin.editors.charter.EventsData; class CharterEventScreen extends UISubstateWindow { public var cam:FlxCamera; @@ -40,11 +41,11 @@ class CharterEventScreen extends UISubstateWindow { add(iconsPanel); addButton = new UIButton(windowSpr.x + 1, windowSpr.y + 31, "", function() { - openSubState(new CharterEventTypeSelection(function(eventType) { + openSubState(new CharterEventTypeSelection(function(eventName) { chartEvent.events.push({ time: Conductor.getTimeForStep(chartEvent.step), params: [], - type: eventType + name: eventName }); changeTab(chartEvent.events.length-1); })); @@ -105,11 +106,10 @@ class CharterEventScreen extends UISubstateWindow { if (id >= 0 && id < chartEvent.events.length) { curEvent = id; var curEvent = chartEvent.events[curEvent]; - var data = CharterEvent.getEventInfo(curEvent.type); - eventName.text = data.name; + eventName.text = curEvent.name; // add new elements var y:Float = eventName.y + eventName.height + 10; - for(k=>param in data.params) { + for(k=>param in EventsData.getEventParams(curEvent.name)) { function addLabel() { var label:UIText = new UIText(eventName.x, y, 0, param.name); y += label.height + 4; @@ -121,30 +121,30 @@ class CharterEventScreen extends UISubstateWindow { case TString: addLabel(); var textBox:UITextBox = new UITextBox(eventName.x, y, cast value); - y += textBox.height + 10; + y += textBox.height + 30; paramsPanel.add(textBox); paramsFields.push(textBox); case TBool: var checkbox = new UICheckbox(eventName.x, y, param.name, cast value); - y += checkbox.height + 10; + y += checkbox.height + 8; paramsPanel.add(checkbox); paramsFields.push(checkbox); case TInt(min, max, step): addLabel(); var numericStepper = new UINumericStepper(eventName.x, y, cast value, step.getDefault(1), 0, min, max); - y += numericStepper.height + 10; + y += numericStepper.height + 30; paramsPanel.add(numericStepper); paramsFields.push(numericStepper); case TFloat(min, max, step, precision): addLabel(); var numericStepper = new UINumericStepper(eventName.x, y, cast value, step.getDefault(1), precision, min, max); - y += numericStepper.height + 10; + y += numericStepper.height + 30; paramsPanel.add(numericStepper); paramsFields.push(numericStepper); case TStrumLine: addLabel(); var dropdown = new UIDropDown(eventName.x, y, 320, 32, [for(k=>s in cast(FlxG.state, Charter).strumLines.members) 'Strumline #${k+1} (${s.strumLine.characters[0]})'], cast value); - y += dropdown.height + 10; + y += dropdown.height + 30; paramsPanel.add(dropdown); paramsFields.push(dropdown); default: diff --git a/source/funkin/editors/charter/CharterEventTypeSelection.hx b/source/funkin/editors/charter/CharterEventTypeSelection.hx index d04a0970..201d9600 100644 --- a/source/funkin/editors/charter/CharterEventTypeSelection.hx +++ b/source/funkin/editors/charter/CharterEventTypeSelection.hx @@ -1,11 +1,11 @@ package funkin.editors.charter; -import funkin.backend.chart.ChartData.ChartEventType; +import funkin.editors.charter.EventsData; class CharterEventTypeSelection extends UISubstateWindow { - var callback:ChartEventType->Void; + var callback:String->Void; - public function new(callback:ChartEventType->Void) { + public function new(callback:String->Void) { super(); this.callback = callback; } @@ -16,11 +16,10 @@ class CharterEventTypeSelection extends UISubstateWindow { var w:Int = winWidth - 20; var lastIndex:Int = 0; - for(k=>eventType in ChartEventType.getChartEventTypes()) { - var type = CharterEvent.getEventInfo(eventType); - add(new UIButton(10, 41 + (32 * k), type.name, function() { + for(k=>eventName in EventsData.eventsList) { + add(new UIButton(10, 41 + (32 * k), eventName, function() { close(); - callback(eventType); + callback(eventName); }, w)); lastIndex = k; diff --git a/source/funkin/editors/charter/EventsData.hx b/source/funkin/editors/charter/EventsData.hx new file mode 100644 index 00000000..e2803c81 --- /dev/null +++ b/source/funkin/editors/charter/EventsData.hx @@ -0,0 +1,88 @@ +package funkin.editors.charter; + +import hscript.Parser; +import hscript.Interp; +import haxe.Json; +import sys.io.File; +import openfl.Assets; +import haxe.io.Path; +import funkin.backend.assets.Paths; + +using StringTools; + +class EventsData { + public static var defaultEventsList:Array = ["HScript Call", "Camera Movement", "BPM Change", "Alt Animation Toggle"]; + public static var defaultEventsParams:Map> = [ + "HScript Call" => [{name: "Function Name", type: TString, defValue: "myFunc"}, {name: "Function Parameters (String split with commas)", type: TString, defValue: ""}], + "Camera Movement" => [{name: "Camera Target", type: TStrumLine, defValue: 0}], + "BPM Change" => [{name: "Target BPM", type: TFloat(1), defValue: 100}], + "Alt Animation Toggle" => [{name: "Strumline", type: TStrumLine, defValue: 0}, {name: "Enable", type: TBool, defValue: true}], + ]; + + public static var eventsList:Array = defaultEventsList.copy(); + public static var eventsParams:Map> = defaultEventsParams.copy(); + + public static function getEventParams(name:String):Array { + return eventsParams.exists(name) ? eventsParams.get(name) : []; + } + + public static function reloadEvents() { + eventsList = defaultEventsList.copy(); + eventsParams = defaultEventsParams.copy(); + + var hscriptInterp:Interp = new Interp(); + hscriptInterp.variables.set("Bool", TBool); + hscriptInterp.variables.set("Int", function (?min:Int, ?max:Int, ?step:Float):EventParamType {return TInt(min, max, step);}); + hscriptInterp.variables.set("Float", function (?min:Int, ?max:Int, ?step:Float, ?precision:Int):EventParamType {return TFloat(min, max, step, precision);}); + hscriptInterp.variables.set("String", TString); + hscriptInterp.variables.set("StrumLine", TStrumLine); + + var hscriptParser:Parser = new Parser(); + hscriptParser.allowJSON = hscriptParser.allowMetadata = false; + + for (file in Paths.getFolderContent('data/events/', true, BOTH)) { + if (Path.extension(file) != "json") continue; + var eventName:String = Path.withoutExtension(Path.withoutDirectory(file)); + + eventsList.push(eventName); + eventsParams.set(eventName, []); + + var fileTxt:String = Assets.getText(file); + if (fileTxt.trim() == "") {continue;} + + try { + var data:Dynamic = Json.parse(fileTxt); + if (data == null || data.params == null) continue; + + var finalParams:Array = []; + for (paramData in cast(data.params, Array)) { + try { + finalParams.push({name: paramData.name, type: hscriptInterp.expr(hscriptParser.parseString(paramData.type)), defValue: paramData.defaultValue}); + } catch (e) {trace('Error parsing event param ${paramData.name} - ${eventName}: $e');} + } + eventsParams.set(eventName, finalParams); + } catch (e) {trace('Error parsing file $file: $e');} + } + + hscriptInterp = null; hscriptParser = null; + } +} + +typedef EventInfo = { + var params:Array; + var paramValues:Array; +} + +typedef EventParamInfo = { + var name:String; + var type:EventParamType; + var defValue:Dynamic; +} + +enum EventParamType { + TBool; + TInt(?min:Int, ?max:Int, ?step:Float); + TFloat(?min:Int, ?max:Int, ?step:Float, ?precision:Int); + TString; + TStrumLine; +} \ No newline at end of file diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 38672c56..8f0cd79f 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -61,7 +61,7 @@ class Note extends FlxSprite public var strumID(get, never):Int; private function get_strumID() { - var id = noteData % 4; + var id = noteData % strumLine.members.length; if (id < 0) id = 0; return id; } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 365eb22b..250872f6 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -1,5 +1,6 @@ package funkin.game; +import funkin.editors.charter.EventsData; import funkin.backend.system.RotatingSpriteGroup; import funkin.editors.charter.Charter; import funkin.savedata.FunkinSave; @@ -550,21 +551,22 @@ class PlayState extends MusicBeatState // dadMidpoint.put(); var camPos:FlxPoint = new FlxPoint(0, 0); - if (!chartingMode || Options.charterEnablePlaytestScripts) { switch(SONG.meta.name) { // case "": // ADD YOUR HARDCODED SCRIPTS HERE! default: - for(content in [ - Paths.getFolderContent('songs/${SONG.meta.name.toLowerCase()}/scripts', true, fromMods ? MODS : BOTH), - Paths.getFolderContent('data/charts/', true, fromMods ? MODS : BOTH)]) { - for(file in content) { - var ext = Path.extension(file).toLowerCase(); - if (Script.scriptExtensions.contains(ext)) - scripts.add(Script.create(file)); - } + function addScript(file:String) { + var ext = Path.extension(file).toLowerCase(); + if (Script.scriptExtensions.contains(ext)) + scripts.add(Script.create(file)); } + + for(content in [Paths.getFolderContent('songs/${SONG.meta.name.toLowerCase()}/scripts', true, fromMods ? MODS : BOTH), Paths.getFolderContent('data/charts/', true, fromMods ? MODS : BOTH)]) + for(file in content) addScript(file); + + for (file in Paths.getFolderContent('data/events/', true, fromMods ? MODS : BOTH)) + if (EventsData.eventsList.contains(Path.withoutExtension(Path.withoutDirectory(file)))) addScript(file); } } @@ -633,6 +635,12 @@ class PlayState extends MusicBeatState // CAMERA & HUD INITIALISATION #if REGION + + if (!scripts.event("onPreGenerateStrums", new CancellableEvent()).cancelled) { + generateStrums(); + scripts.call("onPostGenerateStrums"); + } + for(str in strumLines) str.generate(str.data, (chartingMode && Charter.startHere) ? Charter.startTime : null); @@ -659,6 +667,8 @@ class PlayState extends MusicBeatState healthBarBG.scrollFactor.set(); add(healthBarBG); + + healthBar = new FlxBar(healthBarBG.x + 4, healthBarBG.y + 4, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), this, 'health', 0, maxHealth); healthBar.scrollFactor.set(); @@ -782,11 +792,6 @@ class PlayState extends MusicBeatState if (scripts.event("onStartCountdown", new CancellableEvent()).cancelled) return; } - if (!scripts.event("onPreGenerateStrums", new CancellableEvent()).cancelled) { - generateStrums(); - scripts.call("onPostGenerateStrums"); - } - startedCountdown = true; Conductor.songPosition = 0; Conductor.songPosition -= Conductor.crochet * introLength; @@ -897,7 +902,7 @@ class PlayState extends MusicBeatState // get first camera focus for(e in events) { if (e.time > 10) break; - if (e.type == CAM_MOVEMENT) { + if (e.name == "Camera Movement") { executeEvent(e); break; } @@ -1170,24 +1175,24 @@ class PlayState extends MusicBeatState if (event == null) return; if (event.params == null) return; - switch(event.type) { - case CUSTOM: - if (event.params[0] is String && event.params[1] is Array) { - scripts.call(event.params[0], event.params[1]); + if (scripts.event("onEvent", EventManager.get(EventGameEvent).recycle(event)).cancelled) return; + + switch(event.name) { + case "HScript Call": + if (event.params[0] is String && event.params[1] is String) { + scripts.call(event.params[0], event.params[1].split(',')); } - case CAM_MOVEMENT: + case "Camera Movement": if (event.params[0] is Int) curCameraTarget = event.params[0]; - case BPM_CHANGE: - // automatically handled by conductor - case ALT_ANIM_TOGGLE: + case "BPM Change": // automatically handled by conductor + case "Alt Animation Toggle": if (event.params[0] is Int && event.params[1] is Bool) { var strLine = strumLines.members[event.params[0]]; if (strLine != null) strLine.altAnim = cast event.params[1]; } - // todo!!! - default: + case "Unknown": } } diff --git a/source/funkin/game/Strum.hx b/source/funkin/game/Strum.hx index 1e3b3d99..d4d8fe4a 100644 --- a/source/funkin/game/Strum.hx +++ b/source/funkin/game/Strum.hx @@ -9,16 +9,48 @@ class Strum extends FlxSprite { public var scrollSpeed:Null = null; // custom scroll speed per strum public var noteAngle:Null = null; - + public var lastDrawCameras(default, null):Array = []; + public var getPressed:StrumLine->Bool = null; + public var getJustPressed:StrumLine->Bool = null; + public var getJustReleased:StrumLine->Bool = null; + + public inline function __getPressed(strumLine:StrumLine):Bool { + return getPressed != null ? getPressed(strumLine) : switch(ID) { + case 0: strumLine.controls.NOTE_LEFT; + case 1: strumLine.controls.NOTE_DOWN; + case 2: strumLine.controls.NOTE_UP; + case 3: strumLine.controls.NOTE_RIGHT; + default: false; + } + } + public inline function __getJustPressed(strumLine:StrumLine) { + return getJustPressed != null ? getJustPressed(strumLine) : switch(ID) { + case 0: strumLine.controls.NOTE_LEFT_P; + case 1: strumLine.controls.NOTE_DOWN_P; + case 2: strumLine.controls.NOTE_UP_P; + case 3: strumLine.controls.NOTE_RIGHT_P; + default: false; + } + } + public inline function __getJustReleased(strumLine:StrumLine) { + return getJustReleased != null ? getJustReleased(strumLine) : switch(ID) { + case 0: strumLine.controls.NOTE_LEFT_R; + case 1: strumLine.controls.NOTE_DOWN_R; + case 2: strumLine.controls.NOTE_UP_R; + case 3: strumLine.controls.NOTE_RIGHT_R; + default: false; + } + } + public inline function getScrollSpeed(?note:Note):Float { if (note != null && note.scrollSpeed != null) return note.scrollSpeed; if (scrollSpeed != null) return scrollSpeed; if (PlayState.instance != null) return PlayState.instance.scrollSpeed; return 1; } - + public inline function getNotesAngle(?note:Note):Float { if (note != null && note.noteAngle != null) return note.noteAngle; if (noteAngle != null) return noteAngle; @@ -44,7 +76,7 @@ class Strum extends FlxSprite { public function updateNotePosition(daNote:Note) { if (!daNote.exists) return; - + daNote.__strumCameras = lastDrawCameras; daNote.__strum = this; daNote.scrollFactor.set(scrollFactor.x, scrollFactor.y); @@ -63,7 +95,7 @@ class Strum extends FlxSprite { var realOffset = FlxPoint.get(0, 0); if (daNote.isSustainNote) offset.y -= N_WIDTHDIV2; - + if (Std.int(daNote.__noteAngle % 360) != 0) { var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180); var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180); @@ -81,9 +113,9 @@ class Strum extends FlxSprite { realOffset.y = offset.y; } realOffset.y *= -1; - + daNote.setPosition(x + realOffset.x, y + realOffset.y); - + offset.put(); realOffset.put(); } diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index 3d959738..ca8ac584 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -187,11 +187,13 @@ class StrumLine extends FlxTypedGroup { __justPressed.clear(); __justReleased.clear(); - __pressed.pushGroup(controls.NOTE_LEFT, controls.NOTE_DOWN, controls.NOTE_UP, controls.NOTE_RIGHT); - __justPressed.pushGroup(controls.NOTE_LEFT_P, controls.NOTE_DOWN_P, controls.NOTE_UP_P, controls.NOTE_RIGHT_P); - __justReleased.pushGroup(controls.NOTE_LEFT_R, controls.NOTE_DOWN_R, controls.NOTE_UP_R, controls.NOTE_RIGHT_R); + for(s in members) { + __pressed.push(s.__getPressed(this)); + __justPressed.push(s.__getJustPressed(this)); + __justReleased.push(s.__getJustReleased(this)); + } - var event = PlayState.instance.scripts.event("onKeyShit", EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id)); + var event = PlayState.instance.scripts.event("onInputUpdate", EventManager.get(InputSystemEvent).recycle(__pressed, __justPressed, __justReleased, this, id)); if (event.cancelled) return; __pressed = CoolUtil.getDefault(event.pressed, []); @@ -224,68 +226,67 @@ class StrumLine extends FlxTypedGroup { for(e in __notePerStrum) if (e != null) PlayState.instance.goodNoteHit(this, e); forEach(function(str:Strum) { - str.updatePlayerInput(__pressed[str.ID], __justPressed[str.ID], __justReleased[str.ID]); + str.updatePlayerInput(str.__getPressed(this), str.__getJustPressed(this), str.__getJustReleased(this)); }); - PlayState.instance.scripts.call("onPostKeyShit"); + PlayState.instance.scripts.call("onPostInputUpdate"); } public inline function addHealth(health:Float) PlayState.instance.health += health * (opponentSide ? -1 : 1); - public function generateStrums(amount:Int = 4) { + public inline function generateStrums(amount:Int = 4) { for (i in 0...4) - { - var babyArrow:Strum = new Strum((FlxG.width * strumOffset) + (Note.swagWidth * (i - 2)), PlayState.instance.strumLine.y); - babyArrow.ID = i; + add(createStrum(i)); + } - var event = PlayState.instance.scripts.event("onStrumCreation", EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i)); - - if (!event.cancelled) { - babyArrow.frames = Paths.getFrames(event.sprite); - babyArrow.animation.addByPrefix('green', 'arrowUP'); - babyArrow.animation.addByPrefix('blue', 'arrowDOWN'); - babyArrow.animation.addByPrefix('purple', 'arrowLEFT'); - babyArrow.animation.addByPrefix('red', 'arrowRIGHT'); - - babyArrow.antialiasing = true; - babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7)); - - switch (babyArrow.ID % 4) - { - case 0: - babyArrow.animation.addByPrefix('static', 'arrowLEFT'); - babyArrow.animation.addByPrefix('pressed', 'left press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'left confirm', 24, false); - case 1: - babyArrow.animation.addByPrefix('static', 'arrowDOWN'); - babyArrow.animation.addByPrefix('pressed', 'down press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'down confirm', 24, false); - case 2: - babyArrow.animation.addByPrefix('static', 'arrowUP'); - babyArrow.animation.addByPrefix('pressed', 'up press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'up confirm', 24, false); - case 3: - babyArrow.animation.addByPrefix('static', 'arrowRIGHT'); - babyArrow.animation.addByPrefix('pressed', 'right press', 24, false); - babyArrow.animation.addByPrefix('confirm', 'right confirm', 24, false); - } + /** + * Creates a strum and returns the created strum (needs to be added manually). + * @param i Index of the strum + * @param animPrefix (Optional) Animation prefix (`left` = `arrowLEFT`, `left press`, `left confirm`). + */ + public function createStrum(i:Int, ?animPrefix:String) { + if (animPrefix == null) + animPrefix = switch(i % 4) { + case 0: "left"; + case 1: "down"; + case 2: "up"; + case 3: "right"; + case _: "up"; } + var babyArrow:Strum = new Strum((FlxG.width * strumOffset) + (Note.swagWidth * (i - 2)), PlayState.instance.strumLine.y); + babyArrow.ID = i; - babyArrow.cpu = cpu; - babyArrow.updateHitbox(); - babyArrow.scrollFactor.set(); + var event = PlayState.instance.scripts.event("onStrumCreation", EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix)); - if (event.__doAnimation) - { - babyArrow.y -= 10; - babyArrow.alpha = 0; - FlxTween.tween(babyArrow, {y: babyArrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)}); - } + if (!event.cancelled) { + babyArrow.frames = Paths.getFrames(event.sprite); + babyArrow.animation.addByPrefix('green', 'arrowUP'); + babyArrow.animation.addByPrefix('blue', 'arrowDOWN'); + babyArrow.animation.addByPrefix('purple', 'arrowLEFT'); + babyArrow.animation.addByPrefix('red', 'arrowRIGHT'); - add(babyArrow); + babyArrow.antialiasing = true; + babyArrow.setGraphicSize(Std.int(babyArrow.width * 0.7)); - babyArrow.playAnim('static'); + babyArrow.animation.addByPrefix('static', 'arrow${event.animPrefix.toUpperCase()}'); + babyArrow.animation.addByPrefix('pressed', '${event.animPrefix} press', 24, false); + babyArrow.animation.addByPrefix('confirm', '${event.animPrefix} confirm', 24, false); } + + babyArrow.cpu = cpu; + babyArrow.updateHitbox(); + babyArrow.scrollFactor.set(); + + if (event.__doAnimation) + { + babyArrow.y -= 10; + babyArrow.alpha = 0; + FlxTween.tween(babyArrow, {y: babyArrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * i)}); + } + babyArrow.playAnim('static'); + + insert(i, babyArrow); + return babyArrow; } /**