Working With...Area Events
Area events are snippets of text that can be set to print on every turn, or random turns, or every x number of turns. They are intended to provide ambient texture. Area events are subject to String Array Function, which means they can be set to provide a range of results.
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
String Array Function
Area events are subject to String Array Function, which means they can be set to provide responses in a variety of ways.
String
To start with, here is the very simplest version of creating an area event
for a room by setting area_events to a single string.
MyGame.createAsset({
class: "Room",
name: "Southern Dunes",
area_events: "Sands shift beneath your feet. ",
Shorthand Array
That string will be appended to the game's output for every turn that the
player is in this room. But that's pretty boring. We want to set a variety
of responses so that each turn prints a different one. We can do that by
setting
area_events to an array of strings.
MyGame.createAsset({
class: "Room",
name: "Southern Dunes",
area_events: [
"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. ",
],
});
Longhand Array
Those messages will print one every turn that the player is in the room. But that seems like it might be too much distracting text. Maybe we only want a message to print once in a while. We can control that by providing our array in the full longhand format, which offers more granular control over the order of events and their chance of occurring.
MyGame.createAsset({
class: "Room",
name: "Southern Dunes",
area_events: {
chance: 0.1, // infrequently
randomize: true, // vs each in order
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. ",
],
},
});
When you provide a shorthand array, it gets automatically converted to a
longhand array format under the hood, using global settings to set
chance and randomize. Setting an array this way
basically just means pre-empting the conversion process. The
chance setting sets the odds of a message printing
per turn. The way that odds work, this means that a value of 0.1
has a 1 in 10 chance of printing a message per turn, but
not that it will print 1 time in 10. Rolling the dice with 0.1
odds, a message might print 3 turns in a row or might not print for 20
turns.
Function
area_events can be set to a function. This means you can
provide dynamic results. For instance, if you had a day/night cycle, you
might set a function to print a different set of events during day and
night.
MyGame.createAsset({
class: "Room",
name: "Southern Dunes",
area_events: function(){
if( MyGame.getVar(is_night) ) { // using a world variable
return A.FX.pickRandom([ // utility method for randomizing an array from within a function
`An incredible tapestry of stars flares overhead. `,
`A meteor streaks across the sky. `,
`Moonlight shimmers across the dunes. `,
]);
}
else {
return A.FX.pickRandom([
`The blazing sun bakes the desert floor. `,
`Heat haze shimmers across the dunes. `,
`Random grains of sand sparkle with reflected sunlight. `,
]);
}
},
});
Zones
Rooms can subscribe to zones, which have their own area events, which allows every rooms in the zone to share common events.
MyGame.createAsset({
class: "Room",
name: "Southern Dunes",
zone: "Desert Zone"
});
MyGame.createAsset({
class: "Room",
name: "Northern Dunes",
zone: "Desert Zone"
});
MyGame.createAsset({
class: "Zone",
name: "Desert Zone",
area_events: {
chance: 0.1, // infrequently
randomize: true, // vs each in order
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. ",
],
},
});
Enable / Disable
Area events can be enabled and disabled during gameplay by setting
game.settings.enable_area_events, which means that you can turn
them on and off in response to other game states.
MyGame.settings.set({
enable_area_events: true,
});
Further Reference
- Working with Area Scenery
- Working with Area Zones
- enable_area_events in Settings
- String Array Function in Author's Manual
- Room class in Reference Manual
- Zone class in Reference Manual