Codename Logo Codename Logo

Cutscenes/Dialogue Scripts

APIWiki

Cutscenes/Dialogue Scripts

Cutscenes/Dialogue Scripts make Scripted Cutscenes/Dialogues possible!
It is highly suggested to take a look at the Cutscenes and Dialogues page before starting here!

For the both of them: you can start them manually with also with custom prefix through other scripts using the startCutscene PlayState function or other ways that will be said down below.
For more advanced users: if you even want to avoid using the startCutscene function you can play with classes like VideoCutscene, ScriptedCutscene and etc; check the source code!

Cutscenes

You can automatically start a scripted cutscene by placing the script in ./song/YOUR SONG/cutscene.hx.

The cutscenes code is rather simple to recreate, you can find the most simple examples in Tankman's songs and a bit of advanced ones inside Roses and Thorns: if you checked Roses you can also understand that the game automatically detects for scripts that are named as end-cutscene.hx like with any other cutscenes as it was already said in Cutscenes and Dialogues.

The parent of the script is the Scripted Cutscene's instance itself (the class is named ScriptedCutscene) which is a substate.
The code has SOME functions that can be found in the substates behavior referenced in the All of the script calls page, such as create, destroy, stepHit and more.
(I'd recommend to actually mainly use destroy to for example destroy some eventual sprites, stop some eventual timers or such as the cutscene COULD get skipped and so end/finish prematurely)

Important functions to use when coding the scripted cutscene:

Dialogues

Before starting: you can check every calls (for characters and boxes as well) in the All of the script calls page!

Dialogue Scripts behave differently than Scripted Cutscenes: the main difference is that they get initialized when a dialogue cutscene also gets started.
To start one you must place a script with the same name of the dialogue's xml file (just with different extensions obliviously).

The parent of the script is the Dialogue Cutscene's instance itself (the class is named DialogueCutscene, you can also check every useable variable and function in there!) which is a substate.
By default once the Dialogue Cutscene substate opens, it temporarily pauses already existing timers, tweens and such; mess with the parentDisabler variable (uses the FunkinParentDisabler class) in the script if you want them to behave differently!

A kinda advanced example of scripted dialogue can be found in the Week 6 Roses song where the dialogue waits 1 second before appearing to show angry senpai and play the spooky sound:

function next(first:Bool) {
    if(first && canProceed) {
        canProceed = false;
        dialogueLines[0].playSound.play();
        new FlxTimer().start(1, (_) -> this.next(true));
    }
    else if(this.lastLine == null) canProceed = true;  // If its not null means the dialogue is not at the first one!  - Nex
}

Dialogue Character

These scripts use a DialogueCharacter class instance as parent (so you can also check the variables and such easily!).

There's not much to say besides that the parent, and so the actual character, obliviously behaves like a FunkinSprite.

An example of scripted dialogue character can be found in Senpai where every time it plays the angry-show animation, it's going to cancel the hide tween and in the case of another animation it immediately completes the tween, making Senpai looks like as if it disappears instantly:

function postHide() {
    if(curTween != null) {
        if(animation.curAnim?.name == 'angry-show') curTween.cancel();
        else curTween.percent = 1;
    }
}

Dialogue Box

These scripts use a DialogueBox class instance as parent (so you can also check the variables and such easily!).

There's not much to say here too and like the dialogue characters, the parent and so the actual box, obliviously behaves like a FunkinSprite.
But also it's important to remember that on every line, in the xml, it's possible to place a callback attribute on any line (like already said in the Cutscenes and Dialogues page) that allows to call any function inside of this dialogue box's script as soon as that specific line gets shown on screen.

A big example of scripted dialogue box can be found in Week 6 with the Hating Simulator's pixel dialogue box that makes a background fade with a pixel-ish tween and a moving pixel hand appear on the bottom right part of the box:

var loopedTimer:FlxTimer;
var bgFade:FlxSprite;
var hand:FlxSprite;

function postCreate() {
    bgFade = new FlxSprite().makeSolid(FlxG.width + 100, FlxG.height + 100, 0xFFB3DFd8);
    bgFade.screenCenter();
    bgFade.scrollFactor.set();
    bgFade.alpha = 0;
    cutscene.insert(0, bgFade);

    loopedTimer = new FlxTimer().start(0.83, function(tmr:FlxTimer)
    {
        bgFade.alpha += (1 / 5) * 0.7;
        if (bgFade.alpha > 0.7)
            bgFade.alpha = 0.7;
    }, 5);

    hand = new FlxSprite(0, 600).loadGraphic(Paths.image('stages/school/ui/hand_textbox'));
    hand.scale.set(4, 4);
    hand.updateHitbox();
}

var finished:Bool = false;
function close(event) {
    if(finished) return;
    else event.cancelled = true;
    cutscene.canProceed = false;

    cutscene.curMusic?.fadeOut(1, 0);
    for(c in cutscene.charMap) c.visible = false;

    loopedTimer.cancel();
    loopedTimer = new FlxTimer().start(0.2, function(tmr:FlxTimer)
    {
        if (tmr.elapsedLoops <= 5) {
            cutscene.dialogueBox.alpha -= 1 / 5;
            cutscene.dialogueBox.text.alpha -= 1 / 5;
            bgFade.alpha -= (1 / 5) * 0.7;
            hand.alpha -= 1 / 5;
        } else {
            finished = true;
            cutscene.close();
        }
    }, 6);
}

var time:Float = 0;
function update(elapsed:Float) {
    if(hand.visible = dialogueEnded) {
        hand.x = 1060 + Math.sin((time += elapsed) * Math.PI * 2) * 12;
        hand.x -= hand.x % hand.scale.x;
        hand.y -= hand.y % hand.scale.y;
    }
}

function postPlayBubbleAnim() {
    cutscene.remove(hand);
    if(active && visible)
        cutscene.add(hand);
}

Result of the two Dialogue example scripts:

Written by: Nex_isDumb
Last updated: 2024-10-14