mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-28 04:59:50 +01:00
port antagonist control
This commit is contained in:
1 parent
45811b5c18
commit
d251c31b92
8 files changed
+293
-282
No files matched your search
@@ -20,6 +20,16 @@
|
||||
},
|
||||
|
||||
"tanks": {
|
||||
"custom_shell": {
|
||||
"type": "Type",
|
||||
"caliber": "Caliber",
|
||||
"penetration": "Penetration",
|
||||
"normalization": "Normalization",
|
||||
"ricochet": "Ricochet",
|
||||
"exit": "Exit",
|
||||
"reset": "Reset"
|
||||
},
|
||||
|
||||
"tabs": {
|
||||
"model": "Model",
|
||||
"dynamic_armor": "Dynamic armor",
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.antagonist-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
|
||||
gap: var(--space-4);
|
||||
|
||||
transition: var(--duration-brief);
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: var(--space-4);
|
||||
|
||||
transform: translate(calc(100% + var(--space-4)), -50%);
|
||||
|
||||
&[data-visible="true"] {
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
import { alias, romanize, uniqueGuns } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Popover } from "radix-ui";
|
||||
import { useMemo } from "react";
|
||||
import { DuelModule, useDuel } from "../../hooks/useDuel";
|
||||
import { useEquipment } from "../../hooks/useEquipment";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { useUnwrapper } from "../../hooks/useUnwrapper";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { TankopediaDisplay } from "../../stores/tankopediaPersistent/constants";
|
||||
import type { ComputedCharacteristics } from "../../types/characteristics";
|
||||
import { EqualIcon } from "../EqualIcon";
|
||||
import { IconButton } from "../IconButton";
|
||||
import { CustomShellButton } from "../TankopediaOptions/components/CustomShellButton";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
interface TankopediaAntagonistControlProps {
|
||||
antagonistCharacteristics: ComputedCharacteristics;
|
||||
}
|
||||
|
||||
export function TankopediaAntagonistControl({
|
||||
antagonistCharacteristics,
|
||||
}: TankopediaAntagonistControlProps) {
|
||||
const strings = useStrings();
|
||||
const unwrap = useUnwrapper();
|
||||
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
const hasCustomShell = Tankopedia.use(
|
||||
(state) => state.customShell !== undefined,
|
||||
);
|
||||
const equalize = Tankopedia.use((state) => state.environment.equalize);
|
||||
|
||||
const hasCalibratedShells = useEquipment("protagonist", 103);
|
||||
const hasEnhancedArmor = useEquipment("protagonist", 110);
|
||||
|
||||
const tank = useDuel("antagonist", DuelModule.Tank);
|
||||
const gun = useDuel("antagonist", DuelModule.Gun);
|
||||
const shell = useDuel("antagonist", DuelModule.Shell);
|
||||
|
||||
const antagonistUniqueGuns = useMemo(
|
||||
() => uniqueGuns(tank.turrets),
|
||||
[tank.turrets],
|
||||
);
|
||||
|
||||
const isVisible = requestedDisplay === TankopediaDisplay.DynamicArmor;
|
||||
|
||||
return (
|
||||
<div className={styles["antagonist-control"]} data-visible={isVisible}>
|
||||
<Text lowContrast>
|
||||
{literals(strings.common.units.mm, {
|
||||
value: (
|
||||
antagonistCharacteristics.get("penetration") as number
|
||||
).toFixed(0),
|
||||
})}
|
||||
</Text>
|
||||
|
||||
{antagonistUniqueGuns.length > 1 && (
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<IconButton
|
||||
radius="full"
|
||||
variant="soft"
|
||||
color="gray"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
<Text
|
||||
size="1"
|
||||
color="gray"
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
mr="2"
|
||||
mb="1"
|
||||
>
|
||||
{romanize(gun.tier)}
|
||||
</Text>
|
||||
|
||||
<img
|
||||
alt="Antagonist Gun"
|
||||
src={alias("api", "/icons/modules/gun.webp")}
|
||||
style={{
|
||||
width: "65%",
|
||||
height: "65%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</Popover.Trigger>
|
||||
|
||||
<Popover.Content side="left" align="center">
|
||||
<div>
|
||||
{[...antagonistUniqueGuns].reverse().map(({ gun, turret }) => (
|
||||
<IconButton key={gun.id}>
|
||||
<img src={alias("api", "/icons/modules/gun.webp")} />
|
||||
</IconButton>
|
||||
// <ModuleButton
|
||||
// module="gun"
|
||||
// key={gun.id}
|
||||
// onClick={() => {
|
||||
// Tankopedia.mutate((draft) => {
|
||||
// draft.antagonist.turret = turret.id;
|
||||
// draft.antagonist.gun = gun.id;
|
||||
// draft.antagonist.shell = gun.shells[0].id;
|
||||
// });
|
||||
// }}
|
||||
// selected={gun.id === antagonistGun.id}
|
||||
// discriminator={romanize(gun.tier)}
|
||||
// secondaryDiscriminator={
|
||||
// <Text style={{ fontSize: "0.75em" }}>
|
||||
// {literals(strings.common.units.mm, {
|
||||
// value: gun.shells[0].caliber.toFixed(0),
|
||||
// })}
|
||||
// </Text>
|
||||
// }
|
||||
// />
|
||||
))}
|
||||
</div>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
)}
|
||||
|
||||
<div>
|
||||
{gun.shells.map((thisShell) => (
|
||||
<IconButton
|
||||
key={thisShell.id}
|
||||
selected={thisShell.id === shell.id && !hasCustomShell}
|
||||
alt={unwrap(thisShell.name!)}
|
||||
src={alias("api", `/icons/shells/${thisShell.icon}.webp`)}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.antagonist.shell = thisShell.id;
|
||||
draft.shot = undefined;
|
||||
draft.customShell = undefined;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<CustomShellButton />
|
||||
</div>
|
||||
|
||||
<div
|
||||
direction="column"
|
||||
style={{
|
||||
pointerEvents: "auto",
|
||||
borderRadius: "var(--radius-full)",
|
||||
}}
|
||||
overflow="hidden"
|
||||
>
|
||||
<IconButton
|
||||
color={hasCalibratedShells ? undefined : "gray"}
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
radius="none"
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.shot = undefined;
|
||||
|
||||
if (hasCalibratedShells) {
|
||||
delete draft.protagonist.equipment[0];
|
||||
} else {
|
||||
draft.antagonist.equipment[0] = 1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={alias("api", "/icons/equipment/103.webp")}
|
||||
style={{
|
||||
width: "50%",
|
||||
height: "50%",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color={hasEnhancedArmor ? undefined : "gray"}
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
radius="none"
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
if (hasEnhancedArmor) {
|
||||
delete draft.protagonist.equipment[4];
|
||||
} else {
|
||||
draft.antagonist.equipment[4] = 0;
|
||||
}
|
||||
|
||||
draft.shot = undefined;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Enhanced Armor"
|
||||
src={alias("api", "/icons/equipment/110.webp")}
|
||||
style={{
|
||||
width: "50%",
|
||||
height: "50%",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<IconButton
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
color={equalize ? undefined : "gray"}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.environment.equalize = !draft.environment.equalize;
|
||||
draft.shot = undefined;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<EqualIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+12
-43
@@ -12,15 +12,15 @@ import {
|
||||
} from "@radix-ui/themes";
|
||||
import { throttle } from "lodash-es";
|
||||
import { type ChangeEvent } from "react";
|
||||
import { Duel } from "../../../../../../stores/duel";
|
||||
import { useLocale } from "../../../hooks/useLocale";
|
||||
import { DuelModule, useDuel } from "../../../hooks/useDuel";
|
||||
import { useStrings } from "../../../hooks/useStrings";
|
||||
import { Tankopedia } from "../../../stores/tankopedia";
|
||||
|
||||
export function CustomShellButton() {
|
||||
const customShell = Tankopedia.use((state) => state.customShell);
|
||||
const gun = Duel.use((state) => state.protagonist.gun);
|
||||
const antagonistShell = Duel.use((state) => state.antagonist.shell);
|
||||
const { strings } = useLocale();
|
||||
const gun = useDuel("protagonist", DuelModule.Gun);
|
||||
const antagonistShell = useDuel("antagonist", DuelModule.Shell);
|
||||
const strings = useStrings();
|
||||
|
||||
return (
|
||||
<Popover.Root
|
||||
@@ -55,12 +55,7 @@ export function CustomShellButton() {
|
||||
<>
|
||||
<Flex direction="column" gap="2">
|
||||
<Flex align="center" justify="between" gap="4">
|
||||
<Text>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.type
|
||||
}
|
||||
</Text>
|
||||
<Text>{strings.tanks.custom_shell.type}</Text>
|
||||
<Select.Root
|
||||
value={`${customShell.type}`}
|
||||
onValueChange={(value) => {
|
||||
@@ -121,12 +116,7 @@ export function CustomShellButton() {
|
||||
</Flex>
|
||||
|
||||
<Flex align="center" justify="between" gap="4">
|
||||
<Text>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.caliber
|
||||
}
|
||||
</Text>
|
||||
<Text>{strings.tanks.custom_shell.caliber}</Text>
|
||||
<TextField.Root
|
||||
variant="classic"
|
||||
style={{ maxWidth: "6rem" }}
|
||||
@@ -157,12 +147,7 @@ export function CustomShellButton() {
|
||||
</Flex>
|
||||
|
||||
<Flex align="center" justify="between" gap="4">
|
||||
<Text>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.penetration
|
||||
}
|
||||
</Text>
|
||||
<Text>{strings.tanks.custom_shell.penetration}</Text>
|
||||
<TextField.Root
|
||||
variant="classic"
|
||||
style={{ maxWidth: "6rem" }}
|
||||
@@ -197,12 +182,7 @@ export function CustomShellButton() {
|
||||
customShell.type === ShellType.SHELL_TYPE_APCR) && (
|
||||
<>
|
||||
<Flex align="center" justify="between" gap="4" py="1">
|
||||
<Text>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.normalization
|
||||
}
|
||||
</Text>
|
||||
<Text>{strings.tanks.custom_shell.normalization}</Text>
|
||||
|
||||
<Flex
|
||||
align="center"
|
||||
@@ -234,12 +214,7 @@ export function CustomShellButton() {
|
||||
</Flex>
|
||||
|
||||
<Flex align="center" justify="between" gap="4" py="1">
|
||||
<Text>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.ricochet
|
||||
}
|
||||
</Text>
|
||||
<Text>{strings.tanks.custom_shell.ricochet}</Text>
|
||||
|
||||
<Flex align="center" gap="2" flexGrow="1" maxWidth="15rem">
|
||||
<Text color="gray">
|
||||
@@ -300,10 +275,7 @@ export function CustomShellButton() {
|
||||
<Flex justify="end" mt="6" gap="2">
|
||||
<Popover.Close>
|
||||
<Button color="red" variant="outline">
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic
|
||||
.custom_shell.exit
|
||||
}
|
||||
{strings.tanks.custom_shell.exit}
|
||||
</Button>
|
||||
</Popover.Close>
|
||||
<Button
|
||||
@@ -314,10 +286,7 @@ export function CustomShellButton() {
|
||||
});
|
||||
}}
|
||||
>
|
||||
{
|
||||
strings.website.tools.tankopedia.sandbox.dynamic.custom_shell
|
||||
.reset
|
||||
}
|
||||
{strings.tanks.custom_shell.reset}
|
||||
</Button>
|
||||
</Flex>
|
||||
</>
|
||||
|
||||
@@ -1,28 +1,7 @@
|
||||
import { alias, romanize, uniqueGuns } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n/src/literals";
|
||||
import {
|
||||
Crosshair1Icon,
|
||||
EnterFullScreenIcon,
|
||||
ExitFullScreenIcon,
|
||||
EyeOpenIcon,
|
||||
ShadowInnerIcon,
|
||||
ShadowNoneIcon,
|
||||
SunIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DropdownMenu,
|
||||
Flex,
|
||||
IconButton,
|
||||
Popover,
|
||||
SegmentedControl,
|
||||
Tabs,
|
||||
Text,
|
||||
Tooltip,
|
||||
} from "@radix-ui/themes";
|
||||
import { Suspense, useState, type RefObject } from "react";
|
||||
import { Pose, poseEvent } from "../../core/blitzkit/pose";
|
||||
import { Flex, IconButton, Popover, Text } from "@radix-ui/themes";
|
||||
import { useState, type RefObject } from "react";
|
||||
import { DuelModule, useDuel } from "../../hooks/useDuel";
|
||||
import { useEquipment } from "../../hooks/useEquipment";
|
||||
import { useFullScreen } from "../../hooks/useFullScreen";
|
||||
@@ -32,25 +11,26 @@ import { useUnwrapper } from "../../hooks/useUnwrapper";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
|
||||
import { TankopediaDisplay } from "../../stores/tankopediaPersistent/constants";
|
||||
import type { ComputedCharacteristics } from "../../types/characteristics";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { EqualIcon } from "../EqualIcon";
|
||||
import { ModuleButton } from "../ModuleButtons/ModuleButton";
|
||||
import { ScreenshotButton } from "../ScreenshotButton";
|
||||
import { SmallTankIcon } from "../SmallTankIcon";
|
||||
import {
|
||||
SidebarIconButton,
|
||||
SidebarIconGroup,
|
||||
} from "../TankopediaSidebarIconButtons";
|
||||
import { TankSearch } from "../TankSearch";
|
||||
import { CustomShellButton } from "./components/CustomShellButton";
|
||||
import { DynamicArmorSwitcher } from "./components/DynamicArmorSwitcher";
|
||||
import { SpallLinerSwitcher } from "./components/SpallLinerSwitcher";
|
||||
|
||||
type OptionsProps = MaybeSkeletonComponentProps & {
|
||||
canvas: RefObject<HTMLCanvasElement>;
|
||||
antagonistCharacteristics: ComputedCharacteristics;
|
||||
};
|
||||
|
||||
export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
export function TankopediaOptions({
|
||||
canvas,
|
||||
skeleton,
|
||||
antagonistCharacteristics,
|
||||
}: OptionsProps) {
|
||||
const strings = useStrings();
|
||||
const unwrap = useUnwrapper();
|
||||
|
||||
@@ -80,206 +60,9 @@ export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
gap="2"
|
||||
direction="column"
|
||||
top="50%"
|
||||
right={
|
||||
requestedDisplay === TankopediaDisplay.DynamicArmor ? "3" : "-4rem"
|
||||
}
|
||||
style={{
|
||||
position: "absolute",
|
||||
transform: "translateY(-50%)",
|
||||
transitionDuration: "200ms",
|
||||
}}
|
||||
align="end"
|
||||
>
|
||||
{!hasCustomShell && (
|
||||
<Text color="gray" size={{ initial: "1", sm: "2" }}>
|
||||
{/* {literals(strings.common.units.mm, {
|
||||
value: (
|
||||
resolvePenetrationCoefficient(
|
||||
hasCalibratedShells,
|
||||
equalize,
|
||||
antagonistShell.type,
|
||||
equalizer,
|
||||
) * antagonistShell.penetration!.near
|
||||
).toFixed(0),
|
||||
})} */}
|
||||
what
|
||||
</Text>
|
||||
)}
|
||||
|
||||
|
||||
{antagonistUniqueGuns.length > 1 && (
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<IconButton
|
||||
radius="full"
|
||||
variant="soft"
|
||||
color="gray"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
<Text
|
||||
size="1"
|
||||
color="gray"
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
mr="2"
|
||||
mb="1"
|
||||
>
|
||||
{romanize(antagonistGun.tier)}
|
||||
</Text>
|
||||
|
||||
<img
|
||||
alt="Antagonist Gun"
|
||||
src={alias("api", "/icons/modules/gun.webp")}
|
||||
style={{
|
||||
width: "65%",
|
||||
height: "65%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</Popover.Trigger>
|
||||
|
||||
<Popover.Content side="left" align="center">
|
||||
<Flex gap="2">
|
||||
{[...antagonistUniqueGuns].reverse().map(({ gun, turret }) => (
|
||||
<ModuleButton
|
||||
module="gun"
|
||||
key={gun.id}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.antagonist.turret = turret.id;
|
||||
draft.antagonist.gun = gun.id;
|
||||
draft.antagonist.shell = gun.shells[0].id;
|
||||
});
|
||||
}}
|
||||
selected={gun.id === antagonistGun.id}
|
||||
discriminator={romanize(gun.tier)}
|
||||
secondaryDiscriminator={
|
||||
<Text style={{ fontSize: "0.75em" }}>
|
||||
{literals(strings.common.units.mm, {
|
||||
value: gun.shells[0].caliber.toFixed(0),
|
||||
})}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
)}
|
||||
|
||||
<SidebarIconGroup>
|
||||
{antagonistGun.shells.map((thisShell) => (
|
||||
<SidebarIconButton
|
||||
key={thisShell.id}
|
||||
selected={thisShell.id === antagonistShell.id && !hasCustomShell}
|
||||
alt={unwrap(thisShell.name!)}
|
||||
src={alias("api", `/icons/shells/${thisShell.icon}.webp`)}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.antagonist.shell = thisShell.id;
|
||||
draft.shot = undefined;
|
||||
draft.customShell = undefined;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<CustomShellButton />
|
||||
</SidebarIconGroup>
|
||||
|
||||
<Flex
|
||||
direction="column"
|
||||
style={{
|
||||
pointerEvents: "auto",
|
||||
borderRadius: "var(--radius-full)",
|
||||
}}
|
||||
overflow="hidden"
|
||||
>
|
||||
<IconButton
|
||||
color={hasCalibratedShells ? undefined : "gray"}
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
radius="none"
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.shot = undefined;
|
||||
|
||||
if (hasCalibratedShells) {
|
||||
delete draft.protagonist.equipment[0];
|
||||
} else {
|
||||
draft.antagonist.equipment[0] = 1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Calibrated Shells"
|
||||
src={alias("api", "/icons/equipment/103.webp")}
|
||||
style={{
|
||||
width: "50%",
|
||||
height: "50%",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color={hasEnhancedArmor ? undefined : "gray"}
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
radius="none"
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
if (hasEnhancedArmor) {
|
||||
delete draft.protagonist.equipment[4];
|
||||
} else {
|
||||
draft.antagonist.equipment[4] = 0;
|
||||
}
|
||||
|
||||
draft.shot = undefined;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Enhanced Armor"
|
||||
src={alias("api", "/icons/equipment/110.webp")}
|
||||
style={{
|
||||
width: "50%",
|
||||
height: "50%",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
|
||||
<SpallLinerSwitcher />
|
||||
</Flex>
|
||||
|
||||
{!skeleton && modelRequested && (
|
||||
<Suspense>
|
||||
<DynamicArmorSwitcher />
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
variant="soft"
|
||||
size={{ initial: "2", sm: "3" }}
|
||||
color={equalize ? undefined : "gray"}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.environment.equalize = !draft.environment.equalize;
|
||||
draft.shot = undefined;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<EqualIcon />
|
||||
</IconButton>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
{/* <Flex
|
||||
direction="column"
|
||||
align="center"
|
||||
position="absolute"
|
||||
@@ -407,7 +190,7 @@ export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
}}
|
||||
>
|
||||
<SegmentedControl.Item value={`${TankopediaDisplay.Model}`}>
|
||||
<Tooltip content={strings.tanks.tabs.model}>
|
||||
<Tooltip tooltip={strings.tanks.tabs.model}>
|
||||
<Flex height="100%" align="center">
|
||||
<img
|
||||
src="/assets/images/icons/tankopedia-model.png"
|
||||
@@ -417,7 +200,7 @@ export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
</Tooltip>
|
||||
</SegmentedControl.Item>
|
||||
<SegmentedControl.Item value={`${TankopediaDisplay.DynamicArmor}`}>
|
||||
<Tooltip content={strings.tanks.tabs.dynamic_armor}>
|
||||
<Tooltip tooltip={strings.tanks.tabs.dynamic_armor}>
|
||||
<Flex height="100%" align="center">
|
||||
<img
|
||||
src="/assets/images/icons/tankopedia-dynamic-armor.png"
|
||||
@@ -427,7 +210,7 @@ export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
</Tooltip>
|
||||
</SegmentedControl.Item>
|
||||
<SegmentedControl.Item value={`${TankopediaDisplay.StaticArmor}`}>
|
||||
<Tooltip content={strings.tanks.tabs.model}>
|
||||
<Tooltip tooltip={strings.tanks.tabs.model}>
|
||||
<Flex height="100%" align="center">
|
||||
<img
|
||||
src="/assets/images/icons/tankopedia-static-armor.png"
|
||||
@@ -484,7 +267,7 @@ export function TankopediaOptions({ canvas, skeleton }: OptionsProps) {
|
||||
</Dialog.Root>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { useModel } from "../../hooks/useModel";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
|
||||
import { TankopediaDisplay } from "../../stores/tankopediaPersistent/constants";
|
||||
import type { ComputedCharacteristics } from "../../types/characteristics";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { ArmorPlateDisplay } from "../ArmorPlateDisplay";
|
||||
import { CanvasAutoClear } from "../CanvasAutoClear";
|
||||
@@ -21,17 +22,19 @@ import { ShotDisplay } from "../ShotDisplay";
|
||||
import { SmartCanvas } from "../SmartCanvas";
|
||||
import { StaticArmor, type ThicknessRange } from "../StaticArmor";
|
||||
import { TankModel } from "../TankModel";
|
||||
import { TankopediaOptions } from "../TankopediaOptions";
|
||||
import { TankopediaAntagonistControl } from "../TankopediaAntagonistControl";
|
||||
import { TankopediaSkinSwitcher } from "../TankopediaSkinSwitcher";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
type TankSandboxProps = MaybeSkeletonComponentProps & {
|
||||
thicknessRange: ThicknessRange;
|
||||
antagonistCharacteristics: ComputedCharacteristics;
|
||||
};
|
||||
|
||||
export function TankopediaSandbox({
|
||||
skeleton,
|
||||
thicknessRange,
|
||||
antagonistCharacteristics,
|
||||
}: TankSandboxProps) {
|
||||
const wrapper = useRef<HTMLDivElement>(null);
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
@@ -172,7 +175,9 @@ export function TankopediaSandbox({
|
||||
</SmartCanvas>
|
||||
|
||||
<TankopediaSkinSwitcher />
|
||||
<TankopediaOptions />
|
||||
<TankopediaAntagonistControl
|
||||
antagonistCharacteristics={antagonistCharacteristics}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -191,12 +191,14 @@ export function computeCharacteristics(
|
||||
return computed;
|
||||
}
|
||||
|
||||
export function useCharacteristics() {
|
||||
const protagonist = Tankopedia.use((state) => state.protagonist);
|
||||
const antagonist = Tankopedia.use((state) => state.antagonist);
|
||||
export function useCharacteristics(side: DuelSide) {
|
||||
const A = Tankopedia.use((state) => state[side]);
|
||||
const B = Tankopedia.use(
|
||||
(state) => state[side === "antagonist" ? "protagonist" : "antagonist"],
|
||||
);
|
||||
const environment = Tankopedia.use((state) => state.environment);
|
||||
|
||||
return computeCharacteristics({ protagonist, antagonist }, environment);
|
||||
return computeCharacteristics({ protagonist: A, antagonist: B }, environment);
|
||||
}
|
||||
|
||||
export function computeDefaultCharacteristics(tank: TankDefinition) {
|
||||
|
||||
@@ -30,7 +30,8 @@ export const Page = withErrorWrapper(
|
||||
const protagonist = Tankopedia.use((state) => state.protagonist);
|
||||
const equalize = Tankopedia.use((state) => state.environment.equalize);
|
||||
|
||||
const characteristics = useCharacteristics();
|
||||
const characteristics = useCharacteristics("protagonist");
|
||||
const antagonistCharacteristics = useCharacteristics("antagonist");
|
||||
|
||||
const thicknessRange = useMemo(() => {
|
||||
const entries = Object.values(tanks.tanks);
|
||||
@@ -62,6 +63,7 @@ export const Page = withErrorWrapper(
|
||||
|
||||
<div className={styles.sandbox}>
|
||||
<TankopediaSandbox
|
||||
antagonistCharacteristics={antagonistCharacteristics}
|
||||
skeleton={skeleton}
|
||||
thicknessRange={thicknessRange}
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user