Working With...Aspects
Aspect is the term we use for the parts of an asset that holds other assets,
whether that's a surfaces or a container. Our primary five* aspects are:
in, on, under, behind,
attached. Any tangible asset can have aspects. For example, a pot
might have an in aspect, which contains water. A table might have
an on aspect, which holds papers. All rooms have an
in aspect, which holds everything in the room, including the
player. Assets can also have multiple aspects. For example, a bed might have
an on aspect and also an under aspect. In short,
aspects are how we put things in things.
* Aspects aren't limited to the core five. For example you might create an
over aspect to provide a response to player input like
look over wall.
Demo Game
// WorkingWithAspects.js
/* global AdventureJS A WorkingWithAspects G */
var G = (WorkingWithAspects = new AdventureJS.Game(
"WorkingWithAspects",
"WorkingWithAspectsContainer"
));
// --------------------------------------------------
// Settings
// --------------------------------------------------
G.settings.set({
display: "inline",
layout: "classic",
title: "Working With Aspects",
author: "Ivan Cockrum",
description: "Today we are Working With Aspects ",
version: "0.0.1",
debug: {
general: true,
},
log: {
all: true,
},
});
// --------------------------------------------------
// Player (and their pen)
// --------------------------------------------------
G.createAsset({
class: "Player",
name: "Explorer",
place: { in: "Aspects Laboratory" },
});
G.createAsset({
class: "Pen",
name: "pen",
place: { in: "Explorer" },
description: `
Just an ordinary, everyday fountain pen. My pen. My pen!
`,
});
// --------------------------------------------------
// Rooms
// --------------------------------------------------
G.createAsset({
class: "Room",
name: "Aspects Laboratory",
description: function () {
let msg = `
Welcome to the Aspects Demo. Each of the objects here
features various types of aspects. A control studded
{a:console} stands near one wall of the room.
Against the wall opposite is a beaten {a:chesterfield sofa}.
At the very center of the room lies a {a:round platform}.
Floating over the platform is a {a:featureless gray cube},
which appears to be slowly rotating on one axis. ${items()}
`;
return msg;
},
});
// --------------------------------------------------
// Console
// --------------------------------------------------
G.createAsset({
class: "Desk",
name: "console",
synonyms: ["control", "control"],
adjectives: ["studded"],
place: { in: "Aspects Laboratory" },
is: { listed: false },
description: `
The console has various controls and blinking lights
that we're not going to get into in this demo.
More importantly, the console's surface features
a bisected platform that looks a bit like a dual-deck
turntable, which looks like it can hold two items.
Below the console is a cabinet, currently
{cabinet[is]open[or]closed}.
`,
// The Desk class comes with an "on" aspect
// predefined, but we want to limit the number
// of assets that can be placed on the console.
aspects: {
on: {
capacity: { count: 2 },
},
// We're going to attach the cabinet to the console,
// and setting list_contents_in_examine to false
// prevents the cabinet from being listed in the
// console's description.
attached: {
list_contents_in_examine: false,
},
},
});
// The Cabinet class has an "in" aspect which isn't
// limited to any particular assets or classes,
// so a player can put all the strangelets in here.
G.createAsset({
class: "Cabinet",
name: "cabinet",
adjective: "console",
place: { attached: "console" },
// is_closed: true is a shortcut to is: { closed: true }
// any is.property can be set this way
is_closed: true,
});
// --------------------------------------------------
// Chesterfield sofa
// --------------------------------------------------
G.createAsset({
class: "Couch",
name: "chesterfield sofa",
place: { in: "Aspects Laboratory" },
description: `
One wall of the lab is dominated by an oxblood red
leather chesterfield sofa. Its many missing buttons
attest to its frequent use as an improvised bed.
`,
});
G.createAsset({
class: "Paper",
name: "crumpled sheet of paper",
synonyms: ["tesseract", "scratches", "scrawls", "sheet", "drawing"],
description: `
The crumpled sheet of paper bears various
scratches and scrawls. Chief among them is what
appears to be a crude drawing of a tesseract.
`,
place: { under: "chesterfield sofa" },
});
// --------------------------------------------------
// Round platform
// --------------------------------------------------
G.createAsset({
class: "Entity",
name: "round platform",
place: { in: "Aspects Laboratory" },
description: function () {
let msg = `
The center of the room is filled by a broad round
platform dressed up with blinky sci-fi lights like
a right proper Star Trek prop. A featureless gray
cube floats over the platform. ${items()}
`;
return msg;
},
aspects: ["over"],
// Prevent the platform being listed as inventory
// because we're mentioning it in the room description.
is: { listed: false },
});
// --------------------------------------------------
// Featureless cube
// --------------------------------------------------
G.createAsset({
class: "Entity",
name: "featureless cube",
adjectives: ["gray", "grey"],
description: function () {
let msg = `
There is a featureless gray cube here, floating above the floor
and slowly rotating on one axis. The cube appears to be solid,
and yet, through some strange trick of perspective, it also appears
to be hollow, as you can see the inside of it. ${items()}
`;
return msg;
},
// We're going to limit each aspect of this cube
// to only permit one specific asset.
aspects: {
in: { accepts_assets: ["plumbus"] },
on: { accepts_assets: ["voorheer"] },
under: { accepts_assets: ["beznat"] },
behind: { accepts_assets: ["armunk"] },
attached: { accepts_assets: ["chipler"] },
over: { accepts_assets: ["schmigibo"] },
},
place: { over: "round platform" },
// We're using Entity class for this object,
// which doesn't support "put in" and "take from"
// so we need to add those.
iov: ["put", "take"],
is: { listed: false },
});
// We want to use a bit of dynamic text to describe
// the items in proximity to the cube. We want to do
// it in a couple of places, so we've made a small
// custom function to handle it.
const items = function () {
let msg = "";
const l = G.$("featureless cube").getAllNestedContents().length;
switch (l) {
case 0:
// No text
break;
case 1:
msg += `An item is positioned near the cube, floating relative to it. `;
break;
default:
// Anything more than 1
msg += `Some items are positioned near the cube, floating relative to it. `;
break;
}
return msg;
};
// --------------------------------------------------
// Custom class
// --------------------------------------------------
// We're going to create a custom class
// for the items in the cube
G.createClass({
extend: "Entity",
class: "Strangelet",
// We're going to add some verb subscriptions.
// Our Strangelet class extends Entity, which
// only has a few basic verbs. Strangelets will
// need at least put and take.
// This is a shorthand for adding verb subscriptions
// to a custom class.
//
dov: ["put", "take"],
// This also works.
//
// dov: {
// put: true,
// take: true,
// },
// If you want to customize the verb subscription,
// use the longhand form.
//
// dov: {
// put: { on_failure: `You totally failed to put the thing. ` },
// take: { on_first_success: `You took the thing! ` },
// },
});
// --------------------------------------------------
// Strangelets
// --------------------------------------------------
G.createAsset({
class: "Strangelet",
name: "plumbus",
place: { in: "featureless cube" },
description: `
Looking at the plumbus, somehow {we} just know
that it can only fit <em>in</em> the featureless cube.
`,
});
G.createAsset({
class: "Strangelet",
name: "voorheer",
place: { on: "featureless cube" },
description: `
Somehow the voorheer communicates to {us} that
it is only meant to go <em>on</em> the featureless cube.
`,
});
G.createAsset({
class: "Strangelet",
name: "armunk",
place: { behind: "featureless cube" },
description: `
Ah, the armunk. The armunk, a little voice in {our} tells us,
can only be placed <em>behind</em> the featureless cube.
`,
});
G.createAsset({
class: "Strangelet",
name: "beznat",
place: { under: "featureless cube" },
description: `
{Our} dear old grandmother had a beznat once. {We} remember
that it could only ever be placed <em>under</em> the featureless cube.
`,
});
G.createAsset({
class: "Strangelet",
name: "chipler",
place: { attached: "featureless cube" },
description: `
Chipler, {our} dear chipler. It must only be <em>attached</em>
to the featureless cube.
`,
});
G.createAsset({
class: "Strangelet",
name: "schmigibo",
place: { over: "featureless cube" },
description: `
Why did {we} even get this schmigibo, anyway?
All it does is hover <em>over</em> the featureless cube.
`,
});
Demo Source files
Right-click and choose "Save as..." to download source files.
Notes:
- Demo games are set to a small size to fit doc pages. They can easily be enlarged via display settings.
- Demo games all use the same theme. Colors and fonts can be changed via custom CSS.
- Demo games don't include the core AdventureJS code. To run downloaded games locally, you'll need to also download copies of the core JS and CSS and set up this local folder structure.
AdventureJS └── js | └── adventure.js └── css | └── adventurejs.css └── games ├── demogame01 ├── demogame02 └── demogame03
Aspect Shorthand
Before we get into the details, know that there is a very brief shorthand method for adding aspects to assets. (Keep in mind that many asset classes have aspects predefined.)
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: [ "in", "on" ],
});
That one line, aspects: [ "in", "on" ], will add
in and on aspects to an asset, with all of an
aspect's
default properties
(we'll get into how to configure those in the next sections).
Basic Aspect Longhand
Using the longhand method, here's the very minimum needed to define an aspect. Most built-in asset classes already have aspects defined, but you never know when you'll want to create your own.
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: { in: true },
});
By setting aspects: { in: true }, we're creating an
in aspect that we can put other assets in. Here's how to put
another asset in an aspect.
MyGame.createAsset({
class: "Gem",
name: "diamond",
place: {in: "treasure chest"},
});
The form of place: {in: "treasure chest"} is how we store an
asset's place under the hood, but there are a couple of alternative
shorthands that you may use if you prefer.
This version uses place: "treasure chest". Since this shorthand
does not specify an aspect, AdventureJS will use the chest's default aspect.
Most built-in classes already have default aspects. If you're making your
own custom classes and using this shorthand, just be sure that your classes
have a default_aspect property.
MyGame.createAsset({
class: "Gem",
name: "diamond",
place: "treasure chest",
});
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
default_aspect: "in",
});
This version uses in: "treasure chest". Most built-in classes
already have aspects where you'd expect them to be. If you try to place an
asset in an aspect that doesn't exist on its target, one will be created
during game startup.
MyGame.createAsset({
class: "Gem",
name: "ruby",
// this only works for the five primary aspects: in, on, under, behind, attached
in: "treasure chest",
});
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
aspects: [in],
});
Aspect Settings
Next we'll get into the granular details of controlling an aspect's
behavior. In the example above where we set
aspects: { in: true }, we're creating an in aspect
with default settings. An aspect's settings allow you to control these
properties:
accepts_assets
Specify only particular assets to be allowed in this aspect. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
accepts_assets: [ "ruby", "diamond", "emerald" ],
}
},
});
accepts_classes
Specify only certain classes to be allowed in this aspect. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
accepts_classes: [ "Gem", "Coin" ],
}
},
});
capacity
Specify capacity limits for assets placed in this aspect, including height, width, depth, quantity, and weight. For each property, -1 means infinite, aka no limits. These limits control what the player can put into the aspect, but not what the author can put in. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
capacity: {
height: 2,
width: 4,
depth: 3,
count: 20,
weight: 100,
},
}
},
});
excludes_assets
Specify particular assets that are not allowed in this aspect, so for instance accept class Gem, but not certain gems. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
excludes_assets: [ "coal", "stone" ],
}
},
});
excludes_classes
Specify certain classes to exclude from this aspect, for instance to say we don't want anything Edible to be placed in this chest. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
excludes_classes: [ "Edible" ],
}
},
});
know_contents_with_parent
Whether the contents of the aspect become known when the player knows the asset. By default, when an asset becomes known to a player, its contents also become known (unless inside a closed container). You might not want nested assets known until the player examines the asset. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
know_contents_with_parent: false,
}
},
});
list_contents_in_examine
Whether the contents of the aspect are listed when a player examines the asset. By default, examining an asset also list its contents, but there may be cases where you don't want that behavior, such as when nested assets are attached to the main asset and already mentioned in the asset description, like this desk/bench combo. [More info...]
MyGame.createAsset({
class: "Desk",
name: "student desk",
place: "Classroom",
description: "It's an old-fashioned lift top school desk with an attached bench."
aspects: {
attached: {
list_contents_in_examine: false,
}
},
});
MyGame.createAsset({
class: "Chair",
name: "bench",
place: { attached: "student desk" },
});
list_contents_in_room
Whether the contents of the aspect are listed in the room description. This is useful for things that are baked into the room description. For example, imagine a typewriter on a desk that is included in the room description, so that you don't want it listed among the room's inventory. [More info...]
MyGame.createAsset({
class: "Desk",
name: "office desk",
place: "Accounts Office",
description: "The desk is dominated by an old Corona typewriter. "
aspects: {
on: {
list_contents_in_room: false,
}
},
});
MyGame.createAsset({
class: "Typewriter",
name: "Corona typewriter",
on: "office desk",
});
nest
Whether the player can enter the aspect. Players can't automatically enter aspects. Add a nest to allow a player to enter an aspect. For instance, a bathtub might need a nest so a player can enter it, but a bathroom sink probably would not. Nests have their own set of properties for managing how players can interact with them. [More info...], also see Working with Nests
MyGame.createAsset({
class: "BasicBathtub",
name: "obsidian tub",
place: "Bathroom",
aspects: {
in: {
aspects: { in: { nest: { can: { enter: true } } } }
}
},
});
orientation
Whether the aspect is horizontal or vertical. Aspect orientation is horizontal by default, but can be set to vertical. Currently this has no impact on aspect contents, but it may in the future. [More info...]
MyGame.createAsset({
class: "Tree",
name: "giant redwood",
place: "Muir Woods",
aspects: {
on: {
orientation: "vertical",
}
},
});
player_can_add_contents
Whether the player can add assets to the aspect. By default, players can add objects to aspects, unless limited by other options, but that can be disabled with this option. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
player_can_add_contents: false,
}
},
});
player_can_remove_contents
Whether the player can remove assets from the aspect. By default, players can remove objects from aspects, unless limited by other options, but that can be disabled with this option. This is useful for attached assets, such as the drawers of a desk. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
player_can_remove_contents: false,
}
},
});
see_contents_with_parent
Whether the contents of the aspect become seen when the player sees the asset. By default, when an asset is seen by a player, its contents also become seen (unless inside a closed container). You might not want nested assets seen until the player examines the asset. [More info...]
MyGame.createAsset({
class: "Chest",
name: "treasure chest",
place: "Treasure Room",
aspects: {
in: {
see_contents_with_parent: false,
}
},
});
vessel
Whether the aspect can contain substances. Aspects don't automatically handle substances. They need a Vessel attached to them. Vessels have their own set of properties for managing contents and quantities. [More info...]
MyGame.createAsset({
class: "DrinkingGlass",
name: "water glass",
place: "Bathroom",
aspects: {
in: {
vessel: { volume: 250, substance_id: "water" },
}
},
});
If an author tries to create an aspect on a class that already has one, the existing aspect will be used, but any settings set by the author will be applied to it.
Further Reference
- Asset.isAspect() Functions in Author's Manual
- Aspect class in Reference Manual