Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
// findNestedIndirectObjects.js
(function () {
  /* global adventurejs A */
  var p = adventurejs.Tangible.prototype;
  /**
   * Returns a list of assets nested in this asset, if any, that can perform
   * the specified verb upon the specified asset as defined in the
   * target asset.dov[verb].with_assets/with_classes
   * property. Works with verbs including open & close, pick,
   * lock & unlock, and seal & unseal.
   * @memberOf adventurejs.Tangible
   * @method adventurejs.Tangible#findNestedIndirectObjects
   * @param {String} verb The name of a verb.
   * @param {Object|String} direct_object An asset or asset ID of a direct object that the player has tried to perform an indirect verb on.
   * @returns {Array} An array of indirect objects, if found.
   */
  p.findNestedIndirectObjects = function Tangible_findNestedIndirectObjects(
    verb,
    direct_object
  ) {
    // we might've received a string
    if ("string" === typeof direct_object) {
      direct_object = this.game.getAsset(direct_object);
    }
    if (!verb || !this.game.dictionary.verbs[verb] || !direct_object) {
      return [];
    }
    verb = this.game.dictionary.verbs[verb];
    if (!direct_object.isDOV(verb) && !verb.allow_iov_on_iov) {
      return [];
    }

    this.game.log(
      "L1489",
      "log",
      "high",
      `[findNestedIndirectObjects.js] ${verb.name} ${direct_object.name}`,
      "Game"
    );
    var subject = this.game.getInput().getSubject();

    var indirect_objects = [];
    let dov_classes = [];
    let dov_assets = [];

    if (direct_object.isDOV(verb)) {
      dov_classes = dov_classes.concat(
        direct_object.dov[verb.name].with_classes
      );
      dov_assets = dov_assets.concat(direct_object.dov[verb.name].with_assets);
    }

    // account for verbs like write and type which treat
    // both tool and target as indirect objects
    if (verb.allow_iov_on_iov) {
      dov_classes = dov_classes.concat(
        direct_object.iov[verb.name].with_classes
      );
      dov_assets = dov_assets.concat(direct_object.iov[verb.name].with_assets);
    }

    // get class instances in player
    // findNestedAssetsWithClass calls getAllNestedContents
    if (dov_classes) {
      for (var i = 0; i < dov_classes.length; i++) {
        var classed_ids = this.findNestedAssetsWithClass(dov_classes[i]);
        for (var id = 0; id < classed_ids.length; id++) {
          indirect_objects.push(classed_ids[id]);
        }
      }
    }

    // find dov_assets in tangible
    if (dov_assets) {
      for (var i = 0; i < dov_assets.length; i++) {
        var indirect_object = this.game.getAsset(dov_assets[i]);
        if (indirect_object && indirect_object.isWithin(this))
          indirect_objects.push(indirect_object);
      }
    }

    // classes_this_can_verb
    var inventory = this.getAllNestedContents();
    for (var i = 0; i < inventory.length; i++) {
      var inventory_item = this.game.getAsset(inventory[i]);
      if (
        inventory_item.iov[verb.name]?.with_classes &&
        inventory_item.iov[verb.name].with_classes.includes(direct_object.id)
      ) {
        var dupe = false;
        for (var asset in indirect_objects) {
          if (indirect_objects[asset].id === inventory_item.id) dupe = true;
        }
        if (!dupe) indirect_objects.push(indirect_object);
      }
    }

    // subtract unknown / unreachable items
    for (var i = indirect_objects.length - 1; i > -1; i--) {
      // it's possible for player to not know about items in inventory
      var asset = indirect_objects[i];
      if (!subject.knowsAbout(asset)) indirect_objects.splice(i);
      if (!asset.areAnscestorsKnown()) indirect_objects.splice(i);
    }

    return indirect_objects;
  };
})();