Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
Tutorial explaining how to take advantage of fields that use getStringArrayFunction in AdventureJS. tutorial, getSAF, getStringArrayFunction

Basic Scripting:String Array Function

AdventureJS, being an interactive fiction engine, is all about – you guessed it – text! Text, and the many ways and forms of serving it to the player. Because there is no one right way of writing text, AdventureJS tries very hard to accommodate a plethora of methods. At the heart of that accommodation is the getStringArrayFunction() function (or getSAF() for short). Most of an author's work will pass through this function before being printed to the player.

getStringArrayFunction() does what its name suggests - it takes a string or an array or a function as input, and tries to handle whatever it receives. If it finds a string, it passes the string. If it finds an array, it pulls an element from the array, either randomly or sequentially depending on settings. If it finds a function, it calls the function. The function may return a string or it may call other executable code (which may also print strings).

Authors can take advantage of this to work with whichever methods they feel most comfortable. Strings are for authors who want to write, but not code. Functions are for authors who want to write their own code. Arrays fall somewhere in between – offering a code-free way for authors to create some variation in canned responses.

General Examples:

String

MyGame.createAsset({
  class: "Desk",
  name: "desk",
  description: "An old school wooden desk. ",
});

Array

Array has several options for controlling how items of an array are selected.

  • array contains the items to be returned.
  • randomize return a random item each time. If false, return array items sequentially.
  • index when returning array items sequentially, tracks the last returned array item.
  • reset if not using randomize, returns items sequentially. On reaching the last item in the array, if reset is true, will start over at the beginning; if reset is false, will return the last item each time.
  • frequency determines how often an item is returned. If frequency is 1, an item is always returned; if frequency is 0.5, there is a 50 / 50 chance of an item being returned; if frequency is 0.05, there is a 1 in 20 chance of an item being returned. You probably wouldn't use this for a description property, but is useful for setting room.area_events and zone.area_events to print randomly.
MyGame.createAsset({
  class: "Blotter",
  name: "blotter",
  descriptions: {
    look: {
      randomize: true,
      array: [
        "The words 'live and let die' are scrawled on the blotter. ",
        "The desk blotter has 'born to bleed' carved into it. ",
        "You see 'zep rulez!' scratched in to the desk blotter. ",
      ],
    },
  },
});

Function

Functions can do more than just return strings – they can run custom logic that calls other functions. Right now we're only interested in returning strings. This example uses a placeholder.

MyGame.createAsset({
  class: "Drawer",
  name: "drawer",
  descriptions: {
    look: function(){
      return "The drawer is { drawer [is] open [or] closed }. ";
    },
  },
});

Where to use it

Following is a list of properties that pass through getStringArrayFunction(). Any strings that are returned by any method can contain HTML/CSS and placeholders.

Settings

game.settings contains a collection of game-wide settings that can be set with game.settings.set({}).

game.settings.if_input_is_empty_print_this

This property can be set to print when the player presses the return key with an empty input.

String

MyGame.settings.set({
  if_input_is_empty_print_this: `I didn't see any input. `,
});
game.settings.if_parser_has_no_response_print_this

This property can be set to print when the parser is unable to parse the player's input.

The {input} placeholder will substitute the turn's full input.

String

MyGame.settings.set({
  if_parser_has_no_response_print_this: `{input} wasn't understood. `,
});
game.settings.if_word_is_common_print_this

This property can be set to print when player inputs an unknown word.

The {word} placeholder will substitute the unknown word.

String

MyGame.settings.set({
  if_word_is_common_print_this: `{We} {don't} know of any {word}. `,,
});
game.settings.if_verb_is_unknown_print_this

This property can be set to print when player inputs an unknown verb. If this is set, it takes precedence over if_word_is_common_print_this.

The {word} placeholder will substitute the unknown word.

String

MyGame.settings.set({
  if_verb_is_unknown_print_this: `{We} {don't} know how to {word} anything. `,
});
game.settings.if_word_is_common_print_this

This property can be set to print when player uses a word that the author hasn't defined but which is listed in game.dictionary.common_words. If this is set, it takes precedence over if_word_is_common_print_this.

The {word} placeholder will substitute the unknown word.

String

MyGame.settings.set({
  if_word_is_common_print_this: `{We} {don't} know of any {word}. `,
});
game.settings.if_room_is_dark_print_this

This property can be set to print when the player enters a dark room.

String

MyGame.settings.set({
  if_room_is_dark_print_this: `It is pitch black. {We} {are} likely to be eaten by a grue. `,
});

Assets

A few asset properties are universal; others are specific to certain classes.

asset.description

All assets have an asset.description property. For some asset types, asset.description is an alias to asset.descriptions.look, but any assets may have multiple properties under asset.descriptions.[...], such as listen, smell, feel, etc.

String

MyGame.createAsset({
  class: "Thing",
  name: "rainbow gem",
  description: "This gem pulses through all the colors of the rainbow. It currently is {gemcolor}. ",
});

Array

MyGame.createAsset({
  class: "Thing",
  name: "rainbow gem",
  description: {
    randomize: true,
    array: [
      `The gem appears a dark blood red. `,
      `The gem shows a deep warm orange. `,
      `The gem shines a brilliant yellow. `,
      `The gem blooms a lively green. `,
      `The gem whorls a cool blue. `,
      `The gem thrums a solid indigo. `,
      `The gem vibrates a bright violet. `,
    ],
  },
});

Function

MyGame.createAsset({
  class: "Thing",
  name: "rainbow gem",
  description: function() {
    const colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];
    const random_color = colors[Math.floor(Math.random() * colors.length)];
    return `The gem glows with a deep, rich, glossy ${random_color} color. `;
  },
});
asset.descriptions.[...]

Default asset.descriptions.[...] for Tangible class include look, brief, verbose, careful, closed, open, taste, feel, smell, sound, behind, in, on, over, through, under. It's also possible to add arbitrary properties, and nested properties. See default descriptions and description modifiers for more information.

String

MyGame.createAsset({
  class: "Window",
  name: "icy window",
  descriptions: {
    through: "Through the icy window {we} can see nothing more than a frozen white expanse. ",  
  },  
});

Array

MyGame.createAsset({
  class: "Window",
  name: "icy window",
  descriptions: {
    through: {
      randomize: true,
      array: [ 
        "The snow covered wasteland beyond the open window reflects the arctic sun. ",
        "The view through the window is briefly obscured by a sudden flurry of snow. ",
        "Through the icy window {we} can see nothing more than a frozen white expanse. ",
      ],
    },  
  },  
});

Function

MyGame.createAsset({
  class: "Window",
  name: "icy window",
  descriptions: {
    through: function () {
      if (MyGame.$("icy window").$is("closed")) {
        return "The closed window is iced over nearly to the point of opacity, though {we} can see frosted white light through it.";
      } else {
        return "Through the open window {we} can see the frozen wasteland.";
      }
    },  
  },  
});
exit.descriptions.for_exits_list

This property allows authors to customize how individual exits are listed in the room's list of exits. Useful for adding state-based logic to exit descriptions, or drawing attention to specific exits.

String

MyGame.createAsset({
  class: "Exit",
  name: "hole in the ground",
  direction: "down",
  destination: "rabbit warren",
  descriptions: {
    look: "You see a hole in the ground. ",
    for_exits_list: "down through the hole in the ground",
  },
});

Function

MyGame.createAsset({
  class: "Exit",
  name: "hole in the ground",
  direction: "down",
  destination: "rabbit warren",
  descriptions: {
    look: "You see a hole in the ground. ",
    for_exits_list: function() {
      let description = "down through the hole in the ground";
      if (MyGame.getPlayer().knowsAbout("rabbit warren")) {
        description +=
          " to visit the rabbits in the rabbit warren";
      }
      return description;
    },
  },
});
exit.descriptions.travel

This property can be set to print when player uses this exit.

String

MyGame.createAsset({
  class: "Exit",
  name: "hole in the ground",
  direction: "down",
  destination: "rabbit warren",
  descriptions: {
    look: "You see a hole in the ground. ",
    travel: "You wriggle down through the hole. ",
  },
});

Function

MyGame.createAsset({
  class: "Exit",
  name: "hole in the ground",
  direction: "down",
  destination: "rabbit warren",
  descriptions: {
    look: "You see a hole in the ground. ",
    travel: function() {
      let description = "down through the hole in the ground";
      if (MyGame.getPlayer().knowsAbout("rabbit warren")) {
        description +=
          " to visit the rabbits in the rabbit warren";
      }
      return description;
    },
  },
});
room.descriptions.exits

This property can be set to print a customized list of a room's exits.

String

MyGame.createAsset({
  class: "Room",
  name: "rabbit warren",
  descriptions: {
    exits: "{We} can exit the warren either by climbing back up through the hole in the roof, or by exploring the tunnel that leads further down. ",
  },
});

Function

MyGame.createAsset({
  class: "Room",
  name: "rabbit warren",
  descriptions: {
    exits: function() {
      let description = "{We} can exit the warren by climbing back up ";
      if (MyGame.getPlayer().knowsAbout("forest glade")) {
        description += " to the forest glade";
      } else {
        description += " through the hole in the roof";
      }
      description += " or by ";
      if (MyGame.getPlayer().knowsAbout("deep chamber")) {
        description += " climbing down to the deep chamber";
      } else {
        description += " exploring the tunnel that leads further down";
      }
      description += ". ";
    },
  },
});
character.constrained_msg

This property can be set to print when a player character is unable to perform an action due to being constrained. It is a broad override that is not verb-specific.

String

MyGame.createAsset({
  class: "Player",
  name: "Hero",
  constrained_msg: "{We} can't do that while {we're} constrained. ",
});

Array

MyGame.createAsset({
  class: "Player",
  name: "Hero",
  constrained_msg: {
    array: [
      "Nope. ",
      "Not a chance. ",
      "Not while {we're} in that condition, {we} {don't}. ",
    ],
  },
});

Function

MyGame.createAsset({
  class: "Player",
  name: "Hero",
  constrained_msg: function() {
    if (MyGame.getPlayer().isOnFloor()) {
      return "{We} can't do that while {we're} on the floor. ";
    } else {
      return "{We're} too bound up to do that. ";
    }
  },
});
character.ignore_msg

This property can be set to print when a non-player character has no response to the player asking or telling.

String

MyGame.createAsset({
  class: "NPC",
  name: "Roger the Shrubber",
  ignore_msg: "Roger the Shrubber ignores {us}. ",
});

Array

MyGame.createAsset({
  class: "NPC",
  name: "Roger the Shrubber",
  ignore_msg: {
    randomize: true,
    array: [
      "Roger the Shrubber rolls his eyes at ${us}. ",
      "Roger the Shrubber doesn't seem to care. ",
      "Roger the Shrubber has nothing to say to that. ",
      "Roger the Shrubber hacks at a small shrubbery. ",
      "Roger the Shrubber makes a small path between two shrubberies. ",
    ],
  },
});

Function

MyGame.createAsset({
  class: "NPC",
  name: "Roger the Shrubber",
  ignore_msg: function() {
    if(MyGame.$("Roger the Shrubber").knowsAbout("stolen shrub")){
      return "Roger the Shrubber glares angrily at {us} but says nothing. ";
    }
    else {
      return "Roger the Shrubber appears to have nothing to say. ";
    }
  },
});

Verbs

Built-in verbs can be modified with game.patchVerb() (a shortcut to game.dictionary.patchVerb()). The following methods can be used to broadly override a verb's success or failure messages for all assets.

verb.override_failure_msg

This property can be used to override all failure messages for the specified verb.

String

MyGame.patchVerb({
  name: "take",
  override_failure_msg: "No. ",
});

Array

MyGame.patchVerb({
  name: "take",
  override_failure_msg: {
    randomize: true,
    array: [
      "No.",
      "{We} find that {we} can't.",
      "Why would {we} want to?",
      "Don't be stoopid.",
    ],
  },
});
verb.override_success_msg

This property can be used to override all success messages for the specified verb.

String

MyGame.patchVerb({
  name: "take",
  override_success_msg: "Ok. ",
});

Array

MyGame.patchVerb({
  name: "take",
  override_success_msg: {
    randomize: true,
    array: [
      "Ok.",
      "Success!",
      "You pick it up and go cat go.",
      "I don't know why {we'd} want it but now {we've} got it.",
    ],
  },
});

Verb Subscriptions

Assets must subscribe to a verb for the verb to be applied to them. Verb subscriptions can be modified per asset, and come in two flavors: dov (direct object of verb) and iov (indirect object of verb). The two subscription types are identical, but distinct per object, which is to say that one object may have a direct subscription and an indirect subscription to the same verb. That is why we list them separately here.

dov
asset.dov.verb.on_first_success

This property can be set to print the first time the verb succeeds in being applied to the direct object.

String

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    plugIn: {
      on_first_success: "BOUMMMMMMmmmmmmmm. The computer starts up with a deep bassy power chord. ",
    },
    unplug: {
      on_first_success: "BEEEooop. The computer display shrinks to a point, then goes black. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    plugIn: {
      on_first_success: function () {
        MyGame.scorecard.completeEvent("plug in any computer part");
        return this.dov.plugIn.on_success();
      },
    },
    unplug: {
      on_first_success: function () {
        MyGame.scorecard.completeEvent("unplug any computer part");
        return this.dov.unplug.on_success();
      },
    },
  },
});
asset.dov.verb.on_success

This property can be set to print when the verb succeeds in being applied to the direct object.

String

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    plugIn: {
      on_success: "The computer starts up with a deep bassy power chord. ",
    },
    unplug: {
      on_success: "The computer display shrinks to a point, then goes black. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    plugIn: {
      on_success: function () {
        MyGame.setVar("turn_on_computer_count", MyGame.getVar("turn_on_computer_count") + 1 );
        return "The computer starts up with a deep bassy power chord. ";
      },
    },
    unplug: {
      on_success: function () {
        MyGame.setVar("turn_off_computer_count", MyGame.getVar("turn_off_computer_count") + 1 );
        return "The computer display shrinks to a point, then goes black. ";
      },
    },
  },
});
asset.dov.verb.on_first_failure

This property can be set to print the first time the verb fails to be applied to the direct object.

String

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    unplug: {
      on_first_failure: "{We} shock {ourself} trying to pull the thick plug out of the power supply. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    unplug: {
      on_first_failure: function () {
        MyGame.setVar("shock_count", 1);
        return "{We} shock {ourself} trying to pull the thick plug out of the power supply. ";
      },
    },
  },
});
asset.dov.verb.on_failure

This property can be set to print when the verb fails to be applied to the direct object.

String

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    unplug: {
      on_failure: "{We} get another shock. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Computer",
  name: "computer",
  dov: {
    unplug: {
      on_failure: function () {
        MyGame.setVar("shock_count", MyGame.getVar("shock_count") + 1);
        return "{We} get another shock. ";
      },
    },
  },
});
asset.dov.verb.then_destroy

This property can be set to print when the direct object is destroyed after applying the verb.

String

MyGame.createAsset({
  class: "Edible",
  name: "fairy cake",
  dov: { 
    eat: { 
      then_destroy: "The fairy cake leaves a light tingling sensation in {our} mouth. " 
    } 
  },
});

Function

MyGame.createAsset({
  class: "Edible",
  name: "fairy cake",
  dov: { 
    eat: { 
      then_destroy: function() {
        MyGame.setVar("ate_cake", true);
        return "The fairy cake leaves a light tingling sensation in {our} mouth. ";
      }
    } 
  },
});
iov
asset.iov.verb.on_first_success

This property can be set to print the first time the verb succeeds in being applied to the indirect object.

String

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    plugIn: {
      on_first_success: "As {we} plug in the power cord, the outlet flares with a bright blue spark! ",
    },
    unplug: {
      on_first_success: "As {we} remove the power cord, the outlet pops and fizzles. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    plugIn: {
      on_first_success: function () {
        MyGame.setVar("spark_count", MyGame.getVar("spark_count") + 1);
        return "As {we} plug in the power cord, the outlet flares with a bright blue spark! ";
      },
    },
    unplug: {
      on_first_success: function () {
        MyGame.setVar("pop_count", MyGame.getVar("spark_count") + 1);
        return "As {we} remove the power cord, the outlet pops and fizzles. ";
      },
    },
  },
});
asset.iov.verb.on_success

This property can be set to print when the verb succeeds in being applied to the indirect object.

String

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    plugIn: {
      on_success: "The outlet flares again! ",
    },
    unplug: {
      on_success: "The outlet pops again. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    plugIn: {
      on_success: function () {
        MyGame.setVar("spark_count", 1);
        return "The outlet flares again! ";
      },
    },
    unplug: {
      on_success: function () {
        MyGame.setVar("pop_count", + 1);
        return "The outlet pops again. ";
      },
    },
  },
});
asset.iov.verb.on_first_failure

This property can be set to print the first time the verb fails to be applied to the indirect object.

String

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    unplug: {
      on_first_failure: "{We} shock {ourself} trying to pull the power cord away out of the outlet. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    unplug: {
      on_first_failure: function () {
        MyGame.setVar("shock_count", 1);
        return "{We} shock {ourself} trying to pull the power cord away out of the outlet.  ";
      },
    },
  },
});
asset.iov.verb.on_failure

This property can be set to print when the verb fails to be applied to the indirect object.

String

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    unplug: {
      on_failure: "{We} get another shock. ",
    },
  },
});

Function

MyGame.createAsset({
  class: "Outlet",
  name: "brass outlet",
  iov: {
    unplug: {
      on_failure: function () {
        MyGame.setVar("shock_count", MyGame.getVar("shock_count") + 1);
        return "{We} get another shock. ";
      },
    },
  },
});
asset.iov.verb.then_destroy

This property can be set to print when the indirect object is destroyed after applying the verb.

String

MyGame.createAsset({
  class: "Key",
  name: "glass key",
  iov: { 
    unlock: { 
      then_destroy: "The glass key shatters into pieces. " 
    } 
  },
});

Function

MyGame.createAsset({
  class: "Key",
  name: "glass key",
  iov: { 
    unlock: { 
      then_destroy: function() {
        MyGame.setVar("broke_key", true);
        return "The glass key shatters into pieces. ";
      }
    } 
  },
});

Intervals

Intervals are asset-specific functions that are called every turn while they are active. For example, sinks have an emit() function that starts when water is turned on, which prints a "running water" message every turn. Intervals can run any code. If they return text, the text is printed on its own line. Authors can use game.startInterval() and game.stopInterval() to start and stop an interval. The state of running intervals is saved with the game state, so that authors can rely on interval states to carry across undo and save/restore operations. See Basic Scripting: Intervals for more information about working with intervals.

game.startInterval({id, callback, times, frequency})

Function | String

This example sets two intervals. One interval calls a non-printing function every turn, which changes the color of the rainbow gem. The second interval calls another function on every third turn, which prints a string if the gem is visible to the player.

MyGame.createAsset({
  class: "Thing",
  name: "rainbow gem",
  place: { in: "Treasure Room" },
  changeColor: function () {
    const colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];
    const random_color = colors[Math.floor(Math.random() * colors.length)];
    MyGame.setVar("gem_color", random_color);
  },
  printColor: function () {
    if(MyGame.getPlayer().canSee(this)) {
      return `A small {gem_color} glint catches {our} eye. `;
    }
  },
  description: `The gem glows with a rich, glossy {gem_color}. `,
});
MyGame.setVar("gem_color", "blue"); // set initial color
MyGame.startInterval({ id: "rainbow gem", callback: "changeColor" });
MyGame.startInterval({ id: "rainbow gem", callback: "printColor", frequency: 3 });

Image Dock

dock.messages

GUI (or Graphical User Interface) features allow authors to create text / graphic hybrid games – like those made by Legend Entertainment, such as Erik the Unready the Spellcasting series – by adding background images, buttons for verbs, buttons for inventory items, the whole shebang. Background images are contained in image docks, and these can be set to print a message when a player clicks on them.

Array

MyGame.createImageDock({
  id: "MyImageDock",
  cssclasses: ["my-custom-class"],
  type: "Room",
  messages: {
    randomize: true,
    frequency: 0.33, // roughly 1 in 3 times
    array: [
      "{We} clicked the picture, but there's no need for that. It's just a visual reference. ",
      "There's no need to click. Sorry, but this isn't a point & click game.",
      "Move on, there's nothing to do in the picture. ",
      "Whattaya think this is, a point & click game? ",
    ],
  },
});

Scorecard

Authors can use scorecards to control a game's scoring. That includes the points, the content, and the format of score updates, and also how the score appears in the game display. To learn more about customizing scorecards, see Customize Output: Scorecards.

Authors using functions for score_format and score_message have access to several variables.

  • this.score represents the old score prior to the update.
  • this.newscore represents the updated score.
  • this.diff represents the difference between the old score and the updated score.
  • this.total represents the total game points available.
scorecard.score_message

This property can be set to print when player earns any score update. A default score message looks like this: `[ ** Your score went up by 1 point ** ]`

String

MyGame.scorecard.set({
  score_message: `{Our} score went up! `,
});

Array

MyGame.scorecard.set({
  score_message: {
    randomize: true,
    array: [
      `{Our} score went up! `,
      `{We} got another point! `,
      `{We} earned a point! `,
    ],
  },
});

Function

MyGame.scorecard.set({
  score_message: function(){
    return `Dude, {we} totally just got ${this.diff} new points!`
  },
});
scorecard.score_format

This property can be set to customize the score as it appears in the game display. score_format has access to these scorecard variables: this.score, this.newscore, this.diff, and this.total. It does process Javascript template literals but it does not process AdventureJS placeholders. Here are some simple examples.

Function

MyGame.scorecard.set({
  score_format: function()
  {
    return `${this.score} / ${this.total}`;
  }
});

Function

MyGame.scorecard.set({
  score_format: function()
  {
    return `Score: ${this.score} out of ${this.total}`;
  }
});

Function

MyGame.scorecard.set({
  score_format: function()
  {
    return `You've got ${this.score} of ${this.total} points.`;
  }
});

Area Scenery

AdventureJS includes a variety of area scenery out of the box, such as sun, moon, sky, clouds, etc. Area scenery items exist so that players who refer to them can be given meaningful responses, even when there are no interactable objects. Scenery also includes placeholders for things like absent walls and doors, which the author hasn't implemented, but which players might try to examine.

Area scenery exists globally, but can be customized at three different levels: game, zone, and room. They are disabled by default at all levels and can be enabled à la carte. The method for enabling scenery game-wide is distinct from the methods for enabling scenery for zones and rooms. Examples of each are provided below.

game.setAreaScenery()
Set Area Scenery Gamewide

Enable area scenery by calling game.setAreaScenery(). You must set enabled: true to enable individual items. If an item is not enabled, a player trying to refer to it will receive a generic response such as "There doesn't appear to be any air present."

Because area scenery are non-interactable, you may find it useful to enable them even if they're not technically present. For instance, in the example below, we use the sun and moon scenery assets to return custom responses, even if one or the other isn't visible.

String | Array | Function

MyGame.setAreaScenery({
      air: {
        enabled: true,
        description: {
          randomize: true,
          array: [
            `{We} detect nothing unusual about the air. `,
            `{We} smell a touch of crushed rosemary in the air. `,
            `{We} smell a hint of recent rain on freshly mown grass. `,
            `The air has the smell of sudden heavy rain on hot, dry asphalt. `,
          ],
        },
      },
      sun: {
        enabled: true,
        description: function() {
          if(MyGame.getVar("is_day")===true) {
            return `A fiery ball of exploding hydrogen. `;
          } else {
            return `It's night. The sun is out of sight beyond the horizon. `;
          }
        },
      },
      moon: {
        enabled: true,
        description: function() {
          if(MyGame.getVar("is_day")===true) {
            return `It's hiding somewhere beyond the horizon. Hiding FROM YOU. `;
          } else {
            return `A bright silver sliver. Silver sliver. Silver sliver. Try saying that three times fast. `;
          }
        },
      },
      stars: {
        enabled: true,
        description: function() {
          if(MyGame.getVar("is_day")===true) {
            return `{We} can't see any right now. Perhaps they'll come out tonight. `;
          } else {
            return `A brilliant tapestry of... uh... white dots, in... black velvet. Dammit, do {we} know how many writers have described the stars? All the good words, taken! `;
          }
        },
      },
      sound: {
        enabled: true,
        description: `{We} hear the constant sigh of a slight breeze. `,
      },
    });
    
zone.area_scenery
Set Area Scenery by Zone

Scenery that is described by a zone will be available to any rooms in the zone. If a room in the zone has its own scenery descriptions, that will take precedence over the zone scenery. In this example, the Eastern Dunes room will share the Desert Zone's scenery.

String | Array | Function

MyGame.createAsset({
      class: "Room",
      name: "Eastern Dunes",
      zone: "Desert Zone",
    });
    MyGame.createAsset({
      class: "Zone",
      name: "Desert Zone",
      area_scenery: {
        air: {
          enabled: true,
          description: {
            randomize: true,
            array: [
              `The air is hot and dry here. `,
              `Curiously, {we} smell a faint hint of cinnamon. `,
              `A sere wind wicks the sweat from {our} skin, though it offers no relief from the heat. `,
            ],
          },
        },
        sun: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `It burns overhead, baking everything in sight, including {us}. `;
            } else {
              return `Blessed night. The temperature has plummeted though. `;
            }
          },
        },
        moon: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `Perhaps it's a pale disk in the sky, or perhaps that's a shimmering mirage, it's hard to say. `;
            } else {
              return `It shines down upon {us}, full and crisp and bright, the brightest moon {we've} ever seen. `;
            }
          },
        },
        stars: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `None are visible during the day. `;
            } else {
              return `The desert air is incredibly crisp. Above {us} looms the clearest field of stars {we've} ever known, the full expanse of the milky way. `;
            }
          },
        },
        sound: {
          enabled: true,
          description: `The desert wind rises and falls, from secret whispers to distant shrieks. `,
        },    
      },
    });
    
room.area_scenery
Set Area Scenery by Room

A room's scenery descriptions will only be available in that room. If a room is in a zone, the room's scenery descriptions will take precedence over the zone scenery descriptions or the game's scenery descriptions. In this example, the Oasis room is in the Desert Zone, but overrides some of the Desert Zone's scenery.

MyGame.createAsset({
      class: "Room",
      name: "Oasis",
      zone: "Desert Zone",
    });
    MyGame.createAsset({
      class: "Zone",
      name: "Desert Zone",
      area_scenery: {
        air: {
          enabled: true,
          description: {
            randomize: true,
            array: [
              `The air here is bessedly cool relative to the scorching desert winds. `,
              `A warm, moist breeze licks {our} bare skin. `,
              `A gentle floral perfume wafts through the oasis. `,
            ],
          },
        },
        sun: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `The sun splashes intermittently through the woven canopy of broad leaves overhead. `;
            } else {
              return `It's down. `;
            }
          },
        },
        moon: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `There may perhaps be a palce moon in the daytime sky, but {we} can't see it through the dense canopy of the oasis. `;
            } else {
              return `A tiny splash of moonlight ripples across the pond at the heart of the oasis. `;
            }
          },
        },
        stars: {
          enabled: true,
          description: function() {
            if(MyGame.getVar("is_day")===true) {
              return `None are visible during the day. `;
            } else {
              return `The broad leaves of the oasis form a nearly solid canopy, obscuring the stars. `;
            }
          },
        },
        sound: {
          enabled: true,
          description: `A trickle, a bubble, a burble. Somewhere in the oasis there is an active spring. `,
        },    
      },
    });
    

Area Events

Assets of class Room and Zone each have an area_events property that can be set to randomly print ambient events to the display.

zone.area_events

This property can be set to print randomly while player is in any room in the specified zone.

MyGame.createAsset({
  class: "Zone",
  name: "Desert Zone",
  area_events: [
    {
      frequency: .1,
      randomize: true,
    },
    "You hear the distant shriek of a desert hawk. ",
    "A flurry of sand trickles down a nearby dune. ",
    "A shimmer of heat haze rises up from the sands. "
  ],
});
room.area_events

This property can be set to print randomly while player is in the specified room. Room events take precedence over zone events. If a room in the zone has its own events, only those will be printed.

MyGame.createAsset({
  class: "Room",
  name: "Oasis",
  zone: "Desert Zone",
  area_events: [
    {
      frequency: .1,
      randomize: true,
    },
    "Water burbles in the spring at the heart of the oasis. ",
    "The leaves overhead brush gently against each other in the breeze, sssh-sssh-sssh. ",
    "A breeze blows through the oasis, cool, then warm, then cool again. ",
    "A distant coyote's howl chills {us} in the shadow of the oasis. "
  ],
});

Further reference

Advanced Javascript users may wish to use arrow functions with getStringArrowFunction. While it's possible, it comes with caveats. Find more information at Advanced Scripting: Arrow Functions.