BLEED_STATUS_DESCRIPTION = StatusDescription("Bleed", GraphicChar(None, colors.RED, icon.DROP_ICON), "You will take damage each turn you do not rest.") LIFE_STEAL_STATUS_DESCRIPTION = StatusDescription("Life Steal", GraphicChar(None, colors.RED, icon.LIFE_STEAL_ICON), "When an enemy dies within sight you will heal one point of health.") class StunnedActor(Actor):
    """
    Entities with this actor will do nothing.
    """
    def __init__(self):
        super(StunnedActor, self).__init__()

    def on_tick(self, time):
        if self.parent.has("status_bar"):
            self.parent.status_bar.add(Status.STUNNED_STATUS_DESCRIPTION)

    def act(self):
        """
        Just returns energy spent, shows it's stunned.
        """
        self.parent.char_printer.append_fg_color_blink_frames([colors.CHAMPAGNE])
        return gametime.single_turn class DamageType(Flag):
    """
    Component which only has a component type. Composites with this component has this flag.
    """

    def __init__(self, damage_type):
        super(DamageType, self).__init__(damage_type)
        self.tags = Tags.DAMAGE_TYPE class DamageTypes(object):
    PHYSICAL = "physical_damage_type"
    MAGIC = "magic_damage_type"
    BLUNT = "blunt_damage_type"
    PIERCING = "piercing_damage_type"
    CUTTING = "cutting_damage_type"
    BLEED = "bleed_damage_type"
    ACID = "acid_damage_type"
    POISON = "poison_damage_type"
    LIGHTNING = "lightning_damage_type"
    FIRE = "fire_damage_type"
    REFLECT = "reflect_damage_type"

    IGNORE_ARMOR = "ignore_armor_damage_type"

    FALL = "fall_damage_type" class PoisonEntityEffectFactory(object):
    def __init__(self, source_entity, total_damage, turn_interval, turns_to_live):
        self.source_entity = source_entity
        self.total_damage = total_damage
        self.turn_interval = turn_interval
        self.turns_to_live = turns_to_live

    def __call__(self):
        damage_per_turn = self.total_damage / (self.turns_to_live / self.turn_interval)
        return DamageOverTimeEffect(self.source_entity, damage_per_turn, [DamageTypes.POISON],
                                    self.turn_interval, self.turns_to_live,
                                    messenger.POISON_MESSAGE, POISON_STATUS_DESCRIPTION, meld_id="poison") class AddEffectToOtherSeenEntities(Leaf):
    """
    Adds effects to seen entities other than self.
    """

    def __init__(self, effect_factory, ttl=1):
        super(AddEffectToOtherSeenEntities, self).__init__()
        self.component_type = "add_effect_to_other_seen_entities_" + str(effect_factory)
        self.effect_factory = effect_factory
        self.ttl = ttl

    def before_tick(self, time):
        seen_entities = self.parent.vision.get_seen_entities()
        for entity in seen_entities:
            if not entity is self.parent:
                entity.effect_queue.add(AddSpoofChild(self.parent, self.effect_factory(), self.ttl)) class HealAnEntityOnDeath(Leaf):
    """
    Will Heal an entity when parent has died.
    """

    def __init__(self, source_entity):
        super(HealAnEntityOnDeath, self).__init__()
        self.component_type = "heal_entity_on_death"
        self.source_entity = source_entity
        self.target_entity = source_entity

    def on_tick(self, time):
        if self.parent.health.is_dead():
            self.target_entity.health_modifier.heal(1) class Leaf(Component):
    """
    Abstract leaf class of composite design pattern.

    Component classes of leaf type should inherit from this class.
    """

    def __init__(self):
        super(Leaf, self).__init__()

    def get_relative_of_type(self, component_type):
        return self.parent.get_child_or_ancestor(component_type)

    def has_relative_of_type(self, component_type):
        return self.parent.has_child_or_ancestor(component_type) class RandomStepper(Stepper):
    def __init__(self):
        super(RandomStepper, self).__init__()
        self.component_type = "stepper"

    def try_move_or_bump(self, _):
        new_position = geometry.add_2d(random.choice(direction.DIRECTIONS), self.parent.position.value)
        return super(RandomStepper, self).try_move_or_bump(new_position)

    def before_tick(self, time):
        if self.parent.has("status_bar"):
            self.parent.status_bar.add(Status.STUMBLE_STATUS_DESCRIPTION) class DataTypes:
    CLASS = "job"
    RACE = "race"

    ENERGY = "energy"
    CRIT_MULTIPLIER = "crit_multiplier"
    UNARMED_CRIT_CHANCE = "unarmed_crit_chance"
    CRIT_CHANCE = "crit_chance"
    CRIT_CHANCE_WEAPON = "crit_chance_weapon_effect"
    STRENGTH = "strength"
    ARMOR = "armor"
    ACCURACY = "accuracy"
    DAMAGE = "damage"
    STEALTH = "stealth"
    AWARENESS = "awareness"
    EVASION = "evasion"

    COUNTER_ATTACK_CHANCE = "counter_attack_chance"
    OFFENCIVE_ATTACK_CHANCE = "offencive_attack_chance"
    DEFENCIVE_ATTACK_CHANCE = "defencive_attack_chance"

    MELEE_SPEED = "melee_speed"
    SHOOT_SPEED = "shoot_speed"
    THROW_SPEED = "throw_speed"
    THROW_ITEM_SPEED = "throw_item_speed"
    CAST_SPEED = "cast_speed"

    MELEE_DAMAGE_MULTIPLIER = "melee_damage_multiplier"
    THROW_DAMAGE_MULTIPLIER = "throw_damage_multiplier"

    INTELLIGENCE = "intelligence"
    GAME_PIECE_TYPE = "game_piece_type"
    MOVEMENT_SPEED = "movement_speed"
    FACTION = "faction"

    WEIGHT = "weight"
    WEAPON_RANGE = "weapon_range"

    SIGHT_RADIUS = "sight_radius"
    SKIP_ACTION_CHANCE = "skip_action_chance"

    DENSITY = "density"
    CLOUD_TYPE = "cloud_type"
    CLONE_FUNCTION = "clone_function"

    MINIMUM_DEPTH = "minimum_depth"

    GAME_STATE = "game_state" class DataPointBonusSpoof(Leaf):
    """
    Defines a bonus value, if this is added to an entity as spoof.
    The entity will get that bonus added to the normal value.
    """
    def __init__(self, component_type, bonus_value):
        super(DataPointBonusSpoof, self).__init__()
        self.component_type = component_type
        self.bonus_value = bonus_value

    @property
    def value(self):
        return self.next.value + self.bonus_value

    @value.setter
    def value(self, new_value):
        self.next.value = new_value class DataPoint(Leaf):
    """
    Class for components holding a single data point.
    """
    def __init__(self, component_type, value, tags=[]):
        super(DataPoint, self).__init__()
        self.tags |= set(tags)
        self.component_type = component_type
        self.value = value
import random
import colors
import entityeffect
import gametime
import geometry
import messenger
from Status import BLEED_STATUS_DESCRIPTION, LIFE_STEAL_STATUS_DESCRIPTION
from actor import StunnedActor
from attacker import DamageType, DamageTypes
from compositecommon import PoisonEntityEffectFactory, AddEffectToOtherSeenEntities, HealAnEntityOnDeath
from compositecore import Leaf
from mover import RandomStepper
from stats import DataTypes, DataPointBonusSpoof, DataPoint


class StatBonusEquipEffectWithItemStat(StatBonusEquipEffect):
    def __init__(self, stat, bonus):
        super(StatBonusEquipEffectWithItemStat, self).__init__(stat, bonus)

    def equipped_effect(self, entity):
        """
        Causes the entity that equips this have a bonus to one stat.
        """
        entity.add_spoof_child(DataPointBonusSpoof(self.stat, self.bonus))
        self.parent.add_spoof_child(self._item_stat())
        self._equipped_effect(entity)

    def _equipped_effect(self, entity):
        pass

    def first_tick(self, time):
        self.parent.add_spoof_child(self._item_stat())
        self._first_tick(time)

    def _first_tick(self, time):
        pass

    def _item_stat(self):
        return None


class CounterAttackEffect(StatBonusEquipEffectWithItemStat):
    def __init__(self, effect_chance):
        super(CounterAttackEffect, self).__init__(DataTypes.COUNTER_ATTACK_CHANCE, effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "counter_attack"

    def _item_stat(self):
        return ItemStat(COUNTER_ITEM_STAT_TYPE, self.effect_chance, colors.PURPLE, "Counter",
                        ItemStat.PERCENT_FORMAT, order=30, is_common_stat=False)


class IgnoreArmorAttackEffect(BeforeAttackEffect):
    def __init__(self, effect_chance):
        super(IgnoreArmorAttackEffect, self).__init__(effect_chance)
        self.component_type = "ignore_armor_attack"
        self.tags.add("equipped_effect")

    def before_attack_effect(self, source_entity, target_entity):
        self.parent.add_spoof_child(DamageType(DamageTypes.IGNORE_ARMOR))

    def equipped_effect(self, entity):
        self.parent.add_spoof_child(self._item_stat())

    def _item_stat(self):
        return ItemStat("ignore_armor_weapon_effect", self.effect_chance, colors.BLUE, "Ignore Armor",
                        ItemStat.PERCENT_FORMAT, order=30, is_common_stat=False)


class CritChanceBonusEffect(StatBonusEquipEffectWithItemStat):
    def __init__(self, effect_chance):
        super(CritChanceBonusEffect, self).__init__(DataTypes.CRIT_CHANCE, effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "crit_chance_bonus"

    def _item_stat(self):
        return ItemStat(DataTypes.CRIT_CHANCE_WEAPON, self.effect_chance, colors.RED, "Crit %",
                        ItemStat.PERCENT_FORMAT, order=40, is_common_stat=True)


class OffenciveAttackEffect(StatBonusEquipEffectWithItemStat):
    def __init__(self, effect_chance):
        super(OffenciveAttackEffect, self).__init__(DataTypes.OFFENCIVE_ATTACK_CHANCE, effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "offencive_attack"

    def _item_stat(self):
        return ItemStat(DataTypes.OFFENCIVE_ATTACK_CHANCE, self.effect_chance, colors.LIGHT_GREEN, "Strike Step",
                        ItemStat.PERCENT_FORMAT, order=40, is_common_stat=False)


class DefenciveAttackEffect(StatBonusEquipEffectWithItemStat):
    def __init__(self, effect_chance):
        super(DefenciveAttackEffect, self).__init__(DataTypes.DEFENCIVE_ATTACK_CHANCE, effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "defencive_attack"

    def _item_stat(self):
        return ItemStat(DataTypes.DEFENCIVE_ATTACK_CHANCE, self.effect_chance, colors.LIGHT_GREEN, "Def Strike",
                        ItemStat.PERCENT_FORMAT, order=40, is_common_stat=False)


class BleedAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(BleedAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "bleed_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        turns = random.randrange(2, 6)
        damage_per_turn = 1
        damage_interval = 1
        bleed_effect = entityeffect.BleedEffect(source_entity, damage_per_turn, [DamageTypes.BLEED],
                                                damage_interval, turns,
                                                messenger.BLEED_MESSAGE, BLEED_STATUS_DESCRIPTION)
        target_entity.effect_queue.add(bleed_effect)

    def _item_stat(self):
        return ItemStat("bleed_weapon_effect", self.effect_chance, colors.RED, "Bleed",
                        ItemStat.PERCENT_FORMAT, order=30, is_common_stat=False)


class PoisonAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(PoisonAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "poison_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        min_damage = 4
        max_damage = 8
        turn_interval = 2
        turns = 20

        factory = PoisonEntityEffectFactory(source_entity, random.randrange(min_damage, max_damage), turn_interval, turns)