niko bellic
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE codename-engine-dialogue-box>
|
||||
<dialoguebox scale="0.9" y="100">
|
||||
<!-- All positions for the dialogue box -->
|
||||
<charpos name="left" x="-500" y="0" />
|
||||
<charpos name="middle" x="0" y="0" />
|
||||
<charpos name="right" x="500" y="0" flipBubble="true" />
|
||||
|
||||
<!--
|
||||
All animations for the dialogue box
|
||||
For example, if you wanna add an "angry" animation, add an animation named "angry" (box idle), and "angry-open" (not needed, for box apparition)
|
||||
-->
|
||||
<anim name="normal" anim="speech bubble normal" fps="24" loop="true"/>
|
||||
<anim name="normal-open" anim="Speech Bubble Normal Open" fps="24" />
|
||||
|
||||
<anim name="angry" anim="AHH speech bubble" fps="24" loop="true"/>
|
||||
<anim name="angry-open" anim="speech bubble loud open" fps="24" />
|
||||
</dialoguebox>
|
||||
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE codename-engine-dialogue-character>
|
||||
<character>
|
||||
<anim name="normal" anim="normal" fps="24" />
|
||||
</character>
|
||||
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE codename-engine-dialogue-character>
|
||||
<character>
|
||||
<anim name="normal" anim="normal" fps="24" />
|
||||
</character>
|
||||
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE codename-engine-dialogue-character>
|
||||
<character>
|
||||
<anim name="normal" anim="normal" fps="24" />
|
||||
</character>
|
||||
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextureAtlas imagePath="boyfriend.png">
|
||||
<!-- Created with Adobe Animate version 21.0.1.37179 -->
|
||||
<!-- http://www.adobe.com/products/animate.html -->
|
||||
<SubTexture name="normal0000" x="2" y="2" width="407" height="413"/>
|
||||
</TextureAtlas>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextureAtlas imagePath="dad.png">
|
||||
<!-- Created with Adobe Animate version 21.0.1.37179 -->
|
||||
<!-- http://www.adobe.com/products/animate.html -->
|
||||
<SubTexture name="normal0000" x="2" y="2" width="357" height="558"/>
|
||||
</TextureAtlas>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 300 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextureAtlas imagePath="niko.png">
|
||||
<!-- Created with Adobe Animate version 21.0.1.37179 -->
|
||||
<!-- http://www.adobe.com/products/animate.html -->
|
||||
<SubTexture name="normal0000" x="2" y="2" width="445" height="811"/>
|
||||
</TextureAtlas>
|
||||
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE codename-engine-dialogue>
|
||||
<dialogue box="default">
|
||||
<!-- All characters -->
|
||||
<char name="dad" char="dad" position="left" />
|
||||
<char name="girlfriend" char="girlfriend" position="middle" />
|
||||
<char name="boyfriend" char="boyfriend" position="right" />
|
||||
<char name="niko" char="niko" position="middle" />
|
||||
|
||||
<!-- Lines -->
|
||||
<line char="dad" stay="true">
|
||||
yo its me your enemy! how are you
|
||||
</line>
|
||||
<line char="boyfriend">
|
||||
shut up u stupid bitch
|
||||
ur useless af!!! loser!
|
||||
</line>
|
||||
<line char="girlfriend">
|
||||
agreed
|
||||
</line>
|
||||
<line char="dad" bubble="angry">
|
||||
shut up! u should respect me! im your dad!
|
||||
</line>
|
||||
<line char="boyfriend">
|
||||
haha no ur not my dad loser im a dream stan i dont have one
|
||||
</line>
|
||||
<line char="girlfriend" bubble="angry">
|
||||
HOW COULD YOU
|
||||
</line>
|
||||
<line char="dad">
|
||||
ok shut up and lets rap battle now u blue midget thing or whatever idot!
|
||||
</line>
|
||||
<line char="boyfriend" bubble="angry">
|
||||
TF U MEAN U 13' SKYSCRAPER MF BRO CANT EVEN FIT IN HIS CAR TF
|
||||
</line>
|
||||
<line char="girlfriend">
|
||||
loser!
|
||||
</line>
|
||||
<line char="dad">
|
||||
no u
|
||||
</line>
|
||||
<line char="boyfriend" bubble="angry" callback="emotionalDamage">
|
||||
HOW COULD YOU??? THIS IS WAR NOW!
|
||||
</line>
|
||||
<line char="niko">
|
||||
yo its me niko bellic from the video game "Grand Theft Auto IV"
|
||||
</line>
|
||||
<line char="boyfriend" bubble="angry">
|
||||
NO FUCKING WAY
|
||||
</line>
|
||||
<line char="dad">
|
||||
NIKO BELLIC? yo ur cousin fat
|
||||
</line>
|
||||
<line char="niko">
|
||||
fuck you dimitri rascalov
|
||||
</line>
|
||||
<line char="dad" bubble="angry">
|
||||
HOW DOES HE KNOW MY REAL IDENTITY
|
||||
</line>
|
||||
<line char="boyfriend">
|
||||
ok now stfu and lets rap its getting annoying
|
||||
</line>
|
||||
</dialogue>
|
||||
@@ -3,6 +3,7 @@ function create() {
|
||||
pixelNotesForBF = false;
|
||||
enablePixelUI = true;
|
||||
enableCameraHacks = false;
|
||||
playCutscenes = true;
|
||||
}
|
||||
|
||||
function postCreate() {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2101
|
||||
2112
|
||||
@@ -1,10 +1,101 @@
|
||||
package funkin.cutscenes;
|
||||
|
||||
import flixel.system.FlxSound;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxCamera;
|
||||
import openfl.utils.Assets;
|
||||
import funkin.cutscenes.dialogue.*;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class DialogueCutscene extends Cutscene {
|
||||
public var dialoguePath:String;
|
||||
public var dialogueData:Access;
|
||||
|
||||
public var charMap:Map<String, DialogueCharacter> = [];
|
||||
|
||||
public var dialogueLines:Array<DialogueLine> = [];
|
||||
public var curLine:DialogueLine = null;
|
||||
public var dialogueBox:DialogueBox;
|
||||
|
||||
public var nextSFX:FlxSound;
|
||||
|
||||
public function new(dialoguePath:String, callback:Void->Void) {
|
||||
super(callback);
|
||||
this.dialoguePath = dialoguePath;
|
||||
camera = new FlxCamera();
|
||||
camera.bgColor = 0;
|
||||
FlxG.cameras.add(camera, false);
|
||||
}
|
||||
|
||||
public override function create() {
|
||||
super.create();
|
||||
|
||||
try {
|
||||
dialogueData = new Access(Xml.parse(Assets.getText(dialoguePath)).firstElement());
|
||||
|
||||
// Add characters
|
||||
for(char in dialogueData.nodes.char) {
|
||||
if (!char.has.name) continue;
|
||||
if (charMap.exists(char.att.name))
|
||||
Logs.trace('2 dialogue characters share the same name (${char.att.name}, ${char.att.name}). The old character has been replaced.');
|
||||
add(charMap[char.att.name] = new DialogueCharacter(char.att.name, char.getAtt('position').getDefault('default')));
|
||||
}
|
||||
|
||||
// Add lines
|
||||
for(node in dialogueData.nodes.line) {
|
||||
dialogueLines.push({
|
||||
text: XMLUtil.fixXMLText(node.innerHTML),
|
||||
char: node.getAtt('char').getDefault('boyfriend'),
|
||||
bubble: node.getAtt('bubble').getDefault('normal'),
|
||||
callback: node.getAtt('callback'),
|
||||
speed: node.has.speed ? Std.parseFloat(node.att.speed).getDefault(0.02) : 0.02
|
||||
});
|
||||
}
|
||||
|
||||
// Add dialogue box
|
||||
dialogueBox = new DialogueBox(dialogueData.getAtt("box").getDefault("default"));
|
||||
add(dialogueBox);
|
||||
|
||||
next();
|
||||
} catch(e) {
|
||||
Logs.trace('Error while loading dialogue at ${dialoguePath}', ERROR);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
if (controls.ACCEPT)
|
||||
next();
|
||||
}
|
||||
|
||||
public function next() {
|
||||
if ((curLine = dialogueLines.shift()) == null) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
for(c in charMap) {
|
||||
if (c.visible) {
|
||||
// TODO: remove character smoothly
|
||||
}
|
||||
}
|
||||
|
||||
if (charMap[curLine.char] != null)
|
||||
dialogueBox.popupChar(charMap[curLine.char]);
|
||||
dialogueBox.playBubbleAnim(curLine.bubble);
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
FlxG.cameras.remove(camera);
|
||||
}
|
||||
}
|
||||
|
||||
typedef DialogueLine = {
|
||||
var text:String;
|
||||
var char:String;
|
||||
var bubble:String;
|
||||
var callback:String;
|
||||
var speed:Float;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package funkin.cutscenes.dialogue;
|
||||
|
||||
import openfl.utils.Assets;
|
||||
import flixel.FlxG;
|
||||
import flixel.math.FlxPoint;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class DialogueBox extends FunkinSprite {
|
||||
public var dialogueBoxData:Access;
|
||||
public var positions:Map<String, CharPosDef> = [];
|
||||
|
||||
public function new(name:String) {
|
||||
super();
|
||||
try {
|
||||
dialogueBoxData = new Access(Xml.parse(Assets.getText(Paths.xml('dialogue/boxes/$name'))).firstElement());
|
||||
|
||||
loadSprite(Paths.image('dialogue/boxes/${dialogueBoxData.getAtt('sprite').getDefault(name)}'));
|
||||
|
||||
for(anim in dialogueBoxData.nodes.anim) {
|
||||
if (!anim.has.name) continue;
|
||||
XMLUtil.addXMLAnimation(this, anim);
|
||||
}
|
||||
|
||||
for(pos in dialogueBoxData.nodes.charpos) {
|
||||
if (!pos.has.name) continue;
|
||||
positions[pos.att.name] = {
|
||||
x: pos.has.x ? Std.parseFloat(pos.att.x).getDefault(0) : 0,
|
||||
y: pos.has.y ? Std.parseFloat(pos.att.y).getDefault(0) : 0,
|
||||
flipBubble: pos.getAtt('flipBubble') == "true"
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
} catch(e) {
|
||||
active = false;
|
||||
Logs.trace('Couldn\'t load dialogue box "$name": ${e.toString()}', ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function popupChar(char:DialogueCharacter) {
|
||||
if (!active) return;
|
||||
var pos = positions[char.positionName];
|
||||
if (pos == null) return;
|
||||
|
||||
if (!char.visible) {
|
||||
char.alpha = 0;
|
||||
char.visible = true;
|
||||
char.setPosition(pos.x, pos.y + 100);
|
||||
char.show(pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
public function playBubbleAnim(bubble:String) {
|
||||
if (hasAnimation('$bubble-open'))
|
||||
playAnim('$bubble-open', true);
|
||||
else
|
||||
playAnim(bubble);
|
||||
visible = true;
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
positions = null;
|
||||
}
|
||||
}
|
||||
|
||||
typedef CharPosDef = {
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
var flipBubble:Bool;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package funkin.cutscenes.dialogue;
|
||||
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import openfl.utils.Assets;
|
||||
import haxe.xml.Access;
|
||||
|
||||
class DialogueCharacter extends FunkinSprite {
|
||||
public var charData:Access;
|
||||
public var curTween:FlxTween;
|
||||
public var positionName:String;
|
||||
|
||||
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';
|
||||
offset.set(
|
||||
charData.has.x ? Std.parseFloat(charData.att.x).getDefault(0) : 0,
|
||||
charData.has.y ? Std.parseFloat(charData.att.y).getDefault(0) : 0);
|
||||
scale.scale(charData.has.scale ? Std.parseFloat(charData.att.scale).getDefault(1) : 1);
|
||||
for(anim in charData.nodes.anim)
|
||||
XMLUtil.addXMLAnimation(this, anim, true);
|
||||
} catch(e) {
|
||||
Logs.trace('Failed to load dialogue character $name: ${e.toString()}', ERROR);
|
||||
}
|
||||
visible = false;
|
||||
}
|
||||
|
||||
public function show(y:Float) {
|
||||
if (curTween != null)
|
||||
curTween.cancel();
|
||||
|
||||
curTween = FlxTween.tween(this, {alpha: 1, y: y}, 0.5, {ease: FlxEase.cubeOut});
|
||||
}
|
||||
}
|
||||
@@ -696,18 +696,24 @@ class PlayState extends MusicBeatState
|
||||
if (playCutscenes) {
|
||||
var videoCutscene = Paths.video('${PlayState.SONG.song.toLowerCase()}-cutscene');
|
||||
var videoCutsceneAlt = Paths.file('songs/${PlayState.SONG.song.toLowerCase()}/cutscene.mp4');
|
||||
var dialogue = Paths.file('songs/${PlayState.SONG.song.toLowerCase()}/dialogue.xml');
|
||||
persistentUpdate = false;
|
||||
if (cutscene != null) {
|
||||
openSubState(new ScriptedCutscene(cutscene, function() {
|
||||
startCountdown();
|
||||
}));
|
||||
} else if (Assets.exists(dialogue)) {
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
openSubState(new DialogueCutscene(dialogue, function() {
|
||||
startCountdown();
|
||||
}));
|
||||
} else if (Assets.exists(videoCutsceneAlt)) {
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
openSubState(new VideoCutscene(videoCutsceneAlt, function() {
|
||||
startCountdown();
|
||||
}));
|
||||
persistentDraw = false;
|
||||
}else if (Assets.exists(videoCutscene)) {
|
||||
} else if (Assets.exists(videoCutscene)) {
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
openSubState(new VideoCutscene(videoCutscene, function() {
|
||||
startCountdown();
|
||||
|
||||
@@ -170,6 +170,11 @@ class XMLUtil {
|
||||
}
|
||||
return MISSING_PROPERTY;
|
||||
}
|
||||
|
||||
public static inline function fixXMLText(text:String) {
|
||||
var v:String;
|
||||
return [for(l in text.split("\n")) if ((v = l.trim()) != "") v].join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
typedef AnimData = {
|
||||
|
||||
Reference in New Issue
Block a user