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 WeaponMeleeAttacker(WeaponAttacker):
    def __init__(self, weapon):
        super(WeaponMeleeAttacker, self).__init__(weapon)
        self.component_type = "melee_attacker"

    def can_hit(self, entity):
        if geometry.chess_distance(self.parent.position.value, entity.position.value) > 1:
            return False
        return True class WeaponRangedAttacker(WeaponAttacker):
    def __init__(self, weapon):
        super(WeaponRangedAttacker, self).__init__(weapon)
        self.component_type = "ranged_attacker"

    def can_hit(self, entity):
        return True class Composite(Component):
    """
    Abstract composite class of composite design pattern.

    Component classes of composite type should inherit from this class.
    Composite objects may hold other Components.

    component_type is needed if this composite will be a child.
    """

    def __init__(self, component_type=None):
        super(Composite, self).__init__()
        self.component_type = component_type
        self._spoofed_children = {}
        self._children = {}
        self._children_tag_table = {}

    def __getinitargs__(self):
        return ()

    def get_child(self, component_type):
        return self.__getattr__(component_type)

    def set_child(self, child):
        """
        Adds a child component to this component.
        If the child already has a parent an exception is thrown.
        """
        if child.tags is None:
            raise Exception("Missing tags when: Component {0} tried ta add_child "
                            "component: {1} to its children. ".format(str(self), str(child)))
        if child.component_type is None:
            raise Exception("Missing component_type when: Component {0} tried ta add_child "
                            "component: {1} to its children. ".format(str(self), str(child)))
        if not child._parent is None:
            raise Exception("Component {0} tried ta add_child "
                            "component: {1} to its children. "
                            "But it already "
                            "had parent: {2}.".format(str(self), str(child), str(child.parent)))
        if self.has(child.component_type):
            self.remove_component_of_type(child.component_type)
        self._children[child.component_type] = child
        self._add_child_to_tag_table(child)
        child.parent = self

    def add_spoof_child(self, child):
        """
        Adds a spoofed child component to this composite.
        If the child already has a parent an exception is thrown.
        """
        if child.tags is None:
            raise Exception("Component {0} tried to add_child "
                            "component: {1} to its children. "
                            "But tags "
                            "was not set.".format(str(self), str(child)))
        if child.component_type is None:
            raise Exception("Component {0} tried to add_child "
                            "component: {1} to its children. "
                            "But component_type "
                            "was not set.".format(str(self), str(child)))
        if not child._parent is None and child.parent != self:
            raise Exception("Component {0} tried to add_child "
                            "component: {1} to its children. "
                            "But it already "
                            "had parent: {2}.".format(str(self), str(child), str(child.parent)))
        if not child.component_type in self._spoofed_children:
            self._spoofed_children[child.component_type] = []
        self._spoofed_children[child.component_type].append(child)
        self._add_child_to_tag_table(child)
        child.parent = self

    def _add_child_to_tag_table(self, child):
        for tag in child.tags:
            if not tag in self._children_tag_table:
                self._children_tag_table[tag] = []
            self._children_tag_table[tag].append(child)

    def _remove_child_from_tag_table(self, child):
        for tag in child.tags:
            if tag in self._children_tag_table:
                self._children_tag_table[tag].remove(child)

    def reset_spoofed_children(self):
        """
        Removes all spoofed children.
        """
        for child_type in self._spoofed_children.values():
            for child in child_type:
                self.remove_component(child)
        self._spoofed_children = {}  # Unecessary?

    def remove_component(self, child):
        """
        Removes a child component from this component.
        """
        if (child.component_type in self._children and
                    child is self._children[child.component_type]):
                child.parent = None
                del self._children[child.component_type]
        if (child.component_type in self._spoofed_children and
                    child in self._spoofed_children[child.component_type]):
            self._spoofed_children[child.component_type].remove(child)
            child.parent = None
        self._remove_child_from_tag_table(child)
        return child

    def remove_component_of_type(self, component_type):
        """
        Removes a child component of a type of this component.
        """
        if component_type in self._children:
            return self.remove_component(self._children[component_type])
        return None

    def update(self):
        """
        Runs update on all child components.
        """
        map(lambda x: x.update(), self._children.values())

    def first_tick(self, time):
        """
        Runs first_tick on all child components.
        """
        visited_component_types = set()
        for component_type, component in self._spoofed_children.iteritems():
            visited_component_types.add(component_type)
            component[0].first_tick(time)
        components_without_spoof = [component for key, component in self._children.iteritems()
                                    if not key in visited_component_types]
        for component in components_without_spoof:
            component.first_tick(time)

    def before_tick(self, time):
        """
        Runs before_tick on all child components.
        """
        visited_component_types = set()
        for component_type, component in self._spoofed_children.iteritems():
            visited_component_types.add(component_type)
            component[0].before_tick(time)
        components_without_spoof = [component for key, component in self._children.iteritems()
                                    if not key in visited_component_types]
        for component in components_without_spoof:
            component.before_tick(time)

    def on_tick(self, time):
        """
        Runs on_tick on all child components.
        """
        visited_component_types = set()
        for component_type, component in self._spoofed_children.iteritems():
            visited_component_types.add(component_type)
            component[0].on_tick(time)
        components_without_spoof = [component for key, component in self._children.iteritems()
                                    if not key in visited_component_types]
        for component in components_without_spoof:
            component.on_tick(time)

    def after_tick(self, time):
        """
        Runs after_tick on all child components.
        """
        visited_component_types = set()
        for component_type, component in self._spoofed_children.iteritems():
            visited_component_types.add(component_type)
            component[0].after_tick(time)
        components_without_spoof = [component for key, component in self._children.iteritems()
                                    if not key in visited_component_types]
        for component in components_without_spoof:
            component.after_tick(time)

    def send_message(self, message):
        """
        Sends message to all child components.
        """
        map(lambda x: x.send_message(message), self._children.values())

    def __getattr__(self, component_type):
        if component_type == "_spoofed_children" or component_type == "_children":
            raise AttributeError("Tried to access field {0} from composite {1} "
                                 "But it doesn't exist.".format(str(component_type),
                                                                str(self)))
        try:
            if (component_type in self._spoofed_children and
                        len(self._spoofed_children[component_type]) > 0):
                return self._spoofed_children[component_type][0]
            return self._children[component_type]
        except KeyError:
            error_message = ("Tried to access component {0} from composite {1} "
                             "But it doesn't exist.".format(str(component_type), str(self)))
            if self.has("description"):
                error_message += "\n The name of the composite is: " + self.description.name
            raise AttributeError(error_message)

    def get_original_child(self, component_type):
        """
        Gets the "real" child of the composite.
        """
        return self._children[component_type]

    def get_spoofed_children_of_type(self, component_type):
        try:
            return self._spoofed_children[component_type]
        except KeyError:
            raise Exception("Tried to access components of type"
                            " {0} from composite {1} "
                            "But it doesn't exist.".format(str(component_type),
                                                           str(self)))

    def has(self, component_type):
        """
        Returns true if this component has a child of the given type.

        False otherwise.
        """
        return component_type in self._children

    def has_tag(self, tag):
        """
        Returns true if this component has the given tag.

        False otherwise.
        """
        return tag in self.tags

    # TODO: rename to descendant
    def get_children_with_tag(self, tag):
        """
        Gets the list of all children with the given tag.
        """
        if tag in self._children_tag_table:
            result = self._children_tag_table[tag]
        else:
            result = []
        composite_children = [c for c in self._children.values() if isinstance(c, Composite)]
        grand_children = []
        for c in composite_children:
            grand_children += c.get_children_with_tag(tag)
        return result + grand_children

    def get_child_or_ancestor(self, component_type):
        if component_type in self._children:
            return self._children[component_type]
        elif self._parent:
            return self.parent.get_child_or_ancestor(component_type)
        else:
            raise Exception("Tried to find relative of type: [" + component_type + "] but it doesn't exist")

    def has_child_or_ancestor(self, component_type):
        if component_type in self._children:
            return True
        elif self._parent:
            return self.parent.get_child_or_ancestor(component_type)
        else:
            return False 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 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 ExtraSwingAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(ExtraSwingAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "extra_swing_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        source_entity.melee_attacker.try_hit(target_entity)

    def _item_stat(self):
        return ItemStat("extra_swing", self.effect_chance, colors.LIGHT_BLUE, "Extra Swing",
                        ItemStat.PERCENT_FORMAT, order=10, 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 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 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 StunAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(StunAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "stun_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        return target_entity.effect_queue.add(entityeffect.AddSpoofChild(source_entity, StunnedActor(),
                                                                         gametime.single_turn))

    def _item_stat(self):
        return ItemStat("Stun", self.effect_chance, colors.CHAMPAGNE, "Stun",
                        ItemStat.PERCENT_FORMAT, order=20, 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 RangeItemStat(ItemStat):
    def __init__(self, component_type, min_value, max_value, color_fg, screen_name=None,
                 order=50, is_common_stat=True):
        super(RangeItemStat, self).__init__(component_type, min_value, color_fg, screen_name=screen_name,
                                            formatting=ItemStat.REGULAR_FORMAT, order=order,
                                            is_common_stat=is_common_stat)
        self.min = min_value
        self.max = max_value

    def get_value_text(self):
        return str(self.min) + "-" + str(self.max) + "  " class ItemStat(DataPoint):
    REGULAR_FORMAT = 0
    PERCENT_FORMAT = 1
    MULTIPLIER_FORMAT = 2
    RANGE_FORMAT = 3

    def __init__(self, component_type, value, color_fg, screen_name=None, formatting=REGULAR_FORMAT, order=50,
                 is_common_stat=True):
        super(ItemStat, self).__init__(component_type, value)
        self.tags.add("item_stat")
        self.color_fg = color_fg
        self.order = order
        if screen_name:
            self._screen_name = screen_name
        else:
            self._screen_name = component_type
        self.format = formatting
        self.is_common_stat = is_common_stat

    def get_value_text(self):
        if self.format == ItemStat.PERCENT_FORMAT:
            return "{:.0f}".format(self.value * 100) + "% "
        elif self.format == ItemStat.MULTIPLIER_FORMAT:
            return "x {:.1f}".format(self.value)
        else:
            return str(self.value) + "  "

    def get_text(self, width):
        return str(self._screen_name + self.get_value_text().rjust(width - len(self._screen_name))) 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 KnockBackAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(KnockBackAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "knock_back_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        knock_position = geometry.other_side_of_point(self.parent.position.value,
                                                      target_entity.position.value)
        target_entity.mover.try_move(knock_position)

    def _item_stat(self):
        return ItemStat("knock_back_weapon_effect", self.effect_chance, colors.CHAMPAGNE, "Knock Back",
                        ItemStat.PERCENT_FORMAT, order=25, is_common_stat=False) class TripAttackEffect(AttackEffectWithItemStat):
    def __init__(self, effect_chance):
        super(TripAttackEffect, self).__init__(effect_chance)
        self.effect_chance = effect_chance
        self.component_type = "trip_attack_effect"

    def attack_effect(self, source_entity, target_entity):
        return target_entity.effect_queue.add(entityeffect.AddSpoofChild(source_entity, RandomStepper(),
                                                                         gametime.single_turn))

    def _item_stat(self):
        return ItemStat("trip", self.effect_chance, colors.YELLOW, "Trip",
                        ItemStat.PERCENT_FORMAT, order=20, is_common_stat=False) class GraphicChar(Leaf):
    """
    Composites holding this has a graphical representation as a char.
    """

    def __init__(self, color_bg, color_fg, icon):
        super(GraphicChar, self).__init__()
        self.component_type = "graphic_char"
        self._color_bg = color_bg
        self._color_fg = color_fg
        self._icon = icon

    @property
    def color_bg(self):
        if self._color_bg:
            return self._color_bg
        elif self.next:
            return self.next.color_bg
        return None


    @color_bg.setter
    def color_bg(self, value):
        self._color_bg = value

    @property
    def color_fg(self):
        if self._color_fg:
            return self._color_fg
        elif self.next:
            return self.next.color_fg
        return None

    @color_fg.setter
    def color_fg(self, value):
        self._color_fg = value

    @property
    def icon(self):
        if self._icon:
            return self._icon
        elif self.next:
            return self.next.icon
        return None

    @icon.setter
    def icon(self, value):
        self._icon = value

    def copy(self):
        """
        Makes a copy of this component.
        """
        return GraphicChar(self.color_bg, self.color_fg, self.icon) def set_item_components(item, game_state):
    item.set_child(DataPoint(DataTypes.ENERGY, -gametime.single_turn))
    item.set_child(Position())
    item.set_child(DoNothingActor())
    item.set_child(DungeonLevel())
    item.set_child(Mover())
    item.set_child(DataPoint(DataTypes.GAME_PIECE_TYPE, GamePieceTypes.ITEM))
    item.set_child(DataPoint(DataTypes.GAME_STATE, game_state))
    item.set_child(CharPrinter())
    new_drop_action(DROP_ACTION_TAG, item)
    item.set_child(PlayerThrowItemAction())
    set_thrown_item_hit_floor_action(item, [MoveTriggeredEffect(), LocalMessageEffect(messenger.ITEM_HITS_THE_GROUND_HEAVY)])
    set_thrown_item_hit_chasm_action(item, [MoveTriggeredEffect(), LocalMessageEffect(messenger.ITEM_FALLS_DOWN_CHASM)])
    return item class AddSpoofChildEquipEffect2(Leaf):
    def __init__(self, spoof_child, status_icon=None):
        super(AddSpoofChildEquipEffect2, self).__init__()
        self.component_type = "equipment_add_spoof_component_" + spoof_child.component_type
        self.tags.add("equipped_effect")

        self.spoof_child = spoof_child
        self.status_icon = status_icon

    def equipped_effect(self, entity):
        """
        Causes the entity that equips this have a spoofed component child.
        """
        entity.effect_queue.add(entityeffect.AddSpoofChild(entity, self.spoof_child, 1))
        if self.status_icon:
            entity.effect_queue.add(entityeffect.StatusIconEntityEffect(entity, self.status_icon, 1)) class ReEquipAction(Action):
    """
    An Item with this component can be equipped on an entity.

    If an item is already in that
    equipment slot that item will be unequipped first.
    """

    def __init__(self):
        super(ReEquipAction, self).__init__()
        self.component_type = "reequip_action"
        self.tags.add("reequip_action")
        self.name = "Equip"
        self.display_order = 90

    def act(self, **kwargs):
        """
        Will attempt to equip the parent item to the given entity.
        """
        source_entity = kwargs[action.SOURCE_ENTITY]
        if action.EQUIPMENT_SLOT in kwargs:
            equipment_slot = kwargs[action.EQUIPMENT_SLOT]
        else:
            equipment_slot = self.get_equipment_slot(source_entity)
        old_item = None
        if source_entity.equipment.slot_is_equiped(equipment_slot):
            old_item = source_entity.equipment.unequip(equipment_slot)
        self._re_equip(source_entity, equipment_slot)
        if not old_item is None:
            source_entity.inventory.try_add(old_item)
        self.add_energy_spent_to_entity(source_entity)

    def get_equipment_slot(self, source_entity):
        """
        Finds the right equipment slot.
        """
        open_slots = (source_entity.equipment.get_open_slots_of_type
                      (self.parent.equipment_type.value))
        if len(open_slots) > 0:
            return open_slots[0]
        else:
            return (source_entity.equipment.get_slots_of_type
                    (self.parent.equipment_type.value))[0]

    def can_act(self, **kwargs):
        """
        Returns true if it is a valid action to reequip that item.
        """
        return True

    def _re_equip(self, target_entity, equipment_slot):
        """
        Performs the actual reequip.
        """
        re_equip_effect = entityeffect.ReEquip(target_entity, equipment_slot, self.parent)
        target_entity.effect_queue.add(re_equip_effect)
        target_entity.inventory.remove_item(self.parent) class EquipmentType(Leaf):
    """
    Holds the equipment type of a equipment item.
    """

    def __init__(self, equipment_type):
        super(EquipmentType, self).__init__()
        self.component_type = "equipment_type"
        self.value = equipment_type class ItemType(Leaf):
    """
    Enumerator class denoting different item types. Inventory is sorted on ItemType.
    """
    POTION = 0
    SCROLL = 1
    BOMB = 2
    DEVICE = 3
    WEAPON = 4
    ARMOR = 5
    JEWELLRY = 6
    AMMO = 7
    ENERGY_SHPERE = 7

    ALL = [POTION, BOMB, DEVICE, WEAPON, ARMOR, JEWELLRY, AMMO, ENERGY_SHPERE]

    def __init__(self, item_type):
        super(ItemType, self).__init__()
        self.component_type = "item_type"
        self.value = item_type class PlayerCastMissileSpellAction(PlayerMissileAction):
    def __init__(self, item, missile_graphic):
        super(PlayerCastMissileSpellAction, self).__init__(missile_graphic)
        self.component_type = "cast_spell_action"
        self.name = "Cast Spell"
        self.display_order = 95
        self.item = item

    def add_energy_spent_to_entity(self, entity):
        """
        Help method for spending energy for the act performing entity.
        """
        entity.actor.newly_spent_energy += entity.cast_speed.value

    def missile_hit_effect(self, dungeon_level, position, game_state, source_entity):
        self.hit_position(dungeon_level, position, source_entity)

    def hit_position(self, dungeon_level, position, source_entity):
        target_entity = dungeon_level.get_tile(position).get_first_entity()
        if target_entity is None:
            return
        source_entity.ranged_attacker.try_hit(target_entity)

    def can_act(self, **kwargs):
        return True

    def max_missile_distance(self, **kwargs):
        return self.item.weapon_range.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 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 Damage(Leaf):
    """
    Holds min and max damage.
    """
    def __init__(self, min, max):
        super(Damage, self).__init__()
        self.component_type = "damage_data_point"
        self.min = min
        self.max = max class Description(Leaf):
    """
    Composites holding this has some describing text and a name.
    """
    def __init__(self, name, description):
        super(Description, self).__init__()
        self.component_type = "description"
        self._name = name
        self.description = description

    @property
    def name(self):
        return self._name

    @property
    def long_name(self):
        if self.parent.has("is_named"):
            return self._name
        else:
            return "the " + self._name
    @name.setter
    def name(self, value):
        self._name = value

    def copy(self):
        """
        Makes a copy of this component.
        """
        return Description(self.name, self.description)
import action
import colors
import equipment
import icon
from attacker import DamageType, DamageTypes, WeaponMeleeAttacker, WeaponRangedAttacker
from compositecore import Composite, Leaf
from equipmenteffect import CritChanceBonusEffect, ExtraSwingAttackEffect, BleedAttackEffect, DefenciveAttackEffect, CounterAttackEffect, StunAttackEffect, IgnoreArmorAttackEffect, RangeItemStat, ItemStat, OffenciveAttackEffect, KnockBackAttackEffect, TripAttackEffect
from graphic import GraphicChar
from item import set_item_components
from item_components import AddSpoofChildEquipEffect2, ReEquipAction, EquipmentType, ItemType
from missileaction import PlayerCastMissileSpellAction
from stats import DataPoint, DataTypes, Damage
from text import Description
    c.set_child(Description("Whip",
                            "An unusual weapon, most often used for torture."))
    c.set_child(GraphicChar(None, colors.ORANGE_D, icon.WHIP))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

    c.set_child(accuracy_item_stat(10))
    c.set_child(damage_item_stat(1, 4))

    c.set_child(CritChanceBonusEffect(0.15))
    c.set_child(crit_multiplier_item_stat(2.5))

    c.set_child(TripAttackEffect(0.50))
    c.set_child(DefenciveAttackEffect(0.30))
    c.set_child(StunAttackEffect(0.10))

    return c


def new_axe(game_state):
    """
    A composite component representing a Sword item.
    """
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Axe",
                                "This old axe has seen many battles, but age hasn't dulled the blade."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.AXE))
    c.set_child(DataPoint(DataTypes.WEIGHT, 10))

    c.set_child(damage_item_stat(3, 5))
    c.set_child(accuracy_item_stat(8))

    c.set_child(CritChanceBonusEffect(0.1))
    c.set_child(crit_multiplier_item_stat(2))

    c.set_child(OffenciveAttackEffect(0.75))
    c.set_child(BleedAttackEffect(0.1))
    return c


def damage_item_stat(min_value, max_value):
    return RangeItemStat(DataTypes.DAMAGE, min_value, max_value, colors.WHITE, "Damage", order=0)


def accuracy_item_stat(value):
    return ItemStat(DataTypes.ACCURACY, value, colors.LIGHT_ORANGE, "Accuracy", order=10)


def crit_multiplier_item_stat(value):
    return ItemStat(DataTypes.CRIT_MULTIPLIER, value, colors.RED, "Crit x", ItemStat.MULTIPLIER_FORMAT, order=30)


def set_ranged_weapon_components(item):
    item.set_child(EquipmentType(equipment.EquipmentTypes.RANGED_WEAPON))
    item.set_child(ItemType(ItemType.WEAPON))
    item.set_child(ReEquipAction())
    item.set_child(AddSpoofChildEquipEffect2(WeaponRangedAttacker(item)))


def new_gun(game_state):
    gun = Composite()
    set_item_components(gun, game_state)
    set_ranged_weapon_components(gun)
    gun.set_child(RangeWeaponType(RangeWeaponType.GUN))
    gun.set_child(Description("Gun",
                              "This was once a fine weapon, \
                               but age has torn it real bad.\n\
                               The wooden handle is dry and gray, \
                               you see rust eating into the iron pipe."))
    gun.set_child(GraphicChar(None, colors.WHITE, icon.GUN))
    gun.set_child(DataPoint(DataTypes.WEAPON_RANGE, 15))
    gun.set_child(accuracy_item_stat(13))
    gun.set_child(damage_item_stat(5, 25))
    gun.set_child(BleedAttackEffect(1))

    gun.set_child(CritChanceBonusEffect(0.3))
    gun.set_child(crit_multiplier_item_stat(2.0))

    gun.set_child(DataPoint(DataTypes.WEIGHT, 5))
    return gun


def new_sling(game_state):
    sling = Composite()
    set_item_components(sling, game_state)
    set_ranged_weapon_components(sling)
    sling.set_child(RangeWeaponType(RangeWeaponType.SLING))
    sling.set_child(Description("Sling",
                                "This weapon propels rocks more effectively than throwing them would."))
    sling.set_child(GraphicChar(None, colors.ORANGE, icon.SLING))
    sling.set_child(DataPoint(DataTypes.WEAPON_RANGE, 4))
    sling.set_child(DataPoint(DataTypes.WEIGHT, 3))
    sling.set_child(accuracy_item_stat(5))
    sling.set_child(damage_item_stat(1, 3))

    sling.set_child(CritChanceBonusEffect(0.2))
    sling.set_child(crit_multiplier_item_stat(2.0))

    sling.set_child(StunAttackEffect(1))

    return sling


def new_bolas(game_state):
    sling = Composite()
    set_item_components(sling, game_state)
    set_ranged_weapon_components(sling)
    sling.set_child(RangeWeaponType(RangeWeaponType.SLING))
    sling.set_child(Description("Bolas",
                                "Two weights strung together by a string, when thrown they may trip the victim."))
    sling.set_child(GraphicChar(None, colors.CHAMPAGNE, icon.HEART + 18))
    sling.set_child(DataPoint(DataTypes.WEAPON_RANGE, 4))
    sling.set_child(DataPoint(DataTypes.WEIGHT, 3))
    sling.set_child(accuracy_item_stat(3))
    sling.set_child(damage_item_stat(1, 2))

    sling.set_child(CritChanceBonusEffect(0.2))
    sling.set_child(crit_multiplier_item_stat(2.0))


    sling.set_child(TripAttackEffect(0.4))