GameSource/xthing.c

/*
    xthing
    ------
    A little set of routines that allow you to stuff
    tasks in the time manager queue, which will be fed back to you
    in the XThingList queue, accessed within the application's
    main loop by calling ProcessXThingTask.
        
    7:17:22 PM  10/28/92
    By Brigham Stevens
    Apple Computer, Inc.
    Developer Technical Support
    
    
    At init time call InitXThingTimer.
    Call StartXThing to add a task and start its clock.
    Call AddXThing to only add a task and NOT start its clock.
    At the end of your program call KillAllXThingTasks
    If your task wants to remove itself, it should return false.
    
    Xthing tasks have the form of:
    
    Boolean XThingUpdateTask(xthing *xtp, long dataRef)
    {
        myDataStruct *mdp;
        Boolean      result;
        
        mdp = (myDataStruct *)dataRef;
        
        mdp.count++;                // do something usefull (less)
        
        if(mdp.count)
            result = true;          // want to be run again
        else
            result = false;         // tell Xthing not to re-install us
    }
 
    See Sprite.c for more examples.
    
*/
 
#include "xthing.h"
#include "ZAMProtos.h"
 
static void XThingTimeTask(void);
 
static long     xThingCount = 0;
static xQHdr    XThingList;
 
void InitXThingTimer(void)
{
    xInitQueueHeader(&XThingList);
}
 
static void XThingTimeTask(void)
{   
    /* Time manager points to time task record in a1 */
    /* We have all our data located after that, so it */
    /* is simple to just do our  thing */
    
    asm {   
            st.b        xthing.taskFlag(a1)         
    }
}
 
void ProcessXThingTask(short numTasksToProcess)
/*
    Whip through the queue until there
    are no more entires.  Each item is
    ripped from the queue, it's associated task
    is called, and the item is then fed back to
    the Time Manager task, which will give it back to us here
    when it is done chewing on it.
    
    If the user interface slows down because of too many things going on,
    you might want to add a task that basically calls your event loop
    once in a while.  Then you could make this the main loop of your
    program if you were so inclined.
*/
{
    xthing          *xtp;
    updateProc      updateJSR;
    Boolean         reTime;
    OSErr           err;
    
    for(xtp = (xthing*)XThingList.qHead; xtp != nil; xtp = xtp->next) {
        if(xtp->taskFlag) {
            xtp->taskFlag = false;
            updateJSR = (updateProc)xtp->actionProc;
            if(updateJSR)  {
                reTime = (*updateJSR)(xtp,xtp->dataRef);
                if(reTime) {
                    RmvTime(&xtp->timer);
                    InsTime(&xtp->timer);
                    PrimeTime(&xtp->timer, xtp->interval);
                }
            }
        }
    }
}
 
 
void EnqueueXThing(xthing *xtp)
{
 
    xThingCount++;
    
    if(xtp->inList == false) {          // change to bit field in taskFlag later
        xEnqueue(xtp,&XThingList);
        xtp->inList = true;
    }
}
 
void AddXThing(xthing *xtp, long prime, updateProc updtProc, long dataRef)
/*
    This adds a thing to the xthing list, but does not start the tasks
*/
{
    short   err = noErr;
        
    if(err == noErr) {
        /* set up default values */
        
        xtp->timer.tmAddr = (ProcPtr)XThingTimeTask;
        
        xtp->interval = prime;
        xtp->taskFlag = false;  
        xtp->dataRef = dataRef;
        xtp->actionProc = updtProc;
        xtp->waiting = true;
 
        EnqueueXThing(xtp);
    }
 
}
 
 
xthing *StartXThing(xthing *xtp, long prime, updateProc updtProc, long dataRef)
/*
    The best thing about this
    is that it takes almost NO parameters
    pass the timing interval in prime
    a pointer to the update routine in updtProc
    and an application-defined reference in refcon.
*/
{
    short   err = noErr;
    
    /* allocate a new thing */
    if(xtp == nil) {
        xtp = (xthing*)NewPtrClear(sizeof(xthing));
        if(!xtp){
            err = MemError();
            ErrMsgCode("\pNewPtrClear failed in StartThing",err);
        }
    }
    
    if(err == noErr) {
        /* set up default values */
        
        xtp->timer.tmAddr = (ProcPtr)XThingTimeTask;
        
        xtp->interval = prime;
        xtp->taskFlag = false;  
        xtp->dataRef = dataRef;
        xtp->actionProc = updtProc;
        xtp->waiting = true;
 
        EnqueueXThing(xtp);
        
        InsTime((QElemPtr)&xtp->timer);
        PrimeTime(&xtp->timer, xtp->interval);
    }
 
    return xtp;
}
 
 
void KillAllXThingTasks(void)
{
    xthing          *xtp;
    
    for(xtp = (xthing*)XThingList.qHead; xtp != nil; xtp = xtp->next) {
        if( (xtp->timer.qType & TaskActiveFlag) != 0)
            RmvTime(&xtp->timer);
    }
}