Ditransitive actions are actions that require two objects in order to perform it. The objects need to be accessible to the current player (or in the world if no player). Ditransitive actions are treated as normal transitive actions if only one object is used, though. The words or phrases that separate the two objects are called "conjunctions," and are declared with the action.
use key with door give bottle to hermit stab monster with sword
...where with and to are conjunctions, and key, bottle, sword, hermit, monster, and door are names of objects in the module.
action [MODIFIERS] ditransitive [IDENTIFIER] [NAME_CLAUSE] ;
[MODIFIERS] |
An optional declaration of one or more additional modifiers for action behavior. strict: Apply "strict behavior" to the handling of this action. "Strict" ditransitive actions require both objects to be specified, only searches for action handling blocks in the order that the objects are specified, and do not tolerate additional things typed at the interpreter past the parsed objects and conjunction after the action. reversed: Apply "reversed behavior" to the handling of this action: if "strict," action handling blocks are searched in the opposite manner (the first object is object 2, the second object is object 1). This has no effect if "strict" is not specified. |
[IDENTIFIER] | An internal identifier that represents this action in the rest of TAMEScript. This is used to find what entry blocks throughout the code should be executed when a name associated with this action is parsed by the interpreter or when a specific action is queued by another command. This identifier must not be used to describe another element. |
[NAME_CLAUSE] |
The keyword named followed by a comma-delimited list of strings that the
interpreter is supposed to associate with this command. The compiler does not check for
name duplicates - equivalent names overwrite their association. Names, internally, are
sanitized to what the interpreter accepts. After the list of action names, the keywords uses conjunctions are required as well as a comma-delimited list of strings that the interpreter uses as valid conjunctions for separating both objects. This clause is optional - if no names are declared, this is not parse-able in the interpreter. Leaving this out is a way to make "private" actions. |
Non-strict ditransitive actions that lack a second object are treated as transitive actions.
The following are a few examples of transitive action declarations:
action ditransitive a_mix named "mix", "combine" uses conjunctions "and", "with";
action strict ditransitive a_talk_to named "talk to" uses conjunctions "about";
action strict reversed ditransitive a_give named "give" uses conjunctions "to";
DITRANSITIVE action handling is a little tricky - depending on whether or not the action is labelled strict, it will try both combinations of "object 1 on-action-with object 2" and "object 2 on-action-with object 1", stopping after it finds a qualifying block. Only the first interpreted object is used as the target element (including the "ancestor" and "other" handling blocks) if the action is strict, and only the second interpreted object is used as the target element (including the "ancestor" and "other" handling blocks) if the action is strict and reversed.
If a valid onActionWith() block for a ditransitive action and target object is not found, TAME looks for an onActionWithAncestor() block to call that matches. If that does not exist, it calls onActionWithOther(). And if that does not exist, TAME looks for onUnhandledAction() blocks to call on the current player, if any, and then the world.
Then if that is not found, an ERROR cue is added to the Response.
action general a_quit named "quit", "exit";
action transitive a_talk named "talk to";
action transitive a_examine named "examine", "look at", "x";
action strict ditransitive a_mix named "mix", "combine" uses conjunctions "with", "and";
action strict reversed ditransitive a_give named "give" uses conjunctions "to";
module
{
title = "Paint Delivery";
}
/********************************** All paint. *******************************/
object archetype o_paint
{
// Override this!
function getColor()
{
return false;
}
// On mix with any other paint-category item.
onActionWithAncestor(a_mix, o_paint)
{
textln("I think these don't need any more mixing.");
}
// On mix with anything else.
onActionWithOther(a_mix)
{
textln("I can't mix these together.");
}
onAction(a_examine)
{
textln("Looks like a can of " + getColor() + " paint.");
}
onWorldBrowse()
{
textln("A can of " + getColor() + " paint is here.");
}
}
object o_paint_orange : o_paint named "paint", "orange paint"
{
override function getColor()
{
return "orange";
}
}
object o_paint_purple : o_paint named "paint", "purple paint"
{
override function getColor()
{
return "purple";
}
}
object o_paint_green : o_paint named "paint", "green paint"
{
override function getColor()
{
return "green";
}
}
object o_paint_blue : o_paint named "paint", "blue paint"
{
override function getColor()
{
return "blue";
}
}
object o_paint_yellow : o_paint named "paint", "yellow paint"
{
override function getColor()
{
return "yellow";
}
onActionWith(a_mix, o_paint_blue)
{
textln("Hey, it made green paint!");
giveObject(world, o_paint_green);
}
}
object o_paint_red : o_paint named "paint", "red paint"
{
override function getColor()
{
return "red";
}
onActionWith(a_mix, o_paint_yellow)
{
textln("Hey, it made orange paint!");
giveObject(world, o_paint_orange);
}
onActionWith(a_mix, o_paint_blue)
{
textln("Hey, it made purple paint!");
giveObject(world, o_paint_purple);
}
}
/********************************** All people. *******************************/
object archetype o_person
{
init()
{
talkedto = false;
}
// fallback on wrong paint.
onActionWithAncestor(a_give, o_paint)
{
textln("\"I don't want that color of paint!\"");
}
onActionWithOther(a_give)
{
textln("I don't think they want that.");
}
}
// It's a person named Bob!
object o_bob : o_person named "bob", "guy", "man"
{
onAction(a_talk)
{
if (!talkedto)
{
textln("Bob says, \"I want orange paint.\"");
talkedto = true;
}
else
{
textln("Bob says, \"I still want orange paint.\"");
}
}
onAction(a_examine)
{
textln("It's a guy named Bob.");
if (talkedto)
textln("He wants orange paint.");
}
onWorldBrowse()
{
textln("A guy named Bob is here.");
}
onActionWith(a_give, o_paint_orange)
{
textln("Bob says \"thank you\" and disappears.");
removeObject(o_paint_orange);
removeObject(o_bob);
}
}
// It's a woman named Susan!
object o_susan : o_person named "susan", "gal", "woman"
{
onAction(a_talk)
{
if (!talkedto)
{
textln("Susan says, \"I want purple paint.\"");
talkedto = true;
}
else
{
textln("Susan says, \"I still want purple paint.\"");
}
}
onAction(a_examine)
{
textln("It's a gal named Susan.");
if (talkedto)
textln("She wants purple paint.");
}
onWorldBrowse()
{
textln("A gal named Susan is here.");
}
onActionWith(a_give, o_paint_purple)
{
textln("Susan says \"thank you\" and disappears.");
removeObject(o_paint_purple);
removeObject(o_susan);
}
}
world
{
function winCheck()
{
textln("");
// check if Bob and Susan have absconded.
if (objectHasNoOwner(o_bob) & objectHasNoOwner(o_susan))
{
textln("Everyone is happy!");
quit;
}
else
{
browse(world);
}
}
start()
{
giveObject(world, o_bob);
giveObject(world, o_susan);
giveObject(world, o_paint_red);
giveObject(world, o_paint_yellow);
giveObject(world, o_paint_blue);
textln("These people need a color of paint.");
textln("TALK TO them to figure out what they want.");
textln("MIX the paint to make different colors, then GIVE the paint to them.");
winCheck();
}
onAction(a_quit)
{
quit;
}
onUnhandledAction(a_give)
{
textln("I can't give that to somebody.");
}
onUnhandledAction(a_mix)
{
textln("I can't mix those things together.");
}
onIncompleteCommand(a_give)
{
textln("What do you want to give to whom?");
}
onIncompleteCommand(a_mix)
{
textln("What do you want to mix with what?");
}
onIncompleteCommand(a_examine)
{
textln("What do you want to examine?");
}
onIncompleteCommand(a_talk)
{
textln("Who do you want to talk to?");
}
onAmbiguousCommand()
{
textln("Be more specific.");
}
onMalformedCommand(a_talk)
{
textln("I can't talk to that.");
}
onMalformedCommand()
{
textln("I don't understand.");
}
onUnknownCommand()
{
textln("I can't do that.");
}
afterSuccessfulCommand()
{
winCheck();
}
}