As you might have seen, FWN has a scrollable, zoomable map.Players (or rather, builders) can place area tiles on that map and from the data gathered therein, relational data is derived (what area is next to each other; what is the actual distance between two points on the global map).


That data is used to make area transitions. Instead of builders pasting down triggers on map edges, some crafty code walks the supermap edges and sees if there are areas bordering; and if the tiles on both sides are walkable. Triggers (placeables, actually) are generated automatically, and there is no more confusion about transition tags, broken links, or similar.

As of now, this only works for maps that can be placed on a map, not interior areas. Maps do not actually have to be overland - the system supports multiple layers, so we might have some for overland travel, some for the Fardrimm; even some for caves. The only prequisites are that they are next to each other and on the same level.

Translating Coordinates

You might not have thought it, but this was one of the trickier parts. 

All map layers have a predefined origin. One might naively assume that you could just pick the upper left point of a map; however, that has some pitfalls only apparent after some careful thought.

  • Having no predefined origin means, for instance, that the whole map moves if you insert a column on the left.This would mean regenerating all transitions, instead of only parts.
  • Having no fixed origin from which to count from means that you would have to relocate all placed entities on the map by hand, if the origin changes.
  • Once you go far (actually, really far - about 20000km in ballpark-math, thanks to NWN using floats and not doubles natively) into one direction; you run into floating point issues where the decimal part isn't wide enough to accommodate sub-meter precision. That's 200 map 10x10 tiles. Note to self: Enthusiasm about a supermap of this size might be premature.

Additionally, NWN coordinates have no ken about any relation data between areas. All any object knows is it's localspace coordinates, called a Location [ X, Y, Z ]. In the best spirit of vector mathematics, things are flipped as to what a layman might expect, where the vector origin is the bottom left corner of a map. To translate that onto a supermap, you have to take that into account, as well as the offset from the actual map origin as described above.

The next part was placing tiles in the mapping library I've decided to use. Most maps in the real world aren't actually flat! While the plethora of coordinate systems is a fascinating topic for sure, none of it fits into what I wanted to do.  I need a flat, non-curved map space that ideally tanslates meters into a on-screen pixel ratio. So there was some more fiddling, since the map lib actually expects map data split up like Google Maps does it. I just wanted to feed actual minimaps into it; as a concession, I've split it up into 10x10 tiles and just fudged the numbers until the scale looked about right.

Systems integration

The map supports displaying arbitary entities (as can be seen in the screenshot). Any object wanting to display on the map needs to send out a "ping" – that is, a publish over redis that contains relevant location and naming data. As usual, this is a good, very fast (in the order of 1-2 milliseconds per object) way to decouple dependencies and make sure that nothing breaks, should a ping go amiss, or FWN crash.

Analogously, events can be sent from FWN to the gameserver over the same channel. A simple publish triggers a script inside nwserver. Use cases might include "Teleport To", "Spawn Object", and so on.


Ideally, editing would be done through FWN itself. However, that is for the future. Fow now we're simply using a Google Docs spreadsheet, that FWN reads (via the google API).

While not really a limitation of the underlying code, to make things simpler (both for builders and for managing the map), map tiles are limited to multiples of 10. So maps can be any variation of (10, 20, 30) x (10, 20, 30), to a maximum of 30x30. Each cell on the spreadsheet corresponds to a 10x10 part of a map.

There is preliminary support to place custom map markers, zones and vector lines on the map (and read those from NWScript). The idea was to disconnect spawner definitions from .git files, and maybe allow reliable cross-area waypoints. This is not implemented yet.


  • No labels