Meta Commands - ThePix/QuestJS GitHub Wiki

A meta-command is about the game system, rather than the game world. LOOK, NORTH and GET HAT are all the game world; they are telling the player character to do something in that world. HELP and TRANSCRIPT are not like that, they are about the user herself interacting with the game system instead.

HELP, ABOUT/CREDITS and WARNINGS

These three commands tell the user about the game - how to play it, who wrote it, what warning are relevant. They all use scripts defined in the language file, as they are mostly about outputting text.

For the HELP and ABOUT commands, you can append your own game-specific help to the end of the built-in help by setting an array of strings called settings.additionalHelp or settings.additionalAbout. For the ABOUT command, you can also give a list of people you are thanking in settings.thanks, again an array of strings. For WARNINGS, use settings.warnings, which can be a string or again an array of strings. These should be set in the settings.js file.

settings.additionalHelp = ['HINT: To get you started, you might want to investigate the tower.']
settings.thanks = ['Kyle', 'Lara'];
settings.warnings = 'No warnings are applicable to this game.'

You can, alternatively, create functions from scratch for any of these. In that case, the function needs to go into a different file (I suggest code.js). You need to find the relevant command, and then set its "script" attribution. Note that it must return world.SUCCESS_NO_TURNSCRIPTS.

findCmd('MetaHelp').script = function() {
  metamsg("Help is available on a number of topics...");
  metamsg("{color:red:HELP GENERAL} or {color:red:HELP GEN}: How to play parser games");
  metamsg("{color:red:HELP GAME}: Suggestions on what to actually do");
  metamsg("{color:red:HELP NPC}: Interacting with other characters");
  metamsg("{color:red:HELP SYSTEM}: About the game system");
  metamsg("{color:red:HELP CREDITS}: Credits, obviously!");
  return world.SUCCESS_NO_TURNSCRIPTS;
}

SPOKEN, INTRO and UNSPOKEN

The SPOKEN command will have Quest read aloud the text. Given you will have missed the introiductory text at this point, the INTRO command will repeat it (though that relies on games using it properly!). UNSPOKEN turns off this feature.

VERBOSE, TERSE, BRIEF

This control when room descriptions are given. With VERBOSE, a room is described every time the player enters it, with TERSE only the first time, with BRIEF never (but the user can see descriptions with LOOK).

This is controlled in the room template, using the text processor, which defaults to this:

settings.roomTemplate = [
  "#{cap:{hereName}}",
  "{terse:{hereDesc}}",
  "{objectsHere:You can see {objects} here.}",
  "{exitsHere:You can go {exits}.}",
],

I am not sure how much a user will ever use TERSE or BRIEF, but they were present in early adventure games, and it seems therefore to be required in modern games.

TRANSCRIPT

The TRANSCRIPT or SCRIPT commands can be used to handle recording the input and output. This can be very useful when testing a game, as the author can go back through it and see exactly what happened, and how the user got there.

Use SCRIPT ON to turn on recording and SCRIPT OFF to turn it off. To clear the stored data, use SCRIPT CLEAR. To clear the old data and turn recording on in one step, use SCRIPT START.

Use SCRIPT SHOW to display it - it will appear in a new tab; you will not lose your place in the game. Some browsers (Firefox especially) may block the new tab, but will probably give the option to allow it in a banner at the top. You will probably need to do the command again.

You can add a comment to the transcript by starting your text with an asterisk, *, or semi-colon, ;, - Quest will record it, but otherwise just ignore it.

Everything gets saved to "LocalStorage", so will be saved between sessions. If you complete the game the text input will disappear, however if you have a transcript recording, a link will be available to access it.

If settings.playMode is set to "beta" then the transcript will be automatically going from the start (so your beta-testers do not have to remember to). You can also do ctrl-Enter to quickly open a new tab showing the transcript (a shortcut for SCRIPT SHOW).

Once you have a transcript, it is worthwhile pasting it into a word processor like MS Word or LibreOffice, and doing a grammar and spell check. It will probably pick up things the Notepad++ spell check cannot.

You can use the transcript facility to record a walk-through. Start it as normal, but do SCRIPT WALK to open a new tab with the walk-through. More on walk-throughs here.

SAVE and LOAD

The details of how a game is saved is discussed elsewhere.

Typing SAVE or LOAD tells the user about the save/load system. SAVE or LOAD with a filename will save or load the game to or from LocalStorage. You can also DELETE a file, or use DIR to see a list of saved games. To save to file, use FSAVE or FLOAD with a filename.

HINT

The default HINT command just says there are no hints. There are a lot of ways to set up hints, making it difficult to build something in, but we will look at some alternatives.

However you handle hints, you need to give the existing command a new script. Here is a very simple example to get us going. It starts by using findCmd to get the named command, then sets its "script" attribute. This simple version just prints the same message whatever the player's progress.

findCmd('MetaHint').script = function() {
  metamsg('See if you can stop the profession using the doomsday machine. Perhaps try to cut the power?')
}

This version is location-based. If the current location has a "hint" attribute, that will get displayed.

findCmd('MetaHint').script = function() {
  if (currentLocation.hint) {
    metamsg(currentLocation.hint);
  }
  else {
    return lang.hintScript()
  }
}

This is a much more involved version that tracks the player's progress, giving hints about how to achieve the next stage (you can see it in action here).

findCmd('MetaHint').script = function() {
  if (typeof hint.data[game.player.hintCounter].hint === 'string') {
    metamsg(hint.data[game.player.hintCounter].hint)
  }
  else if (typeof hint.data[game.player.hintCounter].hint === 'function') {
    hint.data[game.player.hintCounter].hint()
  }
  else {
    console.log(hint.data[game.player.hintCounter].name)
    console.log("hint.data[game.player.hintCounter].hint is a " + (typeof hint.data[game.player.hintCounter].hint))
  }
  return world.SUCCESS_NO_TURNSCRIPTS;
}

It assumes there is a "hint" dictionary, with an attribute "data" containing all the hints. It should be set up like this:

const hint = {}

hint.data = [
  { name:'waitAtStart', hint:'Just type WAIT to get to the next stage.'},
  { name:'northToKitchen', hint:'Type NORTH to go into the kitchen.'},
]

Two functions are included, the first for progressing the hint, the second for testing the progress.

hint.now = function(name) {
  const n = hint.data.findIndex(el => el.name === name)
  if (n === -1) throw "No hint found called " + name
  if (n > game.player.hintCounter) {
    game.player.hintCounter = n
    if (hint.data[n].tutorial) {
      for (let s of hint.data[n].tutorial.split('|')) tmsg(s)
    }
  }
}

hint.before = function(name) {
  const n = hint.data.findIndex(el => el.name === name)
  if (n === -1) throw "No hint found called " + name
  return (n > game.player.hintCounter) 
}