Repeat Through a Rulebook

version 4 by Ron Newcomb

  • Home page
  • Beginning
  • Previous



  • 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.