diff --git a/assets/data/dialogue/boxes/default.xml b/assets/data/dialogue/boxes/default.xml index 2f95670f..f40a3196 100644 --- a/assets/data/dialogue/boxes/default.xml +++ b/assets/data/dialogue/boxes/default.xml @@ -1,8 +1,8 @@ - + + --> + --> diff --git a/assets/data/dialogue/boxes/senpai.xml b/assets/data/dialogue/boxes/senpai.xml new file mode 100644 index 00000000..430dc9f2 --- /dev/null +++ b/assets/data/dialogue/boxes/senpai.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/data/dialogue/characters/pixelBf.xml b/assets/data/dialogue/characters/pixelBf.xml new file mode 100644 index 00000000..5292d4de --- /dev/null +++ b/assets/data/dialogue/characters/pixelBf.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/assets/data/dialogue/characters/senpai.xml b/assets/data/dialogue/characters/senpai.xml new file mode 100644 index 00000000..ffe5d244 --- /dev/null +++ b/assets/data/dialogue/characters/senpai.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/assets/images/dialogue/boxes/pixel/dialogueBox.png b/assets/images/dialogue/boxes/pixel/dialogueBox.png new file mode 100644 index 00000000..dbc7ae3e Binary files /dev/null and b/assets/images/dialogue/boxes/pixel/dialogueBox.png differ diff --git a/assets/images/dialogue/boxes/pixel/dialogueBox.xml b/assets/images/dialogue/boxes/pixel/dialogueBox.xml new file mode 100644 index 00000000..50d3f2e9 --- /dev/null +++ b/assets/images/dialogue/boxes/pixel/dialogueBox.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/assets/images/dialogue/characters/pixel/boyfriend.png b/assets/images/dialogue/characters/pixel/boyfriend.png new file mode 100644 index 00000000..2756eaf0 Binary files /dev/null and b/assets/images/dialogue/characters/pixel/boyfriend.png differ diff --git a/assets/images/dialogue/characters/pixel/boyfriend.xml b/assets/images/dialogue/characters/pixel/boyfriend.xml new file mode 100644 index 00000000..e4f6210a --- /dev/null +++ b/assets/images/dialogue/characters/pixel/boyfriend.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/dialogue/characters/pixel/senpai.png b/assets/images/dialogue/characters/pixel/senpai.png new file mode 100644 index 00000000..4e60d818 Binary files /dev/null and b/assets/images/dialogue/characters/pixel/senpai.png differ diff --git a/assets/images/dialogue/characters/pixel/senpai.xml b/assets/images/dialogue/characters/pixel/senpai.xml new file mode 100644 index 00000000..0a4916b3 --- /dev/null +++ b/assets/images/dialogue/characters/pixel/senpai.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/songs/roses/dialogue.xml b/assets/songs/roses/dialogue.xml new file mode 100644 index 00000000..904cf803 --- /dev/null +++ b/assets/songs/roses/dialogue.xml @@ -0,0 +1,17 @@ + + + + + + + + + Not bad for an ugly worm. + + + But this time I'll rip your nuts off right after your girlfriend finishes gargling mine. + + + Bop beep be be skdoo bep + + \ No newline at end of file diff --git a/assets/songs/roses/end-cutscene.hx b/assets/songs/roses/end-cutscene.hx index 885a2b55..e265ba2c 100644 --- a/assets/songs/roses/end-cutscene.hx +++ b/assets/songs/roses/end-cutscene.hx @@ -1,4 +1,3 @@ -static var roses_shouldPlayOnThorns = false; var self = this; __script__.setParent(PlayState.instance); @@ -36,10 +35,7 @@ function create() { FlxG.camera.followLerp = 0; FlxTween.tween(camGame.scroll, {x: -366, y: 192}, 3, { ease: FlxEase.cubeInOut, - onComplete: (_) -> { - roses_shouldPlayOnThorns = true; - self.close(); - } + onComplete: (_) -> {self.close();} }); } }); diff --git a/assets/songs/senpai/dialogue.xml b/assets/songs/senpai/dialogue.xml new file mode 100644 index 00000000..5a0115c4 --- /dev/null +++ b/assets/songs/senpai/dialogue.xml @@ -0,0 +1,17 @@ + + + + + + + + + Ah, a new fair maiden has come in search of true love! + + + A serenade between gentlemen shall decide where her beautiful heart shall reside. + + + Beep bo bop + + \ No newline at end of file diff --git a/assets/songs/thorns/creepyDialogue.xml b/assets/songs/thorns/creepyDialogue.xml new file mode 100644 index 00000000..75ee0d15 --- /dev/null +++ b/assets/songs/thorns/creepyDialogue.xml @@ -0,0 +1,22 @@ + + + + + + + + Direct contact with real humans, after being trapped in here for so long... + + + and HER of all people. + + + I'll make her father pay for what he's done to me and all the others,,,, + + + I'll beat you and make you take my place. + + + You don't mind your bodies being borrowed right? It's only fair... + + \ No newline at end of file diff --git a/assets/songs/thorns/cutscene.hx b/assets/songs/thorns/cutscene.hx index 88369443..9d0be5b8 100644 --- a/assets/songs/thorns/cutscene.hx +++ b/assets/songs/thorns/cutscene.hx @@ -1,6 +1,5 @@ import flixel.addons.util.FlxSimplex; -static var roses_shouldPlayOnThorns = false; var self = this; __script__.setParent(PlayState.instance); @@ -9,13 +8,6 @@ var senpaiEvil:FlxSprite; var dfx = 0; var dfy = 0; function create() { - // Cutscene stuff - if(!roses_shouldPlayOnThorns) { - disableScript(); - self.close(); - return; - } - roses_shouldPlayOnThorns = false; camHUD.visible = false; var red:FlxSprite = new FlxSprite().makeSolid(FlxG.width + 100, FlxG.height + 100, 0xFFff1b31); @@ -64,7 +56,7 @@ function create() { white.destroy(); camHUD.visible = true; - self.close(); + self.startDialogue("songs/" + PlayState.instance.SONG.meta.name.toLowerCase() + "/creepyDialogue.xml", self.close); } }); diff --git a/assets/sounds/Senpai_Dies.mp3 b/assets/sounds/Senpai_Dies.mp3 deleted file mode 100644 index e5749a14..00000000 Binary files a/assets/sounds/Senpai_Dies.mp3 and /dev/null differ diff --git a/assets/sounds/Senpai_Dies.ogg b/assets/sounds/Senpai_Dies.ogg deleted file mode 100644 index 68647de8..00000000 Binary files a/assets/sounds/Senpai_Dies.ogg and /dev/null differ diff --git a/assets/sounds/pixel/clickText.mp3 b/assets/sounds/pixel/clickText.mp3 new file mode 100644 index 00000000..b34a82c0 Binary files /dev/null and b/assets/sounds/pixel/clickText.mp3 differ diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx index b7120680..7058ae28 100644 --- a/source/funkin/backend/utils/XMLUtil.hx +++ b/source/funkin/backend/utils/XMLUtil.hx @@ -1,10 +1,9 @@ package funkin.backend.utils; -import flixel.animation.FlxAnimation; import funkin.backend.FunkinSprite; import funkin.backend.system.ErrorCode; import funkin.backend.FunkinSprite.XMLAnimType; -import funkin.backend.system.interfaces.IBeatReceiver; +import flixel.util.FlxColor; import haxe.xml.Access; import funkin.backend.system.interfaces.IOffsetCompatible; @@ -61,16 +60,14 @@ class XMLUtil { } /** - * Creates a new sprite based on a XML node. + * Overrides a sprite based on a XML node. */ - public static function createSpriteFromXML(node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, ?cl:Class):FunkinSprite { + public static function loadSpriteFromXML(spr:FunkinSprite, node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT):FunkinSprite { if (parentFolder == null) parentFolder = ""; - var spr:FunkinSprite = cl != null ? Type.createInstance(cl, []) : new FunkinSprite(); spr.name = node.getAtt("name"); spr.antialiasing = true; - - spr.loadSprite(Paths.image('$parentFolder${node.getAtt("sprite")}', null, true)); + spr.loadSprite(Paths.image('$parentFolder${node.getAtt("sprite").getDefault(spr.name)}', null, true)); spr.spriteAnimType = defaultAnimType; if (node.has.type) { @@ -88,15 +85,14 @@ class XMLUtil { if (node.has.scroll) { var scroll:Null = Std.parseFloat(node.att.scroll); if (scroll.isNotNull()) spr.scrollFactor.set(scroll, scroll); - } else { - if (node.has.scrollx) { - var scroll:Null = Std.parseFloat(node.att.scrollx); - if (scroll.isNotNull()) spr.scrollFactor.x = scroll; - } - if (node.has.scrolly) { - var scroll:Null = Std.parseFloat(node.att.scrolly); - if (scroll.isNotNull()) spr.scrollFactor.y = scroll; - } + } + if (node.has.scrollx) { + var scroll:Null = Std.parseFloat(node.att.scrollx); + if (scroll.isNotNull()) spr.scrollFactor.x = scroll; + } + if (node.has.scrolly) { + var scroll:Null = Std.parseFloat(node.att.scrolly); + if (scroll.isNotNull()) spr.scrollFactor.y = scroll; } if (node.has.skewx) { var skew:Null = Std.parseFloat(node.att.skewx); @@ -107,6 +103,14 @@ class XMLUtil { if (skew.isNotNull()) spr.skew.y = skew; } if (node.has.antialiasing) spr.antialiasing = node.att.antialiasing == "true"; + if (node.has.width) { + var width:Null = Std.parseFloat(node.att.width); + if (width.isNotNull()) spr.width = width; + } + if (node.has.height) { + var height:Null = Std.parseFloat(node.att.height); + if (height.isNotNull()) spr.height = height; + } if (node.has.scale) { var scale:Null = Std.parseFloat(node.att.scale); if (scale.isNotNull()) spr.scale.set(scale, scale); @@ -119,14 +123,29 @@ class XMLUtil { var scale:Null = Std.parseFloat(node.att.scaley); if (scale.isNotNull()) spr.scale.y = scale; } + if (node.has.graphicSize) { + var graphicSize:Null = Std.parseInt(node.att.graphicSize); + if (graphicSize.isNotNull()) spr.setGraphicSize(graphicSize, graphicSize); + } + if (node.has.graphicSizex) { + var graphicSizex:Null = Std.parseInt(node.att.graphicSizex); + if (graphicSizex.isNotNull()) spr.setGraphicSize(graphicSizex); + } + if (node.has.graphicSizey) { + var graphicSizey:Null = Std.parseInt(node.att.graphicSizey); + if (graphicSizey.isNotNull()) spr.setGraphicSize(0, graphicSizey); + } if (node.has.updateHitbox && node.att.updateHitbox == "true") spr.updateHitbox(); - if(node.has.zoomfactor) + if (node.has.zoomfactor) spr.zoomFactor = Std.parseFloat(node.getAtt("zoomfactor")).getDefault(spr.zoomFactor); if (node.has.alpha) spr.alpha = Std.parseFloat(node.getAtt("alpha")).getDefault(spr.alpha); + if(node.has.color) + spr.color = FlxColor.fromString(node.getAtt("color")).getDefault(0xFFFFFFFF); + if (node.has.playOnCountdown) spr.skipNegativeBeats = node.att.playOnCountdown == "true"; if (node.has.beatInterval) @@ -156,6 +175,15 @@ class XMLUtil { return spr; } + /** + * Creates a new sprite based on a XML node. + */ + public static inline function createSpriteFromXML(node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, ?cl:Class, ?args:Array):FunkinSprite { + if(cl == null) cl = FunkinSprite; + if(args == null) args = []; + return loadSpriteFromXML(Type.createInstance(cl, args), node, parentFolder, defaultAnimType); + } + public static function extractAnimFromXML(anim:Access, animType:XMLAnimType = NONE, loop:Bool = false):AnimData { var animData:AnimData = { name: null, diff --git a/source/funkin/game/NoteGroup.hx b/source/funkin/game/NoteGroup.hx index 546f2bbe..97b34da6 100644 --- a/source/funkin/game/NoteGroup.hx +++ b/source/funkin/game/NoteGroup.hx @@ -71,6 +71,13 @@ class NoteGroup extends FlxTypedGroup { @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; } + /** + * Gets the correct order of notes + **/ + public function get(id:Int) { + return members[length - 1 - id]; + } + public override function forEach(noteFunc:Note->Void, recursive:Bool = false) { i = length-1; __loopSprite = null; diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 99d4608c..74d9c15c 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -801,7 +801,7 @@ class PlayState extends MusicBeatState */ public function startCutscene(prefix:String = "", ?cutsceneScriptPath:String, ?callback:Void->Void, checkSeen:Bool = false) { if (callback == null) callback = startCountdown; - if (checkSeen && seenCutscene) { + if ((checkSeen && seenCutscene) || !playCutscenes) { callback(); return; } @@ -809,34 +809,31 @@ class PlayState extends MusicBeatState if (cutsceneScriptPath == null) cutsceneScriptPath = Paths.script('songs/${SONG.meta.name.toLowerCase()}/${prefix}cutscene'); - if (playCutscenes) { - inCutscene = true; - var videoCutscene = Paths.video('${PlayState.SONG.meta.name.toLowerCase()}-${prefix}cutscene'); - var videoCutsceneAlt = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}cutscene.mp4'); - var dialogue = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}dialogue.xml'); - persistentUpdate = true; - var toCall:Void->Void = function() { - if(checkSeen) seenCutscene = true; - callback(); - } + inCutscene = true; + var videoCutscene = Paths.video('${PlayState.SONG.meta.name.toLowerCase()}-${prefix}cutscene'); + var videoCutsceneAlt = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}cutscene.mp4'); + var dialogue = Paths.file('songs/${PlayState.SONG.meta.name.toLowerCase()}/${prefix}dialogue.xml'); + persistentUpdate = true; + var toCall:Void->Void = function() { + if(checkSeen) seenCutscene = true; + callback(); + } - if (cutsceneScriptPath != null && Assets.exists(cutsceneScriptPath)) { - openSubState(new ScriptedCutscene(cutsceneScriptPath, toCall)); - } else if (Assets.exists(dialogue)) { - MusicBeatState.skipTransIn = true; - openSubState(new DialogueCutscene(dialogue, toCall)); - } else if (Assets.exists(videoCutsceneAlt)) { - MusicBeatState.skipTransIn = true; - persistentUpdate = false; - openSubState(new VideoCutscene(videoCutsceneAlt, toCall)); - persistentDraw = false; - } else if (Assets.exists(videoCutscene)) { - MusicBeatState.skipTransIn = true; - persistentUpdate = false; - openSubState(new VideoCutscene(videoCutscene, toCall)); - persistentDraw = false; - } else - callback(); + if (cutsceneScriptPath != null && Assets.exists(cutsceneScriptPath)) { + openSubState(new ScriptedCutscene(cutsceneScriptPath, toCall)); + } else if (Assets.exists(dialogue)) { + MusicBeatState.skipTransIn = true; + openSubState(new DialogueCutscene(dialogue, toCall)); + } else if (Assets.exists(videoCutsceneAlt)) { + MusicBeatState.skipTransIn = true; + persistentUpdate = false; + openSubState(new VideoCutscene(videoCutsceneAlt, toCall)); + persistentDraw = false; + } else if (Assets.exists(videoCutscene)) { + MusicBeatState.skipTransIn = true; + persistentUpdate = false; + openSubState(new VideoCutscene(videoCutscene, toCall)); + persistentDraw = false; } else callback(); } @@ -1072,8 +1069,6 @@ class PlayState extends MusicBeatState public inline function getIconRPC():String return SONG.meta.icon; - var __songPlaying:Bool = false; - var __wasAutoPause:Bool = false; @:dox(hide) override public function onFocus():Void { @@ -1188,8 +1183,10 @@ class PlayState extends MusicBeatState function updateIconPositions() { var iconOffset:Int = 26; - iconP1.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0)) - iconOffset); - iconP2.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0))) - (iconP2.width - iconOffset); + var center:Float = healthBar.x + healthBar.width * FlxMath.remapToRange(healthBar.percent, 0, 100, 1, 0); + + iconP1.x = center - iconOffset; + iconP2.x = center - (iconP2.width - iconOffset); health = FlxMath.bound(health, 0, maxHealth); diff --git a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx index 20262a04..4604b353 100644 --- a/source/funkin/game/cutscenes/dialogue/DialogueBox.hx +++ b/source/funkin/game/cutscenes/dialogue/DialogueBox.hx @@ -8,6 +8,7 @@ import haxe.xml.Access; class DialogueBox extends FunkinSprite { public var dialogueBoxData:Access; public var positions:Map = []; + public var everPlayedAny:Bool = false; public var textTypeSFX:String = Paths.sound('dialogue/text'); public var nextSFX:String = Paths.sound('dialogue/next'); @@ -18,12 +19,22 @@ class DialogueBox extends FunkinSprite { super(); try { dialogueBoxData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/boxes/$name'))).firstElement()); + if(!dialogueBoxData.has.sprite) dialogueBoxData.x.set("sprite", name); + XMLUtil.loadSpriteFromXML(this, dialogueBoxData, "dialogue/boxes/", NONE); + visible = false; - loadSprite(Paths.image('dialogue/boxes/${dialogueBoxData.getAtt('sprite').getDefault(name)}')); + var preX:Float = x; + screenCenter(X); x += preX; + y += FlxG.height - height; - for(anim in dialogueBoxData.nodes.anim) { - if (!anim.has.name) continue; - XMLUtil.addXMLAnimation(this, anim); + if(dialogueBoxData.has.textSound) textTypeSFX = Paths.sound(dialogueBoxData.att.textSound); + if(dialogueBoxData.has.nextSound) nextSFX = Paths.sound(dialogueBoxData.att.nextSound); + + animation.finishCallback = (name:String) -> { + if(name.endsWith("-open") || name.endsWith("-firstOpen")) { + playAnim(name.substr(0, name.length - 5)); + setText(__nextText, __speed); + } } for(pos in dialogueBoxData.nodes.charpos) { @@ -35,16 +46,6 @@ class DialogueBox extends FunkinSprite { }; } - if (dialogueBoxData.has.textSound) textTypeSFX = Paths.sound(dialogueBoxData.att.textSound); - if (dialogueBoxData.has.nextSound) nextSFX = Paths.sound(dialogueBoxData.att.nextSound); - - antialiasing = dialogueBoxData.getAtt("antialiasing").getDefault("true") == "true"; - screenCenter(X); - y = FlxG.height - height; - if (dialogueBoxData.has.x) x += Std.parseFloat(dialogueBoxData.att.x).getDefault(0); - if (dialogueBoxData.has.y) y += Std.parseFloat(dialogueBoxData.att.y).getDefault(0); - visible = false; - var textNode = dialogueBoxData.node.text; if (textNode == null) throw "The dialog box XML requires one text element."; @@ -57,6 +58,16 @@ class DialogueBox extends FunkinSprite { text.font = Paths.font('${textNode.getAtt("font").getDefault("vcr.ttf")}'); text.antialiasing = textNode.getAtt("antialiasing").getDefault("false") == "true"; text.sounds = [FlxG.sound.load(textTypeSFX)]; + if(textNode.has.borderStyle) { + text.borderStyle = switch(textNode.att.borderStyle.trim().toLowerCase()) { + case "none": NONE; + case "shadow": SHADOW; + case "outline_fast": OUTLINE_FAST; + default: OUTLINE; + } + text.borderSize = Std.parseFloat(textNode.getAtt("borderSize")).getDefault(1); + text.borderColor = textNode.getAtt("borderColor").getColorFromDynamic().getDefault(0xFFFFFFFF); + } } catch(e) { active = false; Logs.trace('Couldn\'t load dialogue box "$name": ${e.toString()}', ERROR); @@ -80,13 +91,14 @@ class DialogueBox extends FunkinSprite { this.__speed = speed; this.text.resetText(text); FlxG.sound.play(nextSFX); - if (hasAnimation('$bubble-open')) - playAnim('$bubble-open', true); + if(hasAnimation('$bubble-open')) playAnim('$bubble-open', true); + else if(hasAnimation('$bubble-firstOpen') && !everPlayedAny) playAnim('$bubble-firstOpen', true); else { playAnim(bubble); setText(__nextText, __speed); } visible = true; + everPlayedAny = true; } public function setText(text:String, speed:Float = 0.02) { @@ -94,17 +106,6 @@ class DialogueBox extends FunkinSprite { this.text.start(speed, true); } - public override function update(elapsed:Float) { - super.update(elapsed); - if (isAnimFinished()) { - var animName = getAnimName(); - if (animName.endsWith("-open")) { - playAnim(animName.substr(0, animName.length - 5)); - setText(__nextText, __speed); - } - } - } - public override function destroy() { super.destroy(); positions = null; diff --git a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx index 32d241a8..f3097d66 100644 --- a/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx +++ b/source/funkin/game/cutscenes/dialogue/DialogueCharacter.hx @@ -6,23 +6,30 @@ import haxe.xml.Access; class DialogueCharacter extends FunkinSprite { public var charData:Access; public var curTween:FlxTween; - public var curTweenContext:DialogueCharTweenContext = NONE; + public var curAnimContext:DialogueCharAnimContext = NONE; public var positionName:String; + public var finishCallback:String->Void = null; public function new(name:String, position:String) { super(); this.positionName = position; try { charData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/characters/$name'))).firstElement()); - loadSprite(Paths.image('dialogue/characters/${charData.getAtt('sprite').getDefault(name)}')); - antialiasing = charData.getAtt('antialiasing').getDefault('true') == 'true'; - scale.scale(charData.has.scale ? Std.parseFloat(charData.att.scale).getDefault(1) : 1); - updateHitbox(); - offset.set( - charData.has.x ? Std.parseFloat(charData.att.x).getDefault(0) : 0, - (charData.has.y ? Std.parseFloat(charData.att.y).getDefault(0) : 0) + this.height); - for(anim in charData.nodes.anim) - XMLUtil.addXMLAnimation(this, anim, true); + if(!charData.has.sprite) charData.x.set("sprite", name); + if(!charData.has.updateHitbox) charData.x.set("updateHitbox", "true"); + XMLUtil.loadSpriteFromXML(this, charData, "dialogue/characters/", LOOP); + + animation.finishCallback = (name:String) -> { + switch(name) + { + case 'show': hasAnimation('normal') ? playAnim('normal', true) : animation.stop(); + case 'hide': alpha = 0; + } + if(finishCallback != null) finishCallback(name); + } + + offset.set(x, y + height); + x = 0; y = 0; } catch(e) { Logs.trace('Failed to load dialogue character $name: ${e.toString()}', ERROR); } @@ -30,29 +37,34 @@ class DialogueCharacter extends FunkinSprite { } public function show(x:Float, y:Float) { - if (curTweenContext != (curTweenContext = POPIN)) { - setPosition(x, y + 100); - if (curTween != null) - curTween.cancel(); + if (curAnimContext == (curAnimContext = POPIN)) return; + visible = true; + if (hasAnimation('show')) { + playAnim('show', true); + setPosition(x, y); + alpha = 1; + } else { + setPosition(x, y + 100); + if(curTween != null) curTween.cancel(); + playAnim('normal', true); alpha = 0; - visible = true; - curTween = FlxTween.tween(this, {alpha: 1, y: y}, 0.2, {ease: FlxEase.quintOut}); } } public function hide() { - if (curTweenContext != (curTweenContext = POPOUT)) { - if (curTween != null) - curTween.cancel(); - + if (curAnimContext == (curAnimContext = POPOUT)) return; + + if(hasAnimation('hide')) playAnim('hide', true); + else { + if(curTween != null) curTween.cancel(); curTween = FlxTween.tween(this, {alpha: 0, y: y + 100}, 0.2, {ease: FlxEase.quintIn}); } } } -enum abstract DialogueCharTweenContext(Int) { +enum abstract DialogueCharAnimContext(Int) { var NONE = -1; var POPIN = 0; var POPOUT = 1;