From bc6257a0c3efa9bc366184ef81c8348b9d4be451 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Oct 2026 10:47:00 -0500 Subject: [PATCH] reloads --- .../website/src/config/characteristics.ts | 20 ++++- .../src/config/characteristicsGroups.ts | 7 +- .../src/hooks/useCharacteristicRenderer.tsx | 78 ++++++++++++------- .../src/tankopedia/calculateRankings.ts | 42 +++++++++- packages/website/src/types/characteristics.ts | 5 ++ 5 files changed, 118 insertions(+), 34 deletions(-) diff --git a/packages/website/src/config/characteristics.ts b/packages/website/src/config/characteristics.ts index e8b28f067..27e08c4db 100644 --- a/packages/website/src/config/characteristics.ts +++ b/packages/website/src/config/characteristics.ts @@ -101,6 +101,24 @@ export const characteristics = { }, }, + reloads: { + type: CharacteristicType.NumberList, + + should_render({ gun }) { + return gun.gun_type!.$case === "auto_reloader"; + }, + + compute({ gun, characteristic }) { + if (gun.gun_type!.$case !== "auto_reloader") return []; + + const reloadCoefficient = characteristic("_reload_coefficient") as number; + + return gun.gun_type!.value.shell_reloads.map( + (reload) => reload * reloadCoefficient, + ); + }, + }, + intra_clip: { type: CharacteristicType.Number, @@ -195,8 +213,6 @@ export const characteristics = { // module_damage_range: unavailable, - // reloads: unavailable, - clip_size: { type: CharacteristicType.Number, diff --git a/packages/website/src/config/characteristicsGroups.ts b/packages/website/src/config/characteristicsGroups.ts index f7fd37c1f..40a11270e 100644 --- a/packages/website/src/config/characteristicsGroups.ts +++ b/packages/website/src/config/characteristicsGroups.ts @@ -87,7 +87,12 @@ export const characteristicsGroups: CharacteristicsGroup[] = [ units: "s", ranking: CharacteristicRanking.LowerIsBetter, }, - { name: "reloads", decimals: 1, units: "s" }, + { + name: "reloads", + decimals: 1, + units: "s", + ranking: CharacteristicRanking.LowerIsBetter, + }, { toy: "reload" }, ], diff --git a/packages/website/src/hooks/useCharacteristicRenderer.tsx b/packages/website/src/hooks/useCharacteristicRenderer.tsx index cc153f9a8..9aab682de 100644 --- a/packages/website/src/hooks/useCharacteristicRenderer.tsx +++ b/packages/website/src/hooks/useCharacteristicRenderer.tsx @@ -1,10 +1,12 @@ import { literalsArray } from "@blitzkit/i18n/src/literals"; -import { type ReactNode } from "react"; +import { Fragment, type ReactNode } from "react"; import { Text } from "../components/Text"; +import { characteristics } from "../config/characteristics"; import type { CharacteristicRenderConfig, CharacteristicReturnType, } from "../types/characteristics"; +import { CharacteristicType } from "../types/characteristics"; import { useLocale } from "./useLocale"; import { useStrings } from "./useStrings"; @@ -21,39 +23,61 @@ export function useCharacteristicRenderer() { if (config.render) return config.render({ output: characteristic, strings }); - if (typeof characteristic === "number") { - if (Number.isFinite(characteristic)) { - let value: ReactNode = characteristic; + function renderNumber( + value: number, + units: CharacteristicRenderConfig["units"], + ): ReactNode { + if (!Number.isFinite(value)) return `${value < 0 ? "-" : ""}∞`; - if (config.decimals !== undefined) { - value *= 10 ** config.decimals; - value = Math.round(value); - value /= 10 ** config.decimals; - } + let rendered: ReactNode = value; - if (config.localize) { - value = value.toLocaleString(locale); - } else { - value = value.toFixed(config.decimals); - } - - if (config.units !== undefined) { - value = literalsArray(strings.units[config.units], { - value: {value}, - }); - } - - return value; + if (config.decimals !== undefined) { + rendered *= 10 ** config.decimals; + rendered = Math.round(rendered); + rendered /= 10 ** config.decimals; } - return `${characteristic < 0 ? "-" : ""}∞`; + if (config.localize) { + rendered = rendered.toLocaleString(locale); + } else { + rendered = rendered.toFixed(config.decimals); + } + + if (units !== undefined) { + rendered = literalsArray(strings.units[units], { + value: {rendered}, + }); + } + + return rendered; } - if (typeof characteristic === "string") { - return characteristic; - } + switch (characteristics[config.name].type) { + case CharacteristicType.Enum: + return characteristic as string; - throw new Error("Unknown characteristic type"); + case CharacteristicType.Number: + return renderNumber(characteristic as number, config.units); + + case CharacteristicType.NumberList: { + const values = (characteristic as number[]).map((value, index) => ( + + {index > 0 && ", "} + {renderNumber(value, undefined)} + + )); + + if (config.units === undefined) return values; + + return ( + <> + {literalsArray(strings.units[config.units], { + value: {values}, + })} + + ); + } + } } return renderCharacteristic; diff --git a/packages/website/src/tankopedia/calculateRankings.ts b/packages/website/src/tankopedia/calculateRankings.ts index 6d0f3d037..bf26b823b 100644 --- a/packages/website/src/tankopedia/calculateRankings.ts +++ b/packages/website/src/tankopedia/calculateRankings.ts @@ -1,8 +1,11 @@ +import { characteristics as characteristicDefinitions } from "../config/characteristics"; import { characteristicsGroups } from "../config/characteristicsGroups"; import { CharacteristicRanking as CharacteristicRankingDirection, + CharacteristicType, type CharacteristicName, type CharacteristicRenderConfig, + type CharacteristicReturnType, type ComputedCharacteristics, } from "../types/characteristics"; @@ -24,6 +27,35 @@ export interface CharacteristicRank { score: number; } +function rankingValue( + name: CharacteristicName, + value?: CharacteristicReturnType, +) { + if (value === undefined) return; + + switch (characteristicDefinitions[name].type) { + case CharacteristicType.Enum: + return; + + case CharacteristicType.Number: + return value as number; + + case CharacteristicType.NumberList: { + const values = value as number[]; + + if (values.length === 0) return; + + let total = 0; + + for (const current of values) { + total += current; + } + + return total / values.length; + } + } +} + export function calculateRankings( characteristics: ComputedCharacteristics, comparisons: ComputedCharacteristics[], @@ -31,7 +63,9 @@ export function calculateRankings( const rankings = new Map(); for (const [name, value] of characteristics) { - if (typeof value !== "number" || name[0] === "_") continue; + const currentValue = rankingValue(name, value); + + if (currentValue === undefined || name[0] === "_") continue; const config = characteristicConfigs.get(name)!; @@ -41,13 +75,13 @@ export function calculateRankings( config.ranking === CharacteristicRankingDirection.LowerIsBetter; const values = comparisons - .map((comparison) => comparison.get(name)) - .filter((other) => typeof other === "number"); + .map((comparison) => rankingValue(name, comparison.get(name))) + .filter((other) => other !== undefined); if (values.length === 0) continue; const betterCount = values.filter((other) => - lowerIsBetter ? other < value : other > value, + lowerIsBetter ? other < currentValue : other > currentValue, ).length; rankings.set(name, { diff --git a/packages/website/src/types/characteristics.ts b/packages/website/src/types/characteristics.ts index a74da634e..46e155e15 100644 --- a/packages/website/src/types/characteristics.ts +++ b/packages/website/src/types/characteristics.ts @@ -27,6 +27,10 @@ export type Characteristic = { type: CharacteristicType.Number; compute(context: CharacteristicContext): number; } + | { + type: CharacteristicType.NumberList; + compute(context: CharacteristicContext): number[]; + } ); export type CharacteristicScript = ( @@ -63,6 +67,7 @@ export type CrewStatRole = "commander" | "loader" | "gunner" | "driver"; export enum CharacteristicType { Enum, Number, + NumberList, } export enum CharacteristicRanking {