home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Add-Ons / After Dark / Rae / rae.c next >
Encoding:
Text File  |  1994-04-20  |  18.9 KB  |  772 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3. // see the README file for version notes
  4.  
  5. #include "GraphicsModule_Types.h"
  6. #include "Sounds.h"
  7.  
  8.  
  9.  
  10. typedef struct sicn {
  11.     unsigned char bits[32];
  12. } sicnStruct, *sicnPtr, **sicnHandle;
  13.  
  14. typedef struct infostruct {
  15.     /*unsigned short*/
  16.     short            GND[128];                        // ??
  17.     BitMap            face;
  18.  
  19.     Handle            faceSICN;                        // faces resource
  20.     short            numFaces;
  21.     short            curFace;
  22.     short            lastFace;
  23.     short            whichFace;                        // which item # in the menu?
  24.     
  25.     short            failedToStart;                    // watchdog 
  26.     
  27.     short            time;                            // "timer" for decay, etc
  28.     short            state;
  29.     int                x, y,
  30.                     xvel, yvel,
  31.                     xacc, yacc,
  32.                     xpos, ypos;
  33.     int                xx, yy;                            // temp/save values
  34.     Rect            myRect;
  35.     Handle            sndBounce;                        // handle to 'boink' sound
  36.     Handle            sndScream;                        // scream sound
  37.     SoundInfoHandle    soundInfo;                        // handle to AD sound thing
  38.     long            soundTicks;                        // sound timer to keep us from 
  39.                                                     // sounding yucky
  40.     
  41. } infostruct, *infostructPtr, **infostructHandle;
  42.  
  43. #define BOING_SOUND_ID    256
  44. #define SCREAM_SOUND_ID 129
  45.  
  46. #define BASE_FACE_ID    256                        // MENUs items are 1-based, not 0
  47.  
  48. #define DOUBLE_FACE
  49.  
  50. #define SOUND_TIMER        3                        // wait for # ticks
  51.                                                 // before playing the next one
  52. #define MAX_ITERATIONS    (128)
  53.  
  54. unsigned short RangedRdm( unsigned short min, unsigned short max );
  55. void SetRGBColor(void);
  56.  
  57. int drawit(GMParamBlockPtr params, infostructPtr info, int x, int y );
  58. int decay(int v);
  59. void ChooseFace(GMParamBlockPtr params, infostructPtr info);
  60.  
  61. #if 1
  62. #define XMIN    (params->qdGlobalsCopy->qdThePort->portRect.left)
  63. #define YMIN    (params->qdGlobalsCopy->qdThePort->portRect.top)
  64. #define XMAX    (params->qdGlobalsCopy->qdThePort->portRect.right)
  65. #define YMAX    (params->qdGlobalsCopy->qdThePort->portRect.bottom)
  66. #define TOP        YMIN
  67. #define BOT        (YMAX-1)
  68.  
  69. #else
  70.  
  71. #define HEIGHT  16
  72. #define WIDTH   16
  73. #define XMIN    0
  74. #define YMIN    0
  75. #define XMAX    511
  76. #define YMAX    341
  77. #define TOP     YMIN
  78. #define BOT     (YMAX-1)
  79. #endif
  80.  
  81. enum {
  82.     RAE_STARTING,
  83.     RAE_FALLING,
  84.     RAE_SETTLING,
  85.     RAE_DONE,
  86.     RAE_RESET
  87. };
  88.  
  89.  
  90. // these are the functs that need defined ...
  91. OSErr DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params);
  92. OSErr DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  93. OSErr DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  94. OSErr DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params);
  95. OSErr DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  96.  
  97. // extra ones
  98. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  99. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params);
  100.  
  101.  
  102. // this is borrowed from the example code from Bouncing Ball ...
  103. /* some macros to simplify synchronizing to the vertical retrace. */
  104. #define SynchFlag(m) (params->monitors->monitorList[m].synchFlag)
  105. #define SynchVBL(m) synchFlag = &SynchFlag(m); *synchFlag = false; while(!*synchFlag);
  106.  
  107.  
  108. static unsigned char facebits[32] = {
  109.     0x07, 0xe0, 0x18, 0x18, 0x20, 0x04, 0x42, 0x42, 0x42, 0x42,
  110.     0x82, 0x41, 0x80, 0x01, 0x80, 0x01, 0x84, 0x21, 0x88, 0x11,
  111.     0x94, 0x29, 0x43, 0xc2, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18,
  112.     0x07, 0xe0
  113. };
  114.  
  115. //////////////////////////////////////////////////////////////////////////////////////
  116. // this is the first funct called by AD ... we need to allocate and initialize here
  117. OSErr
  118. DoInitialize(Handle *storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  119.     Handle             h;
  120.     infostructPtr    info;
  121.     short            offRowBytes;
  122.     // error messages
  123.     StringPtr spaceErrMsg = (StringPtr)"\prae: Not enough memory!!";
  124.     // misc vars  ..
  125.     short            i; 
  126.  
  127.     // Randomize...
  128.     params->qdGlobalsCopy->qdRandSeed = TickCount();
  129.  
  130.     h = NewHandle( sizeof(infostruct) );
  131.     if (h == (Handle)nil) {
  132.         BlockMove(spaceErrMsg, params->errorMessage, spaceErrMsg[0]+1);
  133.         return ModuleError;
  134.     }
  135.     *storage = h;
  136.     MoveHHi(h);
  137.     HLock(h);
  138.     info = (infostructPtr)(*h);
  139.  
  140.     info->myRect = params->qdGlobalsCopy->qdThePort->portRect;
  141. //    SetRect( &(info->myRect), 0, 0, XMAX+1, YMAX+1);
  142.     
  143.  
  144.     info->soundTicks = TickCount();
  145.  
  146.     info->whichFace = params->controlValues[1];
  147.  
  148.  
  149.     info->faceSICN = NULL;
  150.     info->sndBounce = NULL;
  151.     info->sndScream = NULL;
  152.     ChooseFace(params,  info);
  153.  
  154. // set up the GND 
  155.     for (i=0; i<128; i++) {
  156.         info->x = i<<3;
  157.         if (info->x <= XMIN+8 || info->x >= XMAX-8)
  158.             info->GND[i] = 0;
  159.         else {
  160.             info->GND[i] = BOT - 9;
  161.             if (i&01)
  162.                 if (info->GND[i-1]==0)
  163.                     info->GND[i] = 0;
  164.                 else
  165.                     info->GND[i] -= 7;
  166.         }
  167.     }
  168.  
  169.     info->state = RAE_STARTING;
  170.     info->failedToStart = 0;
  171.     
  172.     HUnlock( h);
  173.     return noErr;
  174. }
  175.  
  176. //////////////////////////////////////////////////////////////////////////////////////
  177. // the screen saver has been awakened! time to ditch the storage and wave goodbye
  178. OSErr 
  179. DoClose(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  180.  
  181.     // soundInfoHandle to ditch ??
  182.     if ( ( (infostructPtr)(*storage) )->soundInfo  != NULL)
  183.         CloseSound( ((infostructPtr)(*storage) )->soundInfo, 
  184.                 params->sndChannel);
  185.     
  186.     // ditch the bounce sound
  187.     if (((infostructPtr)(*storage) )->sndBounce != (Handle)NULL)
  188.         ReleaseResource( ((infostructPtr)(*storage) )->sndBounce );
  189.         
  190.     // ditch the scream sound also
  191.     if (  ((infostructPtr)(*storage) )->sndScream  != (Handle)NULL)
  192.         ReleaseResource( ((infostructPtr)(*storage) )->sndScream);
  193.  
  194.     // ditch the SICN handle
  195.     if ( ((infostructPtr)(*storage) )->faceSICN != (Handle)NULL)
  196.         ReleaseResource( ((infostructPtr)(*storage) )->faceSICN );
  197.  
  198.     // finally, ditch the memory we had allocated
  199.     DisposHandle( storage);
  200.     return noErr;
  201. }
  202.  
  203.  
  204.  
  205. //////////////////////////////////////////////////////////////////////////////////////
  206. // make the screen go black
  207. OSErr
  208. DoBlank(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) {
  209.     infostructPtr        info;
  210.     
  211.     // darken the screen ...
  212.     FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  213.  
  214.     return noErr;
  215.  
  216. }
  217.  
  218. //////////////////////////////////////////////////////////////////////////////////////
  219. // this is the workhorse routine. It does the continual screen work to make
  220. // this screen saver what it is.
  221. OSErr 
  222. DoDrawFrame(Handle storage, RgnHandle blankRgn, GMParamBlockPtr params) 
  223. {
  224.     infostructPtr    info;
  225.     Rect             tmpRect;
  226.     short             a, b;
  227.  
  228.  
  229.     HLock(storage);
  230.     info = (infostructPtr)(*storage);
  231.  
  232. #ifdef DEBUGIT
  233. SetRect( &tmpRect, 0, 0, 50, 20);
  234. EraseRect( &tmpRect);
  235. MoveTo( 10, 15);
  236. a = info->xvel;
  237. b = info->yvel;
  238. if (a < 0) {
  239.     DrawChar('-');
  240.     DrawChar('0' - a);
  241. } else {
  242.     DrawChar( '+');
  243.     DrawChar( '0' + a);
  244. }
  245. DrawChar('.');
  246. if (b < 0) {
  247.     DrawChar('-');
  248.     DrawChar('0' - (b/10) );
  249.     DrawChar('0' - (b%10) );
  250. } else {
  251.     DrawChar('+');
  252.     DrawChar('0' + (b/10) );
  253.     DrawChar('0' + (b%10) );
  254. }
  255.  
  256. #endif
  257.  
  258. // quick check ... to help out demo mode
  259.     if (info->whichFace != params->controlValues[1] ) {
  260.     // someone changed the menu - choose that face for them...
  261.     // first - erase us, if we're onscreen
  262.     
  263.         //info->curFace = info->lastFace;
  264.         drawit( params, info, info->x, info->y);
  265.  
  266.     // set new face ... then go get it + it's sound
  267.         info->whichFace = params->controlValues[1];
  268.         ChooseFace(params, info);
  269.         
  270.     // put a new face onscreen ... so when we erase it, it's correct!
  271.         drawit( params, info, info->x, info->y);
  272.     }
  273.  
  274. // -------------------------------------------------------------------------
  275. //            ALL DONE ... or major reset coming ... boom
  276. // -------------------------------------------------------------------------
  277.         if (info->state == RAE_RESET) {
  278.             short i;
  279.             
  280.             // aaggghhh!!!
  281.             if (info->sndScream != (Handle)NULL ) {
  282.                 long    waste;
  283.                 
  284.                 PlaySound( info->soundInfo, params->sndChannel, info->sndScream);
  285.                 Delay(30L, &waste);
  286.             }
  287.             
  288.             
  289.             // set up the GND 
  290.             for (i=0; i<128; i++) {
  291.                 info->x = i<<3;
  292.                 if (info->x <= XMIN+8 || info->x >= XMAX-8)
  293.                     info->GND[i] = 0;
  294.                 else {
  295.                     info->GND[i] = BOT - 9;
  296.                     if (i&01)
  297.                         if (info->GND[i-1]==0)
  298.                             info->GND[i] = 0;
  299.                         else
  300.                             info->GND[i] -= 7;
  301.                 }
  302.             }
  303.     
  304.             // darken the screen ...
  305.             FillRgn(blankRgn, params->qdGlobalsCopy->qdBlack);
  306.             info->state = RAE_STARTING;
  307.             info->failedToStart = 0;
  308.             HUnlock(storage);
  309.             return noErr;
  310.         }
  311.     
  312.     
  313. // -------------------------------------------------------------------------
  314. //            BALL DONE  start another now
  315. // -------------------------------------------------------------------------
  316.         if (info->state == RAE_DONE) {
  317.  
  318.             info->state = RAE_STARTING;
  319.             info->failedToStart = 0;
  320.             HUnlock(storage);
  321.             return noErr;
  322.         }
  323.     
  324. // -------------------------------------------------------------------------
  325. //            STARTING OUT
  326. // -------------------------------------------------------------------------
  327.     if (info->state == RAE_STARTING) {    
  328.  
  329.         if (info->failedToStart > MAX_ITERATIONS) {
  330.             info->state = RAE_RESET;
  331.             HUnlock(storage);
  332.             return noErr;
  333.         }
  334.  
  335.             info->xpos = Random() & 0177; // 0177 == 127 == 0x7F
  336.             if (info->GND[info->xpos] <= TOP) {
  337.                 info->failedToStart++;
  338.                 HUnlock(storage);
  339.                 return noErr;
  340.             }
  341.             info->failedToStart = 0;
  342.  
  343.             info->x = (info->xpos) << 3;
  344.             //  |01 means an odd number
  345.             //    &07 means to ensure only the last 3 bits are on
  346.             // info->xvel = 4 - ((Random()|01) & 07);
  347.             info->xvel = 4 - 
  348.                 ( (RangedRdm(0, 255) | 01) & 07 );
  349.                 
  350.             info->yacc = 1;
  351.             info->yvel = 1;        // was 0
  352.             info->y = TOP;
  353.             info->state = RAE_FALLING;
  354.  
  355.             info->curFace = info->lastFace =  0;
  356.  
  357.             info->xx = info->yy = 0;        // joe
  358.  
  359.             drawit(params, info, info->x, info->y);            
  360.  
  361.             HUnlock(storage);
  362.             return noErr;
  363.     }
  364.     
  365. // -------------------------------------------------------------------------
  366. //             FALLING 
  367. // -------------------------------------------------------------------------
  368.     if (info->state == RAE_FALLING) {
  369.         long        waste;
  370.         short        eraseX, eraseY;            // saved values of where to erase
  371.         
  372.     
  373.         // we'll get called into this section with the info->time var incremented
  374.         // through each iteration ...
  375.         info->time++;
  376.         
  377.         
  378.         // save the values - so we erase closer to the time
  379.         // when we draw (reduce that flicker)
  380.         eraseX = info->x;
  381.         eraseY = info->y;
  382.         
  383.         // save the x and the y 
  384.         info->xx = info->x; 
  385.         info->yy = info->y; 
  386.         
  387.         // update the acceleration
  388.         info->yvel += info->yacc;
  389.  
  390.         // move it along it's way
  391.         info->y += info->yvel;
  392.         info->x += info->xvel;
  393.         
  394.         if (info->y > info->GND[info->x>>3]) {    /* bounce? */
  395.  
  396.             // make a noise
  397.             if (info->sndBounce != (Handle)NULL  
  398. #ifdef SOUND_TIMER
  399.                     && ( TickCount() > (info->soundTicks + params->controlValues[2] ))
  400. #else
  401.                     && !SoundBusy( info->soundInfo, params->sndChannel)
  402. #endif
  403.                      ) {
  404.                 info->soundTicks = TickCount();
  405.                 PlaySound( info->soundInfo, params->sndChannel, info->sndBounce);
  406.             }
  407.  
  408.             
  409. #ifdef DOUBLE_FACE
  410.             // if we're going fast, show an extra face, at the bounce
  411.             if (info->yvel>5) {
  412.                 short savedFace;
  413.                 savedFace = info->lastFace;
  414.                 
  415.                 if (info->numFaces > 1)  // more than 1 face? show the second one!!
  416.                     info->curFace = 1;
  417.                 drawit(params, info, info->x, info->y);        // place the face
  418.                 Delay(1L, &waste);
  419.                 drawit(params, info, info->x, info->y);        // erase the face
  420.                 info->lastFace = savedFace;
  421.                 
  422.             } else 
  423. #endif // DOUBLE_FACE
  424.                 if (info->numFaces > 1)     // more than 1 face? show second one!!
  425.                     info->curFace = 1;
  426.                 
  427.             if (info->y <= info->GND[info->xx>>3]) { /* side collision? */
  428.                 info->x = info->xx;
  429.                 info->xvel = -info->xvel;
  430.  
  431.             } else if (info->yy <= info->GND[info->x>>3]) { /*bottom? */
  432.  
  433.                 info->y = info->yy;
  434.                 info->yvel = -info->yvel;
  435.                 
  436.             } else {    /* corner */
  437.             
  438.                 info->x = info->xx;
  439.                 info->y = info->yy;
  440.                 
  441.                 info->xvel = -info->xvel;
  442.                 info->yvel = -info->yvel;
  443.             }
  444.             
  445.             // every 15 bounces (?) (\017) we decay the x velocity
  446.             if ((info->time & 017) == 0)
  447.                 info->xvel = decay(info->xvel);
  448.             
  449.             // is it down to zero ?
  450.             if (info->xvel == 0) {
  451.             
  452.                 info->xpos = (info->x) >> 3;
  453.  
  454.                     // go right 
  455.                 if (info->GND[info->xpos-1] < info->GND[info->xpos]
  456.                  && info->GND[info->xpos]   < info->GND[info->xpos+1])
  457.                     info->xvel = 1;
  458.                     /* go left */
  459.                 else if (info->GND[info->xpos-1] > info->GND[info->xpos]
  460.                       && info->GND[info->xpos]   > info->GND[info->xpos+1])
  461.                     info->xvel = -1;
  462.                     /* on hilltop */
  463.                 else if (info->GND[info->xpos-1] > info->GND[info->xpos]
  464.                       && info->GND[info->xpos]   < info->GND[info->xpos+1]) {
  465.                     if (Random() & 01)
  466.                         info->xvel = 1;
  467.                     else
  468.                         info->xvel = -1;
  469.                 }
  470.             }
  471.             
  472.             // decay the y velocity at each bounce
  473.             info->yvel = decay(info->yvel);    
  474.                         
  475.         } // end of 'if BOUNCE' 
  476.             else info->curFace = 0;    // set the face back to the starting one!!
  477.  
  478.  
  479.  
  480.         if (params->controlValues[0]) {
  481.                 short saveIt;
  482.                 
  483.                 saveIt = info->curFace;
  484.                 
  485.                 info->curFace = info->lastFace;
  486.                 drawit( params, info, eraseX, eraseY);
  487.                 
  488.                 info->curFace = saveIt;
  489.         }
  490.  
  491.         // place the face (was ->xx, ->yy)
  492.         drawit(params, info, info->x, info->y);
  493.     
  494.         
  495.         if (info->xvel==0 && info->yvel==0 && info->y > info->GND[info->x>>3]-4) {
  496.             info->state = RAE_SETTLING;
  497.             HUnlock(storage);
  498.             return noErr;
  499.         }
  500.     } // end of the falling section
  501.  
  502.     
  503.     
  504.     
  505. // -------------------------------------------------------------------------
  506. //             SETTLING 
  507. // -------------------------------------------------------------------------
  508.     if (info->state == RAE_SETTLING) {
  509.     
  510.  
  511.         // time to erase it
  512.         drawit(params, info, info->x, info->y);    
  513.  
  514.         info->curFace = 0;
  515.  
  516.         /* find stable position */
  517.         if (info->GND[(info->xpos)-1] <    info->GND[info->xpos] && 
  518.             info->GND[info->xpos]   >    info->GND[(info->xpos)+1]) {
  519.             
  520.             // place it?
  521.             drawit(params, info, (info->xpos)<<3, info->GND[info->xpos]);
  522.             // update the "ground" array to know there is something here
  523.             info->GND[info->xpos] -= 21;
  524.             
  525.             if (info->GND[(info->xpos)-1] <= 0)
  526.                 info->GND[info->xpos] -= 7;
  527.                 
  528.             info->GND[(info->xpos)+1] -= 7;
  529.             info->state = RAE_DONE;    // all done
  530.             HUnlock(storage);
  531.             return noErr;
  532.         }
  533.         
  534.         /* roll right */
  535.         if (    info->GND[(info->xpos)-1]    <    info->GND[info->xpos] && 
  536.                 info->GND[info->xpos]        <    info->GND[(info->xpos)+1]) {
  537.             info->xpos++;
  538.             HUnlock(storage);
  539.             return noErr;
  540.         }
  541.         /* roll left */
  542.         if (    info->GND[(info->xpos)-1]    >    info->GND[info->xpos] && 
  543.                 info->GND[info->xpos]        >    info->GND[(info->xpos)+1]) {
  544.             info->xpos--;
  545.             HUnlock(storage);
  546.             return noErr;
  547.         }
  548.         /* on hilltop, choose at Random */
  549.         if (    info->GND[(info->xpos)-1]    >    info->GND[info->xpos] && 
  550.                 info->GND[info->xpos]        <    info->GND[(info->xpos)+1]) {
  551.             if (Random() & 01)
  552.                 info->xpos++;
  553.             else
  554.                 info->xpos--;
  555.             HUnlock(storage);
  556.             return noErr;
  557.         }
  558.         
  559.         // none of the above tests worked ... so something is wrong!!!!!
  560.         /* else botch */
  561.         if (info->sndScream != (Handle)NULL ) {
  562.             long waste;
  563.             
  564.             info->soundTicks = TickCount();
  565.             PlaySound( info->soundInfo, params->sndChannel, info->sndScream);
  566.             Delay(30L, &waste);
  567.         }
  568.  
  569.         // place the face
  570.         // drawit(params, info, (info->xpos)<<3, info->GND[info->xpos]);
  571.         
  572.         // erase the screen
  573.         //PaintRect(&(info->myRect) );
  574.         info->state = RAE_RESET;    // was RAE_DONE all done
  575.         
  576.         HUnlock(storage);
  577.         return noErr;
  578.     }    
  579.  
  580.  
  581. AllDone:
  582.     HUnlock(storage);
  583.     return noErr;
  584. }
  585.  
  586. //////////////////////////////////////////////////////////////////////////////////////
  587. // this is called when they click on something in the control panel
  588. OSErr 
  589. DoSetUp(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  590.  
  591.     return noErr;
  592. }
  593.  
  594.  
  595.  
  596. OSErr DoSelected(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  597.     return noErr;
  598. }
  599.  
  600.  
  601.  
  602. OSErr DoAboutBox(RgnHandle blankRgn, short message, GMParamBlockPtr params) {
  603.  
  604.     return noErr;
  605. }
  606.  
  607.  
  608.  
  609. // drawit - place the rae on the screen 
  610. // pass the params + the locked down pointer to the infostruct
  611. drawit(params, info, x, y)
  612. GMParamBlockPtr params;
  613. infostructPtr info;
  614. int x,y;
  615. {       
  616.     int i;
  617.     Rect trect;
  618.     RGBColor        black = {0,0,0}, White = {65535,65535,65535};
  619. volatile    register Boolean *synchFlag;
  620.     long    waste;
  621.  
  622.  
  623.     if (x<XMIN)
  624.         x = XMIN+8;
  625.         
  626.     if (y<TOP)
  627.         y = TOP+8;
  628.         
  629.     if (x>XMAX)
  630.         x = XMAX-8;
  631.     
  632.     info->xpos = x>>3;
  633.     if (y > info->GND[info->xpos])
  634.         y = info->GND[info->xpos];
  635.  
  636.     /* was a call to bitblt() */
  637.     SetRect(&trect, x-12, y-8, x+4, y+8);
  638.  
  639.  
  640.     ForeColor( whiteColor);
  641.     BackColor( blackColor);
  642.     
  643.     if (info->faceSICN != NULL) {
  644.         HLock( info->faceSICN );
  645.         info->face.baseAddr = *info->faceSICN + (info->curFace * sizeof( sicnStruct ) );
  646.         info->lastFace = info->curFace;
  647.     } else {
  648.         info->face.baseAddr = (QDPtr) &facebits[0];
  649.         info->lastFace = info->curFace;
  650.     }
  651.  
  652.     SynchVBL( 0 );
  653.     CopyBits(&info->face, ¶ms->qdGlobalsCopy->qdThePort->portBits, 
  654.             &info->face.bounds, &trect, 
  655.                 srcXor, 0L);
  656.                 
  657.     if (info->faceSICN != NULL)
  658.         HUnlock( info->faceSICN);
  659.  
  660. }
  661.  
  662. decay(v)
  663. register v;
  664. {
  665.     if (v==0)
  666.         return(v);
  667.     if (v > 0)
  668.         return(v-1-(v>>3));
  669.     return(v+1-(v>>3));
  670. }
  671.  
  672.  
  673.  
  674. // this is from the Think C reference code example ...
  675. unsigned short RangedRdm( unsigned short min, unsigned short max )
  676. /* assume that min is less than max */
  677. {
  678.     // uh ... not this isn't quite right - it's between 0 and 65535, not 65536
  679.     unsigned    qdRdm;    /* treat return value as 0-65536 */
  680.     long    range, t;
  681.     
  682.     // just to be safe, I'll put this here
  683.     if (min > max) {
  684.         DebugStr("\pMin greater then Max in RangedRdm. Type 'G' and return to continue.");
  685.         return min;
  686.     }
  687.     
  688.     qdRdm = Random();
  689.     range = max - min;
  690.     // max - min gives us the the difference between max and min ... that is 
  691.     // not inclusive. It gives us { min <= range < max }
  692.     // so we never see that max number!!
  693.     range++;
  694.     t = ((long)qdRdm * range) / 65536;     /* now 0 <= t <= range */
  695.     return( t+min );
  696. }
  697.  
  698. // ONLY works with color QD - CHECK first!
  699. void 
  700. SetRGBColor( void) {
  701. RGBColor    r;
  702.  
  703. //#define MIN_VALUE    32767    // brigher colors :)
  704. //#define MIN_VALUE 16384
  705. //#define MIN_VALUE 8192
  706. //#define MIN_VALUE 4096
  707. #define MIN_VALUE 2048
  708.  
  709.     r.red = (unsigned short) RangedRdm( MIN_VALUE, 65535);
  710.     r.green = (unsigned short) RangedRdm( MIN_VALUE, 65535);
  711.     r.blue = (unsigned short) RangedRdm( MIN_VALUE, 65535);
  712.     
  713.     RGBForeColor(&r);
  714.  
  715. }
  716.  
  717.  
  718.  
  719. void
  720. ChooseFace(GMParamBlockPtr params, infostructPtr info ) {
  721.  
  722. // ditch old ...
  723.     if (info->faceSICN != NULL) {
  724.         ReleaseResource( info->faceSICN);
  725.         info->faceSICN = NULL;
  726.     }
  727.     if (info->sndBounce != NULL) {
  728.         ReleaseResource( info->sndBounce);
  729.         info->sndBounce = NULL;
  730.     }
  731.     if (info->sndScream != NULL) {
  732.         ReleaseResource( info->sndScream);
  733.         info->sndScream = NULL;
  734.     }
  735.  
  736. // get new ...
  737.     info->faceSICN = GetResource('SICN', BASE_FACE_ID + info->whichFace);
  738.     
  739.     if (info->faceSICN != (Handle)NULL) {
  740.         MoveHHi( info->faceSICN );
  741.         info->numFaces = SizeResource( info->faceSICN ) / sizeof(sicnStruct) ;
  742.         info->face.baseAddr = *info->faceSICN;
  743.         info->face.rowBytes = 2;
  744.         SetRect( &(info->face.bounds), 0, 0, 16, 16);
  745.         info->curFace = info->lastFace = 0;
  746.         
  747.     } else { // fall back to the default, hard-coded facebits
  748.         SysBeep(0);
  749.         // set up the bitmap
  750.         info->face.baseAddr = (QDPtr) &facebits[0];
  751.         info->face.rowBytes = 2;
  752.         SetRect( &(info->face.bounds), 0, 0, 16, 16);
  753.         info->curFace = info->lastFace = 0;
  754.         info->numFaces = 1;
  755.     }
  756.  
  757.             
  758. // sound?
  759.     if (params->systemConfig & SoundAvailable)  {
  760.         info->sndBounce = GetResource('snd ', BOING_SOUND_ID + info->whichFace);
  761.         info->sndScream = GetResource('snd ', SCREAM_SOUND_ID);
  762.     } else {
  763.         info->sndBounce = NULL;
  764.         info->sndScream = NULL;
  765.     }
  766.     
  767.     if (info->sndBounce != (Handle)NULL || info->sndScream != (Handle)NULL ) 
  768.         info->soundInfo = OpenSound(params);
  769.     else 
  770.         info->soundInfo = NULL;
  771.  
  772. }