def dharok_attack(self, other: NPC) -> DamageData: """Returns a distribution of scythe damage and probability values""" dharok_set = [ "dharok's greataxe", "dharok's helm", "dharok's platebody", "dharok's platelegs" ] assert self.wearing(dharok_set) self.hitpoints_current = 1 max_hit_scale_factor = 1 + ( (self.hitpoints - self.hitpoints_current) / 100 * (self.hitpoints / 100)) attack_roll_modifier, damage_modifier = (1, max_hit_scale_factor) damage_type_defence_roll = self.style.damage_type attack_roll = self.player_maximum_attack_roll(other, attack_roll_modifier) defence_roll = other.npc_maximum_defence_roll(damage_type_defence_roll) accuracy = cb.accuracy(attack_roll, defence_roll) max_hit = self.player_max_hit(other, damage_modifier) attack_distribution = cb.hit_distribution(max_hit, accuracy) AttackDistribution = DamageData(attack_distribution, self.attack_speed, accuracy) return AttackDistribution
def attack_npc(self, other: NPC, special_attack: bool = False) -> DamageData: """Returns accuracy and max hit against an NPC, special attack assumed to be false by default""" if special_attack: attack_roll_modifier = self.special_accuracy_modifier damage_modifier = [ self.special_damage_modifier_1, self.special_damage_modifier_2 ] damage_type_defence_roll = self.special_defence_roll else: attack_roll_modifier, damage_modifier = (1, 1) damage_type_defence_roll = self.style.damage_type attack_roll = self.player_maximum_attack_roll(other, attack_roll_modifier) defence_roll = other.npc_maximum_defence_roll(damage_type_defence_roll) accuracy = cb.accuracy(attack_roll, defence_roll) max_hit = self.player_max_hit(other, damage_modifier) attack_distribution = cb.hit_distribution(max_hit, accuracy) AttackDistribution = DamageData(attack_distribution, self.attack_speed, accuracy) return AttackDistribution
def scythe_attack(self, other: NPC) -> DamageData: """Returns a distribution of scythe damage and probability values""" assert self.wearing('scythe of vitur') MainAttack = self.attack_npc(other) base_max_hit = MainAttack.max_hit accuracy = MainAttack.accuracy distributions = [MainAttack.damage_distribution] damage_modifiers = [0.5, 0.25] for modifier in damage_modifiers: distributions.append( cb.hit_distribution(math.floor(base_max_hit * modifier), accuracy)) combined_distribution = convolution_list(distributions) ScytheAttack = DamageData(combined_distribution, self.attack_speed, 1 - (1 - accuracy)**len(distributions)) return ScytheAttack
def chinchompa(self, other: NPC, targets: int = 1, distance: int = None) -> DamageData: """Returns a DamageData object representing a chinchompa thrown at many NPCs""" assert isinstance(self.style, RangedStyle) maximum_targets = 11 targets = min([maximum_targets, targets]) if distance: mod_tuple = self.style.distance_modifier_tuple range_tuple = ((0 <= distance <= 3), (4 <= distance <= 6), (7 <= distance)) attack_roll_modifier = float(np.dot(mod_tuple, range_tuple)) else: attack_roll_modifier = 1 damage_modifier = 1 attack_roll = self.player_maximum_attack_roll(other, attack_roll_modifier) defence_roll = other.npc_maximum_defence_roll(cb.ranged) accuracy = cb.accuracy(attack_roll, defence_roll) max_hit = self.player_max_hit(other, damage_modifier) attack_distribution_given_hit = cb.hit_distribution( max_hit, prob_hit=1, num=targets) # all or nothing distr. attack_distribution_modified = {} for key, val in attack_distribution_given_hit.items(): attack_distribution_modified[key] = val * accuracy attack_distribution_modified[0] += 1 - accuracy ChinchompaAttack = DamageData(attack_distribution_modified, self.attack_speed, accuracy) return ChinchompaAttack
def crossbow_distribution(self, other: NPC, style_bonus_attack: int, style_bonus_strength: int, pot_bonus: int, attack_modifier: cb.modifier_types, strength_modifier: cb.modifier_types, bolt_type: str, kandarin_hard_diary: bool = True) -> dict: """TODO: Make this work with the new styleReturns a crossbow damage/probability distribution TODO: implement the other bolts actually""" if bolt_type != 'ruby': raise Exception base_spec_chance, damage_modifier = cb.enchanted_bolts_spec_chance[ bolt_type] spec_chance = base_spec_chance * (1 + kandarin_hard_diary * 0.10) base_acc, base_max = self.attack_npc(other, style_bonus_attack, style_bonus_strength, pot_bonus, "ranged", attack_modifier, strength_modifier) spec_acc, _ = self.attack_npc(other, style_bonus_attack, style_bonus_strength, pot_bonus, "ranged", attack_modifier, strength_modifier, attack_roll_modifier=2) spec_acc = max([1 * (bolt_type == "diamond"), spec_acc]) ranged_visible = self.ranged + pot_bonus # modifies spec_max by flat % or % visible ranged level depending on bolt type spec_max = math.floor( base_max * (1 + damage_modifier * (bolt_type in cb.enchanted_bolts_flat_percent)) + ranged_visible * (bolt_type in cb.enchanted_bolts_percent_visible_ranged_level)) spec_max = (bolt_type != 'ruby') * spec_max + (bolt_type == 'ruby') * min( [math.floor(other.hitpoints_current * 0.20), 100]) base_distribution = cb.hit_distribution(base_max, base_acc) for dmg, prob in base_distribution.items(): base_distribution[dmg] = prob * (1 - spec_chance) spec_distribution = {0: 1 - spec_acc, spec_max: spec_acc} for dmg, prob in spec_distribution.items(): if dmg in base_distribution: base_distribution[dmg] += prob * spec_chance else: base_distribution[dmg] = prob * spec_chance prob_sum = sum(base_distribution.values()) assert math.fabs(prob_sum - 1) < 1e10 return base_distribution