home *** CD-ROM | disk | FTP | other *** search
/ Adventures in Heaven 2 / adventuresinheaven2powergamesfordosandwindows.iso / windows / arcade / cbzone / c_main.c < prev    next >
C/C++ Source or Header  |  1992-05-27  |  27KB  |  796 lines

  1. #include "c_includ.h"
  2. /*
  3.  * Cbzone - xbzone w/ improvements in C
  4.  *
  5.  * Version 1.0 in Fortran by Justin S. Revenaugh -- MIT (5/86)
  6.  * C port and modifications by Todd W. Mummert -- CMU (12/90)
  7.  *   email bugs and comments concerning this game to:
  8.  *                 mummert+@sam.cs.cmu.edu
  9.  *
  10.  * Copyright Notice:  This program is freely distributable on a
  11.  * nonprofit basis as long as this notice is maintained on all
  12.  * copies. Inclusion of any program code or derivative thereof
  13.  * for commercial purposes is expressly forbidden.
  14.  * December 10, 1990.
  15.  *
  16.  * RCS Info
  17.  *  $Header: c_main.c,v 1.1 91/01/12 02:03:34 mummert Locked $
  18.  *
  19.  * Bugs/Features:
  20.  *   Tanks still pass through each other.  Missiles/copters don't
  21.  *   collide with one another unless below 80 ft.  Consider these
  22.  *   features for now.
  23.  *
  24.  * Enhancement Ideas:
  25.  *  -Convert the graphics routines to general purpose routines...
  26.  *   The graphics are either multiline(segments) or polyline(connected).
  27.  *   Polyline lines can either be open or closed.  This could all be
  28.  *   done in a single routine with the number of mlines and plines
  29.  *   passed in...maybe too much bookkeeping involved.
  30.  *  -Have the ability to have both tanks and missiles on the screen at
  31.  *   the same time.  Never bothered to do it, for I initially thought
  32.  *   it would be unplayable.  Not so sure now.
  33.  *  -Make this multiplayer...two basic approaches.  The first is one
  34.  *   program controlling two displays.  The second is running on
  35.  *   different machines, passing the necessary objects back/forth.  Since
  36.  *   you wouldn't need to pass graphics information, this is not
  37.  *   a lot of information to update. Instead of a call to move<enemy>
  38.  *   you would get back the changes made by your opponent.
  39.  *
  40.  *  -If you make any interesting changes, please send them to me and I'll
  41.  *   incorporate them into the next release.
  42.  */
  43.  
  44.  
  45. Option option;
  46. Optionp opt = &option;
  47.  
  48. /*
  49.  * Just initialize the array prior to starting play.  Associate
  50.  * the salvos with the correct objects.  Set the cosines of some
  51.  * of the angles to 1.
  52.  */
  53. void initarray(o)
  54.      Genericp o;
  55. {
  56.   Genericp s;
  57.   Genericp g;
  58.   Genericp pl = o;
  59.   int i, j;
  60.  
  61.   pl->type = IS_PLAYER;                 /* player is always the first */
  62.   pl->attr = START_LIVING;              /* object.  Same size as the */
  63.   pl->criticalx = 45.0;                 /* other tanks.  */
  64.   pl->criticaly = 70.0;
  65.   for (g=o; g<o+opt->mobjects; g++) {
  66.     g->ca = 1.0;                        /* for those objects which */
  67.     for (j=0; j<5; j++)                 /* have rotating parts, set */
  68.       g->dc[j].ctp = g->dc[j].cta = 1.0;  /* the cos to 1.0 */
  69.   }
  70.  
  71.   s = o+opt->sstart;                    /* player gets msalvos, each  */
  72.   pl->salvo = s;                        /* enemy gets one.  the salvos */
  73.   for (i=0; i<opt->msalvos; i++) {      /* must know who their owner */
  74.     s->salvo = pl;                      /* is for a variety of reasons */
  75.     s->type = IS_SALVO;                 /* first the player */
  76.     s->lntype = LN_SALVO;
  77.     s++;
  78.   }
  79.   for (g=o+opt->estart; g<o+opt->lstart; g++) {
  80.     g->salvo = s;                       /* now the enemies */
  81.     s->salvo = g;
  82.     s->type = IS_SALVO;
  83.     s->lntype = LN_SALVO;
  84.     s++;
  85.   }
  86. }
  87.  
  88. /*
  89.  * The main routine for cbzone.  Probably more complicated than it
  90.  * need be...but it takes care of all the interobject dependencies.
  91.  * Therefore other routines work on a single object (in general).
  92.  * placeobjects() will place however many objects it can, while
  93.  * scanner() needs to know where all the enemies are.
  94.  */
  95. void cbzone_main(argc, argv)
  96.      int argc;
  97.      char* argv[];
  98. {
  99.   Genericp o;
  100.   Genericp pl, g, g2, s;
  101.   char key;
  102.   float alpha, ddx2, ddx, ddy2, ddy, dif, diff, dx, dy, v, dist;
  103.   float blocksize = 100.0;
  104.   float blocksizesqrd = 10000.0;
  105.   float check, testx, testy;
  106.   float landerthreshold = 0.5;
  107.   float threshold = 0.7;
  108.   int deadcount, i, icheck, position[2];
  109.   int nummissile = 0;
  110.   int missilecount = 0;
  111.   int nextmissile = 1200;
  112.   int numleft = 3;
  113.   LONG score = 0;
  114.   LONG scorebase = 0;
  115.   Bool new_salvo_flag, new_sight_flag, event, tank_stranded;
  116.   Bool aligned = False;
  117.   Bool blocked_flag = False;
  118.   Bool dead = False;
  119.   Bool first = True;
  120.   Bool firstmissile = True;
  121.   Bool keylast = True;
  122.   Bool lander = False;
  123.   Bool missilerun = False;
  124.   Bool salvo_flag = False;
  125.   Bool sens = False;
  126.   Bool sight_flag = False;
  127. //  extern long time();  ***HACK HACK HACK EricFo removed this
  128.   struct timeval tstart;
  129.   struct timeval tend;
  130.   long tdiff, limit;
  131. #ifdef DEVELOPER
  132.   int passes = 0;
  133.   struct timeval game_start;
  134.   struct timeval game_end;
  135. #endif //DEVELOPER
  136.  
  137.   gprinqconfig(&argc, argv);
  138.   limit = opt->delay * 1.2e4;
  139.  
  140.   /* now that we have parsed the options, we know how large to */
  141.   /* make the world.  Use calloc here as most of the array     */
  142.   /* should start off 0.                                       */
  143.  
  144.   pl = o = (Genericp) calloc(opt->mobjects,sizeof(Generic));
  145.  
  146.   if (o == NULL) {
  147.     printf("Malloc failed...trying to create too many objects?\n");
  148. #ifdef WIN32
  149.      return;
  150. #else //X11
  151.      exit(1);
  152. #endif
  153.   }
  154.  
  155.   initarray(o);                         /* prepare the main array */
  156.   srandom(time((long *) 0));            /* start things off randomly */
  157.   screeninit();
  158.   updatedisplay(missilerun, lander, score, numleft, sens, False);
  159.   xhairs(aligned);
  160.   gprinqcursor(position);
  161.   event = gprcondeventwait(&key, position);
  162.   joystick(position, sens, pl);
  163.  
  164.   /* place the objects out there to start the game.  if the player is */
  165.   /* is_new, then the objects are placed at a random distance, else   */
  166.   /* the objects get placed on the horizon.                           */
  167.  
  168.   placeobjects(o, missilerun, score);
  169.   pl->attr &= ~IS_NEW;                  /* now the objects can be */
  170.                                         /* placed at the horizon. */
  171.  
  172.   /* now calculate ranges to all the objects and translate them */
  173.   /* into a player-centric coordinate system                    */
  174.  
  175.   pl->ca = cos(pl->azm);
  176.   pl->sa = sin(pl->azm);
  177.   for (g=o+opt->estart; g<o+opt->mobjects; g++)
  178.     if (g->attr & IS_ALIVE) {
  179.       dx = g->x - pl->x;
  180.       dy = g->y - pl->y;
  181.       g->range = sqrt(dx*dx + dy*dy);
  182.       g->proy = -dx * pl->sa + dy * pl->ca;
  183.       g->prox = dx * pl->ca + dy * pl->sa;
  184.     }
  185.  
  186.   scanner(o);
  187.   drawhorizon(pl->azm);
  188.  
  189.   /* now the work really starts....we just iterate through */
  190.   /* the following loop until the player dies or quits     */
  191. #ifdef DEVELOPER
  192.   gettimeofday(&game_start, 0);
  193. #endif
  194.   while (1) {
  195. #ifdef WIN32
  196.     if (GetAsyncKeyState( VK_F1 ) < 0) {
  197.       free(o);
  198.       return;
  199. //      exit(scores(score));  //HACK OUT by Eric Fogelin
  200.     }
  201. #endif
  202.     gettimeofday(&tstart, 0);
  203.     gprinqcursor(position);
  204.     event = gprcondeventwait(&key, position);
  205.  
  206.     if (event && key == 'Q') {
  207.       free(o);
  208.       return;
  209. //      exit(scores(score));  //HACK OUT by Eric Fogelin
  210.     }
  211.  
  212.     if (event && key == 'R') {
  213.       clearentirescreen();
  214.       staticscreen();
  215.       updatedisplay(False, False, -1, 0, False, True);
  216.       updatedisplay(missilerun, lander, score, numleft, sens, False);
  217.       if (sight_flag)
  218.         message(1, False);
  219.       if (pl->attr & IS_BLOCKED)
  220.         message(2, False);
  221.       if (salvo_flag)
  222.         message(3, False);
  223.       scanner(o);
  224.       xhairs(aligned);
  225.       drawhorizon(pl->azm);
  226.     }
  227.  
  228.     joystick(position, sens, pl);
  229.     if (paused)
  230.       continue;
  231.  
  232.     for (i=0; i<opt->msalvos; i++) {    /* now find a shot we can use */
  233.       s = pl->salvo+i;
  234.       if (!(s->attr & STILL_THERE))
  235.         break;
  236.       s = NULL;
  237.     }
  238.     if (event && pl->attr & IS_ALIVE)
  239.       if (keylast) {
  240.         for (i=0; i<opt->msalvos; i++) { /* now find a shot we can use */
  241.           s = pl->salvo+i;
  242.           if (!(s->attr & STILL_THERE))
  243.             break;
  244.           s = NULL;
  245.         }
  246.         if (key == 'a' && s!=NULL) {    /* fire up one shot */
  247.           s->attr = START_LIVING;
  248.           s->ecount = 0;
  249.           s->x = pl->x;
  250.           s->y = pl->y;
  251.           s->z = 0.0;
  252.           s->prox = 0;
  253.           s->proy = 0;
  254.           s->azm = pl->azm;
  255.           s->speed = 40.0;
  256.           keylast = False;
  257.         }
  258.         else if (key == 'b') {          /* center our joystick */
  259.           position[0] = 500;
  260.           position[1] = 355;
  261.           gprsetcursorposition(position);
  262.           joystick(position, sens, pl);
  263.           keylast = False;
  264.         }
  265.         else if (key == 'c') {          /* toggle sensitivity */
  266.           sens = !sens;
  267.           joystick(position, sens, pl);
  268.           keylast = False;
  269.         }
  270.       }
  271.       else if (key == 'A' || key == 'B' || key == 'C')
  272.         keylast = True;                 /* button released */
  273.  
  274.     /* if we can move, update our rotation, bearing (azimuth), and */
  275.     /* position.                                                   */
  276.  
  277.     if (pl->attr & IS_ALIVE && !(pl->attr & IS_BLOCKED)) {
  278.       pl->azm += pl->rotate;
  279.       if (pl->azm > PI2)
  280.         pl->azm -= PI2;
  281.       if (pl->azm <= 0.0)
  282.         pl->azm += PI2;
  283.       pl->ca = cos(pl->azm);
  284.       pl->sa = sin(pl->azm);
  285.     }
  286.     if (pl->attr & IS_ALIVE) {
  287.       pl->x -=  pl->sa * pl->speed;
  288.       pl->y +=  pl->ca * pl->speed;
  289.     }
  290.     else
  291.       pl->speed = 0.0;
  292.  
  293.     /* now call the move generation routines for the objects */
  294.     /* which require thought,  speed and/or rotation may be  */
  295.     /* affected.                                             */
  296.  
  297.     for (g=o+opt->estart; g<o+opt->sstart; g++)
  298.       if (g->attr & IS_ALIVE)
  299.         switch (g->type) {
  300.         case IS_TANK:
  301.           movetank(g, pl); break;
  302.         case IS_SUPER:
  303.           movesuper(g, pl); break;
  304.         case IS_MISSILE:
  305.           movemissile(g, pl, first); break;
  306.         case IS_COPTER:
  307.           movecopter(g, pl); break;
  308.         case IS_LANDER:
  309.           movelander(g, pl); break;
  310.         default:
  311.           printf("Help! Something's alive and I don't know what...\n");
  312. #ifdef WIN32
  313.           return;
  314. #else //X11
  315.           exit(1);
  316. #endif
  317.         }
  318.  
  319.     /* now update their bearing and position */
  320.  
  321.     for (g=o+opt->estart; g<o+opt->lstart; g++) {
  322.       if (g->attr & IS_ALIVE && !(g->attr & IS_BLOCKED))
  323.         g->azm += g->rotate;
  324.       g->ca = cos(g->azm);
  325.       g->sa = sin(g->azm);
  326.       g->x -=  g->sa * g->speed;
  327.       g->y +=  g->ca * g->speed;
  328.     }
  329.     for (g=o+opt->lstart; g<o+opt->bstart; g++)
  330.       if (g->attr & IS_ALIVE) {
  331.         g->ca = cos(g->azm);
  332.         g->sa = sin(g->azm);
  333.         g->x -= g->sa * g->speed;
  334.         g->y += g->ca * g->speed;
  335.       }
  336.  
  337.     /* now compute ranges from objects to the player */
  338.  
  339.     for (g=o+opt->estart; g<o+opt->mobjects; g++)
  340.       if (g->attr & STILL_THERE)
  341.         g->range = sqrt(DIST(g, pl));
  342.  
  343.     for (g=o; g<o+opt->lstart; g++)     /* assume all objects are */
  344.       g->attr &= ~IS_BLOCKED;           /* unblocked              */
  345.  
  346.     /* now check to see if they really were unblocked.  If not, then */
  347.     /* project them back along their path until they are.  This      */
  348.     /* section just checks for being blocked by blocks.              */
  349.  
  350.     for (g=o+opt->bstart; g<o+opt->mobjects; g++) {
  351.       if (g->range < blocksize) {
  352.         pl->attr |= BLOCKED_BY_BLOCK;
  353.         dx = pl->x - g->x;
  354.         dy = pl->y - g->y;
  355.         diff = dy * pl->ca - dx * pl->sa;
  356.         if (pl->speed > 0.0)
  357.           v = diff + sqrt(diff*diff + blocksizesqrd - g->range*g->range);
  358.         else if (pl->speed < 0.0)
  359.           v = diff - sqrt(diff*diff + blocksizesqrd - g->range*g->range);
  360.         pl->x += pl->sa * v;
  361.         pl->y -= pl->ca * v;
  362.       }
  363.       for (g2=o+opt->estart; g2<o+opt->lstart; g2++)
  364.         if (g2->attr & IS_ALIVE &&
  365.             (dist = DIST(g, g2)) < blocksizesqrd) {
  366.           g2->attr |= BLOCKED_BY_BLOCK;
  367.           if (!(g2->type & (IS_MISSILE | IS_COPTER))) {
  368.             dx = g2->x - g->x;
  369.             dy = g2->y - g->y;
  370.             diff = dy * g2->ca - dx * g2->sa;
  371.             if (g2->speed > 0.0)
  372.               v = diff + sqrt(diff*diff + blocksizesqrd - dist);
  373.             else if (g2->speed < 0.0)
  374.               v = diff - sqrt(diff*diff + blocksizesqrd - dist);
  375.             g2->x += g2->sa * v;
  376.             g2->y -= g2->ca * v;
  377.           }
  378.         }
  379.     }
  380.  
  381.     /* if the player moved, or if an enemy did, we need to recompute */
  382.     /* the range to that enemy.                                      */
  383.  
  384.     for (g=o+opt->estart; g<o+opt->lstart; g++)
  385.       if (g->attr & IS_ALIVE &&
  386.           (g->attr & IS_BLOCKED || pl->attr & IS_BLOCKED))
  387.         g->range = sqrt(DIST(g, pl));
  388.  
  389.     /* now check to see if the player is blocked by any enemy.  */
  390.     /* if so, project them back.                                */
  391.  
  392.     for (g=o+opt->estart; g<o+opt->lstart; g++)
  393.       if (g->attr & IS_ALIVE && g->range < blocksize)
  394.         if (!(g->type & (IS_MISSILE | IS_COPTER))) {
  395.           if (g->attr & IS_BLOCKED) {
  396.             pl->speed = 0.0;
  397.             if (fabs(g->speed) < 0.001)
  398.               g->speed = sign(0.001, g->speed);
  399.           }
  400.           pl->attr |= BLOCKED_BY_ENEMY;
  401.           g->attr |= BLOCKED_BY_ENEMY;
  402.           ddx = pl->speed * pl->sa - g->speed * g->sa;
  403.           ddy = pl->speed * pl->ca - g->speed * g->ca;
  404.           ddx2 = ddx*ddx;
  405.           ddy2 = ddy*ddy;
  406.           dx = pl->x - g->x;
  407.           dy = pl->y - g->y;
  408.           dif = ddy * dy - ddx * dx;
  409.           alpha = (dif + sqrt(dif*dif + (blocksizesqrd - g->range*g->range)
  410.                               * (ddx2 + ddy2))) / (ddx2 + ddy2);
  411.           pl->x += alpha * pl->speed * pl->sa;
  412.           pl->y -= alpha * pl->speed * pl->ca;
  413.           g->x += alpha * g->speed * g->sa;
  414.           g->y -= alpha * g->speed * g->ca;
  415.         }
  416.  
  417.     /* if we've moved, recompute distance to all the salvos */
  418.  
  419.     if (pl->attr & IS_BLOCKED)
  420.       for (g=o+opt->sstart; g<o+opt->bstart; g++)
  421.         if (g->attr & IS_ALIVE)
  422.           g->range = sqrt(DIST(g, pl));
  423.  
  424.     /* enemies disappear if their range is greater than 2200. */
  425.     /* We check last[0] to see if they need to be erased.  In */
  426.     /* most cases probably not, unless we really screw with   */
  427.     /* their speed.                                           */
  428.  
  429.     tank_stranded = False;
  430.     for (g=o+opt->estart; g<o+opt->lstart; g++) {
  431.       g->ecount++;
  432.       if (g->attr & IS_ALIVE)
  433.         if (g->range > 2200.0)
  434.           if (g->dc[0].last)
  435.             g->attr = ERASE;
  436.           else
  437.             g->attr = 0;
  438.         else if (g->type & (IS_SUPER | IS_TANK) &&
  439.                  g->ecount > TANK_STRAND_COUNT)
  440.           tank_stranded = True;
  441.     }
  442.  
  443.     /* landers are out of range at 2750 */
  444.  
  445.     for (g=o+opt->lstart; g<o+opt->sstart; g++) {
  446.       g->ecount++;
  447.       if (g->attr & IS_ALIVE && g->range > 2750.0)
  448.         if (g->dc[0].last)
  449.           g->attr = ERASE;
  450.         else
  451.           g->attr = 0;
  452.     }
  453.  
  454.     /* blocks also at 2200 */
  455.  
  456.     for (g=o+opt->bstart; g<o+opt->mobjects; g++)
  457.       if (g->range > 2200.0)
  458.         if (g->dc[0].last)
  459.           g->attr = ERASE;
  460.         else
  461.           g->attr = 0;
  462.  
  463.     /* salvos are never out of range, but their lifetime is limited */
  464.  
  465.     for (g=o+opt->sstart; g<o+opt->bstart; g++) {
  466.       g->ecount++;
  467.       if (g->attr & IS_ALIVE && g->ecount > 50)
  468.         if (g->dc[0].last)
  469.           g->attr = ERASE;
  470.         else
  471.           g->attr = 0;
  472.     }
  473.  
  474.     /* we never set the 'salvo fired' message in this routine.  */
  475.     /* however, we do have to turn it off.  if salvos are alive */
  476.     /* we assume the message is on, once no enemy salvos are    */
  477.     /* alive we turn it off.                                    */
  478.  
  479.     new_salvo_flag = False;
  480.     for (g=o+opt->sstart; g<o+opt->bstart; g++)
  481.       if (g->attr & IS_ALIVE) {         /* if salvo exist and   */
  482.         if (g->salvo != pl)             /* not owned by player  */
  483.           new_salvo_flag = True;        /* then the flag is set */
  484.  
  485.         /* check to see if a salvo hits a block */
  486.  
  487.         for (g2=o+opt->bstart; g2<o+opt->mobjects; g2++)
  488.           if (fabs(g2->x - g->x) < g2->criticalx &&
  489.               fabs(g2->y - g->y) < g2->criticaly) {
  490.             g->attr = START_EXPLODING;
  491.             g->ecount = 0;
  492.           }
  493.  
  494.         /* now check to see if the salvo kills a lander. */
  495.         /* If so, and the player fired the salvo, update */
  496.         /* the score.                                    */
  497.  
  498.         for (g2=o+opt->lstart; g2<o+opt->sstart; g2++)
  499.           if (g2->attr & IS_ALIVE)
  500.             if (DIST(g, g2) < g2->criticalx) {
  501.               g->attr = START_EXPLODING;
  502.               g2->attr = START_EXPLODING;
  503.               g->ecount = 0;
  504.               g2->ecount = 0;
  505.               if (g->salvo == pl) {
  506.                 score += 10000;
  507.                 icheck = score / 100000;
  508.                 if (icheck > scorebase) {
  509.                   numleft++;
  510.                   if (numleft > 4)
  511.                     numleft = 4;
  512.                   scorebase = icheck;
  513.                 }
  514.               }
  515.             }
  516.  
  517.         /* now check to see if the salvo hit any enemy.   The salvo */
  518.         /* cannot hit the one who fired it.  This prevents range    */
  519.         /* checking problems when first fired.                      */
  520.  
  521.         for (g2=o+opt->estart; g2<o+opt->lstart; g2++)
  522.           if (g2->attr & IS_ALIVE && g->salvo != g2) {
  523.             dx = g->x - g2->x;
  524.             dy = g->y - g2->y;
  525.             testx = fabs( dx * g2->ca + dy * g2->sa);
  526.             testy = fabs(-dx * g2->sa + dy * g2->ca);
  527.             if (testx < g2->criticalx && testy < g2->criticaly &&
  528.                 (!(g2->type & (IS_MISSILE | IS_COPTER)) || g2->z < 80.0)) {
  529.               g->attr = START_EXPLODING;
  530.               g2->attr = START_EXPLODING;
  531.               g->ecount = 0;
  532.               g2->ecount = 0;
  533.  
  534.               /* if the player fired, give him credit */
  535.  
  536.               if (g->salvo == pl) {
  537.                 if (g2->type & IS_SUPER)
  538.                   score += 5000;
  539.                 else if (g2->type & (IS_MISSILE | IS_COPTER)) {
  540.                   score += 5000;
  541.                   nummissile--;
  542.                 }
  543.                 else
  544.                   score += 3000;
  545.                 icheck = score / 100000;
  546.                 if (icheck > scorebase) {
  547.                   numleft++;
  548.                   if (numleft > 4)
  549.                     numleft = 4;
  550.                   scorebase = icheck;
  551.                 }
  552.               }
  553.             }
  554.           }
  555.       }
  556.  
  557.     /* check to see if a missile or copter rams a lander */
  558.  
  559.     for (g=o+opt->estart; g<o+opt->lstart; g++)
  560.       if (g->type & (IS_MISSILE | IS_COPTER) && g->attr & IS_ALIVE)
  561.         for (g2=o+opt->lstart; g2<o+opt->sstart; g2++)
  562.           if (g2->attr & IS_ALIVE &&
  563.               DIST(g, g2) < g2->criticalx && g->z < 80) {
  564.             nummissile--;
  565.             g->attr = START_EXPLODING;
  566.             g2->attr = START_EXPLODING;
  567.             g->ecount = 0;
  568.             g2->ecount = 0;
  569.           }
  570.  
  571.     /* now check if we need to draw the object.  */
  572.     /* convert into player-centric coordinates   */
  573.     /* and project a cone forward to see if the  */
  574.     /* enemy is within it. Also align the gun    */
  575.     /* gun sights if necessary.                  */
  576.  
  577.     new_sight_flag = False;
  578.     aligned = False;
  579.     lander = False;
  580.     for (g=o+opt->estart; g<o+opt->mobjects; g++)
  581.       if (g->attr & (IS_ALIVE|IS_EXPLODING)) {
  582.         g->dc[0].seen = False;
  583.         if (g->range < 2000.0) {
  584.           dx = g->x - pl->x;
  585.           dy = g->y - pl->y;
  586.           g->proy = -dx * pl->sa + dy * pl->ca;
  587.           g->prox =  dx * pl->ca + dy * pl->sa;
  588.           check = g->proy / (fabs(g->prox) + 1.0);
  589.           if (check > threshold) {
  590.             g->dc[0].seen = True;
  591.             if (g->type & IS_ENEMY && g->attr & IS_ALIVE)
  592.               new_sight_flag = True;
  593.             if (fabs(g->prox) < 50 && g->attr & IS_ALIVE &&
  594.                 !(g->type & (IS_ABLOCK | IS_SALVO)))
  595.               aligned = True;
  596.           }
  597.           if (g->type & IS_LANDER && g->attr & IS_ALIVE
  598.               && check > landerthreshold) {
  599.             lander = True;
  600.             if (fabs(g->prox) < 60)
  601.               aligned = True;
  602.           }
  603.         }
  604.       }
  605.  
  606.     /* change the various messages, if necessary.  Never use */
  607.     /* the bell, unless opt->loud is True.                   */
  608.  
  609.     if (sight_flag && !new_sight_flag) {
  610.       message(-1, False);
  611.       sight_flag = False;
  612.     }
  613.     else if (!sight_flag && new_sight_flag) {
  614.       message(1, False);
  615.       sight_flag = True;
  616.     }
  617.     if (pl->attr & IS_BLOCKED && !blocked_flag) {
  618.       message(2, True);
  619.       blocked_flag = True;
  620.     }
  621.     else if (!(pl->attr & IS_BLOCKED) && blocked_flag) {
  622.       message(-2, False);
  623.       blocked_flag = False;
  624.     }
  625.     if (salvo_flag && !new_salvo_flag) {
  626.       message(-3, False);
  627.       salvo_flag = False;
  628.     }
  629.     else if (!salvo_flag && new_salvo_flag)
  630.       salvo_flag = True;
  631.  
  632.     scanner(o);
  633.     updatedisplay(missilerun, lander, score, numleft, sens, False);
  634.     xhairs(aligned);
  635.     drawhorizon(pl->azm);
  636.  
  637.     /* now draw all the objects */
  638.  
  639.     for (g=o+opt->estart; g<o+opt->mobjects; g++) {
  640.       if (g->attr & (IS_ALIVE | ERASE))
  641.         drawobject(g, pl);
  642.       else if (g->attr & (IS_EXPLODING | EXERASE))
  643.         switch (g->type) {
  644.         case IS_SALVO:
  645.           explodesalvo(g, pl); break;
  646.         case IS_COPTER:
  647.         case IS_MISSILE:
  648.         case IS_LANDER:
  649.         case IS_TANK:
  650.         case IS_SUPER:
  651.           explodeobject(g, pl); break;
  652.         default:
  653.           printf("Help! Cannot explode what doesn't exist.\n");
  654. #ifdef WIN32
  655.           return;
  656. #else //X11
  657.           exit(1);
  658. #endif
  659.         }
  660.       g->attr &= ~(ERASE | EXERASE);
  661.     }
  662.  
  663.     /* now start checking for player death.  if there is a missile, */
  664.     /* check to see if it rammed the player.                        */
  665.  
  666.     if (missilerun)
  667.       for (g=o+opt->estart; g<o+opt->lstart; g++)
  668.         if (g->attr & IS_ALIVE && g->type & (IS_MISSILE | IS_COPTER) &&
  669.             g->range < blocksize && g->z < 80) {
  670.           g->attr = START_EXPLODING;
  671.           drawcracks();
  672.           pl->attr &= ~IS_ALIVE;
  673.           dead = True;
  674.           deadcount = 0;
  675.         }
  676.  
  677.     /* check to see if any salvos hit. */
  678.  
  679.     for (g=o+opt->sstart; g<o+opt->bstart; g++)
  680.       if (g->attr & IS_ALIVE && g->salvo != pl &&
  681.           g->range < 100.0 && fabs(g->prox) < pl->criticalx &&
  682.           fabs(g->proy) < pl->criticaly) {
  683.         drawobject(g, pl);
  684.         g->attr = 0;
  685.         drawcracks();
  686.         pl->attr &= ~IS_ALIVE;
  687.         dead = True;
  688.         deadcount = 0;
  689.       }
  690.  
  691.     /* if we are dead, redraw the cracks every five turns.  after 50 */
  692.     /* turns, we can start playing again if we have any lives left.  */
  693.  
  694.     if (dead) {
  695.       if (deadcount%5 == 0)
  696.         drawcracks();
  697.       if (deadcount > 50) {
  698.         dead = False;
  699.         numleft--;
  700.         if (numleft < 0) {
  701. #ifdef DEVELOPER
  702.           gettimeofday(&game_end, 0);
  703.           if (opt->output)
  704.             printf("The game took an average %10.8f secs.\n",
  705.                    (game_end.tv_sec-game_start.tv_sec +
  706.                     (game_end.tv_usec-game_start.tv_usec)*1.0e-6)/passes);
  707. #endif //DEVELOPER
  708.           free(o);
  709. #ifdef WIN32
  710.           return;
  711. #else //X11
  712.           exit(scores(score));
  713. #endif
  714.         }
  715.         if (missilerun) {
  716.           nummissile -= 2;
  717.           if (nummissile <= 0 && opt->mtanks) {
  718.             missilerun = False;
  719.             nextmissile = 750 * frand() + 750;
  720.           }
  721.         }
  722.         clearscreen();
  723.         pl->x = 0.0;                    /* reset all our attributes */
  724.         pl->y = 0.0;
  725.         pl->speed = 0.0;
  726.         pl->azm = 0.0;
  727.         pl->ca = 1.0;
  728.         pl->sa = 0.0;
  729.         pl->attr = START_LIVING;
  730.         message(-1, False);             /* turn off all the messages */
  731.         sight_flag = False;
  732.         message(-2, False);
  733.         blocked_flag = False;
  734.         message(-3, False);
  735.         salvo_flag = False;
  736.         for (g=o+opt->estart; g<o+opt->mobjects; g++)
  737.           g->attr = 0;                  /* remove all objects */
  738.       }
  739.     }
  740.  
  741.     /* Now schedule the missile runs.  There will be a missile run if */
  742.     /* mtanks==0 or we are in copter practice or if a tank has been   */
  743.     /* around too long or we haven't had a missile in a while.        */
  744.  
  745.     if (pl->attr & IS_ALIVE && opt->mmissiles &&
  746.         (!opt->mtanks || opt->copters ||
  747.          tank_stranded || missilecount > nextmissile))
  748.       if (!missilerun) {
  749.         missilecount = 0;
  750.         for (g=o+opt->estart; g<o+opt->bstart; g++)
  751.           if (!(g->type & (IS_LANDER | IS_MISSILE | IS_COPTER)))
  752.             if (g->attr & IS_ALIVE)
  753.               g->attr = ERASE;
  754.             else if (g->attr & IS_EXPLODING)
  755.               g->attr = EXERASE;
  756.         nummissile = frand() * 3 * opt->mmissiles + 1;
  757.         if (firstmissile)
  758.           nummissile = 1;
  759.         first = firstmissile;
  760.         firstmissile = False;
  761.         missilerun = True;
  762.       }
  763.  
  764.     /* once this run is over, schedule another one for a later date */
  765.  
  766.     if (missilerun && opt->mtanks && nummissile <= 0) {
  767.       missilerun = False;
  768.       nextmissile = 750 * frand() + 750;
  769.     }
  770.  
  771.     /* now place whatever objects need to be placed.  */
  772.  
  773.     if (!dead)
  774.       placeobjects(o, missilerun, score);
  775.     pl->attr &= ~IS_NEW;                /* in case the player was new */
  776.  
  777.     deadcount++;
  778.     if (!missilerun) missilecount++;
  779.  
  780. /* use timeclock here instead of gettimeofday to get a sync(d, 0)
  781.  * just in case there are graphics we need to draw.
  782.  */
  783.     timeclock(&tend);
  784.     tdiff = limit -
  785.       ((tend.tv_sec-tstart.tv_sec)*1e6+tend.tv_usec-tstart.tv_usec);
  786.     if (tdiff > 0) {
  787.       tend.tv_sec = 0;
  788.       tend.tv_usec = tdiff;
  789.       select(0, 0, 0, 0, &tend);
  790.     }
  791. #ifdef DEVELOPER
  792.     passes++;
  793. #endif //DEVELOPER
  794.   }
  795. }
  796.