diff --git a/docs/changelogs/1.29.16.md b/docs/changelogs/1.29.16.md new file mode 100644 index 000000000..c111d385d --- /dev/null +++ b/docs/changelogs/1.29.16.md @@ -0,0 +1,18 @@ +# BlitzKit 1.29.16 + +Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update. + +## Fixes + +- [GonnaHetzMe] The turret for Centurion I is no longer offset from the body + - Please allow up to 24 hours for the model to update +- Vertical Stabilizers now give the correct 12% buff instead of 15% +- Re-ordering tanks in Compare now works once again +- Fixed review videos from being about the Object 452K across all tanks + - Please allow up to 2 weeks for all tanks to refresh their videos +- Tanks in Mixer with oscillating turrets are not handled properly + +## Features + +- Headings in the Compare tool are now even more compact for mobile devices +- Enabled all tiers for the randomizer in Mixer diff --git a/package.json b/package.json index c9b71bd33..efd85330d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.29.15", + "version": "1.29.16", "license": "BlitzKit License", "private": true, "scripts": { diff --git a/packages/scripts/src/core/blitz/extractModel/index.ts b/packages/scripts/src/core/blitz/extractModel/index.ts index c535c86c6..362898414 100644 --- a/packages/scripts/src/core/blitz/extractModel/index.ts +++ b/packages/scripts/src/core/blitz/extractModel/index.ts @@ -170,6 +170,7 @@ export async function extractModel(vfs: AbstractVFS, path: string) { break; case "TransformComponent": { + component["tc.localTranslation"] = [0, 0, 0]; // Game when is loading model resets position to [0, 0, 0], so any set value is ignored. node.setTranslation(component["tc.localTranslation"]); node.setRotation(component["tc.localRotation"]); node.setScale(component["tc.localScale"]); diff --git a/packages/scripts/src/reviews.ts b/packages/scripts/src/reviews.ts index 2affaae30..1eca4395b 100644 --- a/packages/scripts/src/reviews.ts +++ b/packages/scripts/src/reviews.ts @@ -5,6 +5,7 @@ import { Video, youtubers, } from "@blitzkit/core"; +import locales from "@blitzkit/i18n/locales.json"; import { google } from "googleapis"; import { cloneDeep, uniqBy } from "lodash-es"; import { AssetUploader } from "./core/github/assetUploader"; @@ -42,9 +43,11 @@ for (const tank of tanksSanitized) { } try { + const q = `World of Tanks Blitz ${tank.name.locales[locales.default]}`; + const results = await youtube.search.list({ part: ["snippet"], - q: `World of Tanks Blitz ${tank.name}`, + q, }); if (!results.data.items || results.data.items.length === 0) continue; @@ -54,9 +57,9 @@ for (const tank of tanksSanitized) { (item) => item.snippet?.channelId && item.id?.videoId && - youtubers.some(({ id }) => id === item.snippet?.channelId) + youtubers.some(({ id }) => id === item.snippet?.channelId), ), - (item) => item.snippet!.channelId + (item) => item.snippet!.channelId, ); reviews.reviews[tank.id] = { @@ -66,11 +69,13 @@ for (const tank of tanksSanitized) { ({ id: item.id!.videoId!, author: item.snippet!.channelId!, - } satisfies Video) + }) satisfies Video, ), }; - console.log(`${++done} done; found ${items.length} for ${tank.name.locales.en}`); + console.log( + `${++done} done; found ${items.length} for ${tank.name.locales.en}`, + ); await new Promise((resolve) => setTimeout(resolve, 1000 / 5)); } catch (error) { diff --git a/packages/website/src/components/Compare/CompareRow.tsx b/packages/website/src/components/Compare/CompareRow.tsx index 566a3741a..fdb317b10 100644 --- a/packages/website/src/components/Compare/CompareRow.tsx +++ b/packages/website/src/components/Compare/CompareRow.tsx @@ -14,7 +14,7 @@ import { StickyRowHeaderCell } from "../StickyRowHeaderCell"; type CompareRowProps = { display?: ( - member: Awaited + member: Awaited, ) => number | string | undefined; deltaType?: CompareCellDirection; decimals?: number; @@ -46,7 +46,7 @@ export function CompareRow({ const values = stats.map((stat) => typeof props.value === "function" ? props.value(stat)! - : (stat[props.value] as number) + : (stat[props.value] as number), ); const id = useRef(Math.random()); const name = @@ -56,10 +56,10 @@ export function CompareRow({ return ( - + @@ -156,7 +156,7 @@ export function CompareRow({ ( {`${deltaPercentage > 0 ? "+" : ""}${Math.round( - deltaPercentage * 100 + deltaPercentage * 100, )}%`} ) diff --git a/packages/website/src/components/Compare/CompareSectionTitle.tsx b/packages/website/src/components/Compare/CompareSectionTitle.tsx index 545481905..0c0f6cc68 100644 --- a/packages/website/src/components/Compare/CompareSectionTitle.tsx +++ b/packages/website/src/components/Compare/CompareSectionTitle.tsx @@ -1,7 +1,7 @@ -import { Heading, Table } from '@radix-ui/themes'; -import { times } from 'lodash-es'; -import { CompareEphemeral } from '../../stores/compareEphemeral'; -import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell'; +import { Heading, Table } from "@radix-ui/themes"; +import { times } from "lodash-es"; +import { CompareEphemeral } from "../../stores/compareEphemeral"; +import { StickyColumnHeaderCell } from "../StickyColumnHeaderCell"; export function CompareSectionTitle({ children }: { children: string }) { const memberCount = CompareEphemeral.use((state) => state.members.length); diff --git a/packages/website/src/components/Compare/CompareTable.tsx b/packages/website/src/components/Compare/CompareTable.tsx index 62029fb73..2829fae15 100644 --- a/packages/website/src/components/Compare/CompareTable.tsx +++ b/packages/website/src/components/Compare/CompareTable.tsx @@ -105,13 +105,13 @@ export function CompareTable({ stats }: CompareTableProps) { crewSkills[skill] === 0 ? Var("gray-11") : permanentSkills.includes(skill) - ? Var("crimson-11") - : Var("amber-11"), + ? Var("crimson-11") + : Var("amber-11"), }} /> ))} - ) + ), )} @@ -173,19 +173,19 @@ export function CompareTable({ stats }: CompareTableProps) { consumables, camouflage, }, - index + index, ) => { const equipmentPreset = equipmentDefinitions.presets[tank.equipment_preset]; const provisionsList = availableProvisions( tank, gun, - provisionDefinitions + provisionDefinitions, ); const consumablesList = Object.values( - consumableDefinitions.consumables + consumableDefinitions.consumables, ).filter((consumable) => - checkConsumableProvisionInclusivity(consumable, tank, gun) + checkConsumableProvisionInclusivity(consumable, tank, gun), ); return ( @@ -294,11 +294,11 @@ export function CompareTable({ stats }: CompareTableProps) { {unwrap( provision.id + (provision) => provision.id, )} selected={provisions} disabled={tank.max_provisions === provisions.length} @@ -452,7 +452,7 @@ export function CompareTable({ stats }: CompareTableProps) { CompareEphemeral.mutate((draft) => { draft.members[index].equipmentMatrix = times( 3, - () => times(3, () => 0) + () => times(3, () => 0), ) as EquipmentMatrix; draft.sorting = undefined; }); @@ -501,11 +501,11 @@ export function CompareTable({ stats }: CompareTableProps) { alt={unwrap( consumableDefinitions.consumables[ consumable - ].name + ].name, )} key={consumable} src={asset( - `/icons/consumables/${consumable}.webp` + `/icons/consumables/${consumable}.webp`, )} style={{ left: "50%", @@ -610,7 +610,7 @@ export function CompareTable({ stats }: CompareTableProps) { ); - } + }, )} diff --git a/packages/website/src/components/Compare/TankCard.tsx b/packages/website/src/components/Compare/TankCard.tsx index 3873d2195..6a87f8be6 100644 --- a/packages/website/src/components/Compare/TankCard.tsx +++ b/packages/website/src/components/Compare/TankCard.tsx @@ -55,7 +55,7 @@ export function TankCard({ index, tank }: TankCardProps) { }; }); const closest = distances.reduce((a, b) => - a.distance < b.distance ? a : b + a.distance < b.distance ? a : b, ); dropIndex = closest.index; @@ -85,8 +85,8 @@ export function TankCard({ index, tank }: TankCardProps) { CompareEphemeral.mutate((draft) => { const fromIndex = index; const toIndex = dropIndex > index ? dropIndex - 1 : dropIndex; - const member = draft.members[fromIndex]; + draft.members.splice(fromIndex, 1); draft.members.splice(toIndex, 0, member); }); @@ -99,7 +99,7 @@ export function TankCard({ index, tank }: TankCardProps) { return () => { draggable.current?.removeEventListener("pointerdown", handlePointerDown); }; - }, []); + }, [index]); return ( @@ -141,7 +141,6 @@ export function TankCard({ index, tank }: TankCardProps) { - ); diff --git a/packages/website/src/components/MixerScene/components/Model.tsx b/packages/website/src/components/MixerScene/components/Model.tsx index 25fa9c211..4f5e583d5 100644 --- a/packages/website/src/components/MixerScene/components/Model.tsx +++ b/packages/website/src/components/MixerScene/components/Model.tsx @@ -84,7 +84,7 @@ export function Model() { useEffect(() => { function handleModelTransform( - event: QuicklimeEvent + event: QuicklimeEvent, ) { turretGroup.current.rotation.z = event.data.yaw; gunGroup.current.rotation.x = event.data.pitch; @@ -171,6 +171,49 @@ export function Model() { turretModel.gun_origin.y, ]} > + + {turretNodes.map((node) => { + const isCurrentMantlet = + node.name === + `gun_${turretModel.guns[turret.turret.guns.at(-1)!.id].model_id.toString().padStart(2, "0")}_mask`; + // const isCurrentGun = + // node.name === + // `gun_${gunModel.model_id.toString().padStart(2, "0")}`; + const isVisible = isCurrentMantlet; + + if (!isVisible) return null; + + return jsxTree(node, { + mesh(_, props, key) { + return ( + { + enablePitchRotation.current = true; + handlePointerDown(event); + }} + /> + ); + }, + }); + })} + + {gunNodes.map((node) => { - const isCurrentMantlet = - node.name === - `gun_${gunModel.model_id.toString().padStart(2, "0")}_mask`; + // const isCurrentMantlet = + // node.name === + // `gun_${gunModel.model_id.toString().padStart(2, "0")}_mask`; const isCurrentGun = node.name === `gun_${gunModel.model_id.toString().padStart(2, "0")}`; - const isVisible = isCurrentGun || isCurrentMantlet; + const isVisible = isCurrentGun; if (!isVisible) return null; diff --git a/packages/website/src/components/StickyRowHeaderCell.tsx b/packages/website/src/components/StickyRowHeaderCell.tsx index e3aaa61bf..d7f6a300c 100644 --- a/packages/website/src/components/StickyRowHeaderCell.tsx +++ b/packages/website/src/components/StickyRowHeaderCell.tsx @@ -1,12 +1,16 @@ import { Table } from "@radix-ui/themes"; import type { RowHeaderCellProps } from "@radix-ui/themes/src/components/table.js"; -export function StickyRowHeaderCell({ style, ...props }: RowHeaderCellProps) { +interface Props extends RowHeaderCellProps { + left?: string | number; +} + +export function StickyRowHeaderCell({ style, left = 0, ...props }: Props) { return ( { const turret = tank.turrets.at(-1)!; const turretModel = tankModel.turrets[turret.id]; - return tank.tier >= 10 && !turretModel.yaw; + return !turretModel.yaw; }); export function curateMixer() { diff --git a/packages/website/src/core/blitzkit/tankCharacteristics.ts b/packages/website/src/core/blitzkit/tankCharacteristics.ts index dcab1976c..ccff1c836 100644 --- a/packages/website/src/core/blitzkit/tankCharacteristics.ts +++ b/packages/website/src/core/blitzkit/tankCharacteristics.ts @@ -76,7 +76,7 @@ export function tankCharacteristics( tankModelDefinition: ModelDefinition; equipmentDefinitions: EquipmentDefinitions; provisionDefinitions: ProvisionDefinitions; - } + }, ) { const preset = equipmentDefinitions.presets[tank.equipment_preset]; const turretModelDefinition = tankModelDefinition.turrets[turret.id]; @@ -138,7 +138,7 @@ export function tankCharacteristics( provisionDefinitions.provisions[provision].crew ? total + provisionDefinitions.provisions[provision].crew! / 100 : total, - 0 + 0, ) + (hasImprovedVentilation ? 0.08 : 0); const commanderMastery = 1 + provisionCrewBonus; const loaderMastery = @@ -158,13 +158,13 @@ export function tankCharacteristics( coefficient( [applyReactiveArmor && shell.type !== ShellType.HE, -0.27], [applyDynamicArmor, -0.1], - [applySpallLiner && shell.type === ShellType.HE, -0.2] + [applySpallLiner && shell.type === ShellType.HE, -0.2], ); const assaultDamageCoefficient = gun.assault_ranges && gun.assault_ranges.types.includes(shell.type) - ? gun.assault_ranges.ranges.find( - ({ distance }) => distance >= assaultDistance - )?.factor ?? 0 + ? (gun.assault_ranges.ranges.find( + ({ distance }) => distance >= assaultDistance, + )?.factor ?? 0) : 1; const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]); const reloadCoefficient = @@ -178,16 +178,16 @@ export function tankCharacteristics( const healthCoefficient = coefficient( [hasSandbagArmor, 0.03], [hasEnhancedSandbagArmor, 0.06], - [hasImprovedAssembly, 0.04] + [hasImprovedAssembly, 0.04], ); const shellVelocityCoefficient = coefficient( [hasSupercharger, 0.35], - [hasImprovedGunPowder, 0.3] + [hasImprovedGunPowder, 0.3], ); const aimTimeCoefficient = coefficient( [hasEnhancedGunLayingDrive, -0.15], - [hasReticleCalibration, -0.3] + [hasReticleCalibration, -0.3], ) * coefficient([true, degressiveStat(gunnerMastery)]); const dispersionStillCoefficient = coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) * @@ -197,20 +197,20 @@ export function tankCharacteristics( -0.12, ]); const dispersionHullTraverseCoefficient = coefficient( - [hasVerticalStabilizer, -0.15], - [true, -crewSkills.smooth_turn / 100] + [hasVerticalStabilizer, -0.12], + [true, -crewSkills.smooth_turn / 100], ); const dispersionAfterShotCoefficient = coefficient( - [hasVerticalStabilizer, -0.15], - [true, -crewSkills.soft_recoil / 100] + [hasVerticalStabilizer, -0.12], + [true, -crewSkills.soft_recoil / 100], ); const dispersionMovingCoefficient = coefficient( - [hasVerticalStabilizer, -0.15], - [true, -crewSkills.smooth_driving / 100] + [hasVerticalStabilizer, -0.12], + [true, -crewSkills.smooth_driving / 100], ); const dispersionTurretTraverseCoefficient = coefficient( - [hasVerticalStabilizer, -0.15], - [true, -crewSkills.smooth_turret * (2 / 100)] + [hasVerticalStabilizer, -0.12], + [true, -crewSkills.smooth_turret * (2 / 100)], ); const enginePowerCoefficient = coefficient( [ @@ -225,7 +225,7 @@ export function tankCharacteristics( [hasStandardFuel, 0.03], [hasImprovedFuel, 0.1], [hasGearOil, 0.03], - [hasImprovedGearOil, 0.06] + [hasImprovedGearOil, 0.06], ); const turretTraverseCoefficient = coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) * @@ -234,7 +234,7 @@ export function tankCharacteristics( coefficient( [hasImprovedControl, 0.11], [hasImprovedEnginePowerBoost, 0.01], - [true, crewSkills.virtuoso / 100] + [true, crewSkills.virtuoso / 100], ) * coefficient([true, progressiveStat(driverMastery)]); const resistanceHardCoefficient = @@ -253,22 +253,22 @@ export function tankCharacteristics( tank.class === TankClass.HEAVY ? 0.06 : tank.class === TankClass.MEDIUM - ? 0.08 - : tank.class === TankClass.LIGHT - ? 0.11 - : 0.04, + ? 0.08 + : tank.class === TankClass.LIGHT + ? 0.11 + : 0.04, ]) * coefficient([true, progressiveStat(commanderMastery)]); const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]); const speedForwardsSum = sum( [hasImprovedEnginePowerBoost, 4], [hasGearOil, 2], - [hasImprovedGearOil, 4] + [hasImprovedGearOil, 4], ); const speedBackwardsSum = sum( [hasImprovedEnginePowerBoost, 8], [hasGearOil, 2], - [hasImprovedGearOil, 4] + [hasImprovedGearOil, 4], ); const camouflageCoefficientMoving = sum( [ @@ -278,8 +278,8 @@ export function tankCharacteristics( tank.class === TankClass.TANK_DESTROYER ? 0.04 : tank.class === TankClass.HEAVY - ? 0.03 - : 0.02, + ? 0.03 + : 0.02, ]), ], [ @@ -287,11 +287,11 @@ export function tankCharacteristics( tank.class === TankClass.HEAVY ? 0.02 : tank.class === TankClass.MEDIUM - ? 0.04 - : tank.class === TankClass.LIGHT - ? 0.07 - : 0.1, - ] + ? 0.04 + : tank.class === TankClass.LIGHT + ? 0.07 + : 0.1, + ], ); const camouflageCoefficientStill = sum( [ @@ -302,10 +302,10 @@ export function tankCharacteristics( tank.class === TankClass.TANK_DESTROYER ? 0.04 : tank.class === TankClass.HEAVY - ? 0.03 - : 0.02, + ? 0.03 + : 0.02, ], - [true, crewSkills.camouflage * (3 / 100)] + [true, crewSkills.camouflage * (3 / 100)], ), ], [ @@ -313,18 +313,18 @@ export function tankCharacteristics( tank.class === TankClass.HEAVY ? 0.04 : tank.class === TankClass.MEDIUM - ? 0.08 - : tank.class === TankClass.LIGHT - ? 0.14 - : 0.2, - ] + ? 0.08 + : tank.class === TankClass.LIGHT + ? 0.14 + : 0.2, + ], ); const size = normalizeBoundingBox( unionBoundingBox( tankModelDefinition.bounding_box, - turretModelDefinition.bounding_box - ) + turretModelDefinition.bounding_box, + ), ); const weightKg = tank.weight + engine.weight + track.weight + turret.weight + gun.weight; @@ -344,7 +344,7 @@ export function tankCharacteristics( shell, damageCoefficient, reloadCoefficient, - intraClipCoefficient + intraClipCoefficient, ); const intraClip = gun.gun_type?.$case === "regular" @@ -398,7 +398,7 @@ export function tankCharacteristics( const shellReloads = gun.gun_type!.$case === "auto_reloader" ? gun.gun_type!.value.shell_reloads.map( - (reload) => reload * reloadCoefficient + (reload) => reload * reloadCoefficient, ) : undefined; const shellReload =