SourceForge: atanksaiupgrade/atanksaiupgrade: changeset 44:3957ea3fcb06
- Fixed TextEntryBox-Bug, Player Names can be edited multiple times again atanks-3.9-experimental
authoryamakuzure <yamakuzure@users.sourceforge.net>
Tue Sep 22 09:26:45 2009 +0200 (2 months ago)
branchatanks-3.9-experimental
changeset 443957ea3fcb06
parent 431212983e94b1
child 458216e8eee89f
- Fixed TextEntryBox-Bug, Player Names can be edited multiple times again
- Eventually came around to fix repulsor shields, they needed to be adapted to the new Tank HitBox System
- Made bots more watchful and stamped out some inconsitencies that sometimes lead to (very!) stupid bot decisions
- Bots no longer taunt when they a) use an alternative action or b) know they won't hit their target
src/atanks.cpp
src/explosion.cpp
src/files.cpp
src/player.cpp
src/player.h
src/tank.cpp
     1.1 --- a/src/atanks.cpp	Sun Sep 20 08:32:58 2009 +0200
     1.2 +++ b/src/atanks.cpp	Tue Sep 22 09:26:45 2009 +0200
     1.3 @@ -242,7 +242,7 @@
     1.4        rect (env->db, leftX, y - 2, rightX, y + fontHeight + 2, BLACK);
     1.5  
     1.6        textout_centre_ex (env->db, font, tempText, x, y, BLACK, -1);
     1.7 -      rectfill (env->db, x + (tWidth / 2) + 2, y, x + (tWidth / 2) + 10, y + text_height (font), (flashCount < 25)?WHITE:BLACK);
     1.8 +      rectfill (env->db, x + (tWidth / 2) + 2, y, x + (tWidth / 2) + 10, y + text_height (font), (flashCount < global->frames_per_second)?WHITE:BLACK);
     1.9        env->make_update (leftX - 2, y - 4, fontWidth * textLength + 4, fontHeight + 6);
    1.10        env->make_update (mouse_x, mouse_y, ((BITMAP *) (global->gfxData.M[0].dat))->w, ((BITMAP *) (global->gfxData.M[0].dat))->h);
    1.11        env->make_update (lx, ly, ((BITMAP *) (global->gfxData.M[0].dat))->w, ((BITMAP *) (global->gfxData.M[0].dat))->h);
    1.12 @@ -273,9 +273,9 @@
    1.13        else
    1.14          env->drawScreen();
    1.15        if (! (int)global->os_mouse) show_mouse (screen);
    1.16 -      rest (1);
    1.17 +      _SLEEP;
    1.18        flashCount++;
    1.19 -      flashCount = flashCount % 50;
    1.20 +      flashCount = flashCount % (int)(global->frames_per_second * 2);
    1.21      }
    1.22    if (KeyIsNotEq(KEY_ESC))
    1.23      strncpy (text, tempText, textLength);
    1.24 @@ -1893,9 +1893,9 @@
    1.25          {
    1.26  #ifdef DEBUG_SHOPPING
    1.27            if (iJediCount)
    1.28 -            printf( (char *)"The Jedi summed up a pool of %13d bucks!\n", iJediMoney);
    1.29 +            printf("The Jedi summed up a pool of %13d bucks!\n", iJediMoney);
    1.30            if (iSithCount)
    1.31 -            printf( (char *)"The Sith summed up a pool of %13d bucks!\n", iSithMoney);
    1.32 +            printf("The Sith summed up a pool of %13d bucks!\n", iSithMoney);
    1.33  #endif // DEBUG_SHOPPING
    1.34            if (iJediCount)
    1.35              iJediMoney = (int)(((double)iJediMoney * 0.95) / (double)iJediCount);
    1.36 @@ -1903,9 +1903,9 @@
    1.37              iSithMoney = (int)(((double)iSithMoney * 0.90) / (double)iSithCount);
    1.38  #ifdef DEBUG_SHOPPING
    1.39            if (iJediCount)
    1.40 -            printf( (char *)"Every Jedi will receive %10d credits out of the pool!\n", iJediMoney);
    1.41 +            printf("Every Jedi will receive %10d credits out of the pool!\n", iJediMoney);
    1.42            if (iSithCount)
    1.43 -            printf( (char *)"Every Sith will receive %10d credits out of the pool!\n", iSithMoney);
    1.44 +            printf("Every Sith will receive %10d credits out of the pool!\n", iSithMoney);
    1.45  #endif // DEBUG_SHOPPING
    1.46            for (z = 0; z < global->numPlayers; z++)
    1.47              {
    1.48 @@ -2181,18 +2181,18 @@
    1.49                        if (status)
    1.50                          {
    1.51                            performed_save_game = true;
    1.52 -                          snprintf(description, 64, (char *)"Saved \"%s\" Game.", global->game_name);
    1.53 +                          snprintf(description, 64, "Saved \"%s\" Game.", global->game_name);
    1.54                          }
    1.55                        else
    1.56                          {
    1.57                            performed_save_game = false;
    1.58 -                          strcpy(description, (char *)"Failed to save game.");
    1.59 +                          strcpy(description, "Failed to save game.");
    1.60                          }
    1.61                        draw_text_in_box (env, &area, description);
    1.62                      }
    1.63                    else if (iSaveCount >= global->frames_per_second)
    1.64                      {
    1.65 -                      snprintf(description, 64, (char *)"Game \"%s\" already saved!", global->game_name);
    1.66 +                      snprintf(description, 64, "Game \"%s\" already saved!", global->game_name);
    1.67                        draw_text_in_box (env, &area, description);
    1.68                      }
    1.69                  }
    1.70 @@ -2463,8 +2463,8 @@
    1.71        int iInterSum = 0; // The summed up interest
    1.72  #ifdef DEBUG_SHOPPING
    1.73        cout << endl << "======================================================" << endl;
    1.74 -      printf( (char *)"%2d.: %s enters the bank to get interest:\n", (z+1), global->players[z]->getName());
    1.75 -      printf( (char *)"     Starting Account: %10d\n", global->players[z]->money);
    1.76 +      printf("%2d.: %s enters the bank to get interest:\n", (z+1), global->players[z]->getName());
    1.77 +      printf("     Starting Account: %10d\n", global->players[z]->money);
    1.78        cout << "------------------------------------------------------" << endl;
    1.79  #endif // DEBUG_SHOPPING
    1.80        while (iMoney && (iLevel < 5))
    1.81 @@ -2480,24 +2480,24 @@
    1.82            iInterSum	+=	iInterest;
    1.83            iMoney		-=	iInterest / fIntPerc;
    1.84  #ifdef DEBUG_SHOPPING
    1.85 -          printf( (char *)"     Level %1d:  %8d credits are rated,\n", iLevel, (int)(iInterest / fIntPerc));
    1.86 -          printf( (char *)"     Interest: %8d credits. (%5.2f%%)\n", iInterest, (fIntPerc * 100));
    1.87 +          printf("     Level %1d:  %8d credits are rated,\n", iLevel, (int)(iInterest / fIntPerc));
    1.88 +          printf("     Interest: %8d credits. (%5.2f%%)\n", iInterest, (fIntPerc * 100));
    1.89  #endif // DEBUG_SHOPPING
    1.90            // To get rid of (possible) rounding errors, add a security check:
    1.91            if ((iMoney < (4 * iLevel)) || (iInterest < 1))
    1.92              iMoney = 0; // With less there won't be any more interest anyway!
    1.93  #ifdef DEBUG_SHOPPING
    1.94 -          printf( (char *)"     Unrated : %8d credits left.\n", iMoney);
    1.95 +          printf("     Unrated : %8d credits left.\n", iMoney);
    1.96  #endif // DEBUG_SHOPPING
    1.97          }
    1.98        // Now giv'em their money:
    1.99  #ifdef DEBUG_SHOPPING
   1.100 -      printf( (char *)"     Sum:      %8d credits.\n", iInterSum);
   1.101 +      printf("     Sum:      %8d credits.\n", iInterSum);
   1.102        cout << "------------------------------------------------------" << endl;
   1.103  #endif // DEBUG_SHOPPING
   1.104        global->players[z]->money += iInterSum;
   1.105  #ifdef DEBUG_SHOPPING
   1.106 -      printf( (char *)"     Final Account   : %10d\n", global->players[z]->money);
   1.107 +      printf("     Final Account   : %10d\n", global->players[z]->money);
   1.108        cout << "======================================================" << endl;
   1.109  #endif // DEBUG_SHOPPING
   1.110      }
   1.111 @@ -3664,7 +3664,7 @@
   1.112    status = Load_Weapons_Text(global);
   1.113    if (! status)
   1.114      {
   1.115 -      printf( (char *)"An error occured trying to read weapons file.\n");
   1.116 +      printf("An error occured trying to read weapons file.\n");
   1.117        exit(1);
   1.118      }
   1.119  
   1.120 @@ -3679,7 +3679,7 @@
   1.121            DIR * pDestDir;
   1.122            pDestDir = opendir(global->configDir);
   1.123            if (!pDestDir)
   1.124 -            printf( (char *)"An error has occured trying to set up Atomic Tank folders.\n");
   1.125 +            printf("An error has occured trying to set up Atomic Tank folders.\n");
   1.126            else
   1.127              {
   1.128                closedir(pDestDir);
   1.129 @@ -3690,7 +3690,7 @@
   1.130  
   1.131  
   1.132    memset(fullPath, '\0', sizeof(fullPath));
   1.133 -  snprintf(fullPath, sizeof(fullPath) - 1, (char *)"%s/atanks-config.txt", global->configDir);
   1.134 +  snprintf(fullPath, sizeof(fullPath) - 1, "%s/atanks-config.txt", global->configDir);
   1.135  
   1.136    configFile.open(fullPath);
   1.137    if (configFile.is_open())
   1.138 @@ -3862,7 +3862,7 @@
   1.139              {
   1.140                // make sure the game has a name
   1.141                if (! global->game_name[0])
   1.142 -                strcpy(global->game_name, (char *)"unnamed");
   1.143 +                strcpy(global->game_name, "unnamed");
   1.144  
   1.145                bStatus = game->newGame();
   1.146                assert(bStatus);
     2.1 --- a/src/explosion.cpp	Sun Sep 20 08:32:58 2009 +0200
     2.2 +++ b/src/explosion.cpp	Tue Sep 22 09:26:45 2009 +0200
     2.3 @@ -1,458 +1,458 @@
     2.4 -/*
     2.5 - * atanks - obliterate each other with oversize weapons
     2.6 - * Copyright (C) 2003  Thomas Hudson
     2.7 - *
     2.8 - * This program is free software; you can redistribute it and/or
     2.9 - * modify it under the terms of the GNU General Public License
    2.10 - * as published by the Free Software Foundation; either version 2
    2.11 - * of the License, or (at your option) any later version.
    2.12 - *
    2.13 - * This program is distributed in the hope that it will be useful,
    2.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.16 - * GNU General Public License for more details.
    2.17 - *
    2.18 - * You should have received a copy of the GNU General Public License
    2.19 - * along with this program; if not, write to the Free Software
    2.20 - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    2.21 - * */
    2.22 -
    2.23 -#include "environment.h"
    2.24 -#include "globaldata.h"
    2.25 -#include "explosion.h"
    2.26 -#include "missile.h"
    2.27 -#include "decor.h"
    2.28 -#include "tank.h"
    2.29 -#include "player.h"
    2.30 -
    2.31 -
    2.32 -EXPLOSION::~EXPLOSION ()
    2.33 -{
    2.34 -  _env->removeObject (this);
    2.35 -  weap    = NULL;
    2.36 -  _global = NULL;
    2.37 -  _env    = NULL;
    2.38 -}
    2.39 -
    2.40 -EXPLOSION::EXPLOSION (GLOBALDATA *global, ENVIRONMENT *env, double xpos, double ypos,
    2.41 -                      int weaponType, PLAYER * owner):PHYSICAL_OBJECT(global, env, owner),
    2.42 -    bIsDmgChecked(false),weap(NULL)
    2.43 -{
    2.44 -  drag = 0.95;
    2.45 -  mass = 3;
    2.46 -  a = 1;
    2.47 -  peaked = 0;
    2.48 -  exclock = 500;
    2.49 -  _index = _env->addObject (this);
    2.50 -  if (_index < 0)
    2.51 -    // env is full! delete this!
    2.52 -    delete(this);
    2.53 -  else
    2.54 -    {
    2.55 -      _align = LEFT;
    2.56 -      setPosToValues(xpos, ypos);
    2.57 -      type = weaponType;
    2.58 -      if (type < WEAPONS)
    2.59 -        weap = &weapon[type];
    2.60 -      else
    2.61 -        weap = &naturals[type - WEAPONS];
    2.62 -      radius = weap->radius;
    2.63 -      etime = weap->etime;
    2.64 -      damage = weap->damage;
    2.65 -      eframes = weap->eframes;
    2.66 -
    2.67 -      // make sure dirt appears on the screen, not above the playing area
    2.68 -      if ((type >= DIRT_BALL) && (type <= SUP_DIRT_BALL))
    2.69 -        {
    2.70 -          int iDirtCeiling = MENUHEIGHT + radius + 1;
    2.71 -          if (_global->bIsBoxed)
    2.72 -            iDirtCeiling++;
    2.73 -          if (iDrawY < iDirtCeiling)
    2.74 -            setPosToValues(iDrawX, iDirtCeiling);
    2.75 -        }
    2.76 -    }
    2.77 -}
    2.78 -
    2.79 -EXPLOSION::EXPLOSION (GLOBALDATA *global, ENVIRONMENT *env, double xpos, double ypos, double xvel, double yvel,
    2.80 -                      int weaponType, PLAYER * owner):PHYSICAL_OBJECT(global, env, owner),
    2.81 -    bIsDmgChecked(false),weap(NULL)
    2.82 -{
    2.83 -  initialise ();
    2.84 -  _index = _env->addObject (this);
    2.85 -  if (_index < 0)
    2.86 -    // env is full! delete this!
    2.87 -    delete(this);
    2.88 -  else
    2.89 -    {
    2.90 -      _align = LEFT;
    2.91 -      setPosToValues(xpos, ypos);
    2.92 -      xv = xvel;
    2.93 -      yv = yvel;
    2.94 -      angle = (int)(atan2(xv, yv) / PI * 180);
    2.95 -      while (angle < 0)
    2.96 -        angle += 360;
    2.97 -      while (angle > 360)
    2.98 -        angle -= 360;
    2.99 -
   2.100 -      type = weaponType;
   2.101 -      if (type < WEAPONS)
   2.102 -        weap = &weapon[type];
   2.103 -      else
   2.104 -        weap = &naturals[type - WEAPONS];
   2.105 -      radius = weap->radius;
   2.106 -      etime = weap->etime;
   2.107 -      damage = weap->damage;
   2.108 -      eframes = weap->eframes;
   2.109 -    }
   2.110 -}
   2.111 -
   2.112 -void EXPLOSION::initialise ()
   2.113 -{
   2.114 -  drag = 0.95;
   2.115 -  mass = 3;
   2.116 -  a = 1;
   2.117 -  peaked = 0;
   2.118 -  exclock = 500;
   2.119 -}
   2.120 -
   2.121 -bool EXPLOSION::applyPhysics ()
   2.122 -{
   2.123 -  if (type == NAPALM_JELLY)
   2.124 -    {
   2.125 -      if ((rand () % (int)(300.0 / (dFpsMul < 150.0 ? dFpsMul : 150.0))) == 0)
   2.126 -        {
   2.127 -          DECOR *decor;
   2.128 -          decor = new DECOR (_global, _env, dPosX, dPosY, xv, yv, radius / 2, DECOR_SMOKE);
   2.129 -          assert(decor);
   2.130 -// Right now it is no problem if DECOR can't be created, because env->objects isn't substituted by
   2.131 -// a dynamic approach yet. Rather kill/delete/free decor than anything else!
   2.132 -//          if (!decor)
   2.133 -//            {
   2.134 -//              cerr << "explosion.cc: Failed allocating memory for decor in applyPhysics" << endl;
   2.135 -//              exit (1);
   2.136 -//            }
   2.137 -        }
   2.138 -      // If the dirt below is falling away, napalm can fall, too:
   2.139 -      if (getpixel(_env->terrain, iDrawX, iDrawY + 1) == PINK)
   2.140 -        {
   2.141 -          //yv = dFpsMul;
   2.142 -          _env->make_update(iDrawX - (radius + 4), iDrawY - (radius + 4), (radius + 4) * 2, (radius + 4) * 2);
   2.143 -          PHYSICAL_OBJECT::applyPhysics();
   2.144 -        }
   2.145 -      else
   2.146 -        yv = 0.0;
   2.147 -    }
   2.148 -  return (hitSomething);
   2.149 -}
   2.150 -
   2.151 -
   2.152 -void EXPLOSION::explode ()
   2.153 -{
   2.154 -  int calcblow;
   2.155 -  double distance;
   2.156 -  int z;
   2.157 -  calcblow = 1;
   2.158 -
   2.159 -  if (peaked == 1 && a <= EXPLOSIONFRAMES + 1)
   2.160 -    {
   2.161 -      exclock += dFpsMul;
   2.162 -      if (exclock > weap->etime)
   2.163 -        {
   2.164 -          exclock = 0;
   2.165 -          a++;
   2.166 -          requireUpdate ();
   2.167 -        }
   2.168 -      if (a > EXPLOSIONFRAMES + 1)
   2.169 -        {
   2.170 -          destroy = true;
   2.171 -        }
   2.172 -    }
   2.173 -  if (a <= EXPLODEFRAMES + 1)
   2.174 -    {
   2.175 -      TANK *tank;
   2.176 -      if (!bIsDmgChecked)
   2.177 -        {
   2.178 -          // First time checks
   2.179 -          bIsDmgChecked = true;
   2.180 -          for (int index = 0; (tank = (TANK*)_env->getNextOfClass (TANK_CLASS, &index)) && tank; index++)
   2.181 -            {
   2.182 -              // is tank directly above explosion?
   2.183 -              if ((abs(iDrawX - tank->iDrawX) < radius) && ((iDrawY - tank->iDrawY) >= 0))
   2.184 -                tank->pOwner->setDamager(pOwner);
   2.185 -            }
   2.186 -
   2.187 -          if ((type <= TECTONIC) || (type >= WEAPONS))
   2.188 -            {
   2.189 -              for (int index = 0; (tank = (TANK*)_env->getNextOfClass (TANK_CLASS, &index)) && tank; index++)
   2.190 -                {
   2.191 -// substituted by TANK::isTankHit
   2.192 -//                  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.193 -//                    {
   2.194 -//                      double dXDistance = abs (dPosX - tank->dPosX);
   2.195 -//                      double dYDistance;
   2.196 -//                      if (dPosY > tank->dPosY)
   2.197 -//                        dYDistance     = abs (dPosY - tank->dPosY) - (TANKHEIGHT * (3.0 / 4.0)); // To include the bottom of the tank
   2.198 -//                      else
   2.199 -//                        dYDistance     = abs (dPosY - tank->dPosY) - (TANKHEIGHT * (3.0 / 8.0)); // The top has to be hit, but not only brushed
   2.200 -//
   2.201 -//                      if (dYDistance < 0) dYDistance = 0;
   2.202 -//
   2.203 -//                      if ( (dYDistance  <= (radius / 20))
   2.204 -//                           && (dXDistance  >= (TANKWIDTH / 2)))
   2.205 -//                        distance = FABSDISTANCE(dXDistance, dYDistance, 0, 0);
   2.206 -//                      else
   2.207 -//                        distance = 2 * radius; // clear outside the explosion!
   2.208 -//#ifdef DEBUG
   2.209 -//                      if ((dXDistance < (radius + TANKHEIGHT / 2)) && (dYDistance < 25))
   2.210 -//                        {
   2.211 -//                          cout << endl << "Shape: " << radius << " x " << (radius / 20) << endl;
   2.212 -//                          printf( (char *)"Tank  X = % 4d, Tank  Y = % 4d\n", tank->iDrawX, tank->iDrawY);
   2.213 -//                          printf( (char *)"Explo X = % 4d, Explo Y = % 4d\n", iDrawX, iDrawY);
   2.214 -//                          printf( (char *)"Dist  X = % 4d, Dist  Y = % 4d\n", (int)dXDistance, (int)dYDistance);
   2.215 -//                          cout << "Distance: " << distance << endl;
   2.216 -//                        }
   2.217 -//#endif // DEBUG
   2.218 -//                    }
   2.219 -//                  else
   2.220 -//                    distance = FABSDISTANCE(dPosX, dPosY, tank->dPosX, tank->dPosY);
   2.221 -
   2.222 -                  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.223 -                    {
   2.224 -                      tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_HOELLIPSE);
   2.225 -                      if (abs(iDrawX - tank->iDrawX) < (TANKWIDTH / 2))
   2.226 -                        distance = 2 * radius;
   2.227 -                    }
   2.228 -                  else if (type == DRILLER)
   2.229 -                    tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_VEELLIPSE);
   2.230 -                  else
   2.231 -                    tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_CIRCLE);
   2.232 -
   2.233 -                  if (distance <= (radius + TANKHEIGHT/2) && tank->l > 0)
   2.234 -                    {
   2.235 -                      _global->updateMenu = 1;
   2.236 -
   2.237 -                      if (pOwner)
   2.238 -                        tank->damage = (int) ((float) damage * ((float) 1 - ((abs (distance) / (float)radius) / 2)) * pOwner->damageMultiplier);
   2.239 -                      // player is not used in weather attacks
   2.240 -                      else
   2.241 -                        tank->damage = (int) (float) damage * ((float) 1 - ((abs (distance) / (float)radius) / 2));
   2.242 -                      tank->pOwner->setDamager(pOwner);
   2.243 -                      tank->applyDamage ();
   2.244 -                    }
   2.245 -                }
   2.246 -              if (type >= TREMOR && type <= TECTONIC)
   2.247 -                {
   2.248 -                  angle = (int)(atan2 (yv, xv) / PI * 180);
   2.249 -                  while (angle <   0.0) angle += 360.0;
   2.250 -                  while (angle > 360.0) angle -= 360.0;
   2.251 -                }
   2.252 -            }
   2.253 -        }
   2.254 -      exclock += dFpsMul;
   2.255 -      if (exclock > weap->etime)
   2.256 -        {
   2.257 -          exclock = 0;
   2.258 -          a++;
   2.259 -          requireUpdate ();
   2.260 -        }
   2.261 -      if (a >= EXPLODEFRAMES + 1 && !peaked)
   2.262 -        {
   2.263 -          calcblow = 0;
   2.264 -        }
   2.265 -    }
   2.266 -  if (!calcblow)
   2.267 -    {
   2.268 -      if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.269 -        {
   2.270 -          ellipsefill (_env->terrain, iDrawX, iDrawY, radius, radius / 20, PINK);
   2.271 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius / 20 + 1), (radius + 1) * 2, (radius / 20 + 1) * 2);
   2.272 -
   2.273 -        }
   2.274 -      else if (type == DRILLER)
   2.275 -        {
   2.276 -          ellipsefill (_env->terrain, iDrawX, iDrawY, radius / 20, radius, PINK);
   2.277 -          setUpdateArea( iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.278 -        }
   2.279 -      else if (type <= LAST_EXPLOSIVE || type >= WEAPONS)
   2.280 -        {
   2.281 -
   2.282 -          if (type != NAPALM_JELLY)
   2.283 -            {
   2.284 -              circlefill (_env->terrain, iDrawX, iDrawY, radius, PINK);
   2.285 -              setUpdateArea (iDrawX - radius, iDrawY - radius, (radius * 2) - 2, (radius * 2) - 2);
   2.286 -            }
   2.287 -        }
   2.288 -      else  if ((type >= RIOT_BOMB) && (type <= HVY_RIOT_BOMB))
   2.289 -        {
   2.290 -          circlefill (_env->terrain, iDrawX, iDrawY, radius, PINK);
   2.291 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.292 -        }
   2.293 -      else if ((type >= RIOT_CHARGE) && (type <= RIOT_BLAST))
   2.294 -        {
   2.295 -          double sx = dPosX - (SCT.sin(angle) * 15);
   2.296 -          double sy = dPosY - (SCT.cos(angle) * 15);
   2.297 -          triangle (_env->terrain,
   2.298 -                    (int)sx,
   2.299 -                    (int)sy,
   2.300 -                    (int)(sx + (SCT.sin(angle + 45) * radius)),
   2.301 -                    (int)(sy + (SCT.cos(angle + 45) * radius)),
   2.302 -                    (int)(sx + (SCT.sin(angle + 315) * radius)),
   2.303 -                    (int)(sy + (SCT.cos(angle + 315) * radius)), PINK);
   2.304 -          setUpdateArea ((int)sx - (radius + 1), (int)sy - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.305 -        }
   2.306 -      else if ((type >= DIRT_BALL) && (type <= SUP_DIRT_BALL))
   2.307 -        {
   2.308 -          BITMAP *tmp;		//for mixing
   2.309 -
   2.310 -          tmp = create_bitmap(radius * 2, radius * 2);
   2.311 -          clear_to_color(tmp, PINK);
   2.312 -          for (int count = 0; count < radius ; count++)
   2.313 -            {
   2.314 -              circle (tmp, radius, radius, count, (pOwner)?pOwner->color: WILDDIRT );
   2.315 -            }
   2.316 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.317 -
   2.318 -          //copy terrain over explosion
   2.319 -          masked_blit(_env->terrain, tmp, iDrawX - radius, iDrawY - radius, 0, 0, radius*2, radius*2);
   2.320 -
   2.321 -          //blit back exploded terrain
   2.322 -          masked_blit(tmp, _env->terrain, 0, 0,iDrawX - radius, iDrawY - radius, radius*2, radius*2);
   2.323 -
   2.324 -          destroy_bitmap(tmp);
   2.325 -        }
   2.326 -
   2.327 -      for (z = -1; z <= (_current.w + 2); z++)
   2.328 -        setSlideColumnDimensions (_global, _env, _current.x + z, true);
   2.329 -      calcblow = 1;
   2.330 -      peaked = 1;
   2.331 -      dispersing = 1;
   2.332 -    }
   2.333 -}
   2.334 -
   2.335 -void EXPLOSION::draw (BITMAP *dest)
   2.336 -{
   2.337 -  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.338 -    {
   2.339 -      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.340 -        {
   2.341 -          rotate_scaled_sprite (dest, (BITMAP *) _global->gfxData.flameFront[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2],
   2.342 -                                iDrawX - radius, iDrawY - (radius / 20), itofix (0), ftofix ((double) radius / 300));
   2.343 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius / 20 + 1), (radius + 1) * 2, (radius / 20 + 1) * 2);
   2.344 -        }
   2.345 -    }
   2.346 -  else if (type == DRILLER)
   2.347 -    {
   2.348 -      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.349 -        {
   2.350 -          rotate_scaled_sprite(dest, (BITMAP *) _global->gfxData.flameFront[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2], iDrawX - (radius), iDrawY - (radius / 20), itofix(192), ftofix(radius / 300));
   2.351 -          setUpdateArea( iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.352 -        }
   2.353 -    }
   2.354 -  else if (type == NAPALM_JELLY)
   2.355 -    {
   2.356 -      int blobSize = (int)(radius - ((double)a / EXPLOSIONFRAMES) * radius + 1);
   2.357 -      if (blobSize > radius) blobSize = radius;
   2.358 -      if (blobSize > 0)
   2.359 -        {
   2.360 -          int iTrans = (blobSize * 16) > 128 ? 128 : (blobSize * 16);
   2.361 -          drawing_mode (DRAW_MODE_TRANS, NULL, 0, 0);
   2.362 -          if (blobSize > 5)
   2.363 -            {
   2.364 -              // Outer Ring
   2.365 -              set_trans_blender (0, 0, 0, iTrans / 4);
   2.366 -              circle (dest, iDrawX, iDrawY, blobSize + 3, NAPALMRINGA);
   2.367 -            }
   2.368 -          if (blobSize > 3)
   2.369 -            {
   2.370 -              // Outer Ring
   2.371 -              set_trans_blender (0, 0, 0, iTrans / 2);
   2.372 -              circle (dest, iDrawX, iDrawY, blobSize + 2, NAPALMRINGB);
   2.373 -            }
   2.374 -          if (blobSize > 1)
   2.375 -            {
   2.376 -              // Inner Ring
   2.377 -              set_trans_blender (0, 0, 0, iTrans );
   2.378 -              circle (dest, iDrawX, iDrawY, blobSize + 1, NAPALMRINGA);
   2.379 -            }
   2.380 -          // The Blob Itself
   2.381 -          drawing_mode (DRAW_MODE_SOLID, NULL, 0, 0);
   2.382 -          circlefill (dest, iDrawX, iDrawY, blobSize, NAPALMJELLY);
   2.383 -        }
   2.384 -      setUpdateArea (iDrawX - (radius + 4), iDrawY - (radius + 4), (radius + 4) * 2, (radius + 4) * 2);
   2.385 -      // Blit back terrain:
   2.386 -      masked_blit(_env->terrain, dest,
   2.387 -                  iDrawX - (radius + 4), iDrawY - (radius + 4),
   2.388 -                  iDrawX - (radius + 4), iDrawY - (radius + 4),
   2.389 -                  (radius + 4) * 2 * 2, (radius + 4) * 2 * 2);
   2.390 -    }
   2.391 -  else if (type <= LAST_EXPLOSIVE || type >= WEAPONS)
   2.392 -    {
   2.393 -      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.394 -        {
   2.395 -          /*  - background needs to be cleard immediately to allow chain missiles to work
   2.396 -          		  (and horizontal spreads look *far* better, too! ;) )
   2.397 -          		Note: Shaped charges are always shot alone, and they live off their visual effect.
   2.398 -          					Adding the immediate destruction on them, too, would cut off some of the effect... */
   2.399 -          if	(a <= EXPLODEFRAMES)
   2.400 -            circlefill (_env->terrain, iDrawX, iDrawY, (int)((radius / EXPLODEFRAMES) * a), PINK);
   2.401 -          rotate_scaled_sprite(dest, (BITMAP *) _global->gfxData.explosions[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2],
   2.402 -                               iDrawX - radius, iDrawY - radius, itofix (0), ftofix ((double) radius / 107));
   2.403 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.404 -        }
   2.405 -    }
   2.406 -  else if ( (type <= TECTONIC) && (type >= TREMOR) )
   2.407 -    {
   2.408 -      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.409 -        {
   2.410 -          drawFracture (_global, _env, _env->terrain, &_current, iDrawX, iDrawY, angle, (int)(((double)a / EXPLODEFRAMES) * (radius / 4)), radius, 5, 0);
   2.411 -        }
   2.412 -    }
   2.413 -  else if ((type >= RIOT_BOMB) && (type <= HVY_RIOT_BOMB))
   2.414 -    {
   2.415 -      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.416 -        {
   2.417 -          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.418 -          circlefill (_env->terrain, iDrawX, iDrawY, startCirc, PINK);
   2.419 -          circle (dest, iDrawX, iDrawY, startCirc, pOwner->color);
   2.420 -          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.421 -        }
   2.422 -    }
   2.423 -  else if ((type >= RIOT_CHARGE) && (type <= RIOT_BLAST))
   2.424 -    {
   2.425 -      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.426 -        {
   2.427 -          double sx = dPosX - (SCT.sin(angle) * 15);
   2.428 -          double sy = dPosY - (SCT.cos(angle) * 15);
   2.429 -          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.430 -          triangle (dest, (int)sx, (int)sy,
   2.431 -                    (int)(sx + (SCT.sin(angle + 45) * startCirc)),
   2.432 -                    (int)(sy + (SCT.cos(angle + 45) * startCirc)),
   2.433 -                    (int)(sx + (SCT.sin(angle + 315)* startCirc)),
   2.434 -                    (int)(sy + (SCT.cos(angle + 315)* startCirc)), pOwner->color);
   2.435 -          setUpdateArea ((int)sx - (startCirc + 1), (int)sy - (startCirc + 1), (startCirc + 1) * 2, (startCirc + 1) * 2);
   2.436 -        }
   2.437 -    }
   2.438 -  else
   2.439 -    {
   2.440 -      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.441 -        {
   2.442 -          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.443 -          circlefill (dest, iDrawX, iDrawY, startCirc, (pOwner)?pOwner->color: WILDDIRT );
   2.444 -          startCirc += (radius / EXPLODEFRAMES) * 2;
   2.445 -          setUpdateArea (iDrawX - startCirc, iDrawY - startCirc, startCirc * 2, startCirc * 2);
   2.446 -          // Blit back terrain:
   2.447 -          masked_blit(_env->terrain, dest,
   2.448 -                      iDrawX - startCirc, iDrawY - startCirc,
   2.449 -                      iDrawX - startCirc, iDrawY - startCirc,
   2.450 -                      startCirc * 2, startCirc * 2);
   2.451 -        }
   2.452 -    }
   2.453 -}
   2.454 -
   2.455 -int EXPLOSION::isSubClass (int classNum)
   2.456 -{
   2.457 -  if (classNum == EXPLOSION_CLASS)
   2.458 -    return (TRUE);
   2.459 -  else
   2.460 -    return (FALSE);
   2.461 -}
   2.462 +/*
   2.463 + * atanks - obliterate each other with oversize weapons
   2.464 + * Copyright (C) 2003  Thomas Hudson
   2.465 + *
   2.466 + * This program is free software; you can redistribute it and/or
   2.467 + * modify it under the terms of the GNU General Public License
   2.468 + * as published by the Free Software Foundation; either version 2
   2.469 + * of the License, or (at your option) any later version.
   2.470 + *
   2.471 + * This program is distributed in the hope that it will be useful,
   2.472 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.473 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2.474 + * GNU General Public License for more details.
   2.475 + *
   2.476 + * You should have received a copy of the GNU General Public License
   2.477 + * along with this program; if not, write to the Free Software
   2.478 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   2.479 + * */
   2.480 +
   2.481 +#include "environment.h"
   2.482 +#include "globaldata.h"
   2.483 +#include "explosion.h"
   2.484 +#include "missile.h"
   2.485 +#include "decor.h"
   2.486 +#include "tank.h"
   2.487 +#include "player.h"
   2.488 +
   2.489 +
   2.490 +EXPLOSION::~EXPLOSION ()
   2.491 +{
   2.492 +  _env->removeObject (this);
   2.493 +  weap    = NULL;
   2.494 +  _global = NULL;
   2.495 +  _env    = NULL;
   2.496 +}
   2.497 +
   2.498 +EXPLOSION::EXPLOSION (GLOBALDATA *global, ENVIRONMENT *env, double xpos, double ypos,
   2.499 +                      int weaponType, PLAYER * owner):PHYSICAL_OBJECT(global, env, owner),
   2.500 +    bIsDmgChecked(false),weap(NULL)
   2.501 +{
   2.502 +  drag = 0.95;
   2.503 +  mass = 3;
   2.504 +  a = 1;
   2.505 +  peaked = 0;
   2.506 +  exclock = 500;
   2.507 +  _index = _env->addObject (this);
   2.508 +  if (_index < 0)
   2.509 +    // env is full! delete this!
   2.510 +    delete(this);
   2.511 +  else
   2.512 +    {
   2.513 +      _align = LEFT;
   2.514 +      setPosToValues(xpos, ypos);
   2.515 +      type = weaponType;
   2.516 +      if (type < WEAPONS)
   2.517 +        weap = &weapon[type];
   2.518 +      else
   2.519 +        weap = &naturals[type - WEAPONS];
   2.520 +      radius = weap->radius;
   2.521 +      etime = weap->etime;
   2.522 +      damage = weap->damage;
   2.523 +      eframes = weap->eframes;
   2.524 +
   2.525 +      // make sure dirt appears on the screen, not above the playing area
   2.526 +      if ((type >= DIRT_BALL) && (type <= SUP_DIRT_BALL))
   2.527 +        {
   2.528 +          int iDirtCeiling = MENUHEIGHT + radius + 1;
   2.529 +          if (_global->bIsBoxed)
   2.530 +            iDirtCeiling++;
   2.531 +          if (iDrawY < iDirtCeiling)
   2.532 +            setPosToValues(iDrawX, iDirtCeiling);
   2.533 +        }
   2.534 +    }
   2.535 +}
   2.536 +
   2.537 +EXPLOSION::EXPLOSION (GLOBALDATA *global, ENVIRONMENT *env, double xpos, double ypos, double xvel, double yvel,
   2.538 +                      int weaponType, PLAYER * owner):PHYSICAL_OBJECT(global, env, owner),
   2.539 +    bIsDmgChecked(false),weap(NULL)
   2.540 +{
   2.541 +  initialise ();
   2.542 +  _index = _env->addObject (this);
   2.543 +  if (_index < 0)
   2.544 +    // env is full! delete this!
   2.545 +    delete(this);
   2.546 +  else
   2.547 +    {
   2.548 +      _align = LEFT;
   2.549 +      setPosToValues(xpos, ypos);
   2.550 +      xv = xvel;
   2.551 +      yv = yvel;
   2.552 +      angle = (int)(atan2(xv, yv) / PI * 180);
   2.553 +      while (angle < 0)
   2.554 +        angle += 360;
   2.555 +      while (angle > 360)
   2.556 +        angle -= 360;
   2.557 +
   2.558 +      type = weaponType;
   2.559 +      if (type < WEAPONS)
   2.560 +        weap = &weapon[type];
   2.561 +      else
   2.562 +        weap = &naturals[type - WEAPONS];
   2.563 +      radius = weap->radius;
   2.564 +      etime = weap->etime;
   2.565 +      damage = weap->damage;
   2.566 +      eframes = weap->eframes;
   2.567 +    }
   2.568 +}
   2.569 +
   2.570 +void EXPLOSION::initialise ()
   2.571 +{
   2.572 +  drag = 0.95;
   2.573 +  mass = 3;
   2.574 +  a = 1;
   2.575 +  peaked = 0;
   2.576 +  exclock = 500;
   2.577 +}
   2.578 +
   2.579 +bool EXPLOSION::applyPhysics ()
   2.580 +{
   2.581 +  if (type == NAPALM_JELLY)
   2.582 +    {
   2.583 +      if ((rand () % (int)(300.0 / (dFpsMul < 150.0 ? dFpsMul : 150.0))) == 0)
   2.584 +        {
   2.585 +          DECOR *decor;
   2.586 +          decor = new DECOR (_global, _env, dPosX, dPosY, xv, yv, radius / 2, DECOR_SMOKE);
   2.587 +          assert(decor);
   2.588 +// Right now it is no problem if DECOR can't be created, because env->objects isn't substituted by
   2.589 +// a dynamic approach yet. Rather kill/delete/free decor than anything else!
   2.590 +//          if (!decor)
   2.591 +//            {
   2.592 +//              cerr << "explosion.cc: Failed allocating memory for decor in applyPhysics" << endl;
   2.593 +//              exit (1);
   2.594 +//            }
   2.595 +        }
   2.596 +      // If the dirt below is falling away, napalm can fall, too:
   2.597 +      if (getpixel(_env->terrain, iDrawX, iDrawY + 1) == PINK)
   2.598 +        {
   2.599 +          //yv = dFpsMul;
   2.600 +          _env->make_update(iDrawX - (radius + 4), iDrawY - (radius + 4), (radius + 4) * 2, (radius + 4) * 2);
   2.601 +          PHYSICAL_OBJECT::applyPhysics();
   2.602 +        }
   2.603 +      else
   2.604 +        yv = 0.0;
   2.605 +    }
   2.606 +  return (hitSomething);
   2.607 +}
   2.608 +
   2.609 +
   2.610 +void EXPLOSION::explode ()
   2.611 +{
   2.612 +  int calcblow;
   2.613 +  double distance;
   2.614 +  int z;
   2.615 +  calcblow = 1;
   2.616 +
   2.617 +  if (peaked == 1 && a <= EXPLOSIONFRAMES + 1)
   2.618 +    {
   2.619 +      exclock += dFpsMul;
   2.620 +      if (exclock > weap->etime)
   2.621 +        {
   2.622 +          exclock = 0;
   2.623 +          a++;
   2.624 +          requireUpdate ();
   2.625 +        }
   2.626 +      if (a > EXPLOSIONFRAMES + 1)
   2.627 +        {
   2.628 +          destroy = true;
   2.629 +        }
   2.630 +    }
   2.631 +  if (a <= EXPLODEFRAMES + 1)
   2.632 +    {
   2.633 +      TANK *tank;
   2.634 +      if (!bIsDmgChecked)
   2.635 +        {
   2.636 +          // First time checks
   2.637 +          bIsDmgChecked = true;
   2.638 +          for (int index = 0; (tank = (TANK*)_env->getNextOfClass (TANK_CLASS, &index)) && tank; index++)
   2.639 +            {
   2.640 +              // is tank directly above explosion?
   2.641 +              if ((abs(iDrawX - tank->iDrawX) < radius) && ((iDrawY - tank->iDrawY) >= 0))
   2.642 +                tank->pOwner->setDamager(pOwner);
   2.643 +            }
   2.644 +
   2.645 +          if ((type <= TECTONIC) || (type >= WEAPONS))
   2.646 +            {
   2.647 +              for (int index = 0; (tank = (TANK*)_env->getNextOfClass (TANK_CLASS, &index)) && tank; index++)
   2.648 +                {
   2.649 +// substituted by TANK::isTankHit
   2.650 +//                  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.651 +//                    {
   2.652 +//                      double dXDistance = abs (dPosX - tank->dPosX);
   2.653 +//                      double dYDistance;
   2.654 +//                      if (dPosY > tank->dPosY)
   2.655 +//                        dYDistance     = abs (dPosY - tank->dPosY) - (TANKHEIGHT * (3.0 / 4.0)); // To include the bottom of the tank
   2.656 +//                      else
   2.657 +//                        dYDistance     = abs (dPosY - tank->dPosY) - (TANKHEIGHT * (3.0 / 8.0)); // The top has to be hit, but not only brushed
   2.658 +//
   2.659 +//                      if (dYDistance < 0) dYDistance = 0;
   2.660 +//
   2.661 +//                      if ( (dYDistance  <= (radius / 20))
   2.662 +//                           && (dXDistance  >= (TANKWIDTH / 2)))
   2.663 +//                        distance = FABSDISTANCE(dXDistance, dYDistance, 0, 0);
   2.664 +//                      else
   2.665 +//                        distance = 2 * radius; // clear outside the explosion!
   2.666 +//#ifdef DEBUG
   2.667 +//                      if ((dXDistance < (radius + TANKHEIGHT / 2)) && (dYDistance < 25))
   2.668 +//                        {
   2.669 +//                          cout << endl << "Shape: " << radius << " x " << (radius / 20) << endl;
   2.670 +//                          printf("Tank  X = % 4d, Tank  Y = % 4d\n", tank->iDrawX, tank->iDrawY);
   2.671 +//                          printf("Explo X = % 4d, Explo Y = % 4d\n", iDrawX, iDrawY);
   2.672 +//                          printf("Dist  X = % 4d, Dist  Y = % 4d\n", (int)dXDistance, (int)dYDistance);
   2.673 +//                          cout << "Distance: " << distance << endl;
   2.674 +//                        }
   2.675 +//#endif // DEBUG
   2.676 +//                    }
   2.677 +//                  else
   2.678 +//                    distance = FABSDISTANCE(dPosX, dPosY, tank->dPosX, tank->dPosY);
   2.679 +
   2.680 +                  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.681 +                    {
   2.682 +                      tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_HOELLIPSE);
   2.683 +                      if (abs(iDrawX - tank->iDrawX) < (TANKWIDTH / 2))
   2.684 +                        distance = 2 * radius;
   2.685 +                    }
   2.686 +                  else if (type == DRILLER)
   2.687 +                    tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_VEELLIPSE);
   2.688 +                  else
   2.689 +                    tank->isTankHit(iDrawX, iDrawY, &distance, radius, EXPLO_CIRCLE);
   2.690 +
   2.691 +                  if (distance <= (radius + TANKHEIGHT/2) && tank->l > 0)
   2.692 +                    {
   2.693 +                      _global->updateMenu = 1;
   2.694 +
   2.695 +                      if (pOwner)
   2.696 +                        tank->damage = (int) ((float) damage * ((float) 1 - ((abs (distance) / (float)radius) / 2)) * pOwner->damageMultiplier);
   2.697 +                      // player is not used in weather attacks
   2.698 +                      else
   2.699 +                        tank->damage = (int) (float) damage * ((float) 1 - ((abs (distance) / (float)radius) / 2));
   2.700 +                      tank->pOwner->setDamager(pOwner);
   2.701 +                      tank->applyDamage ();
   2.702 +                    }
   2.703 +                }
   2.704 +              if (type >= TREMOR && type <= TECTONIC)
   2.705 +                {
   2.706 +                  angle = (int)(atan2 (yv, xv) / PI * 180);
   2.707 +                  while (angle <   0.0) angle += 360.0;
   2.708 +                  while (angle > 360.0) angle -= 360.0;
   2.709 +                }
   2.710 +            }
   2.711 +        }
   2.712 +      exclock += dFpsMul;
   2.713 +      if (exclock > weap->etime)
   2.714 +        {
   2.715 +          exclock = 0;
   2.716 +          a++;
   2.717 +          requireUpdate ();
   2.718 +        }
   2.719 +      if (a >= EXPLODEFRAMES + 1 && !peaked)
   2.720 +        {
   2.721 +          calcblow = 0;
   2.722 +        }
   2.723 +    }
   2.724 +  if (!calcblow)
   2.725 +    {
   2.726 +      if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.727 +        {
   2.728 +          ellipsefill (_env->terrain, iDrawX, iDrawY, radius, radius / 20, PINK);
   2.729 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius / 20 + 1), (radius + 1) * 2, (radius / 20 + 1) * 2);
   2.730 +
   2.731 +        }
   2.732 +      else if (type == DRILLER)
   2.733 +        {
   2.734 +          ellipsefill (_env->terrain, iDrawX, iDrawY, radius / 20, radius, PINK);
   2.735 +          setUpdateArea( iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.736 +        }
   2.737 +      else if (type <= LAST_EXPLOSIVE || type >= WEAPONS)
   2.738 +        {
   2.739 +
   2.740 +          if (type != NAPALM_JELLY)
   2.741 +            {
   2.742 +              circlefill (_env->terrain, iDrawX, iDrawY, radius, PINK);
   2.743 +              setUpdateArea (iDrawX - radius, iDrawY - radius, (radius * 2) - 2, (radius * 2) - 2);
   2.744 +            }
   2.745 +        }
   2.746 +      else  if ((type >= RIOT_BOMB) && (type <= HVY_RIOT_BOMB))
   2.747 +        {
   2.748 +          circlefill (_env->terrain, iDrawX, iDrawY, radius, PINK);
   2.749 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.750 +        }
   2.751 +      else if ((type >= RIOT_CHARGE) && (type <= RIOT_BLAST))
   2.752 +        {
   2.753 +          double sx = dPosX - (SCT.sin(angle) * 15);
   2.754 +          double sy = dPosY - (SCT.cos(angle) * 15);
   2.755 +          triangle (_env->terrain,
   2.756 +                    (int)sx,
   2.757 +                    (int)sy,
   2.758 +                    (int)(sx + (SCT.sin(angle + 45) * radius)),
   2.759 +                    (int)(sy + (SCT.cos(angle + 45) * radius)),
   2.760 +                    (int)(sx + (SCT.sin(angle + 315) * radius)),
   2.761 +                    (int)(sy + (SCT.cos(angle + 315) * radius)), PINK);
   2.762 +          setUpdateArea ((int)sx - (radius + 1), (int)sy - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.763 +        }
   2.764 +      else if ((type >= DIRT_BALL) && (type <= SUP_DIRT_BALL))
   2.765 +        {
   2.766 +          BITMAP *tmp;		//for mixing
   2.767 +
   2.768 +          tmp = create_bitmap(radius * 2, radius * 2);
   2.769 +          clear_to_color(tmp, PINK);
   2.770 +          for (int count = 0; count < radius ; count++)
   2.771 +            {
   2.772 +              circle (tmp, radius, radius, count, (pOwner)?pOwner->color: WILDDIRT );
   2.773 +            }
   2.774 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.775 +
   2.776 +          //copy terrain over explosion
   2.777 +          masked_blit(_env->terrain, tmp, iDrawX - radius, iDrawY - radius, 0, 0, radius*2, radius*2);
   2.778 +
   2.779 +          //blit back exploded terrain
   2.780 +          masked_blit(tmp, _env->terrain, 0, 0,iDrawX - radius, iDrawY - radius, radius*2, radius*2);
   2.781 +
   2.782 +          destroy_bitmap(tmp);
   2.783 +        }
   2.784 +
   2.785 +      for (z = -1; z <= (_current.w + 2); z++)
   2.786 +        setSlideColumnDimensions (_global, _env, _current.x + z, true);
   2.787 +      calcblow = 1;
   2.788 +      peaked = 1;
   2.789 +      dispersing = 1;
   2.790 +    }
   2.791 +}
   2.792 +
   2.793 +void EXPLOSION::draw (BITMAP *dest)
   2.794 +{
   2.795 +  if (type >= SHAPED_CHARGE && type <= CUTTER)
   2.796 +    {
   2.797 +      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.798 +        {
   2.799 +          rotate_scaled_sprite (dest, (BITMAP *) _global->gfxData.flameFront[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2],
   2.800 +                                iDrawX - radius, iDrawY - (radius / 20), itofix (0), ftofix ((double) radius / 300));
   2.801 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius / 20 + 1), (radius + 1) * 2, (radius / 20 + 1) * 2);
   2.802 +        }
   2.803 +    }
   2.804 +  else if (type == DRILLER)
   2.805 +    {
   2.806 +      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.807 +        {
   2.808 +          rotate_scaled_sprite(dest, (BITMAP *) _global->gfxData.flameFront[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2], iDrawX - (radius), iDrawY - (radius / 20), itofix(192), ftofix(radius / 300));
   2.809 +          setUpdateArea( iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.810 +        }
   2.811 +    }
   2.812 +  else if (type == NAPALM_JELLY)
   2.813 +    {
   2.814 +      int blobSize = (int)(radius - ((double)a / EXPLOSIONFRAMES) * radius + 1);
   2.815 +      if (blobSize > radius) blobSize = radius;
   2.816 +      if (blobSize > 0)
   2.817 +        {
   2.818 +          int iTrans = (blobSize * 16) > 128 ? 128 : (blobSize * 16);
   2.819 +          drawing_mode (DRAW_MODE_TRANS, NULL, 0, 0);
   2.820 +          if (blobSize > 5)
   2.821 +            {
   2.822 +              // Outer Ring
   2.823 +              set_trans_blender (0, 0, 0, iTrans / 4);
   2.824 +              circle (dest, iDrawX, iDrawY, blobSize + 3, NAPALMRINGA);
   2.825 +            }
   2.826 +          if (blobSize > 3)
   2.827 +            {
   2.828 +              // Outer Ring
   2.829 +              set_trans_blender (0, 0, 0, iTrans / 2);
   2.830 +              circle (dest, iDrawX, iDrawY, blobSize + 2, NAPALMRINGB);
   2.831 +            }
   2.832 +          if (blobSize > 1)
   2.833 +            {
   2.834 +              // Inner Ring
   2.835 +              set_trans_blender (0, 0, 0, iTrans );
   2.836 +              circle (dest, iDrawX, iDrawY, blobSize + 1, NAPALMRINGA);
   2.837 +            }
   2.838 +          // The Blob Itself
   2.839 +          drawing_mode (DRAW_MODE_SOLID, NULL, 0, 0);
   2.840 +          circlefill (dest, iDrawX, iDrawY, blobSize, NAPALMJELLY);
   2.841 +        }
   2.842 +      setUpdateArea (iDrawX - (radius + 4), iDrawY - (radius + 4), (radius + 4) * 2, (radius + 4) * 2);
   2.843 +      // Blit back terrain:
   2.844 +      masked_blit(_env->terrain, dest,
   2.845 +                  iDrawX - (radius + 4), iDrawY - (radius + 4),
   2.846 +                  iDrawX - (radius + 4), iDrawY - (radius + 4),
   2.847 +                  (radius + 4) * 2 * 2, (radius + 4) * 2 * 2);
   2.848 +    }
   2.849 +  else if (type <= LAST_EXPLOSIVE || type >= WEAPONS)
   2.850 +    {
   2.851 +      if (a > 1 && a <= EXPLOSIONFRAMES + 1)
   2.852 +        {
   2.853 +          /*  - background needs to be cleard immediately to allow chain missiles to work
   2.854 +          		  (and horizontal spreads look *far* better, too! ;) )
   2.855 +          		Note: Shaped charges are always shot alone, and they live off their visual effect.
   2.856 +          					Adding the immediate destruction on them, too, would cut off some of the effect... */
   2.857 +          if	(a <= EXPLODEFRAMES)
   2.858 +            circlefill (_env->terrain, iDrawX, iDrawY, (int)((radius / EXPLODEFRAMES) * a), PINK);
   2.859 +          rotate_scaled_sprite(dest, (BITMAP *) _global->gfxData.explosions[(a + (EXPLOSIONFRAMES * weap->eframes)) - 2],
   2.860 +                               iDrawX - radius, iDrawY - radius, itofix (0), ftofix ((double) radius / 107));
   2.861 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.862 +        }
   2.863 +    }
   2.864 +  else if ( (type <= TECTONIC) && (type >= TREMOR) )
   2.865 +    {
   2.866 +      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.867 +        {
   2.868 +          drawFracture (_global, _env, _env->terrain, &_current, iDrawX, iDrawY, angle, (int)(((double)a / EXPLODEFRAMES) * (radius / 4)), radius, 5, 0);
   2.869 +        }
   2.870 +    }
   2.871 +  else if ((type >= RIOT_BOMB) && (type <= HVY_RIOT_BOMB))
   2.872 +    {
   2.873 +      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.874 +        {
   2.875 +          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.876 +          circlefill (_env->terrain, iDrawX, iDrawY, startCirc, PINK);
   2.877 +          circle (dest, iDrawX, iDrawY, startCirc, pOwner->color);
   2.878 +          setUpdateArea (iDrawX - (radius + 1), iDrawY - (radius + 1), (radius + 1) * 2, (radius + 1) * 2);
   2.879 +        }
   2.880 +    }
   2.881 +  else if ((type >= RIOT_CHARGE) && (type <= RIOT_BLAST))
   2.882 +    {
   2.883 +      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.884 +        {
   2.885 +          double sx = dPosX - (SCT.sin(angle) * 15);
   2.886 +          double sy = dPosY - (SCT.cos(angle) * 15);
   2.887 +          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.888 +          triangle (dest, (int)sx, (int)sy,
   2.889 +                    (int)(sx + (SCT.sin(angle + 45) * startCirc)),
   2.890 +                    (int)(sy + (SCT.cos(angle + 45) * startCirc)),
   2.891 +                    (int)(sx + (SCT.sin(angle + 315)* startCirc)),
   2.892 +                    (int)(sy + (SCT.cos(angle + 315)* startCirc)), pOwner->color);
   2.893 +          setUpdateArea ((int)sx - (startCirc + 1), (int)sy - (startCirc + 1), (startCirc + 1) * 2, (startCirc + 1) * 2);
   2.894 +        }
   2.895 +    }
   2.896 +  else
   2.897 +    {
   2.898 +      if (a > 1 && a <= EXPLODEFRAMES + 1)
   2.899 +        {
   2.900 +          int startCirc = (radius / EXPLODEFRAMES) * a;
   2.901 +          circlefill (dest, iDrawX, iDrawY, startCirc, (pOwner)?pOwner->color: WILDDIRT );
   2.902 +          startCirc += (radius / EXPLODEFRAMES) * 2;
   2.903 +          setUpdateArea (iDrawX - startCirc, iDrawY - startCirc, startCirc * 2, startCirc * 2);
   2.904 +          // Blit back terrain:
   2.905 +          masked_blit(_env->terrain, dest,
   2.906 +                      iDrawX - startCirc, iDrawY - startCirc,
   2.907 +                      iDrawX - startCirc, iDrawY - startCirc,
   2.908 +                      startCirc * 2, startCirc * 2);
   2.909 +        }
   2.910 +    }
   2.911 +}
   2.912 +
   2.913 +int EXPLOSION::isSubClass (int classNum)
   2.914 +{
   2.915 +  if (classNum == EXPLOSION_CLASS)
   2.916 +    return (TRUE);
   2.917 +  else
   2.918 +    return (FALSE);
   2.919 +}
     3.1 --- a/src/files.cpp	Sun Sep 20 08:32:58 2009 +0200
     3.2 +++ b/src/files.cpp	Tue Sep 22 09:26:45 2009 +0200
     3.3 @@ -372,7 +372,7 @@
     3.4            if (status == -1)
     3.5              {
     3.6                // No, something is badly wrong!
     3.7 -              printf( (char *)"Error occured. Unable to create sub directory:\n\"%s\"", global->configDir);
     3.8 +              printf("Error occured. Unable to create sub directory:\n\"%s\"", global->configDir);
     3.9                bResult = false;
    3.10              }
    3.11          }
    3.12 @@ -542,6 +542,7 @@
    3.13    do { }
    3.14    while (mouse_b);
    3.15    clear_keybuf();
    3.16 +  iKeyPressed = 0;
    3.17  }
    3.18  
    3.19  
    3.20 @@ -563,7 +564,7 @@
    3.21    path_to_file = (char *) calloc( strlen(global->dataDir) + 32, sizeof(char) );
    3.22    if (! path_to_file)
    3.23      {
    3.24 -      printf( (char *)"Memory error occured while loading weapons.\n");
    3.25 +      printf("Memory error occured while loading weapons.\n");
    3.26        return FALSE;
    3.27      }
    3.28  
    3.29 @@ -582,7 +583,7 @@
    3.30    wfile = fopen(path_to_file, "r");
    3.31    if (! wfile)
    3.32      {
    3.33 -      printf( (char *)"Unable to open weapons file. (%s)\n", path_to_file);
    3.34 +      printf("Unable to open weapons file. (%s)\n", path_to_file);
    3.35        return FALSE;
    3.36      }
    3.37    // free memory
    3.38 @@ -724,8 +725,8 @@
    3.39                               &(item[item_count].selectable),// 3
    3.40                               &(item[item_count].techLevel), // 4
    3.41                               &(item[item_count].sound),     // 5
    3.42 -                             &(item[item_count].vals[0]),   // 6
    3.43 -                             &(item[item_count].vals[1]),   // 7
    3.44 +                             &(item[item_count].vals[0]),   // 6 (Shield Energy)
    3.45 +                             &(item[item_count].vals[1]),   // 7 (Shield Repuslion)
    3.46                               &(item[item_count].vals[2]),   // 8
    3.47                               &(item[item_count].vals[3]),   // 9
    3.48                               &(item[item_count].vals[4]),   //10
    3.49 @@ -785,7 +786,7 @@
    3.50      status = scandir(global->configDir, &my_list, Filter_File, alphasort);
    3.51      if (status < 0)
    3.52        {
    3.53 -        printf( (char *)"Error trying to find saved games.\n");
    3.54 +        printf("Error trying to find saved games.\n");
    3.55          return NULL;
    3.56        }
    3.57  
     4.1 --- a/src/player.cpp	Sun Sep 20 08:32:58 2009 +0200
     4.2 +++ b/src/player.cpp	Tue Sep 22 09:26:45 2009 +0200
     4.3 @@ -185,18 +185,19 @@
     4.4    if (iType > (int) DEADLY_PLAYER)
     4.5      iType  =  (int) DEADLY_PLAYER;
     4.6  
     4.7 -  sAIData.iRangeFindAttempts = (int)pow(iType + round((iType + 1) / 2), 2);  // Useless: 4  , Deadly: 64
     4.8 -  sAIData.iRetargetAttempts  = (int)(pow(iType, 2) + 2);      // Useless:  3  , Deadly: 27
     4.9 -  sAIData.dFocusRate         = ((double) iType * 2.0) / 10.0; // Useless:  0.2, Deadly:  1.0
    4.10 -  sAIData.iWeapPoolSize      = iType * 3;                     // Useless:  3  , Deadly: 15
    4.11 -  sAIData.dErrorMultiplier   = 4.0 * ((double)(DEADLY_PLAYER + 1 - iType) / ((double)sAIData.iRangeFindAttempts / (double)iType));
    4.12 -
    4.13 -  /* Type      iType  RFA  RTA   FR   EM
    4.14 -     Useless     1      4    3  0,2  2,0000
    4.15 -     Guesser     2     16    6  0,4  1,1034
    4.16 -     Rangefind   3     25   11  0,6  0,5455
    4.17 -     Targetter   4     49   18  0,8  0,2520
    4.18 -     Deadly      5     64   27  1,0  0,0917
    4.19 +  sAIData.dErrorMultiplier   = 2.5 / pow((double)iType, 2); // 2.50 - 0.10 (But 1.0 is max, set below)
    4.20 +  sAIData.dFocusRate         = (double)iType / (double)DEADLY_PLAYER; // 0.2 - 1.0
    4.21 +  sAIData.iRangeFindAttempts = (int)round(pow(iType * 2, 2) / ((int)DEADLY_PLAYER + 2 - iType)) + 4; // 5 - 54
    4.22 +  sAIData.iRetargetAttempts  = iType * 3; // 3 - 15
    4.23 +  sAIData.iWeapPoolSize      = iType * 3; // 3 - 15;
    4.24 +  if (sAIData.dErrorMultiplier > 1.0) sAIData.dErrorMultiplier = 1.0;
    4.25 +
    4.26 +  /* Type    Value  RFA  RTT  FR   EM
    4.27 +     Useless    1    5    3  0,2  1,00
    4.28 +     Guesser    2    7    6  0,4  0,63
    4.29 +     Rangefind  3   13    9  0,6  0,28
    4.30 +     Targetter  4   25   12  0,8  0,16
    4.31 +     Deadly     5   54   15  1,0  0,10
    4.32     */
    4.33  }
    4.34  
    4.35 @@ -871,9 +872,9 @@
    4.36  
    4.37  #ifdef DEBUG_AIDATA
    4.38        if (weapCount < WEAPONS)
    4.39 -        printf( (char *)"%23s (weapon): % 5d", weapon[weapCount].name, _weaponPreference[weapCount]);
    4.40 -      else
    4.41 -        printf( (char *)"%23s ( item ): % 5d", item[weapCount-WEAPONS].name, _weaponPreference[weapCount]);
    4.42 +        printf("%23s (weapon): % 5d", weapon[weapCount].name, _weaponPreference[weapCount]);
    4.43 +      else
    4.44 +        printf("%23s ( item ): % 5d", item[weapCount-WEAPONS].name, _weaponPreference[weapCount]);
    4.45        cout << endl;
    4.46  #endif // DEBUG_AIDATA
    4.47      }
    4.48 @@ -889,7 +890,7 @@
    4.49              {
    4.50                _weaponPreference[weapCount] = (int)((double)_weaponPreference[weapCount] * dWorth);
    4.51  #ifdef DEBUG_AIDATA
    4.52 -              printf( (char *)"%23s (weapon) amplified to: % 5d", weapon[weapCount].name, _weaponPreference[weapCount]);
    4.53 +              printf("%23s (weapon) amplified to: % 5d", weapon[weapCount].name, _weaponPreference[weapCount]);
    4.54                cout << endl;
    4.55  #endif // DEBUG_AIDATA
    4.56              }
    4.57 @@ -905,7 +906,7 @@
    4.58              {
    4.59                _weaponPreference[weapCount] = (int)((double)_weaponPreference[weapCount] * dWorth);
    4.60  #ifdef DEBUG_AIDATA
    4.61 -              printf( (char *)"%23s ( item ) amplified to: % 5d", item[weapCount-WEAPONS].name, _weaponPreference[weapCount]);
    4.62 +              printf("%23s ( item ) amplified to: % 5d", item[weapCount-WEAPONS].name, _weaponPreference[weapCount]);
    4.63                cout << endl;
    4.64  #endif // DEBUG_AIDATA
    4.65              }
    4.66 @@ -1529,8 +1530,8 @@
    4.67                    if (sAIData.pTankPool[i] == pTargetTank)
    4.68                      {
    4.69                        // Without this, the shield would be nearly useless!
    4.70 -                      xAccel *= (0.75 * sAIData.dFocusRate);
    4.71 -                      yAccel *= (0.75 * sAIData.dFocusRate);
    4.72 +                      xAccel *= sAIData.dFocusRate;
    4.73 +                      yAccel *= sAIData.dFocusRate;
    4.74                        // But the lesser bots wouldn't hit anything anymore if more than
    4.75                        // pTargetTank would be handled like that!
    4.76                      }
    4.77 @@ -1761,7 +1762,7 @@
    4.78                            double xAccel = dVelX, yAccel = dVelY;
    4.79                            sAIData.pTankPool[i]->repulse (dPosX + dVelX, dPosY + dVelY, &xAccel, &yAccel, tank->cw);
    4.80                            if (sAIData.pTankPool[i] == pTargetTank)
    4.81 -                            xAccel *= (0.75 * sAIData.dFocusRate);
    4.82 +                            xAccel *= sAIData.dFocusRate;
    4.83                            dVelX += xAccel;
    4.84                          }
    4.85                      }
    4.86 @@ -1816,8 +1817,8 @@
    4.87                        if (sAIData.pTankPool[i] == pTargetTank)
    4.88                          {
    4.89                            // Without this, the shield would be nearly useless!
    4.90 -                          xAccel *= (0.75 * sAIData.dFocusRate);
    4.91 -                          yAccel *= (0.75 * sAIData.dFocusRate);
    4.92 +                          xAccel *= sAIData.dFocusRate;
    4.93 +                          yAccel *= sAIData.dFocusRate;
    4.94                            // But the lesser bots wouldn't hit anything anymore if more
    4.95                            // than pTargetTank would be handled like that!
    4.96                          }
    4.97 @@ -2454,11 +2455,11 @@
    4.98        if (!aIsOneShot && (iSpreadCount > 1))
    4.99          {
   4.100            if (iSpreadCount == 2)
   4.101 -            printf( (char *)" (%3d ", iCalcAngle - 90);
   4.102 -          else
   4.103 -            printf( (char *)",%3d ", iCalcAngle - 90);
   4.104 +            printf(" (%3d ", iCalcAngle - 90);
   4.105 +          else
   4.106 +            printf(",%3d ", iCalcAngle - 90);
   4.107            if (iSpread == iSpreadCount)
   4.108 -            printf( (char *)"\b)");
   4.109 +            printf("\b)");
   4.110          }
   4.111  #endif // DEBUG_AIM
   4.112      }
   4.113 @@ -2489,7 +2490,7 @@
   4.114          {
   4.115            // Record the best found values in sAIData if possible and wanted
   4.116  #ifdef DEBUG_AIM
   4.117 -          printf( (char *)" New best Overshoot: %5d\n", iOvershoot);
   4.118 +          printf(" New best Overshoot: %5d\n", iOvershoot);
   4.119  #endif // DEBUG_AIM
   4.120            sAIData.iBestAngle     = iAngle;
   4.121            sAIData.iBestPower     = iPower;
   4.122 @@ -2502,10 +2503,10 @@
   4.123  #endif // DEBUG_AIM
   4.124  
   4.125        // Call for a fail if we did not succeed in having a better overshoot
   4.126 -      if (abs(abs(sAIData.iPrevOvershoot) - abs(sAIData.iCurrOvershoot)) < iCalcType)
   4.127 +      if (abs(abs(sAIData.iPrevOvershoot) - abs(sAIData.iCurrOvershoot)) < 2)
   4.128          {
   4.129            sAIData.iAimFailCount++;
   4.130 -          if (sAIData.iAimFailCount > (iCalcType + 1))
   4.131 +          if (sAIData.iAimFailCount > (2 * (iCalcType + 1)))
   4.132              {
   4.133                sAIData.iAimingRound = sAIData.iRangeFindAttempts;
   4.134  #ifdef DEBUG_AIM
   4.135 @@ -2922,18 +2923,21 @@
   4.136        if (sAIData.iAimingRound >= sAIData.iRangeFindAttempts)
   4.137          {
   4.138            // rangefind had its goes, so see what we can change now:
   4.139 -          if (sAIData.iAimFailCount > (iCalcType + 1))
   4.140 +          if (sAIData.iAimFailCount > (2 * (iCalcType + 1)))
   4.141              {
   4.142                // rangeFind has given up, so start completely different!
   4.143 -              int iAngleRange = 180;
   4.144 +              int iAngleRange = 70;
   4.145 +
   4.146                if (_env->current_wallType == WALL_STEEL)
   4.147 -                iAngleRange /= 2;
   4.148 +                iAngleRange = 50; // Not too steep, please!
   4.149 +
   4.150                if (sAIData.dTargetX > tank->iDrawX)
   4.151                  // shoot basically to the right:
   4.152 -                iRawAngle = 90 + (rand() % iAngleRange);
   4.153 +                iRawAngle = RNG.random(100, 100 + iAngleRange);
   4.154                else
   4.155                  // shoot basically to the left:
   4.156 -                iRawAngle = 270 - (rand() % iAngleRange);
   4.157 +                iRawAngle = RNG.random(260, 260 - iAngleRange);
   4.158 +
   4.159                sAIData.iCurrAngle = (sAIData.iCurrAngle + iRawAngle) / 2;
   4.160                sAIData.iCurrPower = (sAIData.iCurrPower + (rand() % (MAX_POWER / 2))) / 2;
   4.161  #ifdef DEBUG_AIM
   4.162 @@ -2979,7 +2983,7 @@
   4.163    double angle;
   4.164  
   4.165    angle = atan2 ((double)dx, (double)dy) / PI * 180;
   4.166 -  angle += RNG.random(-10.0, 10.0) * sAIData.dErrorMultiplier; // changed, it was a bit large!
   4.167 +  angle += RNG.random(-10.0, 10.0) * sAIData.dErrorMultiplier;
   4.168  
   4.169    if (angle < 0)
   4.170      angle = angle + 360;
   4.171 @@ -4244,11 +4248,10 @@
   4.172                    // If we are too short, we might be able to "break through"
   4.173                    if ( (sAIData.iHitDistance < 0)
   4.174                         &&(abs(sAIData.iBestOvershoot) > iRadius)
   4.175 -                       &&(rand() % (iCalcType + 1)))
   4.176 -                    {
   4.177 -                      checkShootingPath();
   4.178 -                      iRadius *= 2;
   4.179 -                    }
   4.180 +                       &&(rand() % (iCalcType + 1))
   4.181 +                       &&checkShootingPath() )
   4.182 +                    iRadius *= 2;
   4.183 +
   4.184                    // Now see whether we are satisfied...
   4.185                    if ( (abs(sAIData.iHitDistance) < (iRadius + (iRadius / iCalcType)))
   4.186                         ||(abs(sAIData.iBestOvershoot) < iRadius)
   4.187 @@ -4275,10 +4278,16 @@
   4.188                        // Every Bot has a chance to have a critical success on a d20 with their skill level:
   4.189                        if (RNG.random(1, 20) > iCalcType)
   4.190                          applyErrorMod(); // Nice... a bit like AD&D, isn't it?
   4.191 +#ifdef DEBUG_AIM
   4.192 +                      else
   4.193 +                        cout << "Error-Adjusting: CRITICAL HIT!" << endl;
   4.194 +#endif // DEBUG_AIM
   4.195  
   4.196                        // Last one: if we are revenging, tell em!
   4.197 -                      if  ( (tank->cw < WEAPONS)                          // Wepaon selected?
   4.198 +                      if  ( !sAIData.bIsAlternate                         // Never taunt on alternative actions!
   4.199 +                            &&(tank->cw < WEAPONS)                        // Wepaon selected?
   4.200                              &&(weapon[tank->cw].damage > 1)               // One that delivers damage?
   4.201 +                            &&(abs(sAIData.iHitDistance) < (iRadius + (iRadius / iCalcType))) // And is hitting?
   4.202                              && pTargetTank                                // We have shot at a target ...
   4.203                              &&(pTargetTank != tank)                       // ...that is not our own tank?
   4.204                              &&(sAIData.pRevengeTo == pTargetTank->pOwner) // And the target is our revengee?
   4.205 @@ -4822,22 +4831,12 @@
   4.206    */
   4.207  void PLAYER::applyErrorMod()
   4.208  {
   4.209 -  int iCalcType = (int)type;
   4.210 -
   4.211 -  if (iCalcType < (int)USELESS_PLAYER) iCalcType = (int)USELESS_PLAYER;
   4.212 -  if (iCalcType > (int)DEADLY_PLAYER ) iCalcType = (int)DEADLY_PLAYER;
   4.213 -
   4.214    if (abs(sAIData.iBestOvershoot) <= sAIData.iOvershootLimit)
   4.215      {
   4.216        // We are hitting okay, so apply (possible) errors:
   4.217 -// substituted witrh RNG.random()
   4.218 -//      int iErrorMod = (int)DEADLY_PLAYER - iCalcType + 2; // Useless: 6, Deadly: 2
   4.219 -//      int iAngleMod =      (rand() % iErrorMod);          // Useless: 0 -  5, Deadly: 0 -  1
   4.220 -//      int iPowerMod = 10 * (rand() % iErrorMod);          // Useless: 0 - 50, Deadly: 0 - 10
   4.221 -      int iErrorMod = 2 * ((int)DEADLY_PLAYER - iCalcType + 1); // Useless: 10, Deadly: 2
   4.222 -      int iAngleMod = (RNG.random( 2, iErrorMod) / 2) - 1;       // Useless: 0 -  4, Deadly: 0
   4.223 -      int iPowerMod = (RNG.random(10, iErrorMod * 10) / 2) - 5;  // Useless: 0 - 95, Deadly: 0 - 15
   4.224 -      // With the * 2 Errormod and /2 Angle/PowerMod, the maximum error has only halve the normal chance
   4.225 +      int iAngleMod = (int)round(RNG.random( 10) * sAIData.dErrorMultiplier); // Useless Max  10, Deadly Max  1
   4.226 +      int iPowerMod = (int)round(RNG.random(100) * sAIData.dErrorMultiplier); // Useless Max 100, Deadly Max 10
   4.227 +
   4.228        // 25 % to get a flattening anglemod (aka nearing to the ground)
   4.229        if (!(rand() % 4))
   4.230          iAngleMod *= -1;
   4.231 @@ -4873,7 +4872,7 @@
   4.232  
   4.233  
   4.234  #ifdef DEBUG_AIM
   4.235 -      printf( (char *)"Error-Adjusting: Angle %3d Power %4d\n", iAngleMod, iPowerMod);
   4.236 +      printf("Error-Adjusting: Angle %3d Power %4d\n", iAngleMod, iPowerMod);
   4.237  #endif // DEBUG_AIM
   4.238  
   4.239      }
   4.240 @@ -5079,7 +5078,7 @@
   4.241    for ( i = 0; i < sAIData.iWeapPoolSize; i++)
   4.242      {
   4.243        cout << i << ".: ";
   4.244 -      printf( (char *)"% 5d Pref - ", _weaponPreference[sAIData.iWeaponPool[i]]);
   4.245 +      printf("% 5d Pref - ", _weaponPreference[sAIData.iWeaponPool[i]]);
   4.246        if (sAIData.iWeaponPool[i] < WEAPONS)
   4.247          cout << "\"" << weapon[sAIData.iWeaponPool[i]].name << "\"" << endl;
   4.248        else
   4.249 @@ -5334,7 +5333,7 @@
   4.250    *
   4.251    * @todo: document this function
   4.252    */
   4.253 -void PLAYER::checkShootingPath()
   4.254 +bool PLAYER::checkShootingPath()
   4.255  {
   4.256    int  iLeft       = 1;
   4.257    int  iRight      = _global->screenWidth - 2;
   4.258 @@ -5447,19 +5446,72 @@
   4.259            sAIData.iBestWeapon = TECTONIC;
   4.260          }
   4.261      }
   4.262 -
   4.263 -  // Test 3: See whether we can free the path with riot bombs:
   4.264 +  // Test 3: See whether we can free the shooting path with flipped angle
   4.265 +  if (!bIsFinished)
   4.266 +    {
   4.267 +      int iModAngle = 180 + (180 - sAIData.iBestAngle); // flip angle
   4.268 +
   4.269 +      if (iModAngle <= 180)
   4.270 +        {
   4.271 +          // Test for shooting to the right
   4.272 +          if ( (!tank->shootClearance(iModAngle - iAngleMod, weapon[RIOT_BLAST].radius - iAngleMod))
   4.273 +             &&nm[RIOT_BLAST])
   4.274 +            {
   4.275 +              bIsFinished = true;
   4.276 +              sAIData.iBestWeapon = RIOT_BLAST;
   4.277 +            }
   4.278 +          else if ( (!tank->shootClearance(iModAngle - iAngleMod, weapon[RIOT_CHARGE].radius - iAngleMod))
   4.279 +                  &&nm[RIOT_CHARGE])
   4.280 +            {
   4.281 +              bIsFinished = true;
   4.282 +              sAIData.iBestWeapon = RIOT_CHARGE;
   4.283 +            }
   4.284 +          // If we had success with this idea, the angle needs to be modified:
   4.285 +          if (bIsFinished)
   4.286 +            {
   4.287 +              sAIData.iBestAngle = iModAngle - iAngleMod;
   4.288 +              if (sAIData.iBestAngle < 90)
   4.289 +                sAIData.iBestAngle = 90;
   4.290 +            }
   4.291 +        }
   4.292 +      else
   4.293 +        {
   4.294 +          // Test for shooting to the left
   4.295 +          if ( (!tank->shootClearance(iModAngle + iAngleMod, weapon[RIOT_BLAST].radius - iAngleMod))
   4.296 +             &&nm[RIOT_BLAST])
   4.297 +            {
   4.298 +              bIsFinished = true;
   4.299 +              sAIData.iBestWeapon = RIOT_BLAST;
   4.300 +            }
   4.301 +          else if ( (!tank->shootClearance(iModAngle + iAngleMod, weapon[RIOT_CHARGE].radius - iAngleMod))
   4.302 +                  &&nm[RIOT_CHARGE])
   4.303 +            {
   4.304 +              bIsFinished = true;
   4.305 +              sAIData.iBestWeapon = RIOT_CHARGE;
   4.306 +            }
   4.307 +          // If we had success with this idea, the angle needs to be modified:
   4.308 +          if (bIsFinished)
   4.309 +            {
   4.310 +              sAIData.iBestAngle = iModAngle + iAngleMod;
   4.311 +              if (sAIData.iBestAngle > 270)
   4.312 +                sAIData.iBestAngle = 270;
   4.313 +            }
   4.314 +        }
   4.315 +    }
   4.316 +
   4.317 +  // Test 4: See whether we can free the path with riot bombs:
   4.318    if (!bIsFinished)
   4.319      {
   4.320        // Nope, we had no success... Look for blasting the way free with riot bombs
   4.321        if ( (iHitLevel > (iTgtLevel + weapon[RIOT_BOMB].radius))
   4.322 -           &&nm[HVY_RIOT_BOMB])
   4.323 +           &&nm[HVY_RIOT_BOMB]
   4.324 +           &&(iHitDist < weapon[HVY_RIOT_BOMB].radius) )
   4.325          {
   4.326            bIsFinished = true;
   4.327            sAIData.iBestWeapon = HVY_RIOT_BOMB;
   4.328          }
   4.329        else if ( (iHitLevel <= (iTgtLevel + weapon[RIOT_BOMB].radius))
   4.330 -                &&nm[RIOT_BOMB])
   4.331 +              &&(iHitDist < weapon[RIOT_BOMB].radius) )
   4.332          {
   4.333            bIsFinished = true;
   4.334            sAIData.iBestWeapon = RIOT_BOMB;
   4.335 @@ -5469,6 +5521,8 @@
   4.336    // Apply new best weapon if successful above
   4.337    if (bIsFinished)
   4.338      tank->cw = sAIData.iBestWeapon;
   4.339 +
   4.340 +  return(bIsFinished);
   4.341  }
   4.342  
   4.343  
     5.1 --- a/src/player.h	Sun Sep 20 08:32:58 2009 +0200
     5.2 +++ b/src/player.h	Tue Sep 22 09:26:45 2009 +0200
     5.3 @@ -186,7 +186,7 @@
     5.4      inline bool AIStageFireWeapon() _PWX_WARNUNUSED _PWX_FORCEINLINE;        //!< erm... obvious, too, isn't it?
     5.5      inline void applyErrorMod() _PWX_FORCEINLINE;                            //!< Mod iBestAngle/Power to be somewhat wrong
     5.6      inline void calculateAttackValues(bool aAllowFlip) _PWX_FORCEINLINE;     //!< set up basic angle/power values
     5.7 -    inline void checkShootingPath() _PWX_FORCEINLINE;                        //!< reverts to freeing methods if the path is blocked
     5.8 +    inline bool checkShootingPath() _PWX_WARNUNUSED _PWX_FORCEINLINE;        //!< reverts to freeing methods if the path is blocked
     5.9      inline void checkTankPool() _PWX_FORCEINLINE;                            //!< ensures pTankPool safety
    5.10      inline bool hasAntiDirtWeapon() _PWX_WARNUNUSED;                         //!< returns true if the bot has a weapon in the pool that can be fired when buried
    5.11      inline void setAdjustedTargetX() _PWX_FORCEINLINE;                       //!< varies sAIData.dTargetX according to tank->cw
     6.1 --- a/src/tank.cpp	Sun Sep 20 08:32:58 2009 +0200
     6.2 +++ b/src/tank.cpp	Tue Sep 22 09:26:45 2009 +0200
     6.3 @@ -585,36 +585,72 @@
     6.4  
     6.5  void TANK::repulse (double xpos, double ypos, double *xaccel, double *yaccel, int aWeaponType)
     6.6  {
     6.7 -  double xdist = xpos - dPosX;
     6.8 -  double ydist = ypos - dPosY;
     6.9 -  double dVelX = *xaccel;
    6.10 -  double dVelY = *yaccel;
    6.11 +  double dVelX  = *xaccel;
    6.12 +  double dVelY  = *yaccel;
    6.13 +  double dXDist = 0.0;
    6.14 +  double dYDist = 0.0;
    6.15 +  double dXAcc  = 0.0;
    6.16 +  double dYAcc  = 0.0;
    6.17  
    6.18    *xaccel = 0.0;
    6.19    *yaccel = 0.0;
    6.20  
    6.21    if (repulsion != 0)
    6.22      {
    6.23 -      if ((xdist < 0.075) && (xdist > -0.075)) xdist = 0.075;
    6.24 -      if ((ydist < 0.025) && (ydist > -0.025)) ydist = 0.025;
    6.25 +      if (xpos <= iBoxLeft)        dXDist = FABSDISTANCE(iBoxLeft  + 1, 0, xpos, 0);
    6.26 +      else if (xpos >= iBoxRight)  dXDist = FABSDISTANCE(iBoxRight - 1, 0, xpos, 0);
    6.27 +      if (ypos <= iBoxTop)         dYDist = FABSDISTANCE(0, iBoxTop    + 1, 0, ypos);
    6.28 +      else if (ypos >= iBoxBottom) dYDist = FABSDISTANCE(0, iBoxBottom - 1, 0, ypos);
    6.29 +      if (dXDist < 0.75) dXDist = 0.0;
    6.30 +      if (dYDist < 0.25) dYDist = 0.0;
    6.31 +      if ((dXDist > 0.0) || (dYDist > 0.0))
    6.32 +        {
    6.33 +          if (xpos < dPosX) dXDist *= -1.0;
    6.34 +          if (ypos < dPosY) dYDist *= -1.0;
    6.35  
    6.36 -      double distance2 = (xdist * xdist) + (ydist * ydist);
    6.37 -      double distance = sqrt (distance2);
    6.38 +          double distance2 = (dXDist * dXDist) + (dYDist * dYDist);
    6.39 +          double distance = sqrt (distance2);
    6.40  
    6.41 -      if (distance < (60.0 + sqrt ((double)repulsion)))
    6.42 -        {
    6.43 -          // no dFpsMul mod here, because PLAYER::traceShellTrajectory() needs clean values
    6.44 -          *xaccel = repulsion * (xdist / distance) / distance2;
    6.45 -          *yaccel = repulsion * (ydist / distance) / distance2;
    6.46 +          /* Shield repulsion currently is:
    6.47 +             Light:   250 (sqrt() = 15,81)
    6.48 +             Medium:  500 (sqrt() = 22,36)
    6.49 +             Heavy:  1000 (sqrt() = 31,62) */
    6.50 +          if (distance < (40.0 + sqrt ((double)repulsion)))
    6.51 +            {
    6.52 +              // no dFpsMul mod here, because PLAYER::traceShellTrajectory() needs clean values
    6.53 +              dXAcc = repulsion * (dXDist / distance) / distance2;
    6.54 +              dYAcc = repulsion * (dYDist / distance) / distance2;
    6.55  
    6.56 -          // Maybe we need to correct those values:
    6.57 -          if ( (ypos < (dPosY + TANKHEIGHT))
    6.58 -             &&(dVelY >= 0.0)
    6.59 -             &&(abs(dVelX) <= 1.0)
    6.60 -             &&( (aWeaponType < BURROWER) || (aWeaponType > PENETRATOR))
    6.61 -             &&(*yaccel > 0.0) )
    6.62 -            *yaccel *= -1.0;
    6.63 -        }
    6.64 +              // Maybe we need to correct those values:
    6.65 +              if ( (ypos < (dPosY + TANKHEIGHT)) // Not below the tank
    6.66 +                 &&(dVelY >= 0.0) // And moving down
    6.67 +                 &&(abs(dVelX) <= 1.0) // But not to fast horizontally
    6.68 +                 &&( (aWeaponType < BURROWER) || (aWeaponType > PENETRATOR))
    6.69 +                 &&(dYAcc > 0.0) ) // And current Y-Accell is downwards, too
    6.70 +                dYAcc *= -1.0; // Push upwards instead
    6.71 +
    6.72 +              // Repulsion must not be too high
    6.73 +              if (abs(dXAcc) > 1.0)
    6.74 +                {
    6.75 +                  // X-Repulsion is too high
    6.76 +                  if (dXAcc < 0)
    6.77 +                    dXAcc = -1.0;
    6.78 +                  else
    6.79 +                    dXAcc = 1.0;
    6.80 +                }
    6.81 +              if (abs(dYAcc) > 1.0)
    6.82 +                {
    6.83 +                  // Y-Repulsion is too high
    6.84 +                  if (dYAcc < 0)
    6.85 +                    dYAcc = -1.0;
    6.86 +                  else
    6.87 +                    dYAcc = 1.0;
    6.88 +                }
    6.89 +            }
    6.90 +          // Now write back the results:
    6.91 +          *xaccel = dXAcc;
    6.92 +          *yaccel = dYAcc;
    6.93 +        } // If either dist is greater than 0
    6.94      }
    6.95  }
    6.96  
    6.97 @@ -734,29 +770,38 @@
    6.98  
    6.99  int TANK::get_heaviest_shield ()
   6.100  {
   6.101 -  if (pOwner->ni[ITEM_HVY_REPULSOR_SHIELD])
   6.102 +  if ((pOwner->type >= (int)USELESS_PLAYER) && (pOwner->type <= (int)DEADLY_PLAYER)
   6.103 +      &&(pOwner->getDefensiveness() > 0.0))
   6.104      {
   6.105 -      return ITEM_HVY_REPULSOR_SHIELD;
   6.106 +      // A defensive bot, it favours normal shields
   6.107 +      if (pOwner->ni[ITEM_HVY_SHIELD])
   6.108 +        return ITEM_HVY_SHIELD;
   6.109 +      if (pOwner->ni[ITEM_HVY_REPULSOR_SHIELD])
   6.110 +        return ITEM_HVY_REPULSOR_SHIELD;
   6.111 +      if (pOwner->ni[ITEM_MED_SHIELD])
   6.112 +        return ITEM_MED_SHIELD;
   6.113 +      if (pOwner->ni[ITEM_MED_REPULSOR_SHIELD])
   6.114 +        return ITEM_MED_REPULSOR_SHIELD;
   6.115 +      if (pOwner->ni[ITEM_LGT_SHIELD])
   6.116 +        return ITEM_LGT_SHIELD;
   6.117 +      if (pOwner->ni[ITEM_LGT_REPULSOR_SHIELD])
   6.118 +        return ITEM_LGT_REPULSOR_SHIELD;
   6.119      }
   6.120 -  if (pOwner->ni[ITEM_HVY_SHIELD])
   6.121 +  else
   6.122      {
   6.123 -      return ITEM_HVY_SHIELD;
   6.124 -    }
   6.125 -  if (pOwner->ni[ITEM_MED_REPULSOR_SHIELD])
   6.126 -    {
   6.127 -      return ITEM_MED_REPULSOR_SHIELD;
   6.128 -    }
   6.129 -  if (pOwner->ni[ITEM_MED_SHIELD])
   6.130 -    {
   6.131 -      return ITEM_MED_SHIELD;
   6.132 -    }
   6.133 -  if (pOwner->ni[ITEM_LGT_REPULSOR_SHIELD])
   6.134 -    {
   6.135 -      return ITEM_LGT_REPULSOR_SHIELD;
   6.136 -    }
   6.137 -  if (pOwner->ni[ITEM_LGT_SHIELD])
   6.138 -    {
   6.139 -      return ITEM_LGT_SHIELD;
   6.140 +      // Aggressive bots and humans favour repulsor shields
   6.141 +      if (pOwner->ni[ITEM_HVY_REPULSOR_SHIELD])
   6.142 +        return ITEM_HVY_REPULSOR_SHIELD;
   6.143 +      if (pOwner->ni[ITEM_HVY_SHIELD])
   6.144 +        return ITEM_HVY_SHIELD;
   6.145 +      if (pOwner->ni[ITEM_MED_REPULSOR_SHIELD])
   6.146 +        return ITEM_MED_REPULSOR_SHIELD;
   6.147 +      if (pOwner->ni[ITEM_MED_SHIELD])
   6.148 +        return ITEM_MED_SHIELD;
   6.149 +      if (pOwner->ni[ITEM_LGT_REPULSOR_SHIELD])
   6.150 +        return ITEM_LGT_REPULSOR_SHIELD;
   6.151 +      if (pOwner->ni[ITEM_LGT_SHIELD])
   6.152 +        return ITEM_LGT_SHIELD;
   6.153      }
   6.154    return ITEM_NO_SHIELD;
   6.155  }