Activities contents
The Activities Stack.
Activities are more like nested function calls than independent processes; they finish in reverse order of starting, and are placed on a stack. This needs only very limited size in practice: 20 might seem a bit low, but making it much higher simply means that oddball bugs in the user's code – where activities recursively cause themselves ad infinitum – will be caught less efficiently.
16Constant MAX_NESTED_ACTIVITIES = 20;
17Global activities_sp = 0;
18Array activities_stack --> MAX_NESTED_ACTIVITIES;
19Array activity_parameters_stack --> MAX_NESTED_ACTIVITIES;
Rule Debugging Inhibition.
The output from RULES or RULES ALL becomes totally illegible if it is applied even to the activities printing names of objects, so this is inhibited when any such activity is running. FixInhibitFlag is called each time the stack changes and ensures that inhibit_flag has exactly this meaning.
28Global inhibit_flag = 0;
29Global saved_debug_rules = 0;
30[ FixInhibitFlag n act inhibit_rule_debugging;
31 for (n=0:n<activities_sp:n++) {
32 act = activities_stack-->n;
33 if (act == PRINTING_THE_NAME_ACT or PRINTING_THE_PLURAL_NAME_ACT or
34 PRINTING_ROOM_DESC_DETAILS_ACT or PRINTING_INVENTORY_DETAILS_ACT or
35 LISTING_CONTENTS_ACT or GROUPING_TOGETHER_ACT or PRINTING_RESPONSE_ACT)
36 inhibit_rule_debugging = true;
37 }
38 if ((inhibit_flag == false) && (inhibit_rule_debugging)) {
39 saved_debug_rules = debug_rules;
40 debug_rules = 0;
41 }
42 if ((inhibit_flag) && (inhibit_rule_debugging == false)) {
43 debug_rules = saved_debug_rules;
44 }
45 inhibit_flag = inhibit_rule_debugging;
46];
Testing Activities.
The following tests whether a given activity A is currently running whose parameter-object matches description desc, where as usual the description is represented by a routine testing membership, and where zero desc means that any parameter is valid. Alternatively, we can require a specific parameter value of val.
56[ TestActivity A desc val i;
57 for (i=0:i<activities_sp:i++)
58 if (activities_stack-->i == A) {
59 if (desc) {
60 if ((desc)(activity_parameters_stack-->i)) rtrue;
61 } else if (val) {
62 if (val == activity_parameters_stack-->i) rtrue;
63 } else rtrue;
64 }
65 rfalse;
66];
Emptiness.
An activity is defined by its three rulebooks: it is empty if they are all empty.
73[ ActivityEmpty A x;
74 x = Activity_before_rulebooks-->A;
75 if (rulebooks_array-->x ~= EMPTY_RULEBOOK) rfalse;
76 x = Activity_for_rulebooks-->A;
77 if (rulebooks_array-->x ~= EMPTY_RULEBOOK) rfalse;
78 x = Activity_after_rulebooks-->A;
79 if (rulebooks_array-->x ~= EMPTY_RULEBOOK) rfalse;
80 rtrue;
81];
82
83[ RulebookEmpty rb;
84 if (rulebooks_array-->rb ~= EMPTY_RULEBOOK) rfalse;
85 rtrue;
86];
Process Activity Rulebook.
This is really much like processing any rulebook, except that self is temporarily set to the parameter, and is preserved by the process.
93[ ProcessActivityRulebook rulebook parameter rv;
94 @push self;
95 if (parameter) self = parameter;
96 rv = FollowRulebook(rulebook, parameter, true);
97 @pull self;
98 if (rv) rtrue;
99 rfalse;
100];
Carrying Out Activities.
This is a three-stage process; most activities are run by calling the following simple routine, but some are run by calling the three subroutines independently.
107[ CarryOutActivity A o rv;
108 BeginActivity(A, o);
109 rv = ForActivity(A, o);
110 EndActivity(A, o);
111 return rv;
112];
Begin.
Note that when an activity based on the conjectural "future action" is being run – in a few parser-related cases, that is – the identity of this action is put temporarily into action, and the current value saved while this takes place. That allows rules in the activity rulebooks to have preambles based on the current action, and yet be tested against what is not yet the current action.
123[ BeginActivity A o x;
124 if (activities_sp == MAX_NESTED_ACTIVITIES) return RunTimeProblem(RTP_TOOMANYACTS);
125 activity_parameters_stack-->activities_sp = o;
126 activities_stack-->(activities_sp++) = A;
127 FixInhibitFlag();
128 MStack_CreateAVVars(A);
129 if (Activity_atb_rulebooks->A) { x = action; action = action_to_be; }
130 o = ProcessActivityRulebook(Activity_before_rulebooks-->A, o);
131 if (Activity_atb_rulebooks->A) action = x;
132 return o;
133];
138[ ForActivity A o x;
139 if (Activity_atb_rulebooks->A) { x = action; action = action_to_be; }
140 o = ProcessActivityRulebook(Activity_for_rulebooks-->A, o);
141 if (Activity_atb_rulebooks->A) action = x;
142 return o;
143];
148[ EndActivity A o rv x;
149 if ((activities_sp > 0) && (activities_stack-->(activities_sp-1) == A)) {
150 if (Activity_atb_rulebooks->A) { x = action; action = action_to_be; }
151 rv = ProcessActivityRulebook(Activity_after_rulebooks-->A, o);
152 if (Activity_atb_rulebooks->A) action = x;
153 activities_sp--; FixInhibitFlag();
154 MStack_DestroyAVVars(A);
155 return rv;
156 }
157 return RunTimeProblem(RTP_CANTABANDON);
158];
Abandon.
For (very) rare cases where an activity must be abandoned midway; such an activity must be being run by calling the three stages individually, and EndActivity must not have been called yet.
166[ AbandonActivity A o;
167 if ((activities_sp > 0) && (activities_stack-->(activities_sp-1) == A)) {
168 activities_sp--; FixInhibitFlag();
169 MStack_DestroyAVVars(A);
170 return;
171 }
172 return RunTimeProblem(RTP_CANTEND);
173];