home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / VRAC / XASTER.ZIP / XASTER < prev   
Text File  |  1992-11-19  |  34KB  |  1,050 lines

  1.      Here is the source to Xasteroids, version 4.2.  Changes include better
  2. collision detection, shields, & explosions.  Many thanks to Peter
  3. Phillips.  If anyone wants the shorter & simpler version 3.1, write me.
  4.  
  5.      This program runs under UNIX in the X-Windows or OpenWindows
  6. environment.  It could probably be modified for other operating systems
  7. without difficulty.  I compile it under quasi-BSD with this command:
  8.  
  9. cc -I/util/X11/include -L/util/X11/lib ast.c -lm -lX11 -o ast.out -O
  10.  
  11. That is, include files /util/X11/include, use the library in /util/X11/lib,
  12. source file ast.c, use the math and X11 libraries, object file will
  13. be ast.out, and Optimize.
  14.  
  15.      Cut the stuff below into ast.docs and ast.c.  Then compile ast.c.
  16. I know it is bad practice to put everything in one file, but I wanted to
  17. make it easy to compile.
  18.  
  19.      If you like the game, please send $5 to
  20.  
  21.     Phil Goetz
  22.     4023 Huckleberry Row
  23.     Ellicott City, MD 21043
  24.  
  25.      Even if you don't register, please send a note to my e-mail address
  26. so I know how many people use Xasteroids.  Then I may be motivated to
  27. update it again, or write new programs...
  28. Send any comments, suggestions, bug reports, modifications, etc., to
  29.  
  30.     goetz@cs.buffalo.EDU
  31.  
  32.      Lots of people have complained that Xasteroids wouldn't run fast
  33. enough on their display.  I had different ideas on how to affect the speed,
  34. and implemented all of them.  So Version 3 came with more speed controls
  35. than most people like to think about:
  36.  
  37.      1 2: Scale of movement (default 1):  Increasing this causes each object to
  38. move further every turn.
  39. Advantage:    Can be changed in smaller amounts than moves/frame.
  40. Disadvantage:    Increasing it too much can cause bullets to fly through
  41. asteroids without hitting them.  Looks jerky.
  42.  
  43.      v b: Moves per frame (default 1):  Increasing this causes the main loop to
  44. execute more times before updating the display.
  45. Advantages:    Avoids the problem of bullets flying through asteroids.
  46. Disadvantages:    Increases only by integer amounts.
  47.  
  48.      , .: Delay:    Used when your client runs too fast to play comfortably.
  49.  
  50.      n m: Object size:    If your client is too slow, decrease the size and resize
  51. the window to a smaller size.  Then type 'x' to use XFillRectangle erase.
  52.  
  53.      Playing with scale of movement, object size, and window size can give you
  54. very different games.
  55.  
  56. Known bugs:
  57.      David Elliot (dce@sonyusa.sony.com) says that he had to put an
  58. XSync(disp) after the XDrawLines call or he would get protocol errors.
  59.  
  60.      On anything slower than a SPARCstation 1, or on any color screen,
  61. it will really drag.  There should be a way to set color screens to use
  62. a bitmap of depth 1, but I don't know how.  Please tell me if you do.
  63.      The code is not optimized because the XWindows
  64. calls take the vast majority of the time.  I tried, for instance,
  65. reading sines and cosines from a table instead of calculating them -
  66. it made no noticeable difference in speed.  Similarly, the collision
  67. detection could be optimized only to check objects nearby - but why
  68. bother.  Same goes for using registers, pointers to frequently-referenced
  69. array elements, etc.  It MIGHT make a significant difference in runtime
  70. if you replace the vector drawing with bitmaps.  It runs a LOT slower on
  71. color displays.
  72.      The vast majority of time seems to be used in erasing the pixmap
  73. each round, & there isn't much to do about that.  My tests have indicated
  74. that blanking individual asteroids rather than the whole screen would
  75. take comparable time, unless you had a complicated routine to optimize
  76. blanking.
  77.      If you modify this program, please send me a copy.  Modifications
  78. I would like to see include:  sound (esp. for Sparcstations), drawing
  79. the asteroids to pixmaps so they can be put on the screen quicker
  80. (though not much quicker - the X calls seem to take most of the time),
  81. an options screen to set parameters such as speed, whether bullets
  82. can be fired before your current ones are dead, whether to start in the
  83. center of the screen between levels), a permanent high score file
  84. to be displayed sometimes between games, and jagged fractal asteroids
  85. (not just removal of the lines to the center; I like those).
  86. ---------------------
  87. ast.docs:
  88.          Xasteroids
  89.     Copyright 1990 by Phil Goetz
  90.         goetz@cs.Buffalo.EDU
  91.  
  92. Keypress    Command
  93. --------        -------
  94.     e        Rotate counterclockwise ("left")
  95.     r        Rotate clockwise ("right")
  96.     w        Rotate 45 degrees counterclockwise
  97.     t        Rotate 45 degrees clockwise
  98.     d        Increase counterclockwise rotational velocity
  99.     f        Increase clockwise rotational velocity
  100.     o        Thrust
  101.     p        Fire
  102.     `        Shields
  103.   space        Hyperspace
  104.     s        Start new ship in center of playing field
  105.         (Also used to start a new game)
  106.    esc         Pause
  107.     Q        Quit
  108. Speed commands:    Key associated with faster speed is to the right of its
  109.         corresponding key associated with slower speed.
  110.     .        Decrease delay:  Speed game up
  111.     ,        Increase delay:  Slow the game down
  112.     m        Decrease size    ("Minimize")
  113.     n        Increase size
  114.     b        Increase # of moves/frame
  115.     v        Decrease # of moves/frame
  116.     2        Increase scale of movement
  117.     1        Decrease scale of movement
  118.  
  119. Object        Score
  120. -------        -----
  121. Big asteroid    25
  122. Medium asteroid    50
  123. Little asteroid    100
  124. Enemy spaceship    500
  125. Enemy bullet    500
  126.  
  127. Commands can only be entered when the mouse pointer is in the
  128. asteroids window.
  129.  
  130. Resize the window with your window manager
  131. at any time for a different playing field.
  132. ---------------------
  133. ast.c:
  134. /*    Xasteroids
  135.     Copyright 1990 by Phil Goetz
  136.     goetz@cs.buffalo.EDU
  137.     Version 4.2, 4/1/92
  138.  
  139.     Changes from version 3.1:
  140.  
  141.         Better collision detection:  Actually checks for intersection
  142.             of line segments if non-round objects are very close.
  143.         Explosions!  (Thanks to Peter Phillips.)
  144.         Fine rotation repeating detected using KeyRelease.
  145.         Thrust indicator behind ship.  (Thanks to Peter Phillips.)
  146.         Doesn't place ship in center of screen for new levels.
  147.         Seeds random-number generator with time.
  148.             (Thanks to Craig Smith.)
  149.         Shields!  (Thanks to Peter Phillips.  I rewrote the bounce code
  150.             & added the energy bar & other refinements.)
  151.         Solved won't-take-input bug. (Thanks to Doug Merritt.)
  152.         Detects failure of XOpenDisplay. (Thanks to Pat Ryan.)
  153.  
  154.     Contributors:    Peter Phillips <pphillip@cs.ubc.ca>
  155.             Pat Ryan <pat@jaameri.gsfc.nasa.gov>
  156.             Craig Smith <csmith@cscs.UUCP>
  157.             Doug Merritt <doug@netcom.com>
  158. */
  159. #include <stdio.h>        /* For NULL    */
  160. #include <X11/Xlib.h>
  161. #include <X11/Xutil.h>
  162. #include <X11/cursorfont.h>    /* For erasing cursor - not important    */
  163. #include <math.h>
  164.  
  165. /* Indexes for 1st dimension of obj    */
  166. /* The order they are in is important    */
  167. #define    AST    0
  168. #define    ENEMY    96
  169. #define ENEMYBUL 97
  170. #define    FBUL    98
  171. #define    LASTBUL    102
  172. #define    SHIP    103
  173. #define LASTOBJ 103    /* Must be ship!  See makeasts().    */
  174.  
  175. /* Shapes    */
  176. /* Order is important!  See collide().    */
  177. #define    ASTSHAPE1    0
  178. #define ASTSHAPE2    1
  179. #define ASTSHAPE3    2
  180. #define ENBULSH        3
  181. #define    BULSHAPE    4
  182. #define    SHIPSHAPE    5
  183. #define SHIPTHRSHAPE    6
  184. #define    ENEMYSHAPE    7
  185. #define LASTSHAPE    7
  186.  
  187. /* Masses    */
  188. #define M_BIG    8.0
  189. #define M_MED    4.0
  190. #define M_SMALL    1.0
  191. #define M_SHIP    1.5
  192. #define M_ENEMY    1.0
  193. #define M_BULLET 0.1
  194.  
  195. /* Keys        */
  196. #define FIRE        'p'
  197. #define PAUSE        27    /* escape    */
  198. #define SHIELD        '`'
  199. #define THRUST        'o'
  200.  
  201. #define BMAX        300    /* Max particles in a "boom" + 1    */
  202. #define letheight    20    /* height of font    */
  203. #define    pi        3.1415926535897932384
  204. #define SHIPSIZE    28
  205.  
  206. typedef struct _Boom *Boom;
  207. struct _Boom {Boom next; int dur, part; double bcoord[BMAX][2], bvec[BMAX][2]};
  208. typedef struct {int shape, alive, time;
  209.         double mass, x, y, xvel, yvel, rot, rotvel} Objtype;
  210. typedef struct {double angle; int length} PolarPair;
  211. typedef struct {double x, y, mag} Vector;
  212.  
  213. /* Global variables:    */
  214. Objtype    obj[SHIP+1];
  215. /*    In shapes pairs, 1st # is radians, 2nd is length in pixels.
  216.     Degrees: 0 ->, pi/2 down, pi <-, 3*pi/2 up
  217.     IF YOU CHANGE THE SHAPES, you MUST change numpairs & shapesize
  218. */
  219. PolarPair shapes[LASTSHAPE+1][11] =
  220.     {    {{0,0}, {3*pi/2,40}, {0,20}, {pi/4,28}, {pi/2,40}, /* just crossed 0-deg line */
  221.          {3*pi/4,28},{pi,40},{5*pi/4,28},{3*pi/2,40},{7*pi/4,28},{0,20}},
  222. /*    hexagon if you prefer
  223.         {{0,0}, {3*pi/2, 20}, {pi/6, 20}, {pi/2, 20},
  224.                  {5*pi/6, 20}, {7*pi/6, 20}, {3*pi/2, 20}, {11*pi/6, 20}},
  225. */
  226.         {{0,0}, {3*pi/2,20}, {0,10}, {pi/4,14}, {pi/2,20},
  227.          {3*pi/4,14},{pi,20},{5*pi/4,14},{3*pi/2,20},{7*pi/4,14},{0,10}},
  228.         {{0,0}, {3*pi/2,10}, {0,5}, {pi/4,7}, {pi/2,10},
  229.          {3*pi/4,7},{pi,10},{5*pi/4,7},{3*pi/2,10},{7*pi/4,7},{0,5}},
  230.         {{0,0}, {7*pi/4, 4}, {pi/4, 4}, {3*pi/4, 4}, {5*pi/4, 4}},
  231.         {{0,0}, {0,10}},
  232.         {{0,0}, {5*pi/4,28}, {0,20}, {pi/4,28},{3*pi/4,28},{pi,20},{7*pi/4,28}},    /* Ship */
  233.         {{0,0}, {5*pi/4,28}, {0,20}, {pi/4,28},{3*pi/4,28},{pi,20},
  234.          {7*pi/4,28}, {3*pi/4, 7}, {9*pi/8, 13}, {15*pi/8, 13}},    /* Thrusting ship */
  235.         {{0,0}, {pi,20},{7*pi/4,28},{pi/4,28},{pi,20}}
  236.     };
  237. Boom    blist = NULL;
  238. double    drawscale = 1, speedscale = 1;
  239. int    width, height,
  240.     energy,        /* # of turns shield is good for    */
  241.     highscore = 0,
  242.     nextbul = FBUL,            /* Obj# of next bullet fired    */
  243.     numasts, oldscore = 99,
  244.     rndint = 73, ships, score,
  245.     numpairs[LASTSHAPE+1]    = {11, 11, 11, 5, 2, 7, 10, 5},
  246.     shapesize[LASTSHAPE+1]    = {44, 21, 10, 2, 1, SHIPSIZE+1, 35, 20},
  247.     shield_on;
  248.  
  249. initasts()
  250. {    int i;
  251.     extern Objtype obj[SHIP+1];
  252.  
  253.     for (i = 0; i < LASTOBJ+1; i++)
  254.     {    obj[i].rot = 0;
  255.         obj[i].rotvel = 0;
  256.     }
  257.     for (i = 0; i < ENEMY; i++)
  258.     {    obj[i].shape = ASTSHAPE1;
  259.     }
  260.     obj[SHIP].shape = SHIPSHAPE;
  261.     obj[SHIP].mass = M_SHIP;
  262.     obj[ENEMY].shape = ENEMYSHAPE;
  263.     obj[ENEMY].mass = M_ENEMY;
  264.     obj[ENEMYBUL].shape = ENBULSH;
  265.     obj[ENEMYBUL].mass = M_BULLET;
  266.     for (i = FBUL; i < LASTBUL+1; i++)
  267.     {    obj[i].shape = BULSHAPE;
  268.         obj[i].mass = M_BULLET;
  269. }    }
  270.  
  271. makeasts(level)
  272. {    int i;
  273.     extern Objtype obj[SHIP+1];
  274.     extern int numasts, rndint;
  275.     extern double speedscale;
  276.     unsigned char a;
  277.  
  278.     for (i = 0; i < SHIP; i++)
  279.         obj[i].alive = 0; /* Erase objs from last level except ship */
  280.     for (i = ENEMYBUL; i < LASTBUL+1; i++)
  281.         obj[i].time = 0;        /* No bullets in the air */
  282.     for (i = 0; i < level+4; i++)    /* Asteroids:            */
  283.     {    a = rand(rndint); a>>=1;    /* a = rand# from 0 to 127 */
  284.         if (a > 63)
  285.             obj[i].x = (double) a;
  286.             else obj[i].x = (double) (width - a);
  287.         a = rand(rndint); a>>=1;    /* Now the same for y    */
  288.         if (a >  63)
  289.             obj[i].y = (double) a;
  290.             else obj[i].y = (double) height - a;
  291.         a = rand(rndint); a = 4 - a>>5;
  292.         obj[i].rot = (double) a;
  293.         a = rand(rndint);
  294.         obj[i].rotvel = ((double) a)/2048;
  295.         a = rand(rndint);
  296.         obj[i].xvel = cos((double) a);
  297.         obj[i].yvel = sin((double) a);
  298.         obj[i].shape = ASTSHAPE1;
  299.         obj[i].mass = M_BIG;
  300.         obj[i].alive = 1;
  301.     }
  302.     numasts = i;
  303. }
  304.  
  305. makeenemy(level)    /* Start an enemy ship    */
  306.     int level;
  307. {    extern Objtype obj[SHIP+1];
  308.     extern int height, rndint;
  309.     unsigned char c;
  310.  
  311.     obj[ENEMY].alive = 1;
  312.     obj[ENEMY].x = 0;
  313.     obj[ENEMY].y = (double) height/4;
  314.     c = rand(rndint); obj[ENEMY].y += (double) c; /* May put enemy outside window    */
  315.     obj[ENEMY].xvel = (double) level/2;
  316.     obj[ENEMY].yvel = 0;
  317. }
  318.  
  319. int nextast()    /* Find next unused asteroid object    */
  320. {    extern Objtype obj[SHIP+1];
  321.     int i;
  322.     for (i = 0; obj[i].alive; i++);    /* guaranteed to find one    */
  323.     return i;
  324. }
  325.  
  326. int collide(i, j)    /* Returns non-zero if i collided with j    */
  327.             /* Ship must be j!  (See below)            */
  328.     int i, j;
  329. {    extern Objtype obj[SHIP+1];
  330.     extern int shapesize[LASTSHAPE+1];
  331.     extern double drawscale;
  332.     double    mi, mj,                /* Slopes of lines    */
  333.         ix1, ix2, iy1, iy2, jx1, jx2, jy1, jy2,    /* Endpoints    */
  334.         roti, rotj,
  335.         xcross,    ycross,        /* coord of intersection    */
  336.         z;
  337.     int    diff, xd, yd,
  338.         a, b,
  339.         shapei, shapej;
  340.     xd = obj[i].x - obj[j].x;
  341.     yd = obj[i].y - obj[j].y;
  342.     diff = sqrt((double)(xd*xd + yd*yd));
  343.     shapei = obj[i].shape; shapej = obj[j].shape;
  344.     /* Note this will miss if drawscale is < 0    */
  345.     if (diff < (shapesize[shapei] + shapesize[shapej])*drawscale)
  346.     {   /* If both are round objects, approximation is good */
  347.         if (shapei < SHIPSHAPE && shapej < SHIPSHAPE) return 1;
  348.         if (j == SHIP && shield_on) return 1;    /* Ship always j! */
  349.         roti = obj[i].rot; rotj = obj[j].rot;
  350.         ix1 = (double) obj[i].x; iy1 = (double) obj[i].y;
  351.         for (a = 1; a < numpairs[shapei]; a++)
  352.         {    ix2 = ix1 + (double) shapes[shapei][a].length * drawscale *
  353.             cos(shapes[shapei][a].angle + roti);
  354.         iy2 = iy1 + (double) shapes[shapei][a].length * drawscale *
  355.             sin(shapes[shapei][a].angle + roti);
  356.         if (ix1 == ix2)
  357.         {    printf("\nif1 = if2"); return 1;} /* Easy way out */
  358.         mi = (iy2-iy1)/(ix2-ix1);
  359.         z = mi*ix1;
  360.         jx1 = (double) obj[j].x; jy1 = (double) obj[j].y;
  361.         for (b = 1; b < numpairs[shapej]; b++)
  362.         {    jx2 = jx1 + (double) shapes[shapej][b].length *
  363.                 drawscale * cos(shapes[shapej][b].angle + rotj);
  364.             jy2 = jy1 + (double) shapes[shapej][b].length *
  365.                 drawscale * sin(shapes[shapej][b].angle + rotj);
  366.             if (jx1 == jx2)
  367.             {    ycross = ix1 + (jx1-ix1)*mi;
  368.                 if ((jx1-ix1) * (ix2-jx1) >= 0 &&
  369.                     (ycross-jy1)*(jy2-ycross) >= 0)
  370.                     return 1;
  371.                 else jx2 += .0001;    /* Avoid divide by 0 */
  372.             }
  373.             mj = (jy2-jy1)/(jx2-jx1);
  374.             if (mj == mi) goto Loopend;    /* Parallel lines */
  375.             xcross = (iy1 - jy1 + mj*jx1 - z) / (mj - mi);
  376.             if ((xcross-ix1) * (ix2-xcross) > 0
  377.                 && (xcross-jx1) * (jx2-xcross) > 0) return 1;
  378. Loopend:        jx1 = jx2; jy1 = jy2;
  379.         }
  380.         ix1 = ix2; iy1 = iy2;
  381.     }   }
  382.     return 0;
  383. }
  384.  
  385. blastpair(i, j)        /* Generate random velocity vector v.    */
  386.     int i, j ;    /* Add v to i, -v to j.            */
  387. {    extern int rndint;
  388.     extern Objtype obj[SHIP+1];
  389.     unsigned char c;    /* for rand    */
  390.     double vx, vy;
  391.     c = rand(rndint);
  392. /*    c = 4 - c>>5;    if you need angles from -3 to 4        */
  393.     c>>2;        /* possibly save some time on sin/cos    */
  394.     vx = cos((double) c); vy = sin((double) c);
  395.     obj[i].xvel = obj[i].xvel + vx;
  396.     obj[i].yvel = obj[i].yvel + vy;
  397.     obj[j].xvel = obj[j].xvel - vx;
  398.     obj[j].yvel = obj[j].yvel - vy;
  399.     obj[i].rotvel = obj[i].rotvel + .05;
  400.     obj[j].rotvel = obj[j].rotvel - .05;
  401. }
  402.  
  403. /* dot product of 2 vectors    */
  404. #define dot(i,j)    (i.x*j.x + i.y*j.y)
  405. /* rotational inertia (constant eliminated) of obj. i    */
  406. #define rotinert(i)    (double) (obj[i].mass*shapesize[obj[i].shape]*shapesize[obj[i].shape])
  407.  
  408. /* cause two objects to collide elastically    */
  409. bounce(i, j)
  410. int    i,j;
  411. {
  412. double    rotrat, temp;
  413. extern    Objtype obj[SHIP+1];
  414. Vector    vi, vj,        /* velocity of objs i, j        */
  415.     ij,        /* vector from center of i to center of j */
  416.     vi_ij, vj_ij,    /* velocity of obj along vector ij    */
  417.     vipij, vjpij,    /* velocity perpendicular to ij        */
  418.     vi_ijf, vj_ijf;    /* post-collision velocity along ij    */
  419.  
  420. vi.x = obj[i].xvel; vi.y = obj[i].yvel;
  421. vj.x = obj[j].xvel; vj.y = obj[j].yvel;
  422. ij.x = obj[j].x - obj[i].x; ij.y = obj[j].y - obj[i].y;
  423. ij.mag = sqrt(ij.x*ij.x + ij.y*ij.y);
  424. /*
  425. Calculate velocities projected onto ij;
  426.     vi_ij = vi*cos(a) = (vi dot ij) / |ij|        */
  427. vi_ij.mag = dot(vi, ij) / ij.mag;
  428. vi_ij.x = (ij.x * vi_ij.mag) / ij.mag;
  429. vi_ij.y = (ij.y * vi_ij.mag) / ij.mag;
  430. vj_ij.mag = dot(vj, ij) / ij.mag;
  431. vj_ij.x = (ij.x * vj_ij.mag) / ij.mag;
  432. vj_ij.y = (ij.y * vj_ij.mag) / ij.mag;
  433. if (vi_ij.mag - vj_ij.mag < 0)    /* Objs moving away from each other -
  434.     Since objs are round (at least when bouncing), this means
  435.     they are moving away from each other already.    */
  436.     return;
  437. /*
  438. Calculate component of velocities perpendicular to ij:
  439.     |vipij| = |vi|*sin(a) = |vi x ij| / |ij|
  440. Same as
  441.     |vipij| = |vi|*cos(pi/2 - a) = (vi dot (perp. to ij)) / |ij|    */
  442. temp = vi.y*ij.x - vi.x*ij.y;    /* - (cross product when 3rd coord is 0)*/
  443. temp /= (ij.mag*ij.mag);
  444. vipij.x = -ij.y*temp; vipij.y = ij.x*temp;
  445. temp = (vj.x*ij.y - vj.y*ij.x) / (ij.mag*ij.mag);
  446. vjpij.x = -ij.y*temp; vjpij.y = ij.x*temp;
  447. /*
  448. Calculate the linear elastic collision along ij:
  449.     mass(i)*vi_ij + mass(j)*vj_ij = mass(i)*vi_ijf + mass(j)*vj_ijf
  450.     vi_ij + vi_ijf = vj_ij + vj_ijf    (derived by dividing equation
  451.     for conservation of kinetic energy by eq. for cons. of momentum) */
  452. temp = obj[i].mass/obj[j].mass;
  453. vj_ijf.x = (temp * (2*vi_ij.x - vj_ij.x) + vj_ij.x) / (1 + temp);
  454. vj_ijf.y = (temp * (2*vi_ij.y - vj_ij.y) + vj_ij.y) / (1 + temp);
  455. vi_ijf.x = vj_ijf.x + vj_ij.x - vi_ij.x;
  456. vi_ijf.y = vj_ijf.y + vj_ij.y - vi_ij.y;
  457. /*
  458. Now, given vi_ijf and vj_ijf, add them to the perpendicular
  459.     components to get final velocity vectors        */
  460. obj[i].xvel = vi_ijf.x + vipij.x;
  461. obj[i].yvel = vi_ijf.y + vipij.y;
  462. obj[j].xvel = vj_ijf.x + vjpij.x;
  463. obj[j].yvel = vj_ijf.y + vjpij.y;
  464. /*
  465. Now calculate rotational velocity exchange    */
  466. rotrat = rotinert(i)/rotinert(j);
  467. temp = rotrat * (2*obj[i].rotvel - obj[j].rotvel) / (1+rotrat);
  468. obj[i].rotvel = temp + obj[j].rotvel - obj[i].rotvel;
  469. obj[j].rotvel = temp;
  470. }
  471.  
  472. botline(disp, window, gc)    /* Print status line text    */
  473.     Display *disp;
  474.     Drawable window;
  475.     GC gc;
  476. {    extern int highscore, ships, score;
  477.     char text[70];
  478.     sprintf(text, "Ships:%2d   Score:%6d   Shield:        High:%6d",
  479.         ships, score, highscore);
  480.     XDrawImageString (disp, window, gc, 0, height+letheight,
  481.             text, strlen(text));
  482. }
  483.  
  484. printss(disp, window, gc)    /* Print ships and score    */
  485.     Display *disp;
  486.     Drawable window;
  487.     GC gc;
  488. {    extern int height, highscore, oldscore, ships, score;
  489.     extern Objtype obj[SHIP+1];    /* to kill ship    */
  490.     char sstring[30];
  491.  
  492.     if (score != oldscore)
  493.     {    if (score/10000 > oldscore/10000)
  494.         {    ships++; botline(disp, window, gc);}
  495.         if (score/10000 < oldscore/10000)
  496.         {    ships--; botline(disp, window, gc);
  497.             if (!ships) obj[SHIP].alive = 0;
  498.         }
  499.         if (score > highscore)    /* Separate if to avoid flashing */
  500.         {    highscore = score;
  501.             sprintf(sstring, "%6d", highscore);
  502.             XDrawImageString (disp, window, gc, 460,
  503.                 height+letheight, sstring, strlen(sstring));
  504.         }
  505.         sprintf(sstring, "%6d", score);
  506.         XDrawImageString (disp, window, gc, 170, height+letheight,
  507.                 sstring, strlen(sstring));
  508.         oldscore = score;
  509.     }
  510.  
  511.     /* Draw shield energy bar    */
  512.     XFillRectangle(disp, window, gc, 340, height+8, energy>>1, 10);
  513.     XClearArea(disp, window, 340+(energy>>1), height+8, 8, 10, False);
  514. }
  515.  
  516. upscore(killer, up)    /* Only award score for things the player shot */
  517.     int killer, up;
  518. {    extern int score;
  519.     if (killer != ENEMYBUL && killer != SHIP)
  520.         score = score + up;
  521. }
  522.  
  523. /* boom, movebooms, drawbooms all by Peter Phillips */
  524. boom(ob, particles, duration)
  525. int ob;
  526. int particles;
  527. int duration;
  528. { extern int rndint;
  529.   int i;
  530.   unsigned int r1, r2;
  531.   Boom b;
  532.   double x, y;
  533.   double angle, length;
  534.  
  535.   b = (Boom) malloc(sizeof(struct _Boom));
  536.   b->dur = duration;
  537.   b->part = particles;
  538.   x = obj[ob].x;
  539.   y = obj[ob].y;
  540.   for (i = 0; i < particles; i++) {
  541.     r1 = (rand(rndint) >> 2) % 100;
  542.     r2 = (rand(rndint) >> 2) % 7;
  543.  
  544.     b->bcoord[i][0] = x;
  545.     b->bcoord[i][1] = y;
  546.     angle = r1 * pi / 50.0;
  547.     length = 3 + r2;
  548.     b->bvec[i][0] = cos(angle) * length + obj[ob].xvel;
  549.     b->bvec[i][1] = sin(angle) * length + obj[ob].yvel;
  550.   }
  551.   b->next = blist;
  552.   blist = b;
  553. }
  554.  
  555. /* move the various booms that are active */
  556. movebooms()
  557. {
  558.   int i;
  559.   Boom b, prevb;
  560.  
  561.   prevb = NULL;
  562.   b = blist;
  563.   while (b != NULL) {
  564.     b->dur--;
  565.     if (b->dur < 0) { /* delete this boom */
  566.       Boom temp;
  567.  
  568.       temp = b;
  569.       if (prevb == NULL) {
  570.         blist = b->next;
  571.       } else {
  572.         prevb->next = b->next;
  573.       }
  574.       b = b->next;
  575.       free(temp);
  576.     } else {  /* move boom, advance list */
  577.       for (i = 0; i < b->part; i++) {
  578.         b->bcoord[i][0] += b->bvec[i][0];
  579.         b->bcoord[i][1] += b->bvec[i][1];
  580.       }
  581.       prevb = b;
  582.       b = b->next;
  583.     }
  584.   }
  585. }
  586.  
  587. /* Draw the various booms */
  588. drawbooms(disp, window, gc)
  589.      Display *disp;
  590.      Drawable window;
  591.      GC gc;
  592. {
  593.   int i;
  594.   Boom b;
  595.   XPoint figure[BMAX];
  596.  
  597.   b = blist;
  598.   while (b != NULL) {
  599.     for (i = 0; i < b->part; i++) {
  600.       figure[i].x = (int) b->bcoord[i][0];
  601.       figure[i].y = (int) b->bcoord[i][1];
  602.     }
  603.     XDrawPoints(disp, window, gc, figure, b->part, CoordModeOrigin);
  604.     b = b->next;
  605.   }
  606. }
  607.  
  608. deletebooms()    /* delete all booms */
  609. {    Boom b;
  610.  
  611.     b = blist;
  612.     while (b != NULL)
  613.     {    b->dur = 0;
  614.         b = b->next;
  615. }    }
  616.  
  617. killast(killer, i)
  618.     int killer, i;        /* i = Asteroid # to kill    */
  619. {    extern Objtype obj[SHIP+1];
  620.     extern int numasts;
  621.     int k, na, oldna;
  622.  
  623.     if (obj[i].shape == ASTSHAPE1)
  624.     {    na = nextast();        /* Could put 6 lines in a sub */
  625.         obj[na].x = obj[i].x;
  626.         obj[na].y = obj[i].y;
  627.         obj[na].xvel = obj[i].xvel;
  628.         obj[na].yvel = obj[i].yvel;
  629.         obj[na].alive++;
  630.         obj[na].shape = ASTSHAPE2;
  631.         obj[na].mass = M_MED;
  632.         obj[i].shape = ASTSHAPE2;
  633.         obj[i].mass = M_MED;
  634.         blastpair(i, na);
  635.         boom(i, 30, 12);
  636.         numasts++;
  637.         upscore(killer, 25);
  638.     }
  639.     else if (obj[i].shape == ASTSHAPE2)
  640.     {
  641.         for (k = 0; k < 3; k++)
  642.         {    oldna = na;
  643.             na = nextast();
  644.             obj[na].x = obj[i].x;
  645.             obj[na].y = obj[i].y;
  646.             obj[na].xvel = obj[i].xvel;
  647.             obj[na].yvel = obj[i].yvel;
  648.             obj[na].alive++;
  649.             obj[na].shape = ASTSHAPE3;
  650.             obj[na].mass = M_SMALL;
  651.             if (k == 1) blastpair(oldna,na);
  652.         }
  653.         obj[i].shape = ASTSHAPE3;
  654.         obj[i].mass = M_SMALL;
  655.         blastpair(na, i);
  656.         boom(i, 20, 10);
  657.         numasts = numasts + 3;
  658.         upscore(killer, 50);
  659.     }
  660.     else if (obj[i].shape == ASTSHAPE3)
  661.     {    boom(i, 10, 8);
  662.         obj[i].alive = 0; numasts--; upscore(killer, 100);}
  663.     else    /* enemy {ship or bullet}    */
  664.     {    boom(i, 9, 7);
  665.         obj[i].alive = 0; upscore(killer, 500);}
  666. }
  667. moveobjs(crash)
  668.     int *crash;
  669. {    extern Objtype obj[SHIP+1];
  670.     extern int ships;
  671.     extern double speedscale;
  672.     int i, j;    /* Indexes    */
  673.     double *temp;
  674.  
  675.     movebooms();
  676.     for (i = 0; i < LASTOBJ+1; i++)
  677.         if (obj[i].alive)
  678.         {    temp = &obj[i].x;
  679.             *temp = *temp + obj[i].xvel*speedscale;
  680.             while (*temp < 0) *temp = *temp + (double) width;
  681.             while (*temp > width) *temp = *temp - (double) width;
  682.             temp = &obj[i].y;
  683.             *temp = *temp + obj[i].yvel*speedscale;
  684.             while (*temp < 0) *temp = *temp + height;
  685.             while (*temp > height) *temp = *temp - height;
  686.             obj[i].rot = obj[i].rot + obj[i].rotvel;
  687.         }
  688.     for (i = 0; i < FBUL; i++)
  689.         if (obj[i].alive)
  690.         {
  691.         if (obj[SHIP].alive && collide(i, SHIP))
  692.         {    if (shield_on) bounce(SHIP, i);
  693.             else
  694.             {    *crash = 2;
  695.                 ships--; obj[SHIP].alive = 0;
  696.                 killast(SHIP, i);
  697.                 continue;
  698.         }    }
  699.         for (j = ENEMYBUL; j < LASTBUL+1; j++)
  700.             if (obj[j].alive && collide(i, j) &&
  701.                (j != ENEMYBUL || (i != ENEMYBUL && i != ENEMY)))
  702.             {    obj[j].alive = 0;    /* Kill the bullet */
  703.                 /* Don't have 2 bullets kill same asteroid */
  704.                 if (obj[i].alive) killast(j,i);
  705.             }
  706.         }
  707. }
  708.  
  709. fire()
  710. {    extern Objtype obj[SHIP+1];
  711.     extern int width, nextbul;
  712.     extern double drawscale, speedscale;
  713.     double *shiprot, cosrot, sinrot;
  714.  
  715.     obj[nextbul].alive++;
  716.     shiprot = &obj[SHIP].rot;
  717.     cosrot = cos(*shiprot); sinrot = sin(*shiprot);
  718.     obj[nextbul].x = obj[SHIP].x + 20 * cosrot * drawscale;
  719.     obj[nextbul].y = obj[SHIP].y + 20 * sinrot * drawscale;
  720.     obj[nextbul].xvel = obj[SHIP].xvel + 10 * cosrot;
  721.     obj[nextbul].yvel = obj[SHIP].yvel + 10 * sinrot;
  722.     obj[nextbul].rot = *shiprot;
  723.     obj[nextbul].time = width/(speedscale*11);    /* loops before bullet expires    */
  724.     nextbul++; if (nextbul == LASTBUL+1) nextbul = FBUL;
  725. }
  726.  
  727. hyper()
  728. {    extern Objtype obj[SHIP+1];
  729.     extern int width, height, rndint;
  730.     unsigned char c;
  731.     unsigned int i;
  732.  
  733.     c = rand(rndint); i = c; i<<=2;    /* 0 - 1024    */
  734.     while (i > width) i -= width;
  735.     obj[SHIP].x = (double) i;
  736.     c = rand(rndint); i = c; i<<=2;    /* 0 - 1024    */
  737.     while (i > height) i -= height;
  738.     obj[SHIP].y = (double) i;
  739. }
  740.  
  741. vdraw(disp, window, gc, shape, x, y, rot)
  742.     Display *disp;
  743.     Drawable window;
  744.     GC gc;
  745.     int shape;
  746.     double x, y, rot;
  747.  
  748. {    int line;
  749.     extern PolarPair shapes[LASTSHAPE+1][11];
  750.     extern int numpairs[LASTSHAPE+1];
  751.     extern double drawscale;
  752.     XPoint figure[20];
  753.     figure[0].x = (int) x; figure[0].y = (int) y;
  754.     for (line=1; line < numpairs[shape]; line++)    /* 2 pairs = 1 line */
  755.     {    figure[line].x  = (int) shapes[shape][line].length *
  756.             cos(shapes[shape][line].angle + rot) * drawscale;
  757.         figure[line].y  = (int) shapes[shape][line].length *
  758.             sin(shapes[shape][line].angle + rot) * drawscale;
  759.     }
  760.     XDrawLines (disp, window, gc, figure, numpairs[shape], CoordModePrevious);
  761. }
  762.  
  763. main(argc, argv)
  764.     int argc;
  765.     char **argv;
  766. {    Colormap cmap;
  767.     Cursor cursor;
  768.     Display *disp;
  769.     Font font;
  770.     GC gc, pmgc;
  771.     KeySym key;
  772.     Pixmap pixmap;
  773.     Window window;
  774.     XColor black, exact;
  775.     XEvent event;
  776.     XSizeHints hint;
  777.     XWMHints wmhints;
  778.     extern int width, height;
  779.     int screen, depth;
  780.     char text[30];
  781.     unsigned long fg, bg;
  782.  
  783.     extern double drawscale, speedscale;
  784.     extern int numasts, rndint, ships, score, oldscore;
  785.     extern Objtype obj[SHIP+1];
  786.     unsigned char c;    /* for rand    */
  787.     double *temp, dx, dy, dist;
  788.     int level, crashed, flashon, len, pause = 0, delay = 64,
  789.         enemycount, counter, counterstart = 1,
  790.         i,    /* index for drawing objs, counting bullets */
  791.         r;    /* radius of shield circle    */
  792.  
  793.     disp = XOpenDisplay(0);
  794.     if (disp == (Display *) NULL)
  795.     {    fprintf(stderr, "Could not open display\n");
  796.         exit(1);
  797.     }
  798.     screen = DefaultScreen(disp);
  799.     bg = BlackPixel(disp, screen);
  800.     fg = WhitePixel(disp, screen);
  801.     hint.x = 150; hint.y = 200; hint.width = 550; hint.height = 550;
  802.     hint.flags = PPosition | PSize;
  803.     width = hint.width; height = hint.height-letheight-1;
  804.     depth = DefaultDepth (disp, screen);
  805.     window = XCreateSimpleWindow (disp, DefaultRootWindow(disp),
  806.         hint.x, hint.y, hint.width, hint.height, 5, fg, bg);
  807.     pixmap = XCreatePixmap (disp, window, width, height, depth);
  808.     XSetStandardProperties (disp, window, "asteroids", "asteroids", None,
  809.         argv, argc, &hint);
  810.     gc = XCreateGC (disp, window, 0, 0);
  811.     XSetGraphicsExposures(disp, gc, 0);    /* IMPORTANT!  If you do not
  812.         specifically ask not to get Expose events, every XCopyArea
  813.         will generate one, & the event queue will fill up.    */
  814.     font = XLoadFont(disp, "10x20\0");    /* If you don't have this
  815.         font, try replacing it with 9x15\0    */
  816.     XSetFont(disp, gc, font);
  817.     pmgc = XCreateGC (disp, window, 0, 0);
  818.     XSetBackground (disp, gc, bg);
  819.     XSetForeground (disp, gc, fg);
  820.     XSetForeground (disp, pmgc, bg);  /* fg of pixmap is bg of window */
  821.     wmhints.flags = InputHint;
  822.     wmhints.input = True;
  823.     XSetWMHints(disp, window, &wmhints);    /* Thanks to Doug Merritt */
  824.     XSelectInput (disp, window,
  825.         KeyPressMask | KeyReleaseMask | StructureNotifyMask);
  826.     XMapRaised (disp, window);
  827.  
  828.     /* Erase cursor. Just delete next 5 lines if any error.    */
  829.     cmap = XDefaultColormap(disp, screen);
  830.     XAllocNamedColor(disp, cmap, "Black", &exact, &black);
  831.     cursor = XCreateFontCursor(disp, XC_dot);
  832.     XRecolorCursor(disp, cursor, &black, &black);
  833.     XDefineCursor(disp, window, cursor);
  834.  
  835.     XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  836. /*    Can delete next line if it causes trouble    */
  837.     srand((unsigned) time(0));    /* By Craig Smith    */
  838.     initasts();
  839. Newgame:
  840.     deletebooms();
  841.     ships = 3;
  842.     score = 0; oldscore = -1;
  843.     for (level = 0; ;)
  844.     {   if (level < 8) level++;
  845.         makeasts (level);
  846. Newship:    botline(disp, window, gc);
  847.         if (!obj[SHIP].alive)
  848.         {    obj[SHIP].x = width/2;
  849.         obj[SHIP].y = height/2;
  850.         obj[SHIP].xvel = 0;
  851.         obj[SHIP].yvel = 0;
  852.         obj[SHIP].rot = 3*pi/2;
  853.         obj[SHIP].rotvel = 0;
  854.         energy = 80;
  855.         shield_on = 0;
  856.         }
  857.         obj[SHIP].alive = (ships > 0);
  858.         crashed = 0; flashon = 0; enemycount = 20;
  859.         counter = 0;
  860.         while (numasts)
  861.         {    for (i = FBUL; i < LASTBUL+1; i++)  /* Bullet timer */
  862.             if (obj[i].alive)
  863.             {    obj[i].time--;
  864.             if (!obj[i].time) obj[i].alive = 0; /* Not --! */
  865.             }
  866.         while (XEventsQueued(disp, QueuedAfterReading))
  867.         {   XNextEvent(disp, &event);
  868.             switch (event.type)
  869.             {    case MappingNotify:
  870.                 XRefreshKeyboardMapping (&event);
  871.                 break;
  872.             case ConfigureNotify:
  873.                 width = event.xconfigure.width;
  874.                 height = event.xconfigure.height-letheight-1;
  875.                 XFreePixmap (disp, pixmap);
  876.                 pixmap = XCreatePixmap (disp, window, width, height, depth);
  877.                 XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  878.                 botline(disp, window, gc);
  879.                 break;
  880.             case KeyPress:
  881.                 len = XLookupString (&event, text, 10, &key, 0);
  882.                 if (len == 1 && !shield_on) switch (text[0])
  883.                 {    case 'e':
  884.                     obj[SHIP].rotvel = obj[SHIP].rotvel - .1; break;
  885.                 case 'r':
  886.                     obj[SHIP].rotvel = obj[SHIP].rotvel + .1; break;
  887.                 case 'w':
  888.                     obj[SHIP].rot -= pi/4; break;
  889.                 case 't':
  890.                     obj[SHIP].rot += pi/4; break;
  891.                 case 'd':
  892.                     obj[SHIP].rotvel = obj[SHIP].rotvel - .02; break;
  893.                 case 'f':
  894.                     obj[SHIP].rotvel = obj[SHIP].rotvel + .02; break;
  895.                 case THRUST:
  896.                     obj[SHIP].xvel += cos(obj[SHIP].rot);
  897.                     obj[SHIP].yvel += sin(obj[SHIP].rot);
  898.                     obj[SHIP].shape = SHIPTHRSHAPE;
  899.                     break;
  900.                 case FIRE:
  901.                     if (obj[SHIP].alive) fire(); break;
  902.                 case ' ':
  903.                     if (obj[SHIP].alive)
  904.                     {    hyper(); flashon = 1;
  905. /*                    NOT XSetForeground (disp, gc, bg);
  906.     If you set the fg black, & print the highscore, it will effectively erase it.    */
  907.                         XSetForeground (disp, pmgc, fg);
  908.                     XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  909.                     }
  910.                     break;
  911.                 case SHIELD:
  912.                     if (energy)
  913.                     {    shield_on = 1;
  914.                     obj[SHIP].shape = SHIPSHAPE;}
  915.                     break;
  916.                 case '.':    /* decrease delay    */
  917.                     if (delay > 1) delay >>=1; break;
  918.                 case ',':    /* increase delay    */
  919.                     delay <<=1; break;
  920.                 case 'm':    /* decrease drawscale - may go negative */
  921.                     drawscale -= .1; break;
  922.                 case 'n':    /* increase drawscale    */
  923.                     drawscale += .1; break;
  924.                 case '2':    /* increase speedscale    */
  925.                     speedscale += .1; break;
  926.                 case '1':    /* decrease speedscale    */
  927.                     speedscale -= .1; break;
  928.                 case 'b':    /* increase moves/update */
  929.                     counterstart++; break;
  930.                 case 'v':    /* decrease moves/update */
  931.                     if (counterstart > 1) counterstart--;
  932.                     break;
  933.                 case PAUSE:    /* pause    */
  934.                     pause = 1 - pause; break;
  935.                 case '+':    /* cheat    */
  936.                     ships++; botline(disp, window, gc); break;
  937.                 case 'Q':    /* quit        */
  938.                     goto End;
  939.                 case 's':    /* start new ship */
  940.                     if (!obj[SHIP].alive)
  941.                     if (ships < 1) goto Newgame;
  942.                     else goto Newship;
  943.                     break;
  944.                 }
  945.                 break;
  946.             case KeyRelease:
  947.                 len = XLookupString(&event, text, 10, &key, 0);
  948.                 if (len == 1) switch (text[0])
  949.                 {    case 'e':
  950.                     obj[SHIP].rotvel = 0; break;
  951.                 case 'r':
  952.                     obj[SHIP].rotvel = 0; break;
  953.                 case THRUST:
  954.                     obj[SHIP].shape = SHIPSHAPE;
  955.                     break;
  956.                 case SHIELD:
  957.                     shield_on = 0; break;
  958.                 }
  959. /*                break;        */
  960.         }   }
  961.         if (!pause)
  962.         {   moveobjs(&crashed);
  963.             if (ships) score--;    /* timer effect    */
  964.             if (!counter)
  965.             {    counter = counterstart;    /* Restart counter */
  966.             if (crashed == 2)
  967.             {   crashed--; flashon++;
  968.                 boom(SHIP, BMAX-1, 70);
  969.                 XSetForeground (disp, pmgc, fg);
  970.                 XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  971.                 botline(disp, window, gc);
  972.             }
  973.             /* Write copyright notice    */
  974.             if (!ships && blist == NULL)
  975.             {   sprintf(text, "Xasteroids");
  976.                 XDrawImageString (disp, pixmap, gc,
  977.                 width/2-50, height/2-2*letheight,
  978.                 text, strlen(text));
  979.                 sprintf(text, "Copyright 1990 by Phil Goetz");
  980.                 XDrawImageString (disp, pixmap, gc,
  981.                 width/2-140, height/2,
  982.                 text, strlen(text));
  983.                 sprintf(text, "goetz@cs.buffalo.edu");
  984.                 XDrawImageString (disp, pixmap, gc,
  985.                 width/2-100, height/2+2*letheight,
  986.                 text, strlen(text));
  987.             }
  988.             /*    Draw objects    */
  989.             for (i = 0; i <= LASTOBJ; i++)
  990.                 if (obj[i].alive)
  991.                 vdraw(disp, pixmap, gc, obj[i].shape,
  992.                     obj[i].x, obj[i].y, obj[i].rot);
  993.             if (shield_on && obj[SHIP].alive)
  994.             {   r = abs((int) (drawscale*SHIPSIZE));
  995.                 XDrawArc(disp, pixmap, gc,
  996.                 ((int) obj[SHIP].x) - r,
  997.                 ((int) obj[SHIP].y) - r,
  998.                 2*r, 2*r, 0, 360*64);
  999.                 energy--;
  1000.                 if (!energy) shield_on = 0;
  1001.             }
  1002.             drawbooms(disp, pixmap, gc);
  1003.             /* update display:    */
  1004.             XCopyArea(disp, pixmap, window, gc, 0, 0, width, height, 0, 0);
  1005.             printss(disp, window, gc);
  1006.             /* erase objects    */
  1007.             XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  1008.             if (flashon)
  1009.             {   flashon--;
  1010.                 XSetForeground (disp, pmgc, bg);
  1011.                 XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
  1012.             }
  1013.             XSync(disp, 0);
  1014.             }
  1015.             counter--;
  1016.             c = rand(rndint)>>8;
  1017.             if (!obj[ENEMY].alive)
  1018.             {   if (c < level)
  1019.                 {    c = rand(rndint);
  1020.                 if (c < level * 10) makeenemy(level);
  1021.             }   }
  1022.             else
  1023.             obj[ENEMY].yvel += (c>128+6*obj[ENEMY].yvel) ? .5 : -.5;
  1024.             enemycount--; if (!enemycount)
  1025.             {    enemycount = 100;
  1026.             if (obj[ENEMY].alive)
  1027.             {   obj[ENEMYBUL].alive++;
  1028.                 obj[ENEMYBUL].x = obj[ENEMY].x;
  1029.                 obj[ENEMYBUL].y = obj[ENEMY].y;
  1030.                 dx = obj[SHIP].x - obj[ENEMY].x;
  1031.                 dy = obj[SHIP].y - obj[ENEMY].y;
  1032.                 dist = sqrt(dx*dx + dy*dy);
  1033.                 obj[ENEMYBUL].xvel = 3*dx/dist;
  1034.                 obj[ENEMYBUL].yvel = 3*dy/dist;
  1035.             }
  1036.             else    obj[ENEMYBUL].alive = 0;
  1037.             }
  1038.             for (i = 0; i < delay; i++);
  1039.         }
  1040.         }
  1041.     }
  1042. End:    printf("\nYour high score was %d\n", highscore);
  1043.     XFreeGC (disp, gc);
  1044.     XFreeGC (disp, pmgc);
  1045.     XFreePixmap (disp, pixmap);
  1046.     XDestroyWindow (disp, window);
  1047.     XCloseDisplay (disp);
  1048.     exit(0);
  1049. }
  1050.