class SpritePatrol(State): def __init__(self, sprite, ai): super(SpritePatrol, self).__init__(cfg.SpriteState.PATROL) self.sprite = sprite self.ai = ai self.enter_timer = Timer() self.view_sensor_timer = Timer(ai.VIEW_SENSOR_TICK) def choose_a_backside_direction(self, current_direction): total = cfg.Direction.TOTAL opposite_direction = (current_direction + 4) % total return choice([(opposite_direction - 1) % total, opposite_direction, (opposite_direction + 1) % total]) def enter(self, last_state): self.enter_timer.begin(gauss(self.ai.WALK_TIME_MU, self.ai.WALK_TIME_SIGMA)) self.sprite.direction = self.choose_a_backside_direction(self.sprite.direction) def send_actions(self): if self.view_sensor_timer.is_begin(): if self.view_sensor_timer.exceed(): self.view_sensor_timer.begin() return (cfg.EnemyAction.LOOKOUT, cfg.EnemyAction.WALK) else: return (cfg.EnemyAction.WALK, ) else: self.view_sensor_timer.begin() return (cfg.EnemyAction.WALK, ) def check_conditions(self): sp = self.sprite if sp.brain.target is not None: sp.set_emotion(cfg.SpriteEmotion.ALERT) if sp.attacker.chance(sp.brain.target): #print "patrol to attack" return cfg.SpriteState.OFFENCE if happen(self.ai.PATROL_TO_CHASE_PROB): #print "patrol to chase" return cfg.SpriteState.CHASE return cfg.SpriteState.DEFENCE if sp.brain.interrupt: sp.brain.interrupt = False return cfg.SpriteState.STAY if self.enter_timer.exceed(): return cfg.SpriteState.STAY def exit(self): self.enter_timer.clear()
class SpriteStay(State): def __init__(self, sprite, ai): super(SpriteStay, self).__init__(cfg.SpriteState.STAY) self.sprite = sprite self.ai = ai self.enter_timer = Timer() self.view_sensor_timer = Timer(ai.VIEW_SENSOR_TICK) def enter(self, last_state): self.enter_timer.begin(gauss(self.ai.STAY_TIME_MU, self.ai.STAY_TIME_SIGMA)) # turn for a random direction if the last state is the same "stay" if last_state and last_state.id == cfg.SpriteState.STAY \ and happen(self.ai.STAY_CHANGE_DIRECTION_PROB): self.sprite.direction = choice(cfg.Direction.ALL) # a random direction from "all" if happen(self.ai.EMOTION_SILENT_PROB): self.sprite.set_emotion(cfg.SpriteEmotion.SILENT) def send_actions(self): if self.view_sensor_timer.is_begin(): if self.view_sensor_timer.exceed(): self.view_sensor_timer.begin() return (cfg.EnemyAction.LOOKOUT, cfg.EnemyAction.STAND) else: return (cfg.EnemyAction.STAND, ) else: self.view_sensor_timer.begin() return (cfg.EnemyAction.STAND, ) def check_conditions(self): sp = self.sprite if sp.brain.target is not None: sp.set_emotion(cfg.SpriteEmotion.ALERT) # discover a target if happen(self.ai.STAY_TO_OFFENCE_PROB) and sp.attacker.chance(sp.brain.target): #print "to attack" return cfg.SpriteState.OFFENCE if happen(self.ai.STAY_TO_CHASE_PROB): return cfg.SpriteState.CHASE return cfg.SpriteState.DEFENCE if self.enter_timer.exceed(): if happen(self.ai.STAY_TO_PATROL_PROB): #print "stay to patrol" return cfg.SpriteState.PATROL else: return cfg.SpriteState.STAY def exit(self): self.enter_timer.clear()
class SpriteDefence(State): def __init__(self, sprite, ai): super(SpriteDefence, self).__init__(cfg.SpriteState.DEFENCE) self.sprite = sprite self.ai = ai self.enter_timer = Timer() #self.action_to_do = cfg.EnemyAction.STAND def enter(self, last_state): self.enter_timer.begin(gauss(self.ai.DEFENCE_TIME_MU, self.ai.DEFENCE_TIME_SIGMA)) sp = self.sprite sp.direction = cal_face_direct(sp.pos.as_tuple(), sp.brain.target.pos.as_tuple()) #if sp.hp_status == cfg.HpStatus.DANGER and happen(self.ai.DEFENCE_BACKWARD_PROB): # self.action_to_do = cfg.EnemyAction.BACKWARD #else: # self.action_to_do = cfg.EnemyAction.STAND def send_actions(self): return (cfg.EnemyAction.STAND, ) #return (self.action_to_do, ) def check_conditions(self): sp = self.sprite if self.enter_timer.exceed(): if happen(self.ai.DEFENCE_TO_OFFENCE_PROB) and sp.attacker.chance(sp.brain.target): return cfg.SpriteState.OFFENCE distance_to_target = sp.pos.get_distance_to(sp.brain.target.pos) if happen(self.ai.DEFENCE_TO_CHASE_PROB) and distance_to_target <= self.ai.CHASE_RANGE : return cfg.SpriteState.CHASE if distance_to_target > self.ai.CHASE_RANGE: sp.brain.target = None return cfg.SpriteState.STAY return cfg.SpriteState.DEFENCE else: sp.direction = cal_face_direct(sp.pos.as_tuple(), sp.brain.target.pos.as_tuple()) def exit(self): self.enter_timer.clear()
class SpriteOffence(State): def __init__(self, sprite, ai): super(SpriteOffence, self).__init__(cfg.SpriteState.OFFENCE) self.sprite = sprite self.ai = ai self.enter_timer = Timer() def enter(self, last_state): sp = self.sprite sp.brain.persistent = True sp.direction = cal_face_direct(sp.pos.as_tuple(), sp.brain.target.pos.as_tuple()) self.enter_timer.begin(gauss(self.ai.OFFENCE_GO_DELAY_TIME_MU, self.ai.OFFENCE_GO_DELAY_TIME_SIGMA)) def send_actions(self): if not self.enter_timer.exceed(): # add delay time for attack return (cfg.EnemyAction.STAND, ) sp = self.sprite return (cfg.EnemyAction.ATTACK, ) if sp.brain.persistent else (cfg.EnemyAction.STAND, ) def check_conditions(self): sp = self.sprite if sp.brain.persistent: return if sp.attacker.chance(sp.brain.target): return cfg.SpriteState.OFFENCE if happen(self.ai.OFFENCE_TO_CHASE_PROB): return cfg.SpriteState.CHASE return cfg.SpriteState.DEFENCE def exit(self): self.enter_timer.clear() self.sprite.brain.persistent = False
class SpriteChase(State): def __init__(self, sprite, ai, waypoints): super(SpriteChase, self).__init__(cfg.SpriteState.CHASE) self.sprite = sprite self.ai = ai self.pathfinder = pathfinding.Astar(sprite, waypoints) self.steerer = Steerer(sprite) self.enter_timer = Timer() self.target_move_threshold = sfg.WayPoint.STEP_WIDTH * 4 def enter(self, last_state): sp = self.sprite if last_state and last_state.id in (cfg.SpriteState.STAY, cfg.SpriteState.PATROL): # discover hero right now, record the time for action delay self.enter_timer.begin(self.ai.CHASE_GO_DELAY_TIME) sp.direction = cal_face_direct(sp.pos.as_tuple(), sp.brain.target.pos.as_tuple()) sp.brain.destination = sp.brain.target.pos.copy() path = self.pathfinder.find(sp.brain.destination.as_tuple(), sfg.WayPoint.STEP_WIDTH * 2) self.steerer.init(path) def send_actions(self): if self.enter_timer.is_begin() and not self.enter_timer.exceed(): # delay chase action for a more real effect return (cfg.EnemyAction.STAND, ) if self.steerer.is_ok: self.steerer.run() if not self.steerer.is_end: return (cfg.EnemyAction.STEER, ) return (cfg.EnemyAction.STAND, ) def check_conditions(self): sp = self.sprite if happen(self.ai.CHASE_TO_OFFENCE_PROB) and sp.attacker.chance(sp.brain.target): #print "to attack" return cfg.SpriteState.OFFENCE if (not self.steerer.is_ok) or happen(self.ai.CHASE_TO_DEFENCE_PROB): return cfg.SpriteState.DEFENCE distance_to_target = sp.pos.get_distance_to(sp.brain.target.pos) if distance_to_target <= self.ai.CHASE_RANGE: target_move = sp.brain.destination.get_distance_to(sp.brain.target.pos) if target_move > self.target_move_threshold or self.steerer.is_end: #print "chase to chase" return cfg.SpriteState.CHASE else: # lose target #print "lose target" sp.brain.target = None sp.set_emotion(cfg.SpriteEmotion.CHAOS) return cfg.SpriteState.STAY def exit(self): self.sprite.brain.destination = None self.enter_timer.clear()