sysrules.t

documentation
#charset "us-ascii"
#include "advlite.h"

/*----------------------------------------------------------------------------*/
/*  
 *   SYSRULES (System Rules) EXTENSION By Eric Eve
 *
 *   This extension requires the Rules Extension
 *
 *   The Sysrules extension defines a number of rulebooks and rules that add
 *   more flexibility to certain aspects of the adv3Lite library.
 */

/*  
 *   RuleBook that can contain rules run at Preinit. By default this Rulebook
 *   starts out empty. [SYSRULES EXTENSION]
 */
preinitRules: RuleBook
    contValue = nil
;

/* PreinitObject to run PreinitRules for SYSRULES EXTENSION. */
preinitRulesRunner: PreinitObject
    execute()
    {
        preinitRules.follow();
    }
    /* 
     *   Make sure we've initialized both the library and all the rules before
     *   we try to run our rules.
     */
    execBeforeMe = [adv3LibPreinit, rulePreinit]
;

/* A rule belonging to the preinitRules RuleBook. [SYSRULES EXTENSION] */
class PreinitRule: Rule
    location = preinitRules
;

/*  
 *   RuleBook that can contain rules run at Init. By default this Rulebook
 *   starts out empty. [SYSRULES EXTENSION] */

initRules: RuleBook
    contValue = nil
;

/* InitObject to run InitRules. [SYSRULES EXTENSION] */
initRulesRunner: InitObject
    execute()
    {
        initRules.follow();
    }
    execBeforeMe = [adv3LibInit]
;


/* A rule belonging to the initRules RuleBook. [SYSRULES EXTENSION] */
class InitRule: Rule
    location = initRules
;

/* A Rule beloning to the turnEndRules RuleBook. [SYSRULES EXTENSION] */
class TurnEndRule: Rule
    location = turnEndRules
;

/* 
 *   The turnEndRules execute the various things that need to happen at the end
 *   of each turn, including the current location's roomDaemon, any current
 *   Fuses and Daemons (via the eventManager), and advancing the turn counter.
 *   Additional rules can be added if game code wants something else to occur at
 *   the end of each turn. [SYSRULES EXTENSION]
 */
turnEndRules: RuleBook
    contValue = nil
;

/* [SYSRULES EXTENSION] By default add a paragraph break before doing anything else at the end of turn. */
+ turnEndSpacerRule: Rule
    follow()
    {
        "<.p>";
    }
    priority = 10000
;


/* Execute the player character's current location's roomDaemon. [SYSRULES EXTENSION]
+ roomDaemonRule: Rule
    follow()
    {
        /* Execute the player character's current location's roomDaemon. */
        gPlayerChar.getOutermostRoom.roomDaemon();  
    }
    priority = 9000
;
    
/* 
 *   If the events.t module is included, execute all current Daemons and
 *   Fuses [SYSRULES EXTENSION]
 */	
+  executeEventsRule: Rule
    follow()
    {
        /* 
         *   If the events.t module is included, execute all current Daemons and
         *   Fuses.
         */
        if(defined(eventManager) && eventManager.executeTurn())          
            ;
    }
    priority = 8000
;

/* Advance the turn counter  [SYSRULES EXTENSION]*/
+ advanceTurnCounterRule: Rule
    follow()
    {
        /* Advance the turn counter */
        libGlobal.totalTurns += gAction.turnsTaken;
    }
    priority = 50
;
        
/*  
 *   An AfterRule is a rule belonging to the afterRules Rulebook. Note than
 *   unlike after rules in I7 these are executed after the action is fully
 *   complete, i.e. *after* the report stage. [SYSRULES EXTENSION]
 */
class AfterRule: Rule
    location = afterRules
    
    /* The current action */
    currentAction = (rulebook.currentAction)
;

/*  Rulebook to carry out after action notifications. [SYSRULES EXTENSION] */
afterRules: RuleBook
    contValue = nil
    
    /* 
     *   The current action; this is set by the current action's afterAction()
     *   method.
     */
    currentAction = nil
;

/* 
 * Rule to check whether the illumination level has changed for the actor and make the
 * appropriate announcement if so. [SYSRULES EXTENSION]
 */
checkIlluminationRule: AfterRule
    follow()
    {
        /* 
         *   If the actor is still in the same room s/he started out in, check
         *   whether the current illumination level has changed, and, if so,
         *   either show a room description or announce the onset of darkness,
         *   as appropriate.
         */
        local ac = currentAction;
        
        if(ac.oldRoom == gActor.getOutermostRoom)
        {
            if(ac.oldRoom.isIlluminated)
            {
                if(!ac.wasIlluminated)
                {   
                    "<.p>";
                    ac.oldRoom.lookAroundWithin();
                }
            }
            else if(ac.wasIlluminated)
            {
                DMsg(onset of darkness, '\n{I} {am} plunged into darkness. ');
            }
        }
        "<.p>";
        
    }
    priority = 10000
;
  
* Rule to call the afterAction notifications on all currently active scenes. [SYSRULES EXTENSION] */  
notifyScenesAfterRule: AfterRule
    follow()
    {
        /* Call the afterAction notifications on all currently active scenes. */
        if(defined(sceneManager))
           sceneManager.notifyAfter();        
    }
    priority = 9000
;

roomNotifyAfterRule: AfterRule
    follow()
    {
        /* 
         *   Call the afterAction notification on the current room and its
         *   regions.
         */
        gActor.getOutermostRoom.notifyAfter();
    }
    
    priority = 8000
;

scopeListNotifyAfterRule: AfterRule
    follow()
    {
        
        /* 
         *   Call the afterAction notification on every object in scope. Note
         *   that we have to recalculate the scope list here in case the action
         *   has changed it.
         */
        foreach(local cur in Q.scopeList(gActor))
        {
            cur.afterAction();
        }
        
    }
    
    priority = 7000    
;

/*  
 *   The BeforeRule class provides a convenient means of defining rules that
 *   belong to the beforeRules RuleBook. We derive it from ReplaceRedirector as
 *   well as Rule in case users want to use the doInstead() interface to
 *   redirect one action to another from a BeforeRule.
 */
class BeforeRule: Rule, ReplaceRedirector
    location = beforeRules
    
    /* The current action */
    currentAction = (rulebook.currentAction)
;

/*  
 *   The main function of the beforeRules is to carry out our before action
 *   notifications.
 */
beforeRules: RuleBook
    contValue = nil
    
    /* 
     *   The current action; this is set by the current action's beforeAction()
     *   method.
     */
    currentAction = nil
;

/* 
 *   Check any Preconditions relating to the action as a whole (as
 *   opposed to any of its objects. [SYSRULES EXTENSION]
 */  
checkActionPreconditionsRule: BeforeRule
    follow()
    {
        /* 
         *   Check any Preconditions relating to the action as a whole (as
         *   opposed to any of its objects.
         */
        if(!currentAction.checkActionPreconditions())
            exit;
    }
    
    priority = 10000
;

/*  
 *   Call the before action handling on the current actor (in its
 *   capacity as actor) [SYSRULES EXTENSION]
 */
actorActionRule: BeforeRule
    follow()
    {
        /*  
         *   Call the before action handling on the current actor (in its
         *   capacity as actor)
         */
        gActor.actorAction();
    }
    
    priority = 9000
;

/* 
 *   If the sceneManager is present then send a before action
 *   notification to every currently active Scene. [SYSRULES EXTENSION]
 */
sceneNotifyBeforeRule: BeforeRule
    follow()
    {
        /* 
         *   If the sceneManager is present then send a before action
         *   notification to every currently active Scene.
         */
        if(defined(sceneManager))
            sceneManager.notifyBefore();
    }
    
    priority = 8000
;

/* 
 *   Call roomBeforeAction() on the current actor's location, and
 *   regionBeforeAction() on all the regions it's in.
 */
roomNotifyBeforeRule: BeforeRule
    follow()
    {
        /* 
         *   Call roomBeforeAction() on the current actor's location, and
         *   regionBeforeAction() on all the regions it's in.
         */        
        gActor.getOutermostRoom.notifyBefore();   
    }
    
    priority = 7000
;

/* Call the beforeAction method of every object in scope.  [SYSRULES EXTENSION]*/
scopeListNotifyBeforeRule: BeforeRule
    follow()
    {
        /* Call the beforeAction method of every object in scope. */
        foreach(local cur in currentAction.scopeList)
        {
            cur.beforeAction();
        }
    }
    
    priority = 6000
;


modify Action
    
    /* 
     *   Carry out the post-action processing. This first checks to see if
     *   there's been a change in illumination. If there has we either show a
     *   room description (if the actor's location is now lit) or announce the
     *   onset of darkness. We then call the after action notifications first on
     *   the actor's current room and then on every object in scope.
     *
     *   Note that afterAction() is called from the current Command object.
     *   [MODIFIED FOR SYSRULES EXTENSION]
     */
    afterAction()
    {
        /* 
         *   If the current action is considered a failure, we don't carry out
         *   any after action handling, since in this case there's no action to
         *   react to.
         */
        if(actionFailed)
            return;
        
        /*  
         *   Register ourselves as the current action for our afterRules
         *   Rulebook
         */
        afterRules.currentAction = self;
        
        
        /*   
         *   Let the afterRules carry out the rest of the after action handling.
         */
        afterRules.follow();
        
    }
    
    /* [MODIFIED FOR SYSRULES EXTENSION] Use the beforeRules RuleBook to carry out the before action handling. */
    beforeAction()
    {
        
        /* 
         *   If we don't already have a scope list for the current action, build
         *   it now.
         */
        if(nilToList(scopeList).length == 0)
            buildScopeList;
        
        /*   
         *   Register this action as the one the beforeRules RuleBook needs to
         *   deal with.
         */
        beforeRules.currentAction = self;
              
        /*  
         *   Get the beforeRules RuleBook to carry out the rest of the before
         *   action handling.
         */
        beforeRules.follow();
        
    }
    
       
    /* 
	 * [MODIFIED FOR SYSRULES EXTENSION] 
	 * Use the turnEnd RuleBook to carry out the end-of-turn processing.
	 */
    turnSequence()
    {
        /* Execute the rulebook that takes care of end-of-turn processing */
        turnEndRules.follow();                   
    }
;




/*  
 *   The reportRules provide a convenient entry point to customize standard
 *   action reports under particular circumstances. [SYSRULES EXTENSION]
 */
reportRules: RuleBook
    /* 
     *   The current action; this is set by the current action's report()
     *   method.
     */
    currentAction = nil
    
    /* 
     *   This is the one RuleBook where we don't define contValue = nil, since
     *   normally we'll want the first matching rule to stop execution of the
     *   rulebook.
     */
    // contValue = null
;

/* A ReportRule is a rule belonging to the reportRules RuleBook. [SYSRULES EXTENSION] */
class ReportRule: Rule   
    location = reportRules
    
    /* The current action (the action that has just invoked our rulebook). */
    currentAction = (rulebook.currentAction)
;

/* Output any pending implicit action reports [SYSRULES EXTENSION] */
reportImplicitActionsRule: ReportRule
    follow()
    {
        /* Output any pending implicit action reports */
        "<<currentAction.buildImplicitActionAnnouncement(true)>>";   
        
        nostop;
    }
    
    priority = 10000
;

/*  
 *   The standardReportRule reports the action in the standard way defined on
 *   the direct object's action-specified report method. [SYSRULES EXTENSION]
 */
standardReportRule: ReportRule
    follow()
    {
        local ca = currentAction;
        
        ca.curDobj.(ca.reportDobjProp); 
    }
    
    /* 
     *   Make this normally the last report rule to be considered, so that any
     *   custom rule will take precedence.
     */
    priority = 0
;


modify TAction
    /* 
     *   MODIFIED FOR SYSRULES EXTENSION   
     *
     *   reportAction() is called only after all the action routines have been
     *   run and the list of dobjs acted on is known. It only does anything if
     *   the action is not implicit. It can thus be used to summarize a list of
     *   identical actions carried out on every object in reportList or to print
     *   a report that is not wanted if the action is implicit. By default we
     *   call the dobj's reportDobjProp to handle the report.
     *
     *   Note that this method is usually called from the current Command object
     *   after its finished iterated over all the direct objects involved in the
     *   command.
     *
     *   This modified version uses the reportRules rulebook to make it easy to
     *   insert differently worded summary reports.
     */    
    reportAction()
    {
        /* 
         *   If we're not an implicit action and there's something in our report
         *   list to report on, execute the report stage of this action.
         */
        if(!isImplicit && reportList.length > 0)
        {
            /* Register this action with the reportRules RuleBook */
            reportRules.currentAction = self;
            
            /* Let the report rules handle it. */
            reportRules.follow();                      
        }

    }
;

/* ------------------------------------------------------------------------ */
/* 
 *   Modified version to work with the turnStartRules. This repeatedly prompts
 *   the player for a command and then processes the command until the game
 *   ends. [MODIFIED FOR SYSRULES EXTENSION]
 */
replace mainCommandLoop()
{

    local txt;

    /* 
     *   Set the current actor to the player character at the start of the game
     *   (to ensure we have a current actor defined).
     */
    gActor = gPlayerChar;
    
    /* 
     *   Repeat this loop, which asks for a command and then parses it, until
     *   the game comes to an end.
     */
    do
    {
        turnStartRules.follow();
            
        
        /* 
         *   From here on use code from the original version of mainCommandLoop,
         *   since it's awkward to continue to follows rules inside the try...
         *   catch block, and in any case it would be inadvisable to tamper with
         *   what this section of code does.
         */
        try
        {
            /* Read a new command from the keyboard. */
            txt = inputManager.getInputLine();
            "<./inputline>\n";   
            
            /* Pass the command through all our StringPreParsers */
            txt = StringPreParser.runAll(txt, Parser.rmcType());
            
            /* 
             *   If the txt is now nil, a StringPreParser has fully dealt with
             *   the command, so go back and prompt for another one.
             */        
            if(txt == nil)
                continue;
            
            /* Parse and execute the command. */
            Parser.parse(txt);
        }
        catch(TerminateCommandException tce)
        {
            
        }      
        
    } while (true);    
    
}

/* Rulebook for start of turn rules [SYSRULES EXTENSION] */
turnStartRules: RuleBook
    contValue = nil
;

/* Rule for use in the startTurnRules rulebook [SYSRULES EXTENSION]
class TurnStartRule: Rule
    location = turnStartRules
;

/* Rule to update the status line. [SYSRULES EXTENSION] */
updateStatusLineRule: TurnStartRule
    follow()
    {
         /* Update the status line. */
        statusLine.showStatusLine();
    }
    
    priority = 10000
;

/* Rule to display score notifications if the score module is included. [SYSRULES EXTENSION] */
scoreNotificationRule: TurnStartRule
    follow()
    {
        /* Display score notifications if the score module is included. */
        if(defined(scoreNotifier) && scoreNotifier.checkNotification())
            ;
    }
    
    priority = 9000
;

/* Rule to run any PromptDaemons if the events module is included [SYSRULES EXTENSION] */
promptDaemonRule: TurnStartRule
    follow()
    {
        /* run any PromptDaemons if the events module is included */
        if(defined(eventManager) && eventManager.executePrompt())
            ;
    }
    priority = 8000
;

/* Rule to output a paragraph break at the start of a turn. [SYSRULES EXTENSION] */
commandSpacingRule: TurnStartRule
    follow()
    {
        /* Output a paragraph break */
        "<.p>";
    }
    
    /* 
     *   We give this a low priority since this should normally come just before
     *   the command prompt.
     */
    priority = 20
;

/* Rule to start displaying the input line [SYSRULES EXTENSION] */
startInputLineRule: TurnStartRule
    follow()
    {
        "<.inputline>";
    }
    priority = 10
;

/* Rule to display the command prompt. [SYSRULES EXTENSION] */
displayCommandPromptRule: TurnStartRule
    follow()    
    {            
        DMsg(command prompt, '>');        
    }
    
    /* 
     *   This rule should normally be executed right at the end of its RuleBook,
     *   just before inputting a command.
     */
    priority = 0
;

Adv3Lite Library Reference Manual
Generated on 03/07/2024 from adv3Lite version 2.1