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 / tank.cpp < prev    next >
C/C++ Source or Header  |  2010-09-05  |  41KB  |  1,432 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 "floattext.h"
  24. #include "explosion.h"
  25. #include "teleport.h"
  26. #include "missile.h"
  27. #include "player.h"
  28. #include "beam.h"
  29. #include "tank.h"
  30.  
  31.  
  32. /*
  33. The deconstructor should be split into two pieces. One function for
  34. destroying a tank and another strictly for cleaning up a tank's memory
  35. whether it was destoryed or not.
  36. -- Jesse
  37. */
  38. TANK::~TANK ()
  39. {
  40. /*
  41.   #ifdef NETWORK
  42.   if (player)        // we should always have a player, but better safe than sorry
  43.   {
  44.       int player_index = 0;
  45.       bool found = false;
  46.       char buffer[64];
  47.       while ( (player_index < _global->numPlayers) && (!found) )
  48.       {
  49.           // get the player index
  50.           if ( ( _global->players[player_index]->tank ) && (_global->players[player_index]->tank == this) )
  51.               found = true;
  52.           else
  53.               player_index++;
  54.      }
  55.      if (found)        // we should have found a match and now we send it to all clients
  56.      {
  57.          sprintf(buffer, "REMOVETANK %d", player_index);
  58.          _global->Send_To_Clients(buffer);
  59.      }
  60.   }
  61.   #endif
  62.   if (_global && player)
  63.     {
  64.       int random_item;
  65.       if (_global->violent_death)
  66.         {
  67.           random_item = rand() % VIOLENT_CHANCE;
  68.           if ( ( random_item > _global->violent_death ) && (random_item <= VIOLENT_DEATH_HEAVY) )
  69.             random_item = (int) _global->violent_death;
  70.  
  71.           switch (random_item)
  72.             {
  73.             case VIOLENT_DEATH_LIGHT:
  74.               player->ni[ITEM_VENGEANCE] += 1;
  75.               break;
  76.             case VIOLENT_DEATH_MEDIUM:
  77.               player->ni[ITEM_DYING_WRATH] += 1;
  78.               break;
  79.             case VIOLENT_DEATH_HEAVY:
  80.               player->ni[ITEM_FATAL_FURY] += 1;
  81.               break;
  82.             }     //end of switch
  83.         }
  84.  
  85.       if (player->ni[ITEM_FATAL_FURY] > 0)
  86.         {
  87.           int numLaunch = (int)item[ITEM_FATAL_FURY].vals[SELFD_NUMBER];
  88.           cw = (int)item[ITEM_FATAL_FURY].vals[SELFD_TYPE];
  89.           player->ni[ITEM_FATAL_FURY]--;
  90.           player->nm[cw] += numLaunch;
  91.           for (int count = numLaunch; count > 0; count--)
  92.             {
  93.               a = rand () % 180 + 90;
  94.               p = rand () % (MAX_POWER / 2);
  95.               activateCurrentSelection ();
  96.             }
  97.         }
  98.       else if (player->ni[ITEM_DYING_WRATH] > 0)
  99.         {
  100.           int numLaunch = (int)item[ITEM_DYING_WRATH].vals[SELFD_NUMBER];
  101.           cw = (int)item[ITEM_DYING_WRATH].vals[SELFD_TYPE];
  102.           player->ni[ITEM_DYING_WRATH]--;
  103.           player->nm[cw] += numLaunch;
  104.           for (int count = numLaunch; count > 0; count--)
  105.             {
  106.               a = rand () % 180 + 90;
  107.               p = rand () % (MAX_POWER / 2);
  108.               activateCurrentSelection ();
  109.             }
  110.         }
  111.       else if (player->ni[ITEM_VENGEANCE] > 0)
  112.         {
  113.           int numLaunch = (int)item[ITEM_VENGEANCE].vals[SELFD_NUMBER];
  114.           cw = (int)item[ITEM_VENGEANCE].vals[SELFD_TYPE];
  115.           player->ni[ITEM_VENGEANCE]--;
  116.           player->nm[cw] += numLaunch;
  117.           for (int count = numLaunch; count > 0; count--)
  118.             {
  119.               a = rand () % 180 + 90;
  120.               p = rand () % (MAX_POWER / 2);
  121.               activateCurrentSelection ();
  122.             }
  123.         }
  124.     }
  125.    */
  126.  
  127.   if (player)
  128.     {
  129.       player->tank = NULL;
  130.       player = NULL;
  131.     }
  132.   if (_global)
  133.     {
  134.       _global->numTanks--;
  135.       if (_global->currTank == this)
  136.         _global->currTank = NULL;
  137.     }
  138.  
  139.   if (shieldText)
  140.     delete (shieldText);
  141.   if (healthText)
  142.     delete (healthText);
  143.   if (nameText)
  144.     delete (nameText);
  145.  
  146.   if (_env)
  147.     _env->removeObject(this);
  148.  
  149.   shieldText  = NULL;
  150.   healthText  = NULL;
  151.   nameText    = NULL;
  152.   _env        = NULL;
  153.   _global     = NULL;
  154.   creditTo    = NULL;
  155.   _target     = NULL;
  156. }
  157.  
  158. TANK::TANK (GLOBALDATA *global, ENVIRONMENT *env):PHYSICAL_OBJECT(),_target(NULL),creditTo(NULL),
  159.                                                 healthText(NULL),shieldText(NULL),nameText(NULL)
  160. {
  161.   setEnvironment (env);
  162.   _global = global;
  163.   // Ask for memory
  164.   healthText = new FLOATTEXT (global, env, NULL, 0, 0, WHITE, CENTRE);
  165.   if (!healthText)
  166.     {
  167.       perror ( "tank.cc: Failed allocating memory for healthText in TANK::TANK");
  168.       // exit (1);
  169.     }
  170.  
  171.   shieldText = new FLOATTEXT (global, env, NULL, 0, 0, makecol (200, 200, 255), CENTRE);
  172.   if (!shieldText)
  173.     {
  174.       perror ( "tank.cc: Failed allocating memory for shieldText in TANK::TANK");
  175.       // exit (1);
  176.     }
  177.  
  178.   if (global->name_above_tank)
  179.     {
  180.       nameText = new FLOATTEXT (global, env, NULL, 0, 0, WHITE, CENTRE);
  181.       if (! nameText)
  182.         {
  183.           perror ( "tank.cc: Failed allocating memory for nameText in TANK::TANK");
  184.           // exit(1);
  185.         }
  186.     }
  187.  
  188.   // Other initial pointers:
  189.   _align = LEFT;
  190.   _global->numTanks++;
  191.  
  192.   player = NULL;
  193. }
  194.  
  195. void TANK::initialise ()
  196. {
  197.   PHYSICAL_OBJECT::initialise ();
  198.   drag = 0.5;
  199.   mass = 3000;
  200.   repulsion = 0;
  201.   shieldColor = 0;
  202.   shieldThickness = 0;
  203.   t = 0;
  204.   sh = 0;
  205.   _targetX = -1;
  206.   _targetY = -1;
  207.   newRound ();
  208. }
  209.  
  210. void TANK::newRound ()
  211. {
  212.   char buf[10];
  213.  
  214.   cw = 0;
  215.   damage = 0;
  216.   pen = 0;
  217.   para = 0;
  218.   creditTo = NULL;
  219.   p = MAX_POWER / 2;
  220.   a = (rand () % 180) + 90;
  221.   if (sh > 0 && sht > 0)
  222.     if (player)
  223.       player->ni[sht]++;
  224.   sh = 0;
  225.   repulsion = 0;
  226.   // shPhase = rand () % 360;
  227.   shPhase = 0;
  228.   delta_phase = 0.1;
  229.   sht = 0;
  230.   l = 100;
  231.   repair_rate = 0;
  232.   if (player)
  233.     {
  234.       double tmpL = 0;
  235.       tmpL += (int)(player->ni[ITEM_ARMOUR] * item[ITEM_ARMOUR].vals[0]);
  236.       tmpL += (int)(player->ni[ITEM_PLASTEEL] * item[ITEM_PLASTEEL].vals[0]);
  237.       repair_rate = Get_Repair_Rate();
  238.       if (tmpL > 0)
  239.         l += (int)pow (tmpL, 0.6);
  240.  
  241.       if (healthText)
  242.         healthText->set_color( player->color );
  243.       if (nameText)
  244.         {
  245.           nameText->set_text ( player->getName() );
  246.           nameText->set_color ( player->color );
  247.         }
  248.     }
  249.   maxLife = l;
  250.   ds = 0;
  251.   fs = 0;
  252.   sprintf (buf, "%d", l);
  253.   healthText->set_text (buf);
  254.   // delay_fall = GRAVITY_DELAY;
  255.   delay_fall = (int) labs(_env->landSlideDelay * 100);
  256.   fire_another_shot = 0;
  257.   shots_fired = 0;
  258.  
  259. }
  260.  
  261.  
  262.  
  263. void TANK::Destroy()
  264. {
  265.   #ifdef NETWORK
  266.   if (player)    // we should always have a player, but better safe than sorry
  267.   {
  268.       int player_index = 0;
  269.       bool found = false;
  270.       char buffer[64];
  271.       while ( (player_index < _global->numPlayers) && (!found) )
  272.       {
  273.           // get the player index
  274.           if ( ( _global->players[player_index]->tank ) && (_global->players[player_index]->tank == this) )
  275.               found = true;
  276.           else
  277.               player_index++;
  278.      }
  279.      if (found)        // we should have found a match and now we send it to all clients
  280.      {
  281.          sprintf(buffer, "REMOVETANK %d", player_index);
  282.          _global->Send_To_Clients(buffer);
  283.      }
  284.   }
  285.   #endif
  286.  
  287.    if (_global && player)
  288.     {
  289.       int random_item;
  290.       if (_global->violent_death)
  291.         {
  292.           random_item = rand() % VIOLENT_CHANCE;
  293.           if ( ( random_item > _global->violent_death ) && (random_item <= VIOLENT_DEATH_HEAVY) )
  294.             random_item = (int) _global->violent_death;
  295.  
  296.           switch (random_item)
  297.             {
  298.             case VIOLENT_DEATH_LIGHT:
  299.               player->ni[ITEM_VENGEANCE] += 1;
  300.               break;
  301.             case VIOLENT_DEATH_MEDIUM:
  302.               player->ni[ITEM_DYING_WRATH] += 1;
  303.               break;
  304.             case VIOLENT_DEATH_HEAVY:
  305.               player->ni[ITEM_FATAL_FURY] += 1;
  306.               break;
  307.             }     //end of switch
  308.         }
  309.  
  310.         if (player->ni[ITEM_FATAL_FURY] > 0)
  311.         {
  312.           int numLaunch = (int)item[ITEM_FATAL_FURY].vals[SELFD_NUMBER];
  313.           cw = (int)item[ITEM_FATAL_FURY].vals[SELFD_TYPE];
  314.           player->ni[ITEM_FATAL_FURY]--;
  315.           player->nm[cw] += numLaunch;
  316.           for (int count = numLaunch; count > 0; count--)
  317.             {
  318.               a = rand () % 180 + 90;
  319.               p = rand () % (MAX_POWER / 2);
  320.               activateCurrentSelection ();
  321.             }
  322.         }
  323.         else if (player->ni[ITEM_DYING_WRATH] > 0)
  324.         {
  325.           int numLaunch = (int)item[ITEM_DYING_WRATH].vals[SELFD_NUMBER];
  326.           cw = (int)item[ITEM_DYING_WRATH].vals[SELFD_TYPE];
  327.           player->ni[ITEM_DYING_WRATH]--;
  328.           player->nm[cw] += numLaunch;
  329.           for (int count = numLaunch; count > 0; count--)
  330.             {
  331.               a = rand () % 180 + 90;
  332.               p = rand () % (MAX_POWER / 2);
  333.               activateCurrentSelection ();
  334.             }
  335.         }
  336.         else if (player->ni[ITEM_VENGEANCE] > 0)
  337.         {
  338.           int numLaunch = (int)item[ITEM_VENGEANCE].vals[SELFD_NUMBER];
  339.           cw = (int)item[ITEM_VENGEANCE].vals[SELFD_TYPE];
  340.           player->ni[ITEM_VENGEANCE]--;
  341.           player->nm[cw] += numLaunch;
  342.           for (int count = numLaunch; count > 0; count--)
  343.             {
  344.               a = rand () % 180 + 90;
  345.               p = rand () % (MAX_POWER / 2);
  346.               activateCurrentSelection ();
  347.             }
  348.         }
  349.     }
  350. }
  351.  
  352.  
  353.  
  354. void TANK::update ()
  355. {
  356.   VIRTUAL_OBJECT::update ();
  357. }
  358.  
  359. void TANK::requireUpdate ()
  360. {
  361.   VIRTUAL_OBJECT::requireUpdate ();
  362. }
  363.  
  364. void TANK::applyDamage ()
  365. {
  366.   char buf[10];
  367.   FLOATTEXT *damageText;
  368.   FLOATTEXT *revengeText;
  369.   FLOATTEXT *gloatText;
  370.   FLOATTEXT *suicideText;
  371.   char *temp_text;
  372.   bool killed = false;
  373.  
  374.   if (damage > sh + l)
  375.     {
  376.       damage = sh + l;
  377.       killed = true;
  378.       player->killed++;
  379.     }
  380.   sh -= (int)damage;
  381.   if (creditTo)
  382.     {
  383.       if (player != creditTo)      //enemy hit ++
  384.         {
  385.           if ( killed )
  386.             creditTo->kills++;
  387.           creditTo->money += (int)(damage * _global->scoreHitUnit);
  388.           if (creditTo->tank)
  389.           {
  390.                 char the_money[64];
  391.                 sprintf(the_money, "$%s", Add_Comma( (int) (damage * _global->scoreHitUnit) ) );
  392.                 // show how much the shooter gets
  393.                 FLOATTEXT *moneyText = new FLOATTEXT(_global, _env, the_money,
  394.                                     (int) creditTo->tank->x, (int) creditTo->tank->y - 30,
  395.                                     makecol(0, 255, 0), CENTRE);
  396.                 if (moneyText)
  397.                 {
  398.                       // moneyText->xv = 0;
  399.                       // moneyText->yv = -0.5;
  400.                       moneyText->set_speed(0.0, -0.5);
  401.                       moneyText->maxAge = 200;
  402.                 }
  403.                 
  404.           }
  405.           // this tank is destroyed, the attacker gloats
  406.           if ( (killed) && (! creditTo->gloating) )
  407.             {
  408.               // avoid trying to print victory message over a dead tank
  409.               if (creditTo->tank)
  410.                 {
  411.                   temp_text = creditTo->selectGloatPhrase();
  412.                   gloatText = new FLOATTEXT (_global, _env,
  413.                                              // creditTo->selectGloatPhrase( (double) damage / maxLife),
  414.                                              temp_text,
  415.                                              (int) creditTo->tank->x, (int) creditTo->tank->y - 30,
  416.                                              creditTo->color, CENTRE);
  417.                   if (gloatText)
  418.                   {
  419.                     // gloatText->xv = 0;
  420.                     // gloatText->yv = -0.4;
  421.                     gloatText->set_speed(0.0, -0.4);
  422.                     gloatText->maxAge = 300;
  423.                   }
  424.                   else
  425.                       perror ( "tank.cc: Failed allocating memory for gloatText in applyDamage.");
  426.                   creditTo->gloating = true;
  427.                 }
  428.             }
  429.  
  430.           if ((int)player->type != HUMAN_PLAYER)
  431.             {
  432.               if (player->revenge == creditTo)
  433.                 {
  434.                   player->annoyanceFactor += damage;
  435.                 }
  436.               else
  437.                 {
  438.                   player->annoyanceFactor = damage;
  439.                 }
  440.               if (  (player->annoyanceFactor > (player->vengeanceThreshold * maxLife) )
  441.                   &&((rand() % 100) <= player->vengeful) )
  442.                 {
  443.                   player->revenge = creditTo;
  444.                   temp_text = player->selectRevengePhrase();
  445.                   revengeText = new FLOATTEXT (_global, _env,
  446.                                                // player->selectRevengePhrase ((double)damage / maxLife),
  447.                                                temp_text,
  448.                                                (int)x, (int)y - 30,
  449.                                                player->color, CENTRE);
  450.                   if (revengeText)
  451.                   {
  452.                     // revengeText->xv = 0;
  453.                     // revengeText->yv = -0.4;
  454.                     revengeText->set_speed(0.0, -0.4);
  455.                     revengeText->maxAge = 300;
  456.                   }
  457.                   else
  458.                       perror ( "tank.cc: Failed allocating memory for revengeText in applyDamage");
  459.                 }
  460.             }
  461.         }
  462.       else      //self hit --
  463.         {
  464.           if ( (creditTo->money - (damage * _global->scoreSelfHit)) < 0)
  465.             creditTo->money = 0;
  466.           else
  467.             creditTo->money -= (int)(damage * _global->scoreSelfHit);
  468.  
  469.           if (damage >= (l + sh) )
  470.             {
  471.               temp_text = player->selectSuicidePhrase();
  472.               suicideText = new FLOATTEXT (_global, _env,
  473.                                            player->selectSuicidePhrase(),
  474.                                            (int) x, (int) y - 30,
  475.                                            player->color, CENTRE);
  476.               if (suicideText)
  477.               {
  478.                  // suicideText->xv = 0;
  479.                  // suicideText->yv = -0.4;
  480.                  suicideText->set_speed(0.0, -0.4);
  481.                  suicideText->maxAge = 300;
  482.               }
  483.               else
  484.                   perror ( "tank.cc: Failed allocating memory for suicideText in applyDamage.");
  485.             }
  486.         }
  487.     }
  488.  
  489.   if (sh < 0)
  490.     l += sh;
  491.   if (l < 0)
  492.     l = 0;
  493.   if (sh <= 0)
  494.     {
  495.       repulsion = 0;
  496.       shieldColor = 0;
  497.       shieldThickness = 0;
  498.       sh = 0;
  499.     }
  500.  
  501.   if ((int)damage > 0)
  502.     {
  503.       flashdamage = 1;
  504.       sprintf (buf, "%d", (int)damage);
  505.       damageText = new FLOATTEXT (_global, _env,
  506.                                   NULL, (int)x, (int)y,
  507.                                   makecol (255, 0, 0), CENTRE);
  508.       if (damageText)
  509.       {
  510.          damageText->set_text(buf);
  511.          // damageText->xv = 0;
  512.          // damageText->yv = -0.2;
  513.          damageText->set_speed(0.0, -0.2);
  514.          damageText->maxAge = 300;
  515.          // damageText->sway = NORMAL_SWAY;
  516.       }
  517.       else
  518.           perror ( "tank.cc: Failed allocating memory for damageText in TANK::TANK");
  519.     }
  520.   if (sh > 0)
  521.     {
  522.       sprintf (buf, "%d", sh);
  523.       shieldText->set_text (buf);
  524.     }
  525.   else
  526.     {
  527.       shieldText->set_text ( "");
  528.     }
  529.   sprintf (buf, "%d", l);
  530.   healthText->set_text (buf);
  531. }
  532.  
  533. void TANK::framelyAccounting ()
  534. {
  535.   /*
  536.   if (shPhase < 0)
  537.     shPhase = rand () % 360;
  538.   shPhase += (int)(item[sht].vals[SHIELD_ENERGY] / sh) + 10;
  539.   while (shPhase >= 360)
  540.     shPhase -= 360;
  541.   */
  542.   shPhase = shPhase + delta_phase;
  543.   if ( ( shPhase > 5) || (shPhase < -2) )
  544.      delta_phase = -delta_phase;
  545. }
  546.  
  547. int TANK::applyPhysics (GLOBALDATA *global)
  548. {
  549.   int stable = 0;
  550.   int landed_on_tank;
  551.  
  552.   // if we are buried, rockets shouldn't work
  553.   if ( howBuried() )
  554.   {
  555.     xv = 0;
  556.     if (yv < 0)
  557.        yv = 0;
  558.   }
  559.  
  560.   // make sure the tank does not leave the screen when flying
  561.   if ( (yv < 0) && (y < TANKHEIGHT) )
  562.      yv = 0;
  563.  
  564.   if (yv < 0)
  565.       x += xv * 4;
  566.  
  567.   if (!flashdamage)
  568.     {
  569.       if (x + xv < 1 || x + xv > (_global->screenWidth-1))
  570.         xv = -xv;    //bounce on the border
  571.       int pixelCol = getpixel (_env->terrain, (int)x, (int)y + (TANKHEIGHT - TANKSAG));
  572.  
  573.       // check to see if we have landed on another tank -- Jesse
  574.       landed_on_tank = tank_on_tank ( global );
  575.  
  576.       // we are falling and have hit the bottom of the screen or fallen onto dirt or on a tank
  577.       if ((l > 0) && (yv > 0) && ((y >= _global->screenHeight - TANKHEIGHT) ||
  578.                                   (pixelCol != PINK) ||
  579.                                   (landed_on_tank) ))
  580.         {
  581.           //count damage and add money
  582.           damage = (int) (yv * 10);
  583.           if (damage >= 10)
  584.             damage -= 10;
  585.           else damage = 0;
  586.           creditTo = NULL;
  587.           yv = 0;
  588.           xv = 0;
  589.           // if we passed the bottom, then stop on bottom
  590.           if (y > _global->screenHeight - TANKHEIGHT)
  591.             y = _global->screenHeight - TANKHEIGHT;
  592.  
  593.           // delay_fall = GRAVITY_DELAY;
  594.           delay_fall = (int) _env->landSlideDelay * 100;
  595.  
  596.         }
  597.  
  598.       // the tank is falling
  599.       else if ((y < _global->screenHeight - TANKHEIGHT) && (pixelCol == PINK) && (l > 0) &&
  600.                (! landed_on_tank) && (_env->landSlideType > LANDSLIDE_NONE) )
  601.         {
  602.           delay_fall--;
  603.           if ( (delay_fall > 0) && (_env->landSlideType == LANDSLIDE_CARTOON) )
  604.             return stable;
  605.  
  606.           #ifdef OLD_GAMELOOP
  607.           if (para && para < 3 && !_env->pclock)
  608.             para++;
  609.           #else
  610.           if ( (para) && (para < 3) )
  611.             para++;
  612.           #endif
  613.           if (!para)
  614.             {
  615.               yv += _env->gravity * (100.0 / _global->frames_per_second);
  616.               y += yv;
  617.             }
  618.           else
  619.             {
  620.               double accel = (_env->wind - xv) / mass * (drag + 0.35) * _env->viscosity;
  621.               xv += accel;
  622.               yv += _env->gravity * (100.0 / _global->frames_per_second);
  623.               if (yv > 0.5 )
  624.                 yv = 0.5;
  625.               x += xv;
  626.               y += yv;
  627.             }
  628.           // falling, deploy parachute
  629.           if (!para)
  630.             {
  631.               if ((player->ni[ITEM_PARACHUTE]) && (yv >= 1.0))
  632.                 {
  633.                   _env->pclock = 1;
  634.                   para = 1;
  635.                   player->ni[ITEM_PARACHUTE]--;
  636.                 }
  637.  
  638.             }
  639.           requireUpdate ();
  640.         }
  641.       else
  642.         {
  643.           stable = 1;
  644.           if (damage && !pen)
  645.             {
  646.               applyDamage ();
  647.  
  648.               pen = 1;
  649.             }
  650.           para = 0;
  651.         }
  652.     }
  653.   else
  654.     {
  655.       flashdamage++;
  656.     }
  657.   return (stable);
  658. }
  659.  
  660. void TANK::explode ()
  661. {
  662.   FLOATTEXT *revengeText;
  663.   EXPLOSION *explosion;
  664.   char *temp_text;
  665.  
  666.   if ((int)player->type != HUMAN_PLAYER)
  667.     {
  668.       player->revenge = creditTo;
  669.       temp_text = player->selectRevengePhrase();
  670.       revengeText = new FLOATTEXT (_global, _env,
  671.                                    temp_text,
  672.                                    (int)x, (int)y - 30,
  673.                                    player->color, CENTRE);
  674.       if (revengeText)
  675.       {
  676.           // revengeText->xv = 0;
  677.           // revengeText->yv = -0.4;
  678.           revengeText->set_speed(0.0, -0.4);
  679.           revengeText->maxAge = 300;
  680.       }
  681.       else
  682.           perror ( "tank.cc: Failed allocating memory for revengeText in TANK::explode");
  683.     }
  684.   explosion = new EXPLOSION (_global, _env, x, y, 1);
  685.   if (explosion)
  686.   {
  687.      explosion->player = player;
  688.      explosion->bIsWeaponExplosion = false;
  689.   }
  690.   else
  691.       perror ( "tank.cc: Failed allocating memory for explosion in TANK::explode");
  692.   
  693.  
  694.   destroy = TRUE;
  695.   play_sample ((SAMPLE *)_global->sounds[WEAPONSOUNDS], 255, 128, 1000, 0);
  696. }
  697.  
  698. void TANK::repulse (double xpos, double ypos, double *xaccel, double *yaccel, int aWeaponType)
  699. {
  700.   if (repulsion != 0)
  701.     {
  702.       double xdist = xpos - x;
  703.       double ydist = -1.0 * fabs(ypos - y);
  704.  
  705.       if ((xdist < 0.1) && (xdist > -0.1)) xdist = 0.1;
  706.       if ((ydist < 0.1) && (ydist > -0.1)) ydist = -0.1; // Assume missile comes from above
  707.  
  708.       if (    (aWeaponType >= BURROWER) && (aWeaponType <= PENETRATOR)
  709.            &&(ypos > y)    )
  710.         ydist *= -1.0; // they normally come from below!
  711.  
  712.       double distance2 = (xdist * xdist) + (ydist * ydist);
  713.       double distance = sqrt (distance2);
  714.  
  715.       if (distance < (60.0 + sqrt ((double)repulsion)))
  716.         {
  717.           *xaccel = repulsion * (xdist / distance) / distance2;
  718.           *yaccel = repulsion * (ydist / distance) / distance2;
  719.         }
  720.     }
  721. }
  722.  
  723. void TANK::printHealth (int offset)
  724. {
  725.   int textpos = -5;
  726.  
  727.   shieldText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
  728.   if (sh > 0)
  729.     textpos -= 10;
  730.   healthText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
  731.  
  732.   // display player name
  733.   if (nameText)
  734.   {
  735.       textpos -= 10;
  736.       nameText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
  737.   }
  738. }
  739.  
  740. void TANK::draw (BITMAP *dest, int healthOffset)
  741. {
  742.   int turretAngle;
  743.  
  744.   // check for foggy weather
  745.   if ( ( _env->fog ) && ( _global->currTank != this ) )
  746.     {
  747.       addUpdateArea ((int)(x - TANKWIDTH) - 3, (int)y - 25, 35, 46);
  748.       requireUpdate ();
  749.       return;
  750.     }
  751.  
  752.   // get bitmap for tank
  753.   if (player)
  754.   {
  755.       switch ( (int) player->tank_bitmap)
  756.         {
  757.         case CLASSIC_TANK:
  758.           use_tank_bitmap = 8;
  759.           use_turret_bitmap = 1;
  760.           turret_x = x;
  761.           turret_y = y + (TANKHEIGHT / 2);
  762.           break;
  763.         case BIGGREY_TANK:
  764.           use_tank_bitmap = 9;
  765.           use_turret_bitmap = 2;
  766.           turret_y = y;
  767.           turret_x = x;
  768.           break;
  769.         case T34_TANK:
  770.           use_tank_bitmap = 10;
  771.           use_turret_bitmap = 3;
  772.           turret_y = y;
  773.           turret_x = x;
  774.           break;
  775.         case HEAVY_TANK:
  776.           use_tank_bitmap = 11;
  777.           use_turret_bitmap = 4;
  778.           turret_y = y;
  779.           turret_x = x;
  780.           break;
  781.         case FUTURE_TANK:
  782.           use_tank_bitmap = 12;
  783.           use_turret_bitmap = 5;
  784.           turret_y = y;
  785.           turret_x = x;
  786.           break;
  787.         case UFO_TANK:
  788.           use_tank_bitmap = 13;
  789.           use_turret_bitmap = 6;
  790.           turret_y = y;
  791.           turret_x = x;
  792.           break;
  793.         case SPIDER_TANK:
  794.           use_tank_bitmap = 14;
  795.           use_turret_bitmap = 7;
  796.           turret_y = y;
  797.           turret_x = x;
  798.           break;
  799.          case BIGFOOT_TANK:
  800.           use_tank_bitmap = 15;
  801.           use_turret_bitmap = 8;
  802.           turret_y = y;
  803.           turret_x = x;
  804.           break;
  805.         default:
  806.           use_tank_bitmap = 0;
  807.           use_turret_bitmap = 0;
  808.           turret_x = x;
  809.           turret_y = y;
  810.           break;
  811.         }
  812.     }
  813.  
  814.   rectfill (dest, (int) x - (TANKWIDTH - 1),
  815.             (int) (y + TANKHEIGHT) - 2,
  816.             (int) (x + TANKWIDTH) - 2,
  817.             (int) (y + TANKHEIGHT),
  818.             this->player->color);
  819.   // draw_sprite (dest, (BITMAP *) _global->gfxData.T[use_tank_bitmap].dat, (int) x - TANKWIDTH, (int) y);
  820.  
  821. /*
  822.   Drawing shields this way seems to cause a crash on multi-cpu
  823.   systems. Taking this out and creating new shield
  824.   drawing routine below. -- Jesse
  825.  
  826.   if (sh > 0)
  827.     {
  828.       int phaseValue = 1;
  829.  
  830.       drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
  831.       _env->current_drawing_mode = DRAW_MODE_TRANS;
  832.       set_trans_blender (0, 0, 0, (int)50);
  833.       // avoid sub-index
  834.       if ( shPhase < 0 )
  835.         shPhase = 0;
  836.       if (sht >= ITEM_LGT_SHIELD && sht <= ITEM_HVY_SHIELD)
  837.         {
  838.           phaseValue = (int)(_global->slope[(int)shPhase][0] * 3);
  839.         }
  840.       else if (sht >= ITEM_LGT_REPULSOR_SHIELD && sht <= ITEM_HVY_REPULSOR_SHIELD)
  841.         {
  842.           phaseValue = (int)(shPhase / 360 * 6);
  843.         }
  844.  
  845.       ellipsefill (dest, (int) x, (int) y, TANKWIDTH + 6 + phaseValue, TANKHEIGHT - 1, shieldColor);
  846.       set_trans_blender (0, 0, 0, (int)
  847.                          (50 + (((float) sh / (float) (item[sht]).vals[SHIELD_ENERGY]) * (float) 150)));
  848.       for (int thicknessCount = 0; thicknessCount < shieldThickness; thicknessCount++)
  849.         {
  850.           ellipse (dest, (int) x - (shieldThickness / 2) + thicknessCount, (int) y,
  851.                    TANKWIDTH + 6 + phaseValue, TANKHEIGHT - 1, shieldColor);
  852.         }
  853.       drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
  854.       _env->current_drawing_mode = DRAW_MODE_SOLID;
  855.     }   // end of drawing shield
  856. */
  857.  
  858.   if (sh > 0)
  859.   {
  860.      int thickness = 2;
  861.      int counter;
  862.      int wobble = (int) shPhase;
  863.  
  864.      if ( (sht == ITEM_LGT_SHIELD) || (sht == ITEM_LGT_REPULSOR_SHIELD) )
  865.        thickness = 1;
  866.      else if ( (sht == ITEM_HVY_REPULSOR_SHIELD) || (sht == ITEM_HVY_SHIELD) )
  867.        thickness = 3;
  868.  
  869.      if (! shieldColor)        // client may not have set colour
  870.      {
  871.          shieldColor = makecol ((int)item[sht].vals[SHIELD_RED],
  872.                              (int)item[sht].vals[SHIELD_GREEN],
  873.                              (int)item[sht].vals[SHIELD_BLUE]);
  874.      }
  875.      for (counter = 0; counter < thickness; counter++)
  876.          circle(dest, (int) x, (int) y, 
  877.                 TANKHEIGHT + counter + wobble, shieldColor);
  878.   }
  879.  
  880.   draw_sprite (dest, (BITMAP *) _global->tank[use_tank_bitmap], (int) x - TANKWIDTH, (int) y);
  881.   turretAngle = (int) ((float) (90 - a) * ((float) 256 / (float) 360));
  882.   rotate_sprite (dest, (BITMAP *) _global->tankgun[use_turret_bitmap],
  883.                  (int) turret_x - GUNLENGTH, (int) turret_y - (GUNLENGTH - 2), itofix (turretAngle));
  884.  
  885.  
  886.   // when using rockets, show flame
  887.   if (yv < 0)
  888.   {
  889.       rectfill(dest, (int) x - TANKWIDTH, (int) y + TANKHEIGHT, x + TANKWIDTH, y + TANKHEIGHT + 10, makecol(250, 150, 0) );
  890.   }
  891.  
  892.   if (sh > 0)
  893.     setUpdateArea ((int)x - TANKWIDTH - 15, (int)y - TANKHEIGHT,
  894.                    ((TANKWIDTH + 15) * 2) + 1, (TANKHEIGHT * 2) + 20);
  895.   else
  896.     setUpdateArea ((int)x - GUNLENGTH - 1, (int)y - GUNLENGTH - 1,
  897.                    (GUNLENGTH * 2) + 2, TANKHEIGHT + GUNLENGTH + 20);
  898.   if (para)
  899.     {
  900.       draw_sprite (dest, (BITMAP *) _global->tank[para],
  901.                    (int) (x - TANKWIDTH) - 3, (int) y - 25);
  902.       addUpdateArea ((int)(x - TANKWIDTH) - 3, (int)y - 25, 35, 66);
  903.     }
  904.  
  905.   printHealth (healthOffset);
  906.   requireUpdate ();
  907. }
  908.  
  909. int TANK::get_heaviest_shield ()
  910. {
  911.   if (player->ni[ITEM_HVY_REPULSOR_SHIELD])
  912.     {
  913.       return ITEM_HVY_REPULSOR_SHIELD;
  914.     }
  915.   if (player->ni[ITEM_HVY_SHIELD])
  916.     {
  917.       return ITEM_HVY_SHIELD;
  918.     }
  919.   if (player->ni[ITEM_MED_REPULSOR_SHIELD])
  920.     {
  921.       return ITEM_MED_REPULSOR_SHIELD;
  922.     }
  923.   if (player->ni[ITEM_MED_SHIELD])
  924.     {
  925.       return ITEM_MED_SHIELD;
  926.     }
  927.   if (player->ni[ITEM_LGT_REPULSOR_SHIELD])
  928.     {
  929.       return ITEM_LGT_REPULSOR_SHIELD;
  930.     }
  931.   if (player->ni[ITEM_LGT_SHIELD])
  932.     {
  933.       return ITEM_LGT_SHIELD;
  934.     }
  935.   return ITEM_NO_SHIELD;
  936. }
  937.  
  938.  
  939.  
  940.  
  941. void TANK::simActivateCurrentSelection ()
  942. {
  943.   char buf[16];
  944.  
  945.   if (_global->turntype != TURN_SIMUL)
  946.     {
  947.       activateCurrentSelection();
  948.       if (fire_another_shot)
  949.         fire_another_shot--;
  950.     }
  951.   else
  952.     {
  953.       _env->stage = 1;
  954.     }
  955.  
  956.   // allow naturals to happen again
  957.   _env->naturals_since_last_shot = 0;
  958.  
  959.   // apply repairs
  960.   l += repair_rate;
  961.   if (l > maxLife)
  962.     l = maxLife;
  963.   sprintf (buf, "%d", l);
  964.   healthText->set_text(buf);
  965.  
  966.   // avoid having key presses read in next turn
  967.   clear_keybuf();
  968. }
  969.  
  970.  
  971.  
  972.  
  973. void TANK::activateCurrentSelection ()
  974. {
  975.   int z;
  976.  
  977.   // avoid firing weapons on exit in Windows
  978.   if ( (_global->command == GLOBAL_COMMAND_QUIT) ||
  979.        (_global->command == GLOBAL_COMMAND_MENU) )
  980.     return;
  981.  
  982.   // remove status from top bar at next redraw
  983.   if (_global->tank_status)
  984.       _global->tank_status[0] = 0;
  985.  
  986.   _env->time_to_fall--;
  987.   if (_env->time_to_fall < 0)
  988.     // _env->time_to_fall = (rand() % MAX_GRAVITY_DELAY) + 1;
  989.     _env->time_to_fall = (rand() % (int)_env->landSlideDelay) + 1;
  990.  
  991.   if (cw < WEAPONS)
  992.     {
  993.       player->changed_weapon = false;
  994.       if (cw)
  995.         player->nm[cw]--;
  996.  
  997.       _env->stage = 1;
  998.       _env->am = weapon[cw].spread;
  999.       _env->realm = _env->am;
  1000.  
  1001.       if (cw < BALLISTICS)
  1002.         {
  1003.           play_sample ((SAMPLE *) _global->sounds[weapon[cw].sound], 255, 128, 1000, 0);
  1004.           for (z = 0; z < _env->am; z++)
  1005.             {
  1006.               MISSILE *newmis;
  1007.               double mxv,myv;
  1008.               int ca;
  1009.  
  1010.               ca = a + ((SPREAD * z) - (SPREAD * (_env->am - 1) / 2));
  1011.               double dPower = (double)p;
  1012.               if ((dPower < 200.0) && ((cw == RIOT_CHARGE) || (cw == RIOT_BLAST)))
  1013.                 dPower = 200.0;
  1014.  
  1015.               mxv = _global->slope[ca][0] * dPower * (100.0 / _global->frames_per_second) / 100.0;
  1016.               myv = _global->slope[ca][1] * dPower * (100.0 / _global->frames_per_second) / 100.0;
  1017.  
  1018.               newmis = new MISSILE(_global, _env,
  1019.                                    turret_x + (_global->slope[ca][0] * GUNLENGTH) /*- mxv*/,
  1020.                                    turret_y + (_global->slope[ca][1] * GUNLENGTH) /*- myv*/,
  1021.                                    mxv, myv, cw);
  1022.               if (newmis)
  1023.               {
  1024.                 newmis->physics = 0;
  1025.                 newmis->age = 0;
  1026.                 newmis->player = player;
  1027.               }
  1028.               else
  1029.                   perror ( "tank.cc: Failed allocating memory for newmis in TANK::activateCurrentSelection");
  1030.               // set up volley
  1031.               if (! fire_another_shot)
  1032.                 {
  1033.                     fire_another_shot = weapon[cw].delay * VOLLY_DELAY;
  1034.                     if ( weapon[cw].delay )
  1035.                     {
  1036.                       shots_fired = shots_fired - (weapon[cw].delay - 1);
  1037.                     }
  1038.                 }
  1039.  
  1040.               if (player->ni[ITEM_DIMPLEP])
  1041.                 {
  1042.                   player->ni[ITEM_DIMPLEP]--;
  1043.                   newmis->drag *= item[ITEM_DIMPLEP].vals[0];
  1044.                 }
  1045.               else if (player->ni[ITEM_SLICKP])
  1046.                 {
  1047.                   player->ni[ITEM_SLICKP]--;
  1048.                   newmis->drag *= item[ITEM_SLICKP].vals[0];
  1049.                 }
  1050.             }
  1051.         }
  1052.       else          // BEAM weapon
  1053.         {
  1054.           play_sample ((SAMPLE *) _global->sounds[weapon[cw].sound], 255, 128, 1000, 0);
  1055.           for (z = 0; z < _env->am; z++)
  1056.             {
  1057.               BEAM *newbeam;
  1058.               int ca;
  1059.  
  1060.               ca = a + ((SPREAD * z) - (SPREAD * (_env->am - 1) / 2));
  1061.  
  1062.               newbeam = new BEAM (_global, _env,
  1063.                                   turret_x + (_global->slope[ca][0] * GUNLENGTH),
  1064.                                   turret_y + (_global->slope[ca][1] * GUNLENGTH),
  1065.                                   ca, cw);
  1066.               if (newbeam)
  1067.               {
  1068.                  newbeam->physics = 0;
  1069.                  newbeam->age = 0;
  1070.                  newbeam->player = player;
  1071.               }
  1072.               else
  1073.                   perror ( "tank.cc: Failed allocating memory for newbeam in TANK::activateCurrentSelection");
  1074.             }
  1075.  
  1076.         }
  1077.     }
  1078.   else           // activate an item
  1079.     {
  1080.       int itemNum = cw - WEAPONS;
  1081.       if (itemNum < ITEM_VENGEANCE || itemNum > ITEM_FATAL_FURY)
  1082.         player->ni[itemNum]--;
  1083.       _env->stage = 1;
  1084.       if (itemNum == ITEM_TELEPORT)
  1085.         {
  1086.           int teleXDest = (rand () % (_global->screenWidth - TANKWIDTH * 2)) + TANKWIDTH;
  1087.           int teleYDest = (rand () % (_global->screenHeight - TANKHEIGHT * 2)) + TANKHEIGHT;
  1088.           TELEPORT *teleport;
  1089.           creditTo = player;
  1090.           teleport = new TELEPORT (_global, _env, this, teleXDest, teleYDest, TANKHEIGHT * 4 + GUNLENGTH, 120);
  1091.           if (!teleport)
  1092.             {
  1093.               perror ( "tank.cc: Failed allocating memory for teleport in TANK::activateCurrentSelection");
  1094.               // exit (1);
  1095.             }
  1096.         }
  1097.       else if (itemNum == ITEM_SWAPPER)
  1098.         {
  1099.           int random_tank_number;
  1100.           TANK *other_tank;
  1101.           TELEPORT *my_teleport, *other_teleport;
  1102.  
  1103.           // pick a random tank (not us)
  1104.           random_tank_number = rand() % _global->numTanks;
  1105.           other_tank = _env->order[random_tank_number];
  1106.           while ( (! other_tank) || (other_tank == this) )
  1107.             {
  1108.               random_tank_number++;
  1109.               if (random_tank_number > _global->maxNumTanks)
  1110.                 random_tank_number = 0;
  1111.               other_tank = _env->order[random_tank_number];
  1112.             }
  1113.           creditTo = player;
  1114.           // create a teleport ojbect for this tank
  1115.           my_teleport = new TELEPORT (_global, _env, this, (int) other_tank->x, (int) other_tank->y, TANKHEIGHT * 4 + GUNLENGTH, 120);
  1116.           // create a teleport object for the other tank
  1117.           other_teleport = new TELEPORT (_global, _env, other_tank, (int) x, (int) y, TANKHEIGHT * 4 + GUNLENGTH, 120);
  1118.  
  1119.         }
  1120.       else if (itemNum == ITEM_MASS_TELEPORT)
  1121.       {
  1122.           TELEPORT *my_teleport;
  1123.           int count;
  1124.           int XDest, YDest;
  1125.           TANK *current_tank;
  1126.           
  1127.           for (count = 0; count < _global->numPlayers; count++)
  1128.           {
  1129.              current_tank = _global->players[count]->tank;
  1130.              if (current_tank)
  1131.              {
  1132.                 XDest = (rand () % (_global->screenWidth - TANKWIDTH * 2)) + TANKWIDTH;
  1133.                 YDest = (rand () % (_global->screenHeight - TANKHEIGHT * 2)) + TANKHEIGHT;
  1134.                 creditTo = player;
  1135.                 my_teleport = new TELEPORT(_global, _env, current_tank, XDest, YDest, TANKHEIGHT * 4 + GUNLENGTH, 120);
  1136.              }
  1137.           }
  1138.              
  1139.       }
  1140.  
  1141.       else if ( itemNum == ITEM_ROCKET )
  1142.       {
  1143.          yv = -10;
  1144.          y -= 10;
  1145.          if (a < 180)
  1146.          {
  1147.                xv += 0.3;
  1148.          }
  1149.          else if (a > 180)
  1150.          {
  1151.               xv -= 0.3;
  1152.          }
  1153.  
  1154.          applyPhysics(_global);
  1155.       }
  1156.  
  1157.       else if ( itemNum == ITEM_FAN )
  1158.         {
  1159.           // play wind sound
  1160.           play_sample ((SAMPLE *) _global->sounds[2], 255, 128, 1000, 0);
  1161.           if (a < 180)   // move wind to the right
  1162.             _env->wind += (p / 20);
  1163.           else     // wind to the left
  1164.             _env->wind -= (p / 20);
  1165.  
  1166.           // make sure wind is not too strong
  1167.           if (_env->wind < (-_env->windstrength / 2) )
  1168.             _env->wind = -_env->windstrength / 2;
  1169.           else if (_env->wind > (_env->windstrength / 2) )
  1170.             _env->wind = _env->windstrength / 2;
  1171.  
  1172.           _env->lastwind = _env->wind;
  1173.  
  1174.         }
  1175.       else if ((itemNum >= ITEM_VENGEANCE) &&
  1176.                (itemNum <= ITEM_FATAL_FURY))
  1177.         {
  1178.           creditTo = player;
  1179.           damage = l + sh;
  1180.         }
  1181.     }
  1182.  
  1183.   // if we are out of this type of weapon
  1184.   // then switch to another
  1185.   if (! player->nm[cw] )
  1186.     {
  1187.       cw = WEAPONS - 1;
  1188.       while ( (cw > 0) && (! player->nm[cw] ) )
  1189.         cw--;
  1190.       player->changed_weapon = true;
  1191.     }
  1192.  
  1193.   shots_fired++;
  1194.   player->time_left_to_fire = _global->max_fire_time;
  1195.  
  1196.   // if not performing a volly and the player is AI then randomly select next weapon
  1197.   // else if ( ( player->type > HUMAN_PLAYER ) && (! fire_another_shot) )
  1198.   //    cw = player->Select_Random_Weapon();
  1199.  
  1200. }
  1201.  
  1202.  
  1203. void TANK::boost_up_shield ()
  1204. {
  1205.   char buf[10];
  1206.   int s = get_heaviest_shield ();
  1207.  
  1208.   if ((s != ITEM_NO_SHIELD) && (player->ni[s] > 0))
  1209.     {
  1210.       player->ni[s]--;
  1211.       sh = (int)item[s].vals[SHIELD_ENERGY];
  1212.       repulsion = (int)item[s].vals[SHIELD_REPULSION];
  1213.       shieldColor = makecol ((int)item[s].vals[SHIELD_RED],
  1214.                              (int)item[s].vals[SHIELD_GREEN],
  1215.                              (int)item[s].vals[SHIELD_BLUE]);
  1216.       shieldThickness = (int)item[s].vals[SHIELD_THICKNESS];
  1217.       sht = s;
  1218.       ds = sht;
  1219.       player->last_shield_used = s;
  1220.     }
  1221.   if (sh)
  1222.     {
  1223.       sprintf (buf, "%d", sh);
  1224.       shieldText->set_text (buf);
  1225.     }
  1226.   else
  1227.     {
  1228.       shieldText->set_text ( "");
  1229.     }
  1230. }
  1231. void TANK::reactivate_shield ()
  1232. {
  1233.   if (!sh)          //if no shield remains, try to reload
  1234.     {
  1235.       boost_up_shield ();
  1236.     }
  1237. }
  1238.  
  1239. int TANK::howBuried ()
  1240. {
  1241.   int turrAngle;
  1242.   int buryCount = 0;
  1243.  
  1244.   for (turrAngle = 90; turrAngle < 270; turrAngle++)
  1245.     {
  1246.       if (getpixel (_env->terrain, (int)(x + (_global->slope[turrAngle][0] * GUNLENGTH)), (int)(y + (_global->slope[turrAngle][1] * GUNLENGTH))) != PINK)
  1247.         buryCount++;
  1248.     }
  1249.  
  1250.   return (buryCount);
  1251. }
  1252.  
  1253. int TANK::shootClearance (int targetAngle, int minimumClearance)
  1254. {
  1255.   int clearance = 2;
  1256.   int iXpos, iYpos;
  1257.   do
  1258.     {
  1259.       iXpos    =    (int)(x + (_global->slope[targetAngle][0] * (GUNLENGTH + clearance)));
  1260.       iYpos = (int)(y + (_global->slope[targetAngle][1] * (GUNLENGTH + clearance)));
  1261.       if ((iYpos <= MENUHEIGHT) || (iXpos <= 1) || (iXpos >= (_global->screenWidth - 2)))
  1262.         clearance = minimumClearance; // done it! There can't be dirt any more!
  1263.       else
  1264.         clearance++;
  1265.     }
  1266.   while ((clearance < minimumClearance) && (getpixel(_env->terrain, iXpos, iYpos) == PINK));
  1267.  
  1268.   // If we are going for a particular minimumClearance (< screenWidth), it is important whether we hit a wall
  1269.   if (minimumClearance < _global->screenWidth)
  1270.     {
  1271.       int iWall = _env->current_wallType;
  1272.       if (    _global->bIsBoxed && (iYpos <= MENUHEIGHT)
  1273.            &&((iWall == WALL_STEEL) || (iWall == WALL_WRAP)) )
  1274.         clearance = -1; // Wall hit on ceiling
  1275.       if (    ((iXpos <= 1) || (iXpos >= (_global->screenWidth - 2)))
  1276.            &&(iWall == WALL_STEEL)    )
  1277.         clearance = -1; // Wall hit on sides
  1278.     }
  1279.  
  1280.   return (clearance >= minimumClearance?1:0);
  1281. }
  1282.  
  1283. int TANK::isSubClass (int classNum)
  1284. {
  1285.   if (classNum == TANK_CLASS)
  1286.     return (TRUE);
  1287.   else
  1288.     return (FALSE);
  1289.   //return (PHYSICAL_OBJECT::isSubClass (classNum));
  1290. }
  1291.  
  1292.  
  1293.  
  1294. /*
  1295. This function checks to see if there is a tank directly below this
  1296. one. This is to determine if we landed on someone.
  1297. The function returns TRUE if we landed on another tank and
  1298. FALSE if we did not.
  1299. -- Jesse
  1300. */
  1301. int TANK::tank_on_tank( GLOBALDATA *global )
  1302. {
  1303.   int found_tank = FALSE;
  1304.   int player_count = 0;
  1305.   int delta_x, delta_y;
  1306.  
  1307.   while ( ( player_count < global->numPlayers ) && (! found_tank) )
  1308.     {
  1309.       // check to make sure this player is alive
  1310.       if ( global->players[player_count]->tank )
  1311.         {
  1312.           // make sure this isn't our own tank
  1313.           if ( ( global->players[player_count]->tank->x != x ) || (global->players[player_count]->tank->y != y ) )
  1314.             {
  1315.               // check to see if tanks are within TANK_WIDTH of each other's x
  1316.               delta_x = (int) (x - global->players[player_count]->tank->x);
  1317.               delta_y = (int) (y - global->players[player_count]->tank->y);
  1318.  
  1319.               if ( ( abs(delta_x) <= TANKWIDTH ) && ( (delta_y < 0) && (delta_y >= -TANKHEIGHT) ) )
  1320.                 found_tank = TRUE;
  1321.  
  1322.             }    // end of this is our own tank
  1323.         }
  1324.       player_count++;
  1325.     }
  1326.  
  1327.   return found_tank;
  1328. }
  1329.  
  1330.  
  1331.  
  1332. /*
  1333. This function figures out how many points a tank
  1334. will repair itself each turn. This is based
  1335. on the number of repair kits a player has.
  1336. The amount is returned as an int.
  1337. -- Jesse
  1338. */
  1339. int TANK::Get_Repair_Rate()
  1340. {
  1341.   int num_kits;
  1342.   int repair_units = 0;
  1343.   int increase_amount = 5;
  1344.  
  1345.   num_kits = player->ni[ITEM_REPAIRKIT];
  1346.   while (num_kits > 0)
  1347.     {
  1348.       repair_units += increase_amount;
  1349.       if (increase_amount > 1)
  1350.         increase_amount--;
  1351.       num_kits--;
  1352.     }
  1353.  
  1354.   return repair_units;
  1355. }
  1356.  
  1357.  
  1358.  
  1359. /*
  1360. This function tries to move the tank either
  1361. left or right one unit. The direction is passed
  1362. in.
  1363. The function returns TRUE if the tank is moved and
  1364. FALSE if something is in the way or the
  1365. tank cannot be moved for some reason.
  1366. -- Jesse
  1367. */
  1368. int TANK::Move_Tank(int direction)
  1369. {
  1370.   int pixel;
  1371.   int destination_x;
  1372.  
  1373.   // do we have fuel?
  1374.   if ( player->ni[ITEM_FUEL] < 1 )
  1375.     return FALSE;
  1376.  
  1377.   // see where we want to go
  1378.   if (direction == DIR_RIGHT)
  1379.     destination_x = (int) (x + TANKWIDTH - 2);
  1380.   else
  1381.     destination_x = (int) (x - (TANKWIDTH + 1) );
  1382.  
  1383.   if (_env->landType != LANDTYPE_NONE)
  1384.     {
  1385.       // check for something in the way
  1386.       pixel = getpixel (_env->terrain, destination_x, (int) (y + (TANKHEIGHT / 2)) );
  1387.       if (pixel != PINK)
  1388.         return FALSE;
  1389.     }
  1390.  
  1391.   // move tank
  1392.   if (direction == DIR_RIGHT)
  1393.     x++;
  1394.   else
  1395.     x--;
  1396.  
  1397.   player->ni[ITEM_FUEL]--;
  1398.  
  1399.   return TRUE;
  1400. }
  1401.  
  1402. void TANK::setEnvironment(ENVIRONMENT *env)
  1403. {
  1404.   if (!_env || (_env != env))
  1405.     {
  1406.       _env = env;
  1407.       _index = _env->addObject (this);
  1408.     }
  1409. }
  1410.  
  1411.  
  1412. /*
  1413. Give credit to the tank who killed us.
  1414. */
  1415. void TANK::Give_Credit(GLOBALDATA *global)
  1416. {
  1417.      if (creditTo)
  1418.      {
  1419.         // we shot ourselves
  1420.         if (creditTo == player)
  1421.            creditTo->money -= (int) global->scoreUnitSelfDestroy;
  1422.         else   // we were killed by someone else
  1423.            creditTo->money += (int) global->scoreUnitDestroyBonus;
  1424.  
  1425.         // avoid over-flow
  1426.         if (creditTo->money < 0)
  1427.             creditTo->money = 0;
  1428.         creditTo = NULL;
  1429.      }
  1430. }
  1431.  
  1432.