mirror of
https://github.com/ganelson/inform.git
synced 2024-07-17 22:44:25 +03:00
313 lines
16 KiB
HTML
313 lines
16 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html>
|
||
|
<head>
|
||
|
<title>S/rt3</title>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<meta http-equiv="Content-Language" content="en-gb">
|
||
|
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
||
|
</head>
|
||
|
<body>
|
||
|
|
||
|
<!--Weave of 'S/rt4' generated by 7-->
|
||
|
<ul class="crumbs"><li><a href="../webs.html">★</a></li><li><a href="index.html">basic_inform Template Library</a></li><li><b>Rulebooks Template</b></li></ul><p class="purpose">To work through the rules in a rulebook until a decision is made.</p>
|
||
|
|
||
|
<ul class="toc"><li><a href="#SP1">§1. Latest Rule Result</a></li><li><a href="#SP2">§2. Following</a></li><li><a href="#SP3">§3. Specifying Outcomes</a></li><li><a href="#SP4">§4. Discovering Outcomes</a></li><li><a href="#SP5">§5. Printing Rule Names</a></li><li><a href="#SP6">§6. Casting</a></li><li><a href="#SP7">§7. Debugging</a></li></ul><hr class="tocbar">
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Latest Rule Result. </b>This used to be a large data structure which kept track of the effect of
|
||
|
procedural rules, but in January 2011 procedurals were abolished. It retains
|
||
|
only one purpose: as a place to record the result of the most recently
|
||
|
completed rule. This used to sit on the top of the stack, and is now the
|
||
|
only thing which ever sits on it. So the "stack" has just one 3-word
|
||
|
record now. The meanings of these are as follows. The first word is one of
|
||
|
the following:
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<ul class="items"><li>(1) <code class="display"><span class="extract">RS_SUCCEEDS</span></code> indicates that the most recent rule or rulebook processed
|
||
|
ended in success. Word 2 is <code class="display"><span class="extract">false</span></code> if there's no value, or the kind if there
|
||
|
is, in which case word 3 contains the value itself.
|
||
|
</li><li>(2) <code class="display"><span class="extract">RS_FAILS</span></code> is similar, but for a failure. Note that failures can also
|
||
|
return values.
|
||
|
</li><li>(3) <code class="display"><span class="extract">RS_NEITHER</span></code> is similar except that it cannot return any value, so that
|
||
|
words 2 and 3 are meaningless.
|
||
|
</li></ul>
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">Constant RS_NEITHER = 0;</span>
|
||
|
<span class="plain">Constant RS_SUCCEEDS = 1;</span>
|
||
|
<span class="plain">Constant RS_FAILS = 2;</span>
|
||
|
|
||
|
<span class="plain">Array latest_rule_result --> 3;</span>
|
||
|
|
||
|
<span class="plain">[ RecordRuleOutcome usage rule1 rule2;</span>
|
||
|
<span class="plain">if ((latest_rule_result-->0 == RS_SUCCEEDS or RS_FAILS) &&</span>
|
||
|
<span class="plain">(KOVIsBlockValue(latest_rule_result-->1)))</span>
|
||
|
<span class="plain">BlkValueFree(latest_rule_result-->2);</span>
|
||
|
<span class="plain">if ((usage == RS_SUCCEEDS or RS_FAILS) && (KOVIsBlockValue(rule1)))</span>
|
||
|
<span class="plain">rule2 = BlkValueCopy(BlkValueCreate(rule1), rule2);</span>
|
||
|
<span class="plain">latest_rule_result-->0 = usage;</span>
|
||
|
<span class="plain">latest_rule_result-->1 = rule1;</span>
|
||
|
<span class="plain">latest_rule_result-->2 = rule2;</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. Following. </b>Until January 2011, there were two ways to invoke a rulebook: to "follow" it
|
||
|
or simply "process" it. With the demise of procedural rules, these became
|
||
|
equivalent.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph">In the early days of Inform 7, stack usage became a serious issue since
|
||
|
some forms of the Frotz Z-machine interpreter provided only 4K of stack
|
||
|
by default. ("Only" 4K. In the mid-1980s, one of the obstacles facing
|
||
|
IF authors at Infocom was the need to get the stack usage down to fewer
|
||
|
than 600 bytes in order that the story file could be run on the smaller
|
||
|
home computers of the day.) <code class="display"><span class="extract">FollowRulebook</span></code> was the major consumer of
|
||
|
stack space, on average, because of its frequent recursion. Now that the
|
||
|
process is simpler, this has become less problematic, since the routine
|
||
|
now has fewer local variables.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"><code class="display"><span class="extract">FollowRulebook</span></code> takes three arguments, of which only the first is
|
||
|
compulsory:
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<ul class="items"><li>(a) The <code class="display"><span class="extract">rulebook</span></code> is an I7 value of kind "rule", which means it can be
|
||
|
either the ID number of a rulebook — from 0 up to N-1, where N is the
|
||
|
number of rulebooks compiled by Inform, typically about 600 — or else the
|
||
|
address of a routine representing an individual rule.
|
||
|
</li><li>(b) The <code class="display"><span class="extract">parameter</span></code> supplied to the rulebook. Much as arguments can be supplied
|
||
|
to a function in a conventional language's function call, so a parameter can be
|
||
|
supplied whenever a rulebook is invoked.
|
||
|
</li><li>(c) <code class="display"><span class="extract">no_paragraph_skips</span></code> is a flag: if explicitly set <code class="display"><span class="extract">true</span></code>, then the rulebook
|
||
|
is run with paragraph breaking suppressed. This is the process by which
|
||
|
paragraph division points are placed between rules, so that if two rules both
|
||
|
print text then a paragraph break appears between. While that is appropriate
|
||
|
for rulebooks attached to actions or for "every turn" rules, it is disastrous
|
||
|
for rulebooks attached to activities such as "printing the name of
|
||
|
something".
|
||
|
</li></ul>
|
||
|
<p class="inwebparagraph"><code class="display"><span class="extract">FollowRulebook</span></code> returns <code class="display"><span class="extract">R</span></code> if rule <code class="display"><span class="extract">R</span></code> in the rulebook (or rule) chose to
|
||
|
"succeed" or "fail", and <code class="display"><span class="extract">false</span></code> if it made no choice. (To repeat: if
|
||
|
the rule explicitly fails, then <code class="display"><span class="extract">FollowRulebook</span></code> returns <code class="display"><span class="extract">true</span></code>. It's easy
|
||
|
to write plausible-looking code which goes wrong because it assumes that the
|
||
|
return value is success vs. failure.) The outcome of <code class="display"><span class="extract">FollowRulebook</span></code> is
|
||
|
stored as described above: thus the most recent rule or rulebook succeeded
|
||
|
or failed if —
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">(latest_rule_result-->0 == RS_SUCCEEDS)</span>
|
||
|
<span class="plain">(latest_rule_result-->0 == RS_FAILS)</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph">and otherwise there was no decision.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">Global process_rulebook_count; ! Depth of processing recursion</span>
|
||
|
<span class="plain">Global debugging_rules = false; ! Are we tracing rule invocations?</span>
|
||
|
|
||
|
<span class="plain">[ FollowRulebook rulebook parameter no_paragraph_skips</span>
|
||
|
<span class="plain">rv ss spv;</span>
|
||
|
<span class="plain">ss = self;</span>
|
||
|
<span class="plain">if ((Protect_I7_Arrays-->0 ~= 16339) || (Protect_I7_Arrays-->1 ~= 12345)) {</span>
|
||
|
<span class="plain">print "^^*** Fatal programming error: I7 arrays corrupted ***^^";</span>
|
||
|
<span class="plain">@quit;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">if (parameter) { self = parameter; parameter_object = parameter; }</span>
|
||
|
<span class="plain">spv = parameter_value; parameter_value = parameter;</span>
|
||
|
<span class="plain">! we won't need parameter again, so can reuse it</span>
|
||
|
<span class="plain">parameter = debugging_rules;</span>
|
||
|
<span class="plain">#ifndef MEMORY_ECONOMY;</span>
|
||
|
<span class="plain">if (debugging_rules) {</span>
|
||
|
<span class="plain">DebugRulebooks(rulebook, parameter);</span>
|
||
|
<span class="plain">process_rulebook_count = process_rulebook_count + debugging_rules;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">#endif;</span>
|
||
|
<span class="plain">if ((rulebook >= 0) && (rulebook < NUMBER_RULEBOOKS_CREATED)) {</span>
|
||
|
<span class="plain">rv = rulebooks_array-->rulebook;</span>
|
||
|
<span class="plain">if (rv ~= EMPTY_RULEBOOK) {</span>
|
||
|
<span class="plain">if (rulebook ~= ACTION_PROCESSING_RB) MStack_CreateRBVars(rulebook);</span>
|
||
|
<span class="plain">if (say__p) RulebookParBreak(no_paragraph_skips);</span>
|
||
|
<span class="plain">rv = rv(no_paragraph_skips);</span>
|
||
|
<span class="plain">if (rulebook ~= ACTION_PROCESSING_RB) MStack_DestroyRBVars(rulebook);</span>
|
||
|
<span class="plain">} else {</span>
|
||
|
<span class="plain">rv = 0;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">} else {</span>
|
||
|
<span class="plain">if (say__p) RulebookParBreak(no_paragraph_skips);</span>
|
||
|
<span class="plain">rv = indirect(rulebook);</span>
|
||
|
<span class="plain">if (rv == 2) rv = reason_the_action_failed;</span>
|
||
|
<span class="plain">else if (rv) rv = rulebook;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">if (rv) {</span>
|
||
|
<span class="plain">#ifndef MEMORY_ECONOMY;</span>
|
||
|
<span class="plain">if (debugging_rules) {</span>
|
||
|
<span class="plain">process_rulebook_count = process_rulebook_count - debugging_rules;</span>
|
||
|
<span class="plain">if (process_rulebook_count < 0) process_rulebook_count = 0;</span>
|
||
|
<span class="plain">spaces(2*process_rulebook_count);</span>
|
||
|
<span class="plain">if (latest_rule_result-->0 == RS_SUCCEEDS) print "[stopped: success]^";</span>
|
||
|
<span class="plain">if (latest_rule_result-->0 == RS_FAILS) print "[stopped: fail]^";</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">#endif;</span>
|
||
|
<span class="plain">} else {</span>
|
||
|
<span class="plain">if (debugging_rules)</span>
|
||
|
<span class="plain">process_rulebook_count = process_rulebook_count - debugging_rules;</span>
|
||
|
<span class="plain">latest_rule_result-->0 = RS_NEITHER;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">debugging_rules = parameter;</span>
|
||
|
<span class="plain">self = ss; parameter_value = spv;</span>
|
||
|
<span class="plain">return rv;</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RulebookParBreak no_paragraph_skips;</span>
|
||
|
<span class="plain">if ((no_paragraph_skips == false) && (say__pc & PARA_NORULEBOOKBREAKS == 0))</span>
|
||
|
<span class="plain">DivideParagraphPoint();</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. Specifying Outcomes. </b>The following provide ways for rules to succeed, fail or decline to do
|
||
|
either.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"><code class="display"><span class="extract">SetRulebookOutcome</span></code> is a little different: it changes the outcome state
|
||
|
of the most recent rule completed, not the current one. (It's used only
|
||
|
when saving and restoring this in the actions machinery: rules should not
|
||
|
call it.)
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">[ ActRulebookSucceeds rule_id;</span>
|
||
|
<span class="plain">if (rule_id) reason_the_action_failed = rule_id;</span>
|
||
|
<span class="plain">RulebookSucceeds();</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ ActRulebookFails rule_id;</span>
|
||
|
<span class="plain">if (rule_id) reason_the_action_failed = rule_id;</span>
|
||
|
<span class="plain">RulebookFails();</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RulebookSucceeds weak_kind value;</span>
|
||
|
<span class="plain">RecordRuleOutcome(RS_SUCCEEDS, weak_kind, value);</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RulebookFails weak_kind value;</span>
|
||
|
<span class="plain">RecordRuleOutcome(RS_FAILS, weak_kind, value);</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RuleHasNoOutcome;</span>
|
||
|
<span class="plain">RecordRuleOutcome(RS_NEITHER, 0, 0);</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ SetRulebookOutcome a;</span>
|
||
|
<span class="plain">latest_rule_result-->0 = a;</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. Discovering Outcomes. </b>And here is how to tell what the results were.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">[ RulebookOutcome a;</span>
|
||
|
<span class="plain">a = latest_rule_result-->0;</span>
|
||
|
<span class="plain">if ((a == RS_FAILS) || (a == RS_SUCCEEDS)) return a;</span>
|
||
|
<span class="plain">return RS_NEITHER;</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RulebookFailed;</span>
|
||
|
<span class="plain">if (latest_rule_result-->0 == RS_FAILS) rtrue; rfalse;</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ RulebookSucceeded;</span>
|
||
|
<span class="plain">if (latest_rule_result-->0 == RS_SUCCEEDS) rtrue; rfalse;</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ ResultOfRule RB V F K a;</span>
|
||
|
<span class="plain">if (RB) FollowRulebook(RB, V, F);</span>
|
||
|
<span class="plain">a = latest_rule_result-->0;</span>
|
||
|
<span class="plain">if ((a == RS_FAILS) || (a == RS_SUCCEEDS)) {</span>
|
||
|
<span class="plain">a = latest_rule_result-->1;</span>
|
||
|
<span class="plain">if (a) return latest_rule_result-->2;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">if (K) return DefaultValueOfKOV(K);</span>
|
||
|
<span class="plain">return 0;</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. Printing Rule Names. </b>This is the I6 printing rule used for a value of kind "rule", which as
|
||
|
noted above can either be rulebook ID numbers in the range 0 to N-1 or
|
||
|
are addresses of individual rules.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph">Names of rules and rulebooks take up a fair amount of space, and one of the
|
||
|
main memory economies enforced by the "Use memory economy" option is to
|
||
|
omit the necessary arrays. (It's not the text which is the problem so
|
||
|
much as the table of addresses pointing to that text, which has to live in
|
||
|
precious readable memory on the Z-machine.)
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP6"></a><b>§6. Casting. </b>Nothing needs to be done to a rulebook value to make it a rule value.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">[ RULEBOOK_TY_to_RULE_TY r;</span>
|
||
|
<span class="plain">return r;</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. Debugging. </b>Two modest routines to print out the names of rules and rulebooks when they
|
||
|
occur, in so far as memory economy allows this.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="plain">[ DebugRulebooks subs parameter i;</span>
|
||
|
<span class="plain">spaces(2*process_rulebook_count);</span>
|
||
|
<span class="plain">print "[", (RulePrintingRule) subs;</span>
|
||
|
<span class="plain">if (parameter) print " / on O", parameter;</span>
|
||
|
<span class="plain">print "]^";</span>
|
||
|
<span class="plain">];</span>
|
||
|
|
||
|
<span class="plain">[ DB_Rule R N blocked;</span>
|
||
|
<span class="plain">if (R==0) return;</span>
|
||
|
<span class="plain">print "[Rule ~", (RulePrintingRule) R, "~ ";</span>
|
||
|
<span class="plain">#ifdef NUMBERED_RULES; print "(", N, ") "; #endif;</span>
|
||
|
<span class="plain">if (blocked == false) "applies.]";</span>
|
||
|
<span class="plain">print "does not apply (wrong ";</span>
|
||
|
<span class="plain">if (blocked == 1) print "scene";</span>
|
||
|
<span class="plain">if (blocked == 2) print "action";</span>
|
||
|
<span class="plain">if (blocked == 3) print "actor";</span>
|
||
|
<span class="plain">if (blocked == 4) print "context";</span>
|
||
|
<span class="plain">print ").]^";</span>
|
||
|
<span class="plain">];</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<hr class="tocbar">
|
||
|
<ul class="toc"><li><a href="S-rt3.html">Back to 'RTP Template'</a></li><li><a href="S-st.html">Continue with 'Sort Template'</a></li></ul><hr class="tocbar">
|
||
|
<!--End of weave-->
|
||
|
</body>
|
||
|
</html>
|
||
|
|