Introduce constants for repeated ids

This commit is contained in:
Jan Bader
2026-06-17 22:34:43 +02:00
parent 019bb5f860
commit 84959d2e8b
+29 -24
View File
@@ -18,14 +18,19 @@ const EFFECTS = [
{ id: "health", label: "Health", cap: 15, group: "defense" },
];
const PROFILE_IDS = Object.freeze({ LIFESTEAL: "lifesteal", REGEN: "regen" });
const COMBAT_STYLES = Object.freeze({ MELEE: "melee", RANGED: "ranged", SKILL: "skill" });
const PIECE_TYPES = Object.freeze({ ITEM: "item", MOUNT: "mount", PET: "pet", SKILL: "skill" });
const REPLACEMENT_TARGETS = Object.freeze({ MOUNT: "mount", PET: "pet" });
const PROFILES = {
lifesteal: {
[PROFILE_IDS.LIFESTEAL]: {
label: "Lifesteal (DPS + Lifesteal)",
weights: { critChance: 10, critDamage: 6, blockChance: 2, healthRegen: 2, lifesteal: 10, doubleChance: 10, damage: 10, meleeDamage: 6, rangedDamage: 6, attackSpeed: 9, skillDamage: 7, skillCooldown: 7, health: 3 },
baseDamage: 1.25,
baseHealth: 0.45,
},
regen: {
[PROFILE_IDS.REGEN]: {
label: "Regen (Health + Regen)",
weights: { critChance: 4, critDamage: 2, blockChance: 7, healthRegen: 12, lifesteal: 5, doubleChance: 4, damage: 4, meleeDamage: 2, rangedDamage: 2, attackSpeed: 3, skillDamage: 3, skillCooldown: 3, health: 12 },
baseDamage: 0.45,
@@ -47,10 +52,10 @@ const FIXED_ITEMS = [
{ name: "Belt", baseType: "health", baseValue: 1150000 },
];
const slots = [
...FIXED_ITEMS.map((item, i) => ({ type: "item", title: `Item ${i + 1}`, fixed: item })),
{ type: "mount", title: "Mount" },
...Array.from({ length: 3 }, (_, i) => ({ type: "pet", title: `Pet ${i + 1}` })),
{ type: "skill", title: "Skill", noEffects: true },
...FIXED_ITEMS.map((item, i) => ({ type: PIECE_TYPES.ITEM, title: `Item ${i + 1}`, fixed: item })),
{ type: PIECE_TYPES.MOUNT, title: "Mount" },
...Array.from({ length: 3 }, (_, i) => ({ type: PIECE_TYPES.PET, title: `Pet ${i + 1}` })),
{ type: PIECE_TYPES.SKILL, title: "Skill", noEffects: true },
];
const $ = (selector) => document.querySelector(selector);
@@ -65,8 +70,8 @@ let state = loadDraft() || createDefaultState();
function createDefaultState() {
return {
profile: "lifesteal",
combatStyle: "melee",
profile: PROFILE_IDS.LIFESTEAL,
combatStyle: COMBAT_STYLES.MELEE,
recommendationCount: 8,
pieces: slots.map((slot, index) => createDefaultPiece(slot, index)),
newItem: createDefaultNewItem(),
@@ -101,7 +106,7 @@ function createDefaultPiece(slot, index) {
function enforceFixedPieceFields(piece, index) {
const fixed = FIXED_ITEMS[index];
if (!fixed || piece.type !== "item") return piece;
if (!fixed || piece.type !== PIECE_TYPES.ITEM) return piece;
const baseValue = Number(piece.baseValue || (fixed.baseType === "damage" ? piece.baseDamage : piece.baseHealth) || fixed.baseValue);
return {
...piece,
@@ -121,7 +126,7 @@ function normalizeState(candidate) {
...fallback,
...candidate,
profile,
combatStyle: ["melee", "ranged", "skill"].includes(candidate?.combatStyle) ? candidate.combatStyle : "melee",
combatStyle: Object.values(COMBAT_STYLES).includes(candidate?.combatStyle) ? candidate.combatStyle : COMBAT_STYLES.MELEE,
recommendationCount: Math.min(20, Math.max(3, Number(candidate?.recommendationCount || 8))),
newItem: normalizeNewItem(candidate?.newItem),
pieces: fallback.pieces.map((piece, index) => normalizePiece(piece, candidate?.pieces?.[index], index)),
@@ -167,9 +172,9 @@ function normalizeEffects(candidateEffects) {
function normalizeProfile(profile) {
if (PROFILES[profile]) return profile;
if (["damage", "skill", "balanced"].includes(profile)) return "lifesteal";
if (profile === "survival") return "regen";
return "lifesteal";
if (["damage", "skill", "balanced"].includes(profile)) return PROFILE_IDS.LIFESTEAL;
if (profile === "survival") return PROFILE_IDS.REGEN;
return PROFILE_IDS.LIFESTEAL;
}
function clampEffectValue(type, value) {
@@ -193,8 +198,8 @@ function render() {
function getReplacementOptions() {
return [
...FIXED_ITEMS.map((item, index) => ({ value: `item-${index}`, label: item.name })),
{ value: "mount", label: "Mount" },
{ value: "pet", label: "Pet (worst current pet)" },
{ value: REPLACEMENT_TARGETS.MOUNT, label: "Mount" },
{ value: REPLACEMENT_TARGETS.PET, label: "Pet (worst current pet)" },
];
}
@@ -430,10 +435,10 @@ function getReplacementTargetPiece(target, pieceScores) {
const pinned = state.pieces.find((piece) => piece.id === state.newItem.targetPieceId);
if (pinned) return pinned;
}
if (target === "mount") return state.pieces.find((piece) => piece.type === "mount") || null;
if (target === "pet") {
if (target === REPLACEMENT_TARGETS.MOUNT) return state.pieces.find((piece) => piece.type === PIECE_TYPES.MOUNT) || null;
if (target === REPLACEMENT_TARGETS.PET) {
return [...pieceScores]
.filter(({ piece }) => piece.type === "pet")
.filter(({ piece }) => piece.type === PIECE_TYPES.PET)
.sort((a, b) => a.score - b.score)[0]?.piece || null;
}
const fixed = /^item-(\d+)$/.exec(target || "");
@@ -446,7 +451,7 @@ function createNewItemCandidate(target) {
const fixedBaseHealth = fixed?.baseType === "health" ? Number(state.newItem.baseHealth || fixed.baseValue) : 0;
return {
id: "new-item",
type: target === "mount" ? "mount" : target === "pet" ? "pet" : "item",
type: target === REPLACEMENT_TARGETS.MOUNT ? PIECE_TYPES.MOUNT : target === REPLACEMENT_TARGETS.PET ? PIECE_TYPES.PET : PIECE_TYPES.ITEM,
name: "New item",
baseDamage: fixed ? fixedBaseDamage : Number(state.newItem.baseDamage || 0),
baseHealth: fixed ? fixedBaseHealth : Number(state.newItem.baseHealth || 0),
@@ -524,11 +529,11 @@ function deltaClass(value) {
return "delta-neutral";
}
function calculateDps(totals, combatStyle = "melee") {
function calculateDps(totals, combatStyle = COMBAT_STYLES.MELEE) {
return calculateDamageDetails(totals, combatStyle).dps;
}
function calculateDamageDetails(totals, combatStyle = "melee") {
function calculateDamageDetails(totals, combatStyle = COMBAT_STYLES.MELEE) {
const effects = totals.effects;
const baseDamage = Math.max(0, totals.baseDamage);
const globalDamage = 1 + effects.damage / 100;
@@ -540,7 +545,7 @@ function calculateDamageDetails(totals, combatStyle = "melee") {
const critDamage = effects.critDamage / 100;
const crit = 1 + critChance * critDamage;
const critHit = singleHit * (1 + critDamage);
const cooldown = combatStyle === "skill" ? 1 / Math.max(0.05, 1 - effects.skillCooldown / 100) : 1;
const cooldown = combatStyle === COMBAT_STYLES.SKILL ? 1 / Math.max(0.05, 1 - effects.skillCooldown / 100) : 1;
return {
singleHit,
critHit,
@@ -570,8 +575,8 @@ function calculateRegenDetails(totals, dps) {
}
function getStyleDamageBonus(effects, combatStyle) {
if (combatStyle === "ranged") return effects.rangedDamage;
if (combatStyle === "skill") return effects.skillDamage;
if (combatStyle === COMBAT_STYLES.RANGED) return effects.rangedDamage;
if (combatStyle === COMBAT_STYLES.SKILL) return effects.skillDamage;
return effects.meleeDamage;
}