A plugin for actions, by which animate characters change the world model.
§1. Support for actions is contained in the "actions" plugin, which occupies this entire chapter.
void ActionsPlugin::start(void) { ActionsNodes::nodes_and_annotations(); PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, ActionsPlugin::make_special_meanings); PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, ActionsPlugin::new_base_kind_notify); PluginManager::plug(COMPILE_CONSTANT_PLUG, RTActions::actions_compile_constant); PluginManager::plug(OFFERED_PROPERTY_PLUG, ActionVariables::actions_offered_property); PluginManager::plug(OFFERED_SPECIFICATION_PLUG, ActionsPlugin::actions_offered_specification); PluginManager::plug(TYPECHECK_EQUALITY_PLUG, ActionsPlugin::actions_typecheck_equality); PluginManager::plug(PRODUCTION_LINE_PLUG, ActionsPlugin::production_line); Vocabulary::set_flags(Vocabulary::entry_for_text(L"doing"), ACTION_PARTICIPLE_MC); Vocabulary::set_flags(Vocabulary::entry_for_text(L"asking"), ACTION_PARTICIPLE_MC); } int ActionsPlugin::production_line(int stage, int debugging, stopwatch_timer *sequence_timer) { if (stage == INTER1_CSEQ) { BENCH(RTNamedActionPatterns::compile); BENCH(RTActions::ActionData); BENCH(RTActions::ActionCoding_array); BENCH(RTActions::ActionHappened); BENCH(RTActions::compile_action_routines); } return FALSE; }
§2. It may be useful to distinguish three ideas right from the outset:
- ● An "action" is a specific impulse by a person in the model world to effect some change within it: for example, "Henry taking the brick". Here Henry is the "actor", and the brick is "the noun". Actions can be "stored" so that they are values in their own right; thus, a variable could be set to the value "Henry taking the brick", and this would have kind K_stored_action.
- ● An "action name" — not an ideal thing to call it, but traditional — is the type of action involved, taken in isolation: for example, "taking". These can also be values at run-time, and have kind K_action_name.
- ● An "action pattern" is a textual description which matches some actions but not others, and can be vague or specific: for example, "wearing or examining something". Action patterns are in general not values, but names can be given to them so that they are — see Named Action Patterns — and then they have the kind K_description_of_action.
- ● A "past action pattern", which can never in any way be a value, is a description of an action which have happened in the past: for example, "dropped the hat".
kind *K_action_name = NULL; kind *K_stored_action = NULL; kind *K_description_of_action = NULL;
§3. These are created by a Neptune file inside WorldModelKit, and are recognised by their Inter identifiers:
int ActionsPlugin::new_base_kind_notify(kind *new_base, text_stream *name, wording W) { if (Str::eq_wide_string(name, L"ACTION_NAME_TY")) { K_action_name = new_base; return TRUE; } if (Str::eq_wide_string(name, L"DESCRIPTION_OF_ACTION_TY")) { K_description_of_action = new_base; return TRUE; } if (Str::eq_wide_string(name, L"STORED_ACTION_TY")) { K_stored_action = new_base; return TRUE; } return FALSE; }
§5. A stored action can always be compared to a gerund: for instance,
if the current action is taking something...
int ActionsPlugin::actions_typecheck_equality(kind *K1, kind *K2) { if ((Kinds::eq(K1, K_stored_action)) && (Kinds::eq(K2, K_description_of_action))) return TRUE; return FALSE; }
§6. Though K_action_name is very like an enumeration kind, its possible values, which correspond to action_name objects, are not strictly speaking instances in the Inform world model. (Because they do not have properties: see Action Variables for what they have instead.)
Two actions in particular are sacred: "going", because it has additional clauses in action patterns, and "waiting", because it is the default value for K_action_name values: waiting it is the zero of actions.
action_name *going_action = NULL; action_name *waiting_action = NULL;
§7. These are recognised by their English names when defined by the Standard Rules. (So there is no need to translate this to other languages.)
<notable-actions> ::= waiting | going
- This is Preform grammar, not regular C code.
§8. Because action_name values are not instances, we cannot recognise them when instances are created, and instead have to do it directly when this is called by the function creating them:
void ActionsPlugin::notice_new_action_name(action_name *an) { if (<notable-actions>(ActionNameNames::tensed(an, IS_TENSE))) { if ((<<r>> == 1) && (going_action == NULL)) going_action = an; if ((<<r>> == 0) && (waiting_action == NULL)) waiting_action = an; } } action_name *ActionsPlugin::default_action_name(void) { if (waiting_action == NULL) internal_error("wait action not ready"); return waiting_action; }
§9. And because K_action_name values have no properties, they cannot store a "specification" text as one, and have to make their own arrangements:
int ActionsPlugin::actions_offered_specification(parse_node *owner, wording W) { if (Rvalues::is_CONSTANT_of_kind(owner, K_action_name)) { IXActions::actions_set_specification_text( Rvalues::to_action_name(owner), Wordings::first_wn(W)); return TRUE; } return FALSE; }
§10. The rest of this section is given over to the Preform grammar for dealing with the special meaning "X is an action...", which creates new action names. These can be quite complicated:
Inserting it into is an action applying to two things.
Verifying the story file is an action out of world and applying to nothing.
int ActionsPlugin::make_special_meanings(void) { SpecialMeanings::declare(ActionsPlugin::new_action_SMF, I"new-action", 2); return FALSE; } action_name *an_being_parsed = NULL; int ActionsPlugin::new_action_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "Taking something is an action." case ACCEPT_SMFT: Check that this validly declares an action10.1; break; case PASS_1_SMFT: Parse the subject and object phrases10.2; break; } return FALSE; }
§10.1. Check that this validly declares an action10.1 =
if (<new-action-sentence-object>(OW)) { if (<<r>> == FALSE) return FALSE; parse_node *O = <<rp>>; <np-unparsed>(SW); V->next = <<rp>>; V->next->next = O; return TRUE; }
- This code is used in §10.
§11. <nounphrase-actionable> here is an awkward necessity, designed to prevent the regular sentence "The impulse is an action name that varies" from being parsed as an instance of "... is an action ...", creating a new action.
<new-action-sentence-object> ::= <indefinite-article> <new-action-sentence-object-unarticled> | ==> { pass 2 } <new-action-sentence-object-unarticled> ==> { pass 1 } <new-action-sentence-object-unarticled> ::= action <nounphrase-actionable> | ==> { TRUE, RP[1] } action ==> Issue PM_BadActionDeclaration problem11.1 <nounphrase-actionable> ::= ^<variable-creation-tail> ==> { 0, Diagrams::new_UNPARSED_NOUN(W) } <variable-creation-tail> ::= *** that/which vary/varies | *** variable
- This is Preform grammar, not regular C code.
§11.1. Issue PM_BadActionDeclaration problem11.1 =
Problems::Using::assertion_problem(Task::syntax_tree(), _p_(PM_BadActionDeclaration), "it is not sufficient to say that something is an 'action'", "without giving the necessary details: for example, 'Unclamping " "is an action applying to one thing.'"); ==> { FALSE, NULL };
- This code is used in §11.
§10.2. Supposing that all that worked, the SP of the sentence is the name for the new action, and the OP can include a wide range of details about it.
Parse the subject and object phrases10.2 =
if ((V->next) && (V->next->next)) if (<action-sentence-subject>(Node::get_text(V->next))) { an_being_parsed = <<rp>>; an_being_parsed->indexing_data.designers_specification = V->next->next; ActionsPlugin::clear_clauses(); <action-sentence-object>(Node::get_text(V->next->next)); }
- This code is used in §10.
§12. The subject noun phrase needs little further parsing — it's the name of the action-to-be. A successful match here causes the new action_name structure to be created.
<action-sentence-subject> ::= <action-name> | ==> Issue PM_ActionAlreadyExists problem12.1 ... ==> { 0, PL::Actions::act_new(W) }
- This is Preform grammar, not regular C code.
§12.1. Issue PM_ActionAlreadyExists problem12.1 =
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ActionAlreadyExists), "that seems to be an action already existing", "so it cannot be redefined now. If you would like to reconfigure " "an action in the standard set - for instance if you prefer " "'unlocking' to apply to only one thing, not two - create a new " "action for what you need ('keyless unlocking', perhaps) and then " "change the grammar to use the new action rather than the old " "('Understand \"unlock [something]\" as keyless unlocking.')."); ==> { fail nonterminal };
- This code is used in §12.
§13. The object NP is a sequence of "action clauses" which can occur in any order, which are allowed but not required to be delimited as a list, and which can inconveniently contain the word "and"; not only that, but note that in
applying to one thing and one number
the initial text "applying to one thing" would be valid as it stands.
<action-sentence-object> ::= <action-clauses> | ==> { 0, - } ... ==> Issue PM_ActionClauseUnknown problem13.9 <action-clauses> ::= ... | ==> { lookahead } <action-clauses> <action-clause-terminated> | ==> { R[2], - }; ActionsPlugin::clause(R[2]); <action-clause-terminated> ==> { R[1], - }; ActionsPlugin::clause(R[1]); <action-clause-terminated> ::= <action-clause> , and | ==> { pass 1 } <action-clause> and | ==> { pass 1 } <action-clause> , | ==> { pass 1 } <action-clause> ==> { pass 1 } <action-clause> ::= out of world | ==> { OOW_ACT_CLAUSE, - }; Make out of world13.1 abbreviable | ==> { ABBREV_ACT_CLAUSE, - }; Make abbreviable13.2 with past participle ... | ==> { PP_ACT_CLAUSE, - }; Give irregular participle13.3 applying to <action-applications> | ==> { APPLYING_ACT_CLAUSE, - } requiring light ==> { LIGHT_ACT_CLAUSE, - }; Require light13.4 <action-applications> ::= nothing | one <act-req> and one <act-req> | ==> Set kind and access for two13.7 one <act-req> and <act-req> | ==> Set kind and access for two13.7 <act-req> and one <act-req> | ==> Set kind and access for two13.7 <act-req> and <act-req> | ==> Set kind and access for two13.7 nothing or one <act-req> | ==> Set kind and access for an optional one13.5 one <act-req> | ==> Set kind and access for one13.6 two <act-req> | ==> Set kind and access for one, doubling up13.8 <act-req> | ==> Set kind and access for one13.6 ... ==> Issue PM_ActionMisapplied problem13.10; <act-req> ::= <act-req-inner> ==> Check action kind13.11; <act-req-inner> ::= <action-access> <k-kind> | ==> { R[1], RP[2] } <k-kind> ==> { UNRESTRICTED_ACCESS, RP[1] } <action-access> ::= visible | ==> { DOESNT_REQUIRE_ACCESS, - } touchable | ==> { REQUIRES_ACCESS, - } carried ==> { REQUIRES_POSSESSION, - }
- This is Preform grammar, not regular C code.
§13.1. Make out of world13.1 =
ActionSemantics::make_action_out_of_world(an_being_parsed);
- This code is used in §13.
ActionNameNames::make_abbreviable(an_being_parsed);
- This code is used in §13.
§13.3. Give irregular participle13.3 =
ActionNameNames::set_irregular_past(an_being_parsed, GET_RW(<action-clause>, 1));
- This code is used in §13.
ActionSemantics::make_action_require_light(an_being_parsed);
- This code is used in §13.
§13.5. Set kind and access for an optional one13.5 =
ActionSemantics::give_action_an_optional_noun(an_being_parsed, R[1], RP[1]);
- This code is used in §13.
§13.6. Set kind and access for one13.6 =
ActionSemantics::give_action_one_noun(an_being_parsed, R[1], RP[1]);
- This code is used in §13 (twice).
§13.7. Set kind and access for two13.7 =
ActionSemantics::give_action_two_nouns(an_being_parsed, R[1], RP[1], R[2], RP[2]);
- This code is used in §13 (four times).
§13.8. Set kind and access for one, doubling up13.8 =
ActionSemantics::give_action_two_nouns(an_being_parsed, R[1], RP[1], R[1], RP[1]);
- This code is used in §13.
§13.9. Issue PM_ActionClauseUnknown problem13.9 =
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ActionClauseUnknown), "the action definition contained text I couldn't follow", "and may be too complicated.");
- This code is used in §13.
§13.10. Issue PM_ActionMisapplied problem13.10 =
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ActionMisapplied), "an action can only apply to things or to kinds of value", "for instance: 'photographing is an action applying to " "one visible thing'."); ==> { REQUIRES_ACCESS, K_thing };
§13.11. Check action kind13.11 =
int A = R[1]; kind *K = RP[1]; if (Kinds::eq(K, K_thing)) { if (A == UNRESTRICTED_ACCESS) A = REQUIRES_ACCESS; ==> { A, K_object }; } else if (Kinds::Behaviour::is_subkind_of_object(K)) { Issue PM_ActionMisapplied problem13.10; } else if (A != UNRESTRICTED_ACCESS) { Issue PM_ActionMisapplied problem13.10; } else { ==> { A, K }; }
- This code is used in §13.
§14. For years this was not erroneous, but you now can't write, say, "X is an action applying to nothing, applying to nothing, requiring light and applying to nothing".
define OOW_ACT_CLAUSE 1 define PP_ACT_CLAUSE 2 define APPLYING_ACT_CLAUSE 3 define LIGHT_ACT_CLAUSE 4 define ABBREV_ACT_CLAUSE 5
int an_clauses_filled[6]; void ActionsPlugin::clear_clauses(void) { for (int i=1; i<=5; i++) an_clauses_filled[i] = FALSE; } void ActionsPlugin::clause(int N) { if (an_clauses_filled[N]) StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ActionClauseRepeated), "that seems to repeat a clause", "or to specify something twice over."); an_clauses_filled[N] = TRUE; }