1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00
royalnet/rpgpack/commands/dndspell.py

205 lines
8.6 KiB
Python
Raw Normal View History

2019-11-11 09:34:05 +00:00
import aiohttp
import sortedcontainers
2020-02-18 00:15:36 +00:00
import logging
2019-11-11 09:34:05 +00:00
from royalnet.commands import *
2020-02-18 00:15:36 +00:00
from royalnet.utils import ordinalformat, andformat, sentry_exc
2020-09-16 00:37:31 +00:00
import royalnet.serf as rs
2019-11-11 09:34:05 +00:00
from ..utils import parse_5etools_entry
2020-02-18 00:15:36 +00:00
log = logging.getLogger(__name__)
2019-11-11 09:34:05 +00:00
class DndspellCommand(Command):
name: str = "dndspell"
aliases = ["spell"]
description: str = "Ottieni informazioni su una magia di D&D5e."
syntax = "{nomemagia}"
_dnddata: sortedcontainers.SortedKeyList = None
2020-09-16 00:37:31 +00:00
def __init__(self, serf: rs.Serf, config: "ConfigDict"):
super().__init__(serf, config)
self.serf.tasks.add(self._fetch_dnddata())
2019-11-11 09:34:05 +00:00
async def _fetch_dnddata(self):
self._dnddata = self._dnddata = sortedcontainers.SortedKeyList([], key=lambda i: i["name"].lower())
async with aiohttp.ClientSession() as session:
for url in [
"https://5e.tools/data/spells/spells-ai.json",
"https://5e.tools/data/spells/spells-ggr.json",
"https://5e.tools/data/spells/spells-phb.json",
"https://5e.tools/data/spells/spells-scag.json",
2020-02-18 00:15:36 +00:00
"https://5e.tools/data/spells/spells-xge.json",
"https://5e.tools/data/spells/spells-ua-frw.json",
2019-11-11 09:34:05 +00:00
"https://5e.tools/data/spells/spells-stream.json",
2020-02-18 00:15:36 +00:00
"https://5e.tools/data/spells/spells-llk.json",
"https://5e.tools/data/spells/spells-ua-saw.json",
2019-11-11 09:34:05 +00:00
"https://5e.tools/data/spells/spells-ua-mm.json",
"https://5e.tools/data/spells/spells-ua-ss.json",
"https://5e.tools/data/spells/spells-ua-tobm.json",
2020-02-18 00:15:36 +00:00
"https://5e.tools/data/spells/spells-ua-ar.json",
2019-11-11 09:34:05 +00:00
]:
async with session.get(url) as response:
j = await response.json()
for spell in j["spell"]:
self._dnddata.add(spell)
2020-02-18 00:15:36 +00:00
self._test_all()
2019-11-11 09:34:05 +00:00
@staticmethod
def _parse_spell(spell: dict) -> str:
2020-02-18 13:48:21 +00:00
string = [f'✨ [b]{spell["name"]}[/b]\n']
2020-02-18 00:15:36 +00:00
# Source (manual, page)
2019-11-11 09:34:05 +00:00
if "source" in spell:
2020-02-18 00:15:36 +00:00
if "page" in spell:
string.append(f'[i]{spell["source"]}, page {spell["page"]}[/i]\n')
else:
string.append(f'[i]{spell["source"]}[/i]\n')
string.append("\n")
# Level
2020-02-18 13:48:21 +00:00
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"]])
2020-02-18 00:15:36 +00:00
# School
string.append({
"A": "Abjuration",
"C": "Conjuration",
"D": "Divination",
"E": "Enchantment",
"V": "Evocation",
"I": "Illusion",
"N": "Necromancy",
"P": "Psionic",
"T": "Transmutation",
}[spell["school"]])
2020-02-18 13:48:21 +00:00
string.append("\n\n")
2020-02-18 00:15:36 +00:00
# Cast time
for time in spell.get("time", []):
string.append(f'Cast time: ⌛️ [b]{time["number"]} {time["unit"]}[/b]\n')
# Cast range
range = spell.get("range")
if range:
if range["type"] == "point":
distance = range["distance"]
if distance["type"] == "touch":
string.append("Range: 👉 [b]Touch[/b]\n")
elif distance["type"] == "self":
string.append("Range: 👤 [b]Self[/b]\n")
elif distance["type"] == "sight":
string.append("Range: 👁 [b]Sight[/b]\n")
elif distance["type"] == "unlimited":
string.append("Range: ♾ [b]Unlimited[/b]\n")
2019-11-11 09:34:05 +00:00
else:
2020-02-18 00:15:36 +00:00
string.append(f'Range: 🏹 [b]{spell["range"]["distance"]["amount"]}'
2020-02-18 13:48:21 +00:00
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')
2020-02-18 00:15:36 +00:00
elif range["type"] == "special":
string.append("Range: ⭐️ Special")
2020-02-18 13:48:21 +00:00
else:
string.append('Range: ⚠️[b]UNKNOWN[/b]')
2020-02-18 00:15:36 +00:00
# Components
components = spell.get("components")
if components:
string.append(f'Components: ')
if components.get("v", False):
string.append("👄 [b]Verbal[/b] | ")
if components.get("s", False):
string.append("🤙 [b]Somatic[/b] | ")
if components.get("r", False):
string.append("©️ [b]Royalty[/b] | ")
if components.get("m", False):
if isinstance(components["m"], dict):
string.append(f'💎 [b]Material[/b] ([i]{spell["components"]["m"]["text"]}[/i]) | ')
elif isinstance(components["m"], str):
string.append(f'💎 [b]Material[/b] ([i]{spell["components"]["m"]}[/i]) | ')
string[-1] = string[-1].replace(" | ", "\n")
string.append("\n")
# Durations
for duration in spell.get("duration", []):
if duration["type"] == "timed":
string.append(f'Duration: 🕒 [b]{duration["duration"]["amount"]} {duration["duration"]["type"]}[/b]')
elif duration["type"] == "instant":
string.append('Duration: ☁️ [b]Instantaneous[/b]')
elif duration["type"] == "special":
string.append('Duration: ⭐️ [b]Special[/b]')
elif duration["type"] == "permanent":
string.append(f"Duration: ♾ [b]Permanent[/b] (ends on {andformat(duration['ends'], final=' or ')})")
else:
string.append(f'Duration: ⚠️[b]UNKNOWN[/b]')
if duration.get("concentration", False):
string.append(" (requires 🧠 Concentration)")
string.append("\n")
# Extra data
meta = spell.get("meta")
if meta:
if meta.get("ritual", False):
string.append("🔮 Can be casted as ritual\n")
string.append("\n")
# Text entries
2019-11-11 09:34:05 +00:00
for entry in spell.get("entries", []):
2020-02-18 00:15:36 +00:00
string.append(parse_5etools_entry(entry))
string.append("\n\n")
# At an higher level... text entries
2019-11-11 09:34:05 +00:00
for entry in spell.get("entriesHigherLevel", []):
2020-02-18 00:15:36 +00:00
string.append(parse_5etools_entry(entry))
string.append("\n\n")
return "".join(string)
2019-11-11 09:34:05 +00:00
async def run(self, args: CommandArgs, data: CommandData) -> None:
if self._dnddata is None:
await data.reply("⚠️ Il database degli oggetti di D&D non è ancora stato scaricato.")
return
search = args.joined().lower()
result = self._dnddata[self._dnddata.bisect_key_left(search)]
await data.reply(self._parse_spell(result))
2020-02-18 00:15:36 +00:00
def _test_all(self):
for spell in self._dnddata:
try:
log.debug(f"Testing: {spell['name']}")
2020-04-11 01:08:42 +00:00
result = self._parse_spell(spell)
2020-02-18 00:15:36 +00:00
except Exception as e:
log.error(f"Failed: {spell['name']}")
sentry_exc(e)
log.info(f"All spell tests complete!")