diff --git a/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl b/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl index 7bd9312f1..b5b6f4a50 100644 --- a/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl +++ b/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl @@ -53,8 +53,8 @@ void main() { float spacedArmorThickness = spacedArmorBufferFragment.r * penetration; remainingPenetration -= spacedArmorThickness; - if (isExplosive && remainingPenetration > 0.0) { - // there is a 50% penetration loss per meter for HE based shells + if (isExplosive && !canSplash && remainingPenetration > 0.0) { + // there is a 50% penetration loss per meter for HEAT shells remainingPenetration -= 0.5 * remainingPenetration * distanceFromSpacedArmor; } } @@ -68,7 +68,7 @@ void main() { // only allow splashing if the damage equation deals more than 0 damage float nominalArmorThickness = finalThickness - remainingPenetration; float finalDamage = 0.5 * damage * (1.0 - distanceFromSpacedArmor / explosionRadius) - 1.1 * nominalArmorThickness; - splashChance = finalDamage > 0.0 ? 1.0 : 0.0; + splashChance = finalDamage > 0.0 ? 1.0 : 0.0; // TODO: add randomization here? } else { splashChance = 0.0; } diff --git a/src/components/Armor/components/ShotDisplay.tsx b/src/components/Armor/components/ShotDisplay.tsx index eda5f8652..cf2ae9ef5 100644 --- a/src/components/Armor/components/ShotDisplay.tsx +++ b/src/components/Armor/components/ShotDisplay.tsx @@ -4,13 +4,17 @@ import { Euler, Quaternion, Vector3 } from 'three'; import { radToDeg } from 'three/src/math/MathUtils'; import { J_HAT } from '../../../constants/axis'; import { isExplosive } from '../../../core/blitz/isExplosive'; +import { NaNFallback } from '../../../core/math/NaNFallback'; import { AngledPenetration } from '../../../icons/AngledPenetration'; import { Block } from '../../../icons/Block'; import { NominalPenetration } from '../../../icons/NominalPenetration'; import { Ricochet } from '../../../icons/Ricochet'; import { useDuel } from '../../../stores/duel'; import { + ShotLayer, + ShotLayerBase, ShotLayerGap, + ShotLayerNonExternal, useTankopediaTemporary, } from '../../../stores/tankopedia'; import { ArmorType } from './SpacedArmorScene'; @@ -79,10 +83,10 @@ export function ShotDisplay() { style={{ backgroundColor: trueStatus === 'penetration' - ? '#00ff0080' + ? '#00ff00c0' : trueStatus === 'blocked' - ? '#ff000080' - : '#ffff0080', + ? '#ff0000c0' + : '#ffff00c0', border: 'none', }} > @@ -93,9 +97,11 @@ export function ShotDisplay() { width: '100%', display: 'block', textAlign: 'center', + color: + trueStatus === 'ricochet' ? 'black' : undefined, }} > - {layer.index + 1} + {layer.index + 1} )} @@ -155,25 +161,54 @@ export function ShotDisplay() { {shot && (() => { + const firstLayer = shot.layers[0] as Exclude; const lastLayer = shot.layers.at(-1)!; - const lastStatus = lastLayer.status; + const midPointLayer = (shot.layers.findLast( + (layer) => layer.type !== null && layer.status === 'ricochet', + ) ?? + shot.layers.findLast( + (layer) => layer.type !== null, + )) as ShotLayerBase; + const distanceFromSpacedArmor = firstLayer.point.distanceTo( + shot.point, + ); + + console.log(distanceFromSpacedArmor); return ( - {lastStatus[0].toUpperCase()} - {lastStatus.slice(1)} - {lastStatus === 'penetration' && - `: ${shell.damage.module}hp`} + {lastLayer.status[0].toUpperCase()} + {lastLayer.status.slice(1)} + {lastLayer.status === 'penetration' && + `: ${Math.round(shell.damage.armor)}hp`} + {lastLayer.status === 'blocked' && + shell.type === 'he' && + `: ${NaNFallback( + Math.max( + 0, + Math.round( + 0.5 * + shell.damage.armor * + (1 - + distanceFromSpacedArmor / + shell.explosionRadius!) - + 1.1 * + (midPointLayer as ShotLayerNonExternal) + .thicknessAngled, + ), + ), + 0, + )}hp`} {shot.layers.map((layer) => { @@ -223,6 +258,7 @@ export function ShotDisplay() { {layer.type === null && ( + {/* why is it x50? i can't pretend to understand this shit */} {Math.round(layer.distance * 1000)}mm (- {Math.round(Math.min(100, layer.distance * 50))}% penetration) diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx index 7bc70448c..426d17479 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx @@ -9,6 +9,7 @@ import { Vector3, } from 'three'; import { degToRad } from 'three/src/math/MathUtils'; +import { canSplash } from '../../../../core/blitz/canSplash'; import { isExplosive } from '../../../../core/blitz/isExplosive'; import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration'; import { hasEquipment } from '../../../../core/blitzkrieg/hasEquipment'; @@ -93,6 +94,7 @@ export function SpacedArmorSceneComponent({ const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1; const shell = useDuel.getState().antagonist!.shell; const explosive = isExplosive(shell.type); + const splashing = canSplash(shell.type); const penetration = resolveNearPenetration(shell.penetration) * (hasCalibratedShells @@ -171,17 +173,17 @@ export function SpacedArmorSceneComponent({ const distance = ( shot.layers.at(-1) as ShotLayerBase ).point.distanceTo(intersections[0].point); - if (explosive) + if (explosive && !splashing) remainingPenetration -= 0.5 * remainingPenetration * distance; - const wasted = remainingPenetration < 0; + const blocked = remainingPenetration < 0; shot.layers.push({ type: null, - status: wasted ? 'blocked' : 'penetration', + status: blocked ? 'blocked' : 'penetration', distance, }); - if (wasted) return; + if (blocked) return; } for (const intersection of intersections) { @@ -197,7 +199,7 @@ export function SpacedArmorSceneComponent({ const previousIntersection = intersections[layerIndex - 1]; const distance = intersection.distance - previousIntersection.distance; - if (explosive) + if (explosive && !splashing) remainingPenetration -= 0.5 * remainingPenetration * distance; const wasted = remainingPenetration < 0; diff --git a/src/core/math/NaNFallback.ts b/src/core/math/NaNFallback.ts new file mode 100644 index 000000000..d1b93b662 --- /dev/null +++ b/src/core/math/NaNFallback.ts @@ -0,0 +1,3 @@ +export function NaNFallback(value: number, fallback: number) { + return isNaN(value) ? fallback : value; +} diff --git a/src/stores/tankopedia.ts b/src/stores/tankopedia.ts index 43879b663..3cbaeb781 100644 --- a/src/stores/tankopedia.ts +++ b/src/stores/tankopedia.ts @@ -57,7 +57,7 @@ interface ShotLayerExternal extends ShotLayerBase { type: ArmorType.External; } -interface ShotLayerNonExternal extends ShotLayerBase { +export interface ShotLayerNonExternal extends ShotLayerBase { type: Exclude; angle: number; thicknessAngled: number;