Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
//mergeWorld.js
/*global adventurejs A*/

/**
 * Deep mergeWorld function for simple object types,
 * used to merge restored save game files into baseline game state.
 * @method adventurejs.Game#mergeWorld
 * @memberOf adventurejs.Game
 * @param {Object} source
 * @param {Object} dest
 * @returns {Object} dest
 */
adventurejs.mergeWorld = function Adventurejs_mergeWorld(source, dest) {
  //this.game.log( "log", "high", "mergeWorld(, 'CopyOperations' )" );
  var starttime = new Date().getTime();

  // merge updated properties from saved game
  // console.log( source );
  var props = Object.keys(source);

  for (var i = 0; i < props.length; i++) {
    var prop = props[i];

    // if source has a prop that's not in dest,
    // initialize its class if it has one then clone it
    if (source[prop] && !dest[prop]) {
      // Some class properties can be strings or objects and there
      // are cases where we've defined strings as class defaults,
      // but may receive objects from authors.
      // For example eyeglasses defaults to descriptions.look = "foo"
      // and we need to prevent conflicts if player uses view modifiers
      // such as descriptions.look = {default: "foo", carefully: "bar" }
      if ("string" === typeof dest && Array.isArray(source)) {
        dest = [];
      } else if ("string" === typeof dest && "object" === typeof source) {
        dest = {};
      }

      if (source[prop].class) {
        // console.warn( "mergeWorld > make new instance of " + source[ prop ].class );
        dest[prop] = new adventurejs[source[prop].class](
          source[prop].id,
          this.game_name
        );
      }
      try {
        dest[prop] = A.clone.call(this.game, source[prop]);
      } catch (err) {
        this.game.log("L1043", "warn", 0, err.message, "CopyOperations");
        continue;
      }
    }

    // if source has a prop with a class,
    // and dest has a prop without a class,
    // instantiate the class in dest then copy props
    if (source[prop] && dest[prop] && source[prop].class && !dest[prop].class) {
      dest[prop] = new adventurejs[source[prop].class](
        source[prop].id,
        this.game_name
      );
      dest[prop] = A.clone.call(this.game, source[prop]);
    }

    // or if it's one of these types then just clone it
    else if (
      "string" === typeof source[prop] ||
      !source[prop] ||
      "function" === typeof source[prop] ||
      Array.isArray(source[prop]) ||
      "object" !== typeof source[prop] ||
      null === source[prop]
    ) {
      dest[prop] = A.clone.call(this.game, source[prop]);
    }

    // or recurse
    else {
      dest[prop] = A.mergeWorld.call(this, source[prop], dest[prop]);
    }
  }

  //this.game.log( "log", "high", "mergeWorld(, 'CopyOperations' ) took "
  //+ ( ( new Date().getTime() - starttime ) / 1000 )
  //+ " seconds." );
  return dest;
};