Pre-release
Adventure.js Docs Downloads
Score: 0 Moves: 0
// setVerbSubscription.js
(function () {
  /*global adventurejs A*/
  "use strict";
  var p = adventurejs.Asset.prototype;
  /**
   * <strong>setVerbSubscription</strong> constructs verb subscriptions
   * at asset.dov / asset.iov. It's intended mostly
   * as a private function, though it is available to authors.
   * An early version takes a string with separate params object.
   * A later version takes an object that includes the verb name
   * as an object key and params as value.
   * // valid (for now) early version
   * this.setIOV('hold',{with_params:{max_connections:2}});
   * // valid later version with one verb
   * this.setIOV( { hold: { with_params: { max_connections:2 } } } );
   * // valid later version with multiple verbs
   * this.setIOVs([
   *   { hold: { with_params: { max_connections:3 } } },
   *   { smell: true },
   * ]);
   * @memberOf adventurejs.Asset
   * @method adventurejs.Asset#setVerbSubscription
   * @param {String} object_of
   * @param {String|Object} verb An early version takes a string,
   * with separate params object. A later version takes an object
   * that includes the verb name as an object key and params as value.
   * @param {Object} params An optional param that works with the
   * earlier version.
   * @todo phase out earlier version
   */
  p.setVerbSubscription = function Asset_setObjectOfVerb(object_of, verb) {
    if (!object_of) return; // no object type
    let params;

    // does verb look like this: { verb: {} }
    if ("object" === typeof verb) {
      params = verb[Object.keys(verb)[0]];
      verb = Object.keys(verb)[0];
    }

    if (!verb || !this.game.dictionary.verbs[verb]) return; // no verb

    // we allow this shortcut {dov:{verb:true}}
    // did author use shortcut to enable verb subscription?

    if (params === true) {
      params = { enabled: true, with_nothing: true }; // we accept a bool
    }
    if (params === false) {
      params = { enabled: false };
    }
    // no other accepted form of params received?
    if ("object" !== typeof params) {
      params = { enabled: true, with_nothing: true };
    }
    if ("undefined" === typeof params.enabled) {
      params.enabled = true;
    }

    // if verb setting exists and params include nothing new, we're done
    if (this[object_of][verb] && !Object.keys(params).length) {
      return this[object_of][verb];
    }

    // is asset not already subscribed to verb?
    if (!this[object_of][verb]) {
      this[object_of][verb] = new adventurejs.VerbSubscription(
        verb,
        this.game_name,
        this.id
      );

      // set constructor name which gives us a way to find inheritance
      // @TODO this doesn't work the way I expected it to
      // need to loop through __proto__ to find which ancestor
      // this prop initiated from, but as verb subscriptions are set in
      // asset constructors, they're not available from here - rethink this
      this[object_of][verb].inherited_from = this.constructor.name;

      // save the verb name back to the verb subscription
      this[object_of][verb].name = verb;

      // copy verb.with_params
      // IMPORTANT: use JSON.parse(JSON.stringify(with_params))
      this[object_of][verb].with_params = JSON.parse(
        JSON.stringify(this.game.dictionary.verbs[verb].with_params)
      );
    }

    // if params include nothing new, we're done
    if (!Object.keys(params).length) {
      return this[object_of][verb];
    }

    // apply params from asset class or game file
    // which may include with_params and is therefore deep
    this[object_of][verb] = A.deepSet.call(
      this.game,
      params,
      this[object_of][verb]
    );

    // did author set a string for with_assets? we'll allow it
    if ("string" === typeof this[object_of][verb].with_assets) {
      this[object_of][verb].with_assets = [this[object_of][verb].with_assets];
    }

    if (this[object_of][verb].with_assets.length) {
      for (var i = 0; i < this[object_of][verb].with_assets.length; i++) {
        // author probably used names - set to ids
        this[object_of][verb].with_assets[i] = A.serialize(
          this[object_of][verb].with_assets[i]
        );
        // we want to validate these asset name/ids,
        // but at this point paired assets may not yet have been created
      }

      // was automatically setting with_nothing/anything
      // but maybe should leave that for author to explicitly set
      object_of === "dov"
        ? (this[object_of][verb].with_nothing = false)
        : (this[object_of][verb].with_anything = false);
    }

    // did author set a string for with_classes? we'll allow it
    if ("string" === typeof this[object_of][verb].with_classes) {
      this[object_of][verb].with_classes = [this[object_of][verb].with_classes];
    }

    if (this[object_of][verb].with_classes.length) {
      for (var i = this[object_of][verb].with_classes.length - 1; i >= 0; i--) {
        // validate classes
        var klass = this[object_of][verb].with_classes[i];
        if (!adventurejs[klass]) {
          var msg = `${this.id}.${object_of}.${verb}.with_classes.${klass}: ${klass} isn't recognized as an adventurejs class and was removed. `;
          this.game.log("warn", 0, msg, "Asset");
          this[object_of][verb].with_classes.splice(i);
        }
      }
      object_of === "dov"
        ? (this[object_of][verb].with_nothing = false)
        : (this[object_of][verb].with_anything = false);
    }

    // if no supporting assets, set anything/nothing to true?
    if (
      !this[object_of][verb].with_assets.length &&
      !this[object_of][verb].with_classes.length
    ) {
      //this[object_of][verb].with_anything = true;
      //this[object_of][verb].with_nothing = true;
    }

    return this[object_of][verb];
  };
})();