From fb8d5fddb5d87176dd7153af39ba892d4ec5df26 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 22 Feb 2020 02:16:54 +0100 Subject: [PATCH] Add Active Battles --- rpgpack/commands/__init__.py | 3 + rpgpack/commands/dndactivebattle.py | 65 +++++++++++++++++++ rpgpack/commands/dnditem.py | 12 ++-- rpgpack/commands/dndnew.py | 4 +- rpgpack/commands/dndnewbattle.py | 2 +- rpgpack/commands/testfaction.py | 2 +- rpgpack/commands/testhealth.py | 2 +- rpgpack/tables/__init__.py | 2 + rpgpack/tables/dndactivebattle.py | 2 +- rpgpack/tables/dndbattle.py | 12 ++++ rpgpack/tables/dndbattleunit.py | 4 +- rpgpack/tables/dndcharacters.py | 2 +- rpgpack/types/__init__.py | 8 +++ .../{utils => types}/dndproficiencytype.py | 3 +- rpgpack/{utils => types}/faction.py | 0 rpgpack/{utils => types}/health.py | 0 rpgpack/utils/__init__.py | 13 ++-- rpgpack/utils/getactivebattle.py | 36 ++++++++++ rpgpack/utils/getactivechar.py | 10 +-- rpgpack/utils/getinterfacedata.py | 10 +++ 20 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 rpgpack/commands/dndactivebattle.py create mode 100644 rpgpack/types/__init__.py rename rpgpack/{utils => types}/dndproficiencytype.py (64%) rename rpgpack/{utils => types}/faction.py (100%) rename rpgpack/{utils => types}/health.py (100%) create mode 100644 rpgpack/utils/getactivebattle.py create mode 100644 rpgpack/utils/getinterfacedata.py diff --git a/rpgpack/commands/__init__.py b/rpgpack/commands/__init__.py index fde32940..29b717e3 100644 --- a/rpgpack/commands/__init__.py +++ b/rpgpack/commands/__init__.py @@ -11,6 +11,7 @@ from .dndspell import DndspellCommand from .testhealth import TesthealthCommand from .testfaction import TestfactionCommand from .dndnewbattle import DndnewbattleCommand +from .dndactivebattle import DndactivebattleCommand # Enter the commands of your Pack here! available_commands = [ @@ -25,6 +26,8 @@ available_commands = [ DndspellCommand, TesthealthCommand, TestfactionCommand, + DndnewbattleCommand, + DndactivebattleCommand, ] # Don't change this, it should automatically generate __all__ diff --git a/rpgpack/commands/dndactivebattle.py b/rpgpack/commands/dndactivebattle.py new file mode 100644 index 00000000..9506510d --- /dev/null +++ b/rpgpack/commands/dndactivebattle.py @@ -0,0 +1,65 @@ +from royalnet.commands import * +from royalnet.utils import asyncify +from ..tables import DndCharacter, DndActiveBattle, DndBattle +from ..utils import get_active_battle, get_interface_data +import pickle + + +class DndactivebattleCommand(Command): + name: str = "dndactivebattle" + + description: str = "Set a D&D battle as active." + + aliases = ["dab", "dndab", "activebattle", "dactivebattle"] + + syntax = "{name|id}" + + async def run(self, args: CommandArgs, data: CommandData) -> None: + BattleT = self.alchemy.get(DndBattle) + ABattleT = self.alchemy.get(DndActiveBattle) + + identifier = args.joined() + active_battle = await get_active_battle(data) + + # Display the active character + if identifier == "": + if active_battle is None: + await data.reply("ℹ️ No battles have ever been activated in this chat.") + else: + await data.reply(active_battle.battle.create_message()) + return + + # Find the battle + try: + identifier = int(identifier) + except ValueError: + # Find the battle by name + battles = await asyncify(data.session.query(BattleT).filter_by(name=identifier).all) + if len(battles) >= 2: + char_string = "\n".join([f"[c]{battle.id}[/c]" for battle in battles]) + raise CommandError(f"Multiple battles share the name [b]{identifier}[/b], " + f"please activate one of them by using their id:\n{char_string}") + elif len(battles) == 1: + battle = battles[0] + else: + battle = None + else: + # Find the battle by id + battle = await asyncify(data.session.query(BattleT) + .filter_by(id=identifier) + .one_or_none) + if battle is None: + raise CommandError("No such battle found.") + # Check if the player already has an active character + if active_battle is None: + # Create a new active battle + active_battle = ABattleT( + battle=battle, + interface_name=self.interface.name, + interface_data=pickle.dumps(get_interface_data(data))) + data.session.add(active_battle) + else: + # Change the active character + active_battle.battle = battle + await data.session_commit() + await data.reply(f"⚔️ [b]{battle}[/b]! Roll initiative!") diff --git a/rpgpack/commands/dnditem.py b/rpgpack/commands/dnditem.py index 1948e7ed..2d1f8218 100644 --- a/rpgpack/commands/dnditem.py +++ b/rpgpack/commands/dnditem.py @@ -56,24 +56,26 @@ class DnditemCommand(Command): # Type item_type = item.get("type") if item_type: - string.append(f"Type: [b]{item_type}[/b]") + string.append(f"Type: [b]{item_type}[/b]\n") # Value item_value = item.get("value") if item_value: - string.append(f"Value: [b]{item_value}[/b]") + string.append(f"Value: [b]{item_value}[/b]\n") # Weight item_weight = item.get("weight") if item_weight: - string.append(f"Value: [b]{item_weight}[/b]") + string.append(f"Value: [b]{item_weight}[/b]\n") # Rarity item_rarity = item.get("rarity") if item_rarity: - string.append(f"Rarity: [b]{item_rarity}[/b]") + string.append(f"Rarity: [b]{item_rarity}[/b]\n") else: - string.append(f"Rarity: [b]Mundane[/b]") + string.append(f"Rarity: [b]Mundane[/b]\n") + + string.append("\n") # Text entries for entry in item.get("entries", []): diff --git a/rpgpack/commands/dndnew.py b/rpgpack/commands/dndnew.py index 9d241da8..b76d50dc 100644 --- a/rpgpack/commands/dndnew.py +++ b/rpgpack/commands/dndnew.py @@ -2,7 +2,7 @@ import re # noinspection PyUnresolvedReferences from royalnet.commands import * from ..tables import DndCharacter -from ..utils import DndProficiencyType +from ..types import DndProficiencyType class DndnewCommand(Command): @@ -66,4 +66,4 @@ class DndnewCommand(Command): raise CommandError(f"Mandatory parameter '{param_name}' is missing.") raise - await data.reply(f"✅ Character [b]{character.name}[/b] created!") + await data.reply(f"✅ Character [b]{character.name}[/b] (ID: {character.character_id}) created!") diff --git a/rpgpack/commands/dndnewbattle.py b/rpgpack/commands/dndnewbattle.py index e978ccad..77819f19 100644 --- a/rpgpack/commands/dndnewbattle.py +++ b/rpgpack/commands/dndnewbattle.py @@ -26,4 +26,4 @@ class DndnewbattleCommand(rc.Command): data.session.add(battle) await data.session_commit() - await data.reply(f"✅ Battaglia [b]{battle.name}[/b] creata!") + await data.reply(f"✅ Battle [b]{battle.name}[/b] (ID: {battle.id}) created!") diff --git a/rpgpack/commands/testfaction.py b/rpgpack/commands/testfaction.py index 30bfa5b8..d29b1882 100644 --- a/rpgpack/commands/testfaction.py +++ b/rpgpack/commands/testfaction.py @@ -1,7 +1,7 @@ from typing import * import royalnet import royalnet.commands as rc -from ..utils import Faction +from ..types import Faction class TestfactionCommand(rc.Command): diff --git a/rpgpack/commands/testhealth.py b/rpgpack/commands/testhealth.py index 3acf0518..e1c68cf4 100644 --- a/rpgpack/commands/testhealth.py +++ b/rpgpack/commands/testhealth.py @@ -1,7 +1,7 @@ from typing import * import royalnet import royalnet.commands as rc -from ..utils import Health +from ..types import Health class TesthealthCommand(rc.Command): diff --git a/rpgpack/tables/__init__.py b/rpgpack/tables/__init__.py index dd1cd652..b73dad5c 100644 --- a/rpgpack/tables/__init__.py +++ b/rpgpack/tables/__init__.py @@ -3,6 +3,7 @@ from .dndactivecharacters import DndActiveCharacter from .dndcharacters import DndCharacter from .dndbattle import DndBattle from .dndbattleunit import DndBattleUnit +from .dndactivebattle import DndActiveBattle # Enter the tables of your Pack here! available_tables = [ @@ -10,6 +11,7 @@ available_tables = [ DndCharacter, DndBattle, DndBattleUnit, + DndActiveBattle, ] # Don't change this, it should automatically generate __all__ diff --git a/rpgpack/tables/dndactivebattle.py b/rpgpack/tables/dndactivebattle.py index 9ebfb10c..620fe9a1 100644 --- a/rpgpack/tables/dndactivebattle.py +++ b/rpgpack/tables/dndactivebattle.py @@ -12,7 +12,7 @@ class DndActiveBattle: @declared_attr def battle(self): - return relationship("DndCharacter", foreign_keys=self.battle_id, backref="active_in") + return relationship("DndBattle", foreign_keys=self.battle_id, backref=backref("activated_in")) @declared_attr def interface_name(self): diff --git a/rpgpack/tables/dndbattle.py b/rpgpack/tables/dndbattle.py index 12b5ae63..62666ccb 100644 --- a/rpgpack/tables/dndbattle.py +++ b/rpgpack/tables/dndbattle.py @@ -17,3 +17,15 @@ class DndBattle: @declared_attr def description(self): return Column(String, nullable=False) + + def __repr__(self): + return f"<{self.__class__.__qualname__} {self.name}>" + + def __str__(self): + return f"{self.name}" + + def create_message(self): + string = [] + string.append(f"⚔️ [b]{self.name}[/b]\n") + string.append(f"{self.description}\n") + return "".join(string) diff --git a/rpgpack/tables/dndbattleunit.py b/rpgpack/tables/dndbattleunit.py index 5f16079b..64b98720 100644 --- a/rpgpack/tables/dndbattleunit.py +++ b/rpgpack/tables/dndbattleunit.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declared_attr -from ..utils import Health, Faction +from ..types import Health, Faction class DndBattleUnit: @@ -17,7 +17,7 @@ class DndBattleUnit: @declared_attr def battle(self): - return relationship("DndBattle", backref="units") + return relationship("DndBattle", foreign_keys=self.battle_id, backref="units") @declared_attr def initiative(self): diff --git a/rpgpack/tables/dndcharacters.py b/rpgpack/tables/dndcharacters.py index 3a34c8b3..6ce52dec 100644 --- a/rpgpack/tables/dndcharacters.py +++ b/rpgpack/tables/dndcharacters.py @@ -2,7 +2,7 @@ import math from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import * -from ..utils import DndProficiencyType +from ..types import DndProficiencyType class DndCharacter: diff --git a/rpgpack/types/__init__.py b/rpgpack/types/__init__.py new file mode 100644 index 00000000..a768f883 --- /dev/null +++ b/rpgpack/types/__init__.py @@ -0,0 +1,8 @@ +from .dndproficiencytype import DndProficiencyType +from .faction import Faction +from .health import Health + +__all__ = [ + "Faction", + "Health", +] \ No newline at end of file diff --git a/rpgpack/utils/dndproficiencytype.py b/rpgpack/types/dndproficiencytype.py similarity index 64% rename from rpgpack/utils/dndproficiencytype.py rename to rpgpack/types/dndproficiencytype.py index d7ba925b..9054c120 100644 --- a/rpgpack/utils/dndproficiencytype.py +++ b/rpgpack/types/dndproficiencytype.py @@ -1,6 +1,7 @@ import enum +# TODO: Rename this. It will break the whole database. class DndProficiencyType(enum.Enum): NONE = 0 HALF_PROFICIENCY = 0.5 @@ -8,4 +9,4 @@ class DndProficiencyType(enum.Enum): EXPERTISE = 2 def __str__(self): - return str(self.value) \ No newline at end of file + return str(self.value) diff --git a/rpgpack/utils/faction.py b/rpgpack/types/faction.py similarity index 100% rename from rpgpack/utils/faction.py rename to rpgpack/types/faction.py diff --git a/rpgpack/utils/health.py b/rpgpack/types/health.py similarity index 100% rename from rpgpack/utils/health.py rename to rpgpack/types/health.py diff --git a/rpgpack/utils/__init__.py b/rpgpack/utils/__init__.py index 8aa30fb3..b965057a 100644 --- a/rpgpack/utils/__init__.py +++ b/rpgpack/utils/__init__.py @@ -1,14 +1,11 @@ -from .dndproficiencytype import DndProficiencyType from .parse5etoolsentry import parse_5etools_entry -from .getactivechar import get_active_character, get_interface_data -from .faction import Faction -from .health import Health +from .getinterfacedata import get_interface_data +from .getactivechar import get_active_character +from .getactivebattle import get_active_battle __all__ = [ - "DndProficiencyType", "parse_5etools_entry", - "get_active_character", "get_interface_data", - "Faction", - "Health", + "get_active_character", + "get_active_battle", ] diff --git a/rpgpack/utils/getactivebattle.py b/rpgpack/utils/getactivebattle.py new file mode 100644 index 00000000..3afee0c9 --- /dev/null +++ b/rpgpack/utils/getactivebattle.py @@ -0,0 +1,36 @@ +from typing import * +from ..tables import DndActiveBattle +from ..utils import get_interface_data +import royalnet.utils as ru +import royalnet.commands as rc +import pickle + + +async def get_active_battle(data: rc.CommandData) -> Optional[DndActiveBattle]: + interface = data._interface + alchemy = interface.alchemy + idata = get_interface_data(data) + + DndAcBaT = alchemy.get(DndActiveBattle) + active_battles: List[DndActiveBattle] = await ru.asyncify( + data.session + .query(DndAcBaT) + .filter_by(interface_name=interface.name) + .all + ) + + for active_battle in active_battles: + if interface.name == "telegram": + # interface_data is chat id + chat_id = pickle.loads(active_battle.interface_data) + if chat_id == idata: + return active_battle + elif interface.name == "discord": + # interface_data is channel id + chat_id = pickle.loads(active_battle.interface_data) + if chat_id == idata: + return active_battle + else: + raise rc.UnsupportedError("This interface isn't supported yet.") + + return None diff --git a/rpgpack/utils/getactivechar.py b/rpgpack/utils/getactivechar.py index eb358d5b..35555994 100644 --- a/rpgpack/utils/getactivechar.py +++ b/rpgpack/utils/getactivechar.py @@ -1,19 +1,11 @@ from typing import * from ..tables import DndActiveCharacter +from ..utils import get_interface_data 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 diff --git a/rpgpack/utils/getinterfacedata.py b/rpgpack/utils/getinterfacedata.py new file mode 100644 index 00000000..5e39133b --- /dev/null +++ b/rpgpack/utils/getinterfacedata.py @@ -0,0 +1,10 @@ +import royalnet.commands as rc + + +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.")