class Action(Leaf):
    """
    Abstract component, all sub components of this type should define an
    action. A entity should be able to use the parent entity
    using the action.
    """
    def __init__(self, name="XXX_Action_Name_XXX", display_order=100, energy_cost=gametime.single_turn):
        super(Action, self).__init__()
        self.tags.add("user_action")
        self.name = name
        self.display_order = display_order
        self.energy_cost = energy_cost

    def __call__(self, *args, **kwargs):
        self.act(*args, **kwargs)

    def delayed_act(self, *args, **kwargs):
        return DelayedFunctionCall(self.act, *args, **kwargs)

    def delayed_can_act(self, *args, **kwargs):
        return DelayedFunctionCall(self.can_act, *args, **kwargs)

    def act(self, **kwargs):
        """
        The action that this component defines.
        """
        pass

    def can_act(self, **kwargs):
        """
        Returns true if it is valid to call the act method.
        """
        return True

    def add_energy_spent_to_entity(self, entity):
        """
        Help method for spending energy for the act performing entity.
        """
        entity.actor.newly_spent_energy += self.energy_cost 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 RemoveChildEffect(EntityEffect):
    def __init__(self, source_entity, component_type, time_to_live, meld_id=None):
        super(RemoveChildEffect, self).__init__(source_entity=source_entity,
                                                effect_type=EffectTypes.REMOVE_CHILD,
                                                time_to_live=time_to_live,
                                                meld_id=meld_id)
        self.component_type = component_type

    def update(self, time_spent):
        self.target_entity.remove_component_of_type(self.component_type)
        self.tick(time_spent) class AddSpoofChild(EntityEffect):
    def __init__(self, source_entity, spoof_child, time_to_live, message_effect=None, meld_id=None, effect_id=None,
                 status_description=None):
        super(AddSpoofChild, self).__init__(source_entity=source_entity,
                                            effect_type=EffectTypes.ADD_SPOOF_CHILD,
                                            time_to_live=time_to_live,
                                            meld_id=meld_id,
                                            effect_id=effect_id)
        self.status_description = status_description
        self.message_effect = message_effect
        self.spoof_child = spoof_child

    def update(self, time_spent):
        self.target_entity.add_spoof_child(self.spoof_child)
        if self.message_effect:
            self.message()
        self.update_status_icon()
        self.tick(time_spent)

    def update_status_icon(self):
        if self.status_description and self.target_entity.has("status_bar"):
            self.target_entity.status_bar.add(self.status_description)

    def message(self):
        messenger.msg.send_visual_message(
            self.message_effect % {"source_entity": self.source_entity.description.long_name,
                                   "target_entity": self.target_entity.description.long_name},
            self.target_entity.position.value) class BeforeAttackEffect(Leaf):
    TAG = "before_attack_effect"

    def __init__(self, effect_chance):
        super(BeforeAttackEffect, self).__init__()
        self.effect_chance = effect_chance
        self.tags.add(BeforeAttackEffect.TAG)

    def roll_to_hit(self):
        return random.random() < self.effect_chance

    def before_attack_effect(self, source_entity, target_entity):
        pass 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) class DamageTakenEffect(Leaf):
    """
    Subclasses may define an effect that happens when parent takes damage.
    """

    def __init__(self):
        super(DamageTakenEffect, self).__init__()
        self.tags.add("damage_taken_effect")

    def effect(self, damage, source_entity, damage_types=[]):
        pass EQUIP_MESSAGE = "%(source_entity)s equips %(item)s."
UNEQUIP_MESSAGE = "%(source_entity)s puts away %(item)s."
HEAL_MESSAGE = "%(source_entity)s heals %(target_entity)s for %(health)s health."
HEALTH_POTION_MESSAGE = "The health potion heals %(target_entity)s for %(health)s health."
DISSOLVE_MESSAGE = "%(source_entity)s dissolves %(target_entity)s for %(damage)s damage."
HIT_MESSAGE = "%(source_entity)s hits %(target_entity)s for %(damage)s damage."
MISS_MESSAGE = "%(source_entity)s misses %(target_entity)s."
CRIT_MESSAGE = "%(source_entity)s critically hits %(target_entity)s for %(damage)s damage."
HAUNT_MESSAGE = "%(source_entity)s haunts the %(target_entity)s!"
HEART_STOP_MESSAGE = "%(target_entity)s clutches its heart."
DARKNESS_MESSAGE = "An unnatural darkness fills the dungeon."
PICK_UP_MESSAGE = "You pick up %(item)s."
POISON_MESSAGE = "%(target_entity)s takes %(damage)s in poison damage."
BLEED_MESSAGE = "%(target_entity)s is bleeding out %(damage)s damage."
DOWN_STAIRS_HEAL_MESSAGE = "Your feel vitalized by your progress, you regain %(health)s health."
FALL_DOWN_MESSAGE = "You take a damage of %(damage)s from the fall."
DRINK_FOUNTAIN_MESSAGE = "You drink from the fountain, your max health increases by %(health)s."
HURT_BY_EXPLOSION = "The explosion blasts %(target_entity)s for %(damage)s damage."
HURT_BY_FIRE = "The fire burns %(target_entity)s for %(damage)s damage."
WONT_BREAK_OUT_OF_WEB_MESSAGE = "%(target_entity)s is stuck in the spider web."
BREAKS_OUT_OF_WEB_MESSAGE = "%(target_entity)s breaks free."
WANT_TO_JUMP_DOWN_CHASM = "Are you sure you want to drop down the chasm?"
PRESS_ENTER_TO_ACCEPT = "Press ENTER to accept, another key to reject."
PLAYER_TELEPORT_MESSAGE = "Your surroundings seem different."
PLAYER_SWITCH_MESSAGE = "Your surrounding is replaced."
PLAYER_MAP_MESSAGE = "You surroundings suddenly seem familiar."
PLAYER_PUSH_SCROLL_MESSAGE = "You as you form the words of the scroll your voice turns into a strong wind."
GLASS_TURNING_MESSAGE = "You surroundings suddenly seem more transparent."
SWAP_DEVICE_MESSAGE = "Your surroundings has changed."
ZAP_DEVICE_MESSAGE = "%(source_entity)s zaps %(target_entity)s for %(damage)s damage!"
HEALTH_DEVICE_MESSAGE = "%(target_entity)s is healed by the device for %(health)s health."
STARE_PARALYZE_MESSAGE = "%(source_entity)s stares at %(target_entity)s, it's paralyzed!."
NO_LONGER_PARALYZED_MESSAGE = "%(source_entity)s is no longer paralyzed."
FROST_POTION_DRINK_MESSAGE = "That potion was cold as ice! You feel yourself slow down."
FROST_POTION_BREAKS_MESSAGE = "The potion smashes to the ground and creates a freezing cloud of mist!"
POTION_SMASHES_AGAINST_FLOOR_MESSAGE = "The potion smashes to the ground and breaks into pieces."
FLAME_POTION_DRINK_MESSAGE = "As you drink the potion the liquid ignites!"
FLAME_POTION_BREAKS_MESSAGE = "The potion smashes to the ground and creates a roaring fire!"
POISON_POTION_DRINK_MESSAGE = "The potion tastes really nasty, you feel sick!"
POISON_POTION_BREAK_MESSAGE = "The potion smashes to the ground and creates a poisonous cloud of gas!"
POTION_SMASH_TO_GROUND = "The %(target_entity)s smashes to the ground and breaks into pieces."
ITEM_HITS_THE_GROUND_HEAVY = "The %(target_entity)s hits the ground with a thud."
ITEM_HITS_THE_GROUND_LIGHT = "The %(target_entity)s falls to the ground."
ITEM_FALLS_DOWN_CHASM = "The %(target_entity)s falls into the chasm and disappears."
ENTITY_EXPLODES = "%(target_entity)s explodes!"
class Messenger(object):
class Message(object):
    def __init__(self):
    def has_new_message(self):
    def has_new_message(self, value):
    def send_visual_message(self, new_message, position):
    def send_global_message(self, new_message):
    def _message(self, new_message):
    def tail(self, length):
    def clear(self):
    def __init__(self, message):
    def increase(self):
    def tick(self):
    def __str__(self): 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 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() 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
import random
import Status
import colors
import gametime
import geometry as geo
import direction
import rng
from action import Action
from compositecore import Leaf
from entityeffect import RemoveChildEffect, AddSpoofChild
from equipmenteffect import BeforeAttackEffect
from graphic import GraphicChar
from health import DamageTakenEffect
from messenger import msg
from stats import DataPoint, DataTypes
from statusflags import StatusFlags
from actor import Actor
        #    return False

    def update_monster_actor_state(self):
        # Perform Stealth Check
        if self.notice_player_check():
            self.parent.monster_actor_state.value = MonsterActorState.HUNTING
        elif (not self.can_see_player() and  # forget player check.
                      self.parent.monster_actor_state.value == MonsterActorState.HUNTING and
                  rng.coin_flip() and rng.coin_flip() and rng.coin_flip()):
            self.parent.monster_actor_state.value = MonsterActorState.WANDERING


class StepRandomDirectionActor(MonsterActor):
    """
    Standard Monster AI will chase the player.
    """

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

    def _act(self):
        return self.try_step_random_direction()


class ChasePlayerActor(MonsterActor):
    """
    Standard Monster AI will chase the player.
    """

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

    def no_action_taken(self):
        return self.newly_spent_energy <= 0

    def _act(self):
        self.parent.dungeon_mask.update_fov()
        self.newly_spent_energy = 0

        self.update_monster_actor_state()

        self.set_path_to_player_if_seen()
        if not self.parent.path.has_path() and not self._is_standing_on_player():
            self.set_path_to_random_walkable_point()

        # Do action
        self.try_do_weighted_action()
        if self.no_action_taken() and self.parent.path.has_path():
            self.newly_spent_energy += self.parent.path.try_step_path()
        if self.no_action_taken():
            self.newly_spent_energy += gametime.single_turn
        return self.newly_spent_energy

    def _is_standing_on_player(self):
        player = self.get_player_if_seen()
        if player is None:
            return False
        return self.parent.position.value == player.position.value


class KeepPlayerAtDistanceActor(MonsterActor):
    """
    Standard Monster AI will chase the player.
    """

    def __init__(self, optimal_distance):
        super(KeepPlayerAtDistanceActor, self).__init__()
        self.optimal_distance = optimal_distance

    def _act(self):
        self.parent.dungeon_mask.update_fov()
        self.newly_spent_energy = 0

        self.update_monster_actor_state()

        self.try_do_weighted_action()
        if not self._keep_player_at_distance():
            self.try_step_random_direction()

        if self.newly_spent_energy == 0:
            self.newly_spent_energy = gametime.single_turn
        return self.newly_spent_energy

    def distance_to_optimal_distance(self, position1, position2):
        return abs(geo.chess_distance(position1, position2) - self.optimal_distance)

    def _keep_player_at_distance(self):
        player = self.get_player_if_seen()
        if player is None:
            return False

        if not self.parent.monster_actor_state.value == MonsterActorState.HUNTING:
            return False

        current_distance_to_optimal = self.distance_to_optimal_distance(self.parent.position.value,
                                                                        player.position.value)
        if current_distance_to_optimal == 0:
            return True

        for d in direction.get_shuffled_directions():
            possible_step = geo.add_2d(d, self.parent.position.value)
            if (self.distance_to_optimal_distance(possible_step, player.position.value)
                    < current_distance_to_optimal):
                energy_used = self.parent.stepper.try_step_in_direction(d)
                if energy_used > 0:
                    self.newly_spent_energy += energy_used
                    return True
        return False


class HuntPlayerIfHurtMe(DamageTakenEffect):
    def __init__(self):
        super(HuntPlayerIfHurtMe, self).__init__()
        self.component_type = "hunt_player_if_hurt_me"

    def effect(self, _, source_entity, damage_types=[]):
        if source_entity and source_entity.has("is_player"):
            self.parent.monster_actor_state.value = MonsterActorState.HUNTING



class StartHuntOnAttack(BeforeAttackEffect):