diff --git a/assets/data/alphabet/normal.xml b/assets/data/alphabet/normal.xml
index 69b7faff..a02526db 100644
--- a/assets/data/alphabet/normal.xml
+++ b/assets/data/alphabet/normal.xml
@@ -14,6 +14,7 @@
down arrow
up arrow
comma
+ comma
period
question mark
start parentheses
diff --git a/source/funkin/menus/ui/NewAlphabet.hx b/source/funkin/menus/ui/NewAlphabet.hx
index 412c0c9b..67cebc1e 100644
--- a/source/funkin/menus/ui/NewAlphabet.hx
+++ b/source/funkin/menus/ui/NewAlphabet.hx
@@ -13,24 +13,25 @@ using StringTools;
using flixel.util.FlxColorTransformUtil;
@:structInit
-class AlphabetLetterData {
- @:optional public var isDefault:Bool = false;
- public var anim:String; // should this be FlxAnimation?
+class AlphabetComponent {
+ public var anim:String;
public var x:Float;
public var y:Float;
- public var advance:Float;
- public var advanceEmpty:Bool;
+
// Precalculated values for angle
public var sin:Float;
public var cos:Float;
public var scaleX:Float;
public var scaleY:Float;
-
- // If null, render spooping as usual I see
- public var components:Array; // components with components lol
}
-// we also need to store components somehow
+@:structInit
+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;
@@ -184,24 +185,34 @@ class NewAlphabet extends FlxSprite {
}
var data = getData(letter);
- var anim = getLetterAnim(letter, data);
- var advance:Float = getAdvance(letter, anim, data);
+ var advance:Float = Math.NaN;
+
+ if (data == null) {
+ frameOffset.x -= defaultAdvance;
+ continue;
+ }
+
+ 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;
+ }
- if (anim == null || __renderData.alpha <= 0.0) {
- frameOffset.x -= advance;
- } else {
var frameToGet = frameTime % anim.numFrames;
frame = frames.frames[anim.frames[frameToGet]];
- var offsetX = data.x + __renderData.offsetX;
- var offsetY = frame.sourceSize.y - lineGap + data.y + __renderData.offsetY;
+ 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;
frameOffset.x -= advance;
- continue;
+ break;
}
if (isGraphicsShader)
shader.setCamSize(_frame.frame.x, _frame.frame.y, _frame.frame.width, _frame.frame.height);
@@ -249,7 +260,7 @@ class NewAlphabet extends FlxSprite {
}
var data = getData(letter);
- __laneWidths[curLine] += getAdvance(letter, getLetterAnim(letter, data), data);
+ __laneWidths[curLine] += (data != null) ? getAdvance(letter, getLetterAnim(letter, data, data.components[0], 0), data) : defaultAdvance;
@:bypassAccessor textWidth = Math.max(textWidth, __laneWidths[curLine]);
}
@@ -296,17 +307,18 @@ class NewAlphabet extends FlxSprite {
return data;
}
- function getLetterAnim(char:String, data:AlphabetLetterData):FlxAnimation {
+ function getLetterAnim(char:String, data:AlphabetLetterData, component:AlphabetComponent, index:Int):FlxAnimation {
if (data == null) return null;
- if (animation.exists(char)) return animation.getByName(char);
+ var name = char + Std.string(index);
+ if (animation.exists(name)) return animation.getByName(name);
- var anim = (data.isDefault) ? data.anim.replace("LETTER", char) : data.anim;
- animation.addByPrefix(char, anim, fps);
- if (!animation.exists(char)) {
+ 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(char);
+ return animation.getByName(name);
}
function checkNode(node:Xml):Void {
@@ -327,23 +339,64 @@ class NewAlphabet extends FlxSprite {
defaults[idx] = {
isDefault: true,
- anim: node.firstChild().nodeValue,
-
- x: 0.0,
- y: 0.0,
advance: 0.0,
advanceEmpty: true,
+ components: [{
+ anim: node.firstChild().nodeValue,
- scaleX: Std.parseFloat(node.get("scaleX")).getDefault(1.0),
- scaleY: Std.parseFloat(node.get("scaleY")).getDefault(1.0),
-
- cos: angleCos,
- sin: angleSin,
-
- components: null
+ x: 0.0,
+ y: 0.0,
+ scaleX: Std.parseFloat(node.get("scaleX")).getDefault(1.0),
+ scaleY: Std.parseFloat(node.get("scaleY")).getDefault(1.0),
+
+ cos: angleCos,
+ sin: angleSin
+ }]
};
+ case "composite":
+ if(!node.exists("char")) {
+ Log.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")) {
+ Log.error(" must have a anim attribute", "Alphabet");
+ return;
+ }
+
+ var angle:Float = Std.parseFloat(component.get("angle")).getDefault(0.0);
+ var angleCos = Math.cos(angle);
+ var angleSin = Math.sin(angle);
+
+ var xOff:Float = -Std.parseFloat(component.get("x")).getDefault(0.0);
+ var yOff:Float = Std.parseFloat(component.get("y")).getDefault(0.0);
+
+ components.push({
+ anim: component.get("anim"),
+
+ x: xOff,
+ y: yOff,
+ scaleX: Std.parseFloat(component.get("scaleX")).getDefault(1.0),
+ scaleY: Std.parseFloat(component.get("scaleY")).getDefault(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")) throw "[Alphabet] must have a char attribute";
+ if(!node.exists("char")) {
+ Log.error(" must have a char attribute", "Alphabet");
+ return;
+ }
var char = node.get("char");
var angle:Float = Std.parseFloat(node.get("angle")).getDefault(0.0);
@@ -356,20 +409,19 @@ class NewAlphabet extends FlxSprite {
letterData.set(char, {
isDefault: false,
- anim: node.firstChild().nodeValue,
-
- x: xOff,
- y: yOff,
advance: advance,
advanceEmpty: Math.isNaN(advance),
+ components: [{
+ anim: node.firstChild().nodeValue,
- scaleX: Std.parseFloat(node.get("scaleX")).getDefault(1.0),
- scaleY: Std.parseFloat(node.get("scaleY")).getDefault(1.0),
-
- cos: angleCos,
- sin: angleSin,
-
- components: null
+ x: xOff,
+ y: yOff,
+ scaleX: Std.parseFloat(node.get("scaleX")).getDefault(1.0),
+ scaleY: Std.parseFloat(node.get("scaleY")).getDefault(1.0),
+
+ cos: angleCos,
+ sin: angleSin
+ }]
});
case "languageSection": // used to only parse characters if a specific language is selected
if(!node.exists("langs")) throw "[Alphabet] must have a langs attribute";