swap to dynamic empty and total mod counting

This commit is contained in:
kvan7
2026-06-11 22:33:33 -05:00
parent 89c3fe96df
commit 597257e523
2 changed files with 174 additions and 67 deletions
@@ -0,0 +1,120 @@
import { ItemRarity, ParsedItem } from "@/parser/ParsedItem";
import { __testExports } from "@/web/price-check/filters/create-stat-filters";
import { describe, expect, it } from "vitest";
import { createTestItem } from "@specs/helper";
import { StatFilterRoll } from "@/web/price-check/filters/interfaces";
describe("item mod count tests", () => {
it.each([
[ItemRarity.Normal, 0],
[ItemRarity.Magic, 1],
[ItemRarity.Rare, 3],
])("%#. Should return correct base for %s", (rarity, expected) => {
const item: ParsedItem = {
...createTestItem(),
rarity,
};
const res = __testExports.itemMaxModifiersBySlot(item, []);
expect(res).toEqual([expected * 2, expected, expected]);
});
function createTestStatByRef(
ref: string,
roll: number,
): { statRef: string; roll: StatFilterRoll } {
return {
statRef: ref,
roll: {
value: roll,
} as unknown as StatFilterRoll,
};
}
it.each([
[ItemRarity.Rare, [], 3, 3],
[ItemRarity.Rare, [{ ref: "# to all Attributes", roll: 1 }], 3, 3],
[ItemRarity.Magic, [{ ref: "# Suffix Modifier allowed", roll: 2 }], 1, 3],
[ItemRarity.Magic, [{ ref: "# Prefix Modifier allowed", roll: -1 }], 0, 1],
[ItemRarity.Rare, [{ ref: "# Suffix Modifier allowed", roll: 2 }], 3, 5],
[ItemRarity.Rare, [{ ref: "# Suffix Modifier allowed", roll: 1 }], 3, 4],
[ItemRarity.Rare, [{ ref: "# Suffix Modifier allowed", roll: -1 }], 3, 2],
[ItemRarity.Rare, [{ ref: "# Suffix Modifier allowed", roll: -2 }], 3, 1],
[ItemRarity.Rare, [{ ref: "# Suffix Modifier allowed", roll: -3 }], 3, 0],
[ItemRarity.Rare, [{ ref: "# Prefix Modifier allowed", roll: 2 }], 5, 3],
[ItemRarity.Rare, [{ ref: "# Prefix Modifier allowed", roll: 1 }], 4, 3],
[ItemRarity.Rare, [{ ref: "# Prefix Modifier allowed", roll: -1 }], 2, 3],
[ItemRarity.Rare, [{ ref: "# Prefix Modifier allowed", roll: -2 }], 1, 3],
[ItemRarity.Rare, [{ ref: "# Prefix Modifier allowed", roll: -3 }], 0, 3],
[
ItemRarity.Rare,
[
{ ref: "# Prefix Modifier allowed", roll: 1 },
{ ref: "# Suffix Modifier allowed", roll: 1 },
],
4,
4,
],
[
ItemRarity.Rare,
[
{ ref: "# Prefix Modifier allowed", roll: 2 },
{ ref: "# Suffix Modifier allowed", roll: -1 },
],
5,
2,
],
[
ItemRarity.Rare,
[
{ ref: "# Prefix Modifier allowed", roll: -1 },
{ ref: "# Suffix Modifier allowed", roll: 2 },
],
2,
5,
],
[
ItemRarity.Rare,
[
{ ref: "# Prefix Modifier allowed", roll: -2 },
{ ref: "# Suffix Modifier allowed", roll: -2 },
],
1,
1,
],
[
ItemRarity.Rare,
[
{ ref: "# Prefix Modifier allowed", roll: -3 },
{ ref: "# Suffix Modifier allowed", roll: 2 },
],
0,
5,
],
])(
"%#. should change amount for items with stats that modify max mods",
(
rarity: ItemRarity,
stats: Array<{ ref: string; roll: number }>,
expectedPrefix,
expectedSuffix,
) => {
const item: ParsedItem = {
...createTestItem(),
rarity,
};
const res = __testExports.itemMaxModifiersBySlot(
item,
stats.map((stat) => createTestStatByRef(stat.ref, stat.roll)),
);
expect(res).toEqual([
expectedPrefix + expectedSuffix,
expectedPrefix,
expectedSuffix,
]);
},
);
});
@@ -788,9 +788,6 @@ function hideAllAugments(filters: StatFilter[]) {
}
}
// TODO
// +1 Prefix Modifier allowed
// -1 Suffix Modifier allowed
function showHasEmptyModifier(ctx: FiltersCreationContext):
| {
empty: ItemHasEmptyModifier;
@@ -803,41 +800,12 @@ function showHasEmptyModifier(ctx: FiltersCreationContext):
return false;
}
if (item.rarity === ItemRarity.Magic) {
const { prefixes: magicPrefixes, suffixes: magicSuffixes } =
explicitModifierCount(item);
if (magicPrefixes && magicSuffixes) {
return false;
}
if (magicPrefixes > 0) {
return {
empty: ItemHasEmptyModifier.Suffix,
counts: {
[ItemHasEmptyModifier.Prefix]: 0,
[ItemHasEmptyModifier.Suffix]: 1,
[ItemHasEmptyModifier.Any]: 1,
},
};
} else if (magicSuffixes > 0) {
return {
empty: ItemHasEmptyModifier.Prefix,
counts: {
[ItemHasEmptyModifier.Prefix]: 1,
[ItemHasEmptyModifier.Suffix]: 0,
[ItemHasEmptyModifier.Any]: 1,
},
};
}
// magic but has no explicit mods (annulled to 0)
return false;
}
if (item.rarity !== ItemRarity.Rare) {
if (item.rarity !== ItemRarity.Rare && item.rarity !== ItemRarity.Magic) {
return false;
}
const { prefixes, suffixes, total } = explicitModifierCount(item);
const maxAmount = itemMaxModifiersBySlot(item);
const maxAmount = itemMaxModifiersBySlot(item, ctx.filters);
if (total !== maxAmount[ItemHasEmptyModifier.Any] && total !== 0) {
const empty =
@@ -887,47 +855,66 @@ function enableGoodRolledFilters(filters: StatFilter[], abovePct: number) {
}
}
function itemMaxModifiersBySlot(item: ParsedItem) {
function itemBaseMaxModifiersOfType(
category: ItemCategory | undefined,
rarity: ItemRarity | undefined,
) {
let base;
switch (item.category) {
case ItemCategory.Jewel:
case ItemCategory.Tablet:
case ItemCategory.Relic:
case ItemCategory.SanctumRelic:
base = 2;
switch (rarity) {
case ItemRarity.Normal:
base = 0;
break;
case ItemRarity.Magic:
base = 1;
break;
default:
base = 3;
switch (category) {
case ItemCategory.Jewel:
case ItemCategory.Tablet:
case ItemCategory.Relic:
case ItemCategory.SanctumRelic:
base = 2;
break;
default:
base = 3;
break;
}
break;
}
return base;
}
function itemMaxModifiersBySlot(
item: ParsedItem,
statsAndRolls: Array<{ statRef: string; roll?: StatFilterRoll }>,
) {
const base = itemBaseMaxModifiersOfType(item.category, item.rarity);
const maxAmount = [2 * base, base, base];
// TODO: change this to be programmatic based on implicits
if (
item.info.refName === "Dusk Amulet" ||
item.info.refName === "Dusk Ring"
) {
maxAmount[ItemHasEmptyModifier.Prefix] += 1;
maxAmount[ItemHasEmptyModifier.Suffix] -= 1;
} else if (
item.info.refName === "Gloam Amulet" ||
item.info.refName === "Gloam Ring"
) {
maxAmount[ItemHasEmptyModifier.Prefix] -= 1;
maxAmount[ItemHasEmptyModifier.Suffix] += 1;
} else if (
item.info.refName === "Penumbra Amulet" ||
item.info.refName === "Penumbra Ring"
) {
maxAmount[ItemHasEmptyModifier.Prefix] += 2;
maxAmount[ItemHasEmptyModifier.Suffix] -= 2;
} else if (
item.info.refName === "Tenebrous Amulet" ||
item.info.refName === "Tenebrous Ring"
) {
maxAmount[ItemHasEmptyModifier.Prefix] -= 2;
maxAmount[ItemHasEmptyModifier.Suffix] += 2;
for (const { statRef, roll } of statsAndRolls) {
if (statRef === "# Prefix Modifier allowed") {
maxAmount[ItemHasEmptyModifier.Prefix] += roll?.value ?? 0;
} else if (statRef === "# Suffix Modifier allowed") {
maxAmount[ItemHasEmptyModifier.Suffix] += roll?.value ?? 0;
}
}
if (maxAmount[ItemHasEmptyModifier.Prefix] < 0) {
maxAmount[ItemHasEmptyModifier.Prefix] = 0;
}
if (maxAmount[ItemHasEmptyModifier.Suffix] < 0) {
maxAmount[ItemHasEmptyModifier.Suffix] = 0;
}
maxAmount[ItemHasEmptyModifier.Any] =
maxAmount[ItemHasEmptyModifier.Prefix] +
maxAmount[ItemHasEmptyModifier.Suffix];
return maxAmount;
}
// Disable since this is export for tests
// eslint-disable-next-line @typescript-eslint/naming-convention
export const __testExports = {
itemMaxModifiersBySlot,
};