Esempio n. 1
0
void CGameHelper::Explosion(const ExplosionParams& params) {
	const float3& dir = params.dir;
	const float3 expPos = params.pos;
	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;


	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 expEdgeEffect = 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, params.projectileID, 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, expEdgeEffect, ignoreOwner, damages, weaponDefID, params.projectileID);
		} else if (hitFeature) {
			DoExplosionDamage(hitFeature, expPos, damageAOE, expEdgeEffect, damages, weaponDefID, params.projectileID);
		}
	} else {
		{
			// damage all units within the explosion radius
			const vector<CUnit*>& units = quadField->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, expEdgeEffect, ignoreOwner, damages, weaponDefID, params.projectileID);
			}

			// 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, expEdgeEffect, ignoreOwner, damages, weaponDefID, params.projectileID);
			}
		}

		{
			// damage all features within the explosion radius
			const vector<CFeature*>& features = quadField->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, expEdgeEffect, damages, weaponDefID, params.projectileID);
			}

			if (hitFeature != NULL && !hitFeatureDamaged) {
				DoExplosionDamage(hitFeature, expPos, damageAOE, expEdgeEffect, damages, weaponDefID, params.projectileID);
			}
		}

		// 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);
	CExplosionCreator::FireExplosionEvent(explosionEvent);

	#if (PLAY_SOUNDS == 1)
	if (weaponDef != NULL) {
		const GuiSoundSet& soundSet = weaponDef->hitSound;

		const unsigned int soundFlags = CCustomExplosionGenerator::GetFlagsFromHeight(expPos.y, altitude);
		const int soundNum = ((soundFlags & (CCustomExplosionGenerator::SPW_WATER | CCustomExplosionGenerator::SPW_UNDERWATER)) != 0);
		const int soundID = soundSet.getID(soundNum);

		if (soundID > 0) {
			Channels::Battle.PlaySample(soundID, expPos, soundSet.getVolume(soundNum));
		}
	}
	#endif
}
Esempio n. 2
0
void CGameHelper::Explosion(
    float3 expPos, const DamageArray& damages,
    float expRad, float edgeEffectiveness,
    float expSpeed, CUnit* owner,
    bool damageGround, float gfxMod,
    bool ignoreOwner, bool impactOnly,
    CExplosionGenerator* explosionGraphics, CUnit* hit,
    const float3& impactDir, int weaponId
) {
    if (luaUI) {
        if ((weaponId >= 0) && (weaponId <= weaponDefHandler->numWeaponDefs)) {
            WeaponDef& wd = weaponDefHandler->weaponDefs[weaponId];
            const float cameraShake = wd.cameraShake;
            if (cameraShake > 0.0f) {
                luaUI->ShockFront(cameraShake, expPos, expRad);
            }
        }
    }

    bool noGfx = eventHandler.Explosion(weaponId, expPos, owner);

#ifdef TRACE_SYNC
    tracefile << "Explosion: ";
    tracefile << expPos.x << " " << damages[0] <<  " " << expRad << "\n";
#endif

    float h2 = ground->GetHeight2(expPos.x, expPos.z);
    expPos.y = std::max(expPos.y, h2);
    expRad = std::max(expRad, 1.0f);

    if (impactOnly) {
        if (hit) {
            DoExplosionDamage(hit, expPos, expRad, expSpeed, ignoreOwner, owner, edgeEffectiveness, damages, weaponId);
        }
    } else {
        float height = std::max(expPos.y - h2, 0.0f);

        // damage all units within the explosion radius
        vector<CUnit*> units = qf->GetUnitsExact(expPos, expRad);
        vector<CUnit*>::iterator ui;
        bool hitUnitDamaged = false;

        for (ui = units.begin(); ui != units.end(); ++ui) {
            CUnit* unit = *ui;

            if (unit == hit) {
                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 (hit && !hitUnitDamaged) {
            DoExplosionDamage(hit, expPos, expRad, expSpeed, ignoreOwner, owner, edgeEffectiveness, damages, weaponId);
        }


        // damage all features within the explosion radius
        vector<CFeature*> features = qf->GetFeaturesExact(expPos, expRad);
        vector<CFeature*>::iterator fi;

        for (fi = features.begin(); fi != features.end(); ++fi) {
            CFeature* feature = *fi;

            DoExplosionDamage(feature, expPos, expRad, owner, 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 (!explosionGraphics) {
            explosionGraphics = stdExplosionGenerator;
        }
        explosionGraphics->Explosion(expPos, damages[0], expRad, owner, gfxMod, hit, impactDir);
    }

    groundDecals->AddExplosion(expPos, damages[0], expRad);

    water->AddExplosion(expPos, damages[0], expRad);
}
Esempio n. 3
0
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);
}