home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / netutils / hypero.arj / HYPEROID.C < prev    next >
C/C++ Source or Header  |  1994-04-12  |  58KB  |  1,963 lines

  1. /*****************************************************************************/
  2. /*HYPEROID.C - a neato game*/
  3. /**/
  4. /*Version: 1.1  Copyright (C) 1990,91 Hutchins Software*/
  5. /*     This software is licenced under the GNU General Public Licence*/
  6. /*     Please read the associated legal documentation*/
  7. /**/
  8. /*Author: Edward Hutchins*/
  9. /*Internet: eah1@cec1.wustl.edu*/
  10. /*USMail: c/o Edward Hutchins, 63 Ridgemoor Dr., Clayton, MO, 63105*/
  11. /**/
  12. /*Revisions:*/
  13. /*10/31/91 made game better/harder - Ed.*/
  14. /**/
  15. /*Music: R.E.M./The Cure/Ministry/Front 242/The Smiths/New Order/Hendrix...*/
  16. /*Beers: Bass Ale, Augsberger Dark*/
  17. /**/
  18. /*03/04/92 ported to Win32 - Paul Tissue & Robert Hess [Microsoft].*/
  19. /*****************************************************************************/
  20. #include "hyperoid.h"
  21.  
  22. /*-- imports*/
  23. IMPORT POINT LetterPart[] FROM(roidsupp.c);
  24. IMPORT LPSTR szNumberDesc[] FROM(roidsupp.c);
  25. IMPORT LPSTR szLetterDesc[] FROM(roidsupp.c);
  26.  
  27. #define WINNT 0x50d
  28.  
  29.  
  30. /*-- globals*/
  31. GLOBAL CHAR szAppName[32];
  32. GLOBAL HANDLE hAppInst;
  33. GLOBAL HWND hAppWnd;
  34. GLOBAL HPALETTE hAppPalette;
  35. GLOBAL INT nDrawDelay;
  36. GLOBAL INT nLevel;
  37. GLOBAL INT nSafe;
  38. GLOBAL INT nShield;
  39. GLOBAL INT nBomb;
  40. GLOBAL INT nBadGuys;
  41. GLOBAL LONG lScore;
  42. GLOBAL LONG lLastLife;
  43. GLOBAL LONG lHighScore;
  44. GLOBAL BOOL bRestart;
  45. GLOBAL BOOL bPaused;
  46. GLOBAL BOOL bBW;
  47. GLOBAL INT vkShld;
  48. GLOBAL INT vkClkw;
  49. GLOBAL INT vkCtrClkw;
  50. GLOBAL INT vkThrst;
  51. GLOBAL INT vkRvThrst;
  52. GLOBAL INT vkFire;
  53. GLOBAL INT vkBomb;
  54. GLOBAL NPOBJ npPlayer;
  55. GLOBAL LIST FreeList;
  56. GLOBAL LIST RoidList;
  57. GLOBAL LIST ShotList;
  58. GLOBAL LIST FlameList;
  59. GLOBAL LIST SpinnerList;
  60. GLOBAL LIST HunterList;
  61. GLOBAL LIST HunterShotList;
  62. GLOBAL LIST SwarmerList;
  63. GLOBAL LIST LetterList;
  64. GLOBAL LIST BonusList;
  65. GLOBAL INT nCos[DEGREE_SIZE];
  66. GLOBAL INT nSin[DEGREE_SIZE];
  67. GLOBAL HPEN hPen[PALETTE_SIZE];
  68. GLOBAL OBJ Obj[MAX_OBJS];
  69. GLOBAL HBITMAP hBitmap[IDB_MAX];
  70. GLOBAL INT isNT = FALSE;
  71.  
  72. /*-- locals*/
  73. LOCAL DWORD dwSeed;
  74. LOCAL INT nScoreLen;
  75. LOCAL CHAR szScore[40];
  76. LOCAL RECT rectScoreClip;
  77. LOCAL RECT rectShotClip;
  78. LOCAL POINT Player[] =
  79. {{0, 0}, {160, 150}, {0, 250}, {96, 150}, {0, 0}};
  80. LOCAL POINT Spinner[] =
  81. {{160, 150}, {224, 100}, {96, 100}, {32, 150}, {160, 150}};
  82. LOCAL POINT Swarmer[] =
  83. {{0, 100}, {64, 100}, {128, 100}, {192, 100}, {0, 100}};
  84.  
  85. LOCAL POINT Hunter[] =
  86. {
  87.    {160, 150}, {0, 250}, {192, 30}, {64, 30},
  88.    {0, 250}, {96, 150}, {128, 150}, {160, 150}
  89. };
  90.  
  91. LOCAL POINT Bonus[] =
  92. {{0, 150}, {102, 150}, {205, 150}, {51, 150}, {154, 150}, {0, 150}};
  93.  
  94.  
  95. /*****************************************************************************/
  96. /*KillBadGuy - kill off a badguy (made into a macro)*/
  97. /*****************************************************************************/
  98. #define KillBadGuy() \
  99.   ( (--nBadGuys <= 0) ? ( SetRestart(RESTART_NEXTLEVEL), TRUE ) : FALSE )
  100.  
  101.  
  102. /*****************************************************************************/
  103. /*WinMain - everybody has to have one*/
  104. /*****************************************************************************/
  105. int APIENTRY
  106.     WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
  107.                 int nCmdShow)
  108. {
  109.    MSG msg;                                /* message */
  110.  
  111. #ifdef WIN32
  112.    GdiSetBatchLimit(2048);
  113. #endif
  114.  
  115.    hAppInst = hInstance;
  116.    if (!hPrevInstance) {
  117.    /* create the class if we're first */
  118.       if (!CreateHyperoidClass())
  119.          return (FALSE);
  120.    }
  121.  
  122.    if (InitHyperoid()) {
  123.       hAppWnd = CreateHyperoidWindow(lpszCmdLine, nCmdShow);
  124.       if (!hAppWnd)
  125.          return (FALSE);
  126.       while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
  127.          TranslateMessage(&msg);
  128.          DispatchMessage(&msg);
  129.       }
  130.    }
  131.  
  132.    ExitHyperoid();
  133.  
  134.    return (msg.wParam);
  135. }
  136.  
  137.  
  138. /*****************************************************************************/
  139. /*HyperoidWndProc - the main window proc for Hyperoid*/
  140. /*****************************************************************************/
  141. LONG APIENTRY
  142.      HyperoidWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
  143. {
  144.    static BOOL fMyResize = FALSE;
  145.  
  146.    switch (message) {
  147.  
  148.       case WM_CREATE:
  149.          RestartHyperoid();
  150.          SetTimer(hWnd, DRAW_TIMER, nDrawDelay, NULL);
  151.          NCPaintHyperoid(hWnd);
  152.          break;
  153.  
  154.       case WM_TIMER:
  155.          switch (wParam) {
  156.  
  157.             case DRAW_TIMER:
  158.                CheckScore(hWnd);
  159.                DrawObjects(hWnd);
  160.                return (0);
  161.  
  162.             case RESTART_TIMER:
  163.                KillTimer(hWnd, RESTART_TIMER);
  164.                bRestart = FALSE;
  165.                RestartHyperoid();
  166.                return (0);
  167.          }
  168.          break;
  169.  
  170.       case WM_SYSCOMMAND:
  171.          switch (wParam) {
  172.  
  173.             case IDM_NEW:
  174.                NewGame(hWnd);
  175.                break;
  176.  
  177.             case IDM_ABOUT:
  178.                AboutHyperoid(hWnd);
  179.                break;
  180.  
  181.             default:
  182.                return (DefWindowProc(hWnd, message, wParam, lParam));
  183.          }
  184.          break;
  185.  
  186.       case WM_QUERYOPEN:
  187.          Panic(FALSE);
  188.          return (DefWindowProc(hWnd, message, wParam, lParam));
  189.  
  190.       case WM_CHAR:
  191.          if (wParam == VK_ESCAPE)
  192.             Panic(TRUE);
  193.          break;
  194.  
  195.       case WM_SYSKEYDOWN:
  196.       case WM_SYSKEYUP:
  197.       case WM_SYSCHAR:
  198.          if (lParam & (1L << 29))        /* alt key is down */
  199.             return (DefWindowProc(hWnd, message, wParam, lParam));
  200.  
  201.          switch (wParam) {
  202.  
  203.             case VK_ESCAPE:
  204.                if (message == WM_SYSKEYDOWN)
  205.                   Panic(TRUE);
  206.                return (0);
  207.  
  208.             case VK_SPACE:
  209.             case VK_TAB:
  210.                return (0);
  211.  
  212.             default:
  213.                return (DefWindowProc(hWnd, message, wParam, lParam));
  214.          }
  215.          break;
  216.  
  217.       case WM_ERASEBKGND:
  218.          return (EraseHyperoidBkgnd(hWnd, (HDC) wParam));
  219.  
  220.       case WM_NCACTIVATE:
  221.       case WM_NCPAINT:
  222.          NCPaintHyperoid(hWnd);
  223.          return (TRUE);
  224.  
  225.       case UM_SIZE:{
  226.             int MaxCoord = (int) max(HIWORD(lParam), LOWORD(lParam));
  227.  
  228.             fMyResize = TRUE;
  229.             SetWindowPos(hWnd, (HWND)NULL, 0, 0, MaxCoord, MaxCoord,
  230.                          SWP_NOMOVE | SWP_NOZORDER);
  231.             return (TRUE);
  232.          }
  233.  
  234.       case WM_SIZE:{
  235.             if (wParam == SIZENORMAL && !fMyResize)
  236.                SendMessage(hWnd, UM_SIZE, wParam, lParam);
  237.             else
  238.                fMyResize = FALSE;
  239.             return (TRUE);
  240.          }
  241.  
  242.       case WM_PAINT:
  243.          PaintHyperoid(hWnd);
  244.          break;
  245.  
  246.       case WM_QUERYNEWPALETTE:{
  247.             HDC hDC = GetDC(hWnd);
  248.  
  249.             SelectPalette(hDC, hAppPalette, 0);
  250.             RealizePalette(hDC);
  251.             ReleaseDC(hWnd, hDC);
  252.  
  253.             return (TRUE);
  254.          }
  255.  
  256.       case WM_DESTROY:
  257.          KillTimer(hWnd, DRAW_TIMER);
  258.          KillTimer(hWnd, RESTART_TIMER);
  259.          SaveHyperoidWindowPos(hWnd);
  260.          PostQuitMessage(0);
  261.          break;
  262.  
  263.       default:
  264.          return (DefWindowProc(hWnd, message, wParam, lParam));
  265.    }
  266.    return (0);
  267. }
  268.  
  269.  
  270. /*****************************************************************************/
  271. /*arand - pseudorandom number from 0 to x-1 (thanks antman!)*/
  272. /*****************************************************************************/
  273. INT APIENTRY
  274.     arand(INT x)
  275. {
  276.    dwSeed = dwSeed * 0x343fd + 0x269ec3;
  277.    return ((INT) (((dwSeed >> 16) & 0x7fff) * x >> 15));
  278. }
  279.  
  280.  
  281. /*****************************************************************************/
  282. /*AddHead - add an object to the head of a list*/
  283. /*****************************************************************************/
  284. VOID APIENTRY
  285.      AddHead(NPLIST npList, NPNODE npNode)
  286. {
  287.    if (npList->npHead) {
  288.       npNode->npNext = npList->npHead;
  289.       npNode->npPrev = NULL;
  290.       npList->npHead = (npList->npHead->npPrev = npNode);
  291.    }
  292.    else {                                /* add to an empty list */
  293.       npList->npHead = npList->npTail = npNode;
  294.       npNode->npNext = npNode->npPrev = NULL;
  295.    }
  296. }
  297.  
  298. /*****************************************************************************/
  299. /*RemHead - remove the first element in a list*/
  300. /*****************************************************************************/
  301. NPNODE APIENTRY
  302.        RemHead(NPLIST npList)
  303. {
  304.    if (npList->npHead) {
  305.       NPNODE npNode = npList->npHead;
  306.  
  307.       if (npList->npTail != npNode) {
  308.          npList->npHead = npNode->npNext;
  309.          npNode->npNext->npPrev = NULL;
  310.       }
  311.       else
  312.          npList->npHead = npList->npTail = NULL;
  313.  
  314.       return (npNode);
  315.    }
  316.    else
  317.       return (NULL);
  318. }
  319.  
  320.  
  321. /*****************************************************************************/
  322. /*Remove - remove an arbitrary element from a list*/
  323. /*****************************************************************************/
  324. VOID APIENTRY
  325.      Remove(NPLIST npList, NPNODE npNode)
  326. {
  327.    if (npNode->npPrev)
  328.       npNode->npPrev->npNext = npNode->npNext;
  329.    else
  330.       npList->npHead = npNode->npNext;
  331.  
  332.    if (npNode->npNext)
  333.       npNode->npNext->npPrev = npNode->npPrev;
  334.    else
  335.       npList->npTail = npNode->npPrev;
  336. }
  337.  
  338.  
  339. /*****************************************************************************/
  340. /*DrawObject - draw a single object*/
  341. /*****************************************************************************/
  342. VOID APIENTRY
  343.      DrawObject(HDC hDC, NPOBJ npObj)
  344. {
  345.    INT nCnt;
  346.    INT nDir = (npObj->nDir += npObj->nSpin);
  347.    INT x = (npObj->Pos.x += npObj->Vel.x);
  348.    INT y = (npObj->Pos.y += npObj->Vel.y);
  349.    POINT Pts[MAX_PTS];
  350.  
  351.    if (x < -CLIP_COORD)
  352.       npObj->Pos.x = x = CLIP_COORD;
  353.    else if (x > CLIP_COORD)
  354.       npObj->Pos.x = x = -CLIP_COORD;
  355.    if (y < -CLIP_COORD)
  356.       npObj->Pos.y = y = CLIP_COORD;
  357.    else if (y > CLIP_COORD)
  358.       npObj->Pos.y = y = -CLIP_COORD;
  359.  
  360.    for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt) {
  361.       WORD wDeg = (WORD) DEG(npObj->Pts[nCnt].x + nDir);
  362.       INT nLen = npObj->Pts[nCnt].y;
  363.  
  364.       Pts[nCnt].x = x + MULDEG(nLen, nCos[wDeg]);
  365.       Pts[nCnt].y = y + MULDEG(nLen, nSin[wDeg]);
  366.    }
  367.  
  368.    if (npObj->byPts > 1) {
  369.       SelectObject(hDC, hPen[BLACK]);
  370.       Polyline(hDC, npObj->Old, npObj->byPts);
  371.       if (npObj->nCount > 0) {
  372.          SelectObject(hDC, hPen[npObj->byColor]);
  373.          Polyline(hDC, Pts, npObj->byPts);
  374.          for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt)
  375.             npObj->Old[nCnt] = Pts[nCnt];
  376.       }
  377.    }
  378.    else {                                /* just a point */
  379. #ifdef WIN32
  380.          SetPixelV(hDC, npObj->Old[0].x, npObj->Old[0].y, PALETTEINDEX(BLACK));
  381. #else
  382.          SetPixel(hDC, npObj->Old[0].x, npObj->Old[0].y, PALETTEINDEX(BLACK));
  383. #endif
  384.       if (npObj->nCount > 0) {
  385. #ifdef WIN32
  386.             SetPixelV(hDC, Pts[0].x, Pts[0].y, PALETTEINDEX(npObj->byColor));
  387. #else
  388.             SetPixel(hDC, Pts[0].x, Pts[0].y, PALETTEINDEX(npObj->byColor));
  389. #endif            
  390.          npObj->Old[0] = Pts[0];
  391.       }
  392.    }
  393. }
  394.  
  395.  
  396. /*****************************************************************************/
  397. /*SetRestart - set the restart timer*/
  398. /*****************************************************************************/
  399. VOID APIENTRY
  400.      SetRestart(RESTART_MODE Restart)
  401. {
  402.    POINT Pt;
  403.    CHAR szBuff[32];
  404.  
  405.    if (bRestart)
  406.       return;
  407.  
  408.    SetTimer(hAppWnd, RESTART_TIMER, RESTART_DELAY, NULL);
  409.    bRestart = TRUE;
  410.    Pt.x = Pt.y = 0;
  411.  
  412.    switch (Restart) {
  413.       case RESTART_GAME:
  414.          SpinLetters("GAME OVER", Pt, Pt, RED, 400);
  415.          break;
  416.  
  417.       case RESTART_LEVEL:
  418.          SpinLetters("NEXT LIFE", Pt, Pt, GREEN, 300);
  419.          break;
  420.  
  421.       case RESTART_NEXTLEVEL:
  422.          wsprintf(szBuff, "LEVEL %u", nLevel + 1);
  423.          PrintLetters(szBuff, Pt, Pt, BLUE, 300);
  424.          break;
  425.    }
  426. }
  427.  
  428.  
  429. /*****************************************************************************/
  430. /*PrintPlayerMessage - show the player a status message*/
  431. /*****************************************************************************/
  432. VOID APIENTRY
  433.      PrintPlayerMessage(LPSTR lpszText)
  434. {
  435.    POINT Pos, Vel;
  436.  
  437.    Pos = npPlayer->Pos;
  438.    Pos.y -= 400;
  439.    Vel.x = 0;
  440.    Vel.y = -50;
  441.  
  442.    PrintLetters(lpszText, Pos, Vel, GREEN, 150);
  443. }
  444.  
  445.  
  446. /*****************************************************************************/
  447. /*AddExtraLife - give the player another life*/
  448. /*****************************************************************************/
  449. VOID APIENTRY
  450.      AddExtraLife(VOID)
  451. {
  452.    PrintPlayerMessage("EXTRA LIFE");
  453.    ++npPlayer->nCount;
  454.    npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
  455.    if (npPlayer->byColor > WHITE)
  456.       npPlayer->byColor = WHITE;
  457. }
  458.  
  459.  
  460. /*****************************************************************************/
  461. /*Hit - something hit an object, do fireworks*/
  462. /*****************************************************************************/
  463. VOID APIENTRY
  464.      Hit(HDC hDC, NPOBJ npObj)
  465. {
  466.    INT nCnt = 0;
  467.  
  468.  
  469.    UNREFERENCED_PARAMETER(hDC);
  470.  
  471.    for (nCnt = 0; nCnt < 8; ++nCnt) {
  472.  
  473.       NPOBJ npFlame = RemHeadObj(&FreeList);
  474.  
  475.       if (!npFlame)
  476.          return;
  477.  
  478.       npFlame->Pos.x = npObj->Pos.x;
  479.       npFlame->Pos.y = npObj->Pos.y;
  480.       npFlame->Vel.x = npObj->Vel.x;
  481.       npFlame->Vel.y = npObj->Vel.y;
  482.       npFlame->nDir = npObj->nDir + (nCnt * DEGREE_SIZE) / 8;
  483.       npFlame->nSpin = 0;
  484.       npFlame->nCount = 6 + arand(10);
  485.       npFlame->byColor = YELLOW;
  486.       npFlame->byPts = 1;
  487.       npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
  488.  
  489.       ACCEL(npFlame, npFlame->nDir, 200 - npFlame->nCount);
  490.       AddHeadObj(&FlameList, npFlame);
  491.    }
  492. }
  493.  
  494.  
  495. /*****************************************************************************/
  496. /*Explode - explode an object*/
  497. /*****************************************************************************/
  498. VOID APIENTRY
  499.      Explode(HDC hDC, NPOBJ npObj)
  500. {
  501.    INT nCnt, nSize = npObj->byPts;
  502.  
  503.    DrawObject(hDC, npObj);
  504.    for (nCnt = 0; nCnt < nSize; ++nCnt) {
  505.       NPOBJ npFlame;
  506.  
  507.       if (arand(2))
  508.          continue;
  509.       if (!(npFlame = RemHeadObj(&FreeList)))
  510.          return;
  511.  
  512.       npFlame->Pos.x = npObj->Pos.x;
  513.       npFlame->Pos.y = npObj->Pos.y;
  514.       npFlame->Vel.x = npObj->Vel.x;
  515.       npFlame->Vel.y = npObj->Vel.y;
  516.       npFlame->nDir = npObj->nDir + nCnt * DEGREE_SIZE / nSize + arand(32);
  517.       npFlame->nSpin = arand(31) - 15;
  518.       npFlame->nCount = 25 + arand(16);
  519.       npFlame->byColor = npObj->byColor;
  520.       npFlame->byPts = 2;
  521.       npFlame->Pts[0] = npObj->Pts[nCnt];
  522.  
  523.       if (nCnt == nSize - 1)
  524.          npFlame->Pts[1] = npObj->Pts[0];
  525.       else
  526.          npFlame->Pts[1] = npObj->Pts[nCnt + 1];
  527.       ACCEL(npFlame, npFlame->nDir, 60 - npFlame->nCount);
  528.       AddHeadObj(&FlameList, npFlame);
  529.    }
  530.    Hit(hDC, npObj);
  531. }
  532.  
  533.  
  534. /*****************************************************************************/
  535. /*HitPlayer - blow up the player*/
  536. /*****************************************************************************/
  537. BOOL APIENTRY
  538.      HitPlayer(HDC hDC, NPOBJ npObj)
  539. {
  540.    POINT Vel;
  541.    INT nMass, nSpin;
  542.  
  543.    if (nSafe || (npPlayer->nCount <= 0))
  544.       return (FALSE);
  545.  
  546.  /* rumble and shake both objects */
  547.    nMass = npPlayer->nMass + npObj->nMass;
  548.  
  549.    nSpin = npPlayer->nSpin + npObj->nSpin;
  550.  
  551.    npObj->nSpin -= MulDiv(nSpin, npPlayer->nMass, nMass);
  552.    npPlayer->nSpin -= MulDiv(nSpin, npObj->nMass, nMass);
  553.  
  554.    Vel.x = npPlayer->Vel.x - npObj->Vel.x;
  555.    Vel.y = npPlayer->Vel.y - npObj->Vel.y;
  556.  
  557.    npObj->Vel.x += MulDiv(Vel.x, npPlayer->nMass, nMass);
  558.    npObj->Vel.y += MulDiv(Vel.y, npPlayer->nMass, nMass);
  559.    npPlayer->Vel.x -= MulDiv(Vel.x, npObj->nMass, nMass);
  560.    npPlayer->Vel.y -= MulDiv(Vel.y, npObj->nMass, nMass);
  561.  
  562.    if (--npPlayer->nCount) {
  563.       npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
  564.       if (npPlayer->byColor > WHITE)
  565.          npPlayer->byColor = WHITE;
  566.       Hit(hDC, npPlayer);
  567.       return (TRUE);
  568.    }
  569.  
  570.  /* final death */
  571.    npPlayer->byColor = WHITE;
  572.    Explode(hDC, npPlayer);
  573.    SetRestart(RESTART_GAME);
  574.    return (FALSE);
  575. }
  576.  
  577.  
  578. /*****************************************************************************/
  579. /*CreateLetter - make a new letter object*/
  580. /*****************************************************************************/
  581. NPOBJ APIENTRY
  582.       CreateLetter(CHAR cLetter, INT nSize, INT nCount)
  583. {
  584.    NPOBJ npLtr;
  585.    INT nCnt;
  586.    LPSTR lpDesc;
  587.  
  588.    if (cLetter >= '0' && cLetter <= '9')
  589.       lpDesc = szNumberDesc[cLetter - '0'];
  590.    else if (cLetter >= 'A' && cLetter <= 'Z')
  591.       lpDesc = szLetterDesc[cLetter - 'A'];
  592.    else if (cLetter >= 'a' && cLetter <= 'z')
  593.       lpDesc = szLetterDesc[cLetter - 'a'];
  594.    else if (cLetter == '.')
  595.       lpDesc = "l";
  596.    else
  597.       return (NULL);
  598.  
  599.    if (npLtr = RemHeadObj(&FreeList)) {
  600.       npLtr->nMass = 1;
  601.       npLtr->nDir = 0;
  602.       npLtr->nSpin = 0;
  603.       npLtr->nCount = nCount;
  604.       npLtr->byColor = WHITE;
  605.       npLtr->byPts = (BYTE) (nCnt = strlen(lpDesc));
  606.  
  607.       while (nCnt--) {
  608.          npLtr->Pts[nCnt] = LetterPart[lpDesc[nCnt] - 'a'];
  609.          npLtr->Pts[nCnt].y = MulDiv(npLtr->Pts[nCnt].y, nSize, LETTER_MAX);
  610.       }
  611.       AddHeadObj(&LetterList, npLtr);
  612.    }
  613.    return (npLtr);
  614. }
  615.  
  616.  
  617. /*****************************************************************************/
  618. /*DrawLetters - draw letters and such*/
  619. /*****************************************************************************/
  620. VOID APIENTRY
  621.      DrawLetters(HDC hDC)
  622. {
  623.    NPOBJ npLtr, npNext;
  624.  
  625.    for (npLtr = HeadObj(&LetterList); npLtr; npLtr = npNext) {
  626.       npNext = NextObj(npLtr);
  627.       switch (--npLtr->nCount) {
  628.          case 3:
  629.             --npLtr->byColor;
  630.             break;
  631.          case 0:
  632.             RemoveObj(&LetterList, npLtr);
  633.             AddHeadObj(&FreeList, npLtr);
  634.             break;
  635.       }
  636.       DrawObject(hDC, npLtr);
  637.    }
  638. }
  639.  
  640.  
  641. /*****************************************************************************/
  642. /*CreateBonus - make a new bonus object*/
  643. /*****************************************************************************/
  644. VOID APIENTRY
  645.      CreateBonus(VOID)
  646. {
  647.    NPOBJ npBonus;
  648.    INT nCnt;
  649.  
  650.    if (npBonus = RemHeadObj(&FreeList)) {
  651.       npBonus->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
  652.       npBonus->Pos.y = -CLIP_COORD;
  653.       npBonus->Vel.x = npBonus->Vel.y = 0;
  654.       npBonus->nDir = arand(DEGREE_SIZE);
  655.       npBonus->nSpin = (arand(2) ? 30 : -30);
  656.       npBonus->nCount = arand(4) + 1;
  657.       npBonus->nDelay = 64 + arand(128);
  658.       npBonus->nMass = 768;
  659.       npBonus->byColor = (BYTE) (WHITE + (npBonus->nCount * 2));
  660.       npBonus->byPts = DIM(Bonus);
  661.  
  662.       for (nCnt = 0; nCnt < DIM(Bonus); ++nCnt)
  663.          npBonus->Pts[nCnt] = Bonus[nCnt];
  664.       ACCEL(npBonus, npBonus->nDir, 30 + nLevel * 2);
  665.       AddHeadObj(&BonusList, npBonus);
  666.    }
  667. }
  668.  
  669.  
  670. /*****************************************************************************/
  671. /*DrawBonuses - process and draw the bonus list*/
  672. /*****************************************************************************/
  673. VOID APIENTRY
  674.      DrawBonuses(HDC hDC)
  675. {
  676.    NPOBJ npBonus, npNext;
  677.    LOCAL INT nNextBonus = 1000;
  678.  
  679.    if (nBadGuys && (--nNextBonus < 0)) {
  680.       CreateBonus();
  681.       nNextBonus = 1000;
  682.    }
  683.  
  684.    for (npBonus = HeadObj(&BonusList); npBonus; npBonus = npNext) {
  685.       NPOBJ npShot;
  686.       INT nDelta;
  687.       RECT rect;
  688.  
  689.       npNext = NextObj(npBonus);
  690.  
  691.       MKRECT(&rect, npBonus->Pos, 150);
  692.  
  693.       if (PTINRECT(&rect, npPlayer->Pos)) {
  694.          if (npPlayer->nCount > 0)
  695.             switch (npBonus->nCount) {
  696.                case 1:
  697.                   {
  698.                      CHAR szBuff[32];
  699.                      LONG lBonus = 1000L * nLevel;
  700.  
  701.                      if (lBonus == 0)
  702.                         lBonus = 500;
  703.                      lScore += lBonus;
  704.                      wsprintf(szBuff, "%ld", lBonus);
  705.                      PrintPlayerMessage(szBuff);
  706.                   }
  707.                   break;
  708.                case 2:
  709.                   nSafe = 15;
  710.                   ++nShield;
  711.                   npPlayer->byColor = GREEN;
  712.                   PrintPlayerMessage("EXTRA SHIELD");
  713.                   break;
  714.                case 3:
  715.                   ++nBomb;
  716.                   PrintPlayerMessage("EXTRA BOMB");
  717.                   break;
  718.                case 4:
  719.                   AddExtraLife();
  720.                   break;
  721.             }
  722.          npBonus->nCount = 0;
  723.          Explode(hDC, npBonus);
  724.          RemoveObj(&BonusList, npBonus);
  725.          AddHeadObj(&FreeList, npBonus);
  726.       }
  727.       else if (INTRECT(&rect, &rectShotClip)) {
  728.          for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
  729.             if (!PTINRECT(&rect, npShot->Pos))
  730.                continue;
  731.             npShot->nCount = 1;
  732.             npBonus->nCount = 0;
  733.             Explode(hDC, npBonus);
  734.             RemoveObj(&BonusList, npBonus);
  735.             AddHeadObj(&FreeList, npBonus);
  736.          }
  737.       }
  738.       if (npBonus->nCount && --npBonus->nDelay <= 0) {
  739.          --npBonus->nCount;
  740.          npBonus->nDelay = 64 + arand(128);
  741.          npBonus->byColor = (BYTE) (WHITE + (npBonus->nCount * 2));
  742.          if (npBonus->nCount == 0) {
  743.             Explode(hDC, npBonus);
  744.             RemoveObj(&BonusList, npBonus);
  745.             AddHeadObj(&FreeList, npBonus);
  746.          }
  747.       }
  748.       nDelta = npPlayer->Pos.x - npBonus->Pos.x;
  749.       while (nDelta < -16 || nDelta > 16)
  750.          nDelta /= 2;
  751.       npBonus->Vel.x += nDelta - npBonus->Vel.x / 16;
  752.       nDelta = npPlayer->Pos.y - npBonus->Pos.y;
  753.       while (nDelta < -16 || nDelta > 16)
  754.          nDelta /= 2;
  755.       npBonus->Vel.y += nDelta - npBonus->Vel.y / 16;
  756.       DrawObject(hDC, npBonus);
  757.    }
  758. }
  759.  
  760.  
  761. /*****************************************************************************/
  762. /*DrawHunterShots - process and draw the hunter shot list*/
  763. /*****************************************************************************/
  764. VOID APIENTRY
  765.      DrawHunterShots(HDC hDC)
  766. {
  767.    NPOBJ npShot, npNext;
  768.  
  769.    for (npShot = HeadObj(&HunterShotList); npShot; npShot = npNext) {
  770.       RECT rect;
  771.  
  772.       npNext = NextObj(npShot);
  773.  
  774.       MKRECT(&rect, npShot->Pos, 200);
  775.  
  776.       if (PTINRECT(&rect, npPlayer->Pos)) {
  777.          HitPlayer(hDC, npShot);
  778.          npShot->nCount = 1;
  779.       }
  780.       switch (--npShot->nCount) {
  781.          case 7:
  782.             npShot->byColor = DKGREEN;
  783.             break;
  784.          case 0:
  785.             RemoveObj(&HunterShotList, npShot);
  786.             AddHeadObj(&FreeList, npShot);
  787.             break;
  788.       }
  789.       DrawObject(hDC, npShot);
  790.    }
  791. }
  792.  
  793.  
  794. /*****************************************************************************/
  795. /*FireHunterShot - fire a hunter bullet*/
  796. /*****************************************************************************/
  797. VOID APIENTRY
  798.      FireHunterShot(NPOBJ npHunt)
  799. {
  800.    NPOBJ npShot;
  801.  
  802.    if (npShot = RemHeadObj(&FreeList)) {
  803.       npShot->Pos.x = npHunt->Pos.x;
  804.       npShot->Pos.y = npHunt->Pos.y;
  805.       npShot->Vel.x = npHunt->Vel.x;
  806.       npShot->Vel.y = npHunt->Vel.y;
  807.       npShot->nMass = 80;
  808.       npShot->nDir = npHunt->nDir + arand(5) - 2;
  809.       npShot->nSpin = (arand(2) ? 10 : -10);
  810.       npShot->nCount = 16 + arand(8);
  811.       npShot->byColor = GREEN;
  812.       npShot->byPts = 2;
  813.       npShot->Pts[0].x = 128;
  814.       npShot->Pts[0].y = 50;
  815.       npShot->Pts[1].x = 0;
  816.       npShot->Pts[1].y = 50;
  817.  
  818.       ACCEL(npShot, npShot->nDir, 200 + npShot->nCount);
  819.       AddHeadObj(&HunterShotList, npShot);
  820.    }
  821. }
  822.  
  823.  
  824. /*****************************************************************************/
  825. /*CreateHunter - make a new hunter*/
  826. /*****************************************************************************/
  827. VOID APIENTRY
  828.      CreateHunter(VOID)
  829. {
  830.    NPOBJ npHunt;
  831.    INT nCnt;
  832.  
  833.    if (npHunt = RemHeadObj(&FreeList)) {
  834.  
  835.       npHunt->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
  836.       npHunt->Pos.y = -CLIP_COORD;
  837.       npHunt->Vel.x = npHunt->Vel.y = 0;
  838.       npHunt->nMass = 16;
  839.       npHunt->nDir = arand(DEGREE_SIZE);
  840.       npHunt->nSpin = 0;
  841.       npHunt->nCount = 1 + arand(nLevel);
  842.       npHunt->nDelay = 2 + arand(10);
  843.       npHunt->byColor = CYAN;
  844.       npHunt->byPts = DIM(Hunter);
  845.  
  846.       for (nCnt = 0; nCnt < DIM(Hunter); ++nCnt)
  847.          npHunt->Pts[nCnt] = Hunter[nCnt];
  848.       ACCEL(npHunt, npHunt->nDir, arand(500) + nLevel * 50);
  849.       AddHeadObj(&HunterList, npHunt);
  850.       nBadGuys++;
  851.    }
  852. }
  853.  
  854.  
  855. /*****************************************************************************/
  856. /*DrawHunters - process and draw the hunter list*/
  857. /*****************************************************************************/
  858. VOID APIENTRY
  859.      DrawHunters(HDC hDC)
  860. {
  861.    NPOBJ npHunt, npNext;
  862.    LOCAL INT nNextHunter = 200;
  863.  
  864.    if (nBadGuys && (--nNextHunter < 0)) {
  865.       CreateHunter();
  866.       nNextHunter = 1000 + arand(1000) - nLevel * 8;
  867.    }
  868.  
  869.    for (npHunt = HeadObj(&HunterList); npHunt; npHunt = npNext) {
  870.       NPOBJ npShot;
  871.       RECT rect;
  872.  
  873.       npNext = NextObj(npHunt);
  874.  
  875.       MKRECT(&rect, npHunt->Pos, 200);
  876.  
  877.       if (PTINRECT(&rect, npPlayer->Pos)) {
  878.          HitPlayer(hDC, npHunt);
  879.          --npHunt->nCount;
  880.          if (npHunt->nCount < 1) {
  881.             KillBadGuy();
  882.             npHunt->byColor = CYAN;
  883.             Explode(hDC, npHunt);
  884.             RemoveObj(&HunterList, npHunt);
  885.             AddHeadObj(&FreeList, npHunt);
  886.          }
  887.          else if (npHunt->nCount == 1)
  888.             npHunt->byColor = DKCYAN;
  889.       }
  890.       else if (INTRECT(&rect, &rectShotClip)) {
  891.          for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
  892.             if (!PTINRECT(&rect, npShot->Pos))
  893.                continue;
  894.             npShot->nCount = 1;
  895.             lScore += npHunt->nCount * 1000;
  896.             if (--npHunt->nCount < 1) {
  897.                KillBadGuy();
  898.                npHunt->byColor = CYAN;
  899.                Explode(hDC, npHunt);
  900.                RemoveObj(&HunterList, npHunt);
  901.                AddHeadObj(&FreeList, npHunt);
  902.             }
  903.             else {
  904.                if (npHunt->nCount == 1)
  905.                   npHunt->byColor = DKCYAN;
  906.                Hit(hDC, npHunt);
  907.             }
  908.             break;
  909.          }
  910.       }
  911.       ACCEL(npHunt, npHunt->nDir, 8);
  912.       npHunt->Vel.x -= npHunt->Vel.x / 16;
  913.       npHunt->Vel.y -= npHunt->Vel.y / 16;
  914.       if (--npHunt->nDelay <= 0) {
  915.          npHunt->nDelay = arand(10);
  916.          npHunt->nSpin = arand(11) - 5;
  917.          FireHunterShot(npHunt);
  918.       }
  919.       DrawObject(hDC, npHunt);
  920.    }
  921. }
  922.  
  923.  
  924. /*****************************************************************************/
  925. /*CreateSwarmer - make a new swarmer*/
  926. /*****************************************************************************/
  927. VOID APIENTRY
  928.      CreateSwarmer(POINT Pos, INT nDir, INT nCount)
  929. {
  930.    NPOBJ npSwarm;
  931.    INT nCnt;
  932.  
  933.    if (npSwarm = RemHeadObj(&FreeList)) {
  934.  
  935.       npSwarm->Pos = Pos;
  936.       npSwarm->Vel.x = npSwarm->Vel.y = 0;
  937.       npSwarm->nDir = nDir;
  938.       npSwarm->nSpin = arand(31) - 15;
  939.       npSwarm->nCount = nCount;
  940.       npSwarm->nDelay = 64 + arand(64);
  941.       npSwarm->nMass = 32;
  942.       npSwarm->byColor = DKGREEN;
  943.       npSwarm->byPts = DIM(Swarmer);
  944.  
  945.       for (nCnt = 0; nCnt < DIM(Swarmer); ++nCnt) {
  946.          npSwarm->Pts[nCnt] = Swarmer[nCnt];
  947.          npSwarm->Pts[nCnt].y += nCount * 10;
  948.       }
  949.       ACCEL(npSwarm, npSwarm->nDir, 30 + nLevel * 2);
  950.       AddHeadObj(&SwarmerList, npSwarm);
  951.       nBadGuys++;
  952.    }
  953. }
  954.  
  955.  
  956. /*****************************************************************************/
  957. /*DrawSwarmers - process and draw the swarmer list*/
  958. /*****************************************************************************/
  959. VOID APIENTRY
  960.      DrawSwarmers(HDC hDC)
  961. {
  962.    NPOBJ npSwarm, npNext;
  963.    LOCAL INT nNextSwarmer = 1000;
  964.  
  965.    if (nBadGuys && (--nNextSwarmer < 0)) {
  966.       POINT Pos;
  967.  
  968.       Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
  969.       Pos.y = -CLIP_COORD;
  970.       CreateSwarmer(Pos, arand(DEGREE_SIZE), 8 + nLevel * 2);
  971.       nNextSwarmer = 1000 + arand(500) - nLevel * 4;
  972.    }
  973.  
  974.    for (npSwarm = HeadObj(&SwarmerList); npSwarm; npSwarm = npNext) {
  975.       NPOBJ npShot;
  976.       RECT rect;
  977.  
  978.       npNext = NextObj(npSwarm);
  979.  
  980.       MKRECT(&rect, npSwarm->Pos, 150 + npSwarm->nCount * 10);
  981.  
  982.       if (PTINRECT(&rect, npPlayer->Pos)) {
  983.          HitPlayer(hDC, npSwarm);
  984.          npSwarm->nCount = 0;
  985.       }
  986.       else if (INTRECT(&rect, &rectShotClip)) {
  987.          for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
  988.             if (!PTINRECT(&rect, npShot->Pos))
  989.                continue;
  990.             npShot->nCount = 1;
  991.             lScore += npSwarm->nCount * 25;
  992.             npSwarm->nCount = 0;
  993.             break;
  994.          }
  995.       }
  996.       if (npSwarm->nCount <= 0) {
  997.          npSwarm->byColor = GREEN;
  998.          KillBadGuy();
  999.          Explode(hDC, npSwarm);
  1000.          RemoveObj(&SwarmerList, npSwarm);
  1001.          AddHeadObj(&FreeList, npSwarm);
  1002.       }
  1003.       else {
  1004.          if ((npSwarm->nCount > 1) && (--npSwarm->nDelay <= 0)) {
  1005.             INT nDir = arand(DEGREE_SIZE);
  1006.             INT nCount = npSwarm->nCount / 2;
  1007.  
  1008.             CreateSwarmer(npSwarm->Pos, nDir, nCount);
  1009.             nCount = npSwarm->nCount - nCount;
  1010.             CreateSwarmer(npSwarm->Pos, nDir + 128, nCount);
  1011.             npSwarm->nCount = 0;
  1012.          }
  1013.          DrawObject(hDC, npSwarm);
  1014.       }
  1015.    }
  1016. }
  1017.  
  1018.  
  1019. /*****************************************************************************/
  1020. /*CreateSpinner - make a new spinner*/
  1021. /*****************************************************************************/
  1022. VOID APIENTRY
  1023.      CreateSpinner(VOID)
  1024. {
  1025.    NPOBJ npSpin;
  1026.    INT nCnt;
  1027.  
  1028.    if (npSpin = RemHeadObj(&FreeList)) {
  1029.       npSpin->Pos.x = arand(CLIP_COORD * 2) - CLIP_COORD;
  1030.       npSpin->Pos.y = -CLIP_COORD;
  1031.       npSpin->Vel.x = npSpin->Vel.y = 0;
  1032.       npSpin->nDir = arand(DEGREE_SIZE);
  1033.       npSpin->nSpin = -12;
  1034.       npSpin->nCount = 1 + arand(nLevel);
  1035.       npSpin->nMass = 64 + npSpin->nCount * 32;
  1036.       npSpin->byColor = (BYTE) (MAGENTA - npSpin->nCount);
  1037.       npSpin->byPts = DIM(Spinner);
  1038.       for (nCnt = 0; nCnt < DIM(Spinner); ++nCnt)
  1039.          npSpin->Pts[nCnt] = Spinner[nCnt];
  1040.       ACCEL(npSpin, npSpin->nDir, 30 + nLevel * 2);
  1041.       AddHeadObj(&SpinnerList, npSpin);
  1042.       ++nBadGuys;
  1043.    }
  1044. }
  1045.  
  1046.  
  1047. /*****************************************************************************/
  1048. /*DrawSpinners - process and draw the spinner list*/
  1049. /*****************************************************************************/
  1050. VOID APIENTRY
  1051.      DrawSpinners(HDC hDC)
  1052. {
  1053.    NPOBJ npSpin, npNext;
  1054.    LOCAL INT nNextSpinner = 1000;
  1055.  
  1056.    if (nBadGuys && (--nNextSpinner < 0)) {
  1057.       CreateSpinner();
  1058.       nNextSpinner = 100 + arand(900) - nLevel * 2;
  1059.    }
  1060.  
  1061.    for (npSpin = HeadObj(&SpinnerList); npSpin; npSpin = npNext) {
  1062.       NPOBJ npShot;
  1063.       INT nDelta;
  1064.       RECT rect;
  1065.  
  1066.       npNext = NextObj(npSpin);
  1067.  
  1068.       MKRECT(&rect, npSpin->Pos, 150);
  1069.  
  1070.       if (PTINRECT(&rect, npPlayer->Pos)) {
  1071.          HitPlayer(hDC, npSpin);
  1072.          --npSpin->nCount;
  1073.          npSpin->byColor = (BYTE) (MAGENTA - npSpin->nCount);
  1074.          if (npSpin->nCount < 1) {
  1075.             KillBadGuy();
  1076.             Explode(hDC, npSpin);
  1077.             RemoveObj(&SpinnerList, npSpin);
  1078.             AddHeadObj(&FreeList, npSpin);
  1079.          }
  1080.       }
  1081.       else if (INTRECT(&rect, &rectShotClip)) {
  1082.          for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
  1083.             if (!PTINRECT(&rect, npShot->Pos))
  1084.                continue;
  1085.             npShot->nCount = 1;
  1086.             lScore += npSpin->nCount * 500;
  1087.             npSpin->byColor = (BYTE) (MAGENTA - (--npSpin->nCount));
  1088.             if (npSpin->nCount < 1) {
  1089.                KillBadGuy();
  1090.                Explode(hDC, npSpin);
  1091.                RemoveObj(&SpinnerList, npSpin);
  1092.                AddHeadObj(&FreeList, npSpin);
  1093.             }
  1094.             else
  1095.                Hit(hDC, npSpin);
  1096.             break;
  1097.          }
  1098.       }
  1099.       nDelta = npPlayer->Pos.x - npSpin->Pos.x;
  1100.       while (nDelta < -16 || nDelta > 16)
  1101.          nDelta /= 2;
  1102.       npSpin->Vel.x += nDelta - npSpin->Vel.x / 16;
  1103.       nDelta = npPlayer->Pos.y - npSpin->Pos.y;
  1104.       while (nDelta < -16 || nDelta > 16)
  1105.          nDelta /= 2;
  1106.       npSpin->Vel.y += nDelta - npSpin->Vel.y / 16;
  1107.       DrawObject(hDC, npSpin);
  1108.    }
  1109. }
  1110.  
  1111.  
  1112. /*****************************************************************************/
  1113. /*CreateRoid - make a new asteroid*/
  1114. /*****************************************************************************/
  1115. VOID APIENTRY
  1116.      CreateRoid(POINT Pos, POINT Vel, INT nSides, BYTE byColor, INT nDir,
  1117.                      INT nSpeed, INT nSpin)
  1118. {
  1119.    NPOBJ npRoid;
  1120.    INT nCnt;
  1121.  
  1122.    if (npRoid = RemHeadObj(&FreeList)) {
  1123.       npRoid->Pos = Pos;
  1124.       npRoid->Vel = Vel;
  1125.       npRoid->nMass = nSides * 128;
  1126.       npRoid->nDir = nDir;
  1127.       npRoid->nSpin = nSpin + arand(11) - 5;
  1128.       npRoid->nCount = nSides * 100;
  1129.       npRoid->byColor = byColor;
  1130.       npRoid->byPts = (BYTE) (nSides + 1);
  1131.       for (nCnt = 0; nCnt < nSides; ++nCnt) {
  1132.          npRoid->Pts[nCnt].x = nCnt * DEGREE_SIZE / nSides + arand(30);
  1133.          npRoid->Pts[nCnt].y = (nSides - 1) * 100 + 20 + arand(80);
  1134.       }
  1135.       npRoid->Pts[nSides] = npRoid->Pts[0];
  1136.       ACCEL(npRoid, nDir, nSpeed);
  1137.       AddHeadObj(&RoidList, npRoid);
  1138.       ++nBadGuys;
  1139.    }
  1140. }
  1141.  
  1142.  
  1143. /*****************************************************************************/
  1144. /*BreakRoid - break up an asteroid*/
  1145. /*****************************************************************************/
  1146. VOID APIENTRY
  1147.      BreakRoid(HDC hDC, NPOBJ npRoid, NPOBJ npShot)
  1148. {
  1149.    INT nCnt, nNew;
  1150.  
  1151.    lScore += npRoid->nCount;
  1152.    if (npShot)
  1153.       npShot->nCount = 1;
  1154.  
  1155.    switch (npRoid->byPts) {
  1156.       case 8:
  1157.          nNew = 2 + arand(3);
  1158.          break;
  1159.       case 7:
  1160.          nNew = 1 + arand(3);
  1161.          break;
  1162.       case 6:
  1163.          nNew = 1 + arand(2);
  1164.          break;
  1165.       case 5:
  1166.          nNew = arand(2);
  1167.          break;
  1168.       default:
  1169.          nNew = 0;
  1170.          break;
  1171.    }
  1172.  
  1173.    if (nNew == 1 && npShot) {              /* don't explode outward */
  1174.       POINT Pt = npRoid->Pos;
  1175.  
  1176.       Pt.x += arand(301) - 150;
  1177.       Pt.y += arand(301) - 150;
  1178.       CreateRoid(Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
  1179.                  npRoid->byColor, npShot->nDir, 8, npRoid->nSpin);
  1180.    }
  1181.    else if (nNew > 0) {
  1182.       INT nSpeed = npRoid->nSpin * npRoid->nSpin * nNew + 16;
  1183.  
  1184.       for (nCnt = 0; nCnt < nNew; ++nCnt) {
  1185.          POINT Pt = npRoid->Pos;
  1186.  
  1187.          Pt.x += arand(601) - 300;
  1188.          Pt.y += arand(601) - 300;
  1189.          CreateRoid(Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
  1190.                     npRoid->byColor,
  1191.                     npRoid->nDir + nCnt * DEGREE_SIZE / nNew + arand(32),
  1192.                     nSpeed + arand(nLevel * 4),
  1193.                     npRoid->nSpin / 2);
  1194.       }
  1195.    }
  1196.  
  1197.    KillBadGuy();
  1198.    ++npRoid->byColor;
  1199.    npRoid->nCount = 0;
  1200.  
  1201.    if (nNew) {
  1202.       Hit(hDC, npRoid);
  1203.       DrawObject(hDC, npRoid);
  1204.    }
  1205.    else
  1206.       Explode(hDC, npRoid);
  1207.    RemoveObj(&RoidList, npRoid);
  1208.    AddHeadObj(&FreeList, npRoid);
  1209. }
  1210.  
  1211.  
  1212. /****************************************************************************'*/
  1213. /*DrawRoids - process and draw the asteroid list*/
  1214. /*****************************************************************************/
  1215. VOID APIENTRY
  1216.      DrawRoids(HDC hDC)
  1217. {
  1218.    NPOBJ npRoid, npNext;
  1219.  
  1220.    for (npRoid = HeadObj(&RoidList); npRoid; npRoid = npNext) {
  1221.       INT nSize = npRoid->nCount;
  1222.       NPOBJ npShot;
  1223.       RECT rect;
  1224.  
  1225.       npNext = NextObj(npRoid);
  1226.  
  1227.       DrawObject(hDC, npRoid);
  1228.  
  1229.       MKRECT(&rect, npRoid->Pos, nSize);
  1230.  
  1231.       if (PTINRECT(&rect, npPlayer->Pos) && HitPlayer(hDC, npRoid)) {
  1232.          npPlayer->nCount = -npPlayer->nCount;
  1233.          npPlayer->byColor = WHITE;
  1234.          Explode(hDC, npPlayer);
  1235.          BreakRoid(hDC, npRoid, NULL);
  1236.          if (nBadGuys)
  1237.             SetRestart(RESTART_LEVEL);
  1238.          else
  1239.             SetRestart(RESTART_NEXTLEVEL);
  1240.       }
  1241.       else if (INTRECT(&rect, &rectShotClip)) {
  1242.          for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot)) {
  1243.             if (!PTINRECT(&rect, npShot->Pos))
  1244.                continue;
  1245.             BreakRoid(hDC, npRoid, npShot);
  1246.             break;
  1247.          }
  1248.       }
  1249.    }
  1250. }
  1251.  
  1252.  
  1253. /*****************************************************************************/
  1254. /*DrawShots - process and draw the player shot list*/
  1255. /*****************************************************************************/
  1256. VOID APIENTRY
  1257.      DrawShots(HDC hDC)
  1258. {
  1259.    NPOBJ npShot, npNext;
  1260.  
  1261.    if (npShot = HeadObj(&ShotList)) {
  1262.       rectShotClip.left = rectShotClip.right = npShot->Pos.x;
  1263.       rectShotClip.top = rectShotClip.bottom = npShot->Pos.y;
  1264.       while (npShot) {
  1265.          npNext = NextObj(npShot);
  1266.          switch (--npShot->nCount) {
  1267.             case 10:
  1268.                npShot->byColor = DKCYAN;
  1269.                break;
  1270.             case 5:
  1271.                npShot->byColor = DKBLUE;
  1272.                break;
  1273.             case 0:
  1274.                RemoveObj(&ShotList, npShot);
  1275.                AddHeadObj(&FreeList, npShot);
  1276.                break;
  1277.          }
  1278.          DrawObject(hDC, npShot);
  1279.          if (npShot->Pos.x < rectShotClip.left)
  1280.             rectShotClip.left = npShot->Pos.x;
  1281.          else if (npShot->Pos.x > rectShotClip.right)
  1282.             rectShotClip.right = npShot->Pos.x;
  1283.          if (npShot->Pos.y < rectShotClip.top)
  1284.             rectShotClip.top = npShot->Pos.y;
  1285.          else if (npShot->Pos.y > rectShotClip.bottom)
  1286.             rectShotClip.bottom = npShot->Pos.y;
  1287.          npShot = npNext;
  1288.       }
  1289.    }
  1290.    else
  1291.       rectShotClip.left = rectShotClip.right = rectShotClip.top = rectShotClip.bottom = 32767;
  1292. }
  1293.  
  1294.  
  1295. /*****************************************************************************/
  1296. /*DrawFlames - process and draw the flame list*/
  1297. /*****************************************************************************/
  1298. VOID APIENTRY
  1299.      DrawFlames(HDC hDC)
  1300. {
  1301.    NPOBJ npFlame, npNext;
  1302.  
  1303.    for (npFlame = HeadObj(&FlameList); npFlame; npFlame = npNext) {
  1304.       npNext = NextObj(npFlame);
  1305.       switch (--npFlame->nCount) {
  1306.          case 7:
  1307.             npFlame->byColor = RED;
  1308.             break;
  1309.          case 3:
  1310.             npFlame->byColor = DKRED;
  1311.             break;
  1312.          case 0:
  1313.             RemoveObj(&FlameList, npFlame);
  1314.             AddHeadObj(&FreeList, npFlame);
  1315.             break;
  1316.       }
  1317.       DrawObject(hDC, npFlame);
  1318.    }
  1319. }
  1320.  
  1321.  
  1322. /*****************************************************************************/
  1323. /*FireShot - fire a bullet*/
  1324. /*****************************************************************************/
  1325. VOID APIENTRY
  1326.      FireShot(VOID)
  1327. {
  1328.    NPOBJ npShot;
  1329.  
  1330.    if (npShot = RemHeadObj(&FreeList)) {
  1331.       npShot->Pos.x = npPlayer->Pos.x;
  1332.       npShot->Pos.y = npPlayer->Pos.y;
  1333.       npShot->Vel.x = npPlayer->Vel.x;
  1334.       npShot->Vel.y = npPlayer->Vel.y;
  1335.       npShot->nMass = 80;
  1336.       npShot->nDir = npPlayer->nDir + arand(3) - 2;
  1337.       npShot->nSpin = (arand(2) ? 30 : -30);
  1338.       npShot->nCount = 16 + arand(8);
  1339.       npShot->byColor = CYAN;
  1340.       npShot->byPts = 2;
  1341.       npShot->Pts[0].x = 128;
  1342.       npShot->Pts[0].y = 50;
  1343.       npShot->Pts[1].x = 0;
  1344.       npShot->Pts[1].y = 50;
  1345.       ACCEL(npShot, npShot->nDir, 200 + npShot->nCount);
  1346.       AddHeadObj(&ShotList, npShot);
  1347.    }
  1348. }
  1349.  
  1350.  
  1351. /*****************************************************************************/
  1352. /*AccelPlayer - move the player forward*/
  1353. /*****************************************************************************/
  1354. VOID APIENTRY
  1355.      AccelPlayer(INT nDir, INT nAccel)
  1356. {
  1357.    NPOBJ npFlame;
  1358.  
  1359.    nDir += npPlayer->nDir;
  1360.    if (nAccel)
  1361.       ACCEL(npPlayer, nDir, nAccel);
  1362.    if (npFlame = RemHeadObj(&FreeList)) {
  1363.       npFlame->Pos.x = npPlayer->Pos.x;
  1364.       npFlame->Pos.y = npPlayer->Pos.y;
  1365.       npFlame->Vel.x = npPlayer->Vel.x;
  1366.       npFlame->Vel.y = npPlayer->Vel.y;
  1367.       npFlame->nDir = nDir + 100 + arand(57);
  1368.       npFlame->nSpin = 0;
  1369.       npFlame->nCount = nAccel + arand(7);
  1370.       npFlame->byColor = YELLOW;
  1371.       npFlame->byPts = 1;
  1372.       npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
  1373.       ACCEL(npFlame, npFlame->nDir, 50 + arand(10));
  1374.       AddHeadObj(&FlameList, npFlame);
  1375.    }
  1376. }
  1377.  
  1378.  
  1379. /*****************************************************************************/
  1380. /*DrawPlayer - process and draw the player*/
  1381. /*****************************************************************************/
  1382. VOID APIENTRY
  1383.      DrawPlayer(HDC hDC)
  1384. {
  1385.    LOCAL INT nBombing = 0;
  1386.    LOCAL INT nShotDelay = 0;
  1387.  
  1388.    if (npPlayer->nCount <= 0)
  1389.       return;
  1390.  
  1391.    if (nSafe > 0) {
  1392.       if (--nSafe == 0) {
  1393.          npPlayer->byColor = (BYTE) (BLACK + npPlayer->nCount);
  1394.          if (npPlayer->byColor > WHITE)
  1395.             npPlayer->byColor = WHITE;
  1396.       }
  1397.    }
  1398.    else if (IsKeyDown(vkShld) && nShield > 0) {
  1399.       nSafe = 15;
  1400.       if (--nShield > 0)
  1401.          npPlayer->byColor = GREEN;
  1402.       else
  1403.          npPlayer->byColor = DKGREEN;
  1404.    }
  1405.  
  1406.    if (nBombing > 0) {
  1407.       if (--nBombing == 0) {
  1408.          ExplodeBadguys(hDC, &SpinnerList);
  1409.          ExplodeBadguys(hDC, &SwarmerList);
  1410.          ExplodeBadguys(hDC, &HunterList);
  1411.       }
  1412.       else {
  1413.          HitList(hDC, &SpinnerList);
  1414.       /* HitList( hDC, &SwarmerList ); */
  1415.          HitList(hDC, &HunterList);
  1416.       }
  1417.    }
  1418.    else if (nBomb && IsKeyDown(vkBomb))
  1419.       --nBomb, nBombing = 5;
  1420.  
  1421.    if (IsKeyDown(vkClkw))
  1422.       npPlayer->nSpin += 6;
  1423.    if (IsKeyDown(vkCtrClkw))
  1424.       npPlayer->nSpin -= 6;
  1425.    if (IsKeyDown(vkThrst))
  1426.       AccelPlayer(0, 12);
  1427.    if (IsKeyDown(vkRvThrst))
  1428.       AccelPlayer(128, 12);
  1429.    if (nShotDelay)
  1430.       --nShotDelay;
  1431.    else if (IsKeyDown(vkFire))
  1432.       FireShot(), nShotDelay = 2;
  1433.    DrawObject(hDC, npPlayer);
  1434.    npPlayer->nSpin /= 2;
  1435. }
  1436.  
  1437.  
  1438. /*****************************************************************************/
  1439. /*GetHyperoidDC - get the correct DC for hyperoid rendering*/
  1440. /*****************************************************************************/
  1441. HDC APIENTRY
  1442.     GetHyperoidDC(HWND hWnd)
  1443. {
  1444.    HDC hDC;
  1445.    INT cx, cy;
  1446.    RECT rect;
  1447.  
  1448.    GetClientRect(hWnd, &rect);
  1449.    cx = rect.right - rect.left;
  1450.    cy = rect.bottom - rect.top;
  1451.  
  1452.    hDC = GetDC(hWnd);
  1453.  
  1454.  /* set up the mapping mode */
  1455.    SetMapMode(hDC, MM_ISOTROPIC);
  1456.    SetWindowExt(hDC, MAX_COORD, MAX_COORD);
  1457.    SetViewportExt(hDC, cx / 2, -cy / 2);
  1458.    SetViewportOrg(hDC, cx / 2, cy / 2);
  1459.  
  1460.  /* realize the palette */
  1461.    SelectPalette(hDC, hAppPalette, 0);
  1462.    RealizePalette(hDC);
  1463.  
  1464.    return (hDC);
  1465. }
  1466.  
  1467.  
  1468. /*****************************************************************************/
  1469. /*DrawObjects - transform and redraw everything in the system*/
  1470. /*****************************************************************************/
  1471. VOID APIENTRY
  1472.      DrawObjects(HWND hWnd)
  1473. {
  1474.    HDC hDC = GetHyperoidDC(hWnd);
  1475.  
  1476.  /* move and draw things (I don't think the order is important...) */
  1477.    DrawPlayer(hDC);
  1478.    DrawFlames(hDC);
  1479.    DrawShots(hDC);
  1480.    DrawRoids(hDC);
  1481.    DrawSpinners(hDC);
  1482.    DrawSwarmers(hDC);
  1483.    DrawHunters(hDC);
  1484.    DrawHunterShots(hDC);
  1485.    DrawLetters(hDC);
  1486.    DrawBonuses(hDC);
  1487.  /* (...but I'm not changing it!!! :-) */
  1488.  
  1489.    ReleaseDC(hWnd, hDC);
  1490. }
  1491.  
  1492.  
  1493. /*****************************************************************************/
  1494. /*SetIndicator - set a quantity indicator*/
  1495. /*****************************************************************************/
  1496. INT APIENTRY
  1497.     SetIndicator(LPSTR lpBuff, CHAR IDBitmap, INT nQuant)
  1498. {
  1499.    if (nQuant > 5) {
  1500.       *lpBuff++ = IDBitmap;
  1501.       *lpBuff++ = IDBitmap;
  1502.       *lpBuff++ = IDBitmap;
  1503.       *lpBuff++ = IDBitmap;
  1504.       *lpBuff++ = IDB_plus;
  1505.    }
  1506.    else {
  1507.       INT nBlank = 5 - nQuant;
  1508.  
  1509.       while (nQuant--)
  1510.          *lpBuff++ = IDBitmap;
  1511.       while (nBlank--)
  1512.          *lpBuff++ = IDB_blank;
  1513.    }
  1514.    return (5);
  1515. }
  1516.  
  1517.  
  1518. /*****************************************************************************/
  1519. /*CheckScore - show the score and such stuff*/
  1520. /*****************************************************************************/
  1521. VOID APIENTRY
  1522.      CheckScore(HWND hWnd)
  1523. {
  1524.    CHAR szBuff[sizeof(szScore)];
  1525.    LPSTR lpBuff = szBuff;
  1526.    INT nLives, nLen, nCnt, x, y;
  1527.    HBITMAP hbmOld;
  1528.    HDC hDC, hDCMem;
  1529.  
  1530.    if (IsIconic(hWnd))
  1531.       return;
  1532.    if (lScore - lLastLife > EXTRA_LIFE) {
  1533.       AddExtraLife();
  1534.       lLastLife = lScore;
  1535.    }
  1536.    nLives = ((npPlayer->nCount > 0) ? npPlayer->nCount : -npPlayer->nCount);
  1537.  
  1538.    *lpBuff++ = IDB_level;
  1539.    wsprintf(lpBuff, "%2.2u", nLevel);
  1540.    while (isdigit(*lpBuff))
  1541.       *lpBuff = (CHAR) (*lpBuff + IDB_num0 - '0'), ++lpBuff;
  1542.    *lpBuff++ = IDB_blank;
  1543.    *lpBuff++ = IDB_score;
  1544.    wsprintf(lpBuff, "%7.7lu", lScore);
  1545.    while (isdigit(*lpBuff))
  1546.       *lpBuff = (CHAR) (*lpBuff + IDB_num0 - '0'), ++lpBuff;
  1547.    *lpBuff++ = IDB_blank;
  1548.    lpBuff += SetIndicator(lpBuff, IDB_life, nLives);
  1549.    lpBuff += SetIndicator(lpBuff, IDB_shield, nShield);
  1550.    lpBuff += SetIndicator(lpBuff, IDB_bomb, nBomb);
  1551.    nLen = lpBuff - szBuff;
  1552.  
  1553.    hDC = GetWindowDC(hWnd);
  1554.    IntersectClipRect(hDC, rectScoreClip.left, rectScoreClip.top,
  1555.                      rectScoreClip.right, rectScoreClip.bottom);
  1556.    hDCMem = CreateCompatibleDC(hDC);
  1557.    hbmOld = SelectObject(hDCMem, hBitmap[0]);
  1558.    x = rectScoreClip.left;
  1559.    y = rectScoreClip.top;
  1560.  
  1561.    for (nCnt = 0; nCnt < nLen; ++nCnt) {
  1562.       if (szBuff[nCnt] != szScore[nCnt]) {
  1563.          SelectObject(hDCMem, hBitmap[szBuff[nCnt] - IDB_blank]);
  1564.          BitBlt(hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY);
  1565.          szScore[nCnt] = szBuff[nCnt];
  1566.       }
  1567.       x += CX_BITMAP;
  1568.    }
  1569.    if (nCnt < nScoreLen) {
  1570.       SelectObject(hDCMem, hBitmap[0]);
  1571.       do {
  1572.          if (szScore[nCnt] != IDB_blank) {
  1573.             BitBlt(hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY);
  1574.             szScore[nCnt] = IDB_blank;
  1575.          }
  1576.          x += CX_BITMAP;
  1577.       } while (++nCnt < nScoreLen);
  1578.    }
  1579.    nScoreLen = nLen;
  1580.  
  1581.    SelectObject(hDCMem, hbmOld);
  1582.    DeleteDC(hDCMem);
  1583.    ReleaseDC(hWnd, hDC);
  1584. }
  1585.  
  1586.  
  1587. /*****************************************************************************/
  1588. /*HitList - Hit() a list of things*/
  1589. /*****************************************************************************/
  1590. VOID APIENTRY
  1591.      HitList(HDC hDC, NPLIST npList)
  1592. {
  1593.    NPOBJ npObj;
  1594.  
  1595.    for (npObj = HeadObj(npList); npObj; npObj = NextObj(npObj))
  1596.       if (npObj->nCount)
  1597.          Hit(hDC, npObj);
  1598. }
  1599.  
  1600.  
  1601. /*****************************************************************************/
  1602. /*ExplodeBadguys - explode a list of badguys*/
  1603. /*****************************************************************************/
  1604. VOID APIENTRY
  1605.      ExplodeBadguys(HDC hDC, NPLIST npList)
  1606. {
  1607.    NPOBJ npObj;
  1608.  
  1609.    while (npObj = HeadObj(npList)) {
  1610.       KillBadGuy();
  1611.       npObj->nCount = 0;
  1612.       Explode(hDC, npObj);
  1613.       RemoveObj(npList, npObj);
  1614.       AddHeadObj(&FreeList, npObj);
  1615.    }
  1616. }
  1617.  
  1618.  
  1619. /*****************************************************************************/
  1620. /*NewGame - start a new game*/
  1621. /*****************************************************************************/
  1622. VOID APIENTRY
  1623.      NewGame(HWND hWnd)
  1624. {
  1625.    HDC hDC = GetHyperoidDC(hWnd);
  1626.  
  1627.    npPlayer->nCount = 0;
  1628.    npPlayer->byColor = WHITE;
  1629.    Explode(hDC, npPlayer);
  1630.    SetRestart(RESTART_GAME);
  1631.    ExplodeBadguys(hDC, &RoidList);
  1632.    ExplodeBadguys(hDC, &SpinnerList);
  1633.    ExplodeBadguys(hDC, &SwarmerList);
  1634.    ExplodeBadguys(hDC, &HunterList);
  1635.  
  1636.    ReleaseDC(hWnd, hDC);
  1637. }
  1638.  
  1639.  
  1640. /*****************************************************************************/
  1641. /*RestartHyperoid - set up a game!*/
  1642. /*****************************************************************************/
  1643. VOID APIENTRY
  1644.      RestartHyperoid(VOID)
  1645. {
  1646.    if (npPlayer->nCount == 0) {
  1647.       POINT Pos, Vel;
  1648.  
  1649.       Pos.x = 0;
  1650.       Pos.y = -CLIP_COORD / 2;
  1651.       Vel.x = 0;
  1652.       Vel.y = 150;
  1653.       PrintLetters(szAppName, Pos, Vel, YELLOW, 800);
  1654.       npPlayer->nCount = 3;
  1655.       if (lHighScore < lScore)
  1656.          lHighScore = lScore;
  1657.       lLastLife = lScore = 0;
  1658.       nLevel = 0;
  1659.       nShield = nBomb = 3;
  1660.    }
  1661.    else if (npPlayer->nCount < 0) {
  1662.    /* cheesy way of restarting after a major collision */
  1663.       npPlayer->nCount = -npPlayer->nCount;
  1664.       nShield = nBomb = 3;
  1665.    }
  1666.  
  1667.    npPlayer->Pos.x = npPlayer->Pos.y = 0;
  1668.    npPlayer->Vel.x = npPlayer->Vel.y = 0;
  1669.    npPlayer->nDir = 64;
  1670.    npPlayer->nSpin = 0;
  1671.    npPlayer->byColor = GREEN;
  1672.    nSafe = 30;
  1673.  
  1674.    if (ShotList.npHead) {
  1675.       NPOBJ npShot;
  1676.  
  1677.       for (npShot = HeadObj(&ShotList); npShot; npShot = NextObj(npShot))
  1678.          npShot->nCount = 1;
  1679.    }
  1680.  
  1681.  /* reseed the asteroid field */
  1682.    if (nBadGuys == 0) {
  1683.       INT nCnt;
  1684.  
  1685.       ++nLevel;
  1686.       for (nCnt = 8 + nLevel; nCnt; --nCnt) {
  1687.          POINT Pos, Vel;
  1688.  
  1689.          Pos.x = arand(MAX_COORD * 2) - MAX_COORD;
  1690.          Pos.y = arand(MAX_COORD * 2) - MAX_COORD;
  1691.          Vel.x = Vel.y = 0;
  1692.          CreateRoid(Pos, Vel, 3 + arand(4),
  1693.                     (BYTE) (arand(2) ? DKYELLOW : DKGREY),
  1694.                     arand(DEGREE_MAX), 12 + arand(nLevel * 2), arand(5));
  1695.       }
  1696.    }
  1697. }
  1698.  
  1699.  
  1700. /*****************************************************************************/
  1701. /*Panic - boss key (or just pause)*/
  1702. /*****************************************************************************/
  1703. VOID APIENTRY
  1704.      Panic(BOOL bPanic)
  1705. {
  1706.    if (bPanic && !bPaused) {
  1707.       bPaused = TRUE;
  1708.       KillTimer(hAppWnd, DRAW_TIMER);
  1709.       SetWindowText(hAppWnd, "Program Manager Help - PROGMAN.HLP");
  1710.       ShowWindow(hAppWnd, SW_SHOWMINNOACTIVE);
  1711.       InvalidateRect(hAppWnd, NULL, TRUE);
  1712.    }
  1713.    else if (bPaused) {                    /* double-panic == normal */
  1714.       bPaused = FALSE;
  1715.       SetWindowText(hAppWnd, szAppName);
  1716.       if (bPanic)
  1717.          ShowWindow(hAppWnd, SW_RESTORE);
  1718.       SetTimer(hAppWnd, DRAW_TIMER, nDrawDelay, NULL);
  1719.    }
  1720. }
  1721.  
  1722.  
  1723. /*****************************************************************************/
  1724. /*PaintHyperoid - paint the hyperoid window*/
  1725. /*****************************************************************************/
  1726. VOID APIENTRY
  1727.      PaintHyperoid(HWND hWnd)
  1728. {
  1729.    PAINTSTRUCT ps;
  1730.  
  1731.    BeginPaint(hWnd, &ps);
  1732.    if (bPaused)
  1733.       DrawIcon(ps.hdc, 2, 2, LoadIcon(hAppInst, INTRES(IDI_PANIC)));
  1734.    EndPaint(hWnd, &ps);
  1735. }
  1736.  
  1737.  
  1738. /*****************************************************************************/
  1739. /*EraseHyperoidBkgnd - fill in the background*/
  1740. /*****************************************************************************/
  1741. BOOL APIENTRY
  1742.      EraseHyperoidBkgnd(HWND hWnd, HDC hDC)
  1743. {
  1744.    HBRUSH hbr;
  1745.    RECT rect;
  1746.  
  1747.    GetClientRect(hWnd, &rect);
  1748.  
  1749.    if (bPaused) {
  1750.  
  1751. #ifdef WIN32
  1752.       SetBrushOrgEx(hDC, 0, 0, NULL);
  1753. #else
  1754.       SetBrushOrg(hDC, 0, 0);
  1755. #endif
  1756.  
  1757.       hbr = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
  1758.    }
  1759.    else {
  1760.       SelectPalette(hDC, hAppPalette, 0);
  1761.       RealizePalette(hDC);
  1762.       hbr = CreateSolidBrush(PALETTEINDEX(BLACK));
  1763.    }
  1764.  
  1765.    FillRect(hDC, &rect, hbr);
  1766.    DeleteObject(hbr);
  1767.    return (TRUE);
  1768. }
  1769.  
  1770.  
  1771. /*****************************************************************************/
  1772. /*DrawShadowRect - draw a shaded rectangle around an object*/
  1773. /*****************************************************************************/
  1774. VOID APIENTRY
  1775.      DrawShadowRect(HDC hDC, LPRECT lpRect, HPEN hHi, HPEN hLo)
  1776. {
  1777.    SelectObject(hDC, hHi);
  1778.    MoveTo(hDC, lpRect->right, lpRect->top);
  1779.    LineTo(hDC, lpRect->left, lpRect->top);
  1780.    LineTo(hDC, lpRect->left, lpRect->bottom);
  1781.    SelectObject(hDC, hLo);
  1782.    LineTo(hDC, lpRect->right, lpRect->bottom);
  1783.    LineTo(hDC, lpRect->right, lpRect->top);
  1784. }
  1785.  
  1786.  
  1787. /*****************************************************************************/
  1788. /*NCPaintHyperoid - paint a custom frame*/
  1789. /*****************************************************************************/
  1790. VOID APIENTRY
  1791.      NCPaintHyperoid(HWND hWnd)
  1792. {
  1793.    HDC hDC, hDCMem;
  1794.    INT cx, cy, cyCap, h;
  1795.    HPEN hpenHi, hpenLo;
  1796.    HBRUSH hbr;
  1797.    HBITMAP hbm, hbmOld;
  1798.    BITMAP bm;
  1799.    RECT rect;
  1800.  
  1801.    if (IsIconic(hWnd))
  1802.       return;
  1803.    hDC = GetWindowDC(hWnd);
  1804.    GetWindowRect(hWnd, &rect);
  1805.    rect.right -= rect.left, rect.left = 0;
  1806.    rect.bottom -= rect.top, rect.top = 0;
  1807.    cx = GetSystemMetrics(SM_CXFRAME);
  1808.    cy = GetSystemMetrics(SM_CYFRAME);
  1809.    cyCap = cy + GetSystemMetrics(SM_CYCAPTION) - 1;
  1810.    h = rect.bottom - (cyCap + cy);
  1811.  
  1812.    SelectPalette(hDC, hAppPalette, 0);
  1813.    RealizePalette(hDC);
  1814.    if (bBW) {
  1815.       hbr = SelectObject(hDC, CreateSolidBrush(PALETTEINDEX(WHITE)));
  1816.       hpenHi = hPen[BLACK];
  1817.       hpenLo = hPen[BLACK];
  1818.    }
  1819.    else {
  1820.       hbr = SelectObject(hDC, CreateSolidBrush(PALETTEINDEX(GREY)));
  1821.       hpenHi = hPen[WHITE];
  1822.       hpenLo = hPen[DKGREY];
  1823.    }
  1824.  
  1825.    PatBlt(hDC, 0, 0, rect.right, cyCap, PATCOPY);
  1826.    PatBlt(hDC, 0, rect.bottom - cy, rect.right, rect.bottom, PATCOPY);
  1827.    PatBlt(hDC, 0, cyCap, cx, h, PATCOPY);
  1828.    PatBlt(hDC, rect.right - cx, cyCap, cx, h, PATCOPY);
  1829.  
  1830.    --rect.bottom;
  1831.    --rect.right;
  1832.    DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
  1833.    --cx;
  1834.    --cy;
  1835.    rect.left += cx;
  1836.    rect.top += cy;
  1837.    rect.right -= cx;
  1838.    rect.bottom -= cy;
  1839.    if (!bBW)
  1840.       DrawShadowRect(hDC, &rect, hpenLo, hpenHi);
  1841.  
  1842.  /* get the title bar rect */
  1843.    ++rect.left;
  1844.    ++rect.top;
  1845.    --rect.right;
  1846.    rect.bottom = rect.top + cyCap - (cy + 2);
  1847.    DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
  1848.    ++rect.right;                          /* for zoom/restore bitmap */
  1849.  
  1850.    hDCMem = CreateCompatibleDC(hDC);
  1851.  
  1852.    hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_CLOSE));
  1853.    GetObject(hbm, sizeof(bm), (LPSTR) & bm);
  1854.    bm.bmWidth /= 2;                       /* they packed two images in here! */
  1855.    hbmOld = SelectObject(hDCMem, hbm);
  1856.    BitBlt(hDC, rect.left, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
  1857.    rect.left += bm.bmWidth;
  1858.  
  1859.    if (IsZoomed(hWnd))
  1860.       hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_RESTORE));
  1861.    else
  1862.       hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_ZOOM));
  1863.    GetObject(hbm, sizeof(bm), (LPSTR) & bm);
  1864.    SelectObject(hDCMem, hbm);
  1865.    rect.right -= bm.bmWidth;
  1866.    BitBlt(hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
  1867.  
  1868.    hbm = LoadBitmap((HINSTANCE)NULL, INTRES(OBM_REDUCE));
  1869.    GetObject(hbm, sizeof(bm), (LPSTR) & bm);
  1870.    SelectObject(hDCMem, hbm);
  1871.    rect.right -= bm.bmWidth;
  1872.    BitBlt(hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
  1873.  
  1874.    --rect.right;
  1875.    DrawShadowRect(hDC, &rect, hpenHi, hpenLo);
  1876.  
  1877.  /* clip the score to the free titlebar area */
  1878.    ++rect.left;
  1879.    ++rect.top;
  1880.    rectScoreClip = rect;
  1881.  
  1882.    DeleteObject(SelectObject(hDCMem, hbmOld));
  1883.    DeleteObject(SelectObject(hDC, hbr));
  1884.    DeleteDC(hDCMem);
  1885.    ReleaseDC(hWnd, hDC);
  1886.  
  1887.  /* make sure the score gets redrawn */
  1888.    for (cx = 0; cx < nScoreLen; ++cx)
  1889.       szScore[cx] = '\0';
  1890. }
  1891.  
  1892.  
  1893. /*****************************************************************************/
  1894. /*InitHyperoid - initialize everything*/
  1895. /*****************************************************************************/
  1896. BOOL APIENTRY
  1897.      InitHyperoid(VOID)
  1898. {
  1899.    DOUBLE dRad;
  1900.    INT nCnt;
  1901.  
  1902.  /* allocate the logical palette */
  1903.    hAppPalette = CreateHyperoidPalette();
  1904.    if (!hAppPalette)
  1905.       return (FALSE);
  1906.    for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt) {
  1907.       hPen[nCnt] = CreatePen(PS_SOLID, 1, PALETTEINDEX(nCnt));
  1908.       if (!hPen[nCnt])
  1909.          return (FALSE);
  1910.    }
  1911.    for (nCnt = 0; nCnt < IDB_MAX; ++nCnt) {
  1912.       hBitmap[nCnt] = LoadBitmap(hAppInst, INTRES(IDB_blank + nCnt));
  1913.       if (!hBitmap[nCnt])
  1914.          return (FALSE);
  1915.    }
  1916.  
  1917.  /* seed the randomizer */
  1918.    dwSeed = GetCurrentTime();
  1919.  
  1920.  /* create the lookup table (should use resources) */
  1921.    for (nCnt = 0; nCnt < DEGREE_SIZE; ++nCnt) {
  1922.       dRad = nCnt * 6.2831855 / DEGREE_SIZE;
  1923.       nCos[nCnt] = (INT) (DEGREE_MAX * cos(dRad));
  1924.       nSin[nCnt] = (INT) (DEGREE_MAX * sin(dRad));
  1925.    }
  1926.  
  1927.  /* get the initialization file info */
  1928.    GetHyperoidIni();
  1929.  
  1930.  /* allocate all objects as free */
  1931.    for (nCnt = 0; nCnt < MAX_OBJS; ++nCnt)
  1932.       AddHeadObj(&FreeList, &(Obj[nCnt]));
  1933.  
  1934.  /* set up the player */
  1935.    npPlayer = RemHeadObj(&FreeList);
  1936.    npPlayer->byPts = DIM(Player);
  1937.    npPlayer->nMass = 0;
  1938.    for (nCnt = 0; nCnt < DIM(Player); ++nCnt)
  1939.       npPlayer->Pts[nCnt] = Player[nCnt];
  1940.  
  1941.  
  1942.    return (TRUE);
  1943. }
  1944.  
  1945.  
  1946. /*****************************************************************************/
  1947. /*ExitHyperoid - quit the damn game already!*/
  1948. /*****************************************************************************/
  1949. VOID APIENTRY
  1950.      ExitHyperoid(VOID)
  1951. {
  1952.    INT nCnt;
  1953.  
  1954.    if (hAppPalette)
  1955.       DeleteObject(hAppPalette);
  1956.    for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt)
  1957.       if (hPen[nCnt])
  1958.          DeleteObject(hPen[nCnt]);
  1959.    for (nCnt = 0; nCnt < IDB_MAX; ++nCnt)
  1960.       if (hBitmap[nCnt])
  1961.          DeleteObject(hBitmap[nCnt]);
  1962. }
  1963.