home *** CD-ROM | disk | FTP | other *** search
- /*
- * atanks - obliterate each other with oversize weapons
- * Copyright (C) 2003 Thomas Hudson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * */
-
-
- #include "environment.h"
- #include "globaldata.h"
- #include "floattext.h"
- #include "explosion.h"
- #include "teleport.h"
- #include "missile.h"
- #include "player.h"
- #include "beam.h"
- #include "tank.h"
-
-
- /*
- The deconstructor should be split into two pieces. One function for
- destroying a tank and another strictly for cleaning up a tank's memory
- whether it was destoryed or not.
- -- Jesse
- */
- TANK::~TANK ()
- {
- /*
- #ifdef NETWORK
- if (player) // we should always have a player, but better safe than sorry
- {
- int player_index = 0;
- bool found = false;
- char buffer[64];
- while ( (player_index < _global->numPlayers) && (!found) )
- {
- // get the player index
- if ( ( _global->players[player_index]->tank ) && (_global->players[player_index]->tank == this) )
- found = true;
- else
- player_index++;
- }
- if (found) // we should have found a match and now we send it to all clients
- {
- sprintf(buffer, "REMOVETANK %d", player_index);
- _global->Send_To_Clients(buffer);
- }
- }
- #endif
- if (_global && player)
- {
- int random_item;
- if (_global->violent_death)
- {
- random_item = rand() % VIOLENT_CHANCE;
- if ( ( random_item > _global->violent_death ) && (random_item <= VIOLENT_DEATH_HEAVY) )
- random_item = (int) _global->violent_death;
-
- switch (random_item)
- {
- case VIOLENT_DEATH_LIGHT:
- player->ni[ITEM_VENGEANCE] += 1;
- break;
- case VIOLENT_DEATH_MEDIUM:
- player->ni[ITEM_DYING_WRATH] += 1;
- break;
- case VIOLENT_DEATH_HEAVY:
- player->ni[ITEM_FATAL_FURY] += 1;
- break;
- } //end of switch
- }
-
- if (player->ni[ITEM_FATAL_FURY] > 0)
- {
- int numLaunch = (int)item[ITEM_FATAL_FURY].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_FATAL_FURY].vals[SELFD_TYPE];
- player->ni[ITEM_FATAL_FURY]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- else if (player->ni[ITEM_DYING_WRATH] > 0)
- {
- int numLaunch = (int)item[ITEM_DYING_WRATH].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_DYING_WRATH].vals[SELFD_TYPE];
- player->ni[ITEM_DYING_WRATH]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- else if (player->ni[ITEM_VENGEANCE] > 0)
- {
- int numLaunch = (int)item[ITEM_VENGEANCE].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_VENGEANCE].vals[SELFD_TYPE];
- player->ni[ITEM_VENGEANCE]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- }
- */
-
- if (player)
- {
- player->tank = NULL;
- player = NULL;
- }
- if (_global)
- {
- _global->numTanks--;
- if (_global->currTank == this)
- _global->currTank = NULL;
- }
-
- if (shieldText)
- delete (shieldText);
- if (healthText)
- delete (healthText);
- if (nameText)
- delete (nameText);
-
- if (_env)
- _env->removeObject(this);
-
- shieldText = NULL;
- healthText = NULL;
- nameText = NULL;
- _env = NULL;
- _global = NULL;
- creditTo = NULL;
- _target = NULL;
- }
-
- TANK::TANK (GLOBALDATA *global, ENVIRONMENT *env):PHYSICAL_OBJECT(),_target(NULL),creditTo(NULL),
- healthText(NULL),shieldText(NULL),nameText(NULL)
- {
- setEnvironment (env);
- _global = global;
- // Ask for memory
- healthText = new FLOATTEXT (global, env, NULL, 0, 0, WHITE, CENTRE);
- if (!healthText)
- {
- perror ( "tank.cc: Failed allocating memory for healthText in TANK::TANK");
- // exit (1);
- }
-
- shieldText = new FLOATTEXT (global, env, NULL, 0, 0, makecol (200, 200, 255), CENTRE);
- if (!shieldText)
- {
- perror ( "tank.cc: Failed allocating memory for shieldText in TANK::TANK");
- // exit (1);
- }
-
- if (global->name_above_tank)
- {
- nameText = new FLOATTEXT (global, env, NULL, 0, 0, WHITE, CENTRE);
- if (! nameText)
- {
- perror ( "tank.cc: Failed allocating memory for nameText in TANK::TANK");
- // exit(1);
- }
- }
-
- // Other initial pointers:
- _align = LEFT;
- _global->numTanks++;
-
- player = NULL;
- }
-
- void TANK::initialise ()
- {
- PHYSICAL_OBJECT::initialise ();
- drag = 0.5;
- mass = 3000;
- repulsion = 0;
- shieldColor = 0;
- shieldThickness = 0;
- t = 0;
- sh = 0;
- _targetX = -1;
- _targetY = -1;
- newRound ();
- }
-
- void TANK::newRound ()
- {
- char buf[10];
-
- cw = 0;
- damage = 0;
- pen = 0;
- para = 0;
- creditTo = NULL;
- p = MAX_POWER / 2;
- a = (rand () % 180) + 90;
- if (sh > 0 && sht > 0)
- if (player)
- player->ni[sht]++;
- sh = 0;
- repulsion = 0;
- // shPhase = rand () % 360;
- shPhase = 0;
- delta_phase = 0.1;
- sht = 0;
- l = 100;
- repair_rate = 0;
- if (player)
- {
- double tmpL = 0;
- tmpL += (int)(player->ni[ITEM_ARMOUR] * item[ITEM_ARMOUR].vals[0]);
- tmpL += (int)(player->ni[ITEM_PLASTEEL] * item[ITEM_PLASTEEL].vals[0]);
- repair_rate = Get_Repair_Rate();
- if (tmpL > 0)
- l += (int)pow (tmpL, 0.6);
-
- if (healthText)
- healthText->set_color( player->color );
- if (nameText)
- {
- nameText->set_text ( player->getName() );
- nameText->set_color ( player->color );
- }
- }
- maxLife = l;
- ds = 0;
- fs = 0;
- sprintf (buf, "%d", l);
- healthText->set_text (buf);
- // delay_fall = GRAVITY_DELAY;
- delay_fall = (int) labs(_env->landSlideDelay * 100);
- fire_another_shot = 0;
- shots_fired = 0;
-
- }
-
-
-
- void TANK::Destroy()
- {
- #ifdef NETWORK
- if (player) // we should always have a player, but better safe than sorry
- {
- int player_index = 0;
- bool found = false;
- char buffer[64];
- while ( (player_index < _global->numPlayers) && (!found) )
- {
- // get the player index
- if ( ( _global->players[player_index]->tank ) && (_global->players[player_index]->tank == this) )
- found = true;
- else
- player_index++;
- }
- if (found) // we should have found a match and now we send it to all clients
- {
- sprintf(buffer, "REMOVETANK %d", player_index);
- _global->Send_To_Clients(buffer);
- }
- }
- #endif
-
- if (_global && player)
- {
- int random_item;
- if (_global->violent_death)
- {
- random_item = rand() % VIOLENT_CHANCE;
- if ( ( random_item > _global->violent_death ) && (random_item <= VIOLENT_DEATH_HEAVY) )
- random_item = (int) _global->violent_death;
-
- switch (random_item)
- {
- case VIOLENT_DEATH_LIGHT:
- player->ni[ITEM_VENGEANCE] += 1;
- break;
- case VIOLENT_DEATH_MEDIUM:
- player->ni[ITEM_DYING_WRATH] += 1;
- break;
- case VIOLENT_DEATH_HEAVY:
- player->ni[ITEM_FATAL_FURY] += 1;
- break;
- } //end of switch
- }
-
- if (player->ni[ITEM_FATAL_FURY] > 0)
- {
- int numLaunch = (int)item[ITEM_FATAL_FURY].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_FATAL_FURY].vals[SELFD_TYPE];
- player->ni[ITEM_FATAL_FURY]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- else if (player->ni[ITEM_DYING_WRATH] > 0)
- {
- int numLaunch = (int)item[ITEM_DYING_WRATH].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_DYING_WRATH].vals[SELFD_TYPE];
- player->ni[ITEM_DYING_WRATH]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- else if (player->ni[ITEM_VENGEANCE] > 0)
- {
- int numLaunch = (int)item[ITEM_VENGEANCE].vals[SELFD_NUMBER];
- cw = (int)item[ITEM_VENGEANCE].vals[SELFD_TYPE];
- player->ni[ITEM_VENGEANCE]--;
- player->nm[cw] += numLaunch;
- for (int count = numLaunch; count > 0; count--)
- {
- a = rand () % 180 + 90;
- p = rand () % (MAX_POWER / 2);
- activateCurrentSelection ();
- }
- }
- }
- }
-
-
-
- void TANK::update ()
- {
- VIRTUAL_OBJECT::update ();
- }
-
- void TANK::requireUpdate ()
- {
- VIRTUAL_OBJECT::requireUpdate ();
- }
-
- void TANK::applyDamage ()
- {
- char buf[10];
- FLOATTEXT *damageText;
- FLOATTEXT *revengeText;
- FLOATTEXT *gloatText;
- FLOATTEXT *suicideText;
- char *temp_text;
- bool killed = false;
-
- if (damage > sh + l)
- {
- damage = sh + l;
- killed = true;
- player->killed++;
- }
- sh -= (int)damage;
- if (creditTo)
- {
- if (player != creditTo) //enemy hit ++
- {
- if ( killed )
- creditTo->kills++;
- creditTo->money += (int)(damage * _global->scoreHitUnit);
- if (creditTo->tank)
- {
- char the_money[64];
- sprintf(the_money, "$%s", Add_Comma( (int) (damage * _global->scoreHitUnit) ) );
- // show how much the shooter gets
- FLOATTEXT *moneyText = new FLOATTEXT(_global, _env, the_money,
- (int) creditTo->tank->x, (int) creditTo->tank->y - 30,
- makecol(0, 255, 0), CENTRE);
- if (moneyText)
- {
- // moneyText->xv = 0;
- // moneyText->yv = -0.5;
- moneyText->set_speed(0.0, -0.5);
- moneyText->maxAge = 200;
- }
-
- }
- // this tank is destroyed, the attacker gloats
- if ( (killed) && (! creditTo->gloating) )
- {
- // avoid trying to print victory message over a dead tank
- if (creditTo->tank)
- {
- temp_text = creditTo->selectGloatPhrase();
- gloatText = new FLOATTEXT (_global, _env,
- // creditTo->selectGloatPhrase( (double) damage / maxLife),
- temp_text,
- (int) creditTo->tank->x, (int) creditTo->tank->y - 30,
- creditTo->color, CENTRE);
- if (gloatText)
- {
- // gloatText->xv = 0;
- // gloatText->yv = -0.4;
- gloatText->set_speed(0.0, -0.4);
- gloatText->maxAge = 300;
- }
- else
- perror ( "tank.cc: Failed allocating memory for gloatText in applyDamage.");
- creditTo->gloating = true;
- }
- }
-
- if ((int)player->type != HUMAN_PLAYER)
- {
- if (player->revenge == creditTo)
- {
- player->annoyanceFactor += damage;
- }
- else
- {
- player->annoyanceFactor = damage;
- }
- if ( (player->annoyanceFactor > (player->vengeanceThreshold * maxLife) )
- &&((rand() % 100) <= player->vengeful) )
- {
- player->revenge = creditTo;
- temp_text = player->selectRevengePhrase();
- revengeText = new FLOATTEXT (_global, _env,
- // player->selectRevengePhrase ((double)damage / maxLife),
- temp_text,
- (int)x, (int)y - 30,
- player->color, CENTRE);
- if (revengeText)
- {
- // revengeText->xv = 0;
- // revengeText->yv = -0.4;
- revengeText->set_speed(0.0, -0.4);
- revengeText->maxAge = 300;
- }
- else
- perror ( "tank.cc: Failed allocating memory for revengeText in applyDamage");
- }
- }
- }
- else //self hit --
- {
- if ( (creditTo->money - (damage * _global->scoreSelfHit)) < 0)
- creditTo->money = 0;
- else
- creditTo->money -= (int)(damage * _global->scoreSelfHit);
-
- if (damage >= (l + sh) )
- {
- temp_text = player->selectSuicidePhrase();
- suicideText = new FLOATTEXT (_global, _env,
- player->selectSuicidePhrase(),
- (int) x, (int) y - 30,
- player->color, CENTRE);
- if (suicideText)
- {
- // suicideText->xv = 0;
- // suicideText->yv = -0.4;
- suicideText->set_speed(0.0, -0.4);
- suicideText->maxAge = 300;
- }
- else
- perror ( "tank.cc: Failed allocating memory for suicideText in applyDamage.");
- }
- }
- }
-
- if (sh < 0)
- l += sh;
- if (l < 0)
- l = 0;
- if (sh <= 0)
- {
- repulsion = 0;
- shieldColor = 0;
- shieldThickness = 0;
- sh = 0;
- }
-
- if ((int)damage > 0)
- {
- flashdamage = 1;
- sprintf (buf, "%d", (int)damage);
- damageText = new FLOATTEXT (_global, _env,
- NULL, (int)x, (int)y,
- makecol (255, 0, 0), CENTRE);
- if (damageText)
- {
- damageText->set_text(buf);
- // damageText->xv = 0;
- // damageText->yv = -0.2;
- damageText->set_speed(0.0, -0.2);
- damageText->maxAge = 300;
- // damageText->sway = NORMAL_SWAY;
- }
- else
- perror ( "tank.cc: Failed allocating memory for damageText in TANK::TANK");
- }
- if (sh > 0)
- {
- sprintf (buf, "%d", sh);
- shieldText->set_text (buf);
- }
- else
- {
- shieldText->set_text ( "");
- }
- sprintf (buf, "%d", l);
- healthText->set_text (buf);
- }
-
- void TANK::framelyAccounting ()
- {
- /*
- if (shPhase < 0)
- shPhase = rand () % 360;
- shPhase += (int)(item[sht].vals[SHIELD_ENERGY] / sh) + 10;
- while (shPhase >= 360)
- shPhase -= 360;
- */
- shPhase = shPhase + delta_phase;
- if ( ( shPhase > 5) || (shPhase < -2) )
- delta_phase = -delta_phase;
- }
-
- int TANK::applyPhysics (GLOBALDATA *global)
- {
- int stable = 0;
- int landed_on_tank;
-
- // if we are buried, rockets shouldn't work
- if ( howBuried() )
- {
- xv = 0;
- if (yv < 0)
- yv = 0;
- }
-
- // make sure the tank does not leave the screen when flying
- if ( (yv < 0) && (y < TANKHEIGHT) )
- yv = 0;
-
- if (yv < 0)
- x += xv * 4;
-
- if (!flashdamage)
- {
- if (x + xv < 1 || x + xv > (_global->screenWidth-1))
- xv = -xv; //bounce on the border
- int pixelCol = getpixel (_env->terrain, (int)x, (int)y + (TANKHEIGHT - TANKSAG));
-
- // check to see if we have landed on another tank -- Jesse
- landed_on_tank = tank_on_tank ( global );
-
- // we are falling and have hit the bottom of the screen or fallen onto dirt or on a tank
- if ((l > 0) && (yv > 0) && ((y >= _global->screenHeight - TANKHEIGHT) ||
- (pixelCol != PINK) ||
- (landed_on_tank) ))
- {
- //count damage and add money
- damage = (int) (yv * 10);
- if (damage >= 10)
- damage -= 10;
- else damage = 0;
- creditTo = NULL;
- yv = 0;
- xv = 0;
- // if we passed the bottom, then stop on bottom
- if (y > _global->screenHeight - TANKHEIGHT)
- y = _global->screenHeight - TANKHEIGHT;
-
- // delay_fall = GRAVITY_DELAY;
- delay_fall = (int) _env->landSlideDelay * 100;
-
- }
-
- // the tank is falling
- else if ((y < _global->screenHeight - TANKHEIGHT) && (pixelCol == PINK) && (l > 0) &&
- (! landed_on_tank) && (_env->landSlideType > LANDSLIDE_NONE) )
- {
- delay_fall--;
- if ( (delay_fall > 0) && (_env->landSlideType == LANDSLIDE_CARTOON) )
- return stable;
-
- #ifdef OLD_GAMELOOP
- if (para && para < 3 && !_env->pclock)
- para++;
- #else
- if ( (para) && (para < 3) )
- para++;
- #endif
- if (!para)
- {
- yv += _env->gravity * (100.0 / _global->frames_per_second);
- y += yv;
- }
- else
- {
- double accel = (_env->wind - xv) / mass * (drag + 0.35) * _env->viscosity;
- xv += accel;
- yv += _env->gravity * (100.0 / _global->frames_per_second);
- if (yv > 0.5 )
- yv = 0.5;
- x += xv;
- y += yv;
- }
- // falling, deploy parachute
- if (!para)
- {
- if ((player->ni[ITEM_PARACHUTE]) && (yv >= 1.0))
- {
- _env->pclock = 1;
- para = 1;
- player->ni[ITEM_PARACHUTE]--;
- }
-
- }
- requireUpdate ();
- }
- else
- {
- stable = 1;
- if (damage && !pen)
- {
- applyDamage ();
-
- pen = 1;
- }
- para = 0;
- }
- }
- else
- {
- flashdamage++;
- }
- return (stable);
- }
-
- void TANK::explode ()
- {
- FLOATTEXT *revengeText;
- EXPLOSION *explosion;
- char *temp_text;
-
- if ((int)player->type != HUMAN_PLAYER)
- {
- player->revenge = creditTo;
- temp_text = player->selectRevengePhrase();
- revengeText = new FLOATTEXT (_global, _env,
- temp_text,
- (int)x, (int)y - 30,
- player->color, CENTRE);
- if (revengeText)
- {
- // revengeText->xv = 0;
- // revengeText->yv = -0.4;
- revengeText->set_speed(0.0, -0.4);
- revengeText->maxAge = 300;
- }
- else
- perror ( "tank.cc: Failed allocating memory for revengeText in TANK::explode");
- }
- explosion = new EXPLOSION (_global, _env, x, y, 1);
- if (explosion)
- {
- explosion->player = player;
- explosion->bIsWeaponExplosion = false;
- }
- else
- perror ( "tank.cc: Failed allocating memory for explosion in TANK::explode");
-
-
- destroy = TRUE;
- play_sample ((SAMPLE *)_global->sounds[WEAPONSOUNDS], 255, 128, 1000, 0);
- }
-
- void TANK::repulse (double xpos, double ypos, double *xaccel, double *yaccel, int aWeaponType)
- {
- if (repulsion != 0)
- {
- double xdist = xpos - x;
- double ydist = -1.0 * fabs(ypos - y);
-
- if ((xdist < 0.1) && (xdist > -0.1)) xdist = 0.1;
- if ((ydist < 0.1) && (ydist > -0.1)) ydist = -0.1; // Assume missile comes from above
-
- if ( (aWeaponType >= BURROWER) && (aWeaponType <= PENETRATOR)
- &&(ypos > y) )
- ydist *= -1.0; // they normally come from below!
-
- double distance2 = (xdist * xdist) + (ydist * ydist);
- double distance = sqrt (distance2);
-
- if (distance < (60.0 + sqrt ((double)repulsion)))
- {
- *xaccel = repulsion * (xdist / distance) / distance2;
- *yaccel = repulsion * (ydist / distance) / distance2;
- }
- }
- }
-
- void TANK::printHealth (int offset)
- {
- int textpos = -5;
-
- shieldText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
- if (sh > 0)
- textpos -= 10;
- healthText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
-
- // display player name
- if (nameText)
- {
- textpos -= 10;
- nameText->set_pos ((int)x, (int)y - TANKHEIGHT + textpos + offset);
- }
- }
-
- void TANK::draw (BITMAP *dest, int healthOffset)
- {
- int turretAngle;
-
- // check for foggy weather
- if ( ( _env->fog ) && ( _global->currTank != this ) )
- {
- addUpdateArea ((int)(x - TANKWIDTH) - 3, (int)y - 25, 35, 46);
- requireUpdate ();
- return;
- }
-
- // get bitmap for tank
- if (player)
- {
- switch ( (int) player->tank_bitmap)
- {
- case CLASSIC_TANK:
- use_tank_bitmap = 8;
- use_turret_bitmap = 1;
- turret_x = x;
- turret_y = y + (TANKHEIGHT / 2);
- break;
- case BIGGREY_TANK:
- use_tank_bitmap = 9;
- use_turret_bitmap = 2;
- turret_y = y;
- turret_x = x;
- break;
- case T34_TANK:
- use_tank_bitmap = 10;
- use_turret_bitmap = 3;
- turret_y = y;
- turret_x = x;
- break;
- case HEAVY_TANK:
- use_tank_bitmap = 11;
- use_turret_bitmap = 4;
- turret_y = y;
- turret_x = x;
- break;
- case FUTURE_TANK:
- use_tank_bitmap = 12;
- use_turret_bitmap = 5;
- turret_y = y;
- turret_x = x;
- break;
- case UFO_TANK:
- use_tank_bitmap = 13;
- use_turret_bitmap = 6;
- turret_y = y;
- turret_x = x;
- break;
- case SPIDER_TANK:
- use_tank_bitmap = 14;
- use_turret_bitmap = 7;
- turret_y = y;
- turret_x = x;
- break;
- case BIGFOOT_TANK:
- use_tank_bitmap = 15;
- use_turret_bitmap = 8;
- turret_y = y;
- turret_x = x;
- break;
- default:
- use_tank_bitmap = 0;
- use_turret_bitmap = 0;
- turret_x = x;
- turret_y = y;
- break;
- }
- }
-
- rectfill (dest, (int) x - (TANKWIDTH - 1),
- (int) (y + TANKHEIGHT) - 2,
- (int) (x + TANKWIDTH) - 2,
- (int) (y + TANKHEIGHT),
- this->player->color);
- // draw_sprite (dest, (BITMAP *) _global->gfxData.T[use_tank_bitmap].dat, (int) x - TANKWIDTH, (int) y);
-
- /*
- Drawing shields this way seems to cause a crash on multi-cpu
- systems. Taking this out and creating new shield
- drawing routine below. -- Jesse
-
- if (sh > 0)
- {
- int phaseValue = 1;
-
- drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
- _env->current_drawing_mode = DRAW_MODE_TRANS;
- set_trans_blender (0, 0, 0, (int)50);
- // avoid sub-index
- if ( shPhase < 0 )
- shPhase = 0;
- if (sht >= ITEM_LGT_SHIELD && sht <= ITEM_HVY_SHIELD)
- {
- phaseValue = (int)(_global->slope[(int)shPhase][0] * 3);
- }
- else if (sht >= ITEM_LGT_REPULSOR_SHIELD && sht <= ITEM_HVY_REPULSOR_SHIELD)
- {
- phaseValue = (int)(shPhase / 360 * 6);
- }
-
- ellipsefill (dest, (int) x, (int) y, TANKWIDTH + 6 + phaseValue, TANKHEIGHT - 1, shieldColor);
- set_trans_blender (0, 0, 0, (int)
- (50 + (((float) sh / (float) (item[sht]).vals[SHIELD_ENERGY]) * (float) 150)));
- for (int thicknessCount = 0; thicknessCount < shieldThickness; thicknessCount++)
- {
- ellipse (dest, (int) x - (shieldThickness / 2) + thicknessCount, (int) y,
- TANKWIDTH + 6 + phaseValue, TANKHEIGHT - 1, shieldColor);
- }
- drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
- _env->current_drawing_mode = DRAW_MODE_SOLID;
- } // end of drawing shield
- */
-
- if (sh > 0)
- {
- int thickness = 2;
- int counter;
- int wobble = (int) shPhase;
-
- if ( (sht == ITEM_LGT_SHIELD) || (sht == ITEM_LGT_REPULSOR_SHIELD) )
- thickness = 1;
- else if ( (sht == ITEM_HVY_REPULSOR_SHIELD) || (sht == ITEM_HVY_SHIELD) )
- thickness = 3;
-
- if (! shieldColor) // client may not have set colour
- {
- shieldColor = makecol ((int)item[sht].vals[SHIELD_RED],
- (int)item[sht].vals[SHIELD_GREEN],
- (int)item[sht].vals[SHIELD_BLUE]);
- }
- for (counter = 0; counter < thickness; counter++)
- circle(dest, (int) x, (int) y,
- TANKHEIGHT + counter + wobble, shieldColor);
- }
-
- draw_sprite (dest, (BITMAP *) _global->tank[use_tank_bitmap], (int) x - TANKWIDTH, (int) y);
- turretAngle = (int) ((float) (90 - a) * ((float) 256 / (float) 360));
- rotate_sprite (dest, (BITMAP *) _global->tankgun[use_turret_bitmap],
- (int) turret_x - GUNLENGTH, (int) turret_y - (GUNLENGTH - 2), itofix (turretAngle));
-
-
- // when using rockets, show flame
- if (yv < 0)
- {
- rectfill(dest, (int) x - TANKWIDTH, (int) y + TANKHEIGHT, x + TANKWIDTH, y + TANKHEIGHT + 10, makecol(250, 150, 0) );
- }
-
- if (sh > 0)
- setUpdateArea ((int)x - TANKWIDTH - 15, (int)y - TANKHEIGHT,
- ((TANKWIDTH + 15) * 2) + 1, (TANKHEIGHT * 2) + 20);
- else
- setUpdateArea ((int)x - GUNLENGTH - 1, (int)y - GUNLENGTH - 1,
- (GUNLENGTH * 2) + 2, TANKHEIGHT + GUNLENGTH + 20);
- if (para)
- {
- draw_sprite (dest, (BITMAP *) _global->tank[para],
- (int) (x - TANKWIDTH) - 3, (int) y - 25);
- addUpdateArea ((int)(x - TANKWIDTH) - 3, (int)y - 25, 35, 66);
- }
-
- printHealth (healthOffset);
- requireUpdate ();
- }
-
- int TANK::get_heaviest_shield ()
- {
- if (player->ni[ITEM_HVY_REPULSOR_SHIELD])
- {
- return ITEM_HVY_REPULSOR_SHIELD;
- }
- if (player->ni[ITEM_HVY_SHIELD])
- {
- return ITEM_HVY_SHIELD;
- }
- if (player->ni[ITEM_MED_REPULSOR_SHIELD])
- {
- return ITEM_MED_REPULSOR_SHIELD;
- }
- if (player->ni[ITEM_MED_SHIELD])
- {
- return ITEM_MED_SHIELD;
- }
- if (player->ni[ITEM_LGT_REPULSOR_SHIELD])
- {
- return ITEM_LGT_REPULSOR_SHIELD;
- }
- if (player->ni[ITEM_LGT_SHIELD])
- {
- return ITEM_LGT_SHIELD;
- }
- return ITEM_NO_SHIELD;
- }
-
-
-
-
- void TANK::simActivateCurrentSelection ()
- {
- char buf[16];
-
- if (_global->turntype != TURN_SIMUL)
- {
- activateCurrentSelection();
- if (fire_another_shot)
- fire_another_shot--;
- }
- else
- {
- _env->stage = 1;
- }
-
- // allow naturals to happen again
- _env->naturals_since_last_shot = 0;
-
- // apply repairs
- l += repair_rate;
- if (l > maxLife)
- l = maxLife;
- sprintf (buf, "%d", l);
- healthText->set_text(buf);
-
- // avoid having key presses read in next turn
- clear_keybuf();
- }
-
-
-
-
- void TANK::activateCurrentSelection ()
- {
- int z;
-
- // avoid firing weapons on exit in Windows
- if ( (_global->command == GLOBAL_COMMAND_QUIT) ||
- (_global->command == GLOBAL_COMMAND_MENU) )
- return;
-
- // remove status from top bar at next redraw
- if (_global->tank_status)
- _global->tank_status[0] = 0;
-
- _env->time_to_fall--;
- if (_env->time_to_fall < 0)
- // _env->time_to_fall = (rand() % MAX_GRAVITY_DELAY) + 1;
- _env->time_to_fall = (rand() % (int)_env->landSlideDelay) + 1;
-
- if (cw < WEAPONS)
- {
- player->changed_weapon = false;
- if (cw)
- player->nm[cw]--;
-
- _env->stage = 1;
- _env->am = weapon[cw].spread;
- _env->realm = _env->am;
-
- if (cw < BALLISTICS)
- {
- play_sample ((SAMPLE *) _global->sounds[weapon[cw].sound], 255, 128, 1000, 0);
- for (z = 0; z < _env->am; z++)
- {
- MISSILE *newmis;
- double mxv,myv;
- int ca;
-
- ca = a + ((SPREAD * z) - (SPREAD * (_env->am - 1) / 2));
- double dPower = (double)p;
- if ((dPower < 200.0) && ((cw == RIOT_CHARGE) || (cw == RIOT_BLAST)))
- dPower = 200.0;
-
- mxv = _global->slope[ca][0] * dPower * (100.0 / _global->frames_per_second) / 100.0;
- myv = _global->slope[ca][1] * dPower * (100.0 / _global->frames_per_second) / 100.0;
-
- newmis = new MISSILE(_global, _env,
- turret_x + (_global->slope[ca][0] * GUNLENGTH) /*- mxv*/,
- turret_y + (_global->slope[ca][1] * GUNLENGTH) /*- myv*/,
- mxv, myv, cw);
- if (newmis)
- {
- newmis->physics = 0;
- newmis->age = 0;
- newmis->player = player;
- }
- else
- perror ( "tank.cc: Failed allocating memory for newmis in TANK::activateCurrentSelection");
- // set up volley
- if (! fire_another_shot)
- {
- fire_another_shot = weapon[cw].delay * VOLLY_DELAY;
- if ( weapon[cw].delay )
- {
- shots_fired = shots_fired - (weapon[cw].delay - 1);
- }
- }
-
- if (player->ni[ITEM_DIMPLEP])
- {
- player->ni[ITEM_DIMPLEP]--;
- newmis->drag *= item[ITEM_DIMPLEP].vals[0];
- }
- else if (player->ni[ITEM_SLICKP])
- {
- player->ni[ITEM_SLICKP]--;
- newmis->drag *= item[ITEM_SLICKP].vals[0];
- }
- }
- }
- else // BEAM weapon
- {
- play_sample ((SAMPLE *) _global->sounds[weapon[cw].sound], 255, 128, 1000, 0);
- for (z = 0; z < _env->am; z++)
- {
- BEAM *newbeam;
- int ca;
-
- ca = a + ((SPREAD * z) - (SPREAD * (_env->am - 1) / 2));
-
- newbeam = new BEAM (_global, _env,
- turret_x + (_global->slope[ca][0] * GUNLENGTH),
- turret_y + (_global->slope[ca][1] * GUNLENGTH),
- ca, cw);
- if (newbeam)
- {
- newbeam->physics = 0;
- newbeam->age = 0;
- newbeam->player = player;
- }
- else
- perror ( "tank.cc: Failed allocating memory for newbeam in TANK::activateCurrentSelection");
- }
-
- }
- }
- else // activate an item
- {
- int itemNum = cw - WEAPONS;
- if (itemNum < ITEM_VENGEANCE || itemNum > ITEM_FATAL_FURY)
- player->ni[itemNum]--;
- _env->stage = 1;
- if (itemNum == ITEM_TELEPORT)
- {
- int teleXDest = (rand () % (_global->screenWidth - TANKWIDTH * 2)) + TANKWIDTH;
- int teleYDest = (rand () % (_global->screenHeight - TANKHEIGHT * 2)) + TANKHEIGHT;
- TELEPORT *teleport;
- creditTo = player;
- teleport = new TELEPORT (_global, _env, this, teleXDest, teleYDest, TANKHEIGHT * 4 + GUNLENGTH, 120);
- if (!teleport)
- {
- perror ( "tank.cc: Failed allocating memory for teleport in TANK::activateCurrentSelection");
- // exit (1);
- }
- }
- else if (itemNum == ITEM_SWAPPER)
- {
- int random_tank_number;
- TANK *other_tank;
- TELEPORT *my_teleport, *other_teleport;
-
- // pick a random tank (not us)
- random_tank_number = rand() % _global->numTanks;
- other_tank = _env->order[random_tank_number];
- while ( (! other_tank) || (other_tank == this) )
- {
- random_tank_number++;
- if (random_tank_number > _global->maxNumTanks)
- random_tank_number = 0;
- other_tank = _env->order[random_tank_number];
- }
- creditTo = player;
- // create a teleport ojbect for this tank
- my_teleport = new TELEPORT (_global, _env, this, (int) other_tank->x, (int) other_tank->y, TANKHEIGHT * 4 + GUNLENGTH, 120);
- // create a teleport object for the other tank
- other_teleport = new TELEPORT (_global, _env, other_tank, (int) x, (int) y, TANKHEIGHT * 4 + GUNLENGTH, 120);
-
- }
- else if (itemNum == ITEM_MASS_TELEPORT)
- {
- TELEPORT *my_teleport;
- int count;
- int XDest, YDest;
- TANK *current_tank;
-
- for (count = 0; count < _global->numPlayers; count++)
- {
- current_tank = _global->players[count]->tank;
- if (current_tank)
- {
- XDest = (rand () % (_global->screenWidth - TANKWIDTH * 2)) + TANKWIDTH;
- YDest = (rand () % (_global->screenHeight - TANKHEIGHT * 2)) + TANKHEIGHT;
- creditTo = player;
- my_teleport = new TELEPORT(_global, _env, current_tank, XDest, YDest, TANKHEIGHT * 4 + GUNLENGTH, 120);
- }
- }
-
- }
-
- else if ( itemNum == ITEM_ROCKET )
- {
- yv = -10;
- y -= 10;
- if (a < 180)
- {
- xv += 0.3;
- }
- else if (a > 180)
- {
- xv -= 0.3;
- }
-
- applyPhysics(_global);
- }
-
- else if ( itemNum == ITEM_FAN )
- {
- // play wind sound
- play_sample ((SAMPLE *) _global->sounds[2], 255, 128, 1000, 0);
- if (a < 180) // move wind to the right
- _env->wind += (p / 20);
- else // wind to the left
- _env->wind -= (p / 20);
-
- // make sure wind is not too strong
- if (_env->wind < (-_env->windstrength / 2) )
- _env->wind = -_env->windstrength / 2;
- else if (_env->wind > (_env->windstrength / 2) )
- _env->wind = _env->windstrength / 2;
-
- _env->lastwind = _env->wind;
-
- }
- else if ((itemNum >= ITEM_VENGEANCE) &&
- (itemNum <= ITEM_FATAL_FURY))
- {
- creditTo = player;
- damage = l + sh;
- }
- }
-
- // if we are out of this type of weapon
- // then switch to another
- if (! player->nm[cw] )
- {
- cw = WEAPONS - 1;
- while ( (cw > 0) && (! player->nm[cw] ) )
- cw--;
- player->changed_weapon = true;
- }
-
- shots_fired++;
- player->time_left_to_fire = _global->max_fire_time;
-
- // if not performing a volly and the player is AI then randomly select next weapon
- // else if ( ( player->type > HUMAN_PLAYER ) && (! fire_another_shot) )
- // cw = player->Select_Random_Weapon();
-
- }
-
-
- void TANK::boost_up_shield ()
- {
- char buf[10];
- int s = get_heaviest_shield ();
-
- if ((s != ITEM_NO_SHIELD) && (player->ni[s] > 0))
- {
- player->ni[s]--;
- sh = (int)item[s].vals[SHIELD_ENERGY];
- repulsion = (int)item[s].vals[SHIELD_REPULSION];
- shieldColor = makecol ((int)item[s].vals[SHIELD_RED],
- (int)item[s].vals[SHIELD_GREEN],
- (int)item[s].vals[SHIELD_BLUE]);
- shieldThickness = (int)item[s].vals[SHIELD_THICKNESS];
- sht = s;
- ds = sht;
- player->last_shield_used = s;
- }
- if (sh)
- {
- sprintf (buf, "%d", sh);
- shieldText->set_text (buf);
- }
- else
- {
- shieldText->set_text ( "");
- }
- }
- void TANK::reactivate_shield ()
- {
- if (!sh) //if no shield remains, try to reload
- {
- boost_up_shield ();
- }
- }
-
- int TANK::howBuried ()
- {
- int turrAngle;
- int buryCount = 0;
-
- for (turrAngle = 90; turrAngle < 270; turrAngle++)
- {
- if (getpixel (_env->terrain, (int)(x + (_global->slope[turrAngle][0] * GUNLENGTH)), (int)(y + (_global->slope[turrAngle][1] * GUNLENGTH))) != PINK)
- buryCount++;
- }
-
- return (buryCount);
- }
-
- int TANK::shootClearance (int targetAngle, int minimumClearance)
- {
- int clearance = 2;
- int iXpos, iYpos;
- do
- {
- iXpos = (int)(x + (_global->slope[targetAngle][0] * (GUNLENGTH + clearance)));
- iYpos = (int)(y + (_global->slope[targetAngle][1] * (GUNLENGTH + clearance)));
- if ((iYpos <= MENUHEIGHT) || (iXpos <= 1) || (iXpos >= (_global->screenWidth - 2)))
- clearance = minimumClearance; // done it! There can't be dirt any more!
- else
- clearance++;
- }
- while ((clearance < minimumClearance) && (getpixel(_env->terrain, iXpos, iYpos) == PINK));
-
- // If we are going for a particular minimumClearance (< screenWidth), it is important whether we hit a wall
- if (minimumClearance < _global->screenWidth)
- {
- int iWall = _env->current_wallType;
- if ( _global->bIsBoxed && (iYpos <= MENUHEIGHT)
- &&((iWall == WALL_STEEL) || (iWall == WALL_WRAP)) )
- clearance = -1; // Wall hit on ceiling
- if ( ((iXpos <= 1) || (iXpos >= (_global->screenWidth - 2)))
- &&(iWall == WALL_STEEL) )
- clearance = -1; // Wall hit on sides
- }
-
- return (clearance >= minimumClearance?1:0);
- }
-
- int TANK::isSubClass (int classNum)
- {
- if (classNum == TANK_CLASS)
- return (TRUE);
- else
- return (FALSE);
- //return (PHYSICAL_OBJECT::isSubClass (classNum));
- }
-
-
-
- /*
- This function checks to see if there is a tank directly below this
- one. This is to determine if we landed on someone.
- The function returns TRUE if we landed on another tank and
- FALSE if we did not.
- -- Jesse
- */
- int TANK::tank_on_tank( GLOBALDATA *global )
- {
- int found_tank = FALSE;
- int player_count = 0;
- int delta_x, delta_y;
-
- while ( ( player_count < global->numPlayers ) && (! found_tank) )
- {
- // check to make sure this player is alive
- if ( global->players[player_count]->tank )
- {
- // make sure this isn't our own tank
- if ( ( global->players[player_count]->tank->x != x ) || (global->players[player_count]->tank->y != y ) )
- {
- // check to see if tanks are within TANK_WIDTH of each other's x
- delta_x = (int) (x - global->players[player_count]->tank->x);
- delta_y = (int) (y - global->players[player_count]->tank->y);
-
- if ( ( abs(delta_x) <= TANKWIDTH ) && ( (delta_y < 0) && (delta_y >= -TANKHEIGHT) ) )
- found_tank = TRUE;
-
- } // end of this is our own tank
- }
- player_count++;
- }
-
- return found_tank;
- }
-
-
-
- /*
- This function figures out how many points a tank
- will repair itself each turn. This is based
- on the number of repair kits a player has.
- The amount is returned as an int.
- -- Jesse
- */
- int TANK::Get_Repair_Rate()
- {
- int num_kits;
- int repair_units = 0;
- int increase_amount = 5;
-
- num_kits = player->ni[ITEM_REPAIRKIT];
- while (num_kits > 0)
- {
- repair_units += increase_amount;
- if (increase_amount > 1)
- increase_amount--;
- num_kits--;
- }
-
- return repair_units;
- }
-
-
-
- /*
- This function tries to move the tank either
- left or right one unit. The direction is passed
- in.
- The function returns TRUE if the tank is moved and
- FALSE if something is in the way or the
- tank cannot be moved for some reason.
- -- Jesse
- */
- int TANK::Move_Tank(int direction)
- {
- int pixel;
- int destination_x;
-
- // do we have fuel?
- if ( player->ni[ITEM_FUEL] < 1 )
- return FALSE;
-
- // see where we want to go
- if (direction == DIR_RIGHT)
- destination_x = (int) (x + TANKWIDTH - 2);
- else
- destination_x = (int) (x - (TANKWIDTH + 1) );
-
- if (_env->landType != LANDTYPE_NONE)
- {
- // check for something in the way
- pixel = getpixel (_env->terrain, destination_x, (int) (y + (TANKHEIGHT / 2)) );
- if (pixel != PINK)
- return FALSE;
- }
-
- // move tank
- if (direction == DIR_RIGHT)
- x++;
- else
- x--;
-
- player->ni[ITEM_FUEL]--;
-
- return TRUE;
- }
-
- void TANK::setEnvironment(ENVIRONMENT *env)
- {
- if (!_env || (_env != env))
- {
- _env = env;
- _index = _env->addObject (this);
- }
- }
-
-
- /*
- Give credit to the tank who killed us.
- */
- void TANK::Give_Credit(GLOBALDATA *global)
- {
- if (creditTo)
- {
- // we shot ourselves
- if (creditTo == player)
- creditTo->money -= (int) global->scoreUnitSelfDestroy;
- else // we were killed by someone else
- creditTo->money += (int) global->scoreUnitDestroyBonus;
-
- // avoid over-flow
- if (creditTo->money < 0)
- creditTo->money = 0;
- creditTo = NULL;
- }
- }
-
-