From 8033e8f7cc25c3ccb27c3a3c2138d681022a2856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:22:12 -0500 Subject: [PATCH] feat: burst compatiblity --- .../core/src/protos/tank_definitions.proto | 1 - packages/core/src/protos/tank_definitions.ts | 22 +----- packages/i18n/strings/en.json | 4 +- .../scripts/src/buildAssets/definitions.ts | 15 ++-- .../Characteristics/components/Firepower.tsx | 4 +- .../components/ReloadVisualizer/index.tsx | 76 ++++++++++++++----- .../components/Characteristics/index.tsx | 2 + .../src/core/blitzkit/tankCharacteristics.ts | 4 + 8 files changed, 78 insertions(+), 50 deletions(-) diff --git a/packages/core/src/protos/tank_definitions.proto b/packages/core/src/protos/tank_definitions.proto index 408806cab..a827ef158 100644 --- a/packages/core/src/protos/tank_definitions.proto +++ b/packages/core/src/protos/tank_definitions.proto @@ -136,7 +136,6 @@ message GunDefinitionAutoLoader { required float clip_reload = 1; required float intra_clip = 2; required float shell_count = 3; - optional Burst burst = 4; } message Burst { diff --git a/packages/core/src/protos/tank_definitions.ts b/packages/core/src/protos/tank_definitions.ts index 2fbdd6202..fdbae9625 100644 --- a/packages/core/src/protos/tank_definitions.ts +++ b/packages/core/src/protos/tank_definitions.ts @@ -408,7 +408,6 @@ export interface GunDefinitionAutoLoader { clip_reload: number; intra_clip: number; shell_count: number; - burst?: Burst; } export interface Burst { @@ -3023,7 +3022,7 @@ export const GunDefinitionRegular: MessageFns = { }; function createBaseGunDefinitionAutoLoader(): GunDefinitionAutoLoader { - return { clip_reload: 0, intra_clip: 0, shell_count: 0, burst: undefined }; + return { clip_reload: 0, intra_clip: 0, shell_count: 0 }; } export const GunDefinitionAutoLoader: MessageFns = { @@ -3040,9 +3039,6 @@ export const GunDefinitionAutoLoader: MessageFns = { if (message.shell_count !== 0) { writer.uint32(29).float(message.shell_count); } - if (message.burst !== undefined) { - Burst.encode(message.burst, writer.uint32(34).fork()).join(); - } return writer; }, @@ -3081,14 +3077,6 @@ export const GunDefinitionAutoLoader: MessageFns = { message.shell_count = reader.float(); continue; } - case 4: { - if (tag !== 34) { - break; - } - - message.burst = Burst.decode(reader, reader.uint32()); - continue; - } } if ((tag & 7) === 4 || tag === 0) { break; @@ -3109,7 +3097,6 @@ export const GunDefinitionAutoLoader: MessageFns = { shell_count: isSet(object.shell_count) ? globalThis.Number(object.shell_count) : 0, - burst: isSet(object.burst) ? Burst.fromJSON(object.burst) : undefined, }; }, @@ -3124,9 +3111,6 @@ export const GunDefinitionAutoLoader: MessageFns = { if (message.shell_count !== 0) { obj.shell_count = message.shell_count; } - if (message.burst !== undefined) { - obj.burst = Burst.toJSON(message.burst); - } return obj; }, @@ -3142,10 +3126,6 @@ export const GunDefinitionAutoLoader: MessageFns = { message.clip_reload = object.clip_reload ?? 0; message.intra_clip = object.intra_clip ?? 0; message.shell_count = object.shell_count ?? 0; - message.burst = - object.burst !== undefined && object.burst !== null - ? Burst.fromPartial(object.burst) - : undefined; return message; }, }; diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 63f628301..37bc896e0 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -1155,7 +1155,9 @@ "shellRange": "Shell range", "shellCapacity": "Shell capacity", "gunType": "Gun type", - "penetrationAt250m": "Penetration at 250m" + "penetrationAt250m": "Penetration at 250m", + "burstShells": "Burst shell count", + "burstInterShell": "Burst inter-shell" } }, diff --git a/packages/scripts/src/buildAssets/definitions.ts b/packages/scripts/src/buildAssets/definitions.ts index 4daad3f97..ea888d1b5 100644 --- a/packages/scripts/src/buildAssets/definitions.ts +++ b/packages/scripts/src/buildAssets/definitions.ts @@ -1324,7 +1324,13 @@ export async function definitions() { unlocks: resolveUnlocks(gun.unlocks), shell_capacity: gun.maxAmmo ?? gunListEntry.maxAmmo, assault_ranges, - + burst: + gun.burst && gun.burst.count > 1 + ? { + count: gun.burst.count, + interval: 60 / gun.burst.rate, + } + : undefined, gun_type: gunType === 'regular' ? { @@ -1350,13 +1356,6 @@ export async function definitions() { intra_clip: 60 / gun.clip!.rate, clip_reload: gun.reloadTime, shell_count: gunClipCount, - burst: - gun.burst && gun.burst.count > 1 - ? { - count: gun.burst.count, - interval: 60 / gun.burst.rate, - } - : undefined, }, }, } satisfies GunDefinition); diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Firepower.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Firepower.tsx index 8324061d0..feb0bbedd 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Firepower.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Firepower.tsx @@ -41,7 +41,9 @@ export function Firepower({ const setPenetrationDistanceDebounced = debounce((value: number) => { setPenetrationDistance(value); }, 500); - const { gun, shell, turret } = Duel.use((state) => state.protagonist); + const turret = Duel.use((state) => state.protagonist.turret); + const gun = Duel.use((state) => state.protagonist.gun); + const shell = Duel.use((state) => state.protagonist.shell); const penetrationDistanceInput = useRef(null); const hasSupercharger = useEquipment(107); const hasCalibratedShells = useEquipment(103); diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/ReloadVisualizer/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/ReloadVisualizer/index.tsx index 4141981a5..a24bbd9ae 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/ReloadVisualizer/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/ReloadVisualizer/index.tsx @@ -1,5 +1,4 @@ -import { type Datum, type Serie } from '@nivo/line'; -import { Box } from '@radix-ui/themes'; +import { Box, Code } from '@radix-ui/themes'; import { times } from 'lodash-es'; import { Quicklime, type QuicklimeCallback } from 'quicklime'; import { useEffect, useRef } from 'react'; @@ -9,6 +8,8 @@ import { VisualizerCard } from '../VisualizerCard'; import { Shell } from './components/Shell'; import { Target } from './components/Target'; +const PRECISION = 2; + export interface ReloadUpdateData { reload: number; shells: number[]; @@ -16,12 +17,12 @@ export interface ReloadUpdateData { export const reloadUpdate = new Quicklime(); -const T = 60; - export function ReloadVisualizer({ stats }: StatsAcceptorProps) { const reloadCircle = useRef(null); const reloadCore = useRef(null); const reloadGlow = useRef(null); + const totalTime = useRef(null); + const progressTime = useRef(null); /** * 3-shell gun example: @@ -38,7 +39,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) { const state = useRef(0); const dpm = useRef(0); const shotPool = useRef(new Set()); - const data = useRef([{ id: 'value', data: [] }]); useEffect(() => { let cancel = false; @@ -52,6 +52,8 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) { } function frame() { + if (!totalTime.current || !progressTime.current) return; + const now = Date.now() / 1000; const dt = now - lastT; let reload; @@ -68,15 +70,30 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) { reload = state.current; shells = shellArray.fill(reload); + totalTime.current.innerHTML = stats.shellReload!.toFixed(PRECISION); + progressTime.current.innerHTML = ( + (1 - reload) * + stats.shellReload! + ).toFixed(PRECISION); + if (state.current >= 1) shoot(); } else if (state.current < stats.shells) { - state.current = Math.min( - stats.shells, - state.current + dt / stats.intraClip!, - ); + const interval = + stats.burstShells === 1 + ? stats.intraClip! + : Math.floor(state.current) % stats.burstShells === 0 + ? stats.intraClip! + : stats.burstInterShell!; + + state.current = Math.min(stats.shells, state.current + dt / interval); shells = times(stats.shells, (index) => index > state.current - 1); reload = state.current % 1; + totalTime.current.innerHTML = interval.toFixed(PRECISION); + progressTime.current.innerHTML = ((1 - reload) * interval).toFixed( + PRECISION, + ); + if (lastState % 1 > state.current % 1) shoot(); } else { state.current = 0; @@ -90,15 +107,6 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) { lastT = now; lastState = state.current; - - (data.current[0].data as Datum[]).push({ - x: now, - y: dpm.current / (stats.dpm + stats.damage), - }); - (data.current[0].data as Datum[]).splice( - 0, - data.current[0].data.findIndex((d) => now - (d.x as number) < T), - ); } frame(); @@ -216,6 +224,38 @@ export function ReloadVisualizer({ stats }: StatsAcceptorProps) { }} /> + + 6.9s + + + 10.0s + + {stats.shells > 1 && times(stats.shells, (index) => ( diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx index 2c59e4ec5..77c881977 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx @@ -87,6 +87,8 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) { modelTransformEvent.dispatch({ pitch, yaw }); }, [hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer]); + console.log(tank.slug, gun.burst, stats.burstShells); + return ( type === CrewType.DRIVER) ? 1.1 : 1.05); const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]); + const burstShells = gun.burst?.count ?? 1; + const burstInterShell = gun.burst?.interval; const armorDamageCoefficient = coefficient([hasTungsten, 0.15]) * coefficient( @@ -581,6 +583,8 @@ export function tankCharacteristics( shellCapacity, gunType, penetrationAt250m, + burstShells, + burstInterShell, }; }