def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths # (for example through other rooms) if for example the player is in a corridor, # it makes sense to keep the path size relatively low to keep the monsters from running # around the map if there's an alternative path really far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths (ex. monster blocking cooridor) # it will still try to move towards the player (closer to the corridor opening) self.move_towards(target.x, target.y, game_map, entities) # Delete path to free memory libtcod.path_delete(my_path)
def move_astar(self, target): # Moves object towards a target using the A* pathfinding algorithm # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(MAP_WIDTH, MAP_HEIGHT) # Scane the current map each turn and set all the walls as unwalkable for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): libtcod.map_set_properties(fov, x1, y1, not gameMap.map[x1][y1].block_sight, not gameMap.map[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Also check that the objects isn't self or the target (so that the start and the end points are free # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for obj in gameMap.objects: if obj.blocks and obj != self and obj != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, obj.x, obj.y, True, False) # Allocate an A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths # (for example through other rooms) if for example the player is in a corridor. # It makes sense to keep path size relatively low to keep the monsters from running # around the map if there's an alternative path really far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path (x, y) = libtcod.path_walk(my_path, True) if x or y: self.position = (x, y) else: # Keep the old move function as a backup so that if there are no paths (for example another # monster blocks a corridor) it will still try to move towards the player # (closer to the corridor opening) self.move_towards(target) # Delete the path to free memory libtcod.path_delete(my_path)
def updatePathToNearestTarget(self, x, y, worldMap, targets): if self.FOV < 3: return None shortestPathLength = 100 targetObject = None for item in targets: path = libtcod.path_new_using_map(self.FOV, 1) libtcod.path_compute(path, x, y, item.x, item.y) if not libtcod.path_is_empty(path): length = libtcod.path_size(path) if length < shortestPathLength: shortestPathLength = length self.path = path self.newPath = True targetObject = item return targetObject
def move_astar(self, target, entities, game_map): # Create FOV map w dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan current map each turn, set walls unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all objects to see if there are objects that must be navigated around for entity in entities: if entity.blocks and entity != self and entity != target: # Set tile as wall so it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate A* path # 1.41 is the normal diagonal cost of moving, set to 0.0 if diagonal moves prohibited my_path = libtcod.path_new_using_map(fov, 1.41) # Compute path between self coords and target coords libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check path exists and shorter than 25 tiles # Path size matters if you want monsters to use alternative longer paths # ex if thru other rooms if player in corridor # Keep path size relatively low to keep monsters from running around the map if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find next coords in computed path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coords to next path tile self.x = x self.y = y else: # Keep old move function as backup so if there are no paths (monster blocking exit) # it will still try to move towards the player self.move_towards(target.x, target.y, game_map, entities) # Delete path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Creates a FOV map that contains the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and sets the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scans all the objects to see if there is any obstacles to navigate around # Checks that the object isn't itself or the target to ensure that the start and end points are free # If AI is next to the target then it will not use the A* approach for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* Path # 1.41 is set as the normal diagonal cost of moving and will be set to 0.0 if diagonal movements are not # possible my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between itself's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Checks if the path exists - the current path size is 25 tiles if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Finds the coordinates in the computed path x, y = libtcod.path_walk(my_path, True) if x or y: # Sets the coordinates to the next path tile self.x = x self.y = y else: # Uses the other move function as a backup incase if there is no paths for A* # Moves towards the target self.move_towards(target.x, target.y, game_map, entities) # Deletes the path libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): #create FOV map with dimensions of map fov = libtcod.map_new(game_map.width, game_map.height) #scan for and mark walls as blocked for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) #scan all obj to see if they must be navigated around #also check obj isn't self or target #AI class handles case if self adj to target for entity in entities: if entity.blocks and entity != self and entity != target: #set tile as wall, so will be moved around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) #Allocate A* path # 1.41 is normal cost of diagonal, 0.0 if prohib my_path = libtcod.path_new_using_map(fov, 1.41) #compute path from self to target libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) #check if path eists, and < 25 tiles #path size matters if alt longer paths wanted if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y, = libtcod.path_walk(my_path, True) if x or y: #set self coord to next tile on path self.x = x self.y = y else: #normal move as fallback self.move_towards(target.x, target.y, game_map, entities) #delete path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = initialize_fov(game_map) for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = tcod.path_new_using_map(fov, 1) tcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = tcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) tcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create FOV map with dimensions of game map fov = libtcod.map_new(game_map.width, game_map.height) # Scan current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or target (so start and end points are free # AI class handles case where self is next to target so no need to worry about that case for entity in entities: if entity != self and entity != target and entity.blocks: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate A* path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute path between self and target libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if path exists, and if the path is shorter than 25 tiles # Makes sense to keep path size low to prevent monsters running around the map if there's an # alternate path far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find next coordinates in the path x, y = libtcod.path_walk(my_path, True) if x or y: # Update coordinates to next tile self.x = x self.y = y else: # Kept as backup so that if there are no paths, it will still try to move towards the player self.move_towards(target.x, target.y, game_map, entities) # free memory libtcod.path_delete(my_path)
def find_path(source, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = tcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): tcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked, ) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != source and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, entity.pos.x, entity.pos.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = tcod.path_new_using_map(fov, 0.0) # Compute the path between self's coordinates and the target's coordinates tcod.path_compute(my_path, source.pos.x, source.pos.y, target.pos.x, target.pos.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths (for example through other # rooms) if for example the player is in a corridor. It makes sense to keep path size relatively low to keep # the monsters from running around the map if there's an alternative path really far away has_path = not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25 # Delete the path to free memory tcod.path_delete(my_path) return has_path
def move_astar(self, target, entities, game_map): fov = tcod.map_new(game_map.width, game_map.height) for y1 in range(game_map.height): for x1 in range(game_map.width): tcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) for entity in entities: if entity.blocks and entity != self and entity != target: tcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = tcod.path_new_using_map(fov, 1.41) tcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: x, y = tcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) tcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): fov = game_map.new_fov_map() for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = libtcod.path_new_using_map(fov, 1.41) libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): """ Utilise l'algorithme de recherche de chemin A* pour le déplacement d'un monstre en direction du joueur. Est appelé dans ai.BasicMonster Parametres: ---------- target : Entity entities : list game_map : GameMap Renvoi: ------- Aucun """ fov = libtcod.map_new(game_map.width, game_map.height) for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = libtcod.path_new_using_map(fov, 1.41) libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, fov_map, game_map, entities): fov_map_astar = fov_map # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov_map_astar, entity.x, entity.y, True, False) # Allocate a A* path my_path = libtcod.path_new_using_map(fov_map_astar, 1.4) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths # (for example through other rooms) if for example the player is in a corridor # It makes sense to keep path size relatively low to keep the monsters from running # around the map if there's an alternative path really far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 10: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths # (for example another monster blocks a corridor). It will still try # to move towards the player (closer to the corridor opening) self.move_towards(target, game_map, entities) # Delete the path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isnt self or the target (so that the start and end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so that it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self coords and target coords libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check path Exists, then also make sure the path is shorter than 25 tiles # Path size matters if you want the monster to use alternative longer paths # It makes sense to keep path size low here if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coords to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup if there are no paths # It will still try to move towards the player self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create FOV map that has the deminision of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, int(self.x), int(self.y), int(target.x), int(target.y)) if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: # Keep the old move function as a backup, if there are no paths self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create another FOV map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the map and set walls as blocked for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan for entities to path around for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # NOTE: The diagonal movement cost is defined here, might want to put in a config somewhere my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # If the path exists and is not too long, walk along if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y # Use dumber pathfinding to just get closer if there is no complete path else: self.move_towards(target.x, target.y, game_map, entities) # Deallocate path libtcod.path_delete(my_path)
def test_astar(map_): astar = libtcodpy.path_new_using_map(map_) assert not libtcodpy.path_compute(astar, *POINTS_AC) assert libtcodpy.path_size(astar) == 0 assert libtcodpy.path_compute(astar, *POINTS_AB) assert libtcodpy.path_get_origin(astar) == POINT_A assert libtcodpy.path_get_destination(astar) == POINT_B libtcodpy.path_reverse(astar) assert libtcodpy.path_get_origin(astar) == POINT_B assert libtcodpy.path_get_destination(astar) == POINT_A assert libtcodpy.path_size(astar) != 0 assert libtcodpy.path_size(astar) > 0 assert not libtcodpy.path_is_empty(astar) for i in range(libtcodpy.path_size(astar)): x, y = libtcodpy.path_get(astar, i) while (x, y) != (None, None): x, y = libtcodpy.path_walk(astar, False) libtcodpy.path_delete(astar)
def test_astar(map_): astar = libtcodpy.path_new_using_map(map_) assert not libtcodpy.path_compute(astar, *POINTS_AC) assert libtcodpy.path_size(astar) == 0 assert libtcodpy.path_compute(astar, *POINTS_AB) assert libtcodpy.path_get_origin(astar) == POINT_A assert libtcodpy.path_get_destination(astar) == POINT_B libtcodpy.path_reverse(astar) assert libtcodpy.path_get_origin(astar) == POINT_B assert libtcodpy.path_get_destination(astar) == POINT_A assert libtcodpy.path_size(astar) != 0 assert libtcodpy.path_size(astar) > 0 assert not libtcodpy.path_is_empty(astar) for i in range(libtcodpy.path_size(astar)): x, y = libtcodpy.path_get(astar, i) while (x, y) != (None, None): x, y = libtcodpy.path_walk(astar, False) libtcodpy.path_delete(astar)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute path libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check exists and path is short if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) # Delete path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as un-walkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around (and obj != self/target) for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate an A* path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def wander(self, **kwargs): _map = kwargs.get('map') fov_map = kwargs.get('fov_map') objects = kwargs.get('objects') player = kwargs.get('player') if not self.saw_player(fov_map, player): if self.destination is not None: path = self.set_path(_map, objects, self.destination, player) if not libtcod.path_is_empty( path[0]) and libtcod.path_size(path[0]) < 25: # self.destination self.brain.active_state = self.investigate self.path = path rand_dir_x = random.randint(-1, 1) rand_dir_y = random.randint(-1, 1) self.owner.move(rand_dir_x, rand_dir_y, _map, fov_map, objects) self.destination = None else: self.brain.active_state = self.chase
def Entity_Move(self, Self_X, Self_Y, Target_x, Target_y): # Checks for a number of entities which hold specific tags, (Hostile, Alien, etc) are on the current map. # Uses A* pathing fov = tcod.map_new(MAP_WIDTH, MAP_HEIGHT) for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): tcod.map_set_properties(fov, x1, y1, not map[x1][y1].block_sight, not map[x1][y1].blocked) for Entity, (Position, Blocks) in self.world.get_components(Components.Position, Components.Move_Through): if Blocks and not self.world.has_component(Entity, Components.Player): tcod.map_set_properties(fov, Position.X, Position.Y, True, False) My_Path = tcod.path_new_using_map(fov, 1.41) tcod.path_compute(My_Path, Self_X, Self_Y, Target_x, Target_y) if not tcod.path_is_empty(My_Path) and tcod.path_size(My_Path) < 25: x, y = tcod.path_walk(My_Path, True) if x or y: tcod.path_delete(My_Path) return x, y else: tcod.path_delete(My_Path) return Self_X, Self_Y
def perform(self, *args, **kwargs): # Create a FOV map that has the dimensions of the map # DeprecationWarning: Call tcod.map.Map(width, height) instead. # fov = tcod.map_new(self.stage.width, self.stage.height) fov = tcod.map.Map(width=self.stage.width, height=self.stage.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(self.stage.height): for x1 in range(self.stage.width): # DeprecationWarning: Set properties using the m.transparent and m.walkable arrays. # tcod.map_set_properties( fov, x1, y1, not self.stage.tiles[x1][y1].block_sight, not self.stage.tiles[x1][y1].blocks) fov.transparent[y1, x1] = not self.stage.tiles[x1][y1].block_sight fov.walkable[y1, x1] = not self.stage.tiles[x1][y1].blocks # Scan all the objects to see if there are objects that must be navigated # around. Check also that the object isn't self or the target (so that # the start and the end points are free). The AI class handles the # situation if self is next to the target so it will not use this A* function # anyway for entity in self.stage.entities: if entity.blocks and entity != self and entity != self.target: # Set the tile as a wall so it must be navigated around # tcod.map_set_properties(fov, entity.x, entity.y, True, False) fov.walkable[entity.y, entity.x] = False # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 # if diagonal moves are prohibited # PendingDeprecationWarning: This function may be deprecated in the future. my_path = tcod.path_new_using_map(m=fov, dcost=1.41) # Compute the path between self's coordinates and the target's coordinates # PendingDeprecationWarning: This function may be deprecated in the future. # Returns a boolean... tcod.path_compute( p=my_path, ox=self.entity.x, oy=self.entity.y, dx=self.target.x, dy=self.target.y ) # Check if the path exists, and in this case, also the path is shorter # than 25 tiles. The path size matters if you want the monster to use # alternative longer paths (for example through other rooms) if for # example the player is in a corridor. It makes sense to keep path size # relatively low to keep the monsters from running around the map if # there's an alternative path really far away # PendingDeprecationWarning: This function may be deprecated in the future. print(tcod.path_size(my_path)) print(my_path) if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path # PendingDeprecationWarning: This function may be deprecated in the future. x, y = tcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile dx, dy = self.stage.calc_dxdy(self.entity.x, self.entity.y, x, y) print(dx, dy) # DeprecationWarning: libtcod objects are deleted automatically. # tcod.path_delete(my_path) return ActionResult( success=True, alt=WalkAction(dx, dy) ) # Keep the old move function as a backup so that if there are no paths # (for example another monster blocks a corridor) it will still try to # move towards the player (closer to the corridor opening) # self.move_towards(self.target.x, self.target.y, self.stage) # DeprecationWarning: libtcod objects are deleted automatically. # tcod.path_delete(my_path) return ActionResult( success=True, alt=MoveTowardAction(self.stage, self.entity, self.target) )
def move_astar(self, target, entities, game_map): fov_map = tcod.map.Map(game_map.width, game_map.height) fov_map.walkable[:] = True fov_map.transparent[:] = True for y1 in range(game_map.height): for x1 in range(game_map.width): if game_map.tiles[x1][y1].blocked or game_map.tiles[x1][ y1].blocking_entity: fov_map.walkable[y1, x1] = False if game_map.tiles[x1][y1].block_sight: fov_map.transparent[y1, x1] = False for entity in entities["monsters"]: if entity.blocks and entity != self and entity != target: fov_map.walkable[entity.y, entity.x] = False if entity.occupied_tiles is not None: fov_map.walkable[entity.y + 1, entity.x + 1] = False fov_map.walkable[entity.y, entity.x + 1] = False fov_map.walkable[entity.y + 1, entity.x] = False fov_map.transparent[entity.y, entity.x] = True for entity in entities["allies"]: if entity.blocks and entity != self and entity != target: fov_map.walkable[entity.y, entity.x] = False if entity.occupied_tiles is not None: fov_map.walkable[entity.y + 1, entity.x + 1] = False fov_map.walkable[entity.y, entity.x + 1] = False fov_map.walkable[entity.y + 1, entity.x] = False fov_map.transparent[entity.y, entity.x] = True # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 # if diagonal moves are prohibited astar = tcod.path.AStar(fov_map) # Compute the path between self's coordinates and the target's # coordinates tcod.path_compute(astar, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths # (for example through other rooms) if for example the player is in a corridor # It makes sense to keep path size relatively low to keep the monsters # from running around the map if there's an alternative path really far # away if not tcod.path_is_empty(astar) and tcod.path_size(astar) < 25: # Find the next coordinates in the computed full path x, y = tcod.path_walk(astar, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y if self.occupied_tiles is not None: self.occupied_tiles = [(x, y), (x, y + 1), (x + 1, y + 1), (x + 1, y)] else: # Keep the old move function as a backup so that if there are no paths # (for example another monster blocks a corridor) # it will still try to move towards the player (closer to the # corridor opening) self.move_towards(target.x, target.y, game_map)
def act(self, game_map, player, fov_map=None, has_los=None): dist = self.owner.distance_to(player) if dist < 2: # Attack the player, even if the entity can't see return self.owner.fighter.attack_entity(player.fighter, target_is_player=True) results = {} given_fov_map = fov_map is not None if (self.owner.sight and dist <= self.owner.sight.fov_radius or self.remaining_chase_turns > 0): owner_x = self.owner.x owner_y = self.owner.y player_x = player.x player_y = player.y if given_fov_map: tcod.map_set_properties(fov_map, owner_x, owner_y, True, True) tcod.map_set_properties(fov_map, player_x, player_y, True, True) else: # This second variable is necessary as creating another # variable called fov_map might shadow the parameter rather # than changing its value fov_map = game_map.generate_fov_map_with_entities( [self.owner, player]) if self.clairvoyant: # Clairvoyant entities can always sense the player when they're # nearby has_los = True if has_los is None: self.owner.sight.get_fov(fov_map) has_los = tcod.map_is_in_fov(fov_map, owner_x, owner_y) if has_los: # If the entity can see the player, reset the chase timer self.remaining_chase_turns = self.chase_duration chase = has_los if not has_los and self.remaining_chase_turns > 0: # Entities will continue chasing the player for chase_duration, # even if they don't have line of sight chase = True self.remaining_chase_turns -= 1 if chase: # 1.41 approximates sqrt(2), the cost of a diagonal moves path = tcod.path_new_using_map(fov_map, 1.41) tcod.path_compute(path, owner_x, owner_y, player_x, player_y) if not tcod.path_is_empty(path) and tcod.path_size(path) < 25: x, y = tcod.path_walk(path, True) if x or y: self.owner.move_to(x, y, game_map, face=True) else: dx = player_x - owner_x dy = player_y - owner_y dx = int(round(dx / dist)) dy = int(round(dy / dist)) if game_map.is_tile_open(owner_x + dx, owner_y + dy): self.owner.move(dx, dy, game_map) tcod.path_delete(path) if given_fov_map: tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, False) tcod.map_set_properties(fov_map, player.x, player.y, True, False) else: tcod.map_delete(fov_map) else: if given_fov_map: # Remove the entity from the given FOV map tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, True) # Wander around aimlessly self.owner.move(randint(-1, 1), randint(-1, 1), game_map) if given_fov_map: # Add the entity to the given FOV map tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, False) return results