home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Inne / Gry / Atomic_Tanks / Atomic-Tanks-5.1.exe / src / missile.cpp < prev    next >
C/C++ Source or Header  |  2009-11-14  |  24KB  |  799 lines

  1. /*
  2.  * atanks - obliterate each other with oversize weapons
  3.  * Copyright (C) 2003  Thomas Hudson
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  * */
  19.  
  20.  
  21. #include "environment.h"
  22. #include "globaldata.h"
  23. #include "explosion.h"
  24. #include "missile.h"
  25. #include "decor.h"
  26. #include "tank.h"
  27.  
  28.  
  29. MISSILE::~MISSILE ()
  30. {
  31.   _env->removeObject (this);
  32.   _global = NULL;
  33.   _env    = NULL;
  34.   weap    = NULL;
  35. }
  36.  
  37. MISSILE::MISSILE (GLOBALDATA *global, ENVIRONMENT *env, double xpos, double ypos, 
  38.                   double xvel, double yvel,
  39.                   int weaponType):PHYSICAL_OBJECT(),weap(NULL)
  40. {
  41.   setEnvironment (env);
  42.   player = NULL;
  43.   _align = LEFT;
  44.   _global = global;
  45.   #ifdef NETWORK
  46.   char buffer[256];
  47.   sprintf(buffer, "MISSILE %d %d %lf %lf %d", (int)xpos, (int)ypos,
  48.                   xvel, yvel, weaponType);
  49.   global->Send_To_Clients(buffer);
  50.   #endif
  51.   x = xpos;
  52.   y = ypos;
  53.   xv = xvel;
  54.   yv = yvel;
  55.   type = weaponType;
  56.   if (type < WEAPONS)
  57.     weap = &weapon[type];
  58.   else
  59.     weap = &naturals[type - WEAPONS];
  60.   mass = weap->mass;
  61.   drag = weap->drag;
  62.   sound = weap->sound;
  63.   expSize = weap->radius;
  64.   etime = weap->etime;
  65.   damage = weap->damage;
  66.   eframes = weap->eframes;
  67.   picpoint = weap->picpoint;
  68.   noimpact = weap->noimpact;
  69.   countdown = -1;
  70.   _bitmap = (BITMAP *)_global->missile[picpoint];
  71.   physics = 0;
  72.   age = 0;
  73.   destroy = FALSE;
  74.   if (type >= SML_METEOR && type <= LRG_METEOR)
  75.     {
  76.       angle = rand () % 360;
  77.       spin = rand () % 20 - 10;
  78.     }
  79.   else
  80.     {
  81.       angle = 0;
  82.       spin = 0;
  83.     }
  84.  
  85.   // Napalm grows, others do not:
  86.   if (type == NAPALM_JELLY)
  87.     {
  88.      bIsGrowing = true;
  89.      iGrowRadius= 1;
  90.     }
  91.   else
  92.     {
  93.      bIsGrowing = false;
  94.      iGrowRadius= expSize;
  95.     }
  96.   if ( (type == FUNKY_BOMBLET) || (type == FUNKY_DEATHLET) )
  97.   {
  98.       int temp_number = rand() % 5;
  99.       switch (temp_number)
  100.       {
  101.          case 0: funky_colour = makecol(200, 0, 0); break;
  102.          case 1: funky_colour = makecol(0, 200, 0); break;
  103.          case 2: funky_colour = makecol(0, 0, 200); break;
  104.          case 3: funky_colour = makecol(200, 200, 0); break;
  105.          case 4: funky_colour = makecol(200, 0, 200); break;
  106.       }
  107.   }
  108. }
  109.  
  110. void MISSILE::initialise ()
  111. {
  112.   PHYSICAL_OBJECT::initialise ();
  113.   physics = 0;
  114.   age = 0;
  115.   if (type >= SML_METEOR && type <= LRG_METEOR)
  116.     {
  117.       angle = rand () % 360;
  118.       spin = rand () % 20 - 10;
  119.     }
  120.   else
  121.     {
  122.       angle = 0;
  123.       spin = 0;
  124.     }
  125. }
  126.  
  127.  
  128.  
  129. int MISSILE::triggerTest ()
  130. {
  131.   int quell = 1;
  132.   TANK *tank;
  133.   double old_delta_x = xv;
  134.  
  135.   // Has it hit a tank?
  136.   for (int objCount = 0; (tank = (TANK*)_env->getNextOfClass (TANK_CLASS, &objCount)) && tank; objCount++)
  137.     {
  138.       if (x > tank->x - TANKWIDTH && x < tank->x + TANKWIDTH && y > tank->y && y < tank->y + TANKHEIGHT && tank->l > 0)
  139.         {
  140.           hitSomething = 1;
  141.           tank->requireUpdate ();
  142.         }
  143.     }
  144.   if (noimpact)
  145.     {
  146.       quell = 1;
  147.     }
  148.   else if ((y > 0) && (hitSomething || (y >= _global->screenHeight) || (getpixel (_env->terrain, (int)x, (int)y) != PINK)))
  149.     // else if ( (y > 0) && (hitSomething || (y >= _global->screenHeight) || (_env->surface[(int)x] <= y) ) )
  150.     {
  151.       quell = 0;
  152.       if (type >= SML_ROLLER && type <= DTH_ROLLER && !physics)
  153.         {
  154.           /* rollerupdate */
  155.           if (age > 1)
  156.             {
  157.  
  158.               quell = 1;
  159.               physics = 1;
  160.               y -= 5;
  161.               if (x < 1)
  162.                 x = 1;
  163.               if (x > (_global->screenWidth - 2))
  164.                 x = (_global->screenWidth - 2);
  165.  
  166.               if ( (y >= _env->surface[(int)x])       // y is surface or below
  167.                    && (y <= _env->surface[(int)x] + 2) )  // but not burried more than 2 px
  168.                 y = _env->surface[(int)x] - 1;
  169.  
  170.               yv = 0.0;
  171.               // if (xv > 0.0) yv = 1.0;
  172.               // if (xv < 0.0) yv =-1.0;
  173.  
  174.               xv = 0.0;
  175.               if (x == 1)
  176.                   xv++;
  177.               else if (x == (_global->screenWidth - 2) )
  178.                   xv--;
  179.               else
  180.               {
  181.                   int can_go_left = FALSE, can_go_right = FALSE;
  182.                   if (getpixel (_env->terrain, (int)x + 1, (int)y + 1) == PINK)
  183.                      can_go_right = TRUE;
  184.                   if (getpixel (_env->terrain, (int)x - 1, (int)y + 1) == PINK)
  185.                      can_go_left = TRUE;
  186.  
  187.                   if ( (can_go_left) && (!can_go_right) )
  188.                   {
  189.                      xv--;
  190.                   }
  191.                   else if ( (! can_go_left) && (can_go_right) )
  192.                   {
  193.                      xv++;
  194.                   }
  195.                   else if ( (can_go_left) && (can_go_right) )
  196.                   {
  197.                      xv = old_delta_x;      // if both are open, continue on old course
  198.                   }
  199.               }
  200.               if (xv == 0.0)     // nothing worked, try something!
  201.               {
  202.                 xv = yv;
  203.               }
  204.               yv = 0.0;
  205.               hitSomething = 0;
  206.             }
  207.           else
  208.             {
  209.               physics = 4;
  210.             }
  211.         }
  212.       else if (type == BURROWER || type == PENETRATOR)
  213.         {
  214.           if (physics == 1)
  215.             {
  216.               if (!hitSomething)
  217.                 quell = 1;
  218.             }
  219.           if (!physics)
  220.             {
  221.               physics = 1;
  222.               xv *= 0.1;
  223.               yv *= 0.1;
  224.               quell = 1;
  225.             }
  226.  
  227.         }
  228.       // our weapon has sub weapons
  229.       else if (weap->submunition >= 0)
  230.         {
  231.           WEAPON *submunition = &weapon[weap->submunition];
  232.  
  233.           quell = 1;
  234.           if (weap->numSubmunitions > 0)
  235.             {
  236.               double divergenceStep = weap->divergence / (weap->numSubmunitions - 1);
  237.               int startPoint;
  238.               int randStart = rand () % 1000000;
  239.               int submunitionPhys = 0;
  240.               double inheritedXV = weap->impartVelocity * xv;
  241.               double inheritedYV = weap->impartVelocity * yv;
  242.  
  243.               if (type == FUNKY_BOMB || type == FUNKY_DEATH)
  244.                 submunitionPhys = 1;
  245.  
  246.               if (divergenceStep < 0)
  247.                 {
  248.                   startPoint = 0;
  249.                 }
  250.               else
  251.                 {
  252.                   startPoint = 180;
  253.                 }
  254.               for (int spreadCount = 0; spreadCount < weap->numSubmunitions; spreadCount++)
  255.                 {
  256.                   MISSILE *newmis;
  257.                   double launchSpeed;
  258.                   int newmisCount;
  259.                   int dAngle;
  260.  
  261.                   dAngle = (int) (startPoint - (weap->divergence / 2) + (divergenceStep * spreadCount));
  262.                   if (weap->spreadVariation > 0)
  263.                     {
  264.                       double variation = Noise (randStart + 1054 + spreadCount) * weap->spreadVariation;
  265.                       dAngle += (int)(weap->divergence * variation);
  266.                     }
  267.                   while (dAngle < 0)
  268.                     dAngle += 360;
  269.                   while (dAngle >= 360)
  270.                     dAngle -= 360;
  271.  
  272.                   newmisCount = submunition->countdown;
  273.                   if (submunition->countVariation > 0)
  274.                     {
  275.                       double variation = Noise (randStart + 78689 + spreadCount) * submunition->countVariation;
  276.                       newmisCount += (int)(submunition->countdown * variation);
  277.                       if (newmisCount <= 0)
  278.                         newmisCount = 1;
  279.                     }
  280.  
  281.                   launchSpeed = weap->launchSpeed;
  282.                   if (weap->speedVariation > 0)
  283.                     {
  284.                       double variation = Noise (randStart + 124786 + spreadCount) * weap->speedVariation;
  285.                       launchSpeed += weap->launchSpeed * variation;
  286.                     }
  287.  
  288.                   newmis = new MISSILE (_global, _env, x, y - 20, _global->slope[dAngle][0] * launchSpeed * (100.0 / _global->frames_per_second) + inheritedXV, _global->slope[dAngle][1] * launchSpeed * (100.0 / _global->frames_per_second) + inheritedYV, weap->submunition);
  289.  
  290.                   if (newmis)
  291.                   {
  292.  
  293.                       newmis->physics = submunitionPhys;
  294.                       newmis->player = player;
  295.                       newmis->countdown = newmisCount;
  296.                       newmis->noimpact = weapon[weap->submunition].noimpact;
  297.                       newmis->setUpdateArea
  298.                        ((int) newmis->x - 20,
  299.                        (int) newmis->y - 20, 40, 40);
  300.                   }
  301.                   else
  302.                       perror ( "missile.cc: Failed allocating memory for newmis in MISSILE::triggerTest (CLUSTER)");
  303.                 }
  304.             }
  305.           destroy = TRUE;
  306.         }
  307.     }
  308.  
  309.   if (countdown >= 0 && age >= countdown)
  310.     {
  311.       quell = 0;
  312.     }
  313.   if (type >= RIOT_CHARGE && type <= RIOT_BLAST)
  314.     {
  315.       quell = 0;
  316.       destroy = TRUE;
  317.     }
  318.   if (!quell)
  319.     {
  320.       _env->realm--;
  321.       trigger ();
  322.     }
  323.  
  324.  
  325.   return (!quell);
  326. }
  327.  
  328. int MISSILE::applyPhysics ()
  329. {
  330.   TANK *ltank;
  331.   int detonate = FALSE;
  332.   int max_age;
  333.   int above_ground;
  334.  
  335.   age++;
  336.  
  337.   // meteors live less time than regular missles
  338.   if ( (type >= SML_METEOR) && (type <= LRG_METEOR) )
  339.     max_age = MAX_METEOR_AGE;
  340.   else
  341.     max_age = MAX_MISSLE_AGE;
  342.  
  343.   // Napalm grows first:
  344.   if (bIsGrowing)
  345.     {
  346.       if (age < max_age)
  347.         {
  348.           iGrowRadius = (int)round((double)expSize * ((double)age / (double)max_age));
  349.           if (iGrowRadius < 2)
  350.             iGrowRadius = 2;
  351.         }
  352.       else
  353.         bIsGrowing = false; // Finished growing!
  354.     }
  355.  
  356.   if ( (age > max_age * _global->frames_per_second) || (y < -65535) )
  357.     detonate = 1;
  358.   if (!physics)
  359.     {
  360.       if (type >= SML_METEOR && type <= LRG_METEOR)
  361.         {
  362.           angle += spin;
  363.           angle = angle % 360;
  364.         }
  365.       else
  366.         {
  367.           angle = (int) (atan (yv / xv) * (180 / PI) * ACHANGE) - 64 + ((xv < 0) ? 128 : 0);
  368.         }
  369.       for (int objCount = 0; (ltank = (TANK*)_env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++)
  370.         {
  371.           if (ltank->player != player)
  372.             {
  373.               double xaccel = 0, yaccel = 0;
  374.               ltank->repulse (x + xv, y + yv, &xaccel, &yaccel, type);
  375.               xv += xaccel;
  376.               yv += yaccel;
  377.             }
  378.         }
  379.       if ( PHYSICAL_OBJECT::applyPhysics () )
  380.       {
  381.         detonate = 1;
  382.       }
  383.       if (! detonate)
  384.         detonate = checkPixelsBetweenPrevAndNow ();
  385.  
  386.       // mirvs trigger above ground
  387.       if ( (! detonate) && ( (type == SMALL_MIRV) || (type == CLUSTER_MIRV) ) )
  388.         {
  389.           above_ground = Height_Above_Ground();
  390.           if ( (above_ground > 0) && (above_ground < TIGGER_HEIGHT) &&
  391.                (yv > 0) )
  392.             detonate = 1;
  393.         }
  394.  
  395.       // if (! detonate &&
  396.       if ( (type == BURROWER || type == PENETRATOR) )
  397.         {
  398.           hitSomething = 0;
  399.           if ( ( y >= _global->screenHeight) &&
  400.                ( (_env->current_wallType == WALL_STEEL) || (_env->current_wallType == WALL_WRAP) ) )
  401.             {
  402.               detonate = TRUE;
  403.               hitSomething = 1;
  404.               y = _global->screenHeight;
  405.               yv = 0;
  406.             }
  407.         }
  408.       if (rand () % 5 == 0)
  409.         {
  410.           DECOR *decor;
  411.           decor = new DECOR (_global, _env, x, y, xv, yv, expSize / 20, DECOR_SMOKE);
  412.           if (!decor)
  413.             {
  414.               perror ( "missile.cc: Failed allocating memory for decor in MISSILE::applyPhysics (METEOR)");
  415.               // exit (1);
  416.             }
  417.         }
  418.     }
  419.   else
  420.     {
  421.       if (type >= SML_ROLLER && type <= DTH_ROLLER)
  422.         {
  423.           /* rollerupdate */
  424.           // check whether we have hit anything
  425.           if (     (x < 1)
  426.                 ||(x > (_global->screenWidth - 2))
  427.                 ||(y > (_global->screenHeight - 2))
  428.                 ||(getpixel(_env->terrain, (int)x, (int)y) != PINK))
  429.             detonate = 1;
  430.           else
  431.             {
  432.               // roll roller
  433.               float fSurfY = (float)_env->surface[(int)x] - 1;
  434.               if ((fSurfY > y) && (y < (_global->screenHeight - 5)))
  435.                 {
  436.                   if (fSurfY < (y + 5))
  437.                     y = fSurfY;
  438.                   else
  439.                     y+=5;
  440.                   if (xv > 0.0)         angle += 3;
  441.                   if (xv < 0.0)         angle -= 3;
  442.                   if (angle < 0)        angle += 256;
  443.                   if (angle > 255)    angle -= 256;
  444.                 }
  445.               else
  446.                 {
  447.                   if (xv > 0.0)
  448.                     {
  449.                       angle += 3;
  450.                       x++;
  451.                     }
  452.                   else
  453.                     {
  454.                       angle -= 3;
  455.                       x--;
  456.                     }
  457.                   if (angle < 0)
  458.                     angle += 256;
  459.                   if (angle > 255)
  460.                     angle -= 256;
  461.                   if    (y >= MENUHEIGHT)
  462.                     {
  463.                       if (fSurfY > y)
  464.                         y++;
  465.                       else if (fSurfY >= (y - 2))
  466.                         y = fSurfY - 1;
  467.                     }
  468.                 }
  469.               if (y > (_global->screenHeight - 5) && !detonate)
  470.                 y = (_global->screenHeight - 5);
  471.             }
  472.         }
  473.       else if (type == FUNKY_BOMBLET || type == FUNKY_DEATHLET)
  474.         {
  475.           //double accel = (_env->wind - xv) / mass * drag;
  476.           if (x + xv < 1 || x + xv > (_global->screenWidth-1))
  477.             {
  478.               xv = -xv;    //bounce on the border
  479.             }
  480.           else
  481.             {
  482.               x += xv;
  483.             }
  484.  
  485.           // hit screen bottom then change the y velocity direction
  486.           if (y + yv >= _global->screenHeight)
  487.             {
  488.               // only bounce if the wall is rubber
  489.               if ( _env->current_wallType == WALL_RUBBER )
  490.                 {
  491.                   yv = -yv * 0.5;
  492.                   xv *= 0.95;
  493.                 }
  494.               // bounce back with more force
  495.               else if ( _env->current_wallType == WALL_SPRING )
  496.                 {
  497.                   yv = -yv * SPRING_CHANGE;
  498.                   xv *= 1.05;
  499.                 }
  500.               // steel or wrap floor, detonate
  501.               else
  502.                 {
  503.                   y = _global->screenHeight;
  504.                   yv = 0;
  505.                   detonate = TRUE;
  506.                 }
  507.             }
  508.           else if (y+yv < 0) //hit screen top
  509.             {
  510.               yv = -yv * 0.5;
  511.               xv *= 0.95;
  512.             }
  513.           y += yv;
  514.         }
  515.       else if (type == BURROWER || type == PENETRATOR)
  516.         {
  517.           angle = (int) (atan (yv / xv) * (180 / PI) * ACHANGE) - 64 + ((xv < 0) ? 128 : 0);
  518.           for (int objCount = 0; (ltank = (TANK*)_env->getNextOfClass (TANK_CLASS, &objCount)) && ltank; objCount++)
  519.             {
  520.               if (ltank->player != player)
  521.                 {
  522.                   double xaccel = 0, yaccel = 0;
  523.                   ltank->repulse (x + xv, y + yv, &xaccel, &yaccel, type);
  524.                   xv += xaccel * 0.1;
  525.                   yv += yaccel * 0.1;
  526.                 }
  527.             }
  528.           if (x + xv < 1 || x + xv > (_global->screenWidth-1))
  529.             {
  530.               // if the wall is rubber, then bouce
  531.               if ( _env->current_wallType == WALL_RUBBER )
  532.                 xv = -xv;    //bounce on the border
  533.               // bounce with more force
  534.               else if ( _env->current_wallType == WALL_SPRING )
  535.                 xv = -xv * SPRING_CHANGE;
  536.               // wall is steel, detonate
  537.               else if ( _env->current_wallType == WALL_STEEL )
  538.                 detonate = TRUE;
  539.               // wrap around to other side of the screen
  540.               else if ( _env->current_wallType == WALL_WRAP )
  541.                 {
  542.                   if (xv < 0)
  543.                     x = _global->screenWidth - 1;
  544.                   else
  545.                     x = 1;
  546.                 }
  547.             }
  548.           if (y + yv >= _global->screenHeight)
  549.             {
  550.               yv = -yv * 0.5;
  551.               xv *= 0.95;
  552.             }
  553.           else if (y+yv < 0)   //hit screen top
  554.             {
  555.               yv = -yv *0.5;
  556.               xv *= 0.95;
  557.             }
  558.           y += yv;
  559.           x += xv;
  560.           yv -= _env->gravity * 0.05 * (100.0 / _global->frames_per_second);
  561.           if (getpixel (_env->terrain, (int)x, (int)y) == PINK)
  562.             {
  563.               detonate = TRUE;
  564.             }
  565.         }
  566.     }
  567.  
  568.   if (detonate)
  569.     {
  570.       hitSomething = 1;
  571.       if (y <= MENUHEIGHT)
  572.         y = MENUHEIGHT + 1;
  573.     }
  574.   else if ((y <= MENUHEIGHT) && _global->bIsBoxed)
  575.     {
  576.       detonate = 1;
  577.       hitSomething = 1; // Sorry, no more ceiling-drops for rollers!
  578.     }
  579.  
  580.   return (detonate);
  581. }
  582.  
  583.  
  584. void MISSILE::trigger ()
  585. {
  586.   EXPLOSION *explosion;
  587.  
  588.   if (type >= TREMOR && type <= TECTONIC)
  589.     explosion = new EXPLOSION (_global, _env, x, y, xv, yv, type);
  590.   else if (type >= RIOT_CHARGE && type <= RIOT_BLAST) 
  591.     explosion = new EXPLOSION (_global, _env, x, y, xv, yv, type);
  592.   else
  593.     explosion = new EXPLOSION (_global, _env, x, y, type);
  594.  
  595.   if (!explosion)
  596.     {
  597.       perror ( "missile.cc: Failed allocating memory for explosion in MISSILE::trigger");
  598.       // exit (1);
  599.     }
  600.   else
  601.      explosion->player = player;
  602.  
  603.  
  604.  
  605.   if ((_env->current_wallType == WALL_WRAP) && (type < WEAPONS))
  606.     {
  607.       EXPLOSION *cSecondExplo = NULL;
  608.       if (x < weapon[type].radius)
  609.         {
  610.           if   (   (type >= TREMOR && type <= TECTONIC)
  611.                    ||(type >= RIOT_CHARGE && type <= RIOT_BLAST)   )
  612.             cSecondExplo = new EXPLOSION (_global, _env, _global->screenWidth + x, y, xv, yv, type);
  613.           else
  614.             cSecondExplo = new EXPLOSION (_global, _env, _global->screenWidth + x, y, type);
  615.           if (!cSecondExplo)
  616.             {
  617.               perror ( "missile.cc: Failed allocating memory for cSecondExplo in MISSILE::trigger");
  618.               // exit (1);
  619.             }
  620.         }
  621.       if (x > (_global->screenWidth - weapon[type].radius))
  622.         {
  623.           if   (   (type >= TREMOR && type <= TECTONIC)
  624.                    ||(type >= RIOT_CHARGE && type <= RIOT_BLAST)   )
  625.             cSecondExplo = new EXPLOSION (_global, _env, x - _global->screenWidth, y, xv, yv, type);
  626.           else
  627.             cSecondExplo = new EXPLOSION (_global, _env, x - _global->screenWidth, y, type);
  628.           if (!cSecondExplo)
  629.             {
  630.               perror ( "missile.cc: Failed allocating memory for cSecondExplo in MISSILE::trigger");
  631.               // exit (1);
  632.             }
  633.         }
  634.       if (cSecondExplo)
  635.         cSecondExplo->player = player;
  636.     }
  637.  
  638.  
  639.  
  640.   destroy = TRUE;
  641.  
  642.   if ((type >= DIRT_BALL && type <= SMALL_DIRT_SPREAD) || (type >= RIOT_CHARGE && type <= RIOT_BLAST))
  643.     {
  644.       play_sample ((SAMPLE *) _global->sounds[9], 128 + (expSize / 2), 128, 1000 - (expSize * 2), 0);
  645.     }
  646.   else if (type == NAPALM_JELLY)
  647.     {
  648.       //play_sample ((SAMPLE *) _global->SOUND[9].dat, 128 + (expSize / 2), 128, 1000 - (expSize * 2), 0);
  649.     }
  650.   else
  651.     {
  652.       play_sample ((SAMPLE *) _global->sounds[WEAPONSOUNDS + sound], 255, 128, 1000, 0);
  653.     }
  654. }
  655.  
  656. void MISSILE::draw (BITMAP *dest)
  657. {
  658.   if (!destroy)
  659.     {
  660.       // draw missile if it is above the screen
  661.       if (y < MENUHEIGHT)
  662.         {
  663.           BITMAP *bbitmap = _bitmap;
  664.           double by = y;
  665.           int bangle = angle;
  666.  
  667.           _bitmap = (BITMAP*)_global->misc[3];
  668.           y = (double)MENUHEIGHT + (_bitmap->h / 2);
  669.           angle = 0;
  670.  
  671.           VIRTUAL_OBJECT::draw (dest);
  672.           _bitmap = bbitmap;
  673.           y = by;
  674.           angle = bangle;
  675.         }
  676.  
  677.       // draw missile on the screen
  678.       else
  679.         {
  680.  
  681.           if (type == NAPALM_JELLY)
  682.             {
  683.               if (bIsGrowing)
  684.                 {
  685.                   circlefill (_env->db, (int)x, (int)y, iGrowRadius - 2, makecol (255, 0, 0));
  686.                   circle(_env->db, (int)x, (int)y, iGrowRadius - 1, makecol(255, 150, 0));
  687.                   circle(_env->db, (int)x, (int)y, iGrowRadius, makecol(255, 150, 0));
  688.                   setUpdateArea ( (int)x - (iGrowRadius + 1),
  689.                                   (int)y - (iGrowRadius + 1),
  690.                                   (iGrowRadius + 1) * 2,
  691.                                   (iGrowRadius + 1) * 2);
  692.                 }
  693.               else
  694.                 {
  695.                   circlefill (_env->db, (int)x, (int)y, expSize - 2, makecol (255, 0, 0));
  696.                   circle(_env->db, (int)x, (int)y, expSize - 1, makecol(255, 150, 0));
  697.                   circle(_env->db, (int)x, (int)y, expSize, makecol(255, 150, 0));
  698.                   setUpdateArea ((int)x - (expSize + 1), (int)y - (expSize + 1), (expSize + 1) * 2, (expSize + 1) * 2);
  699.                 }
  700.               requireUpdate ();
  701.             }   // end of napalm
  702.  
  703.           // try drawing a funky bomblet
  704.           else if ( ( type == FUNKY_BOMBLET) || (type == FUNKY_DEATHLET) )
  705.           {
  706.               circlefill(_env->db, (int) x, (int) y, 4, funky_colour );
  707.               circle(_env->db, (int) x, (int) y, 5, makecol(0, 0, 0) );
  708.               setUpdateArea( (int) x - 10, (int) y - 10, 20, 20);
  709.               requireUpdate();
  710.           } 
  711.           // draw anything else, besides napalm
  712.           else
  713.             {
  714.               VIRTUAL_OBJECT::draw (dest);
  715.             }
  716.         }
  717.     }
  718. }
  719.  
  720.  
  721. void MISSILE::setEnvironment(ENVIRONMENT *env)
  722.     {
  723.       if (!_env || (_env != env))
  724.         {
  725.           _env = env;
  726.           _index = _env->addObject (this);
  727.         }
  728.     }
  729.  
  730.  
  731.  
  732. int MISSILE::isSubClass (int classNum)
  733. {
  734.   if (classNum == MISSILE_CLASS)
  735.     return (TRUE);
  736.   else
  737.     return (FALSE);
  738.   //return (PHYSICAL_OBJECT::isSubClass (classNum));
  739. }
  740.  
  741.  
  742. // This function returns the distance above ground of
  743. // the missile.
  744. int MISSILE::Height_Above_Ground()
  745. {
  746.   int height = (int)y + 1;
  747.  
  748.   if (y < 0)
  749.     return height;
  750.  
  751.   height = _env->surface[(int) x] - y;
  752.   return height;
  753. }
  754.  
  755.  
  756.  
  757. // Check to see if any tanks have SDI defense. If they
  758. // do, then see if this missile should be shot down.
  759. // Returns the shooting tank if a shot is to be fired
  760. // or NULL if no tank will shoot.
  761. TANK *MISSILE::Check_SDI(GLOBALDATA *global)
  762. {
  763.     TANK *my_tank;
  764.     int index;
  765.     double distance;
  766.     int chance;
  767.  
  768.     if (type == NAPALM_JELLY)     // can't shoot jelly
  769.        return NULL;
  770.  
  771.     for (index = 0; index < global->numPlayers; index++)
  772.     {
  773.         if ( ( global->players[index] ) && ( global->players[index]->tank) )
  774.         {
  775.             my_tank = global->players[index]->tank;
  776.             if ( (my_tank->player->ni[ITEM_SDI]) && (my_tank->player != this->player) )
  777.             {
  778.                  distance = pow(x - my_tank->x, 2);
  779.                  distance += pow(y - my_tank->y, 2);
  780.                  distance = sqrt(distance);
  781.                  // only fire if within range and above the tank
  782.                  if ( ( distance < SDI_DISTANCE ) && (my_tank->y > y) )
  783.                  {
  784.                       chance = rand() % 5;
  785.                       if (! chance)
  786.                       {
  787.                          return my_tank;
  788.                       }
  789.                  }        // within range
  790.             }      // we have SDI
  791.         }       // end of we have a valid player/tank
  792.        
  793.     }           // finished going through all players
  794.     
  795.     return NULL;
  796. }
  797.  
  798.  
  799.