Gamefic

Adventure Games and Interactive Fiction

Commands

A game turn (or scene) consists primarily of four steps:

  1. Start the scene
  2. Send output to the player
  3. Receive player input
  4. Finish the scene

The way that player input gets processed in the scene’s finish can vary by scene type. In an Activity scene, the input gets parsed into a command that can be performed by the player’s character. Examples of possible commands are GO NORTH and GET LAMP. This is the typical behavior of a traditional parser-based text game and the default behavior of a Gamefic narrative.

Authors define how narratives respond to commands with the respond method.

Simple Commands

The simplest command form is a single verb. Example:

respond :think do |actor|
  actor.tell "You ponder your predicament."
end

The respond method’s block gets executed in response to a THINK command. The block’s first argument (actor) is always the character performing the action.

Command Arguments

The respond method can take additional arguments that identify the action’s targets, e.g., the direct object of a command.

respond :kick, Thing do |actor, thing|
  actor.tell "You kick #{the thing}."
end

This action allows characters to KICK any object in their direct vicinity.

Actions identify targets by comparing the command’s direct object to the entities the player can access, e.g., other items in the room, items in the character’s inventory, items in nearby open containers, etc. The component that checks for accessible is called a Query.

There are different types of queries that actions can use. In the standard library, the default query is available.

Using Queries

Gamefic provides query methods for specifying which query to use for each target. The above KICK example is equivalent to explicitly available:

respond :kick, available(Thing) do |actor, thing|
  actor.tell "You kick #{the thing}."
end

# OR

respond :kick, Thing do |actor, thing|
  actor.tell "You kick #{the thing}."
end

The available query is suitable for the majority of use cases, but the following queries are also available:

  • anywhere
  • parent
  • children
  • siblings
  • myself
  • plaintext (filters and returns text input instead of an entity)
  • integer (returns an integer instead of an entity)
  • room (requires gamefic-standard)

The anywhere query is exceptional because it allows commands to act on any entity in the game regardless of its vicinity to the player. It can be useful for commands that don’t involve physical interaction, e.g., THINK ABOUT THE CASTLE or EMAIL BOB.

Actions with Specific Targets

The above examples specify Thing as the target. This means the action will be triggered for any Thing the query can find. Authors can specify a specific object to make a specialized version of the action.

In this example, the plot triggers a different action in response to KICK BALL.

construct :field, Room, name: 'field'
construct :ball, Item, name: 'ball', parent: field
make Item, name: 'can', parent: field

introduction do |actor|
  actor.parent = field
  actor.perform 'look'
end

respond :kick, Thing do |actor, thing|
  actor.tell "You kick #{the thing}."
end

respond :kick, ball do |actor, thing|
  actor.tell "You're playing soccer!"
end

If the command’s direct object is the ball, the second action gets triggered. For any other object, the first gets triggered.

Action Orders

The response method associates an action with a verb. In the above examples, the verbs are :think and :kick.

Multiple actions can be associated with the same verb. When a player’s command gets parsed, the game identifies all the actions that potentially match based on the verb and queries. When more than one action exists with the same verb and queries, the last one defined gets executed first.

In this example, the first response will never get executed because the second response overrides it:

respond :think do |actor|
  actor.tell "This won't happen."
end

respond :think do |actor|
  actor.tell "This action that gets executed first."
end

Cascading through Multiple Actions with proceed

Sometimes authors want to add custom behavior for a command but still have the option to execute the previous action. The actor’s proceed method allows it to execute the previous match for the current command.

We can modify the KICK example above so the action that responds to kicking the ball executes the previous action:

respond :kick, ball do |actor, thing|
  actor.proceed
  actor.tell "You're playing soccer!"
end

Result:

$ rake ruby:run

You're in a field. You see a ball and a can here.

> kick can

You kick the can.

> kick ball

You kick the ball.

You're playing soccer!

Next: Creating custom scenes