1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +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 .dndnew import DndnewCommand
from .dndedit import DndeditCommand
from .dndroll import DndrollCommand
from .dndrolladv import DndrolladvCommand
from .dndrolldis import DndrolldisCommand
# Enter the commands of your Pack here!
available_commands = [
@ -17,9 +14,6 @@ available_commands = [
DndinfoCommand,
DndnewCommand,
DndeditCommand,
DndrollCommand,
DndrolladvCommand,
DndrolldisCommand,
]
# Don't change this, it should automatically generate __all__

View file

@ -1,60 +1,35 @@
import re
from royalnet.commands import *
from .dndnew import DndnewCommand
from ..tables import DndCharacter, DndActiveCharacter
class DndeditCommand(Command):
class DndeditCommand(DndnewCommand):
name: str = "dndedit"
description: str = "Edit the active DnD character."
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}
async def run(self, args: CommandArgs, data: CommandData) -> None:
name, level, strength, dexterity, constitution, intelligence, wisdom, charisma, max_hp, armor_class = \
args.match(r"([\w ]+\w)\s*"
r"LV\s+(\d+)\s+"
r"STR\s+(\d+)\s+"
r"DEX\s+(\d+)\s+"
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.")
character_sheet = args.joined()
if character_sheet == "":
await data.reply(self._syntax())
return
author = await data.get_author(error_if_none=True)
char = author.dnd_active_character.character
char.name = name
char.level = level
char.strength = strength
char.dexterity = dexterity
char.constitution = constitution
char.intelligence = intelligence
char.wisdom = wisdom
char.charisma = charisma
char.max_hp = max_hp
char.armor_class = armor_class
data.session.add(char)
if author.dnd_active_character is None:
raise CommandError("You don't have an active character.")
char: DndCharacter = author.dnd_active_character.character
arguments = self._parse(character_sheet)
for key in arguments:
char.__setattr__(key, arguments[key])
await data.session_commit()
await data.reply(f"✅ Edit successful!")

View file

@ -1,6 +1,8 @@
import re
# noinspection PyUnresolvedReferences
from royalnet.commands import *
from ..tables import DndCharacter
from ..utils import DndProficiencyType
class DndnewCommand(Command):
@ -10,51 +12,59 @@ class DndnewCommand(Command):
aliases = ["dn", "dndn", "new", "dnew"]
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}"
syntax = "{name}\n{character_sheet}"
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:
name, level, strength, dexterity, constitution, intelligence, wisdom, charisma, max_hp, armor_class = \
args.match(r"([\w ]+\w)\s*"
r"LV\s+(\d+)\s+"
r"STR\s+(\d+)\s+"
r"DEX\s+(\d+)\s+"
r"COS\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)
character_sheet = args.joined()
if character_sheet == "":
await data.reply(self._syntax())
return
creator = await data.get_author()
name, rest = character_sheet.split("\n", 1)
character = self.alchemy.DndCharacter(name=name, creator=creator, **self._parse(rest))
data.session.add(character)
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)
char = self.alchemy.DndCharacter(name=name,
level=level,
strength=strength,
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!")
await data.session_commit()
except Exception as err:
# THIS IS INTENDED
if err.__class__.__name__ == "IntegrityError":
param_name = re.search(r'in column "(\S+)"', err.args[0]).group(1)
raise CommandError(f"Mandatory parameter '{param_name}' is missing.")
raise
await data.reply(f"✅ Character [b]{character.name}[/b] 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.orm import *
from sqlalchemy.ext.declarative import *
from ..utils import DndProficiencyType
class DndCharacter:
@ -20,71 +21,267 @@ class DndCharacter:
@declared_attr
def name(self):
return Column(String)
return Column(String, nullable=False)
@declared_attr
def strength_score(self):
return Column(Integer, nullable=False)
@property
def strength(self):
return Column(Integer)
@property
def strength_mod(self):
return (self.strength - 10) // 2
return (self.strength_score - 10) // 2
@declared_attr
def dexterity_score(self):
return Column(Integer, nullable=False)
@property
def dexterity(self):
return Column(Integer)
@property
def dexterity_mod(self):
return (self.dexterity - 10) // 2
return (self.dexterity_score - 10) // 2
@declared_attr
def constitution_score(self):
return Column(Integer, nullable=False)
@property
def constitution(self):
return Column(Integer)
@property
def constitution_mod(self):
return (self.constitution - 10) // 2
return (self.constitution_score - 10) // 2
@declared_attr
def intelligence_score(self):
return Column(Integer, nullable=False)
@property
def intelligence(self):
return Column(Integer)
@property
def intelligence_mod(self):
return (self.intelligence - 10) // 2
return (self.intelligence_score - 10) // 2
@declared_attr
def wisdom_score(self):
return Column(Integer, nullable=False)
@property
def wisdom(self):
return Column(Integer)
@property
def wisdom_mod(self):
return (self.wisdom - 10) // 2
return (self.wisdom_score - 10) // 2
@declared_attr
def charisma(self):
return Column(Integer)
def charisma_score(self):
return Column(Integer, nullable=False)
@property
def charisma_mod(self):
return (self.charisma - 10) // 2
def charisma(self):
return (self.charisma_score - 10) // 2
@declared_attr
def level(self):
return Column(Integer)
return Column(Integer, nullable=False)
@property
def proficiency_bonus(self):
return ((self.level - 1) // 4) + 2
@declared_attr
def current_hp(self):
return Column(Integer, nullable=False)
@declared_attr
def max_hp(self):
return Column(Integer)
return Column(Integer, nullable=False)
@declared_attr
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):
return f"<{self.__class__.__qualname__} {self.name}>"
@ -92,14 +289,13 @@ class DndCharacter:
def __str__(self):
return f"{self.name}"
def character_sheet(self):
return f"{self.name}\n" \
f"LV {self.level}\n\n" \
f"STR {self.strength}\n" \
f"DEX {self.dexterity}\n" \
f"CON {self.constitution}\n" \
f"INT {self.intelligence}\n" \
f"WIS {self.wisdom}\n" \
f"CHA {self.charisma}\n\n" \
f"MAXHP {self.max_hp}\n" \
f"AC {self.armor_class}\n" \
def character_sheet(self) -> str:
columns = list(self.__class__.__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 = f"[b]{self.name}[/b]\n"
for column_name in column_names:
value = self.__getattribute__(column_name)
message += f"{column_name} {value}\n"
return message

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)