void CGameHelper::Explosion(const ExplosionParams& params) { const float3& pos = params.pos; const float3& dir = params.dir; const DamageArray& damages = params.damages; // if weaponDef is NULL, this is a piece-explosion // (implicit damage-type -DAMAGE_EXPLOSION_DEBRIS) const WeaponDef* weaponDef = params.weaponDef; const int weaponDefID = (weaponDef != NULL)? weaponDef->id: -CSolidObject::DAMAGE_EXPLOSION_DEBRIS; const float3 expPos = pos; CUnit* owner = params.owner; CUnit* hitUnit = params.hitUnit; CFeature* hitFeature = params.hitFeature; const float craterAOE = std::max(1.0f, params.craterAreaOfEffect); const float damageAOE = std::max(1.0f, params.damageAreaOfEffect); const float edgeEffectiveness = params.edgeEffectiveness; const float expSpeed = params.explosionSpeed; const float gfxMod = params.gfxMod; const float realHeight = ground->GetHeightReal(expPos.x, expPos.z); const float altitude = expPos.y - realHeight; const bool impactOnly = params.impactOnly; const bool ignoreOwner = params.ignoreOwner; const bool damageGround = params.damageGround; const bool noGfx = eventHandler.Explosion(weaponDefID, expPos, owner); if (luaUI) { if (weaponDef != NULL && weaponDef->cameraShake > 0.0f) { luaUI->ShockFront(weaponDef->cameraShake, expPos, damageAOE); } } if (impactOnly) { if (hitUnit) { DoExplosionDamage(hitUnit, owner, expPos, damageAOE, expSpeed, edgeEffectiveness, ignoreOwner, damages, weaponDefID); } else if (hitFeature) { DoExplosionDamage(hitFeature, expPos, damageAOE, damages, weaponDefID); } } else { { // damage all units within the explosion radius const vector<CUnit*>& units = qf->GetUnitsExact(expPos, damageAOE); bool hitUnitDamaged = false; for (vector<CUnit*>::const_iterator ui = units.begin(); ui != units.end(); ++ui) { CUnit* unit = *ui; if (unit == hitUnit) { hitUnitDamaged = true; } DoExplosionDamage(unit, owner, expPos, damageAOE, expSpeed, edgeEffectiveness, ignoreOwner, damages, weaponDefID); } // HACK: for a unit with an offset coldet volume, the explosion // (from an impacting projectile) position might not correspond // to its quadfield position so we need to damage it separately if (hitUnit != NULL && !hitUnitDamaged) { DoExplosionDamage(hitUnit, owner, expPos, damageAOE, expSpeed, edgeEffectiveness, ignoreOwner, damages, weaponDefID); } } { // damage all features within the explosion radius const vector<CFeature*>& features = qf->GetFeaturesExact(expPos, damageAOE); bool hitFeatureDamaged = false; for (vector<CFeature*>::const_iterator fi = features.begin(); fi != features.end(); ++fi) { CFeature* feature = *fi; if (feature == hitFeature) { hitFeatureDamaged = true; } DoExplosionDamage(feature, expPos, damageAOE, damages, weaponDefID); } if (hitFeature != NULL && !hitFeatureDamaged) { DoExplosionDamage(hitFeature, expPos, damageAOE, damages, weaponDefID); } } // deform the map if the explosion was above-ground // (but had large enough radius to touch the ground) if (altitude >= -1.0f) { if (damageGround && !mapDamage->disabled && (craterAOE > altitude) && (damages.craterMult > 0.0f)) { // limit the depth somewhat const float craterDepth = damages.GetDefaultDamage() * (1.0f - (altitude / craterAOE)); const float damageDepth = std::min(craterAOE * 10.0f, craterDepth); const float craterStrength = (damageDepth + damages.craterBoost) * damages.craterMult; const float craterRadius = craterAOE - altitude; mapDamage->Explosion(expPos, craterStrength, craterRadius); } } } if (!noGfx) { // use CStdExplosionGenerator by default IExplosionGenerator* explosionGenerator = stdExplosionGenerator; if (weaponDef != NULL && weaponDef->explosionGenerator != NULL) { explosionGenerator = weaponDef->explosionGenerator; } explosionGenerator->Explosion(0, expPos, damages.GetDefaultDamage(), damageAOE, owner, gfxMod, hitUnit, dir); } CExplosionEvent explosionEvent(expPos, damages.GetDefaultDamage(), damageAOE, weaponDef); FireExplosionEvent(explosionEvent); }
void CGameHelper::Explosion( float3 expPos, const DamageArray& damages, float expRad, float edgeEffectiveness, float expSpeed, CUnit* owner, bool damageGround, float gfxMod, bool ignoreOwner, bool impactOnly, IExplosionGenerator* explosionGenerator, CUnit* hitUnit, const float3& impactDir, int weaponId, CFeature* hitFeature ) { const WeaponDef* wd = weaponDefHandler->GetWeaponById(weaponId); if (luaUI) { if (wd != NULL && wd->cameraShake > 0.0f) { luaUI->ShockFront(wd->cameraShake, expPos, expRad); } } #ifdef TRACE_SYNC tracefile << "Explosion: "; tracefile << expPos.x << " " << damages[0] << " " << expRad << "\n"; #endif const bool noGfx = eventHandler.Explosion(weaponId, expPos, owner); const float h2 = ground->GetHeightReal(expPos.x, expPos.z); expPos.y = std::max(expPos.y, h2); expRad = std::max(expRad, 1.0f); if (impactOnly) { if (hitUnit) { DoExplosionDamage(hitUnit, expPos, expRad, expSpeed, ignoreOwner, owner, edgeEffectiveness, damages, weaponId); } else if (hitFeature) { DoExplosionDamage(hitFeature, expPos, expRad, damages); } } else { float height = std::max(expPos.y - h2, 0.0f); { // damage all units within the explosion radius const vector<CUnit*>& units = qf->GetUnitsExact(expPos, expRad); bool hitUnitDamaged = false; for (vector<CUnit*>::const_iterator ui = units.begin(); ui != units.end(); ++ui) { CUnit* unit = *ui; if (unit == hitUnit) { hitUnitDamaged = true; } DoExplosionDamage(unit, expPos, expRad, expSpeed, ignoreOwner, owner, edgeEffectiveness, damages, weaponId); } // HACK: for a unit with an offset coldet volume, the explosion // (from an impacting projectile) position might not correspond // to its quadfield position so we need to damage it separately if (hitUnit != NULL && !hitUnitDamaged) { DoExplosionDamage(hitUnit, expPos, expRad, expSpeed, ignoreOwner, owner, edgeEffectiveness, damages, weaponId); } } { // damage all features within the explosion radius const vector<CFeature*>& features = qf->GetFeaturesExact(expPos, expRad); bool hitFeatureDamaged = false; for (vector<CFeature*>::const_iterator fi = features.begin(); fi != features.end(); ++fi) { CFeature* feature = *fi; if (feature == hitFeature) { hitFeatureDamaged = true; } DoExplosionDamage(feature, expPos, expRad, damages); } if (hitFeature != NULL && !hitFeatureDamaged) { DoExplosionDamage(hitFeature, expPos, expRad, damages); } } // deform the map if (damageGround && !mapDamage->disabled && (expRad > height) && (damages.craterMult > 0.0f)) { float damage = damages[0] * (1.0f - (height / expRad)); if (damage > (expRad * 10.0f)) { damage = expRad * 10.0f; // limit the depth somewhat } mapDamage->Explosion(expPos, (damage + damages.craterBoost) * damages.craterMult, expRad - height); } } // use CStdExplosionGenerator by default if (!noGfx) { if (explosionGenerator == NULL) { explosionGenerator = stdExplosionGenerator; } explosionGenerator->Explosion(0, expPos, damages[0], expRad, owner, gfxMod, hitUnit, impactDir); } CExplosionEvent explosionEvent(expPos, damages[0], expRad, wd); FireExplosionEvent(explosionEvent); }