diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx
new file mode 100644
index 000000000..495b6b802
--- /dev/null
+++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx
@@ -0,0 +1,220 @@
+import { imgur, ShellType } from '@blitzkit/core';
+import {
+ Button,
+ Dialog,
+ Flex,
+ IconButton,
+ Select,
+ Slider,
+ Text,
+ TextField,
+} from '@radix-ui/themes';
+import { invalidate } from '@react-three/fiber';
+import { useEffect, useState, type ChangeEvent } from 'react';
+import { Duel } from '../../../../../../stores/duel';
+import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
+
+export function CustomShellButton() {
+ const customShell = TankopediaEphemeral.use((state) => state.customShell);
+ const antagonistShell = Duel.use((state) => state.antagonist.shell);
+ const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
+ const [customShellDraft, setCustomShellDraft] = useState(
+ customShell ?? antagonistShell,
+ );
+
+ useEffect(() => {
+ setCustomShellDraft(customShell ?? antagonistShell);
+ }, [antagonistShell, customShell]);
+
+ return (
+
+
+
+
+
+
+
+
+ Custom shell
+
+
+
+ Type
+ {
+ const type = Number(value) as ShellType;
+ const modified = { ...customShellDraft, type };
+
+ switch (type) {
+ case ShellType.AP: {
+ modified.normalization = 5;
+ modified.ricochet = 70;
+ break;
+ }
+ case ShellType.APCR: {
+ modified.normalization = 2;
+ modified.ricochet = 70;
+ break;
+ }
+ case ShellType.HEAT:
+ case ShellType.HE: {
+ modified.normalization = undefined;
+ modified.ricochet = undefined;
+ break;
+ }
+ }
+
+ setCustomShellDraft(modified);
+ }}
+ >
+
+
+
+ AP
+ APCR
+ HEAT
+ HE
+
+
+
+
+
+ Caliber
+ ) => {
+ setCustomShellDraft({
+ ...customShellDraft,
+ caliber: event.target.valueAsNumber,
+ });
+ }}
+ onFocus={(event) => event.target.select()}
+ onKeyDown={(event) => {
+ if (event.key === 'Enter') {
+ (event.target as HTMLInputElement).blur();
+ } else if (event.key === 'Escape') {
+ (event.target as HTMLInputElement).valueAsNumber =
+ customShellDraft.caliber;
+ (event.target as HTMLInputElement).blur();
+ }
+ }}
+ >
+ mm
+
+
+
+
+ Penetration
+ ) => {
+ setCustomShellDraft({
+ ...customShellDraft,
+ penetration: {
+ near: event.target.valueAsNumber,
+ far: event.target.valueAsNumber,
+ },
+ });
+ }}
+ onFocus={(event) => event.target.select()}
+ onKeyDown={(event) => {
+ if (event.key === 'Enter') {
+ (event.target as HTMLInputElement).blur();
+ } else if (event.key === 'Escape') {
+ (event.target as HTMLInputElement).valueAsNumber =
+ customShellDraft.penetration.near;
+ (event.target as HTMLInputElement).blur();
+ }
+ }}
+ >
+ mm
+
+
+
+ {(customShellDraft.type === ShellType.AP ||
+ customShellDraft.type === ShellType.APCR) && (
+ <>
+
+ Normalization
+
+
+
+ {customShellDraft.normalization ?? 0}°
+
+
+ setCustomShellDraft({
+ ...customShellDraft,
+ normalization: value,
+ })
+ }
+ />
+
+
+
+
+ Ricochet
+
+
+ {customShellDraft.ricochet ?? 90}°
+
+ setCustomShellDraft({
+ ...customShellDraft,
+ ricochet: value,
+ })
+ }
+ />
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
index 4aa7749c9..584935368 100644
--- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
+++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
@@ -42,6 +42,7 @@ import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
import { SmallTankIcon } from '../../../../SmallTankIcon';
import { TankSearch } from '../../../../TankSearch';
+import { CustomShellButton } from './components/CustomShellButton';
import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
import { QuickInputs } from './components/QuickInputs';
import { Thicknesses } from './components/Thicknesses';
@@ -52,6 +53,7 @@ interface OptionsProps {
}
export function Options({ thicknessRange, canvas }: OptionsProps) {
+ const customShell = TankopediaEphemeral.use((state) => state.customShell);
const display = TankopediaPersistent.useDeferred(
(state) => state.display,
TankopediaDisplay.Model,
@@ -184,64 +186,40 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
}}
overflow="hidden"
>
- {antagonistGun.gun_type!.value.base.shells.map(
- (thisShell, shellIndex) => (
- {
- invalidate();
- mutateDuel((draft) => {
- draft.antagonist.shell = thisShell;
- });
- mutateTankopediaEphemeral((draft) => {
- draft.shot = undefined;
- });
- }}
- >
-
-
- ),
- )}
-
- {
- invalidate();
- // mutateDuel((draft) => {
- // draft.antagonist.shell = thisShell;
- // });
- mutateTankopediaEphemeral((draft) => {
- draft.shot = undefined;
- });
- }}
- >
-
(
+ {
+ invalidate();
+ mutateDuel((draft) => {
+ draft.antagonist.shell = thisShell;
+ });
+ mutateTankopediaEphemeral((draft) => {
+ draft.shot = undefined;
+ draft.customShell = undefined;
+ });
}}
- />
-
+ >
+
+
+ ))}
+
+