From 199e156e53e060d6ae41afe3ae74b81db546160d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Thu, 29 Feb 2024 12:42:15 -0600
Subject: [PATCH] feat: more accurate HE
---
.../shaders/fragment.glsl | 6 +-
.../Armor/components/ShotDisplay.tsx | 58 +++++++++++++++----
.../SpacedArmorSceneComponent/index.tsx | 12 ++--
src/core/math/NaNFallback.ts | 3 +
src/stores/tankopedia.ts | 2 +-
5 files changed, 61 insertions(+), 20 deletions(-)
create mode 100644 src/core/math/NaNFallback.ts
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;