Add no ink recovery time to certain main weapons in analyzer

This commit is contained in:
Kalle
2026-09-25 20:25:00 +03:00
parent f660c83338
commit 6527a6d204
23 changed files with 121 additions and 5 deletions

View File

@@ -72,6 +72,8 @@ export interface BaseWeaponStats {
CanopyHP?: number;
/** Amount of frames white ink (=no ink recovery during this time) takes */
InkRecoverStop?: number;
InkRecoverStop_WeaponVerticalSwingParam?: number;
InkRecoverStop_WeaponWideSwingParam?: number;
/** How much ink one shot consumes? InkConsume = 0.5 means 2 shots per full tank */
InkConsume?: number;
/** Squeezer rapid fire (secondary mode) consumption per shot */
@@ -297,6 +299,8 @@ export interface AnalyzedBuild {
/** Seconds for Tenacity to fill the special gauge, keyed by how many players the team is down. */
tenacitySecondsToSpecial?: Record<TenacityPlayerDeficit, number>;
mainWeaponWhiteInkSeconds?: number;
mainWeaponWhiteInkSecondsHorizontalSwing?: number;
mainWeaponWhiteInkSecondsVerticalSwing?: number;
subWeaponWhiteInkSeconds: number;
subWeaponInkConsumptionPercentage: Stat;
/** Seconds a full ink tank lasts rolling at full speed (rollers and brushes) */

View File

@@ -169,6 +169,27 @@ describe("Analyze build", () => {
).toBeUndefined();
});
test.each([
{ why: "Painbrush", weaponSplId: 1120, expected: 0.833 },
{ why: "Splatana Stamper", weaponSplId: 8000, expected: 0.667 },
{ why: "Tenta Brella", weaponSplId: 6010, expected: 1.167 },
] as const)(
"Main weapon no ink recovery time comes from the weapon's action params ($why)",
({ weaponSplId, expected }) => {
const analyzed = buildStats({ weaponSplId, hasTacticooler: false });
expect(analyzed.stats.mainWeaponWhiteInkSeconds).toBe(expected);
},
);
test("Roller no ink recovery time is split by swing direction", () => {
const analyzed = buildStats({ weaponSplId: 1010, hasTacticooler: false });
expect(analyzed.stats.mainWeaponWhiteInkSeconds).toBeUndefined();
expect(analyzed.stats.mainWeaponWhiteInkSecondsHorizontalSwing).toBe(0.717);
expect(analyzed.stats.mainWeaponWhiteInkSecondsVerticalSwing).toBe(0.967);
});
test("Squeezer rapid fire has its own ink consumption and run speed", () => {
const analyzed = buildStats({
weaponSplId: 400,

View File

@@ -117,10 +117,15 @@ export function buildStats({
damages: damages(input),
specialWeaponDamages: specialWeaponDamages(input),
subWeaponDefenseDamages: subWeaponDefenseDamages(input),
mainWeaponWhiteInkSeconds:
typeof mainWeaponParams.InkRecoverStop === "number"
? framesToSeconds(mainWeaponParams.InkRecoverStop)
: undefined,
mainWeaponWhiteInkSeconds: optionalFramesToSeconds(
mainWeaponParams.InkRecoverStop,
),
mainWeaponWhiteInkSecondsHorizontalSwing: optionalFramesToSeconds(
mainWeaponParams.InkRecoverStop_WeaponWideSwingParam,
),
mainWeaponWhiteInkSecondsVerticalSwing: optionalFramesToSeconds(
mainWeaponParams.InkRecoverStop_WeaponVerticalSwingParam,
),
subWeaponWhiteInkSeconds: framesToSeconds(subWeaponParams.InkRecoverStop),
subWeaponInkConsumptionPercentage:
subWeaponInkConsumptionPercentage(input),
@@ -846,6 +851,8 @@ export function subWeaponDamageValue({
const framesToSeconds = (frames: number) =>
effectToRounded(Math.ceil(frames) / 60);
const optionalFramesToSeconds = (frames: number | undefined) =>
typeof frames === "number" ? framesToSeconds(frames) : undefined;
function squidFormInkRecoverySeconds(
args: StatFunctionInput,
): AnalyzedBuild["stats"]["squidFormInkRecoverySeconds"] {

View File

@@ -431,6 +431,8 @@ export const weaponParams = {
VerticalSwingUnitGroupParam_DamageParam_DamageMaxValue: 1200,
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 250,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1000,
InkRecoverStop_WeaponVerticalSwingParam: 45,
InkRecoverStop_WeaponWideSwingParam: 40,
InkConsume_WeaponSwingParam: 0.0396,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
@@ -445,6 +447,8 @@ export const weaponParams = {
VerticalSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 350,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
InkRecoverStop_WeaponVerticalSwingParam: 58,
InkRecoverStop_WeaponWideSwingParam: 43,
InkConsume_WeaponSwingParam: 0.085,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
@@ -460,6 +464,8 @@ export const weaponParams = {
VerticalSwingUnitGroupParam_DamageParam_DamageMaxValue: 1800,
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 400,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1800,
InkRecoverStop_WeaponVerticalSwingParam: 70,
InkRecoverStop_WeaponWideSwingParam: 55,
InkConsume_WeaponSwingParam: 0.21,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
},
@@ -474,6 +480,8 @@ export const weaponParams = {
VerticalSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 300,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 1500,
InkRecoverStop_WeaponVerticalSwingParam: 65,
InkRecoverStop_WeaponWideSwingParam: 45,
InkConsume_WeaponVerticalSwingParam: 0.12,
InkConsume_WeaponWideSwingParam: 0.08,
InkConsumeMaxPerFrame_WeaponRollParam: 0.001,
@@ -489,6 +497,8 @@ export const weaponParams = {
VerticalSwingUnitGroupParam_DamageParam_DamageMaxValue: 1200,
WideSwingUnitGroupParam_DamageParam_DamageMinValue: 400,
WideSwingUnitGroupParam_DamageParam_DamageMaxValue: 700,
InkRecoverStop_WeaponVerticalSwingParam: 50,
InkRecoverStop_WeaponWideSwingParam: 45,
InkConsume_WeaponSwingParam: 0.09,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0005,
},
@@ -500,6 +510,7 @@ export const weaponParams = {
BodyParam_Damage: 200,
SwingUnitGroupParam_DamageParam_DamageMinValue: 150,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 300,
InkRecoverStop: 30,
InkConsume_WeaponSwingParam: 0.02,
InkConsumeMaxPerFrame_WeaponRollParam: 0.00125,
},
@@ -510,6 +521,7 @@ export const weaponParams = {
BodyParam_Damage: 250,
SwingUnitGroupParam_DamageParam_DamageMinValue: 200,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 400,
InkRecoverStop: 30,
InkConsume_WeaponSwingParam: 0.027,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0015,
},
@@ -520,6 +532,7 @@ export const weaponParams = {
BodyParam_Damage: 300,
SwingUnitGroupParam_DamageParam_DamageMinValue: 310,
SwingUnitGroupParam_DamageParam_DamageMaxValue: 600,
InkRecoverStop: 50,
InkConsume_WeaponSwingParam: 0.048,
InkConsumeMaxPerFrame_WeaponRollParam: 0.0018,
},
@@ -973,6 +986,7 @@ export const weaponParams = {
MoveSpeed: 0.05,
DamageParam_ValueMax: 1190,
CanopyHP: 7000,
InkRecoverStop: 70,
InkConsumeUmbrella_WeaponShelterCanopyParam: 0.23,
InkConsume_WeaponShelterShotgunParam: 0.11,
},
@@ -985,6 +999,7 @@ export const weaponParams = {
MoveSpeed: 0.072,
DamageParam_ValueMax: 400,
CanopyHP: 2000,
InkRecoverStop: 40,
InkConsume_WeaponShelterShotgunParam: 0.037,
},
"6030": {
@@ -995,6 +1010,7 @@ export const weaponParams = {
MoveSpeed: 0.058,
DamageParam_ValueMax: 900,
CanopyHP: 1500,
InkRecoverStop: 50,
InkConsumeUmbrella_WeaponShelterCanopyParam: 0.15,
InkConsume_WeaponShelterShotgunParam: 0.06,
},
@@ -1073,6 +1089,7 @@ export const weaponParams = {
DamageParam_SplatanaVertical: 700,
DamageParam_SplatanaHorizontalDirect: 550,
DamageParam_SplatanaHorizontal: 350,
InkRecoverStop: 40,
InkConsume_SwingParam: 0.052,
InkConsumeFullCharge_ChargeParam: 0.117,
},
@@ -1090,6 +1107,7 @@ export const weaponParams = {
DamageParam_SplatanaVertical: 600,
DamageParam_SplatanaHorizontalDirect: 450,
DamageParam_SplatanaHorizontal: 300,
InkRecoverStop: 30,
InkConsume_SwingParam: 0.03,
InkConsumeFullCharge_ChargeParam: 0.06,
},
@@ -1106,6 +1124,7 @@ export const weaponParams = {
DamageParam_SplatanaVertical: 800,
DamageParam_SplatanaHorizontalDirect: 700,
DamageParam_SplatanaHorizontal: 400,
InkRecoverStop: 50,
InkConsume_SwingParam: 0.065,
InkConsumeFullCharge_ChargeParam: 0.13,
},

View File

@@ -235,6 +235,26 @@ function BuildAnalyzerPage() {
suffix={t("analyzer:suffix.seconds")}
/>
) : null,
typeof analyzed.stats.mainWeaponWhiteInkSecondsHorizontalSwing ===
"number" ? (
<StatCard
context={context}
key="whiteInkSecondsHorizontalSwing"
stat={analyzed.stats.mainWeaponWhiteInkSecondsHorizontalSwing}
title={t("analyzer:stat.whiteInk.horizontalSwing")}
suffix={t("analyzer:suffix.seconds")}
/>
) : null,
typeof analyzed.stats.mainWeaponWhiteInkSecondsVerticalSwing ===
"number" ? (
<StatCard
context={context}
key="whiteInkSecondsVerticalSwing"
stat={analyzed.stats.mainWeaponWhiteInkSecondsVerticalSwing}
title={t("analyzer:stat.whiteInk.verticalSwing")}
suffix={t("analyzer:suffix.seconds")}
/>
) : null,
typeof analyzed.weapon.brellaCanopyHp === "number" ? (
<StatCard
context={context}

View File

@@ -0,0 +1,5 @@
---
navItem: analyzer
type: bug
---
Build analyzer now shows the no ink recovery time for brushes, rollers, splatanas and brellas

View File

@@ -27,6 +27,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Midlertidig pause for blækpåfyldning efter brug",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Blækforbrug",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -27,6 +27,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Dauer keiner Tintenregeneration nach Nutzung",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Tintentankverbrauch",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -27,6 +27,8 @@
"stat.tenacitySecondsToSpecial_other": "Time to special with Tenacity ({{count}} down)",
"stat.tenacitySecondsToSpecial.explanation": "How long it takes Tenacity to fill the special gauge from empty while your team has that many fewer active players than the opponent's team, e.g. {{teamPlayerCount}}v{{opponentPlayerCount}}. Only the difference between the teams matters, so an even matchup such as 3v3 does not charge the gauge at all.",
"stat.whiteInk": "No ink recovery time after usage",
"stat.whiteInk.horizontalSwing": "No ink recovery time after horizontal swing",
"stat.whiteInk.verticalSwing": "No ink recovery time after vertical swing",
"stat.subWeaponInkConsumptionPercentage": "Ink tank consumption",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "Consumption per shot",
"stat.mainWeaponInkConsumptionPercentage.SWING": "Consumption per swing",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "Tiempo para el especial con Ventaja ({{count}} menos)",
"stat.tenacitySecondsToSpecial.explanation": "El tiempo que tarda Ventaja en llenar el medidor especial desde cero mientras tu equipo tiene menos jugadores activos que el rival, ej. {{teamPlayerCount}} contra {{opponentPlayerCount}}. Solo importa la diferencia entre los equipos, por lo que un duelo igualado como 3 contra 3 no carga el medidor en absoluto.",
"stat.whiteInk": "Tiempo sin recuperar tinta después de su uso",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consumo del tanque de tinta",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "Consumo por disparo",
"stat.mainWeaponInkConsumptionPercentage.SWING": "Consumo por ataque",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "Tiempo para el especial con Tenacidad ({{count}} menos)",
"stat.tenacitySecondsToSpecial.explanation": "El tiempo que tarda Tenacidad en llenar el medidor especial desde cero mientras tu equipo tiene menos jugadores activos que el rival, ej. {{teamPlayerCount}} contra {{opponentPlayerCount}}. Solo importa la diferencia entre los equipos, por lo que un duelo igualado como 3 contra 3 no carga el medidor en absoluto.",
"stat.whiteInk": "Tiempo sin recuperar tinta después de uso",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consumo del tanque de tinta",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "Consumo por disparo",
"stat.mainWeaponInkConsumptionPercentage.SWING": "Consumo por ataque",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Délai avant recharge de l'encre",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consommation du réservoir d'encre",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Délai avant recharge de l'encre",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consommation du réservoir d'encre",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "זמן ללא שחזור דיו לאחר שימוש",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "צריכת דיו מהמיכל",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Tempo senza ricarica inchiostro dopo l'utilizzo",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consumo serbatoio inchisotro",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -25,6 +25,8 @@
"stat.specialLostSplattedByRP": "復活ペナルティアップ付きでやられた場合に失うスペシャルポイント数",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "インクロック",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "インクタンク消費量(%)",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -25,6 +25,8 @@
"stat.specialLostSplattedByRP": "페널티 유저에게 쓰러졌을 대 잃는 스페셜 포인트",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "사용 이후 잉크 회복 불가 시간",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "잉크 소모 비율",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -27,6 +27,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Vertraging van inktvulling na gebruik",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -29,6 +29,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Brak czasu regeneracji farby po użyciu",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Konsumpcja zbiornika farbowego",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -28,6 +28,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Tempo sem recarga de tinta após o uso",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Consumo do tanque de tinta",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -29,6 +29,8 @@
"stat.tenacitySecondsToSpecial_other": "",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "Время до начала восстановления краски после использования",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "Потребление чернил",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -25,6 +25,8 @@
"stat.specialLostSplattedByRP": "被死惩使用者击倒时的特殊武器点数损失",
"stat.tenacitySecondsToSpecial.explanation": "",
"stat.whiteInk": "使用后回墨间隔",
"stat.whiteInk.horizontalSwing": "",
"stat.whiteInk.verticalSwing": "",
"stat.subWeaponInkConsumptionPercentage": "耗墨量",
"stat.mainWeaponInkConsumptionPercentage.NORMAL": "",
"stat.mainWeaponInkConsumptionPercentage.SWING": "",

View File

@@ -627,7 +627,15 @@ function parametersToMainWeaponResult(
Variable_Stand_DegSwerve:
params.VariableWeaponParam?.Stand_DegSwerve ??
params.VariableShotParam?.Stand_DegSwerve,
InkRecoverStop: params.WeaponParam?.InkRecoverStop,
InkRecoverStop:
params.WeaponParam?.InkRecoverStop ??
params.WeaponSwingParam?.InkRecoverStop ??
params.spl__WeaponSaberParam?.SwingParam?.InkRecoverStop ??
params.spl__WeaponShelterShotgunParam?.InkRecoverStop,
InkRecoverStop_WeaponVerticalSwingParam:
params.WeaponVerticalSwingParam?.InkRecoverStop,
InkRecoverStop_WeaponWideSwingParam:
params.WeaponWideSwingParam?.InkRecoverStop,
InkConsume,
InkConsumeVariable: params.VariableWeaponParam?.InkConsume,
InkConsumeSlosher,