diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5b3999774..17e5e3eb5 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -91,6 +91,7 @@
"malum",
"mantlets",
"metallicness",
+ "metalness",
"minitelrose",
"Minotauro",
"MIPMAPCOUNT",
diff --git a/docs/changelogs/1.20.5.md b/docs/changelogs/1.20.5.md
new file mode 100644
index 000000000..8a6f4ca1f
--- /dev/null
+++ b/docs/changelogs/1.20.5.md
@@ -0,0 +1,28 @@
+# BlitzKit 1.20.5
+
+Some QOL changes incoming!
+
+## Changes
+
+- The penetration of the shooter is now displayed above the shell switcher
+- The shot display card is now shown below the tank instead of to the side on narrow screens
+- Added a few more stats to Compare and Tankopedia
+ - Max dispersion
+ - Clipping potential for auto-loaders and auto-reloaders
+ - Raw terrain resistance coefficients
+- Renamed the "Fire" section to "Firepower"
+- The shell selector for the protagonist tank has been moved to the Firepower section's title
+- The table layout of Compare has been compacted and indented in places
+- The tank class and type has now displayed in the hero section of the Tankopedia
+- Removed the default tier X filter
+- Added draggable tracks
+- Added the ability to sort by premium shell DPM
+
+## Fixes
+
+- Clicking enter no longer changes the tank you're viewing when selecting the shooter tank
+- The open in new tab button in Compare now opens in a new tab
+- HEAT shells no longer display ricochet angle
+- The gun depression is now properly reported for the Minotauro line
+- Stopped autofocus of the ghost button in the login card
+- Patreon login now handles bad responses
diff --git a/package.json b/package.json
index 68dade06a..bebbeda26 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "blitzkit",
- "version": "1.20.4",
+ "version": "1.20.5",
"description": "🎉 Tools for everything World of Tanks Blitz",
"main": "src/server.ts",
"type": "module",
diff --git a/src/app/tools/compare/components/TankControl.tsx b/src/app/tools/compare/components/TankControl.tsx
index 423cfe95d..db2fdb73d 100644
--- a/src/app/tools/compare/components/TankControl.tsx
+++ b/src/app/tools/compare/components/TankControl.tsx
@@ -66,7 +66,7 @@ export function TankControl({ index, id }: TankControlProps) {
-
+
diff --git a/src/app/tools/compare/page.tsx b/src/app/tools/compare/page.tsx
index 30d002922..c77980687 100644
--- a/src/app/tools/compare/page.tsx
+++ b/src/app/tools/compare/page.tsx
@@ -178,6 +178,7 @@ export default function Page() {
deltaType = 'higherIsBetter',
decimals,
deltaNominalDisplay,
+ indent,
}: {
name: string;
value:
@@ -191,6 +192,7 @@ export default function Page() {
deltaType?: 'higherIsBetter' | 'lowerIsBetter';
decimals?: number;
deltaNominalDisplay?: (delta: number) => string | number;
+ indent?: boolean;
}) {
const values = stats.map((stat) =>
typeof value === 'function' ? value(stat)! : (stat[value] as number),
@@ -199,7 +201,11 @@ export default function Page() {
return (
-
+
0 && (
-
+
-
-
- {gun.shells.map((thisShell, shellIndex) => (
- {
- mutateCompareTemporary((draft) => {
- draft.members[index].shell = thisShell;
- });
- }}
- >
-
-
- ))}
-
);
@@ -1211,7 +1174,62 @@ export default function Page() {
- Fire
+
+
+
+
+ Firepower
+
+
+
+ {members.map(({ gun, shell, key }, index) => (
+
+
+
+ {gun.shells.map((thisShell, shellIndex) => (
+ {
+ mutateCompareTemporary((draft) => {
+ draft.members[index].shell = thisShell;
+ });
+ }}
+ >
+
+
+ ))}
+
+
+
+ ))}
+
+
+ {hasNonRegularGun && (
+
+ )}
+
-
+
Maneuverability
+
+
+
@@ -1334,17 +1397,19 @@ export default function Page() {
decimals={1}
/>
@@ -1362,19 +1427,21 @@ export default function Page() {
/>
(stats.camouflageStill * 100).toFixed(0)}
deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)}
/>
(stats.camouflageMoving * 100).toFixed(0)}
deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)}
/>
(stats.camouflageShootingStill * 100).toFixed(0)
@@ -1382,7 +1449,8 @@ export default function Page() {
deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)}
/>
(stats.camouflageShootingMoving * 100).toFixed(0)
@@ -1390,7 +1458,8 @@ export default function Page() {
deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)}
/>
(stats.camouflageCaughtOnFire * 100).toFixed(0)
@@ -1398,29 +1467,32 @@ export default function Page() {
deltaNominalDisplay={(delta) => (delta * 100).toFixed(0)}
/>
+
-
diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx
index deca9b5df..9b2fcb026 100644
--- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx
@@ -139,7 +139,7 @@ export function Characteristics() {
- Fire
+ Firepower
{gun.shells.map((thisShell, shellIndex) => (
@@ -297,6 +297,11 @@ export function Characteristics() {
{stats.damage}
+ {gun.type !== 'regular' && (
+
+ {stats.clipDamage!}
+
+ )}
{stats.moduleDamage}
@@ -388,6 +393,15 @@ export function Characteristics() {
>
{stats.dispersionGunDamaged}
+
+ {stats.maxDispersion}
+
{stats.gunDepression}
@@ -520,6 +534,16 @@ export function Characteristics() {
>
{stats.weight}
+
+
+ {stats.hardTerrainCoefficient}
+
+
+ {stats.mediumTerrainCoefficient}
+
+
+ {stats.softTerrainCoefficient}
+
{stats.powerToWeightRatioHardTerrain}
diff --git a/src/app/tools/tankopedia/[id]/components/Control.tsx b/src/app/tools/tankopedia/[id]/components/Control.tsx
index 316d4529d..10ba7cd5a 100644
--- a/src/app/tools/tankopedia/[id]/components/Control.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Control.tsx
@@ -9,7 +9,7 @@ import { modelDefinitions } from '../../../../../core/blitzkit/modelDefinitions'
import { Pose, poseEvent } from '../../../../../core/blitzkit/pose';
import { useAwait } from '../../../../../hooks/useAwait';
import { useDuel } from '../../../../../stores/duel';
-import { useTankopediaPersistent } from '../../../../../stores/tankopedia';
+import { useTankopediaTemporary } from '../../../../../stores/tankopedia';
const poseDistances: Record = {
[Pose.HullDown]: 15,
@@ -62,8 +62,8 @@ export function Controls() {
}, [camera]);
useEffect(() => {
- const unsubscribeTankopedia = useTankopediaPersistent.subscribe(
- (state) => state.model.visual.controlsEnabled,
+ const unsubscribeTankopedia = useTankopediaTemporary.subscribe(
+ (state) => state.controlsEnabled,
(enabled) => {
if (orbitControls.current) orbitControls.current.enabled = enabled;
},
@@ -182,7 +182,7 @@ export function Controls() {
maxDistance={20}
minDistance={5}
ref={orbitControls}
- enabled={useTankopediaPersistent.getState().model.visual.controlsEnabled}
+ enabled={useTankopediaTemporary.getState().controlsEnabled}
rotateSpeed={0.25}
enableDamping={false}
autoRotate={autoRotate}
diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx
index bf9f68b85..f2a1482d6 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx
@@ -1,6 +1,7 @@
import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons';
import { Button, Flex, Heading, Text } from '@radix-ui/themes';
import Link from 'next/link';
+import { classIcons } from '../../../../../../components/ClassIcon';
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
@@ -11,14 +12,15 @@ import { TankSandbox } from './TankSandbox';
import { Options } from './components/Options';
export function HeroSection() {
- const protagonistTank = useDuel((state) => state.protagonist!.tank);
- const antagonistTank = useDuel((state) => state.antagonist!.tank);
+ const protagonist = useDuel((state) => state.protagonist!.tank);
+ const antagonist = useDuel((state) => state.antagonist!.tank);
const wideFormat = useWideFormat(880);
const compareTanks =
- protagonistTank.id === antagonistTank.id
- ? [protagonistTank.id]
- : [protagonistTank.id, antagonistTank.id];
+ protagonist.id === antagonist.id
+ ? [protagonist.id]
+ : [protagonist.id, antagonist.id];
const isFullScreen = useFullScreen();
+ const Icon = classIcons[protagonist.class];
return (
- {protagonistTank.nameFull ?? protagonistTank.name}
+ {' '}
+ {protagonist.nameFull ?? protagonist.name}
- Tier {TIER_ROMAN_NUMERALS[protagonistTank.tier]}{' '}
+ Tier {TIER_ROMAN_NUMERALS[protagonist.tier]}{' '}
{
(strings.common.nations_adjectives as Record)[
- protagonistTank.nation
+ protagonist.nation
]
}{' '}
- {strings.common.tank_class_short[protagonistTank.class]}
+ {strings.common.tank_class_short[protagonist.class]}
diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx
index fe3606d10..ed9d79b1f 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx
@@ -22,6 +22,7 @@ import { useState } from 'react';
import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton';
import { SmallTankIcon } from '../../../../../../../components/SmallTankIcon';
import { resolveNearPenetration } from '../../../../../../../core/blitz/resolveNearPenetration';
+import { resolvePenetrationCoefficient } from '../../../../../../../core/blitz/resolvePenetrationCoefficient';
import { asset } from '../../../../../../../core/blitzkit/asset';
import { Pose, poseEvent } from '../../../../../../../core/blitzkit/pose';
import {
@@ -113,7 +114,17 @@ export function Options() {
top: '50%',
transform: 'translateY(-50%)',
}}
+ align="end"
>
+
+ {(
+ resolvePenetrationCoefficient(
+ hasCalibratedShells,
+ antagonistShell.type,
+ ) * resolveNearPenetration(antagonistShell.penetration)
+ ).toFixed(0)}
+ mm
+
{antagonistGun.shells.map((thisShell, shellIndex) => (
))}
-
{
const awaitedModelDefinitions = useAwait(modelDefinitions);
@@ -117,11 +122,52 @@ export const TankModel = memo(() => {
const isWheel = node.name.startsWith('chassis_wheel_');
const isTrack = node.name.startsWith('chassis_track_');
const isVisible = isHull || isWheel || isTrack;
+ const position = new Vector2();
+ const delta = new Vector2();
if (!isVisible) return null;
+ function translateTexture(offset: number) {
+ const mesh = node.children[0] as Mesh;
+ const material = mesh?.material as MeshStandardMaterial;
+
+ if (!material) return;
+
+ if (material.map) material.map.offset.y += offset;
+ if (material.aoMap) material.aoMap.offset.y += offset;
+ if (material.normalMap) material.normalMap.offset.y += offset;
+ if (material.roughnessMap) material.roughnessMap.offset.y += offset;
+ if (material.metalnessMap) material.metalnessMap.offset.y += offset;
+ }
+
function onPointerDown(event: ThreeEvent) {
+ if (!isTrack) return;
+
+ position.set(event.clientX, event.clientY);
event.stopPropagation();
+
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = false;
+ });
+
+ window.addEventListener('pointermove', handlePointerMove);
+ window.addEventListener('pointerup', handlePointerUp);
+ }
+ function handlePointerMove(event: PointerEvent) {
+ delta.set(event.clientX, event.clientY).sub(position);
+ position.set(event.clientX, event.clientY);
+ const deltaX = delta.x / window.innerWidth;
+ const deltaY = delta.y / window.innerHeight;
+
+ translateTexture(deltaX + deltaY);
+ }
+ function handlePointerUp() {
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = true;
+ });
+
+ window.removeEventListener('pointermove', handlePointerMove);
+ window.removeEventListener('pointerup', handlePointerUp);
}
return jsxTree(
@@ -158,8 +204,8 @@ export const TankModel = memo(() => {
yaw = protagonist.yaw;
pitch = protagonist.pitch;
- mutateTankopediaPersistent((draft) => {
- draft.model.visual.controlsEnabled = false;
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = false;
});
mutateTankopediaTemporary((draft) => {
draft.shot = undefined;
@@ -194,8 +240,8 @@ export const TankModel = memo(() => {
draft.protagonist!.pitch = normalizeAngleRad(pitch);
draft.protagonist!.yaw = normalizeAngleRad(yaw);
});
- mutateTankopediaPersistent((draft) => {
- draft.model.visual.controlsEnabled = true;
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = true;
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
@@ -234,8 +280,8 @@ export const TankModel = memo(() => {
function onPointerDown(event: ThreeEvent) {
event.stopPropagation();
- mutateTankopediaPersistent((draft) => {
- draft.model.visual.controlsEnabled = false;
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = false;
});
mutateTankopediaTemporary((draft) => {
draft.shot = undefined;
@@ -269,8 +315,8 @@ export const TankModel = memo(() => {
modelTransformEvent.emit({ pitch, yaw });
}
function handlePointerUp() {
- mutateTankopediaPersistent((draft) => {
- draft.model.visual.controlsEnabled = true;
+ mutateTankopediaTemporary((draft) => {
+ draft.controlsEnabled = true;
});
mutateDuel((draft) => {
draft.protagonist!.pitch = normalizeAngleRad(pitch);
diff --git a/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx b/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx
index ffeb8e8ef..6983b22e1 100644
--- a/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx
+++ b/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx
@@ -38,7 +38,9 @@ export function RotationInputs() {
function handleTransformEvent({ pitch, yaw }: ModelTransformEventData) {
if (!pitchInput.current || !yawInput.current) return;
- pitchInput.current.value = (-radToDeg(pitch)).toFixed(1);
+ pitchInput.current.value = (
+ -radToDeg(pitch) + (tankModelDefinition.turretRotation?.pitch ?? 0)
+ ).toFixed(1);
if (yaw === undefined) return;
diff --git a/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx b/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx
new file mode 100644
index 000000000..a7f1a0b85
--- /dev/null
+++ b/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx
@@ -0,0 +1,16 @@
+import { Flex } from '@radix-ui/themes';
+import { ShotDisplayCard } from '../../../../../components/Armor/components/ShotDisplayCard';
+
+export function ShotDisplaySection() {
+ return (
+
+
+
+ );
+}
diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx
index 25c32adda..d618d94c0 100644
--- a/src/app/tools/tankopedia/[id]/page.tsx
+++ b/src/app/tools/tankopedia/[id]/page.tsx
@@ -11,6 +11,7 @@ import { HistorySection } from './components/HistorySection';
import { CharacteristicsSection } from './components/Model/CharacteristicsSection';
import { HeroSection } from './components/Model/HeroSection';
import { TechTreeSection } from './components/Model/TechTreeSection';
+import { ShotDisplaySection } from './components/ShotDisplaySection';
import { VideoSection } from './components/VideoSection';
export default function Page({ params }: { params: { id: string } }) {
@@ -77,6 +78,7 @@ export default function Page({ params }: { params: { id: string } }) {
{assigned && (
<>
+
{!exempt && }
{!exempt && }
diff --git a/src/app/tools/tankopedia/components/SearchBar.tsx b/src/app/tools/tankopedia/components/SearchBar.tsx
index 54490e950..66a47398b 100644
--- a/src/app/tools/tankopedia/components/SearchBar.tsx
+++ b/src/app/tools/tankopedia/components/SearchBar.tsx
@@ -10,9 +10,10 @@ import { Sort } from './Sort';
interface SearchBarProps {
topResult?: TankDefinition;
+ onSelect?: (tank: TankDefinition) => void;
}
-export function SearchBar({ topResult }: SearchBarProps) {
+export function SearchBar({ topResult, onSelect }: SearchBarProps) {
const router = useRouter();
const input = useRef(null);
const searching = useTankopediaFilters((state) => state.searching);
@@ -42,7 +43,12 @@ export function SearchBar({ topResult }: SearchBarProps) {
if (event.key !== 'Enter' || !topResult || searching) return;
event.preventDefault();
- router.push(`/tools/tankopedia/${topResult.id}`);
+
+ if (onSelect) {
+ onSelect(topResult);
+ } else {
+ router.push(`/tools/tankopedia/${topResult.id}`);
+ }
},
[topResult],
);
diff --git a/src/app/tools/tankopedia/components/Sort.tsx b/src/app/tools/tankopedia/components/Sort.tsx
index e0a50f4a8..00727a65f 100644
--- a/src/app/tools/tankopedia/components/Sort.tsx
+++ b/src/app/tools/tankopedia/components/Sort.tsx
@@ -43,7 +43,17 @@ export function Sort() {
});
}}
>
- DPM
+ Standard DPM
+
+ {
+ mutateTankopediaFilters((draft) => {
+ draft.sort.by = 'fire.dpmPremium';
+ });
+ }}
+ >
+ Premium DPM
(
(a, b) =>
awaitedGameDefinitions.nations.indexOf(b.nation) -
awaitedGameDefinitions.nations.indexOf(a.nation),
- );
+ )
+ .sort((a, b) => a.tier - b.tier);
break;
case 'survivability.health': {
@@ -179,6 +180,24 @@ export const TankSearch = memo(
);
break;
+ case 'fire.dpmPremium':
+ sorted = filtered.sort(
+ (a, b) =>
+ (a.turrets.at(-1)!.guns.at(-1)!.shells[1]
+ ? resolveDpm(
+ a.turrets.at(-1)!.guns.at(-1)!,
+ a.turrets.at(-1)!.guns.at(-1)!.shells[1],
+ )
+ : 0) -
+ (b.turrets.at(-1)!.guns.at(-1)!.shells[1]
+ ? resolveDpm(
+ b.turrets.at(-1)!.guns.at(-1)!,
+ b.turrets.at(-1)!.guns.at(-1)!.shells[1],
+ )
+ : 0),
+ );
+ break;
+
case 'fire.reload':
sorted = filtered.sort(
(a, b) =>
@@ -360,7 +379,7 @@ export const TankSearch = memo(
return (
-
+
{!filters.search && !filters.searching && (
diff --git a/src/components/Armor/components/ShotDisplay.tsx b/src/components/Armor/components/ShotDisplay.tsx
index 2569378b9..877eec688 100644
--- a/src/components/Armor/components/ShotDisplay.tsx
+++ b/src/components/Armor/components/ShotDisplay.tsx
@@ -1,39 +1,17 @@
-import { Card, Flex, Inset, Separator, Text } from '@radix-ui/themes';
+import { Box, Flex, Text } from '@radix-ui/themes';
import { Html } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import { ComponentProps, useRef } from 'react';
import { Euler, Mesh, Quaternion } from 'three';
-import { radToDeg } from 'three/src/math/MathUtils';
import { J_HAT } from '../../../constants/axis';
import {
- ShotLayer,
ShotLayerNonExternal,
ShotStatus,
useTankopediaTemporary,
} from '../../../stores/tankopedia';
-import { ArmorType } from './SpacedArmorScene';
-import { ExternalModuleVariant } from './SpacedArmorSceneComponent';
+import { ShotDisplayCard } from './ShotDisplayCard';
-const layerTypeNames: Record = {
- [ArmorType.Core]: 'Core',
- [ArmorType.Spaced]: 'Spaced',
- [ArmorType.External]: 'External',
- null: 'Gap',
-};
-
-const externalLayerNames: Record = {
- gun: 'Gun',
- track: 'Tracks',
-};
-
-const shotStatusNames: Record = {
- blocked: 'Blocked',
- ricochet: 'Ricochet',
- penetration: 'penetration',
- splash: 'splash',
-};
-
-const shotStatusColors: Record<
+export const shotStatusColors: Record<
ShotStatus,
ComponentProps['color']
> = {
@@ -44,93 +22,10 @@ const shotStatusColors: Record<
};
const SURFACE_POINT_SIZE = 12;
-const LENGTH_INFINITY = 4;
+export const SHOT_DISPLAY_LENGTH_INFINITY = 4;
const TRACER_THICK = 1 / 32;
const TRACER_THIN = TRACER_THICK / 2;
-function LayerEntry({
- layerIndex,
- shotStatusColor,
- layerName,
- layer,
- angle,
-}: {
- layerIndex?: string;
- shotStatusColor: ComponentProps['color'];
- layerName: string;
- layer: ShotLayer;
- angle?: number;
-}) {
- return (
-
-
- {layerIndex}
-
-
- {layerName}
-
-
- {layer.type === null && (
- <>
-
- {Math.round(layer.distance * 1000).toLocaleString()}
- mm
-
-
-
- {Math.max(-100, Math.round(-50 * layer.distance))}% penetration
-
- >
- )}
-
- {layer.type === ArmorType.External && (
-
- {Math.round(layer.thickness).toLocaleString()}
- mm
-
- )}
-
- {(layer.type === ArmorType.Core || layer.type === ArmorType.Spaced) && (
- <>
-
- {Math.round(layer.thicknessAngled).toLocaleString()}
- {`mm${angle === undefined ? '' : ` ${Math.round(radToDeg(angle))}°`}`}
-
-
-
- {Math.round(layer.thickness).toLocaleString()}
- mm nominal
-
- >
- )}
-
- );
-}
-
export function ShotDisplay() {
const shot = useTankopediaTemporary((state) => state.shot);
const inTracer = useRef(null);
@@ -157,13 +52,13 @@ export function ShotDisplay() {
shot.in.layers.reduce((accumulator, layer) => {
if (layer.type === null) return accumulator + layer.distance;
return accumulator;
- }, 0) + LENGTH_INFINITY;
+ }, 0) + SHOT_DISPLAY_LENGTH_INFINITY;
const outLength =
shot.out && shot.out.layers.length > 0
? (shot.in.layers.at(-1) as ShotLayerNonExternal).point.distanceTo(
(shot.out.layers.at(-1) as ShotLayerNonExternal).point,
)
- : LENGTH_INFINITY;
+ : SHOT_DISPLAY_LENGTH_INFINITY;
const inLast = shot.in.layers.findLast(
(layer) => layer.type !== null,
) as ShotLayerNonExternal;
@@ -181,122 +76,15 @@ export function ShotDisplay() {
transform: 'translateY(-50%)',
}}
>
-
-
-
-
- {shot.in.status !== 'blocked' &&
- shot.in.status !== 'ricochet' && (
- <>
- {Math.round(shot.damage).toLocaleString()}
- hp
- >
- )}
- {` ${shotStatusNames[shot.in.status]} `}
-
-
-
- {shot.in.layers.map((layer, index) => {
- const layerName =
- layer.type === ArmorType.External
- ? externalLayerNames[layer.variant]
- : layerTypeNames[`${layer.type}`];
- const layerIndex =
- layer.type === null
- ? undefined
- : `${(shot.containsGaps ? index / 2 : index) + 1}.`;
- const shotStatusColor =
- shot.in.status === 'splash'
- ? shotStatusColors.splash
- : shotStatusColors[layer.status];
-
- return (
-
- );
- })}
-
-
-
- {shot.out && shot.out.layers.length > 0 && (
- <>
-
-
-
-
- ricochet (-25% penetration)
-
-
-
-
-
-
- {shot.out.status !== 'blocked' &&
- shot.out.status !== 'ricochet' && (
- <>
- {Math.round(shot.damage).toLocaleString()}
- hp
- >
- )}
- {` ${shotStatusNames[shot.out.status]} `}
-
-
-
- {shot.out.layers.map((layer, index) => {
- const layerName =
- layer.type === ArmorType.External
- ? externalLayerNames[layer.variant]
- : layerTypeNames[`${layer.type}`];
- const shiftedIndex = index + shot.out!.layers.length;
- const layerIndex =
- layer.type === null
- ? undefined
- : `${(shot.containsGaps ? shiftedIndex / 2 : shiftedIndex) + 1}.`;
- const shotStatusColor =
- shot.out!.status === 'splash'
- ? shotStatusColors.splash
- : shotStatusColors[layer.status];
-
- return (
-
- );
- })}
-
- >
- )}
-
-
+
+
+