Two Rooms Diverged In A Room: Asymetric navigation and other crimes against mappability

Imagine a road running north and south. It is divided in several places into “rooms”, and the player consistently moves between them with >NORTH and >SOUTH.

Almost everywhere each “slice” of road is precisely one room—there’s no >EAST, >WEST, >IN, or >OUT to any of the road locations.

And then there’s a “wide spot” in the road. Say the road passes through a town, so now we have stuff to the east and west, shops maybe.

First approximation, maybe we just attach the shops directly to the road. But now let us imagine that we have to implement the sidewalks in front of the shops as a navigable location. Is there a particularly clever way to implement this particular map topology?

One “orthodox” IF solution, which uses only canonical map directions and simple connections/topology is to just “stack” the sidewalks between the road and the shops. So now we have something like (from west to east): west shop; west sidewalk; road; east sidewalk; east shop. Movement north from either sidewalk or the road takes you to the single road location directly north of the “wide spot” and moving south from there would take you to the middle location. This is simple, fairly straighforward, and the main objection is that it feels a little clumsy and cluttered.

Another orthodoxy solution, I think less elegant, is more or less the same as above, only using four locations instead of five: west shop; west side of road; east side of road; east shop. Movement from either road location north takes you to the road just north of the wide spot, and moving south from there is either not possible (the player has to use southeast or southwest) or prompts the player for disambiguation (do you want to use the east sidewalk or the west sidewalk). This eliminates some of the clutter but makes navigation less intuitive and disrupts the “feel” of being a north-south road.

Leaving these aside, there are a variety of “non-euclidean” solutions: entering the wide spot from the north takes you to a “middle of the road” location; moving east from there takes you to the east sidewalk; moving west from the east sidewalk takes you to the west sidewalk (skipping the middle of the road location) or something similar. In “real” terms this is probably more intuitive (if you’re crossing a real street you probably think of it as moving from one side to the other, with stopping in the middle not a serious possibility in most circumstances). But it’s also counterintuitive in terms of normal rules of IF navigation. And mapping—as a player, I’d probably find this sort of situation vaguely irritating.

I’m writing in TADS3/adv3, and the contrib module ConSpace offers the ability to define fairly complex room nesting behaviors. This smooths some of the sharp corners off the situation, but I’m not sure if it’s something players would still find jarring. A simple example (in TADS3) with code:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

roadGroup: SpaceConnector;
roadGroupNorth: roadGroup;
roadGroupSouth: roadGroup;

class RoadRoom: Room
        connectionGroup = [ roadGroup ]
        actorInPrep = 'on'
        actorIntoPrep() {
                if(gActor.locationBefore.getOutermostRoom.ofKind(RoadRoom))
                        return('over to');
                else
                        return('onto');
        }
;
class RoadRoomNorth: RoadRoom
        connectionGroup = [ roadGroupNorth ]
        north = northRoad
        east = northeastSidewalk
        west = northwestSidewalk
;
class RoadRoomSouth: Room
        connectionGroup = [ roadGroupSouth ]
        south = southRoad
        east = southeastSidewalk
        west = southwestSidewalk
;

// North part of downtown
northRoadMain:  RoadRoomNorth 'North End Of Downtown' 'north end of downtown' 'middle of the road'
        "This is a road running north and south.  The road is flanked to
        the east and west by shops. "
        south = southRoadMain
;
+me:    Person;
+pebble: Thing 'small round pebble' 'pebble'
        "A small, round pebble. "
;
northeastSidewalk: RoadRoomNorth 'Northeast Sidewalk'
        "This is the sidewalk to the east of the road.  The Northeast Shop is
        just to the east, and the Northwest Shop is across the road to the
        west. "
        south = southeastSidewalk
        west = northwestSidewalk
        east = northeastShop
;
northwestSidewalk: RoadRoomNorth 'Northwest Sidewalk'
        "This is the sidewalk to the west of the road.  The Northwest Shop is
        just west of here, and the Northeast Shop is off to the east, across
        the road. "
        south = southwestSidewalk
        east = northeastSidewalk
        west = northwestShop
;
northeastShop: Room 'Northeast Shop'
        "This is the Northeast Shop.  The only exit is to the west. "
        west = northeastSidewalk
;
northwestShop: Room 'Northwest Shop'
        "This is the Northwest Shop.  A doorway east opens onto the sidewalk. "
        east = northwestSidewalk
;

// South part of downtown
southRoadMain:  RoadRoomSouth 'South End Of Downtown' 'south end of downtown' 'middle of the road'
        "This is a road running north and south.  The road is flanked to
        the east and west by shops. "
        north = northRoadMain
;
southeastSidewalk: RoadRoomSouth 'Southeast Sidewalk'
        "This is the sidewalk to the east of the road.  The Southeast Shop is
        just to the east, and the Southwest Shop is across the road to the
        west. "
        north = northeastSidewalk
        west = southwestSidewalk
        east = southeastShop
;
southwestSidewalk: RoadRoomSouth 'Southwest Sidewalk'
        "This is the sidewalk to the west of the road.  The Southwest Shop is
        just west of here, and the Southeast Shop is off to the east, across
        the road. "
        north = northwestSidewalk
        east = southeastSidewalk
        west = southwestShop
;
southeastShop: Room 'Southeast Shop'
        "This is the Southeast Shop.  The only exit is to the west. "
        west = southeastSidewalk
;
southwestShop: Room 'Southwest Shop'
        "This is the Southwest Shop.  A doorway east opens onto the sidewalk. "
        east = southwestSidewalk
;

// Outside of downtown
northRoad: Room 'North Road'
        "This is the north road.  Everything interesting is south of here. "
        south = northRoadMain
;
southRoad: Room 'South Road'
        "This is the south road.  Downtown, such as it is, lies to the north. "
        north = southRoadMain
;

versionInfo:    GameID
        name = 'sample'
        byline = 'nobody'
        authorEmail = 'nobody <foo@bar.com>'
        desc = '[This space intentionally left blank]'
        version = '1.0'
        IFID = '12345'
;
gameMain:       GameMainDef
        initialPlayerChar = me
;

This gives us a short north-south road and two “slices” of road that are “wide”, having sidewalks and shops alongside the road. A transcript that illustrates the topology:

North End Of Downtown
This is a road running north and south.  The road is flanked to the east and
west by shops.

You see a pebble here.

>e
You walk over to the northeast sidewalk.

>l
Northeast Sidewalk
This is the sidewalk to the east of the road.  The Northeast Shop is just to
the east, and the Northwest Shop is across the road to the west.

On the middle of the road, you see a pebble.

>e
Northeast Shop
This is the Northeast Shop.  The only exit is to the west.

>w
Northeast Sidewalk
This is the sidewalk to the east of the road.  The Northeast Shop is just to
the east, and the Northwest Shop is across the road to the west.

On the middle of the road, you see a pebble.

>w
You walk over to the northwest sidewalk.

>l
Northwest Sidewalk
This is the sidewalk to the west of the road.  The Northwest Shop is just west
of here, and the Northeast Shop is off to the east, across the road.

On the middle of the road, you see a pebble.

>w
Northwest Shop
This is the Northwest Shop.  A doorway east opens onto the sidewalk.

>e
Northwest Sidewalk
This is the sidewalk to the west of the road.  The Northwest Shop is just west
of here, and the Northeast Shop is off to the east, across the road.

On the middle of the road, you see a pebble.

>s
Southwest Sidewalk
This is the sidewalk to the west of the road.  The Southwest Shop is just west
of here, and the Southeast Shop is off to the east, across the road.

>n
Northwest Sidewalk
This is the sidewalk to the west of the road.  The Northwest Shop is just west
of here, and the Northeast Shop is off to the east, across the road.

On the middle of the road, you see a pebble.

>s
Southwest Sidewalk
This is the sidewalk to the west of the road.  The Southwest Shop is just west
of here, and the Southeast Shop is off to the east, across the road.

>s
South Road
This is the south road.  Downtown, such as it is, lies to the north.

>n
South End Of Downtown
This is a road running north and south.  The road is flanked to the east and
west by shops.

>n
North End Of Downtown
This is a road running north and south.  The road is flanked to the east and
west by shops.

You see a pebble here.

>n
North Road
This is the north road.  Everything interesting is south of here.

>s
North End Of Downtown
This is a road running north and south.  The road is flanked to the east and
west by shops.

You see a pebble here.

>e
You walk over to the northeast sidewalk.

>s
Southeast Sidewalk
This is the sidewalk to the east of the road.  The Southeast Shop is just to
the east, and the Southwest Shop is across the road to the west.

>w
You walk into the southwest sidewalk.

>s
South Road
This is the south road.  Downtown, such as it is, lies to the north.

This works, but is to too confusing? Are the examples of this sort of thing being implemented more cleanly/organically/popularly that I’m missing?

Basically the “everything is a square box” approach is mechanically simplest and least confusing (in the sense that it’s the thing that anyone who has ever played any IF would recognize)…but it feels the most cluttered (more moves to cross the road every time) and least “organic” (it’s a bunch of boxes and it “feels” like a bunch of boxes).

Things like the ConSpace example “feel” the most like a “real” space and map reasonably well to what real-world navigation “feels” like (we cross the road to get to the other side, not to reach a waypoint in the middle of the road and thence make a further decision to proceed). But it’s also the least “IF intuitive” (that is, least like “standard” navigation) and potentially more of an irritation to map.

1 Like

My gut reaction as a player is that you do not “have to implement the sidewalks in front of the shops as a navigable location,” and that you shouldn’t. It could be a nice touch to fake it a little bit by tracking state and describing you as being on one sidewalk or another when you exit a store, and narrate you crossing the street when you go from the east shop to the street/sidewalks to the west shop, but don’t make me type extra commands: I’ll just be annoyed at the inconvenience.

I can certainly concoct scenarios where sidewalk locations might be a valid thing to have, but unless you’re writing a game where crossing the street without getting run over by an automobile or stampeding cattle is the central theme of the story, I’d say just don’t do it. Please don’t do it.

My two cents, YMMV, etc.

4 Likes

I agree with this 100% - this is the tack I’ve seen most games use and it works well. So look at that, two more cents, another penny and you’ve got a nickel!

1 Like

I think you should stick with the KISS principle. If all the extra topography does not add to the enjoyment of the game, then leave it out.

I can’t think of any pros. Here are some of the cons:

  • It’s very hard to write engaging room descriptions for boring locations. How many ways are there to describe a road or a sidewalk?
  • Every room description will require extra scenery objects that can be examined (just in case), even though they will not reveal anything new.
  • It is boring and tedious to enter all those commands with extra adjectives to avoid disambiguation questions.
  • It is boring and tedious to play.
1 Like

I’ve been reading Jane Jacobs; I feel compelled to defend the interest and value of the sidewalk. The sidewalk is the thread that stitches a city together! The life of the sidewalk is an elaborate dance in which we all take part!

(I’ll agree with the others that boring locations should be left out, or perhaps just made not boring. But let’s assume you’ve made the sidewalks interesting enough to keep in.)

One odd thing about your example, as I understand it: once you’ve left the middle of the street, the only way to get back to it is to leave town. This is almost certain to annoy players: a little off-grid geometry can be explained away with a nice going message, but making the middle of the street “farther” in move count than the other side is apt to be very annoying, even if there’s no particular reason to stand around in the middle of the road.

Going messages may be a solution to the “entering the town” problem you mention: “The road widens as you head north into town, and traffic forces you to the narrow sidewalk that runs along the eastern edge.”

As Josh mentioned, another approach is to treat whole sections of the street as individual rooms, but keep track of your position in the room somehow. @zarf’s Shade is a well-known example of this effect; it’s a one-room game (well, mostly) but tracks which area of the room you’re in. Everything in the room is in scope, and it’ll move you between areas automatically if you try and interact with something in another area. Worth playing if you haven’t yet!

3 Likes

I don’t particularly disagree with much of what’s been said here…but I wasn’t asking specifically about the sidewalk example, but rather the general case: how to handle when you’ve got topology where you’ve got a “general line of travel” or whatever you want to call it, and (because you don’t want to implement useless locations) it’s mostly “narrow”…and then you have to make it “wide” (to accommodate something that’s gameplay relevant).

I wasn’t specifically asking for a review of the sidewalk implementation in a toy game. But I was assuming that everyone is more or less familiar with roads and the idea of sidewalks running alongside them and so was offering them as a concrete, so to speak, example.

1 Like

Not quite, because this is something that’s handled automagically by ConSpace, although I didn’t talk about it. In the example “game” there’s a pebble in the middle of the road. If you move into one of the sidewalks, the pebble is still visible (because the sidewalk-road-sidewalk set of rooms is all part of a single connectorGroup) and if the player tries to >TAKE PEBBLE the parser will helpfully insert an implicit move that takes the player to the middle of the road. The player can explicitly travel there with something like >STAND NEXT TO PEBBLE. The “game” doesn’t implement any vocabulary to handle something like >STAND IN THE MIDDLE OF THE ROAD, but that’s just an implementation wart that could be handled in a more fleshed-out example.

That said, you raise a good point: when you do this sort of thing, even if you’re “simplifying” travel to make things easier for the player, you probably also want to allow players to “manually” travel to whatever “staging locations” or whatever you want to call them that are mentioned/described/used in the simplification. Or at least handle attempts to explicitly travel to/via them by throwing a “don’t bother”/“not important” failure message.

Yeah, that’s more or less exactly what ConSpace, and the example code I posted, does.

1 Like

That’s cool! Your transcript reads exactly as though they were all distinct rooms hooked up with normal map connections.

The gameplay experience I was vaguely gesturing towards is something like:

Northeast Shop
This is the Northeast Shop.  The only exit is to the west.

>w
North End (by the Northwest Shop)
The Northeast Shop is just to the east, and the Northwest Shop is across the road to the west.

On the middle of the road, you see a pebble.

>get pebble
You move into the center of the street.

Taken.

>l
North End (in the street)
You're dodging traffic in the middle of the street. The Northeast Shop is a ways to the east, and the Northwest Shop is commensurately to the west.

On the middle of the road, you see a pebble.

>w
Northwest Shop
This is the Northwest Shop.  A doorway east opens onto the sidewalk.

ie. cardinal navigation still works between areas, but navigation within an area is relative and mostly automatic. It sounds like ConSpace is capable of this!

Yeah, I got that: guess I should have respended in more general terms instead of just the concrete example, but I like concrete examples, heh. I definitely stand by that advice in general. I tried a few MUDs as a teenager that experimented with a more continuous space and it always just felt kinda clunky.

So for me… If the sub-locations are important enough that you want to do things inside that particular space, then make them separate locations (and maybe fake the wider scene with background descriptions). If you want the “wide” area to feel like a big space that contains smaller pieces, then just fake the sub-locations with descriptions. But having to change stance or stand on a chair or move from location to location in a wider space that’s conceptually one place almost always feels like irrelevant trivia to me…

2 Likes

Yeah, the main “tell” that there’s something else going on is that the pebble is visible from multiple locations, which is not a default behavior with rooms that aren’t bound together in a connectorGroup.

I was (and I guess am) mostly concerned with the “simple navigation” problem—how to arrange the locations such that it’s not confusing or irritating to the player. Or I guess minimally confusing or irritating. Or very specifically minimally unintentionally confusing or irritating. But one of the obvious things I could think of which would be both is if the player is in one of the “through” locations (the middle of the road location that’s part of the north-south navigation pathway) and drops an item and then moves east or west into one of the “leaf” locations. With “normal” rooms-are-a-box navigation, retrieving (or even finding again) the dropped object either becomes a palpably “false” situation (e.g. we can’t see the road from the side of the road) or a metaphysical puzzle involving an elaborate ritual to solve (figuring out how to navigate back to a location you arrived from via non-reversible directional commands).

Automatic-by-reference, mostly. I think the underlying “gimmick” or whatever you want to call it is that you can define “landmarks” within the group that are visible from all locations within the group. Each landmark lives in one specific location, but any/most attempts to interact with the landmark causes an implicit movement within the group to the location’s landmark. And then from that vantage point, other things become visible to the player.

I’m not really using it in the navigation example, because I’m mostly (here) concerned with the “basic navigation” problem. But the reason why I was fiddling around with ConSpace in the first place is because I was interested in implementing a sort of crime scene investigation schtick. I think the most common approach to this is to have triggers in the description(s) of specific objects or scenery elements, with the triggers making additional information/objects/whatever available. That’s cool, but I’m also interested in things like “when you’re standing near the discarded cigarette butts under the tree and you look at the building you can notice that you can’t see the second floor window from there” and so on, which a model like ConSpace’s (and other continuous space models) makes much more straightforward.

1 Like

On the one hand I agree that in most cases the “implicit mobility” of the IF viewpoint both makes sense from a gameplay standpoint and doesn’t feel particularly out of place “narratively”. Like if you’re searching for a blood-stained candlestick in the library or whatever, it makes perfect sense that you can just look out the window or search the bookshelves or check under the comfy chair in the corner without having to type out a bunch of elaborate navigational directions. Even if these actions would necessitate a whole bunch of movements and posture changes on the part of a real person doing all of the above.

On the other hand if your puzzle is, I dunno, changing the oil on a 1971 Ford Pinto, then maybe it does make sense that there are some things that you can only reach when you’re under the car and getting under the car requires special preparation and the things you can reach when you’re under the car aren’t the same ones you can reach when you’re bending over the hood.

In terms of the sort of navigation we’re talking about, imagine you’re travelling east to west atop the ramparts of a castle and run into a dragon parked northbound in the middle of the chemin de ronde (the walkable path). Now, providing navigation such that a player might choose >E; E; NE; SE; E or >E; E; SE; NE; E to get around the dragon from the front or backside (respectively) works, but I think it feels like the ramparts aren’t a straight east-west wall anymore. Similarly, you could encapsulate whatever happens when passing the dragon in a little travel message, but that also will feel different than if you actually get a prompt when you’re in front of or behind the dragon…even if it turns out that there’s nothing to actually do there. Like yeah, in general it makes sense to elide locations where nothing can ever happen and so on, but no player is ever going to sweat over something that only happens summarized in a travel message. Getting a travel message means that it’s safe. Getting a prompt means, especially (and perhaps only) the first time, that something might happen.

1 Like