f37dc9fa76
FastAPI + Postgres backend with fastapi-users auth, games/characters CRUD, and a WebSocket chat endpoint where an x.ai Grok DM narrates play, rolls dice, and maintains character sheets via tool calls. React + Tailwind frontend covers registration/login, game list and creation, participation-code join flow, character viewer, and a real-time chat session view. Docker Compose skeleton (Postgres + backend) included; Caddy/frontend container wiring is deferred to the deploy milestone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
import re
|
|
from random import SystemRandom
|
|
|
|
_rng = SystemRandom()
|
|
|
|
_NOTATION_RE = re.compile(r"^\s*(\d*)d(\d+)\s*(?:([+-])\s*(\d+))?\s*$", re.IGNORECASE)
|
|
|
|
TOOL_SCHEMA = {
|
|
"name": "roll_dice",
|
|
"description": (
|
|
"Roll dice using standard D&D notation (e.g. '1d20+5', '2d6', 'd8-1'). "
|
|
"Always use this tool for any dice roll that affects the game — never invent or guess a result yourself."
|
|
),
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"notation": {
|
|
"type": "string",
|
|
"description": "Dice notation, e.g. '1d20+5'",
|
|
},
|
|
"reason": {
|
|
"type": "string",
|
|
"description": "Short reason for the roll, e.g. 'Geschicklichkeitsrettung, Schwierigkeit 13'",
|
|
},
|
|
},
|
|
"required": ["notation"],
|
|
},
|
|
}
|
|
|
|
|
|
def roll(notation: str) -> dict:
|
|
match = _NOTATION_RE.match(notation)
|
|
if not match:
|
|
raise ValueError(f"Invalid dice notation: {notation!r}")
|
|
|
|
count_str, sides_str, sign, modifier_str = match.groups()
|
|
count = int(count_str) if count_str else 1
|
|
sides = int(sides_str)
|
|
|
|
if not (1 <= count <= 100) or not (2 <= sides <= 1000):
|
|
raise ValueError(f"Dice notation out of allowed range: {notation!r}")
|
|
|
|
modifier = int(modifier_str) if modifier_str else 0
|
|
if sign == "-":
|
|
modifier = -modifier
|
|
|
|
rolls = [_rng.randint(1, sides) for _ in range(count)]
|
|
total = sum(rolls) + modifier
|
|
|
|
return {"notation": notation, "rolls": rolls, "modifier": modifier, "total": total}
|