Release v0.1.4 2026-07-12

This commit is contained in:
Warren H
2026-07-12 13:49:46 -04:00
parent b48b3a4f8f
commit bef71d391a
803 changed files with 3800 additions and 358322 deletions
+36 -35
View File
@@ -1,5 +1,6 @@
import type { HealerClassId, MemberId, BossId, RunBuffId } from "../types";
import { bossCoinDrop, type DifficultySlug, type MaterialStack } from "./loot";
import type { BossGroupId } from "../bossCatalog";
import type { HealerClassId, MemberId, RunBuffId } from "../types";
import { groupDrop, type DifficultySlug, type MaterialStack } from "./loot";
export type GearOwnerId = HealerClassId | Exclude<MemberId, "aelia">;
export type GearSlotId = "weapon" | "helmet" | "chest" | "legs" | "feet";
@@ -22,8 +23,8 @@ export interface GearRecipe {
ownerId: GearOwnerId;
slotId: GearSlotId;
statId: GearStatId;
primaryBossId: BossId;
secondaryBossId: BossId;
primaryGroupId: BossGroupId;
secondaryGroupId: BossGroupId;
}
export interface GearUpgradeCost {
@@ -64,14 +65,14 @@ export const GEAR_STAT_LABELS: Record<GearStatId, string> = {
hazardDamageTaken: "Hazard Damage Taken",
};
type RecipeSeed = Record<GearSlotId, readonly [BossId, BossId]>;
type RecipeSeed = Record<GearSlotId, readonly [BossGroupId, BossGroupId]>;
const HEALER_RECIPES: RecipeSeed = {
weapon: ["vexa", "cindermaw"],
helmet: ["cinderback-ricochet", "sandglass-scorpion"],
chest: ["obsidian-ram-golem", "bulldrome"],
legs: ["ember-mantis-duelist", "cinderback-ricochet"],
feet: ["vexa", "sandglass-scorpion"],
weapon: ["bind-venom", "breath-skyfall"],
helmet: ["ricochet", "burrow-eruption"],
chest: ["charge", "shockwave-fall"],
legs: ["slash-cross", "ricochet"],
feet: ["bind-venom", "burrow-eruption"],
};
const OWNER_RECIPE_SEEDS: Record<GearOwnerId, RecipeSeed> = {
@@ -79,32 +80,32 @@ const OWNER_RECIPE_SEEDS: Record<GearOwnerId, RecipeSeed> = {
druid: HEALER_RECIPES,
shaman: HEALER_RECIPES,
brann: {
weapon: ["obsidian-ram-golem", "bulldrome"],
helmet: ["ember-mantis-duelist", "sandglass-scorpion"],
chest: ["obsidian-ram-golem", "cindermaw"],
legs: ["bulldrome", "cinderback-ricochet"],
feet: ["sandglass-scorpion", "vexa"],
weapon: ["charge", "scuttle-burst"],
helmet: ["slash-cross", "burrow-eruption"],
chest: ["charge", "breath-skyfall"],
legs: ["charge", "ricochet"],
feet: ["burrow-eruption", "bind-venom"],
},
nia: {
weapon: ["cinderback-ricochet", "cindermaw"],
helmet: ["vexa", "sandglass-scorpion"],
chest: ["bulldrome", "obsidian-ram-golem"],
legs: ["cinderback-ricochet", "ember-mantis-duelist"],
feet: ["sandglass-scorpion", "vexa"],
weapon: ["ricochet", "breath-skyfall"],
helmet: ["bind-venom", "burrow-eruption"],
chest: ["charge", "rift-lanes"],
legs: ["ricochet", "slash-cross"],
feet: ["burrow-eruption", "bind-venom"],
},
orin: {
weapon: ["cindermaw", "vexa"],
helmet: ["sandglass-scorpion", "cinderback-ricochet"],
chest: ["vexa", "obsidian-ram-golem"],
legs: ["cinderback-ricochet", "ember-mantis-duelist"],
feet: ["sandglass-scorpion", "bulldrome"],
weapon: ["breath-skyfall", "bind-venom"],
helmet: ["burrow-eruption", "ricochet"],
chest: ["bind-venom", "charge"],
legs: ["ricochet", "slash-cross"],
feet: ["burrow-eruption", "charge"],
},
vale: {
weapon: ["ember-mantis-duelist", "cindermaw"],
helmet: ["cinderback-ricochet", "sandglass-scorpion"],
chest: ["bulldrome", "obsidian-ram-golem"],
legs: ["ember-mantis-duelist", "cinderback-ricochet"],
feet: ["vexa", "sandglass-scorpion"],
weapon: ["slash-cross", "breath-skyfall"],
helmet: ["ricochet", "burrow-eruption"],
chest: ["charge", "rift-lanes"],
legs: ["slash-cross", "ricochet"],
feet: ["bind-venom", "burrow-eruption"],
},
};
@@ -119,8 +120,8 @@ function statFor(ownerId: GearOwnerId, slotId: GearSlotId): GearStatId {
export const GEAR_RECIPES = Object.fromEntries(GEAR_OWNER_ORDER.map((ownerId) => [
ownerId,
Object.fromEntries(GEAR_SLOT_ORDER.map((slotId) => {
const [primaryBossId, secondaryBossId] = OWNER_RECIPE_SEEDS[ownerId][slotId];
return [slotId, { ownerId, slotId, statId: statFor(ownerId, slotId), primaryBossId, secondaryBossId }];
const [primaryGroupId, secondaryGroupId] = OWNER_RECIPE_SEEDS[ownerId][slotId];
return [slotId, { ownerId, slotId, statId: statFor(ownerId, slotId), primaryGroupId, secondaryGroupId }];
})),
])) as Record<GearOwnerId, Record<GearSlotId, GearRecipe>>;
@@ -140,8 +141,8 @@ export function gearUpgradeCosts(ownerId: GearOwnerId, slotId: GearSlotId, curre
const nextLevel = currentLevel + 1 as Exclude<GearLevel, 0>;
const recipe = GEAR_RECIPES[ownerId][slotId];
const difficultySlug = upgradeDifficultySlug(nextLevel);
const primary = bossCoinDrop(recipe.primaryBossId, difficultySlug);
const secondary = bossCoinDrop(recipe.secondaryBossId, difficultySlug);
const primary = groupDrop(recipe.primaryGroupId, difficultySlug);
const secondary = groupDrop(recipe.secondaryGroupId, difficultySlug);
if (nextLevel === 1) return [{ itemId: primary.id, itemName: primary.name, quantity: 2 }];
const primaryQuantity = nextLevel <= 3 ? 3 : nextLevel <= 5 ? nextLevel : nextLevel;
const secondaryQuantity = nextLevel === 2 ? 1 : nextLevel === 3 ? 2 : nextLevel - 1;
@@ -204,7 +205,7 @@ function formatPercent(value: number): string {
return Number.isInteger(value) ? String(value) : value.toFixed(1);
}
// IWT2 parity: +6 through +10 return to Veteran coins while infusion costs use higher tiers.
// IWT2 parity: +6 through +10 return to Veteran drops while infusion costs use higher tiers.
function upgradeDifficultySlug(level: Exclude<GearLevel, 0>): DifficultySlug {
if (level <= 2) return "initiate";
if (level >= 6) return "veteran";