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; }