home *** CD-ROM | disk | FTP | other *** search
/ Current Shareware 1994 January / SHAR194.ISO / desqview / xaster.zip / ASTROIDS.C next >
C/C++ Source or Header  |  1992-11-23  |  37KB  |  892 lines

  1. #include <stdio.h>              /* For NULL     */
  2. #include <X11/Xlib.h>
  3. #include <X11/Xutil.h>
  4. #include <X11/cursorfont.h>     /* For erasing cursor - not important   */
  5. #include <math.h>
  6.  
  7. /* Indexes for 1st dimension of obj     */
  8. /* The order they are in is important   */
  9. #define AST     0
  10. #define ENEMY   96
  11. #define ENEMYBUL 97
  12. #define FBUL    98
  13. #define LASTBUL 102
  14. #define SHIP    103
  15. #define LASTOBJ 103     /* Must be ship!  See makeasts().       */
  16.  
  17. /* Shapes       */
  18. /* Order is important!  See collide().  */
  19. #define ASTSHAPE1       0
  20. #define ASTSHAPE2       1
  21. #define ASTSHAPE3       2
  22. #define ENBULSH         3
  23. #define BULSHAPE        4
  24. #define SHIPSHAPE       5
  25. #define SHIPTHRSHAPE    6
  26. #define ENEMYSHAPE      7
  27. #define LASTSHAPE       7
  28.  
  29. /* Masses       */
  30. #define M_BIG   8.0
  31. #define M_MED   4.0
  32. #define M_SMALL 1.0
  33. #define M_SHIP  1.5
  34. #define M_ENEMY 1.0
  35. #define M_BULLET 0.1
  36.  
  37. /* Keys         */
  38. #define FIRE            'p'
  39. #define PAUSE           27      /* escape       */
  40. #define SHIELD          '`'
  41. #define THRUST          'o'
  42.  
  43. #define BMAX            300     /* Max particles in a "boom" + 1        */
  44. #define letheight       20      /* height of font       */
  45. #define pi              3.1415926535897932384
  46. #define SHIPSIZE        28
  47.  
  48. typedef struct _Boom *Boom;
  49. struct _Boom {Boom next; int dur, part; double bcoord[BMAX][2], bvec[BMAX][2]};
  50. typedef struct {int shape, alive, time;
  51.                 double mass, x, y, xvel, yvel, rot, rotvel} Objtype;
  52. typedef struct {double angle; int length} PolarPair;
  53. typedef struct {double x, y, mag} Vector;
  54.  
  55. /* Global variables:    */
  56. Objtype obj[SHIP+1];
  57. /*      In shapes pairs, 1st # is radians, 2nd is length in pixels.
  58.         Degrees: 0 ->, pi/2 down, pi <-, 3*pi/2 up
  59.         IF YOU CHANGE THE SHAPES, you MUST change numpairs & shapesize
  60. */
  61. PolarPair shapes[LASTSHAPE+1][11] =
  62.         {       {{0,0}, {3*pi/2,40}, {0,20}, {pi/4,28}, {pi/2,40}, /* just crossed 0-deg line */
  63.                  {3*pi/4,28},{pi,40},{5*pi/4,28},{3*pi/2,40},{7*pi/4,28},{0,20}},
  64. /*      hexagon if you prefer
  65.                 {{0,0}, {3*pi/2, 20}, {pi/6, 20}, {pi/2, 20},
  66.                  {5*pi/6, 20}, {7*pi/6, 20}, {3*pi/2, 20}, {11*pi/6, 20}},
  67. */
  68.                 {{0,0}, {3*pi/2,20}, {0,10}, {pi/4,14}, {pi/2,20},
  69.                  {3*pi/4,14},{pi,20},{5*pi/4,14},{3*pi/2,20},{7*pi/4,14},{0,10}},
  70.                 {{0,0}, {3*pi/2,10}, {0,5}, {pi/4,7}, {pi/2,10},
  71.                  {3*pi/4,7},{pi,10},{5*pi/4,7},{3*pi/2,10},{7*pi/4,7},{0,5}},
  72.                 {{0,0}, {7*pi/4, 4}, {pi/4, 4}, {3*pi/4, 4}, {5*pi/4, 4}},
  73.                 {{0,0}, {0,10}},
  74.                 {{0,0}, {5*pi/4,28}, {0,20}, {pi/4,28},{3*pi/4,28},{pi,20},{7*pi/4,28}},        /* Ship */
  75.                 {{0,0}, {5*pi/4,28}, {0,20}, {pi/4,28},{3*pi/4,28},{pi,20},
  76.                  {7*pi/4,28}, {3*pi/4, 7}, {9*pi/8, 13}, {15*pi/8, 13}},        /* Thrusting ship */
  77.                 {{0,0}, {pi,20},{7*pi/4,28},{pi/4,28},{pi,20}}
  78.         };
  79. Boom    blist = NULL;
  80. double  drawscale = 1, speedscale = 1;
  81. int     width, height,
  82.         energy,         /* # of turns shield is good for        */
  83.         highscore = 0,
  84.         nextbul = FBUL,                 /* Obj# of next bullet fired    */
  85.         numasts, oldscore = 99,
  86.         rndint = 73, ships, score,
  87.         numpairs[LASTSHAPE+1]   = {11, 11, 11, 5, 2, 7, 10, 5},
  88.         shapesize[LASTSHAPE+1]  = {44, 21, 10, 2, 1, SHIPSIZE+1, 35, 20},
  89.         shield_on;
  90.  
  91. initasts()
  92. {       int i;
  93.         extern Objtype obj[SHIP+1];
  94.  
  95.         for (i = 0; i < LASTOBJ+1; i++)
  96.         {       obj[i].rot = 0;
  97.                 obj[i].rotvel = 0;
  98.         }
  99.         for (i = 0; i < ENEMY; i++)
  100.         {       obj[i].shape = ASTSHAPE1;
  101.         }
  102.         obj[SHIP].shape = SHIPSHAPE;
  103.         obj[SHIP].mass = M_SHIP;
  104.         obj[ENEMY].shape = ENEMYSHAPE;
  105.         obj[ENEMY].mass = M_ENEMY;
  106.         obj[ENEMYBUL].shape = ENBULSH;
  107.         obj[ENEMYBUL].mass = M_BULLET;
  108.         for (i = FBUL; i < LASTBUL+1; i++)
  109.         {       obj[i].shape = BULSHAPE;
  110.                 obj[i].mass = M_BULLET;
  111. }       }
  112.  
  113. makeasts(level)
  114. {       int i;
  115.         extern Objtype obj[SHIP+1];
  116.         extern int numasts, rndint;
  117.         extern double speedscale;
  118.         unsigned char a;
  119.  
  120.         for (i = 0; i < SHIP; i++)
  121.                 obj[i].alive = 0; /* Erase objs from last level except ship */
  122.         for (i = ENEMYBUL; i < LASTBUL+1; i++)
  123.                 obj[i].time = 0;                /* No bullets in the air */
  124.         for (i = 0; i < level+4; i++)   /* Asteroids:                   */
  125.         {       a = rand(rndint); a>>=1;        /* a = rand# from 0 to 127 */
  126.                 if (a > 63)
  127.                         obj[i].x = (double) a;
  128.                         else obj[i].x = (double) (width - a);
  129.                 a = rand(rndint); a>>=1;        /* Now the same for y   */
  130.                 if (a >  63)
  131.                         obj[i].y = (double) a;
  132.                         else obj[i].y = (double) height - a;
  133.                 a = rand(rndint); a = 4 - a>>5;
  134.                 obj[i].rot = (double) a;
  135.                 a = rand(rndint);
  136.                 obj[i].rotvel = ((double) a)/2048;
  137.                 a = rand(rndint);
  138.                 obj[i].xvel = cos((double) a);
  139.                 obj[i].yvel = sin((double) a);
  140.                 obj[i].shape = ASTSHAPE1;
  141.                 obj[i].mass = M_BIG;
  142.                 obj[i].alive = 1;
  143.         }
  144.         numasts = i;
  145. }
  146.  
  147. makeenemy(level)        /* Start an enemy ship  */
  148.         int level;
  149. {       extern Objtype obj[SHIP+1];
  150.         extern int height, rndint;
  151.         unsigned char c;
  152.  
  153.         obj[ENEMY].alive = 1;
  154.         obj[ENEMY].x = 0;
  155.         obj[ENEMY].y = (double) height/4;
  156.         c = rand(rndint); obj[ENEMY].y += (double) c; /* May put enemy outside window   */
  157.         obj[ENEMY].xvel = (double) level/2;
  158.         obj[ENEMY].yvel = 0;
  159. }
  160.  
  161. int nextast()   /* Find next unused asteroid object     */
  162. {       extern Objtype obj[SHIP+1];
  163.         int i;
  164.         for (i = 0; obj[i].alive; i++); /* guaranteed to find one       */
  165.         return i;
  166. }
  167.  
  168. int collide(i, j)       /* Returns non-zero if i collided with j        */
  169.                         /* Ship must be j!  (See below)                 */
  170.         int i, j;
  171. {       extern Objtype obj[SHIP+1];
  172.         extern int shapesize[LASTSHAPE+1];
  173.         extern double drawscale;
  174.         double  mi, mj,                         /* Slopes of lines      */
  175.                 ix1, ix2, iy1, iy2, jx1, jx2, jy1, jy2, /* Endpoints    */
  176.                 roti, rotj,
  177.                 xcross, ycross,         /* coord of intersection        */
  178.                 z;
  179.         int     diff, xd, yd,
  180.                 a, b,
  181.                 shapei, shapej;
  182.         xd = obj[i].x - obj[j].x;
  183.         yd = obj[i].y - obj[j].y;
  184.         diff = sqrt((double)(xd*xd + yd*yd));
  185.         shapei = obj[i].shape; shapej = obj[j].shape;
  186.         /* Note this will miss if drawscale is < 0      */
  187.         if (diff < (shapesize[shapei] + shapesize[shapej])*drawscale)
  188.         {   /* If both are round objects, approximation is good */
  189.             if (shapei < SHIPSHAPE && shapej < SHIPSHAPE) return 1;
  190.             if (j == SHIP && shield_on) return 1;       /* Ship always j! */
  191.             roti = obj[i].rot; rotj = obj[j].rot;
  192.             ix1 = (double) obj[i].x; iy1 = (double) obj[i].y;
  193.             for (a = 1; a < numpairs[shapei]; a++)
  194.             {   ix2 = ix1 + (double) shapes[shapei][a].length * drawscale *
  195.                         cos(shapes[shapei][a].angle + roti);
  196.                 iy2 = iy1 + (double) shapes[shapei][a].length * drawscale *
  197.                         sin(shapes[shapei][a].angle + roti);
  198.                 if (ix1 == ix2)
  199.                 {       printf("\nif1 = if2"); return 1;} /* Easy way out */
  200.                 mi = (iy2-iy1)/(ix2-ix1);
  201.                 z = mi*ix1;
  202.                 jx1 = (double) obj[j].x; jy1 = (double) obj[j].y;
  203.                 for (b = 1; b < numpairs[shapej]; b++)
  204.                 {       jx2 = jx1 + (double) shapes[shapej][b].length *
  205.                                 drawscale * cos(shapes[shapej][b].angle + rotj);
  206.                         jy2 = jy1 + (double) shapes[shapej][b].length *
  207.                                 drawscale * sin(shapes[shapej][b].angle + rotj);
  208.                         if (jx1 == jx2)
  209.                         {       ycross = ix1 + (jx1-ix1)*mi;
  210.                                 if ((jx1-ix1) * (ix2-jx1) >= 0 &&
  211.                                         (ycross-jy1)*(jy2-ycross) >= 0)
  212.                                         return 1;
  213.                                 else jx2 += .0001;      /* Avoid divide by 0 */
  214.                         }
  215.                         mj = (jy2-jy1)/(jx2-jx1);
  216.                         if (mj == mi) goto Loopend;     /* Parallel lines */
  217.                         xcross = (iy1 - jy1 + mj*jx1 - z) / (mj - mi);
  218.                         if ((xcross-ix1) * (ix2-xcross) > 0
  219.                                 && (xcross-jx1) * (jx2-xcross) > 0) return 1;
  220. Loopend:                jx1 = jx2; jy1 = jy2;
  221.                 }
  222.                 ix1 = ix2; iy1 = iy2;
  223.         }   }
  224.         return 0;
  225. }
  226.  
  227. blastpair(i, j)         /* Generate random velocity vector v.   */
  228.         int i, j ;      /* Add v to i, -v to j.                 */
  229. {       extern int rndint;
  230.         extern Objtype obj[SHIP+1];
  231.         unsigned char c;        /* for rand     */
  232.         double vx, vy;
  233.         c = rand(rndint);
  234. /*      c = 4 - c>>5;   if you need angles from -3 to 4         */
  235.         c>>2;           /* possibly save some time on sin/cos   */
  236.         vx = cos((double) c); vy = sin((double) c);
  237.         obj[i].xvel = obj[i].xvel + vx;
  238.         obj[i].yvel = obj[i].yvel + vy;
  239.         obj[j].xvel = obj[j].xvel - vx;
  240.         obj[j].yvel = obj[j].yvel - vy;
  241.         obj[i].rotvel = obj[i].rotvel + .05;
  242.         obj[j].rotvel = obj[j].rotvel - .05;
  243. }
  244.  
  245. /* dot product of 2 vectors     */
  246. #define dot(i,j)        (i.x*j.x + i.y*j.y)
  247. /* rotational inertia (constant eliminated) of obj. i   */
  248. #define rotinert(i)     (double) (obj[i].mass*shapesize[obj[i].shape]*shapesize[obj[i].shape])
  249.  
  250. /* cause two objects to collide elastically     */
  251. bounce(i, j)
  252. int     i,j;
  253. {
  254. double  rotrat, temp;
  255. extern  Objtype obj[SHIP+1];
  256. Vector  vi, vj,         /* velocity of objs i, j                */
  257.         ij,             /* vector from center of i to center of j */
  258.         vi_ij, vj_ij,   /* velocity of obj along vector ij      */
  259.         vipij, vjpij,   /* velocity perpendicular to ij         */
  260.         vi_ijf, vj_ijf; /* post-collision velocity along ij     */
  261.  
  262. vi.x = obj[i].xvel; vi.y = obj[i].yvel;
  263. vj.x = obj[j].xvel; vj.y = obj[j].yvel;
  264. ij.x = obj[j].x - obj[i].x; ij.y = obj[j].y - obj[i].y;
  265. ij.mag = sqrt(ij.x*ij.x + ij.y*ij.y);
  266. /*
  267. Calculate velocities projected onto ij;
  268.         vi_ij = vi*cos(a) = (vi dot ij) / |ij|          */
  269. vi_ij.mag = dot(vi, ij) / ij.mag;
  270. vi_ij.x = (ij.x * vi_ij.mag) / ij.mag;
  271. vi_ij.y = (ij.y * vi_ij.mag) / ij.mag;
  272. vj_ij.mag = dot(vj, ij) / ij.mag;
  273. vj_ij.x = (ij.x * vj_ij.mag) / ij.mag;
  274. vj_ij.y = (ij.y * vj_ij.mag) / ij.mag;
  275. if (vi_ij.mag - vj_ij.mag < 0)  /* Objs moving away from each other -
  276.         Since objs are round (at least when bouncing), this means
  277.         they are moving away from each other already.   */
  278.         return;
  279. /*
  280. Calculate component of velocities perpendicular to ij:
  281.         |vipij| = |vi|*sin(a) = |vi x ij| / |ij|
  282. Same as
  283.         |vipij| = |vi|*cos(pi/2 - a) = (vi dot (perp. to ij)) / |ij|    */
  284. temp = vi.y*ij.x - vi.x*ij.y;   /* - (cross product when 3rd coord is 0)*/
  285. temp /= (ij.mag*ij.mag);
  286. vipij.x = -ij.y*temp; vipij.y = ij.x*temp;
  287. temp = (vj.x*ij.y - vj.y*ij.x) / (ij.mag*ij.mag);
  288. vjpij.x = -ij.y*temp; vjpij.y = ij.x*temp;
  289. /*
  290. Calculate the linear elastic collision along ij:
  291.         mass(i)*vi_ij + mass(j)*vj_ij = mass(i)*vi_ijf + mass(j)*vj_ijf
  292.         vi_ij + vi_ijf = vj_ij + vj_ijf (derived by dividing equation
  293.         for conservation of kinetic energy by eq. for cons. of momentum) */
  294. temp = obj[i].mass/obj[j].mass;
  295. vj_ijf.x = (temp * (2*vi_ij.x - vj_ij.x) + vj_ij.x) / (1 + temp);
  296. vj_ijf.y = (temp * (2*vi_ij.y - vj_ij.y) + vj_ij.y) / (1 + temp);
  297. vi_ijf.x = vj_ijf.x + vj_ij.x - vi_ij.x;
  298. vi_ijf.y = vj_ijf.y + vj_ij.y - vi_ij.y;
  299. /*
  300. Now, given vi_ijf and vj_ijf, add them to the perpendicular
  301.         components to get final velocity vectors                */
  302. obj[i].xvel = vi_ijf.x + vipij.x;
  303. obj[i].yvel = vi_ijf.y + vipij.y;
  304. obj[j].xvel = vj_ijf.x + vjpij.x;
  305. obj[j].yvel = vj_ijf.y + vjpij.y;
  306. /*
  307. Now calculate rotational velocity exchange      */
  308. rotrat = rotinert(i)/rotinert(j);
  309. temp = rotrat * (2*obj[i].rotvel - obj[j].rotvel) / (1+rotrat);
  310. obj[i].rotvel = temp + obj[j].rotvel - obj[i].rotvel;
  311. obj[j].rotvel = temp;
  312. }
  313.  
  314. botline(disp, window, gc)       /* Print status line text       */
  315.         Display *disp;
  316.         Drawable window;
  317.         GC gc;
  318. {       extern int highscore, ships, score;
  319.         char text[70];
  320.         sprintf(text, "Ships:%2d   Score:%6d   Shield:        High:%6d",
  321.                 ships, score, highscore);
  322.         XDrawImageString (disp, window, gc, 0, height+letheight,
  323.                         text, strlen(text));
  324. }
  325.  
  326. printss(disp, window, gc)       /* Print ships and score        */
  327.         Display *disp;
  328.         Drawable window;
  329.         GC gc;
  330. {       extern int height, highscore, oldscore, ships, score;
  331.         extern Objtype obj[SHIP+1];     /* to kill ship */
  332.         char sstring[30];
  333.  
  334.         if (score != oldscore)
  335.         {       if (score/10000 > oldscore/10000)
  336.                 {       ships++; botline(disp, window, gc);}
  337.                 if (score/10000 < oldscore/10000)
  338.                 {       ships--; botline(disp, window, gc);
  339.                         if (!ships) obj[SHIP].alive = 0;
  340.                 }
  341.                 if (score > highscore)  /* Separate if to avoid flashing */
  342.                 {       highscore = score;
  343.                         sprintf(sstring, "%6d", highscore);
  344.                         XDrawImageString (disp, window, gc, 460,
  345.                                 height+letheight, sstring, strlen(sstring));
  346.                 }
  347.                 sprintf(sstring, "%6d", score);
  348.                 XDrawImageString (disp, window, gc, 170, height+letheight,
  349.                                 sstring, strlen(sstring));
  350.                 oldscore = score;
  351.         }
  352.  
  353.         /* Draw shield energy bar       */
  354.         XFillRectangle(disp, window, gc, 340, height+8, energy>>1, 10);
  355.         XClearArea(disp, window, 340+(energy>>1), height+8, 8, 10, False);
  356. }
  357.  
  358. upscore(killer, up)     /* Only award score for things the player shot */
  359.         int killer, up;
  360. {       extern int score;
  361.         if (killer != ENEMYBUL && killer != SHIP)
  362.                 score = score + up;
  363. }
  364.  
  365. /* boom, movebooms, drawbooms all by Peter Phillips */
  366. boom(ob, particles, duration)
  367. int ob;
  368. int particles;
  369. int duration;
  370. { extern int rndint;
  371.   int i;
  372.   unsigned int r1, r2;
  373.   Boom b;
  374.   double x, y;
  375.   double angle, length;
  376.  
  377.   b = (Boom) malloc(sizeof(struct _Boom));
  378.   b->dur = duration;
  379.   b->part = particles;
  380.   x = obj[ob].x;
  381.   y = obj[ob].y;
  382.   for (i = 0; i < particles; i++) {
  383.     r1 = (rand(rndint) >> 2) % 100;
  384.     r2 = (rand(rndint) >> 2) % 7;
  385.  
  386.     b->bcoord[i][0] = x;
  387.     b->bcoord[i][1] = y;
  388.     angle = r1 * pi / 50.0;
  389.     length = 3 + r2;
  390.     b->bvec[i][0] = cos(angle) * length + obj[ob].xvel;
  391.     b->bvec[i][1] = sin(angle) * length + obj[ob].yvel;
  392.   }
  393.   b->next = blist;
  394.   blist = b;
  395. }
  396.  
  397. /* move the various booms that are active */
  398. movebooms()
  399. {
  400.   int i;
  401.   Boom b, prevb;
  402.  
  403.   prevb = NULL;
  404.   b = blist;
  405.   while (b != NULL) {
  406.     b->dur--;
  407.     if (b->dur < 0) { /* delete this boom */
  408.       Boom temp;
  409.  
  410.       temp = b;
  411.       if (prevb == NULL) {
  412.         blist = b->next;
  413.       } else {
  414.         prevb->next = b->next;
  415.       }
  416.       b = b->next;
  417.       free(temp);
  418.     } else {  /* move boom, advance list */
  419.       for (i = 0; i < b->part; i++) {
  420.         b->bcoord[i][0] += b->bvec[i][0];
  421.         b->bcoord[i][1] += b->bvec[i][1];
  422.       }
  423.       prevb = b;
  424.       b = b->next;
  425.     }
  426.   }
  427. }
  428.  
  429. /* Draw the various booms */
  430. drawbooms(disp, window, gc)
  431.      Display *disp;
  432.      Drawable window;
  433.      GC gc;
  434. {
  435.   int i;
  436.   Boom b;
  437.   XPoint figure[BMAX];
  438.  
  439.   b = blist;
  440.   while (b != NULL) {
  441.     for (i = 0; i < b->part; i++) {
  442.       figure[i].x = (int) b->bcoord[i][0];
  443.       figure[i].y = (int) b->bcoord[i][1];
  444.     }
  445.     XDrawPoints(disp, window, gc, figure, b->part, CoordModeOrigin);
  446.     b = b->next;
  447.   }
  448. }
  449.  
  450. deletebooms()   /* delete all booms */
  451. {       Boom b;
  452.  
  453.         b = blist;
  454.         while (b != NULL)
  455.         {       b->dur = 0;
  456.                 b = b->next;
  457. }       }
  458.  
  459. killast(killer, i)
  460.         int killer, i;          /* i = Asteroid # to kill       */
  461. {       extern Objtype obj[SHIP+1];
  462.         extern int numasts;
  463.         int k, na, oldna;
  464.  
  465.         if (obj[i].shape == ASTSHAPE1)
  466.         {       na = nextast();         /* Could put 6 lines in a sub */
  467.                 obj[na].x = obj[i].x;
  468.                 obj[na].y = obj[i].y;
  469.                 obj[na].xvel = obj[i].xvel;
  470.                 obj[na].yvel = obj[i].yvel;
  471.                 obj[na].alive++;
  472.                 obj[na].shape = ASTSHAPE2;
  473.                 obj[na].mass = M_MED;
  474.                 obj[i].shape = ASTSHAPE2;
  475.                 obj[i].mass = M_MED;
  476.                 blastpair(i, na);
  477.                 boom(i, 30, 12);
  478.                 numasts++;
  479.                 upscore(killer, 25);
  480.         }
  481.         else if (obj[i].shape == ASTSHAPE2)
  482.         {
  483.                 for (k = 0; k < 3; k++)
  484.                 {       oldna = na;
  485.                         na = nextast();
  486.                         obj[na].x = obj[i].x;
  487.                         obj[na].y = obj[i].y;
  488.                         obj[na].xvel = obj[i].xvel;
  489.                         obj[na].yvel = obj[i].yvel;
  490.                         obj[na].alive++;
  491.                         obj[na].shape = ASTSHAPE3;
  492.                         obj[na].mass = M_SMALL;
  493.                         if (k == 1) blastpair(oldna,na);
  494.                 }
  495.                 obj[i].shape = ASTSHAPE3;
  496.                 obj[i].mass = M_SMALL;
  497.                 blastpair(na, i);
  498.                 boom(i, 20, 10);
  499.                 numasts = numasts + 3;
  500.                 upscore(killer, 50);
  501.         }
  502.         else if (obj[i].shape == ASTSHAPE3)
  503.         {       boom(i, 10, 8);
  504.                 obj[i].alive = 0; numasts--; upscore(killer, 100);}
  505.         else    /* enemy {ship or bullet}       */
  506.         {       boom(i, 9, 7);
  507.                 obj[i].alive = 0; upscore(killer, 500);}
  508. }
  509. moveobjs(crash)
  510.         int *crash;
  511. {       extern Objtype obj[SHIP+1];
  512.         extern int ships;
  513.         extern double speedscale;
  514.         int i, j;       /* Indexes      */
  515.         double *temp;
  516.  
  517.         movebooms();
  518.         for (i = 0; i < LASTOBJ+1; i++)
  519.                 if (obj[i].alive)
  520.                 {       temp = &obj[i].x;
  521.                         *temp = *temp + obj[i].xvel*speedscale;
  522.                         while (*temp < 0) *temp = *temp + (double) width;
  523.                         while (*temp > width) *temp = *temp - (double) width;
  524.                         temp = &obj[i].y;
  525.                         *temp = *temp + obj[i].yvel*speedscale;
  526.                         while (*temp < 0) *temp = *temp + height;
  527.                         while (*temp > height) *temp = *temp - height;
  528.                         obj[i].rot = obj[i].rot + obj[i].rotvel;
  529.                 }
  530.         for (i = 0; i < FBUL; i++)
  531.             if (obj[i].alive)
  532.             {
  533.                 if (obj[SHIP].alive && collide(i, SHIP))
  534.                 {       if (shield_on) bounce(SHIP, i);
  535.                         else
  536.                         {       *crash = 2;
  537.                                 ships--; obj[SHIP].alive = 0;
  538.                                 killast(SHIP, i);
  539.                                 continue;
  540.                 }       }
  541.                 for (j = ENEMYBUL; j < LASTBUL+1; j++)
  542.                         if (obj[j].alive && collide(i, j) &&
  543.                            (j != ENEMYBUL || (i != ENEMYBUL && i != ENEMY)))
  544.                         {       obj[j].alive = 0;       /* Kill the bullet */
  545.                                 /* Don't have 2 bullets kill same asteroid */
  546.                                 if (obj[i].alive) killast(j,i);
  547.                         }
  548.             }
  549. }
  550.  
  551. fire()
  552. {       extern Objtype obj[SHIP+1];
  553.         extern int width, nextbul;
  554.         extern double drawscale, speedscale;
  555.         double *shiprot, cosrot, sinrot;
  556.  
  557.         obj[nextbul].alive++;
  558.         shiprot = &obj[SHIP].rot;
  559.         cosrot = cos(*shiprot); sinrot = sin(*shiprot);
  560.         obj[nextbul].x = obj[SHIP].x + 20 * cosrot * drawscale;
  561.         obj[nextbul].y = obj[SHIP].y + 20 * sinrot * drawscale;
  562.         obj[nextbul].xvel = obj[SHIP].xvel + 10 * cosrot;
  563.         obj[nextbul].yvel = obj[SHIP].yvel + 10 * sinrot;
  564.         obj[nextbul].rot = *shiprot;
  565.         obj[nextbul].time = width/(speedscale*11);      /* loops before bullet expires  */
  566.         nextbul++; if (nextbul == LASTBUL+1) nextbul = FBUL;
  567. }
  568.  
  569. hyper()
  570. {       extern Objtype obj[SHIP+1];
  571.         extern int width, height, rndint;
  572.         unsigned char c;
  573.         unsigned int i;
  574.  
  575.         c = rand(rndint); i = c; i<<=2; /* 0 - 1024     */
  576.         while (i > width) i -= width;
  577.         obj[SHIP].x = (double) i;
  578.         c = rand(rndint); i = c; i<<=2; /* 0 - 1024     */
  579.         while (i > height) i -= height;
  580.         obj[SHIP].y = (double) i;
  581. }
  582.  
  583. vdraw(disp, window, gc, shape, x, y, rot)
  584.         Display *disp;
  585.         Drawable window;
  586.         GC gc;
  587.         int shape;
  588.         double x, y, rot;
  589.  
  590. {       int line;
  591.         extern PolarPair shapes[LASTSHAPE+1][11];
  592.         extern int numpairs[LASTSHAPE+1];
  593.         extern double drawscale;
  594.         XPoint figure[20];
  595.         figure[0].x = (int) x; figure[0].y = (int) y;
  596.         for (line=1; line < numpairs[shape]; line++)    /* 2 pairs = 1 line */
  597.         {       figure[line].x  = (int) shapes[shape][line].length *
  598.                         cos(shapes[shape][line].angle + rot) * drawscale;
  599.                 figure[line].y  = (int) shapes[shape][line].length *
  600.                         sin(shapes[shape][line].angle + rot) * drawscale;
  601.         }
  602.         XDrawLines (disp, window, gc, figure, numpairs[shape], CoordModePrevious);
  603. }
  604.  
  605. main(argc, argv)
  606.         int argc;
  607.         char **argv;
  608. {       Colormap cmap;
  609.         Cursor cursor;
  610.         Display *disp;
  611.         Font font;
  612.         GC gc, pmgc;
  613.         KeySym key;
  614.         Pixmap pixmap;
  615.         Window window;
  616.         XColor black, exact;
  617.         XEvent event;
  618.         XSizeHints hint;
  619.         XWMHints wmhints;
  620.         extern int width, height;
  621.         int screen, depth;
  622.         char text[30];
  623.         unsigned long fg, bg;
  624.  
  625.         extern double drawscale, speedscale;
  626.         extern int numasts, rndint, ships, score, oldscore;
  627.         extern Objtype obj[SHIP+1];
  628.         unsigned char c;        /* for rand     */
  629.         double *temp, dx, dy, dist;
  630.         int level, crashed, flashon, len, pause = 0, delay = 64,
  631.                 enemycount, counter, counterstart = 1,
  632.                 i,      /* index for drawing objs, counting bullets */
  633.                 r;      /* radius of shield circle      */
  634.  
  635.         disp = XOpenDisplay(0);
  636.         if (disp == (Display *) NULL)
  637.         {       fprintf(stderr, "Could not open display\n");
  638.                 exit(1);
  639.         }
  640.         screen = DefaultScreen(disp);
  641.         bg = BlackPixel(disp, screen);
  642.         fg = WhitePixel(disp, screen);
  643.         hint.x = 150; hint.y = 200; hint.width = 550; hint.height = 550;
  644.         hint.flags = PPosition | PSize;
  645.         width = hint.width; height = hint.height-letheight-1;
  646.         depth = DefaultDepth (disp, screen);
  647.         window = XCreateSimpleWindow (disp, DefaultRootWindow(disp),
  648.                 hint.x, hint.y, hint.width, hint.height, 5, fg, bg);
  649.         pixmap = XCreatePixmap (disp, window, width, height, depth);
  650.         XSetStandardProperties (disp, window, "asteroids", "asteroids", None,
  651.                 argv, argc, &hint);
  652.         gc = XCreateGC (disp, window, 0, 0);
  653.         XSetGraphicsExposures(disp, gc, 0);     /* IMPORTANT!  If you do not
  654.                 specifically ask not to get Expose events, every XCopyArea
  655.                 will generate one, & the event queue will fill up.      */
  656.         font = XLoadFont(disp, "10x20\0");      /* If you don't have this
  657.                 font, try replacing it with 9x15\0      */
  658.         XSetFont(disp, gc, font);
  659.         pmgc = XCreateGC (disp, window, 0, 0);
  660.         XSetBackground (disp, gc, bg);
  661.         XSetForeground (disp, gc, fg);
  662.         XSetForeground (disp, pmgc, bg);  /* fg of pixmap is bg of window */
  663.         wmhints.flags = InputHint;
  664.         wmhints.input = True;
  665.         XSetWMHints(disp, window, &wmhints);    /* Thanks to Doug Merritt */
  666.         XSelectInput (disp, window,
  667.                 KeyPressMask | KeyReleaseMask | StructureNotifyMask);
  668.         XMapRaised (disp, window);
  669.  
  670.         /* Erase cursor. Just delete next 5 lines if any error. */
  671.         cmap = XDefaultColormap(disp, screen);
  672.         XAllocNamedColor(disp, cmap, "Black", &exact, &black);
  673.         cursor = XCreateFontCursor(disp, XC_dot);
  674.         XRecolorCursor(disp, cursor, &black, &black);
  675.         XDefineCursor(disp, window, cursor);
  676.  
  677.         XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  678. /*      Can delete next line if it causes trouble       */
  679.         srand((unsigned) time(0));      /* By Craig Smith       */
  680.         initasts();
  681. Newgame:
  682.         deletebooms();
  683.         ships = 3;
  684.         score = 0; oldscore = -1;
  685.         for (level = 0; ;)
  686.         {   if (level < 8) level++;
  687.             makeasts (level);
  688. Newship:    botline(disp, window, gc);
  689.             if (!obj[SHIP].alive)
  690.             {   obj[SHIP].x = width/2;
  691.                 obj[SHIP].y = height/2;
  692.                 obj[SHIP].xvel = 0;
  693.                 obj[SHIP].yvel = 0;
  694.                 obj[SHIP].rot = 3*pi/2;
  695.                 obj[SHIP].rotvel = 0;
  696.                 energy = 80;
  697.                 shield_on = 0;
  698.             }
  699.             obj[SHIP].alive = (ships > 0);
  700.             crashed = 0; flashon = 0; enemycount = 20;
  701.             counter = 0;
  702.             while (numasts)
  703.             {   for (i = FBUL; i < LASTBUL+1; i++)  /* Bullet timer */
  704.                     if (obj[i].alive)
  705.                     {   obj[i].time--;
  706.                         if (!obj[i].time) obj[i].alive = 0; /* Not --! */
  707.                     }
  708.                 while (XEventsQueued(disp, QueuedAfterReading))
  709.                 {   XNextEvent(disp, &event);
  710.                     switch (event.type)
  711.                     {   case MappingNotify:
  712.                             XRefreshKeyboardMapping (&event);
  713.                             break;
  714.                         case ConfigureNotify:
  715.                             width = event.xconfigure.width;
  716.                             height = event.xconfigure.height-letheight-1;
  717.                             XFreePixmap (disp, pixmap);
  718.                             pixmap = XCreatePixmap (disp, window, width, height, depth);
  719.                             XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  720.                             botline(disp, window, gc);
  721.                             break;
  722.                         case KeyPress:
  723.                             len = XLookupString (&event, text, 10, &key, 0);
  724.                             if (len == 1 && !shield_on) switch (text[0])
  725.                             {   case 'e':
  726.                                     obj[SHIP].rotvel = obj[SHIP].rotvel - .1; break;
  727.                                 case 'r':
  728.                                     obj[SHIP].rotvel = obj[SHIP].rotvel + .1; break;
  729.                                 case 'w':
  730.                                     obj[SHIP].rot -= pi/4; break;
  731.                                 case 't':
  732.                                     obj[SHIP].rot += pi/4; break;
  733.                                 case 'd':
  734.                                     obj[SHIP].rotvel = obj[SHIP].rotvel - .02; break;
  735.                                 case 'f':
  736.                                     obj[SHIP].rotvel = obj[SHIP].rotvel + .02; break;
  737.                                 case THRUST:
  738.                                     obj[SHIP].xvel += cos(obj[SHIP].rot);
  739.                                     obj[SHIP].yvel += sin(obj[SHIP].rot);
  740.                                     obj[SHIP].shape = SHIPTHRSHAPE;
  741.                                     break;
  742.                                 case FIRE:
  743.                                     if (obj[SHIP].alive) fire(); break;
  744.                                 case ' ':
  745.                                     if (obj[SHIP].alive)
  746.                                     {   hyper(); flashon = 1;
  747. /*                                  NOT XSetForeground (disp, gc, bg);
  748.         If you set the fg black, & print the highscore, it will effectively erase it.   */
  749.                                         XSetForeground (disp, pmgc, fg);
  750.                                         XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  751.                                     }
  752.                                     break;
  753.                                 case SHIELD:
  754.                                     if (energy)
  755.                                     {   shield_on = 1;
  756.                                         obj[SHIP].shape = SHIPSHAPE;}
  757.                                         break;
  758.                                 case '.':       /* decrease delay       */
  759.                                     if (delay > 1) delay >>=1; break;
  760.                                 case ',':       /* increase delay       */
  761.                                     delay <<=1; break;
  762.                                 case 'm':       /* decrease drawscale - may go negative */
  763.                                     drawscale -= .1; break;
  764.                                 case 'n':       /* increase drawscale   */
  765.                                     drawscale += .1; break;
  766.                                 case '2':       /* increase speedscale  */
  767.                                     speedscale += .1; break;
  768.                                 case '1':       /* decrease speedscale  */
  769.                                     speedscale -= .1; break;
  770.                                 case 'b':       /* increase moves/update */
  771.                                     counterstart++; break;
  772.                                 case 'v':       /* decrease moves/update */
  773.                                     if (counterstart > 1) counterstart--;
  774.                                     break;
  775.                                 case PAUSE:     /* pause        */
  776.                                     pause = 1 - pause; break;
  777.                                 case '+':       /* cheat        */
  778.                                     ships++; botline(disp, window, gc); break;
  779.                                 case 'Q':       /* quit         */
  780.                                     goto End;
  781.                                 case 's':       /* start new ship */
  782.                                     if (!obj[SHIP].alive)
  783.                                         if (ships < 1) goto Newgame;
  784.                                         else goto Newship;
  785.                                     break;
  786.                             }
  787.                             break;
  788.                         case KeyRelease:
  789.                             len = XLookupString(&event, text, 10, &key, 0);
  790.                             if (len == 1) switch (text[0])
  791.                             {   case 'e':
  792.                                     obj[SHIP].rotvel = 0; break;
  793.                                 case 'r':
  794.                                     obj[SHIP].rotvel = 0; break;
  795.                                 case THRUST:
  796.                                     obj[SHIP].shape = SHIPSHAPE;
  797.                                     break;
  798.                                 case SHIELD:
  799.                                     shield_on = 0; break;
  800.                             }
  801. /*                          break;              */
  802.                 }   }
  803.                 if (!pause)
  804.                 {   moveobjs(&crashed);
  805.                     if (ships) score--; /* timer effect */
  806.                     if (!counter)
  807.                     {   counter = counterstart; /* Restart counter */
  808.                         if (crashed == 2)
  809.                         {   crashed--; flashon++;
  810.                             boom(SHIP, BMAX-1, 70);
  811.                             XSetForeground (disp, pmgc, fg);
  812.                             XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  813.                             botline(disp, window, gc);
  814.                         }
  815.                         /* Write copyright notice       */
  816.                         if (!ships && blist == NULL)
  817.                         {   sprintf(text, "Xasteroids");
  818.                             XDrawImageString (disp, pixmap, gc,
  819.                                 width/2-50, height/2-2*letheight,
  820.                                 text, strlen(text));
  821.                             sprintf(text, "Copyright 1990 by Phil Goetz");
  822.                             XDrawImageString (disp, pixmap, gc,
  823.                                 width/2-140, height/2,
  824.                                 text, strlen(text));
  825.                             sprintf(text, "goetz@cs.buffalo.edu");
  826.                             XDrawImageString (disp, pixmap, gc,
  827.                                 width/2-100, height/2+2*letheight,
  828.                                 text, strlen(text));
  829.                         }
  830.                         /*      Draw objects    */
  831.                         for (i = 0; i <= LASTOBJ; i++)
  832.                             if (obj[i].alive)
  833.                                 vdraw(disp, pixmap, gc, obj[i].shape,
  834.                                         obj[i].x, obj[i].y, obj[i].rot);
  835.                         if (shield_on && obj[SHIP].alive)
  836.                         {   r = abs((int) (drawscale*SHIPSIZE));
  837.                             XDrawArc(disp, pixmap, gc,
  838.                                 ((int) obj[SHIP].x) - r,
  839.                                 ((int) obj[SHIP].y) - r,
  840.                                 2*r, 2*r, 0, 360*64);
  841.                             energy--;
  842.                             if (!energy) shield_on = 0;
  843.                         }
  844.                         drawbooms(disp, pixmap, gc);
  845.                         /* update display:      */
  846.                         XCopyArea(disp, pixmap, window, gc, 0, 0, width, height, 0, 0);
  847.                         printss(disp, window, gc);
  848.                         /* erase objects        */
  849.                         XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  850.                         if (flashon)
  851.                         {   flashon--;
  852.                             XSetForeground (disp, pmgc, bg);
  853.                             XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  854.                         }
  855.                         XSync(disp, 0);
  856.                     }
  857.                     counter--;
  858.                     c = rand(rndint)>>8;
  859.                     if (!obj[ENEMY].alive)
  860.                         {   if (c < level)
  861.                             {   c = rand(rndint);
  862.                                 if (c < level * 10) makeenemy(level);
  863.                         }   }
  864.                     else
  865.                         obj[ENEMY].yvel += (c>128+6*obj[ENEMY].yvel) ? .5 : -.5;
  866.                     enemycount--; if (!enemycount)
  867.                     {   enemycount = 100;
  868.                         if (obj[ENEMY].alive)
  869.                         {   obj[ENEMYBUL].alive++;
  870.                             obj[ENEMYBUL].x = obj[ENEMY].x;
  871.                             obj[ENEMYBUL].y = obj[ENEMY].y;
  872.                             dx = obj[SHIP].x - obj[ENEMY].x;
  873.                             dy = obj[SHIP].y - obj[ENEMY].y;
  874.                             dist = sqrt(dx*dx + dy*dy);
  875.                             obj[ENEMYBUL].xvel = 3*dx/dist;
  876.                             obj[ENEMYBUL].yvel = 3*dy/dist;
  877.                         }
  878.                         else    obj[ENEMYBUL].alive = 0;
  879.                     }
  880.                     for (i = 0; i < delay; i++);
  881.                 }
  882.             }
  883.         }
  884. End:    printf("\nYour high score was %d\n", highscore);
  885.         XFreeGC (disp, gc);
  886.         XFreeGC (disp, pmgc);
  887.         XFreePixmap (disp, pixmap);
  888.         XDestroyWindow (disp, window);
  889.         XCloseDisplay (disp);
  890.         exit(0);
  891. }
  892.