public ShootTestResult GetShootTestResult(TestShellInfo testShell) { PenetrationState penetrationState = PenetrationState.NotApplicable; double equivalentThickness = 0.0; double impactAngle = 0.0; double nomarlizationAngle = 0.0; bool is2x = false; bool is3x = false; bool mayRicochet = true; bool heatExploded = false; double heatExplodedDistance = 0.0; bool isFirstHit = true; var orderedHits = Hits.OrderBy((h) => h.Distance); foreach (var hit in orderedHits) { var thisImpactAngle = DXUtils.ConvertRadiansToDegrees(Math.Acos(hit.InjectionCosine)); if (isFirstHit) { impactAngle = thisImpactAngle; } if (hit.Armor.UseHitAngle && hit.Armor.Thickness != 0.0) { mayRicochet = mayRicochet && hit.Armor.MayRicochet; double thisNomarlizationAngle = testShell.ShellType.GetBaseNormalization(); if (testShell.Caliber >= hit.Armor.Thickness * 3.0 && testShell.ShellType.HasNormalizationEffect()) { is3x = true; is2x = true; mayRicochet = false; thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness; } else if (testShell.Caliber >= hit.Armor.Thickness * 2.0 && testShell.ShellType.HasNormalizationEffect()) { is3x = false; is2x = testShell.ShellType.HasNormalizationEffect(); thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness; } if (mayRicochet && thisImpactAngle > testShell.ShellType.GetRicochetAngle()) { penetrationState = PenetrationState.Richochet; break; } if (isFirstHit && testShell.ShellType.HasNormalizationEffect()) { if (thisNomarlizationAngle > thisImpactAngle) { thisNomarlizationAngle = thisImpactAngle; } thisImpactAngle -= thisNomarlizationAngle; nomarlizationAngle = thisNomarlizationAngle; } if (!heatExploded) { equivalentThickness += hit.Armor.Thickness / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle)); } else { var distance = (hit.Distance - heatExplodedDistance); var attenuation = 1 - distance * 0.5; if (attenuation < 0) { penetrationState = PenetrationState.Unpenetratable; break; } equivalentThickness += hit.Armor.Thickness / attenuation / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle)); } } else { if (!heatExploded) { equivalentThickness += hit.Armor.Thickness; } else { var distance = (hit.Distance - heatExplodedDistance); var attenuation = 1 - distance * 0.5; if (attenuation < 0) { penetrationState = PenetrationState.Unpenetratable; break; } equivalentThickness += hit.Armor.Thickness / attenuation; } } if (!hit.Armor.IsSpacedArmor) { if (equivalentThickness < 999.0) { penetrationState = PenetrationState.Penetratable; } else { penetrationState = PenetrationState.Unpenetratable; } break; } else { if (testShell.ShellType == ShellType.HE || testShell.ShellType == ShellType.PremiumHE) { penetrationState = PenetrationState.Unpenetratable; break; } else if (testShell.ShellType == ShellType.HEAT && isFirstHit) { heatExploded = true; heatExplodedDistance = hit.Distance; mayRicochet = false; } } isFirstHit = false; } return(new ShootTestResult(penetrationState, equivalentThickness, impactAngle, nomarlizationAngle, is2x, is3x)); }
public void Refresh(TestShellInfo testShell) { this.LogInfo("refresh"); _tracerLines = new List <TracerLineVertex>(); _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position, Penetration = 0 }); PenetrationState penetrationState = PenetrationState.NotApplicable; bool mayRicochet = true; float equivalentThickness = 0.0f; float heatExplodedDistance = 0.0f; bool heatExploded = false; foreach (var hit in _orderedHits) { _hitMeshs.Add(hit.Mesh); if (!heatExploded) { _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness }); } var thisImpactAngle = DXUtils.ConvertRadiansToDegrees(Math.Acos(hit.InjectionCosine)); if (hit.Armor.UseHitAngle && hit.Armor.Thickness != 0.0) { mayRicochet = mayRicochet && hit.Armor.MayRicochet; double thisNomarlizationAngle = testShell.ShellType.GetBaseNormalization(); if (testShell.Caliber >= hit.Armor.Thickness * 3.0) { mayRicochet = false; thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness; } else if (testShell.Caliber >= hit.Armor.Thickness * 2.0) { thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness; } if (mayRicochet && thisImpactAngle > testShell.ShellType.GetRicochetAngle()) { penetrationState = PenetrationState.Richochet; break; } if (testShell.ShellType.HasNormalizationEffect()) { if (thisNomarlizationAngle > thisImpactAngle) { thisNomarlizationAngle = thisImpactAngle; } thisImpactAngle -= thisNomarlizationAngle; } if (!heatExploded) { equivalentThickness += (float)(hit.Armor.Thickness / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle))); } else { var distance = (hit.Distance - heatExplodedDistance); var attenuation = 1 - distance * 0.5; if (attenuation < 0) { _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = 0 }); penetrationState = PenetrationState.Unpenetratable; break; } equivalentThickness += (float)(hit.Armor.Thickness / attenuation / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle))); _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness }); } } else { if (!heatExploded) { equivalentThickness += (float)hit.Armor.Thickness; } else { var distance = (hit.Distance - heatExplodedDistance); var attenuation = 1 - distance * 0.5; if (attenuation < 0) { _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = 0 }); penetrationState = PenetrationState.Unpenetratable; break; } equivalentThickness += (float)(hit.Armor.Thickness / attenuation); _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness }); } } if (!hit.Armor.IsSpacedArmor) { penetrationState = PenetrationState.Penetratable; break; } else { if (testShell.ShellType == ShellType.HE || testShell.ShellType == ShellType.PremiumHE) { penetrationState = PenetrationState.Unpenetratable; break; } else if (testShell.ShellType == ShellType.HEAT && !heatExploded) { heatExploded = true; heatExplodedDistance = hit.Distance; mayRicochet = false; } } _tracerLines.Add(new TracerLineVertex() { Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness }); } if (penetrationState == PenetrationState.Penetratable) { for (int i = 0; i != _tracerLines.Count; ++i) { _tracerLines[i] = new TracerLineVertex() { Position = _tracerLines[i].Position, Penetration = (equivalentThickness - _tracerLines[i].Penetration) * 0.5f }; } } else if (penetrationState == PenetrationState.Richochet || penetrationState == PenetrationState.Unpenetratable || penetrationState == PenetrationState.NotApplicable) { for (int i = 0; i != _tracerLines.Count; ++i) { _tracerLines[i] = new TracerLineVertex() { Position = _tracerLines[i].Position, Penetration = -1.0f }; } } BuildCollision(); }