Add Brush/Roller rolling time to analyzer

This commit is contained in:
Kalle
2026-09-24 20:23:13 +03:00
parent a6460fc135
commit bdcd531f50
23 changed files with 118 additions and 0 deletions

View File

@@ -96,6 +96,8 @@ export interface BaseWeaponStats {
InkConsume_WeaponShelterShotgunParam?: number;
/** How much ink a dualie dodge roll consumes? */
InkConsume_SideStepParam?: number;
/** How much ink rolling with a roller or brush consumes per frame at full rolling speed? */
InkConsumeMaxPerFrame_WeaponRollParam?: number;
/** How much ink a fully charged Splatana shot consumes? */
InkConsumeFullCharge_ChargeParam?: number;
@@ -293,6 +295,8 @@ export interface AnalyzedBuild {
mainWeaponWhiteInkSeconds?: number;
subWeaponWhiteInkSeconds: number;
subWeaponInkConsumptionPercentage: Stat;
/** Seconds a full ink tank lasts rolling at full speed (rollers and brushes) */
mainWeaponRollSeconds?: Stat;
fullInkTankOptions: Array<FullInkTankOption & { id: string }>;
damages: Array<Damage & { id: string }>;
specialWeaponDamages: Array<Damage & { id: string }>;

View File

@@ -190,6 +190,34 @@ describe("Analyze build", () => {
expect(statWithISM.value).toBeLessThan(statWithISM.baseValue);
});
test("Rolling time on a full tank only exists for rollers and brushes", () => {
const splatRoller = buildStats({
weaponSplId: 1010,
hasTacticooler: false,
});
const inkbrush = buildStats({ weaponSplId: 1100, hasTacticooler: false });
const splattershot = buildStats({ weaponSplId: 40, hasTacticooler: false });
expect(splatRoller.stats.mainWeaponRollSeconds?.baseValue).toBe(16.667);
expect(inkbrush.stats.mainWeaponRollSeconds?.baseValue).toBe(13.333);
expect(splattershot.stats.mainWeaponRollSeconds).toBeUndefined();
});
test("ISM increases rolling time on a full tank", () => {
const analyzed = buildStats({ weaponSplId: 1100, hasTacticooler: false });
const analyzedWithISM = buildStats({
weaponSplId: 1100,
abilityPoints: new Map([["ISM", 20]]),
hasTacticooler: false,
});
const stat = analyzed.stats.mainWeaponRollSeconds!;
const statWithISM = analyzedWithISM.stats.mainWeaponRollSeconds!;
expect(statWithISM.baseValue).toBe(stat.baseValue);
expect(statWithISM.value).toBeGreaterThan(statWithISM.baseValue);
});
test("Accounts for Jr. big ink tank with main weapon ink consumption %", () => {
const analyzedJr = buildStats({
weaponSplId: 10,

View File

@@ -125,6 +125,7 @@ export function buildStats({
subWeaponInkConsumptionPercentage:
subWeaponInkConsumptionPercentage(input),
...mainWeaponInkConsumptionPercentages(input),
mainWeaponRollSeconds: mainWeaponRollSeconds(input),
squidFormInkRecoverySeconds: squidFormInkRecoverySeconds(input),
humanoidFormInkRecoverySeconds: humanoidFormInkRecoverySeconds(input),
runSpeed: runSpeed(input),
@@ -388,6 +389,34 @@ function mainWeaponInkConsumptionPercentages(
return result;
}
function mainWeaponRollSeconds({
mainWeaponParams,
abilityPoints,
weaponSplId,
}: StatFunctionInput): AnalyzedBuild["stats"]["mainWeaponRollSeconds"] {
const inkConsumePerFrame =
mainWeaponParams.InkConsumeMaxPerFrame_WeaponRollParam;
if (typeof inkConsumePerFrame !== "number") return;
const { baseEffect, effect } = abilityPointsToEffects({
abilityPoints: apFromMap({
abilityPoints,
ability: "ISM",
}),
key: "ConsumeRt_Main",
weapon: mainWeaponParams,
});
const rollFrames = (consumeRate: number) =>
inkTankSize(weaponSplId) / (inkConsumePerFrame * consumeRate);
return {
baseValue: framesToSeconds(rollFrames(baseEffect)),
value: framesToSeconds(rollFrames(effect)),
modifiedBy: "ISM",
};
}
function mainWeaponInkConsumeByType({
mainWeaponParams,
abilityPoints,

View File

@@ -430,6 +430,7 @@ export const weaponParams = {
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 250,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1000,
InkConsume_WeaponSwingParam: 0.0396,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
"1010": {
Range_SpawnSpeed: 1.8338,
@@ -443,6 +444,7 @@ export const weaponParams = {
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 350,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
InkConsume_WeaponSwingParam: 0.085,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
"1020": {
Range_SpawnSpeed: 2.0289,
@@ -457,6 +459,7 @@ export const weaponParams = {
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 400,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1800,
InkConsume_WeaponSwingParam: 0.21,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
"1030": {
Range_SpawnSpeed: 1.7026,
@@ -471,6 +474,7 @@ export const weaponParams = {
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
InkConsume_WeaponVerticalSwingParam: 0.12,
InkConsume_WeaponWideSwingParam: 0.08,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
"1040": {
Range_SpawnSpeed: 2.2749,
@@ -484,6 +488,7 @@ export const weaponParams = {
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 400,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 700,
InkConsume_WeaponSwingParam: 0.09,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0005,
},
"1100": {
Range_SpawnSpeed: 0.72,
@@ -494,6 +499,7 @@ export const weaponParams = {
SwingUnitGroupParam_DamageParam_DamageMinValue: 150,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 300,
InkConsume_WeaponSwingParam: 0.02,
InkConsumeMaxPerFrame_WeaponRollParam: 0.00125,
},
"1110": {
Range_SpawnSpeed: 0.84,
@@ -503,6 +509,7 @@ export const weaponParams = {
SwingUnitGroupParam_DamageParam_DamageMinValue: 200,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 400,
InkConsume_WeaponSwingParam: 0.027,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0015,
},
"1120": {
Range_SpawnSpeed: 1.05,
@@ -512,6 +519,7 @@ export const weaponParams = {
SwingUnitGroupParam_DamageParam_DamageMinValue: 310,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 600,
InkConsume_WeaponSwingParam: 0.048,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0018,
},
"2000": {
DistanceFullCharge: 16.765,

View File

@@ -214,6 +214,16 @@ function BuildAnalyzerPage() {
suffix="%"
/>
)),
analyzed.stats.mainWeaponRollSeconds ? (
<StatCard
context={context}
key="mainWeaponRollSeconds"
stat={statKeyToTuple("mainWeaponRollSeconds")}
title={t("analyzer:stat.mainWeaponRollSeconds")}
suffix={t("analyzer:suffix.seconds")}
popoverInfo={t("analyzer:stat.mainWeaponRollSeconds.explanation")}
/>
) : null,
typeof analyzed.stats.mainWeaponWhiteInkSeconds === "number" ? (
<StatCard
context={context}

View File

@@ -0,0 +1,5 @@
---
navItem: analyzer
type: feature
---
Build analyzer shows how long rollers and brushes can roll on a full ink tank & the effect of ISM

View File

@@ -38,6 +38,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Påfyldningstid af blæktank i blæksprutteform",
"stat.humanoidFormInkRecoverySeconds": "Påfyldningstid af blæktank i menneskeform",
"stat.quickRespawnTime": "Tilbagekomsttid med Quick respawn (hurtig tilbagekomst)",

View File

@@ -38,6 +38,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Dauer vollst. Tintenregeneration (als Tintenfisch)",
"stat.humanoidFormInkRecoverySeconds": "Dauer vollst. Tintenregeneration (als Humanoid)",
"stat.quickRespawnTime": "Dauer schneller Rückkehr",

View File

@@ -38,6 +38,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "Consumption per full charge",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "Consumption per shield launch",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "Consumption per dodge roll",
"stat.mainWeaponRollSeconds": "Rolling time on a full tank",
"stat.mainWeaponRollSeconds.explanation": "How long a full ink tank lasts when rolling at full speed. Rollers use less ink when moving slower.",
"stat.squidFormInkRecoverySeconds": "Ink tank full recovery time (squid form)",
"stat.humanoidFormInkRecoverySeconds": "Ink tank full recovery time (humanoid form)",
"stat.quickRespawnTime": "Quick respawn time",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "Consumo por carga completa",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "Consumo por lanzamiento de parasol",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "Consumo por voltereta",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Tiempo de recuperación completa del tanque de tinta (forma calamar)",
"stat.humanoidFormInkRecoverySeconds": "Tiempo de recuperación completa del tanque de tinta (forma humanoide)",
"stat.quickRespawnTime": "Tiempo de Retorno exprés",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "Consumo por carga completa",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "Consumo por lanzamiento de parasol",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "Consumo por voltereta",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Tiempo de recuperación completa del tanque de tinta (forma calamar)",
"stat.humanoidFormInkRecoverySeconds": "Tiempo de recuperación completa del tanque de tinta (forma humana)",
"stat.quickRespawnTime": "Tiempo de regeneración rápida",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Temps de recharge du réservoir (calamar)",
"stat.humanoidFormInkRecoverySeconds": "Temps de recharge du réservoir (humanoïde)",
"stat.quickRespawnTime": "Délai de réapparition",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Temps de recharge du réservoir (calamar)",
"stat.humanoidFormInkRecoverySeconds": "Temps de recharge du réservoir (humanoïde)",
"stat.quickRespawnTime": "Délai de réapparition",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "זמן התאוששות מלא של מיכל הדיו (צורת דיונון)",
"stat.humanoidFormInkRecoverySeconds": "זמן התאוששות מלא של מיכל הדיו (צורת אדם)",
"stat.quickRespawnTime": "זמן הופעה מחדש במהירות",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Tempo ricarica piena serbatoio (forma calamaro)",
"stat.humanoidFormInkRecoverySeconds": "Tempo ricarica piena serbatoio (forma umanoide)",
"stat.quickRespawnTime": "Tempo per respawnare con \"Il tempo è colore\"",

View File

@@ -36,6 +36,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "インクタンクの完全回復までの時間(イカ状態)",
"stat.humanoidFormInkRecoverySeconds": "インクタンクの完全回復までの時間(ヒト状態)",
"stat.quickRespawnTime": "復活するまで",

View File

@@ -36,6 +36,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "잉크 완전 회복 시간 (오징어의 모습)",
"stat.humanoidFormInkRecoverySeconds": "잉크 완전 회복 시간 (인간의 모습)",
"stat.quickRespawnTime": "부활 시간 단축",

View File

@@ -38,6 +38,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Volledige hersteltijd inkttank (zwem vorm)",
"stat.humanoidFormInkRecoverySeconds": "",
"stat.quickRespawnTime": "Comeback terugkeertijd",

View File

@@ -40,6 +40,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Czas pełnej regeneracji zbiornika farbowego (forma kalmara)",
"stat.humanoidFormInkRecoverySeconds": "Czas pełnej regeneracji zbiornika farbowego (forma ludzka)",
"stat.quickRespawnTime": "Czas z użyciem Quick Respawn",

View File

@@ -39,6 +39,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Tempo de recarga completa do tanque de tinta (forma de lula/polvo)",
"stat.humanoidFormInkRecoverySeconds": "Tempo de recarga completa do tanque de tinta (forma humanoide)",
"stat.quickRespawnTime": "Tempo de Quick Respawn",

View File

@@ -40,6 +40,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "Время до полного восстановления баллона (в краске)",
"stat.humanoidFormInkRecoverySeconds": "Время до полного восстановления баллона (вне краски)",
"stat.quickRespawnTime": "Время ускоренного воскрешения",

View File

@@ -36,6 +36,8 @@
"stat.mainWeaponInkConsumptionPercentage.SPLATLING_CHARGE": "",
"stat.mainWeaponInkConsumptionPercentage.SHIELD_LAUNCH": "",
"stat.mainWeaponInkConsumptionPercentage.DUALIE_ROLL": "",
"stat.mainWeaponRollSeconds": "",
"stat.mainWeaponRollSeconds.explanation": "",
"stat.squidFormInkRecoverySeconds": "完全回墨时间 (鱿鱼形态)",
"stat.humanoidFormInkRecoverySeconds": "完全回墨时间 (人型形态)",
"stat.quickRespawnTime": "复活时间",

View File

@@ -642,6 +642,8 @@ function parametersToMainWeaponResult(
InkConsume_WeaponShelterShotgunParam:
InkConsume_WeaponShelterShotgunParam(),
InkConsume_SideStepParam: params.SideStepParam?.InkConsume,
InkConsumeMaxPerFrame_WeaponRollParam:
params.WeaponRollParam?.InkConsumeMaxPerFrame,
InkConsume_SwingParam: params.spl__WeaponSaberParam?.SwingParam?.InkConsume,
InkConsumeFullCharge_ChargeParam:
params.spl__WeaponSaberParam?.ChargeParam?.InkConsumeFullCharge ??