# Repeat Through a Rulebook

## version 4 by Ron Newcomb

**Section - PseudoProcessRulebook and PseudoDB_Rule**

[ PseudoProcessRulebook IS CALLED FOR 3 DIFFERENT PURPOSES:

(1): enumerating each rule in a modified rulebook for a REPEAT loop: repeat with R running through Rulebook X

(2): counting the number of rules in a modified rulebook: the number of rules in Rulebook X

(3): searching to see if a particular rule will be considered when a particular modified rulebook is called under the currently in effect Procedural rules: if R is listed in Rulebook X

]

Include (-

[ PseudoDB_Rule n R rreason;

#ifdef LOOP_THRU_RULEBOOKS;

if (R==0) return;

print "@31[Rule ~", (RulePrintingRule) R, "~ ", (string) n;

if (rreason ~= (+directly invoked+)) print " because it was ", (PrintRuleReason) rreason;

print ".]^";

#endif;

rfalse;

];

! This is a recursive routine, and will return TRUE if it was a subcall finishing. The top-level call returns FALSE

[ PseudoProcessRulebook rulebook bits rv rreason

x frame_base substituted_rule usage rbaddress ra gc ga;

(+The reason the rule ran+) = rreason;

#ifdef LOOP_THRU_RULEBOOKS_E;

print "[Considering ~", (RulePrintingRule) rulebook, "~";

if (rreason ~= (+directly invoked+)) print " because it was ", (PrintRuleReason) rreason;

print "...]^";

#endif;

if (rulebook == LITTLE_USED_DO_NOTHING_R)

rfalse;

if (bits)

bits = RS_ACTIVITY | RS_NOSKIPS;

if (rule_frames<0)

rfalse;

! find beginning of rule change stack and stick it in X (so, X = usage ("ignore", "substitute", etc.), X+1 = rulebook 1, X+2 = rulebook2

for (x = rulechange_sp-3: x>=0: x = x - 3)

{

usage = rulechange_stack-->x;

if (usage == RS_FRAME)

{

x=x+3;

break; ! whoops, too far! back up and then we're done, X = beginning of rule change stack

}

if (rulechange_stack-->(x+1) == rulebook)

{

bits = bits | RS_AFFECTED_BIT;

if (usage == RS_MOVEBEFORE or RS_MOVEAFTER)

bits = bits | RS_MOVED_BIT;

}

if (rulechange_stack-->(x+2) == rulebook)

bits = bits | RS_AFFECTED_BIT;

}

if (x<0)

x=0;

frame_base = x;

! now X and frame_base are safely at bottom of the current rule stack

! if the rulebook we're processing is the victim (not anchor) of a MOVE, skip it (the calling PseudoProcessRulebook() sets rv to true to exempt the anchor)

if ((bits & RS_MOVED_BIT) && (rv == false))

return PseudoDB_Rule("would have been moved away", rulebook, rreason);

bits = bits | RS_ACTIVE_BIT | RS_USERESULT_BIT; ! assume each rule is instated and its result (if any) would be used

substituted_rule = rulebook; ! substituted_rule will hold the rule to execute -- including the original if nothing is substituted in

if (bits & RS_AFFECTED_BIT) ! OPTIMIZATION: only process proc. rules if our rule(book) was affected by one

! Step through the rule stack, from bottom to top, using the bits to see which Procedural Rule is the most current.

for (: x<rulechange_sp: x = x + 3)

{

usage = rulechange_stack-->x;

if (rulechange_stack-->(x+1) == rulebook)

{

switch (usage)

{

RS_DONOTRUN: bits = bits & (~RS_ACTIVE_BIT);

RS_RUN: bits = bits | ( RS_ACTIVE_BIT);

RS_DONOTUSE: bits = bits & (~RS_USERESULT_BIT);

RS_USE: bits = bits | ( RS_USERESULT_BIT);

RS_SUBSTITUTE: substituted_rule = rulechange_stack-->(x+2);

}

}

! if another rulebook was "moved before" the rule(book) we're running, run that now!

if ((usage == RS_MOVEBEFORE) && (rulechange_stack-->(x+2) == rulebook))

{

!PseudoDB_Rule("has a rule(book) ~moved before~", rulebook, rreason);

PseudoProcessRulebook(rulechange_stack-->(x+1), (bits & RS_ACTIVITY ~= 0), true, (+moved before+));

}

} ! end FOR loop

! if the rule(book) we're processing has been "ignored" then return; we won't run it (or any rule that was "moved after" it)

if ((bits & RS_ACTIVE_BIT) == 0)

return PseudoDB_Rule("would be ignored", rulebook, rreason);

! otherwise, let's execute this rule(book) !

!!!!!!!!!!!!!!!!!!!

! here we differentiate between (1) repeating through a rulebook, (2) counting rules, and (3) answering IS LISTED IN

if ((ReasonForIterating == 1) && (LookingForRuleInRulebook == NULL))

{ ! if the rule we're Looking To Follow is NULL, that means it was just previously found, and so *this* rule is the Next Rule After. Return it

#ifdef LOOP_THRU_RULEBOOKS_F;

print "[FOUND ~", (RulePrintingRule) substituted_rule, "~].^";

#endif;

LookingForRuleInRulebook = substituted_rule;

DoneSearchingRulebooks = 1;

rfalse; ! (1) returns in triumph!

}

! at this point, if it's (1) it still has some searching to do

if (LookingForRuleInRulebook == substituted_rule) ! if the rule we're looking for is this current rule, then IS LISTED IN will return immediately, but NEXTAFTER will know the next rule is the one it's searching for

{

LookingForRuleInRulebook = NULL; ! found it! inform this function and the Calling funciton via clearing its variable

if (ReasonForIterating == 3) ! if IS CURRENTLY LISTED IN, return in triumph

{

DoneSearchingRulebooks = 1;

rfalse;

}

}

!!!!!!!!!!!!!!!!!!!

! if substituted_rule (or the original rule, which may be in that variable!!) is valid... execute every rule within it

if ((substituted_rule >= 0) && (substituted_rule < {-value:NUMBER_CREATED(rulebook)})) ! if substituted_rule is a rulebook, not a rule (specifically, it is the Inform 6 ID# for a rulebook, 0 thru 380+)

{ ! "ra" means "rule address" -- the rule itself

rbaddress = rulebooks_array-->substituted_rule; ! each rulebook is an array of rules; get it

x = 0; ! index to step through each rule

ra = rbaddress-->0; ! get the first entry of that array, which is a Rule, a NULL, or SPECIAL

PseudoDB_Rule("would apply all of its rules", rulebook, rreason);

if (ra == NULL) ! then we have an empty rulebook

jump RulebookPseudoprocessed;

rv = (bits & RS_ACTIVITY ~= 0);

if (ra ~= (-2)) ! then ra is the first rule

{

for ( : ra ~= NULL : x++, ra = rbaddress-->x)

{

PseudoProcessRulebook(ra, rv, false, (+directly invoked+));

if (DoneSearchingRulebooks == 1)

rfalse;

}

}

else ! (ra == -2) ! ra is SPECIAL; I don't know what that is, but some extra info is spliced into the array

{

x = 1; ! index of the first rule

for (ra = rbaddress-->x : ra ~= NULL : x++, ra = rbaddress-->x)

{

if (gc == 0)

{

ga = ra; ! supposed to be another -2, or an action

x++;

gc = rbaddress-->x; ! supposed to be the length of the spliced-in info, in the range 1 -- 31

if ((gc<1) || (gc>31))

{

gc = 1; ! if out of bounds, set to length 1, and -->x will not be the Rule Address

x--;

}

x++;

ra = rbaddress-->x;

}

gc--; ! countdown on the length

!if (ga ~= (-2) or action)

! continue;

PseudoProcessRulebook(ra, rv, false, (+directly invoked+));

if (DoneSearchingRulebooks == 1)

rfalse;

}

}

}

else ! substituted rule is a rule, not a rulebook

{

#ifdef LOOP_THRU_RULEBOOKS_C;

print "[Rulecount++ on ", (RulePrintingRule) substituted_rule, ".]^";

#endif;

CountRulesInRulebook++;

PseudoDB_Rule("would apply", rulebook, rreason);

}

.RulebookPseudoprocessed;

! step through rulechange stack top-to-bottom, executing rule(s) that were "moved after" the rule(book) we're currently running

if (bits & RS_AFFECTED_BIT) ! same Optimization

for (x=rulechange_sp-3: x>=frame_base: x = x-3)

{

if ((rulechange_stack-->x == RS_MOVEAFTER) && (rulechange_stack-->(x+2) == rulebook))

{

PseudoDB_Rule("has a rule(s) ~moved after~", rulebook, rreason);

PseudoProcessRulebook(rulechange_stack-->(x+1), (bits & RS_ACTIVITY ~= 0), true, (+moved after+));

}

}

rulechange_stack-->rulechange_sp = 0;

#ifdef LOOP_THRU_RULEBOOKS_E;

print " [~", (RulePrintingRule) rulebook, "~ considered.]^";

#endif;

rfalse;

];

-).

Repeat Through a Rulebook ends here.