From 6cdeabcfc131a2b21599b3fa5980a4ecb59539bd Mon Sep 17 00:00:00 2001 From: Supremist Date: Thu, 30 Oct 2025 15:31:17 +0200 Subject: Test Demoralize --- main.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 27 deletions(-) (limited to 'main.py') diff --git a/main.py b/main.py index 0a25394..65c9c45 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ import math from character import CharacterPlan +from distribution import Distribution from game import Difficulty, Roll, d from creature import CreaturePlan from actions import Attack @@ -24,13 +25,6 @@ def treat_wounds(check_res, heal_bonus=0): if check_res == Roll.Crit: return 4*d(8) + heal_bonus -def strike(check_res, dmg, crit_dmg=0): - if check_res == Roll.Success: - return dmg - if check_res == Roll.Crit: - return 2*dmg + crit_dmg - return 0 - def show_stat(name, dist): print(name) @@ -67,26 +61,88 @@ def main(): treat = d(20).apply(Roll.check, 20, bonus+1).apply(treat_wounds, 15) show_stat("Treat Wounds 20 +1", treat) - -def test3(): - # char_js = pb2e.download_character(pfb_id=160180) - char_js = pb2e.open_character("quizrel2") - char_plan = CharacterPlan(char_js) - creature_plan = CreaturePlan(default_difficulty=Difficulty.Moderate) - # creature_plan["reflex"] = Difficulty.High - # creature_plan["ac"] = Difficulty.High - - def calc_damage(level): - char = char_plan.build(level) - creature = creature_plan.build(level) - creature["ac"] -= 2 +class StatsTest: + def __init__(self) -> None: + # self.char_js = pb2e.download_character(pfb_id=160180) + self.char_js = pb2e.open_character("quizrel2") + self.char_plan = CharacterPlan(self.char_js) + self.creature_plan = CreaturePlan(default_difficulty=Difficulty.Moderate) + # self.creature_plan["reflex"] = Difficulty.High + # self.creature_plan["ac"] = Difficulty.High + self.char = self.char_plan.build(1) + + def add_weapons(self): falcata = Weapon("falcata", "martial", "sword", 8, fatal=12) - sword = Weapon("sword", "martial", "sword", 8) + sword = Weapon("pick", "martial", "pick", 6, fatal=10) rapier = Weapon("rapier", "martial", "sword", 6, finesse=True, deadly=8) - sword2 = Weapon("sword_d6", "martial", "sword", 6) - char.weapons = [falcata, sword, rapier, sword2] - char.update_fundamental_runes() + urumi = Weapon("urumi", "martial", "flail", 6, deadly=10) + sword2 = Weapon("tricky pick", "martial", "pick", 6, fatal=10, backstabber=True) + self.char.weapons.extend([sword, falcata, rapier, sword2, urumi]) + + def get_weapon(self, name): + for wp in self.char.weapons: + if wp.name == name: + return wp + raise KeyError + + def set_level(self, level): + self.char = self.char_plan.build(level) + self.creature = self.creature_plan.build(level) + self.add_weapons() + self.char.update_fundamental_runes() + +def test4(): + t = StatsTest() + t.set_level(5) + urumi = t.get_weapon("urumi") + attack = Attack(t.char, t.creature, urumi) + print("Attack: ", Roll.short_str(attack.roll())) + print(f"Attack +{attack.bonus()} vs AC {attack.target.ac()} dmg +{attack.damage_bonus()}") + crit_chance = attack.roll().probabilities[Roll.Crit] + print(t.char.classDC() , t.creature["reflex"]) + prone_save = d(20).apply(Roll.check, t.char.classDC(), t.creature["reflex"]) + print("Prone save: ", Roll.short_str(prone_save)) + prone_chace = prone_save.accumulate_prob(lambda x: x <= Roll.Fail) + print(f"Crit: {crit_chance}; Prone: {prone_chace}; Total Prone Chance: {crit_chance*prone_chace}") + +def make_check(name, bonus, dc): + roll = d(20).apply2(lambda v, bonus: Roll.check(v, dc, bonus), bonus) + if isinstance(bonus, Distribution): + bonus = bonus.expected() + print(f"{name} {bonus:+} vs DC {dc}:", + Roll.short_str(roll), f"Total: {dc-bonus-10:+}") + return roll + +def demoralize_test(): + def bon_mot_pen(check): + if check == Roll.Success: + return -2 + if check == Roll.Crit: + return -3 + return 0 + t = StatsTest() + t.creature_plan["will"] = Difficulty.Moderate + t.set_level(5) + t.char.features["diplomacy"] = 2 + t.char.features["intimidation"] = 4 + intimid_bonus = t.char.proficiency("intimidation") + 1 + will_dc = 10+t.creature["will"] + roll = make_check("Demoralize", intimid_bonus, will_dc) + frightened = roll.apply(lambda x: x if x >= Roll.Success else 0).expected() + print("Frightened:", frightened) + + bon_mot = make_check("Bon mot", t.char.proficiency("diplomacy"), will_dc) + penalty = bon_mot.apply(bon_mot_pen) + print("Bon Mot Penalty:", penalty.expected()) + + roll = make_check("Demoralize2", -penalty+intimid_bonus, will_dc) + frightened = roll.apply(lambda x: x if x >= Roll.Success else 0).expected() + print("Frightened:", frightened) +def test3(): + t = StatsTest() + def calc_damage(level): + t.set_level(level) # print(char.toJSON()) # attack = Attack(char, creature, falcata) # print(Roll.short_str(attack.roll())) @@ -95,8 +151,8 @@ def test3(): # show_stat("falcata", attack.strike()) res = dict() - for weapon in char.weapons: - attack = Attack(char, creature, weapon) + for weapon in t.char.weapons: + attack = Attack(t.char, t.creature, weapon) res[weapon.name] = attack.strike().expected() # res["hp"] = creature["hp"] return res @@ -136,4 +192,5 @@ def levelup_view(title, ylabel, fn): if __name__ == '__main__': - test3() + # test4() + demoralize_test() -- cgit v1.2.3