import asyncio import random import discord from .check import Check from redbot.core import commands, Config from .inventory import RPGInventory from typing import Literal class RPGActions: """ Implements the core RPG mechanics and actions. """ def __init__(self, rpg_cog): self.rpg_cog = rpg_cog self.inventory = RPGInventory(rpg_cog) async def create_character(self, interaction: discord.Interaction, user, character_name): """ Creates a new character for the user. """ # Character Name Validation check = Check(interaction, length=30) if not check.length_under(interaction.message) or not character_name.isalnum(): return await self.rpg_cog.send_message(interaction, "Invalid character name. Please choose a name between 2 and 30 characters long, containing only letters and numbers.") # Retrieve the 'characters' group characters_group = self.rpg_cog.config.member(user).characters # Then, get all characters within that group (await the .all() call) existing_characters = await characters_group.all() # Check for duplicate character names (case-insensitive) if any(existing_name.lower() == character_name.lower() for existing_name in existing_characters): return await self.rpg_cog.send_message(interaction, f"You already have a character named '{character_name}'. Choose another name.") # Retrieve available classes from config try: available_classes = await self.rpg_cog.config.guild(user.guild).get_raw("classes", default=[]) except KeyError: return await self.rpg_cog.send_message(interaction, "No classes have been configured yet. Please contact an admin.") if not available_classes: return await self.rpg_cog.send_message(interaction, "No classes are available yet. Please contact an admin.") # Prompt user to choose a class class_options = "\n".join([f"{i+1}. {class_name}" for i, class_name in enumerate(available_classes)]) await self.rpg_cog.send_message(interaction, f"Choose a class for your character:\n{class_options}") def check(m): return m.author == user and m.channel == interaction.channel and m.content.isdigit() and 1 <= int(m.content) <= len(available_classes) try: class_choice = await self.rpg_cog.bot.wait_for("message", check=check, timeout=30.0) except asyncio.TimeoutError: return await self.rpg_cog.send_message(interaction, "Class selection timed out. Character creation canceled.") selected_class = available_classes[int(class_choice.content) - 1] # Retrieve default stats for the selected class try: default_stats = await self.rpg_cog.config.guild(user.guild).get_raw("characters", "classes", selected_class, "stats") except KeyError: return await self.rpg_cog.send_message(interaction, f"Default stats for class '{selected_class}' haven't been configured yet. Please contact an admin.") # Create character data character_data = { "name": character_name, "class": [selected_class], # Store the selected class "level": 1, "experience": 0, "stats": default_stats.copy(), "inventory": [], "equipment": {}, "skills": [], "gold": 0, "max_health": 100, "health": 100, "mana": 50, "max_mana": 50, } # Store character data in config await characters_group.set_raw(character_name, value=character_data) await self.rpg_cog.config.member(user).active_character.set(character_name) await interaction.response.send_message(interaction, f"Character '{character_name}' (Class: {selected_class}) created for {user.mention}!") async def attack(self, ctx, attacker, target): """ Handles the attack action. """ # Check if attacker and target have active characters if not await self._has_active_character(ctx, attacker): return if not await self._has_active_character(ctx, target): return attacker_data = await self.rpg_cog.config.member(attacker).active_character target_data = await self.rpg_cog.config.member(target).active_character # ... (rest of the attack logic) async def heal(self, ctx, user): """ Handles the heal action. """ # ... (rest of the heal logic) # Helper function to check if a user has an active character async def _has_active_character(self, ctx, user): active_character = await self.rpg_cog.config.member(user).active_character if not active_character: await self.rpg_cog.send_message(ctx, f"{user.mention}, you don't have an active character. Create one using `[p]create_character `.") return False return True async def use_item(self, ctx, user, item_name): """ Handles the use of an item from the inventory. """ # ... (logic to check if the user has the item and handle its effects) # Remove the used item from the inventory await self.inventory.remove_item(ctx, user, item_name)