diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..49f7b87b --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 00000000..e73e6e56 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,11 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://combo.steffo.eu:5432/royalnet + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 00000000..59b11d1d --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..105ce2da --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..82306935 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/rpgpack/commands/dndactive.py b/rpgpack/commands/dndactive.py index fa26727e..9feb4a57 100644 --- a/rpgpack/commands/dndactive.py +++ b/rpgpack/commands/dndactive.py @@ -1,6 +1,8 @@ from royalnet.commands import * from royalnet.utils import asyncify from ..tables import DndCharacter, DndActiveCharacter +from ..utils import get_active_character, get_interface_data +import pickle class DndactiveCommand(Command): @@ -15,17 +17,20 @@ class DndactiveCommand(Command): async def run(self, args: CommandArgs, data: CommandData) -> None: identifier = args.optional(0) author = await data.get_author(error_if_none=True) + active_character = await get_active_character(data) + + # Display the active character if identifier is None: - # Display the active character - if author.dnd_active_character is None: - await data.reply("ℹ️ You have no active characters.") + if active_character is None: + await data.reply("ℹ️ You haven't activated any character in this chat.") else: - await data.reply(f"ℹ️ You currently active character is [b]{author.dnd_active_character}[/b].") + await data.reply(f"ℹ️ Your active character for this chat is [b]{active_character.character}[/b].") return + + # Find the character by name try: identifier = int(identifier) except ValueError: - # Find the character by name chars = await asyncify(data.session.query(self.alchemy.get(DndCharacter)).filter_by(name=identifier).all) if len(chars) >= 2: char_string = "\n".join([f"[c]{char.character_id}[/c] (LV {char.level}) by {char.creator})" for char in chars]) @@ -43,12 +48,16 @@ class DndactiveCommand(Command): if char is None: raise CommandError("No character found.") # Check if the player already has an active character - if author.dnd_active_character is None: + if active_character is None: # Create a new active character - achar = self.alchemy.get(DndActiveCharacter)(character=char, user=author) + achar = self.alchemy.get(DndActiveCharacter)( + character=char, + user=author, + interface_name=self.interface.name, + interface_data=pickle.dumps(get_interface_data(data))) data.session.add(achar) else: # Change the active character - author.dnd_active_character.character = char + active_character.character = char await data.session_commit() await data.reply(f"✅ Active character set to [b]{char}[/b]!") diff --git a/rpgpack/commands/dndedit.py b/rpgpack/commands/dndedit.py index a603c4b6..4e9797fe 100644 --- a/rpgpack/commands/dndedit.py +++ b/rpgpack/commands/dndedit.py @@ -2,6 +2,7 @@ import re from royalnet.commands import * from .dndnew import DndnewCommand from ..tables import DndCharacter +from ..utils import get_active_character class DndeditCommand(DndnewCommand): @@ -18,11 +19,10 @@ class DndeditCommand(DndnewCommand): await data.reply(self._syntax()) return - author = await data.get_author(error_if_none=True) - if author.dnd_active_character is None: + active_character = await get_active_character(data) + if active_character is None: raise CommandError("You don't have an active character.") - - char: DndCharacter = author.dnd_active_character.character + char = active_character.character arguments = self._parse(character_sheet) for key in arguments: diff --git a/rpgpack/commands/dndinfo.py b/rpgpack/commands/dndinfo.py index 9ce41b94..f7176c2e 100644 --- a/rpgpack/commands/dndinfo.py +++ b/rpgpack/commands/dndinfo.py @@ -1,5 +1,6 @@ from royalnet.commands import * from ..tables import DndCharacter, DndActiveCharacter +from ..utils import get_active_character class DndinfoCommand(Command): @@ -13,6 +14,10 @@ class DndinfoCommand(Command): async def run(self, args: CommandArgs, data: CommandData) -> None: author = await data.get_author(error_if_none=True) - if author.dnd_active_character is None: + + active_character = await get_active_character(data) + char = active_character.character + + if char is None: raise CommandError("You don't have an active character.") - await data.reply(author.dnd_active_character.character.character_sheet()) + await data.reply(char.character_sheet()) diff --git a/rpgpack/commands/dndroll.py b/rpgpack/commands/dndroll.py index b306030f..bfb9e314 100644 --- a/rpgpack/commands/dndroll.py +++ b/rpgpack/commands/dndroll.py @@ -2,6 +2,7 @@ import random import math from royalnet.commands import * from ..tables import DndCharacter +from ..utils import get_active_character class DndrollCommand(Command): @@ -73,14 +74,14 @@ class DndrollCommand(Command): "ste": "stealth", "nas": "stealth", "sur": "survival", - "sop": "sopravvivenza", + "sop": "survival", } async def run(self, args: CommandArgs, data: CommandData) -> None: - author = await data.get_author(error_if_none=True) - if author.dnd_active_character is None: + active_character = await get_active_character(data) + if active_character is None: raise CommandError("You don't have an active character.") - char: DndCharacter = author.dnd_active_character.character + char = active_character.character first = args[0] second = args.optional(1) diff --git a/rpgpack/commands/dndspell.py b/rpgpack/commands/dndspell.py index 6a54ebd3..a2c905b3 100644 --- a/rpgpack/commands/dndspell.py +++ b/rpgpack/commands/dndspell.py @@ -50,7 +50,7 @@ class DndspellCommand(Command): @staticmethod def _parse_spell(spell: dict) -> str: - string = ['✨ [b]{spell["name"]}[/b]\n'] + string = [f'✨ [b]{spell["name"]}[/b]\n'] # Source (manual, page) if "source" in spell: @@ -61,10 +61,18 @@ class DndspellCommand(Command): string.append("\n") # Level - if spell["level"] == 0: - string.append(f'[b]Cantrip[/b]\n') - else: - string.append(f'[b]{ordinalformat(spell["level"])}[/b] level\n') + string.append({ + 0: "0️⃣ [b]Cantrip[/b]\n", + 1: "1️⃣ [b]1st[/b] level\n", + 2: "2️⃣ [b]2nd[/b] level\n", + 3: "3️⃣ [b]3rd[/b] level\n", + 4: "4️⃣ [b]4th[/b] level\n", + 5: "5️⃣ [b]5th[/b] level\n", + 6: "6️⃣ [b]6th[/b] level\n", + 7: "7️⃣ [b]7th[/b] level\n", + 8: "8️⃣ [b]8th[/b] level\n", + 9: "9️⃣ [b]9th[/b] level\n", + }[spell["level"]]) # School string.append({ @@ -78,6 +86,7 @@ class DndspellCommand(Command): "P": "Psionic", "T": "Transmutation", }[spell["school"]]) + string.append("\n\n") # Cast time for time in spell.get("time", []): @@ -98,9 +107,29 @@ class DndspellCommand(Command): string.append("Range: ♾ [b]Unlimited[/b]\n") else: string.append(f'Range: 🏹 [b]{spell["range"]["distance"]["amount"]}' - f' {spell["range"]["distance"]["type"]}[/b] ({spell["range"]["type"]})\n') + f' {spell["range"]["distance"]["type"]}[/b] (point)\n') + elif range["type"] == "radius": + string.append(f'Range: ⭕️ [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (radius)\n') + elif range["type"] == "sphere": + string.append(f'Range: 🌕 [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (sphere)\n') + elif range["type"] == "cone": + string.append(f'Range: 🍦 [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (cone)\n') + elif range["type"] == "line": + string.append(f'Range: ➖ [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (line)\n') + elif range["type"] == "hemisphere": + string.append(f'Range: 🌗 [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (hemisphere)\n') + elif range["type"] == "cube": + string.append(f'Range: ⬜️ [b]{spell["range"]["distance"]["amount"]}' + f' {spell["range"]["distance"]["type"]}[/b] (cube)\n') elif range["type"] == "special": string.append("Range: ⭐️ Special") + else: + string.append('Range: ⚠️[b]UNKNOWN[/b]') # Components components = spell.get("components") diff --git a/rpgpack/tables/dndactivecharacters.py b/rpgpack/tables/dndactivecharacters.py index 36693add..1b47ebd1 100644 --- a/rpgpack/tables/dndactivecharacters.py +++ b/rpgpack/tables/dndactivecharacters.py @@ -20,7 +20,15 @@ class DndActiveCharacter: @declared_attr def user(self): - return relationship("User", foreign_keys=self.user_id, backref=backref("dnd_active_character", uselist=False)) + return relationship("User", foreign_keys=self.user_id, backref=backref("dnd_active_characters")) + + @declared_attr + def interface_name(self): + return Column(String) + + @declared_attr + def interface_data(self): + return Column(LargeBinary) def __repr__(self): return f"<{self.__class__.__qualname__} for {self.user_id}: {self.character_id}>" diff --git a/rpgpack/utils/__init__.py b/rpgpack/utils/__init__.py index affccc25..6e271b11 100644 --- a/rpgpack/utils/__init__.py +++ b/rpgpack/utils/__init__.py @@ -1,4 +1,5 @@ from .dndproficiencytype import DndProficiencyType from .parse5etoolsentry import parse_5etools_entry +from .getactivechar import get_active_character, get_interface_data -__all__ = ["DndProficiencyType", "parse_5etools_entry"] +__all__ = ["DndProficiencyType", "parse_5etools_entry", "get_active_character", "get_interface_data"] diff --git a/rpgpack/utils/getactivechar.py b/rpgpack/utils/getactivechar.py new file mode 100644 index 00000000..eb358d5b --- /dev/null +++ b/rpgpack/utils/getactivechar.py @@ -0,0 +1,45 @@ +from typing import * +from ..tables import DndActiveCharacter +import royalnet.utils as ru +import royalnet.commands as rc +import pickle + + +def get_interface_data(data: rc.CommandData): + if data._interface.name == "telegram": + return data.message.chat.id + elif data._interface.name == "discord": + return data.message.channel.id + else: + raise rc.UnsupportedError("This interface isn't supported yet.") + + +async def get_active_character(data: rc.CommandData) -> Optional[DndActiveCharacter]: + interface = data._interface + alchemy = interface.alchemy + user = await data.get_author(error_if_none=True) + idata = get_interface_data(data) + + DndAcChT = alchemy.get(DndActiveCharacter) + active_characters: List[DndActiveCharacter] = await ru.asyncify( + data.session + .query(DndAcChT) + .filter_by(interface_name=interface.name, user=user) + .all + ) + + for active_character in active_characters: + if interface.name == "telegram": + # interface_data is chat id + chat_id = pickle.loads(active_character.interface_data) + if chat_id == idata: + return active_character + elif interface.name == "discord": + # interface_data is channel id + chat_id = pickle.loads(active_character.interface_data) + if chat_id == idata: + return active_character + else: + raise rc.UnsupportedError("This interface isn't supported yet.") + + return None