Verb:unlock
Instance of: AdventureJS.Dictionary.Verb
Defined in: Adventure/Dictionary/verbs/unlock.js, line 6
Tutorials: Subscriptions HowAVerbIsBuilt HowAVerbWorks ModifyVerbs
Description
Unlock a Entity Asset. Requires that the lock has asset.dov.unlock.enabled set to true and its is.locked property set to true. If the lock requires a key, verb will soft prompt for one.
tryUnlockThis tryUnlockThisWithThat tryUnlockThatWithThis doUnlockThis doUnlockThisWithThat doUnlockThatWithThisDemo
// OpenDemo.js
// ----------
/*global AdventureJS A OpenDemo*/
var OpenDemo = new AdventureJS.Game("OpenDemo", "OpenDemoContainer");
OpenDemo.settings.set({
// title, version, and author are shown in the title bar
title: "Open Demo",
version: "0.0.1",
author: "Ivan Cockrum",
description: "This is my great game! Thanks for playing!",
// if this is true, lists of exits will
// show the names of rooms they lead to
print_exits_room_names: true,
// if this is true, lists of exits will
// only include room names known to player
print_exits_room_names_if_known: false,
// if this is true, lists of exits will only
// show room names for exits player has used
print_exits_room_names_if_used: false,
// if this is true, verbose room descriptions will be
// shown on first visit regardless of verbosity settings
print_verbose_room_descriptions_on_first_visit: true,
// if this is true, AdventureJS will print
// debug messages to the game display
// debug: { general: true },
responses: {
// set this to set a default response to
// player input that is not understood
no_response: "I have no response to your input. ",
// set this to provide a default
// response to blank input
empty_input: "I didn't see any input. ",
},
// alternately, game can be set to print
// the current room description with
// if_input_is_empty_print_room_description: true
});
// Foyer
OpenDemo.createAsset({
class: "Room",
name: "Open Demo Foyer",
article: "the",
descriptions: {
look: `Welcome to the Open Demo, where you can try opening and closing things, and locking and unlocking and picking locks, with the verbs <a href='/doc/open.html'>open</a>, <a href='/doc/close.html'>close</a>, <a href='/doc/lock.html'>lock</a>, <a href='/doc/unlock.html'>unlock</a>, <a href='/doc/pick.html'>pick</a>. Visit the other rooms in this demo to find some demonstrations. `,
brief: `Try verbs.
<a href='/doc/open.html'>Open</a>,
<a href='/doc/close.html'>close</a>,
<a href='/doc/lock.html'>lock</a>,
<a href='/doc/unlock.html'>unlock</a>,
<a href='/doc/pick.html'>pick</a>. `,
},
exits: {
// This is a shortcut for creating an Exit. It's useful
// for exits that don't have any special properties or
// an Aperture, which is an Exit's physical presence.
east: "Sitting Room",
},
}); // Open Demo Foyer
// Player
OpenDemo.createAsset({
class: "Player",
name: "Tim Hunter",
place: { in: "Open Demo Foyer" },
is: { active: true },
pronouns: "second",
});
// SittingRoom.js
// ----------
/*global AdventureJS A OpenDemo*/
OpenDemo.createAsset({
class: "Room",
definite_article: "the",
name: "Sitting Room",
descriptions: {
look: "The sitting room has many things on which to sit. None of them are objects though, because this is not a sitting demo. I suppose we should have called it an opening room. Shut up about it already! Instead, try opening and closing things: the playground window, the library door, the chest. Oh, did I mention that there's a window and a door? ",
brief: "Don't sit. Window. Door. ",
},
exits: {
west: "Open Demo Foyer",
},
});
// Sitting Room Out
OpenDemo.createAsset({
class: "Exit",
direction: "out",
place: { in: "Sitting Room" },
destination: "Playground",
descriptions: {
label: `out the window to the
<span class='exit-destination'>Playground</span>`,
travel: `{We} climb clumsily out the window and tumble
to the playground, where you land on your bottom on a
soft tuft of grass. `,
},
aperture: "inside window",
});
// Sitting Room Out - Playground Window
OpenDemo.createAsset({
class: "Window",
name: "inside window",
synonyms: ["playground window", "playground"],
descriptions: {
// Note that this code block uses a combination of Javascript
// ${template literals} and AdventureJS {placeholders}.
// ${one} with a dollar sign is a Javascript template literal.
// The {one} without a dollar sign is an AdventureJS custom
// template. These can be used in combination, but there are
// important differences to be aware of.
//
// AdventureJS placeholders are just strings, and they are
// only evaluated right before they are printed to the display.
//
// By contrast, Javascript template literals are essentially
// variables nested inside strings, and they are evaluated by
// the browser immediately when it encounters them. Meaning,
// if it's in a string that is stored as a property, it will be
// evaluated when the game initializes. If you need a template
// literal not be evaluated until it is called, it needs to be
// wrapped in a function that returns it.
//
// See https://adventurejs.com/doc/CustomizeOutput_Placeholders.html
// for more info.
look: function () {
return `
Through the window, {we} can see a child's playground.
Currently the window is
{inside window [is] locked [or] unlocked} and
{inside window [is] open [or] closed}.
${
!OpenDemo.$("inside window").$didDo("unlock")
? `The window locks and unlocks by way of a simple
sash latch that doesn't require any key. `
: ""
}
${
OpenDemo.$("inside window").$is("locked")
? "Try opening the window without first unlocking it. "
: ""
}
${
!OpenDemo.$("inside window").$is("closed")
? `{We} might just climb through it. `
: ""
}
`;
},
// This commented block below is an alternate version.
// It may appear like it should work the same way,
// but because it has a template literal in a string property,
// it would throw an error when the game is launched.
// look: `The window is
// {inside window [is] open [or] closed} and
// {inside window [is] locked [or] unlocked}.
// It locks by way of a simple sash latch that doesn't require any key.
// ${OpenDemo.$('inside window').$is('locked')?
// 'Try entering "unlock window then open it".':''}
// Beyond the window, {we} can see a child's playground. `,
// Here, we've set a description to use if a player
// inputs "look through window".
through: "You can see a small child's playground through the window. ",
// And here, we're redirecting "look out window"
// to "look through window" so we can capture both
// possibilities without duplicating the code.
out: function () {
return this.descriptions.through;
},
},
is: {
closed: true,
locked: true,
},
dov: {
// window.dov.unlock.with_nothing
// allows the window to be unlocked without use of a key.
unlock: {
with_nothing: true,
on_first_success: function () {
if (!this.is.closed) {
// In some circumstances, when a user inputs 'open thing',
// the verb open may redirect to 'unlock thing'. If that
// happened here, we want to account for it by returning
// our custom open.on_first_success function.
return this.dov.open.on_first_success();
} else {
return "{We} should easily be able to open it now. ";
}
},
},
// lock and unlock params have to be set independently.
// This is so that you could, for instance, set it so that
// once the player unlocks it, it can't be locked again.
lock: { with_nothing: true },
open: {
// on_first_success calls this function and
// appends this string to the native verb output,
// only the first time the player opens the window.
on_first_success: function () {
OpenDemo.scorecard.awardPoint("open window");
return "Now that it's open {we} just might climb out of it. ";
},
// on_first_failure only prints a message
on_first_failure: `But it's just a simple sash
latch that doesn't need any key to unlock it. `,
},
},
// This inside window is linked to the outside window.
// Apertures, aka doors and windows, only exist in one room.
// For a door to be in two rooms, we actually need two doors:
// one side in one room, the other side in the other room.
// We handle each side as a unique asset. In order to keep them
// in sync we use the other_side property, so that if one is
// set as open, so is the other one.
other_side: "outside window",
});
// Sitting Room North
OpenDemo.createAsset({
class: "Exit",
direction: "north",
place: { in: "Sitting Room" },
destination: "Library",
descriptions: {
//look: "It looks frosty that way. ",
// listing is a special description for exits,
// that lets authors customize how individual exits
// are described when the player is presented with a
// list of exits.
label:
"through the door north to the <span class='exit-destination'>Library</span>",
},
aperture: "library door",
});
// Sitting Room North Door - library Door
OpenDemo.createAsset({
class: "Door",
name: "library door",
other_side: "sitting room door",
is: {
closed: true,
locked: true,
},
dov: {
//close: true, // already set for all instances of Door class
open: {
on_first_success: function () {
OpenDemo.scorecard.awardPoint("open library door");
return "Now you can enter the Library. ";
},
},
// Note here how we're setting it so the library door can be
// unlocked with the brass key.
unlock: {
with_assets: ["brass key"],
with_nothing: false,
},
// We set the assets for each verb, lock and unlock, explicitly
// because it's common that an author might want a player to
// unlock a door and then never have to interact with it again.
// So if we want the key to also lock the door, we have to say so.
lock: {
with_assets: ["brass key"],
with_nothing: false,
},
},
descriptions: {
look: "A lovely Victorian nine panel oak door with frosted glass and a scuffed brass lock plate. ",
through: function () {
// Here we're setting a description for "look through door"
// that returns a different value depending on whether the
// door is open or closed.
// "through" is what we call an Aspect, along with behind,
// in, on, under, and many other prepositions. Any Aspect
// can have a unique description set this way.
if (!OpenDemo.$("library door").$is("closed")) {
return "Through the open door you can see shelves stuffed with books and books and books. ";
} else {
return "The glass panes in the door's upper half are quite heavily frosted, and don't reveal anything beyond. ";
}
},
},
});
// coffee table
OpenDemo.createAsset({
class: "Table",
name: "coffee table",
place: { in: "Sitting Room" },
description:
"It's a low, rectangular coffee table, apparently hand carved from oak. ",
adjectives: "wood, wooden, carved, oak",
aspects: {
on: {
nest: { can: { enter: false } },
},
},
dov: {
go: {
doBeforeTry: function (params) {
// See how we're using a Verb Hook here. This is a way
// to inject custom code into a verb when it is applied
// to a particular asset. In this case by hooking into
// go.doBeforeTry, we interrupt the verb before it can
// run its default doTry conditional logic,
// and print our own failure message. This basically means:
// we don't care what the default logic has to say; you
// just don't put your fat feet on the fine furniture.
// See /doc/BasicVerbs_PhaseHooks.html for more info.
OpenDemo.print(
"I mean, {we} could, but it would just be rude. ",
"concatenate_output"
);
return false;
},
},
sit: {
// Here, we're setting sit, stand and lie to use
// the same code as go.doBeforeTry. This is one way
// you could apply the same custom logic to multiple
// verbs on an object. There are also other ways to
// achieve similar results, such as unsubscribing
// the asset from these verbs, or using verb actions.
doBeforeTry: function () {
return this.dov.go.doBeforeTry();
},
},
stand: {
doBeforeTry: function () {
return this.dov.go.doBeforeTry();
},
},
lie: {
doBeforeTry: function () {
return this.dov.go.doBeforeTry();
},
},
},
// Here's an example of a verb reaction.
// This will be superceded by the verb phases up above; to see
// it in action you'll have to comment out the verb phases block.
// Verb reactions are called when a particular action occurs,
// such as moving the player onto an asset, regardless of what
// verb caused it; go, or climb, or jump, or sit, or lie.
// Every verb that results in moving the player into a thing
// tries to call thing.doNestThatToThis(player).
// Verb reactions may be common or unique. doNestThatToThis is a
// very common reaction that will be called in numerous circumstances.
// See /doc/BasicVerbs_ActionHooks.html for more info.
doNestThatToThis: {
// Nesting only applies to characters.
// Tim Hunter is the name of our player character in this game.
"Tim Hunter": function () {
this.game.print(
"Whoa there, podner! Let's keep those fat feet off the fine furniture. "
);
return false;
},
},
// Alternately, if you wanted the same verb effect hook to apply to
// all assets, you could define it as a function itself rather
// than creating nested objects. This is also valid.
// In this case, since the doNestThatToThis function is on the
// coffee table, it would prevent all characters from nesting.
// doNestThatToThis: function()
// {
// this.game.print("Whoa there, podner! Let's keep those fat feet off the fine furniture. ");
// return false;
// },
});
// Library.js
// ----------
/*global AdventureJS A OpenDemo*/
OpenDemo.createAsset({
class: "Room",
name: "Library",
definite_article: "the",
descriptions: {
look: `The library is stuffed with books near
to the point of inducing claustrophia. But also cozy?
It's hard to say precisely. {We} scan the
overflowing shelves. Sadly, none of the books are objects.
Instead, take a look at the bureau and its drawers. `,
brief: "Books. Desk. Door south. ",
},
}); // Library
// Sitting Room south Exit
OpenDemo.createAsset({
class: "Exit",
direction: "south",
place: { in: "Library" },
destination: "Sitting Room",
descriptions: {
//look: "A heavy Victorian nine panel oak door with frosted panes. ",
label: "south to the <span class='exit-destination'>Sitting Room</span>",
},
aperture: "sitting room door",
});
// Sitting Room south door
// Exits have no physical properties. In order to apply
// physical properties to an exit, it needs an Aperture.
// Apertures can be manipulated like other entity assets.
OpenDemo.createAsset({
class: "Door",
name: "sitting room door",
other_side: "library door",
descriptions: {
look: "It's a Victorian 9 panel oak door. ",
open: "The sitting room door is open. ",
closed: "The sitting room door is closed. ",
// Assets can have a number of descriptions to use in
// different contexts. Descriptions can be strings or
// arrays or functions. This example shows a function
// that uses native Javascript logic to return a string.
// See /doc/tutorial-Subscription.html for more info.
through: function () {
// This is one way to refer to objects in custom code:
// GameName.$( "asset name" ).is("property")
// See /doc/Scripting_CustomCode.html for more info.
if (!OpenDemo.$("sitting room door").$is("closed")) {
return "Through the open door {we} can see the Sitting Room. ";
} else {
return "{We} can't see anything through the door's frosted panes. ";
}
},
},
is: {
closed: true,
locked: true,
},
dov: {
open: true,
close: true,
unlock: { with_assets: ["brass key"] },
lock: { with_assets: ["brass key"] },
},
});
// bureau desk
OpenDemo.createAsset({
class: "Desk",
name: "bureau desk",
adjectives: ["oak", "wood", "wooden", "substantial"],
synonyms: [],
place: { in: "Library" },
descriptions: {
// Note that this description is an ordinary string property. Elsewhere in this demo
// we're using traditional functions or arrow functions because they include
// Javascript template literals. This example only includes AdventureJS custom
// templates, which do not get evaluated until output, and are safe to use in strings.
// See /doc/CustomizeOutput_Placeholders.html for more info.
look: `
It's a substantial oak bureau desk with multiple drawers stacked vertically,
top, middle and bottom. The top drawer is { top drawer [is] open [or] closed },
the middle drawer is { middle drawer [is] open [or] closed }, and the bottom
drawer is { bottom drawer [is] open [or] closed }. `,
},
aspects: {
on: {
nest: { can: { enter: false } },
},
},
});
// top drawer
OpenDemo.createAsset({
class: "Drawer",
name: "top drawer",
adjectives: ["desk", "scratched"],
synonyms: ["lock", "lock plate", "scratches"],
// Note how we're using top_drawer.description here whereas we've used
// desk.descriptions.look above. All assets can have multiple
// descriptions. Setting asset.description is a shortcut to setting
// asset.descriptions.look, for when an asset only needs one description.
description: `The top drawer's copper lock plate
seems to be particularly scratched up.
Currently the drawer is { top drawer [is] open [or] closed }. `,
place: { attached: "bureau desk" },
is: {
// Note how we're setting known:true here.
// By default, players can't interact with
// assets until they're known.
// Also by default, attached assets don't
// become known until a player examines
// the asset they're attached to.
known: true,
closed: true,
locked: true,
listed: false,
},
dov: {
// AdventureJS treats 'pick' and 'unlock' as distinct verbs.
// If a player tries to use 'unlock' where 'pick' is defined,
// the parser will try to redirect to 'pick'.
pick: { with_assets: ["copper hairpin"] },
// Pick and unlock are distinct verbs, to allow authors to
// create precise situations. But, making them distinct can
// lead to finicky situations that are unpleasant for players.
// It's a fine line. We could either set it so that both verbs
// work the same way:
// unlock: { with_assets: ['copper hairpin'] },
// Or we give the player a hint, if we don't want unlock to work.
unlock: { on_failure: `{We} might be able to pick it with something. ` },
open: {
on_first_failure: "Bet you didn't see that coming, huh? ",
on_first_success: function () {
OpenDemo.scorecard.awardPoint("open top drawer");
//return " ";
},
},
},
});
// middle drawer
OpenDemo.createAsset({
class: "Drawer",
name: "middle drawer",
synonyms: "middle desk drawer",
description: "The middle drawer is { middle drawer [is] open [or] closed }. ",
adjectives: "desk",
place: { attached: "bureau desk" },
is: {
known: true,
closed: true,
listed: false,
},
});
// bottom drawer
OpenDemo.createAsset({
class: "Drawer",
name: "bottom drawer",
synonyms: "bottom desk drawer",
description: "The bottom drawer is { bottom drawer [is] open [or] closed }. ",
adjectives: "desk",
place: { attached: "bureau desk" },
is: {
known: true,
closed: true,
listed: false,
},
});
// drawers collection
// Collections are a special class that allows players to refer
// to a group of objects and try to apply a verb to all of them,
// or get back a combined description.
// See doc/AdventureJS.Assets.Collection.html for more info.
OpenDemo.createAsset({
class: "Collection",
name: "desk drawers",
place: { attached: "bureau desk" },
targets: ["top drawer", "middle drawer", "bottom drawer"],
synonyms: ["drawers", "three drawers"],
is: {
known: true,
listed: false,
},
descriptions: {
look: function () {
var openCount = [];
var closedCount = [];
var msg = "";
msg += `The bureau has three drawers stacked vertically:
top, middle and bottom, each with a copper lock plate.
The top drawer's lock appears to be rather scratched up.
Currently, `;
// Note how we're using 'this' here. Under normal circumstances
// nested properties don't have access to their top level object.
// AdventureJS uses asset.descriptions.look.call(asset)
// to ensure that asset descriptions can refer to their asset.
// Any property that relies on getStringArrayFunction()
// will have 'this' scoped to its parent asset.
// See /doc/BasicScripting_StringArrayFunction.html for more info.
for (var i in this.collection) {
// this.collection contains asset names.
// We want to get references to the asset objects.
// One way to do this is with GameName.$("my asset")
// See /doc/Scripting_CustomCode.html for more info.
let drawer = OpenDemo.$(this.collection[i]);
// Once we have an asset reference, asset.$is(property)
// is a safe way to try to get asset properties.
drawer.$is("closed")
? closedCount.push(drawer.name)
: openCount.push(drawer.name);
}
if (0 === openCount.length) {
msg += "all three drawers are closed.";
} else if (0 === closedCount.length) {
msg += "all three drawers are open.";
} else if (2 == openCount.length) {
msg += `the ${openCount[0]} and ${openCount[1]}
are open, while the ${closedCount[0]} is closed. `;
} else if (2 == closedCount.length) {
msg += `the ${closedCount[0]} and ${closedCount[1]}
are open, while the ${openCount[0]} is open. `;
}
return msg;
},
},
});
// Playground.js
// ----------
/*global AdventureJS A OpenDemo*/
OpenDemo.createAsset({
class: "Room",
definite_article: "the",
name: "Playground",
descriptions: {
look: `Fireflies speckle the dusk with softly pulsing
motes of light. {We've} come to a modest child's playground
around back of the house. The playground has many things with
which to play, but none of them are objects, and we're not
going to get into it, ok? A window leads back into the house. `,
brief: `Play here. Go window. `,
},
area_scenery: {
fireflies: {
enabled: true,
description:
"Fireflies pulse gently here and there, lending a charming quality to the darkening playground. ",
},
grass: {
enabled: true,
description:
"Occasional tufts of glossy medium height grass dot the yard. ",
},
},
});
// Playground in
OpenDemo.createAsset({
class: "Exit",
direction: "in",
place: { in: "Playground" },
destination: "Sitting Room",
descriptions: {
label: `in to the <span class='exit-destination'>Sitting Room</span>`,
travel: `{We} grab hold of the window sill, scrabble awkwardly up
the siding, and heft {ourself} over the sill and in through the window,
where {we} tumble into the sitting room. `,
},
aperture: "outside window",
});
// outside window
OpenDemo.createAsset({
class: "Window",
name: "outside window",
descriptions: {
// See how this example uses a traditional function.
// Traditional functions are able to be scoped to their
// top level assets which means you can use 'this' with them.
// By contrast if you look at the code for the inside
// window description, you'll see that it uses an arrow
// function. Arrow functions are permitted, but because
// they can't be scoped to their parent asset, they
// can't use 'this'.
look: function () {
return `
Though the sitting room seemed dimly lit, as it is
now dusk outside, the light through the window seems
quite bright from out here.
The window is {inside window [is] open [or] closed}.
${
!this.is.closed
? "{We} should be able to climb back inside. "
: "{We'll} need to open the window if {we} hope to get back through it. "
}
`;
},
// We could instead have used a traditional function here,
// and those do receive scope, which would have let us use
// 'this' to refer to the window.
through:
"The wan light of the sitting room seems quite bright from out here. ",
in: function () {
return this.descriptions.through;
},
},
is: {
closed: true,
locked: true,
},
dov: {
lock: { with_nothing: true },
unlock: { with_nothing: true },
},
// Apertures, aka doors and windows etc, may exist in two places
// one side in one room, and another side in another room.
// We handle each side as a unique asset. In order to keep them
// in sync, meaning open/closed and locked/unlocked, we use the
// other_side property. This outside window asset is linked to
// its other side, a corresponding inside window asset.
other_side: "inside window",
});
// Objects.js
// ----------
/*global AdventureJS A OpenDemo*/
OpenDemo.createAsset({
class: "Chest",
name: "small antique chest",
place: { on: "coffee table" },
descriptions: {
look: function () {
let msg = `It's a small antique Victorian chest,
lacquered in a glossy prussian blue and bound with
ornate blue steel straps that are pitted with age.
Its lid is
{small antique chest [is] locked [or] unlocked} and
{small antique chest [is] open [or] closed}. `;
if (this.game.$("small antique chest").$is("open")) {
msg += `The chest is lined with a rich egg yolk
yellow brocade that presents a startling contrast
to its dark exterior. `;
}
return msg;
},
},
adjectives: ["victorian", "prussian", "blue", "steel", "glossy", "old"],
synonyms: ["straps"],
is: { locked: true, closed: true },
dov: {
open: {
with_nothing: true,
on_first_failure: `{We} didn't think it was going to be that easy, did {we}? `,
on_first_success: function () {
OpenDemo.scorecard.awardPoint("open chest");
//return " ";
},
},
unlock: { with_assets: ["blue steel key"] },
lock: { with_assets: ["blue steel key"] },
},
});
OpenDemo.createAsset({
class: "Paper",
name: "goldenrod sheet",
description: `It's a sheet of goldenrod colored paper with
a child's drawing on it. The drawing appears to feature
a girl with fire engine red hair. The name "Copper" is
scrawled above her in big childlike letters. `,
place: { in: "top drawer" },
});
OpenDemo.createAsset({
class: "Key",
name: "brass key",
synonyms: ["glass bead"],
article: "a",
adjectives: ["burnished", "chonky"],
place: { on: "coffee table" },
description: `It's a burnished brass key with chonky teeth
and a small glass bead mounted in the head. `,
iov: {
unlock: {
// AdventureJS offers many ways to override its default
// actions and output. If
// asset.dov.unlock.on_failure
// is a string, it will be appended to the default unlock
// failure message. In this case, we want to completely
// override the output, so we call this.game.overrideOutput()
// this.game is the same as OpenDemo when called from a scoped function.
// on_failure: function(){ this.game.overrideOutput(
// `Whoops! This brass key doesn't unlock that ${OpenDemo.getInput().getAsset(1).name}. `
// )},
on_first_failure: function () {
this.game.overrideOutput(
`Whoops! Looks like {we} can't unlock ${
OpenDemo.getInput().getAsset(1).article_name
} with the brass key. `
);
},
on_success: `Now you can open the door. `,
then_destroy: true,
on_destroy: `Oh no! The brass key broke! `,
// There's something missing here. We haven't set this key to
// unlock: { with_assets: ['sitting room door'] },
// to indicate that this key can open that lock.
// That's because we've already set that lock to
// unlock: { with_assets: ['brass key'] }
// When assets are linked through verb subscriptions,
// you only have to set one or the other. Two-way connections
// will be completed during game initialization.
},
},
dov: {
take: { on_first_success: "Now to find something to unlock with it. " },
},
}); // brass Key
OpenDemo.createAsset({
class: "Key",
name: "blue steel key",
synonyms: ["blue key", "steel key"],
adjectives: ["victorian"],
iov: { unlock: { with_assets: ["small antique chest"] } },
description: "It's an ornate Victorian key made of blue steel. ",
// article: "a",
place: { in: "top drawer" },
});
OpenDemo.createAsset({
class: "Key",
name: "tiny silver key",
adjectives: ["tiny"],
image: "silverkey",
description:
"It's tiny, and it's silver, and it's a key. It don't open nuthin' so don't even bother. ",
article: "a",
place: { in: "Open Demo Foyer" },
});
OpenDemo.createAsset({
class: "Doll",
name: "Raggedy Ann doll",
place: { in: "Playground" },
descriptions: {
look: function () {
return `It's a threadworn Raggedy Ann doll, either well
loved or abandoned, it's hard to tell which.
${
OpenDemo.$("copper hairpin").$is("attached", this)
? "A patch of her red hair is gathered into a loose pigtail by a hairpin. "
: "Her messy red hair is by turns tangled and patchy. "
} `;
},
},
aspects: {
attached: { list_contents_in_room: false, list_contents_in_examine: false },
},
dov: {
attach: { with_nothing: true },
take: {
on_first_success: function () {
OpenDemo.scorecard.awardPoint("take ann");
//return " ";
},
},
},
});
OpenDemo.createAsset({
class: "Doll",
name: "Raggedy Andy doll",
place: { in: "small antique chest" },
descriptions: {
look: function () {
return `It's a well-loved Raggedy Andy doll in a patched
sailor suit. His red hair is partially covered by a cap
that appears to be sewn on. " } `;
},
},
dov: {
take: {
on_first_success: function () {
OpenDemo.scorecard.awardPoint("take andy");
//return " ";
},
},
},
});
OpenDemo.createAsset({
class: "Lockpick",
name: "copper hairpin",
synonyms: ["pin", "beads", "tines", "head"],
adjectives: ["hammered"],
article: "the",
dov: {
attach: {
with_nothing: true,
on_success: function () {
let indirect_object = this.game.getInput().getAsset(2);
if (indirect_object.name === "Raggedy Ann doll") {
OpenDemo.scorecard.awardPoint("pin ann");
return `The hairpin shapes Ann's ragged hair into a neatly groomed pigtail. `;
}
return `Attached hairpin. `;
},
},
take: {
on_first_success:
"Good catch. It looks like it might be used to pick a lock. ",
on_success: "{We} twirl it between {our} nimble fingers. ",
},
},
iov: {
pick: {
with_assets: ["top drawer"],
then_destroy: true,
on_destroy:
"The hairpin snaps into pieces! {We'll} have to find Raggedy Ann a new one. ",
on_failure:
"And just as well, as the copper is quite soft and probably won't serve long. ",
},
},
descriptions: {
throw: "It skitters across the floor. ",
look: `The hammered copper hairpin has two tines and
a butterfly shaped head with tiny beads affixed to it, in
a vaguely art nouveau style. It's actually quite nice. `,
},
place: { attached: "raggedy ann doll" },
});
// Scorecard.js
// ----------
/*global AdventureJS A OpenDemo*/
OpenDemo.scorecard.set({
// This is how you set score events for your game.
// You can add as few or as many as you like,
// and set points to whatever number you like.
// The names are up to you, so set them however you like.
points: {
"open window": 1,
"take ann": 1,
"open library door": 1,
"open top drawer": 1,
"open chest": 1,
"take andy": 1,
"pin ann": 1,
// Let's say you want the game to start with
// some points already set. You can do that like this.
"preset points": { value: 5, awarded: true, recorded: true },
// You can set negative points too. These unset points cancel
// out the preset points above.
"unset points": { value: -5, awarded: true, recorded: true },
},
// To attach a score event to your custom function, use
// OpenDemo.scorecard.awardPoint('open window');
// You'll see these sprinkled throughout this demo code.
// AdventureJS has built-in scoring functions,
// but you may, if you like, write custom score handling.
// this returns a string
// award_text: `{Our} score went up! `,
// this returns a custom function
// award_text: function(){
// return `Dude, you totally just got ${this.diff} points!`
// },
// Or maybe you just want to tweak the score display.
// By default score appears in 0/0 format, but let's
// say you'd like it to say "Score: 0 out of 0".
// score_format: function()
// {
// return `Score: ${this.score} out of ${this.total}`;
// }
// award_text and score_format have access to some vars:
// - this.score (old score)
// - this.newscore (new score)
// - this.diff (difference between old/new )
// - this.total (total of points available)
});
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
unlock verb logic
Verb logic falls into a few recognizable patterns. Direction verbs tend to be simple and redirect to tryTravel(). Manipulation verbs test whether one asset is allowed to interact with another asset. Locomotion verbs test the player's current ability to move in a specified way. Many verbs are similar, but no two verbs are identical. Each verb has its quirks. If you would like to learn more about general verb logic, we recommend you see the Verb Anatomy and Verb Process pages. Verb phases and verb actions / reactions offer various hooks to customize verb behavior. If you find that you want still more flexibility, you may want to investigate the modifyVerb method, which lets you replace entire blocks of verb code. You can also write verbs from scratch if you're so inclined. See Modify Verbs for a complete list of verb modification methods.
The following sections provide information that is specific to the verb unlock, though they include many features which are common to most verbs.
- Verb Demo
- Verb Subscriptions enable
unlockto act on specific assets, and provide a collection of properties for customizing those interactions. - Sentence Structures help filter player input by defining what sentence structures
unlockcan handle. - Verb Phrases describe the direct and indirect objects that
unlockcan handle. - Verb Phase Hooks offer a broad method for authors to hook into default logic and override it with custom code.
- Verb Action Hooks offer a surgical method for authors to hook into
unlock's default logic and inject custom code. - Verb Reaction Hooks are like verb actions, but occur as secondary effects of successfully applying
unlock. - Verb Params contain properties that are distinct to
unlock. Not all verbs have params. - Verb Methods lists the methods that
unlockinherits from the Verb class. - Verb Properties lists the properties that
unlockinherits from the Verb class.
unlock subscriptions
An asset must be subscribed to a verb for that verb to act upon that asset (with some exceptions). Though verbs are universal, each asset's verb subscriptions are distinct objects that can be used to customize how a given verb interacts with a given asset. To say it another way, a verb subscription is a collection of properties that defines how a verb should be applied to an asset; which allow authors to override a verb's default behaviors on a per-asset basis.
It's important to note that verb subscriptions need to be declared as direct or indirect, depending on whether the asset will be used as a direct object or indirect object. In the case of "unlock lock with key", the lock is the direct object and the key is the indirect object, and each asset needs to be subscribed to unlock in the appropriate way. (It's allowed, and a common pattern, to subscribe assets directly and indirectly to the same verb.)
Expand for example
MyGame.createAsset({
class: "Lock",
name: "lock",
dov: { unlock: true },
});
MyGame.createAsset({
class: "Key",
name: "key",
iov: { unlock: true },
});
As shown in the above example, dov: { unlock: true } is the minimum that is required to subscribe an asset to a verb. However, verb subscriptions have many properties that can be used to customize how this verb is applied to this asset. (Setting any property eliminates the need to set verb: true. ) Below is a list of verb subscription properties that authors may find useful.
-
automatically
{Boolean}
Allows for some verbs to be performed automatically if context calls for
it; for example, when unlocking a door in order to pass through it. An asset's verb subscription setting takes precedence over game settings.
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { automatically: true } }, }); -
automatically_after_use
{Boolean}
This sets it so that a verb can only be applied automatically after a
player has already used it manually. This is to prevent automatic use of
tools from breaking puzzles. For example, imagine one door with many keys
but only one that works; if choosing the right key is part of the puzzle,
this option prevents players from simply saying "unlock door" and having
the right key automatically selected for them. When setting
automatically_after_useto true you don't also have to setautomatically.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { automatically_after_use: true } }, }); -
enabled
{Boolean}
Verb subscriptions are enabled by default, but can be disabled manually.
Temporarily disabling a verb subscription can be a useful method for
controlling an asset. For example, you might disable
openfor a door that needs another action to be completed before it can be opened.Individual verb subscriptions can be enabled / disabled viaExpand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { enabled: true } }, });asset.setDOV(verbname)andasset.unsetDOV(verbname). -
on_success
{String|Array|Function}
If this property returns a string, the string will be appended to the
verb's default success message. Though a string is expected, this property
is handled by
getStringArrayFunction().
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { on_success: "You unlock the universal widget. " } }, }); -
on_first_success
{String|Array|Function}
If this property returns a string, the string will be appended to the
verb's default success message the first time it is applied to this asset.
Though a string is expected, this property is handled by
getStringArrayFunction().
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { on_first_success: "You unlock the universal widget for the first time. " } }, }); -
on_failure
{String|Array|Function}
If this property returns a string, the string will be appended to the
verb's default failure message. Though a string is expected, this property
is handled by
getStringArrayFunction().
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { on_failure: "You failed to unlock the universal widget. " } }, }); -
on_first_failure
{String|Array|Function}
If this property returns a string, the string will be appended to the
verb's default failure message the first time it is applied to this asset.
Though a string is expected, this property is handled by
getStringArrayFunction().
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { on_first_failure: "You failed to unlock the universal widget this first time. " } }, }); -
once
{Boolean}
if true, the verb can only be applied once to the asset. The verb
subscription will be disabled after use. No special message will be printed, but subsequent attempts to use the verb on this asset will explain why it can't be used again.
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { once: true } }, }); -
then_destroy
{Boolean}
If this property is true, the asset will be destroyed after the verb is
applied.
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { then_destroy: true } }, }); -
on_destroy
{String|Array|Function}
If this property returns a string, the asset will be destroyed after the
verb is applied, and the string will be appended to the verb's success
message. Though a string is expected, this property is handled by
getStringArrayFunction().
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { then_destroy: true, on_destroy: "The widget is destroyed!" } }, }); -
with_anything
{Boolean}
Pertains only to indirect objects. If true, this asset can be used as an indirect object of this verb with any direct object.
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", iov: { unlock: { with_anything: true } }, }); -
with_assets
{Boolean}
Use to specify particular assets that can interact with this one using the given verb. For example "unlock door with key" where the specified key is the only asset that can unlock door. This works distinctly for direct and indirect verb subscriptions. So, for instance, in "unlock door with key", the door might have a direct object subscription, while the key has an indirect object description.
Expand for example
MyGame.createAsset({ class: "Door", name: "gold door", dov: { unlock: { with_assets: [ "gold key" ] } }, }); MyGame.createAsset({ class: "Key", name: "gold key", iov: { unlock: { with_assets: [ "gold door" ] } }, }); -
with_classes
{Array}
Use to specify particular classes that can interact with this asset using the given verb. For example "unlock door with skeleton key" where any instance of the class SkeletonKey can unlock door. This works distinctly for direct and indirect verb subscriptions. So, for instance, in "unlock door with skeleton key", the door might have a direct object subscription, while the key has an indirect object description.
Expand for example
MyGame.createAsset({ class: "Door", name: "red door", dov: { unlock: { with_classes: [ "SkeletonKey" ] } }, }); MyGame.createAsset({ class: "SkeletonKey", name: "skeleton key", iov: { unlock: { with_classes: [ "Door", "Chest" ] } }, }); -
with_nothing
{Array}
Pertains only to direct objects. If true, the specified verb can be applied to the direct object without the use of any indirect object.
Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { with_nothing: true } }, }); -
with_params
{Object}
Used to contain a set of parameters that are specific to this particular verb. For example, plugIn includes
with_params.max_connectionsfor setting limits on how many other assets this asset can be plugged into. See the with_params section on this page to learn more aboutunlock's parameters.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { with_params: { unlock_property: value } } }, }); -
with_prepositions
{Array}
Use to limit the prepositions that can be used with this asset. For
instance: "knock over umbrella stand" might fail with a message of "you
can't knock over the umbrella stand"; setting
umbrella_stand.dov.knock.with_prepositions = ["over"]will allow the action to succeed.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { with_prepositions: [ "through", "over" ] } }, }); -
doBeforeTry
{Function}
Verb phases provide methods to override default verb behaviors. See the verb phases section on this page to learn more about
unlock's verb phases.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { doBeforeTry: function () { console.log("unlock.doBeforeTry"); }, } }, }); -
doAfterTry
{Function}
Verb phases provide methods to override default verb behaviors. See the verb phases section on this page to learn more about
unlock's verb phases.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { doAfterTry: function () { console.log("unlock.doAfterTry"); }, } }, }); -
doBeforeSuccess
{Function}
Verb phases provide methods to override default verb behaviors. See the verb phases section on this page to learn more about
unlock's verb phases.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { doBeforeSuccess: function () { console.log("unlock.doBeforeSuccess"); }, } }, }); -
doAfterSuccess
{Function}
Verb phases provide methods to override default verb behaviors. See the verb phases section on this page to learn more about
unlock's verb phases.Expand for example
MyGame.createAsset({ class: "Entity", name: "universal widget", dov: { unlock: { doAfterSuccess: function () { console.log("unlock.doAfterSuccess"); }, } }, });
Notes
- To learn more about working with verb subscriptions, see Verb Subscriptions.
- These are most, but not all, of the properties of a verb subscription. For full reference, see the VerbSubscription class.
unlock sentence structures
accepts_structures: [
"verb noun",
"verb noun preposition noun"
]
The parser uses multiple filtering methods to try to channel player input into useable tokens. Sentence structures are defined for each verb in order to narrow down the input that the verb can handle. For example, the verb "hit" might accept "verb noun" as in "hit troll", or "verb noun preposition noun" as in "hit troll with sword", whereas an intransitive verb like "jump" might accept "verb" as a complete sentence. Input that isn't accepted will return a warning to the player.
A note about adverbs: though the parser does handle some adverbs, such as "carefully examine tiara" and "turn left", it excludes them from consideration in sentence structures. Due to the slipperyness of the English language, an adverb can appear in multiple positions in a sentence while still describing the same verb, which presents enough possible word combinations to make sentence structures less useful as a filtering tool. Instead, the parser puts adverbs aside and handles them separately.
Notes
- It is possible for authors to modify a verb's structures through the use of modifyVerb.
- To learn more about modifying verbs, see Modify Verbs.
unlock phrases
phrase1:
{
accepts_noun: true,
requires_noun: true,
noun_must_be:
{
known: true,
entity: true,
present: true,
visible_unless_carried: true,
reachable: true,
},
},phrase2:
{
accepts_noun: true,
noun_must_be:
{
in_inventory: true,
known: true,
},
accepts_preposition: true,
requires_preposition: true,
preposition_must_be: ["with"],
},
The AdventureJS parser uses multiple filtering methods to try to interpret player input. A verb's phrases may consist of a noun and/or a preposition. Whether any noun is defined as a direct or indirect object is up to that verb's unique logic. Each verb defines a unique set of phrases depending on what its logic can handle. Verbs may handle zero, one, two, or three nouns. The nested noun_must_be object sets conditional qualifiers to help narrow down assets that the verb might act upon. Input that isn't accepted will return a warning to the player.
Notes
- It is possible for authors to modify a verb's phrases through the use of modifyVerb.
- To see a list of properties that can be set for phrases, see the Phrase class.
- To see a list of properties that can be set for phrase.noun_must_be, see the NounMustBe class.
- To learn more about modifying verbs, see Modify Verbs.
unlock phase hooks
Verb phase hooks let authors override verb subscriptions for specific assets when unlock is applied to them. This is a broad method for customizing verb/noun interactions on a per-asset basis. For example, an author might supply completely different logic for "throw feather" vs "throw baseball" vs "throw anvil".
When unlock.do() is called, it attempts to run a sequence of methods, or phases, as listed below. The four hooks have no default logic of their own but provide methods to inject custom code at any point in the life cycle of the verb action. See below for examples of how to use verb phases for unlock.
do
doBeforeTry hook
MyGame.createAsset({
class: "Entity",
name: "This Asset",
dov: {
unlock: {
doBeforeTry: function( params )
{
let msg = `You're about to try to unlock ${this.article_name}. `;
this.game.print(msg);
return;
},
},
},
});
doTry handles logic to determine if unlock can be applied
doAfterTry hook
MyGame.createAsset({
class: "Entity",
name: "This Asset",
dov: {
unlock: {
doAfterTry: function( params )
{
let msg = `You just tried to unlock ${this.article_name}! `;
this.game.print(msg);
return;
},
},
},
});
doBeforeSuccess hook
MyGame.createAsset({
class: "Entity",
name: "This Asset",
dov: {
unlock: {
doBeforeSuccess: function( params )
{
let msg = `You're about to succeed in performing unlock on ${this.article_name}. `;
this.game.print(msg);
return;
},
},
},
});
doSuccess handles state changes and printing messages
doAfterSuccess hook
MyGame.createAsset({
class: "Entity",
name: "This Asset",
dov: {
unlock: {
doAfterSuccess: function( params )
{
let msg = `You succeeded in performing unlock on ${this.article_name}. `;
this.game.print(msg);
return;
},
},
},
});
Expand for example
Assets must have separate direct and indirect verb subscriptions. Consider this singing sword, which is directly subscribed to the verb "take". We want our game to print a custom message when the player tries to take the sword, and a different message when the player succeeds in taking it.
MyGame.createAsset({
class: "Sword",
name: "singing sword",
dov: {
take:
{
doAfterTry: function()
{
let msg = "The sword begins to vibrate as your hand curls around its haft. ";
MyGame.print( msg );
},
doAfterSuccess: function()
{
let msg = "The sword bursts into song in your hand. ";
MyGame.print( msg );
},
},
},
});
Now consider this stone, which is indirectly subscribed to "remove". We want to print messages when the sword is removed from it, so we'll hook into the stone's indirect object subscription. We could put this code on either object. A case like this comes down to author's choice.
MyGame.createAsset({
class: "Entity",
name: "stone",
iov: {
remove:
{
doBeforeTry: function()
{
let msg = "Will the stone judge you worthy enough to remove the sword? "
MyGame.print( msg );
},
doAfterSuccess: function()
{
let msg = "With the sword removed, the stone bursts into rubble! ";
MyGame.print( msg );
MyGame.destroyAsset(this);
},
},
},
});
Notes
- To learn more, see verb phase hooks.
- Verb phase hooks are similar to, but distinct from, verb action hooks and verb reaction hooks, which offer more surgical hooks.
unlock action hooks
Every asset referred to in the turn's input is checked for verb action hooks. These hooks allow authors to inject custom code or print custom text during verb operations. There are two distinct approaches to defining verb actions, designed to accommodate different levels of scripting experience. Authors may use whichever approach they find most comfortable. For more details, see Action Hooks.
-
Simple approach: Define string properties such as
asset.do_unlock. If AdventureJS finds a string, it prints it instead of the default output for that turn. This option is best for authors who want to customize output without writing code. -
Advanced approach: Define method properties such as
asset.doUnlock(). If a method is found, it is called with a parameter object containing any relevant assets from the input (e.g.,asset.doUnlock({asset1,asset2})). The author may use or ignore these parameters. This approach offers complete control over the turn’s outcome: authors can add conditional logic, force success or failure, or revise the default output.
Expand any item to see code examples. Methods are called with a parameter object in the form of action({asset1, asset2, params}) which authors may use or ignore.
tryUnlockThis
Called on This asset in a phrase such as "unlock this". Since no indirect object is given, we treat the player character as an indirect object.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of which player character uses the verb.
MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThis: function () { let msg = "Found custom method at thing_one.tryUnlockThis()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
tryUnlockThisfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThis: { "Player Two": function () { let msg = "Found custom method at thing_one.tryUnlockThis['Player Two']()"; MyGame.print(msg); }, }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this particular verb action, asset1 is the player character, because we've treated it as the indirect object in absence of a player specified object.
MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThis: function ({asset1}) { switch (asset1.name) { case "Player Two": let msg = "Found custom method at thing_one.tryUnlockThis('Player Two')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
doUnlockThis
Called on This asset in a phrase such as "unlock this".
Since no indirect object is given, we treat the player character as an indirect object.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of which player character uses the verb.
MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThis: function () { let msg = "Found custom method at thing_one.doUnlockThis()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
doUnlockThisfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThis: { "Player Two": function () { let msg = "Found custom method at thing_one.doUnlockThis['Player Two']()"; MyGame.print(msg); }, }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this particular verb action, asset1 is the player character, because we've treated it as the indirect object in absence of a player specified object.
MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThis: function ({asset1}) { switch (asset1.name) { case "Player Two": let msg = "Found custom method at thing_one.doUnlockThis('Player Two')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
tryUnlockThisPrepositionThat
Called on This asset in a phrase such as "unlock this with that", where This is the direct object and That is the indirect object.
tryUnlockThisPrepositionThat mirrors tryUnlockThatPrepositionThis. One is called on a direct object; the other on an indirect object. These are equivalent, and you may place code on whichever asset makes sense to you.
This example uses "with" as the preposition, but any preposition can set a unique response.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of what
Thatasset is.MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThisWithThat: function () { let msg = "Found custom method at thing_one.tryUnlockThisWithThat()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
tryUnlockThisPrepositionThatfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThisWithThat: { "Thing Two": function (params) { let msg = "Found custom method at thing_one.tryUnlockThisWithThat['Second Thing']()"; MyGame.print(msg); } }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this verb action, asset1 is the second noun.
MyGame.createAsset({ class: "Entity", name: "Thing One", tryUnlockThisWithThat: function ({asset1}) { switch (asset1.name) { case "Thing Two": let msg = "Found custom method at thing_one.tryUnlockThisWithThat('Second Thing')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
doUnlockThisPrepositionThat
Called on This asset in a phrase such as "unlock this with that", where This is the direct object and That is the indirect object.
doUnlockThisPrepositionThat mirrors doUnlockThatPrepositionThis. One is called on a direct object; the other on an indirect object. These are equivalent, and you may place code on whichever asset makes sense to you.
This example uses "with" as the preposition, but any preposition can set a unique response.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of what
Thatasset is.MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThisWithThat: function () { let msg = "Found custom method at thing_one.doUnlockThisWithThat()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
doUnlockThisPrepositionThatfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThisWithThat: { "Thing Two": function (params) { let msg = "Found custom method at thing_one.doUnlockThisWithThat['Second Thing']()"; MyGame.print(msg); } }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this verb action, asset1 is the second noun.
MyGame.createAsset({ class: "Entity", name: "Thing One", doUnlockThisWithThat: function ({asset1}) { switch (asset1.name) { case "Thing Two": let msg = "Found custom method at thing_one.doUnlockThisWithThat('Second Thing')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
tryUnlockThatPrepositionThis
Called on That asset in a phrase such as "unlock this with that", where That is the indirect object and This is the direct object.
tryUnlockThatPrepositionThis mirrors tryUnlockThisPrepositionThat. One is called on an indirect object; the other on a direct object. These are equivalent, and you may place code on whichever asset makes sense to you.
This example uses "with" as the preposition, but any preposition can set a unique response.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of what
Thatasset is.MyGame.createAsset({ class: "Entity", name: "Thing Two", tryUnlockThatWithThis: function () { let msg = "Found custom method at thing_two.tryUnlockThatWithThis()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
tryUnlockThatPrepositionThisfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing Two", tryUnlockThatWithThis: { "Thing One": function (params) { let msg = "Found custom method at thing_two.tryUnlockThatWithThis['First Thing']()"; MyGame.print(msg); } }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this verb action, asset1 is the second noun.
MyGame.createAsset({ class: "Entity", name: "Thing Two", tryUnlockThatWithThis: function ({asset1}) { switch (asset1.name) { case "Thing One": let msg = "Found custom method at thing_two.tryUnlockThatWithThis('First Thing')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
doUnlockThatPrepositionThis
Called on That asset in a phrase such as "unlock this with that", where That is the indirect object and This is the direct object.
doUnlockThatPrepositionThis mirrors doUnlockThisPrepositionThat. One is called on an indirect object; the other on a direct object. These are equivalent, and you may place code on whichever asset makes sense to you.
This example uses "with" as the preposition, but any preposition can set a unique response.
-
In this example, we ignore the passed parameter. This variation results in the same response regardless of what
Thatasset is.MyGame.createAsset({ class: "Entity", name: "Thing Two", doUnlockThatWithThis: function () { let msg = "Found custom method at thing_two.doUnlockThatWithThis()"; MyGame.print(msg); }, }); -
To limit the method to act only on a certain asset, change the value of
doUnlockThatPrepositionThisfrom a method to an object, use the asset's name as a key on the object, and set that key's value to a method instead.MyGame.createAsset({ class: "Entity", name: "Thing Two", doUnlockThatWithThis: { "Thing One": function (params) { let msg = "Found custom method at thing_two.doUnlockThatWithThis['First Thing']()"; MyGame.print(msg); } }, }); -
Finally, in this example, we apply per-asset logic based on the value of asset1, which is available via our passed parameter. In this verb action, asset1 is the second noun.
MyGame.createAsset({ class: "Entity", name: "Thing Two", doUnlockThatWithThis: function ({asset1}) { switch (asset1.name) { case "Thing One": let msg = "Found custom method at thing_two.doUnlockThatWithThis('First Thing')"; MyGame.print(msg); break; default: // do nothing and allow the default result break; } return; }, });
Notes
- Verb action hooks are specific to their particular verb.
- Which verb action hooks are called depends on the structure of the player's input. Hooks are checked for every asset in the input, including the player character. Which hooks are called depends on the sentence structure of the player's input:
-
Single-object input (e.g., "unlock this"): The hook is called on
Thisasset. Since no indirect object is specified, the player character is treated as an indirect object. -
Multiple-object input (e.g., "unlock this with that"): The hook is called depending on the object’s role in the phrase.
doThisPrepositionThatruns onThisdirect object, whiledoThatPrepositionThisruns onThatindirect object. These are equivalent, and you may place code on whichever asset makes sense to you. Any preposition can be used to define a unique response, for exampleunlock withvsunlock on. -
Sentence structures are commonly mutated during the doTry verb phase, so
tryanddomay act on different sentence structures. -
Verb actions are extremely granular and depend on specific combinations of assets and prepositions. Verb actions are called during a verb's doTry and doSuccess phases, which lets them override a verb's operations. Use them if you want to customize output for specific inputs, but beware of that granularity. Consider
doTake(): it's called when a player takes an asset, so you might want to hook into that; but many other verbs may also move the asset into the player. If you want to catch any method that moves an asset into the player, you may find thedoMoveThisToThatverb reaction more broadly applicable. - By default, string properties override a turn's output, but they can also be set to append or prepend the turn's default output. See verb action hooks for more information.
- Verb reaction hooks are functionally the same as action hooks. The only difference is that reaction hooks are not specific to any verb.
- Verb phase hooks are a different form of hook that allows authors to override entire verb phases.
unlock reaction hooks
Every asset affected by the turn is checked for verb reaction hooks. These hooks allow authors to inject custom code or print custom text during verb operations. Verb reactions are subject to String Array Function, which means they can be set to any of those three types. Authors may use whichever they find most comfortable. See verb reaction hooks for details.
- String: If AdventureJS finds a string, it prints it instead of the default output for that turn. This option is best for authors who want to customize output without writing code.
- Array: If AdventureJS finds an array, it will print an item from the array, using randomization or not according to global settings.
-
Functions: Set a function like
asset.doMoveThisToThat(). If a function is found, it is called with a parameter object containing any relevant assets from the input (e.g.,asset.doMoveThisToThat({asset1})). The author may use or ignore these parameters. This approach offers complete control over the turn’s outcome: authors can add conditional logic, force success or failure, or revise the default output.
Expand any item to see code examples. All methods are called with a parameter object in the form of asset.reaction({asset1, asset2, params}) which authors may use or ignore.
No verb reactions listed for unlock
Notes
- See verb reaction hooks for more details.
- Reaction hooks aren't specific to any particular verb.
-
Verb reactions fire at the end of a turn after the verb's doSuccess phase. Many verbs may call the same reactions. For instance, any verb that moves an asset into the player calls
doMoveThisToThat. This makes them more broadly applicable than verb actions and lets you customize the turn's output regardless of what verb is used. - Verb action hooks work the same way as reaction hooks, but are specific to their particular verb.
- Verb phase hooks are a different form of hook that allows authors to override entire verb phases.