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