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 }