00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <engine/ScorchedContext.h>
00022 #include <engine/ActionController.h>
00023 #include <target/TargetContainer.h>
00024 #include <target/TargetDamageCalc.h>
00025 #include <target/TargetRenderer.h>
00026 #include <target/TargetState.h>
00027 #include <target/TargetSpace.h>
00028 #include <actions/Napalm.h>
00029 #include <actions/CameraPositionAction.h>
00030 #ifndef S3D_SERVER
00031 #include <sprites/ExplosionTextures.h>
00032 #include <GLEXT/GLStateExtension.h>
00033 #include <landscape/Landscape.h>
00034 #include <landscape/DeformTextures.h>
00035 #include <landscape/Smoke.h>
00036 #include <client/ScorchedClient.h>
00037 #endif
00038 #include <landscapemap/LandscapeMaps.h>
00039 #include <landscapedef/LandscapeDefinition.h>
00040 #include <landscapedef/LandscapeTex.h>
00041 #include <weapons/AccessoryStore.h>
00042 #include <common/Defines.h>
00043
00044 static const int deformSize = 3;
00045 static DeformLandscape::DeformPoints deformMap;
00046 static bool deformCreated = false;
00047
00048 #define XY_TO_UINT(x, y) ((((unsigned int) x) << 16) | (((unsigned int) y) & 0xffff))
00049 #define XY2_TO_UINT(x, y) ((((unsigned int) x - x % 2) << 16) | (((unsigned int) y - y % 2) & 0xffff))
00050 #define UINT_TO_X(pt) ((int)(pt >> 16))
00051 #define UINT_TO_Y(pt) ((int)(pt & 0xffff))
00052
00053 Napalm::Napalm(int x, int y, Weapon *weapon,
00054 NapalmParams *params,
00055 WeaponFireContext &weaponContext) :
00056 ActionReferenced("Napalm"),
00057 startX_(x), startY_(y), napalmTime_(0),
00058 weapon_(weapon), params_(params),
00059 weaponContext_(weaponContext),
00060 totalTime_(0), hurtTime_(0),
00061 counter_(0.1f, 0.1f), set_(0),
00062 particleSet_(0)
00063 {
00064 }
00065
00066 Napalm::~Napalm()
00067 {
00068 delete params_;
00069 }
00070
00071 void Napalm::init()
00072 {
00073 if (!deformCreated)
00074 {
00075 deformCreated = true;
00076
00077 Vector center(deformSize + 1, deformSize + 1);
00078 for (int a=0; a<(deformSize + 1) * 2; a++)
00079 {
00080 for (int b=0; b<(deformSize + 1) * 2; b++)
00081 {
00082 Vector pos(a, b);
00083 float dist = (center - pos).Magnitude();
00084 dist /= deformSize;
00085 dist = 1.0f - MIN(1.0f, dist);
00086
00087 DIALOG_ASSERT(a < 100 && b < 100);
00088 deformMap.map[a][b] = fixed::fromFloat(dist);
00089 }
00090 }
00091 }
00092
00093 fixed ShowTime = 5;
00094 FixedVector position(fixed(startX_), fixed(startY_), context_->getLandscapeMaps().
00095 getGroundMaps().getHeight(startX_, startY_));
00096 CameraPositionAction *pos = new CameraPositionAction(
00097 position, ShowTime, 5);
00098 context_->getActionController().addAction(pos);
00099
00100 edgePoints_.insert(XY_TO_UINT(startX_, startY_));
00101
00102 #ifndef S3D_SERVER
00103 if (!context_->getServerMode())
00104 {
00105 set_ = ExplosionTextures::instance()->getTextureSetByName(
00106 params_->getNapalmTexture());
00107 }
00108 #endif // #ifndef S3D_SERVER
00109 }
00110
00111 std::string Napalm::getActionDetails()
00112 {
00113 return S3D::formatStringBuffer("%i,%i %s",
00114 startX_, startY_, weapon_->getParent()->getName());
00115 }
00116
00117 void Napalm::simulate(fixed frameTime, bool &remove)
00118 {
00119 #ifndef S3D_SERVER
00120 if (!context_->getServerMode())
00121 {
00122 if (!napalmPoints_.empty() &&
00123 !params_->getNoSmoke() &&
00124 counter_.nextDraw(frameTime.asFloat()))
00125 {
00126 int count = rand() % napalmPoints_.size();
00127
00128 NapalmEntry *entry = napalmRANDPoints_[napalmRANDPoints_.size() - 1 - count];
00129 fixed posZ =
00130 ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeight(
00131 entry->posX, entry->posY);
00132 Landscape::instance()->getSmoke().
00133 addSmoke(float(entry->posX), float(entry->posY), posZ.asFloat());
00134 }
00135 }
00136 #endif // #ifndef S3D_SERVER
00137
00138
00139
00140
00141 totalTime_ += frameTime;
00142 while (totalTime_ > params_->getStepTime())
00143 {
00144 totalTime_ -= params_->getStepTime();
00145 napalmTime_ += params_->getStepTime();
00146 if (napalmTime_ < params_->getNapalmTime())
00147 {
00148
00149 if (int(napalmPoints_.size()) < params_->getNumberParticles())
00150 {
00151 simulateAddStep();
00152 }
00153
00154
00155 if (napalmPoints_.empty())
00156 {
00157 remove = true;
00158 break;
00159 }
00160 }
00161 else
00162 {
00163
00164 if (!napalmPoints_.empty())
00165 {
00166 simulateRmStep();
00167 }
00168 else
00169 {
00170 remove = true;
00171 break;
00172 }
00173 }
00174 }
00175
00176
00177 hurtTime_ += frameTime;
00178 while (hurtTime_ > params_->getHurtStepTime())
00179 {
00180 hurtTime_ -= params_->getHurtStepTime();
00181
00182 simulateDamage();
00183 }
00184
00185 Action::simulate(frameTime, remove);
00186 }
00187
00188 fixed Napalm::getHeight(int x, int y)
00189 {
00190 LandscapeMaps *hmap = &context_->getLandscapeMaps();
00191 if (x < 0 || y < 0 ||
00192 x > hmap->getGroundMaps().getLandscapeWidth() ||
00193 y > hmap->getGroundMaps().getLandscapeHeight())
00194 {
00195
00196
00197 return fixed::MAX_FIXED;
00198 }
00199
00200
00201
00202
00203
00204 return hmap->getGroundMaps().getHeight(x, y) +
00205 hmap->getGroundMaps().getNapalmHeight(x, y);
00206 }
00207
00208 void Napalm::simulateRmStep()
00209 {
00210 int pset = napalmPoints_.front()->pset;
00211 while (!napalmPoints_.empty())
00212 {
00213
00214 NapalmEntry *entry = napalmPoints_.front();
00215 if (pset != entry->pset) break;
00216
00217
00218
00219 napalmPoints_.pop_front();
00220 int x = entry->posX;
00221 int y = entry->posY;
00222 delete entry;
00223
00224 unsigned int pointsCount = XY2_TO_UINT(x, y);
00225 std::map<unsigned int, int>::iterator countItor =
00226 napalmPointsCount_.find(pointsCount);
00227 if (countItor != napalmPointsCount_.end())
00228 {
00229 countItor->second--;
00230 if (countItor->second == 0) napalmPointsCount_.erase(countItor);
00231 }
00232
00233 context_->getLandscapeMaps().getGroundMaps().getNapalmHeight(x, y) -= params_->getNapalmHeight();
00234 }
00235 }
00236
00237 void Napalm::simulateAddStep()
00238 {
00239 particleSet_++;
00240
00241 std::set<unsigned int> currentEdges = edgePoints_;
00242 edgePoints_.clear();
00243
00244 std::set<unsigned int>::iterator itor;
00245 for (itor = currentEdges.begin();
00246 itor != currentEdges.end();
00247 itor++)
00248 {
00249 unsigned int currentEdge = *itor;
00250 int x = UINT_TO_X(currentEdge);
00251 int y = UINT_TO_Y(currentEdge);
00252
00253 simulateAddEdge(x, y);
00254 }
00255 }
00256
00257 void Napalm::simulateAddEdge(int x, int y)
00258 {
00259
00260 fixed height = getHeight(x, y);
00261
00262 if (!params_->getAllowUnderWater())
00263 {
00264
00265 fixed waterHeight = -10;
00266 LandscapeTex &tex = *context_->getLandscapeMaps().getDefinitions().getTex();
00267 if (tex.border->getType() == LandscapeTexType::eWater)
00268 {
00269 LandscapeTexBorderWater *water =
00270 (LandscapeTexBorderWater *) tex.border;
00271 waterHeight = water->height;
00272 }
00273
00274 if (height < waterHeight)
00275 {
00276
00277 return;
00278 }
00279 }
00280
00281
00282 RandomGenerator &random = context_->getActionController().getRandom();
00283 int offset = (random.getRandFixed() * 31).asInt();
00284 NapalmEntry *newEntry = new NapalmEntry(x, y, offset, particleSet_);
00285 napalmPoints_.push_back(newEntry);
00286 napalmRANDPoints_.push_back(newEntry);
00287
00288 unsigned int pointsCount = XY2_TO_UINT(x, y);
00289 std::map<unsigned int, int>::iterator countItor =
00290 napalmPointsCount_.find(pointsCount);
00291 if (countItor == napalmPointsCount_.end())
00292 {
00293 napalmPointsCount_.insert(std::pair<unsigned int, int>(pointsCount, 1));
00294 }
00295 else
00296 {
00297 countItor->second++;
00298 }
00299
00300 #ifndef S3D_SERVER
00301 if (!context_->getServerMode())
00302 {
00303 ParticleEmitter emitter;
00304 emitter.setAttributes(
00305 params_->getNapalmTime().asFloat(), params_->getNapalmTime().asFloat(),
00306 0.5f, 1.0f,
00307 0.01f, 0.02f,
00308 Vector(0.0f, 0.0f, 0.0f), Vector(0.0f, 0.0f, 0.0f),
00309 Vector(1.0f, 1.0f, 1.0f), 0.9f,
00310 Vector(1.0f, 1.0f, 1.0f), 0.6f,
00311 Vector(1.0f, 1.0f, 1.0f), 0.0f,
00312 Vector(1.0f, 1.0f, 1.0f), 0.1f,
00313 1.5f, 1.5f, 1.5f, 1.5f,
00314 1.5f, 1.5f, 1.5f, 1.5f,
00315 Vector(0.0f, 0.0f, 0.0f),
00316 params_->getLuminance(),
00317 false);
00318 Vector position1(float(x) + 0.5f, float(y) - 0.2f, 0.0f);
00319 Vector position2(float(x) - 0.5f, float(y) - 0.2f, 0.0f);
00320 Vector position3(float(x) + 0.0f, float(y) + 0.5f, 0.0f);
00321 emitter.emitNapalm(
00322 position1,
00323 ScorchedClient::instance()->getParticleEngine(),
00324 set_);
00325 emitter.emitNapalm(
00326 position2,
00327 ScorchedClient::instance()->getParticleEngine(),
00328 set_);
00329 emitter.emitNapalm(
00330 position3,
00331 ScorchedClient::instance()->getParticleEngine(),
00332 set_);
00333
00334
00335 if (!GLStateExtension::getNoTexSubImage())
00336 {
00337 if (height == context_->getLandscapeMaps().getGroundMaps().getHeight(x, y))
00338 {
00339 if (RAND < params_->getGroundScorchPer().asFloat())
00340 {
00341 Vector pos(x, y);
00342 DeformTextures::deformLandscape(pos,
00343 (int) (deformSize + 1),
00344 ExplosionTextures::instance()->getScorchBitmap(
00345 params_->getDeformTexture()),
00346 deformMap);
00347 }
00348 }
00349 }
00350 }
00351 #endif // #ifndef S3D_SERVER
00352
00353 context_->getLandscapeMaps().getGroundMaps().getNapalmHeight(x, y) += params_->getNapalmHeight();
00354
00355
00356
00357 fixed heightL = getHeight(x-1, y);
00358 fixed heightR = getHeight(x+1, y);
00359 fixed heightU = getHeight(x, y+1);
00360 fixed heightD = getHeight(x, y-1);
00361
00362 if (params_->getSingleFlow())
00363 {
00364 fixed *heightLR = 0;
00365 int LR = 0;
00366 if (heightL < heightR)
00367 {
00368 heightLR = &heightL;
00369 LR = -1;
00370 }
00371 else if (heightL == heightR)
00372 {
00373 if (random.getRandUInt() % 2 == 0)
00374 {
00375 heightLR = &heightL;
00376 LR = -1;
00377 }
00378 else
00379 {
00380 heightLR = &heightR;
00381 LR = +1;
00382 }
00383 }
00384 else
00385 {
00386 heightLR = &heightR;
00387 LR = +1;
00388 }
00389
00390 fixed *heightUD = 0;
00391 int UD = 0;
00392 if (heightU < heightD)
00393 {
00394 heightUD = &heightU;
00395 UD = +1;
00396 }
00397 else if (heightU == heightD)
00398 {
00399 if (random.getRandUInt() % 2 == 0)
00400 {
00401 heightUD = &heightU;
00402 UD = +1;
00403 }
00404 else
00405 {
00406 heightUD = &heightD;
00407 UD = -1;
00408 }
00409 }
00410 else
00411 {
00412 heightUD = &heightD;
00413 UD = -1;
00414 }
00415
00416 enum Direction
00417 {
00418 eUD,
00419 eLR,
00420 eNone
00421 } dir = eNone;
00422 if (*heightLR < *heightUD)
00423 {
00424 if (*heightLR < height) dir = eLR;
00425 }
00426 else if (*heightLR == *heightUD)
00427 {
00428 if (*heightLR < height)
00429 {
00430 if (random.getRandUInt() % 2 == 0)
00431 {
00432 dir = eUD;
00433 }
00434 else
00435 {
00436 dir = eLR;
00437 }
00438 }
00439 }
00440 else
00441 {
00442 if (*heightUD < height)
00443 {
00444 if (*heightLR < height) dir = eUD;
00445 }
00446 }
00447
00448 switch (dir)
00449 {
00450 case eUD:
00451 edgePoints_.insert(XY_TO_UINT(x, y + UD));
00452 break;
00453 case eLR:
00454 edgePoints_.insert(XY_TO_UINT(x + LR, y));
00455 break;
00456 default:
00457
00458
00459
00460 edgePoints_.insert(XY_TO_UINT(x, y));
00461 break;
00462 }
00463 }
00464 else
00465 {
00466 int addedCount = 0;
00467 if (heightL < height)
00468 {
00469
00470 addedCount++;
00471 edgePoints_.insert(XY_TO_UINT(x - 1, y));
00472 }
00473 if (heightR < height)
00474 {
00475
00476 addedCount++;
00477 edgePoints_.insert(XY_TO_UINT(x + 1, y));
00478 }
00479 if (heightU < height)
00480 {
00481
00482 addedCount++;
00483 edgePoints_.insert(XY_TO_UINT(x, y + 1));
00484 }
00485 if (heightD < height)
00486 {
00487
00488 addedCount++;
00489 edgePoints_.insert(XY_TO_UINT(x, y - 1));
00490 }
00491 if (addedCount == 0)
00492 {
00493
00494
00495
00496 edgePoints_.insert(XY_TO_UINT(x, y));
00497 }
00498 }
00499 }
00500
00501 void Napalm::simulateDamage()
00502 {
00503 const int EffectRadius = params_->getEffectRadius();
00504
00505
00506
00507
00508 static std::map<unsigned int, fixed> TargetDamageCalc;
00509 TargetDamageCalc.clear();
00510
00511
00512
00513 std::map<unsigned int, int>::iterator itor =
00514 napalmPointsCount_.begin();
00515 std::map<unsigned int, int>::iterator endItor =
00516 napalmPointsCount_.end();
00517 for (;itor != endItor; itor++)
00518 {
00519 unsigned int pointsCount = itor->first;
00520 fixed count = fixed(itor->second);
00521 int x = UINT_TO_X(pointsCount);
00522 int y = UINT_TO_Y(pointsCount);
00523
00524 fixed height = context_->getLandscapeMaps().getGroundMaps().
00525 getHeight(x, y);
00526 FixedVector position(
00527 fixed(x),
00528 fixed(y),
00529 height);
00530
00531 std::map<unsigned int, Target *> collisionTargets;
00532 context_->getTargetSpace().getCollisionSet(position,
00533 fixed(EffectRadius), collisionTargets);
00534 std::map<unsigned int, Target *>::iterator itor;
00535 for (itor = collisionTargets.begin();
00536 itor != collisionTargets.end();
00537 itor++)
00538 {
00539 Target *target = (*itor).second;
00540 if (target->getAlive())
00541 {
00542 std::map<unsigned int, fixed>::iterator damageItor =
00543 TargetDamageCalc.find(target->getPlayerId());
00544 if (damageItor == TargetDamageCalc.end())
00545 {
00546 TargetDamageCalc[target->getPlayerId()] = count * params_->getHurtPerSecond();
00547 }
00548 else
00549 {
00550 TargetDamageCalc[target->getPlayerId()] += count * params_->getHurtPerSecond();
00551 }
00552 }
00553 }
00554 }
00555
00556
00557 if (!TargetDamageCalc.empty())
00558 {
00559 std::map<unsigned int, fixed>::iterator damageItor;
00560 for (damageItor = TargetDamageCalc.begin();
00561 damageItor != TargetDamageCalc.end();
00562 damageItor++)
00563 {
00564 Target *target =
00565 context_->getTargetContainer().getTargetById(damageItor->first);
00566 fixed damage = (*damageItor).second;
00567
00568
00569
00570 if (!target->getTargetState().getNoDamageBurn())
00571 {
00572 TargetDamageCalc::damageTarget(*context_, target, weapon_,
00573 weaponContext_, damage, true, false, false);
00574 }
00575
00576
00577 if (target->getRenderer() &&
00578 !params_->getNoObjectDamage())
00579 {
00580 target->getRenderer()->targetBurnt();
00581 }
00582 }
00583 TargetDamageCalc.clear();
00584 }
00585 }