class Actor(Leaf):
    def __init__(self):
        super(Actor, self).__init__()
        self.component_type = "actor"

        # used by actor to keep track of how much energy was spent this tick.
        self.newly_spent_energy = 0
        self.energy_recovery = gametime.normal_energy_gain

    @property
    def ticks_per_turn(self):
        return gametime.single_turn / self.energy_recovery

    def tick(self):
        """
        Gives the actor an opportunity to act.

        The actor will act if it isn't in an energy debt.
        It also receives some energy.
        """
        if self._should_skip_me():
            self.parent.energy.value - gametime.single_turn
            return
        self.parent.energy.value += self.energy_recovery
        self.check_new_turn()
        need_draw = False
        while self.parent.energy.value > 0:
            if need_draw and self.parent.has("is_player"):  # need a draw in this loop to draw animations but,
                                                                # can skip first draw check_new_turn will draw.
                self.parent.game_state.value.force_draw()
            need_draw = True
            self.parent.energy.value -= self.act()

    def check_new_turn(self):
        if self.parent.has("is_player"):
            turn.ticks_this_turn += 1
            if turn.ticks_this_turn > self.ticks_per_turn:
                turn.current_turn += 1
                turn.ticks_this_turn = 0
                self.parent.game_state.value.force_draw()

    def act(self):
        raise NotImplementedError("act method not implemented for parent:" +
                                  str(self.parent))

    def _should_skip_me(self):
        return self.parent.has("health") and self.parent.health.is_dead()

    def add_energy_spent(self, energy):
        self.newly_spent_energy += energy class StatusAdder(EntityEffect):
    def __init__(self, source_entity, status_flag, time_to_live=1):
        super(StatusAdder, self).__init__(source_entity, time_to_live,
                                          EffectTypes.STATUS_ADDER)
        self.status_flag = status_flag

    def update(self, time_spent):
        status_flags = StatusFlags([self.status_flag])
        status_flags.to_be_removed = True
        self.target_entity.set_child(status_flags)
        self.tick(time_spent) class StatusRemover(EntityEffect):
    def __init__(self, source_entity, status_type_to_remove, time_to_live=1):
        super(StatusRemover, self).__init__(source_entity,
                                            time_to_live,
                                            EffectTypes.STATUS_REMOVER)
        self.status_type_to_remove = status_type_to_remove

    def update(self, time_spent):
        self.queue.remove_status_adder_of_status(self.status_type_to_remove)
        self.tick(time_spent) class EquipmentSlots(object):
    #  Weapons
    MELEE_WEAPON = EquipmentSlot("Melee Weapon", EquipmentTypes.MELEE_WEAPON, icon.SWORD)
    RANGED_WEAPON = EquipmentSlot("Ranged Weapon", EquipmentTypes.RANGED_WEAPON, icon.GUN)

    #  Armor
    HEADGEAR = EquipmentSlot("Headgear", EquipmentTypes.HEADGEAR, icon.HELM)
    ARMOR = EquipmentSlot("Armor", EquipmentTypes.ARMOR, icon.ARMOR)
    BOOTS = EquipmentSlot("Boots", EquipmentTypes.BOOTS, icon.BOOTS)

    #  Jewelry
    RIGHT_RING = EquipmentSlot("Right Ring", EquipmentTypes.RING, icon.RING)
    LEFT_RING = EquipmentSlot("Left Ring", EquipmentTypes.RING, icon.RING)
    AMULET = EquipmentSlot("Amulet", EquipmentTypes.AMULET, icon.AMULET)

    ALL = [MELEE_WEAPON, RANGED_WEAPON, HEADGEAR, ARMOR,
           BOOTS, RIGHT_RING, LEFT_RING, AMULET] class PlayerShootWeaponAction(PlayerMissileAction):
    def __init__(self, ranged_weapon):
        super(PlayerShootWeaponAction, self).__init__()
        self.name = "Shoot"
        self.display_order = 85
        self.ranged_weapon = ranged_weapon
        self._missile_graphic = GraphicChar(None, colors.WHITE, icon.BIG_CENTER_DOT)

    @property
    def missile_graphic(self):
        return self._missile_graphic

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

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

    def can_act(self, **kwargs):
        source_entity = kwargs[SOURCE_ENTITY]
        ammo_items = [item for item in source_entity.inventory.items
                      if item.has("is_ammo")]
        return len(ammo_items) > 0

    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.hit(target_entity)

    def max_missile_distance(self, **kwargs):
        return self.ranged_weapon.weapon_range.value

    def remove_ammo_from_inventory(self, inventory):
        ammo_items = [item for item in inventory.items if item.has("is_ammo")]
        ammo_item_with_least_ammo = min(ammo_items, key=lambda e: e.stacker.size)
        inventory.remove_one_item_from_stack(ammo_item_with_least_ammo) class PlayerSlingStoneAction(PlayerMissileAction):
    def __init__(self, sling_weapon):
        super(PlayerSlingStoneAction, self).__init__(GraphicChar(None, colors.GRAY, icon.STONE))
        self.component_type = "sling_stone_action"
        self.name = "Throw Stone"
        self.display_order = 95
        self.sling_weapon = sling_weapon

    def add_energy_spent_to_entity(self, entity):
        """
        Help method for spending energy for the act performing entity.

        """
        entity.actor.newly_spent_energy += entity.throw_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.hit(target_entity)


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

    def max_missile_distance(self, **kwargs):
        source_entity = kwargs[SOURCE_ENTITY]
        return max_throw_distance(source_entity.strength.value) + self.sling_weapon.weapon_range.value class StatusFlags(Leaf):
    """
    Composites holding this has status flags, describing their behaviour.
    """
    INVISIBILE = 0
    SEE_INVISIBILITY = 1
    FLYING = 2
    IS_ALIVE = 3
    CAN_OPEN_DOORS = 4
    HAS_HEART = 5

    def __init__(self, status_flags=[]):
        super(StatusFlags, self).__init__()
        self.component_type = "status_flags"
        self._status_flags = set(status_flags)
        self._temp_status_flags = set()

    def has_status(self, status):
        """
        Returns True if parent entity has the status given.
        """
        if not self.next is None:
            return (status in self._status_flags or
                    status in self._temp_status_flags or
                    next.has_status(status))
        else:
            return (status in self._status_flags or
                    status in self._temp_status_flags)

    def add_temp_status(self, status):
        """
        Adds a temporary status that will be removed the next tick.
        """
        self._temp_status_flags.add(status)

    def before_tick(self, time):
        self._temp_status_flags = set() def new_dagger(game_state):
    """
    A composite component representing a Knife item.
    """
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Dagger", "A trusty dagger, small and precise but will only inflict small wounds."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.DAGGER))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.CUTTING))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(15))

    c.set_child(CritChanceBonusEffect(0.2))
    c.set_child(crit_multiplier_item_stat(3.5))

    c.set_child(ExtraSwingAttackEffect(0.20))
    c.set_child(BleedAttackEffect(0.10))

    return c def new_spear(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("Spear",
                            "A stick with a sharp piece of metal at one end."
                            "It's a useful weapon when you want to keep danger at bay."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.SPEAR))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

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

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

    c.set_child(DefenciveAttackEffect(0.75))
    c.set_child(CounterAttackEffect(0.1))

    return c def new_morning_star(game_state):
    """
    A composite component representing a Sword item.
    """
    mace = Composite()
    set_item_components(mace, game_state)
    set_melee_weapon_component(mace)
    mace.set_child(Description("Morning Star",
                               "This old club has an lump of iron with rusty spikes at one end."))
    mace.set_child(GraphicChar(None, colors.GRAY, icon.MORNING_STAR))
    mace.set_child(DataPoint(DataTypes.WEIGHT, 8))

    mace.set_child(accuracy_item_stat(8))
    mace.set_child(damage_item_stat(1, 6))

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

    mace.set_child(StunAttackEffect(0.2))
    mace.set_child(IgnoreArmorAttackEffect(0.2))
    mace.set_child(BleedAttackEffect(0.1))

    return mace def new_sword(game_state):
    """
    A composite component representing a Sword item.
    """
    sword = Composite()
    set_item_components(sword, game_state)
    set_melee_weapon_component(sword)
    sword.set_child(Description("Iron Sword",
                                "This old blade has seen some better days, it's as sharp as ever tough."))
    sword.set_child(GraphicChar(None, colors.GRAY, icon.SWORD))
    sword.set_child(DataPoint(DataTypes.WEIGHT, 10))

    sword.set_child(damage_item_stat(2, 5))
    sword.set_child(accuracy_item_stat(10))

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

    sword.set_child(ExtraSwingAttackEffect(0.1))
    sword.set_child(BleedAttackEffect(0.1))
    return sword class RangeWeaponType(DataPoint):
    """
    Component that marks a weapon as a ranged weapon.
    """

    GUN = 0
    SLING = 1
    MAGIC = 2

    def __init__(self, range_weapon_type):
        super(RangeWeaponType, self).__init__("range_weapon_type", range_weapon_type) def new_kris(game_state):
    """
    A composite component representing a Knife item.
    """
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Kris", "A dagger with a wavy blade, its sharp end can cause major damage."))
    c.set_child(GraphicChar(None, colors.GRAY_D, icon.KRIS))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.CUTTING))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(15))

    c.set_child(CritChanceBonusEffect(0.20))
    c.set_child(crit_multiplier_item_stat(3.5))

    c.set_child(ExtraSwingAttackEffect(0.2))
    c.set_child(BleedAttackEffect(0.2))

    return c def new_katar(game_state):
    """
    A composite component representing a Knife item.
    """
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Katar", "A blade with an unusual handle, it looks ancient."))
    c.set_child(GraphicChar(None, colors.CHAMPAGNE, icon.KATAR))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.CUTTING))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(17))

    c.set_child(CritChanceBonusEffect(0.10))
    c.set_child(crit_multiplier_item_stat(3))

    c.set_child(ExtraSwingAttackEffect(0.2))
    c.set_child(CounterAttackEffect(0.2))

    return c def new_cestus(game_state):
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Cestus", "A pair of leather battle gloves, they improve your punches."))
    c.set_child(GraphicChar(None, colors.ORANGE_D, icon.GLOVE))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.BLUNT))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(17))

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

    c.set_child(ExtraSwingAttackEffect(0.3))
    c.set_child(CounterAttackEffect(0.2))
    c.set_child(StunAttackEffect(0.2))

    return c def new_iron_hand(game_state):
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Iron Hand", "A pair of iron battle gloves, they put some weight behind your punches."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.GLOVE))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.BLUNT))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(14))

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

    c.set_child(ExtraSwingAttackEffect(0.20))
    c.set_child(CounterAttackEffect(0.2))
    c.set_child(StunAttackEffect(0.35))

    return c def new_claw(game_state):
    c = Composite()
    set_item_components(c, game_state)
    set_melee_weapon_component(c)
    c.set_child(Description("Claws", "A pair of gloves with sharp blades attached to them,"))
    c.set_child(GraphicChar(None, colors.CHAMPAGNE, icon.CLAWS))
    c.set_child(DataPoint(DataTypes.WEIGHT, 5))
    c.set_child(DamageType(DamageTypes.BLUNT))

    c.set_child(damage_item_stat(1, 3))
    c.set_child(accuracy_item_stat(17))

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

    c.set_child(ExtraSwingAttackEffect(0.15))
    c.set_child(CounterAttackEffect(0.20))
    c.set_child(BleedAttackEffect(0.30))

    return c def new_rapier(game_state):
    """
    A composite component representing a Sword item.
    """
    sword = Composite()
    set_item_components(sword, game_state)
    set_melee_weapon_component(sword)
    sword.set_child(Description("Rapier",
                                "A sword with a thin sharp blade, swift but deadly."))
    sword.set_child(GraphicChar(None, colors.CHAMPAGNE, icon.RAPIER))
    sword.set_child(DataPoint(DataTypes.WEIGHT, 8))

    sword.set_child(damage_item_stat(2, 5))
    sword.set_child(accuracy_item_stat(10))

    sword.set_child(CritChanceBonusEffect(0.2))
    sword.set_child(crit_multiplier_item_stat(2.5))

    sword.set_child(ExtraSwingAttackEffect(0.1))
    sword.set_child(CounterAttackEffect(0.1))
    sword.set_child(OffenciveAttackEffect(0.1))
    return sword def new_scimitar(game_state):
    """
    A composite component representing a Sword item.
    """
    sword = Composite()
    set_item_components(sword, game_state)
    set_melee_weapon_component(sword)
    sword.set_child(Description("Scimitar",
                                "A curved sword, an ancient design from the east."))
    sword.set_child(GraphicChar(None, colors.WHITE, icon.SCIMITAR))
    sword.set_child(DataPoint(DataTypes.WEIGHT, 8))

    sword.set_child(damage_item_stat(2, 5))
    sword.set_child(accuracy_item_stat(12))

    sword.set_child(CritChanceBonusEffect(0.2))
    sword.set_child(crit_multiplier_item_stat(2.5))

    sword.set_child(ExtraSwingAttackEffect(0.1))
    sword.set_child(DefenciveAttackEffect(0.1))
    sword.set_child(OffenciveAttackEffect(0.1))
    return sword def new_club(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("Club",
                                "A thick wooden stick, It may be used as a weapon."))
    c.set_child(GraphicChar(None, colors.ORANGE_D, icon.CLUB))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

    c.set_child(damage_item_stat(1, 6))
    c.set_child(accuracy_item_stat(8))

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

    c.set_child(StunAttackEffect(0.3))
    return c def new_flail(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("Flail",
                            "A wooden handle with a chain and metal ball attached to it."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.FLAIL))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

    c.set_child(damage_item_stat(1, 7))
    c.set_child(accuracy_item_stat(7))

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

    c.set_child(IgnoreArmorAttackEffect(0.3))
    c.set_child(KnockBackAttackEffect(0.2))
    c.set_child(OffenciveAttackEffect(0.1))
    return c def new_hammer(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("Hammer",
                            "A heavy hammer, it may knock away enemies."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.HAMMER))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

    c.set_child(damage_item_stat(1, 7))
    c.set_child(accuracy_item_stat(8))

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

    c.set_child(KnockBackAttackEffect(0.35))
    return c def new_chain_and_ball(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("Chain and Spike Ball",
                            "A huge metal ball on a chain, hard to use but can deal massive damage."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.BALL_AND_CHAIN))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

    c.set_child(damage_item_stat(2, 9))
    c.set_child(accuracy_item_stat(5))

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

    c.set_child(KnockBackAttackEffect(0.20))
    c.set_child(DefenciveAttackEffect(0.60))
    c.set_child(IgnoreArmorAttackEffect(0.10))
    return c def new_halberd(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("Halberd",
                            "A long stick with a with an axe-head at one end."
                            "It's a useful weapon when you want to keep danger at bay."))
    c.set_child(GraphicChar(None, colors.GRAY, icon.HALBERD))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

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

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

    c.set_child(DefenciveAttackEffect(0.75))
    c.set_child(OffenciveAttackEffect(0.20))

    return c def new_trident(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("Trident",
                            "A long stick with a with three sharp points at one end."
                            "It's a useful weapon when you want to keep danger at bay."))
    c.set_child(GraphicChar(None, colors.ORANGE_D, icon.TRIDENT))
    c.set_child(DataPoint(DataTypes.WEIGHT, 8))

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

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

    c.set_child(DefenciveAttackEffect(0.75))
    c.set_child(BleedAttackEffect(0.20))

    return c def new_whip(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("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 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_flame_orb(game_state):
    orb = Composite()
    set_item_components(orb, game_state)
    set_ranged_weapon_components(orb)
    orb.set_child(RangeWeaponType(RangeWeaponType.MAGIC))
    orb.set_child(Description("Flame Orb",
                              "An orb with a living flame inside, it allows the wielder to channel fire from it."))
    orb.set_child(GraphicChar(None, colors.RED, icon.ORB))
    orb.set_child(DataPoint(DataTypes.WEAPON_RANGE, 5))
    orb.set_child(DataPoint(DataTypes.WEIGHT, 2))
    orb.set_child(accuracy_item_stat(5))
    orb.set_child(Damage(2, 4))
    orb.set_child(MagicMissileEffect(GraphicChar(None, colors.RED, icon.BIG_CENTER_DOT)))
    return orb
from actor import Actor
from entityeffect import StatusAdder, StatusRemover
from equipment import EquipmentSlots
from missileaction import PlayerShootWeaponAction, PlayerSlingStoneAction
from statusflags import StatusFlags
from weapon import new_dagger, new_spear, new_morning_star, new_sword, RangeWeaponType, new_kris, new_katar, new_cestus, new_iron_hand, new_claw, new_rapier, new_scimitar, new_club, new_flail, new_hammer, new_chain_and_ball, new_halberd, new_trident, new_whip, new_axe, new_gun, new_sling, new_flame_orb
import monster
import settings
import spawner
import menu
import console
import gametime
import inputhandler
import menufactory
import positionexaminer
import util
        elif key == inputhandler.TAB:
            self.toggle_command_list()
        elif key == inputhandler.USE_PICK_UP:
            self.handle_context_action()
        elif key == inputhandler.PICKUP:  # Pick up
            self.handle_pick_up()
        elif key == inputhandler.FIRE:
            self.throw_or_shoot()
        elif key == inputhandler.ESCAPE:
            self.save_and_quit()
        elif key == inputhandler.REST:  # Rest
            self.newly_spent_energy += gametime.single_turn
        elif key == inputhandler.EXAMINE:
            self.start_examine()
        elif key == inputhandler.AUTO_EXPLORE:
            self.auto_explore()
        elif key == inputhandler.INVENTORY:
            self.try_open_inventory()
        elif key == inputhandler.EQUIPMENT:
            self.open_equipment()
        elif key == inputhandler.WEAR_WIELD:
            self.open_wear_wield_item_action_menu()
        elif key == inputhandler.DRINK:
            self.open_drink_item_action_menu()
        elif key == inputhandler.READ:
            self.open_read_item_action_menu()
        if settings.DEV_MODE_FLAG:
            self.handle_dev_mode_commands(key)

    def step_path(self):
        if self.parent.path.has_path():
            self.newly_spent_energy = self.parent.path.try_step_path()

    def set_path_destination(self, destination):
        if not destination is None:
            if self.parent.memory_map.has_seen_position(destination):
                self.parent.path.compute_path(destination)
            else:
                self.parent.path.set_line_path(destination)

    def handle_move_input(self, key):
        if key in inputhandler.move_controls:
            direction = inputhandler.move_controls[key]
        else:
            direction = inputhandler.vi_move_controls[key]
        self.newly_spent_energy += self.parent.stepper.try_step_in_direction(direction)

    def spawn_context_menu(self):
        context_menu = menufactory.context_menu(self.parent, self.parent.game_state.value.menu_prompt_stack)
        self.parent.game_state.value.start_prompt(context_menu)

    def start_examine(self):
        destination_selector = positionexaminer.PositionSelector(self.parent.game_state.value,
                                                                 self.parent.position.value)
        self.parent.game_state.value.start_prompt(destination_selector)
        destination = destination_selector.selected_position
        self.set_path_destination(destination)

    def try_open_inventory(self):
        if not self.parent.inventory.is_empty():
            inventory_menu = menufactory.inventory_menu(self.parent, self.parent.game_state.value.menu_prompt_stack)
            self.parent.game_state.value.start_prompt(inventory_menu)

    def open_equipment(self):
        equipment_menu = menufactory.equipment_menu(self.parent, self.parent.game_state.value.menu_prompt_stack)
        self.parent.game_state.value.start_prompt(equipment_menu)

    def auto_explore(self):
        closest_enemy = next((entity for entity in self.parent.vision.get_seen_entities_closest_first()
                             if not entity.position.value == self.parent.position.value), None)
        if closest_enemy and not closest_enemy.position.value == self.parent.position.value:
            self.parent.path.compute_path(closest_enemy.position.value)
        else:
            destination = util.get_closest_unseen_walkable_position(self.parent, self.parent.position.value,
                                                                    self.parent.dungeon_level.value)
            if destination:
                self.parent.path.compute_path(destination)
                return
            fountain = next((f for f in
                            self.parent.dungeon_level.value.dungeon_features
                            if f.has("drink_action") and (not f.position.value == self.parent.position.value)), None)
            if fountain:
                destination = fountain.position.value
                self.parent.path.compute_path(destination)
                return

            if 0 < len(self.parent.dungeon_level.value.down_stairs):
                stairs_down = self.parent.dungeon_level.value.down_stairs[0]
                self.parent.path.compute_path(stairs_down.position.value)

    def toggle_command_list(self):
        self.parent.game_state.value.command_list_bar.turn_page()

    def toggle_invisibility(self):
        invisible_flag = StatusFlags.INVISIBILE
        if not self.parent.status_flags.has_status(invisible_flag):
            effect = StatusAdder(self.parent, invisible_flag, time_to_live=float("inf"))
            self.parent.effect_queue.add(effect)
        else:
            invisible_status = StatusFlags.INVISIBILE
            effect = StatusRemover(self.parent, invisible_status, time_to_live=1)
            self.parent.effect_queue.add(effect)
            self.newly_spent_energy += gametime.single_turn

    def shoot_gun(self, weapon):
        shooting = PlayerShootWeaponAction(weapon)
        game_state = self.parent.game_state.value
        if shooting.can_act(source_entity=self.parent, game_state=game_state):
            shooting.act(source_entity=self.parent, game_state=game_state)

    def shoot_sling(self, weapon):
        shooting = PlayerSlingStoneAction(weapon)
        game_state = self.parent.game_state.value
        if shooting.can_act(source_entity=self.parent, game_state=game_state):
            shooting.act(source_entity=self.parent, game_state=game_state)

    def throw_or_shoot(self):
        if not self.parent.equipment.slot_is_equiped(EquipmentSlots.RANGED_WEAPON):
            self.throw_rock()
            return

        weapon = self.parent.equipment.get(EquipmentSlots.RANGED_WEAPON)