# Rolagens, chat e cartão

> Rolar dados e falar no chat pela ficha, preencher as barras do cartão do jogador, e as ajudas de interface: avisos, perguntas, menus, imagens e preferências.

Página: https://docs.rpgdesk.com/fichas/rolagens-e-chat/

## Rolagens

Sem JavaScript, um botão com `data-roll` rola na mesa:

```html
<button data-roll="1d20 + {mod_forca}" data-label="Força de {nome}">Força</button>
```

- No `data-roll`, `{caminho}` vira o **número** do campo (vazio vira 0). Um negativo fica certo: `1d20 + {mod}` com `-2` rola `1d20 - 2`.
- No `data-label`, `{caminho}` vira o **texto** do campo.
- Dentro de uma lista, os caminhos são do item: `data-roll="1d20 + {bonus}"`.

Pelo JavaScript, a rolagem devolve o resultado:

```js
const r = await RPGDesk.dice.roll('2d6+3', { label: 'Dano do machado' });
r.total;      // 11
r.items;      // [{ kind: 'dice', sign: 1, faces: 6, results: [5, 3] }, { kind: 'value', sign: 1, value: 3 }]
r.successes;  // só nas rolagens de sucessos ('5d10 > 7'): quantos
```

As rolagens são as mesmas do chat (veja [Rolagens](https://docs.rpgdesk.com/referencia/rolagens/)) e aparecem no chat para todos, com os dados 3D. Quem rola é o servidor, não a página.

## Chat

```js
await RPGDesk.chat.send('ataca o orc com o machado', { kind: 'action' });
await RPGDesk.chat.send('Ninguém passa!', { kind: 'npc', name: 'Guardião' });
await RPGDesk.chat.local('Só você vê esta linha.');
```

`kind`: `'chat'` (o padrão), `'action'` (como o `/me`), `'laugh'`, `'narrator'` ou `'npc'` (com o `name` do NPC). `local` escreve uma linha no chat só de quem está vendo.

> **Limites**
>
> Cada ficha aberta rola até 10 vezes e manda até 10 mensagens a cada 10 segundos. Passou disso, o pedido é recusado (sem travar a ficha).

## O cartão do jogador

Os cartões em **Participantes** têm barras (vida, energia…) e linhas de texto. A ficha preenche as do **dono** dela:

```js
RPGDesk.card.setBar(0, 18, 22);        // a barra 1: 18 de 22
RPGDesk.card.setBar(1, 9, 12);         // a barra 2
RPGDesk.card.setLine(0, 'Envenenado'); // a linha 1
```

- O número da barra começa em 0: `setBar(0, …)` é a **Barra 1** das [regras de jogo](https://docs.rpgdesk.com/mestres/regras-de-jogo/) da mesa, e `setBar(3, …)`, a última. As linhas também vão de 0 a 3. Quantas aparecem, os nomes e as cores, quem decide é o mestre.
- Os valores são arredondados. Máximo 0 tira a barra.
- Todos com a ficha aberta rodam o mesmo código; o RPG Desk só aceita o pedido de quem pode mudar aquele cartão (o dono e os mestres). Para os outros, a chamada não faz nada.

O jeito comum é acompanhar a vida e mandar para a barra:

```js
doc.watch('pv', (pv) => {
  if (pv && typeof pv === 'object') RPGDesk.card.setBar(0, Number(pv.atual) || 0, Number(pv.max) || 0);
}, { now: true });
```

Numa [tabela da sala](https://docs.rpgdesk.com/fichas/tabelas/), que não tem dono, diga de quem é o cartão: `RPGDesk.card.setBar(0, 7, 12, { userId })`.

## Avisos, perguntas e menus

Dentro do RPG Desk, `alert`, `confirm` e `prompt` não funcionam. Use os do RPG Desk:

```js
RPGDesk.ui.toast('Ficha salva!');                         // 'info', 'success' ou 'error'
const sim = await RPGDesk.ui.confirm('Apagar o inventário?');      // true ou false
const nome = await RPGDesk.ui.prompt('Nome do item?', 'Corda');    // o texto, ou null
const escolha = await RPGDesk.ui.menu(
  [{ id: 'atacar', label: 'Atacar' }, { separator: true }, { id: 'apagar', label: 'Apagar', danger: true }],
  evento,                                                // o clique (MouseEvent) ou { x, y }
);                                                       // o id escolhido, ou null
```

E mais:

- `RPGDesk.ui.openLink(url)`: abre um site noutra aba, depois de a pessoa confirmar;
- `RPGDesk.ui.copy(texto)`: copia para a área de transferência;
- `RPGDesk.ui.download('ficha.json', texto)`: oferece um arquivo para baixar (até 20 MB);
- `RPGDesk.ui.openItem(id)`: abre uma ficha ou cena da biblioteca.

## Imagens

```js
const escolhida = await RPGDesk.files.pickImage();   // { id } ou null
if (escolhida) await doc.set('retrato', escolhida.id);
img.src = await RPGDesk.files.url(doc.get('retrato'));
```

`pickImage` abre a escolha de imagem do RPG Desk (do computador ou das imagens da mesa). Guarde o `id` no documento; `files.url` dá um endereço para o `<img>`. Com `data-image`, o rpgdesk.js faz isso sozinho (veja [Imagens](https://docs.rpgdesk.com/fichas/campos/#imagens-data-image)).

## Preferências e estado da tela

- `RPGDesk.storage.get(chave)` e `RPGDesk.storage.set(chave, valor)`: preferências **da pessoa**, neste navegador, para o seu plugin (até 1 MB). O `localStorage` não funciona dentro do RPG Desk.
- `RPGDesk.view.get(chave)` e `RPGDesk.view.set(chave, valor)`: o estado da tela desta ficha (a aba aberta, um filtro), até 100 KB. Sobrevive quando a ficha muda de espaço ou vai para uma janela própria.

Os dados do personagem vão no documento (`doc`), nunca no `storage`: o `storage` não chega aos outros.
