mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Implement Factions and Health
This commit is contained in:
parent
16adaea355
commit
5f26184ebf
6 changed files with 184 additions and 1 deletions
|
@ -8,6 +8,8 @@ from .dndedit import DndeditCommand
|
||||||
from .dndroll import DndrollCommand
|
from .dndroll import DndrollCommand
|
||||||
from .dnditem import DnditemCommand
|
from .dnditem import DnditemCommand
|
||||||
from .dndspell import DndspellCommand
|
from .dndspell import DndspellCommand
|
||||||
|
from .testhealth import TesthealthCommand
|
||||||
|
from .testfaction import TestfactionCommand
|
||||||
|
|
||||||
# Enter the commands of your Pack here!
|
# Enter the commands of your Pack here!
|
||||||
available_commands = [
|
available_commands = [
|
||||||
|
@ -20,6 +22,8 @@ available_commands = [
|
||||||
DndrollCommand,
|
DndrollCommand,
|
||||||
DnditemCommand,
|
DnditemCommand,
|
||||||
DndspellCommand,
|
DndspellCommand,
|
||||||
|
TesthealthCommand,
|
||||||
|
TestfactionCommand,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Don't change this, it should automatically generate __all__
|
# Don't change this, it should automatically generate __all__
|
||||||
|
|
15
rpgpack/commands/testfaction.py
Normal file
15
rpgpack/commands/testfaction.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from typing import *
|
||||||
|
import royalnet
|
||||||
|
import royalnet.commands as rc
|
||||||
|
from ..utils import FactionColor
|
||||||
|
|
||||||
|
|
||||||
|
class TestfactionCommand(rc.Command):
|
||||||
|
name: str = "testfaction"
|
||||||
|
|
||||||
|
description: str = "Test a faction string."
|
||||||
|
|
||||||
|
syntax: str = "{factionstring}"
|
||||||
|
|
||||||
|
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
|
||||||
|
await data.reply(FactionColor[args[0].upper()].value)
|
15
rpgpack/commands/testhealth.py
Normal file
15
rpgpack/commands/testhealth.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from typing import *
|
||||||
|
import royalnet
|
||||||
|
import royalnet.commands as rc
|
||||||
|
from ..utils import Health
|
||||||
|
|
||||||
|
|
||||||
|
class TesthealthCommand(rc.Command):
|
||||||
|
name: str = "testhealth"
|
||||||
|
|
||||||
|
description: str = "Test a health string."
|
||||||
|
|
||||||
|
syntax: str = "{healthstring}"
|
||||||
|
|
||||||
|
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
|
||||||
|
await data.reply(str(Health.from_text(args[0])))
|
|
@ -1,5 +1,14 @@
|
||||||
from .dndproficiencytype import DndProficiencyType
|
from .dndproficiencytype import DndProficiencyType
|
||||||
from .parse5etoolsentry import parse_5etools_entry
|
from .parse5etoolsentry import parse_5etools_entry
|
||||||
from .getactivechar import get_active_character, get_interface_data
|
from .getactivechar import get_active_character, get_interface_data
|
||||||
|
from .factioncolors import FactionColor
|
||||||
|
from .health import Health
|
||||||
|
|
||||||
__all__ = ["DndProficiencyType", "parse_5etools_entry", "get_active_character", "get_interface_data"]
|
__all__ = [
|
||||||
|
"DndProficiencyType",
|
||||||
|
"parse_5etools_entry",
|
||||||
|
"get_active_character",
|
||||||
|
"get_interface_data",
|
||||||
|
"FactionColor",
|
||||||
|
"Health",
|
||||||
|
]
|
||||||
|
|
14
rpgpack/utils/factioncolors.py
Normal file
14
rpgpack/utils/factioncolors.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from typing import *
|
||||||
|
import enum
|
||||||
|
|
||||||
|
|
||||||
|
class FactionColor(enum.Enum):
|
||||||
|
RED = "🔴"
|
||||||
|
ORANGE = "🟠"
|
||||||
|
YELLOW = "🟡"
|
||||||
|
GREEN = "🟢"
|
||||||
|
BLUE = "🔵"
|
||||||
|
PURPLE = "🟣"
|
||||||
|
BLACK = "⚫️"
|
||||||
|
WHITE = "⚪️"
|
||||||
|
BROWN = "🟤"
|
126
rpgpack/utils/health.py
Normal file
126
rpgpack/utils/health.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
from typing import *
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class Health:
|
||||||
|
def __init__(self,
|
||||||
|
initial_value: int,
|
||||||
|
max_value: int,
|
||||||
|
hidden: Optional[bool] = None,
|
||||||
|
temp_value: Optional[int] = None,
|
||||||
|
deathsave_successes: Optional[int] = None,
|
||||||
|
deathsave_failures: Optional[int] = None):
|
||||||
|
self.value: int = 0
|
||||||
|
self.max_value: int = max_value
|
||||||
|
self.hidden: bool = hidden if hidden else False
|
||||||
|
self.temp_value: int = temp_value if temp_value else 0
|
||||||
|
self.deathsave_successes: int = deathsave_successes if deathsave_successes else 0
|
||||||
|
self.deathsave_failures: int = deathsave_failures if deathsave_failures else 0
|
||||||
|
self.change(initial_value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_text(cls, text: str) -> "Health":
|
||||||
|
match = re.match(r"(h)?([0-9]+)(?:\+([0-9]+))?/([0-9]+)(s{0,3})(f{0,3})", text)
|
||||||
|
if not match:
|
||||||
|
raise ValueError("Could not parse passed string.")
|
||||||
|
hidden, value, temp_value, max_value, ds_successes, ds_failures = match.groups()
|
||||||
|
return cls(initial_value=int(value),
|
||||||
|
max_value=int(max_value),
|
||||||
|
hidden=bool(hidden),
|
||||||
|
temp_value=int(temp_value) if temp_value else None,
|
||||||
|
deathsave_successes=len(ds_successes) if ds_successes else None,
|
||||||
|
deathsave_failures=len(ds_failures) if ds_failures else None)
|
||||||
|
|
||||||
|
def to_text(self) -> str:
|
||||||
|
string = []
|
||||||
|
if self.hidden:
|
||||||
|
string.append("h")
|
||||||
|
string.append(f"{self.value}")
|
||||||
|
if self.temp_value > 0:
|
||||||
|
string.append(f"{self.temp_value:+}")
|
||||||
|
string.append("/")
|
||||||
|
string.append(f"{self.max_value}̋")
|
||||||
|
string.append("s" * self.deathsave_successes)
|
||||||
|
string.append("f" * self.deathsave_failures)
|
||||||
|
return "".join(string)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dead(self) -> bool:
|
||||||
|
return self.deathsave_failures >= 3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stable(self) -> bool:
|
||||||
|
return self.deathsave_successes >= 3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dying(self) -> bool:
|
||||||
|
return self.value <= 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_value(self) -> int:
|
||||||
|
return self.value + self.temp_value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# Dead
|
||||||
|
if self.dead:
|
||||||
|
return "💀"
|
||||||
|
# Stable
|
||||||
|
if self.stable:
|
||||||
|
return f"💔 {self.value}/{self.max_value} "
|
||||||
|
# Dying
|
||||||
|
if self.value <= 0:
|
||||||
|
return "".join([
|
||||||
|
f"💔 {self.value}/{self.max_value} ",
|
||||||
|
"🔷" * self.deathsave_successes,
|
||||||
|
"🔹" * (3 - self.deathsave_successes),
|
||||||
|
" "
|
||||||
|
"🔶" * self.deathsave_failures,
|
||||||
|
"🔸" * (3 - self.deathsave_failures),
|
||||||
|
])
|
||||||
|
# Hidden
|
||||||
|
if self.hidden:
|
||||||
|
return f"🖤 {self.value - self.max_value}"
|
||||||
|
# Temporary HP
|
||||||
|
if self.temp_value > 0:
|
||||||
|
return f"💙 {self.value}+{self.temp_value}/{self.max_value}"
|
||||||
|
# Default
|
||||||
|
return f"❤️ {self.value}/{self.max_value}"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.__class__.__qualname__}.from_text({self.to_text()})"
|
||||||
|
|
||||||
|
def change(self, amount) -> None:
|
||||||
|
# Heal
|
||||||
|
if amount > 0:
|
||||||
|
self.value += amount
|
||||||
|
# Cap at maximum
|
||||||
|
if self.value >= self.max_value:
|
||||||
|
self.value = self.max_value
|
||||||
|
# Restore death saves
|
||||||
|
self.deathsave_successes = 0
|
||||||
|
self.deathsave_failures = 0
|
||||||
|
# Damage
|
||||||
|
else:
|
||||||
|
# First remove temporary health
|
||||||
|
self.temp_value += amount
|
||||||
|
# Then damage health based on how much damage wasn't absorbed
|
||||||
|
if self.temp_value < 0:
|
||||||
|
self.value += self.temp_value
|
||||||
|
self.temp_value = 0
|
||||||
|
# Cap health at 0
|
||||||
|
if self.value < 0:
|
||||||
|
self.value = 0
|
||||||
|
|
||||||
|
def deathsave_success(self) -> None:
|
||||||
|
if self.dying:
|
||||||
|
raise ValueError("Can't roll death saves while alive")
|
||||||
|
if self.stable:
|
||||||
|
raise ValueError("Successful death saves are capped at 3")
|
||||||
|
self.deathsave_successes += 1
|
||||||
|
|
||||||
|
def deathsave_failure(self) -> None:
|
||||||
|
if self.dying:
|
||||||
|
raise ValueError("Can't roll death saves while alive")
|
||||||
|
if self.dead:
|
||||||
|
raise ValueError("Failing death saves are capped at 3")
|
||||||
|
self.deathsave_failures += 1
|
Loading…
Reference in a new issue