00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00103
00104
00105
00106
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
00119
00120 unsigned int pt = (positionX_ << 16) | (positionY_ & 0xffff);
00121 positions.push_front(pt);
00122
00123
00124
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
00136
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
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
00215 if (tank->getState().getState() == TankState::sNormal)
00216 {
00217
00218
00219 if (!tank->getTargetState().getFalling())
00220 {
00221
00222
00223 #ifndef S3D_SERVER
00224 if (!context_->getServerMode())
00225 {
00226
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
00245
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
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
00307 FixedVector newPos(x, y, z);
00308
00309
00310
00311 if (secondz - firstz > context_->getOptionsGame().getMaxClimbingDistance())
00312 {
00313 expandedPositions_.clear();
00314 return;
00315 }
00316
00317
00318
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
00350 if (!MovementMap::allowedPosition(*context_, tank, newPos))
00351 {
00352 expandedPositions_.clear();
00353 return;
00354 }
00355
00356
00357
00358
00359 if (useF && (weapon_->getUseFuel() == -1))
00360 {
00361 tank->getAccessories().rm(weapon_->getParent(), 1);
00362 }
00363
00364
00365 tank->getLife().setRotation(a);
00366 tank->getLife().setTargetPosition(newPos);
00367
00368
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
00378
00379 Target *target = (*itor).second;
00380 if (target->isTarget() &&
00381 target->getTargetState().getDriveOverToDestroy())
00382 {
00383
00384 context_->getActionController().addAction(
00385 new TankDamage(weapon_, target->getPlayerId(), weaponContext_,
00386 target->getLife().getLife(),
00387 false, false, false));
00388
00389
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
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
00454 if (vPoint_) vPoint_->setPosition(newPos);
00455 }