This page as Markdown: https://bloxd.io/docs/how-to-dialogue.md. Every page of these docs, for AI agents: https://bloxd.io/docs/llms.txt

Dialogue

@plugins/dialogue shows a player a line of dialogue in the panel below the crosshair. The line is revealed word by word, and each syllable blips in the speaker's voice as its word appears.

import { sayDialogue, clearDialogue } from "@plugins/dialogue"

onPlayerJoin = (playerId) => {
    sayDialogue(playerId, "Welcome to the forge. Mind the sparks!", {
        speakerName: "Blacksmith",
        voice: "gruff",
    })
}

The plugin is built on the dialogue client option, which you can also set yourself with api.setClientOption, e.g. from a code block. A line set that way stays up until you set the option to null, and setting the same line again does not replay it. Set animateIn: false on it to show the line whole, without its reveal or voice.

A quest giver

Create the quest giver as in A shopkeeper, keeping its ID in questGiverId, with interactionPrompt set to "Talk" and no shop. Each interaction says the next line, guarded as in Guarding a held key:

import { sayDialogue } from "@plugins/dialogue"

const QUEST_LINES = [
    "Ah, a new face! The mine has been quiet for days.",
    "Bring me 3 [[Iron Bar]] and I'll make it worth your while.",
    "Off you go, then!",
]
const INTERACT_COOLDOWN_MS = 800
const lastInteractAt = {}
const nextLineIndex = {}

function sayNextLine(playerId) {
    const index = nextLineIndex[playerId] ?? 0
    sayDialogue(playerId, QUEST_LINES[index], { speakerName: "Miner", voice: "lively" })
    nextLineIndex[playerId] = (index + 1) % QUEST_LINES.length
}

onPlayerAltAction = (playerId, x, y, z, block, targetEId) => {
    if (targetEId === questGiverId) {
        const now = api.now()
        if (now - (lastInteractAt[playerId] ?? 0) >= INTERACT_COOLDOWN_MS) {
            lastInteractAt[playerId] = now
            sayNextLine(playerId)
        }
    }
}

onPlayerLeave = (playerId) => {
    delete lastInteractAt[playerId]
    delete nextLineIndex[playerId]
}

The plugin has its own onPlayerLeave, which runs before yours, so both forget the player.

Logo