package funkin.ui; import openfl.utils.Assets; import openfl.utils.AssetLibrary; import haxe.xml.Access; import funkin.mods.LimeLibrarySymbol; import funkin.mods.ModsAssetLibrary; import flixel.FlxG; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; import flixel.group.FlxSpriteGroup; import flixel.math.FlxMath; import flixel.util.FlxTimer; import flixel.util.FlxColor; using StringTools; /** * Loosley based on FlxTypeText lolol */ class Alphabet 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 = ""; public var widthOfWords:Float = FlxG.width; var yMulti:Float = 1; // custom shit // amp, backslash, question mark, apostrophy, comma, angry faic, period var lastSprite:AlphaCharacter; var xPosResetted:Bool = false; var lastWasSpace: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) { trace("Needs refresh!!"); AlphaCharacter.__alphaPath = path; try { var xml = new Access(Xml.parse(Assets.getText(path)).firstElement()); AlphaCharacter.boldAnims = []; AlphaCharacter.letterAnims = []; for(e in xml.elements) { var bold = e.name == "bold"; var list = bold ? AlphaCharacter.boldAnims : AlphaCharacter.letterAnims; 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 (alphabetPath != AlphaCharacter.__alphaPath) { refreshAlphabetXML(alphabetPath); } else { var libThing = new LimeLibrarySymbol(alphabetPath); if (libThing.library is AssetLibrary) { var library = cast(libThing.library, AssetLibrary); @:privateAccess if (library.__proxy != null && library.__proxy is AssetLibrary) { @:privateAccess library = cast(library.__proxy, AssetLibrary); } #if MOD_SUPPORT if (library is ModsAssetLibrary) { var modLib = cast(library, ModsAssetLibrary); @:privateAccess if (!modLib.__isCacheValid(modLib.cachedBytes, libThing.symbolName)) { refreshAlphabetXML(alphabetPath); } } #end } } if (text != "") { if (typed) { startTypedText(); } else { addText(); } } } public function addText() { doSplitWords(); var xPos:Float = 0; for (character in splitWords) { lastWasSpace = character == " "; if (lastSprite != null) xPos = lastSprite.x + lastSprite.width - x; var letter:AlphaCharacter = new AlphaCharacter(xPos, 0); 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; } } 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; } if (splitWords[loopNum] == " ") { lastWasSpace = true; } // #if (haxe >= "4.0.0") // var isNumber:Bool = AlphaCharacter.numbers.contains(splitWords[loopNum]); // var isSymbol:Bool = AlphaCharacter.symbols.contains(splitWords[loopNum]); // #else // var isNumber:Bool = AlphaCharacter.numbers.indexOf(splitWords[loopNum]) != -1; // var isSymbol:Bool = AlphaCharacter.symbols.indexOf(splitWords[loopNum]) != -1; // #end // if (AlphaCharacter.alphabet.indexOf(splitWords[loopNum].toLowerCase()) != -1 || isNumber || isSymbol) // // if (AlphaCharacter.alphabet.contains(splitWords[loopNum].toLowerCase()) || isNumber || isSymbol) // { // if (lastSprite != null && !xPosResetted) // { // lastSprite.updateHitbox(); // xPos += lastSprite.width + 3; // // if (isBold) // // xPos -= 80; // } // else // { // xPosResetted = false; // } // if (lastWasSpace) // { // xPos += 20; // lastWasSpace = false; // } // // trace(_finalText.fastCodeAt(loopNum) + " " + _finalText.charAt(loopNum)); // // var letter:AlphaCharacter = new AlphaCharacter(30 * loopNum, 0); // var letter:AlphaCharacter = new AlphaCharacter(xPos, 55 * yMulti); // letter.row = curRow; // if (isBold) // { // letter.createBold(splitWords[loopNum]); // } // else // { // if (isNumber) // { // letter.createNumber(splitWords[loopNum]); // } // else if (isSymbol) // { // letter.createSymbol(splitWords[loopNum]); // } // else // { // letter.createLetter(splitWords[loopNum]); // } // letter.x += 90; // } // if (FlxG.random.bool(40)) // { // var daSound:String = "GF_"; // FlxG.sound.play(Paths.soundRandom(daSound, 1, 4)); // } // add(letter); // lastSprite = letter; // } 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(); @:privateAccess group.members = []; _sprites = cast group.members; lastSprite = null; addText(); } } } class AlphaCharacter extends FlxSprite { @:dox(hide) @:noCompletion public static var __alphaPath:String = null; 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); var tex = Paths.getSparrowAtlas('alphabet'); frames = tex; antialiasing = true; } public function createBold(letter:String) { letter = letter.toUpperCase(); if (boldAnims[letter] == null) { visible = false; return; } animation.addByPrefix(letter, boldAnims[letter], 24); animation.play(letter); updateHitbox(); } public function createLetter(letter:String):Void { if (letterAnims[letter] == null) { visible = false; return; } animation.addByPrefix(letter, letterAnims[letter], 24); animation.play(letter); updateHitbox(); y = (110 - height); y += row * 60; } public function createNumber(letter:String):Void { animation.addByPrefix(letter, letter, 24); animation.play(letter); updateHitbox(); } public function createSymbol(letter:String) { switch (letter) { case '.': animation.addByPrefix(letter, 'period', 24); animation.play(letter); y += 50; case "'": animation.addByPrefix(letter, 'apostraphie', 24); animation.play(letter); y -= 0; case "?": animation.addByPrefix(letter, 'question mark', 24); animation.play(letter); case "!": animation.addByPrefix(letter, 'exclamation point', 24); animation.play(letter); } updateHitbox(); } }