From 7ce3eabd17eb918ce326cf401e1e43cd80f62084 Mon Sep 17 00:00:00 2001 From: Sword352 <sword352email@gmail.com> Date: Wed, 8 May 2024 07:35:46 +0200 Subject: [PATCH 01/29] Better character animation offsets handling. --- source/funkin/play/character/BaseCharacter.hx | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index 2796f8123..cb9d5ae3f 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -1,6 +1,7 @@ package funkin.play.character; import flixel.math.FlxPoint; +import flixel.FlxCamera; import funkin.modding.events.ScriptEvent; import funkin.play.character.CharacterData.CharacterDataParser; import funkin.play.character.CharacterData.CharacterRenderType; @@ -118,19 +119,17 @@ class BaseCharacter extends Bopper */ public var cameraFocusPoint(default, null):FlxPoint = new FlxPoint(0, 0); + /** + * Defines the animation offset. + */ + public var animOffset:FlxPoint = FlxPoint.get(); + override function set_animOffsets(value:Array<Float>):Array<Float> { if (animOffsets == null) value = [0, 0]; if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; - // Make sure animOffets are halved when scale is 0.5. - var xDiff = (animOffsets[0] * this.scale.x / (this.isPixel ? 6 : 1)) - value[0]; - var yDiff = (animOffsets[1] * this.scale.y / (this.isPixel ? 6 : 1)) - value[1]; - - // Call the super function so that camera focus point is not affected. - super.set_x(this.x + xDiff); - super.set_y(this.y + yDiff); - + animOffset.set(value[0], value[1]); return animOffsets = value; } @@ -570,11 +569,25 @@ class BaseCharacter extends Bopper } } + // override getScreenPosition (used by FlxSprite's draw method) to account for animation offsets. + override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint + { + var output:FlxPoint = super.getScreenPosition(result, camera); + output -= animOffset; + return output; + } + public override function onDestroy(event:ScriptEvent):Void { this.characterType = OTHER; } + override function destroy():Void + { + animOffset = flixel.util.FlxDestroyUtil.put(animOffset); + super.destroy(); + } + /** * Play the appropriate singing animation, for the given note direction. * @param dir The direction of the note. From dd86934712276f136193033237cb15095cc0e787 Mon Sep 17 00:00:00 2001 From: Sword352 <sword352email@gmail.com> Date: Wed, 8 May 2024 09:22:49 +0200 Subject: [PATCH 02/29] did the requested changes --- source/funkin/play/character/BaseCharacter.hx | 29 ------------------- source/funkin/play/stage/Bopper.hx | 27 +++++++++++++---- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index cb9d5ae3f..eee7d15a2 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -1,7 +1,6 @@ package funkin.play.character; import flixel.math.FlxPoint; -import flixel.FlxCamera; import funkin.modding.events.ScriptEvent; import funkin.play.character.CharacterData.CharacterDataParser; import funkin.play.character.CharacterData.CharacterRenderType; @@ -119,20 +118,6 @@ class BaseCharacter extends Bopper */ public var cameraFocusPoint(default, null):FlxPoint = new FlxPoint(0, 0); - /** - * Defines the animation offset. - */ - public var animOffset:FlxPoint = FlxPoint.get(); - - override function set_animOffsets(value:Array<Float>):Array<Float> - { - if (animOffsets == null) value = [0, 0]; - if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; - - animOffset.set(value[0], value[1]); - return animOffsets = value; - } - /** * If the x position changes, other than via changing the animation offset, * then we need to update the camera focus point. @@ -569,25 +554,11 @@ class BaseCharacter extends Bopper } } - // override getScreenPosition (used by FlxSprite's draw method) to account for animation offsets. - override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint - { - var output:FlxPoint = super.getScreenPosition(result, camera); - output -= animOffset; - return output; - } - public override function onDestroy(event:ScriptEvent):Void { this.characterType = OTHER; } - override function destroy():Void - { - animOffset = flixel.util.FlxDestroyUtil.put(animOffset); - super.destroy(); - } - /** * Play the appropriate singing animation, for the given note direction. * @param dir The direction of the note. diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index 262aff7bc..141a85c8f 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -1,6 +1,7 @@ package funkin.play.stage; import flixel.FlxSprite; +import flixel.FlxCamera; import flixel.math.FlxPoint; import flixel.util.FlxTimer; import funkin.modding.IScriptedClass.IPlayStateScriptedClass; @@ -67,6 +68,11 @@ class Bopper extends StageProp implements IPlayStateScriptedClass return value; } + /** + * Internally used to define the animation offsets to apply. + */ + var _currentAnimOffset:FlxPoint = FlxPoint.get(); + /** * The offset of the character relative to the position specified by the stage. */ @@ -95,12 +101,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass if (animOffsets == null) animOffsets = [0, 0]; if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; - var xDiff = animOffsets[0] - value[0]; - var yDiff = animOffsets[1] - value[1]; - - this.x += xDiff; - this.y += yDiff; - + _currentAnimOffset.set(value[0], value[1]); return animOffsets = value; } @@ -349,6 +350,20 @@ class Bopper extends StageProp implements IPlayStateScriptedClass return this.animation.curAnim.name; } + // override getScreenPosition (used by FlxSprite's draw method) to account for animation offsets. + override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint + { + var output:FlxPoint = super.getScreenPosition(result, camera); + output -= _currentAnimOffset; + return output; + } + + override function destroy():Void + { + _currentAnimOffset = flixel.util.FlxDestroyUtil.put(_currentAnimOffset); + super.destroy(); + } + public function onPause(event:PauseScriptEvent) {} public function onResume(event:ScriptEvent) {} From f6334fb30b12b44635a9574587f7689d2f3beb28 Mon Sep 17 00:00:00 2001 From: Sword352 <sword352email@gmail.com> Date: Wed, 8 May 2024 22:18:41 +0200 Subject: [PATCH 03/29] Use `animOffsets` directly. --- source/funkin/play/stage/Bopper.hx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index 141a85c8f..5485edb3e 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -68,11 +68,6 @@ class Bopper extends StageProp implements IPlayStateScriptedClass return value; } - /** - * Internally used to define the animation offsets to apply. - */ - var _currentAnimOffset:FlxPoint = FlxPoint.get(); - /** * The offset of the character relative to the position specified by the stage. */ @@ -101,7 +96,6 @@ class Bopper extends StageProp implements IPlayStateScriptedClass if (animOffsets == null) animOffsets = [0, 0]; if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; - _currentAnimOffset.set(value[0], value[1]); return animOffsets = value; } @@ -354,16 +348,11 @@ class Bopper extends StageProp implements IPlayStateScriptedClass override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint { var output:FlxPoint = super.getScreenPosition(result, camera); - output -= _currentAnimOffset; + output.x -= animOffsets[0]; + output.y -= animOffsets[1]; return output; } - override function destroy():Void - { - _currentAnimOffset = flixel.util.FlxDestroyUtil.put(_currentAnimOffset); - super.destroy(); - } - public function onPause(event:PauseScriptEvent) {} public function onResume(event:ScriptEvent) {} From 2916bd6ff7ec9f1e136d84323d8880ca009a3f4e Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Fri, 14 Jun 2024 21:52:52 -0700 Subject: [PATCH 04/29] Reorder download Git step in compiling guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved “download Git” from the middle of the guide to the setup step Should prevent errors with Git before installing Git --- docs/COMPILING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index e7c19875a..b8ddee4a7 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -2,14 +2,14 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) + - Download Git from [git-scm.com](https://www.git-scm.com) 1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. 2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Download Git from [git-scm.com](https://www.git-scm.com) -4. Install all haxelibs of the current branch by running `hmm install` -5. Setup lime: `haxelib run lime setup` -6. Platform setup +3. Install all haxelibs of the current branch by running `hmm install` +4. Setup lime: `haxelib run lime setup` +5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: - MSVC v143 VS 2022 C++ x64/x86 build tools @@ -17,8 +17,8 @@ - Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/) - Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/) - HTML5: Compiles without any extra setup -7. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` -8. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). +6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug` +7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State). # Troubleshooting From 9fb4a8719a6cd07aa2af2638adc494786ca5425e Mon Sep 17 00:00:00 2001 From: Hundrec <hundrecard@gmail.com> Date: Sat, 15 Jun 2024 13:37:21 -0400 Subject: [PATCH 05/29] Add ZIP button warning and restructured sentences Each step should be easier to follow with this structure --- docs/COMPILING.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b8ddee4a7..b2a106c86 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -3,12 +3,13 @@ 0. Setup - Download Haxe from [Haxe.org](https://haxe.org) - Download Git from [git-scm.com](https://www.git-scm.com) -1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo: - - `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` - - If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way. -2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`) -3. Install all haxelibs of the current branch by running `hmm install` -4. Setup lime: `haxelib run lime setup` + - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! + - Instead, open a command prompt and do the following steps... +1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule + - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json +3. Run `hmm install` to install all haxelibs of the current branch +4. Run `haxelib run lime setup` to set up lime 5. Platform setup - For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) - When prompted, select "Individual Components" and make sure to download the following: From 841a61408c13ff34760a448c588e35bc3b203bf0 Mon Sep 17 00:00:00 2001 From: Eric <ericmyllyoja@gmail.com> Date: Sun, 16 Jun 2024 18:48:01 -0400 Subject: [PATCH 06/29] Make downloading the assets submodule a separate step. --- docs/COMPILING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/COMPILING.md b/docs/COMPILING.md index b2a106c86..cc90bd348 100644 --- a/docs/COMPILING.md +++ b/docs/COMPILING.md @@ -5,8 +5,9 @@ - Download Git from [git-scm.com](https://www.git-scm.com) - Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors! - Instead, open a command prompt and do the following steps... -1. Run `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git` to clone the repository with the necessary assets submodule - - _If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way._ +1. Run `git clone https://github.com/FunkinCrew/funkin.git` to clone the base repository. +2. Run `git submodule update --init --recursive` to download the game's assets. + - NOTE: By performing this operation, you are downloading Content which is proprietary and protected by national and international copyright and trademark laws. See [the LICENSE.md file for the Funkin.assets](https://github.com/FunkinCrew/funkin.assets/blob/main/LICENSE.md) repo for more information. 2. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json 3. Run `hmm install` to install all haxelibs of the current branch 4. Run `haxelib run lime setup` to set up lime From 8a4f19d603b5900692c8c646c05e8b409688e963 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Tue, 25 Jun 2024 18:22:30 -0400 Subject: [PATCH 07/29] Add change counts labels to Actions labeler --- .github/changed-lines-count-labeler.yml | 12 ++++++++++++ .github/workflows/labeler.yml | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .github/changed-lines-count-labeler.yml diff --git a/.github/changed-lines-count-labeler.yml b/.github/changed-lines-count-labeler.yml new file mode 100644 index 000000000..6f890f534 --- /dev/null +++ b/.github/changed-lines-count-labeler.yml @@ -0,0 +1,12 @@ +# Add 'small' to any changes below 10 lines +small: + max: 9 + +# Add 'medium' to any changes between 10 and 100 lines +medium: + min: 10 + max: 99 + +# Add 'large' to any changes for more than 100 lines +large: + min: 100 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 0bcc420d3..a861af578 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,19 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - name: Set basic labels + uses: actions/labeler@v5 with: sync-labels: true + changed-lines-count-labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + name: An action for automatically labelling pull requests based on the changed lines count + steps: + - name: Set change count labels + uses: vkirilichev/changed-lines-count-labeler@v0.2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + configuration-path: .github/changed-lines-count-labeler.yml From fbc78adb65c7db8b045f1ea5d6599ae7348912a0 Mon Sep 17 00:00:00 2001 From: FlooferLand! <76737186+FlooferLand@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:42:50 +0300 Subject: [PATCH 08/29] Added new settings items --- source/funkin/ui/options/MenuItemEnums.hx | 10 ++ source/funkin/ui/options/PreferencesMenu.hx | 149 +++++++++++------- .../options/items/CheckboxPreferenceItem.hx | 49 ++++++ .../ui/options/items/EnumPreferenceItem.hx | 84 ++++++++++ .../ui/options/items/NumberPreferenceItem.hx | 136 ++++++++++++++++ 5 files changed, 372 insertions(+), 56 deletions(-) create mode 100644 source/funkin/ui/options/MenuItemEnums.hx create mode 100644 source/funkin/ui/options/items/CheckboxPreferenceItem.hx create mode 100644 source/funkin/ui/options/items/EnumPreferenceItem.hx create mode 100644 source/funkin/ui/options/items/NumberPreferenceItem.hx diff --git a/source/funkin/ui/options/MenuItemEnums.hx b/source/funkin/ui/options/MenuItemEnums.hx new file mode 100644 index 000000000..4513a92af --- /dev/null +++ b/source/funkin/ui/options/MenuItemEnums.hx @@ -0,0 +1,10 @@ +package funkin.ui.options; + +// Add enums for use with `EnumPreferenceItem` here! +/* Example: + class MyOptionEnum + { + public static inline var YuhUh = "true"; // "true" is the value's ID + public static inline var NuhUh = "false"; + } + */ diff --git a/source/funkin/ui/options/PreferencesMenu.hx b/source/funkin/ui/options/PreferencesMenu.hx index 783aef0ba..5fbefceed 100644 --- a/source/funkin/ui/options/PreferencesMenu.hx +++ b/source/funkin/ui/options/PreferencesMenu.hx @@ -8,6 +8,11 @@ import funkin.ui.AtlasText.AtlasFont; import funkin.ui.options.OptionsState.Page; import funkin.graphics.FunkinCamera; import funkin.ui.TextMenuList.TextMenuItem; +import funkin.audio.FunkinSound; +import funkin.ui.options.MenuItemEnums; +import funkin.ui.options.items.CheckboxPreferenceItem; +import funkin.ui.options.items.NumberPreferenceItem; +import funkin.ui.options.items.EnumPreferenceItem; class PreferencesMenu extends Page { @@ -69,11 +74,51 @@ class PreferencesMenu extends Page }, Preferences.autoPause); } + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // Indent the selected item. + items.forEach(function(daItem:TextMenuItem) { + var thyOffset:Int = 0; + + // Initializing thy text width (if thou text present) + var thyTextWidth:Int = 0; + if (Std.isOfType(daItem, EnumPreferenceItem)) thyTextWidth = cast(daItem, EnumPreferenceItem).lefthandText.getWidth(); + else if (Std.isOfType(daItem, NumberPreferenceItem)) thyTextWidth = cast(daItem, NumberPreferenceItem).lefthandText.getWidth(); + + if (thyTextWidth != 0) + { + // Magic number because of the weird offset thats being added by default + thyOffset += thyTextWidth - 75; + } + + if (items.selectedItem == daItem) + { + thyOffset += 150; + } + else + { + thyOffset += 120; + } + + daItem.x = thyOffset; + }); + } + + // - Preference item creation methods - + // Should be moved into a separate PreferenceItems class but you can't access PreferencesMenu.items and PreferencesMenu.preferenceItems from outside. + + /** + * Creates a pref item that works with booleans + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + */ function createPrefItemCheckbox(prefName:String, prefDesc:String, onChange:Bool->Void, defaultValue:Bool):Void { var checkbox:CheckboxPreferenceItem = new CheckboxPreferenceItem(0, 120 * (items.length - 1 + 1), defaultValue); - items.createItem(120, (120 * items.length) + 30, prefName, AtlasFont.BOLD, function() { + items.createItem(0, (120 * items.length) + 30, prefName, AtlasFont.BOLD, function() { var value = !checkbox.currentValue; onChange(value); checkbox.currentValue = value; @@ -82,62 +127,54 @@ class PreferencesMenu extends Page preferenceItems.add(checkbox); } - override function update(elapsed:Float) + /** + * Creates a pref item that works with general numbers + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param valueFormatter Will get called every time the game needs to display the float value; use this to change how the displayed value looks + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + * @param min Minimum value (example: 0) + * @param max Maximum value (example: 10) + * @param step The value to increment/decrement by (default = 0.1) + * @param precision Rounds decimals up to a `precision` amount of digits (ex: 4 -> 0.1234, 2 -> 0.12) + */ + function createPrefItemNumber(prefName:String, prefDesc:String, onChange:Float->Void, ?valueFormatter:Float->String, defaultValue:Int, min:Int, max:Int, + step:Float = 0.1, precision:Int):Void { - super.update(elapsed); + var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, step, precision, onChange, valueFormatter); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); + } - // Indent the selected item. - // TODO: Only do this on menu change? - items.forEach(function(daItem:TextMenuItem) { - if (items.selectedItem == daItem) daItem.x = 150; - else - daItem.x = 120; - }); - } -} - -class CheckboxPreferenceItem extends FlxSprite -{ - public var currentValue(default, set):Bool; - - public function new(x:Float, y:Float, defaultValue:Bool = false) - { - super(x, y); - - frames = Paths.getSparrowAtlas('checkboxThingie'); - animation.addByPrefix('static', 'Check Box unselected', 24, false); - animation.addByPrefix('checked', 'Check Box selecting animation', 24, false); - - setGraphicSize(Std.int(width * 0.7)); - updateHitbox(); - - this.currentValue = defaultValue; - } - - override function update(elapsed:Float) - { - super.update(elapsed); - - switch (animation.curAnim.name) - { - case 'static': - offset.set(); - case 'checked': - offset.set(17, 70); - } - } - - function set_currentValue(value:Bool):Bool - { - if (value) - { - animation.play('checked', true); - } - else - { - animation.play('static'); - } - - return currentValue = value; + /** + * Creates a pref item that works with number percentages + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + * @param min Minimum value (default = 0) + * @param max Maximum value (default = 100) + */ + function createPrefItemPercentage(prefName:String, prefDesc:String, onChange:Int->Void, defaultValue:Int, min:Int = 0, max:Int = 100):Void + { + var newCallback = function(value:Float) { + onChange(Std.int(value)); + }; + var formatter = function(value:Float) { + return '${value}%'; + }; + var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, 10, 0, newCallback, formatter); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); + } + + /** + * Creates a pref item that works with enums + * @param values Maps enum values to display strings _(ex: `NoteHitSoundType.PingPong => "Ping pong"`)_ + * @param onChange Gets called every time the player changes the value; use this to apply the value + * @param defaultValue The value that is loaded in when the pref item is created (usually your Preferences.settingVariable) + */ + function createPrefItemEnum(prefName:String, prefDesc:String, values:Map<String, String>, onChange:String->Void, defaultValue:String):Void + { + var item = new EnumPreferenceItem(0, (120 * items.length) + 30, prefName, values, defaultValue, onChange); + items.addItem(prefName, item); + preferenceItems.add(item.lefthandText); } } diff --git a/source/funkin/ui/options/items/CheckboxPreferenceItem.hx b/source/funkin/ui/options/items/CheckboxPreferenceItem.hx new file mode 100644 index 000000000..88c4fb6b0 --- /dev/null +++ b/source/funkin/ui/options/items/CheckboxPreferenceItem.hx @@ -0,0 +1,49 @@ +package funkin.ui.options.items; + +import flixel.FlxSprite.FlxSprite; + +class CheckboxPreferenceItem extends FlxSprite +{ + public var currentValue(default, set):Bool; + + public function new(x:Float, y:Float, defaultValue:Bool = false) + { + super(x, y); + + frames = Paths.getSparrowAtlas('checkboxThingie'); + animation.addByPrefix('static', 'Check Box unselected', 24, false); + animation.addByPrefix('checked', 'Check Box selecting animation', 24, false); + + setGraphicSize(Std.int(width * 0.7)); + updateHitbox(); + + this.currentValue = defaultValue; + } + + override function update(elapsed:Float) + { + super.update(elapsed); + + switch (animation.curAnim.name) + { + case 'static': + offset.set(); + case 'checked': + offset.set(17, 70); + } + } + + function set_currentValue(value:Bool):Bool + { + if (value) + { + animation.play('checked', true); + } + else + { + animation.play('static'); + } + + return currentValue = value; + } +} diff --git a/source/funkin/ui/options/items/EnumPreferenceItem.hx b/source/funkin/ui/options/items/EnumPreferenceItem.hx new file mode 100644 index 000000000..02a273353 --- /dev/null +++ b/source/funkin/ui/options/items/EnumPreferenceItem.hx @@ -0,0 +1,84 @@ +package funkin.ui.options.items; + +import funkin.ui.TextMenuList; +import funkin.ui.AtlasText; +import funkin.input.Controls; +import funkin.ui.options.MenuItemEnums; +import haxe.EnumTools; + +/** + * Preference item that allows the player to pick a value from an enum (list of values) + */ +class EnumPreferenceItem extends TextMenuItem +{ + function controls():Controls + { + return PlayerSettings.player1.controls; + } + + public var lefthandText:AtlasText; + + public var currentValue:String; + public var onChangeCallback:Null<String->Void>; + public var map:Map<String, String>; + public var keys:Array<String> = []; + + var index = 0; + + public function new(x:Float, y:Float, name:String, map:Map<String, String>, defaultValue:String, ?callback:String->Void) + { + super(x, y, name, function() { + callback(this.currentValue); + }); + + updateHitbox(); + + this.map = map; + this.currentValue = defaultValue; + this.onChangeCallback = callback; + + var i:Int = 0; + for (key in map.keys()) + { + this.keys.push(key); + if (this.currentValue == key) index = i; + i += 1; + } + + lefthandText = new AtlasText(15, y, formatted(defaultValue), AtlasFont.DEFAULT); + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // var fancyTextFancyColor:Color; + if (selected) + { + var shouldDecrease:Bool = controls().UI_LEFT_P; + var shouldIncrease:Bool = controls().UI_RIGHT_P; + + if (shouldDecrease) index -= 1; + if (shouldIncrease) index += 1; + + if (index > keys.length - 1) index = 0; + if (index < 0) index = keys.length - 1; + + currentValue = keys[index]; + if (onChangeCallback != null && (shouldIncrease || shouldDecrease)) + { + onChangeCallback(currentValue); + } + } + + lefthandText.text = formatted(currentValue); + } + + function formatted(value:String):String + { + // FIXME: Can't add arrows around the text because the font doesn't support < > + // var leftArrow:String = selected ? '<' : ''; + // var rightArrow:String = selected ? '>' : ''; + return '${map.get(value) ?? value}'; + } +} diff --git a/source/funkin/ui/options/items/NumberPreferenceItem.hx b/source/funkin/ui/options/items/NumberPreferenceItem.hx new file mode 100644 index 000000000..f3cd3cd46 --- /dev/null +++ b/source/funkin/ui/options/items/NumberPreferenceItem.hx @@ -0,0 +1,136 @@ +package funkin.ui.options.items; + +import funkin.ui.TextMenuList; +import funkin.ui.AtlasText; +import funkin.input.Controls; + +/** + * Preference item that allows the player to pick a value between min and max + */ +class NumberPreferenceItem extends TextMenuItem +{ + function controls():Controls + { + return PlayerSettings.player1.controls; + } + + // Widgets + public var lefthandText:AtlasText; + + // Constants + static final HOLD_DELAY:Float = 0.3; // seconds + static final CHANGE_RATE:Float = 0.08; // seconds + + // Constructor-initialized variables + public var currentValue:Float; + public var min:Float; + public var max:Float; + public var step:Float; + public var precision:Int; + public var onChangeCallback:Null<Float->Void>; + public var valueFormatter:Null<Float->String>; + + // Variables + var holdDelayTimer:Float = HOLD_DELAY; // seconds + var changeRateTimer:Float = 0.0; // seconds + + /** + * @param min Minimum value (example: 0) + * @param max Maximum value (example: 100) + * @param step The value to increment/decrement by (example: 10) + * @param callback Will get called every time the user changes the setting; use this to apply/save the setting. + * @param valueFormatter Will get called every time the game needs to display the float value; use this to change how the displayed string looks + */ + public function new(x:Float, y:Float, name:String, defaultValue:Float, min:Float, max:Float, step:Float, precision:Int, ?callback:Float->Void, + ?valueFormatter:Float->String):Void + { + super(x, y, name, function() { + callback(this.currentValue); + }); + lefthandText = new AtlasText(15, y, formatted(defaultValue), AtlasFont.DEFAULT); + + updateHitbox(); + + this.currentValue = defaultValue; + this.min = min; + this.max = max; + this.step = step; + this.precision = precision; + this.onChangeCallback = callback; + this.valueFormatter = valueFormatter; + } + + override function update(elapsed:Float):Void + { + super.update(elapsed); + + // var fancyTextFancyColor:Color; + if (selected) + { + holdDelayTimer -= elapsed; + if (holdDelayTimer <= 0.0) + { + changeRateTimer -= elapsed; + } + + var jpLeft:Bool = controls().UI_LEFT_P; + var jpRight:Bool = controls().UI_RIGHT_P; + + if (jpLeft || jpRight) + { + holdDelayTimer = HOLD_DELAY; + changeRateTimer = 0.0; + } + + var shouldDecrease:Bool = jpLeft; + var shouldIncrease:Bool = jpRight; + + if (controls().UI_LEFT && holdDelayTimer <= 0.0 && changeRateTimer <= 0.0) + { + shouldDecrease = true; + changeRateTimer = CHANGE_RATE; + } + else if (controls().UI_RIGHT && holdDelayTimer <= 0.0 && changeRateTimer <= 0.0) + { + shouldIncrease = true; + changeRateTimer = CHANGE_RATE; + } + + // Actually increasing/decreasing the value + if (shouldDecrease) + { + var isBelowMin:Bool = currentValue - step < min; + currentValue = (currentValue - step).clamp(min, max); + if (onChangeCallback != null && !isBelowMin) onChangeCallback(currentValue); + } + else if (shouldIncrease) + { + var isAboveMax:Bool = currentValue + step > max; + currentValue = (currentValue + step).clamp(min, max); + if (onChangeCallback != null && !isAboveMax) onChangeCallback(currentValue); + } + } + + lefthandText.text = formatted(currentValue); + } + + /** Turns the float into a string */ + function formatted(value:Float):String + { + var float:Float = toFixed(value); + if (valueFormatter != null) + { + return valueFormatter(float); + } + else + { + return '${float}'; + } + } + + function toFixed(value:Float):Float + { + var multiplier:Float = Math.pow(10, precision); + return Math.floor(value * multiplier) / multiplier; + } +} From cd08116aed64f4761087e287a00786b77f40d02b Mon Sep 17 00:00:00 2001 From: FlooferLand! <76737186+FlooferLand@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:44:23 +0300 Subject: [PATCH 09/29] Added getWidth --- source/funkin/ui/AtlasText.hx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source/funkin/ui/AtlasText.hx b/source/funkin/ui/AtlasText.hx index 186d87c2a..ef74abc1e 100644 --- a/source/funkin/ui/AtlasText.hx +++ b/source/funkin/ui/AtlasText.hx @@ -152,6 +152,32 @@ class AtlasText extends FlxTypedSpriteGroup<AtlasChar> } } + public function getWidth():Int + { + var width = 0; + for (char in this.text.split("")) + { + switch (char) + { + case " ": + { + width += 40; + } + case "\n": + {} + case char: + { + var sprite = new AtlasChar(atlas, char); + sprite.revive(); + sprite.char = char; + sprite.alpha = 1; + width += Std.int(sprite.width); + } + } + } + return width; + } + override function toString() { return "InputItem, " + FlxStringUtil.getDebugString([ From 6116ec3639b3720c3b2453be6a76adaa6998e447 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 12 Jul 2024 22:31:04 -0400 Subject: [PATCH 10/29] Some more fixes for offsets handling and stuffs --- source/funkin/play/PauseSubState.hx | 2 +- source/funkin/play/song/Song.hx | 3 ++- source/funkin/play/stage/Bopper.hx | 18 +++--------------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx index d0c759b16..6f8908eea 100644 --- a/source/funkin/play/PauseSubState.hx +++ b/source/funkin/play/PauseSubState.hx @@ -306,7 +306,7 @@ class PauseSubState extends MusicBeatSubState metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT); if (PlayState.instance?.currentDifficulty != null) { - metadataDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase(); + metadataDifficulty.text += PlayState.instance.currentDifficulty.replace('-', ' ').toTitleCase(); } metadataDifficulty.scrollFactor.set(0, 0); metadata.add(metadataDifficulty); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 91d35d8fa..4e9f70920 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -277,7 +277,8 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta // If there are no difficulties in the metadata, there's a problem. if (metadata.playData.difficulties.length == 0) { - throw 'Song $id has no difficulties listed in metadata!'; + trace('[SONG] Warning: Song $id (variation ${metadata.variation}) has no difficulties listed in metadata!'); + continue; } // There may be more difficulties in the chart file than in the metadata, diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index ec7e77a86..de19c51b4 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -80,11 +80,6 @@ class Bopper extends StageProp implements IPlayStateScriptedClass if (globalOffsets == null) globalOffsets = [0, 0]; if (globalOffsets == value) return value; - var xDiff = globalOffsets[0] - value[0]; - var yDiff = globalOffsets[1] - value[1]; - - this.x += xDiff; - this.y += yDiff; return globalOffsets = value; } @@ -315,14 +310,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass function applyAnimationOffsets(name:String):Void { var offsets = animationOffsets.get(name); - if (offsets != null && !(offsets[0] == 0 && offsets[1] == 0)) - { - this.animOffsets = [offsets[0] + globalOffsets[0], offsets[1] + globalOffsets[1]]; - } - else - { - this.animOffsets = globalOffsets; - } + this.animOffsets = offsets; } public function isAnimationFinished():Bool @@ -350,8 +338,8 @@ class Bopper extends StageProp implements IPlayStateScriptedClass override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint { var output:FlxPoint = super.getScreenPosition(result, camera); - output.x -= animOffsets[0]; - output.y -= animOffsets[1]; + output.x -= (animOffsets[0] - globalOffsets[0]) * this.scale.x; + output.y -= (animOffsets[1] - globalOffsets[1]) * this.scale.y; return output; } From 73fc855f8e6eb8efb14e7ab7d35ff269e76287f2 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Thu, 18 Jul 2024 05:23:31 +0100 Subject: [PATCH 11/29] new stage names --- source/funkin/data/stage/StageRegistry.hx | 4 ++-- source/funkin/ui/debug/charting/ChartEditorState.hx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/funkin/data/stage/StageRegistry.hx b/source/funkin/data/stage/StageRegistry.hx index a03371296..fbb6f188e 100644 --- a/source/funkin/data/stage/StageRegistry.hx +++ b/source/funkin/data/stage/StageRegistry.hx @@ -93,8 +93,8 @@ class StageRegistry extends BaseRegistry<Stage, StageData> public function listBaseGameStageIds():Array<String> { return [ - "mainStage", "spookyMansion", "phillyTrain", "limoRide", "mallXmas", "mallEvil", "school", "schoolEvil", "tankmanBattlefield", "phillyStreets", - "phillyBlazin", + "mainStage", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "mallXmas", "mallEvil", "school", "schoolEvil", "tankmanBattlefield", + "phillyStreets", "phillyBlazin", ]; } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index f72cca77f..a4e0de61e 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -5703,9 +5703,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { case 'mainStage': PlayStatePlaylist.campaignId = 'week1'; - case 'spookyMansion': + case 'spookyMansion' | 'spookyMansionErect': PlayStatePlaylist.campaignId = 'week2'; - case 'phillyTrain': + case 'phillyTrain' | 'phillyTrainErect': PlayStatePlaylist.campaignId = 'week3'; case 'limoRide': PlayStatePlaylist.campaignId = 'week4'; From ad93706b1df16f8191e839b6920da4e5e316c071 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Thu, 18 Jul 2024 05:23:37 +0100 Subject: [PATCH 12/29] adjust color shader --- .../graphics/shaders/AdjustColorShader.hx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 source/funkin/graphics/shaders/AdjustColorShader.hx diff --git a/source/funkin/graphics/shaders/AdjustColorShader.hx b/source/funkin/graphics/shaders/AdjustColorShader.hx new file mode 100644 index 000000000..2b0970eeb --- /dev/null +++ b/source/funkin/graphics/shaders/AdjustColorShader.hx @@ -0,0 +1,55 @@ +package funkin.graphics.shaders; + +import flixel.addons.display.FlxRuntimeShader; +import funkin.Paths; +import openfl.utils.Assets; + +class AdjustColorShader extends FlxRuntimeShader +{ + public var hue(default, set):Float; + public var saturation(default, set):Float; + public var brightness(default, set):Float; + public var contrast(default, set):Float; + + public function new() + { + super(Assets.getText(Paths.frag('adjustColor'))); + // FlxG.debugger.addTrackerProfile(new TrackerProfile(HSVShader, ['hue', 'saturation', 'brightness', 'contrast'])); + hue = 0; + saturation = 0; + brightness = 0; + contrast = 0; + } + + function set_hue(value:Float):Float + { + this.setFloat('hue', value); + this.hue = value; + + return this.hue; + } + + function set_saturation(value:Float):Float + { + this.setFloat('saturation', value); + this.saturation = value; + + return this.saturation; + } + + function set_brightness(value:Float):Float + { + this.setFloat('brightness', value); + this.brightness = value; + + return this.brightness; + } + + function set_contrast(value:Float):Float + { + this.setFloat('contrast', value); + this.contrast = value; + + return this.contrast; + } +} From 4bcfbc957f82726973b4aa1428b285d1132a19e7 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Thu, 18 Jul 2024 05:24:15 +0100 Subject: [PATCH 13/29] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 005c96f85..68bf145d5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 005c96f85f4304865acb196e7cc4d6d83f9d76d8 +Subproject commit 68bf145d5786b2c3e4539a46727da67bef1fd039 From a0ab216617b16d87ed363a590979b4cdc8879012 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Thu, 18 Jul 2024 06:04:19 +0100 Subject: [PATCH 14/29] merged rain shader stuff from 'feature/week2-erect-bg-rain' --- .../shaders/RuntimePostEffectShader.hx | 31 +++++++++++++++++++ .../graphics/shaders/RuntimeRainShader.hx | 8 +++++ 2 files changed, 39 insertions(+) diff --git a/source/funkin/graphics/shaders/RuntimePostEffectShader.hx b/source/funkin/graphics/shaders/RuntimePostEffectShader.hx index 9f49da075..d39f57efe 100644 --- a/source/funkin/graphics/shaders/RuntimePostEffectShader.hx +++ b/source/funkin/graphics/shaders/RuntimePostEffectShader.hx @@ -2,6 +2,7 @@ package funkin.graphics.shaders; import flixel.FlxCamera; import flixel.FlxG; +import flixel.graphics.frames.FlxFrame; import flixel.addons.display.FlxRuntimeShader; import lime.graphics.opengl.GLProgram; import lime.utils.Log; @@ -32,6 +33,9 @@ class RuntimePostEffectShader extends FlxRuntimeShader // equals (camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom) uniform vec4 uCameraBounds; + // equals (frame.left, frame.top, frame.right, frame.bottom) + uniform vec4 uFrameBounds; + // screen coord -> world coord conversion // returns world coord in px vec2 screenToWorld(vec2 screenCoord) { @@ -56,6 +60,25 @@ class RuntimePostEffectShader extends FlxRuntimeShader return (worldCoord - offset) / scale; } + // screen coord -> frame coord conversion + // returns normalized frame coord + vec2 screenToFrame(vec2 screenCoord) { + float left = uFrameBounds.x; + float top = uFrameBounds.y; + float right = uFrameBounds.z; + float bottom = uFrameBounds.w; + float width = right - left; + float height = bottom - top; + + float clampedX = clamp(screenCoord.x, left, right); + float clampedY = clamp(screenCoord.y, top, bottom); + + return vec2( + (clampedX - left) / (width), + (clampedY - top) / (height) + ); + } + // internally used to get the maximum `openfl_TextureCoordv` vec2 bitmapCoordScale() { return openfl_TextureCoordv / screenCoord; @@ -80,6 +103,8 @@ class RuntimePostEffectShader extends FlxRuntimeShader { super(fragmentSource, null, glVersion); uScreenResolution.value = [FlxG.width, FlxG.height]; + uCameraBounds.value = [0, 0, FlxG.width, FlxG.height]; + uFrameBounds.value = [0, 0, FlxG.width, FlxG.height]; } // basically `updateViewInfo(FlxG.width, FlxG.height, FlxG.camera)` is good @@ -89,6 +114,12 @@ class RuntimePostEffectShader extends FlxRuntimeShader uCameraBounds.value = [camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom]; } + public function updateFrameInfo(frame:FlxFrame) + { + // NOTE: uv.width is actually the right pos and uv.height is the bottom pos + uFrameBounds.value = [frame.uv.x, frame.uv.y, frame.uv.width, frame.uv.height]; + } + override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram { try diff --git a/source/funkin/graphics/shaders/RuntimeRainShader.hx b/source/funkin/graphics/shaders/RuntimeRainShader.hx index 239276bbe..68a203179 100644 --- a/source/funkin/graphics/shaders/RuntimeRainShader.hx +++ b/source/funkin/graphics/shaders/RuntimeRainShader.hx @@ -32,6 +32,14 @@ class RuntimeRainShader extends RuntimePostEffectShader return time = value; } + public var spriteMode(default, set):Bool = false; + + function set_spriteMode(value:Bool):Bool + { + this.setBool('uSpriteMode', value); + return spriteMode = value; + } + // The scale of the rain depends on the world coordinate system, so higher resolution makes // the raindrops smaller. This parameter can be used to adjust the total scale of the scene. // The size of the raindrops is proportional to the value of this parameter. From 563905ebd42810550904a3c4c894bc24afbc4f30 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Thu, 18 Jul 2024 06:04:32 +0100 Subject: [PATCH 15/29] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 68bf145d5..cfd67caa6 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 68bf145d5786b2c3e4539a46727da67bef1fd039 +Subproject commit cfd67caa688465b4a282837434832c107b661b04 From 6e301bf648e6df451289a4b1a6ef8453766e7a41 Mon Sep 17 00:00:00 2001 From: Burgerballs <107233412+Burgerballs@users.noreply.github.com> Date: Tue, 23 Jul 2024 18:09:39 +0100 Subject: [PATCH 16/29] Update PlayState.hx --- source/funkin/play/PlayState.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8d7d82aab..873082091 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -2043,7 +2043,7 @@ class PlayState extends MusicBeatSubState vocals.pause(); - FlxG.sound.music.play(FlxG.sound.music.time); + FlxG.sound.music.play(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); vocals.time = FlxG.sound.music.time; vocals.play(false, FlxG.sound.music.time); From 1831daac382894aa121180dc8e704d35ce55755c Mon Sep 17 00:00:00 2001 From: Burgerballs <107233412+Burgerballs@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:02:09 +0100 Subject: [PATCH 17/29] Update PlayState.hx --- source/funkin/play/PlayState.hx | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 873082091..18ec0f002 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1417,17 +1417,6 @@ class PlayState extends MusicBeatSubState if (isGamePaused) return false; - if (!startingSong - && FlxG.sound.music != null - && (Math.abs(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 200 - || Math.abs(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 200)) - { - trace("VOCALS NEED RESYNC"); - if (vocals != null) trace(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); - trace(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); - resyncVocals(); - } - if (iconP1 != null) iconP1.onStepHit(Std.int(Conductor.instance.currentStep)); if (iconP2 != null) iconP2.onStepHit(Std.int(Conductor.instance.currentStep)); @@ -1449,6 +1438,17 @@ class PlayState extends MusicBeatSubState // activeNotes.sort(SortUtil.byStrumtime, FlxSort.DESCENDING); } + if (!startingSong + && FlxG.sound.music != null + && (Math.abs(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 100 + || Math.abs(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 100)) + { + trace("VOCALS NEED RESYNC"); + if (vocals != null) trace(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); + trace(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)); + resyncVocals(); + } + // Only bop camera if zoom level is below 135% if (Preferences.zoomCamera && FlxG.camera.zoom < (1.35 * FlxCamera.defaultZoom) @@ -2040,13 +2040,15 @@ class PlayState extends MusicBeatSubState // Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.) if (!FlxG.sound.music.playing) return; - + var timeToPlayAt:Float = Conductor.instance.songPosition - Conductor.instance.instrumentalOffset; + FlxG.sound.music.pause(); vocals.pause(); - FlxG.sound.music.play(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); + FlxG.sound.music.time = timeToPlayAt; + FlxG.sound.music.play(false, timeToPlayAt); - vocals.time = FlxG.sound.music.time; - vocals.play(false, FlxG.sound.music.time); + vocals.time = timeToPlayAt; + vocals.play(false, timeToPlayAt); } /** From 3db0cf3e0ab4817f211cd3d8a74c616b15be1239 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 26 Jul 2024 00:22:36 -0400 Subject: [PATCH 18/29] Update Polymod to support applying JSON patches in the _merge folder of mods. --- hmm.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 375fdd0ac..fabd8b51d 100644 --- a/hmm.json +++ b/hmm.json @@ -123,6 +123,20 @@ "ref": "a8c26f18463c98da32f744c214fe02273e1823fa", "url": "https://github.com/FunkinCrew/json2object" }, + { + "name": "jsonpatch", + "type": "git", + "dir": null, + "ref": "f9b83215acd586dc28754b4ae7f69d4c06c3b4d3", + "url": "https://github.com/EliteMasterEric/jsonpatch" + }, + { + "name": "jsonpath", + "type": "git", + "dir": null, + "ref": "7a24193717b36393458c15c0435bb7c4470ecdda", + "url": "https://github.com/EliteMasterEric/jsonpath" + }, { "name": "lime", "type": "git", @@ -169,7 +183,7 @@ "name": "polymod", "type": "git", "dir": null, - "ref": "bfbe30d81601b3543d80dce580108ad6b7e182c7", + "ref": "98945c6c7f5ecde01a32c4623d3515bf012a023a", "url": "https://github.com/larsiusprime/polymod" }, { From f3624f7e76cdd8dcba0762a39ebe1be28389ecef Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Sun, 28 Jul 2024 01:42:09 -0400 Subject: [PATCH 19/29] Fixes for scripted song events, define vocal tracks per variation, display suffixed difficulties properly. --- source/funkin/data/event/SongEventRegistry.hx | 4 +- source/funkin/data/song/CHANGELOG.md | 7 + source/funkin/data/song/SongData.hx | 59 +++--- source/funkin/modding/PolymodHandler.hx | 2 + source/funkin/play/PlayState.hx | 8 +- source/funkin/play/song/Song.hx | 168 ++++++++++++------ source/funkin/ui/freeplay/FreeplayState.hx | 30 +++- source/funkin/ui/freeplay/SongMenuItem.hx | 3 +- 8 files changed, 188 insertions(+), 93 deletions(-) diff --git a/source/funkin/data/event/SongEventRegistry.hx b/source/funkin/data/event/SongEventRegistry.hx index 9b0163557..5ee2d39fa 100644 --- a/source/funkin/data/event/SongEventRegistry.hx +++ b/source/funkin/data/event/SongEventRegistry.hx @@ -46,7 +46,7 @@ class SongEventRegistry if (event != null) { - trace(' Loaded built-in song event: (${event.id})'); + trace(' Loaded built-in song event: ${event.id}'); eventCache.set(event.id, event); } else @@ -59,9 +59,9 @@ class SongEventRegistry static function registerScriptedEvents() { var scriptedEventClassNames:Array<String> = ScriptedSongEvent.listScriptClasses(); + trace('Instantiating ${scriptedEventClassNames.length} scripted song events...'); if (scriptedEventClassNames == null || scriptedEventClassNames.length == 0) return; - trace('Instantiating ${scriptedEventClassNames.length} scripted song events...'); for (eventCls in scriptedEventClassNames) { var event:SongEvent = ScriptedSongEvent.init(eventCls, "UKNOWN"); diff --git a/source/funkin/data/song/CHANGELOG.md b/source/funkin/data/song/CHANGELOG.md index 4f1c66ade..ca36a1d6d 100644 --- a/source/funkin/data/song/CHANGELOG.md +++ b/source/funkin/data/song/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.4] +### Added +- Added `playData.characters.opponentVocals` to specify which vocal track(s) to play for the opponent. + - If the value isn't present, it will use the `playData.characters.opponent`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the opponent) +- Added `playData.characters.playerVocals` to specify which vocal track(s) to play for the player. + - If the value isn't present, it will use the `playData.characters.player`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the player) + ## [2.2.3] ### Added - Added `charter` field to denote authorship of a chart. diff --git a/source/funkin/data/song/SongData.hx b/source/funkin/data/song/SongData.hx index 7bf3f8f19..f487eb54d 100644 --- a/source/funkin/data/song/SongData.hx +++ b/source/funkin/data/song/SongData.hx @@ -529,12 +529,26 @@ class SongCharacterData implements ICloneable<SongCharacterData> @:default([]) public var altInstrumentals:Array<String> = []; - public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '') + @:optional + public var opponentVocals:Null<Array<String>> = null; + + @:optional + public var playerVocals:Null<Array<String>> = null; + + public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '', ?altInstrumentals:Array<String>, + ?opponentVocals:Array<String>, ?playerVocals:Array<String>) { this.player = player; this.girlfriend = girlfriend; this.opponent = opponent; this.instrumental = instrumental; + + this.altInstrumentals = altInstrumentals; + this.opponentVocals = opponentVocals; + this.playerVocals = playerVocals; + + if (opponentVocals == null) this.opponentVocals = [opponent]; + if (playerVocals == null) this.playerVocals = [player]; } public function clone():SongCharacterData @@ -722,18 +736,6 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw> { return new SongEventDataRaw(this.time, this.eventKind, this.value); } -} - -/** - * Wrap SongEventData in an abstract so we can overload operators. - */ -@:forward(time, eventKind, value, activated, getStepTime, clone) -abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw -{ - public function new(time:Float, eventKind:String, value:Dynamic = null) - { - this = new SongEventDataRaw(time, eventKind, value); - } public function valueAsStruct(?defaultKey:String = "key"):Dynamic { @@ -757,27 +759,27 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR } } - public inline function getHandler():Null<SongEvent> + public function getHandler():Null<SongEvent> { return SongEventRegistry.getEvent(this.eventKind); } - public inline function getSchema():Null<SongEventSchema> + public function getSchema():Null<SongEventSchema> { return SongEventRegistry.getEventSchema(this.eventKind); } - public inline function getDynamic(key:String):Null<Dynamic> + public function getDynamic(key:String):Null<Dynamic> { return this.value == null ? null : Reflect.field(this.value, key); } - public inline function getBool(key:String):Null<Bool> + public function getBool(key:String):Null<Bool> { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getInt(key:String):Null<Int> + public function getInt(key:String):Null<Int> { if (this.value == null) return null; var result = Reflect.field(this.value, key); @@ -787,7 +789,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return cast result; } - public inline function getFloat(key:String):Null<Float> + public function getFloat(key:String):Null<Float> { if (this.value == null) return null; var result = Reflect.field(this.value, key); @@ -797,17 +799,17 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return cast result; } - public inline function getString(key:String):String + public function getString(key:String):String { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getArray(key:String):Array<Dynamic> + public function getArray(key:String):Array<Dynamic> { return this.value == null ? null : cast Reflect.field(this.value, key); } - public inline function getBoolArray(key:String):Array<Bool> + public function getBoolArray(key:String):Array<Bool> { return this.value == null ? null : cast Reflect.field(this.value, key); } @@ -839,6 +841,19 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR return result; } +} + +/** + * Wrap SongEventData in an abstract so we can overload operators. + */ +@:forward(time, eventKind, value, activated, getStepTime, clone, getHandler, getSchema, getDynamic, getBool, getInt, getFloat, getString, getArray, + getBoolArray, buildTooltip, valueAsStruct) +abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw +{ + public function new(time:Float, eventKind:String, value:Dynamic = null) + { + this = new SongEventDataRaw(time, eventKind, value); + } public function clone():SongEventData { diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index 9a9ef9e66..5767199ba 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -234,6 +234,8 @@ class PolymodHandler // NOTE: Scripted classes are automatically aliased to their parent class. Polymod.addImportAlias('flixel.math.FlxPoint', flixel.math.FlxPoint.FlxBasePoint); + Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw); + // Add blacklisting for prohibited classes and packages. // `Sys` diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 32b6e7b62..871c784df 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -580,6 +580,8 @@ class PlayState extends MusicBeatSubState // TODO: Refactor or document var generatedMusic:Bool = false; + var skipEndingTransition:Bool = false; + static final BACKGROUND_COLOR:FlxColor = FlxColor.BLACK; /** @@ -1926,7 +1928,9 @@ class PlayState extends MusicBeatSubState return; } - FlxG.sound.music.onComplete = endSong.bind(false); + FlxG.sound.music.onComplete = function() { + endSong(skipEndingTransition); + }; // A negative instrumental offset means the song skips the first few milliseconds of the track. // This just gets added into the startTimestamp behavior so we don't need to do anything extra. FlxG.sound.music.play(true, startTimestamp - Conductor.instance.instrumentalOffset); @@ -1965,7 +1969,7 @@ class PlayState extends MusicBeatSubState if (vocals == null) return; // Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.) - if (!FlxG.sound.music.playing) return; + if (!(FlxG?.sound?.music?.playing ?? false)) return; vocals.pause(); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 147923add..2e7e13f51 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -494,6 +494,24 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta return diffFiltered; } + public function listSuffixedDifficulties(variationIds:Array<String>, ?showLocked:Bool, ?showHidden:Bool):Array<String> + { + var result = []; + + for (variation in variationIds) + { + var difficulties = listDifficulties(variation, null, showLocked, showHidden); + for (difficulty in difficulties) + { + var suffixedDifficulty = (variation != Constants.DEFAULT_VARIATION + && variation != 'erect') ? '$difficulty-${variation}' : difficulty; + result.push(suffixedDifficulty); + } + } + + return result; + } + public function hasDifficulty(diffId:String, ?variationId:String, ?variationIds:Array<String>):Bool { if (variationIds == null) variationIds = []; @@ -706,10 +724,11 @@ class SongDifficulty * Cache the vocals for a given character. * @param id The character we are about to play. */ - public inline function cacheVocals():Void + public function cacheVocals():Void { for (voice in buildVoiceList()) { + trace('Caching vocal track: $voice'); FlxG.sound.cache(voice); } } @@ -721,6 +740,20 @@ class SongDifficulty * @param id The character we are about to play. */ public function buildVoiceList():Array<String> + { + var result:Array<String> = []; + result = result.concat(buildPlayerVoiceList()); + result = result.concat(buildOpponentVoiceList()); + if (result.length == 0) + { + var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + // Try to use `Voices.ogg` if no other voices are found. + if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix')); + } + return result; + } + + public function buildPlayerVoiceList():Array<String> { var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; @@ -728,62 +761,88 @@ class SongDifficulty // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. - var playerId:String = characters.player; - var voicePlayer:String = Paths.voices(this.song.id, '-$playerId$suffix'); - while (voicePlayer != null && !Assets.exists(voicePlayer)) + if (characters.playerVocals == null) { - // Remove the last suffix. - // For example, bf-car becomes bf. - playerId = playerId.split('-').slice(0, -1).join('-'); - // Try again. - voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); - } - if (voicePlayer == null) - { - // Try again without $suffix. - playerId = characters.player; - voicePlayer = Paths.voices(this.song.id, '-${playerId}'); - while (voicePlayer != null && !Assets.exists(voicePlayer)) + var playerId:String = characters.player; + var playerVoice:String = Paths.voices(this.song.id, '-${playerId}$suffix'); + + while (playerVoice != null && !Assets.exists(playerVoice)) { // Remove the last suffix. + // For example, bf-car becomes bf. playerId = playerId.split('-').slice(0, -1).join('-'); // Try again. - voicePlayer = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + } + if (playerVoice == null) + { + // Try again without $suffix. + playerId = characters.player; + playerVoice = Paths.voices(this.song.id, '-${playerId}'); + while (playerVoice != null && !Assets.exists(playerVoice)) + { + // Remove the last suffix. + playerId = playerId.split('-').slice(0, -1).join('-'); + // Try again. + playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + } } - } - var opponentId:String = characters.opponent; - var voiceOpponent:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); - while (voiceOpponent != null && !Assets.exists(voiceOpponent)) - { - // Remove the last suffix. - opponentId = opponentId.split('-').slice(0, -1).join('-'); - // Try again. - voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + return playerVoice != null ? [playerVoice] : []; } - if (voiceOpponent == null) + else { - // Try again without $suffix. - opponentId = characters.opponent; - voiceOpponent = Paths.voices(this.song.id, '-${opponentId}'); - while (voiceOpponent != null && !Assets.exists(voiceOpponent)) + // The metadata explicitly defines the list of voices. + var playerIds:Array<String> = characters?.playerVocals ?? [characters.player]; + var playerVoices:Array<String> = playerIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + + return playerVoices; + } + } + + public function buildOpponentVoiceList():Array<String> + { + var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + + // Automatically resolve voices by removing suffixes. + // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. + // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. + + if (characters.opponentVocals == null) + { + var opponentId:String = characters.opponent; + var opponentVoice:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); + while (opponentVoice != null && !Assets.exists(opponentVoice)) { // Remove the last suffix. opponentId = opponentId.split('-').slice(0, -1).join('-'); // Try again. - voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + } + if (opponentVoice == null) + { + // Try again without $suffix. + opponentId = characters.opponent; + opponentVoice = Paths.voices(this.song.id, '-${opponentId}'); + while (opponentVoice != null && !Assets.exists(opponentVoice)) + { + // Remove the last suffix. + opponentId = opponentId.split('-').slice(0, -1).join('-'); + // Try again. + opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + } } - } - var result:Array<String> = []; - if (voicePlayer != null) result.push(voicePlayer); - if (voiceOpponent != null) result.push(voiceOpponent); - if (voicePlayer == null && voiceOpponent == null) - { - // Try to use `Voices.ogg` if no other voices are found. - if (Assets.exists(Paths.voices(this.song.id, ''))) result.push(Paths.voices(this.song.id, '$suffix')); + return opponentVoice != null ? [opponentVoice] : []; + } + else + { + // The metadata explicitly defines the list of voices. + var opponentIds:Array<String> = characters?.opponentVocals ?? [characters.opponent]; + var opponentVoices:Array<String> = opponentIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + + return opponentVoices; } - return result; } /** @@ -795,26 +854,19 @@ class SongDifficulty { var result:VoicesGroup = new VoicesGroup(); - var voiceList:Array<String> = buildVoiceList(); - - if (voiceList.length == 0) - { - trace('Could not find any voices for song ${this.song.id}'); - return result; - } + var playerVoiceList:Array<String> = this.buildPlayerVoiceList(); + var opponentVoiceList:Array<String> = this.buildOpponentVoiceList(); // Add player vocals. - if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(voiceList[0])); - // Add opponent vocals. - if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(voiceList[1])); - - // Add additional vocals. - if (voiceList.length > 2) + for (playerVoice in playerVoiceList) { - for (i in 2...voiceList.length) - { - result.add(FunkinSound.load(Assets.getSound(voiceList[i]))); - } + result.addPlayerVoice(FunkinSound.load(playerVoice)); + } + + // Add opponent vocals. + for (opponentVoice in opponentVoiceList) + { + result.addOpponentVoice(FunkinSound.load(opponentVoice)); } result.playerVoicesOffset = offsets.getVocalOffset(characters.player); diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index dc42bd651..2341f04a6 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -339,7 +339,7 @@ class FreeplayState extends MusicBeatSubState // Only display songs which actually have available difficulties for the current character. var displayedVariations = song.getVariationsByCharacter(currentCharacter); trace('Displayed Variations (${songId}): $displayedVariations'); - var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false); + var availableDifficultiesForSong:Array<String> = song.listSuffixedDifficulties(displayedVariations, false, false); trace('Available Difficulties: $availableDifficultiesForSong'); if (availableDifficultiesForSong.length == 0) continue; @@ -1120,7 +1120,7 @@ class FreeplayState extends MusicBeatSubState // NOW we can interact with the menu busy = false; - grpCapsules.members[curSelected].sparkle.alpha = 0.7; + capsule.sparkle.alpha = 0.7; playCurSongPreview(capsule); }, null); @@ -1674,6 +1674,9 @@ class FreeplayState extends MusicBeatSubState songCapsule.init(null, null, null); } } + + // Reset the song preview in case we changed variations (normal->erect etc) + playCurSongPreview(); } // Set the album graphic and play the animation if relevant. @@ -1912,8 +1915,10 @@ class FreeplayState extends MusicBeatSubState } } - public function playCurSongPreview(daSongCapsule:SongMenuItem):Void + public function playCurSongPreview(?daSongCapsule:SongMenuItem):Void { + if (daSongCapsule == null) daSongCapsule = grpCapsules.members[curSelected]; + if (curSelected == 0) { FunkinSound.playMusic('freeplayRandom', @@ -2145,7 +2150,7 @@ class FreeplaySongData function updateValues(variations:Array<String>):Void { - this.songDifficulties = song.listDifficulties(null, variations, false, false); + this.songDifficulties = song.listSuffixedDifficulties(variations, false, false); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, null, variations); @@ -2207,15 +2212,26 @@ class DifficultySprite extends FlxSprite difficultyId = diffId; - if (Assets.exists(Paths.file('images/freeplay/freeplay${diffId}.xml'))) + var assetDiffId:String = diffId; + while (!Assets.exists(Paths.image('freeplay/freeplay${assetDiffId}'))) { - this.frames = Paths.getSparrowAtlas('freeplay/freeplay${diffId}'); + // Remove the last suffix of the difficulty id until we find an asset or there are no more suffixes. + var assetDiffIdParts:Array<String> = assetDiffId.split('-'); + assetDiffIdParts.pop(); + if (assetDiffIdParts.length == 0) break; + assetDiffId = assetDiffIdParts.join('-'); + } + + // Check for an XML to use an animation instead of an image. + if (Assets.exists(Paths.file('images/freeplay/freeplay${assetDiffId}.xml'))) + { + this.frames = Paths.getSparrowAtlas('freeplay/freeplay${assetDiffId}'); this.animation.addByPrefix('idle', 'idle0', 24, true); if (Preferences.flashingLights) this.animation.play('idle'); } else { - this.loadGraphic(Paths.image('freeplay/freeplay' + diffId)); + this.loadGraphic(Paths.image('freeplay/freeplay' + assetDiffId)); } } } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 2eec83223..b4409d377 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -162,7 +162,7 @@ class SongMenuItem extends FlxSpriteGroup sparkle = new FlxSprite(ranking.x, ranking.y); sparkle.frames = Paths.getSparrowAtlas('freeplay/sparkle'); - sparkle.animation.addByPrefix('sparkle', 'sparkle', 24, false); + sparkle.animation.addByPrefix('sparkle', 'sparkle Export0', 24, false); sparkle.animation.play('sparkle', true); sparkle.scale.set(0.8, 0.8); sparkle.blend = BlendMode.ADD; @@ -523,7 +523,6 @@ class SongMenuItem extends FlxSpriteGroup checkWeek(songData?.songId); } - var frameInTicker:Float = 0; var frameInTypeBeat:Int = 0; From 195010c7edf31944e40ad790d44b2c987dd931cd Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Thu, 18 Jul 2024 17:45:48 -0400 Subject: [PATCH 20/29] hxcpp and lime hmm updates for arm64 mac --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index fabd8b51d..60a35d4fe 100644 --- a/hmm.json +++ b/hmm.json @@ -141,7 +141,7 @@ "name": "lime", "type": "git", "dir": null, - "ref": "872ff6db2f2d27c0243d4ff76802121ded550dd7", + "ref": "ede0005c3aedcbfea7b6247bfc4972ecf7f78a14", "url": "https://github.com/FunkinCrew/lime" }, { From 5e04628480b53b3d1c5b7386826ddb7a36e2ad93 Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Sun, 21 Jul 2024 19:02:58 -0400 Subject: [PATCH 21/29] lime shallow cairo --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index 60a35d4fe..ba5274f0d 100644 --- a/hmm.json +++ b/hmm.json @@ -141,7 +141,7 @@ "name": "lime", "type": "git", "dir": null, - "ref": "ede0005c3aedcbfea7b6247bfc4972ecf7f78a14", + "ref": "916da928134edc57db44f604036ae9bec828f340", "url": "https://github.com/FunkinCrew/lime" }, { From e4e4c66c6c06173b187109053769fd4ad4f08758 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Thu, 25 Jul 2024 08:33:01 -0400 Subject: [PATCH 22/29] Update Lime version --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index ba5274f0d..5254fe5dd 100644 --- a/hmm.json +++ b/hmm.json @@ -141,7 +141,7 @@ "name": "lime", "type": "git", "dir": null, - "ref": "916da928134edc57db44f604036ae9bec828f340", + "ref": "a393a54b6120bfa9a2f1db5a16fbf1137d41f257", "url": "https://github.com/FunkinCrew/lime" }, { From 68b7610225aa4fd382d53950d0ae889333d9e752 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Mon, 29 Jul 2024 17:26:49 -0400 Subject: [PATCH 23/29] Update OpenFL to latest (requires a few fixes) --- hmm.json | 14 ++++++++------ source/funkin/audio/visualize/ABotVis.hx | 2 +- source/funkin/audio/visualize/VisShit.hx | 2 +- source/funkin/audio/waveform/WaveformDataParser.hx | 2 +- .../toolboxes/ChartEditorNoteDataToolbox.hx | 4 ++-- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- source/funkin/ui/story/LevelProp.hx | 2 +- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/hmm.json b/hmm.json index 5254fe5dd..e9aa678ef 100644 --- a/hmm.json +++ b/hmm.json @@ -23,8 +23,10 @@ }, { "name": "flixel-text-input", - "type": "haxelib", - "version": "1.1.0" + "type": "git", + "dir": null, + "ref": "951a0103a17bfa55eed86703ce50b4fb0d7590bc", + "url": "https://github.com/FunkinCrew/flixel-text-input" }, { "name": "flixel-ui", @@ -75,14 +77,14 @@ "name": "haxeui-core", "type": "git", "dir": null, - "ref": "5dc4c933bdc029f6139a47962e3b8c754060f210", + "ref": "22f7c5a8ffca90d4677cffd6e570f53761709fbc", "url": "https://github.com/haxeui/haxeui-core" }, { "name": "haxeui-flixel", "type": "git", "dir": null, - "ref": "57c1604d6b5174839d7e0e012a4dd5dcbfc129da", + "ref": "28bb710d0ae5d94b5108787593052165be43b980", "url": "https://github.com/haxeui/haxeui-flixel" }, { @@ -141,7 +143,7 @@ "name": "lime", "type": "git", "dir": null, - "ref": "a393a54b6120bfa9a2f1db5a16fbf1137d41f257", + "ref": "f6153ffcb1ffcf733f91d531eac5fda4189e07f7", "url": "https://github.com/FunkinCrew/lime" }, { @@ -190,7 +192,7 @@ "name": "thx.core", "type": "git", "dir": null, - "ref": "6240b6e136f7490d9298edbe8c1891374bd7cdf2", + "ref": "76d87418fadd92eb8e1b61f004cff27d656e53dd", "url": "https://github.com/fponticelli/thx.core" }, { diff --git a/source/funkin/audio/visualize/ABotVis.hx b/source/funkin/audio/visualize/ABotVis.hx index cf43a8add..a6ad0570e 100644 --- a/source/funkin/audio/visualize/ABotVis.hx +++ b/source/funkin/audio/visualize/ABotVis.hx @@ -54,7 +54,7 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite> public function initAnalyzer() { @:privateAccess - analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 40); + analyzer = new SpectralAnalyzer(snd._channel.__audioSource, 7, 0.1, 40); #if desktop // On desktop it uses FFT stuff that isn't as optimized as the direct browser stuff we use on HTML5 diff --git a/source/funkin/audio/visualize/VisShit.hx b/source/funkin/audio/visualize/VisShit.hx index ba235fe89..83b9496ac 100644 --- a/source/funkin/audio/visualize/VisShit.hx +++ b/source/funkin/audio/visualize/VisShit.hx @@ -117,7 +117,7 @@ class VisShit { // Math.pow3 @:privateAccess - var buf = snd._channel.__source.buffer; + var buf = snd._channel.__audioSource.buffer; // @:privateAccess audioData = cast buf.data; // jank and hacky lol! kinda busted on HTML5 also!! diff --git a/source/funkin/audio/waveform/WaveformDataParser.hx b/source/funkin/audio/waveform/WaveformDataParser.hx index 5aa54d744..ca421581b 100644 --- a/source/funkin/audio/waveform/WaveformDataParser.hx +++ b/source/funkin/audio/waveform/WaveformDataParser.hx @@ -16,7 +16,7 @@ class WaveformDataParser // Method 1. This only works if the sound has been played before. @:privateAccess - var soundBuffer:Null<lime.media.AudioBuffer> = sound?._channel?.__source?.buffer; + var soundBuffer:Null<lime.media.AudioBuffer> = sound?._channel?.__audioSource?.buffer; if (soundBuffer == null) { diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx index 12f7f7d63..100654a02 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorNoteDataToolbox.hx @@ -192,7 +192,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox var paramStepper:NumberStepper = new NumberStepper(); paramStepper.value = (setParamsToPlace ? chartEditorState.noteParamsToPlace[i].value : param.data?.defaultValue) ?? 0.0; paramStepper.percentWidth = 100; - paramStepper.step = param.data?.step ?? 1; + paramStepper.step = param.data?.step ?? 1.0; // this check should be unnecessary but for some reason // even when these are null it will set it to 0 @@ -283,7 +283,7 @@ class ChartEditorNoteDataToolbox extends ChartEditorBaseToolbox return; } - var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, (toolboxNotesGrid?.height ?? 50) + HEIGHT_OFFSET)) + MINIMIZE_FIX; + var heightToSet:Int = Std.int(Math.max(DIALOG_HEIGHT, (toolboxNotesGrid?.height ?? 50.0) + HEIGHT_OFFSET)) + MINIMIZE_FIX; if (this.height != heightToSet) { this.height = heightToSet; diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 2341f04a6..690e3b910 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1527,7 +1527,7 @@ class FreeplayState extends MusicBeatSubState var moveDataX = funnyMoveShit.x ?? spr.x; var moveDataY = funnyMoveShit.y ?? spr.y; var moveDataSpeed = funnyMoveShit.speed ?? 0.2; - var moveDataWait = funnyMoveShit.wait ?? 0; + var moveDataWait = funnyMoveShit.wait ?? 0.0; FlxTween.tween(spr, {x: moveDataX, y: moveDataY}, moveDataSpeed, {ease: FlxEase.expoIn}); diff --git a/source/funkin/ui/story/LevelProp.hx b/source/funkin/ui/story/LevelProp.hx index 0547404a1..4e78415e3 100644 --- a/source/funkin/ui/story/LevelProp.hx +++ b/source/funkin/ui/story/LevelProp.hx @@ -16,7 +16,7 @@ class LevelProp extends Bopper this.propData = value; this.visible = this.propData != null; - danceEvery = this.propData?.danceEvery ?? 0; + danceEvery = this.propData?.danceEvery ?? 0.0; applyData(); } From c9c81fae51e5f2a23ee7fc1ac0cfd499e95b1b9a Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Mon, 29 Jul 2024 21:26:02 -0400 Subject: [PATCH 24/29] assets submod? --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index 005c96f85..aa1231e8c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 005c96f85f4304865acb196e7cc4d6d83f9d76d8 +Subproject commit aa1231e8cf2990bb902eac3b37815c010fa9919a From 3b7e65679357687bd6901f45c120de06970d46f8 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Wed, 31 Jul 2024 14:36:06 +0100 Subject: [PATCH 25/29] add stage names to registry + chart editor --- source/funkin/data/stage/StageRegistry.hx | 4 ++-- source/funkin/ui/debug/charting/ChartEditorState.hx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/funkin/data/stage/StageRegistry.hx b/source/funkin/data/stage/StageRegistry.hx index fbb6f188e..1f0504247 100644 --- a/source/funkin/data/stage/StageRegistry.hx +++ b/source/funkin/data/stage/StageRegistry.hx @@ -93,8 +93,8 @@ class StageRegistry extends BaseRegistry<Stage, StageData> public function listBaseGameStageIds():Array<String> { return [ - "mainStage", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "mallXmas", "mallEvil", "school", "schoolEvil", "tankmanBattlefield", - "phillyStreets", "phillyBlazin", + "mainStage", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallEvil", "school", "schoolEvil", + "tankmanBattlefield", "phillyStreets", "phillyBlazin", ]; } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index a4e0de61e..24d290abd 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -5707,7 +5707,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState PlayStatePlaylist.campaignId = 'week2'; case 'phillyTrain' | 'phillyTrainErect': PlayStatePlaylist.campaignId = 'week3'; - case 'limoRide': + case 'limoRide' | 'limoRideErect': PlayStatePlaylist.campaignId = 'week4'; case 'mallXmas' | 'mallEvil': PlayStatePlaylist.campaignId = 'week5'; From 270748d1081a947c0c84ecd718e65ccb34ba6911 Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Wed, 31 Jul 2024 14:36:24 +0100 Subject: [PATCH 26/29] fuck these decimals messing up my compiling --- source/funkin/ui/freeplay/FreeplayState.hx | 2 +- source/funkin/ui/story/LevelProp.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index dc42bd651..fa895042f 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1527,7 +1527,7 @@ class FreeplayState extends MusicBeatSubState var moveDataX = funnyMoveShit.x ?? spr.x; var moveDataY = funnyMoveShit.y ?? spr.y; var moveDataSpeed = funnyMoveShit.speed ?? 0.2; - var moveDataWait = funnyMoveShit.wait ?? 0; + var moveDataWait = funnyMoveShit.wait ?? 0.0; FlxTween.tween(spr, {x: moveDataX, y: moveDataY}, moveDataSpeed, {ease: FlxEase.expoIn}); diff --git a/source/funkin/ui/story/LevelProp.hx b/source/funkin/ui/story/LevelProp.hx index 0547404a1..4e78415e3 100644 --- a/source/funkin/ui/story/LevelProp.hx +++ b/source/funkin/ui/story/LevelProp.hx @@ -16,7 +16,7 @@ class LevelProp extends Bopper this.propData = value; this.visible = this.propData != null; - danceEvery = this.propData?.danceEvery ?? 0; + danceEvery = this.propData?.danceEvery ?? 0.0; applyData(); } From 8200a08152ceea85cd242b990518007af5d4806f Mon Sep 17 00:00:00 2001 From: FabsTheFabs <flamingkitty24@gmail.com> Date: Wed, 31 Jul 2024 14:36:34 +0100 Subject: [PATCH 27/29] assets submod --- assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets b/assets index cfd67caa6..06067d187 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit cfd67caa688465b4a282837434832c107b661b04 +Subproject commit 06067d187e7699a8eec42ab07c53d195c589a690 From f4968b0ae5211e70f99d68f8de618553c8eb9a35 Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Mon, 5 Aug 2024 10:47:59 -0400 Subject: [PATCH 28/29] openfl hmm commit to dev-funkin --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index e9aa678ef..c72b4240a 100644 --- a/hmm.json +++ b/hmm.json @@ -178,7 +178,7 @@ "name": "openfl", "type": "git", "dir": null, - "ref": "228c1b5063911e2ad75cef6e3168ef0a4b9f9134", + "ref": "8306425c497766739510ab29e876059c96f77bd2", "url": "https://github.com/FunkinCrew/openfl" }, { From c3d497a9d907b38cd11d1fa15f2d9a85bf82db96 Mon Sep 17 00:00:00 2001 From: Cameron Taylor <cameron.taylor.ninja@gmail.com> Date: Wed, 7 Aug 2024 19:01:46 -0400 Subject: [PATCH 29/29] hxcpp bump --- hmm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmm.json b/hmm.json index c72b4240a..aad0be8cf 100644 --- a/hmm.json +++ b/hmm.json @@ -104,7 +104,7 @@ "type": "git", "dir": null, "url": "https://github.com/HaxeFoundation/hxcpp", - "ref": "01cfee282a9a783e10c5a7774a3baaf547e6b0a7" + "ref": "8dc8020f8465027de6c2aaaed90718bc693651ed" }, { "name": "hxcpp-debug-server",