Destinations, not directions - ThePix/QuestJS GitHub Wiki
The compass has been a part of parser-based games since the very first game, and there is a very good reason for that - it works. Pretty much everyone knows how north and south work, it is much less complicated to implement that a system that depends on which way the player is facing. However, it does not feel that natural. It is rare that a novel will mention a compass direction.
One possible alternative is to offer the user a list of destinations. Instead of clicking on the compass rose, the user selects a destination from a list.
This is pretty easy to do.
If you are using side panes, all of this needs to go in settings.js. It turns off the compass, stops the location lit of directions getting save, then adds a new side pane (which is discussed here) and finally goes through all the locations and modifies them, as discussed later.
settings.compassPane = false
settings.saveLoadExcludedAtts.push("dests")
settings.setup = function() {
createAdditionalPane(2, "Go to", 'directions', function() {
let html = ''
if (!currentLocation.dests) return html
for (const ex of currentLocation.dests) {
const dest = w[ex.name]
html += '<div style="margin-bottom: 10px;"><p class="item" onclick="runCmd(\'go to ' + dest.alias.toLowerCase() + '\')">' + dest.headingAlias + '</p></div>'
}
return html
})
for (const key in w) {
const o = w[key]
if (o.dests) {
for (const ex of o.dests) {
const dest = w[ex.name]
if (!dest) log('Warning: ' + ex + ' in the destinations for ' + key + ' is not a location.')
ex.origin = o
ex.dir = 'to ' + (dest.dirAlias ? dest.dirAlias : dest.alias)
}
}
}
}
If you are not using side panes, you can skip much of that, and just use this instead:
settings.setup = function() {
for (const key in w) {
const o = w[key]
if (o.dests) {
for (const ex of o.dests) {
const dest = w[ex.name]
if (!dest) log('Warning: ' + ex + ' in the destinations for ' + key + ' is not a location.')
ex.origin = o
ex.dir = 'to ' + (ex.dirAlias ? ex.dirAlias : dest.alias)
}
}
}
}
Locations need to be set up differently because we now have a list of destinations, rather than attributes taking their name from compass points. Thus, we have a "dests" attribute - an array of Exit objects.
This example has three possible destinations one of which has extra attributes - just like a normal exit.
createRoom("kitchen", {
desc:'A clean room, a clock hanging on the wall. There is a sink in the corner.',
dirAlias:'the kitchen',
dests:[
new Exit("garage"),
new Exit("lounge"),
new Exit('basement', {
isHidden:function() { return w.trapdoor.closed; },
}),
],
afterFirstEnter:function() {
msg("A fresh smell here!");
},
})
There is also a "dirAlias" attribute you can add to the exit. This will be used when the game says the player is going somewhere. We want it to say the player is going to "the kitchen".
Quest sets the "dir" and "origin" attributes of exits automatically, but because our exits are in an unexpected place, we will need to do that. However, we can still get Quest to do most of the work - this was what we did in settings.js.
All of this needs to go in code.js. Even if you are not using the text input, you still need it, as the side pane uses it.
parser.isRoom =function(o) { return o.room }
commands.unshift(new Cmd('GoTo', {
npcCmd:true,
regex:/^(?:go to|go) (.+)$/,
objects:[
{scope:parser.isRoom, extendedScope: true}
],
script:function(objects) {
const room = objects[0][0]
if (room === currentLocation) return failedmsg("As if by magic, you are suddenly... where you already were.")
if (!room.room) return failedmsg("{pv:item:be:true} not a destination.", {item:room})
for (const ex of currentLocation.dests) {
log(ex.name)
if (room.name === ex.name) {
return ex.use(player, ex) ? world.SUCCESS : world.FAILED
}
}
return failedmsg("{pv:item:be:true} not a destination you can get to from here.", {item:room})
},
}))
Ensure you use a custom HELP command, as they built-in help text will be wrong.