From 68251ff4e9408e22451dd91592c7e4cb68dd7585 Mon Sep 17 00:00:00 2001 From: evilchili Date: Sun, 30 Jun 2024 16:09:20 -0700 Subject: [PATCH] fix tests --- pyproject.toml | 2 +- src/ttfrog/db/schema/__init__.py | 1 + src/ttfrog/db/schema/character.py | 49 ++++++++++++++++++------------- test/conftest.py | 7 ++--- test/test_schema.py | 47 +++++++++++++++-------------- 5 files changed, 59 insertions(+), 47 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3d2adc9..8ef55e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" diff --git a/src/ttfrog/db/schema/__init__.py b/src/ttfrog/db/schema/__init__.py index 8abc119..d68feda 100644 --- a/src/ttfrog/db/schema/__init__.py +++ b/src/ttfrog/db/schema/__init__.py @@ -1,5 +1,6 @@ from .character import * from .classes import * +from .constants import * from .log import * from .modifiers import * from .skill import * diff --git a/src/ttfrog/db/schema/character.py b/src/ttfrog/db/schema/character.py index 2d707d6..017ec6a 100644 --- a/src/ttfrog/db/schema/character.py +++ b/src/ttfrog/db/schema/character.py @@ -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: diff --git a/test/conftest.py b/test/conftest.py index 489e592..ef4bf08 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -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) diff --git a/test/test_schema.py b/test/test_schema.py index 721dab0..54ee099 100644 --- a/test/test_schema.py +++ b/test/test_schema.py @@ -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