Debugging - ThePix/QuestJS GitHub Wiki

We all make errors - yes, even me. This page will give some suggests as to how to resolve them.

Most errors manifest with an error message, either on the page or in the console (or both), therefore it is important to have the console open whilst you test your game.

For suggestions on beta-testing, see here.

The Console

Press F12 (or Crtl-Shft-I or Crtl-Shft-J or via a menu) whilst in your browser to open the "Developer Tools" - as far as I can tell, this is the same for all browsers; they look a little different, but the same things are there. I recommend having this open whenever you are working on your game.

The console will appear as a split screen with the web page. It may be at the right, the left or the bottom; there will be an option somewhere allowing you to move it where you want. I prefer to have it to the right.

There will be various tabs; "Elements", "Console", and others. If you do not see the tabs, try dragging the divider between the web page and developer tools to make the latter larger.

The "Elements" tab will show a representation of your web page, laid out so you can see each element. Hover over an element in the console to highlight it on the web page. Clicking on an element to see its styling data in the panel below. This can be very useful if you cannot work out why that window is so small or that text is blue.

The "Console" tab will show any hidden output from the web page, including any errors in your JavaScript code.

The console is kind of partially disabled in "play" mode to discourage users from taking a peek at source code, variables, etc. However, it is not that difficult to bypass that, so do not assume users will never be able to access it.

Errors

File load error

When the browser loads a JavaScript file it actually runs all the code on the page (function code is loaded, rather than run, but that does involve some checking). The first type of error it will detect is, therefore, syntax errors; things like missing commas and brackets. These occur before Quest is properly running, and you will see things missing from the page or not drawn correctly.

Usually the message is clear, and it tells you the exact file and line number where it hit the problem. One error worth highlighting is:

settings.js:60 Uncaught SyntaxError: Unexpected end of input

This happens when you failed to put in the closing brace, }. The browser may not realise until it comes to the end of the file and it has still not found it, and so in this case the line number is not useful. The best advice I can offer is to go back to where you were last making changes and start from there.

Run-time messages

Once Quest is up and running (which should be just before settings.setup is run), it will react to most errors itself. A generic error will appear on the web page, but the details will be in the console. It will usually tell you exactly what is wrong and where, and then a stack trace, indicating where in the code it happened.

It will look something like this:

q6error

In this case, the error is "ReferenceError: player is not defined". What this means is I am trying to use "player" as though it is a global variable; I should have been using game.player (since writing this page, Quest has been modified so now "player" is a global variable). The line below that tells me where: "at Object.checkCanSwitchOn (hideout.js:502)". That tells me it is in a function called "checkCanSwitchOn", in the file hideout.js, at line 502.

Note that sometimes the bug can be lower down the list - this is especially true of errors with the text processor.

You may also see warnings here too. For example, when you load the page (and settings.playMode is "dev"), Quest will check through every exit and give an error message if one is not a proper Exit object or if it goes to an unknown room.

Exceptions

An exception occurs when the browser cannot cope with the code. The browser will again put the details into the console, together with a stack trace.

The stack trace

This is a chain of lines of code. The top one is where the stack trace was called from; the next line down was what called the function the first was in. The third line with be the line that called that function and so on.

So which line is the error in?

Start at the top, and work down. Chances are it is in one of your files rather than a library file (but not necessarily). Also bear in mind it is probably in a file you have recently changed.

If the top line is "errormsg" or a line in _io.js, and the line number is less than 20, you can ignore that; that is just the function printing the message. Chances are the next line is in a library where some checking is being done. It might be worth looking there to see what is being checked, but the error is more likely in the next line. But also read the error message carefully; it might suggest something else entirely.

error1 error2

Note that it has an annoying habit of split line numbers; I have stared at line 28 for ages before realising the error is online 289!

Command not recognised

What if there is no error message, but the parser just fails to find your command or fails to find the right object with it?

The first thing to try is the PARSER command. Use this to turn parser debugging on, then try your command again. You will see a bunch of text; Quest is saying how it scored each command and each object.

If your command is not being considered, the issue may be the regular expression. You might want to try pasting the regular expression into a web site like this, and test the command with it.

If your object is not being considered, is it in scope? If your command does not use extended scope, only the items in world.scope will be considered. You can check what is currently in there by typing world.scope in the developer console and pressing return.

If your command/object is found by Quest, but Quest is picking another, consider boosting the score for a command, or parserPriority for an object (or reducing it for whatever is beating it).

Other Debugging Notes

Custom messages

You can also put code in your files that will print messages to the console. This can be very helpful when trying to work out the logic flow through your game, and checking if it is actually using the code you think it is, and for seeing what the value of something is at that point.

log("This is my string")
log(this)

The log function is a shortcut to the standard JavaScript console.log function; I use it a lot, and it saves typing.

If you send an object or array, the entire object or array will be there and you can check every value if you expand it (note that in Chrome the values will be what they are when you expand it, not at the time the log command was executed; other browsers may vary). It will also report the file and line number (useful when you want to remove it and cannot remember where you put it!).

console1

Do not be afraid to put these statements in the built-in libraries if that is going to help. As long as you remove them later, it will be fine (and the console will tell exactly where they are in case you forget).

Note that msg output is stored in a buffer and may appear out of order compared to other output, so can be misleading.

JavaScript commands

You can also type into the console. Want to know the state of the "torch" object? Just type w.torch (and press enter twice) and all the attributes will be listed, and you can check they are what you expect them to be. You can even run functions from here. Type msg('hello') and "hello" will appear in your game screen. Type w.torch.loc=game.player.name and the torch will be in the player's possession. You can do literally anything from here!

Play Mode

Quest 6 has a number of play modes to facilitate development, set with settings.playMode. Use 'dev' when developing your game, 'beta' for beta-testing, and 'play' when the game is released.

Name dev beta play
Leave page warning n y y
Keyboard shortcuts y y n
Transcript from start n y n
debugmsg visible y y n
Object checking at start y n n
Debugging commands y n n

If the player tries to leave the page (after making at least some interaction), she will get a warning that data will be lost. This is turned off in dev mode (as you tend to reload your game frequently).

Ctrl-Enter can be used as a short cut for SCRIPT SHOW, and the KeyPad-0 can be used as a shortcut for various commands in dev and beta mode.

Transcripts are automatically on from that start in beta mode.

Messages printed with the debugmsg function will only be seen in dev and beta mode.

If in dev mode, at the start of the game Quest will check: that the location exists for every object with a location set; that every direction attribute is an Exit object that is set to an actual location (unless the location is "_"); and that every attribute that is not a direction is not an exit.

When in dev mode, a number of extra commands are available, as discussed in the next section.

Debugging Commands

Warp

Type WARP <object name>. If the object is a room, the player will immediately go there. If it is an item - and it uses the usual "loc" attribute - if will be held by the player (and "scenery" attribute removed). A turn will pass.

This is a quick way to get to where you need to test.

Walk-through

Type WT <name> to run a walk-through.

Walk-throughs are simply arrays of commands, all inside a dictionary called walkthroughs, and are usually best placed in code.js. This example creates a single walk-through called "one".

const walkthroughs = {
  one:[
    "n", "w", "n",
  ]
}

Type HIGHLIGHT to highlight parser, error and meta messages. This can be helpful to pick out issues in a long walkthrough.

More here.

Inspect

Type INSPECT <object> to see all the details about the given object (in the console window). You can also use this to test whether the parser will understand synonyms and abbreviations as you want.

Use INSPECT2 <object> with the object name, as opposed to the alias. This is useful for rooms and for objects not currently reachable in the game.

Cmd

Use CMD <command> to see details for a specific command.

Type CMDS for a full list of commands, together with the regular expression. If useable by NPCs, that will also be noted. Note that sometimes multiple commands are used to handle different word orders (eg PUT ON HAT and PUT HAT ON); by convention, the second form has the same name but with a 2 suffix, the third has a 3 suffix, etc. (but the first has no number). When listed, these will appear as alternative regular expression.

Test

Type TEST to run unit tests (or press the 0 on the number pad with Num Lock off). Unit testing is discussed here.

Parser debugging

The PARSER command toggles debugging information for the parser. When turned on, you will see what commands the parser found as potential matches and what objects, and how it scores them when decided which to use.

Statistics

Use the STATS command to get statistics for your game - number of items, number of NPCs.

You can customise the data provided with settings.statsData which should be an array of dictionaries. Each dictionary needs a name string and a test function that, given an object, returns true (the actual Boolean) if the object should be included in the count, or a number to increase the count by that amount.

This example adds a count of locations flagged with "todo".

settings.statsData = [
  {name:'Objects', test:function(o) { return true }},
  {name:'Locations', test:function(o) { return o.room }},
  {name:'Locations requiring work', test:function(o) { return o.room && o.todo !== undefined }},
  {name:'Items', test:function(o) { return !o.room }},
  {name:'Takeables', test:function(o) { return o.takeable }},
  {name:'Scenery', test:function(o) { return o.scenery }},
  {name:'NPCs', test:function(o) { return o.npc && !o.player }},
]

Note that numbers could change as the game progresses; for example an item might stop being scenery.

Custom debugging commands

You can easily add your own debugging commands - just wrap the normal command in an if statement. This example adds a CHEAT command that will get the player to a certain location, with attributes set and with a certain item. This can be very useful during game development as you can quickly get to the bit of your game that you are working on. When you start on another bit, just change the script. And when you release your game, as long as you set settings.playMode to "play" - which you should be doing anyway - users will not have access to the command as it just will not exist.

if (settings.playMode === 'dev') {
  new Cmd('DebugCheat', {
    regex:/^cheat$/,  
    objects:[
    ],
    script:function(objects) {
      player.loc = 'palace'
      player.status = 14
      player.hasSeenEvidence = true
      w.macguffin.loc = player.name
      return world.SUCCESS
    },
  })
}
⚠️ **GitHub.com Fallback** ⚠️