home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 002.lha / zoing.c < prev    next >
C/C++ Source or Header  |  1986-05-05  |  17KB  |  543 lines

  1.  
  2. char title [] = "Zoing! 1.0 (c) 1986 Alonzo Gariepy, Public Domain";
  3.  
  4. /*  Simulates elastic collision of multiple balls in rectangular area. */
  5. /*      See the doc file accompanying this source code.                */
  6. /*                                                                     */
  7. /*  31 August 1986      Finished and released version 1.0, AMG         */
  8. /*                                                                     */
  9. /*   1 Sept   1986      Added check for 1.2 graphics lib 33, AMG       */
  10. /*                                                                     */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #include <intuition/intuition.h>
  15. #include <graphics/sprite.h>
  16.  
  17. #define LIBVER        libver
  18. long    LIBVER        = 33;          /* need this for ActivateWindow  */
  19. #define ONE_POINT_TWO one_point_two
  20. long    ONE_POINT_TWO = 0;
  21.  
  22. #define MAXBALLS      8
  23. #define BALLS         balls_used    /* defined on command line.    */
  24. #define FRACBITS      6             /* 0<x<7 fixed point integers. */
  25. #define GRAVITY       gravity       /* defined by user. 2 is good. */
  26. #define LEVITY        levity        /* defined by user. 1 is best. */
  27. #define IS_HIRES      1             /* workbench always high res.  */
  28. #define IS_INTERLACE  is_interlace  /* variable due to interlace.  */
  29. #define STEPSPERFRAME 2             /* 0<x<? simulation resolution */
  30. #define SHIFTX        (FRACBITS-IS_HIRES)
  31. #define SHIFTY        shift_y       /* variable due to interlace.  */
  32. #define MINX          0
  33. #define MINY          0
  34. #define MAXX          (SIMX (304))
  35. #define MAXY          max_y         /* variable due to interlace.  */
  36.  
  37. /* defined in arguments() and openwindow() */
  38. long    BALLS, IS_INTERLACE, SHIFTY, MAXY, GRAVITY, LEVITY;
  39.  
  40.  
  41. #define BALL_SPRITE     happyr
  42. #define CURSOR_SPRITE   charlie
  43. #define HEAD_SPRITE     harryr
  44. #define WEIRD_SPRITE    sunnyw
  45. #define SIZEOF_SPRITE   36    /* total words including posctl and term */
  46.  
  47. #define CURSORDX        7     /* The offset from pointer to cursor sprite */
  48. #define CURSORDY        7
  49. #define D               (SIMX (16))
  50.  
  51. #define CONX(x)         ((x) << SHIFTX)
  52. #define CONY(y)         ((y) << SHIFTY)
  53. #define SCREENX(x)      ((x) >> SHIFTX)
  54. #define SCREENY(y)      ((y) >> SHIFTY)
  55. #define SIMX(x)         ((x) << FRACBITS)
  56. #define SIMY(y)         ((y) << FRACBITS)
  57.  
  58. struct NewWindow windef = {
  59.         0, 0, 84 + 8*sizeof(title) - 7, 20,
  60.         -1, -1,
  61.         CLOSEWINDOW,
  62.         WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | WINDOWSIZING,
  63.         NULL, NULL,
  64.         title,
  65.         NULL, NULL, 84 + 8*sizeof("Zoing!") - 9, 0, 0, 0,
  66.         WBENCHSCREEN
  67. };
  68.  
  69. extern  UWORD charlie [SIZEOF_SPRITE];
  70. extern  UWORD amused  [SIZEOF_SPRITE];
  71. /* and you thought Castro was a yogurt for Unix programmers */
  72. extern  UWORD happyw  [SIZEOF_SPRITE];
  73. extern  UWORD angryr  [SIZEOF_SPRITE];
  74. extern  UWORD happyr  [SIZEOF_SPRITE];
  75. extern  UWORD sunnyw  [SIZEOF_SPRITE];
  76. extern  UWORD harryr  [SIZEOF_SPRITE];
  77.  
  78. long    framecount  = 0;
  79. long    cursor      = 0;  /* boolean flag: window and cursor ball active */
  80. long    angry [MAXBALLS];
  81. long    alt_on [MAXBALLS];
  82.  
  83. struct  SimpleSprite spr[MAXBALLS];
  84. struct  Window       *win;
  85. struct  ViewPort     *vp;
  86.  
  87. UWORD   *sprbuf;
  88.  
  89. long    x [MAXBALLS]  = {0, SIMX(300),
  90.                                 SIMX(128),
  91.                           SIMX(114), SIMX(114),
  92.                      SIMX(100), SIMX(100), SIMX(100), };
  93.  
  94. long    y [MAXBALLS]  = {0, SIMY(10),
  95.                                 SIMY(92),
  96.                           SIMY(84), SIMY(100),
  97.                      SIMY(76), SIMY(92), SIMY(108), };
  98.  
  99. long    vx [MAXBALLS] = {0, -180,  0,  0, 0,  0, 0, 0,};
  100. long    vy [MAXBALLS] = {0,  70,   0,  0, 0,  0, 0, 0,};
  101.  
  102. UWORD   *sprites [MAXBALLS] = {charlie, sunnyw, harryr, happyr,
  103.                                happyr,  happyr, happyr, happyr, };
  104.  
  105. UWORD   *sprites_alt [MAXBALLS] = {amused, sunnyw, harryr, angryr,
  106.                                    angryr,  angryr, angryr, angryr, };
  107.  
  108. long    GfxBase, IntuitionBase;
  109.  
  110. main (argc, argv)
  111.     long argc;
  112.     char *argv[];
  113. {
  114.     int i;
  115.  
  116.     openwindow ();
  117.     arguments (argc, argv);
  118.     copysprites ();
  119.     defineballs ();
  120.  
  121.     for (;;)
  122.         {
  123.         trackcursor ();
  124.         doIDCMP ();
  125.         WaitTOF (vp);
  126.         for (i = 0; i < STEPSPERFRAME; ++i)
  127.             {
  128.             collisions ();
  129.             moveballs ();
  130.             }
  131.         showballs ();
  132.         }
  133. }
  134.  
  135. arguments (argc, argv)
  136.     long    argc;
  137.     char    *argv [];
  138. {
  139.     char    *name = (char *)0, usage [sizeof (title)];
  140.     long    i, string = 0;
  141.  
  142.     for (i = 0; i < sizeof (usage) - 1;)
  143.         if (name && (usage [i] = *name))
  144.             ++name, ++i;
  145.         else
  146.             {
  147.             switch (string)
  148.                 {
  149.                 case 0:  name = " Usage: ";
  150.                          string = 1;
  151.                          continue;
  152.                 case 1:  name = argv [0];
  153.                          string = 2;
  154.                          continue;
  155.                 case 2:  name = " balls(1..10) gravity(0..8) ";
  156.                          string = 3;
  157.                          continue;
  158.                 case 3:  break;
  159.                 }
  160.             break;
  161.             }
  162.     usage [sizeof(usage) - 1] = (char)0;
  163.  
  164.     BALLS = MAXBALLS;
  165.     GRAVITY = 0;
  166.     LEVITY  = 0;
  167.     switch (argc)
  168.         {
  169.         case 4:
  170.             LEVITY = atoi (argv [3]);
  171.             if (LEVITY < 0 || LEVITY > 5)
  172.                 seppuku (usage);
  173.             if (LEVITY && ONE_POINT_TWO)
  174.                 ActivateWindow (win);
  175.         case 3:
  176.             GRAVITY = atoi (argv [2]);
  177.             if (GRAVITY < 0 || GRAVITY > 10)
  178.                 seppuku (usage);
  179.         case 2:
  180.             BALLS = atoi (argv [1]) + 1;
  181.             if (*argv [1] == '?' || BALLS < 2 || BALLS > MAXBALLS)
  182.                 seppuku (usage);
  183.         default:
  184.             break;
  185.         }
  186. }
  187.  
  188. trackcursor ()
  189. {
  190.     static   long   oldx, oldy;
  191.     register long   xx, yy;
  192.  
  193.     if (win->Flags & WINDOWACTIVE)
  194.         {
  195.         x [0] = xx = CONX (win->WScreen->MouseX) - SIMX (CURSORDX);
  196.         y [0] = yy = CONY (win->WScreen->MouseY) - SIMX (CURSORDX);
  197.  
  198.         if (cursor)
  199.             {
  200.             vx [0] = (xx - oldx) / STEPSPERFRAME;
  201.             vy [0] = (yy - oldy) / STEPSPERFRAME;
  202.             }
  203.         else
  204.             {
  205.             vx [0] = vy [0] = 0;
  206.             cursor = 1;
  207.             }
  208.         oldx = xx;
  209.         oldy = yy;
  210.         }
  211.     else
  212.         {
  213.         cursor = 0;
  214.         }
  215. }
  216.  
  217.  
  218. moveballs ()         /* move the balls and reflect from walls */
  219. {
  220.     register int     i;
  221.  
  222.     x [0] += vx [0];
  223.     y [0] += vy [0];
  224.  
  225.     for (i = 1; i < BALLS; i++)
  226.         {
  227.         x [i] += vx [i];
  228.         y [i] += vy [i];
  229.  
  230.         for (;;)    /* we might require several bounces */
  231.             {
  232.             if (x [i] <= MINX)
  233.                 x [i] = MINX + MINX - x [i], vx [i] = -vx [i];
  234.             if (x [i] >= MAXX)
  235.                 x [i] = MAXX + MAXX - x [i], vx [i] = -vx [i];
  236.             if (x [i] >= MINX)
  237.                 break;
  238.             }
  239.  
  240.         vy [i] += LEVITY;
  241.         for (;;)
  242.             {
  243.             if (y [i] <= MINY)
  244.                 y [i] = MINY + MINY - y [i], vy [i] = -vy [i];
  245.             if (y [i] >= MAXY)
  246.                 y [i] = MAXY + MAXY - y [i], vy [i] = -vy [i];
  247.             if (y [i] >= MINY)
  248.                 break;
  249.             }
  250.         vy [i] += GRAVITY;
  251.         }
  252. }
  253.  
  254. showballs ()
  255. {
  256.     int        i;
  257.  
  258.     ++framecount;
  259.  
  260.     for (i = 1; i < BALLS; ++i)
  261.         {
  262.         if (alt_on [i] != angry [i])
  263.             {
  264.             ChangeSprite (vp, spr+i, angry[i] ? sprites_alt[i] : sprites[i]);
  265.             alt_on [i] = angry [i];
  266.             }
  267.         MoveSprite (vp, spr + i, SCREENX (x [i]), SCREENY (y [i]));
  268.         }
  269.  
  270. /* I used to make the cursor gloat here, but it was too distracting! */
  271. }
  272.  
  273. openwindow ()
  274. {
  275.     long    height;
  276.  
  277.     if (GfxBase = OpenLibrary ("graphics.library", LIBVER))
  278.         ONE_POINT_TWO = 1;
  279.     else if (GfxBase = OpenLibrary ("graphics.library", 0))
  280.         ONE_POINT_TWO = 0;
  281.     else
  282.         seppuku ("Zoing! Can't open graphics.");
  283.  
  284.     if (!(IntuitionBase = OpenLibrary ("intuition.library", 0)))
  285.         seppuku ("Zoing! Can't open Intuition.");
  286.  
  287.     if (!(win = (struct Window *) OpenWindow (&windef)))
  288.         seppuku ("Zoing! Can't open window.");
  289.     vp = (struct ViewPort *) ViewPortAddress (win);
  290.  
  291.     height = win->WScreen->Height;
  292.  
  293.     IS_INTERLACE = (height > 300) ? 1 : 0;
  294.     SHIFTY = FRACBITS - IS_INTERLACE;
  295.     MAXY = CONY(height) - SIMY(16);
  296. }
  297.  
  298. defineballs ()
  299. {
  300.     long    i, j, color, red, green, blue;
  301.  
  302.     for (i = 16; i <= 19; ++i)
  303.         {
  304.         color = GetRGB4 (vp->ColorMap, i);
  305.         red   = color >> 8 & 0xF;
  306.         green = color >> 4 & 0xF;
  307.         blue  = color      & 0xF;
  308.  
  309.         for (j = 4; j <= 12; j += 4)
  310.             SetRGB4 (vp, i + j, red, green, blue);
  311.         }
  312.  
  313.     for (i = 1; i < BALLS; i++)
  314.         {
  315.         if (GetSprite (spr + i, -1) < 0)
  316.             seppuku ("Zoing! Sprite allocation failed. ");
  317.  
  318.         spr [i].height = 16;
  319.         spr [i].x = SCREENX (x [i]);
  320.         spr [i].y = SCREENY (y [i]);
  321.  
  322.         ChangeSprite (vp, spr + i, sprites [i]);
  323.         }
  324.  
  325.     SetPointer (win, sprites [0], 16, 16, -CURSORDX, -CURSORDY);
  326.     SetWindowTitles (win, title, title);
  327. }
  328.  
  329. free_resources ()
  330. {
  331.         register int i;
  332.  
  333.         for (i = 1; i < BALLS; i++)
  334.                 if (spr [i].num)
  335.                         FreeSprite ((long) spr [i].num);
  336.  
  337.         if (sprbuf)
  338.                 FreeMem (sprbuf, 2*2*SIZEOF_SPRITE * BALLS);
  339.         if (win)
  340.                 CloseWindow (win);
  341.         if (GfxBase)
  342.                 CloseLibrary (GfxBase);
  343.         if (IntuitionBase)
  344.                 CloseLibrary (IntuitionBase);
  345. }
  346.  
  347. doIDCMP ()
  348. {
  349.     long    msg;
  350.  
  351.     if (msg = GetMsg (win -> UserPort))
  352.         {
  353.         ReplyMsg (msg);
  354.         free_resources ();
  355.         printf ("framecount = %ld\n", framecount);
  356.         exit (0);
  357.         }
  358. }
  359.  
  360. seppuku (str)
  361.     char *str;
  362. {
  363.     if (win)
  364.         {
  365.         SetWindowTitles (win, str, -1);
  366.         if (ONE_POINT_TWO)
  367.             ActivateWindow (win);               /* don't die quietly */
  368.         WaitPort (win -> UserPort);
  369.         }
  370.     free_resources ();
  371.     exit (100);
  372. }
  373.  
  374. copysprites ()
  375. {
  376.     UWORD   *cw;       /* current position in buffer of sprite images */
  377.     UWORD   *sprite;   /* current position in sprite                  */
  378.     int     i, j;
  379.  
  380.     if (!(sprbuf = (UWORD *)
  381.                 AllocMem (2 * 2*SIZEOF_SPRITE * BALLS, MEMF_CHIP)))
  382.         seppuku ("Zoing! Can't allocate sprite buffer. ");
  383.  
  384.     cw = sprbuf;    /* current position at top of buffer */
  385.  
  386.  
  387.     for (i = 0; i < BALLS; ++i)
  388.         {
  389.         sprite = sprites [i];
  390.         if (!sprite)
  391.             seppuku ("Zoing! Missing sprite definition. ");
  392.         sprites [i] = cw;
  393.         for (j = 0; j < SIZEOF_SPRITE; ++j)
  394.             *cw++ = *sprite++;
  395.         }
  396.  
  397.     for (i = 0; i < BALLS; ++i)
  398.         {
  399.         sprite = sprites_alt [i];
  400.         if (!sprite)
  401.             seppuku ("Zoing! Missing sprite definition. ");
  402.         sprites_alt [i] = cw;
  403.         for (j = 0; j < SIZEOF_SPRITE; ++j)
  404.             *cw++ = *sprite++;
  405.         }
  406. }
  407.  
  408. collisions ()
  409. {
  410.     /* These are statics so we don't have to worry about stack size. */
  411.     long   i, j;
  412.     long   dx, dy, dh, halfdh, dvx, dvy, evx, evy;
  413.  
  414.     for (i = cursor ? 0 : 1;  i < BALLS; ++i)
  415.         for (j = i+1; j < BALLS; ++j)
  416.             {
  417.             dx = x [i] - x [j];
  418.             dy = y [i] - y [j];
  419.  
  420.             if (dx > D || dx < -D || dy > D || dy < -D)
  421.                 continue;
  422.  
  423.             dh = dx*dx + dy*dy;
  424.                            /* big chunk of fudge */
  425.             if (dh > D*D + (2 << 2*FRACBITS))
  426.                 continue;
  427.  
  428.             dvx = vx [i] - vx [j];
  429.             dvy = vy [i] - vy [j];
  430.  
  431.             if (i == 0)
  432.                 {
  433.                 dvx = dvx*2 - dvx/2;  /* first term:   infinite mass */
  434.                 dvy = dvy*2 - dvy/2;  /* second term:  bit inelastic */
  435.                 }
  436.  
  437.             evx = dx * dvx + dy * dvy;      /* sign of relative speed */
  438.  
  439.             if (evx >= 0)  /* same velocity or position, or departing */
  440.                 continue;
  441.  
  442. /* Since energy is proportional to the square of the velocity, simple   */
  443. /* rounding does not work (errors won't necessarily balance over time). */
  444. /* We'll try to make sure that the middle round value always is rounded */
  445. /* down by subtracting one from halfdh.                                 */
  446.  
  447.             halfdh = dh/2 - 1;   /* if anything we lose energy */
  448.  
  449.             evx = evx * dx;
  450.             if (evx > 0)
  451.                 evx = (evx + halfdh) / dh;
  452.             else
  453.                 evx = (evx - halfdh) / dh;
  454.             evy = (dx * dvy - dy * dvx) * dx;
  455.             if (evy > 0)
  456.                 evy = dvy - (evy + halfdh) / dh;
  457.             else
  458.                 evy = dvy - (evy - halfdh) / dh;
  459.  
  460.             if (i)    /* cursor doesn't change speed */
  461.                 vx [i] -= evx, vy [i] -= evy;
  462.             vx [j] += evx;
  463.             vy [j] += evy;
  464.  
  465.             /* some cute display stuff */
  466.             switch (i)      /* personalities */
  467.                 {
  468.                 case 0:
  469.                     if (j > 2)
  470.                         angry [j] = 1;          /* yuck! */
  471.                     break;
  472.                 case 1: case 2:             /* the fun guys cheer */
  473.                     angry [j] = 0;          /* everybody up       */
  474.                     break;
  475.                 default:
  476.                     angry [i] |= angry [j]; /* infectious grief */
  477.                     angry [j] |= angry [i];
  478.                     break;
  479.                 }
  480.             }
  481. }
  482.  
  483. UWORD charlie [] =   { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
  484.                        0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
  485.                        0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  486.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
  487.                        0x7ffe, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  488.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  489.                      };
  490.  
  491. UWORD amused [] =    { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
  492.                        0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
  493.                        0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  494.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
  495.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  496.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  497.                      };
  498.  
  499. UWORD happyw [] =    { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0020, 0x1ff8,
  500.                        0x0070, 0x3ffc, 0x0ff8, 0x7ffe, 0x3ffc, 0x7ffe,
  501.                        0xf3cf, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
  502.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
  503.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  504.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  505.                      };
  506.  
  507. UWORD angryr [] =    { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
  508.                        0x3ffc, 0x0000, 0x73ce, 0x0c30, 0x7dbe, 0x0240,
  509.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
  510.                        0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xffff, 0x0000,
  511.                        0x7ffe, 0x0000, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  512.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  513.                      };
  514.  
  515. UWORD happyr [] =    { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
  516.                        0x3ffc, 0x0000, 0x7ffe, 0x0000, 0x7ffe, 0x0000,
  517.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xffff, 0x0000,
  518.                        0xffff, 0x0000, 0xffff, 0x0000, 0xeff7, 0x1008,
  519.                        0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  520.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  521.                      };
  522.  
  523. UWORD sunnyw [] =    { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1ff8,
  524.                        0x3ffc, 0x3ffc, 0x7ffe, 0x2184, 0x73ce, 0x4c32,
  525.                        0xf3cf, 0xedb7, 0xffff, 0xe187, 0xfeff, 0xffff,
  526.                        0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
  527.                        0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
  528.                        0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
  529.                      };
  530.  
  531. UWORD harryr [] =    { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1fd8,
  532.                        0x3ffc, 0x3f8c, 0x7ffe, 0x7006, 0x7ffe, 0x4002,
  533.                        0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
  534.                        0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xeff7, 0x1008,
  535.                        0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
  536.                        0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
  537.                      };
  538.  
  539. /*  This program was created with Vladimir Schwartz's editor, PTE, the  */
  540. /*  best likely ever to be available for the Amiga.  The sprite images  */
  541. /*  were designed using Ray R. Larson's SpriteMaker.  Funny how Charlie */
  542. /*  Chaplin and his look alike symbolize similar organizations...       */
  543.