def get_opposed_chance(protagonist: Creature, pro_contest: Contest, antagonist: Creature, ant_contest: Contest = None, modifier: int = 0): ant_contest = ant_contest or pro_contest pro_level = protagonist.get_skill_level(pro_contest) pro_mod = pro_contest.get_attribute_modifier(protagonist) + pro_contest.get_skill_modifier(pro_level) ant_level = antagonist.get_skill_level(ant_contest) ant_mod = ant_contest.get_attribute_modifier(antagonist) + ant_contest.get_skill_modifier(ant_level) target = ant_mod - pro_mod - modifier roll_table = get_opposed_roll_table(pro_level.bonus_dice, ant_level.bonus_dice) return sum(p for result, p in roll_table.items() if result > target)
def get_range_change_desire(self, opponent: Creature, from_range: MeleeRange, to_range: MeleeRange) -> float: """-1.0 to 1.0 scale rating how favorable the given range change is""" range_scores = self.get_melee_range_priority(opponent) from_score = range_scores.get(from_range, 0) to_score = range_scores.get(to_range, 0) if from_score == 0: return 1.0 modifier = ChangeMeleeRangeAction.get_contest_modifier(self.parent) - ChangeMeleeRangeAction.get_contest_modifier(opponent) success_chance = Contest.get_opposed_chance(self.parent, SKILL_EVADE, opponent, SKILL_EVADE, modifier.contest) score = min(max(-1.0, (to_score/from_score - 1.0) * success_chance), 1.0) # account for possible attack of opportunity if score > 0 and from_range > to_range and can_interrupt_action(opponent): attack_ranges = list(MeleeRange.between(from_range, to_range)) attacks = (attack for attack in opponent.get_melee_attacks() if any(attack.can_attack(r) for r in attack_ranges)) attack = max(attacks, key=lambda a: opponent.get_skill_level(a.combat_test), default=None) safety = 1.0 - Contest.get_opposed_chance(opponent, attack.combat_test, self.parent, SKILL_EVADE) if attack is not None: return min(score, safety**2) return score
def get_melee_attack_value(attack: MeleeAttack, attacker: Creature, target: Creature) -> float: expected_damage = get_expected_damage(attack, target) skill_factor = SKILL_FACTOR[attacker.get_skill_level(attack.combat_test)] return expected_damage * skill_factor
def get_attack_value(creature: Creature, attack: MeleeAttackTemplate) -> float: return attack.damage.mean() * SKILL_FACTOR[creature.get_skill_level(attack.combat_test)]
def get_success_chance(self, protagonist: Creature, target: int) -> float: skill_level = protagonist.get_skill_level(self) target -= self.get_attribute_modifier(protagonist) + self.get_skill_modifier(skill_level) roll_table = get_roll_table(skill_level.bonus_dice) return sum(p for roll, p in roll_table.items() if roll > target)
def __init__(self, protagonist: Creature, contest: Contest, modifier: ContestModifier = ContestModifier()): self.contest = contest self.protagonist = protagonist self.skill_level = protagonist.get_skill_level(contest) self.modifier = modifier self.reroll()