fix tests
This commit is contained in:
parent
a8bb6de008
commit
68251ff4e9
|
@ -9,7 +9,7 @@ packages = [
|
|||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
python = "^3.11"
|
||||
python-dotenv = "^0.21.0"
|
||||
typer = "^0.9.0"
|
||||
rich = "^13.7.0"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from .character import *
|
||||
from .classes import *
|
||||
from .constants import *
|
||||
from .log import *
|
||||
from .modifiers import *
|
||||
from .skill import *
|
||||
|
|
|
@ -6,6 +6,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||
|
||||
from ttfrog.db.base import BaseObject, SlugMixin
|
||||
from ttfrog.db.schema.classes import CharacterClass, ClassAttribute
|
||||
from ttfrog.db.schema.constants import Conditions, DamageType, Defenses
|
||||
from ttfrog.db.schema.modifiers import Modifier, ModifierMixin, Stat
|
||||
from ttfrog.db.schema.skill import Skill
|
||||
|
||||
|
@ -212,6 +213,7 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
)
|
||||
|
||||
_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})
|
||||
|
||||
class_map = relationship("CharacterClassMap", cascade="all,delete,delete-orphan")
|
||||
class_list = association_proxy("class_map", "id", creator=class_map_creator)
|
||||
|
@ -272,6 +274,10 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
def traits(self):
|
||||
return self.ancestry.traits
|
||||
|
||||
@property
|
||||
def initiative(self):
|
||||
return self._apply_modifiers("initiative", self.dexterity.bonus)
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
return self._apply_modifiers("speed", self.ancestry.speed)
|
||||
|
@ -294,7 +300,7 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
|
||||
@property
|
||||
def vision_in_darkness(self):
|
||||
return self.apply_modifiers("vision_in_darkness", self.vision if self.vision is not None else 0)
|
||||
return self._apply_modifiers("vision_in_darkness", self.vision if self.vision is not None else 0)
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
|
@ -314,23 +320,26 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
return None
|
||||
return mapping[0]
|
||||
|
||||
def immune(self, damage_type: str, magical: bool = False):
|
||||
return self.defense(damage_type, magical) == 'immune'
|
||||
def immune(self, damage_type: DamageType):
|
||||
return self.defense(damage_type) == Defenses.immune
|
||||
|
||||
def resistant(self, damage_type: str, magical: bool = False):
|
||||
return self.defense(damage_type, magical) == 'resistant'
|
||||
def resistant(self, damage_type: DamageType):
|
||||
return self.defense(damage_type) == Defenses.resistant.value
|
||||
|
||||
def vulnerable(self, damage_type: str, magical: bool = False):
|
||||
return self.defense(damage_type, magical) == 'vulnerable'
|
||||
def vulnerable(self, damage_type: DamageType):
|
||||
return self.defense(damage_type) == Defenses.vulnerable
|
||||
|
||||
def absorbs(self, damage_type: str, magical: bool = False):
|
||||
return self.defense(damage_type, magical) == 'absorbs'
|
||||
def absorbs(self, damage_type: DamageType):
|
||||
return self.defense(damage_type) == Defenses.absorbs
|
||||
|
||||
def defense(self, damage_type: str, magical: bool = False):
|
||||
attr_name = damage_type
|
||||
if magical:
|
||||
attr_name = f"magical_{attr_name}"
|
||||
return self._apply_modifiers(f"defenses.{attr_name}", None)
|
||||
def conditions(self):
|
||||
return [self._apply_modifiers(f"conditions.{name}") for name in Conditions]
|
||||
|
||||
def condition(self, condition_name: str):
|
||||
return self._apply_modifiers(f"conditions.{condition_name}", False)
|
||||
|
||||
def defense(self, damage_type: DamageType):
|
||||
return self._apply_modifiers(damage_type, None)
|
||||
|
||||
def check_modifier(self, skill: Skill, save: bool = False):
|
||||
# if the skill is not assigned, but we have modifiers, apply them to zero.
|
||||
|
@ -387,13 +396,13 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
self._hit_dice.append(HitDie(character_id=self.id, character_class_id=newclass.id))
|
||||
|
||||
def remove_class(self, target):
|
||||
self.class_map = [m for m in self.class_map if m.character_class != target]
|
||||
for mapping in self.character_class_attribute_map:
|
||||
if mapping.character_class == target:
|
||||
self.remove_class_attribute(mapping.class_attribute)
|
||||
for skill in target.skills:
|
||||
self.remove_skill(skill, proficient=True, expert=False, character_class=target)
|
||||
self._hit_dice = [die for die in self._hit_dice if die.character_class != target]
|
||||
self.class_map = [m for m in self.class_map if m.character_class != target]
|
||||
|
||||
def remove_class_attribute(self, attribute):
|
||||
self.character_class_attribute_map = [
|
||||
|
@ -474,15 +483,15 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
|||
def apply_healing(self, value: int):
|
||||
self.hit_points = min(self.hit_points + value, self._max_hit_points)
|
||||
|
||||
def apply_damage(self, value: int, damage_type: str, magical=False):
|
||||
def apply_damage(self, value: int, damage_type: DamageType):
|
||||
total = value
|
||||
if self.absorbs(damage_type, magical):
|
||||
if self.absorbs(damage_type):
|
||||
return self.apply_healing(total)
|
||||
if self.immune(damage_type, magical):
|
||||
if self.immune(damage_type):
|
||||
return
|
||||
if self.resistant(damage_type, magical):
|
||||
if self.resistant(damage_type):
|
||||
total = int(value / 2)
|
||||
elif self.vulnerable(damage_type, magical):
|
||||
elif self.vulnerable(damage_type):
|
||||
total = value * 2
|
||||
|
||||
if total <= self.temp_hit_points:
|
||||
|
|
|
@ -6,6 +6,7 @@ import pytest
|
|||
|
||||
from ttfrog.db import schema
|
||||
from ttfrog.db.manager import db as _db
|
||||
from ttfrog.db.schema.constants import DamageType, Defenses
|
||||
|
||||
FIXTURE_PATH = Path(__file__).parent / "fixtures"
|
||||
|
||||
|
@ -49,14 +50,12 @@ def bootstrap(db):
|
|||
darkvision.add_modifier(schema.Modifier("Darkvision", target="vision_in_darkness", absolute_value=120))
|
||||
tiefling.add_trait(darkvision)
|
||||
|
||||
# resistant to both magical and non-magical sources of fire
|
||||
# resistant to fire
|
||||
infernal_origin = schema.AncestryTrait("Infernal Origin")
|
||||
infernal_origin.add_modifier(schema.Modifier("Infernal Origin", target="defenses.fire", new_value="resistant"))
|
||||
infernal_origin.add_modifier(
|
||||
schema.Modifier("Infernal Origin", target="defenses.magical_fire", new_value="resistant")
|
||||
schema.Modifier("Infernal Origin", target=DamageType.fire, new_value=Defenses.resistant)
|
||||
)
|
||||
tiefling.add_trait(infernal_origin)
|
||||
db.add_or_update(tiefling)
|
||||
|
||||
dragonborn = schema.Ancestry("dragonborn")
|
||||
dragonborn.add_trait(darkvision)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
|
||||
from ttfrog.db import schema
|
||||
from ttfrog.db.schema.constants import DamageType, Defenses
|
||||
|
||||
|
||||
def test_manage_character(db, bootstrap):
|
||||
|
@ -96,6 +97,14 @@ def test_manage_character(db, bootstrap):
|
|||
assert char.check_modifier(athletics) == char.proficiency_bonus + char.strength.bonus == 3
|
||||
assert char.check_modifier(acrobatics) == char.proficiency_bonus + char.dexterity.bonus == 3
|
||||
|
||||
# assert dexterity bonus apply to initiative
|
||||
char._dexterity = 17
|
||||
assert char.dexterity.bonus == 3
|
||||
assert char.initiative == char.dexterity.bonus == 3
|
||||
char.add_modifier(schema.Modifier("+1 initiative", target="initiative", relative_value=1))
|
||||
assert char.initiative == 4
|
||||
char._dexterity = 10
|
||||
|
||||
# multiclass
|
||||
char.add_class(rogue, level=1)
|
||||
db.add_or_update(char)
|
||||
|
@ -279,45 +288,39 @@ def test_defenses(db, bootstrap):
|
|||
with db.transaction():
|
||||
tiefling = db.Ancestry.filter_by(name="tiefling").one()
|
||||
carl = schema.Character(name="Carl", ancestry=tiefling)
|
||||
assert carl.resistant("fire", magical=False)
|
||||
assert carl.resistant("fire", magical=True)
|
||||
carl.apply_damage(5, "fire", magical=True)
|
||||
assert carl.resistant(DamageType.fire)
|
||||
carl.apply_damage(5, DamageType.fire)
|
||||
assert carl.hit_points == 8 # half damage
|
||||
|
||||
immunity = [
|
||||
schema.Modifier("Fire Immunity", target="defenses.fire", new_value="immune"),
|
||||
schema.Modifier("Fire Immunity", target="defenses.magical_fire", new_value="immune")
|
||||
schema.Modifier("Fire Immunity", target=DamageType.fire, new_value=Defenses.immune),
|
||||
]
|
||||
for i in immunity:
|
||||
carl.add_modifier(i)
|
||||
assert carl.immune("fire")
|
||||
carl.apply_damage(5, "fire", magical=True)
|
||||
carl.apply_damage(5, "fire", magical=False)
|
||||
assert carl.immune(DamageType.fire)
|
||||
carl.apply_damage(5, DamageType.fire)
|
||||
assert carl.hit_points == 8 # no damage
|
||||
|
||||
vulnerability = [
|
||||
schema.Modifier("Fire Vulnerability", target="defenses.fire", new_value="vulnerable"),
|
||||
schema.Modifier("Fire Vulnerability", target="defenses.magical_fire", new_value="vulnerable")
|
||||
schema.Modifier("Fire Vulnerability", target=DamageType.fire, new_value=Defenses.vulnerable),
|
||||
]
|
||||
for i in vulnerability:
|
||||
carl.add_modifier(i)
|
||||
assert carl.vulnerable("fire")
|
||||
assert not carl.immune("fire")
|
||||
carl.apply_damage(2, "fire", magical=True)
|
||||
assert carl.vulnerable(DamageType.fire)
|
||||
assert not carl.immune(DamageType.fire)
|
||||
carl.apply_damage(2, DamageType.fire)
|
||||
assert carl.hit_points == 4 # double damage
|
||||
|
||||
absorbs = [
|
||||
schema.Modifier("Absorbs Non-Magical Fire", target="defenses.fire", new_value="absorbs"),
|
||||
]
|
||||
absorbs = [schema.Modifier("Absorbs Non-Magical Fire", target=DamageType.fire, new_value=Defenses.absorbs)]
|
||||
carl.add_modifier(absorbs[0])
|
||||
carl.apply_damage(20, "fire", magical=False)
|
||||
carl.apply_damage(20, DamageType.fire)
|
||||
assert carl.hit_points == carl._max_hit_points == 10
|
||||
|
||||
for i in immunity + vulnerability + absorbs:
|
||||
carl.remove_modifier(i)
|
||||
carl.apply_damage(5, "fire", magical=True)
|
||||
assert carl.resistant("fire")
|
||||
assert not carl.immune("fire")
|
||||
assert not carl.vulnerable("fire")
|
||||
assert not carl.absorbs("fire")
|
||||
carl.apply_damage(5, DamageType.fire)
|
||||
assert carl.resistant(DamageType.fire)
|
||||
assert not carl.immune(DamageType.fire)
|
||||
assert not carl.vulnerable(DamageType.fire)
|
||||
assert not carl.absorbs(DamageType.fire)
|
||||
assert carl.hit_points == 8 # half damage
|
||||
|
|
Loading…
Reference in New Issue
Block a user