diff --git a/.claude/launch.json b/.claude/launch.json index 5bafaa3a4..ff58639ad 100644 --- a/.claude/launch.json +++ b/.claude/launch.json @@ -13,6 +13,13 @@ "runtimeExecutable": "node", "runtimeArgs": ["src/WasmPlayer/dev-server.mjs"], "port": 5175 + }, + { + "name": "DocsSite", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "cwd": "site", + "port": 4321 } ] } diff --git a/.claude/skills/docs-screenshots/SKILL.md b/.claude/skills/docs-screenshots/SKILL.md new file mode 100644 index 000000000..a9cbf7dc6 --- /dev/null +++ b/.claude/skills/docs-screenshots/SKILL.md @@ -0,0 +1,132 @@ +--- +name: docs-screenshots +description: Regenerate stale editor screenshots embedded in site/src/content/docs/ against the current AppShell editor, using a Playwright capture harness +--- + +# Regenerating docs editor screenshots + +## Why this exists + +The migrated Quest 5 docs (`site/src/content/docs/`) embed ~299 screenshots. +Most show the **old Quest 5 desktop/web editor** — a Windows Forms app with a +ribbon toolbar — which no longer exists. Quest Viva ships one unified editor +now (`src/AppShell/`, a SvelteKit SPA, same UI in a browser tab or the +Electron app). This skill captures fresh screenshots against that real, +running editor instead of by hand. + +## Current scope + +**In scope today:** +- **Editor-chrome screenshots** — pages showing the editor's own UI (tree, + tabs, forms, dialogs). Root `site/public/images/` and + `site/public/images/other_guides/`, roughly 150 images. +- **In-game player screenshots** (~60 images, showing gameplay output) — via + `openPreview`/`sendCommand` (see below), which drives the *same* AppShell + draft a capture script already built, through the real toolbar Preview + button into a live WasmPlayer tab. No separate `.aslx` fixtures needed — one + script can build the draft and capture both the editor states and the + resulting gameplay in one run. + +**Out of scope — do not extend this harness to these without re-scoping first:** +- **`site/public/images/helpsheets/`** (~152 images) — a large, distinct + beginner-oriented track. Worth its own decision on approach before touching. +- **External/non-Quest images** — Trizbort app screenshots, YouTube embed UI, + hand-drawn diagrams like `architecture.png`. Not Quest UI; nothing to regenerate. + +## How it works + +`tests/e2e/docs-screenshots/` (part of the `quest-e2e` Playwright package — +see `.claude/skills/verify/SKILL.md` for the base convention this extends): + +- **`lib.mjs`** — shared helpers: `createLocalDraft`, `selectTreeNode`, + `addElement`, `openTab`, `fieldByLabel`/`setLabeledField`/`selectLabeledField`, + `capture`, `openPreview`/`sendCommand` (player screenshots, see below), and + the `runCapture` try/finally wrapper. Reuse these rather than re-deriving + selectors — they're built on DOM patterns already proven out across + `tests/e2e/verify-appshell-*.mjs`. +- **One capture script per doc page**, e.g. + `capture-tutorial-creating-a-simple-game.mjs`. Each script walks through + *that page's own narrative* — the same room/object names and steps the + prose already tells the reader to perform — and calls `capture()` at every + point the doc currently embeds a screenshot, saving over the **existing + filename** in `site/public/images/`. Same filename in, same filename out — + no markdown edits needed. + +Viewport is fixed at 960×800 (`lib.mjs`'s `VIEWPORT`), light theme, for a +consistent look across captures. Narrower than AppShell's usual 1280 dev-preview +width on purpose — Starlight downscales images to its ~700-800px content column, +so a narrower source image means less downscaling and more legible on-screen text. +`capture()` crops to the last relevant element's bottom edge (`untilLocator`) +rather than the full viewport height, since most states don't fill it. + +## Adding a new capture script + +1. Read the target doc page and note, in order, what state each embedded + image is meant to show — usually obvious from the surrounding prose (it's + literally instructing the reader what to click/type right before each image). +2. Start the AppShell dev server (`.claude/launch.json`'s `AppShell` config, + `npm run dev` in `src/AppShell`, port 5174). +3. Walk the same steps interactively first (browser tooling, or Playwright's + inspector) to confirm selectors/labels — **don't guess DOM structure**. + Property-panel fields have no id/name/aria-label; they're `label` + immediately followed by the input, which is what `fieldByLabel` encodes. + Watch for real ellipsis characters (`…`, not `...`) in placeholders, and + remember tab bars can have near-duplicate labels (e.g. an object has both + an "Object" tab and an "Objects" tab) — `openTab`/`addElement` use exact + role matching for this reason, not substring `:has-text()`. +4. Write `capture-.mjs` in `tests/e2e/docs-screenshots/`, importing + from `./lib.mjs`, following `capture-tutorial-creating-a-simple-game.mjs` + as the reference example. +5. Run it: `cd tests/e2e && node docs-screenshots/capture-.mjs http://localhost:5174` +6. `Read` each output image and check it actually matches what the doc prose + describes before considering it done (right object names, right tab, right + content — not just "a screenshot got saved"). + +## Capturing player (gameplay) screenshots + +`openPreview(page)` clicks the toolbar's Preview button and returns the +WasmPlayer tab it opens (a second Playwright `page` in the same browser +context — Preview always opens via `window.open`, proxied to the same origin +so the editor tab and player tab can talk over `BroadcastChannel`; see +`vite.config.ts`'s `/player` proxy comment). **The original editor page must +stay open and untouched for the whole capture** — it's the thing answering +WasmPlayer's game-bytes request, including on every reload. + +```js +const playerPage = await openPreview(page); +await sendCommand(playerPage, 'open fridge'); +await capture(playerPage, out('Containerfridge.png'), { untilLocator: playerPage.locator('#txtCommand') }); +``` + +`sendCommand` waits for the previous turn to finish (`window.canSendCommand`) +both before and after submitting, so the transcript is fully settled by the +time you call `capture()` — no arbitrary `waitForTimeout`. `capture()` itself +is unchanged and works against either page; `#txtCommand` is always the last +element in the transcript, so it's the natural `untilLocator` for player shots. + +**Gotcha:** several container/object fields the tutorial text references +(e.g. "List children when object is looked at or opened") are flagged +`` in the `.aslx` control definition and live behind a collapsed +"Advanced" `` at the bottom of their tab (see +`tests/e2e/verify-appshell-advanced-controls.mjs`) — invisible, and +`.check()`/`.fill()` will hang waiting for visibility, until you click +`page.locator('summary', { hasText: 'Advanced' })` open first. + +## Pointing at a specific control + +`capture()` takes an optional `cursorAt` to draw a synthetic cursor (a real +screenshot never captures the actual OS pointer) at a locator's position — +either the locator itself (tip centered on it) or `{ locator, at }` with +`at` one of `'center' | 'left' | 'right' | 'top' | 'bottom'`, e.g. pointing at +the left edge of a dropdown you're about to describe opening. Note this only +*points at* a control — it can't show a native ` + + + + Sex: Male + Female + + + + +``` + +I have chosen to set out the widgets in a table, as this helps keep things neatly aligned. I have a single text field, and two radio buttons. How to code HTML tables and widgets is beyond the scope of this article, but there are plenty of resources on the internet. + +It is a good idea to always give default values as it will stop the player leaving anything blank. This is complicated enough without checking for empty fields and then re-showing the dialogue panel! + +To get the code into your game, add this to your game start script: + +```quest +JS.addText (GetFileData("dialogue.html")) +``` + +If you start the game, you will see your widgets, but they are embedded in the page. We need JQuery to insert them into a dialogue panel. To do that, add this JavaScript code to the file: + +```xml + +``` +There are two parts to this. The first part of that defines a function called `setValues`. At the moment it just closes the dialogue box. + +The other part puts the HTML into a dialogue box. I am not going deeply into JavaScript, but briefly the first line says we are defining a function that will be called when the document is loaded. The second line puts out HTML into a jQuery dialogue, using the `dialog` method. The next two lines obvious set the width and height of the dialogue (and you may well need to make these bigger for your dialogue panel). The next three lines define a block that adds buttons to it. Just one button here, called "Done", which will call the `setValues` function we defined before. The next line removes the "Close" button from the dialogue, ensuring the only way to get passed the dialogue is clicking the "Done" button (try deleting the line and see what it looks like to see the difference). + +Save the file. Now if you go into the game, you will see the dialogue panel, and it will disappear when you click "Done". + + +## Communicating with Quest + +The next step is to get the data into your game. This will be done with the special JavaScript function `ASLEvent`, which is provided by Quest. A complication here is that that can only take two parameters; the name of the Quest function to use, and a string. Either we need to use it numerous times, once for each value, or use it once but send it all the data in a single string. We will be doing the latter. + +In the code above there was this function: + +```js +function setValues() { + $("#dialog_window_1").dialog("close"); +} +``` + +We need to change that to collect the data, and then to send it to Quest. You can get data from a form element with the JQuery `val` method. For text, it is trivial: + +```js +name = $('#name_input').val(); +``` + +For the radio buttons, a bit more complicated: + +```js +gender = $("input:radio[name='sex_input']:checked").val(); +``` + +Both values need to be combined into a single string, separated by some obscure character; I use |. The new code looks like this: + +```js +function setValues() { + $("#dialog_window_1").dialog("close"); + answer = $('#name_input').val() + "|" + $("input:radio[name='sex_input']:checked").val(); + ASLEvent("HandleDialogue", answer); +} +``` + +Then we need to create a function in Quest to accept that data. Add it in the normal way, and call it `HandleDialogue`, no return type, and a single parameter, s. Paste in this code: + +```quest +l = Split(s, "|") +msg ("You are " + StringListItem(l, 0) + ", " + StringListItem(l, 1)) +``` + +The first line splits the given string on the separator character, the second line just displays it. Obviously you could set attributes on the player object here if desired. + + +## Disabling other input + +The dialogue box is not "modal", which means that the player can play your game whilst the dialogue box is still there. The best way around that is to turn off the command bar and panes on the right in the editor (_Interface_ tab of the game object), and turn them back on it the `HandleDialogue` function, so that is now: + +```quest +JS.panesVisible(true) +JS.uiShow("#txtCommandDiv") +l = Split(s, "|") +msg ("You are " + StringListItem(l, 0) + ", " + StringListItem(l, 1)) +``` + + +To load the file into the page, add this to the game's start script: + +```quest +JS.addText (GetFileData("dialogue.html")) +``` + + +In the [second part](/howto/ux/ui-dialogue-points) we will build on this to create a dialogue panel where the player can assign points to attributes. diff --git a/site/src/content/docs/howto/ux/ui-fonts.md b/site/src/content/docs/howto/ux/ui-fonts.md new file mode 100644 index 000000000..35c629394 --- /dev/null +++ b/site/src/content/docs/howto/ux/ui-fonts.md @@ -0,0 +1,40 @@ +--- +title: Fonts +sidebar: + order: 6 +--- + +## Fonts + +There are about a dozen "base fonts" available in Quest. These are fonts that are pretty much guaranteed to be available on any computer (or at least equivalents, so we have Arial on PC, or Helvetica on Mac or failing that sans-serif). + +If you want to change the font during a game, use the `SetFontName` function. This allows you to list the equivalent fonts, so will ensure users on other operating systems see more-or-less the same thing. + +```quest +SetFontName("Arial, Heletica, sans-serif") +msg("This is in Heletica") +SetFontName("'Courier New', Courier, monospace") +msg("This is in Courier") +SetFontName("Impact, Charcoal, sans-serif") +msg("This is in Charcoal") +``` + +The sans-serif and monospace are generic fonts; there are also serif, cursive and fantasy. They will all map to something on every computer, though the cursive and fantasy tend to fall well short of the names. + +You also have access to web fonts. These are provided on-line by Google, and by default you can access just one in your game. To use any more, you need to call the `SetWebFontName` to pull the font off the internet, and then `SetFontName` as normal to actually use it. + +```quest +// Pull the fonts off the internet +SetWebFontName("Wallpoet") +SetWebFontName("Admina") + +// Now we can swap between them as much as we like +SetFontName("Wallpoet") +msg("This is in Wallpoet") +SetFontName("Admina") +msg("This is in Admina") +SetFontName("Wallpoet") +msg("This is in Wallpoet") +``` + +Make sure you choose a font that is easy to read for the main text! \ No newline at end of file diff --git a/site/src/content/docs/howto/ux/ui-game-play.md b/site/src/content/docs/howto/ux/ui-game-play.md new file mode 100644 index 000000000..3ebe870f9 --- /dev/null +++ b/site/src/content/docs/howto/ux/ui-game-play.md @@ -0,0 +1,57 @@ +--- +title: The UI and game-play +sidebar: + order: 1 +--- + +Quest offers a number of options for the player to interact with the game: + +- Command bar +- Hyperlinks +- Game panes on the right + +Before releasing your game, you should consider if all these are applicable to the game. + +## Command bar + +The command bar is the traditional input method for interactive fiction. It offers the most flexibility to the player, creating a great sense (or illusion at least) of freedom. At the same time, this puts extra demands on the creator, as she has to anticipate all reasonable commands. If an object is mentioned in a room description, many players will expect to be able to look at it. You will also need to think of all possible synonyms for objects and verbs. + +However, if you decide to turn off the command bar, you need to address the limitations of hyperlinks and the game panes. By default, they can only handle moving the player to another room and simple VERB OBJECT commands. How will the player do stings like LOOK, WAIT, PUT BALL IN SACK and ATTACK ORC WITH FIREBALL? + +The command bar can be turned off or customised on the _Interface_ tab of the game object. + + +## Hyperlinks + +Hyperlinks are the bread-and-butter of hypertext books, and Quest allows you to build games that are entirely navigated by such link, but still has a sophisticated world model (i.e., objects and rooms existing in a meaningful relationship to each other). + +Quest will create hyperlinks for you. In object lists, each object will be given a link, that will show a list of appropriate options. In the exits list, each exit again will be a hyperlink. + +In addition, you can use text processor commands to add your own link. Text processor commands are indicated by curly braces, with the sections separated by colons. + +> If you would like help, click {command:HELP:here}. + +> Perhaps you could {command:PUT BALL IN SACK:put the ball in the sack} + +The text processor command in this case is called "command", so that is the first section. The next part I put it in capitals, but it does not have to be; this is the actual command, what the player would type into the command bar. This can be as complicated as you like - just as long as Quest can understand it. The last bit is the text the player sees. + +Hyperlinks can be turned off and customised from the _Display_ tab. You can give objects their own individual hyperlink colour on their _Object_ tab. + + +## Game panes + +The game panes are an alternative to hyperlinks, and may be more appropriate if you do not want your text interrupted by underlining and different colours. The compass also gives a quick indication of what exits are available. As with hyperlinks, Quest will list the appropriate verbs for an object. + +The game panes can be turned off or customised on the _Interface_ tab of the game object. + +### Command pane + +An additional pane can be added for simple commands, such as LOOK and WAIT, that the player can click instead of typing. See [Custom Command Panes](/howto/ux/command_pane) for how to set it up. + + +## Further consideration + +It can be easier to create puzzles for a game using the command bar, as it is far less obvious to the player what to do at a certain point (in contrast to randomly linking links until something works). This can also lead to the "guess the verb" problem, where the player is trying to work out what obscure phrase the game is expecting next. + +If you choose to have the command bar in addition to either hyperlinks or the game panes, be aware that some players may assume they can complete the game using exclusively one or the other. + diff --git a/site/src/content/docs/howto/ux/ui-location-bar.md b/site/src/content/docs/howto/ux/ui-location-bar.md new file mode 100644 index 000000000..6f112997d --- /dev/null +++ b/site/src/content/docs/howto/ux/ui-location-bar.md @@ -0,0 +1,111 @@ +--- +title: Messing with the location bar +sidebar: + order: 7 +--- + +_NOTE:_ Basic knowledge of HTML will be useful here. + +By default the location (or status) bar across the top of screen tells the player the current room. You can turn it off, and you can change how it looks, on the _Interface_ tab of the game object. + +In HTML terms, it consists of two elements: the "location" element, which holds the text, and is updated when the player goes into the room; and the "status" element, which contains it, and to which the styling is applied. + +Using JQuery we can change the location bar to display anything we want. The basic code (in JavaScript( is this: + +```js +$('#location').replaceWith('Some new HTML code') +``` + +That new HTML can include a new "location" element, in which case Quest will continue to update the location, or not if you do not want that. + + +## Tracking turns and score + +A good example would be to show the score and number of turns in the top right corner, and keep the room name in the left corner. To do that, we will insert a table into the location bar, one row high, two columns wide. The first cell is called "location", so will still display the room name, the second is called "altlocation". + +```quest +s = "" +s = s + "" +s = s + "" +s = s + "
0/0
" +JS.eval ("$('#location').replaceWith('" + s + "')") +if (HasAttribute(game, "pov")) { + JS.eval ("$('#altlocation').html('" + game.score + "/" + game.turncount + "')") +} +``` + +I find it easiest to build up the string in steps so I can see it all, so the first four lines do that, the fifth line just replaces the "location" element. + +The last three lines update the display to the current values. At the start of the game, those attributes do not exist, and we do not want this code to run (we only need it when the player reloads a saved game). So we check if the "pov" attribute of the game object has been set. If it has, we are loading a saved game, and need to update. + +This needs to go in the "User interface initialisation script", on the _Advanced scripts_ tab of the game object (tick "Show advanced scripts..." on the _Features_ tab if you cannot see it). + +If you go in game, you show see the score and turn... but it does not update. + + +## Updating the display + +We need to first initialise the score and turn counter, and this has to be done in the start script, on the _Scripts_ tab of the game object, as we want this to happen at the start of the game, but not when a saved game is loaded: + +```quest +game.turncount = 0 +game.score = 0 +``` + +Now add a new turn script, and tick it to be enabled at the start. Paste in this code, which will increment the turn counter, and then update the location bar. + +```quest +game.turncount = game.turncount + 1 +JS.eval ("$('#altlocation').html('" + game.score + "/" + game.turncount + "')") +``` + + +## Adding commands + +We can also add commands to the location bar. Just change the "User interface initialisation script" to this: + +```quest +s = "" +s = s + "" +s = s + "" +s = s + "" +s = s + "
" +s = s + "LOOK |" +s = s + "WAIT0/0
" +JS.eval ("$('#location').replaceWith('" + s + "')") +if (HasAttribute(game, "pov")) { + JS.eval ("$('#altlocation').html('" + game.score + "/" + game.turncount + "')") +} +``` + +The first line is the same as before, as are the last seven (except the "location" element is now centrally aligned). The difference is we have inserted these three lines: + +```xml +s = s + "" +s = s + "LOOK |" +s = s + "WAIT" +``` + +They add a new cell to the table, so now it has three columns. Note that `width=\"25%\"` adjusts the width of the new cell, you may want to modify that number to suit your game. + +Our new table cell has two commands, LOOK and WAIT. When it is on the page, the HTML for the LOOK command will look like this: + +```xml +LOOK +``` + +The "onclick" attribute is an event handler; when the player clicks this element, run the JavaScript. In this case it runs the Quest JavaScript function, `ASLEvent`, which in turn will call the Quest function `HandleSingleCommand`, passing it the value "look". The "style" attribute changes the cursor to tell the player this is clickable. + +When we put this code into Quest, we need to escape the double quotes, by putting a backslash before them, so Quest knows they are part of the string, not marking the end of it. We also need to escape the apostrophes so JQuery knows that _they_ are not marking the end of the string for it, and in this case we use the special HTML code `'`. + + +## Modifying the style + +As we have not touched the "status" element, changes you make on the _Interface_ tab will still be applied. The one exception to that is the colour of the text for commands, because links always get displayed in a different colour. The simple way to handle that is to set the colour in the "style" attribute. + +For example, to have it black (note the spelling of "color"!): +```xml +s = s + "" +s = s + "LOOK |" +s = s + "WAIT" +``` diff --git a/site/src/content/docs/howto/ux/ui-style.md b/site/src/content/docs/howto/ux/ui-style.md new file mode 100644 index 000000000..6fe483344 --- /dev/null +++ b/site/src/content/docs/howto/ux/ui-style.md @@ -0,0 +1,83 @@ +--- +title: The UI style +sidebar: + order: 2 +--- + +Quest offers a number of options for making your game look good, and fit the style and atmosphere you want. All these options can be accessed from various tabs on the game object. + +This is the classic Quest interface: + +![](/images/ui-classic.png) + + +## The _display_ tab + +On the Display tab of the game object, there are options for changing the text, the background and (if used) hyperlinks. + +For text, you can set the colour, font and size. There are two types of fonts, the built-in (base) fonts and web fonts. + +A web font will be downloaded to the player's computer when she starts your game, and offers a huge variety of fonts (and a link below will help you choose). When choosing a font, remember that text adventures involve a fair bit of reading, so ensure you chose a font that not only looks cool, but is easy to read too. Changing the font size can also improve readability. + +If you do use a web font, it is a good idea to also select a suitable base font, and this will be used if the web font cannot be accessed. + +The background section allows you to set the colour of the page and the margins on either side. You can also choose to have an image for the margins, and to make the page transparent. You can also have the page a blend from one colour at the top to another at the bottom. Some restraint is suggested here! + +There are further options for setting the style for hyperlinks, and also for verb text (the drop down lists that appear when an object hyperlink to clicked). + +This example shows the subtle use of a colour blend, in a game with the command line turned off. + +![](/images/ui-no-cursor.png) + + +## The _interface_ tab + +The Interface tab is where you control the features of the UI. Here you can turn on or off: the map; the game panes; the command bar; the location bar; the border; custom layout; and the picture frame. + +Turning a feature on will display additional options for that feature. + +### Map + +You can set the scale and height. You can also set the colour and width for exits. + + +### Game panes + +You can selectively turn off a pane, or add a [command pane](/howto/ux/command_pane) or [custom status pane](/howto/ux/custom_panes). You can move the status and compass to the top (which will stop them moving up and down as the inventory changes). You can also select from a number of colour schemes. + +### Command bar + +You can use a shadow box, or no box at all (and give own cursor). Due to the limitations of CSS, if you are using a colour blend for the background, the command bar background will ignore it, so the classic box is probably best. + +This example uses a cursor with the panes turned off to give a minimalist look. + +![](/images/ui-cursor.png) + +You can use any HTML character as the cursor (or several), and there are some [pretty funky ones](https://www.w3schools.com/charsets/ref_utf_symbols.asp) in UTF-8, from a pointing hand to the yin yang symbol (though they may not be available in every font in every browser, so do test thoroughly). + +To get these symbols in your game, you need to use the decimal value, with `&#` before it and `;` after. This will give a heart cursor, for example: + +> ♥ + +### Location bar + +You can turn off the classic location bar style, and set your own colours. See [Messing with the location bar](/howto/ux/ui-location-bar) for how to customise it further with code. + +### Border + +The border surrounds the page, separating it from the margins. You can set the colour. + +### Custom layout + +You can set the padding and the width. + +### Picture frame + +You can set it to be clear for rooms with no image set. + + +## The _room descriptions_ tab + +With the Room Descriptions tab, you can control what happens when the player enters a room (or types LOOK). Note that "Automatically generate room descriptions" does not mean Quest will do the work for you! Rather, it means it will list the exits and the objects for you. If the box is ticked, you can control their order by modifying the numbers (set to zero if you do not what that one displayed). + +Hopefully most of the options are self-explanatory; experiment and see what works best for your game. diff --git a/site/src/content/docs/howto/world/about_save.md b/site/src/content/docs/howto/world/about_save.md new file mode 100644 index 000000000..e2d52cca2 --- /dev/null +++ b/site/src/content/docs/howto/world/about_save.md @@ -0,0 +1,45 @@ +--- +title: When the player saves a game +sidebar: + order: 13 +--- + +When a player saves a game, she saves _everything_. + +Everything in Quest is an object with attributes, and potentially all those attributes could change. So Quest saves the lot. In effect, playing the game is like editing and saving your own version of it. + +When the player later loads a saved game, Quest does not do anything with the original. It does not need to know anything about the original, because all the data, the entire game (in its modified state) was saved. + +That works fine, until you update your game. + +When the player now loads a saved game, Quest does not bother to look at the game itself. The player saved the old version (in whatever game state), and so that is what is loaded, and so the player is still using the old version. + +Generally, this is not much of a problem; hopefully your original game was in a decent state before you released it (you did beta-test, right?). For longer games, players may be disappointed that they need to start again to see new content. + +Possibly the biggest problem is when you upload your latest version, you may be confused why the changes are not there. It may be because you are played a saved game; you need to restart the game to see the changes. + + +## Are there any alternatives? + +If you feel you absolutely must have player's saved games updated too, you have two approaches, neither of which will be easy to implement. + +### Patching + +One approach would be to upload a text file to a website with all your changes in it, and have a command, PATCH, that fetches the file, checks if the patch has already been installed, and if not, apply the changes. + +The "apply the changes" bit is the difficult bit. You would need to devise a set of instructions for the text file that the PATCH command could process to create objects and exits and to update existing ones. + +Your PATCH command would need to be in the original game. + +You would need to think about how a player could do several patches. + +Quest does not currently expose a way to convert a string into an executable script at the `.aslx` level, so all your scripts would need to be in your original game (but you can add them to new objects). + +I am not aware of anyone attempting this. Test well before release. + + +### Alternative saving + +An alternative approach is to have your own save system. To get this to work you would need to flag every attribute that can potentially change, and just save them. Then the player would restart the game, and use a new LOAD command, apply her saved file, and all those attributes get set. + +There is a library available [here](https://github.com/ThePix/quest/wiki/Library:-Save-and-Load). diff --git a/site/src/content/docs/howto/world/changing_templates.md b/site/src/content/docs/howto/world/changing_templates.md new file mode 100644 index 000000000..e14ba31a2 --- /dev/null +++ b/site/src/content/docs/howto/world/changing_templates.md @@ -0,0 +1,53 @@ +--- +title: Changing templates +sidebar: + order: 2 +--- + +When a player types in a command that Quest doesn't recognise, it will by default respond "I don't understand your command". If you mis-type the name of an object, you get "I can't see that". These responses are all very well, but it might break the flow of our game if they don't fit in with the rest of the text that we've written. Fortunately, Quest provides a way for you to change all of its default responses - in fact none of the text is "hard coded" at all, which is why it is possible to create games in any language, not just English. + +The standard responses are all defined by **templates**, and these all exist in the **standard libraries**. These libraries contain standard game text, most of the standard behaviour in a game, all of the Editor screens - in fact a lot of Quest's functionality comes from the libraries. The libraries are .aslx files, just like your game file - a lot of Quest is written in Quest itself. + +Everything in the libraries is included in your game, but the Editor usually hides all this from you, so you can focus on your game itself. You can view library elements by clicking the Filter button at the bottom of the editor tree, and selecting "Show Library Elements". + +![](/images/Showlibraryelements.png) + +When you turn this on, you'll see all of the standard commands and functions that are included in a game. + +Click "Advanced" in the tree and then "Templates". You'll see a full list of templates. + +![](/images/Templates.png) + +To edit one of these templates, you must first copy it into your game file, as you can't edit the library directly. Click the "Copy" button in the top right, and you'll be able to modify the template text. + +There is a second section "Dynamic Templates", which contains templates which are more than just static text. These templates change depending on the object they're referring to. For example, the TakeSuccessful template is used when you pick up an object - usually it says "You pick it up", but in the case of a plural object it would say "You pick them up". + +A Dynamic Template is an expression, and the relevant object is passed in to the expression via a variable called "object". So the TakeSuccessful template expression is: + +```quest +"You pick " + object.article + " up." +``` + +Using the object article means that this template can print the correct thing for a singular or plural object, or even a male/female character if you have one that can be taken. + +These Dynamic Templates often take advantage of some functions which are defined in the English.aslx library - the [Conjugate](/functions/string#conjugate) and [WriteVerb](/functions/string#writeverb) functions ensure that correct English is written. For example, the AlreadyOpen template is: + +```quest +WriteVerb(object, "be") + " already open." +``` + +This means it will correctly write "It is already open", "They are already open" etc. + +## Printing square brackets + +Since text in square brackets gets automatically substituted with a template's contents, you need another way to print an actual square bracket. As the output is HTML, you can use the HTML code `[`. + +This in your code will give an open square bracket, `[`, on output: + +``` +[ +``` + +## See also + +For the underlying `