mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
fix: update all
This commit is contained in:
1 parent
bdea9fdab3
commit
e2f50871ec
86 files changed
+1939
-1537
No files matched your search
+3
-3
@@ -24,7 +24,7 @@ export function Crew({ stats }: StatsAcceptorProps) {
|
||||
provisionDefinitions.provisions[provision].crew
|
||||
? total + provisionDefinitions.provisions[provision].crew! / 100
|
||||
: total,
|
||||
0
|
||||
0,
|
||||
) + (hasImprovedVentilation ? 0.08 : 0);
|
||||
const commanderMastery = 1 + provisionCrewBonus;
|
||||
|
||||
@@ -71,7 +71,7 @@ export function Crew({ stats }: StatsAcceptorProps) {
|
||||
decimals={0}
|
||||
noRanking
|
||||
value={() =>
|
||||
(member.type === CrewType.COMMANDER
|
||||
(member.type === CrewType.CREW_TYPE_COMMANDER
|
||||
? commanderMastery
|
||||
: commanderMastery * 1.1) * 100
|
||||
}
|
||||
@@ -93,7 +93,7 @@ export function Crew({ stats }: StatsAcceptorProps) {
|
||||
? strings.website.tools.tankopedia.crew[
|
||||
CREW_MEMBER_NAMES[sub]
|
||||
]
|
||||
: sub
|
||||
: sub,
|
||||
)
|
||||
.join(", ")}
|
||||
</Flex>
|
||||
|
||||
+6
-6
@@ -38,7 +38,7 @@ export function Firepower({
|
||||
const selected = thisShell.id === shell.id;
|
||||
|
||||
return (
|
||||
<Tooltip content={unwrap(thisShell.name)} key={thisShell.id}>
|
||||
<Tooltip content={unwrap(thisShell.name!)} key={thisShell.id}>
|
||||
<IconButton
|
||||
color={selected ? undefined : "gray"}
|
||||
variant={selected ? "solid" : "soft"}
|
||||
@@ -59,7 +59,7 @@ export function Firepower({
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(thisShell.name)}
|
||||
alt={unwrap(thisShell.name!)}
|
||||
width={16}
|
||||
height={16}
|
||||
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
||||
@@ -119,7 +119,7 @@ export function Firepower({
|
||||
name={literals(
|
||||
strings.website.tools.tankopedia.characteristics.values
|
||||
.shell_index,
|
||||
{ index: index + 1 }
|
||||
{ index: index + 1 },
|
||||
)}
|
||||
decimals={2}
|
||||
deltaType="lowerIsBetter"
|
||||
@@ -191,7 +191,7 @@ export function Firepower({
|
||||
name={literals(
|
||||
strings.website.tools.tankopedia.characteristics.values
|
||||
.dispersion_at_distance,
|
||||
{ distance: 100 }
|
||||
{ distance: 100 },
|
||||
)}
|
||||
/>
|
||||
<InfoWithDelta
|
||||
@@ -249,7 +249,7 @@ export function Firepower({
|
||||
/>
|
||||
<InfoWithDelta value="gunDepression" stats={stats} decimals={1} indent />
|
||||
<InfoWithDelta stats={stats} decimals={1} indent value="gunElevation" />
|
||||
{gunModelDefinition.pitch.front && (
|
||||
{gunModelDefinition.pitch!.front && (
|
||||
<>
|
||||
<InfoWithDelta
|
||||
stats={stats}
|
||||
@@ -265,7 +265,7 @@ export function Firepower({
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{gunModelDefinition.pitch.back && (
|
||||
{gunModelDefinition.pitch!.back && (
|
||||
<>
|
||||
<InfoWithDelta
|
||||
stats={stats}
|
||||
|
||||
+9
-9
@@ -1,13 +1,13 @@
|
||||
import type { QuicklimeEvent } from 'quicklime';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import type { Group } from 'three';
|
||||
import { awaitableModelDefinitions } from '../../../../../../../../core/awaitables/modelDefinitions';
|
||||
import type { QuicklimeEvent } from "quicklime";
|
||||
import { useEffect, useRef } from "react";
|
||||
import type { Group } from "three";
|
||||
import { awaitableModelDefinitions } from "../../../../../../../../core/awaitables/modelDefinitions";
|
||||
import {
|
||||
modelTransformEvent,
|
||||
type ModelTransformEventData,
|
||||
} from '../../../../../../../../core/blitzkit/modelTransform';
|
||||
import { Duel } from '../../../../../../../../stores/duel';
|
||||
import { ModelChunk } from './ModelChunk';
|
||||
} from "../../../../../../../../core/blitzkit/modelTransform";
|
||||
import { Duel } from "../../../../../../../../stores/duel";
|
||||
import { ModelChunk } from "./ModelChunk";
|
||||
|
||||
const modelDefinitions = await awaitableModelDefinitions;
|
||||
|
||||
@@ -39,8 +39,8 @@ export function CanvasContent() {
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<group ref={hullWrapper} position={[0, 0, turretModel.gun_origin.z]}>
|
||||
<group position={[0, 0, -turretModel.gun_origin.z]}>
|
||||
<group ref={hullWrapper} position={[0, 0, turretModel.gun_origin!.z]}>
|
||||
<group position={[0, 0, -turretModel.gun_origin!.z]}>
|
||||
<ModelChunk only="body" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
+20
-20
@@ -1,13 +1,13 @@
|
||||
import { mauveDark } from '@radix-ui/colors';
|
||||
import { LineBasicMaterial, MeshBasicMaterial } from 'three';
|
||||
import { awaitableModelDefinitions } from '../../../../../../../../core/awaitables/modelDefinitions';
|
||||
import { jsxTree } from '../../../../../../../../core/blitzkit/jsxTree';
|
||||
import { useModel } from '../../../../../../../../hooks/useModel';
|
||||
import { Duel } from '../../../../../../../../stores/duel';
|
||||
import { mauveDark } from "@radix-ui/colors";
|
||||
import { LineBasicMaterial, MeshBasicMaterial } from "three";
|
||||
import { awaitableModelDefinitions } from "../../../../../../../../core/awaitables/modelDefinitions";
|
||||
import { jsxTree } from "../../../../../../../../core/blitzkit/jsxTree";
|
||||
import { useModel } from "../../../../../../../../hooks/useModel";
|
||||
import { Duel } from "../../../../../../../../stores/duel";
|
||||
|
||||
const modelDefinitions = await awaitableModelDefinitions;
|
||||
|
||||
const surfaceMaterial: Record<Props['only'], MeshBasicMaterial> = {
|
||||
const surfaceMaterial: Record<Props["only"], MeshBasicMaterial> = {
|
||||
gun: new MeshBasicMaterial({
|
||||
color: mauveDark.mauve8,
|
||||
toneMapped: false,
|
||||
@@ -23,7 +23,7 @@ const surfaceMaterial: Record<Props['only'], MeshBasicMaterial> = {
|
||||
opacity: 0.5,
|
||||
}),
|
||||
};
|
||||
const outlineMaterial: Record<Props['only'], LineBasicMaterial> = {
|
||||
const outlineMaterial: Record<Props["only"], LineBasicMaterial> = {
|
||||
gun: new LineBasicMaterial({
|
||||
color: mauveDark.mauve11,
|
||||
toneMapped: false,
|
||||
@@ -41,7 +41,7 @@ const outlineMaterial: Record<Props['only'], LineBasicMaterial> = {
|
||||
};
|
||||
|
||||
interface Props {
|
||||
only: 'gun' | 'turret' | 'body';
|
||||
only: "gun" | "turret" | "body";
|
||||
}
|
||||
|
||||
export function ModelChunk({ only }: Props) {
|
||||
@@ -53,8 +53,8 @@ export function ModelChunk({ only }: Props) {
|
||||
const turretModel = tankModel.turrets[turret.id];
|
||||
const gunModel = turretModel.guns[gun.id];
|
||||
|
||||
const originZ = tankModel.turret_origin.z + turretModel.gun_origin.z;
|
||||
const originY = tankModel.turret_origin.y + turretModel.gun_origin.y;
|
||||
const originZ = tankModel.turret_origin!.z + turretModel.gun_origin!.z;
|
||||
const originY = tankModel.turret_origin!.y + turretModel.gun_origin!.y;
|
||||
|
||||
const { gltf } = useModel(tank.id);
|
||||
const nodes = Object.values(gltf.nodes);
|
||||
@@ -64,25 +64,25 @@ export function ModelChunk({ only }: Props) {
|
||||
{nodes.map((node) => {
|
||||
const isCurrentMantlet =
|
||||
node.name ===
|
||||
`gun_${gunModel.model_id.toString().padStart(2, '0')}_mask`;
|
||||
`gun_${gunModel.model_id.toString().padStart(2, "0")}_mask`;
|
||||
const isCurrentGun =
|
||||
node.name === `gun_${gunModel.model_id.toString().padStart(2, '0')}`;
|
||||
node.name === `gun_${gunModel.model_id.toString().padStart(2, "0")}`;
|
||||
const isGun = isCurrentGun || isCurrentMantlet;
|
||||
|
||||
const isCurrentTurret =
|
||||
node.name ===
|
||||
`turret_${turretModel.model_id.toString().padStart(2, '0')}`;
|
||||
`turret_${turretModel.model_id.toString().padStart(2, "0")}`;
|
||||
const isTurret = isCurrentTurret;
|
||||
|
||||
const isHull = node.name === 'hull';
|
||||
const isWheel = node.name.startsWith('chassis_wheel_');
|
||||
const isTrack = node.name.startsWith('chassis_track_');
|
||||
const isHull = node.name === "hull";
|
||||
const isWheel = node.name.startsWith("chassis_wheel_");
|
||||
const isTrack = node.name.startsWith("chassis_track_");
|
||||
const isBody = isHull || isWheel || isTrack;
|
||||
|
||||
if (
|
||||
(only === 'gun' && !isGun) ||
|
||||
(only === 'turret' && !isTurret) ||
|
||||
(only === 'body' && !isBody)
|
||||
(only === "gun" && !isGun) ||
|
||||
(only === "turret" && !isTurret) ||
|
||||
(only === "body" && !isBody)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+8
-8
@@ -51,21 +51,21 @@ export function GunFlexibilityVisualizer({
|
||||
const [yaw, setYaw] = useState(0);
|
||||
const [pitch, setPitch] = useState(0);
|
||||
const [minPitch, setMinPitch] = useState(
|
||||
-degToRad(gunModel.pitch.front?.max ?? gunModel.pitch.max)
|
||||
-degToRad(gunModel.pitch!.front?.max ?? gunModel.pitch!.max),
|
||||
);
|
||||
const [maxPitch, setMaxPitch] = useState(
|
||||
-degToRad(gunModel.pitch.front?.min ?? gunModel.pitch.min)
|
||||
-degToRad(gunModel.pitch!.front?.min ?? gunModel.pitch!.min),
|
||||
);
|
||||
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
const highlighter = useRef<HTMLDivElement>(null);
|
||||
const pointer = useRef<HTMLDivElement>(null);
|
||||
|
||||
const p = gunModel.pitch;
|
||||
const p = gunModel.pitch!;
|
||||
const y = turretModel.yaw;
|
||||
const f = p.front;
|
||||
const b = p.back;
|
||||
const t = gunModel.pitch.transition ?? DEFAULT_PITCH_TRANSITION;
|
||||
const t = gunModel.pitch!.transition ?? DEFAULT_PITCH_TRANSITION;
|
||||
|
||||
let d = "";
|
||||
|
||||
@@ -223,12 +223,12 @@ export function GunFlexibilityVisualizer({
|
||||
const hasImprovedVerticalStabilizer = hasEquipment(
|
||||
122,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = hasEquipment(
|
||||
124,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
|
||||
const min = applyPitchYawLimits(
|
||||
@@ -237,7 +237,7 @@ export function GunFlexibilityVisualizer({
|
||||
p,
|
||||
y,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
const max = applyPitchYawLimits(
|
||||
Math.PI,
|
||||
@@ -245,7 +245,7 @@ export function GunFlexibilityVisualizer({
|
||||
p,
|
||||
y,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
yaw = min[1];
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ export function ShellSwitcher() {
|
||||
const selected = thisShell.id === shell.id;
|
||||
|
||||
return (
|
||||
<Tooltip content={unwrap(thisShell.name)} key={thisShell.id}>
|
||||
<Tooltip content={unwrap(thisShell.name!)} key={thisShell.id}>
|
||||
<IconButton
|
||||
size="3"
|
||||
color={selected ? undefined : "gray"}
|
||||
@@ -36,7 +36,7 @@ export function ShellSwitcher() {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(thisShell.name)}
|
||||
alt={unwrap(thisShell.name!)}
|
||||
style={{ width: "1.125rem", height: "1.125rem" }}
|
||||
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
||||
/>
|
||||
|
||||
+6
-6
@@ -26,13 +26,13 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const consumables = Duel.use((state) => state.protagonist.consumables);
|
||||
const camouflage = Duel.use((state) => state.protagonist.camouflage);
|
||||
const assaultDistance = Duel.use(
|
||||
(state) => state.protagonist.assaultDistance
|
||||
(state) => state.protagonist.assaultDistance,
|
||||
);
|
||||
const equipmentMatrix = Duel.use(
|
||||
(state) => state.protagonist.equipmentMatrix
|
||||
(state) => state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const { tank, turret, gun, engine, track, shell } = Duel.use(
|
||||
(state) => state.protagonist
|
||||
(state) => state.protagonist,
|
||||
);
|
||||
const stockEngine = tank.engines[0];
|
||||
const stockTrack = tank.tracks[0];
|
||||
@@ -67,7 +67,7 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
tankModelDefinition,
|
||||
equipmentDefinitions: equipmentDefinitions,
|
||||
provisionDefinitions: provisionDefinitions,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
@@ -77,10 +77,10 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
modelTransformEvent.last!.pitch,
|
||||
modelTransformEvent.last!.yaw,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
modelTransformEvent.dispatch({ pitch, yaw });
|
||||
|
||||
+46
-46
@@ -43,11 +43,11 @@ interface ModuleWithUnlocks {
|
||||
}
|
||||
|
||||
const moduleTypeTypeIconName: Record<ModuleType, string> = {
|
||||
[ModuleType.VEHICLE]: "",
|
||||
[ModuleType.ENGINE]: "engine",
|
||||
[ModuleType.TRACKS]: "chassis",
|
||||
[ModuleType.TURRET]: "turret",
|
||||
[ModuleType.GUN]: "gun",
|
||||
[ModuleType.MODULE_TYPE_VEHICLE]: "",
|
||||
[ModuleType.MODULE_TYPE_ENGINE]: "engine",
|
||||
[ModuleType.MODULE_TYPE_TRACKS]: "chassis",
|
||||
[ModuleType.MODULE_TYPE_TURRET]: "turret",
|
||||
[ModuleType.MODULE_TYPE_GUN]: "gun",
|
||||
};
|
||||
|
||||
function ModuleButton({
|
||||
@@ -63,7 +63,7 @@ function ModuleButton({
|
||||
top: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
const isTank = unlock.type === ModuleType.VEHICLE;
|
||||
const isTank = unlock.type === ModuleType.MODULE_TYPE_VEHICLE;
|
||||
const { locale } = useLocale();
|
||||
|
||||
const button = (
|
||||
@@ -91,7 +91,7 @@ function ModuleButton({
|
||||
{TIER_ROMAN_NUMERALS[tier]}
|
||||
</Text>
|
||||
|
||||
{unlock.cost.value > 0 && (
|
||||
{unlock.cost!.value > 0 && (
|
||||
<Flex
|
||||
style={{
|
||||
position: "absolute",
|
||||
@@ -103,12 +103,12 @@ function ModuleButton({
|
||||
gap={isTank ? "1" : undefined}
|
||||
>
|
||||
<Text size="1" color="gray">
|
||||
{formatCompact(locale, unlock.cost.value)}
|
||||
{formatCompact(locale, unlock.cost!.value)}
|
||||
</Text>
|
||||
|
||||
<img
|
||||
alt={unlock.cost.type}
|
||||
src={asset(`icons/currencies/${unlock.cost.type}.webp`)}
|
||||
alt={unlock.cost!.type}
|
||||
src={asset(`icons/currencies/${unlock.cost!.type}.webp`)}
|
||||
style={{
|
||||
width: 12,
|
||||
height: 12,
|
||||
@@ -171,16 +171,16 @@ export function Modules() {
|
||||
|
||||
function setByUnlock(unlock: Unlock) {
|
||||
Duel.mutate((draft) => {
|
||||
if (unlock.type === ModuleType.TURRET) {
|
||||
if (unlock.type === ModuleType.MODULE_TYPE_TURRET) {
|
||||
draft.protagonist.turret = draft.protagonist.tank.turrets.find(
|
||||
(turret) => turret.id === unlock.id
|
||||
(turret) => turret.id === unlock.id,
|
||||
)!;
|
||||
|
||||
// Check if current gun exists in new turret
|
||||
const gunInNewTurret = draft.protagonist.turret.guns.find(
|
||||
(gun) => gun.id === draft.protagonist.gun.id
|
||||
(gun) => gun.id === draft.protagonist.gun.id,
|
||||
);
|
||||
|
||||
|
||||
if (gunInNewTurret) {
|
||||
// Gun exists - get it FROM this turret
|
||||
draft.protagonist.gun = gunInNewTurret;
|
||||
@@ -190,9 +190,9 @@ export function Modules() {
|
||||
draft.protagonist.gun = draft.protagonist.turret.guns.at(-1)!;
|
||||
draft.protagonist.shell = draft.protagonist.gun.shells[0];
|
||||
}
|
||||
} else if (unlock.type === ModuleType.GUN) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_GUN) {
|
||||
const gunInTurret = draft.protagonist.turret.guns.find(
|
||||
(gun) => gun.id === unlock.id
|
||||
(gun) => gun.id === unlock.id,
|
||||
);
|
||||
if (gunInTurret) {
|
||||
draft.protagonist.gun = gunInTurret;
|
||||
@@ -200,23 +200,23 @@ export function Modules() {
|
||||
} else {
|
||||
// TODO: warn somehow?
|
||||
const suitableTurret = draft.protagonist.tank.turrets.find((turret) =>
|
||||
turret.guns.some((gun) => gun.id === unlock.id)
|
||||
turret.guns.some((gun) => gun.id === unlock.id),
|
||||
)!;
|
||||
const gunInSuitableTurret = suitableTurret.guns.find(
|
||||
(gun) => gun.id === unlock.id
|
||||
(gun) => gun.id === unlock.id,
|
||||
)!;
|
||||
|
||||
draft.protagonist.turret = suitableTurret;
|
||||
draft.protagonist.gun = gunInSuitableTurret;
|
||||
draft.protagonist.shell = gunInSuitableTurret.shells[0];
|
||||
}
|
||||
} else if (unlock.type === ModuleType.ENGINE) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_ENGINE) {
|
||||
draft.protagonist.engine = draft.protagonist.tank.engines.find(
|
||||
(engine) => engine.id === unlock.id
|
||||
(engine) => engine.id === unlock.id,
|
||||
)!;
|
||||
} else if (unlock.type === ModuleType.TRACKS) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_TRACKS) {
|
||||
draft.protagonist.track = draft.protagonist.tank.tracks.find(
|
||||
(track) => track.id === unlock.id
|
||||
(track) => track.id === unlock.id,
|
||||
)!;
|
||||
}
|
||||
});
|
||||
@@ -231,19 +231,19 @@ export function Modules() {
|
||||
const central = !first && !last;
|
||||
let module: ModuleDefinition | TankDefinition | undefined = undefined;
|
||||
|
||||
if (unlock.type === ModuleType.TRACKS) {
|
||||
if (unlock.type === ModuleType.MODULE_TYPE_TRACKS) {
|
||||
module = tank.tracks.find((track) => track.id === unlock.id)!;
|
||||
} else if (unlock.type === ModuleType.ENGINE) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_ENGINE) {
|
||||
module = tank.engines.find((engine) => engine.id === unlock.id)!;
|
||||
} else if (unlock.type === ModuleType.TURRET) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_TURRET) {
|
||||
module = tank.turrets.find((turret) => turret.id === unlock.id)!;
|
||||
} else if (unlock.type === ModuleType.GUN) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_GUN) {
|
||||
module = tank.turrets
|
||||
.find((turret) =>
|
||||
turret.guns.some((gun) => gun.id === unlock.id)
|
||||
turret.guns.some((gun) => gun.id === unlock.id),
|
||||
)!
|
||||
.guns.find((gun) => gun.id === unlock.id)!;
|
||||
} else if (unlock.type === ModuleType.VEHICLE) {
|
||||
} else if (unlock.type === ModuleType.MODULE_TYPE_VEHICLE) {
|
||||
module = tankDefinitions.tanks[unlock.id];
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ export function Modules() {
|
||||
gap="2"
|
||||
position="relative"
|
||||
>
|
||||
{unlock.cost.value > 0 && (
|
||||
{unlock.cost!.value > 0 && (
|
||||
<>
|
||||
{unlocks.length > 1 && (
|
||||
<div
|
||||
@@ -302,24 +302,24 @@ export function Modules() {
|
||||
unlock={unlock}
|
||||
tier={extractModule(module).tier}
|
||||
selected={
|
||||
(unlock.type === ModuleType.TURRET
|
||||
(unlock.type === ModuleType.MODULE_TYPE_TURRET
|
||||
? turret.id
|
||||
: unlock.type === ModuleType.GUN
|
||||
: unlock.type === ModuleType.MODULE_TYPE_GUN
|
||||
? gun.id
|
||||
: unlock.type === ModuleType.ENGINE
|
||||
: unlock.type === ModuleType.MODULE_TYPE_ENGINE
|
||||
? engine.id
|
||||
: unlock.type === ModuleType.TRACKS
|
||||
: unlock.type === ModuleType.MODULE_TYPE_TRACKS
|
||||
? track.id
|
||||
: -1) === unlock.id
|
||||
}
|
||||
top={
|
||||
unlock.type === ModuleType.TURRET
|
||||
unlock.type === ModuleType.MODULE_TYPE_TURRET
|
||||
? extractModule(module).id == topTurret.id
|
||||
: unlock.type === ModuleType.GUN
|
||||
: unlock.type === ModuleType.MODULE_TYPE_GUN
|
||||
? extractModule(module).id === topGun.id
|
||||
: unlock.type === ModuleType.ENGINE
|
||||
: unlock.type === ModuleType.MODULE_TYPE_ENGINE
|
||||
? extractModule(module).id === topEngine.id
|
||||
: unlock.type === ModuleType.TRACKS
|
||||
: unlock.type === ModuleType.MODULE_TYPE_TRACKS
|
||||
? extractModule(module).id === topTrack.id
|
||||
: false
|
||||
}
|
||||
@@ -342,7 +342,7 @@ export function Modules() {
|
||||
{(extractModule(module) as ModuleWithUnlocks).unlocks &&
|
||||
tree(
|
||||
type,
|
||||
(extractModule(module) as ModuleWithUnlocks).unlocks!
|
||||
(extractModule(module) as ModuleWithUnlocks).unlocks!,
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
@@ -397,32 +397,32 @@ export function Modules() {
|
||||
</Flex>
|
||||
|
||||
<Flex gap="2" wrap="wrap" gapY="6">
|
||||
{tree(ModuleType.ENGINE, [
|
||||
{tree(ModuleType.MODULE_TYPE_ENGINE, [
|
||||
{
|
||||
cost: { type: "xp", value: 0 },
|
||||
id: engine0.id,
|
||||
type: ModuleType.ENGINE,
|
||||
type: ModuleType.MODULE_TYPE_ENGINE,
|
||||
},
|
||||
])}
|
||||
{tree(ModuleType.TRACKS, [
|
||||
{tree(ModuleType.MODULE_TYPE_TRACKS, [
|
||||
{
|
||||
cost: { type: "xp", value: 0 },
|
||||
id: track0.id,
|
||||
type: ModuleType.TRACKS,
|
||||
type: ModuleType.MODULE_TYPE_TRACKS,
|
||||
},
|
||||
])}
|
||||
{tree(ModuleType.TURRET, [
|
||||
{tree(ModuleType.MODULE_TYPE_TURRET, [
|
||||
{
|
||||
cost: { type: "xp", value: 0 },
|
||||
id: turret0.id,
|
||||
type: ModuleType.TURRET,
|
||||
type: ModuleType.MODULE_TYPE_TURRET,
|
||||
},
|
||||
])}
|
||||
{tree(ModuleType.GUN, [
|
||||
{tree(ModuleType.MODULE_TYPE_GUN, [
|
||||
{
|
||||
cost: { type: "xp", value: 0 },
|
||||
id: gun0.id,
|
||||
type: ModuleType.GUN,
|
||||
type: ModuleType.MODULE_TYPE_GUN,
|
||||
},
|
||||
])}
|
||||
</Flex>
|
||||
|
||||
@@ -41,7 +41,7 @@ export function GameModeSection() {
|
||||
style={{
|
||||
borderRadius: "var(--radius-3)",
|
||||
background: `url(${asset(
|
||||
`icons/game_mode_banners/${id}.webp`
|
||||
`icons/game_mode_banners/${id}.webp`,
|
||||
)})`,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
@@ -51,7 +51,7 @@ export function GameModeSection() {
|
||||
flexGrow="1"
|
||||
style={{
|
||||
background: `url(${asset(
|
||||
`icons/game_mode_banners/${id}.webp`
|
||||
`icons/game_mode_banners/${id}.webp`,
|
||||
)})`,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
@@ -71,7 +71,7 @@ export function GameModeSection() {
|
||||
justify="center"
|
||||
>
|
||||
<Text size="4" weight="bold">
|
||||
{unwrap(gameMode.name)}
|
||||
{unwrap(gameMode.name!)}
|
||||
</Text>
|
||||
|
||||
<Flex direction="column">
|
||||
@@ -88,9 +88,9 @@ export function GameModeSection() {
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/provisions/${id}.webp`)}
|
||||
alt={unwrap(provisions.name)}
|
||||
alt={unwrap(provisions.name!)}
|
||||
/>
|
||||
{unwrap(provisions.name)}
|
||||
{unwrap(provisions.name!)}
|
||||
</Flex>
|
||||
</Text>
|
||||
);
|
||||
@@ -109,9 +109,9 @@ export function GameModeSection() {
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/consumables/${id}.webp`)}
|
||||
alt={unwrap(consumable.name)}
|
||||
alt={unwrap(consumable.name!)}
|
||||
/>
|
||||
{unwrap(consumable.name)}
|
||||
{unwrap(consumable.name!)}
|
||||
</Flex>
|
||||
</Text>
|
||||
);
|
||||
|
||||
+15
-15
@@ -68,29 +68,29 @@ export function CustomShellButton() {
|
||||
const modified = { ...customShell, type };
|
||||
|
||||
switch (type) {
|
||||
case ShellType.AP: {
|
||||
case ShellType.SHELL_TYPE_AP: {
|
||||
modified.normalization = 5;
|
||||
modified.ricochet = 70;
|
||||
modified.explosion_radius = undefined;
|
||||
break;
|
||||
}
|
||||
case ShellType.APCR: {
|
||||
case ShellType.SHELL_TYPE_APCR: {
|
||||
modified.normalization = 2;
|
||||
modified.ricochet = 70;
|
||||
modified.explosion_radius = undefined;
|
||||
break;
|
||||
}
|
||||
case ShellType.HEAT: {
|
||||
case ShellType.SHELL_TYPE_HEAT: {
|
||||
modified.normalization = undefined;
|
||||
modified.ricochet = undefined;
|
||||
modified.explosion_radius = undefined;
|
||||
}
|
||||
case ShellType.HE: {
|
||||
case ShellType.SHELL_TYPE_HE: {
|
||||
modified.normalization = undefined;
|
||||
modified.ricochet = undefined;
|
||||
modified.explosion_radius =
|
||||
gun.shells.find(
|
||||
(shell) => shell.type === ShellType.HE
|
||||
(shell) => shell.type === ShellType.SHELL_TYPE_HE,
|
||||
)?.explosion_radius ?? 1;
|
||||
break;
|
||||
}
|
||||
@@ -104,16 +104,16 @@ export function CustomShellButton() {
|
||||
<Select.Trigger variant="classic" />
|
||||
|
||||
<Select.Content>
|
||||
<Select.Item value={`${ShellType.AP}`}>
|
||||
<Select.Item value={`${ShellType.SHELL_TYPE_AP}`}>
|
||||
{strings.common.shells.ap}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.APCR}`}>
|
||||
<Select.Item value={`${ShellType.SHELL_TYPE_APCR}`}>
|
||||
{strings.common.shells.ap_cr}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.HEAT}`}>
|
||||
<Select.Item value={`${ShellType.SHELL_TYPE_HEAT}`}>
|
||||
{strings.common.shells.hc}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.HE}`}>
|
||||
<Select.Item value={`${ShellType.SHELL_TYPE_HE}`}>
|
||||
{strings.common.shells.he}
|
||||
</Select.Item>
|
||||
</Select.Content>
|
||||
@@ -166,11 +166,11 @@ export function CustomShellButton() {
|
||||
<TextField.Root
|
||||
variant="classic"
|
||||
style={{ maxWidth: "6rem" }}
|
||||
defaultValue={customShell.penetration.near}
|
||||
defaultValue={customShell.penetration!.near}
|
||||
type="number"
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.customShell!.penetration.near =
|
||||
draft.customShell!.penetration!.near =
|
||||
event.target.valueAsNumber;
|
||||
});
|
||||
}}
|
||||
@@ -182,7 +182,7 @@ export function CustomShellButton() {
|
||||
(event.target as HTMLInputElement).blur();
|
||||
} else if (event.key === "Escape") {
|
||||
(event.target as HTMLInputElement).valueAsNumber =
|
||||
customShell.penetration.near;
|
||||
customShell.penetration!.near;
|
||||
(event.target as HTMLInputElement).blur();
|
||||
}
|
||||
}}
|
||||
@@ -193,8 +193,8 @@ export function CustomShellButton() {
|
||||
</TextField.Root>
|
||||
</Flex>
|
||||
|
||||
{(customShell.type === ShellType.AP ||
|
||||
customShell.type === ShellType.APCR) && (
|
||||
{(customShell.type === ShellType.SHELL_TYPE_AP ||
|
||||
customShell.type === ShellType.SHELL_TYPE_APCR) && (
|
||||
<>
|
||||
<Flex align="center" justify="between" gap="4" py="1">
|
||||
<Text>
|
||||
@@ -264,7 +264,7 @@ export function CustomShellButton() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{customShell.type === ShellType.HE && (
|
||||
{customShell.type === ShellType.SHELL_TYPE_HE && (
|
||||
<Flex align="center" justify="between" gap="4">
|
||||
<Text>Explosion radius</Text>
|
||||
<TextField.Root
|
||||
|
||||
+7
-7
@@ -38,7 +38,7 @@ export function QuickInputs() {
|
||||
}
|
||||
|
||||
function handleTransformEvent(
|
||||
event: QuicklimeEvent<ModelTransformEventData>
|
||||
event: QuicklimeEvent<ModelTransformEventData>,
|
||||
) {
|
||||
syncInputValues(event.data);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export function QuickInputs() {
|
||||
|
||||
if (isNaN(value)) {
|
||||
yawInput.current!.value = radToDeg(
|
||||
modelTransformEvent.last!.yaw
|
||||
modelTransformEvent.last!.yaw,
|
||||
).toFixed(1);
|
||||
return;
|
||||
}
|
||||
@@ -85,15 +85,15 @@ export function QuickInputs() {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
modelTransformEvent.last!.pitch,
|
||||
degToRad(value),
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
modelTransformEvent.dispatch({ pitch, yaw });
|
||||
yawInput.current!.value = radToDeg(
|
||||
modelTransformEvent.last!.yaw
|
||||
modelTransformEvent.last!.yaw,
|
||||
).toFixed(1);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
@@ -129,10 +129,10 @@ export function QuickInputs() {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
degToRad(value + initialGunPitch),
|
||||
modelTransformEvent.last!.yaw,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.dispatch({ pitch, yaw });
|
||||
pitchInput.current!.value = (
|
||||
|
||||
@@ -54,12 +54,12 @@ type OptionsProps = MaybeSkeletonComponentProps & {
|
||||
|
||||
export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
||||
const hasCustomShell = Tankopedia.use(
|
||||
(state) => state.customShell !== undefined
|
||||
(state) => state.customShell !== undefined,
|
||||
);
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
const isFullScreen = useFullScreen();
|
||||
const advancedHighlighting = TankopediaPersistent.use(
|
||||
(state) => state.advancedHighlighting
|
||||
(state) => state.advancedHighlighting,
|
||||
);
|
||||
const fullScreenAvailable = useFullscreenAvailability(true);
|
||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||
@@ -102,8 +102,8 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
||||
value: (
|
||||
resolvePenetrationCoefficient(
|
||||
hasCalibratedShells,
|
||||
antagonistShell.type
|
||||
) * antagonistShell.penetration.near
|
||||
antagonistShell.type,
|
||||
) * antagonistShell.penetration!.near
|
||||
).toFixed(0),
|
||||
})}
|
||||
</Text>
|
||||
@@ -203,7 +203,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(thisShell.name)}
|
||||
alt={unwrap(thisShell.name!)}
|
||||
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
||||
style={{
|
||||
width: "50%",
|
||||
@@ -456,7 +456,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
||||
<Dialog.Trigger>
|
||||
<Button variant="solid" highContrast>
|
||||
<Crosshair1Icon />
|
||||
{unwrap(antagonistTank.name)}
|
||||
{unwrap(antagonistTank.name!)}
|
||||
<SmallTankIcon id={antagonistTank.id} size={16} />
|
||||
</Button>
|
||||
</Dialog.Trigger>
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ export function Title() {
|
||||
const protagonist = Duel.use((state) => state.protagonist.tank);
|
||||
const revealed = Tankopedia.use((state) => state.revealed);
|
||||
const disturbed = Tankopedia.use((state) => state.disturbed);
|
||||
const name = unwrap(protagonist.name);
|
||||
const name = unwrap(protagonist.name!);
|
||||
const fontSize = revealed
|
||||
? disturbed
|
||||
? "1.5rem"
|
||||
|
||||
+14
-14
@@ -53,24 +53,24 @@ export function Controls({
|
||||
const protagonistGunModelDefinition =
|
||||
protagonistTurretModelDefinition.guns[protagonistGun.id];
|
||||
const protagonistHullOrigin = new Vector3(
|
||||
protagonistTrackModelDefinition.origin.x,
|
||||
protagonistTrackModelDefinition.origin.y,
|
||||
-protagonistTrackModelDefinition.origin.z,
|
||||
protagonistTrackModelDefinition.origin!.x,
|
||||
protagonistTrackModelDefinition.origin!.y,
|
||||
-protagonistTrackModelDefinition.origin!.z,
|
||||
);
|
||||
const protagonistTurretOrigin = new Vector3(
|
||||
protagonistModelDefinition.turret_origin.x,
|
||||
protagonistModelDefinition.turret_origin.y,
|
||||
-protagonistModelDefinition.turret_origin.z,
|
||||
protagonistModelDefinition.turret_origin!.x,
|
||||
protagonistModelDefinition.turret_origin!.y,
|
||||
-protagonistModelDefinition.turret_origin!.z,
|
||||
);
|
||||
const protagonistGunOrigin = new Vector3(
|
||||
protagonistTurretModelDefinition.gun_origin.x,
|
||||
protagonistTurretModelDefinition.gun_origin.y,
|
||||
-protagonistTurretModelDefinition.gun_origin.z,
|
||||
protagonistTurretModelDefinition.gun_origin!.x,
|
||||
protagonistTurretModelDefinition.gun_origin!.y,
|
||||
-protagonistTurretModelDefinition.gun_origin!.z,
|
||||
);
|
||||
const antagonistGunHeight =
|
||||
protagonistTrackModelDefinition.origin.y +
|
||||
antagonistModelDefinition.turret_origin.y +
|
||||
antagonistTurretModelDefinition.gun_origin.y;
|
||||
protagonistTrackModelDefinition.origin!.y +
|
||||
antagonistModelDefinition.turret_origin!.y +
|
||||
antagonistTurretModelDefinition.gun_origin!.y;
|
||||
const disturbed = Tankopedia.use((state) => state.disturbed);
|
||||
const doAutoRotate = autoRotate && !disturbed;
|
||||
const gunHeight =
|
||||
@@ -119,7 +119,7 @@ export function Controls({
|
||||
const [pitch] = applyPitchYawLimits(
|
||||
-Infinity,
|
||||
0,
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistGunModelDefinition.pitch!,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
@@ -152,7 +152,7 @@ export function Controls({
|
||||
const [pitch] = applyPitchYawLimits(
|
||||
0,
|
||||
0,
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistGunModelDefinition.pitch!,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
|
||||
+7
-7
@@ -1,9 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
import { degToRad } from 'three/src/math/MathUtils.js';
|
||||
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
|
||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||
import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform';
|
||||
import { Duel } from '../../../../../../stores/duel';
|
||||
import { useEffect } from "react";
|
||||
import { degToRad } from "three/src/math/MathUtils.js";
|
||||
import { awaitableModelDefinitions } from "../../../../../../core/awaitables/modelDefinitions";
|
||||
import { applyPitchYawLimits } from "../../../../../../core/blitz/applyPitchYawLimits";
|
||||
import { modelTransformEvent } from "../../../../../../core/blitzkit/modelTransform";
|
||||
import { Duel } from "../../../../../../stores/duel";
|
||||
|
||||
const modelDefinitions = await awaitableModelDefinitions;
|
||||
|
||||
@@ -20,7 +20,7 @@ export function InitialAligner() {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
degToRad(8),
|
||||
degToRad(25),
|
||||
gunModel.pitch,
|
||||
gunModel.pitch!,
|
||||
turretModel.yaw,
|
||||
);
|
||||
|
||||
|
||||
+8
-8
@@ -134,12 +134,12 @@ export function TankModel() {
|
||||
const hasImprovedVerticalStabilizer = hasEquipment(
|
||||
122,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = hasEquipment(
|
||||
124,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
@@ -150,10 +150,10 @@ export function TankModel() {
|
||||
modelTransformEvent.last!.pitch,
|
||||
modelTransformEvent.last!.yaw +
|
||||
delta.x * (Math.PI / boundingRect.width),
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.dispatch({ pitch, yaw });
|
||||
}
|
||||
@@ -217,12 +217,12 @@ export function TankModel() {
|
||||
const hasImprovedVerticalStabilizer = hasEquipment(
|
||||
122,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = hasEquipment(
|
||||
124,
|
||||
Duel.state.protagonist.tank.equipment_preset,
|
||||
Duel.state.protagonist.equipmentMatrix
|
||||
Duel.state.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
@@ -231,10 +231,10 @@ export function TankModel() {
|
||||
[pitch, yaw] = applyPitchYawLimits(
|
||||
pitch - delta.y * (Math.PI / boundingRect.height),
|
||||
yaw + delta.x * (Math.PI / boundingRect.width),
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.dispatch({ pitch, yaw });
|
||||
}
|
||||
|
||||
+5
-5
@@ -37,9 +37,9 @@ export function TransitionSkeleton() {
|
||||
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
||||
const trackModelDefinition = tankModelDefinition.tracks[track.id];
|
||||
const wrapper = useRef<Group>(null);
|
||||
const hullOrigin = correctZYTuple(trackModelDefinition.origin);
|
||||
const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin);
|
||||
const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin);
|
||||
const hullOrigin = correctZYTuple(trackModelDefinition.origin!);
|
||||
const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin!);
|
||||
const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin!);
|
||||
|
||||
useTankTransform(track, turret, turretContainer, gunContainer);
|
||||
|
||||
@@ -77,7 +77,7 @@ export function TransitionSkeleton() {
|
||||
<group ref={turretContainer}>
|
||||
{armorNodes.map((node) => {
|
||||
const isCurrentTurret = node.name.startsWith(
|
||||
`turret_${turretModelDefinition.model_id.toString().padStart(2, "0")}`
|
||||
`turret_${turretModelDefinition.model_id.toString().padStart(2, "0")}`,
|
||||
);
|
||||
const isVisible = isCurrentTurret;
|
||||
if (!isVisible) {
|
||||
@@ -102,7 +102,7 @@ export function TransitionSkeleton() {
|
||||
<group ref={gunContainer}>
|
||||
{armorNodes.map((node) => {
|
||||
const isCurrentGun = node.name.startsWith(
|
||||
`gun_${gunModelDefinition.model_id.toString().padStart(2, "0")}`
|
||||
`gun_${gunModelDefinition.model_id.toString().padStart(2, "0")}`,
|
||||
);
|
||||
const isVisible = isCurrentGun;
|
||||
|
||||
|
||||
+4
-4
@@ -73,7 +73,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
-Infinity,
|
||||
0,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
@@ -88,7 +88,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
Infinity,
|
||||
0,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
);
|
||||
@@ -102,7 +102,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
0,
|
||||
0,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
);
|
||||
@@ -124,7 +124,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
modelTransformEvent.last!.pitch,
|
||||
modelTransformEvent.last!.yaw,
|
||||
gunModelDefinition.pitch,
|
||||
gunModelDefinition.pitch!,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
@@ -22,13 +22,13 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const thicknessRange = useMemo(() => {
|
||||
const entries = Object.values(tankDefinitions.tanks);
|
||||
const filtered = entries.filter(
|
||||
(thisTank) => thisTank.tier === protagonist.tier
|
||||
(thisTank) => thisTank.tier === protagonist.tier,
|
||||
);
|
||||
const value =
|
||||
(filtered.reduce((accumulator, thisTank) => {
|
||||
return (
|
||||
accumulator +
|
||||
thisTank.turrets.at(-1)!.guns.at(-1)!.shells[0].penetration.near
|
||||
thisTank.turrets.at(-1)!.guns.at(-1)!.shells[0].penetration!.near
|
||||
);
|
||||
}, 0) /
|
||||
filtered.length) *
|
||||
@@ -99,11 +99,11 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
isFullScreen
|
||||
? "100vh"
|
||||
: disturbed
|
||||
? "calc(100svh - 8rem)"
|
||||
: {
|
||||
initial: "28rem",
|
||||
md: "calc(100svh - 14rem)",
|
||||
}
|
||||
? "calc(100svh - 8rem)"
|
||||
: {
|
||||
initial: "28rem",
|
||||
md: "calc(100svh - 14rem)",
|
||||
}
|
||||
}
|
||||
maxWidth={isFullScreen ? undefined : "120rem"}
|
||||
flexGrow="1"
|
||||
|
||||
+3
-3
@@ -36,7 +36,7 @@ export function VoteCaster() {
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Content maxWidth="23rem">
|
||||
<Dialog.Title>Voting for {unwrap(tank.name)}</Dialog.Title>
|
||||
<Dialog.Title>Voting for {unwrap(tank.name!)}</Dialog.Title>
|
||||
|
||||
<Flex direction="column" mt="4">
|
||||
<Flex align="center" justify="between">
|
||||
@@ -118,10 +118,10 @@ export function VoteCaster() {
|
||||
survivability === null
|
||||
? ""
|
||||
: `survivability=${survivability}&`
|
||||
}player=${wargaming.id}&token=${wargaming.token}`
|
||||
}player=${wargaming.id}&token=${wargaming.token}`,
|
||||
)
|
||||
.then(
|
||||
(response) => response.json() as Promise<BlitzkitResponse>
|
||||
(response) => response.json() as Promise<BlitzkitResponse>,
|
||||
)
|
||||
.then((json) => {
|
||||
setShowDialogue(false);
|
||||
|
||||
@@ -3,20 +3,20 @@ import {
|
||||
TankPriceType,
|
||||
TankType,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '@blitzkit/core';
|
||||
import { Box, Flex } from '@radix-ui/themes';
|
||||
import { Var } from '../../../core/radix/var';
|
||||
import { useLocale } from '../../../hooks/useLocale';
|
||||
import { App } from '../../../stores/app';
|
||||
import { Duel } from '../../../stores/duel';
|
||||
import { classIcons } from '../../ClassIcon';
|
||||
import { CopyableCode } from '../../CopyableCode';
|
||||
import { Listing } from './components/Listing';
|
||||
} from "@blitzkit/core";
|
||||
import { Box, Flex } from "@radix-ui/themes";
|
||||
import { Var } from "../../../core/radix/var";
|
||||
import { useLocale } from "../../../hooks/useLocale";
|
||||
import { App } from "../../../stores/app";
|
||||
import { Duel } from "../../../stores/duel";
|
||||
import { classIcons } from "../../ClassIcon";
|
||||
import { CopyableCode } from "../../CopyableCode";
|
||||
import { Listing } from "./components/Listing";
|
||||
|
||||
const NATIONAL_BANNER_POSITION_OVERRIDES: Record<string, string> = {
|
||||
germany: '50% 35%',
|
||||
france: '50% 35%',
|
||||
other: '50% 35%',
|
||||
germany: "50% 35%",
|
||||
france: "50% 35%",
|
||||
other: "50% 35%",
|
||||
};
|
||||
|
||||
export function MetaSection() {
|
||||
@@ -30,10 +30,10 @@ export function MetaSection() {
|
||||
<Box
|
||||
style={{
|
||||
background: `url(/assets/images/national-wallpapers/${protagonist.nation}.jpg)`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition:
|
||||
NATIONAL_BANNER_POSITION_OVERRIDES[protagonist.nation] ?? 'center',
|
||||
NATIONAL_BANNER_POSITION_OVERRIDES[protagonist.nation] ?? "center",
|
||||
}}
|
||||
flexGrow="1"
|
||||
maxWidth="120rem"
|
||||
@@ -41,9 +41,9 @@ export function MetaSection() {
|
||||
<Box
|
||||
style={{
|
||||
background: `url(${asset(`flags/scratched/${protagonist.nation}.webp`)})`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'min(53rem, 80vw)',
|
||||
backgroundPosition: '-8rem 50%',
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "min(53rem, 80vw)",
|
||||
backgroundPosition: "-8rem 50%",
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@@ -51,19 +51,19 @@ export function MetaSection() {
|
||||
align="center"
|
||||
py="6rem"
|
||||
style={{
|
||||
background: `linear-gradient(${Var('black-a8')}, ${Var('black-a8')}, ${Var('gray-1')})`,
|
||||
background: `linear-gradient(${Var("black-a8")}, ${Var("black-a8")}, ${Var("gray-1")})`,
|
||||
}}
|
||||
>
|
||||
<Flex direction="column" align="center" gap="6">
|
||||
<Flex
|
||||
gap={{ initial: '2', sm: '8' }}
|
||||
direction={{ initial: 'column', sm: 'row' }}
|
||||
gap={{ initial: "2", sm: "8" }}
|
||||
direction={{ initial: "column", sm: "row" }}
|
||||
>
|
||||
<Flex direction="column" width="100%" gap="2">
|
||||
<Listing label={strings.website.tools.tankopedia.meta.nation}>
|
||||
<Flex align="center" gap="1">
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
style={{ width: "1em", height: "1em" }}
|
||||
alt={protagonist.nation}
|
||||
src={asset(`flags/circle/${protagonist.nation}.webp`)}
|
||||
/>
|
||||
@@ -86,10 +86,10 @@ export function MetaSection() {
|
||||
<Listing
|
||||
label={strings.website.tools.tankopedia.meta.type}
|
||||
color={
|
||||
protagonist.type === TankType.COLLECTOR
|
||||
? 'blue'
|
||||
: protagonist.type === TankType.PREMIUM
|
||||
? 'amber'
|
||||
protagonist.type === TankType.TANK_TYPE_COLLECTOR
|
||||
? "blue"
|
||||
: protagonist.type === TankType.TANK_TYPE_PREMIUM
|
||||
? "amber"
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
@@ -117,7 +117,7 @@ export function MetaSection() {
|
||||
label={strings.website.tools.tankopedia.meta.dev_name}
|
||||
>
|
||||
<CopyableCode
|
||||
copy={devName}
|
||||
copy={protagonist.dev_name}
|
||||
variant="soft"
|
||||
highContrast
|
||||
color="gray"
|
||||
@@ -126,37 +126,38 @@ export function MetaSection() {
|
||||
</CopyableCode>
|
||||
</Listing>
|
||||
)}
|
||||
{protagonist.type === TankType.PREMIUM && (
|
||||
{protagonist.type === TankType.TANK_TYPE_PREMIUM && (
|
||||
<Listing
|
||||
label={strings.website.tools.tankopedia.meta.purchase}
|
||||
>
|
||||
<Flex align="center" gap="1">
|
||||
{protagonist.price.value / 400}
|
||||
{protagonist.price!.value / 400}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
style={{ width: "1em", height: "1em" }}
|
||||
alt="gold"
|
||||
src={asset('icons/currencies/gold.webp')}
|
||||
src={asset("icons/currencies/gold.webp")}
|
||||
/>
|
||||
</Flex>
|
||||
</Listing>
|
||||
)}
|
||||
<Listing
|
||||
label={
|
||||
protagonist.type === TankType.RESEARCHABLE
|
||||
protagonist.type === TankType.TANK_TYPE_RESEARCHABLE
|
||||
? strings.website.tools.tankopedia.meta.purchase
|
||||
: strings.website.tools.tankopedia.meta.restoration
|
||||
}
|
||||
>
|
||||
<Flex align="center" gap="1">
|
||||
{protagonist.price.value.toLocaleString(locale)}
|
||||
{protagonist.price!.value.toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
alt={TankPriceType[protagonist.price.type]}
|
||||
style={{ width: "1em", height: "1em" }}
|
||||
alt={TankPriceType[protagonist.price!.type]}
|
||||
src={asset(
|
||||
`icons/currencies/${
|
||||
protagonist.price.type === TankPriceType.GOLD
|
||||
? 'gold'
|
||||
: 'silver'
|
||||
protagonist.price!.type ===
|
||||
TankPriceType.TANK_PRICE_TYPE_GOLD
|
||||
? "gold"
|
||||
: "silver"
|
||||
}.webp`,
|
||||
)}
|
||||
/>
|
||||
@@ -164,15 +165,16 @@ export function MetaSection() {
|
||||
</Listing>
|
||||
<Listing label={strings.website.tools.tankopedia.meta.sale}>
|
||||
<Flex align="center" gap="1">
|
||||
{(protagonist.price.value / 2).toLocaleString(locale)}
|
||||
{(protagonist.price!.value / 2).toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
alt={TankPriceType[protagonist.price.type]}
|
||||
style={{ width: "1em", height: "1em" }}
|
||||
alt={TankPriceType[protagonist.price!.type]}
|
||||
src={asset(
|
||||
`icons/currencies/${
|
||||
protagonist.price.type === TankPriceType.GOLD
|
||||
? 'gold'
|
||||
: 'silver'
|
||||
protagonist.price!.type ===
|
||||
TankPriceType.TANK_PRICE_TYPE_GOLD
|
||||
? "gold"
|
||||
: "silver"
|
||||
}.webp`,
|
||||
)}
|
||||
/>
|
||||
@@ -188,9 +190,9 @@ export function MetaSection() {
|
||||
.value as number
|
||||
).toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
style={{ width: "1em", height: "1em" }}
|
||||
alt="xp"
|
||||
src={asset('icons/currencies/xp.webp')}
|
||||
src={asset("icons/currencies/xp.webp")}
|
||||
/>
|
||||
</Flex>
|
||||
</Listing>
|
||||
|
||||
@@ -36,7 +36,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||
? 0
|
||||
: (tank.research_cost.research_cost_type!.value as number) /
|
||||
xpMultiplier),
|
||||
0
|
||||
0,
|
||||
);
|
||||
const averages = averageDefinitions.averages[tank.id]?.mu;
|
||||
const averageXp = averages ? averages.xp / averages.battles : undefined;
|
||||
@@ -78,7 +78,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(tank.name)}
|
||||
alt={unwrap(tank.name!)}
|
||||
src={asset(`icons/tanks/big/${id}.webp`)}
|
||||
width={64}
|
||||
height={64}
|
||||
@@ -92,7 +92,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||
<Text color="gray" size="1">
|
||||
{TIER_ROMAN_NUMERALS[tank.tier]}
|
||||
</Text>
|
||||
<Text wrap="nowrap">{unwrap(tank.name)}</Text>
|
||||
<Text wrap="nowrap">{unwrap(tank.name!)}</Text>
|
||||
</Flex>
|
||||
<Flex gap="2" align="center">
|
||||
<Text color="gray" size="1" wrap="nowrap">
|
||||
@@ -122,7 +122,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||
objectPosition: "center",
|
||||
}}
|
||||
/>
|
||||
{formatCompact(locale, tank.price.value)}
|
||||
{formatCompact(locale, tank.price!.value)}
|
||||
</Flex>
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -135,7 +135,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||
? strings.website.tools.tankopedia.tech_tree.battle
|
||||
: literals(
|
||||
strings.website.tools.tankopedia.tech_tree.battles,
|
||||
{ count: games }
|
||||
{ count: games },
|
||||
))}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -26,14 +26,18 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
function extend(line: Line): Line[] {
|
||||
const root = tankDefinitions.tanks[line.at(-1)!];
|
||||
|
||||
if (root.ancestors === undefined || root.ancestors.length === 0 || root.tier === 1) {
|
||||
if (
|
||||
root.ancestors === undefined ||
|
||||
root.ancestors.length === 0 ||
|
||||
root.tier === 1
|
||||
) {
|
||||
return [line];
|
||||
} else {
|
||||
if (root.ancestors.length === 1 || root.tier === 2) {
|
||||
line.push(
|
||||
root.ancestors.find(
|
||||
(ancestor) => !tankDefinitions.tanks[ancestor].deprecated
|
||||
) ?? root.ancestors[0]
|
||||
(ancestor) => !tankDefinitions.tanks[ancestor].deprecated,
|
||||
) ?? root.ancestors[0],
|
||||
);
|
||||
return extend(line);
|
||||
} else {
|
||||
@@ -52,7 +56,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const [lineIndex, setLineIndex] = useState(0);
|
||||
const line = useMemo(
|
||||
() => (lines.length === 0 ? [master.id] : [...lines[lineIndex]].reverse()),
|
||||
[master, lineIndex]
|
||||
[master, lineIndex],
|
||||
);
|
||||
const totalXp = line.reduce(
|
||||
(xp, id) =>
|
||||
@@ -62,11 +66,11 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
? 0
|
||||
: (tankDefinitions.tanks[id].research_cost.research_cost_type!
|
||||
.value as number)),
|
||||
0
|
||||
0,
|
||||
);
|
||||
const totalCredits = line.reduce(
|
||||
(credits, id) => credits + tankDefinitions.tanks[id].price.value,
|
||||
0
|
||||
(credits, id) => credits + tankDefinitions.tanks[id].price!.value,
|
||||
0,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -75,7 +79,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
});
|
||||
|
||||
if (
|
||||
master.type !== TankType.RESEARCHABLE ||
|
||||
master.type !== TankType.TANK_TYPE_RESEARCHABLE ||
|
||||
master.ancestors === undefined ||
|
||||
master.ancestors.length === 0
|
||||
) {
|
||||
|
||||
Reference in new issue
Block a user