From 798efb3fb6080286d941fa420f21a5e9517a1ee9 Mon Sep 17 00:00:00 2001 From: Hikari Date: Wed, 18 Mar 2026 17:38:56 -0700 Subject: [PATCH 1/2] fix: correct equipment stat regressions and purchasable item balance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full equipment audit revealed 9 items where stats were duplicated, regressed, or where purchasable items were weaker than free boss drops: - Void Conduit: 4x → 7x combat (100M essence sink was equal to zone-6 drop) - Void Edge: 2.75x → 3.25x combat (purchasable was weaker than Celestial Blade) - Astral Robe: 2.25x → 2.75x gold (boss drop was weaker than Titan's Aegis) - Philosopher's Stone: 2x → 2.25x click (duplicated Frost Crystal) - Eternal Flame: 1.15x → 1.25x gold (regressed vs Philosopher's Stone) - Celestial Focus: 2.5x → 3x click (20M essence sink was weaker than Angel's Halo) - Abyssal Tome: 3x → 3.75x gold (50M essence sink was equal to Heaven's Mantle) - Crystal Matrix: 4x → 4.75x gold (20M crystal sink was equal to Sinslayer Aegis) - Infernal Gem: 3.5x → 4x click (5M crystal sink was identical to Prism Eye) Closes #54 --- apps/api/src/data/equipment.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/api/src/data/equipment.ts b/apps/api/src/data/equipment.ts index 551035b..014ff27 100644 --- a/apps/api/src/data/equipment.ts +++ b/apps/api/src/data/equipment.ts @@ -101,7 +101,7 @@ export const defaultEquipment: Array = [ type: "weapon", }, { - bonus: { combatMultiplier: 2.75 }, + bonus: { combatMultiplier: 3.25 }, cost: { crystals: 500, essence: 2000, gold: 0 }, description: "A blade made of compressed nothingness. It does not cut — it simply unmakes.", @@ -204,7 +204,7 @@ export const defaultEquipment: Array = [ type: "armour", }, { - bonus: { goldMultiplier: 2.25 }, + bonus: { goldMultiplier: 2.75 }, description: "Woven from threads of pure starlight harvested by the Astral Wraith. Income flows like cosmic energy.", equipped: false, @@ -305,7 +305,7 @@ export const defaultEquipment: Array = [ type: "trinket", }, { - bonus: { clickMultiplier: 2, goldMultiplier: 1.25 }, + bonus: { clickMultiplier: 2.25, goldMultiplier: 1.25 }, description: "The legendary stone that grants mastery over gold and combat alike.", equipped: false, @@ -316,7 +316,7 @@ export const defaultEquipment: Array = [ type: "trinket", }, { - bonus: { clickMultiplier: 2.25, goldMultiplier: 1.15 }, + bonus: { clickMultiplier: 2.25, goldMultiplier: 1.25 }, description: "A flame that has never been extinguished, sealed in crystal by the Phoenix Lord. It burns with the power of rebirth.", equipped: false, @@ -697,7 +697,7 @@ export const defaultEquipment: Array = [ }, // ── Purchasable endgame sinks ───────────────────────────────────────────── { - bonus: { clickMultiplier: 2.5 }, + bonus: { clickMultiplier: 3 }, cost: { crystals: 0, essence: 20_000_000, gold: 0 }, description: "A lens of compressed celestial light that sharpens every strike with divine precision.", @@ -709,7 +709,7 @@ export const defaultEquipment: Array = [ type: "trinket", }, { - bonus: { goldMultiplier: 3 }, + bonus: { goldMultiplier: 3.75 }, cost: { crystals: 0, essence: 50_000_000, gold: 0 }, description: "A book written in the language of the deep — reading it aligns your guild's operations with abyssal efficiency.", @@ -721,7 +721,7 @@ export const defaultEquipment: Array = [ type: "armour", }, { - bonus: { combatMultiplier: 4 }, + bonus: { combatMultiplier: 7 }, cost: { crystals: 0, essence: 100_000_000, gold: 0 }, description: "A weapon that channels void energy — the absence of resistance makes every strike devastating.", @@ -733,7 +733,7 @@ export const defaultEquipment: Array = [ type: "weapon", }, { - bonus: { clickMultiplier: 3.5, goldMultiplier: 1.5 }, + bonus: { clickMultiplier: 4, goldMultiplier: 1.5 }, cost: { crystals: 5_000_000, essence: 0, gold: 0 }, description: "A gem forged in the heart of the Infernal Court — it burns with productivity and righteous fury in equal measure.", @@ -745,7 +745,7 @@ export const defaultEquipment: Array = [ type: "trinket", }, { - bonus: { goldMultiplier: 4 }, + bonus: { goldMultiplier: 4.75 }, cost: { crystals: 20_000_000, essence: 0, gold: 0 }, description: "Armour structured around a crystalline lattice of optimal income calculations. Every gold piece finds you faster.", -- 2.52.0 From 84be2aab8ad4a7628e09da6a702fe5ff803e5469 Mon Sep 17 00:00:00 2001 From: Hikari Date: Wed, 18 Mar 2026 18:35:05 -0700 Subject: [PATCH 2/2] feat: sort equipment by combined stat power within each slot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Equipment cards within each slot (weapon/armour/trinket) now render in ascending order of combined bonus power — the sum of all multiplier bonuses — so stronger items always appear further down the list. Hybrid items such as Volcanic Plate sort correctly without needing a per-slot primary stat. Closes #55 --- apps/web/src/components/game/equipmentPanel.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/web/src/components/game/equipmentPanel.tsx b/apps/web/src/components/game/equipmentPanel.tsx index 376df27..004bd0e 100644 --- a/apps/web/src/components/game/equipmentPanel.tsx +++ b/apps/web/src/components/game/equipmentPanel.tsx @@ -7,6 +7,7 @@ /* eslint-disable react/no-multi-comp -- Sub-component is tightly coupled to the panel */ /* eslint-disable max-lines-per-function -- Complex component with many render paths */ /* eslint-disable complexity -- Complex component with many conditional render paths */ +/* eslint-disable max-lines -- Equipment panel with set bonus display and sort logic */ import { type JSX, useState } from "react"; import { useGame } from "../../context/gameContext.js"; import { EQUIPMENT_SETS } from "../../data/equipmentSets.js"; @@ -188,6 +189,20 @@ const EquipmentCard = ({ ); }; +/** + * Computes a combined power score for sorting — sum of all bonus multipliers. + * Using the sum (rather than a single stat) keeps hybrid items in sensible order. + * @param item - The equipment piece whose bonus multipliers are summed. + * @returns The combined bonus value. + */ +const equipmentPower = (item: Equipment): number => { + return ( + (item.bonus.combatMultiplier ?? 1) + + (item.bonus.goldMultiplier ?? 1) + + (item.bonus.clickMultiplier ?? 1) + ); +}; + const slotOrder: Array = [ "weapon", "armour", "trinket" ]; const slotLabel: Record = { armour: "🛡️ Armour", @@ -320,6 +335,8 @@ const EquipmentPanel = (): JSX.Element => { {slotOrder.map((slotType) => { const items = equipment.filter((item) => { return item.type === slotType && (showLocked || item.owned); + }).sort((a, b) => { + return equipmentPower(a) - equipmentPower(b); }); return (
-- 2.52.0