discord-plugins/Dice/dice.py
2025-09-13 15:41:49 +00:00

90 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""
Dice rolling plugin for UnturfDiscordBot (package entry point name: 'dice').
Provides a /roll command and an optional mention-based listener.
"""
import sys
import os
# Add parent directory to path to import bot module
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
from random import randint
from typing import Optional
from bot import DiscordPlugin
from discord.ext import commands
import discord
from discord import app_commands
def _roll(quant: int, dmax: int) -> str:
rolls = [randint(1, dmax) for _ in range(quant)]
return f"{', '.join(map(str, rolls))} for a total of {sum(rolls)}"
class DicePlugin(DiscordPlugin):
"""Roll dice."""
name = "Dice" # This will be the display name in /plugins
async def initialize(self, bot: commands.Bot, config: dict):
await super().initialize(bot, config)
settings = config.get("settings", {})
self.max_dice: int = int(settings.get("max_dice", 2))
self.max_sides: int = int(settings.get("max_sides", 6))
self.logger.info(
f"DicePlugin initialized (max_dice={self.max_dice}, max_sides={self.max_sides})"
)
async def setup(self):
@self.bot.tree.command(name="roll", description="Roll dice (e.g., 2d6)")
async def roll_cmd(interaction: discord.Interaction, quant: int = 2, sides: int = 6) -> None:
if quant < 2 or quant > self.max_dice:
await interaction.response.send_message(
f"You must roll between 2 and {self.max_dice} dice.",
ephemeral=True,
)
return
if sides < 2 or sides > self.max_sides:
await interaction.response.send_message(
f"Dice must have between 2 and {self.max_sides} sides.",
ephemeral=True,
)
return
result = _roll(quant, sides)
await interaction.response.send_message(
f"🎲 Rolled {quant}d{sides}: {result}"
)
async def _on_message(message: discord.Message):
if message.author.bot:
return
if not self.bot.user or not self.bot.user.mentioned_in(message):
return
content = message.content.lower().replace(" ", "")
if "roll" in content and "d" in content:
try:
seg = content.split("roll", 1)[1]
if seg.startswith("s"):
seg = seg[1:]
parts = seg.strip().split("d", 1)
quant = int(''.join(ch for ch in parts[0] if ch.isdigit()) or "0")
sides = int(''.join(ch for ch in parts[1] if ch.isdigit()) or "0")
if 2 <= quant <= self.max_dice and 6 <= sides <= self.max_sides:
result = _roll(quant, sides)
await message.reply(f"🎲 Rolled {quant}d{sides}: {result}")
except Exception:
pass
self._on_message = _on_message # type: ignore[attr-defined]
self.bot.add_listener(self._on_message, name="on_message")
async def teardown(self):
listener = getattr(self, "_on_message", None)
if listener is not None:
try:
self.bot.remove_listener(listener, name="on_message")
except Exception:
pass
self.logger.info("DicePlugin teardown complete")