Commands
A game turn (or scene) consists primarily of four steps:
- Start the scene
- Send output to the player
- Receive player input
- 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