diff --git a/assets/data/dialogue/boxes/default.xml b/assets/data/dialogue/boxes/default.xml
index f40a3196..b67c4ab0 100644
--- a/assets/data/dialogue/boxes/default.xml
+++ b/assets/data/dialogue/boxes/default.xml
@@ -8,9 +8,9 @@
-
+
-
+
-
+
- yo its me your enemy! how are you
+ yo its me your enemy! how are you
shut up u stupid bitch
@@ -59,4 +59,10 @@
ok now stfu and lets rap its getting annoying
+
+ Wanna have sex later cutie
+
+
+ bro what
+
\ No newline at end of file
diff --git a/assets/songs/thorns/cutscene.hx b/assets/songs/thorns/cutscene.hx
index ee84365e..79a46451 100644
--- a/assets/songs/thorns/cutscene.hx
+++ b/assets/songs/thorns/cutscene.hx
@@ -47,7 +47,7 @@ function create() {
if(FlxG.camera._fxFadeAlpha > 0.3) swagTimer.reset();
else {
camHUD.visible = true;
- self.startDialogue("songs/" + PlayState.instance.SONG.meta.name.toLowerCase() + "/creepyDialogue.xml", self.close);
+ self.startDialogue("assets/songs/" + PlayState.instance.SONG.meta.name.toLowerCase() + "/creepyDialogue.xml", self.close);
}
});
});
diff --git a/source/funkin/backend/scripting/events/DialogueBoxSetTextEvent.hx b/source/funkin/backend/scripting/events/DialogueBoxSetTextEvent.hx
deleted file mode 100644
index b8b7072a..00000000
--- a/source/funkin/backend/scripting/events/DialogueBoxSetTextEvent.hx
+++ /dev/null
@@ -1,12 +0,0 @@
-package funkin.backend.scripting.events;
-
-import flixel.sound.FlxSound;
-
-final class DialogueBoxSetTextEvent extends CancellableEvent
-{
- public var text:String;
-
- public var speed:Float;
-
- public var customTypeSFX:Array;
-}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DynamicEvent.hx b/source/funkin/backend/scripting/events/DynamicEvent.hx
new file mode 100644
index 00000000..077fec27
--- /dev/null
+++ b/source/funkin/backend/scripting/events/DynamicEvent.hx
@@ -0,0 +1,12 @@
+package funkin.backend.scripting.events;
+
+/**
+ * Event with random dynamic values useful for making your own custom events
+ */
+final class DynamicEvent extends CancellableEvent {
+ public var value1:Dynamic = null;
+ public var value2:Dynamic = null;
+ public var value3:Dynamic = null;
+ public var value4:Dynamic = null;
+ public var value5:Dynamic = null;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DialogueBoxCharPopupEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueBoxCharPopupEvent.hx
similarity index 68%
rename from source/funkin/backend/scripting/events/DialogueBoxCharPopupEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueBoxCharPopupEvent.hx
index 3b36c160..ad098040 100644
--- a/source/funkin/backend/scripting/events/DialogueBoxCharPopupEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueBoxCharPopupEvent.hx
@@ -1,8 +1,10 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import funkin.game.cutscenes.dialogue.DialogueCharacter;
final class DialogueBoxCharPopupEvent extends CancellableEvent
{
public var char:DialogueCharacter;
+
+ public var force:Bool;
}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DialogueBoxPlayBubbleEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueBoxPlayBubbleEvent.hx
similarity index 71%
rename from source/funkin/backend/scripting/events/DialogueBoxPlayBubbleEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueBoxPlayBubbleEvent.hx
index 0baf7a65..66363a4d 100644
--- a/source/funkin/backend/scripting/events/DialogueBoxPlayBubbleEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueBoxPlayBubbleEvent.hx
@@ -1,5 +1,6 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
+import funkin.backend.utils.XMLUtil.TextFormat;
import flixel.sound.FlxSound;
final class DialogueBoxPlayBubbleEvent extends CancellableEvent
@@ -10,6 +11,8 @@ final class DialogueBoxPlayBubbleEvent extends CancellableEvent
public var text:String;
+ public var format:Array;
+
public var speed:Float;
public var customSFX:FlxSound;
diff --git a/source/funkin/backend/scripting/events/dialogue/DialogueBoxSetTextEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueBoxSetTextEvent.hx
new file mode 100644
index 00000000..91c3d113
--- /dev/null
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueBoxSetTextEvent.hx
@@ -0,0 +1,15 @@
+package funkin.backend.scripting.events.dialogue;
+
+import funkin.backend.utils.XMLUtil.TextFormat;
+import flixel.sound.FlxSound;
+
+final class DialogueBoxSetTextEvent extends CancellableEvent
+{
+ public var text:String;
+
+ public var format:Array;
+
+ public var speed:Null;
+
+ public var customTypeSFX:Array;
+}
\ No newline at end of file
diff --git a/source/funkin/backend/scripting/events/DialogueBoxStructureEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueBoxStructureEvent.hx
similarity index 83%
rename from source/funkin/backend/scripting/events/DialogueBoxStructureEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueBoxStructureEvent.hx
index 83923d09..cabda907 100644
--- a/source/funkin/backend/scripting/events/DialogueBoxStructureEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueBoxStructureEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import haxe.xml.Access;
diff --git a/source/funkin/backend/scripting/events/DialogueCharHideEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueCharHideEvent.hx
similarity index 82%
rename from source/funkin/backend/scripting/events/DialogueCharHideEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueCharHideEvent.hx
index 8b372643..c06cce27 100644
--- a/source/funkin/backend/scripting/events/DialogueCharHideEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueCharHideEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import funkin.game.cutscenes.dialogue.DialogueCharacter.DialogueCharAnimContext;
diff --git a/source/funkin/backend/scripting/events/DialogueCharShowEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueCharShowEvent.hx
similarity index 84%
rename from source/funkin/backend/scripting/events/DialogueCharShowEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueCharShowEvent.hx
index acdb26dc..5f9456d8 100644
--- a/source/funkin/backend/scripting/events/DialogueCharShowEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueCharShowEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import funkin.game.cutscenes.dialogue.DialogueCharacter.DialogueCharAnimContext;
diff --git a/source/funkin/backend/scripting/events/DialogueCharStructureEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueCharStructureEvent.hx
similarity index 83%
rename from source/funkin/backend/scripting/events/DialogueCharStructureEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueCharStructureEvent.hx
index 11503096..c518179b 100644
--- a/source/funkin/backend/scripting/events/DialogueCharStructureEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueCharStructureEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import haxe.xml.Access;
diff --git a/source/funkin/backend/scripting/events/DialogueStructureEvent.hx b/source/funkin/backend/scripting/events/dialogue/DialogueStructureEvent.hx
similarity index 79%
rename from source/funkin/backend/scripting/events/DialogueStructureEvent.hx
rename to source/funkin/backend/scripting/events/dialogue/DialogueStructureEvent.hx
index da4d5da4..97ac8a03 100644
--- a/source/funkin/backend/scripting/events/DialogueStructureEvent.hx
+++ b/source/funkin/backend/scripting/events/dialogue/DialogueStructureEvent.hx
@@ -1,4 +1,4 @@
-package funkin.backend.scripting.events;
+package funkin.backend.scripting.events.dialogue;
import haxe.xml.Access;
diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx
index d73304c1..67d0b4c0 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -1,5 +1,8 @@
package funkin.backend.utils;
+import flixel.text.FlxText;
+import openfl.text.TextFormatAlign;
+import funkin.backend.utils.XMLUtil.TextFormat;
import flixel.tweens.FlxTween;
import flixel.system.frontEnds.SoundFrontEnd;
import flixel.sound.FlxSound;
@@ -457,6 +460,47 @@ class CoolUtil
return xml.att.resolve(name);
}
+ /**
+ * Sets automatically all the compatible formats to a text.
+ *
+ * WARNING: These are dependant from the font, so if the font doesn't support for example the `bold` format it won't work!
+ * @param text Text to set the format for
+ * @param formats Array of the formats (to get the formats from a node, you can use `XMLUtil.getTextFormats(node)`)
+ */
+ public static function autoSetFormat(text:FlxText, formats:Array) {
+ var i = 0;
+ @:privateAccess
+ for(format in formats) {
+ var fmtt = format.format;
+ var start = i;
+ var end = i + format.text.length;
+ i = end;
+ if(Reflect.fields(fmtt).length == 0) continue;
+ 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.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;
+ fmt.borderColor = Reflect.hasField(fmtt, "borderColor") ? FlxColor.fromString(fmtt.borderColor) : text.borderColor;
+ fmt.format.align = Reflect.hasField(fmtt, "align") ? TextFormatAlign.fromString(fmtt.align) : FlxTextAlign.toOpenFL(text.alignment);
+
+ if(Reflect.hasField(fmtt, "leading")) fmt.format.leading = Std.parseInt(fmtt.leading);
+ if(Reflect.hasField(fmtt, "kerning")) fmt.format.kerning = fmtt.kerning == "true";
+ if(Reflect.hasField(fmtt, "blockIndent")) fmt.format.blockIndent = Std.parseInt(fmtt.blockIndent);
+ if(Reflect.hasField(fmtt, "bullet")) fmt.format.bullet = fmtt.bullet == "true";
+ if(Reflect.hasField(fmtt, "indent")) fmt.format.indent = Std.parseInt(fmtt.indent);
+ if(Reflect.hasField(fmtt, "leftMargin")) fmt.format.leftMargin = Std.parseInt(fmtt.leftMargin);
+ if(Reflect.hasField(fmtt, "letterSpacing")) fmt.format.letterSpacing = Std.parseFloat(fmtt.letterSpacing);
+ if(Reflect.hasField(fmtt, "rightMargin")) fmt.format.rightMargin = Std.parseInt(fmtt.rightMargin);
+ if(Reflect.hasField(fmtt, "tabStops")) fmt.format.tabStops = [for(x in cast(fmtt.tabStops, String).split(",")) Std.parseInt(x)];
+ if(Reflect.hasField(fmtt, "underline")) fmt.format.underline = fmtt.underline == "true";
+ text.addFormat(fmt, start, end);
+ }
+ return text;
+ }
+
/**
* Loads an animated graphic, and automatically animates it.
* @param spr Sprite to load the graphic for
diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx
index 7058ae28..0ac1bef7 100644
--- a/source/funkin/backend/utils/XMLUtil.hx
+++ b/source/funkin/backend/utils/XMLUtil.hx
@@ -5,9 +5,13 @@ import funkin.backend.system.ErrorCode;
import funkin.backend.FunkinSprite.XMLAnimType;
import flixel.util.FlxColor;
import haxe.xml.Access;
+import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.system.interfaces.IOffsetCompatible;
using StringTools;
+
+typedef TextFormat = { text:String, format:Dynamic }
+
/**
* Class made to make XML parsing easier.
*/
@@ -279,6 +283,51 @@ class XMLUtil {
var v:String;
return [for(l in text.split("\n")) if ((v = l.trim()) != "") v].join("\n");
}
+
+ /**
+ * WARNING: will edit directly the node!
+ */
+ public static function fixSpacingInNode(node:Access):Access {
+ var arr = [for(x in node.x) x];
+ for(i => n in arr) {
+ if(n.nodeType == PCData) {
+ if(i == 0) n.nodeValue = n.nodeValue.ltrim();
+ if(i == arr.length - 1) n.nodeValue = n.nodeValue.rtrim();
+ if(n.nodeValue.contains("\n")) {
+ var a = n.nodeValue.split("\n");
+ n.nodeValue = [for(i => x in a) i == 0 ? x.rtrim() : i == arr.length - 1 ? x.ltrim() : x.trim()].join("\n");
+ }
+ }
+ }
+ return node;
+ }
+
+ public static function getTextFormats(_node:OneOfTwo, currentFormat:Dynamic = null, parsedSegments:Array = null):Array {
+ var node:Xml = cast _node;
+ if (currentFormat == null)
+ currentFormat = {};
+ if (parsedSegments == null)
+ parsedSegments = [];
+
+ for (child in node) {
+ switch (child.nodeType) {
+ case Element:
+ if (child.nodeName == "format") {
+ var format:Dynamic = Reflect.copy(currentFormat);
+ @:privateAccess for (key => name in child.attributeMap) {
+ Reflect.setField(format, key, name);
+ }
+ getTextFormats(child, format, parsedSegments);
+ }
+ case PCData:
+ parsedSegments.push({ text: child.nodeValue, format: Reflect.copy(currentFormat) });
+ default:
+ // Ignore other node types
+ }
+ }
+
+ return parsedSegments;
+ }
}
typedef AnimData = {
diff --git a/source/funkin/game/SplashGroup.hx b/source/funkin/game/SplashGroup.hx
index 1fad99d4..75008a29 100644
--- a/source/funkin/game/SplashGroup.hx
+++ b/source/funkin/game/SplashGroup.hx
@@ -23,82 +23,84 @@ class SplashGroup extends FlxTypedGroup {
* Creates a new Splash group
* @param path Path to the splash data (xml)
*/
- public function new(path) {
+ public function new(path:String) {
super();
try {
xml = new Access(Xml.parse(Assets.getText(path)).firstElement());
if (!xml.has.sprite) throw "The element requires a sprite attribute.";
-
- var splashSprite = new FunkinSprite();
- splashSprite.antialiasing = true;
- splashSprite.active = splashSprite.visible = false;
- splashSprite.loadSprite(Paths.image(xml.att.sprite));
-
- /**
- * ANIMATIONS
- */
- for(strum in xml.nodes.strum) {
- var id:Null = Std.parseInt(strum.att.id);
- if (id != null) {
- animationNames[id] = [];
- for(anim in strum.nodes.anim) {
- if (!anim.has.name) continue;
- XMLUtil.addXMLAnimation(splashSprite, anim, false);
- animationNames[id].push(anim.att.name);
- }
- }
- }
- if (animationNames.length <= 0)
- animationNames.push([]);
- for(anim in xml.nodes.anim) {
- if (!anim.has.name) continue;
- XMLUtil.addXMLAnimation(splashSprite, anim, false);
- for(a in animationNames) {
- if (a == null) continue;
- a.push(anim.att.name);
- }
- }
- /**
- * END OF ANIMATIONS
- */
- splashSprite.animation.finishCallback = function(name) {
- splashSprite.active = splashSprite.visible = false;
- };
-
- if (xml.has.scale) splashSprite.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1));
- if (xml.has.alpha) splashSprite.alpha = Std.parseFloat(xml.att.alpha).getDefault(1);
- if (xml.has.antialiasing) splashSprite.antialiasing = xml.att.antialiasing == "true";
-
- add(splashSprite);
-
- for (i in 0...7) {
- // make 7 additional splashes
- var spr = FunkinSprite.copyFrom(splashSprite);
- spr.animation.finishCallback = function(name) {
- spr.active = spr.visible = false;
- };
- add(spr);
- }
+ var splash = createSplash(xml.att.sprite);
+ setupAnims(xml, splash);
+ pregenerateSplashes(splash);
+ add(splash);
// immediatly draw once and put image in GPU to prevent freezes
// TODO: change to graphics cache
- splashSprite.drawComplex(FlxG.camera);
- } catch(e) {
+ splash.drawComplex(FlxG.camera);
+ } catch(e:Dynamic) {
Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR);
valid = false;
}
-
maxSize = 8;
}
+ function createSplash(imagePath:String) {
+ var splash = new FunkinSprite();
+ splash.antialiasing = true;
+ splash.active = splash.visible = false;
+ splash.loadSprite(Paths.image(imagePath));
+ if (xml.has.scale) splash.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1));
+ if (xml.has.alpha) splash.alpha = Std.parseFloat(xml.att.alpha).getDefault(1);
+ if (xml.has.antialiasing) splash.antialiasing = xml.att.antialiasing == "true";
+ return splash;
+ }
+
+ function setupAnims(xml:Access, splash:FunkinSprite) {
+ for(strum in xml.nodes.strum) {
+ var id:Null = Std.parseInt(strum.att.id);
+ if (id != null) {
+ animationNames[id] = [];
+ for(anim in strum.nodes.anim) {
+ if (!anim.has.name) continue;
+ XMLUtil.addXMLAnimation(splash, anim, false);
+ animationNames[id].push(anim.att.name);
+ }
+ }
+ }
+
+ // if (animationNames.length <= 0)
+ // animationNames.push([]);
+
+ for(anim in xml.nodes.anim) {
+ if (!anim.has.name) continue;
+ XMLUtil.addXMLAnimation(splash, anim, false);
+ for(a in animationNames) {
+ if (a == null) continue;
+ a.push(anim.att.name);
+ }
+ }
+ splash.animation.finishCallback = function(name:String) {
+ splash.active = splash.visible = false;
+ };
+ }
+
+ function pregenerateSplashes(splash:FunkinSprite) {
+ // make 7 additional splashes
+ for(i in 0...7) {
+ var spr = FunkinSprite.copyFrom(splash);
+ spr.animation.finishCallback = function(name:String) {
+ spr.active = spr.visible = false;
+ };
+ add(spr);
+ }
+ }
+
public function getSplashAnim(id:Int):String {
if (animationNames.length <= 0) return null;
id %= animationNames.length;
- if (animationNames[id] == null) return null;
- if (animationNames[id].length <= 0) return null;
- return animationNames[id][FlxG.random.int(0, animationNames[id].length-1)];
+ if (animationNames[id] == null || animationNames[id].length <= 0) return null;
+ return animationNames[id][FlxG.random.int(0, animationNames[id].length - 1)];
}
var __splash:FunkinSprite;
diff --git a/source/funkin/game/cutscenes/DialogueCutscene.hx b/source/funkin/game/cutscenes/DialogueCutscene.hx
index d4c706e3..656df6f2 100644
--- a/source/funkin/game/cutscenes/DialogueCutscene.hx
+++ b/source/funkin/game/cutscenes/DialogueCutscene.hx
@@ -1,7 +1,9 @@
package funkin.game.cutscenes;
import funkin.backend.utils.FunkinParentDisabler;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.dialogue.*;
+import funkin.backend.scripting.events.CancellableEvent;
+import funkin.backend.scripting.events.DynamicEvent;
import funkin.backend.scripting.Script;
import flixel.sound.FlxSound;
import funkin.game.cutscenes.dialogue.*;
@@ -49,7 +51,7 @@ class DialogueCutscene extends Cutscene {
public override function create() {
super.create();
- add(parentDisabler = new FunkinParentDisabler());
+ add(parentDisabler = new FunkinParentDisabler()); // MESS WITH THIS IN SCRIPTS TO RESUME PLAYSTATE'S TWEENS!! - Nex
try {
var event = EventManager.get(DialogueStructureEvent).recycle(dialogueData);
event.dialogueData = new Access(Xml.parse(Assets.getText(dialoguePath)).firstElement());
@@ -64,7 +66,7 @@ class DialogueCutscene extends Cutscene {
Logs.trace('2 dialogue characters share the same name (${char.att.name}, ${char.att.name}). The old character has been replaced.');
var leChar:DialogueCharacter = new DialogueCharacter(char.att.name, char.getAtt('position').getDefault('default'));
- if(char.has.defaultAnim) leChar.defaultAnim = char.getAtt('defaultAnim');
+ if(char.has.defaultAnim) leChar.defaultAnim = char.att.defaultAnim;
add(charMap[char.att.name] = leChar);
}
@@ -74,26 +76,28 @@ class DialogueCutscene extends Cutscene {
// Add lines
for(node in dialogueData.nodes.line) {
+ var formats = XMLUtil.getTextFormats(XMLUtil.fixSpacingInNode(node));
var volume:Null = 0.8;
var line:DialogueLine = {
- text: XMLUtil.fixXMLText(node.innerHTML),
+ text: [for(x in formats) x.text].join(""),
+ format: formats,
char: node.getAtt('char').getDefault('boyfriend'),
bubble: node.getAtt('bubble').getDefault('normal'),
callback: node.getAtt('callback'),
changeDefAnim: node.getAtt('changeDefAnim'),
- speed: node.has.speed ? Std.parseFloat(node.att.speed).getDefault(0.05) : 0.05,
+ speed: Std.parseFloat(node.getAtt("speed")).getDefault(0.05),
musicVolume: node.has.musicVolume ? (volume = Std.parseFloat(node.att.speed).getDefault(0.8)) : null,
- changeMusic: node.has.changeMusic ? FlxG.sound.load(Paths.music(node.getAtt('changeMusic')), volume, true) : null,
- playSound: node.has.playSound ? FlxG.sound.load(Paths.sound(node.getAtt('playSound'))) : null,
- nextSound: node.has.nextSound ? FlxG.sound.load(Paths.music(node.getAtt('nextSound'))) : 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,
textSound: null
};
- if(node.has.textSound) line.textSound = FlxG.sound.load(Paths.sound(node.getAtt('textSound')));
+ if(node.has.textSound) line.textSound = FlxG.sound.load(Paths.sound(node.att.textSound));
else if(!useDef) {
var char:DialogueCharacter = charMap[line.char];
if(char != null && char.charData != null && char.charData.has.textSound)
- line.textSound = FlxG.sound.load(Paths.sound(char.charData.getAtt("textSound")));
+ line.textSound = FlxG.sound.load(Paths.sound(char.charData.att.textSound));
}
dialogueLines.push(line);
@@ -107,6 +111,7 @@ class DialogueCutscene extends Cutscene {
next(true);
} catch(e) {
Logs.trace('Error while loading dialogue at ${dialoguePath}: ${e.toString()}', ERROR);
+ trace(CoolUtil.getLastExceptionStack());
close();
}
dialogueScript.call("postCreate");
@@ -122,7 +127,6 @@ class DialogueCutscene extends Cutscene {
dialogueScript.call("update", [elapsed]);
if(controls.ACCEPT) {
- @:privateAccess
if(dialogueBox.dialogueEnded) next();
else dialogueBox.text.skip();
}
@@ -134,8 +138,9 @@ class DialogueCutscene extends Cutscene {
public var canProceed:Bool = true;
public function next(playFirst:Bool = false) {
+ var event = EventManager.get(DynamicEvent).recycle(playFirst);
dialogueScript.call("next", [playFirst]);
- if(!canProceed) return;
+ if(event.cancelled || !canProceed) return;
if ((curLine = dialogueLines.shift()) == null) {
if(lastLine != null && dialogueBox.hasAnimation(lastLine.bubble + "-close")) {
@@ -148,7 +153,10 @@ class DialogueCutscene extends Cutscene {
return;
}
- for(k=>c in charMap)
+ if (curLine.callback != null)
+ dialogueScript.call(curLine.callback, [playFirst]);
+
+ for (k=>c in charMap)
if (k != curLine.char)
c.hide();
@@ -160,7 +168,7 @@ class DialogueCutscene extends Cutscene {
}
var finalSuffix:String = playFirst && dialogueBox.hasAnimation(curLine.bubble + "-firstOpen") ? "-firstOpen" : dialogueBox.hasAnimation(curLine.bubble + "-open") ? "-open" : "";
- dialogueBox.playBubbleAnim(curLine.bubble, finalSuffix, curLine.text, curLine.speed, curLine.nextSound, curLine.textSound != null ? [curLine.textSound] : null, finalSuffix == "-firstOpen" || finalSuffix == "-open", !playFirst);
+ dialogueBox.playBubbleAnim(curLine.bubble, finalSuffix, curLine.text, curLine.format, curLine.speed, curLine.nextSound, curLine.textSound != null ? [curLine.textSound] : null, finalSuffix == "-firstOpen" || finalSuffix == "-open", !playFirst);
if(curLine.playSound != null) curLine.playSound.play();
if(curLine.changeMusic != null) {
@@ -196,6 +204,7 @@ class DialogueCutscene extends Cutscene {
typedef DialogueLine = {
var text:String;
+ var format:Array;
var char:String;
var bubble:String;
var callback:String;
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
index 68cc5157..caf45949 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx
@@ -1,13 +1,14 @@
package funkin.game.cutscenes.dialogue;
-import funkin.backend.scripting.events.*;
+import funkin.backend.scripting.events.dialogue.*;
+import funkin.backend.scripting.events.PlayAnimEvent;
import funkin.backend.scripting.events.PlayAnimEvent.PlayAnimContext;
import funkin.backend.scripting.events.CancellableEvent;
import funkin.backend.scripting.Script;
import flixel.sound.FlxSound;
import flixel.addons.text.FlxTypeText;
-import flixel.text.FlxText;
import flixel.math.FlxPoint;
+import flixel.util.FlxColor;
import haxe.xml.Access;
class DialogueBox extends FunkinSprite {
@@ -72,7 +73,7 @@ class DialogueBox extends FunkinSprite {
textNode.has.width ? Std.parseInt(textNode.att.width).getDefault(FlxG.width) : FlxG.width, "");
text.color = textNode.getAtt("color").getColorFromDynamic().getDefault(0xFF000000);
text.size = Std.parseInt(textNode.att.size).getDefault(20);
- text.font = Paths.font('${textNode.getAtt("font").getDefault("vcr.ttf")}');
+ text.font = Paths.font(textNode.getAtt("font").getDefault("vcr.ttf"));
text.antialiasing = textNode.getAtt("antialiasing").getDefault("false") == "true";
if(textNode.has.borderStyle) {
text.borderStyle = switch(textNode.att.borderStyle.trim().toLowerCase()) {
@@ -81,6 +82,9 @@ class DialogueBox extends FunkinSprite {
case "outline_fast": OUTLINE_FAST;
default: OUTLINE;
}
+ text.borderQuality = Std.parseFloat(textNode.getAtt("borderQuality")).getDefault(1);
+ text.shadowOffset.x = Std.parseFloat(textNode.getAtt("shadowOffsetX")).getDefault(1);
+ text.shadowOffset.y = Std.parseFloat(textNode.getAtt("shadowOffsetY")).getDefault(1);
text.borderSize = Std.parseFloat(textNode.getAtt("borderSize")).getDefault(1);
text.borderColor = textNode.getAtt("borderColor").getColorFromDynamic().getDefault(0xFFFFFFFF);
}
@@ -112,29 +116,31 @@ class DialogueBox extends FunkinSprite {
}
public function popupChar(char:DialogueCharacter, force:Bool = false) {
- var event = EventManager.get(DialogueBoxCharPopupEvent).recycle(char);
+ var event = EventManager.get(DialogueBoxCharPopupEvent).recycle(char, force);
dialogueBoxScript.call("popupChar", [event]);
if (event.cancelled || event.char == null || !active) return;
var pos = positions[event.char.positionName];
if (pos == null) return;
- event.char.show((FlxG.width / 2) + pos.x, FlxG.height - pos.y, null, force);
+ event.char.show((FlxG.width / 2) + pos.x, FlxG.height - pos.y, null, event.force);
+ flipX = pos.flipBubble;
+ dialogueBoxScript.call("postPopupChar", [event]);
}
- public function playBubbleAnim(bubble:String, suffix:String = '', text:String = '', speed:Float = 0.05, ?customSFX:FlxSound, ?customTypeSFX:Array, setTextAfter:Bool = false, allowDefault:Bool = true) {
- var event = EventManager.get(DialogueBoxPlayBubbleEvent).recycle(bubble, suffix, text, speed, customSFX, customTypeSFX, setTextAfter, allowDefault);
+ public function playBubbleAnim(bubble:String, suffix:String = '', text:String = '', ?format:Array, speed:Float = 0.05, ?customSFX:FlxSound, ?customTypeSFX:Array, setTextAfter:Bool = false, allowDefault:Bool = true) {
+ var event = EventManager.get(DialogueBoxPlayBubbleEvent).recycle(bubble, suffix, text, format, speed, customSFX, customTypeSFX, setTextAfter, allowDefault);
dialogueBoxScript.call("playBubbleAnim", [event]);
if(event.cancelled) return;
if(event.customSFX != null) event.customSFX.play();
else if(event.allowDefault) FlxG.sound.play(nextSFX);
var idk:Void->Void = () -> {
- if(text != null && text.trim().length > 0) setText(event.text, event.speed, event.customTypeSFX);
+ if(text != null && text.trim().length > 0) startText(event.text, event.format, event.speed, event.customTypeSFX);
else dialogueEnded = true;
}
dialogueEnded = false;
- this.text.resetText('');
+ resetText();
var anim:String = event.bubble + event.suffix;
if(hasAnimation(anim)) playAnim(anim, true);
if(!event.setTextAfter) idk();
@@ -148,16 +154,30 @@ class DialogueBox extends FunkinSprite {
dialogueBoxScript.call("postPlayBubbleAnim", [event]);
}
- public function setText(text:String, speed:Float = 0.05, ?customTypeSFX:Array) {
- var event = EventManager.get(DialogueBoxSetTextEvent).recycle(text, speed, customTypeSFX);
- dialogueBoxScript.call("setText", [event]);
+ public function resetText(text:String = '', ?formats:Array, ?event:DialogueBoxSetTextEvent) {
+ if(event == null) event = EventManager.get(DialogueBoxSetTextEvent).recycle(text, formats, null, null);
+ dialogueBoxScript.call("resetText", [event]);
if(event.cancelled) return;
+ this.text.clearFormats();
+ if(formats != null)
+ this.text.autoSetFormat(formats);
+
this.text.resetText(event.text);
+ dialogueBoxScript.call("postResetText");
+ }
+
+ public function startText(text:String = '', ?format:Array, speed:Float = 0.05, ?customTypeSFX:Array) {
+ var event = EventManager.get(DialogueBoxSetTextEvent).recycle(text, format, speed, customTypeSFX);
+ dialogueBoxScript.call("startText", [event]);
+ if(event.cancelled) return;
+
+ resetText(event.text, event.format, event);
this.text.sounds = event.customTypeSFX != null ? event.customTypeSFX : defaultTextTypeSFX;
this.text.delay = event.speed;
this.text.start(event.speed, true);
this.text.completeCallback = () -> dialogueEnded = true;
+ dialogueBoxScript.call("postStartText");
}
public override function destroy() {
diff --git a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
index 73088192..97701e1f 100644
--- a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
+++ b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx
@@ -1,7 +1,7 @@
package funkin.game.cutscenes.dialogue;
-import funkin.backend.scripting.events.*;
-import funkin.backend.scripting.events.PlayAnimEvent.PlayAnimContext;
+import funkin.backend.scripting.events.PlayAnimEvent;
+import funkin.backend.scripting.events.dialogue.*;
import funkin.backend.scripting.events.CancellableEvent;
import funkin.backend.scripting.Script;
import flixel.tweens.FlxTween;