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_towards(self, target_x, target_y): #Upgraded the move_towards to use the libtcod path algorythms and solving a bug #where the monsters "waited" near the doors #path = libtcod.path_new_using_map(fov_map,1) path = libtcod.path_new_using_function(MAP_WIDTH, MAP_HEIGHT, path_func, map, 1) libtcod.path_compute(path, self.x, self.y, target_x, target_y) (end_x,end_y) = libtcod.path_get(path, 0) dx = end_x - self.x dy = end_y - self.y self.move(dx, dy)
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 process(self, game): visible =self.game.fov.is_visible(self.x, self.y) moved = False if visible: self.seen += 1 self.color = tcod.color_lerp(tcod.dark_gray, self.orig_color, (self.seen % 50) / 100.0) if self.seen % 50 == 0: self.game.duplicate(self) if self.seen == 200: self.character = 'o' self.movement = 0.4 elif self.seen == 400: self.character = 'O' self.movement = 0.6 path = tcod.path_new_using_map(self.game.fov.fov, 1.0) tcod.path_compute(path, self.x, self.y, self.game.player.x, self.game.player.y) if tcod.path_size(path) > 2: self.points += self.movement if self.points >= 1: self.points -= 1 x, y = tcod.path_get(path, 1) self.move(x - self.x, y - self.y) moved = True tcod.path_delete(path) if not moved: self.points += self.movement if self.points >= 1: self.points -= 1 movement = [ (0, 0), (0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (-1, -1), (-1, 1), (1, -1) ] self.move(*random.choice(movement)) return True
def tick(self, world_map, creature): if self.tick_time == 0: self.compute_path(world_map, creature) if self.tick_time < self.path_length: x, y = tcod.path_get(self.path, self.tick_time) z = creature.z if not world_map[(x, y, z)].is_walkable(): # Path is not walkable anymore ! # We'll try to rebuild it... self.compute_path(world_map, creature) else: creature.move((x, y, 0)) else: self.finish() super(Walking, self).tick(world_map, creature)
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_towards(self, target_x, target_y): global fov_map path = libtcod.path_new_using_map(fov_map) libtcod.path_compute(path, self.x, self.y, target_x, target_y) x,y = libtcod.path_get(path, 0) if x is None: self.move(0, 0) else: dx = int(round(target_x - x)) dy = int(round(target_y - y)) if dx != 0: dx = dx/abs(dx) if dy != 0: dy = dy/abs(dy) self.move(dx, dy) libtcod.path_delete(path)
def can_hear(obj, x,y, volume): if ( on(obj,DEAD) or on(obj,DEAF) or not obj.stats.get('hearing') ): return False dist=maths.dist(obj.x, obj.y, x, y) maxHearDist=volume*obj.stats.get('hearing')/AVG_HEARING if (obj.x == x and obj.y == y): return (0,0,maxHearDist,) if dist > maxHearDist: return False # calculate a path path=path_init_sound() path_compute(path, obj.x,obj.y, x,y) pathSize=libtcod.path_size(path) if dist >= 2: semifinal=libtcod.path_get(path, 0) xf,yf=semifinal dx=xf - obj.x dy=yf - obj.y else: dx=0 dy=0 path_destroy(path) loudness=(maxHearDist - pathSize - (pathSize - dist)) if loudness > 0: return (dx,dy,loudness)
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 tick(self,world): if self.explored: return if not self.goal: [self.goal,self.path] = self.findExplorePoint(world) if not self.goal: path=world.getPathable() self.explored=True unseen=0 for n in path: if not world.isSeen(n[0],n[1]):unseen=unseen+1 print "Exploration done,",unseen,"unseen tiles" return self.path_progress=0 [next_x,next_y]=libtcod.path_get(self.path, self.path_progress) self.x=next_x self.y=next_y self.path_progress=self.path_progress+1 if libtcod.path_size(self.path)==self.path_progress: self.goal=None self.path=None
def nodes(self): rr = range(self.path.size()) return [Pos(*libtcod.path_get(self.path, i)) for i in rr]
def move_towards(self, target_x, target_y): path = libtcod.path_new_using_map(fov_map) libtcod.path_compute(path, self.x, self.y, target_x, target_y) dx, dy = libtcod.path_get(path, 0) self.move_absolute(dx, dy) libtcod.path_delete(path)
def libtcod_path_to_list(path_map): ''' get a libtcod path into a list ''' return [libtcod.path_get(path_map, i) for i in xrange(libtcod.path_size(path_map))]
def path_toward(self, target_x, target_y): if libtcod.path_compute(base_path, self.owner.x, self.owner.y, target_x, target_y): (path_x, path_y) = libtcod.path_get(base_path, 0) dx = path_x - self.owner.x dy = path_y - self.owner.y self.owner.move(dx, dy)
def get_node(self, idx): return Pos( *libtcod.path_get(self.path, idx))
def get_node(self, idx): return Pos(*libtcod.path_get(self.path, idx))
def update(self): tcod_map = self.game.dungeon.tcod_map if not self.path: self.path = libtcod.path_new_using_map(tcod_map) pos = self.entity.pos visible = self.game.player.fov(*pos) done = False while not done: if self.state == AI_INACTIVE: #not used yet done = True elif self.state == AI_SLEEPING: wake_up = False for s in self.sounds: if self.game.rng.percent(min(95,s[0]*(self.creature.perception+5)/10)): wake_up = True if self.creature.health < self.creature.max_health: wake_up = True if wake_up: self.state = AI_RESTING self.entity.notify(Event(EVENT_WAKE_UP, actor=self.entity)) else: #continue sleeping done = True elif self.state == AI_RESTING: self.creature.fov.refresh() if self.check_for_player(): self.state = AI_FIGHTING self.entity.notify(Event(EVENT_NOTICE, actor=self.entity)) else: #continue to rest or wander? if self.game.rng.percent(20): done = True else: self.state = AI_WANDERING elif self.state == AI_WANDERING: self.creature.fov.refresh() if self.check_for_player(): self.state = AI_FIGHTING self.entity.notify(Event(EVENT_NOTICE, actor=self.entity)) else: direction = (0,0) while not (self.valid_movement(direction) or self.game.cur_level.get_tile(self.entity.x+direction[0],self.entity.y+direction[1]).creature==self.game.player): directions = [(1,1),(1,-1),(-1,1),(-1,-1), (0,1),(0,-1),(1,0),(-1,0)] if self.prev_dir: directions += [self.prev_dir]*6 if self.prev_dir[0]==0: directions += [(1,self.prev_dir[1])]*2 directions += [(-1,self.prev_dir[1])]*2 elif self.prev_dir[1]==0: directions += [(self.prev_dir[0],1)]*2 directions += [(self.prev_dir[0],-1)]*2 else: directions += [(self.prev_dir[0],0)]*2 directions += [(0,self.prev_dir[1])]*2 direction = self.game.rng.choose(directions) t = self.game.cur_level(self.entity.x+direction[0], self.entity.y+direction[1]) if self.game.rng.percent(10): self.state = AI_RESTING done=True elif t.creature is self.game.player: self.entity.notify(EVENT_NOTICE, actor=self.entity) self.state = AI_FIGHTING else: self.entity.move_to(self.entity.x+direction[0], self.entity.y+direction[1]) self.prev_dir=direction done=True elif self.state == AI_FIGHTING: if self.creature.fov(*self.game.player.pos): self.last_saw_player = 0 else: #increase last_saw_player and fall asleep if it's been too long self.last_saw_player += 1 if self.last_saw_player >= 5: self.state = AI_SLEEPING new_player_pos = self.game.player.pos #get latest player pos and recalculate path if needed if self.player_pos != new_player_pos: self.player_pos = new_player_pos self.compute_path(*self.player_pos) if (self.path_index < libtcod.path_size(self.path) and self.game.player.creature.alive):#walk path x,y = libtcod.path_get(self.path, self.path_index) event = self.entity.move_to(x,y) if event.event_type == EVENT_MOVE: #successfully moved, increase path index self.path_index += 1 done = True elif self.entity.distance_to(*self.player_pos) < 2: #didn't move but can attack player self.creature.attack(self.game.player) done = True else: #didn't move or attack, try new path self.compute_path(*self.player_pos) else: #end of path and don't know where to go now done = True self.sounds = [] if self.state != AI_INACTIVE and self.state != AI_SLEEPING: self.creature.fov.refresh()
def libtcod_path_to_list(path_map): ''' get a libtcod path into a list ''' return [ libtcod.path_get(path_map, i) for i in xrange(libtcod.path_size(path_map)) ]
def map_init_dungeon(width, height): def path_cost(xFrom, yFrom, xTo, yTo, alg_array): if alg_array[xTo][yTo] == 0: return 1 if alg_array[xTo][yTo] == 3: return 0.01 else: return 10 room_prefabs_10x10 = [] f = open('resources/map_prefabs/map_prefabs[10x10].csv', 'r').read().split('\n') # 10x10 for i in range(len(f[0]) // 10): for j in range(len(f) // 10): room = '' for y in range(10): for x in range(10): room += f[j * 10 + x][i * 10 + y] room_prefabs_10x10.append(room) room_prefabs_5x5 = [] f = open('resources/map_prefabs/map_prefabs[5x5].csv', 'r').read().split('\n') # 10x10 for i in range(len(f[0]) // 5): for j in range(len(f) // 5): room = '' for y in range(5): for x in range(5): room += f[j * 5 + x][i * 5 + y] room_prefabs_5x5.append(room) monsters_pool = [[game_content.m_slime], []] alg_array = [[0 for j in range(height)] for i in range(width)] terrain = [[0 for j in range(height)] for i in range(width)] items = [] entities = [] creatures = [] rooms = [] room_exits = [] room_connections = [] rooms_size = [(10, 10), (5, 5)] rooms.append((width // 2 - 3, height // 2 - 3, 6, 6)) for x in range(width // 2 - 3, width // 2 + 3): for y in range(height // 2 - 3, height // 2 + 3): if y == height // 2 and (x == width // 2 - 3 or x == width // 2 + 3): alg_array[x][y] = 7 room_exits.append((x, y, -1)) else: alg_array[x][y] = 2 available_spots = [ (x, y) for x in range(width) for y in range(height) if x > 6 and x < width - 12 and y > 6 and y < height - 12 ] for x in range(len(available_spots)): append = True i, j = available_spots.pop(random.randint(0, len(available_spots) - 1)) w, h = random.choice(rooms_size) newRoom = (i, j, w, h) #X, Y, W, H for room in rooms: if util.rectangle_intersects(newRoom, room): append = False if append == True: rooms.append(newRoom) for roomIndex in range(len(rooms))[0:]: room = rooms[roomIndex] if room[2] == 10 and room[3] == 10: room_layout = random.choice(room_prefabs_10x10) for x in range(room[2]): for y in range(room[3]): alg_array[x + room[0]][y + room[1]] = int( room_layout[x * 10 + y]) if int(room_layout[x * 10 + y]) == 7: room_exits.append( (x + room[0], y + room[1], roomIndex)) elif room[2] == 5 and room[3] == 5: room_layout = random.choice(room_prefabs_5x5) for x in range(room[2]): for y in range(room[3]): alg_array[x + room[0]][y + room[1]] = int( room_layout[x * 5 + y]) if int(room_layout[x * 5 + y]) == 7: room_exits.append( (x + room[0], y + room[1], roomIndex)) for exit_init in room_exits: path = libtcodpy.path_new_using_function(width, height, path_cost, alg_array, 0) other_exits = sorted([ exit_other for exit_other in room_exits if exit_other[2] != exit_init[2] and ( exit_other[2], exit_init[2]) not in room_connections ], key=lambda e: util.simpledistance( (exit_init[0], exit_init[1]), (e[0], e[1]))) if len(other_exits) > 0: exit_end = other_exits[0] else: exit_end = sorted([ exit_other for exit_other in room_exits if exit_other[2] != exit_init[2] ], key=lambda e: util.simpledistance( (exit_init[0], exit_init[1]), (e[0], e[1])))[0] room_connections.append((exit_init[2], exit_end[2])) room_connections.append((exit_end[2], exit_init[2])) libtcodpy.path_compute(path, exit_init[0], exit_init[1], exit_end[0], exit_end[1]) for i in range(libtcodpy.path_size(path) - 1): x, y = libtcodpy.path_get(path, i) alg_array[x][y] = 3 for x in range(len(alg_array)): for y in range(len(alg_array[x])): if alg_array[x][y] in [0, 1]: terrain[x][y] = game_content.t_cave_wall(x, y) else: terrain[x][y] = game_content.t_cave_floor(x, y) if alg_array[x][y] == 4: creatures.append( random.choice(monsters_pool[GAME.level])(x, y)) if alg_array[x][y] == 7: entities.append( game_content.n_door( x, y, game_content.SPRITESHEET_ENTITIES.image_at( (0, 32, 32, 32)), game_content.SPRITESHEET_ENTITIES.image_at( (32, 32, 32, 32), colorkey=game_constants.COLOR_COLORKEY))) terrain[x][y].passable = False terrain[x][y].transparent = False return terrain, items, entities, creatures
def nodes(self): rr = range(self.path.size()) return [ Pos( *libtcod.path_get(self.path, i) ) for i in rr ]
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()