void CGameHelper::DoExplosionDamage(CFeature* feature, const float3& expPos, float expRad, CUnit* owner, const DamageArray& damages) { CollisionVolume* cv = feature->collisionVolume; if (cv) { float3 dif = (feature->midPos + cv->GetOffsets()) - expPos; float expDist = std::max(dif.Length(), 0.1f); float expMod = (expRad - expDist) / expRad; // always do some damage with explosive stuff // (DDM wreckage etc. is too big to normally // be damaged otherwise, even by BB shells) // NOTE: this will also be only approximate // for non-spherical volumes if ((expRad > 8.0f) && (expDist < (cv->GetBoundingRadius() * 1.1f)) && (expMod < 0.1f)) { expMod = 0.1f; } if (expMod > 0.0f) { feature->DoDamage(damages * expMod, owner, dif * (damages.impulseFactor * expMod / expDist * (damages[0] + damages.impulseBoost))); } } }
bool CWeapon::AdjustTargetVectorLength( CUnit* targetUnit, float3& targetPos, float3& targetVec, float3& targetDir) const { bool retCode = false; const float tbScale = math::fabsf(targetBorder); CollisionVolume* cvOld = targetUnit->collisionVolume; CollisionVolume cvNew = CollisionVolume(targetUnit->collisionVolume); CollisionQuery cq; // test for "collision" with a temporarily volume // (scaled uniformly by the absolute target-border // factor) cvNew.RescaleAxes(tbScale, tbScale, tbScale); cvNew.SetTestType(CollisionVolume::COLVOL_HITTEST_DISC); targetUnit->collisionVolume = &cvNew; if (CCollisionHandler::DetectHit(targetUnit, weaponMuzzlePos, ZeroVector, NULL)) { // our weapon muzzle is inside the target unit's volume; this // means we do not need to make any adjustments to targetVec targetVec = ZeroVector; } else { targetDir.SafeNormalize(); // otherwise, perform a raytrace to find the proper length correction // factor for non-spherical coldet volumes based on the ray's ingress // (for positive TB values) or egress (for negative TB values) position; // this either increases or decreases the length of <targetVec> but does // not change its direction cvNew.SetTestType(CollisionVolume::COLVOL_HITTEST_CONT); // make the ray-segment long enough so it can reach the far side of the // scaled collision volume (helps to ensure a ray-intersection is found) // // note: ray-intersection is NOT guaranteed if the volume itself has a // non-zero offset, since here we are "shooting" at the target UNIT's // midpoint const float3 targetOffset = targetDir * (cvNew.GetBoundingRadius() * 2.0f); const float3 targetRayPos = targetPos + targetOffset; if (CCollisionHandler::DetectHit(targetUnit, weaponMuzzlePos, targetRayPos, &cq)) { if (targetBorder > 0.0f) { targetVec -= (targetDir * ((targetPos - cq.p0).Length())); } if (targetBorder < 0.0f) { targetVec += (targetDir * ((cq.p1 - targetPos).Length())); } } retCode = true; } targetUnit->collisionVolume = cvOld; // true indicates we took the else-branch and targetDir is now normalized return retCode; }