mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Merge pull request #97 from Steffo99/dndproficiency
Use proficiencies for dnd
This commit is contained in:
commit
1174502290
10 changed files with 447 additions and 256 deletions
|
@ -4,4 +4,3 @@ from .commands import available_commands
|
||||||
from .tables import available_tables
|
from .tables import available_tables
|
||||||
|
|
||||||
__all__ = ["commands", "tables", "available_commands", "available_tables"]
|
__all__ = ["commands", "tables", "available_commands", "available_tables"]
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ 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 .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 = [
|
||||||
|
@ -18,8 +16,6 @@ available_commands = [
|
||||||
DndnewCommand,
|
DndnewCommand,
|
||||||
DndeditCommand,
|
DndeditCommand,
|
||||||
DndrollCommand,
|
DndrollCommand,
|
||||||
DndrolladvCommand,
|
|
||||||
DndrolldisCommand,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Don't change this, it should automatically generate __all__
|
# Don't change this, it should automatically generate __all__
|
||||||
|
|
|
@ -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!")
|
||||||
|
|
|
@ -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,60 @@ 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 = "ℹ️ Character Sheet syntax:\n[p]\nName\n"
|
||||||
|
for column_name in column_names:
|
||||||
|
message += f"{column_name} _\n"
|
||||||
|
message += "[/p]"
|
||||||
|
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!")
|
|
||||||
|
|
|
@ -1,94 +1,146 @@
|
||||||
import typing
|
import re
|
||||||
import random
|
import random
|
||||||
from royalnet.commands import *
|
from royalnet.commands import *
|
||||||
from royalnet.utils import plusformat
|
|
||||||
from ..tables import DndCharacter, DndActiveCharacter
|
from ..tables import DndCharacter, DndActiveCharacter
|
||||||
|
from royalnet.utils import plusformat
|
||||||
|
|
||||||
|
|
||||||
class DndrollCommand(Command):
|
class DndrollCommand(Command):
|
||||||
name: str = "dndroll"
|
name: str = "dndroll"
|
||||||
|
|
||||||
description: str = "Roll as the active DnD character."
|
description: str = "Roll dice as the active DnD character."
|
||||||
|
|
||||||
aliases = ["dr", "dndr", "droll"]
|
aliases = ["dr", "dndr", "roll", "droll"]
|
||||||
|
|
||||||
syntax = "{stat} [proficiency] [modifier]"
|
|
||||||
|
|
||||||
tables = {DndCharacter, DndActiveCharacter}
|
tables = {DndCharacter, DndActiveCharacter}
|
||||||
|
|
||||||
@staticmethod
|
_skill_names = {
|
||||||
def _roll():
|
"str": "strength",
|
||||||
return random.randrange(1, 21)
|
"for": "strength",
|
||||||
|
"dex": "dexterity",
|
||||||
|
"des": "dexterity",
|
||||||
|
"con": "constitution",
|
||||||
|
"cos": "constitution",
|
||||||
|
"inte": "intelligence",
|
||||||
|
"wis": "wisdom",
|
||||||
|
"sag": "wisdom",
|
||||||
|
"cha": "charisma",
|
||||||
|
"car": "charisma",
|
||||||
|
|
||||||
_roll_string = "1d20"
|
"ststr": "strength_save",
|
||||||
|
"stfor": "strength_save",
|
||||||
|
"stdex": "dexterity_save",
|
||||||
|
"stdes": "dexterity_save",
|
||||||
|
"stcon": "constitution_save",
|
||||||
|
"stcos": "constitution_save",
|
||||||
|
"stint": "intelligence_save",
|
||||||
|
"stwis": "wisdom_save",
|
||||||
|
"stsag": "wisdom_save",
|
||||||
|
"stcha": "charisma_save",
|
||||||
|
"stcar": "charisma_save",
|
||||||
|
|
||||||
|
"tsstr": "strength_save",
|
||||||
|
"tsfor": "strength_save",
|
||||||
|
"tsdex": "dexterity_save",
|
||||||
|
"tsdes": "dexterity_save",
|
||||||
|
"tscon": "constitution_save",
|
||||||
|
"tscos": "constitution_save",
|
||||||
|
"tsint": "intelligence_save",
|
||||||
|
"tswis": "wisdom_save",
|
||||||
|
"tssag": "wisdom_save",
|
||||||
|
"tscha": "charisma_save",
|
||||||
|
"tscar": "charisma_save",
|
||||||
|
|
||||||
|
"acr": "acrobatics",
|
||||||
|
"add": "animal_handling",
|
||||||
|
"ani": "animal_handling",
|
||||||
|
"arc": "arcana",
|
||||||
|
"ath": "athletics",
|
||||||
|
"dec": "deception",
|
||||||
|
"ing": "deception",
|
||||||
|
"his": "history",
|
||||||
|
"sto": "history",
|
||||||
|
"ins": "insight",
|
||||||
|
"intu": "insight",
|
||||||
|
"inti": "intimidation",
|
||||||
|
"inv": "investigation",
|
||||||
|
"med": "medicine",
|
||||||
|
"nat": "nature",
|
||||||
|
"perc": "perception",
|
||||||
|
"perf": "performance",
|
||||||
|
"pers": "persuasion",
|
||||||
|
"rel": "religion",
|
||||||
|
"sle": "sleight_of_hand",
|
||||||
|
"soh": "sleight_of_hand",
|
||||||
|
"rap": "sleight_of_hand",
|
||||||
|
"ste": "stealth",
|
||||||
|
"nas": "stealth",
|
||||||
|
"sur": "survival",
|
||||||
|
"sop": "sopravvivenza",
|
||||||
|
}
|
||||||
|
|
||||||
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
||||||
author = await data.get_author(error_if_none=True)
|
author = await data.get_author(error_if_none=True)
|
||||||
if author.dnd_active_character is None:
|
if author.dnd_active_character is None:
|
||||||
raise CommandError("You don't have an active character.")
|
raise CommandError("You don't have an active character.")
|
||||||
char: DndCharacter = author.dnd_active_character.character
|
char: DndCharacter = author.dnd_active_character.character
|
||||||
stat: str = args[0]
|
|
||||||
second: typing.Optional[str] = args.optional(1)
|
first = args[0]
|
||||||
third: typing.Optional[str] = args.optional(2)
|
second = args.optional(1)
|
||||||
|
third = args.optional(2)
|
||||||
|
|
||||||
|
advantage = False
|
||||||
|
disadvantage = False
|
||||||
|
extra_modifier = 0
|
||||||
|
|
||||||
if third:
|
if third:
|
||||||
extra_mod: int = int(third)
|
try:
|
||||||
else:
|
extra_modifier = int(third)
|
||||||
extra_mod: int = 0
|
except ValueError:
|
||||||
|
raise InvalidInputError("Invalid modifier value (third parameter).")
|
||||||
if second:
|
if second.startswith("a") or second.startswith("v"):
|
||||||
if second.startswith("e") or second.startswith("x"):
|
advantage = True
|
||||||
proficiency_mul: float = 2.0
|
elif second.startswith("d") or second.startswith("d"):
|
||||||
proficiency_name: str = " with Expertise"
|
disadvantage = True
|
||||||
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:
|
else:
|
||||||
raise CommandError(f"Unknown proficiency type '{second}'")
|
raise InvalidInputError("Invalid advantage string (second parameter).")
|
||||||
proficiency_mod: int = int(char.proficiency_bonus * proficiency_mul)
|
|
||||||
|
elif second:
|
||||||
|
try:
|
||||||
|
extra_modifier = int(second)
|
||||||
|
except ValueError:
|
||||||
|
if second.startswith("a") or second.startswith("v"):
|
||||||
|
advantage = True
|
||||||
|
elif second.startswith("d") or second.startswith("d"):
|
||||||
|
disadvantage = True
|
||||||
|
else:
|
||||||
|
raise InvalidInputError("Invalid modifier value or advantage string (second parameter).")
|
||||||
|
|
||||||
|
skill_short_name = first
|
||||||
|
for root in self._skill_names:
|
||||||
|
if skill_short_name.startswith(root):
|
||||||
|
skill_name = self._skill_names[root]
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
proficiency_name: str = ""
|
raise CommandError("Invalid skill name (first parameter).")
|
||||||
proficiency_mod: int = 0
|
|
||||||
|
|
||||||
if stat.startswith("st") or stat.startswith("fo"):
|
skill_modifier = char.__getattribute__(skill_name)
|
||||||
stat_mod: int = char.strength_mod
|
modifier = skill_modifier + extra_modifier
|
||||||
stat_name: str = "[i]STR[/i]"
|
modifier_str = plusformat(modifier, empty_if_zero=True)
|
||||||
elif stat.startswith("de"):
|
|
||||||
stat_mod: int = char.dexterity_mod
|
if advantage:
|
||||||
stat_name: str = "[i]DEX[/i]"
|
roll_a = random.randrange(1, 21)
|
||||||
elif stat.startswith("co"):
|
roll_b = random.randrange(1, 21)
|
||||||
stat_mod: int = char.constitution_mod
|
roll = max([roll_a, roll_b])
|
||||||
stat_name: str = "[i]CON[/i]"
|
total = roll + modifier
|
||||||
elif stat.startswith("in"):
|
await data.reply(f"🎲 2d20h1{modifier_str} = ({roll_a}|{roll_b}){modifier_str} = [b]{total}[/b]")
|
||||||
stat_mod: int = char.intelligence_mod
|
elif disadvantage:
|
||||||
stat_name: str = "[i]INT[/i]"
|
roll_a = random.randrange(1, 21)
|
||||||
elif stat.startswith("wi") or stat.startswith("sa"):
|
roll_b = random.randrange(1, 21)
|
||||||
stat_mod: int = char.wisdom_mod
|
roll = min([roll_a, roll_b])
|
||||||
stat_name: str = "[i]WIS[/i]"
|
total = roll + modifier
|
||||||
elif stat.startswith("ch") or stat.startswith("ca"):
|
await data.reply(f"🎲 2d20l1{modifier_str} = ({roll_a}|{roll_b}){modifier_str} = [b]{total}[/b]")
|
||||||
stat_mod: int = char.charisma_mod
|
|
||||||
stat_name: str = "[i]CHA[/i]"
|
|
||||||
else:
|
else:
|
||||||
raise CommandError(f"Unknown stat '{stat}'")
|
roll = random.randrange(1, 21)
|
||||||
|
total = roll + modifier
|
||||||
total_mod = stat_mod + proficiency_mod + extra_mod
|
await data.reply(f"🎲 1d20{modifier_str} = {roll}{modifier_str} = [b]{total}[/b]")
|
||||||
|
|
||||||
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]")
|
|
||||||
|
|
|
@ -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"
|
|
|
@ -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"
|
|
|
@ -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_save_proficiency(self):
|
||||||
|
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def dexterity_save_proficiency(self):
|
||||||
|
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def constitution_save_proficiency(self):
|
||||||
|
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def intelligence_save_proficiency(self):
|
||||||
|
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def wisdom_save_proficiency(self):
|
||||||
|
return Column(Enum(DndProficiencyType), nullable=False, default=DndProficiencyType.NONE)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def charisma_save_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_save_proficiency.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dexterity_save(self):
|
||||||
|
return self.dexterity + self.proficiency_bonus * self.dexterity_save_proficiency.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def constitution_save(self):
|
||||||
|
return self.constitution + self.proficiency_bonus * self.constitution_save_proficiency.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def intelligence_save(self):
|
||||||
|
return self.intelligence + self.proficiency_bonus * self.intelligence_save_proficiency.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wisdom_save(self):
|
||||||
|
return self.wisdom + self.proficiency_bonus * self.wisdom_save_proficiency.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def charisma_save(self):
|
||||||
|
return self.charisma + self.proficiency_bonus * self.charisma_save_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" \
|
|
||||||
|
|
3
royalnet/packs/rpg/utils/__init__.py
Normal file
3
royalnet/packs/rpg/utils/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from .dndproficiencytype import DndProficiencyType
|
||||||
|
|
||||||
|
__all__ = ["DndProficiencyType"]
|
11
royalnet/packs/rpg/utils/dndproficiencytype.py
Normal file
11
royalnet/packs/rpg/utils/dndproficiencytype.py
Normal 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)
|
Loading…
Reference in a new issue