9ac01d217f
Бросок синхронизирован на пульте и презентации; d100 как десятки; оверлей скрывается только кнопкой «Убрать». Co-authored-by: Cursor <cursoragent@cursor.com>
65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import {
|
|
clampDiceCount,
|
|
createInitialDiceRollState,
|
|
formatDiceNotation,
|
|
isDiceSides,
|
|
rollDiceValues,
|
|
type DiceRollEvent,
|
|
type DiceRollState,
|
|
} from '../../shared/types/diceRoll';
|
|
|
|
export class DiceRollSessionStore {
|
|
private state: DiceRollState = createInitialDiceRollState();
|
|
|
|
getState(): DiceRollState {
|
|
return this.state;
|
|
}
|
|
|
|
clear(): DiceRollState {
|
|
this.state = createInitialDiceRollState();
|
|
return this.state;
|
|
}
|
|
|
|
dispatch(event: DiceRollEvent): DiceRollState {
|
|
switch (event.kind) {
|
|
case 'clear': {
|
|
if (!this.state.active && this.state.values.length === 0) return this.state;
|
|
this.state = {
|
|
...createInitialDiceRollState(),
|
|
revision: this.state.revision + 1,
|
|
};
|
|
return this.state;
|
|
}
|
|
case 'hideOverlay': {
|
|
if (!this.state.active) return this.state;
|
|
this.state = {
|
|
...this.state,
|
|
revision: this.state.revision + 1,
|
|
active: false,
|
|
startedAt: null,
|
|
};
|
|
return this.state;
|
|
}
|
|
case 'roll': {
|
|
if (!isDiceSides(event.sides)) return this.state;
|
|
const count = clampDiceCount(event.count);
|
|
const values = rollDiceValues(count, event.sides);
|
|
const total = values.reduce((a, b) => a + b, 0);
|
|
this.state = {
|
|
revision: this.state.revision + 1,
|
|
active: true,
|
|
notation: formatDiceNotation(count, event.sides),
|
|
values,
|
|
total,
|
|
startedAt: Date.now(),
|
|
};
|
|
return this.state;
|
|
}
|
|
default: {
|
|
const _exhaustive: never = event;
|
|
return _exhaustive;
|
|
}
|
|
}
|
|
}
|
|
}
|