async def character_edit(self, message: Message, attribute: str, value: str): character = await self._get_active_character(message.author) attr = attribute.lower() if attr == 'age': try: age = int(value.strip()) except ValueError: age = -1 if age < 0: raise CommandException( f'Invalid age "{value}", must be a positive integer.') character['age'] = age elif attr == 'status': val = value.strip() if len(val) > 140: raise CommandException( f'Status `{val}` is too long, 140 characters maximum.') character['status'] = val elif attr == 'appearance': character['appearance'] = value.strip() elif attr == 'avatar': # Check if the image exists response = requests.get(value) if response.status_code >= 400: raise CommandException( f'Failed to fetch image from URL `{value}`') character['avatar'] = value.strip() elif attr in ('force', 'presence', 'guts', 'wits', 'sensation', 'reflection'): try: val = int(value.strip()) except ValueError: val = -1 if val < 0: raise CommandException( f'Invalid ability "{value}", must be a positive integer.') character['abilities'][attr] = val else: raise CommandException(f'Invalid attribute name "{attribute}"') await self._save_config(message.guild) await message.channel.send(f'Character edited.')
async def character_create(self, message: Message, name: str) -> None: characters = await self._get_player_characters(message.author) name_id = self._get_character_id(name) if not NAMES_REGEX.match(name_id): raise CommandException( f'Invalid character name "{name}": only letters, numbers, ' f'spaces and periods are allowed.') if name_id in characters['characters']: raise CommandException(f'Character "{name}" already exists.') characters['characters'][name_id] = { 'name': name.strip(), 'age': None, 'appearance': None, 'avatar': None, 'actions': 0, 'status': None, 'abilities': { 'force': 0, 'presence': 0, 'guts': 0, 'wits': 0, 'sensation': 0, 'reflection': 0 }, 'inventory': [], 'prisms': [ 'Basic', 'Force', 'Presence', 'Guts', 'Wits', 'Sensation', 'Reflection' ] } characters['active'] = name_id await self._save_config(message.guild) await message.channel.send(f'Character "{name}" has been created.')
async def character_delete(self, message: Message, name: str) -> None: characters = await self._get_player_characters(message.author) name_id = self._get_character_id(name) if name_id not in characters['characters']: raise CommandException(f'Character "{name}" does not exist.') del characters['characters'][name_id] if characters['active'] == name_id: characters['active'] = None await self._save_config(message.guild) await message.channel.send(f'Character "{name}" has been deleted.')
async def drop(self, message: Message, item: str) -> None: character = await self._get_active_character(message.author) item_clean = item.strip() if item_clean not in character['inventory']: raise CommandException( f'{character["name"]} does not own "{item_clean}".') character['inventory'].remove(item_clean) await self._save_config(message.guild) await message.channel.send(f'Dropped "{item_clean}".') await self.bot.get_chronicle(message.guild).log_from_channel( message.channel, f'**{character["name"]}** dropped **{item_clean}**', )
async def prism_rm(self, message: Message, prism: str, character: str, user: str) -> None: character = await self._get_character_by_name_and_mention( message, character, message.mentions[0]) if not character: return prism_clean = prism.strip() if prism_clean not in character['prisms']: raise CommandException( f'{character["name"]} does not own "{prism_clean}".') character['prisms'].remove(prism_clean) await self._save_config(message.guild) await message.channel.send( f'Removed "{prism_clean}" from {character["name"]}.')
async def npc_move(self, message: Message, npc_name: str, new_room: str): new_channel = self.find_channel_by_name( message.guild, new_room, self.roleplay.rooms[new_room].section) if not new_channel: raise CommandException(f'Invalid room "{new_room}"') assert isinstance(new_channel, TextChannel) npc = await self._get_npc_by_name(npc_name) in_room = message.channel.name in self.roleplay.rooms await self._move_npc_to_room(message.guild, npc['name'], new_room) if in_room: await message.channel.send(f'**{npc["name"]}** moves to {new_room}' ) await new_channel.send( f'**{npc["name"]}** moves in from {message.channel.name}') else: await new_channel.send(f'**{npc["name"]}** appears') await self.bot.get_chronicle(message.guild).log_movement( npc['name'], new_room, message.channel if in_room else None)
def _get_config(guild: Guild) -> Dict[str, Any]: config = State.get_config(guild.id) if not config or not config.get('rp'): raise CommandException( 'No active roleplay, characters not available.') return config
async def _get_npc_by_name(self, npc_name: str) -> Dict[str, Any]: query = self._get_character_id(npc_name) npc_id = fuzzy_search(query, self.npcs.keys()) if npc_id is not None: return self.npcs[npc_id] raise CommandException(f'Failed to locate NPC.')
async def _get_characters_by_player( self, message: Message) -> Dict[str, Dict[str, Any]]: config = self._get_config(message.guild) if 'characters' not in config: raise CommandException('Characters are not set up.') return config['characters']