improve conditions test
This commit is contained in:
parent
e2ff1eb027
commit
b68dda2b77
|
@ -7,7 +7,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
from ttfrog.db.base import BaseObject, SlugMixin
|
from ttfrog.db.base import BaseObject, SlugMixin
|
||||||
from ttfrog.db.schema.classes import CharacterClass, ClassFeature
|
from ttfrog.db.schema.classes import CharacterClass, ClassFeature
|
||||||
from ttfrog.db.schema.constants import DamageType, Defenses
|
from ttfrog.db.schema.constants import DamageType, Defenses
|
||||||
from ttfrog.db.schema.modifiers import Condition, Modifier, ModifierMixin, Stat
|
from ttfrog.db.schema.modifiers import Modifier, ModifierMixin, Stat
|
||||||
from ttfrog.db.schema.skill import Skill
|
from ttfrog.db.schema.skill import Skill
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -32,6 +32,7 @@ def skill_creator(fields):
|
||||||
return fields
|
return fields
|
||||||
return CharacterSkillMap(**fields)
|
return CharacterSkillMap(**fields)
|
||||||
|
|
||||||
|
|
||||||
def condition_creator(fields):
|
def condition_creator(fields):
|
||||||
if isinstance(fields, CharacterConditionMap):
|
if isinstance(fields, CharacterConditionMap):
|
||||||
return fields
|
return fields
|
||||||
|
@ -165,6 +166,7 @@ class CharacterClassFeatureMap(BaseObject):
|
||||||
uselist=False,
|
uselist=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CharacterConditionMap(BaseObject):
|
class CharacterConditionMap(BaseObject):
|
||||||
__tablename__ = "character_condition_map"
|
__tablename__ = "character_condition_map"
|
||||||
__table_args__ = (UniqueConstraint("condition_id", "character_id"),)
|
__table_args__ = (UniqueConstraint("condition_id", "character_id"),)
|
||||||
|
@ -173,6 +175,7 @@ class CharacterConditionMap(BaseObject):
|
||||||
character_id: Mapped[int] = mapped_column(ForeignKey("character.id"), nullable=True, default=None)
|
character_id: Mapped[int] = mapped_column(ForeignKey("character.id"), nullable=True, default=None)
|
||||||
condition = relationship("Condition", lazy="immediate")
|
condition = relationship("Condition", lazy="immediate")
|
||||||
|
|
||||||
|
|
||||||
class Character(BaseObject, SlugMixin, ModifierMixin):
|
class Character(BaseObject, SlugMixin, ModifierMixin):
|
||||||
__tablename__ = "character"
|
__tablename__ = "character"
|
||||||
|
|
||||||
|
@ -207,9 +210,15 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
||||||
nullable=False, default=10, info={"min": 0, "max": 30, "modifiable_class": Stat}
|
nullable=False, default=10, info={"min": 0, "max": 30, "modifiable_class": Stat}
|
||||||
)
|
)
|
||||||
|
|
||||||
_actions_per_turn: Mapped[int] = mapped_column(nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True})
|
_actions_per_turn: Mapped[int] = mapped_column(
|
||||||
_bonus_actions_per_turn: Mapped[int] = mapped_column(nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True})
|
nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True}
|
||||||
_reactions_per_turn: Mapped[int] = mapped_column(nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True})
|
)
|
||||||
|
_bonus_actions_per_turn: Mapped[int] = mapped_column(
|
||||||
|
nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True}
|
||||||
|
)
|
||||||
|
_reactions_per_turn: Mapped[int] = mapped_column(
|
||||||
|
nullable=False, default=1, info={"min": 0, "max": 99, "modifiable": True}
|
||||||
|
)
|
||||||
|
|
||||||
vision: Mapped[int] = mapped_column(default=None, nullable=True, info={"min": 0, "modifiable": True})
|
vision: Mapped[int] = mapped_column(default=None, nullable=True, info={"min": 0, "modifiable": True})
|
||||||
exhaustion: Mapped[int] = mapped_column(nullable=False, default=0, info={"min": 0, "max": 5})
|
exhaustion: Mapped[int] = mapped_column(nullable=False, default=0, info={"min": 0, "max": 5})
|
||||||
|
@ -220,7 +229,9 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
||||||
_skills = relationship("CharacterSkillMap", uselist=True, cascade="all,delete,delete-orphan", lazy="immediate")
|
_skills = relationship("CharacterSkillMap", uselist=True, cascade="all,delete,delete-orphan", lazy="immediate")
|
||||||
skills = association_proxy("_skills", "skill", creator=skill_creator)
|
skills = association_proxy("_skills", "skill", creator=skill_creator)
|
||||||
|
|
||||||
_conditions = relationship("CharacterConditionMap", uselist=True, cascade="all,delete,delete-orphan", lazy="immediate")
|
_conditions = relationship(
|
||||||
|
"CharacterConditionMap", uselist=True, cascade="all,delete,delete-orphan", lazy="immediate"
|
||||||
|
)
|
||||||
conditions = association_proxy("_conditions", "condition", creator=condition_creator)
|
conditions = association_proxy("_conditions", "condition", creator=condition_creator)
|
||||||
|
|
||||||
character_class_feature_map = relationship("CharacterClassFeatureMap", cascade="all,delete,delete-orphan")
|
character_class_feature_map = relationship("CharacterClassFeatureMap", cascade="all,delete,delete-orphan")
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey, UniqueConstraint, String
|
from sqlalchemy import ForeignKey, String, UniqueConstraint
|
||||||
from sqlalchemy.ext.declarative import declared_attr
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
# from sqlalchemy.ext.associationproxy import association_proxy
|
|
||||||
|
|
||||||
from ttfrog.db.base import BaseObject
|
from ttfrog.db.base import BaseObject
|
||||||
|
|
||||||
|
# from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
|
|
||||||
|
|
||||||
class Modifiable:
|
class Modifiable:
|
||||||
def __new__(cls, base, modified=None):
|
def __new__(cls, base, modified=None):
|
||||||
|
@ -334,7 +335,7 @@ class Condition(BaseObject):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
mods = ''
|
mods = ""
|
||||||
if self._modifiers:
|
if self._modifiers:
|
||||||
mods = "\n" + "\n".join([f" - {mod}" for mod in self._modifiers])
|
mods = "\n" + "\n".join([f" - {mod}" for mod in self._modifiers])
|
||||||
return f"{self.name}{mods}"
|
return f"{self.name}{mods}"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ttfrog.db import schema
|
from ttfrog.db import schema
|
||||||
from ttfrog.db.schema.conditions import conditions
|
|
||||||
from ttfrog.db.schema.constants import Conditions, DamageType, Defenses
|
from ttfrog.db.schema.constants import Conditions, DamageType, Defenses
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +226,9 @@ def test_modifiers(db, bootstrap):
|
||||||
# test sets of modifiers from conditions are applied when a condition is active
|
# test sets of modifiers from conditions are applied when a condition is active
|
||||||
incapacitated = schema.Condition(name="incapacitated")
|
incapacitated = schema.Condition(name="incapacitated")
|
||||||
incapacitated.add_modifier(schema.Modifier(target="actions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(schema.Modifier(target="actions_per_turn", absolute_value=0, name="Incapacitated"))
|
||||||
incapacitated.add_modifier(schema.Modifier(target="bonus_actions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(
|
||||||
|
schema.Modifier(target="bonus_actions_per_turn", absolute_value=0, name="Incapacitated")
|
||||||
|
)
|
||||||
incapacitated.add_modifier(schema.Modifier(target="reactions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(schema.Modifier(target="reactions_per_turn", absolute_value=0, name="Incapacitated"))
|
||||||
db.add_or_update(incapacitated)
|
db.add_or_update(incapacitated)
|
||||||
assert carl.actions_per_turn == 1
|
assert carl.actions_per_turn == 1
|
||||||
|
@ -421,32 +422,47 @@ def test_condition_immunity(db, bootstrap):
|
||||||
db.add_or_update(carl)
|
db.add_or_update(carl)
|
||||||
assert carl.has_condition(poisoned)
|
assert carl.has_condition(poisoned)
|
||||||
|
|
||||||
|
|
||||||
def test_partial_immunities(db, bootstrap):
|
def test_partial_immunities(db, bootstrap):
|
||||||
"""
|
"""
|
||||||
Test that individual modifiers applied by a condition can be negated even if not immune to the condition.
|
Test that individual modifiers applied by a condition can be negated even if not immune to the condition.
|
||||||
"""
|
"""
|
||||||
with db.transaction():
|
with db.transaction():
|
||||||
tiefling = db.Ancestry.filter_by(name="tiefling").one()
|
# Create some modifiers and conditions for this test
|
||||||
carl = schema.Character(name="Carl", ancestry=tiefling)
|
fly = schema.Modifier(target="fly_speed", absolute_value=30, name="Fly Spell")
|
||||||
|
cannot_move = schema.Modifier(name="Cannot Move (Petrified", target="speed", absolute_value=0)
|
||||||
poisoned = schema.Condition(name=DamageType.poison)
|
poisoned = schema.Condition(name=DamageType.poison)
|
||||||
poison_immunity = schema.Modifier("Poison Immunity", target=DamageType.poison, new_value=Defenses.immune)
|
poison_immunity = schema.Modifier("Poison Immunity", target=DamageType.poison, new_value=Defenses.immune)
|
||||||
|
|
||||||
|
# incapacitated applies several modifiers
|
||||||
incapacitated = schema.Condition(name=Conditions.incapacitated)
|
incapacitated = schema.Condition(name=Conditions.incapacitated)
|
||||||
incapacitated.add_modifier(schema.Modifier(target="actions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(schema.Modifier(target="actions_per_turn", absolute_value=0, name="Incapacitated"))
|
||||||
incapacitated.add_modifier(schema.Modifier(target="bonus_actions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(
|
||||||
|
schema.Modifier(target="bonus_actions_per_turn", absolute_value=0, name="Incapacitated")
|
||||||
|
)
|
||||||
incapacitated.add_modifier(schema.Modifier(target="reactions_per_turn", absolute_value=0, name="Incapacitated"))
|
incapacitated.add_modifier(schema.Modifier(target="reactions_per_turn", absolute_value=0, name="Incapacitated"))
|
||||||
|
|
||||||
# petrified incapacitates you, and makes you immune to poison
|
# petrified applies several modifiers but also incapacitates you!
|
||||||
petrified = schema.Condition(name=Conditions.petrified)
|
petrified = schema.Condition(name=Conditions.petrified)
|
||||||
assert petrified.add_modifier(poison_immunity)
|
assert petrified.add_modifier(poison_immunity)
|
||||||
|
assert petrified.add_modifier(cannot_move)
|
||||||
assert petrified.add_condition(incapacitated)
|
assert petrified.add_condition(incapacitated)
|
||||||
db.add_or_update([poisoned, poison_immunity, incapacitated, petrified])
|
db.add_or_update([fly, cannot_move, poisoned, poison_immunity, incapacitated, petrified])
|
||||||
|
|
||||||
|
# hi carl
|
||||||
|
tiefling = db.Ancestry.filter_by(name="tiefling").one()
|
||||||
|
carl = schema.Character(name="Carl", ancestry=tiefling)
|
||||||
|
|
||||||
|
# carl casts fly!
|
||||||
|
assert carl.fly_speed is None
|
||||||
|
assert carl.add_modifier(fly)
|
||||||
|
assert carl.fly_speed == carl.speed == carl.ancestry.speed
|
||||||
|
db.add_or_update(carl)
|
||||||
|
|
||||||
# poison carl
|
# poison carl
|
||||||
carl.add_condition(poisoned)
|
|
||||||
db.add_or_update(carl)
|
|
||||||
assert not carl.immune(DamageType.poison)
|
assert not carl.immune(DamageType.poison)
|
||||||
|
assert carl.add_condition(poisoned)
|
||||||
|
db.add_or_update(carl)
|
||||||
|
|
||||||
# petrify carl
|
# petrify carl
|
||||||
assert not carl.immune(Conditions.petrified)
|
assert not carl.immune(Conditions.petrified)
|
||||||
|
@ -458,6 +474,8 @@ def test_partial_immunities(db, bootstrap):
|
||||||
|
|
||||||
# but carl still can't move
|
# but carl still can't move
|
||||||
assert carl.actions_per_turn == 0
|
assert carl.actions_per_turn == 0
|
||||||
|
assert carl.speed == 0
|
||||||
|
assert carl.fly_speed == 0
|
||||||
|
|
||||||
# greater restoration ftw!
|
# greater restoration ftw!
|
||||||
assert carl.remove_condition(petrified)
|
assert carl.remove_condition(petrified)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user