home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Glypha 3v2 / GlyphaIII Code ƒ / Graphics.c < prev    next >
Encoding:
Text File  |  1995-06-30  |  39.9 KB  |  1,140 lines  |  [TEXT/CWIE]

  1.  
  2. //============================================================================
  3. //----------------------------------------------------------------------------
  4. //                                    Graphics.c
  5. //----------------------------------------------------------------------------
  6. //============================================================================
  7.  
  8. // I like to isolate all the graphic routines - put them in their own file.
  9. // This way all the thousands of Rect variables and Pixmaps have a place to go.
  10. // Anyway, this file contains all the drawing routines.
  11.  
  12. #include "Externs.h"
  13. #include <Palettes.h>
  14.  
  15.  
  16. #define kUpperEyeHeight            100
  17. #define kLowerEyeHeight            200
  18. #define kNumLightningPts        8
  19. #define kMaxNumUpdateRects        32
  20.  
  21.  
  22. void QuickUnionRect (Rect *, Rect *, Rect *);
  23. void CheckPlayerWrapAround (void);
  24. void DrawHand (void);
  25. void DrawEye (void);
  26. void DrawPlayer (void);
  27. void CheckEnemyWrapAround (short);
  28. void DrawEnemies (void);
  29.  
  30.  
  31. Rect        backSrcRect, workSrcRect, obSrcRect, playerSrcRect;
  32. Rect        numberSrcRect, idleSrcRect, enemyWalkSrcRect, enemyFlySrcRect;
  33. Rect        obeliskRects[4], playerRects[11], numbersSrc[11], numbersDest[11];
  34. Rect        updateRects1[kMaxNumUpdateRects], updateRects2[kMaxNumUpdateRects];
  35. Rect        flameSrcRect, flameDestRects[2], flameRects[4], eggSrcRect;
  36. Rect        platformSrcRect, platformCopyRects[9], helpSrcRect, eyeSrcRect;
  37. Rect        helpSrc, helpDest, handSrcRect, handRects[2], eyeRects[4];
  38. Point        leftLightningPts[kNumLightningPts], rightLightningPts[kNumLightningPts];
  39. CGrafPtr    backSrcMap, workSrcMap, obeliskSrcMap, playerSrcMap, eyeSrcMap;
  40. CGrafPtr    numberSrcMap, idleSrcMap, enemyWalkSrcMap, enemyFlySrcMap;
  41. CGrafPtr    flameSrcMap, eggSrcMap, platformSrcMap, helpSrcMap, handSrcMap;
  42. GrafPtr        playerMaskMap, enemyWalkMaskMap, enemyFlyMaskMap, eggMaskMap;
  43. GrafPtr        handMaskMap, eyeMaskMap;
  44. RgnHandle    playRgn;
  45. short        numUpdateRects1, numUpdateRects2;
  46. Boolean        whichList, helpOpen, scoresOpen;
  47.  
  48. extern    handInfo    theHand;
  49. extern    eyeInfo        theEye;
  50. extern    prefsInfo    thePrefs;
  51. extern    playerType    thePlayer;
  52. extern    enemyType    theEnemies[];
  53. extern    Rect        enemyRects[24];
  54. extern    WindowPtr    mainWindow;
  55. extern    long        theScore, wasTensOfThousands;
  56. extern    short        livesLeft, levelOn, numEnemies;
  57. extern    Boolean        evenFrame;
  58.  
  59.  
  60. //==============================================================  Functions
  61. //--------------------------------------------------------------  DrawPlatforms
  62.  
  63. // This function draws all the platforms on the background pixmap and the…
  64. // work pixmap.  It needs to know merely how many of them to draw.
  65.  
  66. void DrawPlatforms (short howMany)
  67. {
  68.     if (howMany > 3)            // If there are more than 3 platforms…
  69.     {                            // Draw a platform to background pixmap.
  70.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  71.                 &((GrafPtr)backSrcMap)->portBits, 
  72.                 &platformCopyRects[2], &platformCopyRects[7], srcCopy, playRgn);
  73.                                 // Draw a platform to work pixmap.
  74.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  75.                 &((GrafPtr)workSrcMap)->portBits, 
  76.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, playRgn);
  77.                                 // Add rectangle to update list to be drawn to screen.
  78.         AddToUpdateRects(&platformCopyRects[7]);
  79.                                 // Ditto for a second platform.
  80.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  81.                 &((GrafPtr)backSrcMap)->portBits, 
  82.                 &platformCopyRects[4], &platformCopyRects[8], srcCopy, playRgn);
  83.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  84.                 &((GrafPtr)workSrcMap)->portBits, 
  85.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, playRgn);
  86.         AddToUpdateRects(&platformCopyRects[8]);
  87.     }
  88.     else                        // If there are 3 or less platforms…
  89.     {
  90.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  91.                 &((GrafPtr)backSrcMap)->portBits, 
  92.                 &platformCopyRects[3], &platformCopyRects[7], srcCopy, playRgn);
  93.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  94.                 &((GrafPtr)workSrcMap)->portBits, 
  95.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, playRgn);
  96.         AddToUpdateRects(&platformCopyRects[7]);
  97.         
  98.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  99.                 &((GrafPtr)backSrcMap)->portBits, 
  100.                 &platformCopyRects[5], &platformCopyRects[8], srcCopy, playRgn);
  101.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  102.                 &((GrafPtr)workSrcMap)->portBits, 
  103.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, playRgn);
  104.         AddToUpdateRects(&platformCopyRects[8]);
  105.     }
  106.     
  107.     if (howMany > 5)        // If there are more than 5 platforms…
  108.     {
  109.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  110.                 &((GrafPtr)backSrcMap)->portBits, 
  111.                 &platformCopyRects[0], &platformCopyRects[6], srcCopy, playRgn);
  112.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  113.                 &((GrafPtr)workSrcMap)->portBits, 
  114.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, playRgn);
  115.         AddToUpdateRects(&platformCopyRects[6]);
  116.     }
  117.     else                    // If there are 5 or less platforms…
  118.     {
  119.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  120.                 &((GrafPtr)backSrcMap)->portBits, 
  121.                 &platformCopyRects[1], &platformCopyRects[6], srcCopy, playRgn);
  122.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  123.                 &((GrafPtr)workSrcMap)->portBits, 
  124.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, playRgn);
  125.         AddToUpdateRects(&platformCopyRects[6]);
  126.     }
  127. }
  128.  
  129. //--------------------------------------------------------------  ScrollHelp
  130.  
  131. // This function scrolls the help screen.  You pass it a number of pixels…
  132. // to scroll up or down (positive or negative number).
  133.  
  134. void ScrollHelp (short scrollDown)
  135. {
  136.     OffsetRect(&helpSrc, 0, scrollDown);        // Move the source rectangle.
  137.     
  138.     if (helpSrc.bottom > 398)                    // Check to see we don't go too far.
  139.     {
  140.         helpSrc.bottom = 398;
  141.         helpSrc.top = helpSrc.bottom - 199;
  142.     }
  143.     else if (helpSrc.top < 0)
  144.     {
  145.         helpSrc.top = 0;
  146.         helpSrc.bottom = helpSrc.top + 199;
  147.     }
  148.                                                 // Draw "scrolled" help screen.
  149.     CopyBits(&((GrafPtr)helpSrcMap)->portBits, 
  150.             &(((GrafPtr)mainWindow)->portBits), 
  151.             &helpSrc, &helpDest, srcCopy, 0L);
  152. }
  153.  
  154. //--------------------------------------------------------------  OpenHelp
  155.  
  156. // Bring up the help screen.  This is a kind of "wipe" or "barn door" effect.
  157.  
  158. void OpenHelp (void)
  159. {
  160.     Rect        wallSrc, wallDest;
  161.     short        i;
  162.     
  163.     SetRect(&helpSrc, 0, 0, 231, 0);    // Initialize source and destination rects.
  164.     helpDest = helpSrc;
  165.     OffsetRect(&helpDest, 204, 171);
  166.     
  167.     SetRect(&wallSrc, 0, 0, 231, 199);
  168.     OffsetRect(&wallSrc, 204, 171);
  169.     wallDest = wallSrc;
  170.     
  171.     for (i = 0; i < 199; i ++)            // Loop through 1 pixel at a time.
  172.     {
  173.         LogNextTick(1L);                // Speed governor.
  174.         helpSrc.bottom++;                // Grow help source rect.
  175.         helpDest.bottom++;                // Grow help dest as well.
  176.         wallSrc.bottom--;                // Shrink wall source.
  177.         wallDest.top++;                    // Shrink wall dest.
  178.         
  179.                                         // So, as the help graphic grows, the wall graphic…
  180.                                         // shrinks.  Thus it is as though the wall is…
  181.                                         // lifting up to expose the help screen beneath.
  182.         
  183.                                         // Copy slightly larger help screen.
  184.         CopyBits(&((GrafPtr)helpSrcMap)->portBits, 
  185.                 &(((GrafPtr)mainWindow)->portBits), 
  186.                 &helpSrc, &helpDest, srcCopy, 0L);
  187.                                         // Copy slightly smaller wall graphic.
  188.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  189.                 &(((GrafPtr)mainWindow)->portBits), 
  190.                 &wallSrc, &wallDest, srcCopy, 0L);
  191.         
  192.         WaitForNextTick();                // Speed governor.
  193.     }
  194.     helpOpen = TRUE;                    // When done, set flag to indicate help is open.
  195. }
  196.  
  197. //--------------------------------------------------------------  CloseWall
  198.  
  199. // Close the wall over whatever screen is up (help screen or high scores).
  200. // Since the wall just comes down over the opening - covering whatever was beneath,…
  201. // it's simpler than the above function.
  202.  
  203. void CloseWall (void)
  204. {
  205.     Rect        wallSrc, wallDest;
  206.     short        i;
  207.     
  208.     SetRect(&wallSrc, 0, 0, 231, 0);    // Initialize source and dest rects.
  209.     wallDest = wallSrc;
  210.     OffsetRect(&wallDest, 204, 370);
  211.     OffsetRect(&wallSrc, 204, 171);
  212.     
  213.     for (i = 0; i < 199; i ++)            // Do it one pixel at a time.
  214.     {
  215.         wallSrc.bottom++;                // Grow bottom of wall source.
  216.         wallDest.top--;                    // Move down wall dest.
  217.                                         // Draw wall coming down.
  218.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  219.                 &(((GrafPtr)mainWindow)->portBits), 
  220.                 &wallSrc, &wallDest, srcCopy, 0L);
  221.     }                                    // Note, no speed governing (why bother?).
  222. }
  223.  
  224. //--------------------------------------------------------------  OpenHighScores
  225.  
  226. // This function is practically identical to the OpenHelp().  The only real…
  227. // difference is that we must first draw all the high scores offscreen before…
  228. // lifting the wall to reveal them.
  229.  
  230. void OpenHighScores (void)
  231. {
  232.     RGBColor    theRGBColor, wasColor;
  233.     Rect        wallSrc, wallDest;
  234.     Rect        scoreSrc, scoreDest;
  235.     Str255        scoreStr;
  236.     short        i, scoreWide;
  237.     
  238.     SetRect(&scoreSrc, 0, 0, 231, 0);                // Initialize source and dest rects.
  239.     OffsetRect(&scoreSrc, 204, 171);
  240.     scoreDest = scoreSrc;
  241.     
  242.     SetRect(&wallSrc, 0, 0, 231, 199);
  243.     OffsetRect(&wallSrc, 204, 171);
  244.     wallDest = wallSrc;
  245.     
  246.     SetPort((GrafPtr)workSrcMap);                    // We'll draw scores to the work pixmap.
  247.     PaintRect(&wallSrc);                            // Paint it black.
  248.     
  249.     GetForeColor(&wasColor);                        // Save the foreground color.
  250.     
  251.     TextFont(geneva);                                // Use Geneva 12 point Bold font.
  252.     TextSize(12);
  253.     TextFace(bold);
  254.     
  255.     Index2Color(132, &theRGBColor);                    // Get the 132nd color in RGB form.
  256.     RGBForeColor(&theRGBColor);                        // Make this color the pen color.
  257.     MoveTo(scoreSrc.left + 36, scoreSrc.top + 20);    // Get pen in right position to draw.
  258.     DrawString("\pGlypha III High Scores");            // Draw the title.
  259.     
  260.     TextFont(geneva);                                // Use Geneva 9 point Bold font.
  261.     TextSize(9);
  262.     TextFace(bold);
  263.     
  264.     for (i = 0; i < 10; i++)                        // Walk through all 10 high scores.
  265.     {
  266.         Index2Color(133, &theRGBColor);                // Use color 133 (in palette).
  267.         RGBForeColor(&theRGBColor);
  268.         NumToString((long)i + 1L, scoreStr);        // Draw "place" (1, 2, 3, …).
  269.         MoveTo(scoreSrc.left + 8, scoreSrc.top + 40 + (i * 16));
  270.         DrawString(scoreStr);
  271.         
  272.         Index2Color(128, &theRGBColor);                // Use color 128 (from palette).
  273.         RGBForeColor(&theRGBColor);
  274.         MoveTo(scoreSrc.left + 32, scoreSrc.top + 40 + (i * 16));
  275.         DrawString(thePrefs.highNames[i]);            // Draw the high score name (Sue, …).
  276.         
  277.         Index2Color(164, &theRGBColor);                // Use color 164 (from palette).
  278.         RGBForeColor(&theRGBColor);
  279.         NumToString(thePrefs.highScores[i], scoreStr);
  280.         scoreWide = StringWidth(scoreStr);            // Right justify.
  281.         MoveTo(scoreSrc.left + 191 - scoreWide, scoreSrc.top + 40 + (i * 16));
  282.         DrawString(scoreStr);                        // Draw the high score (12,000, …).
  283.         
  284.         Index2Color(134, &theRGBColor);                // Use color 134 (from palette).
  285.         RGBForeColor(&theRGBColor);
  286.         NumToString(thePrefs.highLevel[i], scoreStr);
  287.         scoreWide = StringWidth(scoreStr);            // Right justify.
  288.         MoveTo(scoreSrc.left + 223 - scoreWide, scoreSrc.top + 40 + (i * 16));
  289.         DrawString(scoreStr);                        // Draw highest level (12, 10, …).
  290.     }
  291.     
  292.     RGBForeColor(&wasColor);                        // Restore foreground color.
  293.     
  294.     SetPort((GrafPtr)mainWindow);
  295.     
  296.     for (i = 0; i < 199; i ++)                        // Now the standard scroll functions.
  297.     {
  298.         LogNextTick(1L);
  299.         scoreSrc.bottom++;
  300.         scoreDest.bottom++;
  301.         wallSrc.bottom--;
  302.         wallDest.top++;
  303.         
  304.         CopyBits(&((GrafPtr)workSrcMap)->portBits, 
  305.                 &(((GrafPtr)mainWindow)->portBits), 
  306.                 &scoreSrc, &scoreDest, srcCopy, 0L);
  307.         
  308.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  309.                 &(((GrafPtr)mainWindow)->portBits), 
  310.                 &wallSrc, &wallDest, srcCopy, 0L);
  311.         
  312.         WaitForNextTick();
  313.     }
  314.     
  315.     scoresOpen = TRUE;                                // Flag that the scores are up.
  316. }
  317.  
  318. //--------------------------------------------------------------  UpdateLivesNumbers
  319.  
  320. // During a game, this function is called to reflect the current number of lives.
  321. // This is "lives remaining", so 1 is subtracted before displaying it to the screen.
  322. // The lives is "wrapped around" after 99.  So 112 lives will display as 12.  It's…
  323. // a lot easier to handle numbers this way (it beats a recursive function that might…
  324. // potentially draw across the entire screen.
  325.  
  326. void UpdateLivesNumbers (void)
  327. {
  328.     short        digit;
  329.     
  330.     digit = (livesLeft - 1) / 10;        // Get the "10's" digit.
  331.     digit = digit % 10L;                // Keep it less than 10 (0 -> 9).
  332.     if ((digit == 0) && ((livesLeft - 1) < 10))
  333.         digit = 10;                        // Use a "blank" space if zero and less than 10.
  334.                                         // Draw digit.
  335.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  336.             &((GrafPtr)backSrcMap)->portBits, 
  337.             &numbersSrc[digit], &numbersDest[0], srcCopy, 0L);
  338.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  339.             &(((GrafPtr)mainWindow)->portBits), 
  340.             &numbersDest[0], &numbersDest[0], srcCopy, 0L);
  341.     
  342.     digit = (livesLeft - 1) % 10;        // Get 1's digit.
  343.                                         // Draw digit.
  344.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  345.             &((GrafPtr)backSrcMap)->portBits, 
  346.             &numbersSrc[digit], &numbersDest[1], srcCopy, 0L);
  347.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  348.             &(((GrafPtr)mainWindow)->portBits), 
  349.             &numbersDest[1], &numbersDest[1], srcCopy, 0L);
  350. }
  351.  
  352. //--------------------------------------------------------------  UpdateScoreNumbers
  353.  
  354. // This function works just like the above function.  However, we allow the…
  355. // score to go to 6 digits (999,999) before rolling over.  Note however, that…
  356. // in both the case of the score, number of lives, etc., the game does in fact…
  357. // keep track of the "actual" number.  It is just that only so many digits are…
  358. // being displayed.
  359.  
  360. void UpdateScoreNumbers (void)
  361. {
  362.     long        digit;
  363.     
  364.     digit = theScore / 100000L;        // Get "hundreds of thousands" digit.
  365.     digit = digit % 10L;            // Clip off anything greater than 9.
  366.     if ((digit == 0) && (theScore < 1000000L))
  367.         digit = 10;                    // Use blank space if zero.
  368.                                     // Draw digit.
  369.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  370.             &((GrafPtr)backSrcMap)->portBits, 
  371.             &numbersSrc[digit], &numbersDest[2], srcCopy, 0L);
  372.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  373.             &(((GrafPtr)mainWindow)->portBits), 
  374.             &numbersDest[2], &numbersDest[2], srcCopy, 0L);
  375.     
  376.     digit = theScore / 10000L;        // Get "tens of thousands" digit.
  377.     if (digit > wasTensOfThousands)    // Check for "extra life" here.
  378.     {
  379.         livesLeft++;                // Increment number of lives.
  380.         UpdateLivesNumbers();        // Reflect new lives on screen.
  381.         wasTensOfThousands = digit;    // Note that life was given.
  382.     }
  383.     digit = digit % 10L;            // Clip off anything greater than 9.
  384.     if ((digit == 0) && (theScore < 100000L))
  385.         digit = 10;                    // Use blank space if zero.
  386.                                     // Draw digit.
  387.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  388.             &((GrafPtr)backSrcMap)->portBits, 
  389.             &numbersSrc[digit], &numbersDest[3], srcCopy, 0L);
  390.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  391.             &(((GrafPtr)mainWindow)->portBits), 
  392.             &numbersDest[3], &numbersDest[3], srcCopy, 0L);
  393.     
  394.     digit = theScore / 1000L;        // Handle "thousands" digit.
  395.     digit = digit % 10L;
  396.     if ((digit == 0) && (theScore < 10000L))
  397.         digit = 10;
  398.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  399.             &((GrafPtr)backSrcMap)->portBits, 
  400.             &numbersSrc[digit], &numbersDest[4], srcCopy, 0L);
  401.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  402.             &(((GrafPtr)mainWindow)->portBits), 
  403.             &numbersDest[4], &numbersDest[4], srcCopy, 0L);
  404.     
  405.     digit = theScore / 100L;        // Handle 100's digit.
  406.     digit = digit % 10L;
  407.     if ((digit == 0) && (theScore < 1000L))
  408.         digit = 10;
  409.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  410.             &((GrafPtr)backSrcMap)->portBits, 
  411.             &numbersSrc[digit], &numbersDest[5], srcCopy, 0L);
  412.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  413.             &(((GrafPtr)mainWindow)->portBits), 
  414.             &numbersDest[5], &numbersDest[5], srcCopy, 0L);
  415.     
  416.     digit = theScore / 10L;            // Handle 10's digit.
  417.     digit = digit % 10L;
  418.     if ((digit == 0) && (theScore < 100L))
  419.         digit = 10;
  420.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  421.             &((GrafPtr)backSrcMap)->portBits, 
  422.             &numbersSrc[digit], &numbersDest[6], srcCopy, 0L);
  423.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  424.             &(((GrafPtr)mainWindow)->portBits), 
  425.             &numbersDest[6], &numbersDest[6], srcCopy, 0L);
  426.     
  427.     digit = theScore % 10L;            // Handle 1's digit.
  428.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  429.             &((GrafPtr)backSrcMap)->portBits, 
  430.             &numbersSrc[digit], &numbersDest[7], srcCopy, 0L);
  431.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  432.             &(((GrafPtr)mainWindow)->portBits), 
  433.             &numbersDest[7], &numbersDest[7], srcCopy, 0L);
  434. }
  435.  
  436. //--------------------------------------------------------------  UpdateLevelNumbers
  437.  
  438. // Blah, blah, blah.  Just like the above functions but handles displaying the…
  439. // level the player is on.  We allow 3 digits here (up to 999) before wrapping.
  440.  
  441. void UpdateLevelNumbers (void)
  442. {
  443.     short        digit;
  444.     
  445.     digit = (levelOn + 1) / 100;        // Do 100's digit.
  446.     digit = digit % 10L;
  447.     if ((digit == 0) && ((levelOn + 1) < 1000))
  448.         digit = 10;
  449.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  450.             &((GrafPtr)backSrcMap)->portBits, 
  451.             &numbersSrc[digit], &numbersDest[8], srcCopy, 0L);
  452.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  453.             &(((GrafPtr)mainWindow)->portBits), 
  454.             &numbersDest[8], &numbersDest[8], srcCopy, 0L);
  455.     
  456.     digit = (levelOn + 1) / 10;            // Do 10's digit.
  457.     digit = digit % 10L;
  458.     if ((digit == 0) && ((levelOn + 1) < 100))
  459.         digit = 10;
  460.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  461.             &((GrafPtr)backSrcMap)->portBits, 
  462.             &numbersSrc[digit], &numbersDest[9], srcCopy, 0L);
  463.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  464.             &(((GrafPtr)mainWindow)->portBits), 
  465.             &numbersDest[9], &numbersDest[9], srcCopy, 0L);
  466.     
  467.     digit = (levelOn + 1) % 10;            // Do 1's digit.
  468.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  469.             &((GrafPtr)backSrcMap)->portBits, 
  470.             &numbersSrc[digit], &numbersDest[10], srcCopy, 0L);
  471.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  472.             &(((GrafPtr)mainWindow)->portBits), 
  473.             &numbersDest[10], &numbersDest[10], srcCopy, 0L);
  474. }
  475.  
  476. //--------------------------------------------------------------  GenerateLightning
  477.  
  478. // This function takes a point (h and v) and then generates two lightning bolts…
  479. // (one from the tip of each obelisk) to the point.  It does this by generating…
  480. // a list of segments (as the lightning is broken up into segements).  The drawing…
  481. // counterpart to this function will draw a line connecting these segements (a sort…
  482. // of dot-to-dot).
  483.  
  484. void GenerateLightning (short h, short v)
  485. {
  486.     #define kLeftObeliskH        172
  487.     #define kLeftObeliskV        250
  488.     #define kRightObeliskH        468
  489.     #define kRightObeliskV        250
  490.     #define kWander                16
  491.     
  492.     short        i, leftDeltaH, rightDeltaH, leftDeltaV, rightDeltaV, range;
  493.     
  494.     leftDeltaH = h - kLeftObeliskH;                // Determine the h and v distances between…
  495.     rightDeltaH = h - kRightObeliskH;            // obelisks and the target point.
  496.     leftDeltaV = v - kLeftObeliskV;
  497.     rightDeltaV = v - kRightObeliskV;
  498.     
  499.     for (i = 0; i < kNumLightningPts; i++)        // Calculate an even spread of points between…
  500.     {                                            // obelisk tips and the target point.
  501.         leftLightningPts[i].h = (leftDeltaH * i) / (kNumLightningPts - 1) + kLeftObeliskH;
  502.         leftLightningPts[i].v = (leftDeltaV * i) / (kNumLightningPts - 1) + kLeftObeliskV;
  503.         rightLightningPts[i].h = (rightDeltaH * i) / (kNumLightningPts - 1) + kRightObeliskH;
  504.         rightLightningPts[i].v = (rightDeltaV * i) / (kNumLightningPts - 1) + kRightObeliskV;
  505.     }
  506.     
  507.     range = kWander * 2 + 1;                    // Randomly scatter the points vertically…
  508.     for (i = 1; i < kNumLightningPts - 1; i++)    // but NOT the 1st or last points.
  509.     {
  510.         leftLightningPts[i].v += RandomInt(range) - kWander;
  511.         rightLightningPts[i].v += RandomInt(range) - kWander;
  512.     }
  513. }
  514.  
  515. //--------------------------------------------------------------  FlashObelisks
  516.  
  517. // This function either draws the obelisks "normal" or draws them inverted.
  518. // They're drawn "inverted" as if emanating energy or lit up by the bolts…
  519. // of lightning.  The flag "flashThem" specifies how to draw them.
  520.  
  521. void FlashObelisks (Boolean flashThem)
  522. {    
  523.     if (flashThem)        // Draw them "inverted"
  524.     {
  525.         CopyBits(&((GrafPtr)obeliskSrcMap)->portBits, 
  526.                 &(((GrafPtr)mainWindow)->portBits), 
  527.                 &obeliskRects[0], &obeliskRects[2], 
  528.                 srcCopy, 0L);
  529.         CopyBits(&((GrafPtr)obeliskSrcMap)->portBits, 
  530.                 &(((GrafPtr)mainWindow)->portBits), 
  531.                 &obeliskRects[1], &obeliskRects[3], 
  532.                 srcCopy, 0L);
  533.     }
  534.     else            // Draw them "normal"
  535.     {
  536.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  537.                 &(((GrafPtr)mainWindow)->portBits), 
  538.                 &obeliskRects[2], &obeliskRects[2], 
  539.                 srcCopy, 0L);
  540.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  541.                 &(((GrafPtr)mainWindow)->portBits), 
  542.                 &obeliskRects[3], &obeliskRects[3], 
  543.                 srcCopy, 0L);
  544.     }
  545. }
  546.  
  547. //--------------------------------------------------------------  StrikeLightning
  548.  
  549. // This function draws the lightning bolts.  The PenMode() is set to patXOr…
  550. // so that the lines are drawn inverted (colorwise).  This way, drawing the…
  551. // lightning twice over will leave no pixels disturbed.
  552.  
  553. void StrikeLightning (void)
  554. {
  555.     short        i;
  556.     
  557.     SetPort((GrafPtr)mainWindow);                // Draw straight to screen.
  558.     PenSize(1, 2);                                // Use a tall pen.
  559.     PenMode(patXor);                            // Use XOR mode.
  560.                                                 // Draw lightning bolts with inverted pen.
  561.     MoveTo(leftLightningPts[0].h, leftLightningPts[0].v);
  562.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw left lightning bolt.
  563.     {
  564.         MoveTo(leftLightningPts[i].h, leftLightningPts[i].v);
  565.         LineTo(leftLightningPts[i + 1].h - 1, leftLightningPts[i + 1].v);
  566.     }
  567.     
  568.     MoveTo(rightLightningPts[0].h, rightLightningPts[0].v);
  569.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw right lightning bolt.
  570.     {
  571.         MoveTo(rightLightningPts[i].h, rightLightningPts[i].v);
  572.         LineTo(rightLightningPts[i + 1].h - 1, rightLightningPts[i + 1].v);
  573.     }
  574.     
  575.     PenNormal();                                // Return pen to normal.
  576. }
  577.  
  578. //--------------------------------------------------------------  DumpBackToWorkMap
  579.  
  580. // Simple handy function that copies the entire background pixmap to the…
  581. // work pixmap.
  582.  
  583. void DumpBackToWorkMap (void)
  584. {
  585.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  586.             &((GrafPtr)workSrcMap)->portBits, 
  587.             &backSrcRect, &backSrcRect, srcCopy, 0L);
  588. }
  589.  
  590. //--------------------------------------------------------------  DumpBackToWorkMap
  591.  
  592. // Simple handy function that copies the entire work pixmap to the…
  593. // screen.
  594.  
  595. void DumpMainToWorkMap (void)
  596. {
  597.     CopyBits(&(((GrafPtr)mainWindow)->portBits), 
  598.             &((GrafPtr)workSrcMap)->portBits, 
  599.             &backSrcRect, &backSrcRect, srcCopy, 0L);
  600. }
  601.  
  602. //--------------------------------------------------------------  QuickUnionRect
  603.  
  604. // The Mac Toolbox gives you a UnionRect() function, but, like any Toolbox…
  605. // routine, if we can do it faster, we ought to.  Well, the function below…
  606. // is quick because (among other reasons), it assumes that the two rects…
  607. // being compared are the same size.
  608.  
  609. void QuickUnionRect (Rect *rect1, Rect *rect2, Rect *whole)
  610. {
  611.     if (rect1->left < rect2->left)        // See if we're to use rect1's left.
  612.     {
  613.         whole->left = rect1->left;
  614.         whole->right = rect2->right;
  615.     }
  616.     else                                // Use rect2's left.
  617.     {
  618.         whole->left = rect2->left;
  619.         whole->right = rect1->right;
  620.     }
  621.     
  622.     if (rect1->top < rect2->top)        // See if we're to use rect1's top.
  623.     {
  624.         whole->top = rect1->top;
  625.         whole->bottom = rect2->bottom;
  626.     }
  627.     else                                // Use rect2's top.
  628.     {
  629.         whole->top = rect2->top;
  630.         whole->bottom = rect1->bottom;
  631.     }
  632. }
  633.  
  634. //--------------------------------------------------------------  AddToUpdateRects
  635.  
  636. // This is an elegant way to handle game animation.  It has some drawbacks, but…
  637. // for ease of use, you may not be able to beat it.  The idea is that any time…
  638. // you want something drawn to the screen (copied from an offscreen pixmap to…
  639. // the screen) you pass the rectangle to this routine.  This routine then adds…
  640. // the rectangle to a growing list of these rectangles.  When the game reaches…
  641. // drawing phase, another routine copies all these rectangles.  It is assumed, …
  642. // nonetheless, that you have copied the little graphic offscreen that you want…
  643. // moved to the screen (the shpinx or whatever).  This routine will take care of…
  644. // drawing the shinx or whatever to the screen.
  645.  
  646. void AddToUpdateRects (Rect *theRect)
  647. {
  648.     if (whichList)        // We alternate every odd frame between two lists…
  649.     {                    // in order to hold a copy of rects from last frame.
  650.         if (numUpdateRects1 < (kMaxNumUpdateRects - 1))
  651.         {                // If we are below the maximum # of rects we can handle…
  652.                         // Add the rect to the list (array).
  653.             updateRects1[numUpdateRects1] = *theRect;
  654.                         // Increment the number of rects held in list.
  655.             numUpdateRects1++;
  656.                         // Do simple bounds checking (clip to screen).
  657.             if (updateRects1[numUpdateRects1].left < 0)
  658.                 updateRects1[numUpdateRects1].left = 0;
  659.             else if (updateRects1[numUpdateRects1].right > 640)
  660.                 updateRects1[numUpdateRects1].right = 640;
  661.             if (updateRects1[numUpdateRects1].top < 0)
  662.                 updateRects1[numUpdateRects1].top = 0;
  663.             else if (updateRects1[numUpdateRects1].bottom > 480)
  664.                 updateRects1[numUpdateRects1].bottom = 480;
  665.         }
  666.     }
  667.     else                // Exactly like the above section, but with the other list.
  668.     {
  669.         if (numUpdateRects2 < (kMaxNumUpdateRects - 1))
  670.         {
  671.             updateRects2[numUpdateRects2] = *theRect;
  672.             numUpdateRects2++;
  673.             if (updateRects2[numUpdateRects2].left < 0)
  674.                 updateRects2[numUpdateRects2].left = 0;
  675.             else if (updateRects2[numUpdateRects2].right > 640)
  676.                 updateRects2[numUpdateRects2].right = 640;
  677.             if (updateRects2[numUpdateRects2].top < 0)
  678.                 updateRects2[numUpdateRects2].top = 0;
  679.             else if (updateRects2[numUpdateRects2].bottom > 480)
  680.                 updateRects2[numUpdateRects2].bottom = 480;
  681.         }
  682.     }
  683. }
  684.  
  685. //--------------------------------------------------------------  CheckPlayerWrapAround
  686.  
  687. // This handles drawing wrap-around.  It is such that, when a player walks partly…
  688. // off the right edge of the screen, you see the player peeking through on the left…
  689. // side of the screen.  Since we can't (shouldn't) assume that the physical screen…
  690. // memory wraps around, we'll draw the right player clipped against the right edge…
  691. // of the screen and draw a SECOND PLAYER on the left edge (clipped to the left).
  692.  
  693. void CheckPlayerWrapAround (void)
  694. {
  695.     Rect        wrapRect, wasWrapRect, src;
  696.     
  697.     if (thePlayer.dest.right > 640)        // Player off right edge of screen.
  698.     {
  699.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  700.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  701.         wrapRect.left -= 640;            // Offset it a screenwidth to left.
  702.         wrapRect.right -= 640;
  703.                                         // Ditto with old location.
  704.         wasWrapRect = thePlayer.wasDest;
  705.         wasWrapRect.left -= 640;
  706.         wasWrapRect.right -= 640;
  707.         
  708.         if (thePlayer.mode == kBones)    // Draw second bones.
  709.         {
  710.             src = playerRects[thePlayer.srcNum];
  711.             src.bottom = src.top + thePlayer.frame;
  712.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  713.                     &((GrafPtr)playerMaskMap)->portBits, 
  714.                     &((GrafPtr)workSrcMap)->portBits, 
  715.                     &src, &src, &wrapRect);
  716.         }
  717.         else                            // Draw second player (not bones).
  718.         {
  719.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  720.                     &((GrafPtr)playerMaskMap)->portBits, 
  721.                     &((GrafPtr)workSrcMap)->portBits, 
  722.                     &playerRects[thePlayer.srcNum], 
  723.                     &playerRects[thePlayer.srcNum], 
  724.                     &wrapRect);
  725.         }
  726.         thePlayer.wrap = wrapRect;
  727.         AddToUpdateRects(&wrapRect);    // Add this to our list of update rects.
  728.     }
  729.     else if (thePlayer.dest.left < 0)    // Else if off the left edge…
  730.     {
  731.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  732.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  733.         wrapRect.left += 640;            // Offset it a screenwidth to right.
  734.         wrapRect.right += 640;
  735.                                         // Ditto with old location.
  736.         wasWrapRect = thePlayer.wasDest;
  737.         wasWrapRect.left += 640;
  738.         wasWrapRect.right += 640;
  739.         
  740.         if (thePlayer.mode == kBones)    // Draw second bones.
  741.         {
  742.             src = playerRects[thePlayer.srcNum];
  743.             src.bottom = src.top + thePlayer.frame;
  744.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  745.                     &((GrafPtr)playerMaskMap)->portBits, 
  746.                     &((GrafPtr)workSrcMap)->portBits, 
  747.                     &src, &src, &wrapRect);
  748.         }
  749.         else                            // Draw second player (not bones).
  750.         {
  751.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  752.                     &((GrafPtr)playerMaskMap)->portBits, 
  753.                     &((GrafPtr)workSrcMap)->portBits, 
  754.                     &playerRects[thePlayer.srcNum], 
  755.                     &playerRects[thePlayer.srcNum], 
  756.                     &wrapRect);
  757.         }
  758.         thePlayer.wrap = wrapRect;
  759.         AddToUpdateRects(&wrapRect);    // Add this to our list of update rects.
  760.     }
  761.     else
  762.         thePlayer.wrapping = FALSE;        // Otherwise, we're not wrapping.
  763. }
  764.  
  765. //--------------------------------------------------------------  DrawTorches
  766.  
  767. // This handles drawing the two torch's flames.  It chooses randomly from…
  768. // 4 torch graphics and draws right over the old torches.
  769.  
  770. void DrawTorches (void)
  771. {
  772.     short        who;
  773.     
  774.     who = RandomInt(4);
  775.     if (evenFrame)        // Only draw 1 torch - left on even frames…
  776.     {
  777.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  778.                 &((GrafPtr)workSrcMap)->portBits, 
  779.                 &flameRects[who], &flameDestRects[0], srcCopy, 0L);
  780.         AddToUpdateRects(&flameDestRects[0]);
  781.     }
  782.     else                // and draw the right torch on odd frames.
  783.     {                    // We do this even/odd thing for speed.  Why draw both?
  784.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  785.                 &((GrafPtr)workSrcMap)->portBits, 
  786.                 &flameRects[who], &flameDestRects[1], srcCopy, 0L);
  787.         AddToUpdateRects(&flameDestRects[1]);
  788.     }
  789. }
  790.  
  791. //--------------------------------------------------------------  DrawHand
  792.  
  793. // This function takes care of drawing the hand offscreen.  There are only…
  794. // two (well really three) choices - hand open, hand clutching (or no hand…
  795. // in which case both options are skipped).
  796.  
  797. void DrawHand (void)
  798. {
  799.     if (theHand.mode == kOutGrabeth)        // Fingers open.
  800.     {
  801.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  802.                 &((GrafPtr)handMaskMap)->portBits, 
  803.                 &((GrafPtr)workSrcMap)->portBits, 
  804.                 &handRects[0], 
  805.                 &handRects[0], 
  806.                 &theHand.dest);
  807.         AddToUpdateRects(&theHand.dest);
  808.     }
  809.     else if (theHand.mode == kClutching)    // Fingers clenched.
  810.     {
  811.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  812.                 &((GrafPtr)handMaskMap)->portBits, 
  813.                 &((GrafPtr)workSrcMap)->portBits, 
  814.                 &handRects[1], 
  815.                 &handRects[1], 
  816.                 &theHand.dest);
  817.         AddToUpdateRects(&theHand.dest);
  818.     }
  819. }
  820.  
  821. //--------------------------------------------------------------  DrawEye
  822.  
  823. // This function draws the eye (if it's floating about - stalking).
  824.  
  825. void DrawEye (void)
  826. {
  827.     if (theEye.mode == kStalking)
  828.     {
  829.         CopyMask(&((GrafPtr)eyeSrcMap)->portBits, 
  830.                 &((GrafPtr)eyeMaskMap)->portBits, 
  831.                 &((GrafPtr)workSrcMap)->portBits, 
  832.                 &eyeRects[theEye.srcNum], 
  833.                 &eyeRects[theEye.srcNum], 
  834.                 &theEye.dest);
  835.         AddToUpdateRects(&theEye.dest);
  836.     }
  837. }
  838.  
  839. //--------------------------------------------------------------  CopyAllRects
  840.  
  841. // This function goes through the list of "update rects" and copies from an…
  842. // offscreen pixmap to the main screen.  It is at this instant (during the…
  843. // execution of the below function) that the screen actually changes.  The…
  844. // whole rest of Glypha is, in essence, there only to lead up, ultimately, …
  845. // to this function.
  846.  
  847. void CopyAllRects (void)
  848. {
  849.     short        i;
  850.     
  851.     if (whichList)    // Every other frame, we alternate which list we use.
  852.     {                // Copy new graphics to screen (sphinxes, player, etc.).
  853.         for (i = 0; i < numUpdateRects1; i++)
  854.         {
  855.             CopyBits(&((GrafPtr)workSrcMap)->portBits, 
  856.                     &(((GrafPtr)mainWindow)->portBits), 
  857.                     &updateRects1[i], &updateRects1[i], srcCopy, playRgn);
  858.         }
  859.                     // Patch up old graphics from last frame (old sphinx locations, etc.).
  860.         for (i = 0; i < numUpdateRects2; i++)
  861.         {
  862.             CopyBits(&((GrafPtr)workSrcMap)->portBits, 
  863.                     &(((GrafPtr)mainWindow)->portBits), 
  864.                     &updateRects2[i], &updateRects2[i], srcCopy, playRgn);
  865.         }
  866.                     // Clean up offscreen (get rid of sphinxes, etc.).
  867.         for (i = 0; i < numUpdateRects1; i++)
  868.         {
  869.             CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  870.                     &((GrafPtr)workSrcMap)->portBits, 
  871.                     &updateRects1[i], &updateRects1[i], srcCopy, playRgn);
  872.         }
  873.         
  874.         numUpdateRects2 = 0;    // Reset number of rects to zero.
  875.         whichList = !whichList;    // Toggle flag to use other list next frame.
  876.     }
  877.     else
  878.     {                // Copy new graphics to screen (sphinxes, player, etc.).
  879.         for (i = 0; i < numUpdateRects2; i++)
  880.         {
  881.             CopyBits(&((GrafPtr)workSrcMap)->portBits, 
  882.                     &(((GrafPtr)mainWindow)->portBits), 
  883.                     &updateRects2[i], &updateRects2[i], srcCopy, playRgn);
  884.         }
  885.                     // Patch up old graphics from last frame (old sphinx locations, etc.).
  886.         for (i = 0; i < numUpdateRects1; i++)
  887.         {
  888.             CopyBits(&((GrafPtr)workSrcMap)->portBits, 
  889.                     &(((GrafPtr)mainWindow)->portBits), 
  890.                     &updateRects1[i], &updateRects1[i], srcCopy, playRgn);
  891.         }
  892.                     // Clean up offscreen (get rid of sphinxes, etc.).
  893.         for (i = 0; i < numUpdateRects2; i++)
  894.         {
  895.             CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  896.                     &((GrafPtr)workSrcMap)->portBits, 
  897.                     &updateRects2[i], &updateRects2[i], srcCopy, playRgn);
  898.         }
  899.         
  900.         numUpdateRects1 = 0;    // Reset number of rects to zero.
  901.         whichList = !whichList;    // Toggle flag to use other list next frame.
  902.     }
  903. }
  904.  
  905. //--------------------------------------------------------------  DrawPlayer
  906.  
  907. // Although called "DrawPlayer()", this function actually does its drawing…
  908. // offscreen.  It is the above routine that will finally copy our offscreen…
  909. // work to the main screen.  Anyway, the below function draws the player…
  910. // offscreen in the correct position and state.
  911.  
  912. void DrawPlayer (void)
  913. {
  914.     Rect        src;
  915.     
  916.     if ((evenFrame) && (thePlayer.mode == kIdle))
  917.     {            // On even frames, we'll draw the "flashed" graphic of the player.
  918.                 // If you've played Glypha, you notice that the player begins a…
  919.                 // game flashing alternately between bones and a normal player.
  920.         CopyMask(&((GrafPtr)idleSrcMap)->portBits, 
  921.                 &((GrafPtr)playerMaskMap)->portBits, 
  922.                 &((GrafPtr)workSrcMap)->portBits, 
  923.                 &idleSrcRect, 
  924.                 &playerRects[thePlayer.srcNum], 
  925.                 &thePlayer.dest);
  926.     }
  927.     else if (thePlayer.mode == kBones)
  928.     {            // If the player is dead and a pile of bones…
  929.         src = playerRects[thePlayer.srcNum];
  930.         src.bottom = src.top + thePlayer.frame;
  931.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  932.                 &((GrafPtr)playerMaskMap)->portBits, 
  933.                 &((GrafPtr)workSrcMap)->portBits, 
  934.                 &src, &src, &thePlayer.dest);
  935.     }
  936.     else        // Else, if the player is neither idle nor dead…
  937.     {
  938.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  939.                 &((GrafPtr)playerMaskMap)->portBits, 
  940.                 &((GrafPtr)workSrcMap)->portBits, 
  941.                 &playerRects[thePlayer.srcNum], 
  942.                 &playerRects[thePlayer.srcNum], 
  943.                 &thePlayer.dest);
  944.     }
  945.                 // Now we add the player to the update rect list.
  946.     AddToUpdateRects(&thePlayer.dest);
  947.                 // Record old locations.
  948.     thePlayer.wasH = thePlayer.h;
  949.     thePlayer.wasV = thePlayer.v;
  950.                 // Record old bounds rect.
  951.     thePlayer.wasDest = thePlayer.dest;
  952. }
  953.  
  954. //--------------------------------------------------------------  CheckEnemyWrapAround
  955.  
  956. // This function both determines whether or not an enemy (sphinx) is wrapping around.
  957. // If it is, the "second" wrapped-around enemy is drawn.
  958.  
  959. void CheckEnemyWrapAround (short who)
  960. {
  961.     Rect        wrapRect, wasWrapRect, src;
  962.     
  963.     if (theEnemies[who].dest.right > 640)    // Is enemy off the right edge of screen?
  964.     {
  965.         wrapRect = theEnemies[who].dest;    // Copy bounds.
  966.         wrapRect.left -= 640;                // Offset bounds copy to left (one screen width).
  967.         wrapRect.right -= 640;
  968.                                             // Ditto with old bounds.
  969.         wasWrapRect = theEnemies[who].wasDest;
  970.         wasWrapRect.left -= 640;
  971.         wasWrapRect.right -= 640;
  972.                                             // Handle "egg" enemies.
  973.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  974.         {                                    // Handle "egg" enemy sinking into platform.
  975.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  976.             {
  977.                 src = eggSrcRect;
  978.                 src.bottom = src.top + theEnemies[who].frame;
  979.             }
  980.             else
  981.                 src = eggSrcRect;
  982.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  983.                     &((GrafPtr)eggMaskMap)->portBits, 
  984.                     &((GrafPtr)workSrcMap)->portBits, 
  985.                     &src, &src, &wrapRect);
  986.         }
  987.         else                                // Otherwise, if enemy not an egg…
  988.         {
  989.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  990.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  991.                     &((GrafPtr)workSrcMap)->portBits, 
  992.                     &enemyRects[theEnemies[who].srcNum], 
  993.                     &enemyRects[theEnemies[who].srcNum], 
  994.                     &wrapRect);
  995.         }
  996.         AddToUpdateRects(&wrapRect);        // Add bounds to update rect list.
  997.     }
  998.     else if (theEnemies[who].dest.left < 0)    // Check to see if enemy off left edge instead.
  999.     {
  1000.         wrapRect = theEnemies[who].dest;    // Make a copy of enemy bounds.
  1001.         wrapRect.left += 640;                // Offset it right one screens width.
  1002.         wrapRect.right += 640;
  1003.                                             // Ditto with old bounds.
  1004.         wasWrapRect = theEnemies[who].wasDest;
  1005.         wasWrapRect.left += 640;
  1006.         wasWrapRect.right += 640;
  1007.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  1008.         {                                    // Blah, blah, blah.  This is just like the above.
  1009.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  1010.             {
  1011.                 src = eggSrcRect;
  1012.                 src.bottom = src.top + theEnemies[who].frame;
  1013.             }
  1014.             else
  1015.                 src = eggSrcRect;
  1016.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1017.                     &((GrafPtr)eggMaskMap)->portBits, 
  1018.                     &((GrafPtr)workSrcMap)->portBits, 
  1019.                     &src, &src, &wrapRect);
  1020.         }
  1021.         else
  1022.         {
  1023.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1024.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1025.                     &((GrafPtr)workSrcMap)->portBits, 
  1026.                     &enemyRects[theEnemies[who].srcNum], 
  1027.                     &enemyRects[theEnemies[who].srcNum], 
  1028.                     &wrapRect);
  1029.         }
  1030.         AddToUpdateRects(&wrapRect);
  1031.     }
  1032. }
  1033.  
  1034. //--------------------------------------------------------------  DrawEnemies
  1035.  
  1036. // This function draws all the sphinx enemies (or eggs if they're in that state).
  1037. // It doesn't handle wrap-around (the above function does) but it does call it.
  1038.  
  1039. void DrawEnemies (void)
  1040. {
  1041.     Rect        src;
  1042.     short        i;
  1043.     
  1044.     for (i = 0; i < numEnemies; i++)    // Go through all enemies.
  1045.     {
  1046.         switch (theEnemies[i].mode)        // Handle the different modes as seperate cases.
  1047.         {
  1048.             case kSpawning:                // Spawning enemies are "growing" out of the platform.
  1049.             src = enemyRects[theEnemies[i].srcNum];
  1050.             src.bottom = src.top + theEnemies[i].frame;
  1051.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1052.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1053.                     &((GrafPtr)workSrcMap)->portBits, 
  1054.                     &src, &src, &theEnemies[i].dest);
  1055.             AddToUpdateRects(&theEnemies[i].dest);
  1056.                                         // Don't need to check wrap-around, when enemies…
  1057.                                         // spawn, they're never on the edge of screen.
  1058.             theEnemies[i].wasDest = theEnemies[i].dest;
  1059.             theEnemies[i].wasH = theEnemies[i].h;
  1060.             theEnemies[i].wasV = theEnemies[i].v;
  1061.             break;
  1062.             
  1063.             case kFlying:                // Flying enemies are air borne (gee).
  1064.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1065.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1066.                     &((GrafPtr)workSrcMap)->portBits, 
  1067.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1068.                     &theEnemies[i].dest);
  1069.             AddToUpdateRects(&theEnemies[i].dest);
  1070.             CheckEnemyWrapAround(i);    // I like the word "air bourne".
  1071.             theEnemies[i].wasDest = theEnemies[i].dest;
  1072.             theEnemies[i].wasH = theEnemies[i].h;
  1073.             theEnemies[i].wasV = theEnemies[i].v;
  1074.             break;
  1075.             
  1076.             case kWalking:                // Walking enemies are walking.  Enemies.
  1077.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1078.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1079.                     &((GrafPtr)workSrcMap)->portBits, 
  1080.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1081.                     &theEnemies[i].dest);
  1082.             AddToUpdateRects(&theEnemies[i].dest);
  1083.                                         // Don't need to check wrap-around, enemies walk…
  1084.                                         // only briefly, and never off edge of screen.
  1085.             theEnemies[i].wasDest = theEnemies[i].dest;
  1086.             theEnemies[i].wasH = theEnemies[i].h;
  1087.             theEnemies[i].wasV = theEnemies[i].v;
  1088.             break;
  1089.             
  1090.             case kFalling:                // Falling enemies are in fact eggs!
  1091.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1092.                     &((GrafPtr)eggMaskMap)->portBits, 
  1093.                     &((GrafPtr)workSrcMap)->portBits, 
  1094.                     &eggSrcRect, &eggSrcRect, &theEnemies[i].dest);
  1095.             AddToUpdateRects(&theEnemies[i].dest);
  1096.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1097.             theEnemies[i].wasDest = theEnemies[i].dest;
  1098.             theEnemies[i].wasH = theEnemies[i].h;
  1099.             theEnemies[i].wasV = theEnemies[i].v;
  1100.             break;
  1101.             
  1102.             case kEggTimer:                // These are idle, perhaps hatching, eggs.
  1103.             if (theEnemies[i].frame < 24)
  1104.             {                            // Below countdown = 24, the egss are sinking…
  1105.                 src = eggSrcRect;        // into the platform (hatch time!).
  1106.                 src.bottom = src.top + theEnemies[i].frame;
  1107.             }
  1108.             else
  1109.                 src = eggSrcRect;
  1110.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1111.                     &((GrafPtr)eggMaskMap)->portBits, 
  1112.                     &((GrafPtr)workSrcMap)->portBits, 
  1113.                     &src, &src, &theEnemies[i].dest);
  1114.             AddToUpdateRects(&theEnemies[i].dest);
  1115.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1116.             theEnemies[i].wasDest = theEnemies[i].dest;
  1117.             theEnemies[i].wasH = theEnemies[i].h;
  1118.             theEnemies[i].wasV = theEnemies[i].v;
  1119.             break;
  1120.         }
  1121.     }
  1122. }
  1123.  
  1124. //--------------------------------------------------------------  DrawFrame
  1125.  
  1126. // This function is the "master" drawing function that calls all the above…
  1127. // routines.  It is called once per frame.
  1128.  
  1129. void DrawFrame (void)
  1130. {
  1131.     DrawTorches();                // Gee, draws the torches?
  1132.     DrawHand();                    // Draws the hand?
  1133.     DrawEye();                    // A clue to easing your documentation demands…
  1134.     DrawPlayer();                // is to use "smart" names for your functions.
  1135.     CheckPlayerWrapAround();    // Check for player wrap-around.
  1136.     DrawEnemies();                // Handle all sphinx-type enemy drawing.
  1137.     CopyAllRects();                // Put it all onscreen.
  1138. }
  1139.  
  1140.