Obj DMG Calc: special cases calculation data driven

This commit is contained in:
Kalle
2022-12-10 19:45:42 +02:00
parent 3caecef855
commit 2ba9f62d41
2 changed files with 64 additions and 52 deletions

View File

@@ -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<Record<MainWeaponId, number>> = {
// L-3
300: 3,

View File

@@ -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;