2025-09-01 22:56:39 -05:00
|
|
|
import { Box, Flex } from "@radix-ui/themes";
|
|
|
|
|
import { times } from "lodash-es";
|
2025-11-27 13:54:36 -06:00
|
|
|
import { useEffect, useMemo, useRef } from "react";
|
2026-09-23 10:25:47 -05:00
|
|
|
import { api } from "../../../api/dynamic";
|
2026-04-03 14:53:14 -05:00
|
|
|
import { defaultEqualizer } from "../../../core/blitzkit/tankToDuelMember";
|
2025-09-01 22:56:39 -05:00
|
|
|
import { useFullScreen } from "../../../hooks/useFullScreen";
|
|
|
|
|
import { Duel } from "../../../stores/duel";
|
|
|
|
|
import { Tankopedia } from "../../../stores/tankopedia";
|
|
|
|
|
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps";
|
2026-09-27 16:46:22 -05:00
|
|
|
import type { ThicknessRange } from "../../StaticArmor";
|
2025-09-01 22:56:39 -05:00
|
|
|
import { Options } from "./components/Options";
|
|
|
|
|
import { TankSandbox } from "./components/TankSandbox";
|
|
|
|
|
import { Title } from "./components/TankSandbox/Title";
|
2024-05-03 12:57:04 -05:00
|
|
|
|
2026-08-30 14:26:08 -05:00
|
|
|
const tankDefinitions = await api.tanks();
|
2024-09-21 20:26:58 -05:00
|
|
|
|
2024-11-09 18:38:04 -06:00
|
|
|
export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
2026-04-03 14:53:14 -05:00
|
|
|
const equalize = Duel.use((state) => state.equalize);
|
2025-09-01 22:56:39 -05:00
|
|
|
const disturbed = Tankopedia.use((state) => state.disturbed);
|
2025-09-27 16:07:45 -05:00
|
|
|
const canvas = useRef<HTMLCanvasElement>(null!);
|
2024-05-04 17:02:03 -05:00
|
|
|
const isFullScreen = useFullScreen();
|
2024-09-22 21:12:18 -05:00
|
|
|
const protagonist = Duel.use((state) => state.protagonist.tank);
|
2026-10-05 19:52:46 +13:00
|
|
|
const modelRequested = Tankopedia.use((state) => state.modelRequested);
|
2024-07-29 14:08:52 -05:00
|
|
|
const thicknessRange = useMemo(() => {
|
2024-10-05 23:20:04 -05:00
|
|
|
const entries = Object.values(tankDefinitions.tanks);
|
2024-09-01 18:00:15 -05:00
|
|
|
const filtered = entries.filter(
|
2026-03-31 14:11:45 -05:00
|
|
|
(thisTank) => thisTank.tier === protagonist.tier,
|
2024-09-01 18:00:15 -05:00
|
|
|
);
|
2024-07-30 13:45:52 -05:00
|
|
|
const value =
|
2024-07-31 13:25:58 -05:00
|
|
|
(filtered.reduce((accumulator, thisTank) => {
|
2024-07-30 13:45:52 -05:00
|
|
|
return (
|
|
|
|
|
accumulator +
|
2026-04-03 14:53:14 -05:00
|
|
|
thisTank.turrets.at(-1)!.guns.at(-1)!.shells[0].penetration!.near *
|
|
|
|
|
((equalize ? thisTank.equalizer : undefined) ?? defaultEqualizer)
|
|
|
|
|
.penetration
|
2024-07-30 13:45:52 -05:00
|
|
|
);
|
|
|
|
|
}, 0) /
|
2024-07-31 13:25:58 -05:00
|
|
|
filtered.length) *
|
|
|
|
|
(3 / 4);
|
2024-07-29 14:08:52 -05:00
|
|
|
|
2024-07-30 13:45:52 -05:00
|
|
|
return { value } satisfies ThicknessRange;
|
2026-04-03 14:53:14 -05:00
|
|
|
}, [protagonist, equalize]);
|
2025-05-06 13:29:40 -05:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (disturbed) {
|
2025-09-01 22:56:39 -05:00
|
|
|
document.body.classList.remove("no-navbar");
|
2025-05-06 13:29:40 -05:00
|
|
|
}
|
|
|
|
|
}, [disturbed]);
|
2024-10-18 11:36:50 -05:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
function handleKeyDown(event: KeyboardEvent) {
|
|
|
|
|
times(3, (index) => {
|
2025-09-02 16:24:13 -05:00
|
|
|
if (
|
|
|
|
|
event.key === `${index + 1}` &&
|
|
|
|
|
Duel.state.antagonist.gun.shells.length > index
|
|
|
|
|
) {
|
|
|
|
|
Duel.mutate((draft) => {
|
|
|
|
|
draft.antagonist.shell = Duel.state.antagonist.gun.shells[index];
|
2024-10-18 11:36:50 -05:00
|
|
|
});
|
2025-09-01 22:56:39 -05:00
|
|
|
Tankopedia.mutate((draft) => {
|
2024-11-10 20:59:01 -06:00
|
|
|
draft.customShell = undefined;
|
|
|
|
|
});
|
2024-10-18 11:36:50 -05:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-01 22:56:39 -05:00
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
2024-10-18 11:36:50 -05:00
|
|
|
}, []);
|
2024-07-10 20:47:02 -05:00
|
|
|
|
2024-05-03 12:57:04 -05:00
|
|
|
return (
|
2025-05-06 13:29:40 -05:00
|
|
|
<Flex
|
2025-05-06 13:39:07 -05:00
|
|
|
overflow="hidden"
|
2025-05-06 13:29:40 -05:00
|
|
|
justify="center"
|
|
|
|
|
style={{
|
2025-09-01 22:56:39 -05:00
|
|
|
backgroundColor: "black",
|
2025-05-06 13:29:40 -05:00
|
|
|
}}
|
|
|
|
|
position="relative"
|
|
|
|
|
>
|
|
|
|
|
<Box
|
|
|
|
|
position="absolute"
|
|
|
|
|
width="100%"
|
|
|
|
|
height="100%"
|
|
|
|
|
top="0"
|
|
|
|
|
left="0"
|
|
|
|
|
style={{
|
|
|
|
|
opacity: disturbed ? 0 : 1,
|
2025-09-01 22:56:39 -05:00
|
|
|
background: "black",
|
|
|
|
|
transitionDuration: "1s",
|
2025-05-06 13:29:40 -05:00
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
|
2025-05-07 19:16:10 -05:00
|
|
|
{/* <ScrollHint /> */}
|
2025-05-06 13:29:40 -05:00
|
|
|
|
2024-09-01 23:00:37 -05:00
|
|
|
<Flex
|
2025-09-01 22:56:39 -05:00
|
|
|
direction={{ initial: "column-reverse", md: "row" }}
|
2025-04-14 19:26:41 -05:00
|
|
|
style={{
|
|
|
|
|
zIndex: isFullScreen ? 2 : undefined,
|
2025-09-01 22:56:39 -05:00
|
|
|
transitionDuration: "1s",
|
|
|
|
|
background: isFullScreen ? "black" : undefined,
|
2025-04-14 19:26:41 -05:00
|
|
|
}}
|
2025-08-29 22:51:24 -05:00
|
|
|
height={
|
|
|
|
|
isFullScreen
|
2025-09-01 22:56:39 -05:00
|
|
|
? "100vh"
|
2025-08-29 22:51:24 -05:00
|
|
|
: disturbed
|
2026-03-31 14:11:45 -05:00
|
|
|
? "calc(100svh - 8rem)"
|
|
|
|
|
: {
|
|
|
|
|
initial: "28rem",
|
|
|
|
|
md: "calc(100svh - 14rem)",
|
|
|
|
|
}
|
2025-08-29 22:51:24 -05:00
|
|
|
}
|
2025-09-01 22:56:39 -05:00
|
|
|
maxWidth={isFullScreen ? undefined : "120rem"}
|
2024-09-01 17:00:02 -05:00
|
|
|
flexGrow="1"
|
2025-09-01 22:56:39 -05:00
|
|
|
width={isFullScreen ? "100vw" : undefined}
|
|
|
|
|
position={isFullScreen ? "fixed" : "relative"}
|
|
|
|
|
top={isFullScreen ? "0" : undefined}
|
|
|
|
|
left={isFullScreen ? "0" : undefined}
|
2024-08-28 22:22:53 -05:00
|
|
|
>
|
2025-04-20 21:16:50 -05:00
|
|
|
<Box
|
|
|
|
|
className="tank-sandbox-container"
|
|
|
|
|
flexGrow="1"
|
|
|
|
|
flexBasis="0"
|
|
|
|
|
flexShrink="0"
|
|
|
|
|
position="relative"
|
|
|
|
|
>
|
|
|
|
|
<Box position="absolute" width="100%" height="100%" overflow="hidden">
|
2025-11-27 13:54:36 -06:00
|
|
|
<Box width="100%" height="100%" position="relative">
|
2025-05-05 22:54:39 -05:00
|
|
|
<Box
|
2025-11-27 13:54:36 -06:00
|
|
|
position="absolute"
|
|
|
|
|
width="100%"
|
|
|
|
|
height="100%"
|
|
|
|
|
top="0"
|
|
|
|
|
left="0"
|
2025-05-05 22:54:39 -05:00
|
|
|
>
|
2026-10-05 19:52:46 +13:00
|
|
|
{!skeleton && modelRequested && (
|
|
|
|
|
<Suspense>
|
|
|
|
|
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
|
|
|
|
|
</Suspense>
|
2025-11-27 13:54:36 -06:00
|
|
|
)}
|
2025-05-05 22:54:39 -05:00
|
|
|
</Box>
|
2025-04-20 21:16:50 -05:00
|
|
|
</Box>
|
|
|
|
|
|
2026-10-05 19:52:46 +13:00
|
|
|
<Title skeleton={skeleton} />
|
2025-08-09 12:07:26 -05:00
|
|
|
|
2025-04-20 21:16:50 -05:00
|
|
|
<Options
|
|
|
|
|
skeleton={skeleton}
|
|
|
|
|
canvas={canvas}
|
|
|
|
|
thicknessRange={thicknessRange}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
2024-09-01 23:00:37 -05:00
|
|
|
</Flex>
|
2024-09-01 17:00:02 -05:00
|
|
|
</Flex>
|
2024-05-03 12:57:04 -05:00
|
|
|
);
|
|
|
|
|
}
|