NPC Visibility - ThePix/QuestJS GitHub Wiki

To some degree tis is a work-in-progress, and some of the finer details may change. This page is as much my musings as documentation.

In the simplest cases, if the NPC is in the same location as the player, the player can see what he is doing, and if not she cannot. But there are situations where that is not the case, where the player is in one location, and the NPC in another, but the player can still see him.

Quest uses a function attribute on the NPC called "inSight" to determine if the player can see him. You can add your own to an NPC to do this how you like. This trivial example will have the NPC visible wherever he is.

  inSight:function() {
    return true
  },

This example is for an NPC the player can see if a special link is active, or they are in the same room.

  inSight:function() {
    return player.loc === this.loc || this.specialLinkActive
  },

This example is for a tiny man, only visible when the player is in the nursery and the dolls house is open.

  inSight:function() {
    return player.loc === 'nursery' && !w.dollshouse.closed
  },

By location

Usually the built-in version will work fine, and you just need to set up the location so it will work properly. The advantage to this is that it will then just work for all your NPCs.

You need to do this for the location the NPC is in, rather than the player - though usually that means doing both, as if the player can see the NPC from one location to the other, she will usually also be able to see him when their positions are reversed.

To make NPCs visible in a location, you need to give the location a "visibleFrom" attribute. This can be an array or a function.

Using an array

The array should be a list of locations an NPC can be seen from. This example just has one, but it can be as many as you like. You can also set a string attribute "visibleFromPrefix", and this will be prepended to the description of what the NPC is doing. The same string will be used for all the locations in the array and any NPC.

createRoom("garden", {
  desc:"Very overgrown. The garden opens onto a road to the west, whilst the conservatory is east. There is a hook on the wall.",
  east:new Exit("conservatory"),
  visibleFrom:["dining_room"],
  visibleFromPrefix:"Through the window you can see:",
})

If you do not have a "visibleFromPrefix", then the message is printed without modification.

Using a function

The function is more flexible, but more complicated. It should return false if the NPC cannot be seen, and either true or a string if he can. The string will be prepended if available.

The example above is done using a function below. This allows us to modify the text, so "Henry looks at his watch." becomes "Through the window you can see Henry looking at his watch." To get this to work well could involve a lot of work; this example is only going to handle Henry looking at things.

createRoom("garden", {
  desc:"Very overgrown. The garden opens onto a road to the west, whilst the conservatory is east. There is a hook on the wall.",
  east:new Exit("conservatory"),
  visibleFrom:function(room, request) {
    if (currentLocation.name !== 'dining_room') return false
    return function(str, npc) {
      msg("Through the window you can see " + str.replace('looks', 'looking'), {npc:npc})
    }
  },
})

In fact we can get it a bit more general if we flag verbs in the agenda.

  agenda:[
    "moveTo:hall_south",
    "text:Henry looks{!:verb} at his watch.",
  ],

Now we can search for that. Of course, some verbs double the last consonant or drop as "e", but it is an improvement.

  visibleFrom:function(room, request) {
    if (currentLocation.name !== 'hall') return false
    return function(str, npc) {
      msg("At the end of the hall you see " + str.replace('s{!:verb}', 'ing'), {npc:npc})
    }
  },

The message

We need to think about how we report this to the user. Suppose we have an agenda item when Kyle looks at his watch. If the player is in the same room, the user sees "Kyle looks at his watch." What if the player sees it on a video monitor or through a window? We can just prepend a string "On the screen you see: " or "_Through the window you see: _". This is the basis for the "visibleFromPrefix".

However, it is not as simple as that. What if you want "You see Kyle at his watch through the window." or "Through the window you notice Kyle looking at his watch."? And do we give control of this to the location? Or the agenda? Or the NPC?

Consider a game where NPCs can cross a bridge, and we want a special message about that; "You can hear Kyle walking across the rickety bridge towards you." Clearly we want the exit itself to sort that out. But we also have Jasper the Angry Ghost, who just floats from one room to another. "Jasper floats into the lounge from the west.". In that case we want the NPC to sort it out. But who does it when Jasper floats across the bridge?