If you appreciate the work done within the wiki, please consider supporting The Cutting Room Floor on Patreon. Thanks for all your support!

Notes:Stickybear Reading

From The Cutting Room Floor
Jump to navigation Jump to search

This page contains notes for the game Stickybear Reading.

Source Code

Hello World! Can we get some syntax highlighting in here?

animation.c

#include <stdio.h>
#include <time.h>

#include "dbg.h"

#include "utility.h"
#include "animation.h"
#include "reading.h"


Direc       mfxDir[maxThings];  /* directory of all things in memory */
short       DirNum;     /* holds number of entries in directory */
EraTab      EraTab2;    /* screen 0 (really vidmem2) */
EraTab      EraTab3;    /* screen 1 (really vidmem3) */
EraTabPtr   EraPtr;     /* this always points at the erase table of the rear screen */
ScenePtr    SceneTab[maxScenes]; /* a table of scene ptrs */
int         IDstrips;   /* bkgd strip images */
TOCPtr      strips;     /* bkgd strip images */
TOCPtr      scrolls;
Ptr         scrollchunk;
Boolean     swapflag;
short       daBkgd;     /* index for which bkgd table to draw from */
short       daScroll;   /* index for which scroll band tables to use */
RectListPtr theRectPtr; /* pointer to current rectangle list (hot spots) */


static  Boolean     FrameFlag;  /* gets set if time for scene to do a frame */
static  Boolean     ShowFlag;   /* gets set if items in scene should be displayed */



/*
 * ReinitScene - This Resets default values for a scene.
 */
void ReinitScene(theScene)
    ScenePtr theScene;
{
short           iCtr;       /* # of items counter */
ItemPtr         theItem;


    currentT = clock(); /* get current tick count */

    theScene->Frame = 0;        /* main cycle counter for the scene */
    theScene->NextTime = currentT + theScene->AniDelay;
/*
 * Move initial values to current/working values for each item.
 */
    if (theScene->NumItems != 0) {
        for (iCtr = 0; iCtr < theScene->NumItems; iCtr++) { /* loop for each item of scene */
            theItem = (ItemPtr)((int)theScene + (int)theScene->ItemDir[iCtr].Where);
            switch(theItem->IType) {
                case ITypeShp:
                    ReinitShp((ItemShpPtr)theItem);
                    break;
                case ITypePix:
                    ReinitPix((ItemPixPtr)theItem);
                    break;
                case ITypeSeq:
                    ReinitSeq((ItemSeqPtr)theItem);
                    break;
                case ITypeGrp:
                    ReinitGrp((ItemGrpPtr)theItem);
                    break;
                case ITypeInt:
                    break;
                case ITypeAud:
                    break;
            }
        }
    }
}

/*
 * ReinitShp - Resets shape table initial values.
 */
void ReinitShp(theShp)
    ItemShpPtr theShp;
{
    ReinitGen(&theShp->Gen);
    ReinitPos(&theShp->Pos);

    theShp->Pos.ICurXOff = 0;
    theShp->Pos.ICurYOff = 0;
    theShp->Pos.ICurWide = theShp->Pos.IEraseWide = theShp->ShpIA->NumWide;
    theShp->Pos.ICurHigh = theShp->Pos.IEraseHigh = theShp->ShpIA->NumHigh;
}

/*
 * ReinitSeq - Resets sequence table initial values.
 */
void ReinitSeq(theSeq)
    ItemSeqPtr theSeq;
{
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */

    ReinitGen(&theSeq->Gen);
    ReinitPos(&theSeq->Pos);
    ReinitCyc(&theSeq->Cyc);
    /*
     * Set the dimension values for the initial state.
     * If there are any states.
     */
    if (theSeq->Cyc.ICycSize == 0)
        return;
    theSeqDF = theSeq->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[theSeq->Cyc.IIState].StateIA;
    theSeq->Pos.ICurXOff = theSeqDF->SeqTab[theSeq->Cyc.IIState].StateXOff;
    theSeq->Pos.ICurYOff = theSeqDF->SeqTab[theSeq->Cyc.IIState].StateYOff;
    theSeq->Pos.ICurWide = theSeq->Pos.IEraseWide = theShp->NumWide;
    theSeq->Pos.ICurHigh = theSeq->Pos.IEraseHigh = theShp->NumHigh;
}

void ReinitPix(thePix)
    ItemPixPtr thePix;
{
    ReinitGen(&thePix->Gen);
    ReinitPos(&thePix->Pos);
    ReinitCyc(&thePix->Cyc);
}

void ReinitGrp(theGrp)
    ItemGrpPtr theGrp;
{
    ReinitGen(&theGrp->Gen);
    ReinitPos(&theGrp->Pos);
    ReinitCyc(&theGrp->Cyc);
}


/*
 * ReinitGen Resets the general item table values.
 */
void ReinitGen(theGen)
    ItemPtr theGen;
{
    theGen->IActive = theGen->IIActive;
    theGen->IDisplay = theGen->IIDisplay;
    theGen->IAofA = theGen->IIAofA;
}

/*
 * ReinitPos resets the positional item table values.
 */
void ReinitPos(thePos)
    ItemPosPtr thePos;
{
    thePos->IBox = thePos->IIBox;
    thePos->IPlane = thePos->IIPlane;
    thePos->ICurX = thePos->IEraseX = thePos->IBaseX = thePos->IIBaseX;
    thePos->ICurY = thePos->IEraseY = thePos->IBaseY = thePos->IIBaseY;
    thePos->IVelEnable = thePos->IIVelEnable;
    thePos->IXVel = thePos->IIXVel;
    thePos->IXAcc = thePos->IIXAcc;
    thePos->IXVelCtr = thePos->IXVelDur = thePos->IIXVelDur;
    thePos->IXVelFin = thePos->IIXVelFin;
    thePos->IYVel = thePos->IIYVel;
    thePos->IYAcc = thePos->IIYAcc;
    thePos->IYVelCtr = thePos->IYVelDur = thePos->IIYVelDur;
    thePos->IYVelFin = thePos->IIYVelFin;
}

/*
 * ReinitCyc resets the state cycling item table values.
 */
void ReinitCyc(theCyc)
    ItemCycPtr theCyc;
{
    theCyc->ICycEnable = theCyc->IICycEnable;
    theCyc->ICycCtr = theCyc->ICycle = theCyc->IICycle;
    theCyc->ICycCng = theCyc->IICycCng;
    theCyc->ICycDCtr = theCyc->ICycDur = theCyc->IICycDur;
    theCyc->ICycFin = theCyc->IICycFin;
    theCyc->IState = theCyc->IIState;
}

/*
 * Resolve -
 *
 * First it links item tables with their disk file counterparts.
 *
 * Then it links memory resident disk file with others.  For example, it links sequences
 * with their states and groups with there sequences.
 *
 */

Boolean Resolve()
{
short       sCtr;       /* # of Scenes counter */
short       iCtr;       /* # of items counter */
short       DirInd;
ScenePtr    theScene;   /* pointer to the "current" Scene */
ItemShpPtr  theShp;
ItemSeqPtr  theSeq;
Boolean     myBoo;


    for (sCtr = 0; sCtr < maxScenes; sCtr++) {  /* loop for each scene */
        theScene = SceneTab[sCtr];
        if (theScene != nil) { /* point at a scene */
            if (theScene->NumItems) {
                for (iCtr = 0; iCtr < theScene->NumItems; iCtr++) { /* loop for each item of scene */
                    DirInd = getind(theScene->ItemDir[iCtr].Who); /* search mfxDir for this filename */
                    if (DirInd == -1) { /* try to load from current directory */
                        STATUS2("Resolve can't find %s\n", theScene->ItemDir[iCtr].Who);
                        STATUS2("It has %d characters\n", strlen(theScene->ItemDir[iCtr].Who));
                        return(false); /* file not on directory - tell user somehow */
                    }
                    mfxDir[DirInd].What = theScene->ItemDir[iCtr].What;
                    switch(theScene->ItemDir[iCtr].What) {
                        case ITypeShp:
                            theShp = (ItemShpPtr)((int)theScene + (int)theScene->ItemDir[iCtr].Where);
                            theShp->ShpIA = (ShapePtr) mfxDir[DirInd].Where; /* stuff address from mfxDir */
                            break;
                        case ITypePix:
                            break;
                        case ITypeSeq:
                            theSeq = (ItemSeqPtr)((int)theScene + (int)theScene->ItemDir[iCtr].Where);
                            theSeq->Cyc.ISeqPtr = (SeqPtr)mfxDir[DirInd].Where; /* pointer to memory resident disk image file */
                            theSeq->Cyc.ICycSize = theSeq->Cyc.ISeqPtr->SeqNumSt; /* copy # of states from disk file to item table */
                            myBoo = RslvSeq((SeqPtr)mfxDir[DirInd].Where);
                            if (myBoo == false)
                                return(myBoo);  /* exit at first sign of problems */
                            break;
                        case ITypeGrp:
                            break;
                        case ITypeInt:
                            break;
                        case ITypeAud:
                            break;
                    }
                }
            }
        }
    }
    return(true);
}

/*
 * RslvSeq - Resolve the pointers to the state images of the sequence.
 *
 * Pass the scene and item number.
 */
Boolean RslvSeq(theSeq)
    SeqPtr  theSeq;
{
short       DirInd; /* This is the index into 'mfxDir' (the directory of all things in memory) */
short       resctr;

    if (theSeq->SeqNumSt != 0) {
        for (resctr = 0; resctr < theSeq->SeqNumSt; resctr++) {
            DirInd = getind(theSeq->SeqTab[resctr].StateName); /* search mfxDir for this filename */
            if (DirInd == -1) {
                return(false);
            }
            theSeq->SeqTab[resctr].StateIA = (ShapePtr)mfxDir[DirInd].Where;
        }
    }
    return(true);
}


/*
 * Step - do one frame of animation (for all active scenes in memory).
 */
void Step()
{
short           sCtr;       /* # of Scenes counter */
short           iCtr;       /* # of items counter */
ScenePtr        theScene;   /* pointer to the "current" Scene */
ItemPtr         theItem;

    currentT = clock(); /* get current tick count */

    while (!swapflag);

    /*
     * Erase everything on the rear screen.
     */
    if (EraPtr->EraCtr >= EraTab_Size) {
        STATUS2("*** EraTab has %d items ***\n", EraPtr->EraCtr);
    }
    Erase(EraPtr);
    EraPtr->EraCtr = 0; /* start with empty erase list for this cycle */
    /*
     * Now we are ready to redraw all Scenes.
     * See how many there are and point at the first one.
     */
    for (sCtr = 0; sCtr < maxScenes; sCtr++) {  /* loop for each scene */
        theScene = SceneTab[sCtr];
        if (theScene) { /* point at a scene */
            if (theScene->Active) {
                if (currentT >= theScene->NextTime) {
                    FrameFlag = true;
                    theScene->NextTime = currentT + theScene->AniDelay;
                }
                else
                    FrameFlag = false;
            }
            else
                FrameFlag = false;

            if (theScene->Display)
                ShowFlag = true;
            else
                ShowFlag = false;

            if (FrameFlag || ShowFlag) {
                if (theScene->NumItems != 0) {
                    for (iCtr = 0; iCtr < theScene->NumItems; iCtr++) { /* loop for each item of scene */
                        theItem = (ItemPtr) ((int)theScene + (int)theScene->ItemDir[iCtr].Where);
                        if (theItem->ITofA == theScene->Frame) { /* Time for an action? */
                            if (theItem->ITofA != 0) {

                            }
                        }
                        switch(theItem->IType) {
                            case ITypeShp:
                                DriveShp(theItem);
                                break;
                            case ITypePix:
                                DrivePix(theItem);
                                break;
                            case ITypeSeq:
                                DriveSeq(theItem);
                                break;
                            case ITypeGrp:
                                DriveGrp(theItem);
                                break;
                            case ITypeInt:
                                break;
                            case ITypeAud:
                                break;
                        }
                    }
                }
                if (FrameFlag)
                    theScene->Frame++;
            }
        }
    }
    swap_clut7();
}



void DriveShp(myItem)
    ItemPtr myItem;
{
ItemShpPtr  theShp;
short       ctr;

    theShp = (ItemShpPtr)myItem;

    if (ShowFlag && myItem->IDisplay) {
        Draw(theShp->ShpIA, theShp->Pos.ICurX, theShp->Pos.ICurY); /* draw the shape */

        ctr = EraPtr->EraCtr;
        EraPtr->ETab[ctr].left = theShp->Pos.ICurX;
        EraPtr->ETab[ctr].top = theShp->Pos.ICurY;
        EraPtr->ETab[ctr].right = theShp->Pos.ICurX + theShp->Pos.ICurWide;
        EraPtr->ETab[ctr].bottom = theShp->Pos.ICurY + theShp->Pos.ICurHigh;
        EraPtr->EraCtr++;
    }

    if (FrameFlag && myItem->IActive) {
        DrivePos(&theShp->Pos); /* now add velocity, accel, and update position for next cycle */
    }
}


void DrivePix(myItem)
    ItemPtr myItem;
{
ItemPixPtr  thePix;

    thePix = (ItemPixPtr)myItem;

    if (FrameFlag) {
        DriveCyc(&thePix->Cyc, &thePix->Pos);
    }
}


/*
 * DriveSeq - is used for sequences.
 * DriveCyc must be called before DrivePos as it sets the x,y offsets to use for
 * the current state of the sequence. The first time through, the offsets have been
 * set by the resolve code.
 */
void DriveSeq(myItem)
    ItemPtr myItem;
{
ItemSeqPtr  theSeq;
short       ctr;

    theSeq = (ItemSeqPtr)myItem;

    if (theSeq->Cyc.ICycSize != 0) { /* if empty sequence just exit */
        if (ShowFlag && myItem->IDisplay) {
            Draw(theSeq->Cyc.ISeqPtr->SeqTab[theSeq->Cyc.IState].StateIA,
                theSeq->Pos.ICurX, theSeq->Pos.ICurY);

            ctr = EraPtr->EraCtr;
            EraPtr->ETab[ctr].left = theSeq->Pos.ICurX;
            EraPtr->ETab[ctr].top = theSeq->Pos.ICurY;
            EraPtr->ETab[ctr].right = theSeq->Pos.ICurX + theSeq->Pos.ICurWide;
            EraPtr->ETab[ctr].bottom = theSeq->Pos.ICurY + theSeq->Pos.ICurHigh;
            EraPtr->EraCtr++;
        }

        if (FrameFlag && myItem->IActive) {
            DriveCyc(&theSeq->Cyc, &theSeq->Pos);
            DrivePos(&theSeq->Pos);
        }
        /*
         * Fix 01/26/92 - still call DriveCyc and DrivePos,
         * but disable velocity and cycling.
         * This should make the x,y offsets still figure in the position.
         */



    }
}



void DriveGrp(myItem)
    ItemPtr myItem;
{
ItemGrpPtr  theGrp;

    theGrp = (ItemGrpPtr)myItem;

    if (FrameFlag) {
        DriveCyc(&theGrp->Cyc, &theGrp->Pos);
        DrivePos(&theGrp->Pos);
    }
}




/*
 * DrivePos - do the velocity, acceleration, box limit stuff.
 *
 * When coming here, the image has already been drawn for this animation cycle (at ICurX, ICurY).
 * This code will set the parameters for the next animation cycle after setting
 * the update rectangle.
 */
void DrivePos(thePos)
    ItemPosPtr thePos;
{
short   locShort;

    if (thePos->IVelEnable) { /* If velocity is "allowed" */
        if (thePos->IXVel != thePos->IXVelFin) { /* If current X velocity is not final X vel */
            if (thePos->IXVelCtr == thePos->IXVelDur) { /* is it time to add acceleration? */
                thePos->IXVel += thePos->IXAcc;
                thePos->IXVelCtr = 0;
            }
            else
                (thePos->IXVelCtr)++;
        }
        thePos->IBaseX += thePos->IXVel; /* Add X velocity to current X position to set new X */

        if (thePos->IYVel != thePos->IYVelFin) { /* If current Y velocity is not final Y vel */
            if (thePos->IYVelCtr == thePos->IYVelDur) { /* is it time to add acceleration? */
                thePos->IYVel += thePos->IYAcc;
                thePos->IYVelCtr = 0;
            }
            else
                (thePos->IYVelCtr)++;
        }
        thePos->IBaseY += thePos->IYVel; /* Add Y velocity to current Y position */
    }
    thePos->ICurX = thePos->IBaseX + thePos->ICurXOff; /* Adjust for sequences with offset states */
    thePos->ICurY = thePos->IBaseY + thePos->ICurYOff;
/*
 * Now check the box limits.
 */
    if (thePos->ICurX + (thePos->ICurWide -1) > thePos->IBox.right) {
        thePos->IXVel = 0 - thePos->IXVel; /* negate the velocity */
/*
 * Get the amount of overshoot and make it the offset on the other side of the limit.
 */
        locShort = thePos->ICurX + (thePos->ICurWide -1) - thePos->IBox.right;
        thePos->ICurX = thePos->IBox.right - (thePos->ICurWide -1) - locShort;
        thePos->IBaseX = thePos->ICurX - thePos->ICurXOff;
    }
    if (thePos->ICurX < thePos->IBox.left) {
        thePos->IXVel = 0 - thePos->IXVel; /* negate the velocity */
        thePos->ICurX = thePos->IBox.left + (thePos->IBox.left - thePos->ICurX);
        thePos->IBaseX = thePos->ICurX - thePos->ICurXOff;
    }

    if (thePos->ICurY + (thePos->ICurHigh -1) > thePos->IBox.bottom) {
        thePos->IYVel = 0 - thePos->IYVel; /* negate the velocity */
/*
 * Get the amount of overshoot and make it the offset on the other side of the limit.
 */
        locShort = thePos->ICurY + (thePos->ICurHigh -1) - thePos->IBox.bottom;
        thePos->ICurY = thePos->IBox.bottom - (thePos->ICurHigh -1) - locShort;
        thePos->IBaseY = thePos->ICurY - thePos->ICurYOff;
    }
    if (thePos->ICurY < thePos->IBox.top) {
        thePos->IYVel = 0 - thePos->IYVel; /* negate the velocity */
        thePos->ICurY = thePos->IBox.top + (thePos->IBox.top - thePos->ICurY);
        thePos->IBaseY = thePos->ICurY - thePos->ICurYOff;
    }
}


/*
 * DriveCyc - This code changes the state to draw if the conditions are right.
 * If it does change the state, it also resets the counters and image dimension
 * variables in the item table.
 */
void DriveCyc(theCyc, thePos)
    ItemCycPtr theCyc;
    ItemPosPtr thePos;
{
SeqPtr  theSeq;

    if (theCyc->ICycEnable) { /* If cycling is "allowed" */
        if (theCyc->ICycCtr == 0) {
            theCyc->ICycCtr = theCyc->ICycle;   /* reset counter */
            theCyc->IState++;
            /*
             * check against max # of states
             */
            if (theCyc->IState == theCyc->ICycSize)
                theCyc->IState = 0;
            /*
             * We have a new state to draw for next time, set it's new
             * dimension and offset values.
             */
            theSeq = theCyc->ISeqPtr;
            thePos->ICurWide = (*theSeq->SeqTab[theCyc->IState].StateIA).NumWide;
            thePos->ICurHigh = (*theSeq->SeqTab[theCyc->IState].StateIA).NumHigh;
            thePos->ICurXOff = theSeq->SeqTab[theCyc->IState].StateXOff;
            thePos->ICurYOff = theSeq->SeqTab[theCyc->IState].StateYOff;
        }
        else
            theCyc->ICycCtr--;
    }
}


asm_itrfc.c

#include "utility.h"

/*
 * These are used in Assembly language routines.
 * Set these to reflect the bitmap dimensions when
 * using the Draw and Erase assembly routines.
 */
short           SceneWide16 = 384;
int             SceneWide32 = 384;
short           SceneHigh = 240;
Ptr             EraSrc;     /* source screen to erase from */

bop.c

#include <stdio.h>
#include <errno.h>
#include <modes.h>
#include <aimdef.h>
#include <time.h>
#include <cdfm.h>

#include "dbg.h"

#include "my_types.h"
#include "animation.h"
#include "utility.h"
#include "reading.h"
#include "screen.h"
#include "rtf.h"
#include "bop.h"
#include "sound.h"
#include "file_mgr.h"


static  unsigned    score;
static  char        sscore[10];

static  Boolean     round_over;
static  Boolean     game_over;

static  Ptr         BopData;

static  short       DirSaveBop;
static  Rect        fullRect = {0,1,240,383};
static  short       WhichBop = 0;   /* which bop package to do */
static  ScenePtr    BopScene;
static  ScenePtr    StatScene;
static  ItemPtr     BopItem;
static  Boolean     FirstBop;       /* set if this is first package */

static  short       bop_ctr;        /* down counter for bop image cycling */
static  short       bop_item_index; /* which item was hit */

static  Boolean     ball_active;
static  Boolean     cannon_active;
static  short       cannon_ctr;

static  ItemSeqPtr  the_cannon;
static  ItemSeqPtr  the_wheel;
static  ItemSeqPtr  the_ball;

static  ShapePtr    num_tab[10];    /* pointers to the 10 number shapes for the score */


/*
 * this is the table of the twenty Bop packages that get shuffled
 */
short   Boptab[NumBopPkgs] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    };

static  Bop_Pkg BopPkgs[NumBopPkgs] = {
    "Boppkg1.rtf", 4, 7, 8,
    "Boppkg2.rtf", 4, 6, 8,
    "Boppkg3.rtf", 4, 6, 7,
    "Boppkg4.rtf", 4, 6, 7,
    "Boppkg5.rtf", 6, 7, 9,
    "Boppkg6.rtf", 4, 6, 11,
    "Boppkg7.rtf", 4, 5, 7,
    "Boppkg8.rtf", 5, 6, 8,
    "Boppkg9.rtf", 4, 6, 8,
    "Boppkg10.rtf", 4, 6, 10
    };

static Bop_Row BopRows[NumRows] = {
    837, NumRowItems * 0, 0,2, TopRowSpace, -8, 50, TopRowYpos,
    473, NumRowItems * 1, 0,2, MidRowSpace, -6,100, MidRowYpos,
    225, NumRowItems * 2, 0,2, BotRowSpace, -4, 50, BotRowYpos
    };

static Bop_Item BopItems[NumBopItems];

static  short num_gone;     /* when this reaches 6 we are finished for this level */

/*
 * These are the rectangles for the Bop buttons
 */
static  RectList BopRect = {
    5,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,283,    /* play button */
    177,289,218,350     /* go back button */
    };

static  short   Balls;  /* start the game with this many balls */
static  Rect    ball_rect;  /* this holds the current ball rectangle */
static  Rect    collide_rect; /* this gets set to the previous and current ball rectangles */

/*
 * This is the main code for Bumper's Word Bop
 *
 */
void Bop()
{
Boolean         done;

    SceneTab[MScene] = nil; /* we are not using the 3rd scene (MScene) right now */
    StatScene = SceneTab[BSScene] = (ScenePtr)stuffpkg(ScreenBuf);
    BopScene = SceneTab[BMScene] = (ScenePtr)mfxDir[getind("new.bop.scene")].Where;

    FixScene(BSScene);
    FixScene(BMScene);
    BopScene->AniDelay = Bop_AniDelay;
    SetUpScene(BSScene);    /* status scene - contains score, balls, cannon */
    SetUpScene(BMScene);    /* main scene - contains targets to shoot at */

    StatScene->AniDelay = 0; /* this contains the cannon, wheel, ball, score, # balls */
    StatScene->Active = true;
    StatScene->Display = true;

    /*
     * Set up pointers to the cannon, wheel, and ball item tables
     */
    the_cannon = (ItemSeqPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[cannon_item].Where);
    the_wheel = (ItemSeqPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[wheel_item].Where);
    the_ball = (ItemSeqPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[ball_item].Where);
    init_cannon();  /* get everything lined up */
    /*
     * Set up pointers to the number shapes
     */
    num_tab[0] = (ShapePtr)mfxDir[getind("num0.shp")].Where;
    num_tab[1] = (ShapePtr)mfxDir[getind("num1.shp")].Where;
    num_tab[2] = (ShapePtr)mfxDir[getind("num2.shp")].Where;
    num_tab[3] = (ShapePtr)mfxDir[getind("num3.shp")].Where;
    num_tab[4] = (ShapePtr)mfxDir[getind("num4.shp")].Where;
    num_tab[5] = (ShapePtr)mfxDir[getind("num5.shp")].Where;
    num_tab[6] = (ShapePtr)mfxDir[getind("num6.shp")].Where;
    num_tab[7] = (ShapePtr)mfxDir[getind("num7.shp")].Where;
    num_tab[8] = (ShapePtr)mfxDir[getind("num8.shp")].Where;
    num_tab[9] = (ShapePtr)mfxDir[getind("num9.shp")].Where;

    new_game();             /* initialize the game variables for a new game */

    DirSaveBop = DirNum;    /* save for starting point when loading each new pkg */
    theRectPtr = &BopRect;  /* set list of hotspots */

    mk_bop_scrn();          /* Make the screen for bop */
    new_bop_pkg();          /* Play the curtain closing rtf, load data, open curtains */

    Bop2();                 /* start right in the game */
    if (!game_over) {
        stop_all_audio();
        MkBopBut();             /* make the buttons for bop */
        cursor_show();
        done = false;
        while (!done) {

            chk_help(0, BEARfid, 0, 0); /* no restart audio to pass */
            chk_dim();  /* if it's time to dim, this won't return until undim */
            CheckInput();
            if (theInpTab.ButPress) {
                switch (theInpTab.HotIndex) {
                    case 0: /* Help button */
                        stop_all_audio();
                        start_bkgd_audio(0, BEARfid, false); /* pass channel number */
                        CheckInput();
                        while ((eor_ctr) && (theInpTab.HotIndex == 0) && (!theInpTab.ButPress))
                            CheckInput();
                        stop_all_audio();
                        reset_help();
                        break;
                    case 1: /* speech button */
                        Cursor_Freeze();
                        stop_all_audio();
                        new_bop_speech();
                        start_bkgd_audio(0, BUTTONfid, false); /* pass channel number */
                        changeSpch();
                        while (eor_ctr);
                        stop_all_audio();
                        set_bear_voice();
                        set_button_voice();
                        Cursor_Melt();
                        break;
                    case 2: /* text button */
                        Cursor_Freeze();
                        stop_all_audio();
                        new_bop_text();
                        if (text == English)
                            start_bkgd_audio(3, BUTTONfid, false); /* pass channel number */
                        if (text == Spanish)
                            start_bkgd_audio(1, BUTTONfid, false); /* pass channel number */
                        changeText();
                        while (eor_ctr);
                        stop_all_audio();
                        Cursor_Melt();
                        break;
                    case 3: /* play button */
                        Bop2();         /* play the game */
                        stop_all_audio();
                        if (game_over)
                            done = true;
                        else if (!cannon_active) {
                            MkBopBut();     /* make the buttons for bop */
                            cursor_show();
                        }
                        break;
                    case 4: /* go back button */
                        stop_all_audio();
                        done = true;
                        break;
                }
            }
            last_xpos = inp_xpos;   /* xpos of input device */
            last_ypos = inp_ypos;   /* ypos of input device */
        }
    }
    stop_all_audio();
    NoBopBut();
    cursor_hide();
    Close_Curtains();
    SceneTab[BSScene] = nil; /* don't need these scenes anymore */
    SceneTab[BMScene] = nil;
}


/*
 * new_bop_pkg - Play the curtain closing rtf, load data, open curtains
 */
static void new_bop_pkg()
{
int         fid;
ItemSeqPtr  theSeq;     /* the sequence item table */
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */
short       rowctr, itemctr, tocctr;
short       i, initStat, relXOff, relYOff;
Boolean     stat;
SoundmapDesc    *sm_ptr;
/* play_desc_ptr    play_tab; */

    /*
     * Clear the soundmap buffers
     */
    for (i = 5; i <= 12; i++) {
        memset (snd_array[i].data, 0, BopNounGrpSize * 128);
    }
    for (i = 13; i <= 15; i++) {
        memset (snd_array[i].data, 0, BopFXGrpSize * 128);
    }

#if 0
    if (!FirstBop)
        Close_Curtains();
    else
        FirstBop = false;
    STATUS2("loading %s\n", BopPkgs[Boptab[WhichBop]].PkgName);
#endif

    /*
     * 'play' the new package
     */
    fid = open_file(BopPkgs[Boptab[WhichBop]].PkgName, true);
    if (fid == -1) {
        WhichBop++; /* advance to next package */
        if (WhichBop == NumBopPkgs)
            WhichBop = 0;
        fid = open_file(BopPkgs[Boptab[WhichBop]].PkgName, false);
    }

    stat = play_recs(fid, reinit_rtf, 2, false, false, 0); /* curtain section */
    stat = play_recs(fid, set_bop_pre_aud_pcls, 1, false, false, 0); /* bookmark to audio section */
    stat = play_recs(fid, set_bop_pkg1_pcls, 8, false, false, 0); /* play 8 from the first 16 */
    /*
     * Adjust the soundmaps for the true size of the data just loaded
     */
    sm_ptr = sm_info(audpath, snd_array[5].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[0]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[6].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[1]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[7].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[2]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[8].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[3]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[9].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[4]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[10].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[5]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[11].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[6]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[12].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[7]->PCL_Cnt / 128;
    /*
     * Adjust the soundmaps for the true size of the data just loaded
     */
    stat = play_recs(fid, set_bop_pkg2_pcls, 4, false, false, 0); /* play 4 from the next */
    sm_ptr = sm_info(audpath, snd_array[13].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[0]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[14].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[1]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[15].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[2]->PCL_Cnt / 128;

    DirNum = DirSaveBop;    /* restore number of items in memory before last package */
    BopData = stuffpkg(PkgBuf);     /* now add the package to the master directory */
    /*
     * Link the new sequences to the Bop Scene (the bottom two rows and the words)
     */
    for (tocctr = 0; tocctr < NumRowItems*4; tocctr ++) {
        strcpy(BopScene->ItemDir[tocctr+NumRowItems].Who, pkgTOC->TE[tocctr].Who);
    }
    /*
     * temporarily shut off the status scene as setupscene eventually tries
     * to reinitialize everything in memory and we would like to keep
     * the score and cannon as they are
     */
    SceneTab[BSScene] = 0; /* shut off scene with score, cannon, etc */
    SetUpScene(BMScene); /* the bop main scene (the one with the targets) */
    SceneTab[BSScene] = StatScene;

    tocctr = 0;
    for (rowctr = 0; rowctr < NumRows; rowctr ++) {
        for (itemctr = 0; itemctr < NumRowItems; itemctr ++) {

            theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[tocctr].Where);
            theSeq->Cyc.ICycle = Bop_Cycle;
            theSeqDF = theSeq->Cyc.ISeqPtr;
            theShp = theSeqDF->SeqTab[theSeq->Cyc.IIState].StateIA;

            theSeq->Pos.IXVel = BopRows[rowctr].velocity;
            theSeq->Pos.IBaseY = theSeq->Pos.ICurY = BopRows[rowctr].inity - ((theShp->NumHigh)/2);
            theSeq->Pos.IBaseX = theSeq->Pos.ICurX = BopRows[rowctr].initx - ((theShp->NumWide)/2) +
                (BopRows[rowctr].row_space * itemctr);
            if (theSeq->Pos.IBaseX > RSide) {
                theSeq->Pos.IBaseX =  theSeq->Pos.ICurX = RSide;
                theSeq->Gen.IDisplay = false;
                theSeq->Gen.IActive = false;
            }
            else {
                theSeq->Gen.IDisplay = true;
                theSeq->Gen.IActive = true;
                BopRows[rowctr].last_id = itemctr; /* this is the last so far */
            }
            BopItems[rowctr*NumRowItems+itemctr].hit_ctr = 0;
            BopItems[rowctr*NumRowItems+itemctr].num_states = theSeqDF->SeqNumSt;
            BopItems[rowctr*NumRowItems+itemctr].org_seq_ptr = theSeqDF;
            /*
             * Adjust the state offsets so that the first offset is 0,0
             */
            initStat= theSeq->Cyc.IIState;
            relXOff= theSeqDF->SeqTab[initStat].StateXOff;
            relYOff= theSeqDF->SeqTab[initStat].StateYOff;
            for (i = 0; i < theSeqDF->SeqNumSt; i++) {
                if (i == initStat){
                    theSeqDF->SeqTab[i].StateXOff= 0;
                    theSeqDF->SeqTab[i].StateYOff= 0;
                }
                else{
                    theSeqDF->SeqTab[i].StateXOff-= relXOff;
                    theSeqDF->SeqTab[i].StateYOff-= relYOff;
                }
            }
            tocctr++;
        }
    }

    BopScene->AniDelay = Bop_AniDelay;
    BopScene->Active = true;
    BopScene->Display = true;

    no_vel();   /* stop the x movement of the items */
    Step();     /* draw the first frame of animation */

    currentT = clock();         /* get current tick count */
#if 0
    reset_dim();                /* reset dim counter */
    reset_help();
#endif

    stat = play_recs(fid, reinit_rtf, 2, false, false, 0); /* curtains opening */

    stat = close_file(fid);

    STATUS1("Loaded Bop Package\n");
}

/*
 * new_bop_speech - load just the 8 speech files for the 8 targets
 */
void new_bop_speech()
{
int         fid;
short       i;
Boolean     stat;
SoundmapDesc    *sm_ptr;


    for (i = 5; i <= 12; i++) { /* Clear just the 8 word soundmap buffers */
        memset (snd_array[i].data, 0, BopNounGrpSize * 128);
    }
    /*
     * 'play' the new package
     */
    fid = open_file(BopPkgs[Boptab[WhichBop]].PkgName, false);
    stat = play_recs(fid, set_bop_pre_aud_pcls, 1, false, false, 0); /* bookmark to audio section */
    stat = play_recs(fid, set_bop_aud_pcls, 8, false, false, 0);
    stat = close_file(fid);
    /*
     * Adjust the soundmaps for the true size of the data just loaded
     */
    sm_ptr = sm_info(audpath, snd_array[5].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[0]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[6].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[1]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[7].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[2]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[8].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[3]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[9].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[4]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[10].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[5]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[11].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[6]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[12].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[7]->PCL_Cnt / 128;
}

/*
 * new_bop_text - set alls word on the screen to the other language
 */
void new_bop_text()
{
short       i;
ItemSeqPtr  theSeq;     /* the sequence item table */
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */

    for (i = NumRowItems; i <= NumBopItems; i++) { /* start at the second row */
        if (BopItems[i].hit_ctr == 1) { /* displaying the word */
            theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[i].Where);
            theSeq->Cyc.IState ^= 1;
            theSeqDF = theSeq->Cyc.ISeqPtr;
            theShp = theSeqDF->SeqTab[theSeq->Cyc.IState].StateIA;
            theSeq->Pos.ICurWide = theShp->NumWide;
            theSeq->Pos.ICurHigh = theShp->NumHigh;
        }
    }
}


/*
 * mk_bop_scrn - Build the Bop screen.
 */
void mk_bop_scrn()
{
Ptr         thePtr;
Ptr         scnptrsav;
int         fid;
Boolean     stat;

    /*
     * Save original contents and then set scn_ptr to bkgd scrn
     * (most drawing happens at scn_ptr)
     */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;

    FilCol = 96;
    Fill(fullRect, FilCol); /* fill entire bkgd screen */

    thePtr = mfxDir[getind("boptop.shp")].Where;
    Draw((ShapePtr)thePtr, 0, 0); /* draw the shape */

    thePtr = mfxDir[getind("bopbg.shp")].Where;
    Draw((ShapePtr)thePtr, 60, 36); /* draw the shape */

    scn_ptr = scnptrsav; /* restore scn_ptr */
    /*
     * copy to rear screen, swap, and copy to new rear screen
     */
    copy_bkgd_front();
    /*
     * At this point, plane B is still invisible
     */
    FadeDown(meddisolve);
    BopOn();    /* turn plane mixing off */

    /*
     * Play the first frame of the curtains opening rtf (display the open curtains)
     */
    fid = open_file("CCurt.rtf", false);
    stat = play_recs(fid, reinit_rtf, 1, false, false, 0);
    stat = close_file(fid);

    NoButs();               /* unlink old living room button strip */
    PBFlag = true;          /* bring plane B up also */
    BopScene->Display = false;
    Step();
    FadeUp(meddisolve, false); /* no cursor */
}


/*
 * Close curtains -
 */
static void Close_Curtains()
{
int         fid;
Boolean     stat;

    fid = open_file("CCurt.rtf", false);
    stat = play_recs(fid, reinit_rtf, 2, false, false, 0);
    stat = close_file(fid);
}


/*
 * Open curtains -
 */
static void Open_Curtains()
{
int         fid;
Boolean     stat;

    fid = open_file("OCurt.rtf", false);
    stat = play_recs(fid, reinit_rtf, 2, false, false, 0);
    stat = close_file(fid);
}


/*
 * no_vel - this disables the objects velocity
 */
void no_vel()
{
ItemSeqPtr  theSeq;     /* the sequence item table */
short       ctr;

    for (ctr = 0; ctr < NumBopItems; ctr++) {
        theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[ctr].Where);
        theSeq->Pos.IIVelEnable = theSeq->Pos.IVelEnable = false;
    }
}

/*
 * add_vel - this enables the objects velocity
 */
void add_vel()
{
ItemSeqPtr  theSeq;     /* the sequence item table */
short       ctr;

    for (ctr = 0; ctr < NumBopItems; ctr++) {
        theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[ctr].Where);
        theSeq->Pos.IIVelEnable = theSeq->Pos.IVelEnable = true;
    }
}


/*
 * init_cannon - setup the cannon, wheel, and ball
 */
static void init_cannon()
{
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */
short       i, initStat, relXOff, relYOff;

    /*
     * Adjust the state offsets so that the first offset is 0,0
     */
    theSeqDF = the_cannon->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[the_cannon->Cyc.IIState].StateIA;
    initStat = the_cannon->Cyc.IIState;
    relXOff= theSeqDF->SeqTab[initStat].StateXOff;
    relYOff= theSeqDF->SeqTab[initStat].StateYOff;
    for (i = 0; i < theSeqDF->SeqNumSt; i++) {
        if (i == initStat){
            theSeqDF->SeqTab[i].StateXOff= 0;
            theSeqDF->SeqTab[i].StateYOff= 0;
        }
        else{
            theSeqDF->SeqTab[i].StateXOff-= relXOff;
            theSeqDF->SeqTab[i].StateYOff-= relYOff;
        }
    }

    theSeqDF = the_wheel->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[the_wheel->Cyc.IIState].StateIA;
    initStat = the_wheel->Cyc.IIState;
    relXOff= theSeqDF->SeqTab[initStat].StateXOff;
    relYOff= theSeqDF->SeqTab[initStat].StateYOff;
    for (i = 0; i < theSeqDF->SeqNumSt; i++) {
        if (i == initStat){
            theSeqDF->SeqTab[i].StateXOff= 0;
            theSeqDF->SeqTab[i].StateYOff= 0;
        }
        else{
            theSeqDF->SeqTab[i].StateXOff-= relXOff;
            theSeqDF->SeqTab[i].StateYOff-= relYOff;
        }
    }

    theSeqDF = the_ball->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[the_ball->Cyc.IIState].StateIA;
    initStat = the_ball->Cyc.IIState;
    relXOff= theSeqDF->SeqTab[initStat].StateXOff;
    relYOff= theSeqDF->SeqTab[initStat].StateYOff;
    for (i = 0; i < theSeqDF->SeqNumSt; i++) {
        if (i == initStat){
            theSeqDF->SeqTab[i].StateXOff= 0;
            theSeqDF->SeqTab[i].StateYOff= 0;
        }
        else{
            theSeqDF->SeqTab[i].StateXOff-= relXOff;
            theSeqDF->SeqTab[i].StateYOff-= relYOff;
        }
    }
    show_cannon();
}


/*
 * show_cannon - display the cannon
 */
static void show_cannon()
{

    the_cannon->Pos.IBaseX = the_cannon->Pos.ICurX = cannon_init_xpos;
    the_cannon->Pos.IBaseY = the_cannon->Pos.ICurY = cannon_init_ypos;
    the_cannon->Pos.ICurXOff = 0;
    the_cannon->Pos.ICurYOff = 0;

    the_cannon->Pos.IBox.bottom = 500;
    the_cannon->Pos.IIBox.bottom = 500;

    the_cannon->Gen.IActive = true;
    the_cannon->Gen.IDisplay = true;
    the_cannon->Cyc.ICycEnable = false;
    the_cannon->Cyc.ICycle = 0;
    the_cannon->Cyc.IState = 0;

    the_wheel->Pos.IBaseX = the_wheel->Pos.ICurX = cannon_init_xpos + wheel_xoff;
    the_wheel->Pos.IBaseY = the_wheel->Pos.ICurY =  cannon_init_ypos + wheel_yoff;
    the_wheel->Pos.ICurXOff = 0;
    the_wheel->Pos.ICurYOff = 0;
    the_wheel->Gen.IDisplay = true;
    the_wheel->Gen.IActive = true;
    the_wheel->Cyc.ICycEnable = false;

    ball_active = false;
    cannon_active = true;
    cannon_ctr = 0;
    pt_pos(vidpath, cannon_init_xpos * 2, cannon_init_ypos * 2);    /* reset to center */
}


/*
 * update_cannon -  move the cannon
 *                  pass ( CANNON_LEFT or CANNON_RIGHT )
 *
 */
void update_cannon(offset)
    short   offset;
{

    the_cannon->Pos.IBaseX += offset;
    the_wheel->Pos.IBaseX = the_cannon->Pos.IBaseX + wheel_xoff;

    if (offset < 0) {
        the_wheel->Cyc.IState++;
        if (the_wheel->Cyc.IState == the_wheel->Cyc.ICycSize)
            the_wheel->Cyc.IState = 0;
    }
    else {
        the_wheel->Cyc.IState--;
        if (the_wheel->Cyc.IState == -1)
            the_wheel->Cyc.IState = the_wheel->Cyc.ICycSize - 1;
    }
}

/*
 * hide_cannon -
 */
void hide_cannon()
{

    /*
     * This gets called when the cannon is going behind the curtain.
     * This wont get called if there is a ball, bop, etc currently active.
     */
    the_cannon->Gen.IActive = false;
    the_cannon->Gen.IDisplay = false;
    cannon_active = false;
    cannon_ctr = 0;

    the_wheel->Gen.IActive = false;
    the_wheel->Gen.IDisplay = false;

    if (ball_active) {
        the_ball->Gen.IDisplay = false;
        the_ball->Gen.IActive = false;
        ball_active = false;
    }
}


/*
 * Bop2 - the game part of all this
 */
void Bop2()
{
int     stat;

    while (theInpTab.ButPress)
        CheckInput(); /* wait for button release */
    cursor_hide();
    start_bkgd_audio(BopMusic, BEARfid, true); /* Start bkgd audio */
    NoBopBut();
    show_cannon();          /* also sets pointer to center of screen */
    last_xpos = inp_xpos;   /* xpos of input device */
    last_ypos = inp_ypos;   /* ypos of input device */
    add_vel();              /* let the targets bounce around */
    while ((cannon_active) && (!game_over)) {

        if (stat = chk_help(0, BEARfid, BopMusic, BEARfid))
            add_vel();      /* the dimming code would have disabled the velocity */
        if (stat = chk_dim())   /* if it's time to dim, this won't return until undim */
            add_vel();      /* the dimming code would have disabled the velocity */

        update_audio();
        if (round_over) {
            if ((!cannon_ctr) && (!ball_active) && (!bop_ctr)) {
                stop_all_audio();
                new_round();
                start_bkgd_audio(BopMusic, BEARfid, true); /* Start bkgd audio */
                add_vel();
            }
        }
        if (ball_active)
            check_collision();
        update_rows();
        CheckInput();
        if (inp_xpos > cannon_init_xpos * 2) {
            update_cannon(CANNON_RIGHT);
            pt_pos(vidpath, cannon_init_xpos * 2, cannon_init_ypos * 2);    /* reset to center */
        }
        else if (inp_xpos < cannon_init_xpos * 2) {
            update_cannon(CANNON_LEFT);
            pt_pos(vidpath, cannon_init_xpos * 2, cannon_init_ypos * 2);    /* reset to center */
        }
        if ((the_cannon->Pos.IBaseX < cannon_left_limit) || (the_cannon->Pos.IBaseX > cannon_right_limit)) {
            if ((!cannon_ctr) && (!ball_active) && (!bop_ctr)) {
                hide_cannon();
            }
        }
        if ((cannon_ctr) || (ball_active))
            update_shot(); /* this could return with 'game_over' set */
        else if ((theInpTab.ButPress) && (!bop_ctr) && (!smap_busy) && (!smap_list_ctr) &&
            (!round_over) && (the_cannon->Pos.IBaseX >= cannon_left_limit) && (the_cannon->Pos.IBaseX <= cannon_right_limit))
            init_shot(); /* if there are no bops, no soundmaps being played or in the queue */

        last_xpos = inp_xpos;   /* xpos of input device */
        last_ypos = inp_ypos;   /* ypos of input device */
    }
    no_vel();               /* stop the x movement of the items */
}



/*
 * update_rows -    This sees if new items need to be introduced or
 *                  if old items need to be removed.
 */
static void update_rows()
{
ItemSeqPtr  theSeq;     /* the sequence item table */
ItemSeqPtr  theSeq2;    /* another sequence item table */
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */
short       ctr, the_index;


    /*
     * See if there are any active bop sequences
     */
    if (bop_ctr) {
        bop_ctr--;
        if (!bop_ctr) { /* time to change the image */
            the_ball->Gen.IDisplay = false;
            the_ball->Gen.IActive = false;
            the_ball->Cyc.ICycEnable = false;
            the_ball->Pos.IXVel = 0;
            ball_active = false;

            theSeq = (ItemSeqPtr) ((unsigned)BopScene +
                (unsigned)BopScene->ItemDir[bop_item_index].Where);

            if (bop_item_index >= NumRowItems) { /* less then NumRowItems means top row */
                /*
                 * either restore the original image parameters
                 * or substitute the word sequence
                 */
                 switch (BopItems[bop_item_index].hit_ctr) {

                    case 1: /* switch to the word (if in bottom two rows) */

                        /*
                         * word soundmaps start at snd #5
                         * images for bottom two rows start at item #4
                         * so add 1 to bop_item_index to get sound to play
                         */
                        start_soundmap(snd_array[bop_item_index + 1].smap_id);
                        /*
                         * theSeq2 is a ptr to the word sequence which
                         * appears 8 items later than its image in the scene
                         */
                        theSeq2 = (ItemSeqPtr) ((unsigned)BopScene +
                            (unsigned)BopScene->ItemDir[bop_item_index+8].Where);
                        /*
                         * transfer the word image sequence ptr to the item
                         */
                        theSeq->Cyc.ICycEnable = false;
                        theSeq->Cyc.IState = text; /* text - 0=English, 1=Spanish */
                        if (theSeq->Gen.IActive)
                            theSeq->Gen.IDisplay = true;
                        theSeq->Cyc.ICycSize = 2;

                        theSeqDF = theSeq->Cyc.ISeqPtr = theSeq2->Cyc.ISeqPtr;
                        theShp = theSeqDF->SeqTab[theSeq->Cyc.IState].StateIA;
                        theSeq->Pos.ICurWide = theShp->NumWide;
                        theSeq->Pos.ICurHigh = theShp->NumHigh;

                        theSeq->Pos.ICurXOff = 0;   /* these might be set from last sequence */
                        theSeq->Pos.ICurYOff = 0;   /* they would be added to the new position */

                        theSeq->Pos.IBaseY = theSeq->Pos.ICurY =
                            BopRows[bop_item_index >> 2].inity - ((theShp->NumHigh) >> 1);
                        break;

                    case 2: /* switch back to the original image */

                        /*
                         * see if this is one with a sound effect and
                         * play it if so
                         */
                        if (bop_item_index == BopPkgs[Boptab[WhichBop]].item13)
                            start_soundmap(snd_array[13].smap_id);
                        else if (bop_item_index == BopPkgs[Boptab[WhichBop]].item14)
                            start_soundmap(snd_array[14].smap_id);
                        else if (bop_item_index == BopPkgs[Boptab[WhichBop]].item15)
                            start_soundmap(snd_array[15].smap_id);

                        theSeq->Cyc.ICycEnable = true;
                        theSeq->Cyc.IState = 0; /* might as well start at initial state */
                        if (theSeq->Gen.IActive)
                            theSeq->Gen.IDisplay = true;

                        theSeqDF = theSeq->Cyc.ISeqPtr = BopItems[bop_item_index].org_seq_ptr;
                        theSeq->Cyc.ICycSize = BopItems[bop_item_index].num_states;
                        theShp = theSeqDF->SeqTab[theSeq->Cyc.IState].StateIA;
                        theSeq->Pos.ICurWide = theShp->NumWide;
                        theSeq->Pos.ICurHigh = theShp->NumHigh;

                        theSeq->Pos.IBaseY = theSeq->Pos.ICurY =
                            BopRows[bop_item_index >> 2].inity - ((theShp->NumHigh) >> 1);
                        break;

                    case 3: /* this item is finished */
                        theSeq->Gen.IDisplay = false; /* don't show item anymore */
                        num_gone++;
                        if (num_gone == num_gone_needed) /* change back to 6 for final version */
                            round_over = true;
                        break;
                }
            }
            else { /* it's something from the top row */
                theSeq->Gen.IDisplay = false; /* don't show item anymore */
            }
        }
    }
    for (ctr=0; ctr<NumRows; ctr++) {
        /*
         * check the leading item for time to disable
         */
        the_index = BopRows[ctr].first_item + BopRows[ctr].first_id;
        theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[the_index].Where);
        if (theSeq->Pos.ICurX <= (LSide + 9)) {
            theSeq->Gen.IDisplay = false;
            theSeq->Gen.IActive = false;
            BopRows[ctr].first_id++; /* advance to the next item to be disabled */
            if (BopRows[ctr].first_id == NumRowItems)
                BopRows[ctr].first_id = 0;
        }
        /*
         * See if the last item in the row has advanced far enough
         * for us to introduce a new item.
         */
        the_index = BopRows[ctr].first_item + BopRows[ctr].last_id;
        theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[the_index].Where);
        if ((theSeq->Pos.IXVel < 0 ) && ((theSeq->Pos.ICurX + BopRows[ctr].row_space) <= RSide)) {
            BopRows[ctr].last_id++;
            if (BopRows[ctr].last_id == NumRowItems)
                BopRows[ctr].last_id = 0;
            the_index = BopRows[ctr].first_item + BopRows[ctr].last_id;
            theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[the_index].Where);
            if (theSeq->Gen.IActive) {
                STATUS2("The next item for row %d is not ready !!!\n", ctr);
                BopRows[ctr].last_id--;
                if (BopRows[ctr].last_id == 0)
                    BopRows[ctr].last_id = NumRowItems - 1;
            }
            else {
                theSeqDF = theSeq->Cyc.ISeqPtr;
                theShp = theSeqDF->SeqTab[theSeq->Cyc.IState].StateIA;
                theSeq->Pos.IBaseX = theSeq->Pos.ICurX = RSide - (theShp->NumWide / 2);
                theSeq->Gen.IActive = true;

                /* if it still has a life */
                if (BopItems[the_index].hit_ctr < 3)    /* 3 = hit thrice (gone) */
                    theSeq->Gen.IDisplay = true;

                theSeq->Pos.IXVel = BopRows[ctr].velocity;
            }
        }
    }
}


/*
 * init_shot - shoot the ball
 */
static void init_shot()
{

    /*
     *the first few cycles involve the cannon only, the ball appears later
     */
    the_cannon->Cyc.ICycEnable = true;
    cannon_ctr = 12;        /* # of animation cycles for cannon to do (unless ball tops out first) */
}


/*
 * update_shot - check the cannon's state, move the ball,  and check for top of screen
 */
static void update_shot()
{
Boolean     stat;

    stat = false;
    if (cannon_ctr == 10) {
        /*
         * Start the ball - initial position relative to the cannon's
         */
        the_ball->Pos.IBaseX = the_ball->Pos.ICurX = the_cannon->Pos.IBaseX + ball_xoff;
        the_ball->Pos.IBaseY = the_ball->Pos.ICurY =  the_cannon->Pos.IBaseY + ball_yoff;
        the_ball->Pos.IXVel = 0;
        the_ball->Pos.IYVel = ball_velocity;
        the_ball->Gen.IDisplay = true;
        the_ball->Gen.IActive = true;
        the_ball->Cyc.ICycEnable = false;
        the_ball->Cyc.IState = 0;
        ball_active = true;
        start_soundmap(snd_array[shot_snd].smap_id);
    }

    if (cannon_ctr) { /* see if its time to stop the cannon from cycling */
        cannon_ctr--;
        if (!cannon_ctr) {
            the_cannon->Cyc.ICycEnable = false;
        }
    }

    if ((ball_active) && (the_ball->Pos.IBaseY <= ball_min)) { /* is ball off top of screen ? */
        the_ball->Gen.IDisplay = false;
        the_ball->Gen.IActive = false;
        ball_active = false;
        start_soundmap(snd_array[miss_snd].smap_id);
        /*
         * If the cannon is still going, disable it
         */
        if (cannon_ctr) {
            the_cannon->Cyc.ICycEnable = false;
            the_cannon->Cyc.IState = 0;
            cannon_ctr = 0;
        }
        game_over = loose_ball();   /* take a ball away */
    }
}



/*
 * check_collision - this checks for collisions and processes any hit items
 *
 * returns 'true' if all items have been removed
 */
static void check_collision()
{
short       ctr;
ItemSeqPtr  theSeq;     /* the sequence item table */
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */


    ball_rect.left = the_ball->Pos.ICurX;
    ball_rect.top = the_ball->Pos.ICurY;
    ball_rect.right = the_ball->Pos.ICurX + ball_width;
    ball_rect.bottom = the_ball->Pos.ICurY + ball_height;

    for (ctr = 0; ctr < NumBopItems; ctr++) {
        theSeq = (ItemSeqPtr) ((unsigned)BopScene + (unsigned)BopScene->ItemDir[ctr].Where);
        if ((theSeq->Gen.IActive) && (theSeq->Gen.IDisplay)) {
            if (theSeq->Pos.ICurX <=  ball_rect.right) {
                if (theSeq->Pos.ICurY <=  ball_rect.bottom) {
                    theSeqDF = theSeq->Cyc.ISeqPtr;
                    theShp = theSeqDF->SeqTab[theSeq->Cyc.IState].StateIA;
                    if (theSeq->Pos.ICurX + theShp->NumWide >=  ball_rect.left) {
                        if (theSeq->Pos.ICurY + theShp->NumHigh >=  ball_rect.top) {
                            if (ctr < 4) {
                                if ((ctr == 0) || (ctr == 2)) { /* stars */
                                    start_soundmap(snd_array[star_snd].smap_id);
                                    score += BopRows[ctr/NumRowItems].points;
                                    show_score();
                                    add_ball(); /* add a ball */
                                }
                                else { /* orbs */
                                    start_soundmap(snd_array[sphere_snd].smap_id);
                                    if (score >= BopRows[ctr/NumRowItems].points) {
                                        score -= BopRows[ctr/NumRowItems].points;
                                        show_score();
                                    }
                                    game_over = loose_ball();   /* take a ball away */
                                }
                            }
                            else {
                                start_soundmap(snd_array[bop_snd].smap_id);
                                score += BopRows[ctr/NumRowItems].points;
                                show_score();
                            }
                            /*
                             * Transfer the images velocity to the ball
                             * also convert for different sized images
                             */
                            bop_item_index = ctr;   /* which item was hit */
                            theSeq->Gen.IDisplay = false; /* turn off the original object */
                            the_ball->Pos.IXVel = theSeq->Pos.IXVel;
                            the_ball->Pos.IYVel = 0;
                            the_ball->Cyc.ICycEnable = true;

                            theSeqDF = the_ball->Cyc.ISeqPtr;
                            theShp = theSeqDF->SeqTab[the_ball->Cyc.IState].StateIA;
                            the_ball->Pos.ICurWide = theShp->NumWide;
                            the_ball->Pos.ICurHigh = theShp->NumHigh;

                            the_ball->Pos.IBaseY = the_ball->Pos.ICurY =
                                BopRows[bop_item_index >> 2].inity - ((theShp->NumHigh) >> 1);

                            bop_ctr = 6;            /* down counter for bop image cycling */
                            BopItems[bop_item_index].hit_ctr++;
                            break;  /* don't check for multiple hits */
                        }
                    }
                }
            }
        }
    }
}


/*
 * new_game - reinit the number of balls and score and display both of these
 */
static void new_game()
{
short       ctr;
ItemShpPtr  theShp;     /* shape item table */

    FirstBop = true;
    Balls = ball_new_amount;
    for (ctr = 0; ctr < ball_box_max; ctr++) {
        theShp = (ItemShpPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[ctr].Where);
        theShp->Gen.IActive = true;
        theShp->Gen.IDisplay = true;
    }
    for (ctr=0; ctr<NumBopItems; ctr++) {
        BopItems[ctr].hit_ctr = 0;
    }
    for (ctr=0; ctr<NumRows; ctr++) {
        BopRows[ctr].first_id = 0;
        BopRows[ctr].last_id = 0;
    }
    score = 0;
    bop_ctr = 0;
    num_gone = 0;
    round_over = false;
    game_over = false;
    show_score();
}


/*
 * new_round -
 */
static void new_round()
{
short   ctr;

    for (ctr=0; ctr<NumBopItems; ctr++) {
        BopItems[ctr].hit_ctr = 0;
    }
    for (ctr=0; ctr<NumRows; ctr++) {
        BopRows[ctr].first_id = 0;
        BopRows[ctr].last_id = 0;
    }
    bop_ctr = 0;
    num_gone = 0;
    round_over = false;
    WhichBop++; /* advance to next package */
    if (WhichBop == NumBopPkgs)
        WhichBop = 0;
    new_bop_pkg();
}


/*
 * show_score - display the score
 */
static void show_score()
{
short   ctr;
ItemShpPtr  theShp;     /* shape item table */


    STATUS2("score = %d\n", score);

    sprintf(sscore,"%7d",score);
    for (ctr=0; ctr<7; ctr++) {
        if (sscore[ctr] != 0x20) { /* space character */
            theShp = (ItemShpPtr) ((unsigned)StatScene +
                (unsigned)StatScene->ItemDir[ctr+5].Where); /* MSD of score is item #5 */
            theShp->ShpIA = num_tab[sscore[ctr] - 0x30];
        }
        else {
            theShp = (ItemShpPtr) ((unsigned)StatScene +
                (unsigned)StatScene->ItemDir[ctr+5].Where); /* MSD of score is item #5 */
            theShp->ShpIA = num_tab[0];
        }
    }
}


/*
 * loose_ball - remove one of the stockpile of balls
 *
 * The ball item numbers are 0,1,2,3,4
 * The storage box in top can display up to 5 balls.
 * The cannon still holds one even when the ball box is empty.
 *
 * return 'true' if all balls are gone
 */
static Boolean loose_ball()
{
ItemShpPtr  theShp;     /* shape item table */

    if ( (Balls > 1) && (Balls < 7) ) { /* balls=1 means the ball box is already empty */
        theShp = (ItemShpPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[Balls-2].Where);
        theShp->Gen.IActive = false;
        theShp->Gen.IDisplay = false;
    }
    Balls--;
    if (!Balls)
        return(true);
    else
        return(false);
}

/*
 * add_ball - add to the stockpile of balls
 *
 */
static void add_ball()
{
ItemShpPtr  theShp;     /* shape item table */

    if (Balls <= ball_box_max) { /* six balls or greater means the ball box is full */
        theShp = (ItemShpPtr) ((unsigned)StatScene + (unsigned)StatScene->ItemDir[Balls-1].Where);
        theShp->Gen.IActive = true;
        theShp->Gen.IDisplay = true;
    }
    Balls++;
}

buttons.c

#include <stdio.h>
#include <ucm.h>
#include <errno.h>

#include "dbg.h"

#include "utility.h"
#include "screen.h"
#include "buttons.h"
#include "animation.h"
#include "reading.h"
#include "sentbld.h"


int         butline = ButTop * 2;       /* current scan line that button bitmap is linked to */
Boolean     PlayFlag;                   /* true means the play button is active/usable */
TOCPtr      butTOC;     /* the table of contents of the button package */
Ptr         butData;    /* where the image data starts */

static Rect buttRect = {0,0,70,383};    /* enclosing rectangle for button strip */
static Rect buttRect2 = {1,1,69,382};   /* enclosing rectangle for button strip */


/*
 * DrawButShps - draw the rectangles that hold the words and icons
 */
void DrawButShps()
{
Ptr     butPtr;

    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but1_shp].Where);
    Draw((ShapePtr)butPtr, 33, 7);
    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but2_shp].Where);
    Draw((ShapePtr)butPtr, 88, 7);
    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but3_shp].Where);
    Draw((ShapePtr)butPtr, 155, 7);

    if (ModMod == ModBook)
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but6_shp].Where);
    else
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but4_shp].Where);
    Draw((ShapePtr)butPtr, 222, 7);

    if ((ModMod == ModSent2u) || (ModMod == ModSent2d))
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but7_shp].Where);
    else
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[but5_shp].Where);
    Draw((ShapePtr)butPtr, 289, 7);
}


/*
 * DrawButIcns - draw the icons on the button rectangles
 */
void DrawButIcns()
{
Ptr     butPtr;

    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[huh_shp].Where);
    Draw((ShapePtr)butPtr, 53, 13);
    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lips_shp].Where);
    Draw((ShapePtr)butPtr, 100, 14);
    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[text_shp].Where);
    Draw((ShapePtr)butPtr, 178, 13);

    if ((ModMod == ModSent1) || (ModMod == ModBook) || (ModMod == ModBop)) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[left_shp].Where);
        Draw((ShapePtr)butPtr, 301, 15);
    }

    if (ModMod == ModMain) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[bye_shp].Where);
        Draw((ShapePtr)butPtr, 310, 12);
    }

    if ( ((ModMod == ModSent1) || (ModMod == ModSent2u) || (ModMod == ModSent2d))
        && (PlayFlag)) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[tv_shp].Where);
        Draw((ShapePtr)butPtr, 239, 13);
    }

    if (ModMod == ModBop) { /* same as above check */
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[tv_shp].Where);
        Draw((ShapePtr)butPtr, 239, 13);
    }
}


/*
 * DrawButWrds - draw the words on the button rectangles
 */
void DrawButWrds()
{
Ptr     butPtr;

    if (text == English) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[help_e_shp].Where);
        Draw((ShapePtr)butPtr, 45, 33); /* draw the button shape */

        if (speech == Spanish) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_se_shp].Where);
            Draw((ShapePtr)butPtr, 95, 33); /* draw the button shape */
        }
        else {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_ee_shp].Where);
            Draw((ShapePtr)butPtr, 96, 33); /* draw the button shape */
        }

        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_ee_shp].Where);
        Draw((ShapePtr)butPtr, 163, 33); /* draw the button shape */

        if ((ModMod == ModSent1) || (ModMod == ModBook) || (ModMod == ModBop)) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[back_e_shp].Where);
            Draw((ShapePtr)butPtr, 306, 33); /* draw the button shape */
        }

        if (ModMod == ModMain) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[bye_e_shp].Where);
            Draw((ShapePtr)butPtr, 309, 33); /* draw the button shape */
        }

        if (((ModMod == ModSent1) || (ModMod == ModSent2u) ||
         (ModMod == ModSent2d))  && (PlayFlag)) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_e_shp].Where);
            Draw((ShapePtr)butPtr, 240, 33);
        }

        if (ModMod == ModBop) { /* same results as for above check */
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_e_shp].Where);
            Draw((ShapePtr)butPtr, 240, 33);
        }
    }
    if(text == Spanish) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[help_s_shp].Where);
        Draw((ShapePtr)butPtr, 39, 33); /* draw the button shape */

        if (speech == English) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_es_shp].Where);
            Draw((ShapePtr)butPtr, 100, 33); /* draw the button shape */
        }
        else {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_ss_shp].Where);
            Draw((ShapePtr)butPtr, 94, 33); /* draw the button shape */
        }

        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[lang_ss_shp].Where);
        Draw((ShapePtr)butPtr, 161, 33); /* draw the button shape */

        if ((ModMod == ModSent1) || (ModMod == ModBook) || (ModMod == ModBop)) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[back_s_shp].Where);
            /* Draw((ShapePtr)butPtr, 294, 33); */ /* draw the button shape */
            Draw((ShapePtr)butPtr, 303, 33); /* draw the button shape */
        }

        if (ModMod == ModMain) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[bye_s_shp].Where);
            Draw((ShapePtr)butPtr, 303, 34);
        }

        if (((ModMod == ModSent1) || (ModMod == ModSent2u) ||
         (ModMod == ModSent2d))  && (PlayFlag)) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_s_shp].Where);
            Draw((ShapePtr)butPtr, 229, 33);
        }

        if (ModMod == ModBop) {
            butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_s_shp].Where);
            Draw((ShapePtr)butPtr, 229, 33);
        }
    }
}


/*
 * NewBut - redraw the rectangles, icons, words, but don't redo the fill
 */
void NewBut()
{
Ptr     scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;
    DrawButShps();  /* draw the rectangles */
    DrawButIcns();  /* draw the icons */
    DrawButWrds();  /* draw the words */
    scn_ptr = scnptrsav;
}


/*
 * MkSentBut - Make Sentence Builder Buttons
 */
void MkSentBut()
{
Ptr     butPtr;
Ptr     scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;

    Fill(buttRect, FilCol); /* wipeout whatever used to be here */

    DrawButShps();  /* draw the rectangles */
    DrawButIcns();  /* draw the icons */
    DrawButWrds();  /* draw the words */

    /*
     * Draw the bottom shadow shape onto the button strip sub-screen.
     * Also draw the contents of the play button if this is screen 2.
     */
    if (ModMod == ModSent1) {
        butPtr = mfxDir[getind("shadow1.shp")].Where;
        Draw((ShapePtr)butPtr, 33, 0); /* draw the two smaller shadows */
    }
    else {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[shadow2_shp].Where);
        Draw((ShapePtr)butPtr, 33, 0); /* draw the huge box shadow */
        LetPlay();  /* draw the play button contents */
    }
    scn_ptr = scnptrsav;

/*
 * Link the 70 scan line button strip to the plane B LCT.
 */
    dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
}

/*
 * MkBopBut - Make Word Bop Buttons
 */
void MkBopBut()
{
Ptr     scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;

    Fill(buttRect, 15); /* black */
    Fill(buttRect2, FilCol);

    DrawButShps();  /* draw the rectangles */
    DrawButIcns();  /* draw the icons */
    DrawButWrds();  /* draw the words */

    scn_ptr = scnptrsav;
    /*
     * Link the 70 scan line button strip to the plane B LCT.
     */
    dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
    /*
     * turn on the matte in plane A to let the buttons show through
     */
    bop_but_matte_on();
}

void NoBopBut()
{
    /*
     * Unlink the 70 scan line button strip to the plane B LCT.
     */
    dc_wrli(vidpath,lctid2,butline,0,cp_nop());
    /*
     * turn off the matte in plane A
     */
    bop_but_matte_off();
}


/*
 * MkMainBut - Make Main Menu Buttons
 *      When this is called, plane A is being shown so we can
 *      do whatever we want here.
 */
void MkMainBut()
{
Ptr     butPtr;
Ptr     scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;
    /*
     * Draw the button strip background for the living room
     */
    butPtr = mfxDir[getind("buttonblock.shp")].Where;
    Draw((ShapePtr)butPtr, 0, 0); /* draw the button shape */

    DrawButShps();  /* draw the rectangles */
    DrawButIcns();  /* draw the icons */
    DrawButWrds();  /* draw the words */

    scn_ptr = scnptrsav;
    /*
     * Link the 70 scan line button strip to the plane B LCT.
     */
    dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
}



/*
 * MkBookBut - Make Word Book Buttons
 *      When this is called, plane A is being shown so we can
 *      do whatever we want here.
 */
void MkBookBut()
{
Ptr     butPtr;
Ptr     scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;

    Fill(buttRect, FilCol); /* wipeout whatever used to be here */

    DrawButShps();  /* draw the rectangles */
    DrawButIcns();  /* draw the icons */
    DrawButWrds();  /* draw the words */

    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[shadow2_shp].Where);
    Draw((ShapePtr)butPtr, 33, 0); /* draw the huge box shadow */

    scn_ptr = scnptrsav;
/*
 * Link the 70 scan line button strip to the plane B LCT.
 */
    dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
}




/*
 * LetPlay - draws the icon and text for the play button
 */
void LetPlay()
{
Ptr         butPtr;
Ptr         scnptrsav;

    scnptrsav = scn_ptr;
    scn_ptr = vidmem4;
    butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[tv_shp].Where);
    Draw((ShapePtr)butPtr, 239, 13);
    if(text == English) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_e_shp].Where);
        Draw((ShapePtr)butPtr, 240, 33);
    }
    if(text == Spanish) {
        butPtr = (Ptr) ((unsigned)butData + (unsigned)butTOC->TE[play_s_shp].Where);
        Draw((ShapePtr)butPtr, 229, 33);
    }
    scn_ptr = scnptrsav;
    PlayFlag = true;
}


/*
 * MoveBut - pass this 'false' to move the buttin strip up
 *           pass it 'true' to move the button strip down
 *
 * When this gets called we either have the scroll mask active
 * or we have a real time file frame present in plane A.
 * This code changes the values of either the matte or the transparent
 * area of the plane A rtf frame.
 */
void MoveBut(butdir)
    Boolean butdir;
{
Boolean     butflg = true;
int         stat;


    while (butflg) {
        swapflag = false;   /*  scan line interrupt will set to allow next frame */

        if ((stat = dc_ssig(vidpath,SLI_SIGNAL,0)) == -1) {
            STATUS2("couldn't set SLI in MoveBut. error number %d\n", errno);
        }

        /* STATUS1("Waiting\n"); */
        while (!swapflag);
        /* STATUS1("Got\n"); */

        if (butdir) {   /* true means going down */
            if (butline == ButBot * 2)
                butflg = false; /* we're finished, reset butflg */
            else {
                butline += 2;
                dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
                dc_wrli(vidpath,lctid2,butline-2,0,cp_nop());
                if (useRTF) { /* adjust the transparency line of plane A */
                    dc_wrli(vidpath,lctid0,butline,0,cp_matte(0,MO_RES,MF_MF0,ICF_MIN,0));
                    dc_wrli(vidpath,lctid0,butline-2,0,cp_nop());
                }
                else { /* adjust the scrolling mask to the new button line */
                    dc_wrli(vidpath,lctid0,butline,0,cp_matte (0, MO_RES, MF_MF0, ICF_MIN, 0));
                    dc_wrli(vidpath,lctid0,butline,1,cp_matte (1, MO_END, MF_MF0, ICF_MIN, 0));
                    dc_wrli(vidpath,lctid0,butline-2,0,cp_nop());
                    dc_wrli(vidpath,lctid0,butline-2,1,cp_nop());
                }
            }
        }
        else {  /* button strip moving up */
            if (butline == ButTop * 2)
                butflg = false;
            else {
                butline -= 2;
                dc_wrli(vidpath,lctid2,butline,0,cp_dadr((int)vidmem4));
                dc_wrli(vidpath,lctid2,butline+2,0,cp_nop());
                if (useRTF) { /* adjust the transparency line of plane A */
                    dc_wrli(vidpath,lctid0,butline,0,cp_matte(0,MO_RES,MF_MF0,ICF_MIN,0*2));
                    dc_wrli(vidpath,lctid0,butline+2,0,cp_nop());
                }
                else { /* adjust the scrolling mask to the new button line */
                    dc_wrli(vidpath,lctid0,butline,0,cp_matte (0, MO_RES, MF_MF0, ICF_MIN, 0));
                    dc_wrli(vidpath,lctid0,butline,1,cp_matte (1, MO_END, MF_MF0, ICF_MIN, 0));
                    dc_wrli(vidpath,lctid0,butline+2,0,cp_nop());
                    dc_wrli(vidpath,lctid0,butline+2,1,cp_nop());
                }
            }
        }
    }
}

/*
 * NoButs - this unlinks the button bitmap from the main screen
 */
void NoButs()
{
    dc_wrli(vidpath,lctid2,butline,0,cp_nop());
}

cursor_mgr.c

/****************************************************************************
*   FILENAME:   cursor_mgr.c
*   PROJECT:    Sticky Bear Reading
*   PURPOSE:    Fully localize utility for managing the cursor through signals
*   FUNCTIONS:  Update_Coord ()
*               Get_Coord ()
*               Get_Button ()
*               Set_Coord ()
*               cursor_mgr ()
*   AUTHOR:     Douglas Yoon
*   DATE:       June 29, 1992
*   LOCATION:   Philips Interactive Media of America, DC office
*   REVISED:    6/29/92 Version 1
*   REVISED:    6/30/92 Version 1.01 dgc Added call to pt_coord when
*                                   case is CM_BUTTON in cursor_mgr
*   REVISED:    9/22/92 Version 1.02 dcc/dgc Limit cursor to safe area
*                                   Handle PAL
*   REVISED:    10/2/92 Version 1.03 dcc/dgc Added cursor hold/release
*
*****************************************************************************/

#include "dbg.h"
#include "cursor_mgr.h"
#include "screen.h"
#include "utility.h"


static int
    gCurX;
static int
    gCurY;



/**********************************/
/* This function should be only  */
/* be called from a signal handler. */
/* It will call on the cursor */
/* manager to update its local */
/* variables */
/**********************************/
void Update_Coord ()
{
    int butn;
    int x_c;
    int y_c;

    cursor_mgr (&x_c, &y_c, &butn, CM_UPDATE);
}

/**********************************/
/* This function will return */
/* what is believes to be */
/* the current cursor position */
/**********************************/
void Get_Coord (x_c, y_c)
int *x_c;
int *y_c;
{
    int butn;

    cursor_mgr (x_c, y_c, &butn, CM_COORD);
    if (PALflag) *y_c -= 40;
}

/**********************************/
/* This function will return the */
/* button state as specified by the */
/* Green Book */
/**********************************/
void Get_Buttons (butn)
int *butn;
{
    int x_c;
    int y_c;

    cursor_mgr (&x_c, &y_c, butn, CM_BUTTON);
}

/**********************************/
/* Will send a message to the cursor */
/* manager to move the cursor to */
/* a specific spot */
/**********************************/
void Set_Coord (x, y)
int x;              /* these can not be passed directly since */
int y;              /* they are registers !!! */
{
    int butn;
    int x_c;
    int y_c;

    x_c = x;
    y_c = y;

    cursor_mgr (&x_c, &y_c, &butn, CM_MOVE);
}


/**********************************/
/* Will send a message to the cursor */
/* manager to freeze the cursor */
/**********************************/
void Cursor_Freeze ()
{
    int butn;
    int x_c;
    int y_c;

    cursor_mgr (&x_c, &y_c, &butn, CM_FREEZE);
}

/**********************************/
/* Will send a message to the cursor */
/* manager to release the cursor */
/**********************************/
void Cursor_Melt ()
{
    int butn;
    int x_c;
    int y_c;

    cursor_mgr (&x_c, &y_c, &butn, CM_MELT);
}


/**********************************/
/* The cursor manager proper !!! */
/**********************************/
void cursor_mgr (x_c, y_c, butn, context)
int *butn;
int *x_c;
int *y_c;
int context;
{
    static int button = 0;              /* local "global" variables */
    static int x_coord = 0;             /* to keep track of the cursor */
    static int y_coord = 0;             /* and the button states */

    switch (context)
    {
        case CM_UPDATE:                 /* find out from the system, where the */
            pt_coord (vidpath, &button, &x_coord, &y_coord); /* cursor currently */

            {
                short
                    reset;

                reset = 0;

                if (x_coord > safe_rect.right)
                    x_coord = reset = safe_rect.right;
                if (x_coord < safe_rect.left)
                    x_coord = reset = safe_rect.left;
                if (y_coord > safe_rect.bottom)
                    y_coord = reset = safe_rect.bottom;
                if (y_coord < safe_rect.top)
                    y_coord = reset = safe_rect.top;
                if ( reset )
                    pt_pos (vidpath, x_coord, y_coord);
            }

            gc_pos (vidpath, x_coord, y_coord);             /* exists */
            break;

        case CM_COORD:                  /* return the x,y coordinates */
            *x_c = x_coord;
            *y_c = y_coord;
            break;

        case CM_BUTTON:                 /* return the buttons' states */
            pt_coord (vidpath, &button, &x_coord, &y_coord); /* cursor currently */
            *butn = button;
            break;

        case CM_MOVE:                   /* move the cursor and graphic */
            x_coord = *x_c;
            y_coord = *y_c;
            pt_pos (vidpath, x_coord, y_coord); /* REEEAL EXPENSIVE CALL!!! */
            gc_pos (vidpath, x_coord, y_coord);
            break;

        case CM_FREEZE:                 /* freeze the cursor */
            pt_rel (vidpath);
            pt_coord (vidpath, &button, &x_coord, &y_coord); /* cursor currently */
            gCurX = x_coord;
            gCurY = y_coord;
            break;

        case CM_MELT:                   /* start accepting cursor input again */
            pt_pos (vidpath, gCurX, gCurY); /* start from where we froze */
            pt_ssig (vidpath, PTR_SIGNAL);
            break;

    }
}


file_mgr.c

#include <stdio.h>
#include <ucm.h>
#include <errno.h>
#include <modes.h>
#include <csd.h>

#include "dbg.h"

#include "my_types.h"
#include "file_mgr.h"
#include "rtf.h"
#include "screen.h"
#include "sound.h"
#include "reading.h"


short               eor_ctr;
short               trigger_ctr;
Boolean             play_error;
static  short       gCurDataDir = 0;

/*
 * open_file - opens a file and returns the ID
 *
 * Pass     -   char *filename, Boolean just_say_no (true = return error , false = quit program)
 *
 * Returns  -   int FID
 */
int open_file(name, just_say_no)
    char *name;
    Boolean just_say_no;
{
int     fid;

    if ((fid = open(name,S_IREAD)) == -1) {
        STATUS3("Can't open %s. Error Number %d\n", name, errno);
        if ((fid = open(name,S_IREAD)) == -1) {
            STATUS3("Can't open %s on second try. Error Number %d\n", name, errno);
            if (just_say_no)
                return(-1);
            else
                DoDirtyDisc();
        }
    }
    return(fid);
}


/*
 * play_recs - play record(s) of a real time file
 *
 * Pass     -   int         - file ID
 *              (*func)()   - function pointer to setup routine (sets up PCB)
 *              short       - # records to play
 *              Boolean     - async - exit after starting play
 *              Boolean     - abortable
 *              short       - # triggers required before abort allowed
 *
 * Returns  -   Boolean     - true if file was aborted before completion
 */
Boolean play_recs(fid, setup, recs, async, abortable, trigs)
    int     fid;
    void    (*setup) ();
    short   recs;
    Boolean async;
    Boolean abortable;
    short   trigs;
{
int         stat;
Boolean     early = false; /* gets set if abort happens */
int         ctr;
Boolean     retry;


    if (setup)
        setup();        /* set up the PCB for this play */
    trigger_ctr = trigs; /* if file is interruptable , we need this many triggers first */

    play_error = false; /* the signal handler might set this */
    thePCB->PCB_Rec = recs;
    eor_ctr = recs;
    ss_play(fid,thePCB);

    if (async)
        return(false); /* return once the play has been started  */

    while (eor_ctr) {
        if (abortable) {
            Get_Buttons(&stat);
            /*
             * trigger_ctr gets decremented for each trigger received during the RTF play.
             */
            if ((stat & 0x03) && (!trigger_ctr) && (!early)) {
                ss_abort(fid);
                early = true;
            }
        }
    }
    if (play_error) {
        STATUS2("Had trouble playing file. Error Number %d\n", errno);
        close_file(fid);
        DoDirtyDisc();
    }
    if (!abortable) { /* if this was a data load without an av rtf, check the pcls for error */
        retry = false;
        for (ctr=0; ctr<recs; ctr++) {
            if (pcl_tab[ctr]->PCL_Ctrl & 0x80) {
                STATUS2("pcl_tab[%d]->PCL_Ctrl is in trouble\n", ctr);
                retry = true;
            }
        }
        if (retry) {
#if 0
            for (ctr=0; ctr<recs; ctr++) {
                pcl_tab[ctr]->PCL_Ctrl = 0;
                pcl_tab[ctr]->PCL_Cnt = 0;
            }
            thePCB->PCB_Rec = recs;
            eor_ctr = recs;
            ss_play(fid,thePCB);
            while (eor_ctr);

            retry = false;
            for (ctr=0; ctr<recs; ctr++) {
                if (pcl_tab[ctr]->PCL_Ctrl & 0x80) {
                    STATUS2("pcl_tab[%d]->PCL_Ctrl is in trouble on second try\n", ctr);
                    retry = true;
                }
            }
#endif
            if (retry)
                close_file(fid);
                DoDirtyDisc();
        }
    }
    return(early);
}


/*
 * close_file - closes a file
 *
 * Pass     -   int - file ID
 *
 * Returns  -   true if error occured
 */
Boolean close_file(fid)
    int fid;
{
int     stat;

    if ((stat = close(fid)) == -1) {
        STATUS2("Can't close file. Error Number %d\n", errno);
        return(true);
    }
    return(false);
}


#if 0
/*
 * try_next_dir - if it can't, this goes to the dirty disc code and never comes back
 */
int try_next_dir()
{
    if (gCurDataDir < 2) {
        STATUS1("Will try next data directory\n");
        unset_files(ModMod);    /* close all open files related to current module */
        SetDataDir(TRUE);       /* advance to next data dir */
        set_files(ModMod);      /* open them all in the new data dir */
    }
    else {
        DoDirtyDisc();
    }
    return(0);
}
#endif


#if 0
/*
 * if n is TRUE then SetDataDir advances to the next data directory.
 * if n is FALSE it merely sets the current data dir.
 */
int SetDataDir(n)
    short n;
{
char    p[32];
char    *cd_dev;
char    *dir1 = "DATA1";
char    *dir2 = "DATA2";

    STATUS1("SetDataDir: Enter\n");

    play_error = false; /* reset this */

    if ( n ) {
        gCurDataDir += 1;
        if ( gCurDataDir > 2 ) {
            DoDirtyDisc(); /* we don't come back here */
        }
    }

    if ( (cd_dev = csd_devname( DT_CDPLAY, 1 )) == NULL ) {
        STATUS1("can't get name of CD player\n");
        return (1);
    }

    strcpy(p, cd_dev);
    if (gCurDataDir == 1)
        strcpy(p, dir1);
    if (gCurDataDir == 2)
        strcpy(p, dir2);

    if ( chdir(p) == -1 ) {
        STATUS1("***** Could not set data directory *****\n");
        DoDirtyDisc(); /* we don't come back here */
    }

    free( cd_dev );         /* Give back memory for csd stuff */

    STATUS1("SetDataDir: Exit\n");

    return(0);
}
#endif


void DoDirtyDisc()
{
int         dirty_fid;
Boolean     stat;
int         but_stat;

    dirty_fid = open_file("dirty.rtf", true);
    if (dirty_fid == -1) {
        STATUS1("can't open dirty disc rtf\n");
        exit(0);
    }
    stat = play_recs(dirty_fid, reinit_rtf, 1, false, false, 0); /* play first frame/record */
    *(short *)vidmem0 = 0x8F00;
    DslvBA(fastdisolve); /* show plane A */
    stat = play_recs(dirty_fid, reinit_rtf, 1, false, true, 0); /* play rest of file */
    stat = close_file(dirty_fid);

    Get_Buttons(&but_stat);
    while (!(but_stat & 0x03)) {
        Get_Buttons(&but_stat);
    }
    exit(0);
}



reading.c

#include <stdio.h>
#include <errno.h>
#include <modes.h>
#include <rtr.h>
#include <aimdef.h>
#include <memory.h>
#include <time.h>
#include <module.h>
#include <ucm.h>
#include <csd.h>
#include <cdfm.h>
#include <bumper.h>

#include "dbg.h"

#include "utility.h"
#include "startup.h"
#include "screen.h"
#include "rtf.h"
#include "sound.h"
#include "buttons.h"
#include "wordbook.h"
#include "sentbld.h"
#include "bop.h"
#include "file_mgr.h"

/*
 * These are the rectangle tables for each section of SB Reading
 */
static  RectList LVRect = {
      7,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,289,218,350,    /* go back button */
     17, 33,163,112,    /* bear #1 - Sara */
     19,117,154,187,    /* bear #2 - Bedford */
     72,235,170,321     /* bear #3 - Bumper */
    };

short       ModMod; /* holds the index for the current program mode/module */
Ptr         PkgBuf;     /* This is the new buffer that holds the data for current module */
Ptr         ButtonBuf;  /* This holds the button images */
/* These are for Sentence Builder */
Ptr         ScreenBuf;  /* screen images */
Ptr         RezBuf;     /* resedit data */
Ptr         Seq1Buf;    /* seq 1 */
Ptr         Seq2Buf;    /* seq 2 */
Ptr         BkgdBuf;    /* background image */

TOCPtr      pkgTOC;     /* pointer to the table of contents for current package */
int         last_xpos;
int         last_ypos;
unsigned long   currentT;   /* current tick count */
unsigned long   HelpTime;   /* clk count for when to do help */
unsigned long   DimTime;    /* clk count for when to dim screen */

int         BUTTONfid;  /* file ID for button audio real time file */
int         BEARfid;    /* file ID for bear speech of current module */
int         TUNEfid;    /* file ID for bkgd music of current module */
int         Eng_bear_fid;
int         Span_bear_fid;
int         Eng_button_fid;
int         Span_button_fid;

int         Tune1ID;    /* 1st file of bkgd tunes (all for word book) */
int         Tune2ID;    /* 2nd file of bkgd tunes (last 4 for word book) */
int         Tune3ID;    /* 1st file of sentence builder bkgd tunes */
int         Tune4ID;    /* 2nd file of sentence builder bkgd tunes */
int         Tune5ID;    /* 3rd file of sentence builder bkgd tunes */


short       speech = English;
short       text = English;

static  Boolean     BearFlag[3];
static  short       BearTalk[3]; /* 0=bear hasn't spoken, 1=has, 2=currently is talking */
static  ItemSeqPtr  MMSeq;
static  ScenePtr    MMScene;
static  short       DirSaveMM;
static  Boolean     SB_shuf = false;
static  Boolean     Sara_shuf = false;
static  Boolean     Bump_shuf = false;

#ifdef WANT_STATUS
#define BUMPER_MEMORY_COLOR SYSRAM
#define TITLE_MEMORY_COLOR  SYSRAM
#else
#define BUMPER_MEMORY_COLOR VIDEO1
#define TITLE_MEMORY_COLOR  VIDEO2
#endif
#define BUMP_ARGNUM     2       /* Max number of bumper cmd line args */
#define BUMPER_PATH_NUM 5       /* Number of open paths to pass */

char    *bumpargblk[BUMP_ARGNUM] = {"cdi_bumper", 0};
char    *bumpdata = "cdi_bumpdata";

extern int  os9forkc();
extern char **environ;


/*
 * This is the main code for Stickybear Reading
 */
void main(argc,argv)
int argc;
char *argv[];
{
int         fid;
int         stat;
Boolean     playstat;
STAT_BLK    seekstat;
int         bumper_status;
mod_exec    *datmod, *modlink(), *modcload();
BUMPER_DATA *bumpmod;
char        *vid_dev,*csd_devname();

    intercept(signal_handler);  /* hook up our signal handler */
    setup_audio();              /* open a path to the audio device */

    /*
     * get the bumper data module into memory
     */
    if ( (int)(datmod = modcload( bumpargblk[0], 0, VIDEO1 )) == SYSERR )
        exit( errno );
    if ( (int)(datmod = modlink( bumpdata, MT_ANY )) == SYSERR )
        exit( errno );
    /*
     * Point to the actual data section of the module
     */
    bumpmod = (BUMPER_DATA *)((char *)datmod + ((DATA_MODULE *)datmod)->data_offset);

    if ( (vid_dev = csd_devname( DT_VIDEO, 1 ) ) == NULL )
        exit( SYSERR );

    /*
     * copy the video device name to the bumper data module
     */
    strcpy( bumpmod->vid_name, vid_dev );

    /*
     * Open path to video device
     */
    if ( (vidpath = open( vid_dev, (S_IREAD | S_IWRITE) )) == SYSERR )
        exit( SYSERR );
    free( vid_dev );            /* Release memory returned by func */
    /*
     * Set compat bit and PAL flag
     */
    if ( set_comp_mode( vidpath, &PALflag ) == SYSERR ) exit( errno );
    /*
     * Create the DCP, shut down the planes, execute DCP
     */
    fctid_RL7 = dc_crfct(vidpath,PA,150,RES_NORMAL);    /* our clut7 in plane A */
    fctid_Clut7 = dc_crfct(vidpath,PB,140,RES_NORMAL);  /* rl7 in plane B */
    lctid0 = dc_crlct(vidpath,PA,240*2,RES_NORMAL); /* used for RL7 screens */
    lctid2 = dc_crlct(vidpath,PB,240*2,RES_NORMAL); /* used for clut7 screens */
    dc_flnk( vidpath, fctid_RL7, lctid0, 0 );
    dc_flnk( vidpath, fctid_Clut7, lctid2, 0 );
    dc_wrfi( vidpath, fctid_RL7, FCT_ICF, cp_icf(PA, ICF_MIN) );
    dc_wrfi( vidpath, fctid_Clut7, FCT_ICF, cp_icf(PB, ICF_MIN) );
    dc_exec( vidpath, fctid_RL7, fctid_Clut7 );

    /*
     * Init the rest of the data module
     */
    bumpmod->dcp.fcta = fctid_RL7;
    bumpmod->dcp.fctb = fctid_Clut7;
    bumpmod->dcp.lcta = lctid0;
    bumpmod->dcp.lctb = lctid2;
    bumpmod->lct_height = MIN_BUMP_LCTHEIGHT;
    bumpmod->pal_flag = PALflag;
    bumpmod->pcb = NULL;
    bumpmod->data_sector = 0;
    bumpmod->app_pa_buf = NULL;
    bumpmod->app_pb_buf = NULL;

    /*
     * fixes for the new bumper
     */
    dc_llnk( vidpath, lctid0, (240 * 2 ) -2, lctid0, (240 * 2 ) -2);
    dc_llnk( vidpath, lctid2, (240 * 2 ) -2, lctid2, (240 * 2 ) -2);

    /*
     * Fork the Bumper
     */
    if ( os9exec( os9forkc, bumpargblk[0], bumpargblk, environ, 0, 0, BUMPER_PATH_NUM ) == SYSERR )
        exit( errno );

    wait( &bumper_status );
    /*
     * Check return status from bumper
     */
    if ( bumpmod->return_status != BE_HUNKY ) {
        if ( bumpmod->return_status == BE_INTERRUPT ) {
            STATUS1("Bumper was interrupted by the user.\n");
        }
        else {
            STATUS2("loader:Bumper returns error 0x%x\n", bumpmod->return_status );
            exit(errno);
        }
    }
    stat = munload( bumpdata, MT_ANY );
    if (stat == -1) {
        STATUS2("****couldn't unload bumpdata. error numer 0x%x\n", errno);
    }

    if (PALflag) {
        safe_rect.top += 40;
        safe_rect.bottom += 40;
    }

    /* SetDataDir(TRUE); */

    setup_CDI();
    setup_rtf();

    dc_exec(vidpath,fctid_RL7,fctid_Clut7);

    pt_ssig(vidpath,PTR_SIGNAL);

    /*
     * initialize cursor delay time
     */
    cursorTime = currentT + cursor_delay;

    set_module(ModMain);
    /*
     * play the intro real time file
     */
    fid = open_file("intro.rtf", false);
    playstat = play_recs(fid, reinit_rtf, 3, false, false, 0); /* play first frame and data */
    dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MAX)); /* bring up plane A */
    playstat = play_recs(fid, reinit_rtf, 1, false, true, 0); /* play rest of file */
    playstat = close_file(fid);
    /*
     * The opening rtf loaded the button package.
     * Set a pointer to the image data section of the package.
     */
    butData = ButtonBuf + ((*(short *)ButtonBuf) * 40 + 4);

    MainMenu();
    /*
     * Quit the program - make the bears say goodbye
     */
    MakeBearLook(Bedford);
    MakeBearLook(Bumper);
    MakeBearLook(Sara);
    Step();
    start_bkgd_audio(14, BEARfid, false); /* say goodbye */
    while (eor_ctr) {
        Get_Buttons(&stat);
        if (stat & 0x03)  {
            ss_abort(BEARfid);
            eor_ctr = 0;
        }
    }
    stop_all_audio();
    /*
     * Play closing real time file and exit.
     *
     * Read in the first frame of the real
     * time file and display it in plane A.
     */
    cursor_hide();

    /*
     * play the exit real time file
     */
    fid = open_file("exit.rtf", false);
    stat = play_recs(fid, reinit_rtf, 1, false, false, 0); /* play first frame/record */
    *(short *)vidmem0 = 0x8F00;
    DslvBA(fastdisolve); /* show plane A */
    stat = play_recs(fid, reinit_rtf, 1, false, true, 0); /* play rest of file */
    if (stat) { /* file was aborted */
        seekstat.asy_sig = 0;
        seekstat.asy_stat = 0; /* book says not to mess with this ? */
        ss_seek(fid, 4368 * FORM1_SECTOR, &seekstat);
        while (!(seekstat.asy_stat & 1));  /* wait for done bit */
        if (seekstat.asy_stat & 0x8000) {
            STATUS2("Error %d occured during seek\n",seekstat.asy_sig);
            STATUS2("asy_sig = 0x%x\n",seekstat.asy_sig);
            STATUS2("asy_stat = 0x%x\n",seekstat.asy_stat);
        }
        else {
            stat = play_recs(fid, reinit_rtf, 1, false, false, 0);
        }
        close_file(fid);
    }
    FadeDown(slowdisolve);

    /*
     * exit_program - give back memory and stuff.
     */
    close_file(Eng_bear_fid);
    close_file(Span_bear_fid);
    close_file(Eng_button_fid);
    close_file(Span_button_fid);

    dc_dlfct(vidpath,fctid_RL7);
    dc_dlfct(vidpath,fctid_Clut7);
    dc_dllct(vidpath,lctid0);
    dc_dllct(vidpath,lctid2);
    if (PALflag) {
        dc_dllct(vidpath,lct_pal_a);
        dc_dllct(vidpath,lct_pal_b);
    }
    close(vidpath);
    DEALLOCATE(RL7Size * FORM2_SECTOR, vidmem0);
    DEALLOCATE(RL7Size * FORM2_SECTOR, vidmem1);
    DEALLOCATE(384 * 240, vidmem2);
    DEALLOCATE(384 * 240, vidmem3);
    DEALLOCATE(384 *  70, vidmem4);
    DEALLOCATE(384 * 240, vidmem5);
    DEALLOCATE(FORM1_SECTOR * MMPkgSecs, PkgBuf);

    DEALLOCATE(FORM1_SECTOR * ButtonBufSize, ButtonBuf);

    close_snd_stuff();
    close_rtf_stuff();

    exit(0);
}



/*
 * Main menu - This displays the livingroom and waits for a button press
 */
void    MainMenu()
{
Boolean     done;
int         fid;
Boolean     stat;

    setup_MM();             /* set up the main menu */

    DslvAB(fastdisolve);

    MakeBearLook(Bedford);
    Step();
    start_bkgd_audio(3, BEARfid, false); /* pass channel number */
    while (eor_ctr) {
        CheckInput();
        if (theInpTab.ButPress) {
            stop_all_audio();
            eor_ctr = 0;
        }
    }
    MakeBearCycle(Bedford);

    start_bkgd_audio(MMMusic, BEARfid, true); /* pass channel number */

    Set_Coord (230,100);
    cursor_show();          /* display the cursor */
    last_xpos = inp_xpos;   /* xpos of input device */
    last_ypos = inp_ypos;   /* ypos of input device */
    done = false;
    while (done == false) {

        update_audio();
        chk_help(6, BEARfid, MMMusic, BEARfid);
        chk_dim();  /* if it's time to dim, this won't return until undim */

        CheckInput(); /* This has to highlite places we are over as well */
        switch (theInpTab.HotIndex) {
            case 0: /* HELP button */
                if (theInpTab.ButPress) {
                    stop_all_audio();
                    start_bkgd_audio(7, BEARfid, false); /* pass channel number */
                    CheckInput();
                    while ((eor_ctr) && (theInpTab.HotIndex == 0) && (!theInpTab.ButPress))
                        CheckInput();
                    stop_all_audio();
                    start_bkgd_audio(MMMusic, BEARfid, true);
                }
                break;
            case 1: /* SPEECH button */
                if (theInpTab.ButPress) {
                    Cursor_Freeze();
                    stop_all_audio();
                    start_bkgd_audio(0, BUTTONfid, false); /* pass channel number */
                    changeSpch();
                    while (eor_ctr);
                    stop_all_audio();
                    set_bear_voice();
                    set_button_voice();
                    start_bkgd_audio(MMMusic, BEARfid, true);
                    Cursor_Melt();
                }
                break;
            case 2: /* TEXT button */
                if (theInpTab.ButPress) {
                    Cursor_Freeze();
                    stop_all_audio();
                    if (text == English)
                        start_bkgd_audio(3, BUTTONfid, false); /* pass channel number */
                    if (text == Spanish)
                        start_bkgd_audio(1, BUTTONfid, false); /* pass channel number */
                    changeText();
                    while (eor_ctr);
                    stop_all_audio();
                    start_bkgd_audio(MMMusic, BEARfid, true);
                    Cursor_Melt();
                }
                break;
            case 3: /* EXIT button */
                if (theInpTab.ButPress) {
                    Cursor_Freeze();
                    stop_all_audio();
                    start_bkgd_audio(2, BUTTONfid, false); /* pass channel number */
                    while (theInpTab.ButPress)
                        CheckInput();   /* wait for button release */
                    while ((!theInpTab.ButPress) && (theInpTab.HotIndex == 3))
                        CheckInput(); /* wait for button press or cursor move away */
                    stop_all_audio();
                    if (theInpTab.ButPress) /* they chose to exit */
                        done = true;
                    else    /* they moved the cursor off the exit button */
                        start_bkgd_audio(MMMusic, BEARfid, true);
                    Cursor_Melt();
                }
                break;


            case 4: /* Sara */
                if ((last_xpos == inp_xpos) && (last_ypos == inp_ypos)) { /* if cursor paused */
                    Cursor_Freeze();
                    stop_all_audio();
                    MakeBearLook(Sara);
                    if (BearTalk[Sara] == 0)
                        start_bkgd_audio(11, BEARfid, false); /* channel 11 = Sara's 1st words */
                    else
                        start_bkgd_audio(12, BEARfid, false); /* channel 12 = Sara's 2nd words */
                    BearTalk[Sara] = 2; /* Sara is talking */
                    Cursor_Melt();
                    while ((theInpTab.HotIndex == 4) && (!theInpTab.ButPress)) {
                        CheckInput();
                        last_xpos = inp_xpos;   /* xpos of input device */
                        last_ypos = inp_ypos;   /* ypos of input device */
                        chk_help(6, BEARfid, MMMusic, BEARfid);
                        chk_dim();  /* if it's time to dim, this won't return until undim */

                        if (BearTalk[Sara] == 1)
                            update_audio();

                        if ((!eor_ctr) && (BearTalk[Sara] == 2)) {
                            stop_all_audio();
                            BearTalk[Sara] = 1; /* Sara has spoken, but is finished */
                            MakeBearCycle(Sara);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                    }

                    if (theInpTab.ButPress) {
                        stop_all_audio();
                        if (BearTalk[Sara] != 2) {
                            MakeBearLook(Sara); /* if she wasn't looking */
                            Step();
                        }
                        start_bkgd_audio(13, BEARfid, false); /* channel 13 = Sara's OK */
                        while (eor_ctr);
                        stop_all_audio();
                        BearTalk[Sara] = 1; /* Sara has spoken, but is finished */
                        MakeBearCycle(Sara);

                        unset_module(ModMain);
                        set_module(ModBook);

                        cursor_hide();

                        if (!Sara_shuf) {
                            get_random_seed();
                            shufshort(wbstab, NumPages);    /* shuffle the wordbook scenes */
                            Sara_shuf = true;
                        }

                        /*
                         * play the wordbook intro real time file
                         */
                        fid = open_file("wdbk.rtf", false);
                        stat = play_recs(fid, reinit_rtf, 1, false, false, 0);
                        *(short *)vidmem0 = 0x8F00;
                        DslvBA(meddisolve); /* show plane A */
                        stat = play_recs(fid, reinit_rtf, 1, false, true, 0); /* play rest of file */
                        stat = close_file(fid);

                        DirNum = DirSaveMM; /* restore first */
                        WordBook(); /* go to the game */
                        DirNum = DirSaveMM;

                        unset_module(ModBook);
                        set_module(ModMain);

                        loadpkg("lv.com", PkgBuf);

                        FadeDown(fastdisolve);
                        setup_MM();
                        PAFlag = false; /* don't bring up plane A */
                        FadeUp(meddisolve, true);
                        start_bkgd_audio(MMMusic, BEARfid, true);
                    }
                    else {
                        Cursor_Freeze();
                        if (BearTalk[Sara] == 2) {
                            stop_all_audio();
                            BearTalk[Sara] = 1; /* Sara has spoken */
                            MakeBearCycle(Sara);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                        Cursor_Melt();
                    }
                }
                break;


            case 5: /* Bedford */
                if ((last_xpos == inp_xpos) && (last_ypos == inp_ypos)) {
                    Cursor_Freeze();
                    stop_all_audio();
                    MakeBearLook(Bedford);
                    start_bkgd_audio(4, BEARfid, false); /* channel 4 = Bedford's 1st and 2nd words */
                    BearTalk[Bedford] = 2;
                    Cursor_Melt();
                    while ((theInpTab.HotIndex == 5) && (!theInpTab.ButPress)) {
                        CheckInput();
                        last_xpos = inp_xpos;   /* xpos of input device */
                        last_ypos = inp_ypos;   /* ypos of input device */
                        chk_help(6, BEARfid, MMMusic, BEARfid);
                        chk_dim();  /* if it's time to dim, this won't return until undim */

                        if (BearTalk[Bedford] == 1)
                            update_audio();

                        if ((!eor_ctr) && (BearTalk[Bedford] == 2)) {
                            stop_all_audio();
                            BearTalk[Bedford] = 1; /* Bedford has spoken, but is finished */
                            MakeBearCycle(Bedford);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                    }
                    if (theInpTab.ButPress) {
                        stop_all_audio();
                        if (BearTalk[Bedford] != 2) {
                            MakeBearLook(Bedford);
                            Step();
                        }
                        start_bkgd_audio(5, BEARfid, false); /* channel 5 = Bedford's OK */
                        while (eor_ctr);
                        stop_all_audio();
                        BearTalk[Bedford] = 1; /* Bedford has spoken, but is finished */
                        MakeBearCycle(Bedford);

                        unset_module(ModMain);
                        set_module(ModSent1);

                        cursor_hide();
#ifndef WANT_SRCDBG
                        if (!SB_shuf) {
                            get_random_seed();
                            shufshort(sbptab, NumSBPkgs);   /* shuffle the sentence builder packages */
                            sbpctr = getran(NumSBPkgs -1);  /* initial seed value for sentence builder packages */
                            SB_shuf = true;
                        }
#endif
                        /*
                         * play the sentence builder intro real time file
                         */
                        fid = open_file("sent.rtf", false);
                        stat = play_recs(fid, reinit_rtf, 2, false, false, 0);
                        *(short *)vidmem0 = 0x8F00;
                        DslvBA(meddisolve); /* show plane A */
                        stat = play_recs(fid, reinit_rtf, 1, false, true, 0); /* play rest of file */
                        stat = close_file(fid);

                        DirNum = DirSaveMM; /* restore first */
                        SentBld(); /* go to the game */
                        DirNum = DirSaveMM;

                        unset_module(ModSent1);
                        set_module(ModMain);

                        loadpkg("lv.com", PkgBuf);

                        FadeDown(fastdisolve);
                        setup_MM();
                        PAFlag = false; /* don't bring up plane A */
                        FadeUp(meddisolve, true);
                        start_bkgd_audio(MMMusic, BEARfid, true);
                    }
                    else {
                        Cursor_Freeze();
                        if (BearTalk[Bedford] == 2) {
                            stop_all_audio();
                            BearTalk[Bedford] = 1; /* Bedford has spoken, and is finished */
                            MakeBearCycle(Bedford);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                        Cursor_Melt();
                    }
                }
                break;


            case 6: /* Bumper */
                if ((last_xpos == inp_xpos) && (last_ypos == inp_ypos)) {
                    Cursor_Freeze();
                    stop_all_audio();
                    MakeBearLook(Bumper);
                    if (BearTalk[Bumper] == 0)
                        start_bkgd_audio(8, BEARfid, false); /* channel 8 = Bumper's 1st words */
                    else
                        start_bkgd_audio(9, BEARfid, false); /* channel 9 = Bumper's 2nd words */
                    BearTalk[Bumper] = 2;
                    Cursor_Melt();
                    while ((theInpTab.HotIndex == 6) && (!theInpTab.ButPress)) {
                        CheckInput();
                        last_xpos = inp_xpos;   /* xpos of input device */
                        last_ypos = inp_ypos;   /* ypos of input device */
                        chk_help(6, BEARfid, MMMusic, BEARfid);
                        chk_dim();  /* if it's time to dim, this won't return until undim */

                        if (BearTalk[Bumper] == 1)
                            update_audio();

                        if ((!eor_ctr) && (BearTalk[Bumper] == 2)) {
                            stop_all_audio();
                            BearTalk[Bumper] = 1; /* Bumper has spoken, but is finished */
                            MakeBearCycle(Bumper);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                    }
                    if (theInpTab.ButPress) {
                        stop_all_audio();
                        if (BearTalk[Bumper] != 2) {
                            MakeBearLook(Bumper);
                            Step();
                        }
                        start_bkgd_audio(10, BEARfid, false); /* channel 10 = Bumper's OK */
                        while (eor_ctr);
                        stop_all_audio();
                        BearTalk[Bumper] = 1; /* Bumper has spoken, but is finished */
                        MakeBearCycle(Bumper);

                        unset_module(ModMain);
                        set_module(ModBop);

                        cursor_hide();

                        if (!Bump_shuf) {
                            get_random_seed();
                            shufshort(Boptab, NumBopPkgs);  /* shuffle the bop packages */
                            Bump_shuf = true;
                        }
                        /*
                         * play the bop intro real time file
                         */
                        fid = open_file("bop.rtf", false);
                        stat = play_recs(fid, set_bop_intro_pcls, 2, false, false, 0);
                        *(short *)vidmem0 = 0x8F00;
                        DslvBA(meddisolve); /* show plane A */
                        stat = play_recs(fid, set_bop_intro_pcls, 1, false, true, 0); /* play rest of file */
                        stat = close_file(fid);

                        DirNum = DirSaveMM; /* restore first */
                        Bop(); /* go to the game */
                        DirNum = DirSaveMM;

                        unset_module(ModBop);
                        set_module(ModMain);

                        loadpkg("lv.com", PkgBuf);

                        FadeDown(fastdisolve);
                        BopOff();   /* turn plane mixing back on */
                        setup_MM();
                        PAFlag = false; /* don't bring up plane A */
                        FadeUp(meddisolve, true);
                        start_bkgd_audio(MMMusic, BEARfid, true);
                    }
                    else {
                        Cursor_Freeze();
                        if (BearTalk[Bumper] == 2) {
                            stop_all_audio();
                            BearTalk[Bumper] = 1; /* Bumper has spoken, but is finished */
                            MakeBearCycle(Bumper);
                            start_bkgd_audio(MMMusic, BEARfid, true);
                        }
                        Cursor_Melt();
                    }
                }
                break;
        }
        last_xpos = inp_xpos;   /* xpos of input device */
        last_ypos = inp_ypos;   /* ypos of input device */
    }
}




/*
 * setup_MM
 */
void setup_MM()
{
Ptr         thePtr;
Ptr         scnptrsav;


    DirSaveMM = DirNum; /* save for when leaving this module */

    theRectPtr = &LVRect;       /* Set list of hotspots */

    currentT = clock();         /* get current tick count */
#if 0
    reset_help();       /* reset help counter */
    reset_dim();        /* reset dim counter */
#endif

    SceneTab[MScene] = (ScenePtr)stuffpkg(PkgBuf);
    FixScene(MScene);
    (*SceneTab[MScene]).Active = true;
    (*SceneTab[MScene]).Display = true;
    SetUpScene(MScene);
    /*
     * Modify the scene now.  First of all, let the scene run at full speed
     * and slow down the bear items if necessary.  Also  decrement the number
     * of states per bear so they don't look at you while cycling.
     */
    MMScene = SceneTab[MScene];
    MMScene->AniDelay = 4;
    MMSeq = (ItemSeqPtr)((int)MMScene + (int)MMScene->ItemDir[0].Where);
    MMSeq->Cyc.ICycle = 1;
    MMSeq->Cyc.ICycSize --;
    MMSeq = (ItemSeqPtr)((int)MMScene + (int)MMScene->ItemDir[1].Where);
    MMSeq->Cyc.ICycle = 1;
    MMSeq->Cyc.ICycSize --;
    MMSeq = (ItemSeqPtr)((int)MMScene + (int)MMScene->ItemDir[2].Where);
    MMSeq->Cyc.ICycle = 1;
    MMSeq->Cyc.ICycSize --;

    NoButs(); /* unlink old button strip */
    /*
     * draw the livingroom background picture
     */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;  /* draw to bkgd screen */
    thePtr = (Ptr) ((unsigned)MMScene + (unsigned)pkgTOC->TE[1].Where); /* bkgd shape is 2nd in package */
    Draw((ShapePtr)thePtr, 0, 0); /* draw the shape */
    scn_ptr = scnptrsav;
    /*
     * copy to rear screen, swap, and copy to new rear screen
     */
    copy_bkgd_front();
    /*
     * Make the buttons for the main menu.
     */
    MkMainBut();

}


/*
 * MakeBearLook - this increments the number of states in the sequence
 *                  and makes the bear look up at you.
 */
void MakeBearLook(theBear)
    short theBear;
{
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */

    MMSeq = (ItemSeqPtr)((int)MMScene + (int)MMScene->ItemDir[theBear].Where);
    MMSeq->Cyc.ICycle = 1;
    MMSeq->Cyc.IState = MMSeq->Cyc.ICycSize;
    MMSeq->Cyc.ICycSize ++;
    MMSeq->Cyc.ICycEnable = false;

    MMSeq->Pos.ICurXOff = MMSeq->Cyc.ISeqPtr->SeqTab[MMSeq->Cyc.IState].StateXOff;
    MMSeq->Pos.ICurYOff = MMSeq->Cyc.ISeqPtr->SeqTab[MMSeq->Cyc.IState].StateYOff;
    theSeqDF = MMSeq->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[MMSeq->Cyc.IState].StateIA;
    MMSeq->Pos.ICurWide = MMSeq->Pos.IEraseWide = theShp->NumWide;
    MMSeq->Pos.ICurHigh = MMSeq->Pos.IEraseHigh = theShp->NumHigh;

    MMSeq->Pos.ICurX = MMSeq->Pos.IBaseX + MMSeq->Pos.ICurXOff;
    MMSeq->Pos.ICurY = MMSeq->Pos.IBaseY + MMSeq->Pos.ICurYOff;

}



/*
 * MakeBearCycle - this returns the bear to its cycling mode.
 */
void MakeBearCycle(theBear)
    short theBear;
{
    MMSeq = (ItemSeqPtr)((int)MMScene + (int)MMScene->ItemDir[theBear].Where);
    MMSeq->Cyc.ICycSize --;
    MMSeq->Cyc.IState = 0;
    MMSeq->Cyc.ICycEnable = true;
    BearFlag[theBear] = false;
}




/*
 * changeSpch -
 */
void changeSpch()
{

    if (speech == English)
        speech = Spanish;
    else
        speech = English;

    NewBut();
}


/*
 * changeText -
 */
void changeText()
{

    if (text == English)
        text = Spanish;
    else
        text = English;

    NewBut();
}



/*
 * set_bear_voice - This opens either the English or Spanish bear rta file
 *                  It depends on the current module (setting of "ModMod").
 */
void set_bear_voice()
{

    if (speech == English)
        BEARfid = Eng_bear_fid;
    if (speech == Spanish)
        BEARfid = Span_bear_fid;
}

/*
 * set_button_voice - This selects either the English or Spanish button rta file
 */
void set_button_voice()
{

    if (speech == English)
        BUTTONfid = Eng_button_fid;
    if (speech == Spanish)
        BUTTONfid = Span_button_fid;
}


/*
 * set_buffers - set PkgBuf to the proper size
 */
void set_buffers(mod)
    short mod;
{
    switch (mod) {
        case ModMain: /* Get enough memory to hold the livingroom package */
            PkgBuf = (char *)ALLOCATE(FORM1_SECTOR * MMPkgSecs, VIDEO1);
            break;
        case ModBook: /* Get enough memory to hold largest WB package */
            PkgBuf = (char *)ALLOCATE(FORM1_SECTOR * WBPkgSecs, VIDEO1);
            break;
        case ModBop: /* Get enough memory to hold largest Bop package */
            PkgBuf = (char *)ALLOCATE(FORM1_SECTOR * BopPkgSecs, VIDEO1);
            break;
        case ModSent1: /* Get enough memory to hold largest Sentence Builder package */
            PkgBuf = (char *)ALLOCATE(FORM1_SECTOR * SBPkgSecs, VIDEO1);
            break;
    }
    if (PkgBuf == (char *)-1L) {
        STATUS2("Can't allocate PkgBuf. errno = %d\n", errno);
    }
    pkgTOC = (TOCPtr)PkgBuf; /* packages always start with a table of contents */
}


/*
 * set_module   -   this allocates buffers, soundmaps,
 *                  opens files and sets pointers to the correct speech files
 */
void  set_module(mod)
    short mod;
{
short       ctr;

    ModMod = mod;   /* global module ID */
    set_buffers(mod);

    switch (mod) {
        case ModMain:
            set_files(mod);
            break;
        case ModBook:
            set_files(mod);
            break;
        case ModBop:
            ScreenBuf = (char *)ALLOCATE(FORM1_SECTOR * BopScrnSecs, VIDEO1); /* screen images */
            if (ScreenBuf == (char *)-1L) {
                STATUS1("Can't allocate ScreenBuf\n");
            }

            snd_array[0].smap_id = SMAP_CREATE(audpath, D_CMONO, 36, &snd_array[0].data); /* bop sound */
            if ( snd_array[0].smap_id == -1 ) {
                STATUS1("Can't get soundmap 0\n");
            }

            snd_array[1].smap_id = SMAP_CREATE(audpath, D_CMONO, 36, &snd_array[1].data); /* sphere sound */
            if ( snd_array[1].smap_id == -1 ) {
                STATUS1("Can't get soundmap 1\n");
            }

            snd_array[2].smap_id = SMAP_CREATE(audpath, D_CMONO, 72, &snd_array[2].data); /* star sound */
            if ( snd_array[2].smap_id == -1 ) {
                STATUS1("Can't get soundmap 2\n");
            }

            snd_array[3].smap_id = SMAP_CREATE(audpath, D_CMONO, 54, &snd_array[3].data); /* miss sound */
            if ( snd_array[3].smap_id == -1 ) {
                STATUS1("Can't get soundmap 3\n");
            }

            snd_array[4].smap_id = SMAP_CREATE(audpath, D_CMONO, 54, &snd_array[4].data); /* shoot sound */
            if ( snd_array[4].smap_id == -1 ) {
                STATUS1("Can't get soundmap 4\n");
            }

            for (ctr=5; ctr<=12; ctr++) {
                snd_array[ctr].smap_id = SMAP_CREATE(audpath, D_CMONO, BopNounGrpSize, &snd_array[ctr].data);
                if ( snd_array[ctr].smap_id == -1 ) {
                    STATUS2("Can't get soundmap %d\n", ctr);
                }
            }

            for (ctr=13; ctr<=15; ctr++) {
                snd_array[ctr].smap_id = SMAP_CREATE(audpath, D_CMONO, BopFXGrpSize, &snd_array[ctr].data);
                if ( snd_array[ctr].smap_id == -1 ) {
                    STATUS2("Can't get soundmap %d\n", ctr);
                }
            }
            set_files(mod);
            break;
        case ModSent1:
        case ModSent2u:
        case ModSent2d:
            ScreenBuf = (char *)ALLOCATE(FORM1_SECTOR * SBScrnSecs, VIDEO1); /* screen images */
            if (ScreenBuf == (char *)-1L) {
                STATUS1("Can't allocate ScreenBuf\n");
            }
            RezBuf = (char *)ALLOCATE(FORM1_SECTOR * RezBufSecs, VIDEO1);   /* resedit data */
            if (RezBuf == (char *)-1L) {
                STATUS1("Can't allocate RezBuf\n");
            }
            Seq1Buf = (char *)ALLOCATE(FORM1_SECTOR * SeqBufSecs, VIDEO1);  /* seq 1 */
            if (Seq1Buf == (char *)-1L) {
                STATUS1("Can't allocate Seq1Buf\n");
            }
            Seq2Buf = (char *)ALLOCATE(FORM1_SECTOR * SeqBufSecs, VIDEO1);  /* seq 2 */
            if (Seq2Buf == (char *)-1L) {
                STATUS1("Can't allocate Seq2Buf\n");
            }
            BkgdBuf = (char *)ALLOCATE(FORM1_SECTOR * BkgdBufSecs, VIDEO1);     /* background image */
            if (BkgdBuf == (char *)-1L) {
                STATUS1("Can't allocate BkgdBuf\n");
            }

            snd_array[0].smap_id = SMAP_CREATE(audpath, D_CMONO, SBNounGrpSize, &snd_array[0].data); /* initial noun */
            if ( snd_array[0].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Eng noun #1\n");
            }

            snd_array[1].smap_id = SMAP_CREATE(audpath, D_CMONO, SBNounGrpSize, &snd_array[1].data); /* Verb */
            if ( snd_array[1].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Span noun #1\n");
            }

            snd_array[2].smap_id = SMAP_CREATE(audpath, D_CMONO, SBVerbGrpSize, &snd_array[2].data); /* final noun */
            if ( snd_array[2].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Eng verb\n");
            }

            snd_array[3].smap_id = SMAP_CREATE(audpath, D_CMONO, SBVerbGrpSize, &snd_array[3].data); /* sound effect */
            if ( snd_array[3].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Span verb\n");
            }

            snd_array[4].smap_id = SMAP_CREATE(audpath, D_CMONO, SBNounGrpSize, &snd_array[4].data); /* Verb */
            if ( snd_array[4].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Eng noun #2\n");
            }

            snd_array[5].smap_id = SMAP_CREATE(audpath, D_CMONO, SBNounGrpSize, &snd_array[5].data); /* final noun */
            if ( snd_array[5].smap_id == -1 ) {
                STATUS1("Can't get soundmap for Span noun #2\n");
            }

            snd_array[6].smap_id = SMAP_CREATE(audpath, D_CMONO, SBFXGrpSize, &snd_array[6].data); /* sound effect */
            if ( snd_array[6].smap_id == -1 ) {
                STATUS1("Can't get soundmap for sound effect\n");
            }

            set_files(mod);
            break;
    }
}



/*
 * unset_module -   this givesback buffers and soundmaps
 */
void unset_module(mod)
    short mod;
{
short           ctr;
SoundmapDesc    *sm_ptr;

    switch (mod) {
        case ModMain:
            unset_files(mod);
            DEALLOCATE(FORM1_SECTOR * MMPkgSecs, PkgBuf); /* release main menu buffer */
            break;

        case ModBook:
            unset_files(mod);
            DEALLOCATE(FORM1_SECTOR * WBPkgSecs, PkgBuf); /* give back WB buffer */
            break;

        case ModBop:
            unset_files(mod);
            /*
             * reset the original soundmap sizes before giving them back
             */
            for (ctr=5; ctr<=12; ctr++) {
                sm_ptr = sm_info(audpath, snd_array[ctr].smap_id);
                sm_ptr->smd_nogrps = BopNounGrpSize;
            }
            for (ctr=13; ctr<=15; ctr++) {
                sm_ptr = sm_info(audpath, snd_array[ctr].smap_id);
                sm_ptr->smd_nogrps = BopFXGrpSize;
            }
            for (ctr=15; ctr>=0; ctr--) {
                SMAP_DESTROY(audpath, snd_array[ctr].smap_id);
                snd_array[ctr].smap_id = 0;
            }
            DEALLOCATE(FORM1_SECTOR * BopScrnSecs, ScreenBuf); /* give back screen image buffer */
            DEALLOCATE(FORM1_SECTOR * BopPkgSecs, PkgBuf); /* give back package buffer */
            break;

        case ModSent1:
        case ModSent2u:
        case ModSent2d:
            unset_files(mod);
            /*
             * reset the original soundmap sizes before giving them back
             */
            sm_ptr = sm_info(audpath, snd_array[0].smap_id);
            sm_ptr->smd_nogrps = SBNounGrpSize;
            sm_ptr = sm_info(audpath, snd_array[1].smap_id);
            sm_ptr->smd_nogrps = SBNounGrpSize;
            sm_ptr = sm_info(audpath, snd_array[2].smap_id);
            sm_ptr->smd_nogrps = SBVerbGrpSize;
            sm_ptr = sm_info(audpath, snd_array[3].smap_id);
            sm_ptr->smd_nogrps = SBVerbGrpSize;
            sm_ptr = sm_info(audpath, snd_array[4].smap_id);
            sm_ptr->smd_nogrps = SBNounGrpSize;
            sm_ptr = sm_info(audpath, snd_array[5].smap_id);
            sm_ptr->smd_nogrps = SBNounGrpSize;
            sm_ptr = sm_info(audpath, snd_array[6].smap_id);
            sm_ptr->smd_nogrps = SBFXGrpSize;
            for (ctr=6; ctr>=0; ctr--) {
                SMAP_DESTROY(audpath, snd_array[ctr].smap_id);
                snd_array[ctr].smap_id = 0;
            }
            DEALLOCATE(FORM1_SECTOR * SBScrnSecs, ScreenBuf);
            DEALLOCATE(FORM1_SECTOR * RezBufSecs, RezBuf);
            DEALLOCATE(FORM1_SECTOR * SeqBufSecs, Seq1Buf);
            DEALLOCATE(FORM1_SECTOR * SeqBufSecs, Seq2Buf);
            DEALLOCATE(FORM1_SECTOR * BkgdBufSecs, BkgdBuf);
            DEALLOCATE(FORM1_SECTOR * SBPkgSecs, PkgBuf); /* give back SB buffer */
            break;
    }
    SNAPSHOT();
}


/*
 * set_files    -   this opens files and sets pointers to the correct speech files
 */
void set_files(mod)
    short mod;
{

    switch (mod) {
        case ModMain:
            Eng_bear_fid = open_file("LV.Eng.rtf", false);
            Span_bear_fid = open_file("LV.Span.rtf", false);
            set_bear_voice();
            set_button_voice();         /* this really needs to be called just once */
            break;
        case ModBook:
            Tune1ID = open_file("tunes1.rtf", false);
            Tune2ID = open_file("tunes2.rtf", false);
            Eng_bear_fid = open_file("BOP.BOOK.Eng.rtf", false);
            Span_bear_fid = open_file("BOP.BOOK.Span.rtf", false);
            set_bear_voice();
            break;
        case ModBop:
            Eng_bear_fid = open_file("BOP.BOOK.Eng.rtf", false);
            Span_bear_fid = open_file("BOP.BOOK.Span.rtf", false);
            set_bear_voice();
            break;
        case ModSent1:
        case ModSent2u:
        case ModSent2d:
            bkgdfid = open_file("bkgd.cmn", false);
            Tune3ID = open_file("tunes3.rtf", false);
            Tune4ID = open_file("tunes4.rtf", false);
            Tune5ID = open_file("tunes5.rtf", false);
            Eng_bear_fid = open_file("SENT.Eng.rtf", false);
            Span_bear_fid = open_file("SENT.Span.rtf", false);
            set_bear_voice();
            break;
    }
}



/*
 * unset_files  -   this closes the files for a module
 */
void unset_files(mod)
    short mod;
{

    close_file(Span_bear_fid);
    close_file(Eng_bear_fid);

    switch (mod) {
        case ModMain:
            break;
        case ModBook:
            close_file(Tune2ID);
            close_file(Tune1ID);
            break;
        case ModBop:
            break;
        case ModSent1:
        case ModSent2u:
        case ModSent2d:
            close_file(Tune5ID);
            close_file(Tune4ID);
            close_file(Tune3ID);
            close_file(bkgdfid);
            break;
    }
}


#if 0
/******************************************************************************
* fork_bump()
******************************************************************************/
void fork_bump( )
int argc;
char **argv;
{
int         vpath;
int         apath;
int         bumper_status;
mod_exec    *datmod, *modlink(), *modcload();
BUMPER_DATA *bumpmod;
char        argstring[5][8];
int         stat;
int         stupid_fct_a, stupid_fct_b;


    STATUS1("fork_bump: ENTER\n");

    errno = 0;

    if ( (int)(datmod = modlink( bumpdata, MT_ANY )) == SYSERR ) {
        if ( (int)(datmod = modcload( bumpdata, 0, VIDEO1 )) == SYSERR ) exit( errno );
    }
    /*
     * Link to the data module
     * Point to the actual data section of the module
     */
    bumpmod = (BUMPER_DATA *)((char *)datmod + ((DATA_MODULE *)datmod)->data_offset);

                            /* Remember height of LCTs */
    bumpmod->lct_height = BUMP_LCT_HEIGHT;

                            /* Get video environment setup */
    if ( bump_init_vid( &vpath, &(bumpmod->dcp), BUMP_LCT_HEIGHT, bumpmod->vid_name ) == SYSERR )
        exit( errno );

        /* Set up audio so it plays */
    if ( (int)((apath = init_audio())) == SYSERR ) exit(errno);


                            /* Set compat bit and PAL flag */
    if ( set_comp_mode( vpath, &(bumpmod->pal_flag) ) == SYSERR ) exit( errno );

                            /* Null these out, assume we don't pass */
    bumpmod->app_pa_buf = NULL;
    bumpmod->app_pb_buf = NULL;
    bumpmod->pcb = NULL;
    bumpmod->data_sector = 0;

                            /* Shut down the planes then execute DCP */
    dc_wrfi( vpath, bumpmod->dcp.fcta, FCT_ICF, cp_icf(PA, ICF_MIN) );
    dc_wrfi( vpath, bumpmod->dcp.fctb, FCT_ICF, cp_icf(PB, ICF_MIN) );
    dc_exec( vpath, bumpmod->dcp.fcta, bumpmod->dcp.fctb );

        /* Load the bumper executable and data module */
    if ( (int)modcload( bumpargblk[0], 0, BUMPER_MEMORY_COLOR) == SYSERR ) exit( errno );

        /* Fork the Bumper */
    if ( os9exec( os9forkc, bumpargblk[0], bumpargblk, environ, 0, 0, BUMPER_PATH_NUM ) == SYSERR )
        exit( errno );

    wait( &bumper_status );

                            /* Check return status from bumper */
    if ( bumpmod->return_status != BE_HUNKY )
        {
            if ( bumpmod->return_status == BE_INTERRUPT )
                {
                    STATUS1("Bumper was interrupted by the user.\n");
                }
            else
                {
                    STATUS2("loader:Bumper returns error 0x%x\n", bumpmod->return_status );
                    exit(errno);
                }
        }


    /*
     * Create new FCTs to keep the screen black
     */
    stupid_fct_a = dc_crfct(vpath,PA,7,RES_NORMAL);
    stupid_fct_b = dc_crfct(vpath,PB,3,RES_NORMAL);
    /*
     * Initialize the FCTs
     */
    dc_wrfi(vpath,stupid_fct_a,0,cp_icm(ICM_CLUT7,ICM_CLUT7,NM_1,EV_OFF,CS_A));
    dc_wrfi(vpath,stupid_fct_a,1,cp_dprm(RMS_NORMAL,PRF_X2,BP_NORMAL));
    dc_wrfi(vpath,stupid_fct_a,2,cp_icf(PA,ICF_MIN));
    dc_wrfi(vpath,stupid_fct_a,3,cp_po(PR_AB));
    dc_wrfi(vpath,stupid_fct_a,4,cp_tci(MIX_ON,TR_CKEY_T,TR_OFF));
    dc_wrfi(vpath,stupid_fct_a,5,cp_phld(PA,PH_OFF,0));
    dc_wrfi(vpath,stupid_fct_a,6,cp_bkcol(BK_LOW, BK_BLACK));

    dc_wrfi(vpath,stupid_fct_b,0,cp_dprm(RMS_NORMAL,PRF_X2,BP_NORMAL));
    dc_wrfi(vpath,stupid_fct_b,1,cp_icf(PB,ICF_MIN));
    dc_wrfi(vpath,stupid_fct_b,2,cp_phld(PB,PH_OFF,0));

    dc_exec(vpath, stupid_fct_a, stupid_fct_b);

    /*
     * get rid of the old FCTs and LCTs
     */
    dc_dllct( vpath, bumpmod->dcp.lcta );
    dc_dllct( vpath, bumpmod->dcp.lctb );
    dc_dlfct( vpath, bumpmod->dcp.fcta );
    dc_dlfct( vpath, bumpmod->dcp.fctb );

    sprintf(argstring[0],"%d",vpath);
    sprintf(argstring[1],"%d",apath);
    sprintf(argstring[2],"%d",(bumpmod->pal_flag==YES?1:0));

    stat = munload( bumpdata, MT_ANY );
    if (stat == -1) {
        STATUS2("****couldn't unload bumpdata. error numer 0x%x\n", errno);
    }

    titleargblk[1] = argstring[0];
    titleargblk[2] = argstring[1];
    titleargblk[3] = argstring[2];

    if ( (int)modcload( titleargblk[0], 0, TITLE_MEMORY_COLOR) == SYSERR )
        exit( errno );

    STATUS1("loader: EXIT\n");

    if ( os9exec( chainc, titleargblk[0], titleargblk, environ, 0, 0, TITLE_PATH_NUM ) == SYSERR )
        exit( errno );
}
#endif

rtf.c

#include <stdio.h>
#include <cdfm.h>
#include <errno.h>
#include <memory.h>
#include <rtr.h>

#include "dbg.h"

#include "utility.h"
#include "animation.h"
#include "rtf.h"
#include "screen.h"
#include "reading.h"
#include "sound.h"
#include "bop.h"
#include "sentbld.h"
#include "wordbook.h"
#include "file_mgr.h"


PCB     *thePCB;    /* play control block */
int     audpath;

PCL     *vid_pcl_0;
PCL     *vid_pcl_1;

PCL     *pcl_tab[max_chans];

PCL     **vid_cils;
PCL     **aud_cils;
PCL     **dat_cils;
PCL     *rear_vid_pcl;  /* points to the pcl that ponits to the rear RL7 buffer */

/*
 * Setup everything to play a real time audio and/or video file.
 */

Boolean setup_rtf()
{
int     ctr;

/*
 * Create the PCB and PCLs we need
 */
    thePCB = (PCB *)ALLOCATE(sizeof(PCB), VIDEO1);
    if (thePCB == (PCB *)-1L)
        return(false);
    memset (thePCB, 0, sizeof(PCB));
/*
 * Get arrays of PCL pointers ready
 */
    vid_cils = (PCL **)ALLOCATE (32*4, VIDEO1);
    if (vid_cils == (PCL **)-1L)
        return(false);
    memset (vid_cils, 0, 32*4);
/*
 * Only 16 channels for bkgd audio are possible.
 */
    aud_cils = (PCL **)ALLOCATE (16*4, VIDEO1);
    if (aud_cils == (PCL **)-1L)
        return(false);
    memset (aud_cils, 0, 16*4);
/*
 * Get 32 of 'em for data
 */
    dat_cils = (PCL **)ALLOCATE (32*4, VIDEO1);
    if (dat_cils == (PCL **)-1L)
        return(false);
    memset (dat_cils, 0, 32*4);


    vid_pcl_0 = (PCL *)ALLOCATE(sizeof(PCL), VIDEO1);
    if ( vid_pcl_0 == (PCL *)-1L ) {
        STATUS1("couldn't get vid_pcl_0\n");
    }
    memset (vid_pcl_0, 0, sizeof(PCL));

    vid_pcl_1 = (PCL *)ALLOCATE(sizeof(PCL), VIDEO1);
    if ( vid_pcl_1 == (PCL *)-1L ) {
        STATUS1("couldn't get vid_pcl_1\n");
    }
    memset (vid_pcl_1, 0, sizeof(PCL));

    for (ctr=0; ctr<max_chans; ctr++) {
        pcl_tab[ctr] = (PCL *)ALLOCATE(sizeof(PCL), VIDEO1);
        if ( pcl_tab[ctr] == (PCL *)-1L ) {
            STATUS2("couldn't get pcl %d\n", ctr);
        }
        memset (pcl_tab[ctr], 0, sizeof(PCL));
    }

    rear_vid_pcl = vid_pcl_0;   /* since we start by showing vidmem0 for RL7 */
    reinit_rtf(); /* We'll be playing a regular (a/v) rtf first */
    return(true);
}


/*
 * reinit_rtf - call this before each real time file play.
 *              (The rtfs with RL7 data and also an rt audio track)
 */
void reinit_rtf()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in reinit_rtf\n");
        stop_all_audio();
    }

    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 1; */              /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = (1 << AUDIO_CHAN) | (1 << VIDEO_CHAN) | (1 << 17) | (1 << 18);
    thePCB->PCB_AChan = (1 << AUDIO_CHAN);  /* send default audio channel to processor */
    thePCB->PCB_Video = vid_cils;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = dat_cils;
    /*
     * reinitialize CILs
     */
    memset (aud_cils, 0, 16*4);
    memset (vid_cils, 0, 32*4);
    memset (dat_cils, 0, 32*4);
    vid_cils[VIDEO_CHAN] = rear_vid_pcl;
    dat_cils[17] = pcl_tab[0];
    dat_cils[18] = pcl_tab[1];
    /*
     * Intialize PCLs for video
     */
    vid_pcl_0->PCL_Ctrl = 0;            /* Control byte */
    vid_pcl_0->PCL_Sig = BUFFER_SIGNAL0; /* Signal to be sent on buffer full */
    vid_pcl_0->PCL_Nxt = vid_pcl_1;     /* Pointer to next PCL */
    vid_pcl_0->PCL_Buf = vidmem0;       /* Pointer to buffer */
    vid_pcl_0->PCL_BufSz = RL7Size;     /* Size of buffer */
    vid_pcl_0->PCL_Cnt = 0;             /* Current offset in buffer */

    vid_pcl_1->PCL_Ctrl = 0;                /* Control byte */
    vid_pcl_1->PCL_Sig = BUFFER_SIGNAL1; /* Signal to be sent on buffer full */
    vid_pcl_1->PCL_Nxt = vid_pcl_0;         /* Pointer to next PCL */
    vid_pcl_1->PCL_Buf = vidmem1;       /* Pointer to buffer */
    vid_pcl_1->PCL_BufSz = RL7Size;     /* Size of buffer */
    vid_pcl_1->PCL_Cnt = 0;             /* Current offset in buffer */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = PkgBuf;           /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = 58;         /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */
    /*
     * Initialize PCL for image data that will be loaded from this rtf
     */
    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    if (ModMod == ModMain) {
        pcl_tab[1]->PCL_Buf = ButtonBuf;            /* Pointer to buffer */
        pcl_tab[1]->PCL_BufSz = ButtonBufSize;  /* Size of buffer */
    }
    if (ModMod == ModSent1) {
        pcl_tab[1]->PCL_Buf = ScreenBuf;            /* Pointer to buffer */
        pcl_tab[1]->PCL_BufSz = SBScrnSecs;     /* Size of buffer */
    }
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */
}



/*
 * set_bop_intro_pcls - call this before each real time file play.
 *              (The rtfs with RL7 data and also an rt audio track)
 */
void set_bop_intro_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_bop_intro_pcls\n");
        stop_all_audio();
    }

    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */

    /* thePCB->PCB_Rec = 1; */  /* gets set in 'play_data' */

    thePCB->PCB_Chan = 0xFFFFFFFF;          /* Channel selection mask - select all */
    thePCB->PCB_AChan = (1 << AUDIO_CHAN);  /* send default audio channel to processor */
    thePCB->PCB_Video = vid_cils;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = dat_cils;
    /*
     * reinitialize CILs
     */
    memset (aud_cils, 0, 16*4);
    memset (vid_cils, 0, 32*4);
    memset (dat_cils, 0, 32*4);
    vid_cils[VIDEO_CHAN] = rear_vid_pcl;
    aud_cils[10] = pcl_tab[0];
    aud_cils[11] = pcl_tab[1];
    aud_cils[12] = pcl_tab[2];
    aud_cils[13] = pcl_tab[3];
    aud_cils[14] = pcl_tab[4];
    dat_cils[15] = pcl_tab[5];
/*
 * Intialize PCLs for video
 */
    vid_pcl_0->PCL_Ctrl = 0;                /* Control byte */
    vid_pcl_0->PCL_Sig = BUFFER_SIGNAL0; /* Signal to be sent on buffer full */
    vid_pcl_0->PCL_Nxt = vid_pcl_1;         /* Pointer to next PCL */
    vid_pcl_0->PCL_Buf = vidmem0;       /* Pointer to buffer */
    vid_pcl_0->PCL_BufSz = RL7Size;     /* Size of buffer */
    vid_pcl_0->PCL_Cnt = 0;             /* Current offset in buffer */

    vid_pcl_1->PCL_Ctrl = 0;                /* Control byte */
    vid_pcl_1->PCL_Sig = BUFFER_SIGNAL1; /* Signal to be sent on buffer full */
    vid_pcl_1->PCL_Nxt = vid_pcl_0;         /* Pointer to next PCL */
    vid_pcl_1->PCL_Buf = vidmem1;       /* Pointer to buffer */
    vid_pcl_1->PCL_BufSz = RL7Size;     /* Size of buffer */
    vid_pcl_1->PCL_Cnt = 0;             /* Current offset in buffer */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[0].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = 3;          /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[1].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = 3;          /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[2].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = 5;          /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[3]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[3]->PCL_Buf = snd_array[3].data;    /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = 4;          /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[4]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[4]->PCL_Buf = snd_array[4].data;    /* Pointer to buffer */
    pcl_tab[4]->PCL_BufSz = 4;          /* Size of buffer */
    pcl_tab[4]->PCL_Cnt = 0;                /* Current offset in buffer */
    /*
     * Initialize PCL for image data that will be loaded from this rtf
     */
    pcl_tab[5]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[5]->PCL_Buf = ScreenBuf;        /* Pointer to buffer */
    pcl_tab[5]->PCL_BufSz = BopScrnSecs;    /* Size of buffer */
    pcl_tab[5]->PCL_Cnt = 0;                /* Current offset in buffer */
}

/*
 * set_bop_pkg1_pcls - Call this before loading each bop package
 */
void set_bop_pkg1_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_bop_pkg_pcls\n");
        stop_all_audio();
    }

    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;           /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;   /* Signal to be sent */
    /* thePCB->PCB_Rec = 8; */      /* this gets set in 'play_recs' */
    thePCB->PCB_AChan = 0;
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = 0;

    memset (aud_cils, 0, 16*4);
    if (speech == English) {

        thePCB->PCB_Chan = 0x000000FF;
        aud_cils[0] = pcl_tab[0];
        aud_cils[1] = pcl_tab[1];
        aud_cils[2] = pcl_tab[2];
        aud_cils[3] = pcl_tab[3];
        aud_cils[4] = pcl_tab[4];
        aud_cils[5] = pcl_tab[5];
        aud_cils[6] = pcl_tab[6];
        aud_cils[7] = pcl_tab[7];
    }
    else {
        thePCB->PCB_Chan = 0x0000FF00;
        aud_cils[8] = pcl_tab[0];
        aud_cils[9] = pcl_tab[1];
        aud_cils[10] = pcl_tab[2];
        aud_cils[11] = pcl_tab[3];
        aud_cils[12] = pcl_tab[4];
        aud_cils[13] = pcl_tab[5];
        aud_cils[14] = pcl_tab[6];
        aud_cils[15] = pcl_tab[7];
    }
    /*
     * The eight words (speech)
     */
    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[5].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[6].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[7].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[3]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[3]->PCL_Buf = snd_array[8].data;    /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[4]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[4]->PCL_Buf = snd_array[9].data;    /* Pointer to buffer */
    pcl_tab[4]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[4]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[5]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[5]->PCL_Buf = snd_array[10].data;   /* Pointer to buffer */
    pcl_tab[5]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[5]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[6]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[6]->PCL_Buf = snd_array[11].data;   /* Pointer to buffer */
    pcl_tab[6]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[6]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[7]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[7]->PCL_Buf = snd_array[12].data;   /* Pointer to buffer */
    pcl_tab[7]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[7]->PCL_Cnt = 0;                /* Current offset in buffer */
}

/*
 * set_bop_pkg2_pcls -
 */
void set_bop_pkg2_pcls()
{

    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;           /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;   /* Signal to be sent */
    /* thePCB->PCB_Rec = 4; */      /* this gets set in 'play_recs' */
    thePCB->PCB_AChan = 0;
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = dat_cils;

    memset (aud_cils, 0, 16*4);
    memset (dat_cils, 0, 32*4);
    thePCB->PCB_Chan = 0x00100007;
    aud_cils[0] = pcl_tab[0];
    aud_cils[1] = pcl_tab[1];
    aud_cils[2] = pcl_tab[2];
    dat_cils[20] = pcl_tab[3];
    /*
     * These are for the 3 sound effects
     */
    pcl_tab[0]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[13].data;   /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = BopFXSecs;  /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[14].data;   /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = BopFXSecs;  /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[15].data;   /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = BopFXSecs;  /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */
    /*
     * image data that will be loaded from this rtf
     */
    pcl_tab[3]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[3]->PCL_Buf = PkgBuf;       /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = BopPkgSecs; /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */
    pcl_tab[3]->PCL_Err = 0;
}


/*
 * set_bop_pre_aud_pcls -
 *
 */
void set_bop_pre_aud_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_bop_pre_aud_pcls\n");
        stop_all_audio();
    }
    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;           /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;   /* Signal to be sent */
    /* thePCB->PCB_Rec = 1; */      /* this gets set in 'play_data' */
    thePCB->PCB_Chan = CHAN_9;
    thePCB->PCB_AChan = 0;
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = 0;

    memset (aud_cils, 0, 16*4);
    aud_cils[9] = pcl_tab[0];

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[5].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */
}


/*
 * set_bop_aud_pcls - Call this before loading just the eight speech files
 *
 * IMPORTANT -  When this is called the variable 'speech' hasn't
 *              been changed yet, so the channels are reversed
 *              from what you would think makes sense.
 */
void set_bop_aud_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_bop_aud_pcls\n");
        stop_all_audio();
    }

    /*
     * Reinit PCB for real time file play
     */
    thePCB->PCB_Stat = 0;           /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;   /* Signal to be sent */
    /* thePCB->PCB_Rec = 8; */      /* this gets set in 'play_data' */
    thePCB->PCB_AChan = 0;
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = 0;

    memset (aud_cils, 0, 16*4);
    if (speech == Spanish) {

        thePCB->PCB_Chan = 0x000000FF;
        aud_cils[0] = pcl_tab[0];
        aud_cils[1] = pcl_tab[1];
        aud_cils[2] = pcl_tab[2];
        aud_cils[3] = pcl_tab[3];
        aud_cils[4] = pcl_tab[4];
        aud_cils[5] = pcl_tab[5];
        aud_cils[6] = pcl_tab[6];
        aud_cils[7] = pcl_tab[7];
    }
    else {
        thePCB->PCB_Chan = 0x0000FF00;
        aud_cils[8] = pcl_tab[0];
        aud_cils[9] = pcl_tab[1];
        aud_cils[10] = pcl_tab[2];
        aud_cils[11] = pcl_tab[3];
        aud_cils[12] = pcl_tab[4];
        aud_cils[13] = pcl_tab[5];
        aud_cils[14] = pcl_tab[6];
        aud_cils[15] = pcl_tab[7];
    }
    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[5].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[6].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[7].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[3]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[3]->PCL_Buf = snd_array[8].data;    /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[4]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[4]->PCL_Buf = snd_array[9].data;    /* Pointer to buffer */
    pcl_tab[4]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[4]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[5]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[5]->PCL_Buf = snd_array[10].data;   /* Pointer to buffer */
    pcl_tab[5]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[5]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[6]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[6]->PCL_Buf = snd_array[11].data;   /* Pointer to buffer */
    pcl_tab[6]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[6]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[7]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[7]->PCL_Buf = snd_array[12].data;   /* Pointer to buffer */
    pcl_tab[7]->PCL_BufSz = BopNounSecs;    /* Size of buffer */
    pcl_tab[7]->PCL_Cnt = 0;                /* Current offset in buffer */
}



/*
 * set_sbpkg1_pcls - call this before playing first record
 * of sentence builder packages
 */
void set_sbpkg1_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_sbpkg1_pcls\n");
        stop_all_audio();
    }

    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 1; */              /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = CHAN_17 | CHAN_18;   /* Channel selection mask 17 & 18 */
    thePCB->PCB_AChan = 0;                  /* Audio to memory selection mask */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = 0;
    thePCB->PCB_Data = dat_cils;

    memset (dat_cils, 0, 32*4);     /* clear old ones first */
    dat_cils[17] = pcl_tab[0];          /* screen 1 packages */
    dat_cils[18] = pcl_tab[1];          /* resedit data */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = PkgBuf;           /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = SBPkgSecs;  /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = RezBuf;           /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = RezBufSecs; /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */
}


/*
 * set_sbpkg2_pcls - call this before playing second record
 * of sentence builder packages. This loads 2 of the 18 sequences
 * of the second record.
 * Pass this the two channel numbers
 *
 * 7/3/92 FIX - This will always play channel 18 as well. This was added
 * to make sure the file pointer is always pointing past all the sequences
 * and at the first audio channel of the third record.
 *
 */
void set_sbpkg2_pcls(ch1, ch2)
    short   ch1;
    short   ch2;
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_sbpkg2_pcls\n");
        stop_all_audio();
    }

    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 3; */                  /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = (1 << ch1) | (1 << ch2) | (1 << 18);
    thePCB->PCB_AChan = 0;                  /* Audio to memory selection mask */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = 0;
    thePCB->PCB_Data = dat_cils;

    memset (dat_cils, 0, 32*4);     /* clear old ones first */
    dat_cils[ch1] = pcl_tab[0];         /* sequence #1 */
    dat_cils[ch2] = pcl_tab[1];         /* sequence #2 */
    dat_cils[18] = pcl_tab[2];          /* dummy - bookmark */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = Seq1Buf;      /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = SeqBufSecs; /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = Seq2Buf;      /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = SeqBufSecs; /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[3].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = SBFXSecs;       /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */
}

/*
 * set_sbpkg3_pcls - call this before playing second record
 * of sentence builder packages. This loads 4 of the 16 soundmaps
 * of the second record.
 * Pass this the four channel numbers
 * This always plays channel 18 as well as a way to advance to the next set or records
 */
void set_sbpkg3_pcls(ch0, ch1, ch2, ch3)
    short   ch0;
    short   ch1;
    short   ch2;
    short   ch3;
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_sbpkg3_pcls\n");
        stop_all_audio();
    }

    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 5; */                  /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = (1 << ch0) | (1 << ch1) | (1 << ch2) | (1 << ch3) | (1 << 18);
    thePCB->PCB_AChan = 0;                  /* Audio to memory selection mask */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data = dat_cils;

    memset (aud_cils, 0, 16*4);
    memset (dat_cils, 0, 32*4);
    aud_cils[ch0] = pcl_tab[0];         /* English intiial noun smap */
    aud_cils[ch1] = pcl_tab[1];         /* Spanish intiial noun smap */
    aud_cils[ch2] = pcl_tab[2];         /* English verb smap */
    aud_cils[ch3] = pcl_tab[3];         /* Spanish verb smap */
    dat_cils[18] = pcl_tab[4];          /* dummy bookmark */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[0].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = SBNounSecs; /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[1].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = SBNounSecs; /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[2].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = SBVerbSecs; /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[3]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[3]->PCL_Buf = snd_array[3].data;    /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = SBVerbSecs; /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[4]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[4]->PCL_Buf = snd_array[4].data;    /* Pointer to buffer */
    pcl_tab[4]->PCL_BufSz = SBFXSecs;       /* Size of buffer */
    pcl_tab[4]->PCL_Cnt = 0;                /* Current offset in buffer */
}


/*
 * set_sbpkg4_pcls -
 */
void set_sbpkg4_pcls(ch0, ch1, ch2)
    short   ch0;
    short   ch1;
    short   ch2;
{

    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 3; */                  /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = (1 << ch0) | (1 << ch1) | (1 << ch2);
    thePCB->PCB_AChan = 0;                  /* Audio to memory selection mask */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data = 0;

    memset (aud_cils, 0, 16*4);
    aud_cils[ch0] = pcl_tab[0];         /* English final noun smap */
    aud_cils[ch1] = pcl_tab[1];         /* Spanish final noun smap */
    aud_cils[ch2] = pcl_tab[2];         /* sound effect smap */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[4].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = SBNounSecs; /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[5].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = SBNounSecs; /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[6].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = SBFXSecs;       /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */
}



/*
 * set_wbpkg_pcls - call this before loading wordbook packages.
 */
void set_wbpkg_pcls()
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in set_wbpkg_pcls\n");
        stop_all_audio();
    }

    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    /* thePCB->PCB_Rec = 1; */              /* this gets set in 'play_recs' */
    thePCB->PCB_Chan = 0x00027FFF;          /* Channel selection mask */
    thePCB->PCB_AChan = 0;                  /* Audio to memory selection mask */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data = dat_cils;

    memset (dat_cils, 0, 32*4);
    memset (aud_cils, 0, 16*4);
    aud_cils[0] = vid_pcl_0;
    aud_cils[1] = vid_pcl_1;
    aud_cils[2] = pcl_tab[0];
    aud_cils[3] = pcl_tab[1];
    aud_cils[4] = pcl_tab[2];
    aud_cils[5] = pcl_tab[3];
    aud_cils[6] = pcl_tab[4];
    aud_cils[7] = pcl_tab[5];
    aud_cils[8] = pcl_tab[6];
    aud_cils[9] = pcl_tab[7];
    aud_cils[10] = pcl_tab[8];
    aud_cils[11] = pcl_tab[9];
    aud_cils[12] = pcl_tab[10];
    aud_cils[13] = pcl_tab[11];
    aud_cils[14] = pcl_tab[12];
    dat_cils[17] = pcl_tab[13];

    vid_pcl_0->PCL_Ctrl = 0;                /* Control byte */
    vid_pcl_0->PCL_Buf = snd_array[0].data; /* Pointer to buffer */
    vid_pcl_0->PCL_BufSz = 40;          /* Size of buffer */
    vid_pcl_0->PCL_Cnt = 0;             /* Current offset in buffer */

    vid_pcl_1->PCL_Ctrl = 0;                /* Control byte */
    vid_pcl_1->PCL_Buf = snd_array[1].data; /* Pointer to buffer */
    vid_pcl_1->PCL_BufSz = 40;          /* Size of buffer */
    vid_pcl_1->PCL_Cnt = 0;             /* Current offset in buffer */

    pcl_tab[0]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[0]->PCL_Buf = snd_array[2].data;    /* Pointer to buffer */
    pcl_tab[0]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[0]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[1]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[1]->PCL_Buf = snd_array[3].data;    /* Pointer to buffer */
    pcl_tab[1]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[1]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[2]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[2]->PCL_Buf = snd_array[4].data;    /* Pointer to buffer */
    pcl_tab[2]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[2]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[3]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[3]->PCL_Buf = snd_array[5].data;    /* Pointer to buffer */
    pcl_tab[3]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[3]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[4]->PCL_Ctrl = 0;               /* Control byte */
    pcl_tab[4]->PCL_Buf = snd_array[6].data;    /* Pointer to buffer */
    pcl_tab[4]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[4]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[5]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[5]->PCL_Buf = snd_array[7].data; /* Pointer to buffer */
    pcl_tab[5]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[5]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[6]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[6]->PCL_Buf = snd_array[8].data;            /* Pointer to buffer */
    pcl_tab[6]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[6]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[7]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[7]->PCL_Buf = snd_array[9].data;            /* Pointer to buffer */
    pcl_tab[7]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[7]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[8]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[8]->PCL_Buf = snd_array[10].data;           /* Pointer to buffer */
    pcl_tab[8]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[8]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[9]->PCL_Ctrl = 0;           /* Control byte */
    pcl_tab[9]->PCL_Buf = snd_array[11].data;           /* Pointer to buffer */
    pcl_tab[9]->PCL_BufSz = 40;         /* Size of buffer */
    pcl_tab[9]->PCL_Cnt = 0;                /* Current offset in buffer */

    pcl_tab[10]->PCL_Ctrl = 0;          /* Control byte */
    pcl_tab[10]->PCL_Buf = snd_array[12].data;          /* Pointer to buffer */
    pcl_tab[10]->PCL_BufSz = 40;            /* Size of buffer */
    pcl_tab[10]->PCL_Cnt = 0;               /* Current offset in buffer */

    pcl_tab[11]->PCL_Ctrl = 0;          /* Control byte */
    pcl_tab[11]->PCL_Buf = snd_array[13].data;  /* Pointer to buffer */
    pcl_tab[11]->PCL_BufSz = 40;            /* Size of buffer */
    pcl_tab[11]->PCL_Cnt = 0;               /* Current offset in buffer */

    pcl_tab[12]->PCL_Ctrl = 0;          /* Control byte */
    pcl_tab[12]->PCL_Buf = snd_array[14].data;  /* Pointer to buffer */
    pcl_tab[12]->PCL_BufSz = 40;            /* Size of buffer */
    pcl_tab[12]->PCL_Cnt = 0;               /* Current offset in buffer */

    pcl_tab[13]->PCL_Ctrl = 0;          /* Control byte */
    pcl_tab[13]->PCL_Buf = PkgBuf;      /* Pointer to buffer */
    pcl_tab[13]->PCL_BufSz = WBPkgSecs; /* Size of buffer */
    pcl_tab[13]->PCL_Cnt = 0;               /* Current offset in buffer */
}


/*
 * setup_bkgd_audio_rtf -
 */
void setup_bkgd_audio_rtf(the_chan)
    int the_chan;
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in setup_bkgd_audio_rtf\n");
        ss_abort (cur_aud_fid);
    }
    thePCB->PCB_Stat = 0;                   /* Current status of the play */
    thePCB->PCB_Sig = PCB_SIGNAL;           /* Signal to be sent */
    thePCB->PCB_Rec = 1;
    thePCB->PCB_Chan = (1 << the_chan);
    thePCB->PCB_AChan = (1 << the_chan);    /* send audio channel to processor */
    thePCB->PCB_Video = 0;
    thePCB->PCB_Audio = aud_cils;
    thePCB->PCB_Data  = 0;

    memset (aud_cils, 0, 16*4);
}


/*
 * close_rtf_stuff -
 */
void close_rtf_stuff()
{
int     ctr;

    DEALLOCATE(sizeof(PCB), thePCB);
    DEALLOCATE(32*4, vid_cils);
    DEALLOCATE(16*4, aud_cils);
    DEALLOCATE(32*4, dat_cils);
    DEALLOCATE(sizeof(PCL), vid_pcl_0);
    DEALLOCATE(sizeof(PCL), vid_pcl_1);
    for (ctr=0; ctr<max_chans; ctr++)
        DEALLOCATE(sizeof(PCL), pcl_tab[ctr]);
}




screen.c

#include <stdio.h>
#include <ucm.h>
#include <modes.h>
#include <csd.h>
#include <aimdef.h>
#include <time.h>
#include <errno.h>

#include "dbg.h"

#include "animation.h"
#include "screen.h"
#include "buttons.h"
#include "sentbld.h"
#include "utility.h"
#include "reading.h"
#include "bop.h"        /* for the no_vel, add_vel routines */


Ptr     scn_ptr;        /* destination screen for draws and erases */
Ptr     vidmem0;        /* pointer to screen 0 (plane A) */
Ptr     vidmem1;        /* pointer to screen 1 (plane A) */
Ptr     vidmem2;        /* pointer to screen 0 (plane B) for clut7 */
Ptr     vidmem3;        /* pointer to screen 1 (plane B) for clut7 */
Ptr     vidmem4;        /* pointer to 70 scan line button strip (plane B) */
Ptr     vidmem5;        /* pointer to bkgd screen for our stuff (plane B) */
int     vidpath;        /* video path */
int     fctid_RL7;      /* field control table ID (RL7) */
int     fctid_Clut7;    /* field control table ID (Clut7) */
int     lctid0;         /* LCT for RL7 screens in plane A */
int     lctid2;         /* LCT for Clut7 screens in plane B */
int     lct_pal_a;      /* LCT for PAL in plane A */
int     lct_pal_b;      /* LCT for PAL in plane B */

short   FilCol;
Boolean PAFlag;         /* plane A flag - true if plane A has ICF */
Boolean PBFlag;         /* plane B flag - true if plane B has ICF */

int     PALflag;
Rect    safe_rect = { 24<<1, 33<<1, 207<<1, 342<<1 };

Boolean cursor_stat;



/************************************************************************
* set_comp_mode()
***
* **** This function was lifted almost entirely out of os9_util.c, the
* ****  only thing changed was the parameter for the pt_org() offset
***
* Purpose:  Set the compatability mode on the CD-I system assuming
*               that the images used are 384 actual bytes wide
* Passed:   the video device number,
*           a ptr to the var which will contain the PAL flag,
*           a ptr to the var which is to hold the pointer origin offset
*               which is returned from dc_setcmp()
* Output:   The compatability mode will be set according to the info
*               found in the CSD,
*           If we are displaying on a 625 line system, the pal_flag will
*               be set to YES, else it will be NO
* Returned: OK or SYSERR
************************************************************************/
int set_comp_mode( vpath, pal_flag )
    int vpath;
    int *pal_flag;
{
char *disp_dev, *disp_param;
char *csd_devname(), *csd_devparam();
REG char *dp;
int mode, org_diff;

#define TV_TYPE_STR     "TV"    /* TV type ID string */
#define PAL_625_STR     "625"   /* Spec's 625 line system */

    if ( (disp_dev = csd_devname( DT_VIDEO, 1 )) == NULL ) {
        STATUS1("Couldn't get disp_dev name\n");
        exit(0);
    }
    if ( (disp_param = csd_devparam( disp_dev )) == NULL ) {
        free( disp_dev );
        STATUS1("Couldn't get disp_param\n");
        exit(0);
    }
    mode = 1;                   /* Mode 1 is for 384 width on Monitor */
    dp = disp_param;            /* If "TV" is found then mode should be 0 */
    while ( *dp != '\0' ) {
        if (strncmp( dp++, TV_TYPE_STR, strlen(TV_TYPE_STR) ) == 0) {
            mode = 0;
            break;
        }
    }
    *pal_flag = 0;              /* Assume NTSC */
    dp = disp_param;            /* If 625 is found, then we are in PAL */
    while ( *dp != '\0' ) {
        if (strncmp( dp++, PAL_625_STR, strlen(PAL_625_STR) ) == 0) {
            *pal_flag = 1;
            if ( mode == 1 )    /* Need mode to be 0 w/384x240 on 625 lines */
                mode = 0;
            break;
        }
    }
    free( disp_dev );           /* Give back memory for csd stuff */
    free( disp_param );
                                /* Set appropriate compatability mode */
                                /*  and set return value to parameter */
    Errchk( org_diff = dc_setcmp( vpath, mode ) );

                                /* Reset ptr to report from offset */
                                /* Also, if in PAL, move org down 40 lines */
    pt_org( vpath, (org_diff >> 16), (org_diff & 0xff) );

    return ( OK );

#undef TV_TYPE_STR
#undef PAL_625_STR

}




void InitMatte()
{
    /*
     * Copy the RL7 matte screen to the two RL7 buffers in plane A
     */
    memcpy(vidmem0, mattePtr, 4354); /* the image data starts 4354 bytes into the file */
    memcpy(vidmem1, mattePtr, 4354);
}

/*
 * Enable the scrolling matte in plane A.  butline is the scan line
 * at which the button bitmap is linked to.
 */
void MatteOn()
{
    dc_wrli(vidpath,lctid0,1*2,2,cp_matte (0, MO_SET, MF_MF0, ICF_MIN, 0*2));
    dc_wrli(vidpath,lctid0,1*2,3,cp_matte (1, MO_RES, MF_MF0, ICF_MIN, 34*2));
    dc_wrli(vidpath,lctid0,1*2,4,cp_matte (2, MO_SET, MF_MF0, ICF_MIN, 350*2));
    dc_wrli(vidpath,lctid0,butline,0,cp_matte (0, MO_RES, MF_MF0, ICF_MIN, 0*2));
    dc_wrli(vidpath,lctid0,butline,1,cp_matte (1, MO_END, MF_MF0, ICF_MIN, 0*2));
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_OFF,TR_MAT0_F ,TR_OFF));
    PAFlag = true; /* set plane A flag */
}

void MatteOff()
{
    NoA();
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_ON,TR_CKEY_T,TR_OFF));
    dc_wrli(vidpath,lctid0,1*2,2,cp_nop());
    dc_wrli(vidpath,lctid0,1*2,3,cp_nop());
    dc_wrli(vidpath,lctid0,1*2,4,cp_nop());
    dc_wrli(vidpath,lctid0,butline,0,cp_nop());
    dc_wrli(vidpath,lctid0,butline,1,cp_nop());
}

/*
 * Enable to middle 120-140 scan lines that
 * the sentence builder RTFs play in
 */
void RTFMatteOn()
{
    /*
     * Modify the LCT for the RL7 screens in plane A.  Set the initial video buffer
     * address to a series of "draw transparent" instructions.  At line 51, set the
     * actual RL7 video buffer. At line 190, point to the transparent buffer again.
     * This should allow the desired parts of plane B to show through.
     */
    dc_wrli(vidpath,lctid0,theLine*2,1,cp_matte(0,MO_SET,MF_MF0,ICF_MIN,0*2));
    dc_wrli(vidpath,lctid0,butline,0,cp_matte(0,MO_RES,MF_MF0,ICF_MIN,0*2));
    dc_wrli(vidpath,lctid0,butline,1,cp_matte(1,MO_END,MF_MF0,ICF_MIN, 0*2));
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_OFF,TR_MAT0_F,TR_OFF));
    PAFlag = true; /* set plane A flag */
}

void RTFMatteOff()
{
    /*
     * Set plane A back to straight RL7 and turn it off
     */
    PAFlag = false;
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_ON,TR_CKEY_T,TR_OFF));
    dc_wrli(vidpath,lctid0,theLine*2,0,cp_nop()); /* this was a link to the bitmap */
    dc_wrli(vidpath,lctid0,theLine*2,1,cp_nop());
    dc_wrli(vidpath,lctid0,butline,0,cp_nop());
    dc_wrli(vidpath,lctid0,butline,1,cp_nop());
}


void bop_but_matte_on()
{
    dc_wrli(vidpath,lctid0,butline,0,cp_matte (0, MO_SET, MF_MF0, ICF_MIN, 0));
    dc_wrli(vidpath,lctid0,butline,1,cp_tci(MIX_OFF,TR_M0CK_T,TR_OFF));
    dc_wrli(vidpath,lctid0,239*2,1,cp_matte (1, MO_END, MF_MF0, ICF_MIN, 0));
}


void bop_but_matte_off()
{
    dc_wrli(vidpath,lctid0,butline,0,cp_nop());
    dc_wrli(vidpath,lctid0,butline,1,cp_nop());
    dc_wrli(vidpath,lctid0,239*2,1,cp_nop());
}


void BopOn()
{
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_OFF,TR_CKEY_T,TR_OFF));
}
void BopOff()
{
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_ON,TR_CKEY_T,TR_OFF));
}


/*
 * swap_clut7 - switches the two screens in plane B.
 * scn_ptr should always be pointing at the rear screen in plane B.
 *
 * This is a two stage "process". A scan line interrupt is first set somewhere
 * below the line that holds the address pointer to the video buffer. When the interrupt
 * is enabled, and the signal is received, it's a safe time to change the address pointer.
 * After this, a scan line interrupt is set for the top line of the lct (the lct
 * varies for PAL of NTSC).
 *
 */
void swap_clut7()
{
int     stat;

    /*
     * clear old phase2 DCP instructions and write new phase1
     */
    if (PALflag) {
        dc_wrli(vidpath,lct_pal_b,PHASE2_SWAP_LINE*2,SWAP_COLUMN,cp_nop());
        dc_wrli(vidpath,lctid2,PHASE1_SWAP_LINE*2,SWAP_COLUMN,cp_sig());
    }
    else {
        dc_wrli(vidpath,lctid2,PHASE2_SWAP_LINE*2,SWAP_COLUMN,cp_nop());
        dc_wrli(vidpath,lctid2,PHASE1_SWAP_LINE*2,SWAP_COLUMN,cp_sig());
    }
    /*
     * now wait for this line to be drawn
     */
    swapflag = false;   /*  signal handler will set this */
    if ((stat = dc_ssig(vidpath,SLI_SIGNAL,0)) == -1) {
        STATUS2("couldn't set phase 1 SLI in swap_clut7. error number %d\n", errno);
    }
    while (!swapflag);
    /*
     * Quickly write the new address instrcutions
     */
    if (scn_ptr == vidmem2) {
        dc_wrli(vidpath,lctid2,0*2,0,cp_dadr((int)vidmem2));
        scn_ptr = vidmem3;
        EraPtr = &EraTab3;
    }
    else {
        dc_wrli(vidpath,lctid2,0*2,0,cp_dadr((int)vidmem3));
        scn_ptr = vidmem2;
        EraPtr = &EraTab2;
    }
    /*
     * clear old phase1 DCP instructions and write new phase2
     */
    if (PALflag) {
        dc_wrli(vidpath,lctid2,PHASE1_SWAP_LINE*2,SWAP_COLUMN,cp_nop());
        dc_wrli(vidpath,lct_pal_b,PHASE2_SWAP_LINE*2,SWAP_COLUMN,cp_sig());
    }
    else {
        dc_wrli(vidpath,lctid2,PHASE1_SWAP_LINE*2,SWAP_COLUMN,cp_nop());
        dc_wrli(vidpath,lctid2,PHASE2_SWAP_LINE*2,SWAP_COLUMN,cp_sig());
    }
    /*
     * set the new signal and exit
     */
    swapflag = false;   /*  signal handler will set this */
    if ((stat = dc_ssig(vidpath,SLI_SIGNAL,0)) == -1) {
        STATUS2("couldn't set phase 2 SLI in swap_clut7. error number %d\n", errno);
    }
}



/*
 * These gradually change the image contibution factor of
 * planes A and B.
 *
 * Pass the delay value to either DslvAB of DslvBA
 */


void DslvAB(delay)
    short delay;
{
short A;

    for (A=0; A<=ICF_MAX; A++) {
        tsleep(delay);
        dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MAX - A));
        dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,A));
    }
    PAFlag = false; /* clear plane A flag */
    PBFlag = true;  /* plane B now has max ICF */
}


void DslvBA(delay)
    short delay;
{
short A;

    for (A=0; A<=ICF_MAX; A++) {
        tsleep(delay);
        dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,A));
        dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,ICF_MAX - A));
    }
    PAFlag = true; /* set plane A flag */
    PBFlag = false;
}

void AddA()
{

#if 0
short A;

    for (A=ICF_MIN; A<=ICF_MAX; A+=7) {
        tsleep(1);
        dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,A));
    }
#endif
    dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MAX));
    PAFlag = true; /* set plane A flag */
}


void AddB()
{

#if 0
short A;

    for (A=ICF_MIN; A<=ICF_MAX; A+=7) {
        tsleep(1);
        dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,A));
    }
#endif
    dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,ICF_MAX));
    PBFlag = true;
}


void NoA()
{

#if 0
short A;

    for (A=ICF_MAX; A>=ICF_MIN; A--) {
        tsleep(1);
        dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,A));
    }
#endif

    dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MIN));
    PAFlag = false; /* clear plane A flag */
}



/*
 * copy_bkgd_front -    This copies the bkgd bitmap to the rear screen in plane B.
 *                      it then swaps the screens in plane B and copies to the new rear screen.
 *                      It sets up all three screens to do our animation
 */
void copy_bkgd_front()
{
    memcpy(scn_ptr, vidmem5, 384 * 240); /* copy it to the rear screen */
    Step(); /* this will draw the first frame of animation and call 'swap' */
    while (!swapflag);
    memcpy(scn_ptr, vidmem5, 384 * 240); /* copy it to the new rear screen */
}



void cursor_show()
{
    gc_show(vidpath);
    cursor_stat = true;
}

void cursor_hide()
{
    gc_hide(vidpath);
    cursor_stat = false;
}

/*
 * FadeDown/FadeUp work with both planes simultaneously
 */
void FadeDown(delay)
    short   delay;
{
short   A;

    cursor_hide();
    for (A=ICF_MAX; A>=ICF_MIN; A--) {
        tsleep(delay);
        if (PAFlag)
            dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,A));
        if (PBFlag)
            dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,A));
    }
}

void FadeUp(delay, cursor)
    short   delay;
    Boolean cursor;
{
short   A;

    for (A=ICF_MIN; A<=ICF_MAX; A++) {
        tsleep(delay);
        if (PAFlag)
            dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,A));
        if (PBFlag)
            dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,A));
    }
    if (cursor)
        cursor_show();
}

sentbld.c

#include <stdio.h>
#include <time.h>
#include <ucm.h>
#include <errno.h>
#include <modes.h>
#include <rtr.h>

#include "dbg.h"

#include "utility.h"
#include "animation.h"
#include "buttons.h"
#include "screen.h"
#include "sentbld.h"
#include "rtf.h"
#include "sound.h"
#include "reading.h"
#include "file_mgr.h"


short       sbpctr;
static  short       WhichSBPkg; /* which package to do */
static  SBInfoPtr   RezPtr;     /* ptr to the resedit section of the package */
static  Ptr         SBPkgData;  /* the data section of the package (past the TOC) */
static  short       WhichBkgd = 0;  /* toggles between 0,1 for which bkgd version to use */
static  short       WhichTune = 0;  /* cycles between 0,1, 2 for which tune to use */
static  int         sbpkgfid;   /* file ID of current sb package file */
static  short       SentNum;    /* which of the 27 sentences to use in the package */
int                 bkgdfid;    /* file ID of the bkgd strip file */
static  short       lastCell;   /* holds hotspot of last cell the star appeared over */
static  int         RTFfid;     /* if one of the sentences has a RTF */
static  SBSclBkPtr  ScrlRez;    /* points to one of the two scroll resource files */
static  short       NxtFScrl;   /* index for next front scroll item to be introduced */
static  short       NxtRScrl;   /* index for next rear scroll item to be introduced */
static  short       ScrlID;

/*
 * This next group of pointers deal with things in the
 * sentence builder common file (sent.com) that gets
 * loaded during the sentence builder intro rtf.
 */
static  ScenePtr    SBScene;
static  ScenePtr    ScrlScene0; /* the first scrolling scene */
static  ScenePtr    ScrlScene1; /* the second scrolling scene */
static  SBBkgdPtr   BGPtr0;     /* pointer to the bkgd rez data #1 */
static  SBBkgdPtr   BGPtr1;     /* pointer to the bkgd rez data #2 */
static  SBSclBkPtr  SCPtr0;     /* pointer to the scroll rez data #1 */
static  TOCPtr      SCTOC;      /* table of contents (TOC) of the scroll data */
static  Ptr         SCData;     /* data section of the combined scroll items */
static  TOCPtr      BGTOC;      /* table of contents (TOC) of the bkgd strips file */
static  Ptr         perPtr;     /* pointer to the period shape */
Ptr     mattePtr;               /* ptr to RL7 screen that resides in plane A */
Boolean useRTF;                 /* true means the selected sentence has a RTF to use */
char    *RTFName;
static  short       RTFctr;     /* down counter used to count rtf plays */
static  ItemSeqPtr  theiSeq;    /* initial item table pointer */
static  ItemSeqPtr  thefSeq;    /* final item table pointer */

/*
 * this is the table of the 47 packages that gets shuffled
 * Sentence Builder Package Tab
 */
short   sbptab[NumSBPkgs] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    10,11,12,13,14,15,16,17,18,19,
    20,21,22,23,24,25,26,27,28,29,
    30,31,32,33,34,35,36,37,38,39,
    40,41,42,43,44,45,46
    };

/*
 * This is kind of the main table for Sentence Builder
 * The first entry is the package filename
 * The second entry is the sentence number (0-26) that has an RTF (or -1 for none)
 * The third entry is the RT filename
 */
static  PkgTab SBPkgTab[NumSBPkgs] = {
    "pkg73.rtf",  9, "BIRD.HOUSE.rtf", 25, "BEE.rtf",
    "pkg19.rtf", 12, "SPACE.rtf", -1, " ",
    "pkg67.rtf", 18, "TRUCK.TREE.rtf", -1, " ",
    "pkg68.rtf",  1, "CYCLE.HOUSE.rtf", -1, " ",
    "pkg30.rtf",  3, "KANG.rtf", -1, " ",
    "pkg58.rtf", -1, " ", -1, " ",
    "pkg110.rtf", -1, " ", -1, " ",
    "pkg99.rtf",  0, "TRAIN.rtf", -1, " ",
    "pkg1.rtf",  15, "TRUCK.ELE.rtf", -1, " ",
    "pkg2.rtf",  19, "CYCLE.GAS.rtf", -1, " ",
    "pkg3.rtf",   3, "BARN.TRACT.rtf", 12, "BARN.CYCLE.rtf",
    "pkg4.rtf",   5, "TRAIN.rtf", 21, "BARN.RACER.rtf",
    "pkg5.rtf",  -1, " ", -1, " ",
    "pkg10.rtf", 11, "DIVER.FISH.rtf", -1, " ",
    "pkg11.rtf",  3, "ROW.ISLE.rtf", 5, "ROW.LIGHT.rtf",
    "pkg13.rtf", 16, "DIVER.SHARK.rtf", -1, " ",
    "pkg14.rtf", -1, " ", -1, " ",
    "pkg18.rtf",  0, "SAILBOAT.rtf", -1, " ",
    "pkg20.rtf",  0, "LIGHTHOUSE.rtf", 10, "BIRD.GIRAFFE.rtf",
    "pkg27.rtf", 10, "BIRD.TREE.rtf", -1, " ",
    "pkg29.rtf",  1, "PANTH.PIG.rtf", 10, "PANTH.CAT.rtf",
    "pkg31.rtf", 19, "TIGER.RABBIT.rtf", -1, " ",
    "pkg36.rtf",  0, "PIG.PANTH.rtf", -1, " ",
    "pkg37.rtf", -1, " ", -1, " ",
    "pkg38.rtf", -1, " ", -1, " ",
    "pkg39.rtf", -1, " ", -1, " ",
    "pkg40.rtf", -1, " ", -1, " ",
    "pkg43.rtf", -1, " ", -1, " ",
    "pkg44.rtf", -1, " ", -1, " ",
    "pkg46.rtf", -1, " ", -1, " ",
    "pkg53.rtf", -1, " ", -1, " ",
    "pkg60.rtf", -1, " ", -1, " ",
    "pkg70.rtf",  3, "TRUCK.KANG.rtf", -1, " ",
    "pkg76.rtf",  0, "BIRD.GIRAFFE.rtf", -1, " ",
    "pkg81.rtf", 14, "LIGHTHOUSE.rtf", -1, " ",
    "pkg83.rtf",  6, "HIPPO.rtf", -1, " ",
    "pkg85.rtf", 16, "PENGUIN.rtf", 18, "KANG.rtf",
    "pkg86.rtf", 18, "DOG.TURTLE.rtf", -1, " ",
    "pkg89.rtf",  3, "PANTH.CHICK.rtf", -1, " ",
    "pkg91.rtf", 12, "BARN.CYCLE.rtf", -1, " ",
    "pkg96.rtf",  3, "ROW.ISLE.rtf", -1, " ",
    "pkg100.rtf", -1, " ", -1, " ",
    "pkg109.rtf", -1, " ", -1, " ",
    "pkg111.rtf", 11, "DOG.BUCKET.rtf", -1, " ",
    "pkg113.rtf",  7, "LION.MOUSE.rtf", -1, " ",
    "pkg116.rtf", -1, " ", -1, " ",
    "pkg118.rtf", 21, "KANG.rtf", -1, " "
};


/*
 * These two tables have their fixed ypos's set, the
 * first and third elements (word index) gets set by the code that chooses the words.
 */
S1Tab Snoun[6] = {
    00, 22, 0000, 0000, 00, 00,
    00, 37, 0000, 0000, 00, 00,
    00, 52, 0000, 0000, 00, 00,
    00,126, 0000, 0000, 00, 00,
    00,141, 0000, 0000, 00, 00,
    00,156, 0000, 0000, 00, 00
};

S1Tab Sverb[3] = {
    00, 74, 0000, 0000, 00, 00,
    00, 89, 0000, 0000, 00, 00,
    00,104, 0000, 0000, 00, 00
};

/*
 * These hold the index of each group of three word/phrases.
 * Each can have the value of 1, 2, or 3
 */
static  short   TopNoun;
static  short   MidVerb;
static  short   BotNoun;

static  short   DirSave1;   /* # of things that were in mfxDir before scrn1 images */
static  short   DirSave2;   /* # of things that were in mfxDir before scrn2 images (verb seqs) */

static  Boolean noun_smap;

/*
 * These are the rectangle tables for each section of SB Reading
 */
static  RectList Sent1Rect = {
    14,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,283,    /* play button */
    177,289,218,350,    /* go back button */
     21, 33, 35,248,    /* initial noun #1 */
     36, 33, 50,248,    /* initial noun #2 */
     51, 33, 65,248,    /* initial noun #3 */
     73, 33, 87,248,    /* verb #1 */
     88, 33,102,248,    /* verb #2 */
    103, 33,117,248,    /* verb #3 */
    125, 33,139,248,    /* final noun #1 */
    140, 33,154,248,    /* final noun #2 */
    155, 33,169,248     /* final noun #3 */
};


static  RectList Sent2bRect = {
    6,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,283,    /* play button */
    177,289,218,319,    /* go back arrow */
    177,320,218,350,    /* go next arrow */
};

static  Rect    BkgdRect = { 52, 34, 190, 350 }; /* large animation window */
static  Rect    fullRect = {  0,  1, 240, 383 }; /* entire CDI screen */
static  Rect    sentRect = { 22, 34,  51, 350 }; /* sentence window */
static  Rect    iNounRect = { 0, 0, 0, 0 };     /* initial noun */
static  Rect    VerbRect = { 0, 0, 0, 0 };      /* verb phrase */
static  Rect    fNounRect = { 0, 0, 0, 0 };     /* final noun */

static  WITab   yTab[101] = {
    2,1,2,1,2,2,2,2,2,2,    /* acrobat, airplane,anteater,astronaut, ball */
    2,2,2,2,2,2,2,4,2,2,    /* balloon, banana, barge, barn, barrel */
    2,4,2,2,2,1,2,2,2,2,    /* bed, bee, bird, book, box */
    2,2,2,2,2,2,2,2,2,2,    /* bridge, bucket, bulldozer, Bumper, buoy */
    2,1,2,2,4,4,4,1,2,2,    /* bus, camel, canoe, car, cat */
    2,2,2,2,2,2,2,0,2,2,    /* cementmixer, chair, chicken, clock, cloud */
    2,4,2,2,4,4,2,2,2,2,    /* clown, computer, cow, diver, dock */
    2,4,2,2,2,2,2,2,2,4,    /* dog, door, duck, elephant, fence */
    2,4,2,4,4,2,2,1,2,2,    /* fish, frog, garage, gasstation, giraffe */
    2,2,2,2,2,1,2,1,2,4,2,4,    /* goat, hanger, helicopter, hippo, horn, house */
    2,2,2,2,2,4,2,2,2,1,    /* iron, island, kangaroo, lighthouse, lion */
    2,4,4,2,2,2,2,2,2,1,    /* monkey, moon, motorboat, motorcycle, mountain */
    4,1,2,2,2,2,2,2,2,2,    /* mouse, ostrich, panther, parachutist, parrot */
    2,2,2,2,2,2,2,2,4,1,    /* penguin, pig, pumpkin, rabbit, racer */
    2,2,2,2,2,2,2,2,2,2,    /* rainbow, rocket, rowboat, sailboat, Sara */
    4,2,2,1,2,2,2,2,2,2,    /* saw, shark, sheep, shoe, skunk */
    2,1,2,2,2,2,2,2,4,2,    /* sock, star, Stickybear, submarine, swan */
    2,4,2,1,2,2,2,2,2,2,    /* table, tanker, taxi, tent, tiger */
    2,2,2,2,2,2,2,1,2,1,    /* tower, tractor, train, tree, truck */
    2,1,2,2,4,2,2,2,2,2     /* tunnel, turtle, wagon, window, zebra */
};

static  WITab   VyTab[] = {
    2,1,2,1,2,2,2,1,        /* bounces away, bounces behind, bounces by, bounces faster */
    2,2,2,2,2,2,2,2,        /* bounces infront, bounces to, bumps into, chases */
    2,2,2,2,2,2,2,1,        /* dances, drifts away, drifts past, drives behind */
    2,2,2,2,2,2,2,2,        /* drives infront, drives into, drives out, drives past */
    2,2,2,2,2,1,2,2,        /* drives up, flies around, flies behind, flies infront */
    2,2,2,2,2,1,2,2,        /* flies over, flies under, floats behind, floats infront */
    2,2,2,1,2,4,2,1,        /* follows, glides past, goes thru, hides behind */
    2,2,2,2,2,2,2,2,        /* honks at, jumps over, lands on, plays with */
    2,1,2,2,2,2,2,2,        /* races behind, races infront, races into, races out */
    2,2,2,1,2,2,2,1,        /* races past, rolls away, runs away, runs behind */
    2,1,2,2,2,2,2,2,        /* runs faster, runs infront, runs past, runs to */
    2,1,2,1,2,2,2,1,        /* skips away, skips behind, skips by, skips faster */
    2,2,2,2,2,1,2,1,        /* skips infront, skips to, slides away, slides behind */
    2,1,2,2,2,2,2,2,        /* slides faster, slides infront, slides past, slides to */
    2,1,2,2,2,2,2,2,        /* splashes behind, splashes infront, stands next, stands on */
    2,1,2,1,2,2,2,2,        /* swims away, swims behind, swims infront, swims over */
    2,2,2,1,2,1,2,2,        /* swims under, walks away, walks behind, walks infront */
    2,2,2,2,2,2,2,2,        /* walks past, walks to, waves at, whistles at */
    2,2,2,1,2,1,2,2,        /* zooms around, zooms away, zooms behind, zooms infront */
    2,2,2,2,2,2,2,2,        /* zooms into, zooms over, zooms past, zooms through  */
    2,2,2,2                 /* zooms under, zooms to */
    };

AITab artTab[9] = {
    0, 0,0,     /* for compatibility with resedit data */
    2,23,0,     /* The */
    2,19,0,     /* the */
    2,11,0,     /* El */
    2,11,0,     /* el */
    2,14,0,     /* La */
    2,10,0,     /* la */
    2,19,0,     /* del */
    2,11,0      /* al */
    };

static  MCAud SBTunes[] = {
    0, 0, 0, 1, 0, 2, 0, 3,
    0, 4, 0, 5, 0, 6, 0, 7,
    0, 8, 0, 9, 0,10, 0,11,
    0,12, 0,13, 0,14, 0,15,

    1, 0, 1, 1, 1, 2, 1, 3,
    1, 4, 1, 5, 1, 6, 1, 7,
    1, 8, 1, 9, 1,10, 1,11,
    1,12, 1,13, 1,14, 1,15,

    2, 0, 2, 1, 2, 2, 2, 3,
    2, 4, 2, 5, 2, 6, 2, 7,
    2, 8, 2, 9, 2,10, 2,11,
    2,12, 2,13, 2,14, 2,15,
    };



void SentBld()
{
short       ctr;
Boolean     done;
Ptr         myPtr;


    /*
     * stuffpkg returns with a ptr to the first byte of the data
     * section of the package (which is where we always place a scene).
     * The rest of the stuff in the package can be found in mfxDir.
     */
    SBScene = SceneTab[MScene] = (ScenePtr)stuffpkg(ScreenBuf);
    ScrlScene0 = SceneTab[ScScene0] = (ScenePtr)mfxDir[getind("scroll6a.scene")].Where;
    ScrlScene1 = SceneTab[ScScene1] = (ScenePtr)mfxDir[getind("scroll6b.scene")].Where;

    FixScene(MScene);
    FixScene(ScScene0);
    FixScene(ScScene1);

    ScrlScene0->AniDelay = ScrlScene1->AniDelay = SBScene->AniDelay = scrn1_AniDelay;

    BGPtr0 = (SBBkgdPtr) mfxDir[getind("bkgdrez1")].Where;  /* pointer to the bkgd rez data #1 */
    BGPtr1 = (SBBkgdPtr) mfxDir[getind("bkgdrez2")].Where;  /* pointer to the bkgd rez data #2 */
    SCPtr0 = (SBSclBkPtr) mfxDir[getind("scrollrez1")].Where; /* pointer to the scroll rez data #1 */
    SCTOC = (TOCPtr) mfxDir[getind("scroll.com")].Where;    /* table of contents (TOC) of the scroll data */
    SCData = (Ptr) SCTOC + ((*(short *)SCTOC) * 40 + 4);    /* data section of the combined scroll items */
    BGTOC = (TOCPtr) mfxDir[getind("bkgd.h")].Where;        /* table of contents (TOC) of the bkgd strips file */

    RezPtr = (SBInfoPtr)RezBuf; /* pointer to resedit data */
    mattePtr = mfxDir[getind("SBmatte.rl7")].Where + 468;
    perPtr = mfxDir[getind("period.shp")].Where; /* ptr to the period shape */
    /*
     * Setup the address pointers to the article shapes
     */
    myPtr = mfxDir[getind("Cpthe.shp")].Where;
    artTab[1].BImage = myPtr;
    myPtr = mfxDir[getind("the.shp")].Where;
    artTab[2].BImage = myPtr;
    myPtr = mfxDir[getind("Cpel.shp")].Where;
    artTab[3].BImage = myPtr;
    myPtr = mfxDir[getind("el.shp")].Where;
    artTab[4].BImage = myPtr;
    myPtr = mfxDir[getind("Cpla.shp")].Where;
    artTab[5].BImage = myPtr;
    myPtr = mfxDir[getind("la.shp")].Where;
    artTab[6].BImage = myPtr;
    myPtr = mfxDir[getind("del.shp")].Where;
    artTab[7].BImage = myPtr;
    myPtr = mfxDir[getind("al.shp")].Where;
    artTab[8].BImage = myPtr;

    DirSave1 = DirNum;

    theRectPtr = &Sent1Rect;    /* set list of hotspots */

    newsbpkg();                 /* load new package */

    MkScrn1(true);      /* Make scrn1 (also include buttons) */
    Step();         /* This will draw the first frame of animation */

    /* set_bkgd_music(); */ /* This sets the bkgd audio rtf to the one containing the correct bkgd music */

    FadeDown(meddisolve);
    PAFlag = false;
    PBFlag = true;
    FadeUp(meddisolve, true); /* Now just bring up plane B */


    start_bkgd_audio(SBMusic, BEARfid, true); /* pass channel number */
    InitMatte();    /* set up the mattes */

    cursor_show();          /* display the cursor */
    done = false;
    while (!done) {

        update_audio();

        chk_help(1, BEARfid, SBMusic, BEARfid);
        chk_dim();  /* if it's time to dim, this won't return until undim */

        CheckInput();
        CheckHighLite();
        if (theInpTab.ButPress) {
            switch (theInpTab.HotIndex) {
                case 0: /* Help button */
                    stop_all_audio();
                    start_bkgd_audio(0, BEARfid, false); /* pass channel number */
                    CheckInput();
                    CheckHighLite();
                    while ((eor_ctr) && (theInpTab.HotIndex == 0) && (!theInpTab.ButPress)) {
                        CheckInput();
                        CheckHighLite();
                    }
                    stop_all_audio();
                    start_bkgd_audio(SBMusic, BEARfid, true);
                    reset_help();
                    break;
                case 1: /* speech button */
                    Cursor_Freeze();
                    stop_all_audio();
                    start_bkgd_audio(0, BUTTONfid, false); /* pass channel number */
                    changeSpch();
                    while (eor_ctr) {
                        Step();
                        CheckHighLite();
                    }
                    stop_all_audio();
                    set_bear_voice();
                    set_button_voice();
                    start_bkgd_audio(SBMusic, BEARfid, true);
                    Cursor_Melt();
                    break;
                case 2: /* text button */
                    Cursor_Freeze();
                    stop_all_audio();
                    if (text == English)
                        start_bkgd_audio(3, BUTTONfid, false); /* pass channel number */
                    if (text == Spanish)
                        start_bkgd_audio(1, BUTTONfid, false); /* pass channel number */
                    changeText();
                    MkScrn1(false); /* don't make new buttons */
                    for (ctr=0; ctr<6; ctr++) {
                        if (Snoun[ctr].CelCol != clearcol)
                            Snoun[ctr].CelUpdate = 2;
                    }
                    for (ctr=0; ctr<3; ctr++) {
                        if (Sverb[ctr].CelCol != clearcol)
                            Sverb[ctr].CelUpdate = 2;
                    }
                    while (eor_ctr) {
                        Step();
                        CheckHighLite();
                    }
                    stop_all_audio();
                    start_bkgd_audio(SBMusic, BEARfid, true);
                    Cursor_Melt();
                    break;
                case 3: /* play button */
                    if (PlayFlag) {
                        stop_all_audio();
                        SBScene->AniDelay = scrn2_AniDelay;
                        DoScrn2();  /* this doesn't return until it's time to do screen 1 */
                        SBScene->AniDelay = scrn1_AniDelay;
                        theRectPtr = &Sent1Rect;    /* set list of hotspots */
                        ModMod = ModSent1;  /* we are on screen one */
                        InitScrn1();
                        MkScrn1(true);      /* Draw screen1 with new buttons as well */
                        FadeUp(meddisolve, true);
                        start_bkgd_audio(SBMusic, BEARfid, true);
                    }
                    break;
                case 4: /* go back button */
                    stop_all_audio();
                    done = true;
                    break;
                case 5:
                case 6:
                case 7:
                    /*
                     * Deselect any other from this group. It's ok if it turns
                     * out to be the one we are selecting.
                     */
                    for (ctr=0; ctr<3; ctr++) {
                        if (Snoun[ctr].CelCol == selcol) {
                            Snoun[ctr].CelCol = 0;
                            Snoun[ctr].CelUpdate = 2;
                        }
                    }
                    Snoun[theInpTab.HotIndex-5].CelCol = selcol;
                    Snoun[theInpTab.HotIndex-5].CelUpdate = 2;
                    SetIcon(theInpTab.HotIndex-5);
                    TopNoun = theInpTab.HotIndex-5;
                    if ((MidVerb != MTPart) && (BotNoun != MTPart) && (PlayFlag == false))
                        LetPlay();
                    break;
                case 8:
                case 9:
                case 10:
                    for (ctr=0; ctr<3; ctr++) {
                        if (Sverb[ctr].CelCol == selcol) {
                            Sverb[ctr].CelCol = 0;
                            Sverb[ctr].CelUpdate = 2;
                        }
                    }
                    Sverb[theInpTab.HotIndex-8].CelCol = selcol;
                    Sverb[theInpTab.HotIndex-8].CelUpdate = 2;
                    MidVerb = theInpTab.HotIndex-8;
                    if ((TopNoun != MTPart) && (BotNoun != MTPart) && (PlayFlag == false))
                        LetPlay();
                    break;
                case 11:
                case 12:
                case 13:
                    for (ctr=3; ctr<6; ctr++) {
                        if (Snoun[ctr].CelCol == selcol) {
                            Snoun[ctr].CelCol = 0;
                            Snoun[ctr].CelUpdate = 2;
                        }
                    }
                    Snoun[theInpTab.HotIndex-8].CelCol = selcol;
                    Snoun[theInpTab.HotIndex-8].CelUpdate = 2;
                    SetIcon(theInpTab.HotIndex-8);
                    BotNoun = theInpTab.HotIndex-11; /* BotNoun is (0-2) */
                    if ((MidVerb != MTPart) && (TopNoun != MTPart) && (PlayFlag == false))
                        LetPlay();
                    break;
            }
        }
        last_xpos = inp_xpos;   /* xpos of input device */
        last_ypos = inp_ypos;   /* ypos of input device */
    }
    SceneTab[ScScene0] = 0; /* Remove these from the scene table */
    SceneTab[ScScene1] = 0; /* so that resolve wont mess with them */
    close_file(sbpkgfid); /* there should always be a package file open in scrn 1 */
}


/*
 * CheckHighLite - see if the cell colors of screen 1 need updating
 */
void CheckHighLite()
{
short   ctr;
Rect    highRect;

    /*
     * This (CheckHighLite) gets called after a call to "Step"
     * which causes swapflag to be cleared (to false)
     * The signal handler will set swapflag (to true) when the scan line interrupts occur
     * on scan line2. We probably want to wait for that to happen before we start
     * updating what we think is the rear screen.
     */

    while (!swapflag);
    /*
     * If we are in one of the nine noun/verb rectangles, set its
     * bkgd color to highcol (unless it's selected)
     */
    if ((theInpTab.HotIndex>=5) && (theInpTab.HotIndex<=7)) {
        if (Snoun[theInpTab.HotIndex-5].CelCol != selcol) {
            Snoun[theInpTab.HotIndex-5].CelCol = highcol;
            Snoun[theInpTab.HotIndex-5].CelUpdate = 2;
        }
    }
    if ((theInpTab.HotIndex>=8) && (theInpTab.HotIndex<=10)) {
        if (Sverb[theInpTab.HotIndex-8].CelCol != selcol) {
            Sverb[theInpTab.HotIndex-8].CelCol = highcol;
            Sverb[theInpTab.HotIndex-8].CelUpdate = 2;
        }
    }
    if ((theInpTab.HotIndex>=11) && (theInpTab.HotIndex<=13)) {
        if (Snoun[theInpTab.HotIndex-8].CelCol != selcol) {
            Snoun[theInpTab.HotIndex-8].CelCol = highcol;
            Snoun[theInpTab.HotIndex-8].CelUpdate = 2;
        }
    }
    /*
     * See if any cells need updating. If a cell is currently using
     * the highlite color, and its CelUpdate counter is zero, it means
     * that it's time to restore the original bkgd color (white).
     */
    for (ctr=0; ctr<6; ctr++) {
        if (Snoun[ctr].CelUpdate) { /* if CelUpdate != 0 */
            highRect.top = Snoun[ctr].WYpos;
            highRect.bottom = highRect.top + 14;
            highRect.left = 34;
            highRect.right = 248;
            Fill(highRect, Snoun[ctr].CelCol);
            Snoun[ctr].CelUpdate--;
            if ((Snoun[ctr].CelUpdate == 0) && (Snoun[ctr].CelCol == highcol)) {
                Snoun[ctr].CelCol = clearcol;
                Snoun[ctr].CelUpdate = 2;
            }
        }
    }

    for (ctr=0; ctr<3; ctr++) {
        if (Sverb[ctr].CelUpdate) { /* if CelUpdate != 0 */
            highRect.top = Sverb[ctr].WYpos;
            highRect.bottom = highRect.top + 14;
            highRect.left = 34;
            highRect.right = 248;
            Fill(highRect, Sverb[ctr].CelCol);
            Sverb[ctr].CelUpdate--;
            if ((Sverb[ctr].CelUpdate == 0) && (Sverb[ctr].CelCol == highcol)) {
                Sverb[ctr].CelCol = clearcol;
                Sverb[ctr].CelUpdate = 2;
            }
        }
    }
    drawwords();
}




/*
 * DoScrn2 - this is the main loop for screen2 of sentence builder.
 */
void DoScrn2()
{
Boolean         done;
long            delayT;     /* tick count to delay until after each animation */
short           theChan;

    SentNum = (TopNoun * 9) + (MidVerb * 3) + BotNoun; /* calculate the sentence index (0-26) */
    ChkRTF();           /* this will set 'useRTF' if there is a RTF for this sentence */
    AddVerbs();         /* Load the two sequences needed for screen2 */
    AddSound();         /* Load the three soundmaps and one FX needed for screen2 */

    ModMod = ModSent2d; /* scrn 2 - buttons down */
    FadeDown(meddisolve);

    if (useRTF)
        DoRTF();            /* start the rtf */
    else {
        MkScrn2();          /* Draw screen2 */
        MatteOn();          /* turn on the scrolling mattes */
        FadeUp(meddisolve, false); /* don't display cursor */

        /*
         * Set the background audio file for this sentence
         */
        switch (SBTunes[RezPtr->packData[SentNum].verbTune[WhichTune]].MCAFile) {
            case 0:
                TUNEfid = Tune3ID;
                break;
            case 1:
                TUNEfid = Tune4ID;
                break;
            case 2:
                TUNEfid = Tune5ID;
                break;
            default:
                STATUS1("Background tune file is OUT OF RANGE!!!!!\n");
                break;
        }
        theChan = SBTunes[RezPtr->packData[SentNum].verbTune[WhichTune]].MCAChan;
        if ((theChan > 15) || (theChan < 0)) {
            STATUS1("Background channel is OUT OF RANGE!!!!!\n");
        }
        WhichTune ++;   /* advance for next time */
        if (WhichTune == 3)
            WhichTune = 0;

        SaySent();
        SBScene->Active = true;
        MoveBut(true);                  /* move buttons down */

        start_bkgd_audio(theChan, TUNEfid, false);  /* start the bkgd tune */
        if (noun_smap) {
            stop_fx_alarm();        /* shut off the old alarm */
            start_soundmap(snd_array[6].smap_id);
            start_fx_alarm();
        }
    }

    currentT = clock();                             /* get current tick count */
#if 0
    reset_dim();        /* reset dim counter */
    reset_help();
#endif
    done = false;

    while (!done) {

        chk_help(7, BEARfid, 0, 0); /* no audio to restart */
        chk_dim();  /* if it's time to dim, this won't return until undim */

        if (fx_time) { /* Check for time to do sound effect */
            start_soundmap(snd_array[6].smap_id);
            fx_time = false;
        }

        if ((!eor_ctr) && (ModMod == ModSent2d)) {   /* Bkgd tune (or RTF) has ended - bring up the buttons */
            if (useRTF) {
                close_file(RTFfid);
                RTFctr--;
                if (!RTFctr) {
                    BeamMeUp();
                }
                else {
                    ReDoRTF();
                }
            }
            else
                BeamMeUp();
        }

        /*
         * numOfClicks == 0 means continuous animation, not something that reaches end of screen
         */
        if ((RezPtr->packData[SentNum].numOfClicks) && (!useRTF) && (ModMod == ModSent2d)) {
            if (SBScene->Frame > RezPtr->packData[SentNum].numOfClicks) {
                SBScene->Active = false;
                delayT = currentT + (CLK_TCK * 2);  /* 2 seconds */
                while ((currentT < delayT) && !theInpTab.ButPress)
                    CheckInput();

                theiSeq->Gen.IDisplay = false; /* stop displaying the first item */

                delayT = currentT + (CLK_TCK * 1);  /* 1 seconds */
                while ((currentT < delayT) && !theInpTab.ButPress)
                    CheckInput();
                ReinitScene(SBScene); /* this sets intial item to displayable */
                SBScene->Active = true;
#if 0
                if (noun_smap)
                    start_soundmap(snd_array[6].smap_id);
#endif
            }
        }

        if ((RezPtr->packData[SentNum].BkgdType) && (!useRTF) && (ModMod == ModSent2d)) /* BkgdType true = scrolling */
            CheckScroll(); /* see if time to intro/delete items */

        CheckInput();
        /*
         * If an action button is pressed, and the screen button strip is down,
         * bring the screen button strip up.
         */
        if ((ModMod == ModSent2d) && theInpTab.ButPress) {
            if (useRTF) {
                ss_abort(RTFfid);
                while(eor_ctr); /* gets cleared by signal handler for abort */
                close_file(RTFfid);
            }
            BeamMeUp();
        }
        else if (theInpTab.ButPress) {
            switch (theInpTab.HotIndex) {
                case 0: /* the Help button */
                    stop_all_audio();
                    start_bkgd_audio(7, BEARfid, false); /* pass channel number */
                    while ((theInpTab.HotIndex == 0) && (eor_ctr))
                        CheckInput();
                    stop_all_audio();
                    currentT = clock();         /* get current tick count */
                    reset_help();
                    break;
                case 1: /* the Speech button */
                    Cursor_Freeze();
                    changeSpch();
                    start_bkgd_audio(0, BUTTONfid, false); /* pass channel number */
                    while (eor_ctr);
                    set_bear_voice();
                    set_button_voice();
                    Cursor_Melt();
                    break;
                case 2: /* the Text button */
                    Cursor_Freeze();
                    if (text == English)
                        start_bkgd_audio(3, BUTTONfid, false); /* pass channel number */
                    if (text == Spanish)
                        start_bkgd_audio(1, BUTTONfid, false); /* pass channel number */
                    changeText();
                    NewSent(-1); /* no highlighting */
                    while (eor_ctr);
                    Cursor_Melt();
                    break;
                case 3: /* the Play button */
                    ModMod = ModSent2d;
                    cursor_hide();
                    if (useRTF) {
                        RTFctr = 3;     /* play each real time file three times */
                        ReDoRTF();      /* restart the rtf */
                    }
                    else {
                        SaySent();
                        MoveBut(true);      /* move buttons down */
                        start_bkgd_audio(theChan, TUNEfid, false);
                        if (noun_smap) {
                            stop_fx_alarm();        /* shut off the old alarm */
                            start_soundmap(snd_array[6].smap_id);
                            start_fx_alarm();
                        }
                        SBScene->Active = true;
                        if (RezPtr->packData[SentNum].BkgdType) { /* true means scrolling */
                            ScrlScene0->Active = true;
                            ScrlScene1->Active = true;
                        }
                    }
                    break;
                case 4: /* same old screen 1 */
                    ExitToOne();
                    done = true;
                    break;
                case 5: /* go to new package in screen 1 */
                    sbpctr++; /* increment for next package */
                    if (sbpctr == NumSBPkgs)
                        sbpctr = 0;
                    ExitToOne();
                    done = true;
                    break;
            }
        }
        last_xpos = inp_xpos;   /* xpos of input device */
        last_ypos = inp_ypos;   /* ypos of input device */
    }
}



/*
 * SaySent - Say the sentence
 */
void SaySent()
{

    NewSent(0); /* highlight initial noun */
    if (speech == English)
        start_soundmap(snd_array[0].smap_id);
    else
        start_soundmap(snd_array[1].smap_id);
    while(smap_busy);
    NewSent(1); /* highlight verb */
    if (speech == English)
        start_soundmap(snd_array[2].smap_id);
    else
        start_soundmap(snd_array[3].smap_id);
    while(smap_busy);
    NewSent(2); /* highlight final noun */
    if (speech == English)
        start_soundmap(snd_array[4].smap_id);
    else
        start_soundmap(snd_array[5].smap_id);
    while(smap_busy);
    NewSent(-1); /* no highlight */
}


/*
 * BeamMeUp - End screen 2 animation, sound and bring button strip up
 */
void BeamMeUp()
{

    if (!useRTF) {
        stop_fx_alarm();        /* shut off sound effect alarm */
        fx_time = false;
        stop_all_audio();
        SBScene->Active = false;
        ScrlScene0->Active = false;
        ScrlScene1->Active = false;
    }
#if 0
    reset_dim();
    reset_help();
#endif
    theRectPtr = &Sent2bRect;   /* set list of hotspots */
    MoveBut(false);             /* move buttons up */
    ModMod = ModSent2u;         /* screen2 - part2 (the buttons in the up position) */
    cursor_show();          /* display the cursor */
}


/*
 * ExitToOne - return to screen1
 */
void ExitToOne()
{
    ScrlScene0->Display = false;
    ScrlScene1->Display = false;
    SBScene->Display = false;
    newsbpkg();         /* should open same old package */
    /* set_bkgd_music(); */ /* set bkgd file back to old one */

    FadeDown(meddisolve);
    if (useRTF) {
        useRTF = false;
        RTFMatteOff();      /* remove RTF matte (window) */
        theLine = 0;        /* link vidmem0 to scan line 0 from now on */
        InitMatte();        /* copy scroll matte image to plane A */
    }
    else {
        MatteOff();         /* remove scrolling mattes */
    }
}


/*
 * newsbpkg - load one of the packages. Really open and play the first record.
 */
void newsbpkg()
{
Boolean         stat;

    DirNum = DirSave1; /* reset to # of things before a package was loaded */

    WhichSBPkg = sbptab[sbpctr];
    sbpkgfid = open_file(SBPkgTab[WhichSBPkg].PkgName, true);
    if (sbpkgfid == -1) {
        STATUS1("had trouble opening a package - will try next\n");
        sbpctr++; /* increment for next package */
        if (sbpctr == NumSBPkgs)
            sbpctr = 0;
        WhichSBPkg = sbptab[sbpctr];
        sbpkgfid = open_file(SBPkgTab[WhichSBPkg].PkgName, false);
    }
    stat = play_recs(sbpkgfid, set_sbpkg1_pcls, 1, false, false, 0);

    STATUS2("Package %s\n", SBPkgTab[WhichSBPkg].PkgName);

    InitScrn1();
}


/*
 * InitScrn1 - setup/reset the icons for screen 1
 */
void InitScrn1()
{
short       ctr;
Ptr         thePtr;
short       i, initStat, relXOff, relYOff;
ItemSeqPtr  theSeq;     /* the sequence item table */
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */
short       midx, midy; /* center of icon box */

    SBPkgData = stuffpkg(PkgBuf); /* stuffpkg returns a ptr to data section (past header) */
    SBScene->NumItems = 6;
    ScrlScene0->NumItems = 0;
    ScrlScene1->NumItems = 0;
    /*
     * The first six entries in the package are really
     * sub packages of sequences and their states.
     * Each of these should probably be stuffed individually
     * Each sequence should probably be assigned to an
     * item table in the scene as well.
     */
    for (ctr = 0; ctr < SBScene->NumItems; ctr ++) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[ctr].Where);
        stuffpkg(thePtr);
        thePtr += 2; /* skip the "# of things in pkg" word */
        strcpy(SBScene->ItemDir[ctr].Who, thePtr); /* first entry is always seq name */
    }
    /*
     * This call to SetUpScene is needed here to link the shapes to their
     * sequences. Without it the icons wouldn't be centered in their boxes
     */
    SetUpScene(MScene);
    /*
     * Center the icons in their little boxes and initialize them
     */
    for (ctr=0; ctr<6; ctr++) {
        theSeq = (ItemSeqPtr) ((unsigned)SBScene + (unsigned)SBScene->ItemDir[ctr].Where);
        theSeq->Gen.IIDisplay = theSeq->Gen.IDisplay = false;
        theSeq->Cyc.IICycEnable = theSeq->Cyc.ICycEnable = true;
        theSeq->Cyc.IICycle = theSeq->Cyc.ICycle = 0;   /* cycle rate delay value */
        theSeq->Pos.IIVelEnable = theSeq->Pos.IVelEnable = false;

        theSeqDF = theSeq->Cyc.ISeqPtr;
        theShp = theSeqDF->SeqTab[theSeq->Cyc.IIState].StateIA;
        if (ctr < 3) /* top icon box */
            midy = 56;
        else
            midy = 136;
        midx = 305;
        theSeq->Pos.IBaseX = theSeq->Pos.IIBaseX = midx - (theShp->NumWide)/2;
        theSeq->Pos.IBaseY = theSeq->Pos.IIBaseY = midy - (theShp->NumHigh)/2;
        /*
         * Adjust the state offsets so that the first offset is 0,0
         */
        initStat= theSeq->Cyc.IIState;
        relXOff= theSeqDF->SeqTab[initStat].StateXOff;
        relYOff= theSeqDF->SeqTab[initStat].StateYOff;
        for (i = 0; i < theSeqDF->SeqNumSt; i++) {
            if (i == initStat){
                theSeqDF->SeqTab[i].StateXOff= 0;
                theSeqDF->SeqTab[i].StateYOff= 0;
            }
            else{
                theSeqDF->SeqTab[i].StateXOff-= relXOff;
                theSeqDF->SeqTab[i].StateYOff-= relYOff;
            }
        }
    }
    SBScene->Active = SBScene->Display = true;
    ScrlScene0->Active = ScrlScene0->Display = false;
    ScrlScene1->Active = ScrlScene1->Display = false;

    currentT = clock();         /* get current tick count */
#if 0
    reset_dim();
    reset_help();
#endif
    DirSave2 = DirNum; /* save # of things before screen 2 stuff is added */

    /*
     * This reinits all word cell colors to white (unselected)
     */
    for (ctr = 0; ctr < SBScene->NumItems; ctr ++)
        Snoun[ctr].CelCol = clearcol; /* Clear the cell color */
    Sverb[0].CelCol = clearcol; /* clear the verb cell colors as well */
    Sverb[1].CelCol = clearcol;
    Sverb[2].CelCol = clearcol;
    /*
     * These three flags hold the indexes (or MTPart for "clear")
     * of each selected sentence part.
     */
    TopNoun = MidVerb = BotNoun = MTPart;
    PlayFlag = false; /* disable the play button */
}



/*
 * SetIcon - Pass this the noun index number (0-5) to activate
 */
void SetIcon(index)
    short index;
{
ItemSeqPtr  theSeq;

    if (index <3) { /* disable the display flag of all three top items */
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[0].Where);
        theSeq->Gen.IDisplay = false;
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[1].Where);
        theSeq->Gen.IDisplay = false;
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[2].Where);
        theSeq->Gen.IDisplay = false;
    }
    else { /* disable the display flag of all three bottom items */
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[3].Where);
        theSeq->Gen.IDisplay = false;
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[4].Where);
        theSeq->Gen.IDisplay = false;
        theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[5].Where);
        theSeq->Gen.IDisplay = false;
    }
    theSeq = (ItemSeqPtr)((unsigned)SBScene + (unsigned)SBScene->ItemDir[index].Where);
    theSeq->Gen.IDisplay = true;
}





/*
 * Play the second record of the rtf. First set the channel selection
 * mask and the PCLs for the two sequence channels that we need.
 * This is also going to play channel 20 so as to position
 * the file pointer past all sequence channels.
 */
void AddVerbs()
{
TOCPtr      theSeqTOC;
SeqPtr      theSeqDF;   /* the sequence disk file */
ShapePtr    theShp;     /* shape disk file */
short       i, initStat, relXOff, relYOff;
Boolean         stat;


    DirNum = DirSave2; /* reset to # of things before a screen 2 package was loaded */
    SBScene->NumItems = 2; /* just the first two items are needed for screen 2 */

    set_sbpkg2_pcls(TopNoun * 3 + MidVerb, BotNoun * 3 + 9 + MidVerb);
    stat = play_recs(sbpkgfid, 0, 3, false, false, 0);

    if (useRTF) {
        SBScene->Active = SBScene->Display = false; /* InitScrn1 will turn this back on */
        return;
    }
    /*
     * Now link the verbs to the scene.
     */
    stuffpkg(Seq1Buf); /* Add contents of sequence packages to mfxDir */
    stuffpkg(Seq2Buf);


    if (RezPtr->packData[SentNum].revFlg) {
        theSeqTOC = (TOCPtr)Seq1Buf; /* point at table of contents of first sequence 'package' */
        strcpy(SBScene->ItemDir[1].Who, theSeqTOC->TE[0].Who); /* first entry is always seq name */
        theSeqTOC = (TOCPtr)Seq2Buf; /* point at table of contents of second sequence 'package' */
        strcpy(SBScene->ItemDir[0].Who, theSeqTOC->TE[0].Who); /* first entry is always seq name */
        theiSeq = (ItemSeqPtr) ((unsigned)SBScene + (unsigned)SBScene->ItemDir[1].Where);
        thefSeq = (ItemSeqPtr) ((unsigned)SBScene + (unsigned)SBScene->ItemDir[0].Where);
    }
    else {
        theSeqTOC = (TOCPtr)Seq1Buf; /* point at table of contents of first sequence 'package' */
        strcpy(SBScene->ItemDir[0].Who, theSeqTOC->TE[0].Who); /* first entry is always seq name */
        theSeqTOC = (TOCPtr)Seq2Buf; /* point at table of contents of second sequence 'package' */
        strcpy(SBScene->ItemDir[1].Who, theSeqTOC->TE[0].Who); /* first entry is always seq name */
        theiSeq = (ItemSeqPtr) ((unsigned)SBScene + (unsigned)SBScene->ItemDir[0].Where);
        thefSeq = (ItemSeqPtr) ((unsigned)SBScene + (unsigned)SBScene->ItemDir[1].Where);
    }
    SetUpScene(MScene); /* call this to get the shapes linked to their sequences */

    theSeqDF = theiSeq->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[theiSeq->Cyc.IIState].StateIA;
    theiSeq->Pos.IIBaseX = BkgdRect.left + RezPtr->packData[SentNum].iNounXPos -1;
    theiSeq->Pos.IIBaseY = BkgdRect.top + RezPtr->packData[SentNum].iNounYPos - (theShp->NumHigh);
    theiSeq->Pos.IIXVel = RezPtr->packData[SentNum].iNounXVel;
    theiSeq->Pos.IIYVel = RezPtr->packData[SentNum].iNounYVel;
    theiSeq->Pos.IIXAcc = RezPtr->packData[SentNum].iNounXAcc;
    theiSeq->Pos.IIYAcc = RezPtr->packData[SentNum].iNounYAcc;
    theiSeq->Pos.IIXVelFin = RezPtr->packData[SentNum].iNounXFinalVel;
    theiSeq->Pos.IIYVelFin = RezPtr->packData[SentNum].iNounYFinalVel;
    theiSeq->Cyc.IICycEnable = RezPtr->packData[SentNum].iNounCycEnable;
    theiSeq->Cyc.IICycle = RezPtr->packData[SentNum].iNounCycRate + 1;
    theiSeq->Pos.IIVelEnable = true;
    theiSeq->Gen.IIDisplay = true;
    theiSeq->Gen.IIActive = true;

    initStat= theiSeq->Cyc.IIState;
    relXOff= theSeqDF->SeqTab[initStat].StateXOff;
    relYOff= theSeqDF->SeqTab[initStat].StateYOff;
    for (i = 0; i < theSeqDF->SeqNumSt; i++) {
        if (i == initStat){
            theSeqDF->SeqTab[i].StateXOff= 0;
            theSeqDF->SeqTab[i].StateYOff= 0;
        }
        else{
            theSeqDF->SeqTab[i].StateXOff-= relXOff;
            theSeqDF->SeqTab[i].StateYOff-= relYOff;
        }
    }

    theSeqDF = thefSeq->Cyc.ISeqPtr;
    theShp = theSeqDF->SeqTab[thefSeq->Cyc.IIState].StateIA;
    thefSeq->Pos.IIBaseX = BkgdRect.left + RezPtr->packData[SentNum].fNounXPos -1;
    thefSeq->Pos.IIBaseY = BkgdRect.top + RezPtr->packData[SentNum].fNounYPos - (theShp->NumHigh);
    thefSeq->Pos.IIXVel = RezPtr->packData[SentNum].fNounXVel;
    thefSeq->Pos.IIYVel = RezPtr->packData[SentNum].fNounYVel;
    thefSeq->Pos.IIXAcc = RezPtr->packData[SentNum].fNounXAcc;
    thefSeq->Pos.IIYAcc = RezPtr->packData[SentNum].fNounYAcc;
    thefSeq->Pos.IIXVelFin = RezPtr->packData[SentNum].fNounXFinalVel;
    thefSeq->Pos.IIYVelFin = RezPtr->packData[SentNum].fNounYFinalVel;
    thefSeq->Cyc.IICycEnable = RezPtr->packData[SentNum].fNounCycEnable;
    thefSeq->Cyc.IICycle = RezPtr->packData[SentNum].fNounCycRate + 1;
    thefSeq->Pos.IIVelEnable = true;
    thefSeq->Gen.IIDisplay = true;
    thefSeq->Gen.IIActive = true;

    initStat= thefSeq->Cyc.IIState;
    relXOff= theSeqDF->SeqTab[initStat].StateXOff;
    relYOff= theSeqDF->SeqTab[initStat].StateYOff;
    for (i = 0; i < theSeqDF->SeqNumSt; i++) {
        if (i == initStat){
            theSeqDF->SeqTab[i].StateXOff= 0;
            theSeqDF->SeqTab[i].StateYOff= 0;
        }
        else{
            theSeqDF->SeqTab[i].StateXOff-= relXOff;
            theSeqDF->SeqTab[i].StateYOff-= relYOff;
        }
    }

    ReinitScene(SBScene); /* move initial values to current values */
    SBScene->Active = false; /* turn this off until after sentence is read */
}


/*
 * Play the third record of the rtf. First set the channel selection
 * mask and the PCLs for the 4 smap channels that we need.
 */
void AddSound()
{
short   ch0;
short   ch1;
short   ch2;
short   ch3;
short   ch4;
short   ch5;
short   ch6;
Boolean combine = false;
Boolean         stat;
SoundmapDesc    *sm_ptr;

    /*
     * Clear the soundmap buffers
     */
    memset (snd_array[0].data, 0, SBNounGrpSize * 128);
    memset (snd_array[1].data, 0, SBNounGrpSize * 128);
    memset (snd_array[2].data, 0, SBVerbGrpSize * 128);
    memset (snd_array[3].data, 0, SBVerbGrpSize * 128);
    memset (snd_array[4].data, 0, SBNounGrpSize * 128);
    memset (snd_array[5].data, 0, SBNounGrpSize * 128);
    memset (snd_array[6].data, 0, SBFXGrpSize * 128);
    /*
     * See if the Spanish verb and final noun are combined.
     */
    if (RezPtr->fNoun[BotNoun].SPrep == 4) { /* 4 = "el" */
        if ((RezPtr->verb[MidVerb].Suffix == 7) || (RezPtr->verb[MidVerb].Suffix == 8))
            combine = true;
    }
    ch0 = TopNoun;          /* English initial noun */
    ch1 = TopNoun + 3;      /* Spanish initial noun */
    ch2 = MidVerb + 6;      /* English verb */
    ch3 = MidVerb + 9;      /* Spanish verb */
    if (combine)
        ch3 += 3;

    ch4 = BotNoun;          /* English final noun */
    ch5 = BotNoun + 3;      /* Spanish final noun */
    if (combine)
        ch5 += 3;
    ch6 = TopNoun + 9;      /* sound effect */

    set_sbpkg3_pcls(ch0, ch1, ch2, ch3);
    stat = play_recs(sbpkgfid, 0, 5, false, false, 0); /* inlude the extra eor for the bookmark */
    /*
     * Adjust the soundmaps for the true size of the data just loaded
     */
    sm_ptr = sm_info(audpath, snd_array[0].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[0]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[1].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[1]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[2].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[2]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[3].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[3]->PCL_Cnt / 128;

    set_sbpkg4_pcls(ch4, ch5, ch6);
    stat = play_recs(sbpkgfid, 0, 3, false, false, 0);
    stat = close_file(sbpkgfid);
    /*
     * Adjust the soundmaps for the true size of the data just loaded
     */
    sm_ptr = sm_info(audpath, snd_array[4].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[0]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[5].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[1]->PCL_Cnt / 128;
    sm_ptr = sm_info(audpath, snd_array[6].smap_id);
    sm_ptr->smd_nogrps = pcl_tab[2]->PCL_Cnt / 128;
    if (sm_ptr->smd_nogrps == 18) /* silence */
        noun_smap = false;
    else
        noun_smap = true;
}



/*
 * MkScrn1 - Build sentence builder screen 1. This code gets called either when
 *          the user is viewing screen2 or the last frame of the real time intro file.
 *
 * When coming here, the 6 nouns and 3 verbs should already be selected.
 *
 * pass 'buts' wether or not to do new buttons as well
 */
void MkScrn1(buts)
    Boolean buts;
{
Ptr         thePtr;
Ptr         scnptrsav;

/*
 * Save original contents and then set scn_ptr to bkgd scrn
 * (most drawing happens at scn_ptr)
 */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;
/*
 * First, draw the five boxes on the background screen
 */
    FilCol = 96;
    Fill(fullRect, FilCol); /* fill entire bkgd screen */
    thePtr = mfxDir[getind("slots.shp")].Where;
    Draw((ShapePtr)thePtr, 33, 21); /* draw the shape */
    Draw((ShapePtr)thePtr, 33, 73); /* draw the shape */
    Draw((ShapePtr)thePtr, 33, 125); /* draw the shape */
    thePtr = mfxDir[getind("topbox.shp")].Where;
    Draw((ShapePtr)thePtr, 256, 21); /* draw the shape */
    thePtr = mfxDir[getind("botbox.shp")].Where;
    Draw((ShapePtr)thePtr, 256, 101); /* draw the shape */
    /*
     * This draws the nine words/phrases in the
     * proper language (still at scn_ptr = bkgd)
     */
    drawwords();

    scn_ptr = scnptrsav; /* restore scn_ptr */
    if (buts)
        NoButs(); /* unlink old button strip */
    /*
     * copy to rear screen, swap, and copy to new rear screen
     */
    copy_bkgd_front();

    if (buts)
        MkSentBut();    /* make the buttons for screen 1 */
}


/*
 * drawwords - this draws the 9 words/phrases
 */
void drawwords()
{
    DrawWord0();
    DrawWord1();
    DrawWord2();
    DrawWord3();
    DrawWord4();
    DrawWord5();
    DrawWord6();
    DrawWord7();
    DrawWord8();
}

/*
 * DrawWord0 - draw initial noun 0
 */
void DrawWord0()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->iNoun[0].EPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[0].EPrep].BImage,nounX,Snoun[0].WYpos
                + artTab[RezPtr->iNoun[0].EPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[0].EPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[6].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[0].WYpos + yTab[RezPtr->iNoun[0].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->iNoun[0].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[0].SPrep].BImage,nounX,Snoun[0].WYpos
                + artTab[RezPtr->iNoun[0].SPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[0].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[15].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[0].WYpos + yTab[RezPtr->iNoun[0].idx].Syoff);
    }
}

/*
 * DrawWord1 - draw initial noun 1
 */
void DrawWord1()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->iNoun[1].EPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[1].EPrep].BImage,nounX,Snoun[1].WYpos
                + artTab[RezPtr->iNoun[1].EPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[1].EPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[7].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[1].WYpos + yTab[RezPtr->iNoun[1].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->iNoun[1].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[1].SPrep].BImage,nounX,Snoun[1].WYpos
                + artTab[RezPtr->iNoun[1].SPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[1].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[16].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[1].WYpos + yTab[RezPtr->iNoun[1].idx].Syoff);
    }
}

/*
 * DrawWord2 - draw initial noun 2
 */
void DrawWord2()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->iNoun[2].EPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[2].EPrep].BImage,nounX,Snoun[2].WYpos
                + artTab[RezPtr->iNoun[2].EPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[2].EPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[8].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[2].WYpos + yTab[RezPtr->iNoun[2].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->iNoun[2].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[2].SPrep].BImage,nounX,Snoun[2].WYpos
                + artTab[RezPtr->iNoun[2].SPrep].Byoff);
            nounX += (artTab[RezPtr->iNoun[2].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[17].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[2].WYpos + yTab[RezPtr->iNoun[2].idx].Syoff);
    }
}

/*
 * DrawWord3 - draw verb 0
 */
void DrawWord3()
{
Ptr     thePtr;

    if (text == English) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[9].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[0].WYpos + VyTab[RezPtr->verb[0].idx].Eyoff);
    }
    if (text == Spanish) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[18].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[0].WYpos + VyTab[RezPtr->verb[0].idx].Syoff);
    }
}

/*
 * DrawWord4 - draw verb 1
 */
void DrawWord4()
{
Ptr     thePtr;

    if (text == English) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[10].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[1].WYpos + VyTab[RezPtr->verb[1].idx].Eyoff);
    }
    if (text == Spanish) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[19].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[1].WYpos + VyTab[RezPtr->verb[1].idx].Syoff);
    }
}

/*
 * DrawWord5 - draw verb 2
 */
void DrawWord5()
{
Ptr     thePtr;

    if (text == English) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[11].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[2].WYpos + VyTab[RezPtr->verb[2].idx].Eyoff);
    }
    if (text == Spanish) {
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[20].Where);
        Draw((ShapePtr)thePtr,strtNX,Sverb[2].WYpos + VyTab[RezPtr->verb[2].idx].Syoff);
    }
}

/*
 * DrawWord6 - draw final noun 0
 */
void DrawWord6()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->fNoun[0].EPrep == 2) { /* the */
            Draw((ShapePtr)artTab[2].BImage,nounX,Snoun[3].WYpos + artTab[2].Byoff);
            nounX += (artTab[2].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[12].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[3].WYpos + yTab[RezPtr->fNoun[0].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->fNoun[0].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->fNoun[0].SPrep].BImage,nounX,Snoun[3].WYpos
                + artTab[RezPtr->fNoun[0].SPrep].Byoff);
            nounX += (artTab[RezPtr->fNoun[0].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[21].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[3].WYpos + yTab[RezPtr->fNoun[0].idx].Syoff);
    }
}

/*
 * DrawWord7 - draw final noun 1
 */
void DrawWord7()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->fNoun[1].EPrep == 2) { /* the */
            Draw((ShapePtr)artTab[2].BImage,nounX,Snoun[4].WYpos + artTab[2].Byoff);
            nounX += (artTab[2].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[13].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[4].WYpos + yTab[RezPtr->fNoun[1].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->fNoun[1].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->fNoun[1].SPrep].BImage,nounX,Snoun[4].WYpos
                + artTab[RezPtr->fNoun[1].SPrep].Byoff);
            nounX += (artTab[RezPtr->fNoun[1].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[22].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[4].WYpos + yTab[RezPtr->fNoun[1].idx].Syoff);
    }
}

/*
 * DrawWord8 - draw final noun 2
 */
void DrawWord8()
{
short   nounX;
Ptr     thePtr;

    if (text == English) {
        nounX = strtNX;
        if  (RezPtr->fNoun[2].EPrep == 2) { /* the */
            Draw((ShapePtr)artTab[2].BImage,nounX,Snoun[5].WYpos + artTab[2].Byoff);
            nounX += (artTab[2].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[14].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[5].WYpos + yTab[RezPtr->fNoun[2].idx].Eyoff);
    }
    if (text == Spanish) {
        nounX = strtNX;
        if  (RezPtr->fNoun[2].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->fNoun[2].SPrep].BImage,nounX,Snoun[5].WYpos
                + artTab[RezPtr->fNoun[2].SPrep].Byoff);
            nounX += (artTab[RezPtr->fNoun[2].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[23].Where);
        Draw((ShapePtr)thePtr,nounX,Snoun[5].WYpos + yTab[RezPtr->fNoun[2].idx].Syoff);
    }
}



/*
 * MkScrn2 - Build sentence builder screen2. This code gets called only when
 *          the user is viewing screen1.
 *
 */
void MkScrn2()
{
Ptr         thePtr;
Ptr         scnptrsav;

    /*
     * fill the bkgd screen then draw the huge box
     */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;
    FilCol = 96;
    Fill(fullRect, FilCol); /* erase bkgd with same color as already there */
    thePtr = mfxDir[getind("hugebox.shp")].Where;
    Draw((ShapePtr)thePtr, 33, 21); /* draw the huge box shape */

    if (!useRTF)
        DrawBkgd();         /* generate the bkgd image in the huge box */

    drawsent(); /* Print the sentence in the upper box */

    scn_ptr = scnptrsav; /* restore scn_ptr */
    NoButs(); /* unlink old button strip */
    /*
     * copy to rear screen, swap, and copy to new rear screen
     */
    copy_bkgd_front();

    MkSentBut(); /* make buttons for screen 2 */
}


/*
 * NewSent - call this to redraw just the sentence window of screen 2
 */
void NewSent(highword)
    short highword;
{
Ptr         scnptrsav;

    /*
     * fill the sentence window
     */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;
    Fill(sentRect, 0); /* fill sentence rectangle with white */
    switch(highword) {
        case 0:
            Fill(iNounRect, selcol);
            break;
        case 1:
            Fill(VerbRect, selcol);
            break;
        case 2:
            Fill(fNounRect, selcol);
            break;
        default:
            break;
    }
    drawsent(); /* Print the sentence in the upper box */
    scn_ptr = scnptrsav; /* restore scn_ptr */
    /*
     * copy to rear screen, swap, and copy to new rear screen
     */
    copy_bkgd_front();
}


/*
 * drawsent - this draws the sentence on screen 2 (in the upper box)
 */
void drawsent()
{
short       sentX;
short       sentY;
ShapePtr    theShape;
Boolean     skipLast;   /* if the Spanish verb phrase "sucks up" the final "el" */
Ptr         thePtr;

    sentX = strtNX;
    sentY = 23;

    iNounRect.left = sentX -2;
    iNounRect.top = sentY;
    if (text == English) {
        if  (RezPtr->iNoun[TopNoun].EPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[TopNoun].EPrep].BImage, sentX,
                 sentY + artTab[RezPtr->iNoun[TopNoun].EPrep].Byoff);
            sentX += (artTab[RezPtr->iNoun[TopNoun].EPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[TopNoun+6].Where);
        Draw((ShapePtr)thePtr,sentX,sentY + yTab[RezPtr->iNoun[TopNoun].idx].Eyoff);
        /*
         * Add the width of the noun shape, plus the standard between word space (spcNX).
         */
        theShape = (ShapePtr)thePtr;
        sentX += (*theShape).NumWide + spcNX;
        iNounRect.right = sentX +2 - spcNX;
        iNounRect.bottom = sentY +15;
        /*
         * Let's see if the verb phrase fits on this line.
         */
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[MidVerb+9].Where);
        theShape = (ShapePtr)thePtr;
        if ((sentX + (*theShape).NumWide) > maxsentX) {
            sentX = strtNX;
            sentY = sentY + spcNY;
        }
        /*
         * We are now in position to draw verb phrase.
         */
        VerbRect.left = sentX -2;
        VerbRect.top = sentY;
        Draw((ShapePtr)thePtr,sentX,sentY + VyTab[RezPtr->verb[MidVerb].idx].Eyoff);
        sentX += (*theShape).NumWide + spcNX;   /* Width of verb phrase added */
        VerbRect.right = sentX +2 - spcNX;
        VerbRect.bottom = sentY +15;


        /*
         * We might as well see if we can fit the final noun on the same line.
         */
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[BotNoun+12].Where);
        theShape = (ShapePtr)thePtr;
        if ((sentX + (*theShape).NumWide) > maxsentX) {
            sentX = strtNX;
            sentY = sentY + spcNY;
        }
        /*
         * We are now in position to draw the final noun.
         * First we have to draw the "the" (usually)
         */
        fNounRect.left = sentX -2;
        fNounRect.top = sentY;
        if  (RezPtr->fNoun[BotNoun].EPrep) {
            Draw((ShapePtr)artTab[RezPtr->fNoun[BotNoun].EPrep].BImage, sentX,
                 sentY + artTab[RezPtr->fNoun[BotNoun].EPrep].Byoff);
            sentX += (artTab[RezPtr->fNoun[BotNoun].EPrep].Bwdth + spcNX);
        }

        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[BotNoun+12].Where);
        theShape = (ShapePtr)thePtr;
        Draw((ShapePtr)thePtr,sentX,sentY + yTab[RezPtr->fNoun[BotNoun].idx].Eyoff);
        sentX += (*theShape).NumWide + spcNX;
        fNounRect.right = sentX +2 - spcNX;
        fNounRect.bottom = sentY +15;
    }

    if (text == Spanish) {
        skipLast = false;   /* As of now we will include the el/la for final noun */
        /*
         * The initial noun is preceeded by an El,La, or nothing
         */
        if (RezPtr->iNoun[TopNoun].SPrep) {
            Draw((ShapePtr)artTab[RezPtr->iNoun[TopNoun].SPrep].BImage, sentX,
                sentY + artTab[RezPtr->iNoun[TopNoun].SPrep].Byoff);
            sentX += (artTab[RezPtr->iNoun[TopNoun].SPrep].Bwdth + spcNX);
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[TopNoun+15].Where);
        Draw((ShapePtr)thePtr,sentX,sentY + yTab[RezPtr->iNoun[TopNoun].idx].Syoff);
        /*
         * Add the width of the noun shape, plus the standard between word space (spcNX).
         */
        theShape = (ShapePtr)thePtr;
        sentX += (*theShape).NumWide + spcNX;
        iNounRect.right = sentX +2 - spcNX;
        iNounRect.bottom = sentY +15;
        /*
         * Let's see if the verb phrase fits on this line.
         */
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[MidVerb+18].Where);
        theShape = (ShapePtr)thePtr;
        if ((sentX + (*theShape).NumWide) > maxsentX) {
            sentX = strtNX;
            sentY = sentY + spcNY;
        }
        /*
         * We are now in position to draw verb phrase.
         */
        VerbRect.left = sentX -2;
        VerbRect.top = sentY;
        Draw((ShapePtr)thePtr,sentX,sentY + VyTab[RezPtr->verb[MidVerb].idx].Syoff);
        sentX += (*theShape).NumWide + spcNX;   /* Width of verb phrase added (for now) */
        /*
         * Here's the semi-tricky part.  If the verb ends with "de", and the
         * final noun begins with "el", an "el" shape must be positioned so that
         * the "e"s from the "de" and "el" "are one".  The final noun would then
         * be drawn after the "del", or even on the next line if necessary.
         *
         * The same bit of trickery applies to verbs ending in "a" combined
         * with "el" starting final nouns. The "a" becomes "al".
         *
         * I guess the first thing to check is if the final noun starts with "el"
         */
        if (RezPtr->fNoun[BotNoun].SPrep == 4) { /* 4 = "el" */
            switch (RezPtr->verb[MidVerb].Suffix) {
                case 7: /* ends in "de", backspace and draw the "el" shape */
                    sentX -= (7 + spcNX);
                    Draw((ShapePtr)artTab[4].BImage,sentX,sentY + artTab[4].Byoff);
                    sentX += (artTab[4].Bwdth + spcNX);
                    skipLast = true;
                    break;
                case 8: /* ends in "a", backspace and draw the "al" shape */
                    sentX -= (7 + spcNX);
                    Draw((ShapePtr)artTab[8].BImage,sentX,sentY + artTab[8].Byoff);
                    sentX += (artTab[8].Bwdth + spcNX);
                    skipLast = true;
                    break;
                default:
                    break;
            }
        }
        VerbRect.right = sentX +2 - spcNX;
        VerbRect.bottom = sentY +15;
        /*
         * We might as well see if we can fit the final noun on the same line.
         */
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[BotNoun+21].Where);
        theShape = (ShapePtr)thePtr;
        if ((sentX + (*theShape).NumWide) > maxsentX) {
            sentX = strtNX;
            sentY = sentY + spcNY;
        }
        /*
         * We are now in position to draw the final noun.
         * See if we need an "el" or "la".
         */
        fNounRect.left = sentX -2;
        fNounRect.top = sentY;
        if (!skipLast) {

            if (RezPtr->fNoun[BotNoun].SPrep) {
                Draw((ShapePtr)artTab[RezPtr->fNoun[BotNoun].SPrep].BImage, sentX,
                    sentY + artTab[RezPtr->fNoun[BotNoun].SPrep].Byoff);
                sentX += (artTab[RezPtr->fNoun[BotNoun].SPrep].Bwdth + spcNX);
            }
        }
        thePtr = (Ptr) ((unsigned)SBPkgData + (unsigned)pkgTOC->TE[BotNoun+21].Where);
        theShape = (ShapePtr)thePtr;
        Draw((ShapePtr)thePtr,sentX,sentY + yTab[RezPtr->fNoun[BotNoun].idx].Syoff);
        sentX += (*theShape).NumWide + spcNX;
        fNounRect.right = sentX +2 - spcNX;
        fNounRect.bottom = sentY +15;
    }
    Draw((ShapePtr)perPtr,sentX -3,sentY + 8); /* don't forget the period */
}


/*
 * DoRTF - Play one of the little rtf's in the middle of the screens in Plane A
 *         Let the sentence window and button strip show through from Plane B
 */
void DoRTF()
{
int     stat;

    theLine = rtfline;
    RTFctr = 3;     /* play each real time file three times */

    RTFfid = open_file(RTFName, false);

    stat = play_recs(RTFfid, reinit_rtf, 1, false, false, 0); /* play first frame and return */

    MkScrn2();          /* Draw screen2 */
    RTFMatteOn();       /* turn on the middle 140 scan lines of plane A */
    /*
     * make sure the matte instructions are in effect before fading up the screen
     */
    swapflag = false;   /*  scan line interrupt will set to allow next frame */
    dc_ssig(vidpath,SLI_SIGNAL,0); /* set for next scan line interrupt */
    while (!swapflag);

    FadeUp(meddisolve, false);

    SaySent();          /* say the sentence */
    MoveBut(true);      /* move buttons down */

    stat = play_recs(RTFfid, reinit_rtf, 1, true, false, 0); /* start play rest of file */

    /*
     * This continues in the main loop of screen 2 code
     */
}

/*
 * ReDoRTF - Play one of the little rtf's in the middle of the screens in Plane A
 *         Let the sentence window and button strip show through from Plane B
 */
void ReDoRTF()
{
int     stat;

    RTFfid = open_file(RTFName, false);
    stat = play_recs(RTFfid, reinit_rtf, 1, false, false, 0); /* play first frame and return */

    if (RTFctr == 3) {
        SaySent();          /* say the sentence */
        MoveBut(true);      /* move buttons down */
    }

    stat = play_recs(RTFfid, reinit_rtf, 1, true, false, 0); /* start play rest of file */
    /*
     * This continues in the main loop of screen 2 code
     */
}



/*
 * ChkRTF - this checks to see if an rtf exists for the sentence to display
 */
void ChkRTF()
{

    useRTF = false;

    if (SentNum == SBPkgTab[WhichSBPkg].RTFNum0) {
        RTFName = (char *)SBPkgTab[WhichSBPkg].RTFName0;
        useRTF = true;
    }
    if (SentNum == SBPkgTab[WhichSBPkg].RTFNum1) {
        RTFName = (char *)SBPkgTab[WhichSBPkg].RTFName1;
        useRTF = true;
    }
}

/*
 * DrawBkgd - This is the code that generates the backgrounds
 *          used for Sentence Builder.
 */

void DrawBkgd()
{
Rect        theRect;
SBBkgdPtr   BkgdRez;
short       BkgdStripID;
short       BkgdID;

    BkgdID = (RezPtr->packData[SentNum].BkgdVer[WhichBkgd]) - 1;
    STATUS2("BkgdID = %d\n", BkgdID);
    WhichBkgd ^= 1; /* toggle for next time */
    /*
     * Get the bkgd type (scroll, static)
     */
    if (RezPtr->packData[SentNum].BkgdType) { /* true means scrolling */
        initScroll();
    }
    else { /* non-scrolling background */
        /*
         * Point at the resource for this background
         */
        if (BkgdID <= 139)
            BkgdRez = BGPtr0;
        else {
            BkgdRez = BGPtr1;
            BkgdID -= 140;
        }
        if (BkgdRez->stripID[BkgdID].dividingYPos == 0) {
            theRect = BkgdRect; /* first set the rectangle to the entire window */
            Fill(theRect, BkgdRez->stripID[BkgdID].topColor);
        }
        else {
            if (BkgdRez->stripID[BkgdID].dividingYPos != -1) {
                theRect = BkgdRect; /* first set the rectangle to the entire window */
                theRect.bottom = theRect.top + BkgdRez->stripID[BkgdID].dividingYPos;
                Fill(theRect, BkgdRez->stripID[BkgdID].topColor);
                /*
                 * Do the bottom color
                 */
                theRect = BkgdRect; /* reset the rectangle to the entire window */
                theRect.top = theRect.top + BkgdRez->stripID[BkgdID].dividingYPos;
                Fill(theRect, BkgdRez->stripID[BkgdID].bottomColor);
                /*
                 * draw a horizon line
                 */
                theRect = BkgdRect; /* reset the rectangle to the entire window */
                theRect.top = theRect.top + BkgdRez->stripID[BkgdID].dividingYPos;
                theRect.bottom = theRect.top +1;
                Fill(theRect, 127);
            }
        }
        /*
         * Load the background strip (maybe)
         * Draw it if there is one.
         * Otherwise draw a horizon line.
         */
        BkgdStripID = BkgdRez->stripID[BkgdID].stripIdx;
        if (BkgdStripID) {
            BkgdStripID--; /* to make index start at 0 */
            loadOne(bkgdfid, BGTOC, BkgdStripID, BkgdBuf);
            Draw((ShapePtr)BkgdBuf, BkgdRect.left -1, BkgdRect.top -1 + BkgdRez->stripID[BkgdID].stripYpos);
        }
    }
}


/*
 * initScroll - This sets up the scrollband(s) for the background
 * whose index is stored in the global variable "daBkgd"
 *
 * This really needs to be called  **AFTER EACH RESOLVE** as these
 * shapes aren't included in mfxDir and stuffing there indivdual
 * names into the scene's ItemDir would be useless.
 */
void initScroll()
{
ItemShpPtr  theShp;
short       ctr;
Rect        theRect;


    ScrlID = (RezPtr->packData[SentNum].BkgdVer[WhichBkgd]) - 1;
    /* STATUS2("ScrollID is %d\n",ScrlID); */

    /*
     * Point at the resource for this scrolling thing
     */
    ScrlRez = SCPtr0;

    /*
     * If the dividing ypos is 0 or -1, don't fill
     */
    if ((ScrlRez->scrollID[ScrlID].dividingYPos != 0) &&
     (ScrlRez->scrollID[ScrlID].dividingYPos != -1)) {
        theRect = BkgdRect; /* first set the rectangle to the entire window */
        theRect.bottom = theRect.top + ScrlRez->scrollID[ScrlID].dividingYPos;
        Fill(theRect, ScrlRez->scrollID[ScrlID].topColor);
        /*
         * Do the bottom color
         */
        theRect = BkgdRect; /* reset the rectangle to the entire window */
        theRect.top = theRect.top + ScrlRez->scrollID[ScrlID].dividingYPos;
        Fill(theRect, ScrlRez->scrollID[ScrlID].bottomColor);
        /*
         * draw a horizon line
         */
        theRect = BkgdRect; /* reset the rectangle to the entire window */
        theRect.top = theRect.top + ScrlRez->scrollID[ScrlID].dividingYPos;
        theRect.bottom = theRect.top +1;
        Fill(theRect, 127);
    }
    /*
     * Set up the twelve scrolling shapes
     * The image addresses are being stuffed directly without inserting their names
     * into the Item Directory of the scene.  Make sure resolve doesn't get called anywhere!!!
     */
    for (ctr=0; ctr<6; ctr++) {
        theShp = (ItemShpPtr)((unsigned) ScrlScene0 + (unsigned) ScrlScene0->ItemDir[ctr].Where);
        theShp->ShpIA = (ShapePtr) ((unsigned)SCData +
         (unsigned)SCTOC->TE[ScrlRez->scrollID[ScrlID].rItmIdx[ctr].itemIdx -1].Where);
        theShp->Gen.IIActive = theShp->Gen.IIDisplay = false;
        theShp->Pos.IIBaseX = BkgdRect.right;
        theShp->Pos.IIBaseY = ScrlRez->scrollID[ScrlID].rYPos - theShp->ShpIA->NumHigh + BkgdRect.top;
        theShp->Pos.IIXVel = ScrlRez->scrollID[ScrlID].rXVel;
        /* now do front scroll band */
        theShp = (ItemShpPtr)((unsigned) ScrlScene1 + (unsigned) ScrlScene1->ItemDir[ctr].Where);
        theShp->ShpIA = (ShapePtr) ((unsigned)SCData +
         (unsigned)SCTOC->TE[ScrlRez->scrollID[ScrlID].fItmIdx[ctr].itemIdx -1].Where);
        theShp->Gen.IIActive = theShp->Gen.IIDisplay = false;
        theShp->Pos.IIBaseX = BkgdRect.right;
        theShp->Pos.IIBaseY = ScrlRez->scrollID[ScrlID].fYPos - theShp->ShpIA->NumHigh + BkgdRect.top;
        theShp->Pos.IIXVel = ScrlRez->scrollID[ScrlID].fXVel;
    }
    NxtRScrl = 0;   /* introduce item #0 next for rear band at next code line number of ticks */
    ScrlRez->scrollID[ScrlID].rCtr = ScrlRez->scrollID[ScrlID].rItmIdx[NxtRScrl].ticksToNext;
    NxtFScrl = 0;   /* introduce item #0 next for front band */
    ScrlRez->scrollID[ScrlID].fCtr = ScrlRez->scrollID[ScrlID].fItmIdx[NxtFScrl].ticksToNext;
    ScrlScene0->Active = ScrlScene0->Display = true;
    ScrlScene1->Active = ScrlScene1->Display = true;
    ScrlScene0->NumItems = ScrlScene1->NumItems = 6;
    ReinitScene(ScrlScene0);
    ReinitScene(ScrlScene1);
}


/*
 * CheckScroll - This sees if any items need to be removed or added to the scroll bands
 */
void CheckScroll()
{
short       ctr;
ItemShpPtr  theShp;


    /*
     * I'm assuming there will always be two scroll bands active or none
     */
    if (!ScrlScene0->Active)
        return; /* scrolling is not active? */

    for (ctr=0; ctr<6; ctr++) {
        theShp = (ItemShpPtr)((unsigned) ScrlScene0 + (unsigned) ScrlScene0->ItemDir[ctr].Where);
        if ((theShp->Pos.IBaseX == 0) || (theShp->Pos.IBaseX + theShp->Pos.IXVel < 0)) {
            /* STATUS2("IBaseX = %d\n",theShp->Pos.IBaseX); */
            ReinitShp(theShp);
        }
        theShp = (ItemShpPtr)((unsigned) ScrlScene1 + (unsigned) ScrlScene1->ItemDir[ctr].Where);
        if ((theShp->Pos.IBaseX == 0) || (theShp->Pos.IBaseX + theShp->Pos.IXVel < 0)) {
            /* STATUS2("IBaseX = %d\n",theShp->Pos.IBaseX); */
            ReinitShp(theShp);
        }
    }

    if (ScrlScene0->Frame >= ScrlRez->scrollID[ScrlID].rCtr) {
        /* STATUS1("Trying to intro new rear item\n"); */
        theShp = (ItemShpPtr)((unsigned) ScrlScene0 + (unsigned) ScrlScene0->ItemDir[NxtRScrl].Where);
        if (!theShp->Gen.IActive) { /* only if it's not being used */
            theShp->Gen.IActive = theShp->Gen.IDisplay = true;
            NxtRScrl++;
            if (NxtRScrl == ScrlScene0->NumItems)
                NxtRScrl = 0;
            ScrlRez->scrollID[ScrlID].rCtr =
             ScrlRez->scrollID[ScrlID].rItmIdx[NxtRScrl].ticksToNext + ScrlScene0->Frame;
        }
    }

    if (ScrlScene1->Frame >= ScrlRez->scrollID[ScrlID].fCtr) {
        /* STATUS1("Trying to intro new front item\n"); */
        theShp = (ItemShpPtr)((unsigned) ScrlScene1 + (unsigned) ScrlScene1->ItemDir[NxtFScrl].Where);
        if (!theShp->Gen.IActive) { /* only if it's not being used */
            theShp->Gen.IActive = theShp->Gen.IDisplay = true;
            NxtFScrl++;
            if (NxtFScrl == ScrlScene1->NumItems)
                NxtFScrl = 0;
            ScrlRez->scrollID[ScrlID].fCtr =
             ScrlRez->scrollID[ScrlID].fItmIdx[NxtFScrl].ticksToNext + ScrlScene1->Frame;
        }
    }
}

snapshot.c

/*******************************************************************************
 file: snapshot.c                                               Richard Pferdner
                                                                Douglas Corarito

  capture memory map and print it out



 SCCS: @(#)snapshot.c   1.1 4/9/91

 7/2/92 DCC Added fflush(),sleep() and added error functionality to asm call

 (C) Copyright 1990 American Interactive Media, All Rights Reserved
*******************************************************************************/


#include <stdio.h>
#include <modes.h>


#ifdef WANT_SNAPSHOT

void snapshot()
{
    unsigned int blockmap[128];         /* map of free fragments */
    unsigned int blockinfo[4];
    unsigned int *blockptr;
    char mem_type;

    blockptr = blockmap;
    if ( getblkmap( blockptr, blockinfo ) == -1 )
        {
            printf("Error while getting block map\n");fflush(stdout);
            return;
        }

    printf( "Minimum alloc size    = 0x%8X (%8d)\n",
             blockinfo[0], blockinfo[0] );

    printf(  "# fragments in system = 0x%8X (%8d)\n",
             blockinfo[1], blockinfo[1] );

    printf(  "Total RAM at startup  = 0x%8X (%8d)\n",
             blockinfo[2], blockinfo[2] );

    printf(  "Current free RAM      = 0x%8X (%8d)\n",
             blockinfo[3], blockinfo[3] );

    printf(  "Dump of memory fragment info: \n" );

    while ( (*blockptr != 0) && ((int)(blockptr-blockmap) < 128 ) )
    {
        if ( *blockptr < 0x080000 )     /* plane A */
            mem_type = 'A';

        else if ( *blockptr < 0x0FFFFF )    /* plane B */
            mem_type = 'B';

/*
        note: as of 10/90 the address of FMV is not specified.
        This is a guess.
        NOT USED *** DCC

        else if ( *blockptr < 0x180000 )
            mem_type = 'C';
*/

        else
            mem_type = 'S';

        printf(  "address = [%c]0x%06X, size = 0x%8X (%8d) \n",
                 mem_type, *blockptr, *(blockptr + 1), *(blockptr + 1) );

        blockptr += 2;
    }

    fflush(stdout);
    sleep(5);
    return;
}


/* getblkmap: loads memory map - d0 = *blockmap, d1 = *blockinfo */

#asm
getblkmap:
    movem.l d0-d3/a0-a1,-(sp)   ; save regs
    movea.l d0,a0               ; set ptr = blockmap
    movea.l d1,a1               ; set a1 = info area
    move.l  #0,d0               ; mem to start at
    move.l  #(128*8),d1         ; length of map
    OS9     F$GBlkMp            ; get map info
    bcs.s   gbm_error           ; check for error
    move.l  d0,(a1)+            ; save min alloc size
    move.l  d1,(a1)+            ; # frags
    move.l  d2,(a1)+            ; total RAM at startup
    move.l  d3,(a1)             ; total free RAM now
    move.l  #0,d0               ; set no error
gbm_done
    movem.l (sp)+,d0-d3/a0-a1   ; restore regs
    rts                         ; and return
gbm_error
    move.l  #-1,d0              ;set error
    bra.s   gbm_done            ;leave
#endasm

#endif



#ifdef WANT_TRACKMEM

long
    gNumPtrs = 0;
long
    gNumAPtrs = 0;
long
    gNumBPtrs = 0;


char *
TrackAllocate(size, type)
    int size;
    int type;
{
    char *
        ptr;
    unsigned long
        p;

    ptr = (char *)srqcmem(size,type);
    if ( (int)(ptr) == -1 )
        {
            printf("Error requesting %d bytes.\n", size);fflush(stdout);sleep(1);
            return(-1);
        }

    gNumPtrs += 1;

    printf("ALLOCATED %d bytes in ",size);
    p = (unsigned long)ptr;
    if ( (p>0x00000000)&&(p<0x00080000) )
        {
            printf("A at 0x%X.",p);
            gNumAPtrs += 1;
        }
    else if ( (p>0x00080000)&&(p<0x00100000) )
        {
            printf("B at 0x%X.",p);
            gNumBPtrs += 1;
        }
    else
        {
            printf("S at 0x%X.",p);
        }

    printf(" [PA=%d,PB=%d,All=%d]\n",gNumAPtrs,gNumBPtrs,gNumPtrs);
    fflush(stdout);sleep(1);

    return(ptr);
}

int
TrackDeallocate(size,address)
    int size;
    char *address;
{
    unsigned long
        p;


    if ( _srtmem(size,address) == -1 )
        {
            printf("Error deallocating %d bytes at 0x%X\n",size,address);
            return(-1);
        }

    printf("DEALLOCATED %d bytes at 0x%X",size,address);
    p = (unsigned long)address;
    if ( (p>0x00000000)&&(p<0x00080000) ) gNumAPtrs -= 1;
    if ( (p>0x00080000)&&(p<0x00100000) ) gNumBPtrs -= 1;
    gNumPtrs -= 1;

    printf(" [PA=%d,PB=%d,All=%d]\n",gNumAPtrs,gNumBPtrs,gNumPtrs);
    fflush(stdout);sleep(1);

    return(0);
}

#endif


#ifdef WANT_TRACKSND

long
    gNumSMaps = 0;


int
TrackSnd(snd_path, snd_type, snd_grps, snd_buf)
    int snd_path;
    int snd_type;
    short snd_grps;
    char **snd_buf;
{
    int
        smap_id;


    smap_id = sm_creat(snd_path, snd_type, snd_grps, snd_buf);
    if ( smap_id == -1 )
    {
        printf("Can't get smap_id\n");
    }

    gNumSMaps += 1;

    printf("SND CREATED: %d bytes at 0x%X id = %d\n",snd_grps * 128, *snd_buf, smap_id );

    printf("gNumSMaps = %d\n",  gNumSMaps);
    fflush(stdout);sleep(1);

    return(smap_id);
}

int
UntrackSnd(snd_path, smap_id)
    int snd_path;
    int smap_id;
{

    if ( sm_close(snd_path, smap_id) == -1 )
        {
            printf("Error deallocating sound map\n");
            return(-1);
        }
    gNumSMaps -= 1;
    printf("SND DESTROYED: id = %d \n", smap_id);

    printf("gNumSMaps = %d\n",  gNumSMaps);
    fflush(stdout);sleep(1);

    return(0);
}

#endif

sound.c

#include <stdio.h>
#include <errno.h>
#include <cdfm.h>
#include <modes.h>
#include <csd.h>
#include <aimdef.h>
#include <procid.h>
#include <iff.h>
#include <memory.h>

#include "dbg.h"

#include "utility.h"
#include "sound.h"
#include "rtf.h"
#include "file_mgr.h"   /* for 'eor_ctr' */


snd_pair        snd_array[max_smaps];

Boolean         smap_busy;
int             cur_aud_fid;
int             cur_aud_channel;
static  int     pause_aud_fid;  /* holds cur_aud_fid during an ss_pause so we can clear cur_aud_fid */
static  int     last_aud_fid;
static  int     last_aud_channel;
static  int     bkgd_audio_stat;
static  int     smap_list[smap_list_size];
static  int     smap_list_next; /* index to next soundmap to start */
static  int     smap_list_last; /* always pointing at next free space in list */
int             smap_list_ctr;  /* number of soundmaps in list */
Boolean         bkgd_audio_loop;

static  STAT_BLK    s_b_a_stat;     /* background audio status block */
STAT_BLK        smap_stat;      /* soundmap status block */

static  int     alarm_stat; /* return status from alarm calls */
int             fx_alarm_id;
Boolean         fx_alarm_stat;  /* wether alarm is on or not */



/*
 * setup_audio -
 */
void setup_audio()
{
short       ctr;
char        *aud_dev;


    if ((aud_dev = csd_devname( DT_AUDIO, 1 )) == NULL ) {
        STATUS1("Couldn't get aud_dev name\n");
        exit(0);
    }
    if ( (int)((audpath = open( aud_dev, (S_IREAD | S_IWRITE)))) == SYSERR ) {
        STATUS1("Couldn't open audpath\n");
        exit(0);
    }
    free( aud_dev );

    if ( sc_atten( audpath, 0x00000000 ) == SYSERR ) {
        STATUS1("Couldn't set attenuation\n");
        exit(0);
    }
    cur_aud_fid = 0;
    smap_busy = false;
    stop_all_audio();   /* reset most other sound variables */

    fx_alarm_stat = false;
    for (ctr = 0; ctr < max_smaps; ctr ++) {
        snd_array[ctr].smap_id = 0;
    }
}


int start_fx_alarm()
{
    if (!fx_alarm_stat) {
        fx_alarm_id = alm_cycle(FX_ALARM_SIGNAL, 0x80000A00); /* every 10 seconds */
        if (fx_alarm_id == -1) {
            STATUS2("Couldn't set fx_alarm_id. Error #%d\n", errno);
            return(-1);
        }
        fx_alarm_stat = true;
    }
    return(0);
}


int stop_fx_alarm()
{
    if (fx_alarm_stat) {
        alarm_stat = alm_delete(fx_alarm_id);
        if (alarm_stat == -1) {
            STATUS2("Couldn't clear fx_alarm_id. Error #%d\n", errno);
            return(-1);
        }
        fx_alarm_stat = false;
    }
    return(0);
}


int start_bkgd_audio(BGChan, theFID, loop)
    short BGChan;
    int theFID;
    Boolean loop;
{

    if (cur_aud_fid) {
        STATUS1("cur_aud_fid is still set in start_bkgd_audio\n");
        ss_abort (cur_aud_fid);
        while(cur_aud_fid);     /* wait for the abort signal */
    }
    s_b_a_stat.asy_sig = 0;
    s_b_a_stat.asy_stat = 0;
    ss_seek(theFID,0,&s_b_a_stat);
    while (!(s_b_a_stat.asy_stat & 0x8001));    /* wait for done bit or error bit */
    if (s_b_a_stat.asy_stat & 0x8000) {
        STATUS2("Error %d occured during seek\n",s_b_a_stat.asy_sig);
        STATUS2("asy_sig = 0x%x\n",s_b_a_stat.asy_sig);
        STATUS2("asy_stat = 0x%x\n",s_b_a_stat.asy_stat);
        /* tsleep(100); */ /* about one second */
        s_b_a_stat.asy_sig = 0;
        s_b_a_stat.asy_stat = 0;
        ss_seek(theFID,0,&s_b_a_stat);
        while (!(s_b_a_stat.asy_stat & 0x8001));    /* wait for done bit or error bit */
        if (s_b_a_stat.asy_stat & 0x8000)
            DoDirtyDisc(); /* we don't come back here */
    }
    setup_bkgd_audio_rtf(BGChan);
    eor_ctr = 1;
    ss_play(theFID,thePCB);
    cur_aud_fid = theFID;
    cur_aud_channel = BGChan;
    bkgd_audio_loop = loop;
    if (bkgd_audio_loop) {
        last_aud_fid = cur_aud_fid;
        last_aud_channel = cur_aud_channel;
    }
    return(0);
}



int start_soundmap(smap_id)
    int smap_id;
{

    if (smap_busy) { /* there is still a soundmap playing - queue this one */
        smap_list[smap_list_last] = smap_id;
        smap_list_last++;
        if (smap_list_last == smap_list_size)
            smap_list_last = 0;
        smap_list_ctr++;
    }
    else { /* just play the soundmap */
        smap_busy = true;
        smap_stat.asy_sig = SM_OUT_SIGNAL;
        smap_stat.asy_stat = 0;
        if (sm_out(audpath, smap_id, &smap_stat) == -1) {
            STATUS2("error 0x%x in start_soundmap\n", errno);
            smap_busy = false;
            return(-1);
        }
    }
    return(0);
}


/*
 * update_audio - this needs to be in the main loop of the application
 *
 * 1 - check if there are soundmaps waiting to be played.
 * 2 - see if bkgd audio is stopped and 'bkgd_audio_loop' is set.
 * 3 -
 */
void update_audio()
{

    if (smap_list_ctr) { /* any sounds in the queue ? */
        if (!smap_busy) { /* if one is not currently playing */
            /* STATUS1("playing from the soundmap queue\n"); */
            start_soundmap(smap_list[smap_list_next]);
            smap_list_next++;
            if (smap_list_next == smap_list_size)
                smap_list_next = 0;
            smap_list_ctr--;
        }
    }
    else if ((!eor_ctr) && (bkgd_audio_loop)) {
        STATUS1("restarting the background audio\n");
        start_bkgd_audio(last_aud_channel, last_aud_fid, true);
    }
}



/*
 * stop_all_audio
 */
void stop_all_audio()
{
    if (cur_aud_fid)
        ss_abort(cur_aud_fid);
    if (smap_busy)
        sm_off(audpath);
    smap_list_next = 0; /* index to next soundmap to start */
    smap_list_last = 0; /* index to last soundmap in list */
    smap_list_ctr = 0;  /* number of soundmaps in list */
    bkgd_audio_loop = false;
    smap_busy = false;  /* should be cleared by signal handler */
    cur_aud_fid = 0;    /* should be cleared by signal handler */
    cur_aud_channel = 0;
}


/*
 * close_snd_stuff -
 */
void close_snd_stuff()
{

    close(audpath);

}

startup.c

#include <stdio.h>
#include <modes.h>
#include <csd.h>
#include <errno.h>
#include <cdfm.h>
#include <aimdef.h>
#include <ucm.h>
#include <memory.h>
#include <rtr.h>

#include "dbg.h"

#include "utility.h"
#include "rtf.h"
#include "screen.h"
#include "sentbld.h"
#include "startup.h"
#include "asm_itrfc.h"
#include "reading.h"
#include "buttons.h"



/*
 * This is the star cursor
 */
static  short StarCur[16] = {
    0x0080,0x0180,0x01C0,0x03E0,
    0x03F1,0x47FF,0xFFFF,0x7FFE,
    0x3FFC,0x1FF8,0x0FF8,0x0FF8,
    0x0FFC,0x1F7C,0x3E1C,0x780E
};

/*
 * Init the player for our stuff
 */

void setup_CDI()
{
short   ctr, index;
char    *ptr1, *ptr2;

    dc_intl(vidpath,0);

    if (PALflag) {
        lct_pal_a = dc_crlct(vidpath,PA,20*2,RES_NORMAL);
        lct_pal_b = dc_crlct(vidpath,PB,20*2,RES_NORMAL);
        dc_flnk(vidpath,fctid_RL7,lct_pal_a,0*2);
        dc_flnk(vidpath,fctid_Clut7,lct_pal_b,0*2);
        dc_llnk(vidpath,lct_pal_a,19*2,lctid0,0*2);
        dc_llnk(vidpath,lct_pal_b,19*2,lctid2,0*2);
        dc_llnk(vidpath,lctid0,239*2,lct_pal_a,0*2);
        dc_llnk(vidpath,lctid2,239*2,lct_pal_b,0*2);
    }
    else {
        dc_flnk(vidpath,fctid_RL7,lctid0,0*2);
        dc_flnk(vidpath,fctid_Clut7,lctid2,0*2);
    }
    /*
     * Initialize the FCTs
     */
    dc_wrfi(vidpath,fctid_RL7,0,cp_icm(ICM_CLUT7,ICM_CLUT7,NM_1,EV_OFF,CS_A));
    dc_wrfi(vidpath,fctid_RL7,1,cp_dprm(RMS_RL,PRF_X2,BP_NORMAL));
    dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MIN));
    dc_wrfi(vidpath,fctid_RL7,3,cp_po(PR_AB));
    dc_wrfi(vidpath,fctid_RL7,4,cp_tci(MIX_ON,TR_CKEY_T,TR_OFF));
    dc_wrfi(vidpath,fctid_RL7,5,cp_phld(PA,PH_OFF,0));
    dc_wrfi(vidpath,fctid_RL7,6,cp_tcol(PA,16,235,16));
    dc_wrfi(vidpath,fctid_RL7,7,cp_mcol(PA,0,0,0));
    dc_wrfi(vidpath,fctid_RL7,8,cp_bkcol(BK_LOW, BK_BLACK));
    dc_wrfi(vidpath,fctid_RL7,10,cp_cbnk(0));
    dc_wrfi(vidpath,fctid_RL7,75,cp_cbnk(1));
    for (ctr=138; ctr<150; ctr++) {
        dc_wrfi(vidpath,fctid_RL7,ctr,cp_nop()); /* clear the clut instr. left from the bumper */
    }

    dc_wrfi(vidpath,fctid_Clut7,1,cp_dprm(RMS_NORMAL,PRF_X2,BP_NORMAL));
    dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,ICF_MIN));
    dc_wrfi(vidpath,fctid_Clut7,3,cp_nop());
    dc_wrfi(vidpath,fctid_Clut7,4,cp_nop());
    dc_wrfi(vidpath,fctid_Clut7,5,cp_phld(PB,PH_OFF,0));
    dc_wrfi(vidpath,fctid_Clut7,7,cp_nop());
    dc_wrfi(vidpath,fctid_Clut7,9,cp_nop());
    dc_wrfi(vidpath,fctid_Clut7,10,cp_cbnk(2));
    dc_wrfi(vidpath,fctid_Clut7,75,cp_cbnk(3));

    /*
     * load and install the Stickybear palette.
     */
    DirNum = 0;                 /* mfxdir starts with no items */
    index = loadthing("sbclut");
    if (index != -1) {
        ptr1 = (char *)(mfxDir[index].Where + 12);
        StorePalette(ptr1);
    }
    else {
        STATUS1("can't find sbclut\n");
    }
    /*
     * Change cursor to star
     */
    pt_org(vidpath,0,0);
    gc_org(vidpath,0,0);
    gc_ptn(vidpath,8,8,16,16,0,StarCur);
    inp_col = 0x80808000; /* yellow - intensity bit (bit 31) on */
    gc_col(vidpath,inp_col);
    gc_blnk(vidpath,0x00000070);

    /*
     * Allocate screen memory (40 sectors for Clut7, 7 sectors for RL7)
     */
    vidmem0 = (Ptr)ALLOCATE(RL7Size * FORM2_SECTOR,VIDEO1);
    if (vidmem0 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem0");
    }

    vidmem1 = (Ptr)ALLOCATE(RL7Size * FORM2_SECTOR,VIDEO1);
    if (vidmem1 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem1");
    }

    /*
     * clear both RL7 buffers
     */
    ptr1 = (char *)vidmem0;
    ptr2 = (char *)vidmem1;
    for (ctr = 0; ctr < 240; ctr ++) {
        *ptr1++ = 0x8F00;
        *ptr2++ = 0x8F00;
    }

    vidmem2 = (Ptr)ALLOCATE(384 * 240,VIDEO2); /* screen 0 for our stuff (plane B) */
    if (vidmem2 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem2");
    }

    vidmem3 = (Ptr)ALLOCATE(384 * 240,VIDEO2); /* screen 1 for our stuff (plane B) */
    if (vidmem3 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem3");
    }

    vidmem4 = (Ptr)ALLOCATE(384 * 70,VIDEO2); /* button strip (plane B) */
    if (vidmem4 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem4");
    }

    vidmem5 = (Ptr)ALLOCATE(384 * 240,VIDEO2); /* bkgd screen for our stuff (plane B) */
    if (vidmem5 == (Ptr)-1L) {
        STATUS1("FAILURE MEMORY => vidmem5");
    }

    /*
     * Initialize LCT
     */
    dc_wrli(vidpath,lctid0,0*2,0,cp_dadr((int)vidmem0));
    dc_wrli(vidpath,lctid2,0*2,0,cp_dadr((int)vidmem2));
    if (PALflag) {
        for (ctr = 0; ctr < 20; ctr++) {
            dc_wrli(vidpath,lct_pal_a,ctr*2,0,cp_dadr((int)vidmem0));
            dc_wrli(vidpath,lct_pal_b,ctr*2,0,cp_dadr((int)vidmem2));
        }
    }


    /*
     * these are for our animation system
     */
    scn_ptr = vidmem3;      /* since we start by showing vidmem2 for clut7 */
    EraPtr = &EraTab3;      /* the erase table for vivmem3 */
    EraTab2.EraCtr = 0;     /* no erase rectangles for screen 0 (vidmem2) */
    EraTab3.EraCtr = 0;     /* no erase rectangles for screen 1 (vidmem3) */
    EraSrc = vidmem5;       /* set the erase source screen to be our Bkgd screen */
    swapflag = true;        /* we are not waiting for a swap to occur */
    DirNum = 0;             /* we don't need the sbclut entry in mfxdir anymore */
    for (ctr=0; ctr < maxScenes; ctr++) /* Initialize the scene table */
        SceneTab[ctr] = 0;
    /*
     * The components that are used to make all buttons in the program
     */
    ButtonBuf = (char *)ALLOCATE(FORM1_SECTOR * ButtonBufSize, VIDEO1);
    if (ButtonBuf == (char *)-1L) {
        STATUS1("Can't allocate ButtonBuf\n");
    }
    butTOC = (TOCPtr)ButtonBuf; /* table of contents is first at buttonbuf */
    /*
     * open the button speech files
     */
    Eng_button_fid = open_file("BUTTON.Eng.rtf", false);
    Span_button_fid = open_file("BUTTON.Span.rtf", false);

}


/*
 * This function installs the 128 color palette whose pointer is passed.
 */
Boolean StorePalette(rgbdata)
    char *rgbdata;
{
    char *b;
    char red,green,blue;
    short i;

    b = rgbdata;

    for (i=0;i<64;i++) {
        red = *b++;
        green = *b++;
        blue = *b++;
        dc_wrfi(vidpath,fctid_RL7,11+i,cp_clut(i,red,green,blue));
        dc_wrfi(vidpath,fctid_Clut7,11+i,cp_clut(i,red,green,blue));
    }
    for (i=0;i<64;i++) {
        red = *b++;
        green = *b++;
        blue = *b++;
        dc_wrfi(vidpath,fctid_RL7,76+i,cp_clut(i,red,green,blue));
        dc_wrfi(vidpath,fctid_Clut7,76+i,cp_clut(i,red,green,blue));
    }
    return(true);
}


utility.c

#include <stdio.h>
#include <errno.h>
#include <modes.h>
#include <aimdef.h>
#include <cdfm.h>
#include <rtr.h>
#include <ucm.h>
#include <memory.h>
#include <time.h>

#include "dbg.h"

#include "animation.h"
#include "utility.h"
#include "screen.h"
#include "sentbld.h"
#include "rtf.h"
#include "reading.h"
#include "cursor_mgr.h"
#include "sound.h"
#include "file_mgr.h"


unsigned short  ranctr;  /* index to random number table */
static  short   rantab[ransize] = {

     99,126, 13, 28, 51, 40,246,141, 14, 55, 88,255, 11,201,208, 66,
    136, 73 ,75,144,214,192,122,150,102,190,182,139,225,167,153,  8,
     36, 13, 62,171, 46, 72,115,240, 31,166,251,  0,174,124,225,178,
    199,230, 70, 31,  7, 79,184, 32,165,249,146, 10, 16, 52,200,166,
     32,110,142,157,180,230,112, 74, 75,116,179, 22,102,  6, 13, 60,
    195,132, 66, 78,147,194,184,194,164,199,190,148, 12,142,196, 48,
     76, 21, 70,179, 19,112,156,212, 71,206,191,  8,182,164,198,107,
    182,239, 79, 47, 92,233,136, 42,174,100,203,255, 32,157, 49,116,
     89,167,122,226,249,180,137,100,212,185,130,115,195, 22, 50,165,
    146,  8, 10, 72, 88,134,131,170,141,161,199,156, 28,119,173, 78,
     53, 37, 79,188, 49, 89,132,189,176, 55, 94,207,126, 47, 47, 67,
     74,250, 90,246 ,84,225, 59, 52,117,230,127,179,212, 69,217,216,
    237,127,219,234,  1,182,131, 94,152,194,131, 42,122,151, 91,205,
     79, 16, 18, 58,128,107,133,142,113,148,207,165,217,159,213, 68,
     28,226, 19,128, 38, 64,176,232, 20,155,143,148, 66,113,215,167,
    191, 34,130,119, 95,235,177, 93, 58, 52,138,  1,229,  9,158,158,
     24,244,131,146,  2,189,139, 34, 64,106,139, 49, 62, 94,101,216,
    187,124,126,137,207,185,140,150,102,190,182,139,225,167,103,  8,
     29, 13, 62,117, 46, 72,145, 13, 31,145,251,  0,135,124,225,124,
    199,230, 63, 31,  7, 26,184, 32, 67,249,146, 51, 16, 52, 99,166,
    109,187,142,157, 42,230,112,151, 75,235,179, 22,179,  6, 13,214,
    195,132, 59,121,191,187,184,194,122,211,202,141, 12,142,223,128,
     38, 21, 70,237, 98,192,235,242, 71, 39, 78,150,175,164,198,119,
    194,225, 71, 39,203, 21,179,102,234,250,147,199, 83,119, 11, 78,
     33,111, 15,218,241,231,180,143, 16,245,190, 59,139,222,143,  1,
    196, 65, 67,129,148,195,191,194,165,132,191,149, 49,179,233,117,
    145,129,139,248,109,149,193,249, 72,207,192,  9,183,104,107,127,
    175, 18,114,169,145, 29,197,113,177, 34,187,239, 93,129, 22,139,
      5,151,115,130,153,239,189,152,213,254,192,102,129,212,151,  9,
    172,108, 57,119,189,128,125,135, 84,172,231,218, 22,220,220,126,
     79, 62,111,221, 99,124,236,251, 13,129,236,240,185,174, 19,227,
    184, 27,181, 81, 57,146,237,153, 50, 45,130,100, 66,102,151,218
    };

long        cursorTime;
int         inp_col;    /* color of cursor */
int         inp_but;    /* button of input device */
int         inp_xpos;   /* xpos of input device */
int         inp_ypos;   /* ypos of input device */
InpTab      theInpTab;  /* holds hotspot index and button press */

short       theLine = 0;    /* scan line to link vidmem0 (RL7 buffer) to */

Boolean     fx_time;

/*
 * FindRect - The application must take care of setting a Ptr to the
 * proper table of rectangles for the current mode.  This code compares
 * the passed x,y coordinates against each rectangle in the list until
 * the rectangle (if any) is found that contains the passed coordinates.
 * It returns the rectangle's index (or -1 if none).
 */
short FindRect(xpos, ypos)
    short xpos;
    short ypos;
{
short ctr;

    for (ctr = 0; ctr <= theRectPtr->RectNum; ctr++) {
        if (xpos >= theRectPtr->theRects[ctr].left) {
            if (xpos <= theRectPtr->theRects[ctr].right) {
                if (ypos >= theRectPtr->theRects[ctr].top) {
                    if (ypos <= theRectPtr->theRects[ctr].bottom) {
                        return(ctr);
                    }
                }
            }
        }
    }
    return (-1);
}



/*
 * stuffbunch places the "who and where", into mfxDir, of each
 * individual thing that got loaded as part of a larger file.
 */
Boolean stuffbunch(theDirPtr, theDataPtr)
    Ptr theDirPtr;
    Ptr theDataPtr;
{
TOCPtr  theTOC;
int     ctr;

    theTOC = (TOCPtr)theDirPtr;
    /* STATUS2("mfxDir has %d items when entering stuffbunch\n", DirNum); */
    /* STATUS2("stuffbunch is adding %d items to mfxDir\n", theTOC->TOCNum); */
    for (ctr=0; ctr < theTOC->TOCNum; ctr++) {
        mfxDir[DirNum].Where = theDataPtr + theTOC->TE[ctr].Where;
        strcpy(mfxDir[DirNum].Who, theTOC->TE[ctr].Who);
        /* STATUS3("stuffbunch is adding %s at 0x%x\n", mfxDir[DirNum].Who, mfxDir[DirNum].Where); */
        DirNum++;       /* increment # of "things" in memory */
        if (DirNum >= maxThings) {
            STATUS1("mfxdir is maxed out ********\n");
        }
    }
    /* STATUS2("mfxDir has %d items when exiting stuffbunch\n", DirNum); */
    return(true);
}


/*
 * loadpkg - Pass this the name of a "package" (a .com file).
 *           This returns a pointer to the .cmn portion (this is handy
 *           when the first thing is a "scene".
 */

Ptr loadpkg(theName, theBuf)
    Str31   theName;
    Ptr     theBuf;
{
int     fid;
Size    theSize;
Size    theSize2;

    fid = open_file(theName, false);

    theSize = _gs_size(fid);

    theSize2 = read(fid, theBuf, theSize);
    if (theSize2 == -1) {
        STATUS1("loadpkg couldn't load the package ***\n");
        close_file(fid);
        return((Ptr)-1);
    }
    close_file(fid);
    /* return(stuffpkg(theBuf)); */ /* we don't need this here */
    return(0);
}


/*
 * stuffpkg - this "resolves" the package at pkgbuf
 */
Ptr stuffpkg(theBuf)
    Ptr     theBuf;
{
Ptr     theDataPtr;

    /*
     * Call the code "stuffbunch" that places everything just loaded into mfxDir
     */
    theDataPtr = theBuf + ((*(short *)theBuf) * 40 + 4);
    stuffbunch(theBuf, theDataPtr);
    return(theDataPtr);
}



/*
 * loadthing loads the thing whose name is passed in 'theName'.
 * It returns the index into mfxDir of its directory record (or -1 if an error occured).
 */
short loadthing(theName)
    Str31 theName;
{

int     fid;
Size    theSize;
Size    theSize2;

    fid = open(theName, S_IREAD);
    if (fid == -1) {
        STATUS2("loadthing can't find %s\n", theName);
        return(fid);
    }

    theSize = _gs_size(fid);
    mfxDir[DirNum].Where = (char *)ALLOCATE(theSize, VIDEO1);
    if (mfxDir[DirNum].Where == (char *)-1L)
    {
        STATUS1("LoadThing FAIL MEMORY\n");
    }
    strcpy(mfxDir[DirNum].Who, theName);

    theSize2 = read(fid, mfxDir[DirNum].Where, theSize);
    if (theSize2 == -1) {
        close_file(fid);
        return(-1);
    }
    /* STATUS4("loadthing loaded 0x%x bytes of %s at 0x%x\n", theSize2, theName, mfxDir[DirNum].Where); */
    close_file(fid);
    DirNum++;       /* increment # of "things" in memory */
    return(DirNum - 1);
}

/*
 * loadOne - This loads one thing from a combined file.
 *
 *  Pass it: findex - file index number (of large data file on disk)
 *           theTOC - Ptr to table of contents (TOC) for large disk file.
 *           tindex - index into TOC
 *           theBuf - Ptr to the buffer
 *
 *  Returns: # bytes read (or -1 for error)
 */
short loadOne(findex, theTOC, tindex, theBuf)
    int     findex;
    TOCPtr  theTOC;
    short   tindex;
    Ptr     theBuf;
{

STAT_BLK    seekstat;
Size    theSize;

    seekstat.asy_sig = 0;
    seekstat.asy_stat = 0;
    ss_seek(findex,theTOC->TE[tindex].Where,&seekstat);
    while (!(seekstat.asy_stat & 1)); /* wait for done bit */
    if (seekstat.asy_stat & 0x8000) {
        STATUS2("Error %d occured during seek\n",seekstat.asy_sig);
        STATUS2("asy_sig = 0x%x\n",seekstat.asy_sig);
        STATUS2("asy_stat = 0x%x\n",seekstat.asy_stat);
        return(-1);
    }
    theSize = read(findex, theBuf, theTOC->TE[tindex].How);
    if (theSize == -1) {
        return(-1);
    }
    return(theSize);
}



/*
 * FixScene - Pass this the scene index number. It will resolve the item table
 *              addresses.
 */
Boolean FixScene(theIndex)
    short theIndex;
{
Size        ITabSize; /* size of an item table is defined in "defines.h" */
ScenePtr    theScene;   /* handle to the "current" Scene */
int         CurOff;
short       ctr;

/*
 * Convert the itemdir "where" entries from (lengths of each item table)
 * to (offsets from start of scene to each item table).
 */
    theScene = SceneTab[theIndex];
    CurOff = sizeof(Scene) - (sizeof(Direc) * maxItems) + (sizeof(Direc) * (*theScene).NumItems);
    for (ctr = 0; ctr < (*theScene).NumItems; ctr++) {
        ITabSize = (int)(*theScene).ItemDir[ctr].Where; /* save size of current table */
        (*theScene).ItemDir[ctr].Where = (Ptr)CurOff;
        CurOff += ITabSize;
    }
    return(true);
}


/*
 * SetupScene - these lines of code have been chopped of the end of LoadScene
 * so that I can alter the item tables filenames before calling resolve/reinit.
 */
Boolean SetUpScene(theIndex)
    short theIndex;
{
Boolean     myBoo;

/*
 * Call the code that makes sure all image/sound data is in memory and resolves
 * all necessary pointers for each item table.
 */
    myBoo = Resolve(); /* link all item tables to their disk file images and disk file images to theirs */
    if (myBoo == false) {
        STATUS1("Resolve returned FALSE!!!\n");
        /* ShowMFX(); */
    }
    ReinitScene(SceneTab[theIndex]);
    return(true);
}

#if 0
/*
 * ShowMFX - prints the contents of mfxDir
 */
void ShowMFX()
{
short   ctr;

    return;
    for (ctr=0; ctr<DirNum; ctr++) {
        STATUS3("Item #%d in mfxDir is %s\n", ctr, mfxDir[ctr].Who);
    }
}
#endif

/*
 *  Pass this the filename to search for.
 *  This returns the index # or (-1) if name not in directory (mfxDir).
 */
short getind(theText)
    char *theText;
{
short   ctr;
short   index = -1;

    for (ctr=0; ctr<DirNum; ctr++) {
        if (strcmp(mfxDir[ctr].Who, theText) == 0) {
            index = ctr;
            break;
        }
    }
    if (index == -1) {
        STATUS2("getind coundn't find %s\n",theText);
    }
    return(index);
}


/*
 *
 * CheckInput - This reads the controller and positions the cursor.
 *              It stuffs values into the table whose address is passed.
 *
 * Pass this structure:
 *      short   HotIndex;  stuffs index number of hotspot (or -1)
 *      Boolean ButPress;  set if controller button is pressed, cleared otherwise
 */
void CheckInput()
{

    Step();

    Get_Coord(&inp_xpos,&inp_ypos);
    Get_Buttons(&inp_but);

    theInpTab.HotIndex = FindRect(inp_xpos/2,inp_ypos/2);
    if (theInpTab.HotIndex == -1)
        inp_col = 0x80808000; /* yellow - intensity bit (bit 31) on */
    else
        if (currentT >= cursorTime) {
            inp_col = (inp_col ^ 0x00008000); /* toggle between yellow and red */
            cursorTime = currentT + cursor_delay;
        }
    gc_col(vidpath,inp_col);

    if (inp_but & 0x03)
        theInpTab.ButPress = true;
    else
        theInpTab.ButPress = false;
}


/*
 * This is the signal handler
 */
int signal_handler(signal)
    int signal;
{
    short   theStat;

    theStat = thePCB->PCB_Stat;
    switch (signal) {

        case SLI_SIGNAL:    /* tell main that scan line interrupt "has happened" */
            swapflag = true;
            break;

        case SM_OUT_SIGNAL: /* sound map has been sent to audio processor */
            smap_busy = false;
            if (!(smap_stat.asy_stat & 1)) {
                STATUS1("have smap signal but done bit is clear\n");
            }
            if (smap_stat.asy_stat & 0x8000) {
                STATUS2("smap error 0x%x\n", smap_stat.asy_sig);
            }
            break;

        case PCB_SIGNAL:
            if ( theStat & SBM_Er ) { /* Error or Abort has occurred */
                if ( thePCB->PCB_Sig == E_ABORT ) {
                    eor_ctr = 0;
                    cur_aud_fid = 0;
                }
                else {
                    STATUS3("Play Error 0x%x, PCB_Stat %x\n\n",thePCB->PCB_Sig, theStat);
                    play_error = true;
                    eor_ctr = 0;
                    cur_aud_fid = 0;
                }
            }
            if ( theStat & SBM_Dn ) { /* Play is finished */
                cur_aud_fid = 0;
                /* STATUS1("Play Finished\n"); */
            }
            if ( theStat & SBM_Eof ) { /* End of File */
                cur_aud_fid = 0;
                /* STATUS1("EOF\n"); */
            }
            if ( theStat & SBM_Trg ) { /* Trigger */
                trigger_ctr --;
                /* STATUS1("Trigger\n"); */
            }
            if ( theStat & SBM_Eor ) { /* End of record */
                eor_ctr --;
                /*STATUS1("EOR\n");*/
            }
            break;

        case PTR_SIGNAL:
            reset_dim();                    /* reset the dim timer */
            reset_help();                   /* reset the help timer */
            Update_Coord();                 /* update the cursor manager */
            pt_ssig(vidpath,PTR_SIGNAL);    /* re-arm the signal */
            /* STATUS1("ptr\n"); */
            break;

        case BUFFER_SIGNAL0:
            vid_pcl_0->PCL_BufSz = RL7Size;
            vid_pcl_0->PCL_Ctrl = 0;                /* Control byte */
            vid_pcl_0->PCL_Cnt = 0;             /* Current offset in buffer */
            dc_wrli (vidpath,lctid0,theLine*2,0,cp_dadr((int)vidmem0));
            rear_vid_pcl = vid_pcl_1;
            break;

        case BUFFER_SIGNAL1:
            vid_pcl_1->PCL_BufSz = RL7Size;
            vid_pcl_1->PCL_Ctrl = 0;                /* Control byte */
            vid_pcl_1->PCL_Cnt = 0;             /* Current offset in buffer */
            dc_wrli (vidpath,lctid0,theLine*2,0,cp_dadr((int)vidmem1));
            rear_vid_pcl = vid_pcl_0;
            break;

        case FX_ALARM_SIGNAL:
            fx_time = true;
            break;

        default:
            break;
    }
    return(0);
}

short getran(limit)
    short limit;
{
short ranval;
short ranval2;

    ranval = rantab[ranctr];
    ranctr++;
    if (ranctr >= ransize)
        ranctr = 0;
    if (ranval > limit) {
        ranval2 = ranval / limit;
        ranval2 *= limit;
        ranval -= ranval2;
    }
    return(ranval);
}

/*
 * get_random_seed
 */
void get_random_seed()
{
short       ctr;

    currentT = clock(); /* get current tick count */
    ranctr = (short) currentT;
    if (ranctr > ransize) {
        ctr = ranctr / ransize;
        ctr *= ransize;
        ranctr -= ctr;
    }
}


/*
 * shufshort - pass this the address and size of a table of short values to shuffle
 */
void shufshort(table, size)
    short   *table;
    short   size;
{
short   ctr;
short   ranval1;
short   ranval2;
short   tempval;

    for (ctr=0; ctr<100; ctr++) {
        ranval1 = getran(size -1);
        ranval2 = getran(size -1);
        tempval = table[ranval1];
        table[ranval1] = table[ranval2];
        table[ranval2] = tempval;
    }
}


/*
 * reset_dim - set a new click count as the target for dimming
 */
void reset_dim()
{
    DimTime = currentT + (CLK_TCK * DimSecs);
}

/*
 * chk_dim
 */
int chk_dim()
{
int     did_dim;
extern  Boolean cursor_stat;

    if (currentT >= DimTime) {

        if (ModMod == ModBop)
            no_vel();               /* stop the x movement of the items */
        if (PAFlag)
            dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MAX/3));
        if (PBFlag)
            dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,ICF_MAX/3));
        if (cursor_stat)
            gc_hide(vidpath); /* we can't call 'cursor_hide' as it clears 'cursor_stat' */
        while ((last_xpos == inp_xpos) && (last_ypos == inp_ypos) && (!theInpTab.ButPress))
            CheckInput();
        if (PAFlag)
            dc_wrfi(vidpath,fctid_RL7,2,cp_icf(PA,ICF_MAX));
        if (PBFlag)
            dc_wrfi(vidpath,fctid_Clut7,2,cp_icf(PB,ICF_MAX));
        if (cursor_stat)
            cursor_show();          /* display the cursor */
        reset_dim();                /* reset dim counter */

        did_dim = 1;
    }
    else
        did_dim = 0;
    return(did_dim);
}


/*
 * reset_help - set a new click count as the target for playing
 *              the automatic help message
 */
void reset_help()
{
    HelpTime = currentT + (CLK_TCK * HelpSecs);
}


/*
 * chk_help -   if it's time to play the help message, do it,
 *              and then restart the backgound audio
 */
int chk_help(hlp_chn, hlp_fid, bkd_chn, bkd_fid)
    short   hlp_chn, bkd_chn;
    int     hlp_fid, bkd_fid;
{
int     did_help;

    if (currentT >= HelpTime) {

        if (ModMod == ModBop)
            no_vel();               /* stop the x movement of the items */

        stop_all_audio();
        start_bkgd_audio(hlp_chn, hlp_fid, false);
        while ((last_xpos == inp_xpos) && (last_ypos == inp_ypos) &&
            (!theInpTab.ButPress) && (eor_ctr)) {
            CheckInput();
        }

        stop_all_audio();
        if (bkd_fid)
            start_bkgd_audio(bkd_chn, bkd_fid, true);
        reset_help();
        did_help = 1;
    }
    else
        did_help = 0;
    return(did_help);
}

wordbook.c

#include <stdio.h>
#include <errno.h>
#include <modes.h>
#include <aimdef.h>
#include <memory.h>
#include <rtr.h>
#include <time.h>

#include "dbg.h"

#include "wordbook.h"
#include "animation.h"
#include "reading.h"
#include "screen.h"
#include "rtf.h"
#include "sound.h"
#include "file_mgr.h"
#include "utility.h"



/*
 * this is the table of the twenty scenes that gets shuffled
 */
short   wbstab[NumPages] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    10,11,12,13,14,15,16,17,18,19
    };


/*
 * These are the hotspots for each wordbook "page"
 * The first 6 are the buttons.
 */

static  RectList farm1Rect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     60, 55,116,117,    /* cow */
     90,137,126,187,    /* chicken */
    114,221,160,295,    /* pig */
     60,291,100,345,    /* tractor */
     36,168, 74,228     /* barn */
    };

static  RectList spaceRect = {
     10,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     41, 53,104,118,    /* astronaut */
     30,247, 74,288,    /* moon */
    100,127,143,183,    /* satellite */
    107,226,167,346     /* rocket */
    };

static  RectList AfricaRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     49, 77,100,150,    /* elephant */
     58,217,100,267,    /* lion */
    100,290,170,341,    /* giraffe */
    100,138,144,200,    /* zebra */
    117, 46,169, 95     /* hippo */
    };

static  RectList farm2Rect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     53,177,100,248,    /* goat */
     60,284,121,341,    /* pumpkin */
    128,292,150,344,    /* duck */
    115,113,160,178,    /* sheep */
     30, 50,110,113     /* scarecrow */
    };

static  RectList AustraliaRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     28,117, 85,167,    /* monkey */
    140,141,160,206,    /* anteater */
     98,295,158,343,    /* ostrich */
     33,218, 70,255,    /* parrot */
     93, 38,150,121     /* kangaroo */
    };

static  RectList oceanRect = {
     10,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     55, 51,110,150,    /* submarine */
     30,171, 54,278,    /* motorboat */
     53,284, 94,332,    /* fish */
    106,157,147,283     /* shark */
    };

static  RectList beachRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
    113, 51,150,141,    /* Sara */
     32,112, 65,171,    /* island */
     40,284, 87,340,    /* sailboat */
     84,156,111,216,    /* rowboat */
    113,241,157,317     /* ball */
    };

static  RectList houseRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     44, 64,133,122,    /* door */
     43,144,100,193,    /* window */
    120,135,160,205,    /* dog */
    114,284,150,337,    /* cat */
     32,250, 80,305     /* tree */
    };

static  RectList vehiclesRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     93, 66,144,154,    /* cement mixer */
    116,265,202,331,    /* motorcycle */
     80,188,120,274,    /* truck */
     35,266, 69,351,    /* train */
     35, 90, 83,176     /* gas station */
    };

static  RectList skyRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     73, 38,100,156,    /* airplane */
     46,190, 77,265,    /* helicopter */
     92,182,127,232,    /* cloud */
    107,258,140,302,    /* bird */
    114, 80,168,118     /* balloon */
    };

static  RectList porchRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     67,115,117,170,    /* barrel */
    126, 90,165,183,    /* mouse */
    124,200,153,238,    /* bucket */
    105,274,147,345,    /* wagon */
     40,298,140,334     /* balloon */
    };

static  RectList interiorRect = {
     10,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     59, 43,166,135,    /* bed */
     49,156,123,231,    /* chair */
    129,208,160,249,    /* banana */
     54,264,151,348     /* telephone */
    };

static  RectList pondRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     84,122,116,199,    /* swan */
     90,275,120,348,    /* frog */
    113,204,164,245,    /* rabbit */
     35,167, 66,235,    /* rainbow */
    115, 60,148,124     /* turtle */
    };

static  RectList windowRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
    100,298,160,340,    /* brush */
     64,180, 89,239,    /* tent */
     36, 57,106,157,    /* house */
    134, 51,160,100,    /* box */
    100,165,160,240     /* shoe */
    };

static  RectList musicRect = {
     10,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     65, 41,158,141,    /* piano */
     45,223,146,291,    /* trombone */
     65,150,163,222,    /* drum */
     81,295,166,344     /* guitar */
    };

static  RectList classroomRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
    104, 60,153,100,    /* globe */
     41, 45, 88,114,    /* blackboard */
     45,149, 89,225,    /* map */
     35,293, 63,325,    /* bell */
    106,255,152,302     /* computer */
    };

static  RectList kitchenRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     42, 96,135,169,    /* Stickybear */
     54,214, 82,263,    /* tea kettle */
     30,272,136,332,    /* refrigerator */
    100,195,150,243,    /* toaster */
    103, 41,143, 83     /* mixer */
    };

static  RectList parkRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     27, 50,160,121,    /* lamp post */
     55,113,118,196,    /* fountain */
     45,225, 88,328,    /* bridge */
    100,305,160,347,    /* bench */
     82,191,160,241     /* clown */
    };

static  RectList sinkRect = {
     11,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
    108,160,140,329,    /* sink */
     35,168,100,237,    /* faucet */
     36,270,105,347,    /* pan */
    100, 69,160,137,    /* pot */
     30, 40, 78,125     /* cans */
    };

static  RectList supermarketRect = {
     10,
    177, 33,218, 82,    /* help button */
    177, 88,218,149,    /* speech button */
    177,155,218,216,    /* text button */
    177,222,218,252,    /* prev button */
    177,253,218,283,    /* next button */
    177,289,218,350,    /* go back button */
     52,253,118,348,    /* cash register */
    126,191,145,261,    /* pie */
     41, 42,137, 87,    /* Bumper */
     75,119,136,177     /* shopping cart */
    };



static  Str31 WBNames[NumPages] = {
    "Africa.rtf",
    "Australia.rtf",
    "beach.rtf",
    "classroom.rtf",
    "farm1.rtf",
    "farm2.rtf",
    "house.rtf",
    "interior.rtf",
    "kitchen.rtf",
    "music.rtf",
    "ocean.rtf",
    "park.rtf",
    "pond.rtf",
    "porch.rtf",
    "sink.rtf",
    "sky.rtf",
    "space.rtf",
    "supermarket.rtf",
    "vehicles.rtf",
    "window.rtf"
    };

static  MCAud WBTunes[NumPages] = {
    0, 0,
    0, 1,
    0, 2,
    0, 3,
    0, 4,
    0, 5,
    0, 6,
    0, 7,
    0, 8,
    0, 9,
    0, 10,
    0, 11,
    0, 12,
    0, 13,
    0, 14,
    0, 15,
    1, 0,
    1, 1,
    1, 2,
    1, 3
    };

static  Ptr WBSpots[NumPages] = {
    &AfricaRect,
    &AustraliaRect,
    &beachRect,
    &classroomRect,
    &farm1Rect,
    &farm2Rect,
    &houseRect,
    &interiorRect,
    &kitchenRect,
    &musicRect,
    &oceanRect,
    &parkRect,
    &pondRect,
    &porchRect,
    &sinkRect,
    &skyRect,
    &spaceRect,
    &supermarketRect,
    &vehiclesRect,
    &windowRect
    };

static  WBSMap Africasmap = {
     15,
     90, 90, 72,    /* elephant */
     72, 72,108,    /* lion */
     90, 90, 18,    /* giraffe */
     90, 72, 72,    /* zebra */
     72,108, 18     /* hippo */
    };

static  WBSMap Australiasmap = {
     15,
     72, 72, 72,    /* monkey */
     90,126,108,    /* anteater */
     90,108, 18,    /* ostrich */
     72, 72, 72,    /* parrot */
     90, 90, 72     /* kangaroo */
    };

static  WBSMap beachsmap = {
     15,
     72, 72,108,    /* Sara */
     72, 72, 18,    /* island */
    108,126,162,    /* sailboat */
    108,144,144,    /* rowboat */
     72, 90, 72     /* ball */
    };

static  WBSMap classroomsmap = {
     15,
     90,108, 72,    /* globe */
     90, 90, 18,    /* blackboard */
     72, 72, 54,    /* map */
     72, 90,126,    /* bell */
     90,108, 90     /* computer */
    };

static  WBSMap farm1smap = {
     15,
     72, 90,108,    /* cow */
     72, 90,108,    /* chicken */
     72, 72, 72,    /* pig */
     90, 90,162,    /* tractor */
     72, 90,180     /* barn */
    };

static  WBSMap farm2smap = {
     15,
     90, 72, 90,    /* goat */
     90,108, 72,    /* pumpkin */
     90, 72, 72,    /* duck */
     72, 72,108,    /* sheep */
     90,126, 90     /* scarecrow */
    };

static  WBSMap housesmap = {
     15,
     72, 90, 90,    /* door */
     90, 90,108,    /* window */
     72, 72, 72,    /* dog */
     72, 90, 90,    /* cat */
     72, 72, 18     /* tree */
    };

static  WBSMap interiorsmap = {
     15,
     72, 72,162,    /* bed */
     72, 72, 36,    /* chair */
     72, 90, 54,    /* banana */
     90, 90,108,    /* telephone */
     18, 18, 18     /* filler */
    };

static  WBSMap kitchensmap = {
     15,
     90, 90,126,    /* Stickybear */
     72, 90,144,    /* teakettle */
    108, 90, 72,    /* refrigerator */
     90,108, 72,    /* toaster */
     90,108,162     /* mixer */
    };

static  WBSMap musicsmap = {
     15,
     72, 72,162,    /* piano */
    108, 90,108,    /* trombone */
     72, 90,108,    /* drum */
     90, 90,144,    /* guitar */
     18, 18, 18     /* filler */
    };

static  WBSMap oceansmap = {
     15,
    108,108,162,    /* submarine */
    108, 90,108,    /* motorboat */
     72, 72, 54,    /* fish */
     90, 90,126,    /* shark */
     18, 18, 18     /* filler */
    };

static  WBSMap parksmap = {
     15,
    108,126, 90,    /* lamppost */
     72, 90,180,    /* fountain */
     90, 90,126,    /* bridge */
     72, 90, 72,    /* bench */
     90, 72, 90     /* clown */
    };

static  WBSMap pondsmap = {
     15,
    108, 72,144,    /* swan */
     72, 72, 54,    /* frog */
     90, 72, 18,    /* rabbit */
    108,108,108,    /* rainbow */
     72, 90, 54     /* turtle */
    };

static  WBSMap porchsmap = {
     15,
     72, 90, 90,    /* barrel */
     90, 90, 36,    /* mouse */
     90, 90, 72,    /* bucket */
     90, 90,126,    /* wagon */
    108, 72, 54     /* balloon */
    };

static  WBSMap sinksmap = {
     15,
     72, 90, 90,    /* sink */
     72,108,162,    /* faucet */
     72, 90, 72,    /* pan */
     72, 72, 54,    /* pot */
     90, 90, 72     /* cans */
    };

static  WBSMap skysmap = {
     15,
     90, 72,180,    /* airplane */
     90,108,108,    /* helicopter */
     90, 72, 18,    /* cloud */
     72, 72, 72,    /* bird */
    108, 72, 54     /* balloon */
    };

static  WBSMap spacesmap = {
     15,
     90,108, 18,    /* astronaut */
     90, 72,162,    /* moon */
     90,108,108,    /* satellite */
     90, 72,108,    /* rocket */
     18, 18, 18     /* filler */
    };

static  WBSMap supermarketsmap = {
     15,
    126,126,126,    /* cash register */
     72, 90, 18,    /* pie */
     90, 72,126,    /* Bumper */
    108, 90,126,    /* shopping cart */
     18, 18, 18     /* filler */
    };

static  WBSMap vehiclessmap = {
     15,
    126,162,126,    /* cement mixer */
    108, 72,108,    /* motorcycle */
     72, 90, 90,    /* truck */
     90, 72,144,    /* train */
    108,162,108     /* gas station */
    };

static  WBSMap windowsmap = {
     15,
     72, 90, 54,    /* brush */
     72, 72, 54,    /* tent */
     90, 72,126,    /* house */
     90, 72, 18,    /* box */
     72, 90, 90     /* shoe */
    };


static  WBSMapPtr WBSMaplists[NumPages] = {
    &Africasmap,
    &Australiasmap,
    &beachsmap,
    &classroomsmap,
    &farm1smap,
    &farm2smap,
    &housesmap,
    &interiorsmap,
    &kitchensmap,
    &musicsmap,
    &oceansmap,
    &parksmap,
    &pondsmap,
    &porchsmap,
    &sinksmap,
    &skysmap,
    &spacesmap,
    &supermarketsmap,
    &vehiclessmap,
    &windowsmap
    };

static  short       DirSaveWB;
static  Rect        fullRect = {0,1,240,383};
static  short       wbsctr = 5;
static  short       WhichPage;  /* which word book page to do */
static  ScenePtr    WBScene;
static  ItemPtr     WBItem;
static  short       LastFXID;       /* ID of last sound effect to play */
static  int         LastFXCtr;      /* ctr for when to do sound effect */

static  Boolean     mute_fx[15];    /* array entry set means don't play sound effect */

/*
 * Sara's wordbook
 */
void WordBook()
{
Boolean     done;
short       ctr;


    WhichPage = wbstab[wbsctr];
    DirSaveWB = DirNum;     /* save for starting point when loading each new 'page' */
    set_bear_voice();       /* set the bear file ID to the appropriate file */

    newWBpkg(1);            /* Load the initial wordbook package */
    MkBookBut();            /* Make the buttons for word book. */
    Step();                 /* This will draw the first frame of animation */

    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true); /* Start bkgd audio */

    DslvAB(fastdisolve);        /* disolve from plane A to plane B */

    Set_Coord (230,100);
    cursor_show();          /* display the cursor */
    done = false;
    while (!done) {

        update_audio();

        chk_help(8, BEARfid, WBTunes[WhichPage].MCAChan, TUNEfid);
        chk_dim();  /* if it's time to dim, this won't return until undim */

        if ((LastFXID != -1) && (fx_time)) { /* Check for time to do sound effect */
            start_soundmap(snd_array[LastFXID].smap_id);
            fx_time = false;
        }

        CheckInput(); /* This checks the input device and calls 'Step' */
        switch (theInpTab.HotIndex) {
            case 0: /* HELP button */
                if (theInpTab.ButPress) {
                    stop_all_audio();
                    start_bkgd_audio(7, BEARfid, false); /* pass channel number */
                    CheckInput();
                    while ((eor_ctr) && (theInpTab.HotIndex == 0) && (!theInpTab.ButPress))
                        CheckInput();
                    stop_all_audio();
                    reset_help();
                    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true);
                }
                break;
            case 1: /* SPEECH button */
                if (theInpTab.ButPress) {
                    Cursor_Freeze();
                    stop_all_audio();
                    start_bkgd_audio(0, BUTTONfid, false); /* pass channel number */
                    changeSpch();
                    while (eor_ctr);
                    set_bear_voice();
                    set_button_voice();
                    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true);
                    Cursor_Melt();
                }
                break;
            case 2: /* TEXT button */
                if (theInpTab.ButPress) {
                    Cursor_Freeze();
                    stop_all_audio();
                    stop_all_audio();
                    if (text == English)
                        start_bkgd_audio(3, BUTTONfid, false); /* pass channel number */
                    if (text == Spanish)
                        start_bkgd_audio(1, BUTTONfid, false); /* pass channel number */
                    changeText();
                    if (text == Spanish) {
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[1].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[2].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[4].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[5].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[7].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[8].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[10].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[11].Where);
                            WBItem->IDisplay = true;
                        }
                        if (WBScene->NumItems == 15) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[13].Where);
                            if (WBItem->IDisplay == true) {
                                WBItem->IDisplay = false;
                                WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[14].Where);
                                WBItem->IDisplay = true;
                            }
                        }
                    }
                    if (text == English) {
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[2].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[1].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[5].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[4].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[8].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[7].Where);
                            WBItem->IDisplay = true;
                        }
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[11].Where);
                        if (WBItem->IDisplay == true) {
                            WBItem->IDisplay = false;
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[10].Where);
                            WBItem->IDisplay = true;
                        }
                        if (WBScene->NumItems == 15) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[14].Where);
                            if (WBItem->IDisplay == true) {
                                WBItem->IDisplay = false;
                                WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[13].Where);
                                WBItem->IDisplay = true;
                            }
                        }
                    }
                    while (eor_ctr);
                    stop_all_audio();
                    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true);
                    Cursor_Melt();
                }
                break;
            case 3: /* PREVIOUS button */
                if (theInpTab.ButPress) {
                    stop_all_audio();
                    wbsctr --;
                    if (wbsctr == -1)
                        wbsctr = NumPages -1;
                    WhichPage = wbstab[wbsctr];
                    newWBpkg(0);    /* Load a wordbook package */
                    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true);
                }
                break;
            case 4: /* NEXT button */
                if (theInpTab.ButPress) {
                    stop_all_audio();
                    wbsctr ++;
                    if (wbsctr == NumPages)
                        wbsctr = 0;
                    WhichPage = wbstab[wbsctr];
                    newWBpkg(1);    /* Load a wordbook package */
                    start_bkgd_audio(WBTunes[WhichPage].MCAChan, TUNEfid, true);
                }
                break;
            case 5: /* GOBACK button */
                if (theInpTab.ButPress) {
                    stop_all_audio();
                    start_bkgd_audio(10, BEARfid, false); /* Sara says "bye" */
                    while (eor_ctr);
                    /* DirNum = DirSaveWB; */   /* restore old value */
                    done = true;
                }
                break;

            case 6: /* Item #0 */
                if ((theInpTab.ButPress) && (!smap_busy) && (!smap_list_ctr)) {
                    WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[0].Where);
                    if (WBItem->IActive == true) { /* already active - disable it */
                        WBItem->IActive = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[1].Where);
                        WBItem->IDisplay = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[2].Where);
                        WBItem->IDisplay = false;
                        if (LastFXID == 2)
                            LastFXID = -1;  /* turn off this sound effect */
                    }
                    else { /* activate the item and proper word shape */
                        WBItem->IActive = true;
                        if (text == English) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[1].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[0].smap_id);
                            else
                                start_soundmap(snd_array[1].smap_id);
                        }
                        else {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[2].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[0].smap_id);
                            else
                                start_soundmap(snd_array[1].smap_id);
                        }
                        stop_fx_alarm();        /* shut off the old alarm */
                        LastFXID = 2;           /* set sound effect ID */
                        if (!mute_fx[LastFXID]) {
                            start_soundmap(snd_array[LastFXID].smap_id);
                            start_fx_alarm();
                        }
                    }
                    while (theInpTab.ButPress)
                        CheckInput(); /* wait for button release */
                }
                break;

            case 7: /* Item #1 */
                if ((theInpTab.ButPress) && (!smap_busy) && (!smap_list_ctr)) {
                    WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[3].Where);
                    if (WBItem->IActive == true) {
                        WBItem->IActive = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[4].Where);
                        WBItem->IDisplay = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[5].Where);
                        WBItem->IDisplay = false;
                        if (LastFXID == 5)
                            LastFXID = -1;  /* turn off this sound effect */
                    }
                    else {
                        WBItem->IActive = true;
                        if (text == English) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[4].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[3].smap_id);
                            else
                                start_soundmap(snd_array[4].smap_id);
                        }
                        else {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[5].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[3].smap_id);
                            else
                                start_soundmap(snd_array[4].smap_id);
                        }
                        stop_fx_alarm();        /* shut off the old alarm */
                        LastFXID = 5;           /* set sound effect ID */
                        if (!mute_fx[LastFXID]) {
                            start_soundmap(snd_array[LastFXID].smap_id);
                            start_fx_alarm();
                        }
                    }
                    while (theInpTab.ButPress)
                        CheckInput();
                }
                break;

            case 8: /* Item #2 */
                if ((theInpTab.ButPress) && (!smap_busy) && (!smap_list_ctr)) {
                    WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[6].Where);
                    if (WBItem->IActive == true) {
                        WBItem->IActive = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[7].Where);
                        WBItem->IDisplay = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[8].Where);
                        WBItem->IDisplay = false;
                        if (LastFXID == 8)
                            LastFXID = -1;  /* turn off this sound effect */
                    }
                    else {
                        WBItem->IActive = true;
                        if (text == English) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[7].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[6].smap_id);
                            else
                                start_soundmap(snd_array[7].smap_id);
                        }
                        else {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[8].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[6].smap_id);
                            else
                                start_soundmap(snd_array[7].smap_id);
                        }
                        stop_fx_alarm();        /* shut off the old alarm */
                        LastFXID = 8;           /* set sound effect ID */
                        if (!mute_fx[LastFXID]) {
                            start_soundmap(snd_array[LastFXID].smap_id);
                            start_fx_alarm();
                        }
                    }
                    while (theInpTab.ButPress)
                        CheckInput();
                }
                break;

            case 9: /* Item #3 */
                if ((theInpTab.ButPress) && (!smap_busy) && (!smap_list_ctr)) {
                    WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[9].Where);
                    if (WBItem->IActive == true) {
                        WBItem->IActive = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[10].Where);
                        WBItem->IDisplay = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[11].Where);
                        WBItem->IDisplay = false;
                        if (LastFXID == 11)
                            LastFXID = -1;  /* turn off this sound effect */
                    }
                    else {
                        WBItem->IActive = true;
                        if (text == English) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[10].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[9].smap_id);
                            else
                                start_soundmap(snd_array[10].smap_id);
                        }
                        else {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[11].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[9].smap_id);
                            else
                                start_soundmap(snd_array[10].smap_id);
                        }
                        stop_fx_alarm();        /* shut off the old alarm */
                        LastFXID = 11;          /* set sound effect ID */
                        if (!mute_fx[LastFXID]) {
                            start_soundmap(snd_array[LastFXID].smap_id);
                            start_fx_alarm();
                        }
                    }
                    while (theInpTab.ButPress)
                        CheckInput();
                }
                break;

            case 10: /* Item #4 */
                if ((theInpTab.ButPress) && (!smap_busy) && (!smap_list_ctr)) {
                    WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[12].Where);
                    if (WBItem->IActive == true) {
                        WBItem->IActive = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[13].Where);
                        WBItem->IDisplay = false;
                        WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[14].Where);
                        WBItem->IDisplay = false;
                        if (LastFXID == 14)
                            LastFXID = -1;  /* turn off this sound effect */
                    }
                    else {
                        WBItem->IActive = true;
                        if (text == English) {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[13].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[12].smap_id);
                            else
                                start_soundmap(snd_array[13].smap_id);
                        }
                        else {
                            WBItem = (ItemPtr)((int)WBScene + (int)WBScene->ItemDir[14].Where);
                            WBItem->IDisplay = true;
                            if (speech == English)
                                start_soundmap(snd_array[12].smap_id);
                            else
                                start_soundmap(snd_array[13].smap_id);
                        }
                        stop_fx_alarm();        /* shut off the old alarm */
                        LastFXID = 14;          /* set sound effect ID */
                        if (!mute_fx[LastFXID]) {
                            start_soundmap(snd_array[LastFXID].smap_id);
                            start_fx_alarm();
                        }
                    }
                    while (theInpTab.ButPress)
                        CheckInput();
                }
                break;
        }
        last_xpos = inp_xpos;   /* xpos of input device */
        last_ypos = inp_ypos;   /* ypos of input device */
    }
    stop_fx_alarm();
    stop_all_audio();
    /*
     * Give back sound map buffers
     */
    for (ctr = 15; ctr >= 0; ctr --) {
        if (snd_array[ctr].smap_id) {
            SMAP_DESTROY(audpath, snd_array[ctr].smap_id);
            snd_array[ctr].smap_id = 0;
        }
    }
}



/*
 * newWBpkg - This loads one of the twenty wordbook packages
 *            The soundmaps are loaded to their buffers
 *            The image data gets loaded at PkgBuf
 */
void newWBpkg(direction)
    short direction;
{
Ptr         thePtr;
Ptr         scnptrsav;
int         fid;
WBSMapPtr   theSMPtr;
short       NumMaps;
int         NumGrps;
short       ctr;
Boolean     stat;


    /*
     * Release old soundmaps
     */
    for (ctr = 15; ctr >= 0; ctr --) {
        if (snd_array[ctr].smap_id) {
            SMAP_DESTROY(audpath, snd_array[ctr].smap_id);
            snd_array[ctr].smap_id = 0;
        }
    }

    /*
     * try opening the new file first, before allocating the new soundmaps
     */
    fid = open_file(WBNames[WhichPage], true);
    if (fid == -1) {
        STATUS1("had trouble opening package - will try another\n");
        if (direction) {
            wbsctr ++;
            if (wbsctr == NumPages)
                wbsctr = 0;
        }
        else {
            wbsctr --;
            if (wbsctr == -1)
                wbsctr = NumPages -1;
        }
        WhichPage = wbstab[wbsctr];
        fid = open_file(WBNames[WhichPage], false);
    }
    /*
     * Create the new soundmaps for this page
     */
    theSMPtr = WBSMaplists[WhichPage];
    NumMaps = theSMPtr->NumSMaps;
    for (ctr=0; ctr<NumMaps; ctr++) {
        NumGrps = (theSMPtr->SMapSize[ctr] +17);
        /*
         * This little 'if/else' became necessary when we switched from AMP
         * to playing soundmaps at the last minute. It used to be okay to
         * mix silence (the 18 soundgroups) with the background audio.  Now
         * it creates a gap in the background audio for no apparent reason
         * for the user. If 'NumGrps' equals 18 we have to set a flag to
         * not play the sound effect. We also must not set the fx_alarm.
         */
        if  (NumGrps == 18 + 17)
            mute_fx[ctr] = true;
        else
            mute_fx[ctr] = false; /* let this audio play */

        snd_array[ctr].smap_id = SMAP_CREATE(audpath, D_CMONO, NumGrps, &snd_array[ctr].data);
        if ( snd_array[ctr].smap_id == -1 ) {
            STATUS1("SMAP_CREATE returned -1\n");
        }
    }

    stat = play_recs(fid, set_wbpkg_pcls, 1, false, false, 0);
    stat = close_file(fid);

    DirNum = DirSaveWB; /* restore old value */

    SceneTab[MScene] = (ScenePtr)stuffpkg(PkgBuf);
    FixScene(MScene);
    WBScene = SceneTab[MScene];
    WBScene->AniDelay = WordBook_AniDelay;
    WBScene->Active = true;
    WBScene->Display = true;
    SetUpScene(MScene);

    /*
     * Set list of hotspots
     */
    theRectPtr = (RectListPtr)WBSpots[WhichPage];

    FilCol = 96; /* should probably be a little more random than this */
    /*
     * Save original contents and then set scn_ptr to bkgd scrn
     * (most drawing happens at scn_ptr)
     */
    scnptrsav = scn_ptr;
    scn_ptr = vidmem5;
    Fill(fullRect, FilCol); /* fill entire bkgd screen */

    thePtr = (Ptr) ((unsigned)WBScene + (unsigned)pkgTOC->TE[1].Where);
    Draw((ShapePtr)thePtr, 32, 25); /* draw the shape */
    scn_ptr = scnptrsav; /* restore scn_ptr */

    copy_bkgd_front();

    /*
     * Set the background audio file for this page
     */
    if (WBTunes[WhichPage].MCAFile)
        TUNEfid = Tune2ID;
    else
        TUNEfid = Tune1ID;

    /*
     * Disable the sound effect stuff for now
     */
    LastFXID = -1;
    fx_time = false;
    currentT = clock();         /* get current tick count */
#if 0
    reset_dim();
    reset_help();
#endif
}