Documentation

Game logic

v2 · Stable

Apply actions

applyActions (required)

type ApplyActionsFn<MetaData = Record<string, unknown>> =
  (gameState: GameState<MetaData>, action: Action) => void;

Called once per legal action. Mutates gameState in place and returns nothing.

export const applyActions: ApplyActionsFn = (state, action) => {
  if (action.type === "SpaceClick") {
    action.space.addPiece(`p${Date.now()}`, new XToken({ order: 1 }));
  } else if (action.type === "PieceClick") {
    action.piece.isSelected = !action.piece.isSelected;
  } else if (action.type === "ButtonClick") {
    if (action.button.id === "end-turn") passTurn(state);
  }
};

The action union

type Action =
  | { type: "SpaceClick"; space: Space }
  | { type: "PieceClick"; piece: Piece }
  | { type: "ButtonClick"; button: Button };

space / piece are the live instances from gameState : see v2-game-state. button is the full Button you returned from getButtons.

An action only reaches you if it was legal: it must have appeared in getAvailableActions for that viewer. You do not need to re-check membership, but you should still validate anything the enumeration can't express.

Multi-step turns

Stash intermediate per-turn state in gameState.metaData. It persists between actions and is visible to everyone.

Need a hand with this?

Join our Discord