Working With...Nests
Nest is a special class
that acts as containers just for characters. Most entity classes have a
place which is their container, whether that is a room or
another asset. A character's place is always their room, and
their nest is anything they are nested in, within the room.
Anything that a player can get in, on, under, or behind has a nest property.
A couch has a nest that a player can sit on. A bed has a nest that a player
can lie in. A desk or table might have a nest that a player can stand on.
The bed, desk, and table might also have nests for the player to go under or
behind. A bicycle or a car has a nest for sitting. Nests are not limited to
furniture and vehicles. If a tree is climable, it's because that tree has a
nest. Nests can be attached to any asset of
Entity class, which is to
say any physical object in the world. Maybe your game has a shrinking ray
that miniaturizes your player: you can add nests to a teacup, a sock, a
mouse hole, or a syringe that injects the player into Martin Short's
bloodstream.
Demo Game
// WorkingWithNests.js
/* global AdventureJS A WorkingWithNests G */
var G = (WorkingWithNests = new AdventureJS.Game(
"WorkingWithNests",
"WorkingWithNestsContainer"
));
// --------------------------------------------------
// Settings
// --------------------------------------------------
G.settings.set({
display: "inline",
layout: "classic",
title: "Working With Nests",
author: "Ivan Cockrum",
description: "Today we are Working With Nests ",
version: "0.0.1",
debug: {
// general: true,
// verbaction: true,
// verbreaction: true,
// verbphase: true,
// travel: true,
},
log: {
// verbaction: true,
// verbreaction: true,
// verbphase: true,
// travel: true,
// game: true,
// verb: true,
// parser: true,
// all: true,
},
});
// --------------------------------------------------
// Player
// --------------------------------------------------
G.createAsset({
class: "Player",
name: "Explorer",
place: { on: "lounge chair" },
can: { swim: true, foo: true },
});
// --------------------------------------------------
// Rooms
// --------------------------------------------------
G.createAsset({
class: "Room",
name: "beach",
definite_article: "the",
// We're going to set up multiple descriptions for look
// depending on where the player is nested.
descriptions: {
look: {
default: `
Welcome to your day at the beach! Your lounge chair
is flanked by a table with a yellow umbrella, and a
beverage cooler lies
{ beverage cooler [is] open [or] closed } at its foot.
You can reach the table and cooler from the chair.
A tall life guard's chair towers over the scene, and
a small changing tent lies in its shadow,
though you'll have to leave the chair to enter those.
An ornate sand castle has been constructed
a little ways down the beach.
`,
// These are description modifiers. They are called
// when player looks at the room from from these
// viewpoints. Unless you specify otherwise, view
// modifiers are appended to descriptions. We can use
// these keywords to specify how to treat modifiers:
// [append], [prepend], [override]
"from lifeguard's chair": `[override]
The lifeguard's chair looks out over the beach.
{Our} lounge chair and table are mostly hidden beneath
{our} big yellow beach umbrella. {We} can see the changing
tent below {us}, and a sand castle a ways down the beach.
`,
"from sand castle": `[override]
From down here in the miniature castle, everything on the
beach looms large. Your lounge chair and table seem
enormous, and the lifeguard's chair towers over it all.
`,
},
},
exits: {},
contains: "sand",
});
// --------------------------------------------------
// Objects
// --------------------------------------------------
G.createAsset({
class: "Solid",
name: "sand",
description: "It's sand. ",
mixwith: {},
dov: { eat: true },
});
// We're using the longhand method for this chair
// just so you can see what it looks like under the hood.
G.createAsset({
class: "Chair",
name: "lifeguard's chair",
synonyms: ["lifeguard"],
place: { in: "Beach" },
is: { listed: false },
description: `The lifeguard's chair is quite high. `,
doPlayerEnter: `[override]
{We} climb up the lifeguard's chair and take
a seat. The high chair offers quite a wide
view of the beach.
`,
aspects: {
on: {
nest: {
// sit is the default posture for chairs
// but we're setting it just to show
posture: "sit",
position: { x: 0, y: 2, z: 0 },
can: {
sit: true,
stand: true,
},
},
},
// chairs don't have an under aspect by default
// so this will create a new aspect for this chair
under: {
nest: {
posture: "stand",
can: {
sit: true,
stand: true,
lie: true,
},
},
},
},
});
// Here's what that same chair looks like in shorthand.
// G.createAsset({
// class: "Chair",
// name: "lifeguard's chair",
// description: `The lifeguard's chair is quite high. `,
// nests: {
// on_posture: "sit",
// on_position: "0,2,0",
// on_can_sit: true,
// on_can_stand: true,
// under_posture: "stand",
// under_can_sit: true,
// under_can_stand: true,
// under_can_lie: true,
// },
// });
// We're using the longhand method for this chair
// just so you can see what it looks like under the hood.
G.createAsset({
class: "Chair",
name: "lounge chair",
adjectives: ["plastic"],
synonyms: ["straps", "aluminum", "frame"],
place: { in: "Beach" },
is: { listed: false },
description: `
The lounge chair is made of plastic straps
hung on a cheap aluminum frame, but it looks
reasonably comfortable enough.
`,
aspects: {
on: {
nest: {
// sit is the default posture for chairs
// but we're setting it just to show
posture: "sit",
can: {
sit: true,
lie: true,
reach: ["lounge table", "cooler", "beverage cooler"],
},
},
},
},
});
// Here is the shorthand version of this asset's nest settings.
// G.createAsset({
// class: "Chair",
// name: "lounge chair",
// place: { in: "Beach" },
// is: { listed: false },
// description: `
// The lounge chair is made of plastic straps
// hung on a cheap aluminum frame, but it looks
// reasonably comfortable enough.
// `,
// nests: {
// on_posture: "sit",
// on_can_sit: true,
// on_can_lie: true,
// on_can_reach: ["lounge table", "cooler", "beverage cooler"],
// },
// });
G.createAsset({
class: "Table",
name: "lounge table",
adjectives: ["plastic"],
place: { in: "Beach" },
is: { listed: false },
description: `
It's a cheap plastic lounge table with
a central hole for an umbrella.
`,
});
G.createAsset({
class: "Container",
name: "beverage cooler",
place: { in: "Beach" },
description: `
It's a red and white plastic beverage cooler.
`,
adjectives: ["plastic", "red", "white"],
dov: { open: true, close: true },
is: { listed: false, closed: true },
aspects: { on: { list_contents_in_room: true } },
});
G.createAsset({
class: "Potion",
name: "can of Orangina",
article: "a",
place: { in: "beverage cooler" },
is: { closed: true },
description: `It's a can of Orangina. `,
// We're going to use a feature of verb subscriptions,
// and set the verb "drink" to destroy the can
// after the player drinks from it.
// There are a number of different ways to override
// a turn's output. Since we're using then_destroy,
// we're going to use on_destroy for the override.
dov: {
drink: {
then_destroy: true,
on_destroy: function () {
let msg = `
{We} slurp down the Orangina and belch
a big healthy citric burp. The can
politely decomposes, leaving you without
any trash to carry around.
`;
G.overrideOutput(msg);
},
},
},
}); //
G.createAsset({
class: "Entity",
name: "sun umbrella",
synonyms: ["citron"],
adjectives: ["large", "yellow"],
// The lounge table hasn't got an attached aspect,
// but setting anything there will lead to creating one
place: { attached: "lounge table" },
is: { listed: false },
description: `
A large yellow umbrella with the word "Citron" printed
on it provides a modicum of shade to the lounge chair.
`,
});
G.createAsset({
class: "Tent",
name: "changing tent",
place: { in: "Beach" },
is: { listed: false, open: true },
synonyms: [
"curtain",
"curtains",
"string",
"strings",
"cubicle",
"changing area",
],
ajdectives: ["loose"],
description: `
Tent is perhaps too generous a term for this changing area,
which is little more than a curtained cubicle rigged up on strings.
`,
nests: {
in_can_stand: true,
in_can_sit: true,
in_can_lie: true,
in_can_kneel: true,
},
doClose: function () {
G.overrideOutput(
`{We} pull the loose curtain as tightly shut as {we} can for modesty's sake. `
);
},
doOpen: function () {
G.overrideOutput(`{We} swipe open the loose curtain. `);
},
});
// We're going to make a sand castle,
// for which there isn't a good built-in class,
// so we're going to use Entity,
// which lacks many properties that
// have been set for other built-ins.
G.createAsset({
class: "Entity",
name: "sand castle",
adjectives: ["ornate"],
place: { in: "Beach" },
is: { listed: false },
dov: { enter: true, exit: true },
descriptions: {
look: {
default: `
The sand castle is curiously detailed.
It almost seems as if {we} could enter it.
`,
"from sand castle": `[override]
Seen from down here, the sand castle is impressively
detailed. A raised parapet circles the castle, with
battlements atop the towers at the four corners.
`,
},
},
default_aspect: "in",
// we're using the shorthand for nests
nests: {
in_can_stand: true,
in_can_sit: true,
in_can_lie: true,
in_can_kneel: true,
},
// We're going to print custom messages when the player
// enters and exits the sand castle.
doPlayerEnter: `[override]
As {we} approach the sand castle, it appears to grow.
{We} look around – at the lifeguard's chair, the lounge
table and chair – and they appear to be growing as well.
It seems that they are not growing at all, but that {we}
are shrinking. Soon the sand castle towers over {us},
revealing greater detail. A portcullis rises over the
front gate, and {we} step inside a shallow depression
in the face of the castle.
`,
doPlayerExit: `[override]
{We} exit through the castle gate, out onto the
beach sands. The castle seems to shrink behind {us}
with every step, until it's just an ordinary sand
castle once more.
`,
});
G.createAsset({
class: "Bucket",
name: "sand bucket",
synonyms: [],
adjectives: ["plastic"],
place: { in: "Beach" },
description: "It's a plastic sand bucket. ",
in: {
vessel: {
volume: 2000,
substance_id: "sand",
},
},
});
G.createAsset({
class: "Shovel",
name: "sand shovel",
adjectives: ["plastic"],
synonyms: [],
place: { in: "Beach" },
description: "It's a plastic sand shovel. ",
});
// This demo doesn't go so far as to let player
// enter the ocean, but we'll throw in an ocean
// object just to catch player inquiries.
G.createAsset({
class: "Entity",
name: "ocean",
synonyms: ["sea", "water", "lake", "surf", "pond"],
place: { attached: "Beach" },
is: { listed: false },
// dov: { swim: true },
nests: { in_can_swim: true },
description: `
The water looks unseasonably cold. Definitely too
cold for swimming.
`,
// This is a catch all that will print this same failure
// message for any verb the player tries to use on it
print_on_verb_failure: `[override]
The water looks unseasonably cold. {We're} not
inclined to interact with it right now.
`,
// trySwim is a verb action
// If a TRY verb action returns a string,
// that's understood to be a failure, and
// that string will be printed to the player
// and the turn will be ended without
// applying the verb.
trySwim: `
Brr. Though the sun is warm, the water looks entirely too cold. Best {we} stay out of the water today.
`,
// Alternatively, it's also possible to set a
// try verb action to a function. Functions can
// run custom logic and don't necessarily need
// to end the turn.
// trySwim: function () {
// let msg = `
// Brr. Though the sun is warm, the water looks entirely too cold. Best {we} stay out of the water today.
// `;
// G.print(msg);
// return false;
// },
});
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
Nest Shorthand
Nests exist inside Aspects which exist inside Entity assets. Under the hood, they look something like this.
asset: { aspects: { on: { nest: { can: { reach: [] } } } } }
We realize that that is an insane amount of curly braces to keep track of, so we do have a shorthand method.
asset: { nests: { on_can_reach: [] } }
It may not be perfect, but we've squeezed out three sets of curly braces for you.
Can Enter, Exit
Nests can be set so that players can't enter or exit them, which might be useful if you want to strap a player down to a chair.
MyGame.createAsset({
class: "Chair",
name: "interrogation seat",
place: { in: "Prison Cell" },
nests: {
on_can_enter: true,
on_can_exit: false,
},
});
Posture & Position
When a player enters a nest, we can explicitly set their posture, so for instance a chair's posture would be sit, a bed's posture would be lie, a treadmill's posture would be stand.
Assets can have dimensions that allow vertical and horizontal travel within the asset. For example, a tree might allow a player to climb among multiple positions. We can set the default position that the player is given when they enter the nest.
MyGame.createAsset({
class: "Tree",
name: "great redwood",
place: { in: "Endor Forest" },
nests: {
on_posture: "cling",
on_position: { x: 0, y: 1, z: 0 },
},
});
There is an even shorter shortcut for position that you may use if you prefer it.
MyGame.createAsset({
class: "Tree",
name: "great redwood",
place: { in: "Endor Forest" },
nests: {
on_posture: "cling",
on_position: "0,1,0",
},
});
Can [Posture]
In addition to setting a player's posture when they enter a nest, we can control what postures the player can assume while in the nest.
MyGame.createAsset({
class: "Chair",
name: "vintage egg chair",
place: { in: "Villain's Lair" },
nests: {
on_can_cling: false,
on_can_float: false,
on_can_hang: false,
on_can_kneel: false,
on_can_lie: false,
on_can_sit: true,
on_can_stand: false,
},
});
Can Reach
A primary consideration of nests is what the player can reach while they are in one. By default, a player in a nest can not reach assets outside of that nest, unless specified otherwise. Here is a shorthand method to specify what is reachable from a nest.
MyGame.createAsset({
class: "Ladder",
name: "ladder",
place: { in: "Library" },
nests: {
on_can_reach: ["bookshelves"]
},
});
Can [Sense]
Nests can be set to deprive players of sensations while they are in them. For example, a sensory deprivation tank might prevent a player from seeing or hearing anything.
MyGame.createAsset({
class: "Chair",
name: "deprivation tank",
place: { in: "" },
nests: {
in_can_hear: false,
in_can_see: false,
in_can_feel: false,
in_can_smell: false,
in_can_taste: false,
},
});
Nest Longhand
You can write out nests in the full longhand style if you prefer. This is the format that is used under the hood.
MyGame.createAsset({
class: "Chair",
name: "lifeguard's chair",
description: `The lifeguard's chair is quite high. `,
aspects: {
on: {
nest: {
// sit is the default posture for chairs
// but we're setting it just to show
posture: "sit",
position: { x:0, y:2, z:0 },
can: {
sit: true,
stand: true,
},
}
},
// chairs don't have an under aspect by default
// so this will create a new aspect for this chair
under: {
nest: {
posture: "stand",
can: {
sit: true,
stand: true,
lie: true,
},
},
},
},
});
For comparison's sake, here's that same chair using shorthand.
MyGame.createAsset({
class: "Chair",
name: "lifeguard's chair",
description: `The lifeguard's chair is quite high. `,
nests: {
on_posture: "sit",
on_position: "0,2,0",
on_can_sit: true,
on_can_stand: true,
under_posture: "stand",
under_can_sit: true,
under_can_stand: true,
under_can_lie: true,
},
});
Further Reference
- Nest class in Reference Manual
- Aspect class in Reference Manual
- Working with Aspects
- Asset.isAspect() Functions in Author's Manual.