class NaturalAttack(MeleeAttack): name = "" on_success = StringBuilder(Attacker, Verb("hit", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "attack,") def can_execute(self, attacker, defender): # Natural attacks should come from the body, in turn it should check for it when used. return True def echo(self, attacker, defender, success, damage, sneak_attack=False): context = contexts.Combat(attacker, defender) if success: if sneak_attack: message = self.on_stealth + "for {} damage!".format(damage) else: message = self.on_success + "for {} damage!".format(damage) else: message = self.on_failure self.game.echo.see(attacker, message, context) def execute(self, attacker, defender, attack_set): sneak_attack = False if attacker.query.special_ability(specialabilities.SneakAttack): if not defender.vision.can_see_object(attacker): sneak_attack = True attacker.events.transmit(events.Attacking(attacker)) hits = 0 for _ in range(0, attack_set.amount): success = self.make_melee_hit_roll(attacker, defender, sneak_attack=sneak_attack) if success: hits += 1 base_attack = attack_set.attack damage = self.make_melee_damage_roll( attacker, base_attack.damage_dice, base_attack.damage_bonus, sneak_attack=sneak_attack ) self.echo(attacker, defender, True, damage, sneak_attack=sneak_attack) defender_health = defender.health if defender_health: defender_health.take_damage(damage, attacker) else: self.echo(attacker, defender, False, 0) return True
def add(self, item): if self.host.equipment: containers = (item.container for item in self.host.equipment.get_all_items() if item.container) for container in containers: if container.add_item(item): message = StringBuilder(Actor, Verb("add", Actor), TargetOne, "to", His(Actor), TargetTwo) context = contexts.TwoTargetAction(self.host, item, container.host) self.host.game.echo.see(self.host, message, context) return True return False
def execute(self, attacker, defender, fired_weapons, distance, compatible_ammo): attacker.events.transmit(events.Attacking(attacker)) for fired_weapon in fired_weapons: ammunition_spent = self.consume_ammunition(attacker, fired_weapon, compatible_ammo) context = contexts.RangedCombat(attacker, defender, fired_weapon, ammunition_spent) message = StringBuilder( Attacker, Verb("fire", Attacker), His(Attacker), AttackerWeapon, "at", Defender ) if self.make_hit_roll(attacker, defender, fired_weapon, distance): damage = self.make_damage_roll(ammunition_spent) message += "hitting for %s damage!" % damage self.game.echo.see(attacker, message, context) defender.health.take_damage(damage, attacker) else: # TODO This message here could be better. message += "missing the shot!" self.game.echo.see(attacker, message, context) return True
class Gaze(NaturalAttack): name = "gaze" base_attack = attacks.Gaze on_success = StringBuilder(Attacker, Verb("gaze", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "gaze,")
class Crush(NaturalAttack): name = "crush" base_attack = attacks.Crush on_success = StringBuilder(Attacker, Verb("crush", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "crushing attack,")
class ConfusionBySwarm(NaturalAttack): name = "Confusion By Swarm" base_attack = attacks.ConfusionBySwarm on_success = StringBuilder(Attacker, Verb("confuse", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "confusing attack,")
class Kick(NaturalAttack): name = "kick" base_attack = attacks.Kick on_success = StringBuilder(Attacker, Verb("kick", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "kick,")
class Punch(NaturalAttack): name = "punch" base_attack = attacks.Punch on_success = StringBuilder(Attacker, Verb("punch", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "punch,")
class Sting(NaturalAttack): name = "sting" base_attack = attacks.Sting on_success = StringBuilder(Attacker, Verb("sting", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "sting,")
class Hoof(NaturalAttack): name = "hoof" base_attack = attacks.Hoof on_success = StringBuilder(Attacker, Verb("hoof", Attacker), Defender) on_failure = StringBuilder(Defender, Verb("dodge", Defender), His(Attacker), "attack!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "hoof,")
class WeaponAttack(MeleeAttack): name = "weapon" base_attack = attacks.WeaponAttack on_success = StringBuilder(Attacker, Verb("hit", Attacker), Defender, "with", His(Attacker), AttackerWeapon) on_failure = StringBuilder(Attacker, Verb("miss", Attacker), Defender, "!") on_stealth = StringBuilder(Attacker, Verb("surprise", Attacker), Defender, "with", His(Attacker), "attack,") def can_execute(self, attacker, defender): if attacker.equipment.get_wielded_items(): return True return False def execute(self, attacker, defender, attack_set): sneak_attack = False sorted_melee_weapons = self._sort_melee_weapons_by_damage(attacker) if attacker.query.special_ability(specialabilities.SneakAttack): if not defender.vision.can_see_object(attacker): sneak_attack = True attacker.events.transmit(events.Attacking(attacker)) for _ in range(attack_set.amount): if sorted_melee_weapons: weapon = sorted_melee_weapons.pop() damage_dice = weapon.melee.melee_damage else: improvised_weapons = self._get_improvised_weapons(attacker) if not improvised_weapons: return True weapon = improvised_weapons.pop() damage_dice = D4(1) success = self.make_melee_hit_roll(attacker, defender, sneak_attack=sneak_attack) if success: damage = self.make_melee_damage_roll(attacker, damage_dice, sneak_attack=sneak_attack) self.echo(attacker, defender, weapon, True, damage, sneak_attack=sneak_attack) if defender.health: defender.health.take_damage(damage, attacker) else: self.echo(attacker, defender, weapon, False, 0, sneak_attack=sneak_attack) return True @staticmethod def _sort_melee_weapons_by_damage(attacker): melee_weapons = [ weapon for weapon in attacker.equipment.get_wielded_items() if weapon.melee ] melee_weapons.sort(key=lambda item: item.melee.melee_damage.sides * item.melee.melee_damage.amount) return melee_weapons @staticmethod def _get_improvised_weapons(attacker): return [weapon for weapon in attacker.equipment.get_wielded_items()] def echo(self, attacker, defender, weapon, success, damage, sneak_attack=False): # TODO I want to have a nice combat message system, I'll think about it. # TODO For now, this poor message. context = contexts.WeaponCombat(attacker, defender, weapon) if success: if sneak_attack: message = self.on_stealth + "for {} damage!".format(damage) else: message = self.on_success + "for {} damage!".format(damage) else: message = self.on_failure self.game.echo.see(attacker, message, context)