Merge branch 'main' of https://github.com/FNF-CNE-Devs/CodenameEngine-Dev
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
name: Windows Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Windows Build
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<!--
|
||||
All positions for characters
|
||||
-->
|
||||
<charpos name="left" x="-500" y="184" />
|
||||
<charpos name="left" x="-500" y="184" flipBubble="true" />
|
||||
<charpos name="middle" x="0" y="184" />
|
||||
<charpos name="right" x="500" y="184" flipBubble="true" />
|
||||
<charpos name="right" x="500" y="184" />
|
||||
|
||||
<!--
|
||||
All animations for the dialogue box
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!--
|
||||
Node containing all text settings
|
||||
-->
|
||||
<text font="pixel.otf" x="239" y="218" width="768" color="#3f2021" size="32" antialiasing="false" borderSize="2" borderStyle="shadow" borderColor="#D89494" />
|
||||
<text font="pixel.otf" x="239" y="218" width="768" color="#3f2021" size="32" antialiasing="false" borderSize="1" borderStyle="shadow" borderColor="#D89494" shadowOffsetX="2" shadowOffsetY="2"/>
|
||||
|
||||
<!--
|
||||
All positions for characters
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE codename-engine-dialogue-character>
|
||||
<character sprite="pixel/senpai" x="-392" y="-599" graphicSizex="1334" antialiasing="false" textSound="pixel/pixelText">
|
||||
<anim name="normal-show" anim="Senpai Portrait Enter instance 10" fps="24" />
|
||||
<anim name="normal-show" anim="Senpai Portrait Enter instance 10" fps="24" x="4.4" />
|
||||
<anim name="angry-show" anim="Senpai Portrait Angry instance 10" x="-56" y="-9" fps="24" />
|
||||
</character>
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<!-- Lines -->
|
||||
<line char="dad">
|
||||
yo its me your enemy! how are you
|
||||
yo its me your <format color="#FF0000">enemy!</format> how are you
|
||||
</line>
|
||||
<line char="boyfriend">
|
||||
shut up u stupid bitch
|
||||
@@ -59,4 +59,10 @@
|
||||
<line char="boyfriend">
|
||||
ok now stfu and lets rap its getting annoying
|
||||
</line>
|
||||
<line char="girlfriend">
|
||||
Wanna <format font="pixel.otf" size="10">have <format color="#33ff33">sex</format> later</format> cutie
|
||||
</line>
|
||||
<line char="boyfriend">
|
||||
bro <format color="#FF0000">what</format>
|
||||
</line>
|
||||
</dialogue>
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<FlxSound>;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+3
-1
@@ -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;
|
||||
}
|
||||
+4
-1
@@ -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<TextFormat>;
|
||||
|
||||
public var speed:Float;
|
||||
|
||||
public var customSFX:FlxSound;
|
||||
@@ -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<TextFormat>;
|
||||
|
||||
public var speed:Null<Float>;
|
||||
|
||||
public var customTypeSFX:Array<FlxSound>;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.backend.scripting.events;
|
||||
package funkin.backend.scripting.events.dialogue;
|
||||
|
||||
import haxe.xml.Access;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.backend.scripting.events;
|
||||
package funkin.backend.scripting.events.dialogue;
|
||||
|
||||
import funkin.game.cutscenes.dialogue.DialogueCharacter.DialogueCharAnimContext;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.backend.scripting.events;
|
||||
package funkin.backend.scripting.events.dialogue;
|
||||
|
||||
import funkin.game.cutscenes.dialogue.DialogueCharacter.DialogueCharAnimContext;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.backend.scripting.events;
|
||||
package funkin.backend.scripting.events.dialogue;
|
||||
|
||||
import haxe.xml.Access;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.backend.scripting.events;
|
||||
package funkin.backend.scripting.events.dialogue;
|
||||
|
||||
import haxe.xml.Access;
|
||||
|
||||
@@ -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<TextFormat>) {
|
||||
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
|
||||
|
||||
@@ -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<Xml, Access>, currentFormat:Dynamic = null, parsedSegments:Array<TextFormat> = null):Array<TextFormat> {
|
||||
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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -163,31 +163,33 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
}
|
||||
|
||||
public inline function updateNotes() {
|
||||
__updateNote_songPos = Conductor.songPosition;
|
||||
if(__updateNote_event == null) __updateNote_event = PlayState.instance.__updateNote_event;
|
||||
notes.forEach(updateNote);
|
||||
}
|
||||
|
||||
var __updateNote_strum:Strum;
|
||||
var __updateNote_songPos:Float;
|
||||
var __updateNote_event:NoteUpdateEvent;
|
||||
public function updateNote(daNote:Note) {
|
||||
__updateNote_strum = members[daNote.noteData];
|
||||
if (__updateNote_strum == null) return;
|
||||
|
||||
PlayState.instance.__updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum);
|
||||
onNoteUpdate.dispatch(PlayState.instance.__updateNote_event);
|
||||
if (PlayState.instance.__updateNote_event.cancelled) return;
|
||||
__updateNote_event.recycle(daNote, FlxG.elapsed, __updateNote_strum);
|
||||
onNoteUpdate.dispatch(__updateNote_event);
|
||||
if (__updateNote_event.cancelled) return;
|
||||
|
||||
var songPosition = Conductor.songPosition;
|
||||
if (__updateNote_event.__updateHitWindow) {
|
||||
daNote.canBeHit = (daNote.strumTime > __updateNote_songPos - (PlayState.instance.hitWindow * daNote.latePressWindow)
|
||||
&& daNote.strumTime < __updateNote_songPos + (PlayState.instance.hitWindow * daNote.earlyPressWindow));
|
||||
|
||||
if (PlayState.instance.__updateNote_event.__updateHitWindow) {
|
||||
daNote.canBeHit = (daNote.strumTime > songPosition - (PlayState.instance.hitWindow * daNote.latePressWindow)
|
||||
&& daNote.strumTime < songPosition + (PlayState.instance.hitWindow * daNote.earlyPressWindow));
|
||||
|
||||
if (daNote.strumTime < songPosition - PlayState.instance.hitWindow && !daNote.wasGoodHit)
|
||||
if (daNote.strumTime < __updateNote_songPos - PlayState.instance.hitWindow && !daNote.wasGoodHit)
|
||||
daNote.tooLate = true;
|
||||
}
|
||||
|
||||
if (cpu && PlayState.instance.__updateNote_event.__autoCPUHit && !daNote.avoid&& !daNote.wasGoodHit && daNote.strumTime < songPosition) PlayState.instance.goodNoteHit(this, daNote);
|
||||
if (cpu && __updateNote_event.__autoCPUHit && !daNote.avoid && !daNote.wasGoodHit && daNote.strumTime < __updateNote_songPos) PlayState.instance.goodNoteHit(this, daNote);
|
||||
|
||||
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.sustainLength) < songPosition) {
|
||||
if (daNote.wasGoodHit && daNote.isSustainNote && daNote.strumTime + (daNote.sustainLength) < __updateNote_songPos) {
|
||||
deleteNote(daNote);
|
||||
return;
|
||||
}
|
||||
@@ -199,11 +201,11 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
}
|
||||
|
||||
|
||||
if (PlayState.instance.__updateNote_event.strum == null) return;
|
||||
if (__updateNote_event.strum == null) return;
|
||||
|
||||
if (PlayState.instance.__updateNote_event.__reposNote) PlayState.instance.__updateNote_event.strum.updateNotePosition(daNote);
|
||||
if (__updateNote_event.__reposNote) __updateNote_event.strum.updateNotePosition(daNote);
|
||||
if (daNote.isSustainNote)
|
||||
daNote.updateSustain(PlayState.instance.__updateNote_event.strum);
|
||||
daNote.updateSustain(__updateNote_event.strum);
|
||||
}
|
||||
|
||||
var __funcsToExec:Array<Note->Void> = [];
|
||||
@@ -302,10 +304,10 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
||||
animPrefix = strumAnimPrefix[i % strumAnimPrefix.length];
|
||||
var babyArrow:Strum = new Strum(startingPos.x + ((Note.swagWidth * strumScale) * i), startingPos.y);
|
||||
babyArrow.ID = i;
|
||||
|
||||
|
||||
if(data.scrollSpeed != null)
|
||||
babyArrow.scrollSpeed = data.scrollSpeed;
|
||||
|
||||
|
||||
var event = EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix);
|
||||
event.__doAnimation = !MusicBeatState.skipTransIn;
|
||||
event = PlayState.instance.scripts.event("onStrumCreation", event);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user