diff options
| author | Supremist <sergkarv@gmail.com> | 2025-10-29 20:58:42 +0200 |
|---|---|---|
| committer | Supremist <sergkarv@gmail.com> | 2025-10-29 20:58:42 +0200 |
| commit | 0ada03ebf6a879e0a77475d525141d1090bcd634 (patch) | |
| tree | c236288c623f3a2c59fd682784e014faab120c61 /character.py | |
| parent | c29738661837749c72e3743c71814703cd11e062 (diff) | |
| download | pf2e_calc-0ada03ebf6a879e0a77475d525141d1090bcd634.tar.xz pf2e_calc-0ada03ebf6a879e0a77475d525141d1090bcd634.zip | |
Track bonuses and penalties from conditions
Diffstat (limited to 'character.py')
| -rw-r--r-- | character.py | 105 |
1 files changed, 65 insertions, 40 deletions
diff --git a/character.py b/character.py index 75329ed..2a306f9 100644 --- a/character.py +++ b/character.py @@ -1,36 +1,10 @@ import re import json +import copy from dataclasses import dataclass, asdict -from items import Armor -from game import LevelingPlan - - -_skill_ability = { -# "classDC" - "perception": "wis", - "fortitude": "con", - "reflex": "dex", - "will": "wis", - "acrobatics": "dex", - "arcana": "int", - "athletics": "str", - "crafting": "int", - "deception": "cha", - "diplomacy": "cha", - "intimidation": "cha", - "medicine": "wis", - "nature": "wis", - "occultism": "int", - "performance": "cha", - "religion": "wis", - "society": "int", - "stealth": "dex", - "survival": "wis", - "thievery": "dex", - "lore1": "int", - "lore2": "int" -} +from items import Armor, Weapon +from game import LevelingPlan, Features, Modifier, Conditions class FeaturesPlan(LevelingPlan, dict): @@ -58,10 +32,9 @@ class FeaturesPlan(LevelingPlan, dict): class Abilities(dict): - field_names = ["str", "dex", "int", "wis", "cha", "con"] def __init__(self, data=None, **kwargs): - super().__init__({field: 10 for field in Abilities.field_names}) + super().__init__({field: 10 for field in Features.abilities}) if data: self.update(data) if kwargs: @@ -123,6 +96,7 @@ class Character: abilities: Abilities features: dict armor: Armor + conditions: Conditions def __init__(self, data): self.data = data @@ -132,7 +106,9 @@ class Character: self.level = 1 self.abilities = Abilities() self.features = dict() - self.armor = Armor("Leather armor", "light", 1) + self.armor = Armor("Unarmored", "light", 0) + self.weapons = [Weapon("Fist", "unarmed", "brawling", 4)] + self.conditions = Conditions() def max_hp(self): per_level = self.hp_per_level + self.abilities.modifier("con") @@ -141,25 +117,62 @@ class Character: def skill_ability(self, skill): if skill == "classDC": return self.data["keyability"] - return _skill_ability.get(skill) + return Features.skill_ability.get(skill) + + def ability_modifier(self, ability): + return self.conditions.modifier([ability]) + self.abilities.modifier(ability) def proficiency_bonus(self, skill): - return self.features.get(skill, 0) + self.level + bonus = self.features.get(skill, 0) + if bonus == 0: + return 0 + return bonus + self.level def proficiency(self, skill): - # TODO + item bonuses - ability = self.skill_ability(skill) - ability = self.abilities.modifier(ability) if ability else 0 - return ability + self.proficiency_bonus(skill) + ability_name = self.skill_ability(skill) + res = Modifier() + if ability_name: + res += self.ability_modifier(ability_name) + res += self.proficiency_bonus(skill) + self.conditions.modifier([skill]) + return res.total() def ac(self): - dex_bonus = min(self.armor.dex_cap, self.abilities.modifier("dex")) + dex_mod = self.conditions.modifier(["dex"], exclude=["ac"]) + dex_mod += self.abilities.modifier("dex") + dex_bonus = min(self.armor.dex_cap, dex_mod.total()) prof = self.proficiency(self.armor.category) - return 10 + dex_bonus + prof + self.armor.ac + armor = Modifier(item=self.armor.ac+self.armor.potency) + armor += self.conditions.modifier(["ac"]) + return (10 + dex_bonus + prof + armor).total() def classDC(self): return 10 + self.proficiency("classDC") + def update_fundamental_runes(self): + try: + self.armor.potency = self.features["armor potency"] + self.armor.resilient = self.features["resilient"] + except KeyError: + pass + try: + for weapon in self.weapons: + weapon.potency = self.features["weapon potency"] + weapon.striking = self.features["striking"] + except KeyError: + pass + + def attack_bonus(self, weapon: Weapon, strike_type="melee"): + dex = self.ability_modifier("dex").total() + mod = self.ability_modifier("str").total() + if strike_type == "melee": + if weapon.finesse: + mod = max(mod, dex) + elif strike_type == "ranged": + mod = dex + prof = max(self.features.get(weapon.category, 0), + self.features.get(weapon.name, 0)) + return mod + prof + weapon.potency + def toJSON(self): methods = ["classDC", "max_hp", "ac"] obj = asdict(self) @@ -168,6 +181,18 @@ class Character: return json.dumps(obj, indent=2) +class Attack: + attacker = None + target = None + previous_attacks = 0 + distance = 0 + # def map(self, previous_attacks): + # factor = max(0, min(2, previous_attacks)) + # if self.agile: + # return factor * -4 + # return factor * -5 + + class CharacterPlan(LevelingPlan): def __init__(self, data) -> None: self.data = data |
