Right-click or long-press the d20 button (per-combatant or Roll All) to open a context menu with Advantage and Disadvantage options. Normal left-click behavior is unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
38 lines
1.0 KiB
TypeScript
38 lines
1.0 KiB
TypeScript
import type { DomainError } from "./types.js";
|
|
|
|
export type RollMode = "normal" | "advantage" | "disadvantage";
|
|
|
|
/**
|
|
* Selects the effective roll from two dice values based on the roll mode.
|
|
* Advantage takes the higher, disadvantage takes the lower.
|
|
*/
|
|
export function selectRoll(
|
|
roll1: number,
|
|
roll2: number,
|
|
mode: RollMode,
|
|
): number {
|
|
if (mode === "advantage") return Math.max(roll1, roll2);
|
|
if (mode === "disadvantage") return Math.min(roll1, roll2);
|
|
return roll1;
|
|
}
|
|
|
|
/**
|
|
* Pure function that computes initiative from a resolved dice roll and modifier.
|
|
* The dice roll must be an integer in [1, 20].
|
|
* Returns the sum (diceRoll + modifier) or a DomainError for invalid inputs.
|
|
*/
|
|
export function rollInitiative(
|
|
diceRoll: number,
|
|
modifier: number,
|
|
): number | DomainError {
|
|
if (!Number.isInteger(diceRoll) || diceRoll < 1 || diceRoll > 20) {
|
|
return {
|
|
kind: "domain-error",
|
|
code: "invalid-dice-roll",
|
|
message: `Dice roll must be an integer between 1 and 20, got ${diceRoll}`,
|
|
};
|
|
}
|
|
|
|
return diceRoll + modifier;
|
|
}
|