Merge pull request #223 from blitzkit/fixes

fixes
This commit is contained in:
TrèsAbhi authored and GitHub committed 2026-03-24 09:39:28 -05:00
commit c1fde44809
13 files changed
+179 -109

No files matched your search

+18
View File
@@ -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
View File
@@ -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"]);
+10 -5
View File
@@ -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 =