# Rolls, chat and card

> Rolling dice and talking in the chat from the sheet, filling in the player's card bars, and the interface helpers: notices, questions, menus, images and preferences.

Page: https://docs.rpgdesk.com/en/fichas/rolagens-e-chat/

## Rolls

Without JavaScript, a button with `data-roll` rolls in the room:

```html
<button data-roll="1d20 + {str_mod}" data-label="{name}'s Strength">Strength</button>
```

- In `data-roll`, `{path}` becomes the field’s **number** (empty becomes 0). A negative number comes out right: `1d20 + {mod}` with `-2` rolls `1d20 - 2`.
- In `data-label`, `{path}` becomes the field’s **text**.
- Inside a list, paths belong to the item: `data-roll="1d20 + {bonus}"`.

From JavaScript, the roll returns the result:

```js
const r = await RPGDesk.dice.roll('2d6+3', { label: 'Axe damage' });
r.total;      // 11
r.items;      // [{ kind: 'dice', sign: 1, faces: 6, results: [5, 3] }, { kind: 'value', sign: 1, value: 3 }]
r.successes;  // only in success rolls ('5d10 > 7'): how many
```

The rolls are the same as the chat’s (see [Rolls](https://docs.rpgdesk.com/en/referencia/rolagens/)) and show up in the chat for everyone, with the 3D dice. The server rolls, not the page.

## Chat

```js
await RPGDesk.chat.send('attacks the orc with the axe', { kind: 'action' });
await RPGDesk.chat.send('None shall pass!', { kind: 'npc', name: 'Warden' });
await RPGDesk.chat.local('Only you see this line.');
```

`kind`: `'chat'` (the default), `'action'` (like `/me`), `'laugh'`, `'narrator'` or `'npc'` (with the NPC’s `name`). `local` writes a line in the chat of whoever is looking only.

> **Limits**
>
> Each open sheet rolls up to 10 times and sends up to 10 messages every 10 seconds. Beyond that, the request is refused (without locking up the sheet).

## The player’s card

The cards in **Participants** have bars (health, energy…) and text lines. The sheet fills in its **owner’s**:

```js
RPGDesk.card.setBar(0, 18, 22);      // bar 1: 18 of 22
RPGDesk.card.setBar(1, 9, 12);       // bar 2
RPGDesk.card.setLine(0, 'Poisoned'); // line 1
```

- The bar number starts at 0: `setBar(0, …)` is **Bar 1** of the room’s [game rules](https://docs.rpgdesk.com/en/mestres/regras-de-jogo/), and `setBar(3, …)`, the last one. Lines also go from 0 to 3. How many show up, their names and colors, the game master decides.
- Values are rounded. A maximum of 0 removes the bar.
- Everyone with the sheet open runs the same code; RPG Desk only accepts the request from whoever can change that card (the owner and the game masters). For the others, the call does nothing.

The usual way is to follow the health and send it to the bar:

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

On a [room table](https://docs.rpgdesk.com/en/fichas/tabelas/), which has no owner, say whose card it is: `RPGDesk.card.setBar(0, 7, 12, { userId })`.

## Notices, questions and menus

Inside RPG Desk, `alert`, `confirm` and `prompt` do not work. Use RPG Desk’s:

```js
RPGDesk.ui.toast('Sheet saved!');                           // 'info', 'success' or 'error'
const yes = await RPGDesk.ui.confirm('Delete the inventory?');      // true or false
const name = await RPGDesk.ui.prompt('Item name?', 'Rope');         // the text, or null
const choice = await RPGDesk.ui.menu(
  [{ id: 'attack', label: 'Attack' }, { separator: true }, { id: 'delete', label: 'Delete', danger: true }],
  event,                                                  // the click (MouseEvent) or { x, y }
);                                                        // the chosen id, or null
```

And more:

- `RPGDesk.ui.openLink(url)`: opens a site in another tab, after the person confirms;
- `RPGDesk.ui.copy(text)`: copies to the clipboard;
- `RPGDesk.ui.download('sheet.json', text)`: offers a file to download (up to 20 MB);
- `RPGDesk.ui.openItem(id)`: opens a sheet or scene from the library.

## Images

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

`pickImage` opens RPG Desk’s image picker (from the computer or the room’s images). Keep the `id` in the document; `files.url` gives an address for the `<img>`. With `data-image`, rpgdesk.js does this by itself (see [Images](https://docs.rpgdesk.com/en/fichas/campos/#images-data-image)).

## Preferences and screen state

- `RPGDesk.storage.get(key)` and `RPGDesk.storage.set(key, value)`: **the person’s** preferences, in this browser, for your plugin (up to 1 MB). `localStorage` does not work inside RPG Desk.
- `RPGDesk.view.get(key)` and `RPGDesk.view.set(key, value)`: this sheet’s screen state (the open tab, a filter), up to 100 KB. It survives when the sheet moves to another space or to a window of its own.

The character’s data goes in the document (`doc`), never in `storage`: `storage` does not reach the others.
