fix: some linting for new proto 6

This commit is contained in:
TrèsAbhi committed 2024-10-06 00:02:50 -05:00
1 parent 96310a9d63
commit 95bb67bcf1
29 files changed
+229 -295

No files matched your search

-1
View File
@@ -8,7 +8,6 @@ export const TANK_CLASSES = [
TankClass.MEDIUM, TankClass.MEDIUM,
TankClass.HEAVY, TankClass.HEAVY,
TankClass.TANK_DESTROYER, TankClass.TANK_DESTROYER,
TankClass.UNRECOGNIZED,
] as const; ] as const;
export const emptyAllStats: BlitzStats = { export const emptyAllStats: BlitzStats = {
@@ -3,5 +3,5 @@ import { CamouflageDefinitions } from '../protos';
import { asset } from './asset'; import { asset } from './asset';
export function fetchCamouflageDefinitions() { export function fetchCamouflageDefinitions() {
return fetchPB(asset('definitions/camoufles.pb'), CamouflageDefinitions); return fetchPB(asset('definitions/camouflages.pb'), CamouflageDefinitions);
} }
@@ -12,7 +12,6 @@ export const SHELL_NAMES: Record<ShellType, string> = {
[ShellType.APCR]: 'APCR', [ShellType.APCR]: 'APCR',
[ShellType.HEAT]: 'HEAT', [ShellType.HEAT]: 'HEAT',
[ShellType.HE]: 'HE', [ShellType.HE]: 'HE',
[ShellType.UNRECOGNIZED]: 'unrecognized',
}; };
export const CREW_MEMBER_NAMES: Record<CrewType, string> = { export const CREW_MEMBER_NAMES: Record<CrewType, string> = {
[CrewType.COMMANDER]: 'Commander', [CrewType.COMMANDER]: 'Commander',
@@ -20,7 +19,6 @@ export const CREW_MEMBER_NAMES: Record<CrewType, string> = {
[CrewType.GUNNER]: 'Gunner', [CrewType.GUNNER]: 'Gunner',
[CrewType.LOADER]: 'Loader', [CrewType.LOADER]: 'Loader',
[CrewType.RADIOMAN]: 'Radioman', [CrewType.RADIOMAN]: 'Radioman',
[CrewType.UNRECOGNIZED]: 'unrecognized',
}; };
export const GUN_TYPE_NAMES: Record< export const GUN_TYPE_NAMES: Record<
Exclude<GunDefinition['gunType'], undefined>['$case'], Exclude<GunDefinition['gunType'], undefined>['$case'],
@@ -38,7 +36,6 @@ export const TANK_ICONS: Record<TankClass, string> = {
[TankClass.LIGHT]: 'https://i.imgur.com/CSNha5V.png', [TankClass.LIGHT]: 'https://i.imgur.com/CSNha5V.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/wvf3ltm.png', [TankClass.MEDIUM]: 'https://i.imgur.com/wvf3ltm.png',
[TankClass.HEAVY]: 'https://i.imgur.com/ECeqlZa.png', [TankClass.HEAVY]: 'https://i.imgur.com/ECeqlZa.png',
[TankClass.UNRECOGNIZED]: 'https://i.imgur.com/6FBBzb9.png', // lmfao click on this
}; };
/** /**
* @deprecated use svg * @deprecated use svg
@@ -48,7 +45,6 @@ export const TANK_ICONS_PREMIUM: Record<TankClass, string> = {
[TankClass.LIGHT]: 'https://i.imgur.com/zdkpTRb.png', [TankClass.LIGHT]: 'https://i.imgur.com/zdkpTRb.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/3z7eHX6.png', [TankClass.MEDIUM]: 'https://i.imgur.com/3z7eHX6.png',
[TankClass.HEAVY]: 'https://i.imgur.com/P3vbmyA.png', [TankClass.HEAVY]: 'https://i.imgur.com/P3vbmyA.png',
[TankClass.UNRECOGNIZED]: 'https://i.imgur.com/6FBBzb9.png',
}; };
/** /**
* @deprecated use svg * @deprecated use svg
@@ -58,7 +54,6 @@ export const TANK_ICONS_COLLECTOR: Record<TankClass, string> = {
[TankClass.LIGHT]: 'https://i.imgur.com/EwhtKkU.png', [TankClass.LIGHT]: 'https://i.imgur.com/EwhtKkU.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/u8YDMBh.png', [TankClass.MEDIUM]: 'https://i.imgur.com/u8YDMBh.png',
[TankClass.HEAVY]: 'https://i.imgur.com/8xRf3nc.png', [TankClass.HEAVY]: 'https://i.imgur.com/8xRf3nc.png',
[TankClass.UNRECOGNIZED]: 'https://i.imgur.com/6FBBzb9.png',
}; };
export const TIERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as const; export const TIERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as const;
export const TIER_ROMAN_NUMERALS: Record<Tier, string> = { export const TIER_ROMAN_NUMERALS: Record<Tier, string> = {
@@ -72,7 +67,6 @@ export const TIER_ROMAN_NUMERALS: Record<Tier, string> = {
[Tier.VIII]: 'VIII', [Tier.VIII]: 'VIII',
[Tier.IX]: 'IX', [Tier.IX]: 'IX',
[Tier.X]: 'X', [Tier.X]: 'X',
[Tier.UNRECOGNIZED]: 'unrecognized',
}; };
export const flags: Record<string, string> = { export const flags: Record<string, string> = {
@@ -90,11 +84,4 @@ export const TREE_TYPE_ICONS: Record<TankType, Record<TankClass, string>> = {
[TankType.RESEARCHABLE]: TANK_ICONS, [TankType.RESEARCHABLE]: TANK_ICONS,
[TankType.PREMIUM]: TANK_ICONS_PREMIUM, [TankType.PREMIUM]: TANK_ICONS_PREMIUM,
[TankType.COLLECTOR]: TANK_ICONS_COLLECTOR, [TankType.COLLECTOR]: TANK_ICONS_COLLECTOR,
[TankType.UNRECOGNIZED]: {
'-1': 'https://i.imgur.com/6FBBzb9.png',
'0': 'https://i.imgur.com/6FBBzb9.png',
'1': 'https://i.imgur.com/6FBBzb9.png',
'2': 'https://i.imgur.com/6FBBzb9.png',
'3': 'https://i.imgur.com/6FBBzb9.png',
},
}; };
+4 -5
View File
@@ -10,17 +10,16 @@ export async function fetchTankNames() {
const tankDefinitionsArray = Object.values(tankDefinitions.tanks); const tankDefinitionsArray = Object.values(tankDefinitions.tanks);
return await Promise.all( return await Promise.all(
tankDefinitionsArray.map(async (tank, index) => { tankDefinitionsArray.map(async (tank) => {
const { id } = tankDefinitionsArray[index];
return { return {
id, id: tank.id,
name: tank.name, name: tank.name,
nameFull: tank.nameFull, nameFull: tank.nameFull,
searchableName: tank.nameFull ?? tank.name, searchableName: tank.nameFull ?? tank.name,
searchableNameDeburr: deburr(tank.nameFull ?? tank.name), searchableNameDeburr: deburr(tank.nameFull ?? tank.name),
camouflages: tank.camouflages camouflages: tank.camouflages
?.map((id) => camouflageDefinitions.camouflages[id].name) ?.map((id) => camouflageDefinitions.camouflages[id]?.name)
.filter(Boolean)
.join(' '), .join(' '),
treeType: tank.type, treeType: tank.type,
}; };
@@ -147,9 +147,6 @@ const blitzkitCrewTypeToBlitz: Record<CrewType, BlitzCrewType> = {
[CrewType.GUNNER]: 'gunner', [CrewType.GUNNER]: 'gunner',
[CrewType.LOADER]: 'loader', [CrewType.LOADER]: 'loader',
[CrewType.RADIOMAN]: 'radioman', [CrewType.RADIOMAN]: 'radioman',
// this should never happen... i hope 😢
[CrewType.UNRECOGNIZED]: 'radioman',
}; };
interface VehicleDefinitions { interface VehicleDefinitions {
invisibility: { invisibility: {
+1
View File
@@ -30,6 +30,7 @@ const args = [
'--ts_proto_opt=esModuleInterop=true', '--ts_proto_opt=esModuleInterop=true',
'--ts_proto_opt=oneof=unions-value', '--ts_proto_opt=oneof=unions-value',
'--ts_proto_opt=removeEnumPrefix=true', '--ts_proto_opt=removeEnumPrefix=true',
'--ts_proto_opt=unrecognizedEnum=false',
'--ts_proto_out=.', '--ts_proto_out=.',
...files.map((file) => `${ROOT}/${file}`), ...files.map((file) => `${ROOT}/${file}`),
]; ];
@@ -3,7 +3,6 @@ import { PlusIcon } from '@radix-ui/react-icons';
import { Box, Flex, Heading, IconButton, Text } from '@radix-ui/themes'; import { Box, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { use, useCallback, useEffect, useMemo, useState } from 'react'; import { use, useCallback, useEffect, useMemo, useState } from 'react';
import * as CompareEphemeral from '../../../stores/compareEphemeral';
export default function Page() { export default function Page() {
const pathname = usePathname(); const pathname = usePathname();
@@ -1,18 +1,18 @@
import { import {
averageDefinitions, fetchAverageDefinitions,
discoveredIdsDefinitions, fetchDiscoveredIdsDefinitions,
formatCompact, formatCompact,
} from '@blitzkit/core'; } from '@blitzkit/core';
import { InfoCircledIcon } from '@radix-ui/react-icons'; import { InfoCircledIcon } from '@radix-ui/react-icons';
import { Callout, Flex } from '@radix-ui/themes'; import { Callout, Flex } from '@radix-ui/themes';
import { use } from 'react';
const discoveredIdsDefinitions = await fetchDiscoveredIdsDefinitions();
const averageDefinitions = await fetchAverageDefinitions();
export function Info() { export function Info() {
const awaitedDiscoveredIdsDefinitions = use(discoveredIdsDefinitions); const samples = discoveredIdsDefinitions.count;
const awaitedAverageDefinitions = use(averageDefinitions);
const samples = awaitedDiscoveredIdsDefinitions.count;
const minutesAgo = Math.floor( const minutesAgo = Math.floor(
(Date.now() - awaitedAverageDefinitions.time) / (1000 * 60), (Date.now() - averageDefinitions.time) / (1000 * 60),
); );
const hoursAgo = Math.floor(minutesAgo / 60); const hoursAgo = Math.floor(minutesAgo / 60);
@@ -2,10 +2,10 @@ import {
asset, asset,
coefficient, coefficient,
CREW_MEMBER_NAMES, CREW_MEMBER_NAMES,
equipmentDefinitions, fetchEquipmentDefinitions,
fetchProvisionDefinitions,
GUN_TYPE_NAMES, GUN_TYPE_NAMES,
isExplosive, isExplosive,
provisionDefinitions,
resolvePenetrationCoefficient, resolvePenetrationCoefficient,
} from '@blitzkit/core'; } from '@blitzkit/core';
import { AccessibilityIcon, InfoCircledIcon } from '@radix-ui/react-icons'; import { AccessibilityIcon, InfoCircledIcon } from '@radix-ui/react-icons';
@@ -24,15 +24,15 @@ import { Fragment, useEffect, useRef, useState } from 'react';
import { Ad, AdType } from '../../../../../../../../website/src/components/Ad'; import { Ad, AdType } from '../../../../../../../../website/src/components/Ad';
import { InfoWithDelta } from '../../../../../../../../website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta'; import { InfoWithDelta } from '../../../../../../../../website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta';
import { applyPitchYawLimits } from '../../../../../../../../website/src/core/blitz/applyPitchYawLimits'; import { applyPitchYawLimits } from '../../../../../../../../website/src/core/blitz/applyPitchYawLimits';
import { tankCharacteristics } from '../../../../../../../../website/src/core/blitzkit/tankCharacteristics';
import { useAdExempt } from '../../../../../../../../website/src/hooks/useAdExempt'; import { useAdExempt } from '../../../../../../../../website/src/hooks/useAdExempt';
import { useEquipment } from '../../../../../../../../website/src/hooks/useEquipment'; import { useEquipment } from '../../../../../../../../website/src/hooks/useEquipment';
import { useTankModelDefinition } from '../../../../../../../../website/src/hooks/useTankModelDefinition'; import { useTankModelDefinition } from '../../../../../../../../website/src/hooks/useTankModelDefinition';
import { Duel } from '../../../../../../../../website/src/stores/duel'; import { Duel } from '../../../../../../../../website/src/stores/duel';
import { TankopediaEphemeral } from '../../../../../../../../website/src/stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../../../../website/src/stores/tankopediaEphemeral';
import { Info } from '../../../../performance/components/Info';
const awaitedEquipmentDefinitions = await equipmentDefinitions; const equipmentDefinitions = await fetchEquipmentDefinitions();
const awaitedProvisionDefinitions = await provisionDefinitions; const provisionDefinitions = await fetchProvisionDefinitions();
export function Characteristics() { export function Characteristics() {
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
@@ -50,8 +50,8 @@ export function Characteristics() {
const provisionCrewBonus = const provisionCrewBonus =
provisions.reduce( provisions.reduce(
(total, provision) => (total, provision) =>
awaitedProvisionDefinitions[provision].crew provisionDefinitions.provisions[provision].crew
? total + awaitedProvisionDefinitions[provision].crew! / 100 ? total + provisionDefinitions.provisions[provision].crew! / 100
: total, : total,
0, 0,
) + (hasImprovedVentilation ? 0.08 : 0); ) + (hasImprovedVentilation ? 0.08 : 0);
@@ -70,7 +70,8 @@ export function Characteristics() {
const stockGun = stockTurret.guns[0]; const stockGun = stockTurret.guns[0];
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const turretModelDefinition = tankModelDefinition.turrets[turret.id];
const gunModelDefinition = turretModelDefinition.guns[gun.id]; const gunModelDefinition =
turretModelDefinition.guns[gun.gunType!.value.base.id];
const stats = tankCharacteristics( const stats = tankCharacteristics(
{ {
tank, tank,
@@ -95,8 +96,8 @@ export function Characteristics() {
}, },
{ {
tankModelDefinition, tankModelDefinition,
equipmentDefinitions: awaitedEquipmentDefinitions, equipmentDefinitions: equipmentDefinitions,
provisionDefinitions: awaitedProvisionDefinitions, provisionDefinitions: provisionDefinitions,
}, },
); );
@@ -143,7 +144,7 @@ export function Characteristics() {
<Heading size="5">Firepower</Heading> <Heading size="5">Firepower</Heading>
<Flex> <Flex>
{gun.shells.map((thisShell, shellIndex) => ( {gun.gunType!.value.base.shells.map((thisShell, shellIndex) => (
<Tooltip content={thisShell.name} key={thisShell.id}> <Tooltip content={thisShell.name} key={thisShell.id}>
<IconButton <IconButton
color={thisShell.id === shell.id ? undefined : 'gray'} color={thisShell.id === shell.id ? undefined : 'gray'}
@@ -152,9 +153,13 @@ export function Characteristics() {
borderTopLeftRadius: shellIndex === 0 ? undefined : 0, borderTopLeftRadius: shellIndex === 0 ? undefined : 0,
borderBottomLeftRadius: shellIndex === 0 ? undefined : 0, borderBottomLeftRadius: shellIndex === 0 ? undefined : 0,
borderTopRightRadius: borderTopRightRadius:
shellIndex === gun.shells.length - 1 ? undefined : 0, shellIndex === gun.gunType!.value.base.shells.length - 1
? undefined
: 0,
borderBottomRightRadius: borderBottomRightRadius:
shellIndex === gun.shells.length - 1 ? undefined : 0, shellIndex === gun.gunType!.value.base.shells.length - 1
? undefined
: 0,
marginLeft: shellIndex === 0 ? 0 : -1, marginLeft: shellIndex === 0 ? 0 : -1,
}} }}
onClick={() => { onClick={() => {
@@ -174,7 +179,7 @@ export function Characteristics() {
))} ))}
</Flex> </Flex>
</Flex> </Flex>
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info> <Info name="Gun type">{GUN_TYPE_NAMES[gun.gunType!.$case]}</Info>
<InfoWithDelta name="DPM" decimals={0} unit="hp / min"> <InfoWithDelta name="DPM" decimals={0} unit="hp / min">
{stats.dpm} {stats.dpm}
</InfoWithDelta> </InfoWithDelta>
@@ -24,7 +24,8 @@ export const PrimaryArmorScene = memo(() => {
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const trackModelDefinition = tankModelDefinition.tracks[track.id]; const trackModelDefinition = tankModelDefinition.tracks[track.id];
const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const turretModelDefinition = tankModelDefinition.turrets[turret.id];
const gunModelDefinition = turretModelDefinition.guns[gun.id]; const gunModelDefinition =
turretModelDefinition.guns[gun.gunType!.value.base.id];
const hullOrigin = correctZYTuple(trackModelDefinition.origin); const hullOrigin = correctZYTuple(trackModelDefinition.origin);
const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin);
const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin);
@@ -68,7 +69,7 @@ export const PrimaryArmorScene = memo(() => {
<group ref={turretContainer}> <group ref={turretContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentTurret = node.name.startsWith( const isCurrentTurret = node.name.startsWith(
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, `turret_${turretModelDefinition.modelId.toString().padStart(2, '0')}`,
); );
const isVisible = isCurrentTurret; const isVisible = isCurrentTurret;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
@@ -102,7 +103,7 @@ export const PrimaryArmorScene = memo(() => {
<group ref={gunContainer}> <group ref={gunContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentGun = node.name.startsWith( const isCurrentGun = node.name.startsWith(
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, `gun_${gunModelDefinition.modelId.toString().padStart(2, '0')}`,
); );
const isVisible = isCurrentGun; const isVisible = isCurrentGun;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
@@ -2,7 +2,6 @@ import {
type ShellDefinition, type ShellDefinition,
canSplash, canSplash,
isExplosive, isExplosive,
resolveNearPenetration,
resolvePenetrationCoefficient, resolvePenetrationCoefficient,
} from '@blitzkit/core'; } from '@blitzkit/core';
import { useFrame } from '@react-three/fiber'; import { useFrame } from '@react-three/fiber';
@@ -69,7 +68,7 @@ export function PrimaryArmorSceneComponent({
); );
material.uniforms.isExplosive.value = isExplosive(shell.type); material.uniforms.isExplosive.value = isExplosive(shell.type);
material.uniforms.canSplash.value = canSplash(shell.type); material.uniforms.canSplash.value = canSplash(shell.type);
material.uniforms.damage.value = shell.damage.armor; material.uniforms.damage.value = shell.armorDamage;
material.uniforms.explosionRadius.value = shell.explosionRadius; material.uniforms.explosionRadius.value = shell.explosionRadius;
const duel = duelStore.getState(); const duel = duelStore.getState();
@@ -91,7 +90,7 @@ export function PrimaryArmorSceneComponent({
const duel = duelStore.getState(); const duel = duelStore.getState();
const hasEnhancedArmor = await hasEquipment( const hasEnhancedArmor = await hasEquipment(
110, 110,
duel.protagonist.tank.equipment, duel.protagonist.tank.equipmentPreset,
equipment, equipment,
); );
material.uniforms.thickness.value = hasEnhancedArmor material.uniforms.thickness.value = hasEnhancedArmor
@@ -101,10 +100,10 @@ export function PrimaryArmorSceneComponent({
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
const duel = duelStore.getState(); const duel = duelStore.getState();
const shell = duel.antagonist.shell; const shell = duel.antagonist.shell;
const penetration = resolveNearPenetration(shell.penetration); const penetration = shell.penetration.near;
const hasCalibratedShells = await hasEquipment( const hasCalibratedShells = await hasEquipment(
103, 103,
duel.antagonist.tank.equipment, duel.antagonist.tank.equipmentPreset,
equipment, equipment,
); );
@@ -37,7 +37,8 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const trackModelDefinition = tankModelDefinition.tracks[track.id]; const trackModelDefinition = tankModelDefinition.tracks[track.id];
const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const turretModelDefinition = tankModelDefinition.turrets[turret.id];
const gunModelDefinition = turretModelDefinition.guns[gun.id]; const gunModelDefinition =
turretModelDefinition.guns[gun.gunType!.value.base.id];
const hullOrigin = correctZYTuple(trackModelDefinition.origin); const hullOrigin = correctZYTuple(trackModelDefinition.origin);
const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin);
const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin);
@@ -105,7 +106,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
<group ref={turretContainer}> <group ref={turretContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentTurret = node.name.startsWith( const isCurrentTurret = node.name.startsWith(
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, `turret_${turretModelDefinition.modelId.toString().padStart(2, '0')}`,
); );
const isVisible = isCurrentTurret; const isVisible = isCurrentTurret;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
@@ -140,7 +141,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
<group ref={gunContainer}> <group ref={gunContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentGun = node.name.startsWith( const isCurrentGun = node.name.startsWith(
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, `gun_${gunModelDefinition.modelId.toString().padStart(2, '0')}`,
); );
const isVisible = isCurrentGun; const isVisible = isCurrentGun;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
@@ -172,7 +173,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
})} })}
{modelNodes.map((node) => { {modelNodes.map((node) => {
const gunString = `gun_${gunModelDefinition.model const gunString = `gun_${gunModelDefinition.modelId
.toString() .toString()
.padStart(2, '0')}`; .padStart(2, '0')}`;
const isCurrentGun = gunModelDefinition.mask const isCurrentGun = gunModelDefinition.mask
@@ -1,6 +1,5 @@
import { import {
isExplosive, isExplosive,
resolveNearPenetration,
resolvePenetrationCoefficient, resolvePenetrationCoefficient,
type ShellDefinition, type ShellDefinition,
} from '@blitzkit/core'; } from '@blitzkit/core';
@@ -54,9 +53,7 @@ export function SpacedArmorSubSpaced({
useEffect(() => { useEffect(() => {
function handleShellChange(shell: ShellDefinition) { function handleShellChange(shell: ShellDefinition) {
material.uniforms.penetration.value = resolveNearPenetration( material.uniforms.penetration.value = shell.penetration.near;
shell.penetration,
);
material.uniforms.caliber.value = shell.caliber; material.uniforms.caliber.value = shell.caliber;
material.uniforms.ricochet.value = degToRad( material.uniforms.ricochet.value = degToRad(
isExplosive(shell.type) ? 90 : shell.ricochet!, isExplosive(shell.type) ? 90 : shell.ricochet!,
@@ -71,7 +68,7 @@ export function SpacedArmorSubSpaced({
const duel = duelStore.getState(); const duel = duelStore.getState();
const hasEnhancedArmor = await hasEquipment( const hasEnhancedArmor = await hasEquipment(
110, 110,
duel.protagonist.tank.equipment, duel.protagonist.tank.equipmentPreset,
equipment, equipment,
); );
material.uniforms.thickness.value = hasEnhancedArmor material.uniforms.thickness.value = hasEnhancedArmor
@@ -81,10 +78,10 @@ export function SpacedArmorSubSpaced({
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
const duel = duelStore.getState(); const duel = duelStore.getState();
const shell = duelStore.getState().antagonist.shell; const shell = duelStore.getState().antagonist.shell;
const penetration = resolveNearPenetration(shell.penetration); const penetration = shell.penetration.near;
const hasCalibratedShells = await hasEquipment( const hasCalibratedShells = await hasEquipment(
103, 103,
duel.antagonist.tank.equipment, duel.antagonist.tank.equipmentPreset,
equipment, equipment,
); );
@@ -1,7 +1,6 @@
import { import {
ShellType, ShellType,
isExplosive, isExplosive,
resolveNearPenetration,
resolvePenetrationCoefficient, resolvePenetrationCoefficient,
} from '@blitzkit/core'; } from '@blitzkit/core';
import { useThree } from '@react-three/fiber'; import { useThree } from '@react-three/fiber';
@@ -104,16 +103,16 @@ export function SpacedArmorSceneComponent({
const hasCalibratedShells = await hasEquipment( const hasCalibratedShells = await hasEquipment(
103, 103,
antagonist.tank.equipment, antagonist.tank.equipmentPreset,
antagonist.equipmentMatrix, antagonist.equipmentMatrix,
); );
const hasEnhancedArmor = await hasEquipment( const hasEnhancedArmor = await hasEquipment(
110, 110,
protagonist.tank.equipment, protagonist.tank.equipmentPreset,
protagonist.equipmentMatrix, protagonist.equipmentMatrix,
); );
const penetration = const penetration =
resolveNearPenetration(shell.penetration) * shell.penetration.near *
resolvePenetrationCoefficient(hasCalibratedShells, shell.type); resolvePenetrationCoefficient(hasCalibratedShells, shell.type);
const thicknessCoefficient = hasEnhancedArmor ? 1.03 : 1; const thicknessCoefficient = hasEnhancedArmor ? 1.03 : 1;
const filteredIntersections = intersections.filter( const filteredIntersections = intersections.filter(
@@ -289,7 +288,7 @@ export function SpacedArmorSceneComponent({
const finalDamage = Math.max( const finalDamage = Math.max(
0, 0,
0.5 * 0.5 *
shell.damage.armor * shell.armorDamage *
(1 - distanceFromSpacedArmor / shell.explosionRadius!) - (1 - distanceFromSpacedArmor / shell.explosionRadius!) -
1.1 * 1.1 *
(lastLayer.thicknessAngled + (lastLayer.thicknessAngled +
@@ -312,7 +311,7 @@ export function SpacedArmorSceneComponent({
shot.damage = finalDamage; shot.damage = finalDamage;
} else { } else {
shot.in.status = 'penetration'; shot.in.status = 'penetration';
shot.damage = shell.damage.armor; shot.damage = shell.armorDamage;
} }
} else { } else {
if (lastLayer.status === 'blocked') { if (lastLayer.status === 'blocked') {
@@ -320,7 +319,7 @@ export function SpacedArmorSceneComponent({
shot.damage = 0; shot.damage = 0;
} else if (lastLayer.status === 'penetration') { } else if (lastLayer.status === 'penetration') {
shot.in.status = 'penetration'; shot.in.status = 'penetration';
shot.damage = shell.damage.armor; shot.damage = shell.armorDamage;
} else { } else {
const caster = new Raycaster(); const caster = new Raycaster();
// https://math.stackexchange.com/a/13263/1222875 // https://math.stackexchange.com/a/13263/1222875
@@ -1,5 +1,6 @@
import { type TankClass } from '@blitzkit/core'; import { TankClass } from '@blitzkit/core';
import type { ComponentProps, ReactNode } from 'react'; import type { ComponentProps, ReactNode } from 'react';
import { StupidCat } from '../StupidCat';
import { ClassHeavy } from './components/ClassHeavy'; import { ClassHeavy } from './components/ClassHeavy';
import { ClassLight } from './components/ClassLight'; import { ClassLight } from './components/ClassLight';
import { ClassMedium } from './components/ClassMedium'; import { ClassMedium } from './components/ClassMedium';
@@ -9,8 +10,9 @@ export const classIcons: Record<
TankClass, TankClass,
(props: ComponentProps<'svg'>) => ReactNode (props: ComponentProps<'svg'>) => ReactNode
> = { > = {
'AT-SPG': ClassTankDestroyer, [TankClass.TANK_DESTROYER]: ClassTankDestroyer,
heavyTank: ClassHeavy, [TankClass.HEAVY]: ClassHeavy,
lightTank: ClassLight, [TankClass.LIGHT]: ClassLight,
mediumTank: ClassMedium, [TankClass.MEDIUM]: ClassMedium,
[TankClass.UNRECOGNIZED]: StupidCat,
}; };
@@ -1,7 +1,7 @@
import { import {
asset, asset,
fetchSkillDefinitions,
permanentSkills, permanentSkills,
skillDefinitions,
TIER_ROMAN_NUMERALS, TIER_ROMAN_NUMERALS,
type Tier, type Tier,
} from '@blitzkit/core'; } from '@blitzkit/core';
@@ -13,7 +13,7 @@ interface CrewSkillManagerProps {
onChange?: (skillLevels: Record<string, number>) => void; onChange?: (skillLevels: Record<string, number>) => void;
} }
const awaitedSkillDefinitions = await skillDefinitions; const skillDefinitions = await fetchSkillDefinitions();
export function CrewSkillManager({ export function CrewSkillManager({
skillLevels, skillLevels,
@@ -21,41 +21,39 @@ export function CrewSkillManager({
}: CrewSkillManagerProps) { }: CrewSkillManagerProps) {
return ( return (
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
{Object.entries(awaitedSkillDefinitions.classes).map( {Object.entries(skillDefinitions.classes).map(([tankClass, skills]) => (
([tankClass, skills]) => ( <Flex gap="2" key={tankClass}>
<Flex gap="2" key={tankClass}> {skills.skills.map((skill) => {
{skills.map((skill) => { const level = skillLevels[skill];
const level = skillLevels[skill];
return ( return (
<GenericTankComponentButton <GenericTankComponentButton
key={skill} key={skill}
special={!permanentSkills.includes(skill)} special={!permanentSkills.includes(skill)}
selected={level > 0} selected={level > 0}
discriminator={ discriminator={
level === 0 ? undefined : TIER_ROMAN_NUMERALS[level as Tier] level === 0 ? undefined : TIER_ROMAN_NUMERALS[level as Tier]
}
icon={asset(`icons/skills/${skill}.webp`)}
onClick={(event) => {
if (!onChange) return;
const draft = { ...skillLevels };
if (event.shiftKey) {
draft[skill] = draft[skill] === 0 ? 7 : 0;
} else {
draft[skill] = level - 1;
if (draft[skill] < 0) draft[skill] = 7;
} }
icon={asset(`icons/skills/${skill}.webp`)}
onClick={(event) => {
if (!onChange) return;
const draft = { ...skillLevels }; onChange(draft);
}}
if (event.shiftKey) { />
draft[skill] = draft[skill] === 0 ? 7 : 0; );
} else { })}
draft[skill] = level - 1; </Flex>
if (draft[skill] < 0) draft[skill] = 7; ))}
}
onChange(draft);
}}
/>
);
})}
</Flex>
),
)}
</Flex> </Flex>
); );
} }
+4 -4
View File
@@ -1,9 +1,9 @@
--- ---
import { gameDefinitions } from '@blitzkit/core'; import { fetchGameDefinitions } from '@blitzkit/core';
import { Code, Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Code, Flex, Heading, Link, Text } from '@radix-ui/themes';
import packageJson from '../../../../package.json'; import packageJson from '../../../../package.json';
const awaitedGameDefinitions = await gameDefinitions; const gameDefinitions = await fetchGameDefinitions();
--- ---
<Flex <Flex
@@ -133,7 +133,7 @@ const awaitedGameDefinitions = await gameDefinitions;
{packageJson.version} {packageJson.version}
</Code> </Code>
<Code size="2" color="gray"> <Code size="2" color="gray">
{awaitedGameDefinitions.version} {gameDefinitions.version}
</Code> </Code>
<Code size="2" color="gray"> <Code size="2" color="gray">
{import.meta.env.PUBLIC_ASSET_BRANCH} {import.meta.env.PUBLIC_ASSET_BRANCH}
@@ -148,7 +148,7 @@ const awaitedGameDefinitions = await gameDefinitions;
</Code> </Code>
<Text size="2" color="gray"> WoT Blitz </Text> <Text size="2" color="gray"> WoT Blitz </Text>
<Code size="2" color="gray"> <Code size="2" color="gray">
{awaitedGameDefinitions.version} {gameDefinitions.version}
</Code> </Code>
<Text size="2" color="gray"> CDN </Text> <Text size="2" color="gray"> CDN </Text>
<Code size="2" color="gray"> <Code size="2" color="gray">
@@ -1,4 +1,4 @@
import { asset, provisionDefinitions } from '@blitzkit/core'; import { asset, fetchProvisionDefinitions } from '@blitzkit/core';
import { GenericTankComponentButton } from './GenericTankComponentButton'; import { GenericTankComponentButton } from './GenericTankComponentButton';
import type { TankComponentButtonProps } from './TankComponentButton'; import type { TankComponentButtonProps } from './TankComponentButton';
@@ -6,12 +6,12 @@ interface ProvisionButtonProps extends TankComponentButtonProps {
provision: number; provision: number;
} }
const awaitedProvisionDefinitions = await provisionDefinitions; const provisionDefinitions = await fetchProvisionDefinitions();
export function ProvisionButton({ provision, ...props }: ProvisionButtonProps) { export function ProvisionButton({ provision, ...props }: ProvisionButtonProps) {
return ( return (
<GenericTankComponentButton <GenericTankComponentButton
tooltip={awaitedProvisionDefinitions[provision].name} tooltip={provisionDefinitions.provisions[provision].name}
icon={asset(`icons/provisions/${provision}.webp`)} icon={asset(`icons/provisions/${provision}.webp`)}
{...props} {...props}
/> />
@@ -0,0 +1,3 @@
export function StupidCat() {
return <img src="https://i.imgur.com/6FBBzb9.png" />;
}
@@ -2,6 +2,7 @@ import {
asset, asset,
fetchGameDefinitions, fetchGameDefinitions,
TANK_CLASSES, TANK_CLASSES,
TankType,
TIER_ROMAN_NUMERALS, TIER_ROMAN_NUMERALS,
type Tier, type Tier,
} from '@blitzkit/core'; } from '@blitzkit/core';
@@ -35,7 +36,7 @@ export function FilterControl({ compact }: FilterControlProps) {
> >
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}> <Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
{times(5, (index) => { {times(5, (index) => {
const tier = (index + 1) as Tier; const tier = index as Tier;
const selected = tankFilters.tiers?.includes(tier); const selected = tankFilters.tiers?.includes(tier);
return ( return (
@@ -46,29 +47,19 @@ export function FilterControl({ compact }: FilterControlProps) {
radius="none" radius="none"
color={selected ? undefined : 'gray'} color={selected ? undefined : 'gray'}
highContrast highContrast
onClick={() => onClick={() => {
// mutateTankFilters((draft) => { if (tankFilters.tiers.includes(tier)) {
// if (draft.tiers?.includes(tier)) { $tankFilters.setKey(
// draft.tiers = draft.tiers?.filter((t) => t !== tier); 'tiers',
// } else { tankFilters.tiers.filter((t) => t !== tier),
// draft.tiers = [...(draft.tiers ?? []), tier]; );
// } } else {
// }) $tankFilters.setKey('tiers', [
...tankFilters.tiers,
{ tier,
if (tankFilters.tiers.includes(tier)) { ]);
$tankFilters.setKey(
'tiers',
tankFilters.tiers.filter((t) => t !== tier),
);
} else {
$tankFilters.setKey('tiers', [
...tankFilters.tiers,
tier,
]);
}
} }
} }}
> >
<Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text> <Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text>
</IconButton> </IconButton>
@@ -78,7 +69,7 @@ export function FilterControl({ compact }: FilterControlProps) {
</Flex> </Flex>
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}> <Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
{times(5, (index) => { {times(5, (index) => {
const tier = (index + 6) as Tier; const tier = (index + 5) as Tier;
const selected = tankFilters.tiers?.includes(tier); const selected = tankFilters.tiers?.includes(tier);
return ( return (
@@ -89,28 +80,19 @@ export function FilterControl({ compact }: FilterControlProps) {
radius="none" radius="none"
color={selected ? undefined : 'gray'} color={selected ? undefined : 'gray'}
highContrast highContrast
onClick={() => onClick={() => {
// mutateTankFilters((draft) => { if (tankFilters.tiers.includes(tier)) {
// if (draft.tiers?.includes(tier)) { $tankFilters.setKey(
// draft.tiers = draft.tiers?.filter((t) => t !== tier); 'tiers',
// } else { tankFilters.tiers.filter((t) => t !== tier),
// draft.tiers = [...(draft.tiers ?? []), tier]; );
// } } else {
// }) $tankFilters.setKey('tiers', [
{ ...tankFilters.tiers,
if (tankFilters.tiers.includes(tier)) { tier,
$tankFilters.setKey( ]);
'tiers',
tankFilters.tiers.filter((t) => t !== tier),
);
} else {
$tankFilters.setKey('tiers', [
...tankFilters.tiers,
tier,
]);
}
} }
} }}
> >
<Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text> <Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text>
</IconButton> </IconButton>
@@ -256,30 +238,19 @@ export function FilterControl({ compact }: FilterControlProps) {
radius="none" radius="none"
color={selected ? undefined : 'gray'} color={selected ? undefined : 'gray'}
highContrast highContrast
onClick={() => onClick={() => {
// mutateTankFilters((draft) => { if (tankFilters.classes.includes(tankClass)) {
// if (draft.classes?.includes(tankClass)) { $tankFilters.setKey(
// draft.classes = draft.classes?.filter( 'classes',
// (c) => c !== tankClass, tankFilters.classes.filter((c) => c !== tankClass),
// ); );
// } else { } else {
// draft.classes = [...(draft.classes ?? []), tankClass]; $tankFilters.setKey('classes', [
// } ...tankFilters.classes,
// }) tankClass,
{ ]);
if (tankFilters.classes.includes(tankClass)) {
$tankFilters.setKey(
'classes',
tankFilters.classes.filter((c) => c !== tankClass),
);
} else {
$tankFilters.setKey('classes', [
...tankFilters.classes,
tankClass,
]);
}
} }
} }}
> >
<Icon style={{ width: '1em', height: '1em' }} /> <Icon style={{ width: '1em', height: '1em' }} />
</IconButton> </IconButton>
@@ -296,73 +267,63 @@ export function FilterControl({ compact }: FilterControlProps) {
<Tooltip content="Researchable"> <Tooltip content="Researchable">
<IconButton <IconButton
variant={ variant={
tankFilters.types?.includes('researchable') ? 'solid' : 'soft' tankFilters.types?.includes(TankType.RESEARCHABLE)
? 'solid'
: 'soft'
} }
radius="none" radius="none"
color={ color={
tankFilters.types?.includes('researchable') ? undefined : 'gray' tankFilters.types?.includes(TankType.RESEARCHABLE)
? undefined
: 'gray'
} }
highContrast highContrast
onClick={() => onClick={() => {
// mutateTankFilters((draft) => { if (tankFilters.types.includes(TankType.RESEARCHABLE)) {
// if (draft.types?.includes('researchable')) { $tankFilters.setKey(
// draft.types = draft.types?.filter( 'types',
// (t) => t !== 'researchable', tankFilters.types.filter((t) => t !== TankType.RESEARCHABLE),
// ); );
// } else { } else {
// draft.types = [...(draft.types ?? []), 'researchable']; $tankFilters.setKey('types', [
// } ...tankFilters.types,
// }) TankType.RESEARCHABLE,
{ ]);
if (tankFilters.types.includes('researchable')) {
$tankFilters.setKey(
'types',
tankFilters.types.filter((t) => t !== 'researchable'),
);
} else {
$tankFilters.setKey('types', [
...tankFilters.types,
'researchable',
]);
}
} }
} }}
> >
<ResearchedIcon style={{ width: '1em', height: '1em' }} /> <ResearchedIcon style={{ width: '1em', height: '1em' }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip content="Premium"> <Tooltip content="Premium">
<IconButton <IconButton
variant={tankFilters.types?.includes('premium') ? 'solid' : 'soft'} variant={
radius="none" tankFilters.types?.includes(TankType.PREMIUM) ? 'solid' : 'soft'
color={tankFilters.types?.includes('premium') ? 'amber' : 'gray'}
highContrast
onClick={() =>
// mutateTankFilters((draft) => {
// if (draft.types?.includes('premium')) {
// draft.types = draft.types?.filter((t) => t !== 'premium');
// } else {
// draft.types = [...(draft.types ?? []), 'premium'];
// }
// })
{
if (tankFilters.types.includes('premium')) {
$tankFilters.setKey(
'types',
tankFilters.types.filter((t) => t !== 'premium'),
);
} else {
$tankFilters.setKey('types', [
...tankFilters.types,
'premium',
]);
}
}
} }
radius="none"
color={
tankFilters.types?.includes(TankType.PREMIUM) ? 'amber' : 'gray'
}
highContrast
onClick={() => {
if (tankFilters.types.includes(TankType.PREMIUM)) {
$tankFilters.setKey(
'types',
tankFilters.types.filter((t) => t !== TankType.PREMIUM),
);
} else {
$tankFilters.setKey('types', [
...tankFilters.types,
TankType.PREMIUM,
]);
}
}}
> >
<Text <Text
color={ color={
tankFilters.types?.includes('premium') ? undefined : 'amber' tankFilters.types?.includes(TankType.PREMIUM)
? undefined
: 'amber'
} }
style={{ display: 'flex', justifyContent: 'center' }} style={{ display: 'flex', justifyContent: 'center' }}
> >
@@ -373,37 +334,32 @@ export function FilterControl({ compact }: FilterControlProps) {
<Tooltip content="Collector"> <Tooltip content="Collector">
<IconButton <IconButton
variant={ variant={
tankFilters.types?.includes('collector') ? 'solid' : 'soft' tankFilters.types?.includes(TankType.COLLECTOR) ? 'solid' : 'soft'
} }
radius="none" radius="none"
color={tankFilters.types?.includes('collector') ? 'blue' : 'gray'} color={
highContrast tankFilters.types?.includes(TankType.COLLECTOR) ? 'blue' : 'gray'
onClick={() =>
// mutateTankFilters((draft) => {
// if (draft.types?.includes('collector')) {
// draft.types = draft.types?.filter((t) => t !== 'collector');
// } else {
// draft.types = [...(draft.types ?? []), 'collector'];
// }
// })
{
if (tankFilters.types.includes('collector')) {
$tankFilters.setKey(
'types',
tankFilters.types.filter((t) => t !== 'collector'),
);
} else {
$tankFilters.setKey('types', [
...tankFilters.types,
'collector',
]);
}
}
} }
highContrast
onClick={() => {
if (tankFilters.types.includes(TankType.COLLECTOR)) {
$tankFilters.setKey(
'types',
tankFilters.types.filter((t) => t !== TankType.COLLECTOR),
);
} else {
$tankFilters.setKey('types', [
...tankFilters.types,
TankType.COLLECTOR,
]);
}
}}
> >
<Text <Text
color={ color={
tankFilters.types?.includes('collector') ? undefined : 'blue' tankFilters.types?.includes(TankType.COLLECTOR)
? undefined
: 'blue'
} }
style={{ display: 'flex', justifyContent: 'center' }} style={{ display: 'flex', justifyContent: 'center' }}
> >
@@ -424,14 +380,9 @@ export function FilterControl({ compact }: FilterControlProps) {
radius="none" radius="none"
color={tankFilters.testing === 'include' ? undefined : 'gray'} color={tankFilters.testing === 'include' ? undefined : 'gray'}
highContrast highContrast
onClick={() => onClick={() => {
// mutateTankFilters((draft) => { $tankFilters.setKey('testing', 'include');
// draft.testing = 'include'; }}
// })
{
$tankFilters.setKey('testing', 'include');
}
}
> >
<ExperimentIcon <ExperimentIcon
style={{ width: '1em', height: '1em', color: 'currentColor' }} style={{ width: '1em', height: '1em', color: 'currentColor' }}
@@ -484,7 +435,6 @@ export function FilterControl({ compact }: FilterControlProps) {
<IconButton <IconButton
color="red" color="red"
onClick={() => { onClick={() => {
// tankFiltersStore.setState(tankFiltersStore.getInitialState(), true);
$tankFilters.set(initialTankFilters); $tankFilters.set(initialTankFilters);
}} }}
> >
@@ -1,16 +1,16 @@
import { equipmentDefinitions } from '@blitzkit/core'; import { fetchEquipmentDefinitions } from '@blitzkit/core';
import { Button, Flex, Heading } from '@radix-ui/themes'; import { Button, Flex, Heading } from '@radix-ui/themes';
import { Duel } from '../../../../stores/duel'; import { Duel } from '../../../../stores/duel';
import { EquipmentManager } from '../../../EquipmentManager'; import { EquipmentManager } from '../../../EquipmentManager';
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
const awaitedEquipmentDefinitions = await equipmentDefinitions; const equipmentDefinitions = await fetchEquipmentDefinitions();
export function Equipment() { export function Equipment() {
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
const protagonist = Duel.use((state) => state.protagonist); const protagonist = Duel.use((state) => state.protagonist);
const equipmentPreset = const equipmentPreset =
awaitedEquipmentDefinitions.presets[protagonist.tank.equipment]; equipmentDefinitions.presets[protagonist.tank.equipmentPreset];
const equipmentMatrix = Duel.use( const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix, (state) => state.protagonist.equipmentMatrix,
); );
@@ -28,7 +28,8 @@ export const TankModel = memo(() => {
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const turretModelDefinition = const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id]; tankModelDefinition.turrets[protagonist.turret.id];
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; const gunModelDefinition =
turretModelDefinition.guns[protagonist.gun.gunType!.value.base.id];
const { gltf } = useModel(protagonist.tank.id); const { gltf } = useModel(protagonist.tank.id);
const nodes = Object.values(gltf.nodes); const nodes = Object.values(gltf.nodes);
const isDynamicArmorActive = Duel.use((state) => const isDynamicArmorActive = Duel.use((state) =>
@@ -135,7 +136,7 @@ export const TankModel = memo(() => {
const isTurret = node.name.startsWith('turret_'); const isTurret = node.name.startsWith('turret_');
const isCurrentTurret = const isCurrentTurret =
node.name === node.name ===
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`; `turret_${turretModelDefinition.modelId.toString().padStart(2, '0')}`;
const isVisible = isCurrentTurret; const isVisible = isCurrentTurret;
const position = new Vector2(); const position = new Vector2();
const delta = new Vector2(); const delta = new Vector2();
@@ -168,7 +169,7 @@ export const TankModel = memo(() => {
const duel = duelStore.getState(); const duel = duelStore.getState();
const hasImprovedVerticalStabilizer = await hasEquipment( const hasImprovedVerticalStabilizer = await hasEquipment(
122, 122,
duel.protagonist.tank.equipment, duel.protagonist.tank.equipmentPreset,
duel.protagonist.equipmentMatrix, duel.protagonist.equipmentMatrix,
); );
const boundingRect = canvas.getBoundingClientRect(); const boundingRect = canvas.getBoundingClientRect();
@@ -231,12 +232,12 @@ export const TankModel = memo(() => {
{nodes.map((node) => { {nodes.map((node) => {
const isCurrentMantlet = const isCurrentMantlet =
node.name === node.name ===
`gun_${gunModelDefinition.model `gun_${gunModelDefinition.modelId
.toString() .toString()
.padStart(2, '0')}_mask`; .padStart(2, '0')}_mask`;
const isCurrentGun = const isCurrentGun =
node.name === node.name ===
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; `gun_${gunModelDefinition.modelId.toString().padStart(2, '0')}`;
const isVisible = isCurrentGun || isCurrentMantlet; const isVisible = isCurrentGun || isCurrentMantlet;
const position = new Vector2(); const position = new Vector2();
const delta = new Vector2(); const delta = new Vector2();
@@ -268,7 +269,7 @@ export const TankModel = memo(() => {
const duel = duelStore.getState(); const duel = duelStore.getState();
const hasImprovedVerticalStabilizer = await hasEquipment( const hasImprovedVerticalStabilizer = await hasEquipment(
122, 122,
duel.protagonist.tank.equipment, duel.protagonist.tank.equipmentPreset,
duel.protagonist.equipmentMatrix, duel.protagonist.equipmentMatrix,
); );
const boundingRect = canvas.getBoundingClientRect(); const boundingRect = canvas.getBoundingClientRect();
@@ -44,7 +44,8 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const turretModelDefinition = const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id]; tankModelDefinition.turrets[protagonist.turret.id];
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; const gunModelDefinition =
turretModelDefinition.guns[protagonist.gun.gunType!.value.base.id];
const display = TankopediaPersistent.useDeferred( const display = TankopediaPersistent.useDeferred(
(state) => state.display, (state) => state.display,
TankopediaDisplay.Model, TankopediaDisplay.Model,
@@ -185,7 +186,6 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
<ArmorPlateDisplay /> <ArmorPlateDisplay />
<AutoClear /> <AutoClear />
{/* idk why the shot display doesn't work without suspense here lol */}
<Suspense fallback={<ModelLoader />}> <Suspense fallback={<ModelLoader />}>
{display === TankopediaDisplay.DynamicArmor && <Armor />} {display === TankopediaDisplay.DynamicArmor && <Armor />}
{display === TankopediaDisplay.StaticArmor && ( {display === TankopediaDisplay.StaticArmor && (
@@ -1,6 +1,6 @@
import { fetchTankDefinitions, TankType } from '@blitzkit/core'; import { fetchTankDefinitions, TankType } from '@blitzkit/core';
import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { Suspense, useEffect, useMemo, useRef } from 'react'; import { Suspense, useMemo, useRef } from 'react';
import { NAVBAR_HEIGHT } from '../../../constants/navbar'; import { NAVBAR_HEIGHT } from '../../../constants/navbar';
import { Var } from '../../../core/radix/var'; import { Var } from '../../../core/radix/var';
import { useFullScreen } from '../../../hooks/useFullScreen'; import { useFullScreen } from '../../../hooks/useFullScreen';
@@ -44,10 +44,6 @@ export function HeroSection() {
return { value } satisfies ThicknessRange; return { value } satisfies ThicknessRange;
}, [protagonist]); }, [protagonist]);
useEffect(() => {
// setDummyLoader(false);
}, []);
return ( return (
<Flex justify="center" style={{ backgroundColor: Var('color-surface') }}> <Flex justify="center" style={{ backgroundColor: Var('color-surface') }}>
<Flex <Flex
@@ -199,10 +199,12 @@ export function MetaSection() {
/> />
</Flex> </Flex>
</Listing> </Listing>
{protagonist.xp && ( {protagonist.researchCost && (
<Listing label="Research XP"> <Listing label="Research XP">
<Flex align="center" gap="1"> <Flex align="center" gap="1">
{protagonist.xp.toLocaleString()} {(
protagonist.researchCost.researchCostType!.value as number
).toLocaleString()}
<img <img
style={{ width: '1em', height: '1em' }} style={{ width: '1em', height: '1em' }}
alt="xp" alt="xp"
@@ -507,9 +507,9 @@ export function tankCharacteristics(
gun.gunType!.value.base.camouflageLoss; gun.gunType!.value.base.camouflageLoss;
const camouflageCaughtOnFire = const camouflageCaughtOnFire =
tank.camouflageOnFire * tank.camouflageStill * camouflageCoefficientStill; tank.camouflageOnFire * tank.camouflageStill * camouflageCoefficientStill;
const width = size[2]; const width = size.z;
const height = size[0]; const height = size.x;
const length = size[1]; const length = size.y;
const volume = width * height * length; const volume = width * height * length;
const shellNormalization = shell.normalization ?? 0; const shellNormalization = shell.normalization ?? 0;
const shellRicochet = isExplosive(shell.type) ? undefined : shell.ricochet; const shellRicochet = isExplosive(shell.type) ? undefined : shell.ricochet;
@@ -32,6 +32,7 @@ const isRoot = pathname === '/';
) )
} }
<meta property="og:site_name" content="BlitzKit" /> <meta property="og:site_name" content="BlitzKit" />
<meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/favicon.png" /> <link rel="icon" type="image/x-icon" href="/favicon.png" />
<Party3 /> <Party3 />
@@ -7,7 +7,7 @@ import { Page } from './index';
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const tankDefinitions = await fetchTankDefinitions(); const tankDefinitions = await fetchTankDefinitions();
return Object.values(tankDefinitions).map((tank) => ({ return Object.values(tankDefinitions.tanks).map((tank) => ({
params: { id: tank.id }, params: { id: tank.id },
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
@@ -43,13 +43,10 @@ export function Page({ id }: PageProps) {
<CalloutsSection /> <CalloutsSection />
<MetaSection /> <MetaSection />
<TechTreeSection /> <TechTreeSection />
{/* {!exempt && <AdMidSectionResponsive />} */}
<CharacteristicsSection /> <CharacteristicsSection />
{/* {!exempt && <AdMidSectionResponsive />} */}
<GameModeSection /> <GameModeSection />
<VideoSection /> <VideoSection />
<HistorySection /> <HistorySection />
{/* {!exempt && <AdMidSectionResponsive mb="6" />} */}
</PageWrapper> </PageWrapper>
</Duel.Provider> </Duel.Provider>
</TankopediaPersistent.Provider> </TankopediaPersistent.Provider>