diff --git a/README.md b/README.md index b4d4bcc9..93b36034 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Also, the command `.\cne test` uses the source assets folder instead of the expo ## Codename Engine Codename Engine is a new Friday Night Funkin' Engine aimed at simplifying modding, along with extensiblity and ease of use.
-Make sure to read the wiki and join the Discord server linked there!
-#### It includes many new features, as seen [here](FEATURES.md)
+### Before making issues or need help with something, check our website [HERE](https://fnf-cne-devs.github.io/) (it contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more)!!! +#### The Engine includes many new features, as seen [here](FEATURES.md)
#### Wanna see the new features added in the most recent update? Click [here](PATCHNOTES.md)
## How to download diff --git a/art/flashFiles/TitleEnter.fla b/art/flashFiles/TitleEnter.fla new file mode 100644 index 00000000..2605cfd3 Binary files /dev/null and b/art/flashFiles/TitleEnter.fla differ diff --git a/assets/data/alphabet.xml b/assets/data/alphabet.xml index 8ae172cd..252af638 100644 --- a/assets/data/alphabet.xml +++ b/assets/data/alphabet.xml @@ -2,33 +2,76 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/data/alphabet/bold.xml b/assets/data/alphabet/bold.xml index b39cc25f..5be5fa4b 100644 --- a/assets/data/alphabet/bold.xml +++ b/assets/data/alphabet/bold.xml @@ -1,6 +1,49 @@ - + menus/alphabet-bold - LETTER bold + character-LETTER0 + character-ampersand + character-anglebracket-left + character-anglebracket-right + character-asterisk + character-at + character-backslash + character-backtick + character-caret + character-colon + character-comma + character-curlybracket-left + character-curlybracket-right + character-dollar + character-doublequote0 + character-equal + character-exclamationmark + character-hyphen + character-percent + character-period + character-plus + character-pound + character-questionmark0 + character-roundbracket-left + character-roundbracket-right + character-semicolon + character-singlequote + character-slash + character-squarebracket-left + character-squarebracket-right + character-tilde0 + character-underscore0 + character-verticalbar0 + + character-zero + character-one + character-two + character-three + character-four + character-five + character-six + character-seven + character-eight + character-nine \ No newline at end of file diff --git a/assets/data/alphabet/normal.xml b/assets/data/alphabet/normal.xml index a02526db..a82323fe 100644 --- a/assets/data/alphabet/normal.xml +++ b/assets/data/alphabet/normal.xml @@ -1,13 +1,17 @@ - + menus/alphabet LETTER capital LETTER lowercase LETTER + g lowercase + j lowercase + p lowercase + q lowercase + y lowercase dollarsign - hashtag amp right arrow left arrow diff --git a/assets/data/config/credits.xml b/assets/data/config/credits.xml deleted file mode 100644 index 4f300fcb..00000000 --- a/assets/data/config/credits.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/data/config/options.xml b/assets/data/config/options.xml deleted file mode 100644 index 888288d7..00000000 --- a/assets/data/config/options.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/data/dialogue/characters/senpai.hx b/assets/data/dialogue/characters/senpai.hx index cd17b115..1ea774d7 100644 --- a/assets/data/dialogue/characters/senpai.hx +++ b/assets/data/dialogue/characters/senpai.hx @@ -1,6 +1,6 @@ function postHide() { if(curTween != null) { - if(animation.curAnim?.name == 'angry-show') curTween.cancel(); + if(getAnimName() == 'angry-show') curTween.cancel(); else curTween.percent = 1; } -} \ No newline at end of file +} diff --git a/assets/data/titlescreen/titlescreen.xml b/assets/data/titlescreen/titlescreen.xml index f16c8b62..323e9ef1 100644 --- a/assets/data/titlescreen/titlescreen.xml +++ b/assets/data/titlescreen/titlescreen.xml @@ -7,7 +7,7 @@ - + diff --git a/assets/fonts/StatusPlz.ttf b/assets/fonts/StatusPlz.ttf new file mode 100644 index 00000000..0f31536f Binary files /dev/null and b/assets/fonts/StatusPlz.ttf differ diff --git a/assets/fonts/vcr.ttf b/assets/fonts/vcr.ttf index dcca687a..24a56b5d 100644 Binary files a/assets/fonts/vcr.ttf and b/assets/fonts/vcr.ttf differ diff --git a/assets/images/menus/alphabet-bold.png b/assets/images/menus/alphabet-bold.png index 012721ce..004a99f5 100644 Binary files a/assets/images/menus/alphabet-bold.png and b/assets/images/menus/alphabet-bold.png differ diff --git a/assets/images/menus/alphabet-bold.xml b/assets/images/menus/alphabet-bold.xml index 26ce48db..7ffb4267 100644 --- a/assets/images/menus/alphabet-bold.xml +++ b/assets/images/menus/alphabet-bold.xml @@ -1,153 +1,514 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/languages/en/Editors.xml b/assets/languages/en/Editors.xml index 71182b3a..0f35b716 100644 --- a/assets/languages/en/Editors.xml +++ b/assets/languages/en/Editors.xml @@ -4,10 +4,11 @@ Autosaving in {0} seconds{1} (Canceled)! - Save & Close - Save - Close Ok + Cancel + Save + Save & Close + Close @@ -260,9 +261,11 @@ + Press ACCEPT to edit this folder. Press ACCEPT to edit this character. New Character Select a character to edit + Select a character to edit in {0} New Character: Feature Not Implemented! diff --git a/assets/languages/en/Main.xml b/assets/languages/en/Main.xml index d8eff461..dec03273 100644 --- a/assets/languages/en/Main.xml +++ b/assets/languages/en/Main.xml @@ -72,7 +72,8 @@ WARNING - This engine is still in a *{0}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress {1} to continue + This engine is still in a *{0}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub. + Press {0} to continue @@ -100,5 +101,7 @@ Easy Normal Hard + Erect + Nightmare \ No newline at end of file diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml index f7debfaf..51e317eb 100644 --- a/assets/languages/en/Options.xml +++ b/assets/languages/en/Options.xml @@ -42,8 +42,7 @@ Engine - - Change Mod or Mode + Mod/Mode diff --git a/assets/shaders/engine/editorBlur.frag b/assets/shaders/engine/editorBlur.frag index 59b91c72..85754b99 100644 --- a/assets/shaders/engine/editorBlur.frag +++ b/assets/shaders/engine/editorBlur.frag @@ -3,19 +3,17 @@ // Used for editors -int steps = 16; -int stepsInside = 2; -float strength = 0.0075; +const int steps = 16; +const int stepsInside = 2; +const float strength = 0.0075; + vec4 getColor(vec2 pos) { - vec2 ps = (pos); - ps = clamp(ps, vec2(0.0), 1.0 - (1.0 / openfl_TextureSize.xy)); - return flixel_texture2D(bitmap, (ps)); + pos = clamp(pos, vec2(0.0), vec2(1.0));//1.0 - (1.0 / openfl_TextureSize.xy)); + return flixel_texture2D(bitmap, pos); } + void main() { - // vec2 camPos = getCamPos(openfl_TextureCoordv); vec2 camPos = openfl_TextureCoordv; - if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0) - return; vec4 color = getColor(camPos); float fsteps = float(steps); diff --git a/assets/shaders/engine/editorBlurFast.frag b/assets/shaders/engine/editorBlurFast.frag index 75ef96af..db476ae8 100644 --- a/assets/shaders/engine/editorBlurFast.frag +++ b/assets/shaders/engine/editorBlurFast.frag @@ -2,58 +2,29 @@ // Used for editors (faster) -//#define iResolution _camSize -#define getTexture textureCam - -#define iResolution openfl_TextureSize -//#define getTexture flixel_texture2D - -float uBlur = 0.015; -float uBrightness = 0.6; +const float uBlur = 0.015; +const float uBrightness = 0.6; vec4 getColor(vec2 pos) { - vec2 ps = (pos); - if (ps.x < 0.0) ps.x = 0.0; - //else if (ps.x > 1.0 - (1.0 / iResolution.x)) ps.x = 1.0 - (1.0 / iResolution.x); - else if (ps.x > 1.0) return vec4(0.0); - if (ps.y < 0.0) ps.y = 0.0; - //else if (ps.y > 1.0 - (1.0 / iResolution.y)) return ps.y = 1.0 - (1.0 / iResolution.y); - else if (ps.y > 1.0) return vec4(0.0); - return flixel_texture2D(bitmap, (ps)); + pos = clamp(pos, vec2(0.0), vec2(1.0));//1.0 - (1.0 / openfl_TextureSize.xy)); + return flixel_texture2D(bitmap, pos); } - -vec2 fixvec2(float x, float y) { // makes an uv the same across sizes - vec2 val = vec2(x, y); - val.xy *= vec2(1280.0, 720.0); - val.xy /= iResolution.xy; - return val; -} -vec2 fixvec2(vec2 uv) { // makes an uv the same across sizes - vec2 val = uv; - val.xy *= vec2(1280.0, 720.0); - val.xy /= iResolution.xy; - return val; -} +uniform sampler2D noiseTexture; +uniform vec2 noiseTextureSize; vec2 random(vec2 p) { - p = vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))); - return fract(sin(p)*4375.5); + p *= openfl_TextureSize; + return texture2D(noiseTexture, p / noiseTextureSize).rg - vec2(0.5); } void main() { - vec2 camPos = (openfl_TextureCoordv); - //vec2 camPos = openfl_TextureCoordv; - if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0) - return; + vec2 camPos = openfl_TextureCoordv; + vec2 blur = vec2(uBlur) * vec2(1.0, openfl_TextureSize.x / openfl_TextureSize.y); - //vec4 color = getColor(camPos); - - vec2 blur = vec2(uBlur) * vec2(1.0, iResolution.x / iResolution.y); - - vec4 a = getColor(camPos+(random(camPos)*blur - blur / 2.0)) * uBrightness; - a += getColor(camPos+(random(camPos+0.1)*blur - blur / 2.0)) * uBrightness; - a += getColor(camPos+(random(camPos+0.2)*blur - blur / 2.0)) * uBrightness; - //a += getColor(camPos+(random(camPos+0.3)*blur - blur / 2.0)) * uBrightness; - gl_FragColor = a / 3.0; + vec4 a = getColor(camPos+random(camPos)*blur); + a += getColor(camPos+random(camPos+0.1)*blur); + //a += getColor(camPos+random(camPos+0.2)*blur); + //a += getColor(camPos+random(camPos+0.3)*blur); + gl_FragColor = (a / 2.0) * uBrightness; } \ No newline at end of file diff --git a/assets/shaders/noise128.png b/assets/shaders/noise128.png new file mode 100644 index 00000000..682cb32a Binary files /dev/null and b/assets/shaders/noise128.png differ diff --git a/assets/shaders/noise256.png b/assets/shaders/noise256.png new file mode 100644 index 00000000..fd2a1410 Binary files /dev/null and b/assets/shaders/noise256.png differ diff --git a/assets/shaders/noise512.png b/assets/shaders/noise512.png new file mode 100644 index 00000000..d50270af Binary files /dev/null and b/assets/shaders/noise512.png differ diff --git a/project.xml b/project.xml index fc5f5474..c8bd462f 100644 --- a/project.xml +++ b/project.xml @@ -118,9 +118,6 @@ - - - diff --git a/source/StringTools.hx b/source/StringTools.hx index 0b495af1..40397636 100644 --- a/source/StringTools.hx +++ b/source/StringTools.hx @@ -219,7 +219,7 @@ class StringTools { If `start` is the empty String `""`, the result is true. **/ - public static #if (java || python || (js && js_es >= 6)) inline #end function startsWith(s:String, start:String):Bool { + public static #if (java || python || (js && js_es >= 6) || cpp) inline #end function startsWith(s:String, start:String):Bool { #if java return (cast s : java.NativeString).startsWith(start); #elseif hl @@ -230,6 +230,8 @@ class StringTools { return (cast s).startsWith(start); #elseif lua return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start); + #elseif cpp + return untyped s.__StartsWith(start); #else return (s.length >= start.length && s.indexOf(start, 0) == 0); #end @@ -242,7 +244,7 @@ class StringTools { If `end` is the empty String `""`, the result is true. **/ - public static #if (java || python || (js && js_es >= 6)) inline #end function endsWith(s:String, end:String):Bool { + public static #if (java || python || (js && js_es >= 6) || cpp) inline #end function endsWith(s:String, end:String):Bool { #if java return (cast s : java.NativeString).endsWith(end); #elseif hl @@ -255,6 +257,8 @@ class StringTools { return (cast s).endsWith(end); #elseif lua return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end); + #elseif cpp + return untyped s.__EndsWith(end); #else var elen = end.length; var slen = s.length; diff --git a/source/flx3d/Flx3DCamera.hx b/source/flx3d/Flx3DCamera.hx index 4e1da93d..129ace5d 100644 --- a/source/flx3d/Flx3DCamera.hx +++ b/source/flx3d/Flx3DCamera.hx @@ -87,7 +87,7 @@ class Flx3DCamera extends FlxCamera { default: new OBJParser(); }, (event:Asset3DEvent) -> { if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { - var mesh:Mesh = cast(event.asset, Mesh); + var mesh:Mesh = cast event.asset; if (material != null) mesh.material = material; meshes.push(mesh); diff --git a/source/flx3d/Flx3DView.hx b/source/flx3d/Flx3DView.hx index e76500c3..5413fe94 100644 --- a/source/flx3d/Flx3DView.hx +++ b/source/flx3d/Flx3DView.hx @@ -60,7 +60,7 @@ class Flx3DView extends FlxView3D { default: new OBJParser(); }, (event:Asset3DEvent) -> { if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { - var mesh:Mesh = cast(event.asset, Mesh); + var mesh:Mesh = cast event.asset; if (material != null) mesh.material = material; meshes.push(mesh); diff --git a/source/funkin/backend/MusicBeatGroup.hx b/source/funkin/backend/MusicBeatGroup.hx index ec6f2693..5cccf0f6 100644 --- a/source/funkin/backend/MusicBeatGroup.hx +++ b/source/funkin/backend/MusicBeatGroup.hx @@ -4,12 +4,12 @@ import funkin.backend.system.interfaces.IBeatReceiver; class MusicBeatGroup extends FlxTypedSpriteGroup implements IBeatReceiver { public function beatHit(curBeat:Int) { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).beatHit(curBeat); } public function stepHit(curStep:Int) { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).stepHit(curStep); } public function measureHit(curMeasure:Int) { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver = cast e;_;}).measureHit(curMeasure); } } \ No newline at end of file diff --git a/source/funkin/backend/MusicBeatState.hx b/source/funkin/backend/MusicBeatState.hx index e519ed0e..56dc1874 100644 --- a/source/funkin/backend/MusicBeatState.hx +++ b/source/funkin/backend/MusicBeatState.hx @@ -192,19 +192,19 @@ class MusicBeatState extends FlxState implements IBeatReceiver @:dox(hide) public function stepHit(curStep:Int):Void { - for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep); + for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).stepHit(curStep); call("stepHit", [curStep]); } @:dox(hide) public function beatHit(curBeat:Int):Void { - for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat); + for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).beatHit(curBeat); call("beatHit", [curBeat]); } @:dox(hide) public function measureHit(curMeasure:Int):Void { - for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure); + for(e in members) if (e != null && e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).measureHit(curMeasure); call("measureHit", [curMeasure]); } @@ -278,8 +278,9 @@ class MusicBeatState extends FlxState implements IBeatReceiver public override function resetSubState() { super.resetSubState(); if (subState != null && subState is MusicBeatSubstate) { - cast(subState, MusicBeatSubstate).parent = this; - cast(subState, MusicBeatSubstate).onSubstateOpen(); + var subState:MusicBeatSubstate = cast subState; + subState.parent = this; + subState.onSubstateOpen(); } } } diff --git a/source/funkin/backend/MusicBeatSubstate.hx b/source/funkin/backend/MusicBeatSubstate.hx index d8ee8076..b8d26038 100644 --- a/source/funkin/backend/MusicBeatSubstate.hx +++ b/source/funkin/backend/MusicBeatSubstate.hx @@ -181,19 +181,19 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver @:dox(hide) public function stepHit(curStep:Int):Void { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).stepHit(curStep); call("stepHit", [curStep]); } @:dox(hide) public function beatHit(curBeat:Int):Void { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).beatHit(curBeat); call("beatHit", [curBeat]); } @:dox(hide) public function measureHit(curMeasure:Int):Void { - for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure); + for(e in members) if (e is IBeatReceiver) ({var _:IBeatReceiver=cast e;_;}).measureHit(curMeasure); call("measureHit", [curMeasure]); } @@ -256,7 +256,8 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver public override function resetSubState() { if (subState != null && subState is MusicBeatSubstate) { - cast(subState, MusicBeatSubstate).parent = this; + var subState:MusicBeatSubstate = cast subState; + subState.parent = this; super.resetSubState(); if (subState != null) cast(subState, MusicBeatSubstate).onSubstateOpen(); diff --git a/source/funkin/backend/assets/Paths.hx b/source/funkin/backend/assets/Paths.hx index de52abe5..9ccec02a 100644 --- a/source/funkin/backend/assets/Paths.hx +++ b/source/funkin/backend/assets/Paths.hx @@ -124,6 +124,14 @@ class Paths return getPath('data/characters/$character.xml', null); } + /** + * Gets the name of a registered font. + * @param font The font's path (if it's already passed as a font name, the same name will be returned) + */ + inline static public function getFontName(font:String) { + return OpenFlAssets.exists(font, FONT) ? OpenFlAssets.getFont(font).fontName : font; + } + public static inline function font(key:String) { return getPath('fonts/$key'); } diff --git a/source/funkin/backend/scripting/MultiThreadedScript.hx b/source/funkin/backend/scripting/MultiThreadedScript.hx index 3ba51f52..24754c7c 100644 --- a/source/funkin/backend/scripting/MultiThreadedScript.hx +++ b/source/funkin/backend/scripting/MultiThreadedScript.hx @@ -33,8 +33,8 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe if (parentScript != null) { if (script is HScript && parentScript is HScript) { - var hscript = cast(script, HScript); - var parentHScript = cast(parentScript, HScript); + var hscript:HScript = cast script; + var parentHScript:HScript = cast parentScript; hscript.interp.variables = parentHScript.interp.variables; hscript.interp.publicVariables = parentHScript.interp.publicVariables; diff --git a/source/funkin/backend/scripting/events/CharacterNodeEvent.hx b/source/funkin/backend/scripting/events/CharacterNodeEvent.hx new file mode 100644 index 00000000..9577a64f --- /dev/null +++ b/source/funkin/backend/scripting/events/CharacterNodeEvent.hx @@ -0,0 +1,21 @@ +package funkin.backend.scripting.events; + +import funkin.game.Character; +import haxe.xml.Access; + +final class CharacterNodeEvent extends CancellableEvent { + /** + * The character instance + */ + public var character:Character; + + /** + * The node which is currently being parsed + */ + public var node:Access; + + /** + * The name of the node, quicker access than e.node.name + */ + public var name:String; +} \ No newline at end of file diff --git a/source/funkin/backend/scripting/events/CharacterXMLEvent.hx b/source/funkin/backend/scripting/events/CharacterXMLEvent.hx new file mode 100644 index 00000000..e4f107fd --- /dev/null +++ b/source/funkin/backend/scripting/events/CharacterXMLEvent.hx @@ -0,0 +1,16 @@ +package funkin.backend.scripting.events; + +import funkin.game.Character; +import haxe.xml.Access; + +final class CharacterXMLEvent extends CancellableEvent { + /** + * The character instance + */ + public var character:Character; + + /** + * The xml + */ + public var xml:Access; +} \ No newline at end of file diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx index 8d4ef85a..f9758b94 100644 --- a/source/funkin/backend/system/Conductor.hx +++ b/source/funkin/backend/system/Conductor.hx @@ -181,7 +181,11 @@ class Conductor private static var __updateMeasure:Bool; private static function update() { - if (FlxG.state != null && FlxG.state is MusicBeatState && cast(FlxG.state, MusicBeatState).cancelConductorUpdate) return; + if (FlxG.state != null && FlxG.state is MusicBeatState) { + var state:MusicBeatState = cast FlxG.state; + if(state.cancelConductorUpdate) + return; + } __updateSongPos(FlxG.elapsed); @@ -233,7 +237,7 @@ class Conductor var state = FlxG.state; while(state != null) { if (state is IBeatReceiver && (state.subState == null || state.persistentUpdate)) { - var st = cast(state, IBeatReceiver); + var st:IBeatReceiver = cast state; if (curStep > oldStep) { for(i in oldStep...curStep) { st.stepHit(i+1); diff --git a/source/funkin/backend/system/Logs.hx b/source/funkin/backend/system/Logs.hx index 4f47c150..336f9443 100644 --- a/source/funkin/backend/system/Logs.hx +++ b/source/funkin/backend/system/Logs.hx @@ -11,8 +11,7 @@ class Logs { public static var nativeTrace = Log.trace; public static function init() { - - Log.trace = function(v : Dynamic, ?infos : Null) { + Log.trace = function(v:Dynamic, ?infos:Null) { var data = [ logText('${infos.fileName}:${infos.lineNumber}: ', CYAN), logText(Std.string(v)) @@ -28,22 +27,48 @@ class Logs { __showInConsole(prepareColoredTrace(data, TRACE)); }; - LogFrontEnd.onLogs = function(Data, Style, FireOnce) { + LogFrontEnd.onLogs = function(data, style, fireOnce) { var prefix = "[FLIXEL]"; var color:ConsoleColor = LIGHTGRAY; var level:Level = INFO; - if (Style == LogStyle.CONSOLE) {prefix = "> "; color = WHITE; level = INFO; } else - if (Style == LogStyle.ERROR) {prefix = "[FLIXEL]"; color = RED; level = ERROR; } else - if (Style == LogStyle.NORMAL) {prefix = "[FLIXEL]"; color = WHITE; level = INFO; } else - if (Style == LogStyle.NOTICE) {prefix = "[FLIXEL]"; color = GREEN; level = VERBOSE;} else - if (Style == LogStyle.WARNING) {prefix = "[FLIXEL]"; color = YELLOW; level = WARNING;} + if (style == LogStyle.CONSOLE) // cant place a switch here as these arent inline values - Nex + { + prefix = "> "; + color = WHITE; + level = INFO; + } + else if (style == LogStyle.ERROR) + { + prefix = "[FLIXEL]"; + color = RED; + level = ERROR; + } + else if (style == LogStyle.NORMAL) + { + prefix = "[FLIXEL]"; + color = WHITE; + level = INFO; + } + else if (style == LogStyle.NOTICE) + { + prefix = "[FLIXEL]"; + color = GREEN; + level = VERBOSE; + } + else if (style == LogStyle.WARNING) + { + prefix = "[FLIXEL]"; + color = YELLOW; + level = WARNING; + } - var d:Dynamic = Data; + var d:Dynamic = data; if (!(d is Array)) d = [d]; var a:Array = d; var strs = [for(e in a) Std.string(e)]; - for(e in strs) { + for(e in strs) + { Logs.trace('$prefix $e', level, color); } }; @@ -55,7 +80,8 @@ class Logs { logText('[ '), logText('${Std.string(time.getHours()).addZeros(2)}:${Std.string(time.getMinutes()).addZeros(2)}:${Std.string(time.getSeconds()).addZeros(2)}', DARKMAGENTA), logText(' |'), - switch(level) { + switch (level) + { case WARNING: logText(' WARNING ', DARKYELLOW); case ERROR: logText(' ERROR ', DARKRED); case TRACE: logText(' TRACE ', GRAY); @@ -79,7 +105,7 @@ class Logs { } public static function __showInConsole(text:Array) { - #if sys + #if (sys && !mobile) while(__showing) { Sys.sleep(0.05); } @@ -91,15 +117,23 @@ class Logs { NativeAPI.setConsoleColors(); Sys.print("\r\n"); __showing = false; + #elseif mobile + while(__showing) { + Sys.sleep(0.05); + } + __showing = true; + @:privateAccess + Sys.print([for(t in text) t.text].join("")); + __showing = false; #else @:privateAccess nativeTrace([for(t in text) t.text].join("")); #end } - public static function traceColored(text:Array, level:Level = INFO) { + public static function traceColored(text:Array, level:Level = INFO) __showInConsole(prepareColoredTrace(text, level)); - } + public static function trace(text:String, level:Level = INFO, color:ConsoleColor = LIGHTGRAY, ?prefix:String) { var text = [logText(text, color)]; if(prefix != null) text.insert(0, getPrefix(prefix)); @@ -144,7 +178,8 @@ enum abstract Level(Int) { var SUCCESS = 5; var FAILURE = 6; } + typedef LogText = { var text:String; var color:ConsoleColor; -} \ No newline at end of file +} diff --git a/source/funkin/backend/system/Main.hx b/source/funkin/backend/system/Main.hx index 9f13e826..7744cc90 100644 --- a/source/funkin/backend/system/Main.hx +++ b/source/funkin/backend/system/Main.hx @@ -1,5 +1,6 @@ package funkin.backend.system; +import funkin.backend.utils.translations.FormatUtil; import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond; import flixel.addons.transition.FlxTransitionableState; import flixel.addons.transition.TransitionData; @@ -58,6 +59,12 @@ class Main extends Sprite public static var gameThreads:Array = []; #end + public static function preInit() { + funkin.backend.utils.NativeAPI.registerAsDPICompatible(); + funkin.backend.system.CommandLineHandler.parseCommandLine(Sys.args()); + funkin.backend.system.Main.fixWorkingDirectory(); + } + public function new() { super(); @@ -166,6 +173,8 @@ class Main extends Sprite } public static function refreshAssets() { + WindowUtils.resetTitle(); + FlxSoundTray.volumeChangeSFX = Paths.sound('menu/volume'); FlxSoundTray.volumeUpChangeSFX = null; FlxSoundTray.volumeDownChangeSFX = null; diff --git a/source/funkin/backend/system/framerate/SystemInfo.hx b/source/funkin/backend/system/framerate/SystemInfo.hx index 79580a21..192ad1df 100644 --- a/source/funkin/backend/system/framerate/SystemInfo.hx +++ b/source/funkin/backend/system/framerate/SystemInfo.hx @@ -91,7 +91,7 @@ class SystemInfo extends FramerateCategory { #end if(openfl.display3D.Context3D.__glMemoryTotalAvailable != -1) { - var vRAMBytes:UInt = cast(flixel.FlxG.stage.context3D.gl.getParameter(openfl.display3D.Context3D.__glMemoryTotalAvailable), UInt); + var vRAMBytes:UInt = cast flixel.FlxG.stage.context3D.gl.getParameter(openfl.display3D.Context3D.__glMemoryTotalAvailable); if (vRAMBytes == 1000 || vRAMBytes == 1 || vRAMBytes <= 0) Logs.error('Unable to grab GPU VRAM'); else diff --git a/source/funkin/backend/system/modules/AudioSwitchFix.hx b/source/funkin/backend/system/modules/AudioSwitchFix.hx index 232c1eb8..86ebcb0a 100644 --- a/source/funkin/backend/system/modules/AudioSwitchFix.hx +++ b/source/funkin/backend/system/modules/AudioSwitchFix.hx @@ -62,6 +62,7 @@ class AudioSwitchFix { } } +@:dox(hide) typedef PlayingSound = { var sound:FlxSound; var time:Float; diff --git a/source/funkin/backend/system/modules/CrashHandler.hx b/source/funkin/backend/system/modules/CrashHandler.hx index 124b915c..1debede9 100644 --- a/source/funkin/backend/system/modules/CrashHandler.hx +++ b/source/funkin/backend/system/modules/CrashHandler.hx @@ -20,10 +20,10 @@ class CrashHandler { public static function onUncaughtError(e:UncaughtErrorEvent) { var m:String = e.error; if (Std.isOfType(e.error, Error)) { - var err = cast(e.error, Error); + var err:Error = cast e.error; m = '${err.message}'; } else if (Std.isOfType(e.error, ErrorEvent)) { - var err = cast(e.error, ErrorEvent); + var err:ErrorEvent = cast e.error; m = '${err.text}'; } var stack = CallStack.exceptionStack(); diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 52a47dc2..df8bf94d 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -626,7 +626,7 @@ class CoolUtil var fmt = new FlxTextFormat(); fmt.format.color = Reflect.hasField(fmtt, "color") ? FlxColor.fromString(fmtt.color) : text.color; - fmt.format.font = Reflect.hasField(fmtt, "font") ? Paths.font(fmtt.font) : text.font; + fmt.format.font = Reflect.hasField(fmtt, "font") ? Paths.getFontName(Paths.font(fmtt.font)) : text.font; fmt.format.size = Reflect.hasField(fmtt, "size") ? Std.parseInt(fmtt.size) : text.size; fmt.format.italic = Reflect.hasField(fmtt, "italic") ? fmtt.italic == "true" : text.italic; fmt.format.bold = Reflect.hasField(fmtt, "bold") ? fmtt.bold == "true" : text.bold; @@ -751,7 +751,10 @@ class CoolUtil */ @:noUsing public static inline function openURL(url:String) { #if linux - Sys.command('/usr/bin/xdg-open', [url]); + // generally `xdg-open` should work in every distro + var cmd = Sys.command("xdg-open", [url]); + // run old command JUST IN CASE it fails, which it shouldn't + if (cmd != 0) cmd = Sys.command("/usr/bin/xdg-open", [url]); #else FlxG.openURL(url); #end diff --git a/source/funkin/backend/utils/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx index 6c27629e..cd27cb0e 100644 --- a/source/funkin/backend/utils/MemoryUtil.hx +++ b/source/funkin/backend/utils/MemoryUtil.hx @@ -140,14 +140,16 @@ class MemoryUtil { reg.match(process.stdout.readAll().toString()); if (process.exitCode() == 0) return reg.matched(1); #elseif linux - var process = new HiddenProcess("sudo", ["dmidecode", "--type", "17"]); + /*var process = new HiddenProcess("sudo", ["dmidecode", "--type", "17"]); if (process.exitCode() != 0) return "Unknown"; var lines = process.stdout.readAll().toString().split("\n"); for (line in lines) { if (line.startsWith("Type:")) { return line.substring("Type:".length).trim(); } - } + }*/ + // TODO: sort of unsafe? also requires users to use `sudo` + // when launching the engine through the CLI, REIMPLEMENT LATER. #end return "Unknown"; } diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx index 78f0b38d..45759231 100644 --- a/source/funkin/backend/utils/NativeAPI.hx +++ b/source/funkin/backend/utils/NativeAPI.hx @@ -113,8 +113,8 @@ class NativeAPI { if(backgroundColor == NONE) backgroundColor = BLACK; - var fg = cast(foregroundColor, Int); - var bg = cast(backgroundColor, Int); + var fg:Int = cast foregroundColor; + var bg:Int = cast backgroundColor; Windows.setConsoleColors((bg * 16) + fg); #elseif sys Sys.print("\x1b[0m"); diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx index 1a272757..5448ef11 100644 --- a/source/funkin/backend/utils/XMLUtil.hx +++ b/source/funkin/backend/utils/XMLUtil.hx @@ -6,6 +6,13 @@ import funkin.backend.FunkinSprite.XMLAnimType; import funkin.backend.FunkinSprite; import funkin.game.Character; import funkin.backend.system.ErrorCode; +import funkin.backend.FunkinSprite.XMLAnimType; +import flixel.util.FlxColor; +import haxe.xml.Access; +import funkin.backend.scripting.Script; +import funkin.backend.scripting.DummyScript; +import funkin.backend.scripting.ScriptPack; +import flixel.util.typeLimit.OneOfTwo; import funkin.backend.system.interfaces.IOffsetCompatible; import haxe.xml.Access; @@ -252,7 +259,7 @@ class XMLUtil { cast(sprite, IOffsetCompatible).addOffset(animData.name, animData.x, animData.y); if (sprite is FunkinSprite) { - var xmlSpr = cast(sprite, FunkinSprite); + var xmlSpr:FunkinSprite = cast sprite; var name = animData.name; switch(animData.animType) { case BEAT: @@ -328,6 +335,51 @@ class XMLUtil { } } +class XMLImportedScriptInfo { + public var path:String; + public var shortLived:Bool = false; + public var loadBefore:Bool = true; + public var importStageSprites:Bool = false; // maybe will change later?? - Nex + public var parentScriptPack:ScriptPack = null; + + public function new(path:String, parentScriptPack:ScriptPack) { + this.parentScriptPack = parentScriptPack; + this.path = path; + } + + public function getScript():Script + return parentScriptPack == null ? null : parentScriptPack.getByPath(path); + + public static function prepareInfos(node:Access, parentScriptPack:ScriptPack, ?onScriptPreLoad:XMLImportedScriptInfo->Void):XMLImportedScriptInfo { + if (!node.has.script || parentScriptPack == null) return null; + + var folder = node.getAtt("folder").getDefault("data/scripts/"); + if (!folder.endsWith("/")) folder += "/"; + + var path = Paths.script(folder + node.getAtt("script")); + var daScript = Script.create(path); + if (daScript is DummyScript) { + Logs.trace('Script Extension at ${path} does not exist.', ERROR); + return null; + } + + var infos = new XMLImportedScriptInfo(daScript.path, parentScriptPack); + infos.shortLived = node.getAtt("isShortLived") == "true" || node.getAtt("shortLived") == "true"; + infos.importStageSprites = node.getAtt("importStageSprites") == "true"; + @:privateAccess infos.loadBefore = shouldLoadBefore(node); + + if (onScriptPreLoad != null) onScriptPreLoad(infos); + parentScriptPack.add(daScript); + daScript.set("scriptInfo", infos); + daScript.load(); + + return infos; + } + + @:dox(hide) public static inline function shouldLoadBefore(node:Access):Bool + return node.getAtt("loadBefore") != "false"; +} + typedef AnimData = { var name:String; var anim:String; diff --git a/source/funkin/backend/utils/translations/FormatUtil.hx b/source/funkin/backend/utils/translations/FormatUtil.hx index cb601fc7..300eef1e 100644 --- a/source/funkin/backend/utils/translations/FormatUtil.hx +++ b/source/funkin/backend/utils/translations/FormatUtil.hx @@ -5,7 +5,7 @@ package funkin.backend.utils.translations; * * For example if the parameter list is just an `Int` which is `9`, `You have been blue balled {0} times` becomes `You have been blue balled 9 times`. */ -class FormatUtil { +final class FormatUtil { private static var cache:Map = new Map(); private static var cacheStr:Map = new Map(); @@ -87,14 +87,17 @@ class ParamFormatInfo implements IFormatInfo { public function format(params:Array):String { if (params == null) params = []; - var str:String = ""; - for (i=>s in strings) { - str += s; - if (i < indexes.length) - str += params[indexes[i]]; - } + var lenStr = strings.length; + var lenInd = indexes.length; - return str; + var arr = new haxe.ds.Vector(lenStr + ((lenStr < lenInd) ? lenStr : lenInd)); + var i = 0; + for (idx=>s in strings) { + arr[i++] = s; + if (idx < lenInd) + arr[i++] = Std.string(params[indexes[idx]]); + } + return arr.join(""); } public function toString():String { diff --git a/source/funkin/editors/EditorPicker.hx b/source/funkin/editors/EditorPicker.hx index c6db792c..5cdf4146 100644 --- a/source/funkin/editors/EditorPicker.hx +++ b/source/funkin/editors/EditorPicker.hx @@ -206,7 +206,7 @@ class EditorPickerOption extends FlxTypedSpriteGroup { iconSpr.x = 25 + ((height - iconSpr.width) / 2); iconSpr.y = (height - iconSpr.height) / 2; - label = new Alphabet(25 + iconSpr.width + 25, 0, name, true); + label = new Alphabet(25 + iconSpr.width + 25, 0, name, "bold"); label.y = (height - label.height) / 2; selectionBG = new FlxSprite().makeGraphic(1, 1, -1); diff --git a/source/funkin/editors/character/CharacterSelection.hx b/source/funkin/editors/character/CharacterSelection.hx index 4416a1ae..b7a83adb 100644 --- a/source/funkin/editors/character/CharacterSelection.hx +++ b/source/funkin/editors/character/CharacterSelection.hx @@ -4,6 +4,7 @@ import funkin.game.Character; import funkin.options.OptionsScreen; import funkin.options.type.IconOption; import funkin.options.type.NewOption; +import funkin.options.type.TextOption; import funkin.options.type.OptionType; class CharacterSelection extends EditorTreeMenu @@ -16,22 +17,46 @@ class CharacterSelection extends EditorTreeMenu bgType = "charter"; super.create(); - var modsList:Array = Character.getList(true); + var isMods:Bool = true; + var modsList:Array = Character.getList(true, true); - var list:Array = [ - for (char in (modsList.length == 0 ? Character.getList(false) : modsList)) - new IconOption(char, translate("acceptCharacter"), Character.getIconFromCharName(char), - function() { - FlxG.switchState(new CharacterEditor(char)); - }) - ]; + if(modsList.length == 0) { + modsList = Character.getList(false, true); + isMods = false; + } - var newChar = translate("newCharacter"); - list.insert(0, new NewOption(newChar, newChar, function() { - openSubState(new UIWarningSubstate(translate("warnings.notImplemented-title"), translate("warnings.notImplemented-body"), [ - {label: TU.translate("editor.ok"), color: 0xFFFF0000, onClick: function(t) {}} - ])); - })); + function generateList(modsList:Array, isMods:Bool, folderPath:String = ""):Array { + var list:Array = []; + + for(char in modsList) { + if(char.endsWith("/")) { + var folderName = CoolUtil.getFilename(char.substr(0, char.length-1)); + + list.push(new TextOption(folderName + " >", translate("acceptFolder"), function() { + var newModsList = Character.getList(isMods, true, char); + var newList:Array = generateList(newModsList, isMods, folderPath + folderName + "/"); + optionsTree.add(new OptionsScreen(folderPath + folderName, translate("desc-folder", [folderPath + folderName + "/"]), newList)); + })); + } else { + list.push(new IconOption(char, translate("acceptCharacter"), Character.getIconFromCharName(folderPath + char, char), + function() { + FlxG.switchState(new CharacterEditor(folderPath + char)); + }) + ); + } + } + + var newChar = translate("newCharacter"); + list.insert(0, new NewOption(newChar, newChar, function() { + openSubState(new UIWarningSubstate(translate("warnings.notImplemented-title"), translate("warnings.notImplemented-body"), [ + {label: TU.translate("editor.ok"), color: 0xFFFF0000, onClick: function(t) {}} + ])); + })); + + return list; + } + + var list = generateList(modsList, isMods); main = new OptionsScreen(TU.translate("characterEditor.name"), translate("desc"), list); diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index e34818f1..be6d13a7 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -681,7 +681,8 @@ class Charter extends UIState { } for (group in [notesGroup, eventsGroup]) { - cast(group, FlxTypedGroup).forEach(function(s) { + var group:FlxTypedGroup = cast group; + group.forEach(function(s) { s.selected = false; if (gridActionType == NONE) { if (s is CharterNote) { @@ -746,21 +747,27 @@ class Charter extends UIState { selectionBox.bHeight = Std.int(Math.abs(mousePos.y - dragStartPos.y)); } else { if (FlxG.keys.pressed.SHIFT) { - for (group in [notesGroup, eventsGroup]) - for(n in cast(group, FlxTypedGroup)) + for (group in [notesGroup, eventsGroup]) { + var group:FlxTypedGroup = cast group; + for(n in group) if (n.handleSelection(selectionBox) && selection.contains(n)) selection.remove(n); + } } else if (FlxG.keys.pressed.CONTROL) { - for (group in [notesGroup, eventsGroup]) - for(n in cast(group, FlxTypedGroup)) + for (group in [notesGroup, eventsGroup]) { + var group:FlxTypedGroup = cast group; + for(n in group) if (n.handleSelection(selectionBox) && !selection.contains(n)) selection.push(n); + } } else { selection = []; - for (group in [notesGroup, eventsGroup]) - for(n in cast(group, FlxTypedGroup)) + for (group in [notesGroup, eventsGroup]) { + var group:FlxTypedGroup = cast group; + for(n in group) if (n.handleSelection(selectionBox)) selection.push(n); + } } selection = __fixSelection(selection); @@ -816,8 +823,14 @@ class Charter extends UIState { changePoint.put(); } - if (s is CharterNote) cast(s, CharterNote).snappedToStrumline = true; - if (s is UISprite) cast(s, UISprite).cursor = BUTTON; + if (s is CharterNote) { + var s:CharterNote = cast s; + s.snappedToStrumline = true; + } + if (s is UISprite) { + var s:UISprite = cast s; + s.cursor = BUTTON; + } } if (!(verticalChange == 0 && horizontalChange == 0)) { notesGroup.sortNotes(); eventsGroup.sortEvents(); @@ -1022,9 +1035,9 @@ class Charter extends UIState { if (selection.length <= 0) return []; notesGroup.autoSort = false; - for (objects in [notesGroup, eventsGroup]) { - var group = cast(objects, FlxTypedGroup); - var member = 0; + for (group in [notesGroup, eventsGroup]) { + var group:FlxTypedGroup = cast group; + var member:Int = 0; while(member < group.members.length) { var s = group.members[member]; if (selection.contains(s)) @@ -1188,7 +1201,7 @@ class Charter extends UIState { noteTypeText.x = noteTopButton.x + noteTopButton.bWidth + 6; noteTypeText.y = Std.int((noteTopButton.bHeight - noteTypeText.height) / 2); } - noteTypeText.text = '($noteType) ${noteTypes[noteType-1] == null ? TU.translate("noteTypes.default") : noteTypes[noteType-1]}'; + noteTypeText.text = '($noteType) ' + (noteTypes[noteType-1] == null ? TU.translate("charter.noteTypes.default") : noteTypes[noteType-1]); super.update(elapsed); @@ -1384,7 +1397,7 @@ class Charter extends UIState { var note:CharterNote = cast s; CNote(note.step - minStep, note.id, note.strumLineID, note.susLength, note.type); } else if (s is CharterEvent) { - var event = cast(s,CharterEvent); + var event:CharterEvent = cast s; CEvent(event.step - minStep, [for (event in event.events) Reflect.copy(event)]); } ]; @@ -1969,9 +1982,9 @@ typedef SelectionDragChange = { public inline function loop(onNote:CharterNote->Void, ?onEvent:CharterEvent->Void, ?draggableOnly:Bool = true) { for (s in this) { if (s is CharterNote && onNote != null && (draggableOnly ? s.draggable: true)) - onNote(cast(s, CharterNote)); + onNote(cast s); else if (s is CharterEvent && onEvent != null && (draggableOnly ? s.draggable: true)) - onEvent(cast(s, CharterEvent)); + onEvent(cast s); } } } diff --git a/source/funkin/editors/charter/CharterEvent.hx b/source/funkin/editors/charter/CharterEvent.hx index af8996a4..1a0abe81 100644 --- a/source/funkin/editors/charter/CharterEvent.hx +++ b/source/funkin/editors/charter/CharterEvent.hx @@ -63,7 +63,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable { generateDefaultIcon(event.name); case "Camera Movement": // custom icon for camera movement - var state = cast(FlxG.state, Charter); + var state:Charter = cast FlxG.state; if (event.params != null && event.params[0] != null && event.params[0] >= 0 && event.params[0] < state.strumLines.length) { // camera movement, use health icon var icon = Character.getIconFromCharName(state.strumLines.members[event.params[0]].strumLine.characters[0]); diff --git a/source/funkin/editors/charter/CharterEventAdd.hx b/source/funkin/editors/charter/CharterEventAdd.hx index cc4ce0bc..7fc74226 100644 --- a/source/funkin/editors/charter/CharterEventAdd.hx +++ b/source/funkin/editors/charter/CharterEventAdd.hx @@ -38,7 +38,7 @@ class CharterEventAdd extends UISliceSprite { curCharterEvent = null; this.step = step; this.y = (step * 40) - (bHeight / 2); - text.text = TU.translate("editors.addEvent"); + text.text = TU.translate("charter.addEvent"); framesOffset = 0; x = -(bWidth = 37 + Math.ceil(text.width)); } @@ -46,7 +46,7 @@ class CharterEventAdd extends UISliceSprite { public function updateEdit(event:CharterEvent) { curCharterEvent = event; this.y = event.y; - text.text = TU.translate("editors.editEvent"); + text.text = TU.translate("charter.editEvent"); framesOffset = 9; x = -(bWidth = 27 + Math.ceil(text.width) + event.bWidth); } diff --git a/source/funkin/editors/charter/CharterEventScreen.hx b/source/funkin/editors/charter/CharterEventScreen.hx index 2189e5af..522bab6a 100644 --- a/source/funkin/editors/charter/CharterEventScreen.hx +++ b/source/funkin/editors/charter/CharterEventScreen.hx @@ -174,7 +174,11 @@ class CharterEventScreen extends UISubstateWindow { colorWheel; case TDropDown(options): addLabel(); - var dropdown = new UIDropDown(eventName.x, y, 320, 32, options, Std.int(Math.abs(options.indexOf(cast value)))); + var optionIndex = options.indexOf(cast value); + if(optionIndex < 0) { + optionIndex = 0; + } + var dropdown = new UIDropDown(eventName.x, y, 320, 32, options, optionIndex); paramsPanel.add(dropdown); paramsFields.push(dropdown); dropdown; case TCharacter: diff --git a/source/funkin/editors/charter/CharterNoteGroup.hx b/source/funkin/editors/charter/CharterNoteGroup.hx index 4c9a1d87..c2c2e388 100644 --- a/source/funkin/editors/charter/CharterNoteGroup.hx +++ b/source/funkin/editors/charter/CharterNoteGroup.hx @@ -33,7 +33,7 @@ class CharterNoteGroup extends FlxTypedGroup { noteFunc(__loopSprite); } for(c in Charter.selection.copy()) - if (c != null && c is CharterNote) noteFunc(cast (c, CharterNote)); + if (c != null && c is CharterNote) noteFunc(cast c); __currentlyLooping = oldCur; } diff --git a/source/funkin/editors/charter/CharterNoteHoverer.hx b/source/funkin/editors/charter/CharterNoteHoverer.hx index e20000a2..3ef2e543 100644 --- a/source/funkin/editors/charter/CharterNoteHoverer.hx +++ b/source/funkin/editors/charter/CharterNoteHoverer.hx @@ -47,7 +47,7 @@ class CharterNoteHoverer extends CharterNote { for (s in Charter.selection) { if (s != null && s.draggable && s is CharterNote) { - var draggingNote:CharterNote = cast(s, CharterNote); + var draggingNote:CharterNote = cast s; y = (draggingNote.step + verticalChange); if (!FlxG.keys.pressed.SHIFT) y -= ((draggingNote.step + verticalChange) diff --git a/source/funkin/editors/ui/UIFileExplorer.hx b/source/funkin/editors/ui/UIFileExplorer.hx index 7cc16320..a122dcec 100644 --- a/source/funkin/editors/ui/UIFileExplorer.hx +++ b/source/funkin/editors/ui/UIFileExplorer.hx @@ -55,8 +55,10 @@ class UIFileExplorer extends UISliceSprite { if (uiElement != null) { uiElement.alpha = alpha; - if (uiElement is UIButton) - cast(uiElement, UIButton).selectable = selectable; + if (uiElement is UIButton) { + var uiElement:UIButton = cast uiElement; + uiElement.selectable = selectable; + } } } diff --git a/source/funkin/editors/ui/UISubstateWindow.hx b/source/funkin/editors/ui/UISubstateWindow.hx index f99e184b..71550ef0 100644 --- a/source/funkin/editors/ui/UISubstateWindow.hx +++ b/source/funkin/editors/ui/UISubstateWindow.hx @@ -1,5 +1,8 @@ package funkin.editors.ui; +import openfl.display.ShaderParameter; +import openfl.display.ShaderInput; +import openfl.filters.ShaderFilter; import flixel.tweens.FlxTween; import funkin.backend.shaders.CustomShader; import openfl.filters.ShaderFilter; @@ -7,7 +10,17 @@ import openfl.filters.ShaderFilter; // TODO: make UIWarningSubstate extend this class UISubstateWindow extends MusicBeatSubstate { var camShaders:Array = []; - var blurShader:CustomShader = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast"); + var blurShader:CustomShader = { + var _ = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast"); + if(!Options.intensiveBlur) { + var noiseTexture:ShaderInput = _.data.noiseTexture; + noiseTexture.input = Assets.getBitmapData("assets/shaders/noise256.png"); + noiseTexture.wrap = REPEAT; + var noiseTextureSize:ShaderParameter = _.data.noiseTextureSize; + noiseTextureSize.value = [noiseTexture.input.width, noiseTexture.input.height]; + } + _; + }; var titleSpr:UIText; var messageSpr:UIText; diff --git a/source/funkin/editors/ui/UITopMenu.hx b/source/funkin/editors/ui/UITopMenu.hx index ae78469d..c4b0471d 100644 --- a/source/funkin/editors/ui/UITopMenu.hx +++ b/source/funkin/editors/ui/UITopMenu.hx @@ -21,9 +21,12 @@ class UITopMenu extends UISliceSprite { public override function update(elapsed:Float) { anyMenuOpened = false; - for(c in members) if (cast(c, UITopMenuButton).curMenu.contextMenuOpened()) { - anyMenuOpened = true; - break; + for(c in members) { + var c:UITopMenuButton = cast c; + if (c.curMenu.contextMenuOpened()) { + anyMenuOpened = true; + break; + } } super.update(elapsed); diff --git a/source/funkin/editors/ui/UIUtil.hx b/source/funkin/editors/ui/UIUtil.hx index 7f9de548..ac445a05 100644 --- a/source/funkin/editors/ui/UIUtil.hx +++ b/source/funkin/editors/ui/UIUtil.hx @@ -5,7 +5,7 @@ import funkin.editors.ui.UIContextMenu.UIContextMenuOption; class UIUtil { public static function follow(spr:FlxSprite, target:FlxSprite, x:Float = 0, y:Float = 0) { - spr.cameras = target is UISprite ? cast(target, UISprite).__lastDrawCameras : target.cameras; + spr.cameras = target is UISprite ? ({var _:UISprite = cast target;_;}).__lastDrawCameras : target.cameras; spr.setPosition(target.x + x, target.y + y); spr.scrollFactor.set(target.scrollFactor.x, target.scrollFactor.y); } diff --git a/source/funkin/editors/ui/UIWarningSubstate.hx b/source/funkin/editors/ui/UIWarningSubstate.hx index 84edf922..4f4a0380 100644 --- a/source/funkin/editors/ui/UIWarningSubstate.hx +++ b/source/funkin/editors/ui/UIWarningSubstate.hx @@ -1,5 +1,8 @@ package funkin.editors.ui; +import openfl.display.ShaderParameter; +import openfl.display.ShaderInput; +import openfl.filters.ShaderFilter; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import funkin.backend.shaders.CustomShader; @@ -7,7 +10,17 @@ import openfl.filters.ShaderFilter; class UIWarningSubstate extends MusicBeatSubstate { var camShaders:Array = []; - var blurShader:CustomShader = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast"); + var blurShader:CustomShader = { + var _ = new CustomShader(Options.intensiveBlur ? "engine/editorBlur" : "engine/editorBlurFast"); + if(!Options.intensiveBlur) { + var noiseTexture:ShaderInput = _.data.noiseTexture; + noiseTexture.input = Assets.getBitmapData("assets/shaders/noise256.png"); + noiseTexture.wrap = REPEAT; + var noiseTextureSize:ShaderParameter = _.data.noiseTextureSize; + noiseTextureSize.value = [noiseTexture.input.width, noiseTexture.input.height]; + } + _; + }; var title:String; var message:String; diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index 51fb7724..a7e93933 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -8,6 +8,9 @@ import flixel.util.FlxColor; import funkin.backend.FunkinSprite; import funkin.backend.scripting.DummyScript; import funkin.backend.scripting.Script; +import funkin.backend.scripting.ScriptPack; +import funkin.backend.scripting.events.CharacterNodeEvent; +import funkin.backend.scripting.events.CharacterXMLEvent; import funkin.backend.scripting.events.DanceEvent; import funkin.backend.scripting.events.DirectionAnimEvent; import funkin.backend.scripting.events.PlayAnimContext; @@ -44,8 +47,13 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset public var cameraOffset:FlxPoint = FlxPoint.get(0, 0); public var globalOffset:FlxPoint = FlxPoint.get(0, 0); - public var script:Script; public var xml:Access; + public var scripts:ScriptPack; + public var xmlImportedScripts:Array = []; + public var script(default, set):Script; + + public function prepareInfos(node:Access) + return XMLImportedScriptInfo.prepareInfos(node, scripts, (infos) -> xmlImportedScripts.push(infos)); public var idleSuffix:String = ""; public var stunned(default, set):Bool = false; @@ -72,16 +80,15 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset script = Script.create(Paths.script(Path.withoutExtension(Paths.xml('characters/$curCharacter')), null, true)); else script = new DummyScript(curCharacter); - script.setParent(this); script.load(); buildCharacter(xml); - script.call("create"); + scripts.call("create"); if (script == null) script = new DummyScript(curCharacter); - script.call("postCreate"); + scripts.call("postCreate"); } @:noCompletion var __swappedLeftRightAnims:Bool = false; @@ -118,7 +125,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset override function update(elapsed:Float) { super.update(elapsed); - script.call("update", [elapsed]); + scripts.call("update", [elapsed]); if (stunned) { __stunnedTime += elapsed; if (__stunnedTime > 5 / 60) @@ -137,7 +144,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset if(debugMode) return; var event = EventManager.get(DanceEvent).recycle(danced); - script.call("onDance", [event]); + scripts.call("onDance", [event]); if (event.cancelled) return; if (isDanceLeftDanceRight) @@ -167,14 +174,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset */ public var danceOnBeat:Bool = true; public override function beatHit(curBeat:Int) { - script.call("beatHit", [curBeat]); + scripts.call("beatHit", [curBeat]); if (danceOnBeat && (curBeat + beatOffset) % beatInterval == 0 && !__lockAnimThisFrame) tryDance(); } public override function stepHit(curStep:Int) - script.call("stepHit", [curStep]); + scripts.call("stepHit", [curStep]); @:noCompletion var __reverseDrawProcedure:Bool = false; public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect { @@ -237,7 +244,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) { var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context); - script.call("onPlayAnim", [event]); + scripts.call("onPlayAnim", [event]); if (event.cancelled) return; super.playAnim(event.animName, event.force, event.context, event.reverse, event.startingFrame); @@ -252,16 +259,16 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset var event = EventManager.get(PointEvent).recycle( midpoint.x + (isPlayer ? -100 : 150) + globalOffset.x + cameraOffset.x, midpoint.y - 100 + globalOffset.y + cameraOffset.y); - script.call("onGetCamPos", [event]); + scripts.call("onGetCamPos", [event]); midpoint.put(); return new FlxPoint(event.x, event.y); } public override function destroy() { - if(script != null) { - script.call('destroy'); - script.destroy(); + if(scripts != null) { + scripts.call('destroy'); + scripts.destroy(); } super.destroy(); @@ -304,9 +311,18 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset } public inline function buildCharacter(xml:Access) { - this.xml = xml; // Modders wassup :D + for(node in xml.elements) + switch(node.name) { + case "use-extension" | "extension" | "ext": + if (!XMLImportedScriptInfo.shouldLoadBefore(node)) continue; + prepareInfos(node); + } + + xml = scripts.event("onCharacterXMLParsed", EventManager.get(CharacterXMLEvent).recycle(this, xml)).xml; + sprite = curCharacter; spriteAnimType = BEAT; + this.xml = xml; // Modders wassup :D if (xml.x.exists("isPlayer")) playerOffsets = (xml.x.get("isPlayer") == "true"); if (xml.x.exists("x")) globalOffset.x = Std.parseFloat(xml.x.get("x")); @@ -314,7 +330,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset if (xml.x.exists("gameOverChar")) gameOverCharacter = xml.x.get("gameOverChar"); if (xml.x.exists("camx")) cameraOffset.x = Std.parseFloat(xml.x.get("camx")); if (xml.x.exists("camy")) cameraOffset.y = Std.parseFloat(xml.x.get("camy")); - if (xml.x.exists("holdTime")) holdTime = CoolUtil.getDefault(Std.parseFloat(xml.x.get("holdTime")), 4); + if (xml.x.exists("holdTime")) holdTime = Std.parseFloat(xml.x.get("holdTime")).getDefaultFloat(4); if (xml.x.exists("flipX")) flipX = (xml.x.get("flipX") == "true"); if (xml.x.exists("icon")) icon = xml.x.get("icon"); if (xml.x.exists("color")) iconColor = FlxColor.fromString(xml.x.get("color")); @@ -330,9 +346,19 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset if (hasInterval) beatInterval = Std.parseInt(xml.x.get("interval")); loadSprite(Paths.image('characters/$sprite')); + for(node in xml.elements) { + switch(node.name) { + case "anim": + XMLUtil.addXMLAnimation(this, node); + case "use-extension" | "extension" | "ext": + if (XMLImportedScriptInfo.shouldLoadBefore(node)) continue; + prepareInfos(node); + default: + // nothing + } - for (anim in xml.nodes.anim) - XMLUtil.addXMLAnimation(this, anim); + scripts.event("onCharacterNodeParsed", EventManager.get(CharacterNodeEvent).recycle(this, node, node.name)); + } for (attribute in xml.x.attributes()) if (!characterProperties.contains(attribute)) @@ -340,6 +366,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset fixChar(__switchAnims, !hasInterval); dance(); + + for (info in xmlImportedScripts) if (info.shortLived) { + var script = info.getScript(); + if (script == null) continue; + + scripts.remove(script); + script.destroy(); + } } public static var characterProperties:Array = [ @@ -423,6 +457,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset return stunned = b; } + // ---- Backwards compat ---- // Interval at which the character will dance (higher number = slower dance) @:noCompletion public var danceInterval(get, set):Int; @:noCompletion private function set_danceInterval(v:Int) @@ -430,13 +465,29 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset @:noCompletion private function get_danceInterval() return beatInterval; + private function set_script(script:Script):Script { + if (scripts == null) (scripts = new ScriptPack("Character")).setParent(this); + + var lastIndex = scripts.scripts.indexOf(this.script); + if(lastIndex >= 0) { + if(script == null) // last != null && new == null + scripts.scripts.splice(lastIndex, 1); + else // last != null && new != null + scripts.scripts[lastIndex] = script; + } else if(script != null) // last == null + scripts.insert(0, script); + + return this.script = script; + } + // ---- end of Backwards compat ---- + public static var FALLBACK_CHARACTER:String = "bf"; public static var FALLBACK_DEAD_CHARACTER:String = "bf-dead"; public static function getXMLFromCharName(character:OneOfTwo):Access { var char:Character = null; if (character is Character) { - char = cast(character, Character); + char = cast character; character = char.curCharacter; } @@ -468,9 +519,10 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset return xml; } - public static function getIconFromCharName(?character:String) { + public static function getIconFromCharName(?character:String, ?defaultIcon:String = null) { if(character == null) return "face"; - var icon:String = character; + if(defaultIcon == null) defaultIcon = character; + var icon:String = defaultIcon; var xml:Access = getXMLFromCharName(character); if (xml != null && xml.x.exists("icon")) icon = xml.x.get("icon"); @@ -478,9 +530,17 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset return icon; } - public static function getList(?mods:Bool = false):Array - return [ - for (path in Paths.getFolderContent('data/characters/', true, mods ? MODS : BOTH)) - if (Path.extension(path) == "xml") CoolUtil.getFilename(path) - ]; + public static function getList(?mods:Bool = false, includeFolders:Bool = false, folder:String = 'data/characters/'):Array { + var list:Array = []; + if(includeFolders) { + for (path in Paths.getFolderDirectories(folder, true, mods ? MODS : BOTH)) { + if(!path.endsWith("/")) path += "/"; + list.push(path); + } + } + for (path in Paths.getFolderContent(folder, true, mods ? MODS : BOTH)) + if (Path.extension(path) == "xml") + list.push(CoolUtil.getFilename(path)); + return list; + } } \ No newline at end of file diff --git a/source/funkin/game/HealthIcon.hx b/source/funkin/game/HealthIcon.hx index 1c7bb59d..07feba62 100644 --- a/source/funkin/game/HealthIcon.hx +++ b/source/funkin/game/HealthIcon.hx @@ -90,11 +90,9 @@ class HealthIcon extends FlxSprite if (animation.curAnim != null) { var i:Int = -1; var oldKey:Int = -1; - for(k=>icon in healthSteps) { - if (k > oldKey && k < health * 100) { - oldKey = k; - i = icon; - } + for (k=>icon in healthSteps) if (k > oldKey && k <= health * 100) { + oldKey = k; + i = icon; } if (i >= 0 && curAnimState != i) { var event = EventManager.get(funkin.backend.scripting.events.HealthIconChangeEvent).recycle(i, this); diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 21e70a6e..60aab276 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -213,7 +213,7 @@ class Note extends FlxSprite public var strumRelativePos:Bool = true; override function drawComplex(camera:FlxCamera) { - var downscrollCam = (camera is HudCamera ? cast(camera, HudCamera).downscroll : false); + var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false); flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); if (downscrollCam) { frameOffset.y += __notePosFrameOffset.y * 2; diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 5599267d..555fba89 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -160,6 +160,11 @@ class PlayState extends MusicBeatState * Boyfriend character */ public var boyfriend(get, set):Character; + /** + * Boyfriend character + * Same as boyfriend, just shorter + **/ + public var bf(get, set):Character; /** * Strum line position @@ -868,12 +873,12 @@ class PlayState extends MusicBeatState Conductor.songPosition = 0; Conductor.songPosition -= Conductor.crochet * introLength - Conductor.songOffset; - var swagCounter:Int = 0; - - startTimer = new FlxTimer().start(Conductor.crochet / 1000, function(tmr:FlxTimer) - { - countdown(swagCounter++); - }, introLength); + if(introLength > 0) { + var swagCounter:Int = 0; + startTimer = new FlxTimer().start(Conductor.crochet / 1000, (tmr:FlxTimer) -> { + countdown(swagCounter++); + }, introLength); + } scripts.call("onPostStartCountdown"); } @@ -1050,7 +1055,7 @@ class PlayState extends MusicBeatState vocals.pause(); } - if (!startTimer.finished) + if (startTimer != null && !startTimer.finished) startTimer.active = false; } @@ -1070,7 +1075,7 @@ class PlayState extends MusicBeatState resyncVocals(); } - if (!startTimer.finished) + if (startTimer != null && !startTimer.finished) startTimer.active = true; paused = false; @@ -1858,6 +1863,16 @@ class PlayState extends MusicBeatState strumLines.members[1].characters = [bf]; return bf; } + private function set_bf(bf:Character):Character { + if (strumLines != null && strumLines.members[1] != null) + strumLines.members[1].characters = [bf]; + return bf; + } + private function get_bf():Character { + if (strumLines != null && strumLines.members[1] != null) + return strumLines.members[1].characters[0]; + return null; + } private function get_dad():Character { if (strumLines != null && strumLines.members[0] != null) return strumLines.members[0].characters[0]; diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index 54b741f3..4ab56a26 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -2,6 +2,9 @@ package funkin.game; import flixel.FlxState; import flixel.math.FlxPoint; +import haxe.xml.Access; +import funkin.backend.utils.XMLUtil.XMLImportedScriptInfo; +import funkin.backend.system.interfaces.IBeatReceiver; import funkin.backend.scripting.DummyScript; import funkin.backend.scripting.Script; import funkin.backend.scripting.events.StageNodeEvent; @@ -30,6 +33,9 @@ class Stage extends FlxBasic implements IBeatReceiver { public function setStagesSprites(script:Script) for (k=>e in stageSprites) script.set(k, e); + public function prepareInfos(node:Access) + return XMLImportedScriptInfo.prepareInfos(node, PlayState.instance.scripts, (infos) -> xmlImportedScripts.push(infos)); + public function new(stage:String, ?state:FlxState) { super(); @@ -136,7 +142,7 @@ class Stage extends FlxBasic implements IBeatReceiver { PlayState.instance.add(PlayState.instance.comboGroup); PlayState.instance.comboGroup; case "use-extension" | "extension" | "ext": - if (__shouldLoadBefore(node) || XMLImportedScriptInfo.prepareInfos(node, this) == null) continue; + if (XMLImportedScriptInfo.shouldLoadBefore(node) || prepareInfos(node) == null) continue; null; default: null; } @@ -201,13 +207,10 @@ class Stage extends FlxBasic implements IBeatReceiver { @:dox(hide) private function __pushNcheckNode(array:Array, node:Access) { array.push(node); - if ((node.name == "use-extension" || node.name == "extension" || node.name == "ext") && __shouldLoadBefore(node)) - XMLImportedScriptInfo.prepareInfos(node, this); + if ((node.name == "use-extension" || node.name == "extension" || node.name == "ext") && XMLImportedScriptInfo.shouldLoadBefore(node)) + prepareInfos(node); } - @:dox(hide) private static inline function __shouldLoadBefore(node:Access):Bool - return node.getAtt("loadBefore") != "false"; - public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo):StageCharPos { var charPos = new StageCharPos(); charPos.visible = charPos.active = false; @@ -317,45 +320,4 @@ typedef StageCharPosInfo = { var y:Float; var flip:Bool; var scroll:Float; -} - -class XMLImportedScriptInfo { - public var path:String; - public var shortLived:Bool = false; - public var loadBefore:Bool = true; - public var importStageSprites:Bool = false; - - public function new(path:String) - this.path = path; - - public function getScript():Script - return PlayState.instance == null ? null : PlayState.instance.scripts.getByPath(path); - - public static function prepareInfos(node:Access, ?stage:Stage):XMLImportedScriptInfo { - if (!node.has.script || PlayState.instance == null) return null; - - var folder = node.getAtt("folder").getDefault("data/scripts/"); - if (!folder.endsWith("/")) folder += "/"; - - var path = Paths.script(folder + node.getAtt("script")); - var daScript = Script.create(path); - if (daScript is DummyScript) { - var msg = 'Script Extension at ${path} does not exist'; - if (stage != null) msg += ' through stage "${stage.stageName}"'; - Logs.trace(msg + ".", ERROR); - return null; - } - - var infos = new XMLImportedScriptInfo(daScript.path); - infos.shortLived = node.getAtt("isShortLived") == "true"; - infos.importStageSprites = node.getAtt("importStageSprites") == "true"; - @:privateAccess infos.loadBefore = Stage.__shouldLoadBefore(node); - - if (stage != null) stage.xmlImportedScripts.push(infos); - PlayState.instance.scripts.add(daScript); - daScript.set("scriptInfo", infos); - daScript.load(); - - return infos; - } } \ No newline at end of file diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index cca45b51..83d9c855 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -318,7 +318,7 @@ class StrumLine extends FlxTypedGroup { babyArrow.scrollSpeed = data.scrollSpeed; var event = EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix); - event.__doAnimation = !MusicBeatState.skipTransIn; + event.__doAnimation = !MusicBeatState.skipTransIn && (PlayState.instance != null ? PlayState.instance.introLength > 0 : true); event = PlayState.instance.scripts.event("onStrumCreation", event); if (!event.cancelled) { diff --git a/source/funkin/game/cutscenes/DialogueCutscene.hx b/source/funkin/game/cutscenes/DialogueCutscene.hx index 7d43e951..6f850007 100644 --- a/source/funkin/game/cutscenes/DialogueCutscene.hx +++ b/source/funkin/game/cutscenes/DialogueCutscene.hx @@ -91,7 +91,7 @@ class DialogueCutscene extends Cutscene { musicVolume: node.has.musicVolume ? (volume = Std.parseFloat(node.att.speed).getDefaultFloat(0.8)) : null, changeMusic: node.has.changeMusic ? FlxG.sound.load(Paths.music(node.att.changeMusic), volume, true) : null, playSound: node.has.playSound ? FlxG.sound.load(Paths.sound(node.att.playSound)) : null, - nextSound: node.has.nextSound ? FlxG.sound.load(Paths.music(node.att.nextSound)) : null, + nextSound: node.has.nextSound ? FlxG.sound.load(Paths.sound(node.att.nextSound)) : null, textSound: null }; @@ -217,4 +217,4 @@ typedef DialogueLine = { var nextSound:FlxSound; var textSound:FlxSound; var changeDefAnim:String; -} \ No newline at end of file +} diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx index fcfae487..68147a00 100644 --- a/source/funkin/menus/BetaWarningState.hx +++ b/source/funkin/menus/BetaWarningState.hx @@ -13,13 +13,13 @@ class BetaWarningState extends MusicBeatState { public override function create() { super.create(); - titleAlphabet = new Alphabet(0, 0, TU.translate("betaWarning.title"), true); + titleAlphabet = new Alphabet(0, 0, TU.translate("betaWarning.title"), "bold"); titleAlphabet.screenCenter(X); add(titleAlphabet); disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32); disclaimer.alignment = CENTER; - disclaimer.applyMarkup(TU.translate("betaWarning.desc", [Main.releaseCycle, "ENTER"]), + disclaimer.applyMarkup(TU.translate("betaWarning.desc", [Main.releaseCycle]) + "\n\n" + TU.translate("betaWarning.proceed", ["ENTER"]), [ new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*") ] diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx index c055a405..bee0eef7 100644 --- a/source/funkin/menus/FreeplayState.hx +++ b/source/funkin/menus/FreeplayState.hx @@ -130,7 +130,7 @@ class FreeplayState extends MusicBeatState for (i in 0...songs.length) { - var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i].displayName, true, false); + var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i].displayName, "bold"); songText.isMenuItem = true; songText.targetY = i; grpSongs.add(songText); diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 509a9d82..802b8e46 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -163,7 +163,7 @@ class MainMenuState extends MusicBeatState var event = event("onSelectItem", EventManager.get(NameEvent).recycle(daChoice)); if (event.cancelled) return; - switch (daChoice) + switch (event.name) { case 'story mode': FlxG.switchState(new StoryMenuState()); case 'freeplay': FlxG.switchState(new FreeplayState()); diff --git a/source/funkin/menus/ModSwitchMenu.hx b/source/funkin/menus/ModSwitchMenu.hx index 79277ff3..309afdad 100644 --- a/source/funkin/menus/ModSwitchMenu.hx +++ b/source/funkin/menus/ModSwitchMenu.hx @@ -28,7 +28,7 @@ class ModSwitchMenu extends MusicBeatSubstate { alphabets = new FlxTypedGroup(); for(mod in mods) { - var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : mod, true); + var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : mod, "bold"); if(mod == ModsFolder.currentModFolder) a.color = FlxColor.LIME; a.isMenuItem = true; diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx index fad1a15b..1f4008a0 100644 --- a/source/funkin/menus/PauseSubState.hx +++ b/source/funkin/menus/PauseSubState.hx @@ -14,6 +14,7 @@ import funkin.editors.charter.Charter; import funkin.menus.StoryMenuState; import funkin.options.OptionsMenu; import funkin.options.keybinds.KeybindsOptions; +import funkin.options.TreeMenu; class PauseSubState extends MusicBeatSubstate { @@ -107,7 +108,7 @@ class PauseSubState extends MusicBeatSubstate for (i in 0...menuItems.length) { var pauseId = "pause." + TU.raw2Id(menuItems[i]); - var songText:Alphabet = new Alphabet(0, (70 * i) + 30, TU.translate(pauseId), true, false); + var songText:Alphabet = new Alphabet(0, (70 * i) + 30, TU.translate(pauseId), "bold"); songText.isMenuItem = true; songText.targetY = i; grpMenuShit.add(songText); @@ -167,9 +168,10 @@ class PauseSubState extends MusicBeatSubstate persistentDraw = false; openSubState(new KeybindsOptions()); case "Change Options": + TreeMenu.lastState = PlayState; FlxG.switchState(new OptionsMenu()); case "Exit to charter": - FlxG.switchState(new funkin.editors.charter.Charter(PlayState.SONG.meta.name, PlayState.difficulty, false)); + FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, false)); case "Exit to menu": if (PlayState.chartingMode && Charter.undos.unsaved) game.saveWarn(false); @@ -217,4 +219,4 @@ class PauseSubState extends MusicBeatSubstate item.alpha = (item.targetY == 0) ? 1 : 0.6; } } -} \ No newline at end of file +} diff --git a/source/funkin/menus/PlaytestingWarningSubstate.hx b/source/funkin/menus/PlaytestingWarningSubstate.hx index 1bd5a00f..de455d83 100644 --- a/source/funkin/menus/PlaytestingWarningSubstate.hx +++ b/source/funkin/menus/PlaytestingWarningSubstate.hx @@ -40,7 +40,7 @@ class PlaytestingWarningSubstate extends MusicBeatSubstate bg.scrollFactor.set(); add(bg); - titleAlphabet = new Alphabet(0, 140, TU.translate("playtesting.warningTitle"), true); + titleAlphabet = new Alphabet(0, 140, TU.translate("playtesting.warningTitle"), "bold"); titleAlphabet.screenCenter(X); add(titleAlphabet); diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx index b67c3cfc..56a708f5 100644 --- a/source/funkin/menus/StoryMenuState.hx +++ b/source/funkin/menus/StoryMenuState.hx @@ -114,6 +114,12 @@ class StoryMenuState extends MusicBeatState { } } + // default difficulty should be the middle difficulty in the array + // to be consistent with base game and whatnot, you know the drill + curDifficulty = Math.floor(weeks[0].difficulties.length * 0.5); + // debug stuff lol + Logs.trace('Middle Difficulty for Week 1 is ${weeks[0].difficulties[curDifficulty]} (ID: $curDifficulty)'); + changeWeek(0, true); DiscordUtil.call("onMenuLoaded", ["Story Menu"]); @@ -163,6 +169,7 @@ class StoryMenuState extends MusicBeatState { if (!force) CoolUtil.playMenuSFX(); for(k=>e in weekSprites.members) { e.targetY = k - curWeek; + e.alpha = k == curWeek ? 1.0 : 0.6; } var str = new StringBuf(); str.add(TU.translate("story.tracks") + "\n\n"); @@ -354,13 +361,13 @@ class StoryMenuState extends MusicBeatState { if (char.animation.exists("confirm")) char.animation.play("confirm"); - PlayState.loadWeek(weeks[curWeek], weeks[curWeek].difficulties[curDifficulty]); + PlayState.loadWeek(event.week, event.difficulty); new FlxTimer().start(1, function(tmr:FlxTimer) { FlxG.switchState(new PlayState()); }); - weekSprites.members[curWeek].startFlashing(); + weekSprites.members[event.weekID].startFlashing(); } } diff --git a/source/funkin/menus/TitleState.hx b/source/funkin/menus/TitleState.hx index b74a8db4..ab190b62 100644 --- a/source/funkin/menus/TitleState.hx +++ b/source/funkin/menus/TitleState.hx @@ -25,8 +25,6 @@ class TitleState extends MusicBeatState public var textGroup:FlxGroup; public var ngSpr:FlxSprite; - public var wackyImage:FlxSprite; - override public function create():Void { curWacky = FlxG.random.getObject(getIntroTextShit()); @@ -40,9 +38,6 @@ class TitleState extends MusicBeatState DiscordUtil.call("onMenuLoaded", ["Title Screen"]); } - var logoBl:FlxSprite; - var gfDance:FlxSprite; - var danceLeft:Bool = false; var titleText:FlxSprite; var titleScreenSprites:MusicBeatGroup; @@ -56,11 +51,9 @@ class TitleState extends MusicBeatState var bg:FlxSprite = new FlxSprite().makeSolid(FlxG.width, FlxG.height, FlxColor.BLACK); add(bg); - #if TITLESCREEN_XML titleScreenSprites = new MusicBeatGroup(); add(titleScreenSprites); loadXML(); - #end if (titleText == null) { titleText = new FlxSprite(100, FlxG.height * 0.8); @@ -78,16 +71,6 @@ class TitleState extends MusicBeatState blackScreen = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK); add(blackScreen); - #if !TITLESCREEN_XML - ngSpr = new FlxSprite(0, FlxG.height * 0.52).loadAnimatedGraphic(Paths.image('newgrounds_logo')); - add(ngSpr); - ngSpr.visible = false; - ngSpr.setGraphicSize(Std.int(ngSpr.width * 0.8)); - ngSpr.updateHitbox(); - ngSpr.screenCenter(X); - ngSpr.antialiasing = true; - #end - FlxG.mouse.visible = false; if (initialized) @@ -192,7 +175,7 @@ class TitleState extends MusicBeatState for (i=>text in textArray) { if (text == "" || text == null) continue; - var money:Alphabet = new Alphabet(0, (i * 60) + 200, text, true, false); + var money:Alphabet = new Alphabet(0, (i * 60) + 200, text, "bold"); money.screenCenter(X); textGroup.add(money); } @@ -200,7 +183,7 @@ class TitleState extends MusicBeatState public function addMoreText(text:String) { - var coolText:Alphabet = new Alphabet(0, (textGroup.length * 60) + 200, text, true, false); + var coolText:Alphabet = new Alphabet(0, (textGroup.length * 60) + 200, text, "bold"); coolText.screenCenter(X); textGroup.add(coolText); } @@ -217,7 +200,6 @@ class TitleState extends MusicBeatState { super.beatHit(curBeat); - #if TITLESCREEN_XML if (curBeat >= titleLength || skippedIntro) { if (!skippedIntro) skipIntro(); return; @@ -225,27 +207,8 @@ class TitleState extends MusicBeatState var introText = titleLines[curBeat]; if (introText != null) introText.show(); - #else - switch (curBeat) - { - case 1: createCoolText(['ninjamuffin99', 'phantomArcade', 'kawaisprite', 'evilsk8er']); - case 3: addMoreText('present'); - case 4: deleteCoolText(); - case 5: createCoolText(['In association', 'with']); - case 7: addMoreText('newgrounds'); ngSpr.visible = true; - case 8: deleteCoolText(); ngSpr.visible = false; - case 9: createCoolText([curWacky[0]]); - case 11: addMoreText(curWacky[1]); - case 12: deleteCoolText(); - case 13: addMoreText('Friday'); - case 14: addMoreText('Night'); - case 15: addMoreText('Funkin'); - case 16: skipIntro(); - } - #end } - #if TITLESCREEN_XML public var xml:Access; public var titleLength:Int = 16; public var titleLines:Map = [ @@ -267,12 +230,14 @@ class TitleState extends MusicBeatState 15 => new IntroText(['Friday', 'Night', "Funkin'"]), ]; + public var titleSprites:Map = []; + public function loadXML() { try { xml = new Access(Xml.parse(Assets.getText(Paths.xml('titlescreen/titlescreen'))).firstElement()); if (xml.hasNode.intro) { titleLines = []; - if (xml.node.intro.has.length) titleLength = CoolUtil.getDefault(Std.parseInt(xml.node.intro.att.length), 16); + if (xml.node.intro.has.length) titleLength = Std.parseInt(xml.node.intro.att.length).getDefault(16); for(node in xml.nodes.sprites) { var parentFolder:String = node.getAtt("folder").getDefault(""); if (parentFolder != "" && !parentFolder.endsWith("/")) parentFolder += "/"; @@ -284,26 +249,28 @@ class TitleState extends MusicBeatState default: titleScreenSprites.add(spr); } + if(node.has.name) titleSprites[node.att.name] = spr; } } for(text in xml.node.intro.nodes.text) { - var beat:Int = CoolUtil.getDefault(text.has.beat ? Std.parseInt(text.att.beat) : null, 0); + var beat:Int = text.has.beat ? Std.parseInt(text.att.beat).getDefault(0) : 0; var texts:Array> = []; - for(e in text.elements) { - switch(e.name) { + for(node in text.elements) { + switch(node.name) { case "line": - if (!e.has.text) continue; - texts.push(e.att.text); + if (!node.has.text) continue; + texts.push(node.att.text); case "introtext": - if (!e.has.line) continue; - texts.push('{introText${e.att.line}}'); + if (!node.has.line) continue; + texts.push('{introText${node.att.line}}'); case "sprite": - if (!e.has.path) continue; - var name:String = e.has.name ? e.att.name : null; - var path:String = e.att.path; - var flipX:Bool = e.has.flipX ? e.att.flipX == "true" : false; - var flipY:Bool = e.has.flipY ? e.att.flipY == "true" : false; - var scale:Float = e.has.scale ? CoolUtil.getDefault(Std.parseFloat(e.att.scale), 1) : 1; + if (!node.has.path) continue; + var name:String = node.has.name ? node.att.name : null; + var path:String = node.att.path; + var flipX:Bool = node.has.flipX ? node.att.flipX == "true" : false; + var flipY:Bool = node.has.flipY ? node.att.flipY == "true" : false; + var scale:Float = node.has.scale ? Std.parseFloat(node.att.scale).getDefault(1) : 1; + texts.push({ name: name, path: path, @@ -320,7 +287,6 @@ class TitleState extends MusicBeatState Logs.error('Failed to load titlescreen XML: $e'); } } - #end var skippedIntro:Bool = false; @@ -328,10 +294,6 @@ class TitleState extends MusicBeatState { if (!skippedIntro) { - #if !TITLESCREEN_XML - remove(ngSpr); - #end - FlxG.camera.flash(FlxColor.WHITE, 4); remove(blackScreen); blackScreen.destroy(); @@ -361,7 +323,7 @@ class IntroText { var image:TitleStateImage = e; if (image.path == null) continue; - var scale:Float = CoolUtil.getDefault(image.scale, 1); + var scale:Float = image.scale.getDefault(1); var yPos:Float = 200; if(state.textGroup.members.length > 0) { @@ -370,8 +332,8 @@ class IntroText { } var sprite = new FlxSprite(0, yPos).loadAnimatedGraphic(Paths.image(image.path)); - sprite.flipX = CoolUtil.getDefault(image.flipX, false); - sprite.flipY = CoolUtil.getDefault(image.flipY, false); + sprite.flipX = image.flipX.getDefault(false); + sprite.flipY = image.flipY.getDefault(false); sprite.scale.set(scale, scale); sprite.updateHitbox(); sprite.screenCenter(X); diff --git a/source/funkin/menus/credits/CreditsCodename.hx b/source/funkin/menus/credits/CreditsCodename.hx index 3deb2310..e3a730ab 100644 --- a/source/funkin/menus/credits/CreditsCodename.hx +++ b/source/funkin/menus/credits/CreditsCodename.hx @@ -11,9 +11,11 @@ using StringTools; class CreditsCodename extends funkin.options.OptionsScreen { public var error:Bool = false; public var author:String = "FNF-CNE-Devs"; + public var totalContributions:Int = 0; + public var mainDevCol:FlxColor = 0xFF9C35D5; public var minContrCol:FlxColor = 0xFFB4A7DA; - public var totalContributions:Int = 0; + public var contribFormats:Array = []; public override function new() { @@ -58,12 +60,17 @@ class CreditsCodename extends funkin.options.OptionsScreen { if(parent == null || parent.treeParent == null) return; var text:String = parent.treeParent.pathDesc.text; parent.treeParent.pathDesc.text = ""; - parent.treeParent.pathDesc.applyMarkup(text, [ + parent.treeParent.pathDesc.applyMarkup(text, contribFormats = [ new FlxTextFormatMarkerPair(new FlxTextFormat(mainDevCol), '*'), new FlxTextFormatMarkerPair(new FlxTextFormat(FlxColor.interpolate(minContrCol, mainDevCol, Options.contributors[curSelected].contributions / totalContributions)), '~') ]); } + override function close() { + super.close(); + for (frmt in contribFormats) parent.treeParent.pathDesc.removeFormat(frmt.format); + } + public function checkUpdate():Bool { var curTime:Float = Date.now().getTime(); if(Options.lastUpdated != null && curTime < Options.lastUpdated + 120000) return false; // Fuck you Github rate limits - Nex diff --git a/source/funkin/menus/ui/Alphabet.hx b/source/funkin/menus/ui/Alphabet.hx index 10779521..4298be57 100644 --- a/source/funkin/menus/ui/Alphabet.hx +++ b/source/funkin/menus/ui/Alphabet.hx @@ -1,284 +1,648 @@ package funkin.menus.ui; -import flixel.group.FlxSpriteGroup; -import flixel.util.FlxColor; -import flixel.util.FlxTimer; -import funkin.backend.assets.AssetsLibraryList; -import funkin.backend.assets.IModsAssetLibrary; -import funkin.backend.assets.LimeLibrarySymbol; +import flixel.util.typeLimit.OneOfTwo; +import haxe.ds.Vector; +import funkin.menus.ui.effects.RegionEffect; + +import flixel.animation.FlxAnimation; +import flixel.util.FlxDirectionFlags; +import flixel.math.FlxPoint; +import flixel.math.FlxAngle; +import flixel.FlxTypes; + import haxe.xml.Access; -import openfl.utils.AssetLibrary; using StringTools; +using flixel.util.FlxColorTransformUtil; -/** - * Loosely based on FlxTypeText lolol - */ -class Alphabet extends FlxSpriteGroup -{ - public var delay:Float = 0.05; - public var paused:Bool = false; +@:structInit +final class AlphabetComponent { + public var anim:String; + public var x:Float; + public var y:Float; + + // Precalculated values for angle + public var shouldRotate:Bool; + public var sin:Float; + public var cos:Float; + public var scaleX:Float; + public var scaleY:Float; + + public var hasColorMode:Bool; + public var colorMode:ColorMode; +} + +@:structInit +final class AlphabetLetterData { + @:optional public var isDefault:Bool = false; + public var advance:Float; + public var advanceEmpty:Bool; + public var components:Array; +} + +enum abstract AlphabetAlignment(ByteUInt) from ByteUInt to ByteUInt { + var LEFT; + var CENTER; + var RIGHT; + + public function getMultiplier():Float { + return switch(this) { + case CENTER: 0.5; + case RIGHT: 1.0; + default: 0.0; + } + } + + @:from + public static function fromString(value:String):AlphabetAlignment + return switch(value) { + case "left": LEFT; + case "center": CENTER; + case "right": RIGHT; + default: LEFT; + } +} + +enum abstract CaseMode(ByteUInt) from ByteUInt to ByteUInt { + var NONE; + var UPPER; + var LOWER; + + @:from + public static function fromString(value:String):CaseMode + return switch(value) { + case "none": NONE; + case "upper": UPPER; + case "lower": LOWER; + default: NONE; + } +} + +enum abstract ColorMode(ByteInt) from ByteInt to ByteInt { + var TINT = 0; + var OFFSET = 1; + var NONE = 2; + + public function setColorTransform(color:openfl.geom.ColorTransform, red:Float, green:Float, blue:Float, alpha:Float) { + var moduloWorkaround:Int = this; + var tintMult = Math.max(-moduloWorkaround + 1, 0); + var tintOffset = Math.min(moduloWorkaround, 1); + var offsetMult = (moduloWorkaround % 2) * 255; + + color.redMultiplier = red * tintMult + tintOffset; + color.greenMultiplier = green * tintMult + tintOffset; + color.blueMultiplier = blue * tintMult + tintOffset; + color.redOffset = red * offsetMult; + color.greenOffset = green * offsetMult; + color.blueOffset = blue * offsetMult; + color.alphaMultiplier = alpha; + } +} + +class Alphabet extends FlxSprite { + public var effects:Array = []; + var __renderData:AlphabetRenderData; + var __component:AlphabetComponent; + + public var text(default, set):String = ""; + @:isVar public var textWidth(get, set):Float; + public var textHeight(get, null):Float; + + public var alignment:AlphabetAlignment = LEFT; + public var forceCase:CaseMode = NONE; + + var __laneWidths:Array = []; // TODO: add alignment. + var __forceWidth:Float = 0.0; // TODO: implement functionality for this. + var __queueResize:Bool = false; + var __animTime:Float = 0.0; + var __ogForceScreen:Bool = false; + + public var originOffset:FlxPoint = FlxPoint.get(); + + public var font(default, set):String; + var colorMode:ColorMode = TINT; + var defaultAdvance:Float = 40.0; + var lineGap:Float = 75.0; + var fps:Float = 24.0; + var letterData:Map = []; + var defaults:Vector = { + var v = new Vector(3); + v[0] = null; + v[1] = null; + v[2] = null; + v; + }; + var loaded:Vector> = { + var v = new Vector(3); + v[0] = []; + v[1] = []; + v[2] = []; + v; + }; + var failedLetters:Array = []; // for menu shit public var targetY:Float = 0; public var isMenuItem:Bool = false; - public var text:String = ""; - - var _finalText:String = ""; - var _curText:String = ""; - - var yMulti:Float = 1; - - // custom shit - // amp, backslash, question mark, apostrophy, comma, angry faic, period - var lastSprite:AlphaCharacter; - var xPosResetted:Bool = false; - - var splitWords:Array = []; - - var isBold:Bool = false; - - private override function set_color(c:Int):Int { - for(e in group.members) { - if (e is AlphaCharacter) { - var char = cast(e, AlphaCharacter); - char.setColor(c, isBold); - } - } - return super.set_color(c); - } - - // TODO: fix this shit refreshing - public function refreshAlphabetXML(path:String) { - AlphaCharacter.__alphaPath = Paths.getAssetsRoot() + path; - try { - var xml = new Access(Xml.parse(Assets.getText(path)).firstElement()); - AlphaCharacter.boldAnims = []; - AlphaCharacter.letterAnims = []; - AlphaCharacter.boldAlphabetPath = AlphaCharacter.letterAlphabetPath = 'ui/alphabet'; - - for(e in xml.elements) { - var bold = e.name == "bold"; - var list = bold ? AlphaCharacter.boldAnims : AlphaCharacter.letterAnims; - if (e.has.spritesheet) { - if (bold) - AlphaCharacter.boldAlphabetPath = e.att.spritesheet; - else - AlphaCharacter.letterAlphabetPath = e.att.spritesheet; - } - for(e in e.nodes.letter) { - if (!e.has.char || !e.has.anim) continue; - var name = e.att.char; - var anim = e.att.anim; - list[name] = anim; - } - } - } catch(e) { - trace(e.details()); - } - } - public function new(x:Float, y:Float, text:String = "", ?bold:Bool = false, typed:Bool = false) - { + public function new(?x:Float, ?y:Float, ?text:String = "", ?font:OneOfTwo = "normal") { super(x, y); + this.text = text; + this.font = (font is String) ? font : ((font == true) ? "bold" : "normal"); // == true just in case + this.__renderData = new AlphabetRenderData(this); + } - _finalText = this.text = text; - isBold = bold; - - var alphabetPath = Paths.xml("alphabet"); - if (Paths.getAssetsRoot() + alphabetPath != AlphaCharacter.__alphaPath) { - refreshAlphabetXML(alphabetPath); - } - #if MOD_SUPPORT else { - var libThing = new LimeLibrarySymbol(alphabetPath); - if (libThing.library is AssetLibrary) { - var library = AssetsLibraryList.getCleanLibrary(libThing.library); - if (library is IModsAssetLibrary) { - var modLib = cast(library, IModsAssetLibrary); - @:privateAccess - if (!modLib.__isCacheValid(library.cachedBytes, libThing.symbolName)) { - refreshAlphabetXML(alphabetPath); - } - } - } - } + override function update(elapsed:Float):Void { + //super.update(elapsed); + // FLXOBJECT UPDATE + #if FLX_DEBUG + @:privateAccess FlxBasic.activeCount += 1; #end - if (text != "") - { - if (typed) - { - startTypedText(); - } - else - { - addText(); - } - } - } + last.set(x, y); - public function addText() - { - doSplitWords(); + if (path != null && path.active) + path.update(elapsed); - var xPos:Float = 0; - var curRow:Int = 0; - for (i=>character in splitWords) - { - if (lastSprite != null) - xPos = lastSprite.x + lastSprite.width - x; + if (moves) + updateMotion(elapsed); - if (xPosResetted && !(xPosResetted = false)) xPos = 0; + wasTouching = touching; + touching = FlxDirectionFlags.NONE; + // FLXOBJECT UPDATE END - var letter:AlphaCharacter = new AlphaCharacter(xPos, 0); - letter.row = curRow; - if (isBold) - letter.createBold(character); - else - letter.createLetter(character); + __animTime += elapsed; + for (effect in effects) + effect.effectTime += elapsed * effect.speed; - // anim not found - if (!letter.visible) - xPos += 40; - - letter.setColor(color, isBold); - add(letter); - - lastSprite = letter; - if (_finalText.fastCodeAt(i) == "\n".code) - { - xPosResetted = true; - curRow += 1; - } - } - } - - function doSplitWords():Void - { - splitWords = _finalText.split(""); - } - - //public var personTalking:String = 'gf'; - - public function startTypedText():Void - { - _finalText = text; - doSplitWords(); - - // trace(arrayShit); - - var loopNum:Int = 0; - - var xPos:Float = 0; - var curRow:Int = 0; - - new FlxTimer().start(0.05, function(tmr:FlxTimer) - { - // trace(_finalText.fastCodeAt(loopNum) + " " + _finalText.charAt(loopNum)); - if (_finalText.fastCodeAt(loopNum) == "\n".code) - { - yMulti += 1; - xPosResetted = true; - xPos = 0; - curRow += 1; - } - loopNum += 1; - - tmr.time = FlxG.random.float(0.04, 0.09); - }, splitWords.length); - } - - override function update(elapsed:Float) - { - super.update(elapsed); - - if (isMenuItem) - { - var scaledY = FlxMath.remapToRange(targetY, 0, 1, 0, 1.3); + if (isMenuItem) { + var scaledY = targetY * 1.3; y = CoolUtil.fpsLerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16); x = CoolUtil.fpsLerp(x, (targetY * 20) + 90, 0.16); } - - if (text != _finalText) { - _finalText = text; - for(e in members) - e.destroy(); - members.clear(); - lastSprite = null; - addText(); - } } - override function draw() { + override function draw():Void { + __ogForceScreen = forceIsOnScreen; + forceIsOnScreen = true; super.draw(); } -} -class AlphaCharacter extends FlxSprite -{ - @:dox(hide) @:noCompletion public static var __alphaPath:String = null; + override function isSimpleRender(?camera:FlxCamera):Bool { + return false; // maybe ill get simple render working another time??? not right now tho. + } - public static var letterAlphabetPath:String; - public static var boldAlphabetPath:String; + override function drawComplex(camera:FlxCamera):Void { + forceIsOnScreen = __ogForceScreen; - public static var boldAnims:Map = []; - public static var letterAnims:Map = []; + if (__queueResize) + recalcSizes(); + var curLine = 0; + var lastLine = 0; + var daText = switch (forceCase) { + case UPPER: text.toUpperCase(); + case LOWER: text.toLowerCase(); + case NONE: text; + } - public var row:Int = 0; + var alignmentMultiplier = alignment.getMultiplier(); - public function setColor(c:FlxColor, isBold:Bool) { - if (isBold) { - colorTransform.redMultiplier = c.redFloat; - colorTransform.greenMultiplier = c.greenFloat; - colorTransform.blueMultiplier = c.blueFloat; - } else { - colorTransform.redOffset = c.red; - colorTransform.greenOffset = c.green; - colorTransform.blueOffset = c.blue; + var ogOffX = frameOffset.x; + var ogOffY = frameOffset.y; + frameOffset.x -= (textWidth - __laneWidths[0]) * alignmentMultiplier; + + var isGraphicsShader = shader != null && shader is flixel.graphics.tile.FlxGraphicsShader; + var ogRed:Float = colorTransform.redMultiplier; + var ogGreen:Float = colorTransform.greenMultiplier; + var ogBlue:Float = colorTransform.blueMultiplier; + var ogAlpha:Float = colorTransform.alphaMultiplier; + + var frameTime = Math.floor(__animTime * fps); + + for (i in 0...daText.length) { + __renderData.reset(this, ogRed, ogGreen, ogBlue, ogAlpha, daText.charAt(i)); + for (effect in effects) { + if (effect.willModify(i, i - lastLine, __renderData)) + effect.modify(i, i - lastLine, __renderData); + } + + var letter = __renderData.letter; + if (letter == "\n") { + curLine++; + lastLine = i + 1; + frameOffset.x = ogOffX - (textWidth - __laneWidths[curLine]) * alignmentMultiplier; + frameOffset.y -= lineGap; + continue; + } + + var data = getData(letter); + + if (data == null) { + frameOffset.x -= defaultAdvance; + continue; + } + + var advance:Float = Math.NaN; + + for (i in 0...data.components.length) { + __component = data.components[i]; + var anim = getLetterAnim(letter, data, __component, i); + advance = (Math.isNaN(advance)) ? getAdvance(letter, anim, data) : advance; + + if (anim == null || __renderData.alpha <= 0.0) + break; // shouldnt this be like continue? + + var frameToGet = frameTime % anim.numFrames; + frame = frames.frames[anim.frames[frameToGet]]; + + var offsetX = __component.x + __renderData.offsetX; + var offsetY = frame.sourceSize.y - lineGap + __component.y + __renderData.offsetY; + frameOffset.x += offsetX; + frameOffset.y += offsetY; + if (!isOnScreen(camera)) { + frameOffset.y -= offsetY; + frameOffset.x -= offsetX; + break; + } + if (isGraphicsShader) + shader.setCamSize(_frame.frame.x, _frame.frame.y, _frame.frame.width, _frame.frame.height); + + if (__component.hasColorMode) + __component.colorMode.setColorTransform(colorTransform, __renderData.red, __renderData.green, __renderData.blue, __renderData.alpha); + else + colorMode.setColorTransform(colorTransform, __renderData.red, __renderData.green, __renderData.blue, __renderData.alpha); + + drawLetter(camera); + frameOffset.y -= offsetY; + frameOffset.x -= offsetX; + } + frameOffset.x -= advance; + } + __component = null; + + setColorTransform(ogRed, ogGreen, ogBlue, ogAlpha, 0, 0, 0, 0); + frameOffset.set(ogOffX, ogOffY); + } + + function drawLetter(camera) { + _frame.prepareMatrix(_matrix, ANGLE_0, checkFlipX() != camera.flipX, checkFlipY() != camera.flipY); + + _matrix.translate(_frame.frame.width * -0.5, _frame.frame.height * -0.5); + _matrix.scale(__component.scaleX, __component.scaleY); + if(__component.shouldRotate) _matrix.rotateWithTrig(__component.cos, __component.sin); + _matrix.translate(_frame.frame.width * 0.5, _frame.frame.height * 0.5); + + _matrix.translate(-origin.x, -origin.y); + + if (frameOffsetAngle != null && frameOffsetAngle != angle) + { + var angleOff = (frameOffsetAngle - angle) * FlxAngle.TO_RAD; + var cos = Math.cos(angleOff); + var sin = Math.sin(angleOff); + // cos doesnt need to be negated + _matrix.rotateWithTrig(cos, -sin); + _matrix.translate(-frameOffset.x, -frameOffset.y); + _matrix.rotateWithTrig(cos, sin); + } + else + _matrix.translate(-frameOffset.x, -frameOffset.y); + + _matrix.scale(scale.x, scale.y); + + if (bakedRotationAngle <= 0) + { + updateTrig(); + + if (angle != 0) + _matrix.rotateWithTrig(_cosAngle, _sinAngle); + } + + getScreenPosition(_point, camera).subtractPoint(offset); + _point.add(origin.x, origin.y); + _matrix.translate(_point.x, _point.y); + + if (isPixelPerfectRender(camera)) + { + _matrix.tx = Math.floor(_matrix.tx); + _matrix.ty = Math.floor(_matrix.ty); + } + + doAdditionalMatrixStuff(_matrix, camera); + + if (layer != null) + layer.drawPixels(this, camera, _frame, framePixels, _matrix, colorTransform, blend, antialiasing, shaderEnabled ? shader : null); + else + camera.drawPixels(_frame, framePixels, _matrix, colorTransform, blend, antialiasing, shaderEnabled ? shader : null); + } + + override function updateHitbox():Void { + offset.set(-0.5 * (width - textWidth), -0.5 * (height - textHeight)); + origin.set(textWidth * 0.5 + originOffset.x, textHeight * 0.5 + originOffset.y); + } + + function recalcSizes():Void { + __queueResize = false; + var curLine = 0; + var daText = switch (forceCase) { + case UPPER: text.toUpperCase(); + case LOWER: text.toLowerCase(); + case NONE: text; + } + @:bypassAccessor textWidth = 0; + textHeight = lineGap; + __laneWidths = [0]; + for (i in 0...daText.length) { + var letter = daText.charAt(i); + if (letter == "\n") { + textHeight += lineGap; + __laneWidths.push(0); + curLine++; + continue; + } + + var data = getData(letter); + __laneWidths[curLine] += (data != null) ? getAdvance(letter, getLetterAnim(letter, data, data.components[0], 0), data) : defaultAdvance; + @:bypassAccessor textWidth = Math.max(textWidth, __laneWidths[curLine]); + } + + origin.set(textWidth * 0.5 + originOffset.x, textHeight * 0.5 + originOffset.y); + } + + function getAdvance(letter:String, anim:FlxAnimation, data:AlphabetLetterData):Float { + if (anim == null) + return defaultAdvance; + + if (data.advanceEmpty && !data.isDefault) { + data.advanceEmpty = false; + data.advance = frames.frames[anim.frames[0]].sourceSize.x; + } + return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance; + } + + function getData(char:String):AlphabetLetterData { + if (failedLetters.contains(char)) return null; + for (i in 0...3) { // this feels wrong + if (loaded[i].contains(char)) + return defaults[i]; + } + + var data:AlphabetLetterData = null; + if (letterData.exists(char)) + data = letterData.get(char); + + if (data == null) { + var charCode:Int = char.charCodeAt(0); + if (charCode >= 'A'.code && charCode <= 'Z'.code && defaults[CaseMode.UPPER] != null) + data = defaults[CaseMode.UPPER]; + else if (charCode >= 'a'.code && charCode <= 'z'.code && defaults[CaseMode.LOWER] != null) + data = defaults[CaseMode.LOWER]; + else + data = defaults[CaseMode.NONE]; + } + + if(data == null) { + failedLetters.push(char); + return null; + } else if (data.isDefault) + loaded[defaultsIndexOf(data)].push(char); + return data; + } + + final function defaultsIndexOf(data:AlphabetLetterData):Int { + //while(i < defaults.length) { + for(i in 0...3) { + if(defaults[i] == data) + return i; + } + return -1; + } + + function getLetterAnim(char:String, data:AlphabetLetterData, component:AlphabetComponent, index:Int):FlxAnimation { + if (data == null) return null; + var name = char + Std.string(index); + if (animation.exists(name)) return animation.getByName(name); + + var anim = (data.isDefault) ? + component.anim.replace("LETTER", char) : + component.anim; + animation.addByPrefix(name, anim, fps); + if (!animation.exists(name)) { + failedLetters.push(char); + return null; + } + return animation.getByName(name); + } + + function checkNode(node:Xml):Void { + switch (node.nodeName) { + case "spritesheet": + if (frames == null) + frames = Paths.getFrames(node.firstChild().nodeValue); + else { + for (frame in Paths.getFrames(node.firstChild().nodeValue).frames) + frames.pushFrame(frame); + } + case "defaultAnim": + var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1; + + var rad:Float = Std.parseFloat(node.get("angle")).getDefaultFloat(0.0) * FlxAngle.TO_RAD; + var angleCos = Math.cos(rad); + var angleSin = Math.sin(rad); + + var res:AlphabetLetterData = { + isDefault: true, + advance: 0.0, + advanceEmpty: true, + components: [{ + anim: node.firstChild().nodeValue, + + x: 0.0, + y: 0.0, + scaleX: Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0), + scaleY: Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0), + + shouldRotate: rad != 0, + cos: angleCos, + sin: angleSin, + + hasColorMode: false, + colorMode: 0 + }] + } + + defaults[idx] = res; + case "composite": + if(!node.exists("char")) { + Logs.error(" must have a char attribute", "Alphabet"); + return; + } + var char = node.get("char"); + var advance:Float = Std.parseFloat(node.get("advance")); + var components:Array = []; + for (component in node.elementsNamed("component")) { + if(!component.exists("anim")) { + Logs.error(" must have a anim attribute", "Alphabet"); + return; + } + + var rad:Float = Std.parseFloat(component.get("angle")).getDefaultFloat(0.0) * FlxAngle.TO_RAD; + var angleCos = Math.cos(rad); + var angleSin = Math.sin(rad); + + var xOff:Float = -Std.parseFloat(component.get("x")).getDefaultFloat(0.0); + var yOff:Float = Std.parseFloat(component.get("y")).getDefaultFloat(0.0); + + var colorMode = ["tint", "offsets", "none"].indexOf(component.get("colorMode")); + + components.push({ + anim: component.get("anim"), + + x: xOff, + y: yOff, + scaleX: Std.parseFloat(component.get("scaleX")).getDefaultFloat(1.0), + scaleY: Std.parseFloat(component.get("scaleY")).getDefaultFloat(1.0), + + shouldRotate: rad != 0, + cos: angleCos, + sin: angleSin, + + hasColorMode: colorMode >= 0, + colorMode: colorMode + }); + } + letterData.set(char, { + isDefault: false, + advance: advance, + advanceEmpty: Math.isNaN(advance), + components: components + }); + case "anim": + if(!node.exists("char")) { + Logs.error(" must have a char attribute", "Alphabet"); + return; + } + var char = node.get("char"); + + var rad:Float = Std.parseFloat(node.get("angle")).getDefaultFloat(0.0) * FlxAngle.TO_RAD; + var angleCos = Math.cos(rad); + var angleSin = Math.sin(rad); + + var xOff:Float = -Std.parseFloat(node.get("x")).getDefaultFloat(0.0); + var yOff:Float = Std.parseFloat(node.get("y")).getDefaultFloat(0.0); + var advance:Float = Std.parseFloat(node.get("advance")); + + var colorMode = ["tint", "offsets", "none"].indexOf(node.get("colorMode")); + + letterData.set(char, { + isDefault: false, + advance: advance, + advanceEmpty: Math.isNaN(advance), + components: [{ + anim: node.firstChild().nodeValue, + + x: xOff, + y: yOff, + scaleX: Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0), + scaleY: Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0), + + shouldRotate: rad != 0, + cos: angleCos, + sin: angleSin, + + hasColorMode: colorMode >= 0, + colorMode: colorMode + }] + }); + case "languageSection": // used to only parse characters if a specific language is selected + if(!node.exists("langs")) { + Logs.error(" must have a langs attribute", "Alphabet"); + return; + } + var langs = [for (lang in node.get("langs").split(",")) lang.trim()]; + // maybe add a way to toggle this off? like force it to add all + if (langs.contains(Options.language)) { + for (langNode in node.elements()) + checkNode(langNode); + } } } - public function new(x:Float, y:Float) - { - super(x, y); - antialiasing = true; - } + function loadFont(value:String):Void { + __queueResize = true; - public function createBold(letter:String) - { - if(!boldAnims.exists(letter)) - letter = letter.toUpperCase(); - if (!boldAnims.exists(letter)) { - visible = false; - active = false; - scale.set(); - width = 40; - return; + var xml:Xml = Xml.parse(Assets.getText(Paths.xml("alphabet/" + value))).firstElement(); + + // reset old values + letterData = new Map(); + defaults = { + var v = new Vector(3); + v[0] = null; + v[1] = null; + v[2] = null; + v; } - frames = Paths.getFrames(boldAlphabetPath); - animation.addByPrefix(letter, boldAnims[letter], 24); - animation.play(letter); - updateHitbox(); - - y += row * height; - } - - public function createLetter(letter:String):Void - { - if (!letterAnims.exists(letter)) { - visible = false; - active = false; - scale.set(); - width = 40; - return; + loaded = { + var v = new Vector(3); + v[0] = []; + v[1] = []; + v[2] = []; + v; } - frames = Paths.getFrames(letterAlphabetPath); - animation.addByPrefix(letter, letterAnims[letter], 24); - animation.play(letter); - updateHitbox(); + failedLetters = []; - y = (110 - height); - y += row * 60; + defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0); + lineGap = Std.parseFloat(xml.get("lineGap")).getDefaultFloat(75.0); + fps = Std.parseFloat(xml.get("fps")).getDefaultFloat(24.0); + forceCase = xml.get("forceCasing").getDefault("none").toLowerCase(); + colorMode = (["offsets", "none"].indexOf(xml.get("colorMode")) + 1); + + frames = null; + + for (node in xml.elements()) + checkNode(node); } -} + + override function destroy():Void { + originOffset = FlxDestroyUtil.destroy(originOffset); + failedLetters = []; + super.destroy(); + } + + function get_textWidth():Float { + if (__queueResize) + recalcSizes(); + return textWidth; + } + function set_textWidth(value:Float):Float { + if(!__queueResize) + __queueResize = __forceWidth != value; + return __forceWidth = value; + } + + override function get_width():Float { + return textWidth * scale.x; + } + override function get_height():Float { + return textHeight * scale.y; + } + + function get_textHeight():Float { + if (__queueResize) + recalcSizes(); + return textHeight; + } + + function set_text(value:String):String { + if(!__queueResize) + __queueResize = text != value; + return text = value; + } + + function set_font(value:String):String { + if (font != value) { + loadFont(font = value); + } + return value; + } +} \ No newline at end of file diff --git a/source/funkin/menus/ui/ClassicAlphabet.hx b/source/funkin/menus/ui/ClassicAlphabet.hx new file mode 100644 index 00000000..4ece8633 --- /dev/null +++ b/source/funkin/menus/ui/ClassicAlphabet.hx @@ -0,0 +1,284 @@ +package funkin.menus.ui; + +import flixel.group.FlxSpriteGroup; +import flixel.util.FlxColor; +import flixel.util.FlxTimer; +import funkin.backend.assets.AssetsLibraryList; +import funkin.backend.assets.IModsAssetLibrary; +import funkin.backend.assets.LimeLibrarySymbol; +import haxe.xml.Access; +import openfl.utils.AssetLibrary; + +using StringTools; + +/** + * Loosely based on FlxTypeText lolol + */ +class ClassicAlphabet extends FlxSpriteGroup +{ + public var delay:Float = 0.05; + public var paused:Bool = false; + + // for menu shit + public var targetY:Float = 0; + public var isMenuItem:Bool = false; + + public var text:String = ""; + + var _finalText:String = ""; + var _curText:String = ""; + + var yMulti:Float = 1; + + // custom shit + // amp, backslash, question mark, apostrophy, comma, angry faic, period + var lastSprite:AlphaCharacter; + var xPosResetted:Bool = false; + + var splitWords:Array = []; + + var isBold:Bool = false; + + private override function set_color(c:Int):Int { + for(e in group.members) { + if (e is AlphaCharacter) { + var char:AlphaCharacter = cast e; + char.setColor(c, isBold); + } + } + return super.set_color(c); + } + + // TODO: fix this shit refreshing + public function refreshAlphabetXML(path:String) { + AlphaCharacter.__alphaPath = Paths.getAssetsRoot() + path; + try { + var xml = new Access(Xml.parse(Assets.getText(path)).firstElement()); + AlphaCharacter.boldAnims = []; + AlphaCharacter.letterAnims = []; + AlphaCharacter.boldAlphabetPath = AlphaCharacter.letterAlphabetPath = 'ui/alphabet'; + + for(e in xml.elements) { + var bold = e.name == "bold"; + var list = bold ? AlphaCharacter.boldAnims : AlphaCharacter.letterAnims; + if (e.has.spritesheet) { + if (bold) + AlphaCharacter.boldAlphabetPath = e.att.spritesheet; + else + AlphaCharacter.letterAlphabetPath = e.att.spritesheet; + } + for(e in e.nodes.letter) { + if (!e.has.char || !e.has.anim) continue; + var name = e.att.char; + var anim = e.att.anim; + list[name] = anim; + } + } + } catch(e) { + trace(e.details()); + } + } + public function new(x:Float, y:Float, text:String = "", ?bold:Bool = false, typed:Bool = false) + { + super(x, y); + + _finalText = this.text = text; + isBold = bold; + + var alphabetPath = Paths.xml("alphabet"); + if (Paths.getAssetsRoot() + alphabetPath != AlphaCharacter.__alphaPath) { + refreshAlphabetXML(alphabetPath); + } + #if MOD_SUPPORT else { + var libThing = new LimeLibrarySymbol(alphabetPath); + if (libThing.library is AssetLibrary) { + var library = AssetsLibraryList.getCleanLibrary(libThing.library); + if (library is IModsAssetLibrary) { + var modLib = cast(library, IModsAssetLibrary); + @:privateAccess + if (!modLib.__isCacheValid(library.cachedBytes, libThing.symbolName)) { + refreshAlphabetXML(alphabetPath); + } + } + } + } + #end + + if (text != "") + { + if (typed) + { + startTypedText(); + } + else + { + addText(); + } + } + } + + public function addText() + { + doSplitWords(); + + var xPos:Float = 0; + 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 + letter.createLetter(character); + + // anim not found + if (!letter.visible) + xPos += 40; + + letter.setColor(color, isBold); + add(letter); + + lastSprite = letter; + if (_finalText.fastCodeAt(i) == "\n".code) + { + xPosResetted = true; + curRow += 1; + } + } + } + + function doSplitWords():Void + { + splitWords = _finalText.split(""); + } + + //public var personTalking:String = 'gf'; + + public function startTypedText():Void + { + _finalText = text; + doSplitWords(); + + // trace(arrayShit); + + var loopNum:Int = 0; + + var xPos:Float = 0; + var curRow:Int = 0; + + new FlxTimer().start(0.05, function(tmr:FlxTimer) + { + // trace(_finalText.fastCodeAt(loopNum) + " " + _finalText.charAt(loopNum)); + if (_finalText.fastCodeAt(loopNum) == "\n".code) + { + yMulti += 1; + xPosResetted = true; + xPos = 0; + curRow += 1; + } + loopNum += 1; + + tmr.time = FlxG.random.float(0.04, 0.09); + }, splitWords.length); + } + + override function update(elapsed:Float) + { + super.update(elapsed); + + if (isMenuItem) + { + var scaledY = FlxMath.remapToRange(targetY, 0, 1, 0, 1.3); + + y = CoolUtil.fpsLerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16); + x = CoolUtil.fpsLerp(x, (targetY * 20) + 90, 0.16); + } + + if (text != _finalText) { + _finalText = text; + for(e in members) + e.destroy(); + members.clear(); + lastSprite = null; + addText(); + } + } + + override function draw() { + super.draw(); + } +} + +class AlphaCharacter extends FlxSprite +{ + @:dox(hide) @:noCompletion public static var __alphaPath:String = null; + + public static var letterAlphabetPath:String; + public static var boldAlphabetPath:String; + + public static var boldAnims:Map = []; + public static var letterAnims:Map = []; + + public var row:Int = 0; + + public function setColor(c:FlxColor, isBold:Bool) { + if (isBold) { + colorTransform.redMultiplier = c.redFloat; + colorTransform.greenMultiplier = c.greenFloat; + colorTransform.blueMultiplier = c.blueFloat; + } else { + colorTransform.redOffset = c.red; + colorTransform.greenOffset = c.green; + colorTransform.blueOffset = c.blue; + } + } + public function new(x:Float, y:Float) + { + super(x, y); + + antialiasing = true; + } + + public function createBold(letter:String) + { + if(!boldAnims.exists(letter)) + letter = letter.toUpperCase(); + if (!boldAnims.exists(letter)) { + visible = false; + active = false; + scale.set(); + width = 40; + return; + } + frames = Paths.getFrames(boldAlphabetPath); + animation.addByPrefix(letter, boldAnims[letter], 24); + animation.play(letter); + updateHitbox(); + + y += row * height; + } + + public function createLetter(letter:String):Void + { + if (!letterAnims.exists(letter)) { + visible = false; + active = false; + scale.set(); + width = 40; + return; + } + frames = Paths.getFrames(letterAlphabetPath); + animation.addByPrefix(letter, letterAnims[letter], 24); + animation.play(letter); + updateHitbox(); + + y = (110 - height); + y += row * 60; + } +} diff --git a/source/funkin/menus/ui/NewAlphabet.hx b/source/funkin/menus/ui/NewAlphabet.hx deleted file mode 100644 index 7a0c76d0..00000000 --- a/source/funkin/menus/ui/NewAlphabet.hx +++ /dev/null @@ -1,593 +0,0 @@ -package funkin.menus.ui; - -import haxe.ds.Vector; -import funkin.menus.ui.effects.RegionEffect; - -import flixel.animation.FlxAnimation; -import flixel.util.FlxDirectionFlags; -import flixel.math.FlxPoint; -import flixel.FlxTypes; - -import haxe.xml.Access; - -using StringTools; -using flixel.util.FlxColorTransformUtil; - -@:structInit -final class AlphabetOutline { - public var anim:String; - public var x:Float; - public var y:Float; -} - -@:structInit -final class AlphabetComponentData { - public var anim:String; - - @:optional public var outline:AlphabetOutline; -} - -@:structInit -final class AlphabetComponent { - public var data:AlphabetComponentData; - public var x:Float; - public var y:Float; - - // Precalculated values for angle - public var sin:Float; - public var cos:Float; - public var scaleX:Float; - public var scaleY:Float; -} - -@:structInit -final class AlphabetLetterData { - @:optional public var isDefault:Bool = false; - public var advance:Float; - public var advanceEmpty:Bool; - public var components:Array; -} - -enum abstract AlphabetAlignment(ByteUInt) from ByteUInt to ByteUInt { - var LEFT; - var CENTER; - var RIGHT; - - public function getMultiplier():Float { - return switch(this) { - case CENTER: 0.5; - case RIGHT: 1.0; - default: 0.0; - } - } - - @:from - public static function fromString(value:String):AlphabetAlignment - return switch(value) { - case "left": LEFT; - case "center": CENTER; - case "right": RIGHT; - default: LEFT; - } -} - -enum abstract CaseMode(ByteUInt) from ByteUInt to ByteUInt { - var NONE; - var UPPER; - var LOWER; - - @:from - public static function fromString(value:String):CaseMode - return switch(value) { - case "none": NONE; - case "upper": UPPER; - case "lower": LOWER; - default: NONE; - } -} - -class NewAlphabet extends FlxSprite { - public var effects:Array = []; - var __renderData:AlphabetRenderData; - - public var text(default, set):String = ""; - @:isVar public var textWidth(get, set):Float; - public var textHeight(get, null):Float; - - public var alignment:AlphabetAlignment = LEFT; - public var forceCase:CaseMode = NONE; - - var __laneWidths:Array = []; // TODO: add alignment. - var __forceWidth:Float = 0.0; // TODO: implement functionality for this. - var __queueResize:Bool = false; - var __animTime:Float = 0.0; - var __ogForceScreen:Bool = false; - - public var originOffset:FlxPoint = FlxPoint.get(); - - public var font(default, set):String; - var transformMult:ByteUInt = 1; // 1 if multipliers (tint), 0 if offset. - var defaultAdvance:Float = 40.0; - var lineGap:Float = 75.0; - var fps:Float = 24.0; - var letterData:Map = []; - var allComponents:Map = []; - var defaults:Vector = { - var v = new Vector(3); - v[0] = null; - v[1] = null; - v[2] = null; - v; - }; - var loaded:Vector> = { - var v = new Vector(3); - v[0] = []; - v[1] = []; - v[2] = []; - v; - }; - var failedLetters:Array = []; - - public function new(?x:Float, ?y:Float, ?font:String = "bold") { - super(x, y); - this.font = font; - this.__renderData = new AlphabetRenderData(this); - } - - override function update(elapsed:Float):Void { - //super.update(elapsed); - // FLXOBJECT UPDATE - #if FLX_DEBUG - @:privateAccess FlxBasic.activeCount += 1; - #end - - last.set(x, y); - - if (path != null && path.active) - path.update(elapsed); - - if (moves) - updateMotion(elapsed); - - wasTouching = touching; - touching = FlxDirectionFlags.NONE; - // FLXOBJECT UPDATE END - - __animTime += elapsed; - for (effect in effects) - effect.effectTime += elapsed * effect.speed; - } - - override function draw():Void { - __ogForceScreen = forceIsOnScreen; - forceIsOnScreen = true; - super.draw(); - } - - override function isSimpleRender(?camera:FlxCamera):Bool { - return false; // maybe ill get simple render working another time??? not right now tho. - } - - override function drawComplex(camera:FlxCamera):Void { - forceIsOnScreen = __ogForceScreen; - - if (__queueResize) - recalcSizes(); - var curLine = 0; - var lastLine = 0; - var daText = switch (forceCase) { - case UPPER: text.toUpperCase(); - case LOWER: text.toLowerCase(); - case NONE: text; - } - - var alignmentMultiplier = alignment.getMultiplier(); - - var ogOffX = frameOffset.x; - var ogOffY = frameOffset.y; - frameOffset.x -= (textWidth - __laneWidths[0]) * alignmentMultiplier; - - var isGraphicsShader = shader != null && shader is flixel.graphics.tile.FlxGraphicsShader; - var offsetMult = (1 - transformMult) * 255; - var ogRed:Float = colorTransform.redMultiplier; - var ogGreen:Float = colorTransform.greenMultiplier; - var ogBlue:Float = colorTransform.blueMultiplier; - var ogAlpha:Float = colorTransform.alphaMultiplier; - - var frameTime = Math.floor(__animTime * fps); - - for (i in 0...daText.length) { - __renderData.reset(this, ogRed, ogGreen, ogBlue, ogAlpha, daText.charAt(i)); - for (effect in effects) { - if (effect.willModify(i, i - lastLine, __renderData)) - effect.modify(i, i - lastLine, __renderData); - } - - var letter = __renderData.letter; - if (letter == "\n") { - curLine++; - lastLine = i + 1; - frameOffset.x = ogOffX - (textWidth - __laneWidths[curLine]) * alignmentMultiplier; - frameOffset.y -= lineGap; - continue; - } - - var data = getData(letter); - - if (data == null) { - frameOffset.x -= defaultAdvance; - continue; - } - - var advance:Float = Math.NaN; - - for (i => com in data.components) { - var anim = getLetterAnim(letter, data, com, i); - advance = (Math.isNaN(advance)) ? getAdvance(letter, anim, data) : advance; - - if (anim == null || __renderData.alpha <= 0.0) { - frameOffset.x -= advance; - break; // shouldnt this be like continue? - } - - var frameToGet = frameTime % anim.numFrames; - frame = frames.frames[anim.frames[frameToGet]]; - - var offsetX = com.x + __renderData.offsetX; - var offsetY = frame.sourceSize.y - lineGap + com.y + __renderData.offsetY; - frameOffset.x += offsetX; - frameOffset.y += offsetY; - if (!isOnScreen(camera)) { - frameOffset.y -= offsetY; - frameOffset.x -= offsetX + advance; - break; - } - if (isGraphicsShader) - shader.setCamSize(_frame.frame.x, _frame.frame.y, _frame.frame.width, _frame.frame.height); - - setColorTransform( - __renderData.red * transformMult, __renderData.green * transformMult, __renderData.blue * transformMult, __renderData.alpha, - Math.round(__renderData.red * offsetMult), Math.round(__renderData.green * offsetMult), Math.round(__renderData.blue * offsetMult), 0 - ); - super.drawComplex(camera); - frameOffset.y -= offsetY; - frameOffset.x -= offsetX + advance; - } - } - - setColorTransform(ogRed, ogGreen, ogBlue, ogAlpha, 0, 0, 0, 0); - frameOffset.set(ogOffX, ogOffY); - } - - override function updateHitbox():Void { - width = Math.abs(scale.x) * textWidth; - height = Math.abs(scale.y) * textHeight; - offset.set(-0.5 * (width - textWidth), -0.5 * (height - textHeight)); - origin.set(textWidth * 0.5 + originOffset.x, textHeight * 0.5 + originOffset.y); - } - - function recalcSizes():Void { - __queueResize = false; - var curLine = 0; - var daText = switch (forceCase) { - case UPPER: text.toUpperCase(); - case LOWER: text.toLowerCase(); - case NONE: text; - } - @:bypassAccessor textWidth = 0; - textHeight = lineGap; - __laneWidths = [0]; - for (i in 0...daText.length) { - var letter = daText.charAt(i); - if (letter == "\n") { - textHeight += lineGap; - __laneWidths.push(0); - curLine++; - continue; - } - - var data = getData(letter); - __laneWidths[curLine] += (data != null) ? getAdvance(letter, getLetterAnim(letter, data, data.components[0], 0), data) : defaultAdvance; - @:bypassAccessor textWidth = Math.max(textWidth, __laneWidths[curLine]); - } - - origin.set(textWidth * 0.5 + originOffset.x, textHeight * 0.5 + originOffset.y); - } - - function getAdvance(letter:String, anim:FlxAnimation, data:AlphabetLetterData):Float { - if (anim == null) - return defaultAdvance; - - if (data.advanceEmpty && !data.isDefault) { - data.advanceEmpty = false; - data.advance = frames.frames[anim.frames[0]].sourceSize.x; - } - return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance; - } - - function getData(char:String):AlphabetLetterData { - if (failedLetters.contains(char)) return null; - for (i in 0...3) { // this feels wrong - if (loaded[i].contains(char)) - return defaults[i]; - } - - var data:AlphabetLetterData = null; - if (letterData.exists(char)) - data = letterData.get(char); - - if (data == null) { - var charCode:Int = char.charCodeAt(0); - if (charCode >= 'A'.code && charCode <= 'Z'.code && defaults[CaseMode.UPPER] != null) - data = defaults[CaseMode.UPPER]; - else if (charCode >= 'a'.code && charCode <= 'z'.code && defaults[CaseMode.LOWER] != null) - data = defaults[CaseMode.LOWER]; - else - data = defaults[CaseMode.NONE]; - } - - if(data == null) { - failedLetters.push(char); - return null; - } else if (data.isDefault) - loaded[defaultsIndexOf(data)].push(char); - return data; - } - - final function defaultsIndexOf(data:AlphabetLetterData):Int { - //while(i < defaults.length) { - for(i in 0...3) { - if(defaults[i] == data) - return i; - } - return -1; - } - - function getLetterAnim(char:String, data:AlphabetLetterData, component:AlphabetComponent, index:Int):FlxAnimation { - if (data == null) return null; - var name = char + Std.string(index); - if (animation.exists(name)) return animation.getByName(name); - - var anim = (data.isDefault) ? - component.data.anim.replace("LETTER", char) : - component.data.anim; - animation.addByPrefix(name, anim, fps); - if (!animation.exists(name)) { - failedLetters.push(char); - return null; - } - return animation.getByName(name); - } - - function checkNode(node:Xml):Void { - switch (node.nodeName) { - case "spritesheet": - if (frames == null) - frames = Paths.getFrames(node.firstChild().nodeValue); - else { - for (frame in Paths.getFrames(node.firstChild().nodeValue).frames) - frames.pushFrame(frame); - } - case "defaultAnim": - var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1; - - var angle:Float = Std.parseFloat(node.get("angle")).getDefaultFloat(0.0); - var angleCos = Math.cos(angle); - var angleSin = Math.sin(angle); - - // register character as component - allComponents.set("DEFAULT_" + idx, { - anim: node.firstChild().nodeValue.trim(), - outline: null - }); - - var res:AlphabetLetterData = { - isDefault: true, - advance: 0.0, - advanceEmpty: true, - components: [{ - data: allComponents.get("DEFAULT_" + idx), - - x: 0.0, - y: 0.0, - scaleX: Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0), - scaleY: Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0), - - cos: angleCos, - sin: angleSin - }] - } - - defaults[idx] = res; - case "component-data": - if(!node.exists("id")) { - Logs.error(" must have an id attribute", "Alphabet"); - return; - } - - var id = node.get("id"); - var anim = node.firstChild().nodeValue.trim(); - var outline:AlphabetOutline = null; - if(node.firstElement() != null) { - var outlineNode = node.firstElement(); - switch(outlineNode.nodeName) { - case "outline": - outline = { - anim: outlineNode.firstChild().nodeValue.trim(), - x: Std.parseFloat(outlineNode.get("x")).getDefaultFloat(0.0), - y: Std.parseFloat(outlineNode.get("y")).getDefaultFloat(0.0) - }; - } - } - - allComponents.set(id, { - anim: anim, - outline: outline - }); - case "composite": - if(!node.exists("char")) { - Logs.error(" must have a char attribute", "Alphabet"); - return; - } - var char = node.get("char"); - var advance:Float = Std.parseFloat(node.get("advance")); - var components:Array = []; - for (component in node.elementsNamed("component")) { - if(!component.exists("id")) { - Logs.error(" must have a id attribute", "Alphabet"); - return; - } - - var angle:Float = Std.parseFloat(component.get("angle")).getDefaultFloat(0.0); - var angleCos = Math.cos(angle); - var angleSin = Math.sin(angle); - - var xOff:Float = -Std.parseFloat(component.get("x")).getDefaultFloat(0.0); - var yOff:Float = Std.parseFloat(component.get("y")).getDefaultFloat(0.0); - - var componentId = component.get("id").trim(); - if(!allComponents.exists(componentId)) { - Logs.error("Component with id '" + componentId + "' does not exist", "Alphabet"); - return; - } - - components.push({ - data: allComponents.get(componentId), - - x: xOff, - y: yOff, - scaleX: Std.parseFloat(component.get("scaleX")).getDefaultFloat(1.0), - scaleY: Std.parseFloat(component.get("scaleY")).getDefaultFloat(1.0), - - cos: angleCos, - sin: angleSin - }); - } - letterData.set(char, { - isDefault: false, - advance: advance, - advanceEmpty: Math.isNaN(advance), - components: components - }); - case "anim": - if(!node.exists("char")) { - Logs.error(" must have a char attribute", "Alphabet"); - return; - } - var char = node.get("char"); - - var angle:Float = Std.parseFloat(node.get("angle")).getDefaultFloat(0.0); - var angleCos = Math.cos(angle); - var angleSin = Math.sin(angle); - - var xOff:Float = -Std.parseFloat(node.get("x")).getDefaultFloat(0.0); - var yOff:Float = Std.parseFloat(node.get("y")).getDefaultFloat(0.0); - var advance:Float = Std.parseFloat(node.get("advance")); - - // register character as component - allComponents.set(char, { - anim: node.firstChild().nodeValue, - outline: null - }); - - letterData.set(char, { - isDefault: false, - advance: advance, - advanceEmpty: Math.isNaN(advance), - components: [{ - data: allComponents.get(char), - - x: xOff, - y: yOff, - scaleX: Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0), - scaleY: Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0), - - cos: angleCos, - sin: angleSin - }] - }); - case "languageSection": // used to only parse characters if a specific language is selected - if(!node.exists("langs")) { - Logs.error(" must have a langs attribute", "Alphabet"); - return; - } - var langs = [for (lang in node.get("langs").split(",")) lang.trim()]; - // maybe add a way to toggle this off? like force it to add all - if (langs.contains(Options.language)) { - for (langNode in node.elements()) - checkNode(langNode); - } - } - } - - function loadFont(value:String):Void { - __queueResize = true; - - var xml:Xml = Xml.parse(Assets.getText(Paths.xml("alphabet/" + value))).firstElement(); - - // reset old values - letterData = new Map(); - defaults = { - var v = new Vector(3); - v[0] = null; - v[1] = null; - v[2] = null; - v; - } - loaded = { - var v = new Vector(3); - v[0] = []; - v[1] = []; - v[2] = []; - v; - } - failedLetters = []; - - defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0); - lineGap = Std.parseFloat(xml.get("lineGap")).getDefaultFloat(75.0); - fps = Std.parseFloat(xml.get("fps")).getDefaultFloat(24.0); - forceCase = xml.get("forceCasing").getDefault("none").toLowerCase(); - transformMult = (xml.get("useColorOffsets") == "true") ? 0 : 1; - - frames = null; - - for (node in xml.elements()) - checkNode(node); - } - - override function destroy():Void { - originOffset = FlxDestroyUtil.destroy(originOffset); - failedLetters = []; - super.destroy(); - } - - function get_textWidth():Float { - if (__queueResize) - recalcSizes(); - return textWidth; - } - function set_textWidth(value:Float):Float { - if(!__queueResize) - __queueResize = __forceWidth != value; - return __forceWidth = value; - } - - function get_textHeight():Float { - if (__queueResize) - recalcSizes(); - return textHeight; - } - - function set_text(value:String):String { - if(!__queueResize) - __queueResize = text != value; - return text = value; - } - - function set_font(value:String):String { - if (font != value) { - loadFont(font = value); - } - return value; - } -} \ No newline at end of file diff --git a/source/funkin/menus/ui/effects/RegionEffect.hx b/source/funkin/menus/ui/effects/RegionEffect.hx index 1eac1025..7f99b166 100644 --- a/source/funkin/menus/ui/effects/RegionEffect.hx +++ b/source/funkin/menus/ui/effects/RegionEffect.hx @@ -3,7 +3,7 @@ package funkin.menus.ui.effects; import flixel.util.FlxColor; class AlphabetRenderData { - public var parent:NewAlphabet; + public var parent:Alphabet; public var letter:String; public var offsetX:Float = 0; public var offsetY:Float = 0; @@ -13,11 +13,11 @@ class AlphabetRenderData { public var blue:Float = 0; public var alpha:Float = 1; - public function new(parent:NewAlphabet) { + public function new(parent:Alphabet) { this.parent = parent; } - public function reset(parent:NewAlphabet, red:Float, green:Float, blue:Float, alpha:Float, letter:String) { + public function reset(parent:Alphabet, red:Float, green:Float, blue:Float, alpha:Float, letter:String) { this.parent = parent; this.letter = letter; this.offsetX = 0; diff --git a/source/funkin/options/keybinds/KeybindSetting.hx b/source/funkin/options/keybinds/KeybindSetting.hx index 191c3233..c793e35a 100644 --- a/source/funkin/options/keybinds/KeybindSetting.hx +++ b/source/funkin/options/keybinds/KeybindSetting.hx @@ -20,7 +20,7 @@ class KeybindSetting extends FlxTypedSpriteGroup { public function new(x:Float, y:Float, name:String, value:String, ?sparrowIcon:String, ?sparrowAnim:String) { super(); this.value = value; - title = new Alphabet(0, 0, name, true); + title = new Alphabet(0, 0, name, "bold"); add(title); var controlArrayP1:Array = Reflect.field(Options, 'P1_${value}'); @@ -31,12 +31,13 @@ class KeybindSetting extends FlxTypedSpriteGroup { for(i in 1...3) { var b = null; + var bx = FlxG.width * (0.25 * (i+1)) - x; if (i == 1) - b = bind1 = new Alphabet(0, 0, "", false); + b = bind1 = new Alphabet(bx, 0, "", "normal"); else - b = bind2 = new Alphabet(0, 0, "", false); + b = bind2 = new Alphabet(bx, 0, "", "normal"); - b.setPosition(FlxG.width * (0.25 * (i+1)) - x, -60); + //b.setPosition(FlxG.width * (0.25 * (i+1)) - x, -60); add(b); } updateText(); diff --git a/source/funkin/options/keybinds/KeybindsOptions.hx b/source/funkin/options/keybinds/KeybindsOptions.hx index b7ced2ee..56e8f0f5 100644 --- a/source/funkin/options/keybinds/KeybindsOptions.hx +++ b/source/funkin/options/keybinds/KeybindsOptions.hx @@ -19,7 +19,7 @@ class KeybindsOptions extends MusicBeatSubstate { public var categories:Array = []; public function translate(id:String, ?args:Array) - return TU.translate("Keybinds." + id, args); + return TU.translate("KeybindsOptions." + id, args); public var settingCam:FlxCamera; @@ -148,7 +148,7 @@ class KeybindsOptions extends MusicBeatSubstate { var k:Int = 0; for(category in categories) { k++; - var title = new Alphabet(0, k * 75, category.name, true); + var title = new Alphabet(0, k * 75, category.name, "bold"); title.screenCenter(X); add(title); diff --git a/source/funkin/options/type/ArrayOption.hx b/source/funkin/options/type/ArrayOption.hx index 5a1496ec..cede15dc 100644 --- a/source/funkin/options/type/ArrayOption.hx +++ b/source/funkin/options/type/ArrayOption.hx @@ -37,8 +37,8 @@ class ArrayOption extends OptionType { this.optionName = optionName; - add(__text = new Alphabet(100, 20, text, true)); - add(__selectiontext = new Alphabet(__text.width + 120, -30, formatTextOption(), false)); + add(__text = new Alphabet(100, 20, text, "bold")); + add(__selectiontext = new Alphabet(__text.width + 120, 20, formatTextOption(), "normal")); rawText = text; } diff --git a/source/funkin/options/type/NumOption.hx b/source/funkin/options/type/NumOption.hx index 17c7ff80..10608350 100644 --- a/source/funkin/options/type/NumOption.hx +++ b/source/funkin/options/type/NumOption.hx @@ -39,8 +39,8 @@ class NumOption extends OptionType { this.changeVal = changeVal; this.optionName = optionName; - add(__text = new Alphabet(100, 20, text, true)); - add(__number = new Alphabet(__text.width + 120, -30, ': $currentSelection', false)); + add(__text = new Alphabet(100, 20, text, "bold")); + add(__number = new Alphabet(__text.width + 120, 20, ': $currentSelection', "normal")); rawText = text; } diff --git a/source/funkin/options/type/TextOption.hx b/source/funkin/options/type/TextOption.hx index b16d285d..8f7ec08d 100644 --- a/source/funkin/options/type/TextOption.hx +++ b/source/funkin/options/type/TextOption.hx @@ -20,7 +20,7 @@ class TextOption extends OptionType { public function new(text:String, desc:String, ?suffix:String = "", ?selectCallback:Void->Void = null) { super(desc); this.selectCallback = selectCallback; - add(__text = new Alphabet(100, 20, text, true)); + add(__text = new Alphabet(100, 20, text, "bold")); this.suffix = suffix; rawText = text; } diff --git a/source/lime/system/System.hx b/source/lime/system/System.hx index 98efafe3..2184f5fe 100644 --- a/source/lime/system/System.hx +++ b/source/lime/system/System.hx @@ -367,7 +367,10 @@ class System #elseif mac Sys.command("/usr/bin/open", [path]); #elseif linux - Sys.command("/usr/bin/xdg-open", [path]); + // generally `xdg-open` should work in every distro + var cmd = Sys.command("xdg-open", [path, "&"]); + // run old command JUST IN CASE it fails, which it shouldn't + if (cmd != 0) cmd = Sys.command("/usr/bin/xdg-open", [path, "&"]); #elseif (js && html5) Browser.window.open(path, "_blank"); #elseif flash @@ -602,9 +605,7 @@ class System { // executes first!! #if (sys && !macro) - funkin.backend.utils.NativeAPI.registerAsDPICompatible(); - funkin.backend.system.CommandLineHandler.parseCommandLine(Sys.args()); - funkin.backend.system.Main.fixWorkingDirectory(); + funkin.backend.system.Main.preInit(); #end if (__applicationEntryPoint == null)