On libtcod fog of war

Google is a curious device. It points its users to my blog post tagged ‘libtcod (dead link, go to https://bitbucket.org/libtcod/libtcod ) fog of war’, despite it not having much to do with actual instructions on how that works. I’ve decided to write an actual post about it, so you won’t be disappointed next time you click the google link pointing to my blog. Read on if that’s why you’re here.

Foreword

I will be writing for version 1.5.1-b2 that I use now, but as far as I know the FOV algorithms didn’t change much from ‘stable’ (actually quite buggy) v 1.5.0. I’m also using python, and I don’t know if the functions work differently, much less how to implement them in any other libtcod-supported language. I’ll have to point you to official libtcod forums (dead link, see above) or #rgrd channel @quakenet.org

Here’s link (dead link, see above) to the libtcod web documentation. Overall the docs are well written, but can be confusing to beginners (such as me, when I’ve done this the first time). The tutorial by Jotaf (dead link, go to http://www.roguebasin.com/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod) that I used for my first project was very helpful. Anyway, let’s get on with this.

Building the FOV map

First, we have to create a FOV map with size of our dungeon map. You can do that with new_map(width, height) function. You only have to do it once per map. Let’s say the map is a rectangle with sides of 50 and 40:

fov_map = libtcod.new_map(50,40)

Of course, you can use variables instead of plain numbers. After that we have to set properties to the map tiles. You should have ‘Tile’ objects listed with ‘blocked’ variable, and maybe ‘block_sight’ variable (if you want tiles that block sight but are passable, or ones that block movement and are see-trough like glass). Map is a two-dimensional table of such objects.  The easiest way to assign values to our new FOV map is to call nested for loop (it might not be the best, or fastest way, it’s just how I’ve done it):

for y in range(50):
    for x in range(40):
        libtcod.map_set_properties(fov_map, x, y, map[x][y].transparent,
           map[x][y].walkable)
libtcod.console_clear(con)

console_clear(con) clears the console, so the map starts blank.

The block_sight and walkable are boolean variables from Tile objects. The way libtcod implements those, True sets both to transparent and walkable. The only reason to set walkable is to use it later for pathfinding toolkit libtcod provides (it works on the same map class as fov toolkit). This is all that is required for building the FOV map. Next, we need to calculate FOV originating from the player character’s position.

FOV calculation

This section (dead link, see above) of documentation lists all available FOV algorithms. Try them out and choose the one that looks best for you. I’m using 0, or FOV_BASIC. This is the main compute function to call (you probably want to call it after every time the player moves):

libtcod.map_compute_fov(fov_map, player_x, player_y, max_radius=6,
    light_walls=True, algo=FOV_BASIC )

That’s it. The player_x/y is player’s position, max_radius is the range of vision, light_walls, if True light up walls next to the ground in view (cosmetic), algo is the algorithm used.

Using the FOV info

Now all you need to do is call functions that retrieve the data from fov_map when needed. For example, when drawing the map on console, you might want to check which tiles to light up as those the player sees right now. For that call a simple is_in_fov function (x and y are coordinates of the tile):

libtcod.map_is_in_fov(fov_map, x, y)

To check if the tile is walkable or transparent (for example, you’d like to set all non-transparent and blocked tiles to be displayed as ‘#’ walls):

libtcod.map_is_transparent(fov_map, x, y)
libtcod.map_is_walkable(fov_map, x, y)

Fog of war effect

To get the fog of war effect everyone is looking for so frantically on my blog, give the tile objects explored property, set it False by default, and then change it to True everytime the tile is in FOV. In the rendering function, check if the tile was explored and render it properly. Et voilà.

That is all.

You can browse my code and see how I’ve done it.

If you have any questions or problems, come over to #rgrd or e-mail me by the contact form above. Good luck and happy roguelike coding :]

M.