From 03437e9aa361c02119cc60809c0af3d7ba8f2386 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Tue, 4 Aug 2026 06:52:20 +0300 Subject: [PATCH] Add main weapon ink consumption % stat --- app/features/build-analyzer/analyzer-types.ts | 6 ++- .../build-analyzer/core/stats.test.ts | 53 +++++++++++++++++++ app/features/build-analyzer/core/stats.ts | 33 ++++++++++++ .../build-analyzer/routes/analyzer.tsx | 12 +++++ locales/da/analyzer.json | 10 ++++ locales/de/analyzer.json | 10 ++++ locales/en/analyzer.json | 10 ++++ locales/es-ES/analyzer.json | 10 ++++ locales/es-US/analyzer.json | 10 ++++ locales/fr-CA/analyzer.json | 10 ++++ locales/fr-EU/analyzer.json | 10 ++++ locales/he/analyzer.json | 10 ++++ locales/it/analyzer.json | 10 ++++ locales/ja/analyzer.json | 10 ++++ locales/ko/analyzer.json | 10 ++++ locales/nl/analyzer.json | 10 ++++ locales/pl/analyzer.json | 10 ++++ locales/pt-BR/analyzer.json | 10 ++++ locales/ru/analyzer.json | 10 ++++ locales/zh/analyzer.json | 10 ++++ 20 files changed, 263 insertions(+), 1 deletion(-) diff --git a/app/features/build-analyzer/analyzer-types.ts b/app/features/build-analyzer/analyzer-types.ts index e5321d504..b2d04c3d2 100644 --- a/app/features/build-analyzer/analyzer-types.ts +++ b/app/features/build-analyzer/analyzer-types.ts @@ -258,6 +258,10 @@ export interface FullInkTankOption { type: InkConsumeType; } +export type MainWeaponInkConsumptionStats = { + [K in InkConsumeType as `mainWeaponInkConsumptionPercentage_${K}`]?: Stat; +}; + export type DamageType = (typeof DAMAGE_TYPE)[number]; export type TenacityPlayerDeficit = (typeof TENACITY_PLAYER_DEFICITS)[number]; @@ -350,7 +354,7 @@ export interface AnalyzedBuild { specialRadiusRangeMin?: Stat; specialRadiusRangeMax?: Stat; specialPowerUpDuration?: Stat; - }; + } & MainWeaponInkConsumptionStats; } export type SpecialEffectType = (typeof SPECIAL_EFFECTS)[number]["type"]; diff --git a/app/features/build-analyzer/core/stats.test.ts b/app/features/build-analyzer/core/stats.test.ts index 8bd8b5fb0..5afb22dde 100644 --- a/app/features/build-analyzer/core/stats.test.ts +++ b/app/features/build-analyzer/core/stats.test.ts @@ -1,8 +1,10 @@ import { describe, expect, test } from "vitest"; import type { MainWeaponId } from "~/modules/in-game-lists/types"; import { mainWeaponIds } from "~/modules/in-game-lists/weapon-ids"; +import { roundToNDecimalPlaces } from "~/utils/number"; import { damageTypeToWeaponType } from "../analyzer-constants"; import { buildStats } from "./stats"; +import { mainWeaponParams } from "./utils"; describe("Analyze build", () => { test("Every main weapon has damage", () => { @@ -151,6 +153,57 @@ describe("Analyze build", () => { [57, 57], ]); + test("Main weapon ink consumption % exists per ink consume type of the weapon", () => { + const analyzedCharger = buildStats({ + weaponSplId: 2010, + hasTacticooler: false, + }); + + expect( + analyzedCharger.stats.mainWeaponInkConsumptionPercentage_TAP_SHOT, + ).toBeDefined(); + expect( + analyzedCharger.stats.mainWeaponInkConsumptionPercentage_FULL_CHARGE, + ).toBeDefined(); + expect( + analyzedCharger.stats.mainWeaponInkConsumptionPercentage_NORMAL, + ).toBeUndefined(); + }); + + test("ISM decreases main weapon ink consumption %", () => { + const analyzed = buildStats({ + weaponSplId: 0, + hasTacticooler: false, + }); + + const analyzedWithISM = buildStats({ + weaponSplId: 0, + abilityPoints: new Map([["ISM", 20]]), + hasTacticooler: false, + }); + + const stat = analyzed.stats.mainWeaponInkConsumptionPercentage_NORMAL!; + const statWithISM = + analyzedWithISM.stats.mainWeaponInkConsumptionPercentage_NORMAL!; + + expect(stat.value).toBe(stat.baseValue); + expect(statWithISM.baseValue).toBe(stat.baseValue); + expect(statWithISM.value).toBeLessThan(statWithISM.baseValue); + }); + + test("Accounts for Jr. big ink tank with main weapon ink consumption %", () => { + const analyzedJr = buildStats({ + weaponSplId: 10, + hasTacticooler: false, + }); + + const jrParams = mainWeaponParams(10); + + expect( + analyzedJr.stats.mainWeaponInkConsumptionPercentage_NORMAL?.baseValue, + ).toBe(roundToNDecimalPlaces((jrParams.InkConsume! * 100) / 1.1)); + }); + test("Sub Power Up Beakon AP boost matches Lean", () => { for (const [subPowerAp, quickSuperJumpAp] of subPowerApToQuickSuperJumpAp) { const analyzed = buildStats({ diff --git a/app/features/build-analyzer/core/stats.ts b/app/features/build-analyzer/core/stats.ts index 53507c8c8..19b137db4 100644 --- a/app/features/build-analyzer/core/stats.ts +++ b/app/features/build-analyzer/core/stats.ts @@ -35,6 +35,7 @@ import type { AnalyzedBuild, DamageType, InkConsumeType, + MainWeaponInkConsumptionStats, MainWeaponParams, SpecialWeaponParams, StatFunctionInput, @@ -123,6 +124,7 @@ export function buildStats({ subWeaponWhiteInkSeconds: framesToSeconds(subWeaponParams.InkRecoverStop), subWeaponInkConsumptionPercentage: subWeaponInkConsumptionPercentage(input), + ...mainWeaponInkConsumptionPercentages(input), squidFormInkRecoverySeconds: squidFormInkRecoverySeconds(input), humanoidFormInkRecoverySeconds: humanoidFormInkRecoverySeconds(input), runSpeed: runSpeed(input), @@ -358,6 +360,37 @@ function subWeaponConsume({ }; } +function mainWeaponInkConsumptionPercentages( + args: StatFunctionInput, +): MainWeaponInkConsumptionStats { + const result: MainWeaponInkConsumptionStats = {}; + + for (const type of INK_CONSUME_TYPES) { + const baseInkConsume = mainWeaponInkConsumeByType({ + ...args, + abilityPoints: new Map(), + type, + }); + + if (typeof baseInkConsume !== "number") continue; + + const inkConsume = mainWeaponInkConsumeByType({ ...args, type }); + invariant(typeof inkConsume === "number"); + + result[`mainWeaponInkConsumptionPercentage_${type}`] = { + baseValue: roundToNDecimalPlaces( + (baseInkConsume * 100) / inkTankSize(args.weaponSplId), + ), + value: roundToNDecimalPlaces( + (inkConsume * 100) / inkTankSize(args.weaponSplId), + ), + modifiedBy: "ISM", + }; + } + + return result; +} + function mainWeaponInkConsumeByType({ mainWeaponParams, abilityPoints, diff --git a/app/features/build-analyzer/routes/analyzer.tsx b/app/features/build-analyzer/routes/analyzer.tsx index 9d34820dc..7a83bc2b2 100644 --- a/app/features/build-analyzer/routes/analyzer.tsx +++ b/app/features/build-analyzer/routes/analyzer.tsx @@ -75,6 +75,7 @@ import type { Stat, SubWeaponDamage, } from "../analyzer-types"; +import { INK_CONSUME_TYPES } from "../analyzer-types"; import { PerInkTankGrid } from "../components/PerInkTankGrid"; import { ABILITIES_WITHOUT_CHUNKS, @@ -207,6 +208,17 @@ function BuildAnalyzerPage() { /> ), + ...INK_CONSUME_TYPES.filter( + (type) => analyzed.stats[`mainWeaponInkConsumptionPercentage_${type}`], + ).map((type) => ( + + )), typeof analyzed.stats.mainWeaponWhiteInkSeconds === "number" && (