Working With...Area Scenery
Area scenery are assets of class Scenery that are created automatically for all games, which exist to provide a description of non-interactable scenery, like the sun, or stars, or a distant mountain range. There are also scenery assets for non-existent exits that can be used to provide responses to players when they try to travel in a direction that doesn't exist. Scenery assets can be set singular, meaning they're only present in one room, or global, meaning they're available in every room.
Demo Game
// WorkingWithAreas.js
/* global AdventureJS A Game */
var WorkingWithAreas = new AdventureJS.Game(
"WorkingWithAreas",
"WorkingWithAreasContainer"
);
// --------------------------------------------------
// Settings
// --------------------------------------------------
WorkingWithAreas.settings.set({
display: "inline",
// layout: "classic",
title: "Working With Areas",
author: "Ivan Cockrum",
description: "Today we are working with areas",
version: "0.0.1",
});
// --------------------------------------------------
// Widgets
// --------------------------------------------------
// Create the widget.
let messages = WorkingWithAreas.createWidget({
class: "Message",
id: "MyMessageWidget",
cssclasses: [],
region: "header",
// title: "Messages",
});
messages.print(`
<div class="message-container">
<div class="day_night">
<span class="day circle"></span>
<span class="night circle"></span>
</div>
<div class="text">
This demo uses Area features: Zones,
Scenery, and Events. In each room, try <i>listen</i>,
<i>x ground</i>, <i>x sun</i>, <i>x sky</i>, <i>x air</i>
to see area scenery defined by room, zone, and game-wide.
The sun rises and falls every 10 turns, changing some scenery.
(And FYI this box is a <a href="/doc/Widgets_MessageWidgets.html">Message Widget</a>. )
</div>
</div>
`);
// --------------------------------------------------
// Player
// --------------------------------------------------
WorkingWithAreas.createAsset({
class: "Player",
name: "Explorer",
place: { in: "Foothills" },
});
// --------------------------------------------------
// Rooms
// --------------------------------------------------
// FOOTHILLS
// The foothills aren't subscribed to any zone and don't
// have individual area settings, so they'll just inherit
// whatever area properties we define globally via setAreaScenery().
WorkingWithAreas.createAsset({
class: "Room",
name: "Foothills",
// definite_article: "the",
the: "the", // shorthand for definite_article
description: `
This room uses the game-wide Area Scenery defined
via the <code>game.setAreaScenery()</code> method.
<br/>
<hr>
The foothills form a transitional landscape between
the southern desert and the northern mountains.
A cavernous entrance leads down to an underground
cavern beneath the rising slopes.
`,
exits: {
down: "Cavern",
northeast: "Northeastern Mountains",
northwest: "Northwestern Mountains",
south: "Southern Desert",
southeast: "Southeastern Desert",
southwest: "Southwestern Desert",
},
});
// NORTHEASTERN MOUNTAINS
// Subscribed to the Mountain Zone
WorkingWithAreas.createAsset({
class: "Room",
name: "Northeastern Mountains",
zone: "Mountain Zone",
description: `
This room uses the Area Scenery defined in
the Mountain Zone.
<br/>
<hr>
This is the Northeastern Mountains room.
`,
exits: {
southwest: "Foothills",
west: "Northwestern Mountains",
},
});
// NORTHWESTERN MOUNTAINS
// Subscribed to the Mountain Zone
WorkingWithAreas.createAsset({
class: "Room",
zone: "Mountain Zone",
name: "Northwestern Mountains",
description: `
This room uses the Area Scenery defined in
the Mountain Zone.
<br/>
<hr>
This is the Northwestern Mountains room.
`,
exits: {
southeast: "Foothills",
east: "Northeastern Mountains",
},
});
// SOUTHERN DESERT
// Subscribed to the Desert Zone
WorkingWithAreas.createAsset({
class: "Room",
name: "Southern Desert",
zone: "Desert Zone",
description: `
This room uses the Area Scenery defined in
the Desert Zone.
<br/>
<hr>
This is the Southern Desert room.
`,
exits: {
north: "Foothills",
east: "Southeastern Desert",
west: "Southwestern Desert",
},
});
// SOUTHEASTERN DESERT
// Subscribed to the Desert Zone
WorkingWithAreas.createAsset({
class: "Room",
name: "Southeastern Desert",
zone: "Desert Zone",
description: `
This room uses the Area Scenery defined in
the Desert Zone.
<br/>
<hr>
This is the Southeastern Desert room.
`,
exits: {
northwest: "Foothills",
west: "Southern Desert",
},
});
// SOUTHWESTERN DESERT
// Subscribed to the Desert Zone
WorkingWithAreas.createAsset({
class: "Room",
name: "Southwestern Desert",
zone: "Desert Zone",
description: `
This room uses the Area Scenery defined in
the Desert Zone.
<br/>
<hr>
This is the Southwestern Desert room.
`,
exits: {
northeast: "Foothills",
east: "Southern Desert",
},
});
// CAVERN
// Has no zone, so we are going to define area properties
// for just this one room. Depending on how you prefer to
// organize code, you might prefer to make a zone for one
// room – that works too.
WorkingWithAreas.createAsset({
class: "Room",
name: "Cavern",
the: "the",
synonyms: ["underground"],
description: `
This room uses Area Scenery defined only for this room.
<br/>
<hr>
This is the Cavern room.
`,
exits: {
up: "Foothills",
},
area_scenery: {
floor: {
enabled: true,
description:
"The ground here is dry and powdery; beneath the accumulated powder, solid stone. ",
},
air: {
enabled: true,
description:
"The air here is chill, but dry, with only the barest hint of mildew. ",
},
sound: {
enabled: true,
description:
"The cavern is brutally silent, like the interior of a mausoleum. ",
},
sky: {
enabled: true,
description: "No trace of the sky can be seen from this deep cavern. ",
},
// For sun, we're using a function that checks our custom is_day var
// to see whether it's day or night, and returns a different
// description, depending. We use this method extensively
// in the upcoming blocks.
sun: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `All you can see of the sun here is a diffuse glow at the cavern entrance. `;
} else {
return `There's no sun at all. The cave is lit only dimly by the bit of flickering starlight that reaches the cave mouth. `;
}
},
},
},
});
// --------------------------------------------------
// Desert zone
// --------------------------------------------------
WorkingWithAreas.createAsset({
class: "Zone",
name: "Desert Zone",
area_scenery: {
floor: {
enabled: true,
description: "{We} see nothing but endless sand beneath {our} feet. ",
},
sound: {
enabled: true,
description:
"{We} can hear the constant papery whisper of sliding sands. ",
},
air: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The hot dry air sears {our} lungs with every breath. `;
} else {
return `Thankfully {we} can breath comfortably in the cool night air. `;
}
},
},
sky: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The atmosphere is so dry that even the sky seems burnt to a pale ochre. `;
} else {
return `The sky is so crisply clear that we can see the entire night's tapestry of shimmering stars. `;
}
},
},
sun: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The sun burns fiercely, broiling the landscape, and {us}. `;
} else {
return `With the sun down, the temperature has plummeted. The desert's night is blessedly cool. `;
}
},
},
},
area_events: {
chance: 0.1, // rare
randomize: true,
array: [
"Sands shift beneath your feet. ",
"A brief dry breeze does nothing to cool you. ",
"Heat haze shimmers over distant dunes. ",
"A distant hawk's shriek fills the air. ",
"The sun beats down relentlessly. ",
],
},
});
// --------------------------------------------------
// Mountain zone
// --------------------------------------------------
WorkingWithAreas.createAsset({
class: "Zone",
name: "Mountain Zone",
area_scenery: {
// We've deliberately left floor and sound undefined here,
// to show how scenery settings cascade. If a room's setting
// for a scenery is null, it will cascade to the zone, and if
// the zone setting is null, it will cascade to the game
// setting. So, while our zone defines some sceneries, the
// ones that are unset will cascade to the global setting.
// floor: { enabled: true, description: "Nothing but endless sand. " },
// sound: {
// enabled: true,
// description: "A constant dry whisper of shifting sands. ",
// },
air: {
enabled: true,
description:
"The air here is cool and crisp, with just a hint of autumn creeping in. ",
},
sky: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The sky is bright and blue, where you can see it through the overlapping branches of the trees. `;
} else {
return `It's night, and shadowy trees dominate the scene. `;
}
},
},
sun: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The sun is bright here in the mountains, and warms your skin where it filters through the trees. `;
} else {
return `The sun is down, leaving you lost among the dark shadows of the trees. `;
}
},
},
},
area_events: {
chance: 0.1,
randomize: true,
array: [
"A cool breeze rustles through the branches overhead. ",
"Sunlight dances patchily across the pine needled floor. ",
"An eagle shrieks, somewhere overhead. ",
],
},
});
// --------------------------------------------------
// Global scenery
// --------------------------------------------------
WorkingWithAreas.setAreaScenery({
floor: {
enabled: true,
description: `A thin carpet of pine needles covers the ground. `,
},
sound: {
enabled: true,
description: `A mild breeze brushes through the local flora. `,
},
air: {
enabled: true,
description: `The air here is pleasantly crisp. `,
},
sun: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `A bright sun gently warms the area. `;
} else {
return `There's no sun to be seen. `;
}
},
},
sky: {
enabled: true,
description: function () {
if (WorkingWithAreas.getVar("is_day") === true) {
return `The sky lies overhead like an endless blue dome. `;
} else {
return `A sea of stars shimmers overhead. `;
}
},
},
});
// --------------------------------------------------
// Manage day/night cycle
// --------------------------------------------------
// We're setting a game variable to use for day/night tracking.
WorkingWithAreas.setVar("is_day", true);
WorkingWithAreas.setVar("turns", 0);
WorkingWithAreas.startInterval({
id: "WorkingWithAreas",
callback: "turncount",
});
WorkingWithAreas.turncount = function () {
WorkingWithAreas.incVar("turns");
let turns = WorkingWithAreas.getVar("turns");
// every ten turns, toggle day/night
if (turns > 1 && turns % 10 === 0) {
WorkingWithAreas.invertVar("is_day");
let is_day = WorkingWithAreas.getVar("is_day");
let msg = is_day ? `The sun rises. ` : `Night falls. `;
updateClasses(is_day);
WorkingWithAreas.print(msg);
}
};
// We've made this updateClasses function to add/remove
// CSS classes to the HTML element that contains the game,
// which we use to toggle the visibility of the sun and moon.
var updateClasses = function (is_day) {
if (is_day) {
WorkingWithAreas.classList.add("day");
WorkingWithAreas.classList.remove("night");
} else {
WorkingWithAreas.classList.remove("day");
WorkingWithAreas.classList.add("night");
}
};
updateClasses(true);
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.min.js └── css | └── adventurejs.min.css └── games ├── demogame01 ├── demogame02 └── demogame03
Built-in Scenery
AdventureJS has several dozen built-in scenery assets. Scenery settings cascade from room to zone to game, which means that it is possible to customize these assets per room, per zone, or game-wide. Built-in scenery falls loosely into three categories.
PHENOMENA
Phenomena scenery includes basic atmospheric elements like sun, moon and stars; landscape elements like trees, the sea, distant mountains; and common weather elements like rain, clouds, lightning and thunder.
WALLS
Wall scenery can help respond to player input like examine east wall. If a room actually has an east wall, you can describe it; if it doesn't, you can use it to offer a non-response like you don't see any east wall here.
- east wall
- west wall
- north wall
- northeast wall
- northwest wall
- south wall
- southeast wall
- southwest wall
- aft wall
- port wall
- starboard wall
- fore wall
Floor and ceiling are similar to walls but slightly different. If you add a real floor or ceiling to a room, it will automatically override the scenery floor/ceiling.
FALSE EXITS
False exits are only presented in rooms that have no real exits for those directions. They can help respond to players trying to use non-existent exits, such as by returning a list of actual exits for the current room.
Apply Scenery to Room
Here's how to apply built-in scenery to one room.
MyGame.createAsset({
class: "Room",
name: "Wooded Glen",
area_scenery: {
sun: {
enabled: true,
description: `Sunlight filters through swaying branches overhead, creating a patchwork of light and shadow. `,
},
},
});
Apply Scenery to Zone
Our sun example can also be applied to a zone instead of a room, making the sun available to all rooms in the zone. This might be helpful for creating below-ground / above-ground zones.
MyGame.createAsset({
class: "Room",
name: "Wooded Glen",
zone: "Woody Zone",
});
MyGame.createAsset({
class: "Room",
name: "Deep Forest",
zone: "Woody Zone",
});
MyGame.createAsset({
class: "zone",
name: "Woody Zone",
area_scenery: {
sun: {
enabled: true,
description: `Sunlight filters through swaying branches overhead, creating a patchwork of light and shadow. `,
},
},
});
Apply Scenery to World
Finally, it is possible to apply built-in scenery to the entire game world.
This uses a different mechanism: the
game.setAreaScenery() method.
MyGame.setAreaScenery({
sun: {
enabled: true,
description: `Sunlight filters through swaying branches overhead, creating a patchwork of light and shadow. `,
},
});
Remember: local effects always override global effects, meaning that room takes precedence over zone, and zone takes precedence over game. You can enable a scenery asset for the entire game, then customize it for a zone, then customize it further for a specific room.
TMI How Scenery Cascades
This diagram shows how scenery settings cascade from room to zone to game. The game asks these questions for every individual global scenery asset. In short:
-
If
scenery: { enabled:true }, show local value for that level. -
If
scenery: { enabled:false }, show nothing for that level. -
If
scenery: { enabled:null }, cascade to the next level.
Is a scenery present?
↓
ROOM
show false?
none null?
pass
ZONE
show false?
none null?
pass
GAME
show false?
none null?
none
Create New Scenery
Under the hood, scenery assets are actually instances of class
Scenery. Technically, you
can make them the same way you make other class instances using
MyGame.createAsset({}). The scenery method we've been showing
here is a shorthand for managing them, and you can use almost the same
shorthand method to create your own new scenery. This example shows how to
create scenery for use in one room.
MyGame.createAsset({
class: "Room",
name: "Wooded Glen",
area_scenery: {
fireflies: {
description: "Blinking fireflies dot the evening air.",
},
},
This results in a fireflies asset in the Wooded Glen.
Blinking fireflies dot the evening air.
Create New Global Scenery
Scenery assets can appear in multiple rooms, and they can optionally have
different descriptions per room. To make a global scenery asset, we need to
add a couple more properties. In this example, we create a scenery asset and
specify it as
origin and global.
MyGame.createAsset({
class: "Room",
name: "Wooded Glen",
area_scenery: {
fireflies: {
description: "Fireflies dot the forest with fairy lights.",
origin: true, // specify that this is the origin
is: { global: true }, // specify that it's global
},
},
});
Making those fireflies global means that they will automatically appear in every room without any particular settings. By default, they will have the same description they were defined with, but alternatively, we can modify their description per room.
MyGame.createAsset({
class: "Room",
name: "Stony Field",
area_scenery: {
fireflies: {
// give this room its own description for this object
description: "Fireflies hover above the stony field.",
},
},
});
Further Reference
- Working with Area Events
- Working with Area Zones
- Basic Scripting: String Array Function in Author's Manual
- Room class in Reference Manual
- Zone class in Reference Manual