sendMessage()
Write a message to the chat log, as the acting token.
Part of the Action API · Function reference
Signature
sendMessage(message: string): void
Synchronous, returns nothing.
Parameters
| Parameter | Type | Description |
|---|---|---|
message |
string |
The message. HTML is allowed. Dice expressions inside it are rolled — see below. |
Returns
Nothing.
What happens to your string
Three passes run over every message, in this order.
1. Dice expressions are rolled. Any NdS pattern — an explicit count, then
one of d4, d6, d8, d10, d12, d20, d100, with an optional +n or -n — is
rolled and replaced with a rich dice row.
sendMessage('The trap fires for 2d6 damage!'); // rolls 2d6 for real
Text inside double quotes is skipped, which is the escape hatch when you want the literal characters:
sendMessage('The spell deals "2d6" fire damage.'); // shows 2d6, rolls nothing
d6 without a count is not matched, and neither are non-standard die sizes
like 2d7.
2. Plain text is wrapped. If the string contains no <, it is wrapped in a
<div> so it lays out like every other chat line. A string that already
contains a tag is left alone.
3. The message is tagged. An invisible marker identifying this action run is prefixed to the message. The chat log groups every message from one run into a single bordered entry, so a chatty action stays one item in the log.
Examples
A line of narration
sendMessage(`${token.name} steps back into the shadows.`);
Formatted output
sendMessage(`
<b>${token.name}</b> casts <i>Bless</i>
<ul>
<li>${targets.map((t) => t.name).join('</li><li>')}</li>
</ul>
`);
A number you already rolled
const damage = roll('2d6', false);
sendMessage(`Searing pain: <b>${damage}</b>.`);
Conditional output
if (!target) {
sendMessage('<i>No target selected.</i>');
return;
}
Notes and gotchas
- Double-rolling is the classic mistake. Interpolating a rolled number
into the string is fine; leaving the expression in the string is not —
sendMessage('Damage: 2d6')rolls a second, unrelated 2d6 inside chat. If you want one roll with a sentence around it, useroll(expr, { text }). - Returning a string does the same thing. An action whose last statement is
return 'text'sends that string to chat with the same processing, so a one-line action needs nosendMessage()at all. Returning anything else that is notundefined/nullprints an orange warning instead. - HTML is rendered, not sanitized here. Keep interpolated values under your own control; a token name is fine, a pasted block of untrusted markup is not.
- In the Test panel nothing is sent. Messages are captured and listed in the panel instead, which is what makes it safe to iterate.
- Damage cards emitted by
applyDamage()travel through this same function and are passed through untouched.
See also
roll()— rolls that print themselvesapplyDamage()— the damage card, which is also a message- Chat and the combat log