Actions
Actions are commands that can be performed by actors. In a text adventure, player input gets parsed into commands for their characters. Examples of possible commands are GO NORTH
and GET LAMP
.
Scripts define actions with the respond
method.
Simple Commands
The simplest command form is a single verb. Example:
Mygame::Plot.script do
respond :think do |actor|
actor.tell "You ponder your predicament."
end
end
The respond
method’s block gets executed in response to the THINK command. The block’s first argument is always the character performing the action.
Action Targets
The respond
method can take additional arguments that identify the action’s targets, e.g., the direct object of a command.
Mygame::Plot.script do
respond :kick, Thing do |actor, thing|
actor.tell "You kick #{the thing}."
end
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 used to perform comparisons is called a Query
.
There are different types of queries that actions can use. In the standard
library, the default query is available
. The above example will compare the user’s input to each Thing
available to the character.
Using Queries
Gamefic provides query methods for specifying which query to use for each target. The above KICK example is equivalent to specifying available
:
Mygame::Plot.script do
respond :kick, available(Thing) do |actor, thing|
actor.tell "You kick #{the thing}."
end
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 entities)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.
require 'gamefic-standard'
Mygame::Plot.seed do
@field = make Room, name: 'field'
@ball = make Item, name: 'ball', parent: @field
@can = make Item, name: 'can', parent: @field
end
Mygame::Plot.script do
introduction do |actor|
actor.parent = @field
actor.tell "You're in a field. You see a ball and a can here."
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
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. As a general rule, the most recently defined match is the one that gets executed.
In this example, the first action will never get executed because the second action overrides it:
Mygame::Plot.script do
respond :think do |actor|
actor.tell "This won't happen."
end
respond :think do |actor|
actor.tell "This is the first THINK action the game finds."
end
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:
Mygame::Plot.script do
respond :kick, @ball do |actor, thing|
actor.proceed
actor.tell "You're playing soccer!"
end
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