1
Fork 0
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:
Steffo 2020-02-19 18:14:39 +01:00
parent 16adaea355
commit 5f26184ebf
6 changed files with 184 additions and 1 deletions

View file

@ -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__

View 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)

View 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])))

View file

@ -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",
]

View 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
View 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