Exemplo n.º 1
0
void CUnitScript::EmitSfx(int sfxType, int piece)
{
#ifndef _CONSOLE
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for emit-sfx");
		return;
	}

	if (ph->particleSaturation > 1.0f && sfxType < SFX_CEG) {
		// skip adding (unsynced!) particles when we have too many
		return;
	}

	// Make sure wakes are only emitted on water
	if ((sfxType >= SFX_WAKE) && (sfxType <= SFX_REVERSE_WAKE_2)) {
		if (ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 0.0f) {
			return;
		}
	}

	float3 relPos = ZeroVector;
	float3 relDir = UpVector;

	if (!GetEmitDirPos(piece, relPos, relDir)) {
		ShowScriptError("emit-sfx: GetEmitDirPos failed");
		return;
	}

	relDir.SafeNormalize();

	const float3 pos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;
	const float3 dir =
		unit->frontdir * relDir.z +
		unit->updir    * relDir.y +
		unit->rightdir * relDir.x;

	float alpha = 0.3f + gu->usRandFloat() * 0.2f;
	float alphaFalloff = 0.004f;
	float fadeupTime = 4;

	const UnitDef* ud = unit->unitDef;
	const MoveDef* md = ud->moveDef;

	// hovercraft need special care
	if (md != NULL && md->moveType == MoveDef::Hover_Move) {
		fadeupTime = 8.0f;
		alpha = 0.15f + gu->usRandFloat() * 0.2f;
		alphaFalloff = 0.008f;
	}

	switch (sfxType) {
		case SFX_REVERSE_WAKE:
		case SFX_REVERSE_WAKE_2: {  //reverse wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_WAKE_2:  //wake 2, in TA it lives longer..
		case SFX_WAKE: {  //regular ship wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_BUBBLE: {  //submarine bubble. does not provide direction through piece vertices..
			float3 pspeed = gu->usRandVector() * 0.1f;
				pspeed.y += 0.2f;

			new CBubbleProjectile(
				pos + gu->usRandVector() * 2.0f,
				pspeed,
				40.0f + gu->usRandFloat() * 30.0f,
				1.0f + gu->usRandFloat() * 2.0f,
				0.01f,
				unit,
				0.3f + gu->usRandFloat() * 0.3f
			);
		} break;

		case SFX_WHITE_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.5f);
			break;
		case SFX_BLACK_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.6f);
			break;
		case SFX_VTOL: {
			const float3 speed =
				unit->speed    * 0.7f +
				unit->frontdir * 0.5f *       relDir.z  +
				unit->updir    * 0.5f * -math::fabs(relDir.y) +
				unit->rightdir * 0.5f *       relDir.x;

			CHeatCloudProjectile* hc = new CHeatCloudProjectile(
				pos,
				speed,
				10 + gu->usRandFloat() * 5,
				3 + gu->usRandFloat() * 2,
				unit
			);
			hc->size = 3;
			break;
		}
		default: {
			if (sfxType & SFX_CEG) {
				// emit defined explosiongenerator
				const unsigned index = sfxType - SFX_CEG;
				if (index >= unit->unitDef->sfxExplGens.size() || unit->unitDef->sfxExplGens[index] == NULL) {
					ShowScriptError("Invalid explosion generator index for emit-sfx");
					break;
				}

				IExplosionGenerator* explGen = unit->unitDef->sfxExplGens[index];
				explGen->Explosion(0, pos, unit->cegDamage, 1, unit, 0, 0, dir);
			}
			else if (sfxType & SFX_FIRE_WEAPON) {
				// make a weapon fire from the piece
				const unsigned index = sfxType - SFX_FIRE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				CWeapon* weapon = unit->weapons[index];

				const float3 targetPos = weapon->targetPos;
				const float3 weaponMuzzlePos = weapon->weaponMuzzlePos;

				weapon->targetPos = pos + dir;
				weapon->weaponMuzzlePos = pos;
				weapon->Fire();
				weapon->weaponMuzzlePos = weaponMuzzlePos;
				weapon->targetPos = targetPos;
			}
			else if (sfxType & SFX_DETONATE_WEAPON) {
				const unsigned index = sfxType - SFX_DETONATE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				// detonate weapon from piece
				const WeaponDef* weaponDef = unit->weapons[index]->weaponDef;

				CGameHelper::ExplosionParams params = {
					pos,
					ZeroVector,
					weaponDef->damages,
					weaponDef,
					unit,                              // owner
					NULL,                              // hitUnit
					NULL,                              // hitFeature
					weaponDef->craterAreaOfEffect,
					weaponDef->damageAreaOfEffect,
					weaponDef->edgeEffectiveness,
					weaponDef->explosionSpeed,
					1.0f,                              // gfxMod
					weaponDef->impactOnly,
					weaponDef->noSelfDamage,           // ignoreOwner
					true,                              // damageGround
				};

				helper->Explosion(params);
			}
		} break;
	}


#endif
}
Exemplo n.º 2
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
}
Exemplo n.º 3
0
void CUnitScript::EmitSfx(int sfxType, int piece)
{
#ifndef _CONSOLE
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for emit-sfx");
		return;
	}

	if (ph->particleSaturation > 1.0f && sfxType < SFX_CEG) {
		// skip adding (unsynced!) particles when we have too many
		return;
	}

	// Make sure wakes are only emitted on water
	if ((sfxType >= SFX_WAKE) && (sfxType <= SFX_REVERSE_WAKE_2)) {
		if (ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 0.0f) {
			return;
		}
	}

	float3 relPos = ZeroVector;
	float3 relDir = UpVector;

	if (!GetEmitDirPos(piece, relPos, relDir)) {
		ShowScriptError("emit-sfx: GetEmitDirPos failed");
		return;
	}

	relDir.SafeNormalize();

	const float3 pos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;
	const float3 dir =
		unit->frontdir * relDir.z +
		unit->updir    * relDir.y +
		unit->rightdir * relDir.x;

	float alpha = 0.3f + gu->usRandFloat() * 0.2f;
	float alphaFalloff = 0.004f;
	float fadeupTime = 4;

	// Hovers need special care
	if (unit->unitDef->canhover) {
		fadeupTime = 8.0f;
		alpha = 0.15f + gu->usRandFloat() * 0.2f;
		alphaFalloff = 0.008f;
	}

	switch (sfxType) {
		case SFX_REVERSE_WAKE:
		case SFX_REVERSE_WAKE_2: {  //reverse wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_WAKE_2:  //wake 2, in TA it lives longer..
		case SFX_WAKE: {  //regular ship wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_BUBBLE: {  //submarine bubble. does not provide direction through piece vertices..
			float3 pspeed = gu->usRandVector() * 0.1f;
				pspeed.y += 0.2f;

			new CBubbleProjectile(
				pos + gu->usRandVector() * 2.0f,
				pspeed,
				40.0f + gu->usRandFloat() * 30.0f,
				1.0f + gu->usRandFloat() * 2.0f,
				0.01f,
				unit,
				0.3f + gu->usRandFloat() * 0.3f
			);
		} break;

		case SFX_WHITE_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.5f);
			break;
		case SFX_BLACK_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.6f);
			break;
		case SFX_VTOL: {
			const float3 speed =
				unit->speed    * 0.7f +
				unit->frontdir * 0.5f *       relDir.z  +
				unit->updir    * 0.5f * -fabs(relDir.y) +
				unit->rightdir * 0.5f *       relDir.x;

			CHeatCloudProjectile* hc = new CHeatCloudProjectile(
				pos,
				speed,
				10 + gu->usRandFloat() * 5,
				3 + gu->usRandFloat() * 2,
				unit
			);
			hc->size = 3;
			break;
		}
		default: {
			if (sfxType & SFX_CEG) {
				// emit defined explosiongenerator
				const unsigned index = sfxType - SFX_CEG;
				if (index >= unit->unitDef->sfxExplGens.size() || unit->unitDef->sfxExplGens[index] == NULL) {
					ShowScriptError("Invalid explosion generator index for emit-sfx");
					break;
				}

				IExplosionGenerator* explGen = unit->unitDef->sfxExplGens[index];
				explGen->Explosion(0, pos, unit->cegDamage, 1, unit, 0, 0, dir);
			}
			else if (sfxType & SFX_FIRE_WEAPON) {
				// make a weapon fire from the piece
				const unsigned index = sfxType - SFX_FIRE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				CWeapon* weapon = unit->weapons[index];

				const float3 targetPos = weapon->targetPos;
				const float3 weaponMuzzlePos = weapon->weaponMuzzlePos;

				// don't override the weapon's target position
				// if it was not set internally (so that force-
				// fire keeps working as expected)
				if (!weapon->haveUserTarget) {
					weapon->targetPos = pos + dir;
				}

				weapon->weaponMuzzlePos = pos;
				weapon->Fire();
				weapon->weaponMuzzlePos = weaponMuzzlePos;

				weapon->targetPos = targetPos;
			}
			else if (sfxType & SFX_DETONATE_WEAPON) {
				const unsigned index = sfxType - SFX_DETONATE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				// detonate weapon from piece
				const WeaponDef* weaponDef = unit->weapons[index]->weaponDef;

				if (weaponDef->soundhit.getID(0) > 0) {
					Channels::Battle.PlaySample(weaponDef->soundhit.getID(0), unit, weaponDef->soundhit.getVolume(0));
				}

				helper->Explosion(
					pos,
					weaponDef->damages,
					weaponDef->areaOfEffect,
					weaponDef->edgeEffectiveness,
					weaponDef->explosionSpeed,
					unit,
					true,
					1.0f,
					weaponDef->noSelfDamage,
					weaponDef->impactOnly,
					weaponDef->explosionGenerator,
					NULL,
					ZeroVector,
					weaponDef->id
				);
			}
		} break;
	}


#endif
}