Doors and Keys

A deep dive into the many design nuances behind doors and keys, how they were implemented, and how they might be improved in the future.
Apr 13 2020

Much of March was spent adding the ability for builders to place doors on room exits. At first glance, this doesn't seem like that much work to implement. A door has a name, impedes movement in a particular direction, and can be opened, closed or locked. Doesn't sound too bad. In reality, there are a lot of nuances to doors and keys, and this post explores them.

The feature is documented here.

Asymmetries

In the traditional spaces we live in, doors are generally symmetrical. The entrance door to a house usually looks roughly the same on both sides and would be referred to by the same name. Similarly, it can be locked on the inside, and on the outside.

How the lock is operated however, may be different. A key may be required on the outside to operate the lock, but on the inside rotating the deadbolt lock may achieve the corresponding operation. So while the default state may be locked on both sides, perhaps one side has a key and the other is operated by a special action.

There are also cases where a builder may want different door names on each side. A good example is a secret bookshelf in a living room, which by pulling a book reveals the way into a backroom. Once in the backroom, the way back out would be simply open door. But from the living room, it may be open bookshelf. The name of the door itself might be different on both sides.

The default state may also be different. The back door to the apartment building where I currently live is locked from the outside by default. I need a key or a fob to enter it. But from the inside, all I have to do is push a horizontal bar in the middle of the door and it swings open with very little effort. There, the outside default door state is locked, and the inside default door state is closed. I don't need a key to go out, but I need one to go in.

Despite all these caveats, the vast majority of the time doors are symmetrical. While we do want to support doors having different names, states, and key requirements on either side, we want to default to the most commonly sought functionality. For that reason, when a builder creates a door in room A going to room B, we automatically create a door going from B to A with the same name, default state and key behavior. But if a builder then edits one side of the door, it will not change the other side to match it.

In terms of player actions, we do always respect symmetry. Taking an action on one side of a door necessarily takes a corresponding action on the other side. When a guest stands outside your house, opening the door from the inside will make the outside door open as well. This is true even if the outside state was locked and the inside state was closed.

The last point worth considering in the topic of symmetry are one-way exits. For example, a trash chute. By definition, is has no reverse exit, and therefore no reverse door. Adding a door to a one-way exit only creates the door on the side that has the connection. Changing a two-way exit that had doors on both sides to one-way will keep only the door on the side that still has the exit. When changing from one-way to two-way however, the platform doesn't want to guess as to what the symmetry rule should be, and the one-way door is removed.

State Change Notifications

Most of the time, a player's map of the world does not change. For this reason, we pass all of the rooms that the player knows about as part of the initial world connection message payload. The implementation of doors, however, changed that. If the initial state of the world is to have the front door of a house be closed, the map will not render a connection between the entrance foyer and the front porch. But if the door is opened, the connection is shown. This means that a player's map needs to update when door states change.

The most obvious scenario is when a player executes a open or close command. The connection in the direction of the action needs to be updated. But what about a player standing on the other side of the door? Their connection in the reverse direction needs to be updated too (unless it's a one-way scenario).

Additionally, players who were not in the room when the state change took place need to be made aware of it once they enter that room (but not before). If I was in the kitchen and the front door was opened, I don't know about that until I get to the entrance room. And because of the way the map is implemented, both the inside room and the outside room's connections need to be updated. Therefore any time a user enters any room, we now have to check for all doors in it, as well as reverse doors in the exit rooms from that room.

Not only is this true when a player enters a room, but it is also true whenever the state of a door resets without any player taking any action. More on that in the following section.

Resetting State

In game design, doors are often used as a gating mechanism. For example, the entrance to a dungeon may only be made accessible if a key is harvested from one of the trash mobs outside of it. In a multiplayer world context, that (modest) challenge should be repeated anew for each raiding party. In other words, that door needs to be set back to closed for the next group.

Up until this feature, mob and item respawns were driven exclusively by individual loaders within a zone. There was no concept of 'zone-wide' respawn. We therefore added to the zone itself a respawn time configuration, and made all loaders inherit by default that parameter from their zone. Individual loaders may still overwrite this, so that a builder can create a subsection of a dungeon that respawns faster than the overall 'reset' interval.

Doors reset their state when the zone's respawn timer expire. This can of course be a dicey situation if a group of raiders is in the process of clearing a dungeon as the reset happens, and we plan down the road to add a feature that short-circuits it if players are in zone. This would necessitate a configuration flag at the zone-level to generally not respawn while players are in it however, because that is generally not desirable by default. Imagine exping in a forest where the mobs never respawn while you are in it? That would be frustrating.

Until such a feature is in place, it is a good idea to make sure that users can get out of locked doors if a zone reset happens. Either by making the inside-to-outside door be closed rather than locked, or by providing a room action to unlock it (say, by pulling a sconce).

Key Snapping, Keyless Locked Doors

Another corollary of the "dungeon entrance" locked door scenario mentioned above, we typically want players to repeat this operation each time they want to enter it. Therefore the key that is used to unlock the front gate has to be valid only for a one-time use. To help with this, we added an option to destroy a key on use. With that option selected, each time a key is used to unlock a door it will snap in two and be destroyed.

Furthermore, there is a case to be made for locked doors that have no keys associated with them. The scenario there is a lever in the room that when pulled will reveal the way north. The action in that situation is carried out by the room itself, which is granted the ability to unlock doors even without a key, something players cannot do.

Door Saving in SPWs

A constant struggle of implementing features in Written Realms are the conflicting expectations between single and multi player worlds. A player logging back into a multiplayer world after several hours will expect things to have changed, and reset back. In single player worlds however, if you opened a door yesterday and logged out, logging back in today the expectation is that the door would still be opened. The passage of time is supposed to 'pause' while you are logged out.

Therefore, we added a sync mechanism to single player worlds so that the state of a door is persisted between play sessions, independent of the door's default state. Of course, this is only true if the zone is set to never respawn.

Future Improvements

We're pretty happy with where we ended up with doors, but there could still be further polish in the future. We already mentioned the 'prevent zone reset if players are still in it' flag that we plan to introduce at the zone level.

Another improvement would be to have secret doors. Currently, while a map will not show a connection where a door is closed, the possibility of an exit in that direction is still indicated by the room's 'exits' section of its description, for example [ exits: S W ]. Even if the W exit is closed, you can still see it as an available exit. Additionally, trying to move in that direction will alert that you cannot because the door is closed or locked.

It's conceivable instead that we would want to completely hide the presence of a door unless the player could deduce its existence based on hints in the room (or surrounding rooms). In that case, the exit would not be marked in the 'exits' prompt, and moving in that direction would give the usual "You cannot go that way." message. Trying to open a locked door in that situation using the wrong name would similarly return a "No 'door' here." message rather than telling you that it is locked.

This would pair nicely with the 'Room Detail' feature we put in last October, where words in a room can be highlighted to provide extra context when clicked on, or looked at.