# 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.

```js
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 after `opts.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.
* `text` is plain text or a `TranslatedText`. `[[Item Name]]` in it shows that item's icon inline, e.g. `"Bring me 3 [[Iron Bar]]"`.
* `speakerName` is shown above the line, as plain text or `CustomTextStyling`, so it can carry a portrait icon.
* `voice` is one of the presets `"soft"`, `"regular"`, `"dark"`, `"high-pitched"`, `"gruff"`, `"lively"`, `"posh"` and `"mechanical"`, or a `SpeechSynth` that 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](https://bloxd.io/docs/dialogue-voices.md).

The plugin is built on the [`dialogue`](https://bloxd.io/docs/client-options/1.md#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](https://bloxd.io/docs/how-to-interactable-npcs.md#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](https://bloxd.io/docs/how-to-interactable-npcs.md#Guarding-a-held-key):

```js
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.
