Files
chat_grid/server/app/items/dice.py

76 lines
2.6 KiB
Python
Raw Normal View History

"""Dice item schema metadata and behavior."""
from __future__ import annotations
import random
from typing import Callable
from ..item_types import ItemUseResult
from ..models import WorldItem
from .helpers import keep_only_known_params
LABEL = "dice"
TOOLTIP = "Great for drinking games or boredom."
EDITABLE_PROPERTIES: tuple[str, ...] = ("title", "sides", "number")
CAPABILITIES: tuple[str, ...] = ("editable", "carryable", "deletable", "usable")
USE_SOUND = "sounds/roll.ogg"
EMIT_SOUND: str | None = None
USE_COOLDOWN_MS = 1000
EMIT_RANGE = 15
DIRECTIONAL = False
DEFAULT_TITLE = "Dice"
DEFAULT_PARAMS: dict = {"sides": 6, "number": 2}
PARAM_KEYS: tuple[str, ...] = ("sides", "number")
PROPERTY_METADATA: dict[str, dict[str, object]] = {
2026-02-22 03:50:52 -05:00
"title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item.", "maxLength": 80},
"sides": {
"valueType": "number",
"tooltip": "Number of sides on each die.",
"range": {"min": 1, "max": 100, "step": 1},
},
"number": {
"valueType": "number",
"tooltip": "How many dice to roll per use.",
"range": {"min": 1, "max": 100, "step": 1},
},
}
def validate_update(_item: WorldItem, next_params: dict) -> dict:
"""Validate and normalize dice params."""
try:
sides = int(next_params.get("sides", 6))
number = int(next_params.get("number", 2))
except (TypeError, ValueError) as exc:
raise ValueError("Dice values must be numbers.") from exc
if not (1 <= sides <= 100 and 1 <= number <= 100):
raise ValueError("Dice sides and number must be between 1 and 100.")
next_params["sides"] = sides
next_params["number"] = number
return keep_only_known_params(next_params, PARAM_KEYS)
def use_item(item: WorldItem, nickname: str, _clock_formatter: Callable[[dict], str]) -> ItemUseResult:
"""Roll dice and report result."""
try:
sides = max(1, min(100, int(item.params.get("sides", 6))))
number = max(1, min(100, int(item.params.get("number", 2))))
except (TypeError, ValueError):
sides = 6
number = 2
rolls = [random.randint(1, sides) for _ in range(number)]
total = sum(rolls)
rolls_text = ", ".join(str(value) for value in rolls)
if number == 1:
return ItemUseResult(
self_message=f"You rolled {item.title}: {rolls_text}.",
others_message=f"{nickname} rolled {item.title}: {rolls_text}.",
)
return ItemUseResult(
self_message=f"You rolled {item.title}: {rolls_text} (total {total}).",
others_message=f"{nickname} rolled {item.title}: {rolls_text} (total {total}).",
)