TankMovement.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <actions/TankMovement.h>
00022 #include <actions/TankFalling.h>
00023 #include <actions/TankDamage.h>
00024 #include <actions/ShotProjectile.h>
00025 #include <engine/ScorchedContext.h>
00026 #include <engine/ActionController.h>
00027 #include <weapons/WeaponMoveTank.h>
00028 #include <weapons/AccessoryStore.h>
00029 #include <landscapemap/LandscapeMaps.h>
00030 #include <landscapedef/LandscapeDefn.h>
00031 #include <landscapedef/LandscapeTex.h>
00032 #include <landscapemap/MovementMap.h>
00033 #include <landscapemap/DeformLandscape.h>
00034 #ifndef S3D_SERVER
00035         #include <landscape/Smoke.h>
00036         #include <landscape/Landscape.h>
00037         #include <image/ImageStore.h>
00038         #include <GLEXT/GLImageModifier.h>
00039         #include <sound/Sound.h>
00040         #include <land/VisibilityPatchGrid.h>
00041 #endif
00042 #include <tank/TankContainer.h>
00043 #include <tank/TankModelStore.h>
00044 #include <tank/TankPosition.h>
00045 #include <tank/TankState.h>
00046 #include <tank/TankModelContainer.h>
00047 #include <tank/TankAccessories.h>
00048 #include <target/TargetLife.h>
00049 #include <target/TargetState.h>
00050 #include <target/TargetSpace.h>
00051 #include <image/ImageStore.h>
00052 #include <common/OptionsScorched.h>
00053 #include <common/Defines.h>
00054 
00055 static const int NoMovementTransitions = 4;
00056 
00057 TankMovement::TankMovement(WeaponFireContext &weaponContext,
00058         WeaponMoveTank *weapon,
00059         int positionX, int positionY) : 
00060         ActionReferenced("TankMovement"),
00061         weaponContext_(weaponContext), 
00062         positionX_(positionX), positionY_(positionY),
00063         timePassed_(0), vPoint_(0), weapon_(weapon),
00064         remove_(false), moving_(true), moveSoundSource_(0),
00065         smokeCounter_(0.1f, 0.1f), stepCount_(0)
00066 {
00067 }
00068 
00069 TankMovement::~TankMovement()
00070 {
00071         if (vPoint_) context_->getViewPoints().releaseViewPoint(vPoint_);
00072 #ifndef S3D_SERVER
00073         if (!context_->getServerMode())
00074         {
00075                 delete moveSoundSource_;
00076                 moveSoundSource_ = 0;
00077         }
00078 #endif
00079 }
00080 
00081 void TankMovement::init()
00082 {
00083         Tank *tank = context_->getTankContainer().getTankById(weaponContext_.getPlayerId());
00084         if (!tank) return;      
00085 
00086         startPosition_ = tank->getLife().getTargetPosition();
00087         vPoint_ = context_->getViewPoints().getNewViewPoint(weaponContext_.getPlayerId());
00088         
00089         // Start the tank movement sound
00090 #ifndef S3D_SERVER
00091         if (!context_->getServerMode()) 
00092         {
00093                 SoundBuffer *moveSound = 
00094                         Sound::instance()->fetchOrCreateBuffer(
00095                                 S3D::getDataFile("data/wav/movement/tankmove.wav"));
00096                 moveSoundSource_ = new VirtualSoundSource(VirtualSoundPriority::eAction, true, false);
00097                 moveSoundSource_->setPosition(tank->getPosition().getTankPosition().asVector());
00098                 moveSoundSource_->play(moveSound);
00099         }
00100 #endif // #ifndef S3D_SERVER
00101 
00102         // As with everything to do with movement
00103         // The xy position is stored as an unsigned int
00104         // to save space, z is calculated from the landscape
00105         // Lower 32 bits = y position
00106         // Upper 32 bits = x positions
00107         std::list<unsigned int> positions;
00108         MovementMap mmap(
00109                 tank, 
00110                 *context_);
00111         FixedVector pos(positionX_, positionY_, 0);
00112         mmap.calculatePosition(pos, mmap.getFuel(weapon_));
00113         
00114         MovementMap::MovementMapEntry entry =
00115                 mmap.getEntry(positionX_, positionY_);
00116         if (entry.type == MovementMap::eMovement)
00117         {
00118                 // Add the end (destination) point to the list of points for the tank
00119                 // to visit
00120                 unsigned int pt = (positionX_ << 16) | (positionY_ & 0xffff);
00121                 positions.push_front(pt);
00122 
00123                 // Work backward to the source point and pre-pend them onto the
00124                 // this of points
00125                 while (entry.srcEntry)
00126                 {
00127                         pt = entry.srcEntry;
00128                         unsigned int x = pt >> 16;
00129                         unsigned int y = pt & 0xffff;
00130                         positions.push_front(pt);
00131                         entry = mmap.getEntry(x, y);
00132                 }
00133         }
00134         
00135         // Expand these positions into a interpolated set of positions with
00136         // x, y and z
00137         std::list<unsigned int>::iterator itor;
00138         for (itor = positions.begin();
00139                 itor != positions.end();)
00140         {
00141                 unsigned int fistpt = (*itor);
00142                 itor++;
00143 
00144                 if (itor != positions.end())
00145                 {
00146                         unsigned int secpt = (*itor);
00147 
00148                         int firstx = int(fistpt >> 16);
00149                         int firsty = int(fistpt & 0xffff);
00150                         int secx = int(secpt >> 16);
00151                         int secy = int(secpt & 0xffff);
00152                         int diffX = secx - firstx;
00153                         int diffY = secy - firsty;
00154                         fixed ang = (atan2x(fixed(diffY), fixed(diffX)) / fixed::XPI * 180) - 90;
00155 
00156                         for (int i=0; i<NoMovementTransitions; i++)
00157                         {
00158                                 fixed currentX = fixed(firstx) + fixed(diffX)/fixed(NoMovementTransitions)*fixed(i+1);
00159                                 fixed currentY = fixed(firsty) + fixed(diffY)/fixed(NoMovementTransitions)*fixed(i+1);
00160                                 expandedPositions_.push_back(
00161                                         PositionEntry(
00162                                                 firstx, firsty, 
00163                                                 secx, secy,
00164                                                 currentX, currentY, 
00165                                                 ang, (i==(NoMovementTransitions-1))));
00166                         }
00167                 }
00168         }
00169 
00170         // If this weapon is set to use a constant amount of fuel then use this amount
00171         if (weapon_->getUseFuel() > 0)
00172         {
00173                 tank->getAccessories().rm(weapon_->getParent(), weapon_->getUseFuel());
00174         }
00175 }
00176 
00177 std::string TankMovement::getActionDetails()
00178 {
00179         return S3D::formatStringBuffer("%u %i,%i %s",
00180                 weaponContext_.getPlayerId(), positionX_, positionY_, 
00181                 weapon_->getParent()->getName());
00182 }
00183 
00184 void TankMovement::simulate(fixed frameTime, bool &remove)
00185 {
00186         if (!remove_)
00187         {
00188                 if (moving_)
00189                 {
00190                         simulationMove(frameTime);
00191                 }
00192         }
00193         else
00194         {
00195                 remove = true;
00196         }
00197 
00198 #ifndef S3D_SERVER
00199         if (remove && moveSoundSource_)
00200         {
00201                 moveSoundSource_->stop();
00202         }
00203 #endif // #ifndef S3D_SERVER
00204         
00205         ActionReferenced::simulate(frameTime, remove);
00206 }
00207 
00208 void TankMovement::simulationMove(fixed frameTime)
00209 {
00210         Tank *tank = 
00211                 context_->getTankContainer().getTankById(weaponContext_.getPlayerId());
00212         if (tank)
00213         {
00214                 // Stop moving if the tank is dead
00215                 if (tank->getState().getState() == TankState::sNormal)
00216                 {
00217                         // Check to see if this tank is falling
00218                         // If it is then we wait until the fall is over
00219                         if (!tank->getTargetState().getFalling())
00220                         {
00221                                 // Add a smoke trail
00222                                 // Check if we are not on the server
00223 #ifndef S3D_SERVER
00224                                 if (!context_->getServerMode())
00225                                 {
00226                                         // Check if this tank type allows smoke trails
00227                                         TankModel *model = context_->getTankModels().getModelByName(
00228                                                 tank->getModelContainer().getTankModelName(),
00229                                                 tank->getTeam(),
00230                                                 tank->isTemp());
00231                                         if (model && model->getMovementSmoke())
00232                                         {
00233                                                 if (smokeCounter_.nextDraw(frameTime.asFloat()))
00234                                                 {
00235                                                         Landscape::instance()->getSmoke().addSmoke(
00236                                                                 tank->getLife().getFloatPosition()[0],
00237                                                                 tank->getLife().getFloatPosition()[1],
00238                                                                 tank->getLife().getFloatPosition()[2]);
00239                                                 }
00240                                         }
00241                                 }
00242 #endif // S3D_SERVER
00243 
00244                                 // Move the tank one position every stepTime seconds
00245                                 // i.e. 1/stepTime positions a second
00246                                 timePassed_ += frameTime;
00247                                 fixed stepTime = weapon_->getStepTime();
00248                                 while (timePassed_ >= stepTime)
00249                                 {
00250                                         timePassed_ -= stepTime;
00251                                         if (!expandedPositions_.empty())
00252                                         {
00253                                                 moveTank(tank);
00254                                         }
00255                                         else break;
00256                                 }
00257 
00258                                 if (expandedPositions_.empty()) moving_ = false;
00259                         }
00260                 }
00261                 else moving_ = false;
00262         }
00263         else moving_ = false;
00264 
00265         if (moving_ == false)
00266         {
00267                 Tank *current = 
00268                         context_->getTankContainer().getTankById(weaponContext_.getPlayerId());
00269                 if (current)
00270                 {
00271                         current->getLife().setRotation(0);
00272                         if (current->getState().getState() == TankState::sNormal)
00273                         {
00274                                 // Move the tank to the final position
00275                                 DeformLandscape::flattenArea(*context_, current->getLife().getTargetPosition());
00276 #ifndef S3D_SERVER
00277                                 if (!context_->getServerMode())
00278                                 {
00279                                         VisibilityPatchGrid::instance()->recalculateErrors(current->getLife().getTargetPosition(), 2);
00280                                 }
00281 #endif
00282                         }
00283                 }
00284 
00285                 remove_ = true;
00286         }
00287 }
00288 
00289 void TankMovement::moveTank(Tank *tank)
00290 {
00291         fixed x = expandedPositions_.front().x;
00292         fixed y = expandedPositions_.front().y;
00293         fixed a = expandedPositions_.front().ang;
00294         bool useF = expandedPositions_.front().useFuel;
00295 
00296         int firstx = expandedPositions_.front().firstX;
00297         int firsty = expandedPositions_.front().firstY;
00298         fixed firstz = context_->getLandscapeMaps().getGroundMaps().getHeight(firstx, firsty);
00299 
00300         int secondx = expandedPositions_.front().secondX;
00301         int secondy = expandedPositions_.front().secondY;
00302         fixed secondz = context_->getLandscapeMaps().getGroundMaps().getHeight(secondx, secondy);
00303         fixed z = context_->getLandscapeMaps().getGroundMaps().getInterpHeight(x, y);
00304         expandedPositions_.pop_front();
00305 
00306         // Form the new tank position
00307         FixedVector newPos(x, y, z);
00308 
00309         // Check we are not trying to climb to high (this may be due
00310         // to the landscape changing after we started move)
00311         if (secondz - firstz > context_->getOptionsGame().getMaxClimbingDistance())
00312         {
00313                 expandedPositions_.clear();
00314                 return;
00315         }
00316 
00317         // Check to see we are not moving into water with a movement restriction
00318         // in place
00319         if (context_->getOptionsGame().getMovementRestriction() ==
00320                 OptionsGame::MovementRestrictionLand ||
00321                 context_->getOptionsGame().getMovementRestriction() ==
00322                 OptionsGame::MovementRestrictionLandOrAbove)
00323         {
00324                 fixed waterHeight = -10;
00325                 LandscapeTex &tex = *context_->getLandscapeMaps().getDefinitions().getTex();
00326                 if (tex.border->getType() == LandscapeTexType::eWater)
00327                 {
00328                         LandscapeTexBorderWater *water = 
00329                                 (LandscapeTexBorderWater *) tex.border;
00330                         waterHeight = water->height;
00331                 }
00332 
00333                 if (context_->getOptionsGame().getMovementRestriction() ==
00334                         OptionsGame::MovementRestrictionLandOrAbove)
00335                 {
00336                         if (waterHeight > startPosition_[2] - fixed(true, 1000))
00337                         {
00338                                 waterHeight = startPosition_[2] - fixed(true, 1000);
00339                         }
00340                 }
00341 
00342                 if (secondz < waterHeight)
00343                 {
00344                         expandedPositions_.clear();
00345                         return;
00346                 }
00347         }
00348 
00349         // Check this new position is allowed
00350         if (!MovementMap::allowedPosition(*context_, tank, newPos))
00351         {
00352                 expandedPositions_.clear();
00353                 return;
00354         }
00355 
00356         // Move the tank to this new position
00357         // Use up one unit of fuel
00358         // -1 means use 1 unit of fuel per movement square
00359         if (useF && (weapon_->getUseFuel() == -1))
00360         {
00361                 tank->getAccessories().rm(weapon_->getParent(), 1);
00362         }
00363 
00364         // Actually move the tank
00365         tank->getLife().setRotation(a);
00366         tank->getLife().setTargetPosition(newPos);
00367 
00368         // Remove the targets that this tank "drives over"
00369         std::map<unsigned int, Target *> collisionTargets;
00370         context_->getTargetSpace().getCollisionSet(
00371                 tank->getLife().getTargetPosition(), 3, collisionTargets, false);
00372         std::map<unsigned int, Target *>::iterator itor;
00373         for (itor = collisionTargets.begin();
00374                 itor != collisionTargets.end();
00375                 itor++)
00376         {
00377                 // Check that this is a target we have driven over
00378                 // and we can destroy it
00379                 Target *target = (*itor).second;
00380                 if (target->isTarget() &&
00381                         target->getTargetState().getDriveOverToDestroy())
00382                 {
00383                         // Kill the target we've driven over
00384                         context_->getActionController().addAction(
00385                                 new TankDamage(weapon_, target->getPlayerId(), weaponContext_, 
00386                                         target->getLife().getLife(),
00387                                         false, false, false));
00388 
00389                         // Do a small explosion where we remove this target
00390                         Accessory *accessory = 
00391                                 context_->getAccessoryStore().findByPrimaryAccessoryName("DriveOverDestroy");
00392                         if (accessory && accessory->getType() == AccessoryPart::AccessoryWeapon)
00393                         {
00394                                 Weapon *weapon = (Weapon *) accessory->getAction();
00395                                 weapon->fireWeapon(*context_, 
00396                                         weaponContext_,
00397                                         tank->getLife().getTargetPosition(), 
00398                                         FixedVector::getNullVector());
00399                         }
00400                 }
00401         }
00402 
00403         // Add tracks
00404 #ifndef S3D_SERVER
00405         if (!context_->getServerMode())
00406         {
00407                 stepCount_++;
00408                 if (stepCount_ % 5 == 0)
00409                 {
00410                         TankModel *model = context_->getTankModels().getModelByName(
00411                                 tank->getModelContainer().getTankModelName(),
00412                                 tank->getTeam(),
00413                                 tank->isTemp());
00414                         if (model)
00415                         {
00416                                 Image *image = 0;
00417                                 if (firstx == secondx)
00418                                 {
00419                                         image = ImageStore::instance()->
00420                                                 loadImage(model->getTracksVId());
00421                                 }
00422                                 else if (firsty == secondy)
00423                                 {
00424                                         image = ImageStore::instance()->
00425                                                 loadImage(model->getTracksHId());
00426                                 }
00427                                 else if (firsty - secondy == firstx - secondx)
00428                                 {
00429                                         image = ImageStore::instance()->
00430                                                 loadImage(model->getTracksVHId());
00431                                 }
00432                                 else 
00433                                 {
00434                                         image = ImageStore::instance()->
00435                                                 loadImage(model->getTracksHVId());
00436                                 }
00437 
00438                                 ImageModifier::addBitmapToLandscape(
00439                                         *context_,
00440                                         *image,
00441                                         newPos[0].asFloat(), 
00442                                         newPos[1].asFloat(),
00443                                         0.04f, 0.04f,
00444                                         true);
00445                         }
00446                 }
00447         }
00448 
00449         if (moveSoundSource_) moveSoundSource_->setPosition(newPos.asVector());
00450 
00451 #endif // #ifndef S3D_SERVER
00452 
00453         // Set viewpoints
00454         if (vPoint_) vPoint_->setPosition(newPos);
00455 }

Generated on Mon Feb 16 15:14:48 2009 for Scorched3D by  doxygen 1.5.3