# Roles

> Let the room decide who may start, pause or change your game, with defaults that work in any room.

Some things only certain players should do: start the match, pick teams,
change the settings. But who that is depends on the room: one room has
admins, another lets everyone do everything.

So the work is split. **Your game declares** its roles, with a sensible
default. **The room decides** who holds them, in code or by hand. Your game
never needs to know what an "admin" is.

## Declare

Declare roles in top-level code:

```ts title="src/roles.ts"
// The room owner is an admin, unless the room decides otherwise.
const admin = game.role("admin", {
  default: "owner",
  label: "Admin: runs the match",
});

// No one referees until someone is given the role.
const referee = game.role("referee", {
  default: "nobody",
  label: "Referee",
});
```

The default applies when nothing else decides:

- `"everyone"`: every player.
- `"nobody"`: no one, until the game, the room or a person gives it.
- `"owner"`: the room's owner, when they're playing.

## Gate the Menu

Give a control the role as its [audience](/games/audiences), and its
request `requires`. Players without the role don't see the control, or see
it disabled, and can't send the request:

```ts title="src/roles.ts"
ui.menu(
  ui.stack({
    children: [
      // Hidden from players who are not admins.
      ui.button({
        label: "Start",
        audience: { role: admin },
        on: { activate: ui.request({ event: "start", requires: admin }) },
      }),
      // Shown, but disabled, to players who are neither admin nor referee.
      ui.button({
        label: "Pause",
        audience: { role: referee },
        outside: Outside.Disabled,
        on: {
          activate: ui.request({ event: "pause", requires: [admin, referee] }),
        },
      }),
    ],
  }),
);
```

`requires` also takes several roles; holding any of them is enough.

## Check and hand out

`role.has(player)` and `role.holders()` answer right away. A game can give
and take its own roles, here to make the first player an admin:

```ts title="src/roles.ts"
// `requires` already gated these requests.
game.on("ui-request", (request) => {
  if (request.event === "start") {
    game.start();
  } else if (request.event === "pause") {
    game.pause();
  }
});

// With no admin in the room, the first player to join becomes one.
game.on("player-join", ({ player }) => {
  if (admin.holders().length === 0) {
    admin.give(player);
  }
});

// Every change, from the game, the room or a person, arrives here.
game.on("role-change", ({ player, role, held }) => {
  if (role === referee && held && !admin.has(player)) {
    game.send(`${player.name} is refereeing`);
  }
});
```

- A `give` or `take` takes effect from the next turn, with a `role-change`
  event.
- The room's decision, and a person's in the Room management modal, wins
  over the game's.
- Keep secret identities, such as who is "it", in game state with
  [audiences](/games/audiences), not in roles: rooms can see roles.

For the room's side, see [Roles & moderation](/rooms/roles-and-moderation).
