diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 9ae13a76..449f82c6 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -7,7 +7,7 @@ jobs:
build:
name: Mac OS Build
permissions: write-all
- runs-on: macos-latest
+ runs-on: macos-13
steps:
- name: Pulling the new commit
uses: actions/checkout@v2
diff --git a/assets/data/characters/bf.xml b/assets/data/characters/bf.xml
index 04e2b3c5..245fbffd 100644
--- a/assets/data/characters/bf.xml
+++ b/assets/data/characters/bf.xml
@@ -11,4 +11,8 @@
-
\ No newline at end of file
+
+
+
+
+
diff --git a/assets/data/notes/Alt Anim Note.hx b/assets/data/notes/Alt Anim Note.hx
index 08acea42..b44b1398 100644
--- a/assets/data/notes/Alt Anim Note.hx
+++ b/assets/data/notes/Alt Anim Note.hx
@@ -1 +1,2 @@
-function onNoteHit(event) if (event.noteType == "Alt Anim Note") event.animSuffix = "-alt";
\ No newline at end of file
+function onNoteHit(event) if (event.noteType == "Alt Anim Note") event.animSuffix = "-alt";
+function onPlayerMiss(event) if (event.noteType == "Alt Anim Note") event.animSuffix = "-alt";
\ No newline at end of file
diff --git a/assets/data/notes/No Anim Note.hx b/assets/data/notes/No Anim Note.hx
index 31eb0c63..206d4f96 100644
--- a/assets/data/notes/No Anim Note.hx
+++ b/assets/data/notes/No Anim Note.hx
@@ -1 +1,2 @@
-function onNoteHit(event) if (event.noteType == "No Anim Note") event.animCancelled = true;
\ No newline at end of file
+function onNoteHit(event) if (event.noteType == "No Anim Note") event.animCancelled = true;
+function onPlayerMiss(event) if (event.noteType == "No Anim Note") event.animCancelled = true;
\ No newline at end of file
diff --git a/assets/data/stages/mall.xml b/assets/data/stages/mall.xml
index 3552cf27..3565f1be 100644
--- a/assets/data/stages/mall.xml
+++ b/assets/data/stages/mall.xml
@@ -1,21 +1,21 @@
-
+
-
+
-
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/source/funkin/backend/assets/ModsFolderLibrary.hx b/source/funkin/backend/assets/ModsFolderLibrary.hx
index eaf4b679..884738c5 100644
--- a/source/funkin/backend/assets/ModsFolderLibrary.hx
+++ b/source/funkin/backend/assets/ModsFolderLibrary.hx
@@ -89,7 +89,7 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return __getFiles(folder, false);
public function __getFiles(folder:String, folders:Bool = false) {
- if (!folder.endsWith("/")) folder = folder + "/";
+ if (!folder.endsWith("/")) folder += "/";
if (!__parseAsset(folder)) return [];
var path = getAssetPath();
try {
diff --git a/source/funkin/backend/assets/Paths.hx b/source/funkin/backend/assets/Paths.hx
index dbc65f8c..dd81ea5b 100644
--- a/source/funkin/backend/assets/Paths.hx
+++ b/source/funkin/backend/assets/Paths.hx
@@ -173,7 +173,7 @@ class Paths
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String) {
if (tempFramesCache.exists(key)) {
var frames = tempFramesCache[key];
- if (frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
+ if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
return frames;
else
tempFramesCache.remove(key);
@@ -271,4 +271,4 @@ class ScriptPathInfo {
this.file = file;
this.library = library;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/backend/assets/ZipFolderLibrary.hx b/source/funkin/backend/assets/ZipFolderLibrary.hx
index 60627c82..ea4dab25 100644
--- a/source/funkin/backend/assets/ZipFolderLibrary.hx
+++ b/source/funkin/backend/assets/ZipFolderLibrary.hx
@@ -20,6 +20,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
public var zip:SysZip;
public var assets:Map = [];
+ public var lowerCaseAssets:Map = [];
+ public var nameMap:Map = [];
public function new(basePath:String, libName:String, ?modName:String) {
this.libName = libName;
@@ -33,8 +35,10 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
zip = SysZip.openFromFile(basePath);
zip.read();
- for(entry in zip.entries)
- assets[entry.fileName.toLowerCase()] = entry;
+ for(entry in zip.entries) {
+ lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
+ nameMap.set(entry.fileName.toLowerCase(), entry.fileName);
+ }
super();
}
@@ -86,6 +90,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
}
_parsedAsset = _parsedAsset.toLowerCase();
+ if(nameMap.exists(_parsedAsset))
+ _parsedAsset = nameMap.get(_parsedAsset);
return true;
}
@@ -105,35 +111,45 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return '[ZIP]$basePath/$_parsedAsset';
}
+ // TODO: rewrite this to 1 function, like ModsFolderLibrary
public function getFiles(folder:String):Array {
- var content:Array = [];
-
- if (!folder.endsWith("/")) folder = folder + "/";
+ if (!folder.endsWith("/")) folder += "/";
if (!__parseAsset(folder)) return [];
+ var content:Array = [];
+
+ var checkPath = _parsedAsset.toLowerCase();
+
@:privateAccess
- for(k=>e in assets) {
- if (k.toLowerCase().startsWith(_parsedAsset)) {
+ for(k=>e in lowerCaseAssets) {
+ if (k.toLowerCase().startsWith(checkPath)) {
+ if(nameMap.exists(k))
+ k = nameMap.get(k);
var fileName = k.substr(_parsedAsset.length);
- if (!fileName.contains("/"))
- content.push(fileName);
+ if (!fileName.contains("/") && fileName.length > 0)
+ content.pushOnce(fileName);
}
}
return content;
}
public function getFolders(folder:String):Array {
- var content:Array = [];
-
- if (!folder.endsWith("/")) folder = folder + "/";
+ if (!folder.endsWith("/")) folder += "/";
if (!__parseAsset(folder)) return [];
+ var content:Array = [];
+
+ var checkPath = _parsedAsset.toLowerCase();
+
@:privateAccess
- for(k=>e in assets) {
- if (k.toLowerCase().startsWith(_parsedAsset)) {
+ for(k=>e in lowerCaseAssets) {
+ if (k.toLowerCase().startsWith(checkPath)) {
+ if(nameMap.exists(k))
+ k = nameMap.get(k);
var fileName = k.substr(_parsedAsset.length);
- if (fileName.contains("/")) {
- var s = fileName.split("/")[0];
+ var index = fileName.indexOf("/");
+ if (index != -1 && fileName.length > 0) {
+ var s = fileName.substr(0, index);
content.pushOnce(s);
}
}
diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx
index 93279d43..1669879d 100644
--- a/source/funkin/backend/chart/Chart.hx
+++ b/source/funkin/backend/chart/Chart.hx
@@ -56,7 +56,6 @@ class Chart {
data.setFieldDefault("name", songName);
data.setFieldDefault("beatsPerMeasure", 4);
data.setFieldDefault("stepsPerBeat", 4);
- data.setFieldDefault("needsVoices", true);
data.setFieldDefault("icon", "face");
data.setFieldDefault("difficulties", []);
data.setFieldDefault("coopAllowed", false);
diff --git a/source/funkin/backend/chart/ChartData.hx b/source/funkin/backend/chart/ChartData.hx
index c46164f5..7e6ad795 100644
--- a/source/funkin/backend/chart/ChartData.hx
+++ b/source/funkin/backend/chart/ChartData.hx
@@ -20,7 +20,6 @@ typedef ChartMetaData = {
public var ?displayName:String;
public var ?beatsPerMeasure:Float;
public var ?stepsPerBeat:Float;
- public var ?needsVoices:Bool;
public var ?icon:String;
public var ?color:Dynamic;
public var ?difficulties:Array;
diff --git a/source/funkin/backend/chart/EventsData.hx b/source/funkin/backend/chart/EventsData.hx
index e801f18f..05f35bde 100644
--- a/source/funkin/backend/chart/EventsData.hx
+++ b/source/funkin/backend/chart/EventsData.hx
@@ -48,7 +48,7 @@ class EventsData {
}
],
"Alt Animation Toggle" => [{name: "Enable On Sing Poses", type: TBool, defValue: true}, {name: "Enable On Idle", type: TBool, defValue: true}, {name: "Strumline", type: TStrumLine, defValue: 0}],
- "Play Animation" => [{name: "Character", type: TStrumLine, defValue: 0}, {name: "Animation", type: TString, defValue: "animation"}],
+ "Play Animation" => [{name: "Character", type: TStrumLine, defValue: 0}, {name: "Animation", type: TString, defValue: "animation"}, {name: "Is forced?", type: TBool, defValue: true}],
];
public static var eventsList:Array = defaultEventsList.copy();
diff --git a/source/funkin/backend/chart/FNFLegacyParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx
index 447aaba9..c6a5be3e 100644
--- a/source/funkin/backend/chart/FNFLegacyParser.hx
+++ b/source/funkin/backend/chart/FNFLegacyParser.hx
@@ -41,7 +41,6 @@ class FNFLegacyParser {
}
result.meta.bpm = data.bpm;
- result.meta.needsVoices = data.needsVoices.getDefault(true);
var camFocusedBF:Bool = false;
var altAnims:Bool = false;
@@ -132,7 +131,7 @@ class FNFLegacyParser {
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
sectionNote[1] += 4;
- swagSection.sectionNotes.push(note);
+ swagSection.sectionNotes.push(sectionNote);
}
}
@@ -145,7 +144,6 @@ class FNFLegacyParser {
song: chart.meta.name,
notes: null,
bpm: chart.meta.bpm,
- needsVoices: chart.meta.needsVoices,
speed: chart.scrollSpeed,
player1: null,
@@ -206,7 +204,6 @@ typedef SwagSong =
var song:String;
var notes:Array;
var bpm:Float;
- var needsVoices:Bool;
var speed:Float;
var ?stage:String;
var ?noteTypes:Array;
diff --git a/source/funkin/backend/scripting/HScript.hx b/source/funkin/backend/scripting/HScript.hx
index 4305519e..f2638f82 100644
--- a/source/funkin/backend/scripting/HScript.hx
+++ b/source/funkin/backend/scripting/HScript.hx
@@ -64,7 +64,13 @@ class HScript extends Script {
}
private function importFailedCallback(cl:Array):Bool {
- var assetsPath = 'assets/source/${cl.join("/")}';
+ if(_importFailedCallback(cl, "") || _importFailedCallback(cl, "source/")) {
+ return true;
+ }
+ return false;
+ }
+ private function _importFailedCallback(cl:Array, prefix:String):Bool {
+ var assetsPath = 'assets/$prefix${cl.join("/")}';
for(hxExt in ["hx", "hscript", "hsc", "hxs"]) {
var p = '$assetsPath.$hxExt';
if (__importedPaths.contains(p))
diff --git a/source/funkin/backend/system/Controls.hx b/source/funkin/backend/system/Controls.hx
index d1a11142..651b510f 100644
--- a/source/funkin/backend/system/Controls.hx
+++ b/source/funkin/backend/system/Controls.hx
@@ -428,13 +428,18 @@ class Controls extends FlxActionSet
return byName[name].check();
}
+ public function getKeyName(control:Control):String
+ {
+ return getDialogueName(getActionFromControl(control));
+ }
+
public function getDialogueName(action:FlxActionDigital):String
{
var input = action.inputs[0];
return switch input.device
{
- case KEYBOARD: return '[${(input.inputID : FlxKey)}]';
- case GAMEPAD: return '(${(input.inputID : FlxGamepadInputID)})';
+ case KEYBOARD: return '${(input.inputID : FlxKey)}';
+ case GAMEPAD: return '${(input.inputID : FlxGamepadInputID)}';
case device: throw 'unhandled device: $device';
}
}
diff --git a/source/funkin/backend/system/MainState.hx b/source/funkin/backend/system/MainState.hx
index 9e4996c7..ff3e9f56 100644
--- a/source/funkin/backend/system/MainState.hx
+++ b/source/funkin/backend/system/MainState.hx
@@ -68,11 +68,6 @@ class MainState extends FlxState {
betaWarningShown = true;
}
- #if sys
- sys.FileSystem.createDirectory('./.temp/');
- #if windows
- try new funkin.backend.utils.native.HiddenProcess("attrib +h .temp")
- catch(e) Logs.warn('Failed to set hidden attribute on .temp folder');
- #end #end
+ CoolUtil.safeSetAttribute('./.temp/', HIDDEN);
}
}
\ No newline at end of file
diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx
index 97ecacc5..b2901b69 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -1,5 +1,8 @@
package funkin.backend.utils;
+#if sys
+import sys.FileSystem;
+#end
import flixel.animation.FlxAnimation;
import flixel.input.keyboard.FlxKey;
import flixel.sound.FlxSound;
@@ -62,18 +65,15 @@ class CoolUtil
*/
@:noUsing public static function deleteFolder(delete:String) {
#if sys
- if (!sys.FileSystem.exists(delete)) return;
- var files:Array = sys.FileSystem.readDirectory(delete);
+ if (!FileSystem.exists(delete)) return;
+ var files:Array = FileSystem.readDirectory(delete);
for(file in files) {
- if (sys.FileSystem.isDirectory(delete + "/" + file)) {
+ if (FileSystem.isDirectory(delete + "/" + file)) {
deleteFolder(delete + "/" + file);
- sys.FileSystem.deleteDirectory(delete + "/" + file);
+ FileSystem.deleteDirectory(delete + "/" + file);
} else {
- try {
- sys.FileSystem.deleteFile(delete + "/" + file);
- } catch(e) {
- Logs.warn("Could not delete " + delete + "/" + file);
- }
+ try FileSystem.deleteFile(delete + "/" + file)
+ catch(e) Logs.warn("Could not delete " + delete + "/" + file);
}
}
#end
@@ -98,6 +98,22 @@ class CoolUtil
#end
}
+ /**
+ * Sets an attribute to a file or a folder adding eventual missing folders in the path
+ * (WARNING: Only works on `windows`. On other platforms the return code it's always going to be `0` but still creates eventual missing folders if the platforms allows it to).
+ * @param path Path to the file or folder
+ * @param attrib The attribute to set (WARNING: There are some non settable attributes, such as the `COMPRESSED` one)
+ * @param useAbsol If it should use the absolute path (By default it's `true` but if it's `false` you can use files outside from this program's directory for example)
+ * @return The result code: 0 means that it failed setting
+ */
+ @:noUsing public static inline function safeSetAttribute(path:String, attrib:NativeAPI.FileAttribute, useAbsol:Bool = true) {
+ addMissingFolders(Path.directory(path));
+
+ var result = NativeAPI.setFileAttribute(path, attrib, useAbsol);
+ if(result == 0) Logs.trace('Failed to set attribute to $path with a code of: $result', WARNING);
+ return result;
+ }
+
/**
* Creates eventual missing folders to the specified `path`
*
@@ -113,9 +129,8 @@ class CoolUtil
for (folder in folders) {
currentPath += folder + "/";
- if (!sys.FileSystem.exists(currentPath)) {
- sys.FileSystem.createDirectory(currentPath);
- }
+ if (!FileSystem.exists(currentPath))
+ FileSystem.createDirectory(currentPath);
}
#end
return path;
diff --git a/source/funkin/backend/utils/FunkinParentDisabler.hx b/source/funkin/backend/utils/FunkinParentDisabler.hx
index 4a7efc3b..07e71a2a 100644
--- a/source/funkin/backend/utils/FunkinParentDisabler.hx
+++ b/source/funkin/backend/utils/FunkinParentDisabler.hx
@@ -41,7 +41,9 @@ class FunkinParentDisabler extends FlxBasic {
}
}
- public override function update(elapsed:Float) {}
+ public override function update(elapsed:Float) {
+ @:privateAccess for(c in __cameras) c.updateFlashSpritePosition();
+ }
public override function draw() {}
public function reset() {
diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx
index a651645e..495403dc 100644
--- a/source/funkin/backend/utils/NativeAPI.hx
+++ b/source/funkin/backend/utils/NativeAPI.hx
@@ -29,6 +29,30 @@ class NativeAPI {
#end
}
+ /**
+ * Gets the specified file's (or folder) attribute.
+ */
+ public static function getFileAttribute(path:String, useAbsol:Bool = true):FileAttribute {
+ #if windows
+ if(useAbsol) path = sys.FileSystem.absolutePath(path);
+ return Windows.getFileAttribute(path);
+ #else
+ return NORMAL;
+ #end
+ }
+
+ /**
+ * Sets the specified file's (or folder) attribute. If it fails, the return value is `0`.
+ */
+ public static function setFileAttribute(path:String, attrib:FileAttribute, useAbsol:Bool = true):Int {
+ #if windows
+ if(useAbsol) path = sys.FileSystem.absolutePath(path);
+ return Windows.setFileAttribute(path, attrib);
+ #else
+ return 0;
+ #end
+ }
+
public static function setDarkMode(title:String, enable:Bool) {
#if windows
Windows.setDarkMode(title, enable);
@@ -61,15 +85,13 @@ class NativeAPI {
var fg = cast(foregroundColor, Int);
var bg = cast(backgroundColor, Int);
Windows.setConsoleColors((bg * 16) + fg);
- #else
- #if sys
+ #elseif sys
Sys.print("\x1b[0m");
if(foregroundColor != NONE)
Sys.print("\x1b[" + Std.int(consoleColorToANSI(foregroundColor)) + "m");
if(backgroundColor != NONE)
Sys.print("\x1b[" + Std.int(consoleColorToANSI(backgroundColor) + 10) + "m");
#end
- #end
}
public static function consoleColorToANSI(color:ConsoleColor) {
@@ -115,6 +137,26 @@ class NativeAPI {
}
}
+enum abstract FileAttribute(Int) {
+ // Settables
+ var ARCHIVE = 0x20;
+ var HIDDEN = 0x2;
+ var NORMAL = 0x80;
+ var NOT_CONTENT_INDEXED = 0x2000;
+ var OFFLINE = 0x1000;
+ var READONLY = 0x1;
+ var SYSTEM = 0x4;
+ var TEMPORARY = 0x100;
+
+ // Non Settables
+ var COMPRESSED = 0x800;
+ var DEVICE = 0x40;
+ var DIRECTORY = 0x10;
+ var ENCRYPTED = 0x4000;
+ var REPARSE_POINT = 0x400;
+ var SPARSE_FILE = 0x200;
+}
+
enum abstract ConsoleColor(Int) {
var BLACK = 0;
var DARKBLUE = 1;
diff --git a/source/funkin/backend/utils/native/Windows.hx b/source/funkin/backend/utils/native/Windows.hx
index 07312d8d..5b03b904 100644
--- a/source/funkin/backend/utils/native/Windows.hx
+++ b/source/funkin/backend/utils/native/Windows.hx
@@ -1,6 +1,7 @@
package funkin.backend.utils.native;
#if windows
+import funkin.backend.utils.NativeAPI.FileAttribute;
import funkin.backend.utils.NativeAPI.MessageBoxIcon;
@:buildXml('
@@ -153,6 +154,22 @@ class Windows {
public static function allocConsole() {
}
+ @:functionCode('
+ return GetFileAttributes(path);
+ ')
+ public static function getFileAttribute(path:String):FileAttribute
+ {
+ return NORMAL;
+ }
+
+ @:functionCode('
+ return SetFileAttributes(path, attrib);
+ ')
+ public static function setFileAttribute(path:String, attrib:FileAttribute):Int
+ {
+ return 0;
+ }
+
@:functionCode('
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index 7739e058..f16fa383 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -526,7 +526,7 @@ class Charter extends UIState {
noteTypes = PlayState.SONG.noteTypes;
FlxG.sound.setMusic(FlxG.sound.load(Paths.inst(__song, __diff)));
- if (PlayState.SONG.meta.needsVoices != false) // null or true
+ if (Assets.exists(Paths.voices(__song, __diff))) // null or true
vocals = FlxG.sound.load(Paths.voices(__song, __diff));
else
vocals = new FlxSound();
@@ -602,7 +602,7 @@ class Charter extends UIState {
var wavesToGenerate:Array<{name:String, sound:FlxSound}> = [
{name: "Inst.ogg", sound: FlxG.sound.music},
];
- if (PlayState.SONG.meta.needsVoices != false)
+ if (@:privateAccess vocals._sound != null) //for some reason Assets.exists returns true regardless if the file actually exists
wavesToGenerate.push({name: "Voices.ogg", sound: vocals});
for (strumLine in strumLines)
diff --git a/source/funkin/editors/charter/CharterMetaDataScreen.hx b/source/funkin/editors/charter/CharterMetaDataScreen.hx
index 900cc721..660e3d89 100644
--- a/source/funkin/editors/charter/CharterMetaDataScreen.hx
+++ b/source/funkin/editors/charter/CharterMetaDataScreen.hx
@@ -15,7 +15,6 @@ class CharterMetaDataScreen extends UISubstateWindow {
public var bpmStepper:UINumericStepper;
public var beatsPerMeasureStepper:UINumericStepper;
public var stepsPerBeatStepper :UINumericStepper;
- public var needsVoicesCheckbox:UICheckbox;
public var customPropertiesButtonList:UIButtonList;
public var displayNameTextBox:UITextBox;
@@ -64,11 +63,6 @@ class CharterMetaDataScreen extends UISubstateWindow {
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, metadata.stepsPerBeat, 1, 0, 1, null, 54);
add(stepsPerBeatStepper);
- needsVoicesCheckbox = new UICheckbox(stepsPerBeatStepper.x + 80 + 26, stepsPerBeatStepper.y, "Voices", metadata.needsVoices);
- add(needsVoicesCheckbox);
- addLabelOn(needsVoicesCheckbox, "Needs Voices");
- needsVoicesCheckbox.y += 6; needsVoicesCheckbox.x += 4;
-
add(title = new UIText(songNameTextBox.x, songNameTextBox.y + 10 + 46, 0, "Menus Data (Freeplay/Story)", 28));
displayNameTextBox = new UITextBox(title.x, title.y + title.height + 36, metadata.displayName);
@@ -97,7 +91,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
add(difficulitesTextBox);
addLabelOn(difficulitesTextBox, "Difficulties");
- customPropertiesButtonList = new UIButtonList(needsVoicesCheckbox.x + needsVoicesCheckbox.width + 105, songNameTextBox.y, 290, 316, '', FlxPoint.get(280, 35), null, 5);
+ customPropertiesButtonList = new UIButtonList(stepsPerBeatStepper.x + 80 + 26 + 105, songNameTextBox.y, 290, 316, '', FlxPoint.get(280, 35), null, 5);
customPropertiesButtonList.frames = Paths.getFrames('editors/ui/inputbox');
customPropertiesButtonList.cameraSpacing = 0;
customPropertiesButtonList.addButton.callback = function() {
@@ -161,7 +155,6 @@ class CharterMetaDataScreen extends UISubstateWindow {
bpm: bpmStepper.value,
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
- needsVoices: needsVoicesCheckbox.checked,
displayName: displayNameTextBox.label.text,
icon: iconTextBox.label.text,
color: colorWheel.curColorString,
diff --git a/source/funkin/editors/charter/SongCreationScreen.hx b/source/funkin/editors/charter/SongCreationScreen.hx
index 95c682ce..7915cae0 100644
--- a/source/funkin/editors/charter/SongCreationScreen.hx
+++ b/source/funkin/editors/charter/SongCreationScreen.hx
@@ -19,7 +19,6 @@ class SongCreationScreen extends UISubstateWindow {
public var bpmStepper:UINumericStepper;
public var beatsPerMeasureStepper:UINumericStepper;
public var stepsPerBeatStepper :UINumericStepper;
- public var needsVoicesCheckbox:UICheckbox;
public var instExplorer:UIFileExplorer;
public var voicesExplorer:UIFileExplorer;
@@ -83,25 +82,6 @@ class SongCreationScreen extends UISubstateWindow {
var voicesUIText:UIText = null;
- needsVoicesCheckbox = new UICheckbox(stepsPerBeatStepper.x + 80 + 26, stepsPerBeatStepper.y, "Voices", true);
- needsVoicesCheckbox.onChecked = function(checked) {
- if (voicesExplorer == null) return;
-
- if(!checked) {
- voicesExplorer.removeFile();
- voicesExplorer.selectable = voicesExplorer.uploadButton.selectable = false;
- voicesUIText.text = "Vocal Audio File";
- } else {
- voicesExplorer.selectable = voicesExplorer.uploadButton.selectable = true;
- voicesUIText.applyMarkup(
- "Vocal Audio File $* Required$",
- [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
- }
- }
- songDataGroup.add(needsVoicesCheckbox);
- addLabelOn(needsVoicesCheckbox, "Needs Voices");
- needsVoicesCheckbox.y += 6; needsVoicesCheckbox.x += 4;
-
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
@@ -195,7 +175,7 @@ class SongCreationScreen extends UISubstateWindow {
public override function update(elapsed:Float) {
if (curPage == 0) {
- if (instExplorer.file != null && (needsVoicesCheckbox.checked ? voicesExplorer.file != null : true))
+ if (instExplorer.file != null)
saveButton.selectable = true;
else saveButton.selectable = false;
} else
@@ -258,7 +238,6 @@ class SongCreationScreen extends UISubstateWindow {
bpm: bpmStepper.value,
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
stepsPerBeat: Std.int(stepsPerBeatStepper.value),
- needsVoices: needsVoicesCheckbox.checked,
displayName: displayNameTextBox.label.text,
icon: iconTextBox.label.text,
color: colorWheel.curColorString,
diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx
index 701505e2..a2d1af5b 100644
--- a/source/funkin/game/Character.hx
+++ b/source/funkin/game/Character.hx
@@ -56,6 +56,8 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public var shadowFrame:CharacterShadowFrame;
public var idleSuffix:String = "";
+ public var anims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"]; // Not making these inline so theyre editable through scripts! - Nex
+
public inline function getCameraPosition()
{
var midpoint = getMidpoint();
@@ -68,12 +70,26 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
return new FlxPoint(event.x, event.y);
}
- var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];
+ public inline function getSingAnim(direction:Int, suffix:String = ""):String
+ {
+ return anims[direction % anims.length] + suffix;
+ }
+ /**
+ * Like `playSingAnimUnsafe` but checks if the character has the animation with the suffix part, otherwhise tries to play the animation without the suffix part.
+ */
public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, Force:Bool = true, Reversed:Bool = false, Frame:Int = 0)
{
- var event = EventManager.get(DirectionAnimEvent).recycle(singAnims[direction % singAnims.length] + suffix, direction, suffix, Context, Reversed, Frame, Force);
+ var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
script.call("onPlaySingAnim", [event]);
+ if (!event.cancelled)
+ playSingAnimUnsafe(event.direction, hasAnimation(event.animName) ? event.suffix : "", event.context, event.force, event.reversed, event.frame);
+ }
+
+ public function playSingAnimUnsafe(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, Force:Bool = true, Reversed:Bool = false, Frame:Int = 0)
+ {
+ var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
+ script.call("onPlaySingAnimUnsafe", [event]);
if (!event.cancelled)
playAnim(event.animName, event.force, event.context, event.reversed, event.frame);
}
@@ -161,7 +177,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
// [ true ][ false ][ true ]
// [ false ][ true ][ true ]
// [ true ][ true ][ false ]
- // bros provided evedince :skull:
+ // bros provided evidence :skull:
if (isPlayer != playerOffsets && switchAnims)
{
// character is flipped
diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx
index af36ff29..4351a9dc 100644
--- a/source/funkin/game/GameOverSubstate.hx
+++ b/source/funkin/game/GameOverSubstate.hx
@@ -108,7 +108,7 @@ class GameOverSubstate extends MusicBeatSubstate
if (controls.BACK)
{
if (PlayState.chartingMode && Charter.undos.unsaved)
- PlayState.instance.saveWarn(false);
+ game.saveWarn(false);
else {
PlayState.resetSongInfos();
if (Charter.instance != null) Charter.instance.__clearStatics();
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index a3d8ae14..1449fcc2 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -988,7 +988,7 @@ class PlayState extends MusicBeatState
curSong = songData.meta.name.toLowerCase();
inst = FlxG.sound.load(Paths.inst(SONG.meta.name, difficulty));
- if (SONG.meta.needsVoices != false) // null or true
+ if (Assets.exists(Paths.voices(SONG.meta.name, difficulty))) // null or true
vocals = FlxG.sound.load(Paths.voices(SONG.meta.name, difficulty));
else
vocals = new FlxSound();
diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx
index 037f9744..d743dd79 100644
--- a/source/funkin/game/StrumLine.hx
+++ b/source/funkin/game/StrumLine.hx
@@ -29,9 +29,9 @@ class StrumLine extends FlxTypedGroup {
*/
public var onNoteUpdate:FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
/**
- * Signal that triggers whenever a note is being updated. Similar to onNoteUpdate, except strumline specific.
+ * Signal that triggers whenever a note is being deleted. Similar to onNoteDelete, except strumline specific.
* To add a listener, do
- * `strumLine.onNoteUpdate.add(function(e:NoteUpdateEvent) {});`
+ * `strumLine.onNoteDelete.add(function(e:SimpleNoteEvent) {});`
*/
public var onNoteDelete:FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
/**
diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx
index 3c28344f..17d41e38 100644
--- a/source/funkin/menus/MainMenuState.hx
+++ b/source/funkin/menus/MainMenuState.hx
@@ -70,13 +70,12 @@ class MainMenuState extends MusicBeatState
FlxG.camera.follow(camFollow, null, 0.06);
- var versionText = [
+ var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, [
'Codename Engine v${Application.current.meta.get('version')}',
TU.translate("mainMenu.commit", [funkin.backend.system.macros.GitCommitMacro.commitNumber, funkin.backend.system.macros.GitCommitMacro.commitHash]),
- TU.translate("mainMenu.openMods", ["TAB"]),
+ TU.translate("mainMenu.openMods", [controls.getKeyName(SWITCHMOD)]),
''
- ].join('\n');
- var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, versionText);
+ ].join('\n'));
versionShit.y -= versionShit.height;
versionShit.scrollFactor.set();
add(versionShit);
diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx
index 3067a40b..094eb07b 100644
--- a/source/funkin/menus/PauseSubState.hx
+++ b/source/funkin/menus/PauseSubState.hx
@@ -113,7 +113,7 @@ class PauseSubState extends MusicBeatSubstate
pauseScript.call("postCreate");
- PlayState.instance.updateDiscordPresence();
+ game.updateDiscordPresence();
}
override function update(elapsed:Float)
@@ -153,7 +153,7 @@ class PauseSubState extends MusicBeatSubstate
close();
case "Restart Song":
parentDisabler.reset();
- PlayState.instance.registerSmoothTransition();
+ game.registerSmoothTransition();
FlxG.resetState();
case "Change Controls":
persistentDraw = false;
@@ -164,7 +164,7 @@ class PauseSubState extends MusicBeatSubstate
FlxG.switchState(new funkin.editors.charter.Charter(PlayState.SONG.meta.name, PlayState.difficulty, false));
case "Exit to menu":
if (PlayState.chartingMode && Charter.undos.unsaved)
- PlayState.instance.saveWarn(false);
+ game.saveWarn(false);
else {
PlayState.resetSongInfos();
if (Charter.instance != null) Charter.instance.__clearStatics();
@@ -177,16 +177,17 @@ class PauseSubState extends MusicBeatSubstate
}
override function destroy()
{
- if(FlxG.cameras.list.contains(camera))
- FlxG.cameras.remove(camera, true);
+ if(camera != FlxG.camera && _cameras != null) {
+ if(FlxG.cameras.list.contains(camera))
+ FlxG.cameras.remove(camera, true);
+ }
pauseScript.call("destroy");
pauseScript.destroy();
- if (pauseMusic != null)
- @:privateAccess {
- FlxG.sound.destroySound(pauseMusic);
- }
-
+ if(pauseMusic != null) {
+ @:privateAccess
+ FlxG.sound.destroySound(pauseMusic);
+ }
super.destroy();
}
diff --git a/source/funkin/menus/ui/Alphabet.hx b/source/funkin/menus/ui/Alphabet.hx
index 5ee79a7e..c76fcb42 100644
--- a/source/funkin/menus/ui/Alphabet.hx
+++ b/source/funkin/menus/ui/Alphabet.hx
@@ -51,7 +51,7 @@ class Alphabet extends FlxSpriteGroup
// TODO: fix this shit refreshing
public function refreshAlphabetXML(path:String) {
- AlphaCharacter.__alphaPath = path;
+ AlphaCharacter.__alphaPath = Paths.getAssetsRoot() + path;
try {
var xml = new Access(Xml.parse(Assets.getText(path)).firstElement());
AlphaCharacter.boldAnims = [];
@@ -86,7 +86,7 @@ class Alphabet extends FlxSpriteGroup
isBold = bold;
var alphabetPath = Paths.xml("alphabet");
- if (alphabetPath != AlphaCharacter.__alphaPath) {
+ if (Paths.getAssetsRoot() + alphabetPath != AlphaCharacter.__alphaPath) {
refreshAlphabetXML(alphabetPath);
}
#if MOD_SUPPORT else {
@@ -122,12 +122,16 @@ class Alphabet extends FlxSpriteGroup
doSplitWords();
var xPos:Float = 0;
- for (character in splitWords)
+ var curRow:Int = 0;
+ for (i=>character in splitWords)
{
if (lastSprite != null)
xPos = lastSprite.x + lastSprite.width - x;
+ if (xPosResetted && !(xPosResetted = false)) xPos = 0;
+
var letter:AlphaCharacter = new AlphaCharacter(xPos, 0);
+ letter.row = curRow;
if (isBold)
letter.createBold(character);
else
@@ -141,6 +145,11 @@ class Alphabet extends FlxSpriteGroup
add(letter);
lastSprite = letter;
+ if (_finalText.fastCodeAt(i) == "\n".code)
+ {
+ xPosResetted = true;
+ curRow += 1;
+ }
}
}
@@ -247,6 +256,8 @@ class AlphaCharacter extends FlxSprite
animation.addByPrefix(letter, boldAnims[letter], 24);
animation.play(letter);
updateHitbox();
+
+ y += row * height;
}
public function createLetter(letter:String):Void
diff --git a/source/funkin/options/OptionsMenu.hx b/source/funkin/options/OptionsMenu.hx
index b346fe5d..af0e8c12 100644
--- a/source/funkin/options/OptionsMenu.hx
+++ b/source/funkin/options/OptionsMenu.hx
@@ -48,8 +48,6 @@ class OptionsMenu extends TreeMenu {
bg.antialiasing = true;
add(bg);
- Framerate.offset.y = 60;
-
main = new OptionsScreen("Options", "Select a category to continue.", [for(o in mainOptions) new TextOption(o.name, o.desc, function() {
if (o.substate != null) {
persistentUpdate = false;
diff --git a/source/funkin/options/TreeMenu.hx b/source/funkin/options/TreeMenu.hx
index 6fb4a8a5..4faa8cd0 100644
--- a/source/funkin/options/TreeMenu.hx
+++ b/source/funkin/options/TreeMenu.hx
@@ -7,6 +7,7 @@ import funkin.backend.FunkinText;
import funkin.editors.ui.UIState;
import funkin.menus.MainMenuState;
import funkin.options.type.OptionType;
+import funkin.backend.system.framerate.Framerate;
class TreeMenu extends UIState {
public var main:OptionsScreen;
@@ -97,6 +98,8 @@ class TreeMenu extends UIState {
var menuChangeTween:FlxTween;
public override function update(elapsed:Float) {
super.update(elapsed);
+
+ Framerate.offset.y = pathBG.height;
// in case path gets so long it goes offscreen
pathLabel.x = lerp(pathLabel.x, Math.max(0, FlxG.width - 4 - pathLabel.width), 0.125);
diff --git a/source/openfl/utils/Assets.hx b/source/openfl/utils/Assets.hx
index e08852cd..db92e530 100644
--- a/source/openfl/utils/Assets.hx
+++ b/source/openfl/utils/Assets.hx
@@ -91,7 +91,7 @@ class Assets
@usage var bitmap = new Bitmap (Assets.getBitmapData ("image.png"));
@param id The ID or asset path for the bitmap
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
- @param useCache Whenever the image should be immediately pushed to GPU.
+ @param pushToGPU Whenever the image should be immediately pushed to GPU.
@return A new BitmapData object
**/
public static function getBitmapData(id:String, useCache:Bool = true, pushToGPU:Bool = true):BitmapData