From ca454bfc7a84b545ba60e92bd85118a56bbee59e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 16 May 2026 19:53:54 +0100 Subject: [PATCH] add projectile example changes These changes are a placeholder because technically we could remove the effects from the projectile class altogether. but for now it fires the effects and uses the projectiles explosion/emitter as a fallback. Also added a specific Ricochet sound effect --- Engine/source/T3D/projectile.cpp | 69 +++++++++++++++++-- .../materials/materialPropertiesManager.cpp | 16 ++++- .../materials/materialPropertiesManager.h | 3 + 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index 4476d70dd..55dbee5e5 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -57,6 +57,7 @@ #include "T3D/lightDescription.h" #include "console/engineAPI.h" #include "T3D/rigidShape.h" +#include "materials/materialPropertiesManager.h" IMPLEMENT_CO_DATABLOCK_V1(ProjectileData); @@ -1122,8 +1123,14 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT } } - // Client (impact) decal. - if ( mDataBlock->decal ) + RayInfo matRay; + BaseMatInstance* hitMat = NULL; + if (gClientContainer.castRay(p + n * 0.05f, p - n * 0.01f, csmStaticCollisionMask, &matRay)) + hitMat = matRay.material; + + // Fallback to datablock decal if no surface effect matched + MaterialPropertiesData* fx = MaterialFXManager.resolve(hitMat); + if (!fx && mDataBlock->decal) gDecalManager->addDecal(p, n, 0.0f, mDataBlock->decal); // Client object @@ -1267,10 +1274,62 @@ void Projectile::simulate( F32 dt ) // specific code should be placed inside the function! onCollision( rInfo.point, rInfo.normal, rInfo.object ); // Next order of business: do we explode on this hit? - if ( mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0 ) + if (mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0) { - mCurrVelocity = Point3F::Zero; - explode( rInfo.point, rInfo.normal, objectType ); + MaterialPropertiesResult fx_result = resolveImpact( + rInfo.material, + mCurrVelocity, + rInfo.normal, + mDataBlock->impactForce, + false); + + // Fire visual effects on client only + if (isClientObject()) + { + MaterialFXManager.fireEffect( + rInfo.material, + rInfo.point, + rInfo.normal, + mCurrVelocity.len(), + mDataBlock->impactForce, + fx_result.didRicochet, + false); + } + + if (fx_result.didRicochet) + { + mCurrVelocity = fx_result.ricochetDirection * fx_result.ricochetSpeed; + newPosition = rInfo.point + rInfo.normal * 0.05f; + } + + if (fx_result.didPenetrate) + { + mCurrVelocity *= fx_result.remainingVelocityFactor; + VectorF normVel = mCurrVelocity; + normVel.normalizeSafe(); + newPosition = rInfo.point + normVel * 0.1f; + } + + if (fx_result.didPenetrate || fx_result.didRicochet) + { + if (isServerObject()) + setMaskBits(BounceMask); + + if (disableSourceObjCollision) + mSourceObject->enableCollision(); + enableCollision(); + + mCurrDeltaBase = newPosition; + mCurrBackDelta = mCurrPosition - newPosition; + mCurrPosition = newPosition; + + xform.setColumn(3, mCurrPosition); + setTransform(xform); + return; + } + + mCurrVelocity = Point3F::Zero; + explode(rInfo.point, rInfo.normal, objectType); } if ( mDataBlock->isBallistic ) diff --git a/Engine/source/materials/materialPropertiesManager.cpp b/Engine/source/materials/materialPropertiesManager.cpp index 3718d9a69..a2d91e95b 100644 --- a/Engine/source/materials/materialPropertiesManager.cpp +++ b/Engine/source/materials/materialPropertiesManager.cpp @@ -26,6 +26,7 @@ MaterialPropertiesData::MaterialPropertiesData() INIT_ASSET(SoftImpactSound); INIT_ASSET(MediumImpactSound); INIT_ASSET(HardImpactSound); + INIT_ASSET(RicochetSound); INIT_ASSET(MeleeSoftSound); INIT_ASSET(MeleeHardSound); @@ -106,6 +107,8 @@ void MaterialPropertiesData::initPersistFields() "Sound for medium-velocity impacts."); INITPERSISTFIELD_SOUNDASSET(HardImpactSound, MaterialPropertiesData, "Sound for high-velocity impacts (bullets, fast projectiles)."); + INITPERSISTFIELD_SOUNDASSET(RicochetSound, MaterialPropertiesData, + "Sound for high-velocity ricochets (bullets, fast projectiles)."); INITPERSISTFIELD_SOUNDASSET(MeleeSoftSound, MaterialPropertiesData, "Melee soft hit sound override. Falls back to SoftImpactSound."); INITPERSISTFIELD_SOUNDASSET(MeleeHardSound, MaterialPropertiesData, @@ -262,6 +265,11 @@ bool MaterialPropertiesData::preload(bool server, String& errorStr) getHardImpactSoundProfile(); } + if (isRicochetSoundValid()) + { + getRicochetSoundProfile(); + } + if (isMeleeSoftSoundValid()) { getMeleeSoftSoundProfile(); @@ -287,6 +295,7 @@ void MaterialPropertiesData::packData(BitStream* stream) PACKDATA_SOUNDASSET(SoftImpactSound); PACKDATA_SOUNDASSET(MediumImpactSound); PACKDATA_SOUNDASSET(HardImpactSound); + PACKDATA_SOUNDASSET(RicochetSound); PACKDATA_SOUNDASSET(MeleeSoftSound); PACKDATA_SOUNDASSET(MeleeHardSound); @@ -338,6 +347,7 @@ void MaterialPropertiesData::unpackData(BitStream* stream) UNPACKDATA_SOUNDASSET(SoftImpactSound); UNPACKDATA_SOUNDASSET(MediumImpactSound); UNPACKDATA_SOUNDASSET(HardImpactSound); + UNPACKDATA_SOUNDASSET(RicochetSound); UNPACKDATA_SOUNDASSET(MeleeSoftSound); UNPACKDATA_SOUNDASSET(MeleeHardSound); @@ -462,6 +472,7 @@ void MaterialPropertiesManager::fireEffect(BaseMatInstance* mat, F32 impactVelocity, F32 impactForce, bool isMelee, + bool isRicochet, bool clientOnly) { MaterialPropertiesData* fx = resolve(mat); @@ -491,6 +502,9 @@ void MaterialPropertiesManager::fireEffect(BaseMatInstance* mat, snd = fx->getHardImpactSoundProfile(); else snd = fx->getMediumImpactSoundProfile(); + + if (isRicochet && fx->isRicochetSoundValid()) + snd = fx->getRicochetSoundProfile(); } if (snd) @@ -579,7 +593,7 @@ MaterialPropertiesResult resolveImpact( BaseMatInstance* mat, F32 glanceDeg = mRadToDeg(mAcos(mClampF(cosGlance, 0.0f, 1.0f))); - bool angleOk = (90.0f - glanceDeg) >= fx->ricochetMinAngle; + bool angleOk = glanceDeg >= fx->ricochetMinAngle; if (angleOk && gRandGen.randF() < fx->ricochetChance) { diff --git a/Engine/source/materials/materialPropertiesManager.h b/Engine/source/materials/materialPropertiesManager.h index e5c2b25a6..4f242fd5b 100644 --- a/Engine/source/materials/materialPropertiesManager.h +++ b/Engine/source/materials/materialPropertiesManager.h @@ -55,6 +55,8 @@ public: DECLARE_ASSET_SETGET(MaterialPropertiesData, MediumImpactSound) DECLARE_SOUNDASSET(MaterialPropertiesData, HardImpactSound) DECLARE_ASSET_SETGET(MaterialPropertiesData, HardImpactSound) + DECLARE_SOUNDASSET(MaterialPropertiesData, RicochetSound) + DECLARE_ASSET_SETGET(MaterialPropertiesData, RicochetSound) // Optional: separate sounds for melee (crowbar clink vs bullet ping // on the same metal surface feel very different) @@ -180,6 +182,7 @@ public: F32 impactVelocity, F32 impactForce, bool isMelee, + bool isRicochet, bool clientOnly = true); void setDefaultEffect(MaterialPropertiesData* data);