// Tangible.js
(function () {
/* global adventurejs A */
/**
* @ajspath adventurejs.Atom.Asset.Matter.Tangible
* @augments adventurejs.Matter
* @class adventurejs.Tangible
* @ajsconstruct MyGame.createAsset({ "class":"Tangible", "name":"foo", [...] })
* @ajsconstructedby adventurejs.Game#createAsset
* @ajsnavheading BaseClasses
* @param {String} game_name The name of the top level game object.
* @param {String} name A name for the object, to be serialized and used as ID.
* @summary Base class for all game objects with physical properties.
* @tutorial Tangibles_AboutTangibles
* @classdesc
* <p>
* <strong>Tangible</strong> is the base class for all
* {@link adventurejs.Asset|Assets} with physical properties
* in the game world, with the exception of Substances.
* All of the properties of Tangible are inherited by all of
* its subclasses, and most subclasses don't define new properties.
* Most subclasses are essentially convenience methods that set
* a group of properties particular to a type of object.
* In theory, an instance of almost any subclass could be made to
* behave like an instance of almost any other subclass,
* simply by setting the right properties. This provides the
* flexibility to mix and match properties to construct game
* assets with customized behaviors.
* </p>
* <p>
* For example, {@link adventurejs.Chair|Chair} defines
* something you can sit on, and
* {@link adventurejs.Bed|Bed} defines something
* you can lie on, but perhaps you want to make something
* like a divan, that you can sit on and lie on. You could
* create a Chair and set asset.aspects.on.nest.can.lie
* property to true.
* </p>
* <pre class="display"><code class="language-javascript">MyGame.createAsset({
* class: "Chair",
* name: "divan",
* descriptions: {look:"A comfortable looking fainting couch. ",),
* aspects:
* {
* on: { nest: { can: { lie: true } } }
* }
* });
* </code></pre>
* This is a simple example of customizing an object, but hopefully
* it gives you an idea of how flexible the Tangible class is.
* Alternatively if you wanted to extensively customize your divan,
* you could define your own Divan class to extend
* {@link adventurejs.Furniture|Furniture}.
**/
class Tangible extends adventurejs.Matter {
constructor(name, game_name) {
super(name, game_name);
this.class = "Tangible";
this.is = new adventurejs.Tangible_Is("is", this.game_name, this.id);
this.can = new adventurejs.Tangible_Can("can", this.game_name, this.id);
this.must = new adventurejs.Tangible_Must(
"must",
this.game_name,
this.id
);
/**
* Containing object for Aspects, aka "in", "out", "under", "behind"
* etc.
* @var {Object} adventurejs.Tangible#aspects
* @default {}
*/
this.aspects = {};
// set direct verb subscriptions
this.setDOVs([
"attach",
"detach",
"get",
// "go",
"hit",
"kick",
"knock",
"move",
"poke",
"pull",
"push",
"shake",
//"turn",
"wave",
//"throw",
]);
// set indirect verb subscriptions
this.setIOVs(["hit", "throw", "flick"]);
//this.player_has_used = false;
/**
* It's possible for player to become nested to an asset without a
* specified preposition. In such cases, this default aspect is used.
* @var {String} adventurejs.Tangible#default_aspect
* @default "on"
*/
this.default_aspect = "on";
/**
* Set whether 'climb' means 'go on', which might apply to assets
* such as stairs and ladders.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!climb_means_go_on
* @default false
*/
this.quirks.climb_means_go_on = false;
/**
* Set whether 'climb' means 'stand on', which might apply to
* furniture and things like boulders which players can stand on.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!climb_means_stand_on
* @default false
*/
this.quirks.climb_means_stand_on = false;
/**
* Set whether 'pull' means 'open', which might apply to drawers.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!pull_means_open
* @default false
*/
this.quirks.pull_means_open = false;
/**
* Set whether 'pull' means 'open', which might apply to drawers.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!pull_means_open
* @default false
*/
this.quirks.push_means_press = false;
/**
* Set whether 'stand' means 'go off' (aka 'get off'), which might apply
* to furniture such as chairs.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!stand_means_get_off
* @default false
*/
this.quirks.stand_means_get_off = false;
/**
* Set whether 'get up' means 'go off' (aka 'get off'), which might apply
* to furniture such as chairs or beds.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!get_up_means_get_off
* @default false
*/
this.quirks.get_up_means_get_off = false;
/**
* Set whether 'get on' means to scale up, which might apply
* to things such as trees.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!get_on_means_go_up
* @default false
*/
this.quirks.get_on_means_go_up = false;
/**
* Set whether 'get off' means to scale down, which might apply
* to things such as trees. Scaling is subject to scale_incremement,
* which, along with object.dimensions.height, sets how many turns
* it takes a player to climb up or down an object.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!get_off_means_go_down
* @default false
*/
this.quirks.get_off_means_go_down = false;
/**
* If set to true, "in" and "on" become interchangeable for some verbs.
* Intended chiefly for things like chairs where "sit in chair"
* and "sit on chair" can be interpreted to mean the same thing.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!in_means_on
* @default false
*/
this.quirks.in_means_on = false;
/**
* If set to true, "put" means "pour" for some verbs.
* Intended chiefly for things like "put syrup on pancakes" which is
* a common phrasing where clearly the speaker means to pour.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!put_means_pour
* @default false
*/
this.quirks.put_means_pour = false;
/**
* Set whether 'jump' means 'jump on' as in jumping up and down on a bed.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!jump_means_jump_on
* @default true
*/
this.quirks.jump_means_jump_on = true;
/**
* Set whether 'jump' means 'jump off' as in jumping off a tree.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!jump_means_jump_off
* @default false
*/
this.quirks.jump_means_jump_off = false;
/**
* Set whether player can step on this asset.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!step_on_means_stamp_on
* @default false
*/
this.quirks.step_on_means_stamp_on = false;
/**
* Set whether verb 'step on' means 'stand on', as with a skateboard or some
* types of furniture.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!step_on_means_stand_on
* @default false
*/
this.quirks.step_on_means_stand_on = false;
/**
* Set whether verb 'flip' means 'toggle', as with a switch.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!flip_means_toggle
* @default false
*/
this.quirks.flip_means_toggle = false;
/**
* Set whether verb 'press' means 'toggle', as with a switch.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!press_means_toggle
* @default false
*/
this.quirks.press_means_toggle = false;
/**
* Set whether verb 'push' means 'toggle', as with a switch.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!push_means_toggle
* @default false
*/
this.quirks.push_means_toggle = false;
/**
* Set whether verb 'pull' means 'toggle', as with a switch.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!pull_means_toggle
* @default false
*/
this.quirks.pull_means_toggle = false;
/**
* Set whether verb 'flick' means 'toggle', as with a switch.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!flick_means_toggle
* @default false
*/
this.quirks.flick_means_toggle = false;
/**
* A string that describes the position the
* {@link adventurejs.Asset|Asset}
* is in, ex "resting" for most non-Character Assets,
* or "lying", "sitting", "standing" etc for
* {@link adventurejs.Characters|Characters}.
* <code class="property">this.game.dictionary.getStringLookup( type, value )</code>.
* Can be referenced in custom code through
* <code class="property">MyGame.dictionary.getStringLookup( type, value )</code>.
* @var {Boolean} adventurejs.Tangible#posture_position
* @default "default"
*/
this.posture_position = this.game.dictionary.getStringLookup(
"posture_positions",
"default"
);
/**
* Set whether player knows a thing is hidden. Useful if player is the one doing
* the hiding, or if player has found an object but not picked it up.
* @var {Boolean} adventurejs.Tangible#player_knows_its_hidden
* @default false
*/
this.player_knows_its_hidden = false;
/**
* Set an asset's percent of buoyancy. No logic has been implemented around this.
* @var {float} adventurejs.Tangible#buoyancy
* @default 0
* @todo Implement.
*/
this.buoyancy = 0; // range 0 to 1
/**
* Set the amount of liquid an asset has absorbed.
* No particular logic has been implemented around absorption.
* @var {Boolean} adventurejs.Tangible#absorption_quantity
* @default 0
*/
this.absorption_quantity = 0;
/**
* Set whether 'pick' means 'unlock'. This is provided to give authors the option
* to choose whether pick and unlock are treated as distinct verbs.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!pick_means_unlock
* @default false
*/
this.quirks.pick_means_unlock = false;
/**
* Set a message to print for asset's single use.
* @var {Boolean} adventurejs.Tangible#use_once_message
* @default false
*/
this.use_once_message = "";
/* *
* Tangible Assets may have numerous descriptions, though all but
* default are optional.
* @var {Object} adventurejs.Tangible#descriptions
* @default { look: "", careful: "", long: "", short: "", brief: "", verbose: "", closed: "", open: "", taste: "", smell:"", listen:"", in:"", through:"", }
*/
this.descriptions = {
look: "",
brief: "",
verbose: "",
careful: "",
closed: "",
open: "",
taste: "",
touch: "",
smell: "",
sound: "",
exits: "",
for_exits_list: "",
behind: "",
in: "",
on: "",
over: "",
through: "",
under: "",
};
/* *
* @var {String} adventurejs.Tangible#description
* @default ""
*/
//this.description = "";//"{We} see nothing worth mentioning.";
/**
* Set whether "look with" is equivalent to "look through". For example,
* in the case of a telescope, "look with telescope" is equivalent to
* "look through telescope". In the case of a window, you can look through
* it, but not look with it. In the case of a candle, you can look with it,
* but not look through it.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!look_with_means_look_through
* @default false
*/
this.quirks.look_with_means_look_through = false;
/**
* Set whether this asset can be swung at another asset, as in swinging a bat at a ball.
* @var {Boolean} adventurejs.Tangible#can!be_swung_at
* @default true
*/
this.can.be_swung_at = true;
// readin'n'writin'
/**
* Set whether this asset can be written in
* like a book.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!write_on_means_write_in
* @default false
*/
this.quirks.write_on_means_write_in = false;
/**
* List of strings that have been written on this asset.
* @var {Array} adventurejs.Tangible#written_strings
* @default []
*/
this.written_strings = [];
/**
* List of strings that have been typed on this asset.
* @var {Array} adventurejs.Tangible#typed_strings
* @default []
*/
this.typed_strings = [];
/**
* Set whether strings written on this asset are appended to its description.
* @var {Boolean} adventurejs.Tangible#append_written_strings_to_description
* @default false
*/
this.append_written_strings_to_description = false;
/**
* Set whether strings typed on this asset are appended to its description.
* @var {Boolean} adventurejs.Tangible#append_typed_strings_to_description
* @default false
*/
this.append_typed_strings_to_description = false;
/**
* Set the ID of a target asset for this asset to type on, as in a screen for a keyboard.
* @var {String} adventurejs.Tangible#typing_targets
* @default ""
*/
this.typing_targets = [];
// ROPES
/**
* Set whether this is taken into player inventory when another asset is tied
* to it. For example, on tying a string that is in inventory to a tin can that
* is not in inventory, it's assumed that player would then pick up the can.
* @var {Boolean} adventurejs.Tangible#on_tie_to_this_take_this
* @default false
*/
this.on_tie_to_this_take_this = false;
/**
* If player uses a rope in inventory to tie to an object that is not in inventory,
* this sets whether the object gets dragged behind when player leaves the current room.
* @var {Boolean} adventurejs.Tangible#on_tie_to_drag_behind_rope
* @default false
*/
this.on_tie_to_drag_behind_rope = false;
/**
* Set whether this asset's description includes things that it is tied to.
* @var {Boolean} adventurejs.Tangible#show_things_this_is_tied_to_in_description
* @default true
*/
this.show_things_this_is_tied_to_in_description = true;
/**
* Set whether 'take' means 'hold', as in the case of hanging ropes.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!take_means_hold
* @default false
*/
this.quirks.take_means_hold = false; // used for swingable things
/**
* Set whether 'let go of' means 'get off', as in the case of assets that
* the player is suspended from, such as hanging from a rope.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!let_go_of_means_go_off
* @default false
*/
this.quirks.let_go_of_means_go_off = false;
/**
* Set whether 'let go of' means 'go down', as in the case of player being
* suspended by a rope above a pit, where letting go means moving to a new Room.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!let_go_of_means_go_down
* @default false
*/
this.quirks.let_go_of_means_go_down = false;
/**
* Set properties for a variety of things a tangible asset can emit.
* @var {Boolean} adventurejs.Tangible#emits
* @default false
* @todo Write logic for this.
*/
this.emits = {
gravity: { enabled: false, level: 0, description: "", results: null },
light: { enabled: false, level: 0, description: "", results: null },
heat: { enabled: false, level: 0, description: "", results: null },
sound: { enabled: false, level: 0, description: "", results: null },
smell: { enabled: false, level: 0, description: "", results: null },
// liquid: { enabled: false, level: 0, description: '', results: null, id:'' },
// gas: { enabled: false, level: 0, description: '', results: null, id:'' },
// slurry: { enabled: false, level: 0, description: '', results: null, id:'' },
// solid: { enabled: false, level: 0, description: '', results: null, id:'' },
substance: {
enabled: false,
level: 0,
description: "",
results: null,
id: "",
},
};
/**
* Set whether this asset must have a location. Chiefly for use with Aperture class.
* Apertures must have a location because they're tied to Exits. Other assets can
* exist without a location, though unlocated tangible assets won't be available to player.
* @var {Boolean} adventurejs.Tangible#location_required
* @default false
*/
this.location_required = false; // some classes must have a location
/**
* Explicitly set whether this asset can exist without a location. Chiefly for use
* with Room class. Rooms will not have a location.
* @var {Boolean} adventurejs.Tangible#location_unneccessary
* @default false
*/
this.location_unneccessary = false; // some classes don't need a location
/**
* Set the minimum light required to see this asset. Meant for situations with
* variable lighting where some objects might be hidden in shadow.
* @var {float} adventurejs.Tangible#min_light_required_to_see
* @default 0.5
* @todo Write logic for this in selectVisible.js
*/
this.min_light_required_to_see = 0.5; // @FUTURE amount of ambient light required to be visible
/**
* @var {Object} adventurejs.Tangible#dimensions
* @default {}
*/
this.appearance = {
/**
* Set the opacity for this asset. Used for assets made of transparent materials
* such as glass, and helps determine whether player can look in or through assets.
* @var {float} adventurejs.Tangible#appearance.opacity
* @default 1
*/
opacity: 1,
/**
* Set the color for this asset. Currently unused.
* @var {float} adventurejs.Tangible#appearance.color
* @default 1
*/
color: "",
};
/**
* @var {Object} adventurejs.Tangible#dimensions
* @default {}
*/
this.dimensions = {
/**
* Set a depth for this asset. Used to calculate whether some assets can fit in other assets.
* @var {float} adventurejs.Tangible#dimensions.depth
* @default 0
*/
depth: 0,
/**
* Set a height for this asset. Used to calculate whether some assets can fit in other assets.
* Also used for climbing and reachability.
* Currently, 1 is considered to be human height, or about six feet.
* @var {float} adventurejs.Tangible#dimensions.height
* @default 0
*/
height: 0,
/**
* Set a length for this asset.
* @var {float} adventurejs.Tangible#dimensions.length
* @default 0
*/
length: 0,
/**
* Set a size for this asset. Meant for figuring whether some assets can fit in other assets.
* Logic for this is incomplete and may be duplicative of width / height / depth.
* @var {float} adventurejs.Tangible#dimensions.size
* @default -1
* @todo Revisit this. Does it conflict with width / height / depth?
*/
size: 0,
/**
* Set a weight for this asset. Used to calculate whether some assets can fit in other assets.
* May also be used for buoyancy though no logic has been written for that.
* @var {float} adventurejs.Tangible#dimensions.weight
* @default -1
* @todo Figure weight into buoyancy?
*/
weight: 0,
/**
* Set a width for this asset. Used to calculate whether some assets can fit in other assets.
* @var {float} adventurejs.Tangible#dimensions.width
* @default 1
*/
width: 0,
};
/**
* XYZ coordinates. Defaults to 0,0,0.
* It's safe to ignore these if you don't want to use them.
* They can be used for things like:
* <ul>
* <li>managing reachability of objects that are on top of other things</li>
* <li>managing reachability of objects in the room while player is climbing or standing atop a thing</li>
* <li>dividing a room up into reachable/unreachable spaces</li>
* <li>managing player depth in an underwater location</li>
* <li>managing player position while flying/floating/levitating</li>
* </ul>
* Here's an example of how to set an object's position.
* <pre class="display"><code class="language-javascript">MyGame.createAsset({
* class: "Stalactite",
* name: "stalactite",
* place: { on: "Colossal Cave" },
* descriptions: {look: "It clings tight to the ceiling. ",},
* height: -2,
* position: { x:0, y:5, z:0 },
* });
* </code></pre>
* Also see related <a href="#height">height</a>.
* @var {Object} adventurejs.Tangible#position
* @default {x:0,y:0,z:0}
*
* @related height
*/
this.position = {
x: 0,
y: 0,
z: 0,
};
/**
* Set whether verb point means aim for this asset.
* If so, point verb will redirect to aim.
* @nestedproprty
* @var {Boolean} adventurejs.Tangible#quirks!point_means_aim
* @default false
*
*/
this.quirks.point_means_aim = false;
/**
* Some Tangibles come pre-coded to handle certain
* "components", classes which can automatically be
* linked with each other to form complex associations.
* For example, a
* {@link adventurejs.Sink|Sink}
* can have matching
* {@link adventurejs.Faucet|Faucet},
* {@link adventurejs.FaucetHandle|FaucetHandles},
* {@link adventurejs.Drain|Drain} and
* {@link adventurejs.Plug|Plug}.
* Not all classes handle components. See each class's documentation
* header for "Components:" and "Can be part of:".
* The registerComponents() method is called during initialization.
* Set up components like this:
* <pre class="display"><code class="language-javascript">MyGame.createAsset({
* class: "Sink",
* name: "sink",
* place: { in: "Bathroom" },
* descriptions:{
* look: function()
* {
* return "A pedestal sink with porcelain handles and
* a stainless steel faucet. Its drain appears to be
* { sink drain [is] open [or] closed }. ";
* }
* },
* components: [
* // each of these is a name of another Asset
* "hot water handle",
* "cold water handle",
* "faucet",
* "drain",
* "plug"
* ],
* });
* </code></pre>
* @var {Array} adventurejs.Tangible#components
* @default []
*
*/
this.components = [];
/**
* When components are linked, a reference to each is saved here.
* @var {Object} adventurejs.Tangible#linked_components
* @default {}
*/
this.linked_components = {};
/**
* If this asset is a linked component of another asset,
* keep a reference to the parent asset.
* @var {Object} adventurejs.Tangible#linked_parent
* @default ""
*
*/
this.linked_parent = "";
/**
*
* @var {Object} adventurejs.Tangible#linkableClasses
* @default {}
*
*/
this.linkableClasses = {};
this.place = {};
} // function Tangible(id)
// PROTOTYPE DEFINED PROPERTIES
/*doc@this*/
get components() {
return this._components;
}
set components(arr) {
this._components = A.validateAssetList(arr);
}
/**
* Get a string representing open / closed state of this asset.
* @var {Boolean} adventurejs.Tangible#print_open_or_closed
* @default false
*/
get print_open_or_closed() {
var state = "neither open nor closed";
if (this.is.closed) state = "closed";
if (false === this.is.closed) state = "open";
return state;
}
/**
* Get / set place. The private var _place is an
* object with two properties: aspect and asset.
* For example: { aspect:"in", asset:"room" }
* However, the public var place appears in the form
* { in: "room" }. This is to make it easier and more
* intuitive for authors to set asset places.
* @var {Object} adventurejs.Tangible#place
*/
get place() {
return { [this._place.aspect]: this._place.asset };
}
set place(value) {
var newplace = { asset: "", aspect: "" };
if (Object(value) !== value) {
let msg = `[Tangible.js] ${this.id}.place received no value. Setting no place. `;
this.game.log("L1405", "warn", "critical", msg, "Tangible");
} else {
// for some reason world.copy was returning {"":"","key":"value"}
// so we need to delete the empty string key
delete value[""];
var keys = Object.keys(value);
if (value.asset && value.aspect) {
// received for example: { aspect:"in", asset:"room" }
// serialize asset name
newplace.aspect = value.aspect;
newplace.asset = A.serialize(value.asset);
} else if (keys.length === 0) {
} else if (keys.length === 1) {
// received for example: { in: "room" }
// verify asset
if ("string" !== typeof value[keys[0]]) {
let msg = `[Tangible.js] ${this.id}.place set to an invalid asset `;
this.game.log("L1406", "error", "critical", msg, "Tangible");
}
// serialize asset name
newplace.asset = A.serialize(value[keys[0]]);
newplace.aspect = keys[0];
} else if (keys.length > 1) {
newplace.asset = value[keys[0]];
newplace.aspect = keys[0];
let msg = `[Tangible.js] ${this.id}.place received more than one location. Using the first. `;
for (var i = 0; i < keys.length; i++) {
msg += keys[i] + ": " + value[keys[i]] + ", ";
}
this.game.log("L1407", "error", "critical", msg, "Tangible");
}
}
if (
this._place &&
this._place.asset &&
this._place.aspect &&
(this._place.asset !== newplace.asset ||
this._place.aspect !== newplace.aspect)
) {
this.game
.getAsset(this._place.asset)
.removeAssetAt(this.id, this._place.aspect);
}
if (
newplace.asset &&
newplace.aspect &&
this.game.getAsset(newplace.asset)
) {
let parent = this.game.getAsset(newplace.asset);
parent.addAssetAt(this.id, newplace.aspect);
if (parent.hasClass("Character")) {
parent.knowAsset(this, true);
parent.seeAsset(this, true);
}
}
this._place = newplace;
}
/**
* <strong>Contains</strong> is a shortcut for creating
* a substance container and filling it with an infinite
* amount of a specified substance.
* It is the equivalent of this code:
* <pre class="display"><code class="language-javascript">this.aspects.in = new adventurejs.Aspect( "in", this.game_name, this.id );
* this.aspects.in.vessel = new adventurejs.Vessel( "in", game_name, this.id )
* .set({
* "volume": Infinity,
* "maxvolume": Infinity,
* "substance_id": substance_id,
* });
* </code></pre>
* <br><br>
* This is to make it easier and more
* intuitive for authors to set things like sand
* in a desert room or water in a swamp room, so that
* if player inputs "fill bowl with water", it can be
* assumed that the room is the source of the substance.
* When multiple substance containers are available,
* usually disambiguation occurs, but in the case of a
* room containing a substance, the room is assumed to
* be the source.
* @var {Object} adventurejs.Tangible#contains
*/
get contains() {
if (this.hasVesselAtAspect("in")) {
return this.aspects.in.vessel.substance_id;
}
return "";
}
set contains(params) {
if ("string" === typeof params) {
params = { substance_id: params };
}
if (!params) params = {};
if (!params.substance_id) {
params.substance_id = "";
}
if (!params.maxvolume) params.maxvolume = Infinity;
if (!params.volume) params.volume = Infinity;
if (!params.enabled) params.enabled = true;
this.setVesselAt("in", params);
}
// METHODS
/**
* Inherited from superclass {@link adventurejs.Asset|Asset}.
* Tangible adds validation methods that are used for all Tangible assets,
* including:
* <ul>
* <li>check for implied dependencies and make them explicit</li>
* <li>check for proper asset location</li>
* <li>set parent associations</li>
* </ul>
*
* @memberOf adventurejs.Tangible
* @method adventurejs.Tangible#validate
* @param {Object} game
* @returns {Boolean}
*/
validate(game) {
super.validate(game);
// Validate place. Many tangibles, generally globals, have no place,
// and that's valid, but if it does have a place, ensure that it refers
// to a valid asset.
if (this._place.asset) {
var place_asset, place_aspect;
place_aspect = Object.keys(this.place)[0];
place_asset = this.game.getAsset(A.serialize(this._place.asset));
// is place_object a tangible game asset?
if (!place_asset || !(place_asset instanceof adventurejs.Tangible)) {
let msg = `[Tangible.js] ${this.name}'s place ${this._place.asset} is unset or invalid. `;
this.game.log("L1408", "error", "critical", msg, "Tangible");
return false;
}
// has place had an Aspect instantiated?
if (
!place_asset.hasAspectAt(place_aspect) ||
!place_asset.getAspectAt(place_aspect).class
) {
place_asset.aspects[place_aspect] = new adventurejs.Aspect(
place_aspect,
this.game_name,
place_asset.id
);
let msg = `[Tangible.js] ${this.constructor.name} ${this.name}'s container, ${place_asset.name}.${place_aspect}, was not set. A new Aspect has been constructed for ${place_asset.name}.${place_aspect}. `;
this.game.log("L1409", "log", "high", msg, "Tangible");
}
}
// has it got no location but requires a location?
if (this.location_required && !this.hasPlace()) {
let msg = `[Tangible.js] ${this.name} hasn't got a place.`;
this.game.log("L1465", "error", "high", msg, "Tangible");
return false;
}
return true;
} // validate
/**
* Inherited from superclass {@link adventurejs.Asset|Asset}.
* Tangible adds initialization methods that are used for all
* Tangible assets, including:
* <ul>
* <li>link related assets</li>
* <li>register components</li>
* </ul>
* @memberOf adventurejs.Tangible
* @method adventurejs.Tangible#initialize
* @param {Object} game
* @returns {Boolean}
*/
initialize(game) {
super.initialize(game);
if (this.getPlaceAsset()) {
this.getPlaceAsset().addAssetAt(this.id, this.getPlacePreposition());
}
this.registerComponents.call(this);
this.linkComponents.call(this);
return true;
} // p.initialize
/**
* Remove this asset from the world before calling superclass.destroy.
* @memberOf adventurejs.Tangible
* @method adventurejs.Tangible#destroy
*/
destroy() {
this.setPlace(); // calling without param removes from parent
// in most cases we call the super method first
// in the case of destroy the last thing to happen
// is removing from lookups
super.destroy();
}
}
adventurejs.Tangible = Tangible;
})();