mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
13 files changed
+179
-109
No files matched your search
@@ -0,0 +1,18 @@
|
|||||||
|
# BlitzKit 1.29.16
|
||||||
|
|
||||||
|
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- [GonnaHetzMe] The turret for Centurion I is no longer offset from the body
|
||||||
|
- Please allow up to 24 hours for the model to update
|
||||||
|
- Vertical Stabilizers now give the correct 12% buff instead of 15%
|
||||||
|
- Re-ordering tanks in Compare now works once again
|
||||||
|
- Fixed review videos from being about the Object 452K across all tanks
|
||||||
|
- Please allow up to 2 weeks for all tanks to refresh their videos
|
||||||
|
- Tanks in Mixer with oscillating turrets are not handled properly
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Headings in the Compare tool are now even more compact for mobile devices
|
||||||
|
- Enabled all tiers for the randomizer in Mixer
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
"version": "1.29.15",
|
"version": "1.29.16",
|
||||||
"license": "BlitzKit License",
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ export async function extractModel(vfs: AbstractVFS, path: string) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "TransformComponent": {
|
case "TransformComponent": {
|
||||||
|
component["tc.localTranslation"] = [0, 0, 0]; // Game when is loading model resets position to [0, 0, 0], so any set value is ignored.
|
||||||
node.setTranslation(component["tc.localTranslation"]);
|
node.setTranslation(component["tc.localTranslation"]);
|
||||||
node.setRotation(component["tc.localRotation"]);
|
node.setRotation(component["tc.localRotation"]);
|
||||||
node.setScale(component["tc.localScale"]);
|
node.setScale(component["tc.localScale"]);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
Video,
|
Video,
|
||||||
youtubers,
|
youtubers,
|
||||||
} from "@blitzkit/core";
|
} from "@blitzkit/core";
|
||||||
|
import locales from "@blitzkit/i18n/locales.json";
|
||||||
import { google } from "googleapis";
|
import { google } from "googleapis";
|
||||||
import { cloneDeep, uniqBy } from "lodash-es";
|
import { cloneDeep, uniqBy } from "lodash-es";
|
||||||
import { AssetUploader } from "./core/github/assetUploader";
|
import { AssetUploader } from "./core/github/assetUploader";
|
||||||
@@ -42,9 +43,11 @@ for (const tank of tanksSanitized) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const q = `World of Tanks Blitz ${tank.name.locales[locales.default]}`;
|
||||||
|
|
||||||
const results = await youtube.search.list({
|
const results = await youtube.search.list({
|
||||||
part: ["snippet"],
|
part: ["snippet"],
|
||||||
q: `World of Tanks Blitz ${tank.name}`,
|
q,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!results.data.items || results.data.items.length === 0) continue;
|
if (!results.data.items || results.data.items.length === 0) continue;
|
||||||
@@ -54,9 +57,9 @@ for (const tank of tanksSanitized) {
|
|||||||
(item) =>
|
(item) =>
|
||||||
item.snippet?.channelId &&
|
item.snippet?.channelId &&
|
||||||
item.id?.videoId &&
|
item.id?.videoId &&
|
||||||
youtubers.some(({ id }) => id === item.snippet?.channelId)
|
youtubers.some(({ id }) => id === item.snippet?.channelId),
|
||||||
),
|
),
|
||||||
(item) => item.snippet!.channelId
|
(item) => item.snippet!.channelId,
|
||||||
);
|
);
|
||||||
|
|
||||||
reviews.reviews[tank.id] = {
|
reviews.reviews[tank.id] = {
|
||||||
@@ -66,11 +69,13 @@ for (const tank of tanksSanitized) {
|
|||||||
({
|
({
|
||||||
id: item.id!.videoId!,
|
id: item.id!.videoId!,
|
||||||
author: item.snippet!.channelId!,
|
author: item.snippet!.channelId!,
|
||||||
} satisfies Video)
|
}) satisfies Video,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`${++done} done; found ${items.length} for ${tank.name.locales.en}`);
|
console.log(
|
||||||
|
`${++done} done; found ${items.length} for ${tank.name.locales.en}`,
|
||||||
|
);
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000 / 5));
|
await new Promise((resolve) => setTimeout(resolve, 1000 / 5));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { StickyRowHeaderCell } from "../StickyRowHeaderCell";
|
|||||||
|
|
||||||
type CompareRowProps = {
|
type CompareRowProps = {
|
||||||
display?: (
|
display?: (
|
||||||
member: Awaited<TankCharacteristics>
|
member: Awaited<TankCharacteristics>,
|
||||||
) => number | string | undefined;
|
) => number | string | undefined;
|
||||||
deltaType?: CompareCellDirection;
|
deltaType?: CompareCellDirection;
|
||||||
decimals?: number;
|
decimals?: number;
|
||||||
@@ -46,7 +46,7 @@ export function CompareRow({
|
|||||||
const values = stats.map((stat) =>
|
const values = stats.map((stat) =>
|
||||||
typeof props.value === "function"
|
typeof props.value === "function"
|
||||||
? props.value(stat)!
|
? props.value(stat)!
|
||||||
: (stat[props.value] as number)
|
: (stat[props.value] as number),
|
||||||
);
|
);
|
||||||
const id = useRef(Math.random());
|
const id = useRef(Math.random());
|
||||||
const name =
|
const name =
|
||||||
@@ -56,10 +56,10 @@ export function CompareRow({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
<StickyRowHeaderCell>
|
<StickyRowHeaderCell left="-1.25rem">
|
||||||
<Flex
|
<Flex
|
||||||
align="center"
|
align="center"
|
||||||
style={{ whiteSpace: "nowrap" }}
|
maxWidth={{ initial: "6rem", sm: "unset" }}
|
||||||
gap={indent ? { initial: "4", sm: "6" } : { initial: "1", sm: "2" }}
|
gap={indent ? { initial: "4", sm: "6" } : { initial: "1", sm: "2" }}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -111,8 +111,8 @@ export function CompareRow({
|
|||||||
const resolvedDisplayValue = display
|
const resolvedDisplayValue = display
|
||||||
? display(stats[index])
|
? display(stats[index])
|
||||||
: decimals === undefined
|
: decimals === undefined
|
||||||
? value
|
? value
|
||||||
: value?.toFixed(decimals);
|
: value?.toFixed(decimals);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CompareCell
|
<CompareCell
|
||||||
@@ -145,8 +145,8 @@ export function CompareRow({
|
|||||||
deltaNominalDisplay
|
deltaNominalDisplay
|
||||||
? deltaNominalDisplay(delta)
|
? deltaNominalDisplay(delta)
|
||||||
: decimals === undefined
|
: decimals === undefined
|
||||||
? delta
|
? delta
|
||||||
: delta.toFixed(decimals)
|
: delta.toFixed(decimals)
|
||||||
}`}
|
}`}
|
||||||
)
|
)
|
||||||
</Text>
|
</Text>
|
||||||
@@ -156,7 +156,7 @@ export function CompareRow({
|
|||||||
<Text color="gray">
|
<Text color="gray">
|
||||||
(
|
(
|
||||||
{`${deltaPercentage > 0 ? "+" : ""}${Math.round(
|
{`${deltaPercentage > 0 ? "+" : ""}${Math.round(
|
||||||
deltaPercentage * 100
|
deltaPercentage * 100,
|
||||||
)}%`}
|
)}%`}
|
||||||
)
|
)
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Heading, Table } from '@radix-ui/themes';
|
import { Heading, Table } from "@radix-ui/themes";
|
||||||
import { times } from 'lodash-es';
|
import { times } from "lodash-es";
|
||||||
import { CompareEphemeral } from '../../stores/compareEphemeral';
|
import { CompareEphemeral } from "../../stores/compareEphemeral";
|
||||||
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
import { StickyColumnHeaderCell } from "../StickyColumnHeaderCell";
|
||||||
|
|
||||||
export function CompareSectionTitle({ children }: { children: string }) {
|
export function CompareSectionTitle({ children }: { children: string }) {
|
||||||
const memberCount = CompareEphemeral.use((state) => state.members.length);
|
const memberCount = CompareEphemeral.use((state) => state.members.length);
|
||||||
|
|||||||
@@ -105,13 +105,13 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
crewSkills[skill] === 0
|
crewSkills[skill] === 0
|
||||||
? Var("gray-11")
|
? Var("gray-11")
|
||||||
: permanentSkills.includes(skill)
|
: permanentSkills.includes(skill)
|
||||||
? Var("crimson-11")
|
? Var("crimson-11")
|
||||||
: Var("amber-11"),
|
: Var("amber-11"),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
),
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -173,19 +173,19 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
consumables,
|
consumables,
|
||||||
camouflage,
|
camouflage,
|
||||||
},
|
},
|
||||||
index
|
index,
|
||||||
) => {
|
) => {
|
||||||
const equipmentPreset =
|
const equipmentPreset =
|
||||||
equipmentDefinitions.presets[tank.equipment_preset];
|
equipmentDefinitions.presets[tank.equipment_preset];
|
||||||
const provisionsList = availableProvisions(
|
const provisionsList = availableProvisions(
|
||||||
tank,
|
tank,
|
||||||
gun,
|
gun,
|
||||||
provisionDefinitions
|
provisionDefinitions,
|
||||||
);
|
);
|
||||||
const consumablesList = Object.values(
|
const consumablesList = Object.values(
|
||||||
consumableDefinitions.consumables
|
consumableDefinitions.consumables,
|
||||||
).filter((consumable) =>
|
).filter((consumable) =>
|
||||||
checkConsumableProvisionInclusivity(consumable, tank, gun)
|
checkConsumableProvisionInclusivity(consumable, tank, gun),
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -294,11 +294,11 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
<img
|
<img
|
||||||
alt={unwrap(
|
alt={unwrap(
|
||||||
provisionDefinitions.provisions[provision]
|
provisionDefinitions.provisions[provision]
|
||||||
.name
|
.name,
|
||||||
)}
|
)}
|
||||||
key={provision}
|
key={provision}
|
||||||
src={asset(
|
src={asset(
|
||||||
`/icons/provisions/${provision}.webp`
|
`/icons/provisions/${provision}.webp`,
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
left: "50%",
|
left: "50%",
|
||||||
@@ -335,7 +335,7 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
<Popover.Content>
|
<Popover.Content>
|
||||||
<ProvisionsManager
|
<ProvisionsManager
|
||||||
provisions={provisionsList.map(
|
provisions={provisionsList.map(
|
||||||
(provision) => provision.id
|
(provision) => provision.id,
|
||||||
)}
|
)}
|
||||||
selected={provisions}
|
selected={provisions}
|
||||||
disabled={tank.max_provisions === provisions.length}
|
disabled={tank.max_provisions === provisions.length}
|
||||||
@@ -452,7 +452,7 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
CompareEphemeral.mutate((draft) => {
|
CompareEphemeral.mutate((draft) => {
|
||||||
draft.members[index].equipmentMatrix = times(
|
draft.members[index].equipmentMatrix = times(
|
||||||
3,
|
3,
|
||||||
() => times(3, () => 0)
|
() => times(3, () => 0),
|
||||||
) as EquipmentMatrix;
|
) as EquipmentMatrix;
|
||||||
draft.sorting = undefined;
|
draft.sorting = undefined;
|
||||||
});
|
});
|
||||||
@@ -501,11 +501,11 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
alt={unwrap(
|
alt={unwrap(
|
||||||
consumableDefinitions.consumables[
|
consumableDefinitions.consumables[
|
||||||
consumable
|
consumable
|
||||||
].name
|
].name,
|
||||||
)}
|
)}
|
||||||
key={consumable}
|
key={consumable}
|
||||||
src={asset(
|
src={asset(
|
||||||
`/icons/consumables/${consumable}.webp`
|
`/icons/consumables/${consumable}.webp`,
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
left: "50%",
|
left: "50%",
|
||||||
@@ -610,7 +610,7 @@ export function CompareTable({ stats }: CompareTableProps) {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function TankCard({ index, tank }: TankCardProps) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
const closest = distances.reduce((a, b) =>
|
const closest = distances.reduce((a, b) =>
|
||||||
a.distance < b.distance ? a : b
|
a.distance < b.distance ? a : b,
|
||||||
);
|
);
|
||||||
|
|
||||||
dropIndex = closest.index;
|
dropIndex = closest.index;
|
||||||
@@ -85,8 +85,8 @@ export function TankCard({ index, tank }: TankCardProps) {
|
|||||||
CompareEphemeral.mutate((draft) => {
|
CompareEphemeral.mutate((draft) => {
|
||||||
const fromIndex = index;
|
const fromIndex = index;
|
||||||
const toIndex = dropIndex > index ? dropIndex - 1 : dropIndex;
|
const toIndex = dropIndex > index ? dropIndex - 1 : dropIndex;
|
||||||
|
|
||||||
const member = draft.members[fromIndex];
|
const member = draft.members[fromIndex];
|
||||||
|
|
||||||
draft.members.splice(fromIndex, 1);
|
draft.members.splice(fromIndex, 1);
|
||||||
draft.members.splice(toIndex, 0, member);
|
draft.members.splice(toIndex, 0, member);
|
||||||
});
|
});
|
||||||
@@ -99,7 +99,7 @@ export function TankCard({ index, tank }: TankCardProps) {
|
|||||||
return () => {
|
return () => {
|
||||||
draggable.current?.removeEventListener("pointerdown", handlePointerDown);
|
draggable.current?.removeEventListener("pointerdown", handlePointerDown);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [index]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StickyColumnHeaderCell width="0">
|
<StickyColumnHeaderCell width="0">
|
||||||
@@ -141,7 +141,6 @@ export function TankCard({ index, tank }: TankCardProps) {
|
|||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<InsertionMarker index={index + 1} />
|
<InsertionMarker index={index + 1} />
|
||||||
</StickyColumnHeaderCell>
|
</StickyColumnHeaderCell>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function Model() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleModelTransform(
|
function handleModelTransform(
|
||||||
event: QuicklimeEvent<ModelTransformEventData>
|
event: QuicklimeEvent<ModelTransformEventData>,
|
||||||
) {
|
) {
|
||||||
turretGroup.current.rotation.z = event.data.yaw;
|
turretGroup.current.rotation.z = event.data.yaw;
|
||||||
gunGroup.current.rotation.x = event.data.pitch;
|
gunGroup.current.rotation.x = event.data.pitch;
|
||||||
@@ -171,6 +171,49 @@ export function Model() {
|
|||||||
turretModel.gun_origin.y,
|
turretModel.gun_origin.y,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
<group
|
||||||
|
position={[
|
||||||
|
-turretTankModel.turret_origin.x -
|
||||||
|
turretTrackModel.origin.x -
|
||||||
|
turretModel.gun_origin.x,
|
||||||
|
-turretTankModel.turret_origin.z -
|
||||||
|
turretTrackModel.origin.z -
|
||||||
|
turretModel.gun_origin.z,
|
||||||
|
-turretTankModel.turret_origin.y -
|
||||||
|
turretTrackModel.origin.y -
|
||||||
|
turretModel.gun_origin.y,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{turretNodes.map((node) => {
|
||||||
|
const isCurrentMantlet =
|
||||||
|
node.name ===
|
||||||
|
`gun_${turretModel.guns[turret.turret.guns.at(-1)!.id].model_id.toString().padStart(2, "0")}_mask`;
|
||||||
|
// const isCurrentGun =
|
||||||
|
// node.name ===
|
||||||
|
// `gun_${gunModel.model_id.toString().padStart(2, "0")}`;
|
||||||
|
const isVisible = isCurrentMantlet;
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return jsxTree(node, {
|
||||||
|
mesh(_, props, key) {
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
{...props}
|
||||||
|
key={key}
|
||||||
|
castShadow
|
||||||
|
receiveShadow
|
||||||
|
onPointerDown={(event) => {
|
||||||
|
enablePitchRotation.current = true;
|
||||||
|
handlePointerDown(event);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})}
|
||||||
|
</group>
|
||||||
|
|
||||||
<group
|
<group
|
||||||
position={[
|
position={[
|
||||||
-gunTankModel.turret_origin.x -
|
-gunTankModel.turret_origin.x -
|
||||||
@@ -185,13 +228,13 @@ export function Model() {
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{gunNodes.map((node) => {
|
{gunNodes.map((node) => {
|
||||||
const isCurrentMantlet =
|
// const isCurrentMantlet =
|
||||||
node.name ===
|
// node.name ===
|
||||||
`gun_${gunModel.model_id.toString().padStart(2, "0")}_mask`;
|
// `gun_${gunModel.model_id.toString().padStart(2, "0")}_mask`;
|
||||||
const isCurrentGun =
|
const isCurrentGun =
|
||||||
node.name ===
|
node.name ===
|
||||||
`gun_${gunModel.model_id.toString().padStart(2, "0")}`;
|
`gun_${gunModel.model_id.toString().padStart(2, "0")}`;
|
||||||
const isVisible = isCurrentGun || isCurrentMantlet;
|
const isVisible = isCurrentGun;
|
||||||
|
|
||||||
if (!isVisible) return null;
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { Table } from "@radix-ui/themes";
|
import { Table } from "@radix-ui/themes";
|
||||||
import type { RowHeaderCellProps } from "@radix-ui/themes/src/components/table.js";
|
import type { RowHeaderCellProps } from "@radix-ui/themes/src/components/table.js";
|
||||||
|
|
||||||
export function StickyRowHeaderCell({ style, ...props }: RowHeaderCellProps) {
|
interface Props extends RowHeaderCellProps {
|
||||||
|
left?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StickyRowHeaderCell({ style, left = 0, ...props }: Props) {
|
||||||
return (
|
return (
|
||||||
<Table.RowHeaderCell
|
<Table.RowHeaderCell
|
||||||
style={{
|
style={{
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
left: 0,
|
left,
|
||||||
backgroundColor: "var(--color-panel)",
|
backgroundColor: "var(--color-panel)",
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { youtubers } from '@blitzkit/core';
|
import { youtubers } from "@blitzkit/core";
|
||||||
import { Box, Flex, Heading, Link, Skeleton, Text } from '@radix-ui/themes';
|
import { Box, Flex, Heading, Link, Skeleton, Text } from "@radix-ui/themes";
|
||||||
import { awaitableReviews } from '../../core/awaitables/reviews';
|
import { awaitableReviews } from "../../core/awaitables/reviews";
|
||||||
import { Var } from '../../core/radix/var';
|
import { Var } from "../../core/radix/var";
|
||||||
import { useLocale } from '../../hooks/useLocale';
|
import { useLocale } from "../../hooks/useLocale";
|
||||||
import { Duel } from '../../stores/duel';
|
import { Duel } from "../../stores/duel";
|
||||||
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
|
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||||
import { PageWrapper } from '../PageWrapper';
|
import { PageWrapper } from "../PageWrapper";
|
||||||
import { VerifiedIcon } from '../VerifiedIcon';
|
import { VerifiedIcon } from "../VerifiedIcon";
|
||||||
|
|
||||||
const reviews = await awaitableReviews;
|
const reviews = await awaitableReviews;
|
||||||
|
|
||||||
@@ -47,22 +47,22 @@ export function VideoSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 'var(--radius-3)',
|
borderRadius: "var(--radius-3)",
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
background: skeleton
|
background: skeleton
|
||||||
? Var('color-panel-solid')
|
? Var("color-panel-solid")
|
||||||
: `url(${image})`,
|
: `url(${image})`,
|
||||||
backgroundPosition: '0 18px',
|
backgroundPosition: "0 18px",
|
||||||
backgroundSize: 'cover',
|
backgroundSize: "cover",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
background: skeleton ? 'transparent' : `url(${image})`,
|
background: skeleton ? "transparent" : `url(${image})`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: "cover",
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: "center",
|
||||||
height: 128,
|
height: 128,
|
||||||
aspectRatio: '16 / 9',
|
aspectRatio: "16 / 9",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
@@ -70,8 +70,8 @@ export function VideoSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
width="100%"
|
width="100%"
|
||||||
justify="center"
|
justify="center"
|
||||||
style={{
|
style={{
|
||||||
backdropFilter: 'blur(4rem)',
|
backdropFilter: "blur(4rem)",
|
||||||
WebkitBackdropFilter: 'blur(4rem)',
|
WebkitBackdropFilter: "blur(4rem)",
|
||||||
}}
|
}}
|
||||||
align="center"
|
align="center"
|
||||||
gap="1"
|
gap="1"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const tanks = Object.values(tankDefinitions.tanks).filter((tank) => {
|
|||||||
const turret = tank.turrets.at(-1)!;
|
const turret = tank.turrets.at(-1)!;
|
||||||
const turretModel = tankModel.turrets[turret.id];
|
const turretModel = tankModel.turrets[turret.id];
|
||||||
|
|
||||||
return tank.tier >= 10 && !turretModel.yaw;
|
return !turretModel.yaw;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function curateMixer() {
|
export function curateMixer() {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export function tankCharacteristics(
|
|||||||
tankModelDefinition: ModelDefinition;
|
tankModelDefinition: ModelDefinition;
|
||||||
equipmentDefinitions: EquipmentDefinitions;
|
equipmentDefinitions: EquipmentDefinitions;
|
||||||
provisionDefinitions: ProvisionDefinitions;
|
provisionDefinitions: ProvisionDefinitions;
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
const preset = equipmentDefinitions.presets[tank.equipment_preset];
|
const preset = equipmentDefinitions.presets[tank.equipment_preset];
|
||||||
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||||
@@ -138,7 +138,7 @@ export function tankCharacteristics(
|
|||||||
provisionDefinitions.provisions[provision].crew
|
provisionDefinitions.provisions[provision].crew
|
||||||
? total + provisionDefinitions.provisions[provision].crew! / 100
|
? total + provisionDefinitions.provisions[provision].crew! / 100
|
||||||
: total,
|
: total,
|
||||||
0
|
0,
|
||||||
) + (hasImprovedVentilation ? 0.08 : 0);
|
) + (hasImprovedVentilation ? 0.08 : 0);
|
||||||
const commanderMastery = 1 + provisionCrewBonus;
|
const commanderMastery = 1 + provisionCrewBonus;
|
||||||
const loaderMastery =
|
const loaderMastery =
|
||||||
@@ -158,13 +158,13 @@ export function tankCharacteristics(
|
|||||||
coefficient(
|
coefficient(
|
||||||
[applyReactiveArmor && shell.type !== ShellType.HE, -0.27],
|
[applyReactiveArmor && shell.type !== ShellType.HE, -0.27],
|
||||||
[applyDynamicArmor, -0.1],
|
[applyDynamicArmor, -0.1],
|
||||||
[applySpallLiner && shell.type === ShellType.HE, -0.2]
|
[applySpallLiner && shell.type === ShellType.HE, -0.2],
|
||||||
);
|
);
|
||||||
const assaultDamageCoefficient =
|
const assaultDamageCoefficient =
|
||||||
gun.assault_ranges && gun.assault_ranges.types.includes(shell.type)
|
gun.assault_ranges && gun.assault_ranges.types.includes(shell.type)
|
||||||
? gun.assault_ranges.ranges.find(
|
? (gun.assault_ranges.ranges.find(
|
||||||
({ distance }) => distance >= assaultDistance
|
({ distance }) => distance >= assaultDistance,
|
||||||
)?.factor ?? 0
|
)?.factor ?? 0)
|
||||||
: 1;
|
: 1;
|
||||||
const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]);
|
const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]);
|
||||||
const reloadCoefficient =
|
const reloadCoefficient =
|
||||||
@@ -178,16 +178,16 @@ export function tankCharacteristics(
|
|||||||
const healthCoefficient = coefficient(
|
const healthCoefficient = coefficient(
|
||||||
[hasSandbagArmor, 0.03],
|
[hasSandbagArmor, 0.03],
|
||||||
[hasEnhancedSandbagArmor, 0.06],
|
[hasEnhancedSandbagArmor, 0.06],
|
||||||
[hasImprovedAssembly, 0.04]
|
[hasImprovedAssembly, 0.04],
|
||||||
);
|
);
|
||||||
const shellVelocityCoefficient = coefficient(
|
const shellVelocityCoefficient = coefficient(
|
||||||
[hasSupercharger, 0.35],
|
[hasSupercharger, 0.35],
|
||||||
[hasImprovedGunPowder, 0.3]
|
[hasImprovedGunPowder, 0.3],
|
||||||
);
|
);
|
||||||
const aimTimeCoefficient =
|
const aimTimeCoefficient =
|
||||||
coefficient(
|
coefficient(
|
||||||
[hasEnhancedGunLayingDrive, -0.15],
|
[hasEnhancedGunLayingDrive, -0.15],
|
||||||
[hasReticleCalibration, -0.3]
|
[hasReticleCalibration, -0.3],
|
||||||
) * coefficient([true, degressiveStat(gunnerMastery)]);
|
) * coefficient([true, degressiveStat(gunnerMastery)]);
|
||||||
const dispersionStillCoefficient =
|
const dispersionStillCoefficient =
|
||||||
coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) *
|
coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) *
|
||||||
@@ -197,20 +197,20 @@ export function tankCharacteristics(
|
|||||||
-0.12,
|
-0.12,
|
||||||
]);
|
]);
|
||||||
const dispersionHullTraverseCoefficient = coefficient(
|
const dispersionHullTraverseCoefficient = coefficient(
|
||||||
[hasVerticalStabilizer, -0.15],
|
[hasVerticalStabilizer, -0.12],
|
||||||
[true, -crewSkills.smooth_turn / 100]
|
[true, -crewSkills.smooth_turn / 100],
|
||||||
);
|
);
|
||||||
const dispersionAfterShotCoefficient = coefficient(
|
const dispersionAfterShotCoefficient = coefficient(
|
||||||
[hasVerticalStabilizer, -0.15],
|
[hasVerticalStabilizer, -0.12],
|
||||||
[true, -crewSkills.soft_recoil / 100]
|
[true, -crewSkills.soft_recoil / 100],
|
||||||
);
|
);
|
||||||
const dispersionMovingCoefficient = coefficient(
|
const dispersionMovingCoefficient = coefficient(
|
||||||
[hasVerticalStabilizer, -0.15],
|
[hasVerticalStabilizer, -0.12],
|
||||||
[true, -crewSkills.smooth_driving / 100]
|
[true, -crewSkills.smooth_driving / 100],
|
||||||
);
|
);
|
||||||
const dispersionTurretTraverseCoefficient = coefficient(
|
const dispersionTurretTraverseCoefficient = coefficient(
|
||||||
[hasVerticalStabilizer, -0.15],
|
[hasVerticalStabilizer, -0.12],
|
||||||
[true, -crewSkills.smooth_turret * (2 / 100)]
|
[true, -crewSkills.smooth_turret * (2 / 100)],
|
||||||
);
|
);
|
||||||
const enginePowerCoefficient = coefficient(
|
const enginePowerCoefficient = coefficient(
|
||||||
[
|
[
|
||||||
@@ -225,7 +225,7 @@ export function tankCharacteristics(
|
|||||||
[hasStandardFuel, 0.03],
|
[hasStandardFuel, 0.03],
|
||||||
[hasImprovedFuel, 0.1],
|
[hasImprovedFuel, 0.1],
|
||||||
[hasGearOil, 0.03],
|
[hasGearOil, 0.03],
|
||||||
[hasImprovedGearOil, 0.06]
|
[hasImprovedGearOil, 0.06],
|
||||||
);
|
);
|
||||||
const turretTraverseCoefficient =
|
const turretTraverseCoefficient =
|
||||||
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
||||||
@@ -234,7 +234,7 @@ export function tankCharacteristics(
|
|||||||
coefficient(
|
coefficient(
|
||||||
[hasImprovedControl, 0.11],
|
[hasImprovedControl, 0.11],
|
||||||
[hasImprovedEnginePowerBoost, 0.01],
|
[hasImprovedEnginePowerBoost, 0.01],
|
||||||
[true, crewSkills.virtuoso / 100]
|
[true, crewSkills.virtuoso / 100],
|
||||||
) * coefficient([true, progressiveStat(driverMastery)]);
|
) * coefficient([true, progressiveStat(driverMastery)]);
|
||||||
|
|
||||||
const resistanceHardCoefficient =
|
const resistanceHardCoefficient =
|
||||||
@@ -253,22 +253,22 @@ export function tankCharacteristics(
|
|||||||
tank.class === TankClass.HEAVY
|
tank.class === TankClass.HEAVY
|
||||||
? 0.06
|
? 0.06
|
||||||
: tank.class === TankClass.MEDIUM
|
: tank.class === TankClass.MEDIUM
|
||||||
? 0.08
|
? 0.08
|
||||||
: tank.class === TankClass.LIGHT
|
: tank.class === TankClass.LIGHT
|
||||||
? 0.11
|
? 0.11
|
||||||
: 0.04,
|
: 0.04,
|
||||||
]) * coefficient([true, progressiveStat(commanderMastery)]);
|
]) * coefficient([true, progressiveStat(commanderMastery)]);
|
||||||
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
||||||
|
|
||||||
const speedForwardsSum = sum(
|
const speedForwardsSum = sum(
|
||||||
[hasImprovedEnginePowerBoost, 4],
|
[hasImprovedEnginePowerBoost, 4],
|
||||||
[hasGearOil, 2],
|
[hasGearOil, 2],
|
||||||
[hasImprovedGearOil, 4]
|
[hasImprovedGearOil, 4],
|
||||||
);
|
);
|
||||||
const speedBackwardsSum = sum(
|
const speedBackwardsSum = sum(
|
||||||
[hasImprovedEnginePowerBoost, 8],
|
[hasImprovedEnginePowerBoost, 8],
|
||||||
[hasGearOil, 2],
|
[hasGearOil, 2],
|
||||||
[hasImprovedGearOil, 4]
|
[hasImprovedGearOil, 4],
|
||||||
);
|
);
|
||||||
const camouflageCoefficientMoving = sum(
|
const camouflageCoefficientMoving = sum(
|
||||||
[
|
[
|
||||||
@@ -278,8 +278,8 @@ export function tankCharacteristics(
|
|||||||
tank.class === TankClass.TANK_DESTROYER
|
tank.class === TankClass.TANK_DESTROYER
|
||||||
? 0.04
|
? 0.04
|
||||||
: tank.class === TankClass.HEAVY
|
: tank.class === TankClass.HEAVY
|
||||||
? 0.03
|
? 0.03
|
||||||
: 0.02,
|
: 0.02,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -287,11 +287,11 @@ export function tankCharacteristics(
|
|||||||
tank.class === TankClass.HEAVY
|
tank.class === TankClass.HEAVY
|
||||||
? 0.02
|
? 0.02
|
||||||
: tank.class === TankClass.MEDIUM
|
: tank.class === TankClass.MEDIUM
|
||||||
? 0.04
|
? 0.04
|
||||||
: tank.class === TankClass.LIGHT
|
: tank.class === TankClass.LIGHT
|
||||||
? 0.07
|
? 0.07
|
||||||
: 0.1,
|
: 0.1,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
const camouflageCoefficientStill = sum(
|
const camouflageCoefficientStill = sum(
|
||||||
[
|
[
|
||||||
@@ -302,10 +302,10 @@ export function tankCharacteristics(
|
|||||||
tank.class === TankClass.TANK_DESTROYER
|
tank.class === TankClass.TANK_DESTROYER
|
||||||
? 0.04
|
? 0.04
|
||||||
: tank.class === TankClass.HEAVY
|
: tank.class === TankClass.HEAVY
|
||||||
? 0.03
|
? 0.03
|
||||||
: 0.02,
|
: 0.02,
|
||||||
],
|
],
|
||||||
[true, crewSkills.camouflage * (3 / 100)]
|
[true, crewSkills.camouflage * (3 / 100)],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -313,18 +313,18 @@ export function tankCharacteristics(
|
|||||||
tank.class === TankClass.HEAVY
|
tank.class === TankClass.HEAVY
|
||||||
? 0.04
|
? 0.04
|
||||||
: tank.class === TankClass.MEDIUM
|
: tank.class === TankClass.MEDIUM
|
||||||
? 0.08
|
? 0.08
|
||||||
: tank.class === TankClass.LIGHT
|
: tank.class === TankClass.LIGHT
|
||||||
? 0.14
|
? 0.14
|
||||||
: 0.2,
|
: 0.2,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const size = normalizeBoundingBox(
|
const size = normalizeBoundingBox(
|
||||||
unionBoundingBox(
|
unionBoundingBox(
|
||||||
tankModelDefinition.bounding_box,
|
tankModelDefinition.bounding_box,
|
||||||
turretModelDefinition.bounding_box
|
turretModelDefinition.bounding_box,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
const weightKg =
|
const weightKg =
|
||||||
tank.weight + engine.weight + track.weight + turret.weight + gun.weight;
|
tank.weight + engine.weight + track.weight + turret.weight + gun.weight;
|
||||||
@@ -344,7 +344,7 @@ export function tankCharacteristics(
|
|||||||
shell,
|
shell,
|
||||||
damageCoefficient,
|
damageCoefficient,
|
||||||
reloadCoefficient,
|
reloadCoefficient,
|
||||||
intraClipCoefficient
|
intraClipCoefficient,
|
||||||
);
|
);
|
||||||
const intraClip =
|
const intraClip =
|
||||||
gun.gun_type?.$case === "regular"
|
gun.gun_type?.$case === "regular"
|
||||||
@@ -398,7 +398,7 @@ export function tankCharacteristics(
|
|||||||
const shellReloads =
|
const shellReloads =
|
||||||
gun.gun_type!.$case === "auto_reloader"
|
gun.gun_type!.$case === "auto_reloader"
|
||||||
? gun.gun_type!.value.shell_reloads.map(
|
? gun.gun_type!.value.shell_reloads.map(
|
||||||
(reload) => reload * reloadCoefficient
|
(reload) => reload * reloadCoefficient,
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
const shellReload =
|
const shellReload =
|
||||||
|
|||||||
Reference in new issue
Block a user