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",
})
}
sayDialogue(playerId, text, opts)shows the line and hides it afteropts.durationMs, 6 seconds by default, counted from when the line starts to appear. A new line replaces the one already up, and saying the same line again replays it.clearDialogue(playerId)hides the line early.textis plain text or aTranslatedText.[[Item Name]]in it shows that item's icon inline, e.g."Bring me 3 [[Iron Bar]]".speakerNameis shown above the line, as plain text orCustomTextStyling, so it can carry a portrait icon.voiceis one of the presets"soft","regular","dark","high-pitched","gruff","lively","posh"and"mechanical", or aSpeechSynththat sets every parameter, such as its waveform, pitch and speaking rate. Leave it out for a silent line. Hear the presets and make a voice of your own in Dialogue Voices.
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.