From 2ba9f62d418a484fadd34d963331a97d8e1dbe3b Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 10 Dec 2022 19:45:42 +0200 Subject: [PATCH] Obj DMG Calc: special cases calculation data driven --- app/modules/analyzer/constants.ts | 43 +++++++++++++++- app/modules/analyzer/objectDamage.ts | 73 +++++++++------------------- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/app/modules/analyzer/constants.ts b/app/modules/analyzer/constants.ts index bec5dd245..505f59656 100644 --- a/app/modules/analyzer/constants.ts +++ b/app/modules/analyzer/constants.ts @@ -1,6 +1,7 @@ import type { DamageType } from "./types"; import type objectDamages from "./object-dmg.json"; -import type { MainWeaponId } from "../in-game-lists"; +import { type MainWeaponId, mainWeaponIds } from "../in-game-lists"; +import invariant from "tiny-invariant"; export const MAX_LDE_INTENSITY = 21; export const MAX_AP = 57; @@ -169,6 +170,46 @@ export const objectDamageJsonKeyPriority: Record< UltraStamp_Throw: null, }; +export const damageTypesToCombine: Partial< + Record< + MainWeaponId, + Array<{ + when: DamageType; + combineWith: DamageType; + /** for this weapon "when" damage already includes "combineWith" damage, so calculating multiplier only */ + multiplierOnly?: boolean; + }> + > +> = { + // Splatana Stamper + 8000: [ + { when: "SPLATANA_VERTICAL_DIRECT", combineWith: "SPLATANA_VERTICAL" }, + { + when: "SPLATANA_HORIZONTAL_DIRECT", + combineWith: "SPLATANA_HORIZONTAL", + multiplierOnly: true, + }, + ], + // Splatana Wiper + 8010: [ + { when: "SPLATANA_VERTICAL_DIRECT", combineWith: "SPLATANA_VERTICAL" }, + { + when: "SPLATANA_HORIZONTAL_DIRECT", + combineWith: "SPLATANA_HORIZONTAL", + multiplierOnly: true, + }, + ], +}; +invariant( + mainWeaponIds.every((id) => { + // not Splatana + if (id < 8000 || id >= 9000) return true; + + return Boolean(damageTypesToCombine[id]); + }), + "Splatana weapon missing from damageTypesToCombine" +); + export const multiShot: Partial> = { // L-3 300: 3, diff --git a/app/modules/analyzer/objectDamage.ts b/app/modules/analyzer/objectDamage.ts index 7a097bce4..bb191a851 100644 --- a/app/modules/analyzer/objectDamage.ts +++ b/app/modules/analyzer/objectDamage.ts @@ -11,6 +11,7 @@ import type { SubWeaponId, } from "../in-game-lists"; import { + damageTypesToCombine, damageTypeToWeaponType, DAMAGE_RECEIVERS, objectDamageJsonKeyPriority, @@ -114,21 +115,12 @@ export function calculateDamage({ damageType: DamageType; isMultiShot: boolean; }) { + const toCombine = (damageTypesToCombine[mainWeaponId] ?? []).find( + (c) => c.when === damageType + ); + const filteredDamages = analyzed.stats.damages - .filter( - (d) => - d.type === damageType || - // Splatana direct seems to use two damage sources - // The way Splatana damage works is a bit confusing: - // Vertical Direct = Vertical + Vertical Direct damage vs. Objects only - // Horizontal Direct = Horizontal + Horizontal Direct damage vs. both objects and players both - // so that's why Horizontal Direct damage has these baked in while - // with Vertical Direct we add them here in not so clean manner - (damageType === "SPLATANA_VERTICAL_DIRECT" && - d.type === "SPLATANA_VERTICAL") || - (damageType === "SPLATANA_HORIZONTAL_DIRECT" && - d.type === "SPLATANA_HORIZONTAL") - ) + .filter((d) => d.type === damageType || toCombine?.combineWith === d.type) .map((damage) => { if (!isMultiShot || !damage.multiShots) return damage; @@ -173,66 +165,45 @@ export function calculateDamage({ { ...damage, objectShredder: true }, ]) .flatMap((damage) => { - if ( - (damageType === "SPLATANA_VERTICAL_DIRECT" && - damage.type === "SPLATANA_VERTICAL") || - (damageType === "SPLATANA_HORIZONTAL_DIRECT" && - damage.type === "SPLATANA_HORIZONTAL") - ) { + if (toCombine?.combineWith === damage.type) { return []; } - const splatanaDmg = (type: "VERTICAL" | "HORIZONTAL") => { - const key = - type === "VERTICAL" ? "SPLATANA_VERTICAL" : "SPLATANA_HORIZONTAL"; - const splatanaVerticalDamage = filteredDamages.find( - (damage) => damage.type === key - ); - invariant(splatanaVerticalDamage); + const otherDamage = () => { + const result = filteredDamages.find( + (damage) => damage.type === toCombine?.combineWith + )?.value; + invariant(result); - return splatanaVerticalDamage.value; + return result; }; const dmg = () => { - if (damageType === "SPLATANA_VERTICAL_DIRECT") { - return damage.value + splatanaDmg("VERTICAL"); + if (toCombine && !toCombine?.multiplierOnly) { + return damage.value + otherDamage(); } return damage.value; }; const baseMultiplier = () => { const normalMultiplier = multipliers[damage.type]![receiver]; - if ( - [ - "SPLATANA_VERTICAL_DIRECT", - "SPLATANA_HORIZONTAL_DIRECT", - ].includes(damageType) - ) { - const otherDamageKey = - damageType === "SPLATANA_VERTICAL_DIRECT" - ? "SPLATANA_VERTICAL" - : "SPLATANA_HORIZONTAL"; - const otherDamage = - damageType === "SPLATANA_VERTICAL_DIRECT" - ? splatanaDmg("VERTICAL") - : splatanaDmg("HORIZONTAL"); + if (toCombine) { const actualDamage = () => { - if (damageType === "SPLATANA_HORIZONTAL_DIRECT") { + if (toCombine.multiplierOnly) { // undo "baked in" damage (see above) - return damage.value - otherDamage; + return damage.value - otherDamage(); } return damage.value; }; - const splatanaVerticalMultiplier = - multipliers[otherDamageKey]![receiver]; - invariant(splatanaVerticalMultiplier); + const otherMultiplier = + multipliers[toCombine.combineWith]![receiver]; // calculate "made up" multiplier that is taking the // weighted average of the two multipliers return ( (normalMultiplier * actualDamage() + - splatanaVerticalMultiplier * otherDamage) / - (actualDamage() + otherDamage) + otherMultiplier * otherDamage()) / + (actualDamage() + otherDamage()) ); } return normalMultiplier;