Command Matching

When a player executes a command, each entity in scope is checked to see if it has relevant command matcher.

before, action, after

Command matchers are defined in either before, action or after entry.

An action is the main action, and is usually defined on a verb. before entries allow an entity to intercept an action. The result of a before action is checked for truthyness. A value of true indicates that command has been handled, and stops further processing by any other before or action entries on any entity or verb.

after entries execute after everything else has been run.

Command Matchers

Command matchers are specified with the following format.

verb()
verb(directObject)
verb(directObject, modifier)
verb(directObject).attribute(indirectObject)
verb(directObject).attribute(subCommand)

The last form is for clausal verbs, where the attribute's argument is itself a whole nested command (see Sub-commands below), rather than a single indirect object.

Specifying and capturing item

Objects and modifiers can be specified exactly, or by capturing a value.

Matching this

this is used to specify that the matcher should match the current object.

Matching a specific object

Use the item id.

eg

push(theBox): print("you push the box")

Matching any object and capturing its id

Specify a capture by providing a variable staring with a $. The variable can then be used later by omitting the $

push($pushable): print("you push " + getFullName(pushable))

Matching any modifier and capturing its value

A modifier capture needs to be matched using the modifier name, there could be several modifiers and we need to know which one matches.

eg

push(this, $direction): print("You push " + direction)
push($pushable, $direction, $effort): print("You push " + getFullName(pushable) + " " + direction + " with " + effort)

examples

Intercepting a simple get command

item: hotRock
name: hot rock
tags:
  - carryable
before:
  get(this): print("Ouch!")

Handling an attributed verb

---
npc: barkeep
name: barkeep
location: theRoom
verbs:
  - ask
---
verb: ask
tags:
  - transitive
attributes:
  - about
---
item: beerThought
location: theRoom
verbs: ask.about
before:
  ask(barkeep).about(this): print("I recommend the porter")
---

Matching a modified verb

item: box
tags:
  - pushable
isStuck: true
before:
  push(this, $direction):
    when: this.isStuck
    then: print("You cannot push the box " + direction)
    otherwise: return(false)

Sub-commands

A clausal verb like tell takes a sub-command as its attribute's argument. That sub-command is written and matched exactly like an ordinary top-level command matcher - subVerb, subVerb(subObjectOrModifier), or subVerb(subObject).attribute(subIndirectObject) - just nested inside the outer attribute call, so the syntax stays the same at every level:

---
item: robot
verbs:
  - tell
before:
  tell(this).to(go($direction)): print("The robot whirs off to the " + direction)
  tell(this).to(fire($target)): print("The robot fires its laser at " + getFullName(target))
---

A bare sub-verb with no arguments (eg wait) is written the same way a bare intransitive verb is at the top level - with or without parentheses, tell(this).to(wait) and tell(this).to(wait()) are equivalent.

The sub-verb itself can also be captured, eg to write one handler for any command - the capture becomes the call name, and still takes whatever arguments that particular sub-verb needs:

before:
  tell(this).to($action($direction)): print("The robot tries to " + action.id + " " + direction)

Attributed sub-verbs

If the sub-verb itself takes an attribute (eg stir soup with spoon), write it exactly as you would at the top level, nested as the single argument to the outer attribute:

before:
  tell(this).to(stir($item).with($tool)): print("The robot stirs " + item.name + " with " + tool.name)

As with a normal attributed verb, if the sub-verb has the indirectOptional tag the .with(...) part can be omitted, eg tell(this).to(stir(soup)) alone still matches tell robot to stir soup.