1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00

Change dnd commands

This commit is contained in:
Steffo 2019-10-24 01:18:00 +02:00
parent d67110be09
commit 50700c7b63
9 changed files with 325 additions and 282 deletions

View file

@ -5,9 +5,6 @@ from .dndactive import DndactiveCommand
from .dndinfo import DndinfoCommand from .dndinfo import DndinfoCommand
from .dndnew import DndnewCommand from .dndnew import DndnewCommand
from .dndedit import DndeditCommand from .dndedit import DndeditCommand
from .dndroll import DndrollCommand
from .dndrolladv import DndrolladvCommand
from .dndrolldis import DndrolldisCommand
# Enter the commands of your Pack here! # Enter the commands of your Pack here!
available_commands = [ available_commands = [
@ -17,9 +14,6 @@ available_commands = [
DndinfoCommand, DndinfoCommand,
DndnewCommand, DndnewCommand,
DndeditCommand, DndeditCommand,
DndrollCommand,
DndrolladvCommand,
DndrolldisCommand,
] ]
# Don't change this, it should automatically generate __all__ # Don't change this, it should automatically generate __all__

View file

@ -1,60 +1,35 @@
import re import re
from royalnet.commands import * from royalnet.commands import *
from .dndnew import DndnewCommand
from ..tables import DndCharacter, DndActiveCharacter from ..tables import DndCharacter, DndActiveCharacter
class DndeditCommand(Command): class DndeditCommand(DndnewCommand):
name: str = "dndedit" name: str = "dndedit"
description: str = "Edit the active DnD character." description: str = "Edit the active DnD character."
aliases = ["de", "dnde", "edit", "dedit"] aliases = ["de", "dnde", "edit", "dedit"]
syntax = "{name}\n" \
"LV {level}\n" \
"\n" \
"STR {strength}\n" \
"DEX {dexterity}\n" \
"CON {constitution}\n" \
"INT {intelligence}\n" \
"WIS {wisdom}\n" \
"CHA {charisma}\n" \
"\n" \
"MAXHP {max_hp}\n" \
"AC {armor_class}"
tables = {DndCharacter, DndActiveCharacter} tables = {DndCharacter, DndActiveCharacter}
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: CommandArgs, data: CommandData) -> None:
name, level, strength, dexterity, constitution, intelligence, wisdom, charisma, max_hp, armor_class = \ character_sheet = args.joined()
args.match(r"([\w ]+\w)\s*"
r"LV\s+(\d+)\s+" if character_sheet == "":
r"STR\s+(\d+)\s+" await data.reply(self._syntax())
r"DEX\s+(\d+)\s+" return
r"CON\s+(\d+)\s+"
r"INT\s+(\d+)\s+"
r"WIS\s+(\d+)\s+"
r"CHA\s+(\d+)\s+"
r"MAXHP\s+(\d+)\s+"
r"AC\s+(\d+)", re.IGNORECASE)
try:
int(name)
except ValueError:
pass
else:
raise CommandError("Character names cannot be composed of only a number.")
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
char = author.dnd_active_character.character if author.dnd_active_character is None:
char.name = name raise CommandError("You don't have an active character.")
char.level = level
char.strength = strength char: DndCharacter = author.dnd_active_character.character
char.dexterity = dexterity
char.constitution = constitution arguments = self._parse(character_sheet)
char.intelligence = intelligence for key in arguments:
char.wisdom = wisdom char.__setattr__(key, arguments[key])
char.charisma = charisma
char.max_hp = max_hp
char.armor_class = armor_class
data.session.add(char)
await data.session_commit() await data.session_commit()
await data.reply(f"✅ Edit successful!") await data.reply(f"✅ Edit successful!")

View file

@ -1,6 +1,8 @@
import re import re
# noinspection PyUnresolvedReferences
from royalnet.commands import * from royalnet.commands import *
from ..tables import DndCharacter from ..tables import DndCharacter
from ..utils import DndProficiencyType
class DndnewCommand(Command): class DndnewCommand(Command):
@ -10,51 +12,59 @@ class DndnewCommand(Command):
aliases = ["dn", "dndn", "new", "dnew"] aliases = ["dn", "dndn", "new", "dnew"]
syntax = "{name}\n" \ syntax = "{name}\n{character_sheet}"
"LV {level}\n" \
"\n" \
"STR {strength}\n" \
"DEX {dexterity}\n" \
"CON {constitution}\n" \
"INT {intelligence}\n" \
"WIS {wisdom}\n" \
"CHA {charisma}\n" \
"\n" \
"MAXHP {max_hp}\n" \
"AC {armor_class}"
tables = {DndCharacter} tables = {DndCharacter}
def _search_value(self, name: str, string: str):
return re.search(r"\s*" + name + r"\s*([0-9]+)\s*", string, re.IGNORECASE)
def _parse(self, character_sheet: str) -> dict:
columns = list(self.alchemy.DndCharacter.__table__.columns)
column_names = [column.name for column in columns if (not column.primary_key and
not column.foreign_keys and
column.name != "name")]
arguments = {}
for column_name in column_names:
match = self._search_value(column_name, character_sheet)
if match:
if column_name.endswith("_proficiency"):
arguments[column_name] = DndProficiencyType(float(match.group(1)))
else:
arguments[column_name] = match.group(1)
return arguments
def _syntax(self) -> str:
columns = list(self.alchemy.DndCharacter.__table__.columns)
column_names = [column.name for column in columns if (not column.primary_key and
not column.foreign_keys and
column.name != "name")]
message = " [b]Character sheet format:[/b]"
for column_name in column_names:
message += f"{column_name} _\n"
return message
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: CommandArgs, data: CommandData) -> None:
name, level, strength, dexterity, constitution, intelligence, wisdom, charisma, max_hp, armor_class = \ character_sheet = args.joined()
args.match(r"([\w ]+\w)\s*"
r"LV\s+(\d+)\s+" if character_sheet == "":
r"STR\s+(\d+)\s+" await data.reply(self._syntax())
r"DEX\s+(\d+)\s+" return
r"COS\s+(\d+)\s+"
r"INT\s+(\d+)\s+" creator = await data.get_author()
r"WIS\s+(\d+)\s+"
r"CHA\s+(\d+)\s+" name, rest = character_sheet.split("\n", 1)
r"MAXHP\s+(\d+)\s+"
r"AC\s+(\d+)", re.IGNORECASE) character = self.alchemy.DndCharacter(name=name, creator=creator, **self._parse(rest))
data.session.add(character)
try: try:
int(name) await data.session_commit()
except ValueError: except Exception as err:
pass # THIS IS INTENDED
else: if err.__class__.__name__ == "IntegrityError":
raise CommandError("Character names cannot be composed of only a number.") param_name = re.search(r'in column "(\S+)"', err.args[0]).group(1)
author = await data.get_author(error_if_none=True) raise CommandError(f"Mandatory parameter '{param_name}' is missing.")
char = self.alchemy.DndCharacter(name=name, raise
level=level,
strength=strength, await data.reply(f"✅ Character [b]{character.name}[/b] created!")
dexterity=dexterity,
constitution=constitution,
intelligence=intelligence,
wisdom=wisdom,
charisma=charisma,
max_hp=max_hp,
armor_class=armor_class,
creator=author)
data.session.add(char)
await data.session_commit()
await data.reply(f"✅ Character [b]{char.name}[/b] ([c]{char.character_id}[/c]) was created!")

View file

@ -1,94 +0,0 @@
import typing
import random
from royalnet.commands import *
from royalnet.utils import plusformat
from ..tables import DndCharacter, DndActiveCharacter
class DndrollCommand(Command):
name: str = "dndroll"
description: str = "Roll as the active DnD character."
aliases = ["dr", "dndr", "droll"]
syntax = "{stat} [proficiency] [modifier]"
tables = {DndCharacter, DndActiveCharacter}
@staticmethod
def _roll():
return random.randrange(1, 21)
_roll_string = "1d20"
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:
raise CommandError("You don't have an active character.")
char: DndCharacter = author.dnd_active_character.character
stat: str = args[0]
second: typing.Optional[str] = args.optional(1)
third: typing.Optional[str] = args.optional(2)
if third:
extra_mod: int = int(third)
else:
extra_mod: int = 0
if second:
if second.startswith("e") or second.startswith("x"):
proficiency_mul: float = 2.0
proficiency_name: str = " with Expertise"
elif second.startswith("f") or second.startswith("n") or second.startswith("c"):
proficiency_mul: float = 1.0
proficiency_name: str = " with Proficiency"
elif second.startswith("h") or second == "/" or second.startswith("m"):
proficiency_mul: float = 0.5
proficiency_name: str = " with Half Proficiency"
elif second.startswith("h") or second == "/" or second.startswith("m"):
proficiency_mul: float = 0.0
proficiency_name: str = " [i]without Proficiency[/i]"
else:
raise CommandError(f"Unknown proficiency type '{second}'")
proficiency_mod: int = int(char.proficiency_bonus * proficiency_mul)
else:
proficiency_name: str = ""
proficiency_mod: int = 0
if stat.startswith("st") or stat.startswith("fo"):
stat_mod: int = char.strength_mod
stat_name: str = "[i]STR[/i]"
elif stat.startswith("de"):
stat_mod: int = char.dexterity_mod
stat_name: str = "[i]DEX[/i]"
elif stat.startswith("co"):
stat_mod: int = char.constitution_mod
stat_name: str = "[i]CON[/i]"
elif stat.startswith("in"):
stat_mod: int = char.intelligence_mod
stat_name: str = "[i]INT[/i]"
elif stat.startswith("wi") or stat.startswith("sa"):
stat_mod: int = char.wisdom_mod
stat_name: str = "[i]WIS[/i]"
elif stat.startswith("ch") or stat.startswith("ca"):
stat_mod: int = char.charisma_mod
stat_name: str = "[i]CHA[/i]"
else:
raise CommandError(f"Unknown stat '{stat}'")
total_mod = stat_mod + proficiency_mod + extra_mod
roll = self._roll()
result = roll + total_mod
await data.reply(f"🎲 Rolling {stat_name}{proficiency_name}{plusformat(extra_mod, empty_if_zero=True)}:\n"
f"{self._roll_string}"
f"{plusformat(stat_mod, empty_if_zero=True)}"
f"{plusformat(proficiency_mod, empty_if_zero=True)}"
f"{plusformat(extra_mod, empty_if_zero=True)}"
f" = "
f"{roll}{plusformat(total_mod, empty_if_zero=True)}"
f" = "
f"[b]{result}[/b]")

View file

@ -1,26 +0,0 @@
import typing
import random
from royalnet.commands import *
from royalnet.utils import plusformat
from .dndroll import DndrollCommand
from ..tables import DndCharacter, DndActiveCharacter
class DndrolladvCommand(DndrollCommand):
name: str = "dndrolladv"
description: str = "Roll with advantage as the active DnD character."
aliases = ["dra", "dndra", "drolladv"]
syntax = "{stat} [proficiency] [modifier]"
tables = {DndCharacter, DndActiveCharacter}
@staticmethod
def _roll():
first = random.randrange(1, 21)
second = random.randrange(1, 21)
return max(first, second)
_roll_string = "2d20h1"

View file

@ -1,26 +0,0 @@
import typing
import random
from royalnet.commands import *
from royalnet.utils import plusformat
from .dndroll import DndrollCommand
from ..tables import DndCharacter, DndActiveCharacter
class DndrolldisCommand(DndrollCommand):
name: str = "dndrolldis"
description: str = "Roll with disadvantage as the active DnD character."
aliases = ["drd", "dndrd", "drolldis"]
syntax = "{stat} [proficiency] [modifier]"
tables = {DndCharacter, DndActiveCharacter}
@staticmethod
def _roll():
first = random.randrange(1, 21)
second = random.randrange(1, 21)
return min(first, second)
_roll_string = "2d20l1"

View file

@ -1,6 +1,7 @@
from sqlalchemy import * from sqlalchemy import *
from sqlalchemy.orm import * from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import * from sqlalchemy.ext.declarative import *
from ..utils import DndProficiencyType
class DndCharacter: class DndCharacter:
@ -20,71 +21,267 @@ class DndCharacter:
@declared_attr @declared_attr
def name(self): def name(self):
return Column(String) return Column(String, nullable=False)
@declared_attr @declared_attr
def strength_score(self):
return Column(Integer, nullable=False)
@property
def strength(self): def strength(self):
return Column(Integer) return (self.strength_score - 10) // 2
@property
def strength_mod(self):
return (self.strength - 10) // 2
@declared_attr @declared_attr
def dexterity_score(self):
return Column(Integer, nullable=False)
@property
def dexterity(self): def dexterity(self):
return Column(Integer) return (self.dexterity_score - 10) // 2
@property
def dexterity_mod(self):
return (self.dexterity - 10) // 2
@declared_attr @declared_attr
def constitution_score(self):
return Column(Integer, nullable=False)
@property
def constitution(self): def constitution(self):
return Column(Integer) return (self.constitution_score - 10) // 2
@property
def constitution_mod(self):
return (self.constitution - 10) // 2
@declared_attr @declared_attr
def intelligence_score(self):
return Column(Integer, nullable=False)
@property
def intelligence(self): def intelligence(self):
return Column(Integer) return (self.intelligence_score - 10) // 2
@property
def intelligence_mod(self):
return (self.intelligence - 10) // 2
@declared_attr @declared_attr
def wisdom_score(self):
return Column(Integer, nullable=False)
@property
def wisdom(self): def wisdom(self):
return Column(Integer) return (self.wisdom_score - 10) // 2
@property
def wisdom_mod(self):
return (self.wisdom - 10) // 2
@declared_attr @declared_attr
def charisma(self): def charisma_score(self):
return Column(Integer) return Column(Integer, nullable=False)
@property @property
def charisma_mod(self): def charisma(self):
return (self.charisma - 10) // 2 return (self.charisma_score - 10) // 2
@declared_attr @declared_attr
def level(self): def level(self):
return Column(Integer) return Column(Integer, nullable=False)
@property @property
def proficiency_bonus(self): def proficiency_bonus(self):
return ((self.level - 1) // 4) + 2 return ((self.level - 1) // 4) + 2
@declared_attr
def current_hp(self):
return Column(Integer, nullable=False)
@declared_attr @declared_attr
def max_hp(self): def max_hp(self):
return Column(Integer) return Column(Integer, nullable=False)
@declared_attr @declared_attr
def armor_class(self): def armor_class(self):
return Column(Integer) return Column(Integer, nullable=False)
@declared_attr
def strength_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def dexterity_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def constitution_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def intelligence_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def wisdom_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def charisma_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def acrobatics_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def animal_handling_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def arcana_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def athletics_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def deception_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def history_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def insight_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def intimidation_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def investigation_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def medicine_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def nature_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def perception_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def performance_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def persuasion_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def religion_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def sleight_of_hand_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def stealth_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@declared_attr
def survival_proficiency(self):
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
@property
def strength_save(self):
return self.strength + self.proficiency_bonus * self.strength_proficiency.value
@property
def dexterity_save(self):
return self.dexterity + self.proficiency_bonus * self.dexterity_proficiency.value
@property
def constitution_save(self):
return self.constitution + self.proficiency_bonus * self.constitution_proficiency.value
@property
def intelligence_save(self):
return self.intelligence + self.proficiency_bonus * self.intelligence_proficiency.value
@property
def wisdom_save(self):
return self.wisdom + self.proficiency_bonus * self.wisdom_proficiency.value
@property
def charisma_save(self):
return self.charisma + self.proficiency_bonus * self.charisma_proficiency.value
@property
def acrobatics(self):
return self.dexterity + self.proficiency_bonus * self.acrobatics_proficiency.value
@property
def animal_handling(self):
return self.wisdom + self.proficiency_bonus * self.animal_handling_proficiency.value
@property
def arcana(self):
return self.intelligence + self.proficiency_bonus * self.arcana_proficiency.value
@property
def athletics(self):
return self.strength + self.proficiency_bonus * self.athletics_proficiency.value
@property
def deception(self):
return self.charisma + self.proficiency_bonus * self.deception_proficiency.value
@property
def history(self):
return self.intelligence + self.proficiency_bonus * self.history_proficiency.value
@property
def insight(self):
return self.wisdom + self.proficiency_bonus * self.insight_proficiency.value
@property
def intimidation(self):
return self.charisma + self.proficiency_bonus * self.intimidation_proficiency.value
@property
def investigation(self):
return self.intelligence + self.proficiency_bonus * self.investigation_proficiency.value
@property
def medicine(self):
return self.wisdom + self.proficiency_bonus * self.medicine_proficiency.value
@property
def nature(self):
return self.intelligence + self.proficiency_bonus * self.nature_proficiency.value
@property
def perception(self):
return self.wisdom + self.proficiency_bonus * self.perception_proficiency.value
@property
def performance(self):
return self.charisma + self.proficiency_bonus * self.performance_proficiency.value
@property
def persuasion(self):
return self.charisma + self.proficiency_bonus * self.persuasion_proficiency.value
@property
def religion(self):
return self.intelligence + self.proficiency_bonus * self.religion_proficiency.value
@property
def sleight_of_hand(self):
return self.dexterity + self.proficiency_bonus * self.sleight_of_hand_proficiency.value
@property
def stealth(self):
return self.dexterity + self.proficiency_bonus * self.stealth_proficiency.value
@property
def survival(self):
return self.wisdom + self.proficiency_bonus * self.survival_proficiency.value
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__qualname__} {self.name}>" return f"<{self.__class__.__qualname__} {self.name}>"
@ -92,14 +289,13 @@ class DndCharacter:
def __str__(self): def __str__(self):
return f"{self.name}" return f"{self.name}"
def character_sheet(self): def character_sheet(self) -> str:
return f"{self.name}\n" \ columns = list(self.__class__.__table__.columns)
f"LV {self.level}\n\n" \ column_names = [column.name for column in columns if (not column.primary_key and
f"STR {self.strength}\n" \ not column.foreign_keys and
f"DEX {self.dexterity}\n" \ column.name != "name")]
f"CON {self.constitution}\n" \ message = f"[b]{self.name}[/b]\n"
f"INT {self.intelligence}\n" \ for column_name in column_names:
f"WIS {self.wisdom}\n" \ value = self.__getattribute__(column_name)
f"CHA {self.charisma}\n\n" \ message += f"{column_name} {value}\n"
f"MAXHP {self.max_hp}\n" \ return message
f"AC {self.armor_class}\n" \

View file

@ -0,0 +1,3 @@
from .dndproficiencytype import DndProficiencyType
__all__ = ["DndProficiencyType"]

View file

@ -0,0 +1,11 @@
import enum
class DndProficiencyType(enum.Enum):
NONE = 0
HALF_PROFICIENCY = 0.5
FULL_PROFICIENCY = 1
EXPERTISE = 2
def __str__(self):
return str(self.value)