예제 #1
0
 def get_up_down_left_right_neighbors(self, coord):
     tiles = self.level.tiles
     neighbors = (
         tiles[add_vector(coord, Dir.North)],
         tiles[add_vector(coord, Dir.South)],
         tiles[add_vector(coord, Dir.West)],
         tiles[add_vector(coord, Dir.East)],
     )
     return neighbors
예제 #2
0
 def get_up_down_left_right_neighbors(self, coord):
     tiles = self.level.tiles
     neighbors = (
         tiles[add_vector(coord, Dir.North)],
         tiles[add_vector(coord, Dir.South)],
         tiles[add_vector(coord, Dir.West)],
         tiles[add_vector(coord, Dir.East)],
     )
     return neighbors
예제 #3
0
 def look(self):
     coord = self.coord
     drawline_flag = False
     direction = Dir.Stay
     while True:
         new_coord = add_vector(coord, direction)
         if self.actions.level.is_legal(new_coord):
             coord = new_coord
         self.io.msg(self.actions.level.look_information(coord))
         if drawline_flag:
             self.io.draw_line(self.coord, coord, ("*", Pair.Yellow))
             self.io.draw_line(coord, self.coord, ("*", Pair.Yellow))
             self.io.msg("LoS: {}".format(self.actions.level.check_los(self.coord, coord)))
         if coord != self.coord:
             symbol, (foreground, background) = self.actions.level.visible_char(coord)
             char = symbol, (foreground, Color.Green)
             self.io.draw_char(char, coord)
             self.io.draw_char(self.actions.level.visible_char(self.coord), self.coord, reverse=True)
         key = self.io.get_key()
         self.actions.redraw()
         direction = Dir.Stay
         if key in Bind.Directions:
             direction = Dir.from_key[key]
         elif key == 'd':
             drawline_flag = not drawline_flag
         elif key == 'b':
             from generic_algorithms import bresenham
             for coord in bresenham(self.actions.level.get_coord(self.coord), coord):
                 self.io.msg(coord)
         elif key == 's':
             if coord in self.actions.level.creatures:
                 self.actions.game.register_status_texts(self.actions.level.creatures[coord])
         elif key in Bind.Cancel or key in Bind.Look_Mode:
             break
예제 #4
0
    def _move_towards(self, target_coord):
        best_action = Action.Move
        best_direction = Dir.Stay
        best_cost = None
        for direction in Dir.AllPlusStay:
            coord = add_vector(self.coord, direction)
            if self.level.is_passable(coord):
                action = Action.Move
            elif coord in self.level.creatures and self.actions.willing_to_swap(
                    self.level.creatures[coord]):
                action = Action.Swap
            else:
                continue

            cost = self.level.distance_heuristic(coord, target_coord)
            if best_cost is None or cost < best_cost:
                best_action = action
                best_direction = direction
                best_cost = cost

        if best_action == Action.Move:
            return self.actions.move(best_direction)
        elif best_action == Action.Swap:
            return self.actions.swap(best_direction)
        else:
            assert False, "AI state bug. Best action was: {}".format(
                best_action)
예제 #5
0
    def _move_towards(self, target_coord):
        best_action = Action.Move
        best_direction = Dir.Stay
        best_cost = None
        for direction in Dir.AllPlusStay:
            coord = add_vector(self.coord, direction)
            if self.level.is_passable(coord):
                action = Action.Move
            elif coord in self.level.creatures and self.actions.willing_to_swap(self.level.creatures[coord]):
                action = Action.Swap
            else:
                continue

            cost = self.level.distance_heuristic(coord, target_coord)
            if best_cost is None or cost < best_cost:
                best_action = action
                best_direction = direction
                best_cost = cost

        if best_action == Action.Move:
            return self.actions.move(best_direction)
        elif best_action == Action.Swap:
            return self.actions.swap(best_direction)
        else:
            assert False, "AI state bug. Best action was: {}".format(best_action)
예제 #6
0
    def movement_multiplier(self, coord, direction):
        origin_multiplier = self.tiles[coord].movement_multiplier
        target_coord = add_vector(coord, direction)
        target_multiplier = self.tiles[target_coord].movement_multiplier

        tile_multiplier = (origin_multiplier + target_multiplier) / 2
        return tile_multiplier * Dir.move_mult(direction)
예제 #7
0
    def movement_multiplier(self, coord, direction):
        origin_multiplier = self.tiles[coord].movement_multiplier
        target_coord = add_vector(coord, direction)
        target_multiplier = self.tiles[target_coord].movement_multiplier

        tile_multiplier = (origin_multiplier + target_multiplier) / 2
        return tile_multiplier * Dir.move_mult(direction)
예제 #8
0
 def act_to_dir(self, direction):
     target_coord = add_vector(self.coord, direction)
     if target_coord in self.level.creatures:
         return self.attack(direction)
     elif self.can_move(direction):
         return self.move(direction)
     else:
         return feedback(ActionError.IllegalMove)
예제 #9
0
 def can_move(self, direction):
     """Free action."""
     if direction not in Dir.AllPlusStay:
         raise ValueError("Illegal movement direction: {}".format(direction))
     elif direction == Dir.Stay:
         return True
     else:
         coord = add_vector(self.coord, direction)
         return self.level.is_legal(coord) and self.level.is_passable(coord)
예제 #10
0
def _finalize_tile(coord, tile, tiles):
    if tile != PyrlTile.Dynamic_Wall:
        return tile

    neighbor_coords = (add_vector(coord, direction) for direction in Dir.All)
    neighbor_tiles = (tiles[coord] for coord in neighbor_coords if tiles.is_legal(coord))
    rocks = (PyrlTile.Dynamic_Wall, PyrlTile.Wall, PyrlTile.Rock)
    if any(handle not in rocks for handle in neighbor_tiles):
        return PyrlTile.Wall
    else:
        return PyrlTile.Rock
예제 #11
0
    def act(self, game_actions, alert_coord):
        self.actions = game_actions

        if self.creature in self.ai_state:
            chase_coord, chase_vector = self.ai_state[self.creature]
        else:
            chase_coord, chase_vector = None, None

        if self.actions.target_in_sight(alert_coord):
            # passive actions
            if chase_coord is not None and chase_coord != alert_coord:
                chase_vector = get_vector(chase_coord, alert_coord)
            chase_coord = alert_coord

            # actions
            if self.actions.can_reach(alert_coord):
                feedback = self.actions.attack(
                    get_vector(self.coord, alert_coord))
            else:
                feedback = self._move_towards(alert_coord)

        else:
            # chasing and already at the target square and has a chase vector to pursue
            if chase_coord == self.coord:
                if chase_vector is not None:
                    # resize the chase vector to the creatures sight so the self.creature can just go there
                    chase_vector = resize_vector_to_len(
                        chase_vector, self.creature.sight)

                    # calculate a new target square
                    overarching_target = add_vector(self.coord, chase_vector)
                    chase_coord = self.level.get_last_pathable_coord(
                        self.coord, overarching_target)

                    # if an obstacle is hit end chase
                    if self.coord == chase_coord:
                        chase_coord, chase_vector = None, None
                else:
                    chase_coord = None

            # actions
            if chase_coord is not None:
                feedback = self._move_towards(chase_coord)
            else:
                feedback = self._move_random()

        if chase_coord is not None or chase_vector is not None:
            self.ai_state[self.creature] = chase_coord, chase_vector
        else:
            self.remove_creature_state(self.creature)

        assert feedback.type not in ActionError, \
            "AI state bug. Got error from game: {} {}".format(feedback.type, feedback.params)
예제 #12
0
    def act(self, game_actions, alert_coord):
        self.actions = game_actions

        if self.creature in self.ai_state:
            chase_coord, chase_vector = self.ai_state[self.creature]
        else:
            chase_coord, chase_vector = None, None

        if self.actions.target_in_sight(alert_coord):
            # passive actions
            if chase_coord is not None and chase_coord != alert_coord:
                chase_vector = get_vector(chase_coord, alert_coord)
            chase_coord = alert_coord

            # actions
            if self.actions.can_reach(alert_coord):
                feedback = self.actions.attack(get_vector(self.coord, alert_coord))
            else:
                feedback = self._move_towards(alert_coord)

        else:
            # chasing and already at the target square and has a chase vector to pursue
            if chase_coord == self.coord:
                if chase_vector is not None:
                    # resize the chase vector to the creatures sight so the self.creature can just go there
                    chase_vector = resize_vector_to_len(chase_vector, self.creature.sight)

                    # calculate a new target square
                    overarching_target = add_vector(self.coord, chase_vector)
                    chase_coord = self.level.get_last_pathable_coord(self.coord, overarching_target)

                    # if an obstacle is hit end chase
                    if self.coord == chase_coord:
                        chase_coord, chase_vector = None, None
                else:
                    chase_coord = None

            # actions
            if chase_coord is not None:
                feedback = self._move_towards(chase_coord)
            else:
                feedback = self._move_random()

        if chase_coord is not None or chase_vector is not None:
            self.ai_state[self.creature] = chase_coord, chase_vector
        else:
            self.remove_creature_state(self.creature)

        assert feedback.type not in ActionError, \
            "AI state bug. Got error from game: {} {}".format(feedback.type, feedback.params)
예제 #13
0
    def swap(self, direction):
        if self.already_acted():
            return feedback(ActionError.AlreadyActed)

        target_coord = add_vector(self.coord, direction)
        if target_coord not in self.level.creatures:
            return feedback(ActionError.NoSwapTarget)

        target_creature = self.level.creatures[target_coord]
        if not self.willing_to_swap(target_creature):
            return feedback(ActionError.SwapTargetResists)

        self.level.swap_creature(self.creature, target_creature)
        move_multiplier = self.level.movement_multiplier(self.coord, direction)
        self._do_action(self.creature.action_cost(Action.Move, move_multiplier))
        return feedback(Action.Swap, direction, target_creature)
예제 #14
0
    def attack(self, direction):
        if self.already_acted():
            return feedback(ActionError.AlreadyActed)

        target_coord = add_vector(self.coord, direction)

        if target_coord in self.level.creatures:
            target = self.level.creatures[target_coord]
        else:
            target = self.level.tiles[target_coord]

        succeeds, damage = get_melee_attack_cr(self.creature, target)
        died = False
        if damage:
            target.receive_damage(damage)
            died = target.is_dead()
        if died:
            self.game.creature_death(target)
        self._do_action(self.creature.action_cost(Action.Attack))
        self._attack_user_message(succeeds, damage, died, target)

        return feedback(Action.Attack, target, succeeds, damage, died)
예제 #15
0
 def get_passable_neighbors(self, coord):
     for direction in Dir.All:
         neighbor_coord = add_vector(coord, direction)
         if self.is_legal(neighbor_coord) and self.tiles[neighbor_coord].is_passable:
             yield direction
예제 #16
0
 def move_creature_to_dir(self, creature, direction):
     target_coord = add_vector(creature.coord, direction)
     self.move_creature(creature, target_coord)
예제 #17
0
 def get_passable_neighbors(self, coord):
     for direction in Dir.All:
         neighbor_coord = add_vector(coord, direction)
         if self.is_legal(neighbor_coord) and self.tiles[neighbor_coord].is_passable:
             yield direction
예제 #18
0
 def get_neighbor_location_coords_and_costs(self, coord):
     for direction in self.get_passable_neighbors(coord):
         neighbor_coord = add_vector(coord, direction)
         multiplier = self.movement_multiplier(coord, direction)
         yield neighbor_coord, round(multiplier * Action.Move.base_cost)
예제 #19
0
 def move_creature_to_dir(self, creature, direction):
     target_coord = add_vector(creature.coord, direction)
     self.move_creature(creature, target_coord)
예제 #20
0
 def get_neighbor_location_coords_and_costs(self, coord):
     for direction in self.get_passable_neighbors(coord):
         neighbor_coord = add_vector(coord, direction)
         multiplier = self.movement_multiplier(coord, direction)
         yield neighbor_coord, round(multiplier * Action.Move.base_cost)