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