Semi-Dynamic ASCII Maps

Submitted by daniko on Mon, 2011-10-17 18:34

Anyone play anything IRE? Well, if you do, you'll know that they have a pretty awesome in-game mapping system. A simple MAP command and you've got yourself a fairly dynamic ASCII paths and rooms picture:

[ ]
[ ]-[ ]-[_]
    [+]-[ ]-

Well, I'm proud of my own similar and halfway-dynamic system that does something similar (did I just use "similar" twice in the same sentence?).

Rather than creating a single blob of map text on each and every room, I've come up with a way to create a single map on a parent room, set coordinates on child rooms and have the "You are Here" marker move about via those coordinates. it's probably not all that amazing for someone who knows what they're doing, but I'm proud of it anyway, and I figure the least I could get from ya'll is a bit of critique on its functionality, style, whatever.

So here we go...

Say you've got a room configuration like the one above (in case you didn't know, IRE has specified "+" as you, "_" as down and "^" as up).

Pick a room that will act as a sort of map parent. It'd be parented to the area/zone/master or whatever, but all other rooms that apply to the single map you wish to make will be parented to it. And hopefully I don't have to tell you to actually DO that. Because you should.

On the map parent:

@set here=map`map_01:[lit([ ])]
@set here=map`map_02:[lit(   \ )] 
@set here=map`map_03:[lit([ ]-[ ]-[_])]
@set here=map`map_04:%b
@set here=map`map_05:[lit(        [^])]
@set here=map`map_06:[lit(       /)]
@set here=map`map_07:[lit(    [ ]-[ ]-)]

Note 1: MAP`MAP_02 - Don't forget to add a space behind the backslash or you'll escape the )-symbol.
Note 2: MAP`MAP_04 might be blank, but it still has to be there. Otherwise the mapper will shove the empty spot out of the way.

Now you're looking at that and saying to yourself, "Oh that's just too simple. Why the heck is he showing us this?"

Like I said, this is inherited from the map parent and your own position will be based on coordinates rather than copying this map to every room in the area.

Now I suppose we could set up the actual mapper command. Either a new object will do or you could just put it on one of your more general global command machines since there's only two things that need setting:

&do_map CMD OBJECT = $+map:@pemit %# = [switch(t(lattrp(%L/map`map_*)),1,[iter(sort(lattrp(%L/map`map_*),lattr),[switch(hasflag(%#,mapcoord),1,ljust(ansi(hw,##:),12))] [switch([and(strmatch(MAP`MAP_xget(%L,map-y),##),hasattr(%L,map-x))],0,xget(%L,##),1,[strreplace(xget(%L,##),sub(xget(%L,map-x),1),1,ansi(hw,switch(hasattr(%L,map-pos),1,xget(%L,map-pos),+)))])],%b,%r)]%r[switch(hasflag(%#,mapcoord),1,%r[ansi(hw,[ljust(X-Coords--->,14)][table([lnum(2,62,%b,4)],3,79)])])],%r[v(msg_nomap)])]

&msg_nomap CMD OBJECT = There is not a map in that location.

Okay. Yes, I have an obsession with switch(). If you don't like it, well then you don't like it. But I do!

Anyway, if you simply +MAP while standing in that map parent room or any of its children, you should see the simple ascii map displayed. Built into the above +map command is also a set of coordinate lines. All that you need to do to turn that on is:

&mapcoord me=1
@set me/mapcoord=visual (optional if the command object is a wizard or see_all)

Now if you +MAP, you should see something like:

MAP`MAP_01:  [ ]
MAP`MAP_02:     \
MAP`MAP_03:  [ ]-[ ]-[_]
MAP`MAP_05:          [^]
MAP`MAP_06:         /
MAP`MAP_07:      [ ]-[ ]-
X-Coords--->  2   6   10  14  18  22  26  30  34  38  42  46  50  54  58  62

The coordinate lines make it much easier to set coordinates in each of the rooms, because now you're going to go into each room parented to the map parent (room where the actual MAP`MAP_## commands are stored), and set MAP-X and MAP-Y attributes on those rooms.

MAP-X will line up with the first digit of the corresponding number on the graphical horizontal axis. As you can see, if MAP`MAP_## are set properly with no leading spaces, the map will be padded in order to line up with the numbers on the x-axis, so it's much easier to figure out what MAP-X will be.

In the same way, MAP-Y will refer to the digit-portion of the MAP`MAP_## label (y-axis if you want). If you program in leading zeros on this digit, MAP-Y will also need those.

So let's say we were standing in the room at (10,5) with a southwest exit and an up exit.

&map-x here=10
&map-y here=05

Now you +MAP and you should see...

MAP`MAP_01:  [ ]
MAP`MAP_02:     \
MAP`MAP_03:  [ ]-[ ]-[_]
MAP`MAP_05:          [+]
MAP`MAP_06:         /
MAP`MAP_07:      [ ]-[ ]-
X-Coords--->  2   6   10  14  18  22  26  30  34  38  42  46  50  54  58  62

Note the + symbol replaced ^. + is the default for your current position. This symbol is changed on a per-room basis (or the map parent room if you so choose) using the MAP-POS attribute. Okay..that's a potential bug I just noticed there...I don't have any checking to make sure that MAP-POS is a 1-character length. Yet another switch around xget(%L,map-pos) to make it switch(strlen(xget(%L,map-pos),1,xget(%L,map-pos),+) ought to fix that.

So yeah! There you go. I've had a few more ideas with it, such as padding the left side of the map with a lot of spaces (20+) and then having +map trim it down to zero. Then the other would be to start the MAP`MAP_## attributes around 12 or so instead of 01. With those two implementations in place, it wouldn't be as difficult to add western or northern rooms onto the map - I wouldn't have to go through every single room and change the coordinates.

Also, the lnum(2,62,%b,4) COULD be changed to lnum(2,width(%#),%b,4)...

So there's my first attempt at a tutorial. Critique is welcome, just so long as you're not holding the ritual cattle prod.