void CDestructibleModel::DoExplosion(char* pTargetName) { CWeapons weapons; weapons.Init(m_hObject); weapons.ObtainWeapon(m_nExplosionWeaponId); weapons.ChangeWeapon(m_nExplosionWeaponId); CWeapon* pWeapon = weapons.GetCurWeapon(); if (!pWeapon) return; weapons.SetAmmo(pWeapon->GetAmmoId()); pWeapon->SetDamageFactor(m_fDamageFactor); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); LTVector vF, vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); vF = rRot.Forward(); // Just blow up in place if we're not supposed to fire along // forward vector and we don't have a target... if (!m_bFireAlongForward) { pWeapon->SetLifetime(0.0f); VEC_SET(vF, 0.0f, -1.0f, 0.0f); // Fire down } // See if we have a target...If so, point at it. if (pTargetName) { ObjArray <HOBJECT, MAX_OBJECT_ARRAY_SIZE> objArray; g_pLTServer->FindNamedObjects(pTargetName, objArray); if (objArray.NumObjects()) { LTVector vObjPos; g_pLTServer->GetObjectPos(objArray.GetObject(0), &vObjPos); vF = vObjPos - vPos; vF.Normalize(); rRot = LTRotation(vF, LTVector(0.0f, 1.0f, 0.0f)); g_pLTServer->SetObjectRotation(m_hObject, &rRot); } } WeaponFireInfo weaponFireInfo; weaponFireInfo.hFiredFrom = m_hObject; weaponFireInfo.vPath = vF; weaponFireInfo.vFirePos = vPos; weaponFireInfo.vFlashPos = vPos; pWeapon->Fire(weaponFireInfo); }
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 }
void CUnitScript::EmitSfx(int type, int piece) { #ifndef _CONSOLE if (!PieceExists(piece)) { ShowScriptError("Invalid piecenumber for emit-sfx"); return; } if (ph->particleSaturation > 1 && type < 1024) { // skip adding (unsynced!) particles when we have too many return; } float3 relPos = ZeroVector; float3 relDir = UpVector; if (!GetEmitDirPos(piece, relPos, relDir)) { ShowScriptError("emit-sfx: GetEmitDirPos failed"); return; } 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; } //Make sure wakes are only emitted on water if ((type >= 2) && (type <= 5)) { if (ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 0) { return; } } switch (type) { case SFX_REVERSE_WAKE: case SFX_REVERSE_WAKE_2: { //reverse wake relDir *= -0.2f; 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 relDir *= 0.2f; 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: { //vtol relDir *= 0.2f; const float3 udir = unit->frontdir * relDir.z + unit->updir * -fabs(relDir.y) + unit->rightdir * relDir.x; CHeatCloudProjectile* hc = new CHeatCloudProjectile( pos, unit->speed * 0.7f + udir * 0.5f, 10 + gu->usRandFloat() * 5, 3 + gu->usRandFloat() * 2, unit ); hc->size = 3; break; } default: { if (type & SFX_CEG) { // emit defined explosiongenerator const unsigned index = type - SFX_CEG; if (index >= unit->unitDef->sfxExplGens.size() || unit->unitDef->sfxExplGens[index] == NULL) { ShowScriptError("Invalid explosion generator index for emit-sfx"); break; } float3 ndir = dir; CExplosionGenerator* explGen = unit->unitDef->sfxExplGens[index]; explGen->Explosion(pos, unit->cegDamage, 1, unit, 0, 0, ndir.SafeNormalize()); } else if (type & SFX_FIRE_WEAPON) { // make a weapon fire from the piece const unsigned index = type - 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; float3 ndir = dir; // 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 + ndir.SafeNormalize(); } weapon->weaponMuzzlePos = pos; weapon->Fire(); weapon->weaponMuzzlePos = weaponMuzzlePos; weapon->targetPos = targetPos; } else if (type & SFX_DETONATE_WEAPON) { const unsigned index = type - 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, float3(0, 0, 0), weaponDef->id ); } } break; } #endif }
void CUnitScript::EmitSfx(int sfxType, int piece) { #ifndef _CONSOLE if (!PieceExists(piece)) { ShowUnitScriptError("Invalid piecenumber for emit-sfx"); return; } if (projectileHandler->GetParticleSaturation() > 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 (CGround::GetApproximateHeight(unit->pos.x, unit->pos.z) > 0.0f) { return; } } float3 relPos = ZeroVector; float3 relDir = UpVector; if (!GetEmitDirPos(piece, relPos, relDir)) { ShowUnitScriptError("emit-sfx: GetEmitDirPos failed"); return; } relDir.SafeNormalize(); const float3 pos = unit->GetObjectSpacePos(relPos); const float3 dir = unit->GetObjectSpaceVec(relDir); float alpha = 0.3f + gu->RandFloat() * 0.2f; float alphaFalloff = 0.004f; float fadeupTime = 4; const UnitDef* ud = unit->unitDef; const MoveDef* md = unit->moveDef; // hovercraft need special care if (md != NULL && md->speedModClass == MoveDef::Hover) { fadeupTime = 8.0f; alpha = 0.15f + gu->RandFloat() * 0.2f; alphaFalloff = 0.008f; } switch (sfxType) { case SFX_REVERSE_WAKE: case SFX_REVERSE_WAKE_2: { //reverse wake new CWakeProjectile( unit, pos + gu->RandVector() * 2.0f, dir * 0.4f, 6.0f + gu->RandFloat() * 4.0f, 0.15f + gu->RandFloat() * 0.3f, alpha, alphaFalloff, fadeupTime ); break; } case SFX_WAKE_2: //wake 2, in TA it lives longer.. case SFX_WAKE: { //regular ship wake new CWakeProjectile( unit, pos + gu->RandVector() * 2.0f, dir * 0.4f, 6.0f + gu->RandFloat() * 4.0f, 0.15f + gu->RandFloat() * 0.3f, alpha, alphaFalloff, fadeupTime ); break; } case SFX_BUBBLE: { //submarine bubble. does not provide direction through piece vertices.. float3 pspeed = gu->RandVector() * 0.1f; pspeed.y += 0.2f; new CBubbleProjectile( unit, pos + gu->RandVector() * 2.0f, pspeed, 40.0f + gu->RandFloat() * GAME_SPEED, 1.0f + gu->RandFloat() * 2.0f, 0.01f, 0.3f + gu->RandFloat() * 0.3f ); } break; case SFX_WHITE_SMOKE: //damaged unit smoke new CSmokeProjectile(unit, pos, gu->RandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, 0.5f); break; case SFX_BLACK_SMOKE: //damaged unit smoke new CSmokeProjectile(unit, pos, gu->RandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, 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( unit, pos, speed, 10 + gu->RandFloat() * 5, 3 + gu->RandFloat() * 2 ); hc->size = 3; break; } default: { if (sfxType & SFX_CEG) { // emit defined explosion-generator (can only be custom, not standard) // index is made valid by callee, an ID of -1 means CEG failed to load explGenHandler->GenExplosion(ud->GetModelExplosionGeneratorID(sfxType - SFX_CEG), pos, dir, unit->cegDamage, 1.0f, 0.0f, unit, NULL); } 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()) { ShowUnitScriptError("Invalid weapon index for emit-sfx"); break; } CWeapon* w = unit->weapons[index]; const SWeaponTarget origTarget = w->GetCurrentTarget(); const float3 origWeaponMuzzlePos = w->weaponMuzzlePos; w->SetAttackTarget(SWeaponTarget(pos + dir)); w->weaponMuzzlePos = pos; w->Fire(true); w->weaponMuzzlePos = origWeaponMuzzlePos; bool origRestored = w->Attack(origTarget); assert(origRestored); } else if (sfxType & SFX_DETONATE_WEAPON) { const unsigned index = sfxType - SFX_DETONATE_WEAPON; if (index >= unit->weapons.size()) { ShowUnitScriptError("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 -1u // projectileID }; helper->Explosion(params); } } break; } #endif }