def damage_roll(pc, power, attack_type=None): melee_weapon = pc.get_melee_weapon(equipped=False) ranged_weapon = pc.get_ranged_weapon(equipped=False) implement = pc.get_equipped_implement() if attack_type is None: attack_type = power.attack_types[0] damage_modifier = power.damage_modifier if damage_modifier == abilities.dexterity and \ power == powers.ranged_basic_attack and \ attack_type == powers.ranged_weapon and \ ranged_weapon is not None and \ ranged_weapon.range_type == weapons.melee_range_type and \ weapons.heavy_thrown_property in ranged_weapon.properties: damage_modifier = abilities.strength if isinstance(damage_modifier, dict): damage_modifier = damage_modifier[attack_type] weapon = melee_weapon weapon = ranged_weapon if attack_type.range_type in ( powers.ranged_range_type, powers.area_range_type ) else weapon value = '' damage_multiplier = power.damage_multiplier(pc) if keywords.weapon in power.keywords and power.damage_dice == dice.weapon: if weapon is None: return None damage_multiplier *= weapon.damage_multiplier if damage_multiplier > 0: value = str(damage_multiplier) if keywords.weapon in power.keywords and power.damage_dice == dice.weapon: if weapon is None: return None damage_dice = weapon.damage_dice if pc.dnd_class == classes.rogue and weapon == weapons.shuriken: damage_dice = dice.larger_dice(damage_dice) value += str(damage_dice) if power.damage_dice is not None and power.damage_dice != dice.weapon: value += str(power.damage_dice) if power.bonus_damage_dice is not None: for d in power.bonus_damage_dice: value += ' + ' + str(power.bonus_damage_dice[d](pc)) + str(d) mod_value = 0 if damage_modifier is not None: if isinstance(damage_modifier, tuple): for mod in damage_modifier: mod_value += calc.mod(pc.ability_value(mod)) else: mod_value += calc.mod(pc.ability_value(damage_modifier)) if keywords.weapon in power.keywords: if weapon is not None: if weapon.magical_bonus > 0: mod_value += weapon.magical_bonus # feat bonus feat_bonus = 0 for feat in pc.known_feats: if isinstance(feat, feats.WeaponFocus) and pc.check_feat(feat): weapon = pc.get_melee_weapon(equipped=False) if attack_type == powers.ranged_weapon: weapon = pc.get_ranged_weapon(equipped=False) if feat.weapon_group in weapon.weapon_groups: feat_bonus = max(feat_bonus, (pc.level + 9) // 10) if feat == feats.goliath_greatweapon_prowess and pc.check_feat(feat): weapon = pc.get_melee_weapon(equipped=False) if weapon.category in (weapons.simple_weapon_category, weapons.military_weapon_category) and \ weapon.hands == 2: feat_bonus = max(feat_bonus, 1 + (pc.level + 9) // 10) if feat == feats.dwarven_weapon_training and pc.check_feat(feat): weapon = pc.get_melee_weapon(equipped=False) if weapons.axe_group in weapon.weapon_groups or weapons.hammer_group in weapon.weapon_groups: feat_bonus = max(feat_bonus, 2) if pc.check_feat(feats.astral_fire): if keywords.fire in power.keywords or keywords.radiant in power.keywords: feat_bonus = max(feat_bonus, (pc.level + 9) // 10) if pc.check_feat(feats.raging_storm): if keywords.lightning in power.keywords or keywords.thunder in power.keywords: feat_bonus = max(feat_bonus, (pc.level + 9) // 10) mod_value += feat_bonus if keywords.implement in power.keywords and implement is not None: if pc.is_proficient_in(implement): mod_value += implement.magical_bonus # other bonuses if pc.check_feat(feats.hellfire_blood) and (keywords.fire in power.keywords or keywords.fear in power.keywords): mod_value += 1 if mod_value > 0 and len(value) > 0: value += ' + ' + str(mod_value) return value
def print_pc_info(pc): print("=======================================") print() print(" *** " + pc.name) print() print("{:<19s}{:s}".format("раса:", str(pc.race))) print("{:<19s}{:s}".format("класс:", str(pc.dnd_class))) print("{:<19s}{:s}".format("уровень:", str(pc.level))) print("{:<19s}{:s}".format("xp:", str(pc.xp))) print() print("{:<19s}{:s}".format("пол:", str(pc.gender))) print("{:<19s}{:s}".format("возраст:", str(pc.age))) print("{:<19s}{:s}".format("рост:", str(pc.height))) print("{:<19s}{:s}".format("вес:", str(pc.weight))) print("{:<19s}{:s}".format("мировоззрение:", str(pc.alignment))) print("{:<19s}{:s}".format("божество:", str(pc.god))) print() print("{:<19s}{:s}".format("скорость:", str(pc.speed_value()))) print("{:<19s}{:s}".format("инициатива:", str(pc.initiative_value()))) print("{:<19s}{:s}".format("хитпоинты:", str(pc.max_hitpoints_value()))) print("{:<19s}{:s}".format("раненый:", str(pc.bloodied_value()))) print("{:<19s}{:s}".format("исцеление на:", str(pc.healing_surge_value()))) print("{:<19s}{:s}".format("исцелений в день:", str(pc.healing_surges_number_value()))) print("{:<19s}{:s}".format("языки:", str(pc.languages))) print("{:<19s}{:s}".format("черты:", str(pc.known_feats))) print() print("инвентарь: {") total_worth = 0 total_weight = 0 for money in lists.list_money(): if money in pc.equipment: total_worth += money.price * pc.equipment[money] total_weight += money.weight * pc.equipment[money] print(" {:s}: {:d}".format(str(money), pc.equipment[money])) print() for item in sorted(pc.equipment): if not isinstance(item, items.Money): if isinstance(item, common.Priceable): if item.price >= 0: total_worth += item.price * pc.equipment[item] total_weight += item.weight * pc.equipment[item] print(" {:s}: {:d}".format(str(item), pc.equipment[item])) print("}") print("надето: {") for part in sorted(characters.body_parts): if pc.equipped_items[part]: print( " " + str(part) + ": " + str(pc.equipped_items[part]) + " (" + ("есть опыт" if pc.is_proficient_in(pc.equipped_items[part]) else "нет опыта") + ")" ) print("}") print() print("оружие наготове:") if pc.get_melee_weapon(equipped=True) is not None: print("{:<19s}{:s}".format("рукопашное:", str(pc.get_melee_weapon(equipped=True)))) elif pc.get_melee_weapon(equipped=False) is not None: print("{:<19s}{:s}".format("рукопашное:", str(pc.get_melee_weapon(equipped=False)) + " (не экипировано)")) else: print("{:<19s}{:s}".format("рукопашное:", "None")) if pc.get_ranged_weapon(equipped=True) is not None: print("{:<19s}{:s}".format("дальнобойное:", str(pc.get_ranged_weapon(equipped=True)))) elif pc.get_ranged_weapon(equipped=False) is not None: print("{:<19s}{:s}".format("дальнобойное:", str(pc.get_ranged_weapon(equipped=False)) + " (не экипировано)")) else: print("{:<19s}{:s}".format("дальнобойное:", "None")) print("{:<19s}{:s}".format("инструмент:", str(pc.get_equipped_implement()))) print() print("общая ценность инвентаря: " + "{:.2f}".format(total_worth)) print("общий вес инвентаря: " + "{:.2f}".format(total_weight)) print() for ability in lists.list_abilities(): print( "{:14s} {:>4d} {:>+4d}".format(ability.name, pc.ability_value(ability), calc.mod(pc.ability_value(ability))) ) print() for defence in lists.list_defences(): print("{:14s} {:>4d}".format(defence.name, pc.defence_value(defence))) print() for skill in lists.list_skills(): print( "{:<16s} {:>2d}{:<s}".format( skill.name, pc.skill_value(skill), " (тренирован)" if skill in pc.trained_skills else "" ) ) print() print("таланты (" + str(powers.at_will_frequency) + "):") for power in pc.get_at_will_powers(): print_power_info(power, pc) print() print("таланты (" + str(powers.encounter_frequency) + "):") for power in pc.get_encounter_powers(): print_power_info(power, pc) print() print("таланты (" + str(powers.daily_frequency) + "):") for power in pc.get_daily_powers(): print_power_info(power, pc) print()
def attack_roll(pc, power, attack_type=None): if power.ability is None: return None melee_weapon = pc.get_melee_weapon(equipped=False) ranged_weapon = pc.get_ranged_weapon(equipped=False) implement = pc.get_equipped_implement() if attack_type is None: attack_type = power.attack_types[0] ability = power.ability if ability == abilities.dexterity and \ power == powers.ranged_basic_attack and \ attack_type == powers.ranged_weapon and \ ranged_weapon is not None and \ ranged_weapon.range_type == weapons.melee_range_type and \ weapons.heavy_thrown_property in ranged_weapon.properties: ability = abilities.strength if isinstance(ability, dict): ability = ability[attack_type] value = pc.level // 2 + calc.mod(pc.ability_value(ability)) if power.ability_modifier: value += power.ability_modifier(pc) weapon = melee_weapon weapon = ranged_weapon if attack_type.range_type in ( powers.ranged_range_type, powers.area_range_type ) else weapon if keywords.weapon in power.keywords: if weapon is None: return None if pc.is_proficient_in(weapon): value += weapon.proficiency_bonus if pc.dnd_class == classes.fighter and pc.fighter_weapon_talent_type == weapon.hands: value += 1 if pc.dnd_class == classes.rogue and weapon == weapons.dagger: value += 1 if weapon.magical_bonus > 0: value += weapon.magical_bonus if keywords.implement in power.keywords and implement is not None: if pc.is_proficient_in(implement): value += implement.magical_bonus # feat bonus feat_bonus = 0 for feat in pc.known_feats: if isinstance(feat, feats.WeaponExpertise) and pc.check_feat(feat): weapon = pc.get_melee_weapon(equipped=False) if attack_type == powers.ranged_weapon: weapon = pc.get_ranged_weapon(equipped=False) if feat.weapon_group in weapon.weapon_groups: feat_bonus = max(feat_bonus, 1 if pc.level < 11 else (2 if pc.level < 21 else 3)) if isinstance(feat, feats.ImplementExpertise): if keywords.implement in power.keywords and implement is not None \ and isinstance(implement, feat.implement_type.__class__): feat_bonus = max(feat_bonus, 1 if pc.level < 11 else (2 if pc.level < 21 else 3)) value += feat_bonus # racial bonus # dragonborn fury if pc.race == races.dragonborn: value += 1 if pc.current_hitpoints <= pc.bloodied_value() else 0 # other bonuses if pc.check_feat(feats.hellfire_blood) and (keywords.fire in power.keywords or keywords.fear in power.keywords): value += 1 return "1к20 + " + str(value)