finalizing the dialogue system 11

more stuff and text formats!

Co-Authored-By: Ne_Eo <NeeEoo@users.noreply.github.com>
This commit is contained in:
⍚~Nex
2024-02-27 01:50:21 +01:00
co-authored by Ne_Eo
parent 0ef969db1f
commit 9ca7f01866
21 changed files with 261 additions and 111 deletions
+60 -58
View File
@@ -23,82 +23,84 @@ class SplashGroup extends FlxTypedGroup<FunkinSprite> {
* 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 <splash> 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<Int> = 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<Int> = 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;
@@ -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<Float> = 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<XMLUtil.TextFormat>;
var char:String;
var bubble:String;
var callback:String;
@@ -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<FlxSound>, 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<XMLUtil.TextFormat>, speed:Float = 0.05, ?customSFX:FlxSound, ?customTypeSFX:Array<FlxSound>, 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<FlxSound>) {
var event = EventManager.get(DialogueBoxSetTextEvent).recycle(text, speed, customTypeSFX);
dialogueBoxScript.call("setText", [event]);
public function resetText(text:String = '', ?formats:Array<XMLUtil.TextFormat>, ?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<XMLUtil.TextFormat>, speed:Float = 0.05, ?customTypeSFX:Array<FlxSound>) {
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() {
@@ -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;