//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#mergeWorld
* @memberOf AdventureJS
* @param {Object} source
* @param {Object} dest
* @returns {Object} dest
*/
AdventureJS.FX.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 );
let c =
AdventureJS[source[prop].class] ||
AdventureJS.Assets[source[prop].class] ||
AdventureJS.AssetHelpers[source[prop].class] ||
AdventureJS.AssetTraits[source[prop].class];
// dest[prop] = new AdventureJS[source[prop].class](
dest[prop] = new c(
source[prop].id,
this.game_name,
source.context_id ? source.context_id : "",
source.id ? source.id : ""
);
}
try {
dest[prop] = A.FX.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) {
let c =
AdventureJS[source[prop].class] ||
AdventureJS.Assets[source[prop].class] ||
AdventureJS.AssetHelpers[source[prop].class] ||
AdventureJS.AssetTraits[source[prop].class];
dest[prop] = new c(
source[prop].id,
this.game_name,
source.context_id ? source.context_id : "",
source.id ? source.id : ""
);
dest[prop] = A.FX.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.FX.clone.call(this.game, source[prop]);
}
// or recurse
else {
dest[prop] = A.FX.mergeWorld.call(this, source[prop], dest[prop]);
}
}
//this.game.log( "log", "high", "mergeWorld(, 'CopyOperations' ) took "
//+ ( ( new Date().getTime() - starttime ) / 1000 )
//+ " seconds." );
return dest;
};