def get_path_pos(self, pos1, pos2, dist): chemin = libtcod.path_new_using_map(self.path_map, 0) print pos1, pos2 libtcod.path_compute(chemin, pos1[0], pos1[1], pos2[0], pos2[1]) print libtcod.path_is_empty(chemin) x, y = libtcod.path_get(chemin, dist) # for i in range(dist): # x,y=libtcod.path_walk(path,False) # print x,y libtcod.path_delete(chemin) return [x, y]
def move_astar(self, target, entities, game_map): 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) max_path_length = 25 if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < max_path_length: 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 find_astar(origin, dest, 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.is_opaque( (x1, y1)), game_map.is_passable((x1, y1))) # 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 pos in [actor.pos for actor in game_map.actors]: if pos != origin and pos != dest: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, pos[0], pos[1], True, False) # Allocate a A* path my_path = tcod.path_new_using_map(fov, 1) # Compute the path between self's coordinates and the target's coordinates tcod.path_compute(my_path, origin[0], origin[1], dest[0], dest[1]) # Check if the path exists if not tcod.path_is_empty(my_path): # Find the next coordinates in the computed full path x, y = tcod.path_walk(my_path, True) # Delete the path to free memory tcod.path_delete(my_path) if x or y: delta = (x - origin[0], y - origin[1]) for act, move in MOVES.items(): if move == delta: return act
def move_astar_xy(self, target_x, target_y, force=False): if self.path is None or force: # print "a* self.path is None" # Create a FOV map that has the dimensions of the map if self.x == target_x and self.y == target_y: return # 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( GameState.current_level.get_fov_map(), 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): self.path = my_path return self.walk_path() 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) return False else: # print "Had path so walked it" return self.walk_path()
def move_astar(self, target): fov = libtcod.map_new(MAP_WIDTH, MAP_HEIGHT) #set move, sight blockers for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): libtcod.map_set_properties(fov, x1, y1, not map[x1][y1].sight_blocker, not map[x1][y1].move_blocker) #Treat tiles occupied by monsters as move blocked for obj in objects: if obj.move_blocker and obj != self and obj != target: libtcod.map_set_properties(fov, obj.x, obj.y, True, False) #Allocate path. Use roguelike geometry (diagonals = cardinals). my_path = libtcod.path_new_using_map(fov, 1.0) #Compute path libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) #Confirm path was found, and is short, then take step. if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < MAX_ASTAR_PATH_LENGTH: x, y = libtcod.path_walk(my_path, True) if x or y: #self.move takes dx, dy so don't use that self.x = x self.y = y #If the path is bad, take direct path to player. #This happens if, say, player is behind a monster in a corridor. else: self.move_towards(target.x, target.y) #Deallocate path memory libtcod.path_delete(my_path)
def move_astar(self, source, target, map): if self.has_required_components(source) and self.has_required_components(target): src = source.get_component(Components.POSITION) fov = source.get_component(Components.FOV) trg = target.get_component(Components.POSITION) # 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 map.entities: if self.has_required_components(entity): pos = entity.get_component(Components.POSITION) if pos.solid and entity != source and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov.fov, pos.x, 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.fov, 1.41) # Compute the path between self's coordinates and the target's coordinates tcod.path_compute(my_path, src.x, src.y, trg.x, trg.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(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 src.x = x src.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.basic_movement.move_towards(trg.x, trg.y, map) # Delete the path to free memory tcod.path_delete(my_path)
def moveAStar(self, target, entities, gameMap): # Create a new FOV map fov = tcod.map_new(gameMap.mapWidth, gameMap.mapHeight) # Scan current map and set all walls as unwalkable for y1 in range(gameMap.mapHeight): for x1 in range(gameMap.mapWidth): tcod.map_set_properties(fov, x1, y1, not gameMap.tiles[x1][y1].blockSight, not gameMap.tiles[x1][y1].blocked) # Scan for blocking entities for entity in entities: if entity.blocks and entity != self and entity != target: tcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate A* Path - No Diagonal Movement path = tcod.path_new_using_map(fov, 0.0) # Compute path tcod.path_compute(path, self.x, self.y, target.x, target.y) # Check if path exists and is shorter than 25 moves if not tcod.path_is_empty(path) and tcod.path_size(path) < 25: x, y = tcod.path_walk(path, recompute = True) # Set X and Y coordinates if x or y: self.x = x self.y = y else: # Backup Move Function self.moveTowards(target.x, target.y, gameMap, entities) tcod.path_delete(path)
def missile_attack(sx, sy, dx, dy, trap=False): cx, cy = sx, sy if sx == dx: char = '|' if sy == dy: char = chr(196) if (sx < dx and sy > dy) or (sx > dx and sy < dy): char = '/' if (sx < dx and sy < dy) or (sx > dx and sy > dy): char = '\\' path = util.set_full_explore_map(game.current_map, False) libtcod.path_compute(path, sx, sy, dx, dy) while not libtcod.path_is_empty(path): cx, cy = libtcod.path_walk(path, False) libtcod.console_blit(game.con, 0, 0, game.MAP_WIDTH, game.MAP_HEIGHT, 0, game.MAP_X, game.MAP_Y) libtcod.console_put_char_ex(0, game.MAP_X + cx - game.curx, game.MAP_Y + cy - game.cury, char, libtcod.light_gray, libtcod.black) libtcod.console_flush() time.sleep(0.05) if trap: for obj in game.current_map.objects: if obj.x == dx and obj.y == dy and not obj.item: damage = util.roll_dice(1, 6) if obj.name == 'player': game.message.new('You are hit by an arrow for ' + str(damage) + ' pts of damage!', game.turns, libtcod.Color(160, 0, 0)) game.player.take_damage(damage, 'an arrow trap') else: obj.entity.take_damage(obj.x, obj.y, damage, 'an arrow', True)
def path_towards_astar(self, game, origin, target): # getting the fov vamp from currentDrawMap doesn't work in debug mode since it isn't initialized # so for the moment I'm recomputing it every time, it's super wasteful but the game chugs along nicely fov = libtcod.map_new(self.width, self.height) list( map( lambda tile: libtcod.map_set_properties( fov, tile.x, tile.y, tile.trasparent, not tile.block), self.get_map_list())) for entity in self.entity_list: if entity != origin and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = libtcod.path_new_using_map(fov, 0.0) libtcod.path_compute(my_path, origin.x, origin.y, target.x, target.y) return_direction = (0, 0) if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 30: x, y = libtcod.path_walk(my_path, True) if x or y: x1 = 1 if origin.x < x else -1 if origin.x > x else 0 y1 = 1 if origin.y < y else -1 if origin.y > y else 0 return_direction = (x1, y1) else: return_direction = self.get_step_towards(origin.x, origin.y, target.x, target.y) libtcod.path_delete(my_path) return return_direction
def move_astar(self, target): fov = libtcod.map_new(MAP_WIDTH, MAP_HEIGHT) for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): libtcod.map_set_properties(fov, x1, y1, not map[x1][y1].block_sight, not map[x1][y1].blocked) for obj in objects: if obj.blocks and obj != self and obj != target: libtcod.map_set_properties(fov, obj.x, obj.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) libtcod.path_delete(my_path)
def astar(source, target): # create a FOV map that has the dimensions of the map fov = lib.map_new(var.MAP_WIDTH, var.MAP_HEIGHT) # scan the current map each turn and set all walls as unwalkable for y1 in range(var.MAP_HEIGHT): for x1 in range(var.MAP_WIDTH): lib.map_set_properties(fov, x1, y1, not var.map[x1][y1].block_sight, not var.map[x1][y1].blocked) # scan all objects to see if there are objects that must be navigated around # check also that the object isn't self or the target (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 ent in var.entities: if ent.blocks and ent != var.player and ent != target: # set the tile as a wall so it must be navigated around lib.map_set_properties(fov, ent.x, ent.y, True, False) # allocate the A* path # The 1.41 is the normal diagonal cost of moving, set to 0 if diagonals are prohibited my_path = lib.path_new_using_map(fov, 1.41) # compute the path between self's coordinates and the targets lib.path_compute(my_path, source.x, source.y, target.x, target.y) # check if the path exists, and in this case, also the path is shorter than 25 tiles if not lib.path_is_empty(my_path) and lib.path_size(my_path) < 25: # find the next coordinates in the computed full path (x, y) = lib.path_walk(my_path, True) else: (x, y) = (None, None) # delete the path lib.path_delete(my_path) return x, y
def move_astar(self, target, entities, game_map, check_explored=False, max_path=25): # 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): if check_explored: libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked and game_map.tiles[x1][y1].explored) else: 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 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 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) < max_path: # 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 return True else: return False 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) return self.move_towards(target.x, target.y, game_map, entities) # Delete the path to free memory libtcod.path_delete(my_path)
def libtcod_path_to_list(path_map): ''' get a libtcod path into a list ''' path = [] while not libtcod.path_is_empty(path_map): x, y = libtcod.path_walk(path_map, True) path.append((x, y)) return path
def takepath(self): # libtcod.path_compute(game.player.path, game.player.destination[0], game.player.destination[1], ...) if libtcod.path_is_empty(self.path): return "empty" else: x, y = libtcod.path_get(self.path, 0) self.owner.x, self.owner.y = libtcod.path_walk(self.path, True) return "pathing"
def move(self): if self.move_stat != 50 - self.speed: self.move_stat += 1 return else: self.move_stat = 0 if not libtcod.path_is_empty(self.path): self.x,self.y = libtcod.path_walk(self.path, True)
def path_to(self, dx, dy): # use algorithm to move (A*) path = libtcod.path_new_using_map(fov_map,1.41) libtcod.path_compute(path, self.owner.x, self.owner.y, dx, dy) if not libtcod.path_is_empty(path): x,y = libtcod.path_walk(path,True) if not x is None: self.move_towards(x,y) libtcod.path_delete(path)
def path_effect(game,ox,oy,dx,dy,decay_time): libtcod.path_compute(game.path,ox,oy,dx,dy) px,py = ox,oy while not libtcod.path_is_empty(game.path): x,y = libtcod.path_walk(game.path,True) cell = line_directions[(px-x,py-y)] px,py = x,y p = Particle(x,y,decay_time,libtcod.yellow,cell,game.ticker,game.con) game.particles.append(p)
def connected_cells(source, target): my_path = libtcod.path_new_using_map(Engine.Fov.get_fov_map(), 1.41) libtcod.path_compute(my_path, source[0], source[1], target[0], target[1]) if not libtcod.path_is_empty(my_path): return True else: return False
def path_effect(game, ox, oy, dx, dy, decay_time): libtcod.path_compute(game.path, ox, oy, dx, dy) px, py = ox, oy while not libtcod.path_is_empty(game.path): x, y = libtcod.path_walk(game.path, True) cell = line_directions[(px - x, py - y)] px, py = x, y p = Particle(x, y, decay_time, libtcod.yellow, cell, game.ticker, game.con) game.particles.append(p)
def test(self, abs_src_x, abs_src_y, abs_dst_x, abs_dst_y): self.compute_path_abs(abs_src_x, abs_src_y, abs_dst_x, abs_dst_y) if libtcod.path_is_empty(self.path): log.info("Path is empty") while True: loc = libtcod.path_walk(self.path, False) if loc != (None, None): loc_abs = (loc[0] + self.x_start, loc[1] + self.y_start) log.info("abs ({},{})".format(*loc_abs)) #print("({},{})".format(*loc)) else: break
def takepath(self, game): #libtcod.path_compute(game.player.path, game.player.destination[0], game.player.destination[1], ...) if libtcod.path_is_empty(self.path): return 'empty' else: #x,y = libtcod.path_get(self.path, 0) x, y = libtcod.path_walk(self.path, True) if (x, y) == (None, None): return 'empty' self.owner.x, self.owner.y = x, y #if self.move(game, dx, dy) == 'blocked': #return 'empty' return 'pathing'
def check_stairs_reachable(self, player, endtile): star = libtcod.map_new(self.width, self.height) for y1 in range(self.height): for x1 in range(self.width): libtcod.map_set_properties(star, x1, y1, not self.tiles[x1][y1].block_sight, not self.tiles[x1][y1].blocked) path = libtcod.path_new_using_map(star, 1) libtcod.path_compute(path, player.x, player.y, endtile[0], endtile[1]) if libtcod.path_is_empty(path): return False return True
def astar(game, from_pos, to_pos): # Create a FOV map that has the dimensions of the map fov = game.stage.map.make_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 actor in game.stage.actors: if actor.pos.x != to_pos.x and actor.pos.y != to_pos.y: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, actor.pos.x, actor.pos.y, isTrans=True, isWalk=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 path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(path, from_pos.x, from_pos.y, to_pos.x, to_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). 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(path) and libtcod.path_size(path) < 25: # Find the next coordinates in the computed full path next_x, next_y = libtcod.path_walk(path, True) libtcod.path_delete(path) return pyro.direction.from_vector(next_x - from_pos.x, next_y - from_pos.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). # Vector from this object to the target, and distance dx = to_pos.x - from_pos.x dy = to_pos.y - from_pos.y distance = math.sqrt(dx ** 2 + dy ** 2) # Normalize it to length 1 (preserving direction), then round it and # convert to integer so the movement is restricted to the map grid dx = int(round(dx / distance)) dy = int(round(dy / distance)) libtcod.path_delete(path) return pyro.direction.from_vector(dx, dy)
def move_astar(self, target): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(MAP_WIDTH, MAP_HEIGHT) # Scan the current map each turn and set all the wall unwalkable for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): libtcod.map_set_properties(fov, x1, y1, not map[x1][y1].block_sight, not map[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 obj in 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 a A* path # The 1.41 is the normal diagonal cost of moving (sqrt(2)). 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: # 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.x, target.y) # Delete the path to free memory libtcod.path_delete(my_path)
def move_astar(self, target): import Pathing print "Astar for " + self.name path = Pathing.astar((self.x, self.y), (target.x, target.y)) if not path: return False self.path = libtcod.path_new_using_map(Fov.get_fov_map(), 1.41) libtcod.path_compute(self.path, self.x, self.y, target.x, target.y) if not libtcod.path_is_empty( self.path) and libtcod.path_size(self.path) < 75: self.walk_path() else: self.move_towards(target.x, target.y)
def move_astar(self, target, entities, game_map): # create FOV map that has dimensions of game map fov = libtcod.map_new(game_map.width, game_map.height) # scan current map each turn and set all walls to be blocking for y in range(game_map.height): for x in range(game_map.width): libtcod.map_set_properties( fov, x, y, not game_map.tiles[x][y].block_sight, not game_map.tiles[x][y].blocked ) # Scan all objects to see if something needs to be navigated around. # Also check that the object isn't self or the target. # Ignore situation where self is next to target -- AI class handles this. for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # set wall so it must be navigated around # Allocate A* path. # 1.41 is the normalized diagonal cost of moving. If diagonal movement is not allowed, then set to 0. my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self and target coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if path exists and is shorter than 25 tiles. # Keep path size low to prevent monsters from running around the map. if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in computed full path. x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to next path tile self.x = x self.y = y else: # Keep old move function as a backup e.g. if something blocks a doorway, # self will still move towards target. 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): # マップの寸法を持つFOVマップを作成。 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) # すべてのオブジェクトをスキャンして,移動しなければならないオブジェクトがあるかどうかを確認 # オブジェクトが自己または対象ではないことも確認(開始点と終了点が自由になるように)。 # AIクラスは、自己がターゲットの隣にいる場合の状況を処理するので、このA*関数を使用しない。 for entity in entities: if entity.blocks and entity != self and entity != target: # タイルを壁として設定し,その周りを移動. libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # A*pathを割り当てる # 1.41は通常の対角線上の移動コストで、対角線上の移動が禁止されている場合は0.0とすることができる。 my_path = libtcod.path_new_using_map(fov, 1.41) # 自己の座標とターゲットの座標の間のpathを計算. libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # pathが存在するかどうかを確認し,この場合もpathが25タイルより短いかどうかを確認 # 例えばプレイヤーが廊下にいる場合など、モンスターに別の長めのパスを使わせたい場合、pathの大きさは重要になる # もし本当に遠くに代替の道があるならば、モンスターがマップを走り回らないようにするために、pathのサイズを比較的小さくしておくのは理にかなっている。 if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # 計算されたfull pathの次の座標を探す x, y = libtcod.path_walk(my_path, True) if x or y: # 次のpathタイルに自己の座標を設定 self.x = x self.y = y else: # 古い移動機能をバックアップとして残しておくことで,パスがない場合(例えば他のモンスターが通路を塞いでしまった場合)には,その機能を利用することができる. # プレイヤーに向かって移動しようとする(通路の開口部に近づけます) self.move_towards(target.x, target.y, game_map, entities) # 空きメモリへのpathを削除します libtcod.path_delete(my_path)
def move_astar(entity, entities, target, fov_map): """Use the A* algorithm to find a path to target, returning the next step along that path""" # TODO: maybe we re-use the existing fov map, but just un-set this entity and the target temporarily # that should save an entities iteration for making everything but entity and target unwalkable # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(init.map_width, init.map_height) # Scan the current map each turn and set all the walls as unwalkable for ent in entities: if ent != entity and ent != target and 'Position' in ent: libtcod.map_set_properties(fov, ent['Position']['x'], ent['Position']['y'], ent['Opacity'] < 0.5, ent['Solid'] < 0.5) # 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, entity['Position']['x'], entity['Position']['y'], target['Position']['x'], target['Position']['y']) # Debugging A* for i in range (libtcod.path_size(my_path)): (x, y) = libtcod.path_get(my_path, i) for ent in entities: if (i < libtcod.path_size(my_path) - 1) and 'Position' in ent and ent['Position']['x'] == x and ent['Position']['y'] == y and 'A*Highlight' in ent: ent['A*Highlight'] = True # 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 (next_x, next_y) = libtcod.path_walk(my_path, True) dx = next_x - entity['Position']['x'] dy = next_y - entity['Position']['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) (dx, dy) = from_a_to_b(entity['Position']['x'], entity['Position']['y'], target['Position']['x'], target['Position']['y']) # Delete the path to free memory libtcod.path_delete(my_path) return (dx, dy)
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 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 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 (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, entities) # Delete the path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # create a fov map at the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # scan 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 objets to see if there are objects that must be navigated around. # check also if object isn't self or the target for entity in entities: if entity.blocks and entity != self and entity != target: #set the tile as a wall so it muyst be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # allocate a A* path # 1.31 normal diag cost of moving, to put to 0 if diagonal forbiden my_path = libtcod.path_new_using_map(fov, 1.41) # compute path between self coordinates and the target coordinate libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # check if path exists && shorter than 25 tiles if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # find next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # set self coordinates to the next path tile self.x = x self.y = y else: # old move function if no path self.move_towards(target.x, target.y, game_map, entities) # delete the path to free memeory 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 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 an A* path # 1.41 is diagonal cost of moving my_path = libtcod.path_new_using_map(fov, 1.41) # Compute path between self's coordinate 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 (e.g. through other rooms) if e.g. the player is in a corridor # Makes sense to keep relatively low to stop monsters running around map if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find 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 old move function as a backup self.move_towards(target.x, target.y, game_map, entities) # Delete path to free memory libtcod.path_delete(my_path)
def render(mouse): libtcod.console_clear(0) libtcod.console_clear(unit_panel.console) main_map.draw(0, cam) #unit_panel rendering #unit rendering libtcod.console_set_alignment(0, libtcod.CENTER) libtcod.console_set_default_background(0, libtcod.black) for u in main_map.units: u.draw(0,cam) #Draw name function if (u.x == mouse.cx + cam.x and u.y == mouse.cy + cam.y) or u == main_map.selected_unit: libtcod.console_print(0, u.x - cam.x, u.y - cam.y -1, u.name) #Draw the destination if moving x,y = libtcod.path_get_destination(u.path) if not libtcod.path_is_empty(u.path): libtcod.console_set_char(0, x - cam.x, y - cam.y, libtcod.CHAR_ARROW_S) unit_panel.draw(main_map)
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_to_target(self, Map): #dx = x - owner.x #dy = y - owner.y #distance = math.sqrt(dx ** 2 + dy ** 2) #dx = int(round(dx / distance)) #dy = int(round(dy / distance)) #self.owner.move(dx, dy) #if path doesnt exist make new path to target owner = self.owner target = owner.target fov_map = Map.fov_map path = libtcod.path_new_using_map(fov_map) libtcod.path_compute(path, owner.x, owner.y, target.x, target.y) # use the path ... if not libtcod.path_is_empty(path) : x,y=libtcod.path_walk(path,True) if not x is None : owner.put(x,y) owner.moved = True
def move_astar(self, target): # Create a FOV map for the actor in question fov = tcod.map_new(settings.MAP_WIDTH, settings.MAP_HEIGHT) # Scan the current map and set all walls as unwalkable for y1 in range(settings.MAP_HEIGHT): for x1 in range(settings.MAP_WIDTH): tcod.map_set_properties( fov, x1, y1, not settings.dungeon_map[x1][y1].block_sight, not settings.dungeon_map[x1][y1].blocked) # Scan all objects to see if anything must be navigated around # Check also that the object isn't self or the target (so that start and endpoints are free) for obj in settings.objects: if obj.blocks and obj != self and obj != target: tcod.map_set_properties(fov, obj.x, obj.y, True, False) # Allocating the A* path # The 1.41 is the normal diagonal cost of moving. my_path = tcod.path_new_using_map(fov, 1.41) tcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists and is shorter than 25 tiles # The path size matters for the monster to use alternative longer paths (player in another room, corridor, etc) # If the path size is too big monsters will run weird routes around the map 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: # set self's coords to the next path tile self.combatant.set_direction(x - self.x, y - self.y) self.x = x self.y = y else: self.move_towards(target.x, target.y) tcod.path_delete(my_path)
def take_turn(self, gamemap_instance): mymap = gamemap_instance.level object_list = gamemap_instance.objects if not self.is_pathmap_created: self.create_path(gamemap_instance) if not libtcod.path_is_empty(self.path): pathx, pathy = libtcod.path_walk(self.path, True) #print 'Explorer is trying to move from (' + str(self.owner.x) + ', ' + str(self.owner.y) + #') to (' + str(pathx) + ', ' + str(pathy) +').' dx = pathx - self.owner.x dy = pathy - self.owner.y distance = sqrt(dx ** 2 + dy ** 2) #normalize it to length 1 (preserving direction), then round it and #convert to integer so the movement is restricted to the map grid dx = int(round(dx / distance)) dy = int(round(dy / distance)) move(gamemap_instance, self.owner, dx, dy) else: #print 'The Explorer ' + self.owner.name + ' has finished their path. Choosing a new one...' self.create_path(gamemap_instance)
def move_player(x, y): # Set globals. global turns, fov_recompute # Create path. player_path = roguelib.path_new_using_map(fov_map, 1.41) # Compute path to walk. roguelib.path_compute(player_path, player.x, player.y, x, y) while not roguelib.path_is_empty(player_path): xx, yy = roguelib.path_walk(player_path, True) if not is_blocked(xx, yy): # Move player. player.x = xx player.y = yy # Increase turns. turns += 1 # Recompute FOV. fov_recompute = True
def take_turn(self, gamemap_instance): """ Current bugs: 1) The worked-on Tile doesn't turn to gravel- why not? 2) The loop doesn't really go back around. They don't pick a new target, especially if they get stuck while walking. They just give up after the first time they bump into something dynamic. """ fov_map = gamemap_instance.fov_map object_list = gamemap_instance.objects mymap = gamemap_instance.level if not self.is_pathmap_created: print 'Builder needs to create_path' self.create_path(gamemap_instance) if not libtcod.path_is_empty(self.path): pathx, pathy = libtcod.path_walk(self.path, True) #print 'Explorer is trying to move from (' + str(self.owner.x) + ', ' + str(self.owner.y) + #') to (' + str(pathx) + ', ' + str(pathy) +').' dx = pathx - self.owner.x dy = pathy - self.owner.y distance = sqrt(dx ** 2 + dy ** 2) #normalize it to length 1 (preserving direction), then round it and #convert to integer so the movement is restricted to the map grid dx = int(round(dx / distance)) dy = int(round(dy / distance)) move(gamemap_instance, self.owner, dx, dy) elif self.work_target[0] is not None: (x, y) = self.work_target (my_x, my_y) = self.owner.x, self.owner.y # The following logic checks to see if they are standing in any of the 8 squares around # the target Tile. I definitely had to draw a diagram for this. if ((my_x+1 == x) and ( (my_y+1 == y) or (my_y == y) or (my_y-1 == y)) ) \ or ((my_x == x) and ( (my_y+1 == y) or (my_y == y) or (my_y-1 == y)) ) \ or ((my_x-1 == x) and ( (my_y+1 == y) or (my_y == y) or (my_y-1 == y)) ): # We have arrived at a Tile that needs work done. Now begin work: print 'Builder is standing at (' + str(my_x) +', '+ str(my_y)+') ' \ 'and is beginning work at (' + str(x) + ', ' + str(y) +').' # Using a switch statement here because eventually there will be other states like # 'building' or 'installing' something, etc for case in switch(mymap[x][y].designation_type): if case('clearing'): mymap[x][y].blocked = False mymap[x][y].block_sight = False mymap[x][y].fore = color_ground mymap[x][y].back = color_ground mymap[x][y].char = GRAVEL # Then reset the tile: mymap[x][y].designated = False mymap[x][y].designation_type = None mymap[x][y].designation_char = None mymap[x][y].being_worked_on = False #gamemap_instance.initialize_fov() print 'Finished work, resetting work_target to None, None.' self.work_target = (None, None) self.is_pathmap_created = False break if case(): break # default else: self.pick_spot_to_work(gamemap_instance) self.create_path(gamemap_instance)
def read_path(self, path, limit): if not libtcod.path_is_empty(path): if libtcod.path_size(path) <= limit: x, y = libtcod.path_walk(path, True) return [x, y] libtcod.path_delete(path)
def take_turn(self): self.get_target() # we have a target if self.target: # target is close enough to attack if self.owner.distance_to_actor(self.target) == 1: self.unset_temp_blocking() return self.owner.melee_attack(self.target) # too far to attack, so try to chase else: self.set_path() # if there is a path, try to walk along it if self.path: # the path is empty, remove the target if libtcod.path_is_empty(self.path): self.target = None self.target_x = None self.target_y = None self.path = None return False # try to walk the path else: x, y = libtcod.path_walk(self.path, False) if x is None: self.path = None return False actor = self.owner.map.actor_at(x, y) feature = self.owner.map.feature_at(x, y) # there is an actor in the way if actor: self.path = None self.set_temp_blocking(actor) return False # there is a closed door in the way, open it elif self.owner.opens_doors and feature.is_door and feature.open == False: self.path = None self.unset_temp_blocking() return feature.interact(self.owner) # otherwise, the space is free; move to that space else: self.owner.move_to(x, y) self.unset_temp_blocking() return True # no path, so just do nothing else: for actor in self.temporary_blocking: if actor.faction == 'neutral' and self.owner.distance_to_actor(actor) == 1: self.owner.melee_attack(actor) self.unset_temp_blocking() return True
def play_game(): global key, mouse, autopilot_on mouse = libtcod.Mouse() key = libtcod.Key() autopilot_on = False tutorial = True while not libtcod.console_is_window_closed(): if game_state == GAME_STATE_VICTORY or game_state == GAME_STATE_PLAYER_DEAD: break libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) libtcod.console_set_default_foreground(0, libtcod.white) renderer.render_all(player=player, objects=objects, game_map=game_map, con=con, panel=panel, projectiles=projectiles, game_msgs=game_msgs, dungeon_level=dungeon_level, mouse=mouse, non_interactive_objects=non_interactive_objects) libtcod.console_flush() renderer.clear_objects(con, objects) renderer.clear_objects(con, projectiles) if tutorial: msgbox("Welcome to the game!\n\n" "You're tasked with a very important mission! The most talented diplomat the Earthlings have is " "travelling to Epsilon Gruis I, where he'll attend peace talks with The Safe Ones and possibly gain " "their support! Obviously this cannot happen, so you must ASSASSINATE THE DIPLOMAT!\n\n" "To reach the diplomat, you must navigate through nine sectors (all crawling with hostiles by the " "way) by using the naturally occurring JUMP POINTS. Our spies have provided INTEL pickups on the way" " that will give you the disposition of the enemy forces in the next sector. If you don't pick up " "the INTEL you'll be flying blind and probably die!\n\n" "Your ship is equipped with a 3-tile cutting laser. End your turn within a distance of 3 to an enemy" " to attack. It's pretty powerful against small ships, but be wary of extended engagements.\n\n" "Good luck captain!\n\n" "CONTROLS:\n" "KEYPAD: Movement\n" "a: autopilot to zone\n" "g: pick up an item in your tile\n" "i: view inventory and use items\n" "d: drop items\n" "r: view sector reports (DO THIS)\n" "<: jump to the next sector (must be on the jump point)\n" "ESC: quit to menu", 70) tutorial = False # TODO: Kind of messy way of structuring this! time = time_to_next_event(objects, projectiles) for obj in objects: if obj.fighter and (obj.ai or obj == player): obj.fighter.pass_time(time) for projectile in projectiles: projectile.fighter.pass_time(time) # Take turn if not autopiloting if player.fighter.time_until_turn == 0 and not autopilot_on: check_level_up() player_action = handle_keys() if player_action == 'exit': break elif player_action != GAME_STATE_DIDNT_TAKE_TURN: player.fighter.end_turn() # Autopilot elif player.fighter.time_until_turn == 0: # Check if there are nearby enemies nearest = closest_monster(TORCH_RADIUS) if key.vk != libtcod.KEY_NONE: autopilot_on = False message('Disengaging autopilot on pilot input!') if nearest: autopilot_on = False message('Enemy ships nearby! Autopilot disengaging!') elif libtcod.path_is_empty(autopilot_path): autopilot_on = False message('You have reached your destination! Autopilot disengaging!') else: (x, y) = libtcod.path_walk(autopilot_path, False) player.move_towards(x, y, game_map, objects) player.fighter.end_turn() else: player_action = None if game_state == GAME_STATE_PLAYING and player_action != GAME_STATE_DIDNT_TAKE_TURN: for o in objects: if o.fighter and o.fighter.time_until_turn == 0 and o.ai: o.ai.take_turn() o.fighter.end_turn() for projectile in projectiles: if projectile.fighter.time_until_turn == 0: projectile.ai.take_turn() projectile.fighter.end_turn()
def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, tile_data): rooms = [] num_rooms = 0 center_of_last_room_x = None center_of_last_room_y = None for r in range(max_rooms): w = randint(room_min_size, room_max_size) h = randint(room_min_size, room_max_size) x = randint(0, map_width - w - 1) y = randint(0, map_height - h - 1) if randint(0, 1): #Make either a rectangular or circular room new_room = Room(x, y, w, h) else: new_room = Room.make_circle_room(x, y, min(w, h)) for other_room in rooms: if new_room.intersect(other_room): break else: self.place_room(new_room, tile_data) (new_x, new_y) = new_room.center() center_of_last_room_x = new_x center_of_last_room_y = new_y if num_rooms == 0: player.x = new_x player.y = new_y else: (prev_x, prev_y) = rooms[num_rooms - 1].center() if randint(0, 1) == 1: self.create_h_tunnel(prev_x, new_x, prev_y) self.create_v_tunnel(prev_y, new_y, new_x) else: self.create_v_tunnel(prev_y, new_y, prev_x) self.create_h_tunnel(prev_x, new_x, new_y) self.place_entities(new_room, entities) rooms.append(new_room) num_rooms += 1 stairs_component = Stairs(self.floor + 1) down_stairs = Entity(center_of_last_room_x, center_of_last_room_y, '>', lc.white, 'Stairs', render_order=RenderOrder.STAIRS, stairs=stairs_component) entities.append(down_stairs) #Check to make sure a path exists from the player to the down stairs fov_map = lc.map_new(self.width, self.height) for y in range(0, self.height): for x in range(0, self.width): lc.map_set_properties(fov_map, x, y, True, not self.tiles[x][y].blocked) lc.map_compute_fov(fov_map, 0, 0, 100, True, 0) path = lc.path_new_using_map(fov_map, 1) lc.path_compute(path, player.x, player.y, down_stairs.x, down_stairs.y) if lc.path_is_empty( path): #If no path exists, make a tunnel to the down stairs if randint(0, 1) == 1: self.create_h_tunnel(down_stairs.x, player.x, down_stairs.y) self.create_v_tunnel(down_stairs.y, player.y, player.x) else: self.create_v_tunnel(down_stairs.y, player.y, down_stairs.x) self.create_h_tunnel(down_stairs.x, player.x, player.y)
def generate_river(): river_start_x = 0 river_start_y = 0 river_end_x = MAP_WIDTH - 1 river_end_y = MAP_HEIGHT - 1 river_noise = [[0 for y in range(MAP_WIDTH)] for x in range(MAP_HEIGHT)] for i in range(MAP_HEIGHT): river_noise[i] = map(lambda a: (2+a)**4, noise_map[i]) # scaled up def river_cost(xFrom, yFrom, xTo, yTo, river_noise): return river_noise[yTo][xTo] path = libtcod.path_new_using_function(MAP_WIDTH, MAP_HEIGHT, river_cost, river_noise) # wish I could just use # (lambda xFrom, yFrom, xTo, yTo, river_noise: river_noise[xTo][yTo]) libtcod.path_compute(path, river_start_x, river_start_y, river_end_x, river_end_y) while not libtcod.path_is_empty(path): x, y = libtcod.path_walk(path, True) g.level_map[y][x] = Tile(tile_types.SHALLOW_WATER) # make a wider river by making all the neighbors water # we need to initialize these separately, but I don't know why x_in_min = False x_in_max = False y_in_min = False y_in_max = False if x-1 >= 0: x_in_min = True if x+1 < MAP_WIDTH: x_in_max = True if y-1 >= 0: y_in_min = True if y+1 < MAP_HEIGHT: y_in_max = True # left if x_in_min: g.level_map[y][x-1] = Tile(tile_types.SHALLOW_WATER) # bottom left if y_in_min: g.level_map[y-1][x-1] = Tile(tile_types.SHALLOW_WATER) # top left if y_in_max: g.level_map[y+1][x-1] = Tile(tile_types.SHALLOW_WATER) # right if x_in_max: g.level_map[y][x+1] = Tile(tile_types.SHALLOW_WATER) # bottom right if y_in_min: g.level_map[y-1][x+1] = Tile(tile_types.SHALLOW_WATER) # top right if y_in_max: g.level_map[y+1][x+1] = Tile(tile_types.SHALLOW_WATER) # bottom if y_in_min: g.level_map[y-1][x] = Tile(tile_types.SHALLOW_WATER) # top if y_in_max: g.level_map[y+1][x] = Tile(tile_types.SHALLOW_WATER) # Iterate through all the tiles. Remove trees on shallow water tiles. for j in range(MAP_HEIGHT): for i in range(MAP_WIDTH): if g.level_map[j][i].type == tile_types.SHALLOW_WATER: for feature in g.terrain_features: if feature.x == i and feature.y == j: g.terrain_features.remove(feature)
def render_map(): # recompute FOV if needed (the player moved or something) libtcod.console_rect(0, game.MAP_X, game.MAP_Y, game.MAP_WIDTH, game.MAP_HEIGHT, True) if game.fov_recompute: find_map_viewport() fov_radius() initialize_fov(True) libtcod.map_compute_fov(game.fov_map, game.char.x, game.char.y, game.FOV_RADIUS, game.FOV_LIGHT_WALLS, game.FOV_ALGO) game.fov_recompute = False # 'torch' animation if game.fov_torch: game.fov_torchx += 0.2 tdx = [game.fov_torchx + 20.0] dx = libtcod.noise_get(game.fov_noise, tdx, libtcod.NOISE_SIMPLEX) * 1.5 tdx[0] += 30.0 dy = libtcod.noise_get(game.fov_noise, tdx, libtcod.NOISE_SIMPLEX) * 1.5 di = 0.4 * libtcod.noise_get(game.fov_noise, [game.fov_torchx], libtcod.NOISE_SIMPLEX) # go through all tiles, and set their background color according to the FOV for y in range(game.MAP_HEIGHT): for x in range(game.MAP_WIDTH): px = x + game.curx py = y + game.cury if not libtcod.map_is_in_fov(game.fov_map, px, py): if game.draw_map and game.current_map.tile_is_explored(px, py): if game.current_map.tile_is_animated(px, py): libtcod.console_put_char_ex(game.con, x, y, game.current_map.tile[px][py]['icon'], game.current_map.tile[px][py]['dark_color'], game.current_map.tile[px][py]['dark_back_color']) else: libtcod.console_put_char_ex(game.con, x, y, game.current_map.tile[px][py]['icon'], game.current_map.tile[px][py]['dark_color'], game.current_map.tile[px][py]['back_dark_color']) else: if not game.fov_torch: if 'animate' in game.current_map.tile[px][py] or 'duration' in game.current_map.tile[px][py]: (front, back, game.current_map.tile[px][py]['lerp']) = render_tiles_animations(px, py, game.current_map.tile[px][py]['color'], game.current_map.tile[px][py]['back_light_color'], game.current_map.tile[px][py]['back_dark_color'], game.current_map.tile[px][py]['lerp']) libtcod.console_put_char_ex(game.con, x, y, game.current_map.tile[px][py]['icon'], front, back) elif game.draw_map: libtcod.console_put_char_ex(game.con, x, y, game.current_map.tile[px][py]['icon'], game.current_map.tile[px][py]['color'], game.current_map.tile[px][py]['back_light_color']) else: base = game.current_map.tile[px][py]['back_light_color'] r = float(px - game.char.x + dx) * (px - game.char.x + dx) + (py - game.char.y + dy) * (py - game.char.y + dy) if r < game.SQUARED_TORCH_RADIUS: l = (game.SQUARED_TORCH_RADIUS - r) / game.SQUARED_TORCH_RADIUS + di if l < 0.0: l = 0.0 elif l > 1.0: l = 1.0 base = libtcod.color_lerp(base, libtcod.gold, l) libtcod.console_put_char_ex(game.con, x, y, game.current_map.tile[px][py]['icon'], game.current_map.tile[px][py]['color'], base) if not game.current_map.tile_is_explored(px, py): game.current_map.tile[px][py].update({'explored': True}) # draw all objects in the map (if in the map viewport), except the player who his drawn last for obj in reversed(game.current_map.objects): if obj.y in range(game.cury, game.cury + game.MAP_HEIGHT) and obj.x in range(game.curx, game.curx + game.MAP_WIDTH) and game.current_map.tile_is_explored(obj.x, obj.y) and obj.name != 'player': if game.draw_map and obj.entity is not None: if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y) and not obj.entity.is_identified(): skill = game.player.find_skill('Mythology') if (game.player.skills[skill].level * 0.8) + 20 >= roll_dice(1, 100): obj.entity.flags.append('identified') game.message.new('You properly identify the ' + obj.entity.unidentified_name + ' as ' + obj.entity.get_name(True) + '.', game.turns) game.player.skills[skill].gain_xp(3) if obj.entity is not None and not obj.entity.is_identified(): obj.draw(game.con, libtcod.white) else: obj.draw(game.con) game.char.draw(game.con) libtcod.console_blit(game.con, 0, 0, game.MAP_WIDTH, game.MAP_HEIGHT, 0, game.MAP_X, game.MAP_Y) game.draw_map = False # move the player if using mouse if game.mouse_move: if mouse_auto_move() and not libtcod.path_is_empty(game.path): game.char.x, game.char.y = libtcod.path_walk(game.path, True) game.fov_recompute = True game.player_move = True else: items_at_feet() game.mouse_move = False # check where is the mouse cursor if not in the act of moving while using the mouse if not game.mouse_move: (mx, my) = (game.mouse.cx - game.MAP_X, game.mouse.cy - 1) px = mx + game.curx py = my + game.cury game.path_dx = -1 game.path_dy = -1 if my in range(game.MAP_HEIGHT) and mx in range(game.MAP_WIDTH): libtcod.console_set_char_background(0, mx + game.MAP_X, my + 1, libtcod.white, libtcod.BKGND_SET) if game.current_map.tile_is_explored(px, py) and not game.current_map.tile_is_blocked(px, py): game.path_dx = px game.path_dy = py if game.mouse.lbutton_pressed: target = [obj for obj in game.current_map.objects if obj.y == py and obj.x == px and obj.entity] if target: mouse_auto_attack(px, py, target[0]) else: game.mouse_move = mouse_auto_move() # draw a line between the player and the mouse cursor if not game.current_map.tile_is_blocked(game.path_dx, game.path_dy): libtcod.path_compute(game.path, game.char.x, game.char.y, game.path_dx, game.path_dy) for i in range(libtcod.path_size(game.path)): x, y = libtcod.path_get(game.path, i) if (y - game.cury) in range(game.MAP_HEIGHT) and (x - game.curx) in range(game.MAP_WIDTH): libtcod.console_set_char_background(0, game.MAP_X + x - game.curx, game.MAP_Y + y - game.cury, libtcod.desaturated_yellow, libtcod.BKGND_SET) libtcod.console_set_default_foreground(0, libtcod.light_yellow) libtcod.console_print_rect(0, game.MAP_X, game.MAP_Y, game.MAP_WIDTH - 18, game.MAP_HEIGHT, get_names_under_mouse()) if game.debug.enable: libtcod.console_print_ex(0, game.MAP_X + game.MAP_WIDTH - 1, game.MAP_Y, libtcod.BKGND_NONE, libtcod.RIGHT, str(game.gametime.hour) + ':' + str(game.gametime.minute).rjust(2, '0') + ' (%3d fps)' % libtcod.sys_get_fps()) if game.hp_anim: render_floating_text_animations()
def playerInput(): # Handles reacting to player input. global fovCompute, turns, actionMenu, gameState, widgets for widget in widgets: if widget.console != topGuiConsole: widget.checkSelected(mouse.cx, mouse.cy-topGuiHeight) else: widget.checkSelected(mouse.cx, mouse.cy) if mouse.lbutton_pressed: if actionMenu[0]: if mouse.cx > actionMenu[3] and mouse.cx < actionMenu[3]+actionWidth: if mouse.cy-topGuiHeight > actionMenu[4] and mouse.cy-topGuiHeight < actionMenu[4]+actionHeight: for widget in widgets: if widget.selected: if actionMenu[5] == "stairs": widget.action() else: widget.action(player, actionMenu[1], actionMenu[2]) # Deletes all widgets created for action menu and resets action menu container. actionMenu = [False, 0, 0, 0, 0, ""] del widgets[2:6] return "ENDTURN" else: if libtcod.map_is_in_fov(fovMap, mouse.cx, mouse.cy-topGuiHeight) and gameState == "ACTIVE": if isWalkable(mouse.cx, mouse.cy-topGuiHeight): if player.distanceTo(mouse.cx, mouse.cy-topGuiHeight) >= 2: pathToCoords = libtcod.path_new_using_map(fovMap, 1) libtcod.path_compute(pathToCoords, player.x, player.y, mouse.cx, mouse.cy-topGuiHeight) while not libtcod.path_is_empty(pathToCoords): newX, newY = libtcod.path_walk(pathToCoords, True) if newX is not None: newX = newX - player.x newY = newY - player.y player.move(player.x+newX, player.y+newY) turns += 1 if isNpcInFov(): break libtcod.path_delete(pathToCoords) fovCompute = True return "ENDTURN" else: player.move(mouse.cx, mouse.cy-topGuiHeight) turns += 1 fovCompute = True return "ENDTURN" if not actionMenu[0]: for widget in widgets: if widget.selected: widget.action() if mouse.rbutton_pressed: if actionMenu[0]: # Deletes all widgets created for action menu and resets action menu container. actionMenu = [False, 0, 0, 0, 0, ""] del widgets[2:6] elif gameState != "ACTIVE": gameState = "ACTIVE" widgets = widgets[0:2] else: if libtcod.map_is_in_fov(fovMap, mouse.cx, mouse.cy-topGuiHeight): getAction(mouse.cx, mouse.cy-topGuiHeight) fovCompute = True if key.pressed and key.vk == libtcod.KEY_SPACE: displayMsgHistory() if key.vk == libtcod.KEY_ESCAPE: if actionMenu[0]: # Deletes all widgets created for action menu and resets action menu container. actionMenu = [False, 0, 0, 0, 0, ""] del widgets[2:6] if gameState != "ACTIVE": gameState = "ACTIVE" widgets = widgets[0:2] return False