Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
// Settings.js
(function () {
  /* global adventurejs A */

  /**
   *
   * @class adventurejs.Settings
   * @ajsinternal
   * @param {Game} game A reference to the game instance.
   * @ajsnavheading FrameworkReference
   * @summary Manages settings for a {@link adventurejs.Game|Game} instance.
   * @classdesc
   * <p>
   * <strong>Settings</strong> is a repository for global Game
   * options. Settings is created automatically
   * by {@link adventurejs.Game|Game}. This is an internal class
   * that authors should not need to construct. However,
   * authors can set options from their game file as
   * shown below, or change them during runtime
   * with calls to <a href="#set">MyGame.settings.set()</a>.
   * </p>
   * <h3 class="examples">Example:</h3>
   * <pre class="display"><code class="language-javascript">var MyGame = new adventurejs.Game( "MyGame", "GameDisplay" );
   * MyGame.settings.set({
   *   max_undos: 20,
   *   show_room_names_in_exit_descriptions: false,
   *   can_auto_open_apertures: false
   * });
   * </code></pre>
   */
  class Settings {
    constructor(game) {
      this.game = game;

      /**
       * Each level of undo stores a snapshot of the entire
       * game state in memory. Raising a game's undo count
       * will increase its memory requirements.
       * @var {Number} adventurejs.Settings#max_undos
       * @default 10
       */
      this.max_undos = 10;

      /**
       * Console logging: control the types of statements that print to console.
       * Useful for debugging.
       * 0 = critical ( warnings & errors only )
       * 1 = high
       * 2 = medium
       * 3 = low
       * @var {Number} adventurejs.Settings#log_level
       * @default 1
       */
      this.log_level = 1;

      /**
       * Trace log statements: control which log levels call console.trace()
       * Useful for debugging.
       * @var {Number} adventurejs.Settings#log_trace_level
       * @default 0
       */
      this.log_trace_level = 0;

      this.include_filename_in_log = false;
      // this.include_filename_in_debug = false;

      /**
       * Console logging: control what keywords log to console.
       * Warnings and Errors will print regardless of settings.
       * See the available list of keywords below. Set false
       * to remove those from console output.
       * <br><br>
       * Set log_keywords.all to true to log all keywords.
       * <br><br>
       * this.log_keywords = {
       * <ul class="ajs-nolist">
       *   <li>all: false,</li>
       *   <li>character: false,</li>
       *   <li>copyoperations: false ,</li>
       *   <li>debug: false,</li>
       *   <li>dictionary: false,</li>
       *   <li>display: false,</li>
       *   <li>exit: false,</li>
       *   <li>game: false,</li>
       *   <li>parser: false,</li>
       *   <li>print: false,</li>
       *   <li>room: false,</li>
       *   <li>saverestore: false,</li>
       *   <li>substanceemitter: false,</li>
       *   <li>substancemixer: false,</li>
       *   <li>tangible: false,</li>
       *   <li>travel: false,</li>
       *   <li>tutorial: false,</li>
       *   <li>utility: false,</li>
       *   <li>verb: false,</li>
       *   <li>verbaction: false,</li>
       *   <li>verbreaction: false,</li>
       *   <li>verbphase: false,</li>
       *   <li>vessel: false,</li>
       *   <li>warning: false,</li>
       * </ul>
       * };
       * @var {Object} adventurejs.Settings#log_keywords
       */
      this.log_keywords = {
        all: false,
        character: false,
        copyoperations: false /* clone, merge, diff, restore, save */,
        debug: false,
        dictionary: false,
        display: false,
        exit: false,
        game: false,
        parser: false,
        print: false,
        room: false,
        saverestore: false,
        substanceemitter: false,
        substancemixer: false,
        tangible: false,
        travel: false,
        tutorial: false,
        utility: false,
        verb: false,
        verbaction: false,
        verbreaction: false,
        verbphase: false,
        vessel: false,
        warning: false,
      };

      /**
       * Display debugging: control what keywords print to the display.
       * See the available list of keywords below. Set individual
       * properties to true to print debug messages to the display.
       * <br><br>
       * <code>verbaction</code>, <code>verbreaction</code>, and
       * <code>verbphase</code> each represent types of hooks that
       * authors can use to inject custom code. Enabling these will
       * show you what hooks fire during a turn.
       * @var {Object} adventurejs.Settings#debug_keywords
       * <br><br>
       * <code>general</code> represents everything else. Any player
       * input that fails will offer an explanation of the failure.
       * <br><br>
       * Set debug_keywords.all to true to log all keywords.
       * <ul>
       *   <li>all: false,</li>
       *   <li>verbaction: false,</li>
       *   <li>verbreaction: false,</li>
       *   <li>verbphase: false,</li>
       *   <li>general: false,</li>
       * </ul>
       */
      this.debug_keywords = {
        all: false,
        verbaction: false,
        verbreaction: false,
        verbphase: false,
        general: false,
      };

      /**
       * If set true, when player tries to go in a direction that hasn't
       * got an {@link adventurejs.Exit|Exit},
       * print the current room's Exits as a reminder
       * of what Exits are available. Though this is a global setting,
       * {@link adventurejs.Room|Rooms}
       * can have their own setting. Room setting overrides global setting.
       * @var {Boolean} adventurejs.Settings#when_travel_fails_list_exits
       * @default true
       */
      this.when_travel_fails_list_exits = true;

      /**
       * If set true,
       * {@link adventurejs.Exit|Exit} descriptions can include
       * the name of the {@link adventurejs.Room|Room} that the
       * Exit leads to. (The logic for this may also consider other
       * conditions such as whether the player knows about the
       * other Room.) Though this is a global setting,
       * Exits can have their own setting. Exit setting overrides
       * global setting.
       * @var {Boolean} adventurejs.Settings#show_room_names_in_exit_descriptions
       * @default true
       */
      this.show_room_names_in_exit_descriptions = true;

      /**
       * If set true,
       * {@link adventurejs.Exit|Exit} descriptions can include
       * the name of the {@link adventurejs.Room|Room} that the
       * Exit leads to once player knows about the destination Room.
       * Generally player must visit a room to know about it, but
       * there can be exceptions.
       * Though this is a global setting,
       * Exits can have their own setting. Exit setting overrides
       * global setting.
       * @var {Boolean} adventurejs.Settings#show_room_names_in_exit_descriptions_only_when_room_is_known
       * @default false
       */
      this.show_room_names_in_exit_descriptions_only_when_room_is_known = false;

      /**
       * If set true,
       * {@link adventurejs.Exit|Exit} descriptions can include
       * the name of the {@link adventurejs.Room|Room} that the
       * Exit leads to once player has used the Exit.
       * Though this is a global setting,
       * Exits can have their own setting. Exit setting overrides
       * global setting.
       * @var {Boolean} adventurejs.Settings#show_room_names_in_exit_descriptions_only_after_exit_has_been_used
       * @default true
       */
      this.show_room_names_in_exit_descriptions_only_after_exit_has_been_used = true;

      /**
       * If true, disambiguation prompts will present an ordered
       * list rather than plain text.
       * <br><br>
       * 'Disambiguation' means the player has asked for an object
       * that could refer to multiple things, and the
       * {@link adventurejs.Parser|Parser}
       * hasn't been able to narrow it down to one object.
       * Let's say there are three cats of different colors in the room.
       * Normally the game would ask the player:
       * <pre class="display">
       * which cat did you mean, the orange cat, the black cat, or the piebald cat?
       * </pre>
       * If this is true, prompts will look like this instead:
       * <pre class="display">
       * Which cat did you mean?
       * 1) the orange cat
       * 2) the black cat
       * 3) the piebald cat
       * </pre>
       * When this is done, the player can enter 1, 2, or 3 and the parser
       * will understand their choice.
       * <br><br>
       * For more information about Disambiguation, see
       * <a href="/doc/NextSteps_Disambiguation.html">How to Disambiguate</a>
       * @var {Boolean} adventurejs.Settings#show_disambiguation_as_ordered_list
       * @default false
       */
      this.show_disambiguation_as_ordered_list = false;

      /**
       * If true, disambiguation prompts will present a plain text
       * paragraph with numbered options in it.
       * <br><br>
       * 'Disambiguation' means the player has asked for an object
       * that could refer to multiple things, and the
       * {@link adventurejs.Parser|Parser}
       * hasn't been able to narrow it down to one object.
       * Let's say there are three kinds of pizza in the room.
       * Normally the game would ask the player:
       * <pre class="display">
       * Which pizza did you mean, the pepperoni pizza,
       * the pineapple pizza, or the vegetable pizza?
       * </pre>
       * If this is true, numbers will be inserted into the text,
       * like this:
       * <pre class="display">
       * Which pizza did you mean, 1) the pepperoni pizza,
       * 2) the pineapple pizza, or 3) the vegetable pizza?
       * </pre>
       * When this is done, the player can enter 1, 2, or 3 and the parser
       * will understand their choice.
       * <br><br>
       * For more information about Disambiguation, see
       * <a href="/doc/NextSteps_Disambiguation.html">How to Disambiguate</a>
       * @var {Boolean} adventurejs.Settings#
       * @default true
       */
      this.show_disambiguation_as_numbered_paragraph = true;

      /**
       * If true, when player enters a blank line,
       * treat it as if player typed "look".
       * Otherwise play dumb.
       * @var {Boolean} adventurejs.Settings#if_input_is_empty_print_room_description
       * @default false
       */
      this.if_input_is_empty_print_room_description = false;

      /**
       * if_input_is_empty_print_this can return string or array or function.
       * @var {*} adventurejs.Dictionary#if_input_is_empty_print_this
       */
      this.if_input_is_empty_print_this = `I didn't see any input. `;

      /**
       * When the parser can't understand a player's input, it prints
       * a generic statement using this string. The statement is
       * also used in some other arbitrary places, which is to say,
       * players may see it a lot.
       * If you would like to customize this output
       * you can do so by setting this property to your preferred
       * output and including {input} as a token to be replaced
       * with the player's input. For example:
       * <pre class="display"><code class="language-javascript">MyGame.settings.set({
       *   if_parser_has_no_response_print_this: "I didn't understand <em class='unparsed'>{input}</em>. ",
       * });
       * </code></pre>
       * This example wraps the player's input in an &lt;em&gt; element so that
       * it can be styled differently from the rest of the output. This
       * isn't required and you can omit the &lt;em&gt; if you prefer.
       * And in fact you don't even need to include the original input
       * if you prefer not to. Just omit <code>{input}</code> from your
       * string and the string will be printed as you set it.
       * <br><br>
       * <code>if_parser_has_no_response_print_this</code> supports the use of
       * <code>{@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}</code>
       * meaning that you can vary it up if you like by setting it to
       * a rotating array of strings or a contextually aware function.
       * @var {Boolean} adventurejs.Settings#if_parser_has_no_response_print_this
       */
      this.if_parser_has_no_response_print_this = `I don't understand what you mean by <em class='ajs-unparsed'>{input}</em>. `;

      /**
       * If the player uses a word that is not known to the parser,
       * but listed in game.dictionary.common_words,
       * print this error message back to the player. Include {word}
       * to print the word back to the player.
       * <br><br>
       * <code>if_word_is_common_print_this</code> supports the use of
       * <code>{@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}</code>
       * meaning that you can vary it up if you like by setting it to
       * a rotating array of strings or a contextually aware function.
       * @var {Boolean} adventurejs.Settings#if_word_is_common_print_this
       */
      this.if_word_is_common_print_this = `{We} {don't} know of any <span class="ajs-common ajs-word">{word}</span>. `;

      /**
       * If the player uses a word that is not known to the parser,
       * print this error message back to the player. Include {word}
       * to print the word back to the player.
       * <br><br>
       * <code>if_word_is_unknown_print_this</code> supports the use of
       * <code>{@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}</code>
       * meaning that you can vary it up if you like by setting it to
       * a rotating array of strings or a contextually aware function.
       * @var {Boolean} adventurejs.Settings#if_word_is_unknown_print_this
       */
      this.if_word_is_unknown_print_this = `{We} {don't} know the word <span class="ajs-unknown ajs-word">{word}</span>. `;

      /**
       * If the player uses a word that is not known to the parser,
       * print this error message back to the player. Include {word}
       * to print the word back to the player.
       * <br><br>
       * <code>if_verb_is_unknown_print_this</code> supports the use of
       * <code>{@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}</code>
       * meaning that you can vary it up if you like by setting it to
       * a rotating array of strings or a contextually aware function.
       * @var {Boolean} adventurejs.Settings#if_verb_is_unknown_print_this
       */
      this.if_verb_is_unknown_print_this = `{We} {don't} know how to <span class="ajs-unknown ajs-word ajs-verb">{word}</span> anything. `;

      /**
       * If the current room is dark, print this instead of a room description.
       * @var {Boolean} adventurejs.Settings#if_room_is_dark_print_this
       */
      this.if_room_is_dark_print_this = `It is pitch black. {We} are likely to be eaten by a grue. `;

      /**
       * If the current room is dark, print this instead of a room name.
       * @var {Boolean} adventurejs.Settings#name_for_dark_rooms
       */
      this.name_for_dark_rooms = `In the dark`;

      /**
       * If true, when player enters just a noun,
       * treat it as if player typed "examine x".
       * Otherwise play dumb.
       * @var {Boolean} adventurejs.Settings#if_input_is_an_asset_name_examine_it
       * @default true
       */
      this.if_input_is_an_asset_name_examine_it = true;

      /**
       * We're all about strings here. Your job as an author is
       * to write lots and lots and lots of them. Sometimes it
       * gets boring seeing the same string over and over again,
       * and you just want to show some alternates.
       * Some properties let you do that through the use of
       * {@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}.
       * You can feed getStringOrArrayOrFunction a string
       * or an array or a function (that returns a string).
       * If you provide an array, this setting determines
       * whether strings in the array are presented in sequence,
       * or randomly. If this setting is true, arrays
       * will be randomized.
       * <br><br>
       * For more information, see
       * <a href="/doc/Scripting_StringArrayFunction.html">How to Use String|Array|Function</a>
       * @var {Boolean} adventurejs.Settings#randomize_arrays_in_getStringOrArrayOrFunction
       * @default false
       * @todo List properties that this applies to.
       */
      this.randomize_arrays_in_getStringOrArrayOrFunction = false;

      /**
       * We're all about strings here. Your job as an author is
       * to write lots and lots and lots of them. Sometimes it
       * gets boring seeing the same string over and over again,
       * and you just want to show some alternates.
       * Some properties let you do that through the use of
       * {@link adventurejs.Game#getStringOrArrayOrFunction|getStringOrArrayOrFunction}.
       * You can feed getStringOrArrayOrFunction a string
       * or an array or a function (that returns a string).
       * If you provide an array, this setting determines
       * whether the array loops back to the beginning when the
       * last item is reached. If this setting is true, arrays
       * will be reset.
       * <br><br>
       * For more information, see
       * <a href="/doc/Scripting_StringArrayFunction.html">How to Use String|Array|Function</a>
       * @var {Boolean} adventurejs.Settings#randomize_arrays_in_getStringOrArrayOrFunction
       * @default true
       * @todo List properties that this applies to.
       */
      this.reset_arrays_in_getStringOrArrayOrFunction = true;

      /**
       * If true, if player tries to interact with an asset that is
       * not carried but which needs to be carried, player will
       * automatically pick up the asset.
       * @var {Boolean} adventurejs.Settings#auto_take_assets
       * @default true
       */
      this.auto_take_assets = true;

      /**
       * If true, if player tries to interact with an asset that is
       * not carried but which needs to be carried, player will
       * automatically pick up the asset, but only if they have
       * previously interacted with the asset.
       * @var {Boolean} adventurejs.Settings#auto_take_assets_after_first_use
       * @default true
       */
      this.auto_take_assets_after_first_use = true;

      /**
       * If true, if player tries to interact with an asset that is
       * inside another, closed asset, the closed asset will be
       * automatically opened if player is carrying any
       * necessary {@link adventurejs.Key|Keys}.
       * @var {Boolean} adventurejs.Settings#auto_open_containers
       * @default true
       */
      this.auto_open_containers = true;

      /**
       * If true, if player tries to interact with an asset that is
       * inside another, closed asset, the closed asset will be
       * automatically opened, but only if player has already
       * opened or closed that asset before, and if player is carrying
       * any necessary {@link adventurejs.Key|Keys}.
       * @var {Boolean} adventurejs.Settings#auto_open_containers_after_first_use
       * @default true
       */
      this.auto_open_containers_after_first_use = true;

      /**
       * Standard value for drinking, in ml. If player
       * {@link drink|drinks} from a
       * {@link adventurejs.Vessel|Vessel},
       * this is the quantity of liquid that will be removed from it
       * (unless the Vessel has custom drink logic).
       * @var {Number} adventurejs.Settings#mouthful
       * @default 100
       */
      this.mouthful = 100;

      /**
       * Standard value for holding in hands, in ml. Generally
       * if player tries to interact with substances without a container
       * they're given some kind of "slips through your fingers" message
       * but in the case of something like "throw sand" when player is
       * on a beach, we'll let them throw a handful of sand,
       * and if the containing object is not infinite, subtract this
       * amount from it.
       * @var {Number} adventurejs.Settings#handful
       * @default 100
       */
      this.handful = 100;

      /**
       * Ambient temperature in celsius.
       * @var {Number} adventurejs.Settings#ambient_temperature
       * @default 20
       * @todo celsius/farenheit conversion
       */
      this.ambient_temperature = 20;

      /**
       * States lookup for substances.
       * @var {Object} adventurejs.Settings#states
       */
      this.states = {
        SOLID: "SOLID",
        LIQUID: "LIQUID",
        GAS: "GAS",
      };

      /**
       * The <code>pronouns</code> setting is a lookup table
       * for use with <code>person</code>.
       * @var {Object} adventurejs.Settings#pronouns
       */
      this.pronouns = {
        FIRST: "first",
        PLURAL: "plural",
        SECOND: "second",
        MALE: "male",
        FEMALE: "female",
        NONBINARY: "nonbinary",
        NONHUMAN: "nonhuman",
      };

      /**
       * The <code>person</code> setting allows you to change
       * the pronouns in all of the default response strings
       * built-in to AdventureJS. For instance, if take
       * has a response that says <code>You pick up the axe.</code>
       * you can change the word You to I in this and all other
       * responses by setting person from seconds to first.
       * @var {String} adventurejs.Settings#person
       */
      this.person = this.pronouns.SECOND;

      // settings so far unused

      this.ambient_gravity = 1;
      this.ambient_light = 1;
      this.light_sources_are_cumulative = false;
      this.ambient_sound = 0;

      this.things_float_on_water = true;
      this.things_sink_in_water = true;
      this.things_disappear_in_water = true;

      this.things_rise_in_low_gravity = true;
      this.things_fall_in_high_gravity = true;
      this.things_disappear_in_space = true;

      /**
       * If <code>print_room_exits</code> is true, a list of
       * exits will be appended to room descriptions.
       * @var {String} adventurejs.Settings#print_room_exits
       */
      this.print_room_exits = true;

      /**
       * If <code>print_room_contents</code> is true, a list of
       * room contents will be appended to room descriptions.
       * @var {String} adventurejs.Settings#print_room_contents
       */
      this.print_room_contents = true;

      this.verbosity = 0;
      this.min_verbosity = -2;
      this.max_verbosity = 1;
      // only -2 to 1 are supported
      // -2 = briefer, -1 = brief, 0 = description, 1 = verbose

      /**
       * If true, game will print brief descriptions of rooms on
       * subsequent visits.
       * @var {String} adventurejs.Settings#print_verbose_room_descriptions_on_first_visit
       */
      this.print_verbose_room_descriptions_on_first_visit = true;

      /**
       * If true, room/zone events will print. See
       * <a href="/doc/NextSteps_SceneEvents.html">Scene Events</a>
       * for more information.
       * @var {Boolean} adventurejs.Settings#enable_events
       * @default true
       */
      this.enable_events = true;

      /**
       * If true, some verbs, on receiving input of sentence
       * structure "verb substance" may infer a substance container
       * if one is required and player is carrying it.
       * This pattern is intended to help with situations
       * where the player may input something like "drink water"
       * without specifying a container. If the player is carrying
       * a glass of water, the game can infer it instead of
       * prompting the player for an object, which may seem
       * obnoxious in some circumstances.
       * @var {Boolean} adventurejs.Settings#infer_containers
       * @default true
       */
      this.infer_containers = true;

      /**
       * If player inputs something like
       * "throw rock at water", the word "water" may be
       * ambiguous because multiple water containers are
       * present: a glass of water, a bottle of water, a lake.
       * If any of those containers is a body of water like
       * a lake or ocean, we can probably assume that the
       * player meant "throw rock in lake". If
       * <code>infer_containers_prefers_reservoir</code>
       * is true, the verb <code>throw</code>'s logic will
       * make that assumption, rather than prompting player
       * to specify an indirect object.
       * @var {Boolean} adventurejs.Settings#infer_containers_prefers_reservoir
       * @default true
       */
      this.infer_containers_prefers_reservoir = true;

      /**
       * If true, when <code>infer_containers</code>
       * results in multiple assets, automatically pick one.
       * Otherwise prompt player to select one.
       * @var {Boolean} adventurejs.Settings#auto_pick_inferred_container
       * @default true
       */
      this.auto_pick_inferred_container = true;

      /**
       * If true, some verbs, on receiving input of sentence
       * structure "verb noun" may infer an indirect object
       * if one is required and player is carrying it.
       * This pattern is intended
       * chiefly for locks and keys, with the idea being that
       * if player inputs "unlock door" while carrying a door
       * key, the game can infer the door key instead of
       * prompting the player for a key, which may seem
       * obnoxious in some circumstances.
       * It works with lock / unlock, seal / unseal, open / close,
       * and some others.
       * @var {Boolean} adventurejs.Settings#infer_objects
       * @default true
       */
      this.infer_objects = true;

      /**
       * If true, <code>infer_objects</code> will
       * only be applied once a player has already interacted
       * with the direct object. This pattern is intended to
       * prevent giving away puzzle solutions. For example,
       * perhaps there are many keys but only one that opens
       * a certain lock, and determining which key opens the
       * lock is part of a puzzle. If this is set to true,
       * it would prevent players from being able to unlock
       * the door without trying all the keys to find the
       * correct one.
       * @var {Boolean} adventurejs.Settings#objects_must_be_used_before_inferring
       * @default false
       */
      this.objects_must_be_used_before_inferring = false;

      /**
       * If true, when <code>infer_objects</code>
       * results in multiple assets,  the first found asset will be used
       * Otherwise prompt player to select one.
       * @var {Boolean} adventurejs.Settings#auto_pick_inferred_objects
       * @default true
       */
      this.auto_pick_inferred_objects = true;

      /**
       * If true, when player tries to travel while nested,
       * player will auto-unnest unless prevented by circumstances.
       * @var {Boolean} adventurejs.Settings#auto_unnest_on_travel
       * @default false
       */
      this.auto_unnest_on_travel = false;

      /**
       * If true, when player tries to travel while
       * kneeling or sitting or lying on the floor,
       * player will stand up automatically.
       * @var {Boolean} adventurejs.Settings#auto_stand_on_travel
       * @default false
       */
      this.auto_stand_on_travel = false;

      /**
       * If true, player will be prevented from traveling
       * while kneeling or sitting or lying on the floor.
       * @var {Boolean} adventurejs.Settings#on_floor_blocks_travel
       * @default false
       */
      this.on_floor_blocks_travel = false;

      /**
       * If true, when player tries inputs something like
       * "ride east on bike" while not nested on the bike,
       * the game will attempt to nest the player automatically.
       * Otherwise the game will return "you're not on the bike".
       * @var {Boolean} adventurejs.Settings#auto_mount_vehicles
       * @default false
       */
      this.auto_mount_vehicles = false;

      /**
       * Set the visibility of the compass rose in the status bar.
       * @var {Boolean} adventurejs.Settings#show_compass_rose_in_status
       * @default true
       */
      this._show_compass_rose_in_status = true;

      /* *
       * Set the status bar compass rose to show a magnified
       * version on hover.
       * @var {Boolean} adventurejs.Settings#magnify_compass_rose_on_hover
       * @default true
       */
      // Object.defineProperty(this, 'magnify_compass_rose_on_hover', {
      //   configurable: true,
      //   get() { return this._magnify_compass_rose_on_hover; },
      //   set(value) {
      //     this._magnify_compass_rose_on_hover = value;
      //     if(this.game.display) this.game.display.exitsContainerEl.classList[value?'add':'remove']('magnify');
      //   },
      // });
      // this.magnify_compass_rose_on_hover = false;

      /* *
       * When we initialize assets, By default we add
       * the name, each word of the name and each pair
       * of words in the name. In some situations this
       * may be excessive and lead to the parser
       * misinterpreting phrases.
       * @var {Boolean} adventurejs.Settings#split_asset_names_for_world_lookup
       * @default true
       */
      //this.split_asset_names_for_world_lookup = true;

      /**
       * We can track the user's x/y/z position. This option sets whether
       * x/z are considered in determining reachability. All tangible assets
       * are created at a default position of x:0,y:0,z:0. At this position,
       * reachability checks will always return true. Now imagine
       * you have a dorm room with a bed and a desk, where the bed is at
       * x:3 and the desk is across the room at x:-3. If this property is true,
       * then their relative distance apart will be taken into account
       * when determining reachability.
       * @var {Boolean} adventurejs.Settings#xz_determines_reachability
       * @default false
       */
      this.xz_determines_reachability = true;

      /**
       * We can track the user's x/y/z position. This option sets whether
       * y is considered in determining reachability. By default,
       * all tangible assets are positioned at x:0,y:0,z:0. Now imagine
       * you have a roof that is 2 high. If this property is true,
       * the height of the roof will be taken into account
       * when determining reachability of objects on the roof.
       * @var {Boolean} adventurejs.Settings#xz_determines_reachability
       * @default false
       * @todo implement this
       */
      this.y_determines_reachability = true;

      /**
       * When a user inputs <code>look</code> or <code>examine</code>, the game
       * looks for a base description for the specified asset, and also looks
       * for any modified descriptions, such as looking with a special light
       * or through a lens or from a particular location. If a modified description
       * is found, depending on how you write descriptions, you may want the
       * modified description appended to the base description, or you may want the
       * modified description to completely replace the base description. This is
       * purely a matter of stylistic preference. See the examples below to learn
       * more about the distinction.
       * <h3 class="examples">Example:</h3>
       * Consider this chalice: it has a base description for "look" and a modified
       * description for "look with occult candle", and it makes sense that we might
       * want to print both.
       * <pre class="display"><code class="language-javascript">var MyGame = new adventurejs.Game( "MyGame", "GameDisplay" );
       * MyGame.createAsset({
       *   class: "Chalice",
       *   name: "chalice",
       *   place: { in: "Treasure Room" },
       *   descriptions: {
       *     look: {
       *       default: "The chalice is baked from rough clay. ",
       *       "with occult candle":
       *         "The light of the candle reveals glowing runes inscribed in the clay. ",
       *     },
       *   },
       * });
       * </code></pre>
       * Now consider this sword. It's set up the same way, but it's written such that
       * we want the modified description to replace the base description entirely.
       * <pre class="display"><code class="language-javascript">var MyGame = new adventurejs.Game( "MyGame", "GameDisplay" );
       * MyGame.createAsset({
       *   class: "Chalice",
       *   name: "chalice",
       *   place: { in: "Treasure Room" },
       *   descriptions: {
       *     look: {
       *       default: "It's an unremarkable steel sword. ",
       *       "with occult candle":
       *         "Seen beneath the light of the occult candle, the sword dances with eldritch flames. ",
       *     },
       *   },
       * });
       * </code></pre>
       * @var {Boolean} adventurejs.Settings#concatenate_descriptions
       * @default false
       */
      this.concatenate_descriptions = true;

      /**
       * Determine whether to consider the last turn when disambiguation is
       * required. For example, consider a room with a gold key, a silver key,
       * and a brass key, where player inputs "take gold key", and then on the
       * next turn inputs "unlock door with key". By default, the parser
       * will find all three keys and prompt for disambiguation, ie
       * "which key did you mean". But we can guess that the player probably
       * meant the key that they just picked up.
       * @var {Boolean} adventurejs.Settings#disambiguation_considers_last_turn
       * @default true
       */
      this.disambiguation_considers_last_turn = true;

      /**
       * If true, the game will print inferences such as
       * "take candy (from baby)".
       * @var {Boolean} adventurejs.Settings#print_inferred
       * @default true
       */
      this.print_inferred = true;

      /**
       * If true, when an asset becomes known, it will be
       * known by all player characters. Only useful when
       * using player character switching.
       * @var {Boolean} adventurejs.Settings#known_by_all_players
       * @default true
       */
      this.known_by_all_players = true;

      /**
       * If true, when an asset becomes seen, it will be
       * seen by all player characters. Only useful when
       * using player character switching.
       * @var {Boolean} adventurejs.Settings#seen_by_all_players
       * @default true
       */
      this.seen_by_all_players = true;

      /**
       * This is an optional flag for authors who use
       * random room / zone events. It's intended so
       * that players can use verb "quiet" to suppress
       * these random events. Whether that is respected
       * is up to authors.
       * @var {Boolean} adventurejs.Settings#quiet
       * @default false
       */
      this.quiet = false;

      /**
       * If an author uses room / zone events and/or
       * character idle events, players may use verb
       * "quiet" to suppress them, if respect_quiet is true.
       * @var {Boolean} adventurejs.Settings#respect_quiet
       * @default true
       */
      this.respect_quiet = true;

      /**
       * If true, text of saved game files will be obfuscated
       * to make them non human readable.
       * @var {Boolean} adventurejs.Settings#obfuscate_saves
       * @default false
       */
      this.obfuscate_saves = false;

      /**
       * If true, when player inputs "go to room", if there are any
       * unlockable doors between player and destination, goTo will
       * fail, leaving player at their origin room.
       * If false, goTo will partially succeed, and only take player
       * as far as the locked door.
       * @var {Boolean} adventurejs.Settings#goto_excludes_locked_doors
       * @default false
       */
      this.goto_excludes_locked_doors = false;

      /**
       * If true, when player inputs "go to room", if the player
       * hasn't visited the room, goTo will fail.
       * @var {Boolean} adventurejs.Settings#goto_excludes_unvisited_locations
       * @default true
       */
      this.goto_excludes_unvisited_locations = true;

      /**
       * If true, when player inputs "go to room", the game will
       * print the description of each room traveled through. If
       * false, room descriptions will be omitted in favor of simple
       * concatenated travel messages, ex: "You go east. You go north.".
       * Note: If the rooms player travels through print messages on
       * enter or exit, those messages may be inserted awkwardly.
       * @var {Boolean} adventurejs.Settings#goto_prints_room_descriptions
       * @default true
       */
      this.goto_prints_room_descriptions = true;

      /**
       * This is a subtle and complex setting.
       * Description modifiers allow authors to provide alternate
       * descriptions for assets when they are seen in certain
       * conditions, such as when wearing x-ray specs, or under
       * a black light, or from a particular location. It's even
       * possible for authors to create complex modifiers that
       * require two or more conditions, such as when wearing the
       * x-ray specs AND under the black light. The logic that
       * determines when to print these descriptions can stack
       * them, or not, depending on this setting, which is to say,
       * if it finds three separate descriptions whose conditions
       * are all met, it may print them all, or only one.
       * <br><br>
       * For example,
       * let's say that "through x-ray specs" and "with black light"
       * are two separate modifiers.
       * If max_level_of_modified_descriptions_to_stack is 0,
       * only the first one found will be printed.
       * If max_level_of_modified_descriptions_to_stack is 1,
       * both descriptions will be printed.
       * <br><br>
       * On the other hand, let's say the author has set
       * "through x-ray specs, with black light" as a third
       * option. It's one combined modifier with two clauses,
       * that is only satisfied if both conditions are tru.
       * If max_level_of_modified_descriptions_to_stack is 0 or 1,
       * only the combined description will be printed.
       * If max_level_of_modified_descriptions_to_stack were
       * set to 2 or higher, the description for
       * "through x-ray specs, with black light" would print,
       * as would any other double claused descriptions
       * whose conditions were met.
       * <br><br>
       * See
       * <a href="Descriptions_DescriptionModifiers.html">Description Modifiers</a>
       * and
       * <a href="Descriptions_AdvancedDescriptions.html">Advanced Descriptions</a>
       * for more info.
       * @var {int} adventurejs.Settings#max_level_of_modified_descriptions_to_stack
       * @default 1
       */
      this.max_level_of_modified_descriptions_to_stack = 1;

      /**
       * If true, when player inputs "write 'foo' with red pen",
       * the written text will be printed to the display with a
       * CSS class that is the name of the color. For example:
       * <span class="red">foo</span>
       * @var {Boolean} adventurejs.Settings#apply_color_classes_to_written_strings
       * @default true
       */
      this.apply_color_classes_to_written_strings = true;
    }

    /**
     * Provides a chainable shortcut method for setting a number of properties on the instance.
     * @method adventurejs.Settings#set
     * @param {Object} props A generic object containing properties to copy to the instance.
     * @returns {adventurejs.Settings} Returns the instance the method is called on (useful for chaining calls.)
     * @chainable
     */
    set(props) {
      // console.log(props);
      return A.deepSet.call(this.game, props, this);
    }

    /**
     * Take input and return a standardized "unparsed" message.
     * {@link adventurejs.Settings#if_parser_has_no_response_print_this|settings.if_parser_has_no_response_print_this}.
     * @memberOf adventurejs.Settings
     * @method adventurejs.Settings#getUnparsedMessage
     */
    getUnparsedMessage(input) {
      this.game.debug(
        `D1158 | Settings.js | input couldn't be parsed, print settings.if_parser_has_no_response_print_this`
      );
      let msg = A.getSAF.call(
        this.game,
        this.game.settings.if_parser_has_no_response_print_this
      );
      let regex = /\{(input)\}/g;
      return msg.replace(regex, `${input}`);
    }

    /**
     * Get if_verb_is_unknown_print_this and substitute word if needed.
     * @method adventurejs.Settings#getUnknownVerbMessage
     * @param {string} word The unknown verb.
     * @returns {string}
     */
    getUnknownVerbMessage(word) {
      let msg = A.getSAF.call(
        this.game,
        this.game.settings.if_verb_is_unknown_print_this
      );
      let regex = /\{(word)\}/g;
      return msg.replace(regex, `${word}`);
    }

    /**
     * Get if_word_is_unknown_print_this and substitute word if needed.
     * @method adventurejs.Settings#getUnknownWordMessage
     * @param {string} word The unknown word.
     * @returns {string}
     */
    getUnknownWordMessage(word) {
      let msg = A.getSAF.call(
        this.game,
        this.game.settings.if_word_is_unknown_print_this
      );
      let regex = /\{(word)\}/g;
      return msg.replace(regex, `${word}`);
    }

    /**
     * Get if_word_is_common_print_this and substitute word if needed.
     * @method adventurejs.Settings#getCommonWordMessage
     * @param {string} word The unknown word.
     * @returns {string}
     */
    getCommonWordMessage(word) {
      let msg = A.getSAF.call(
        this.game,
        this.game.settings.if_word_is_common_print_this
      );
      let regex = /\{(word)\}/g;
      return msg.replace(regex, `${word}`);
    }

    get show_compass_rose_in_status() {
      return this._show_compass_rose_in_status;
    }
    set show_compass_rose_in_status(value) {
      this._show_compass_rose_in_status = value;
      if (this.game.display)
        this.game.display.exitsContainerEl.classList[value ? "remove" : "add"](
          "hidden"
        );
    }
  }
  adventurejs.Settings = Settings;
})();