1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include "LightningCannon.h"
#include "PlasmaRepulser.h"
#include "WeaponDef.h"
#include "WeaponMemPool.h"
#include "Game/GameHelper.h"
#include "Game/TraceRay.h"
#include "Sim/Misc/CollisionHandler.h"
#include "Sim/Misc/GlobalSynced.h"
#include "Sim/Projectiles/WeaponProjectiles/WeaponProjectileFactory.h"
#include "Sim/Units/Unit.h"
#include <vector>
CR_BIND_DERIVED_POOL(CLightningCannon, CWeapon, , weaponMemPool.alloc, weaponMemPool.free)
CR_REG_METADATA(CLightningCannon, (
CR_MEMBER(color)
))
CLightningCannon::CLightningCannon(CUnit* owner, const WeaponDef* def): CWeapon(owner, def)
{
// null happens when loading
if (def != nullptr)
color = def->visuals.color;
}
float CLightningCannon::GetPredictedImpactTime(float3 p) const
{
return 0;
}
void CLightningCannon::FireImpl(const bool scriptCall)
{
float3 curPos = weaponMuzzlePos;
float3 curDir = (currentTargetPos - weaponMuzzlePos).SafeNormalize();
curDir +=
(gsRNG.NextVector() * SprayAngleExperience() + SalvoErrorExperience());
curDir.Normalize();
CUnit* hitUnit = nullptr;
CFeature* hitFeature = nullptr;
CollisionQuery hitColQuery;
float boltLength = TraceRay::TraceRay(curPos, curDir, range, collisionFlags, owner, hitUnit, hitFeature, &hitColQuery);
if (!weaponDef->waterweapon) {
// terminate bolt at water surface if necessary
if ((curDir.y < 0.0f) && ((curPos.y + curDir.y * boltLength) <= 0.0f)) {
boltLength = curPos.y / -curDir.y;
hitUnit = nullptr;
hitFeature = nullptr;
}
}
static std::vector<TraceRay::SShieldDist> hitShields;
hitShields.clear();
TraceRay::TraceRayShields(this, curPos, curDir, range, hitShields);
for (const TraceRay::SShieldDist& sd: hitShields) {
if (sd.dist < boltLength && sd.rep->IncomingBeam(this, curPos, curPos + (curDir * sd.dist), 1.0f)) {
boltLength = sd.dist;
hitUnit = nullptr;
hitFeature = nullptr;
break;
}
}
if (hitUnit != nullptr)
hitUnit->SetLastHitPiece(hitColQuery.GetHitPiece(), gs->frameNum);
const DamageArray& damageArray = damages->GetDynamicDamages(weaponMuzzlePos, currentTargetPos);
const CExplosionParams params = {
curPos + curDir * boltLength, // hitPos (same as hitColQuery.GetHitPos() if no water or shield in way)
curDir,
damageArray,
weaponDef,
owner,
hitUnit,
hitFeature,
damages->craterAreaOfEffect,
damages->damageAreaOfEffect,
damages->edgeEffectiveness,
damages->explosionSpeed,
0.5f, // gfxMod
weaponDef->impactOnly,
weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner
false, // damageGround
-1u // projectileID
};
helper->Explosion(params);
ProjectileParams pparams = GetProjectileParams();
pparams.pos = curPos;
pparams.end = curPos + curDir * (boltLength + 10.0f);
pparams.ttl = weaponDef->beamLaserTTL;
WeaponProjectileFactory::LoadProjectile(pparams);
}
|