generated from nhcarrigan/template
feat: add equipment set bonuses and boss bounty runestones
- Define EquipmentSet type + computeSetBonuses utility in packages/types - Add setId field to Equipment type and assign sets to 27 equipment items - Create 9 named equipment sets (Iron Vanguard → Eternal Throne) with 2pc/3pc bonuses - Apply set combat multiplier in boss route - Apply set gold/click multipliers in tick engine and click handler - Include set bonuses in anti-cheat delta validation - Show active set bonus strip + set badge per card in EquipmentPanel - Add boss first-kill bounty runestones (scaling 1–10 per boss tier) - Update AboutPanel and IDEAS.md
This commit is contained in:
@@ -18,6 +18,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["iron_sword", "chainmail", "mages_focus"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "verdant_vale",
|
||||
bountyRunestones: 1,
|
||||
},
|
||||
{
|
||||
id: "lich_queen",
|
||||
@@ -35,6 +36,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["enchanted_blade", "plate_armour", "arcane_orb"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "verdant_vale",
|
||||
bountyRunestones: 2,
|
||||
},
|
||||
{
|
||||
id: "forest_giant",
|
||||
@@ -52,6 +54,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["hide_armour"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "verdant_vale",
|
||||
bountyRunestones: 3,
|
||||
},
|
||||
// ── Shattered Ruins ───────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -70,6 +73,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shattered_ruins",
|
||||
bountyRunestones: 3,
|
||||
},
|
||||
{
|
||||
id: "bone_colossus",
|
||||
@@ -87,6 +91,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["frost_rune"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shattered_ruins",
|
||||
bountyRunestones: 5,
|
||||
},
|
||||
{
|
||||
id: "elder_dragon",
|
||||
@@ -104,6 +109,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["vorpal_sword", "dragon_scale"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shattered_ruins",
|
||||
bountyRunestones: 7,
|
||||
},
|
||||
// ── Shadow Marshes ────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -122,6 +128,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shadow_marshes",
|
||||
bountyRunestones: 5,
|
||||
},
|
||||
{
|
||||
id: "plague_lord",
|
||||
@@ -139,6 +146,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["runestone_amulet"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shadow_marshes",
|
||||
bountyRunestones: 8,
|
||||
},
|
||||
{
|
||||
id: "mud_kraken",
|
||||
@@ -156,6 +164,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["crystal_shard"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "shadow_marshes",
|
||||
bountyRunestones: 10,
|
||||
},
|
||||
// ── Frozen Peaks ──────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -174,6 +183,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "frozen_peaks",
|
||||
bountyRunestones: 8,
|
||||
},
|
||||
{
|
||||
id: "ice_queen",
|
||||
@@ -191,6 +201,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["frost_crystal"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "frozen_peaks",
|
||||
bountyRunestones: 12,
|
||||
},
|
||||
{
|
||||
id: "void_titan",
|
||||
@@ -208,6 +219,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["philosophers_stone"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "frozen_peaks",
|
||||
bountyRunestones: 15,
|
||||
},
|
||||
// ── Volcanic Depths ───────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -226,6 +238,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["flame_lance"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "volcanic_depths",
|
||||
bountyRunestones: 12,
|
||||
},
|
||||
{
|
||||
id: "magma_titan",
|
||||
@@ -243,6 +256,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["volcanic_plate"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "volcanic_depths",
|
||||
bountyRunestones: 18,
|
||||
},
|
||||
{
|
||||
id: "phoenix_lord",
|
||||
@@ -260,6 +274,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["eternal_flame"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "volcanic_depths",
|
||||
bountyRunestones: 25,
|
||||
},
|
||||
// ── Astral Void (original) ────────────────────────────────────────────────
|
||||
{
|
||||
@@ -278,6 +293,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["astral_robe"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "astral_void",
|
||||
bountyRunestones: 20,
|
||||
},
|
||||
{
|
||||
id: "cosmic_horror",
|
||||
@@ -295,6 +311,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["celestial_blade"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "astral_void",
|
||||
bountyRunestones: 30,
|
||||
},
|
||||
{
|
||||
id: "the_devourer",
|
||||
@@ -312,6 +329,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["infinity_gem"],
|
||||
prestigeRequirement: 0,
|
||||
zoneId: "astral_void",
|
||||
bountyRunestones: 40,
|
||||
},
|
||||
// ── Celestial Reaches ─────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -330,6 +348,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["seraph_wing"],
|
||||
prestigeRequirement: 6,
|
||||
zoneId: "celestial_reaches",
|
||||
bountyRunestones: 30,
|
||||
},
|
||||
{
|
||||
id: "fallen_archangel",
|
||||
@@ -347,6 +366,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["angels_halo"],
|
||||
prestigeRequirement: 7,
|
||||
zoneId: "celestial_reaches",
|
||||
bountyRunestones: 40,
|
||||
},
|
||||
{
|
||||
id: "divine_judge",
|
||||
@@ -364,6 +384,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 8,
|
||||
zoneId: "celestial_reaches",
|
||||
bountyRunestones: 50,
|
||||
},
|
||||
{
|
||||
id: "celestial_titan",
|
||||
@@ -381,6 +402,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["celestial_armour"],
|
||||
prestigeRequirement: 9,
|
||||
zoneId: "celestial_reaches",
|
||||
bountyRunestones: 60,
|
||||
},
|
||||
{
|
||||
id: "the_first_light",
|
||||
@@ -398,6 +420,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["divine_edge", "heaven_mantle"],
|
||||
prestigeRequirement: 10,
|
||||
zoneId: "celestial_reaches",
|
||||
bountyRunestones: 75,
|
||||
},
|
||||
// ── Abyssal Trench ────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -416,6 +439,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["depth_blade"],
|
||||
prestigeRequirement: 9,
|
||||
zoneId: "abyssal_trench",
|
||||
bountyRunestones: 40,
|
||||
},
|
||||
{
|
||||
id: "kraken_elder",
|
||||
@@ -433,6 +457,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["leviathan_eye"],
|
||||
prestigeRequirement: 10,
|
||||
zoneId: "abyssal_trench",
|
||||
bountyRunestones: 55,
|
||||
},
|
||||
{
|
||||
id: "abyssal_colossus",
|
||||
@@ -450,6 +475,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["pressure_plate"],
|
||||
prestigeRequirement: 11,
|
||||
zoneId: "abyssal_trench",
|
||||
bountyRunestones: 70,
|
||||
},
|
||||
{
|
||||
id: "the_deep_one",
|
||||
@@ -467,6 +493,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 12,
|
||||
zoneId: "abyssal_trench",
|
||||
bountyRunestones: 85,
|
||||
},
|
||||
{
|
||||
id: "elder_abomination",
|
||||
@@ -484,6 +511,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["abyssal_edge", "abyss_shroud"],
|
||||
prestigeRequirement: 13,
|
||||
zoneId: "abyssal_trench",
|
||||
bountyRunestones: 100,
|
||||
},
|
||||
// ── Infernal Court ────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -502,6 +530,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["demon_hide"],
|
||||
prestigeRequirement: 12,
|
||||
zoneId: "infernal_court",
|
||||
bountyRunestones: 55,
|
||||
},
|
||||
{
|
||||
id: "hellfire_titan",
|
||||
@@ -519,6 +548,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["hellfire_edge"],
|
||||
prestigeRequirement: 13,
|
||||
zoneId: "infernal_court",
|
||||
bountyRunestones: 70,
|
||||
},
|
||||
{
|
||||
id: "lord_of_sin",
|
||||
@@ -536,6 +566,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["soul_gem"],
|
||||
prestigeRequirement: 14,
|
||||
zoneId: "infernal_court",
|
||||
bountyRunestones: 90,
|
||||
},
|
||||
{
|
||||
id: "infernal_sovereign",
|
||||
@@ -553,6 +584,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 15,
|
||||
zoneId: "infernal_court",
|
||||
bountyRunestones: 110,
|
||||
},
|
||||
{
|
||||
id: "the_fallen",
|
||||
@@ -570,6 +602,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["infernal_edge", "sinslayer_aegis"],
|
||||
prestigeRequirement: 16,
|
||||
zoneId: "infernal_court",
|
||||
bountyRunestones: 135,
|
||||
},
|
||||
// ── Crystalline Spire ─────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -588,6 +621,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["prism_blade"],
|
||||
prestigeRequirement: 15,
|
||||
zoneId: "crystalline_spire",
|
||||
bountyRunestones: 70,
|
||||
},
|
||||
{
|
||||
id: "crystal_drake",
|
||||
@@ -605,6 +639,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 16,
|
||||
zoneId: "crystalline_spire",
|
||||
bountyRunestones: 90,
|
||||
},
|
||||
{
|
||||
id: "the_faceted",
|
||||
@@ -622,6 +657,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["faceted_armour"],
|
||||
prestigeRequirement: 17,
|
||||
zoneId: "crystalline_spire",
|
||||
bountyRunestones: 115,
|
||||
},
|
||||
{
|
||||
id: "diamond_colossus",
|
||||
@@ -639,6 +675,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["prism_eye"],
|
||||
prestigeRequirement: 18,
|
||||
zoneId: "crystalline_spire",
|
||||
bountyRunestones: 140,
|
||||
},
|
||||
{
|
||||
id: "crystal_sovereign",
|
||||
@@ -656,6 +693,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["crystal_sovereign_blade", "diamond_plate"],
|
||||
prestigeRequirement: 19,
|
||||
zoneId: "crystalline_spire",
|
||||
bountyRunestones: 175,
|
||||
},
|
||||
// ── Void Sanctum ──────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -674,6 +712,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["void_annihilator"],
|
||||
prestigeRequirement: 18,
|
||||
zoneId: "void_sanctum",
|
||||
bountyRunestones: 90,
|
||||
},
|
||||
{
|
||||
id: "eternal_shade",
|
||||
@@ -691,6 +730,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["eternal_shroud"],
|
||||
prestigeRequirement: 19,
|
||||
zoneId: "void_sanctum",
|
||||
bountyRunestones: 115,
|
||||
},
|
||||
{
|
||||
id: "the_unmaker",
|
||||
@@ -708,6 +748,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 20,
|
||||
zoneId: "void_sanctum",
|
||||
bountyRunestones: 145,
|
||||
},
|
||||
{
|
||||
id: "void_progenitor",
|
||||
@@ -725,6 +766,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["void_heart_gem"],
|
||||
prestigeRequirement: 21,
|
||||
zoneId: "void_sanctum",
|
||||
bountyRunestones: 180,
|
||||
},
|
||||
{
|
||||
id: "void_emperor",
|
||||
@@ -742,6 +784,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["sanctum_breaker", "void_emperor_plate"],
|
||||
prestigeRequirement: 22,
|
||||
zoneId: "void_sanctum",
|
||||
bountyRunestones: 225,
|
||||
},
|
||||
// ── Eternal Throne ────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -760,6 +803,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["eternal_armour"],
|
||||
prestigeRequirement: 21,
|
||||
zoneId: "eternal_throne",
|
||||
bountyRunestones: 115,
|
||||
},
|
||||
{
|
||||
id: "eternal_knight",
|
||||
@@ -777,6 +821,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["throne_blade"],
|
||||
prestigeRequirement: 22,
|
||||
zoneId: "eternal_throne",
|
||||
bountyRunestones: 150,
|
||||
},
|
||||
{
|
||||
id: "the_undying",
|
||||
@@ -794,6 +839,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 23,
|
||||
zoneId: "eternal_throne",
|
||||
bountyRunestones: 190,
|
||||
},
|
||||
{
|
||||
id: "apex_sovereign",
|
||||
@@ -811,6 +857,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 24,
|
||||
zoneId: "eternal_throne",
|
||||
bountyRunestones: 235,
|
||||
},
|
||||
{
|
||||
id: "the_apex",
|
||||
@@ -828,6 +875,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["apex_sword", "apex_plate", "eternity_stone"],
|
||||
prestigeRequirement: 25,
|
||||
zoneId: "eternal_throne",
|
||||
bountyRunestones: 295,
|
||||
},
|
||||
// ── Primordial Chaos ──────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -846,6 +894,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 26,
|
||||
zoneId: "primordial_chaos",
|
||||
bountyRunestones: 150,
|
||||
},
|
||||
{
|
||||
id: "creation_engine",
|
||||
@@ -863,6 +912,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 27,
|
||||
zoneId: "primordial_chaos",
|
||||
bountyRunestones: 200,
|
||||
},
|
||||
{
|
||||
id: "entropy_avatar",
|
||||
@@ -880,6 +930,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 29,
|
||||
zoneId: "primordial_chaos",
|
||||
bountyRunestones: 265,
|
||||
},
|
||||
{
|
||||
id: "primordial_titan",
|
||||
@@ -897,6 +948,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["chaos_mantle", "titan_core"],
|
||||
prestigeRequirement: 31,
|
||||
zoneId: "primordial_chaos",
|
||||
bountyRunestones: 350,
|
||||
},
|
||||
// ── Infinite Expanse ──────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -915,6 +967,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 33,
|
||||
zoneId: "infinite_expanse",
|
||||
bountyRunestones: 200,
|
||||
},
|
||||
{
|
||||
id: "horizon_beast",
|
||||
@@ -932,6 +985,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 35,
|
||||
zoneId: "infinite_expanse",
|
||||
bountyRunestones: 265,
|
||||
},
|
||||
{
|
||||
id: "infinity_construct",
|
||||
@@ -949,6 +1003,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 37,
|
||||
zoneId: "infinite_expanse",
|
||||
bountyRunestones: 350,
|
||||
},
|
||||
{
|
||||
id: "expanse_sovereign",
|
||||
@@ -966,6 +1021,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["expanse_blade", "void_armour_mk2"],
|
||||
prestigeRequirement: 39,
|
||||
zoneId: "infinite_expanse",
|
||||
bountyRunestones: 465,
|
||||
},
|
||||
// ── Reality Forge ─────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -984,6 +1040,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 41,
|
||||
zoneId: "reality_forge",
|
||||
bountyRunestones: 265,
|
||||
},
|
||||
{
|
||||
id: "reality_shaper",
|
||||
@@ -1001,6 +1058,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 44,
|
||||
zoneId: "reality_forge",
|
||||
bountyRunestones: 350,
|
||||
},
|
||||
{
|
||||
id: "creation_prime",
|
||||
@@ -1018,6 +1076,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 47,
|
||||
zoneId: "reality_forge",
|
||||
bountyRunestones: 465,
|
||||
},
|
||||
{
|
||||
id: "reality_architect",
|
||||
@@ -1035,6 +1094,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["cosmos_blade", "reality_plate"],
|
||||
prestigeRequirement: 49,
|
||||
zoneId: "reality_forge",
|
||||
bountyRunestones: 615,
|
||||
},
|
||||
// ── Cosmic Maelstrom ──────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -1053,6 +1113,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 51,
|
||||
zoneId: "cosmic_maelstrom",
|
||||
bountyRunestones: 350,
|
||||
},
|
||||
{
|
||||
id: "force_prime",
|
||||
@@ -1070,6 +1131,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 54,
|
||||
zoneId: "cosmic_maelstrom",
|
||||
bountyRunestones: 465,
|
||||
},
|
||||
{
|
||||
id: "maelstrom_god",
|
||||
@@ -1087,6 +1149,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 57,
|
||||
zoneId: "cosmic_maelstrom",
|
||||
bountyRunestones: 615,
|
||||
},
|
||||
{
|
||||
id: "cosmic_annihilator",
|
||||
@@ -1104,6 +1167,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["maelstrom_edge", "cosmic_plate"],
|
||||
prestigeRequirement: 59,
|
||||
zoneId: "cosmic_maelstrom",
|
||||
bountyRunestones: 815,
|
||||
},
|
||||
// ── Primeval Sanctum ──────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -1122,6 +1186,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 61,
|
||||
zoneId: "primeval_sanctum",
|
||||
bountyRunestones: 465,
|
||||
},
|
||||
{
|
||||
id: "time_elder",
|
||||
@@ -1139,6 +1204,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 65,
|
||||
zoneId: "primeval_sanctum",
|
||||
bountyRunestones: 615,
|
||||
},
|
||||
{
|
||||
id: "origin_beast",
|
||||
@@ -1156,6 +1222,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 69,
|
||||
zoneId: "primeval_sanctum",
|
||||
bountyRunestones: 815,
|
||||
},
|
||||
{
|
||||
id: "primeval_god",
|
||||
@@ -1173,6 +1240,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["primeval_blade", "ancient_aegis"],
|
||||
prestigeRequirement: 74,
|
||||
zoneId: "primeval_sanctum",
|
||||
bountyRunestones: 1080,
|
||||
},
|
||||
// ── The Absolute ──────────────────────────────────────────────────────────
|
||||
{
|
||||
@@ -1191,6 +1259,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 76,
|
||||
zoneId: "the_absolute",
|
||||
bountyRunestones: 615,
|
||||
},
|
||||
{
|
||||
id: "void_convergence",
|
||||
@@ -1208,6 +1277,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 79,
|
||||
zoneId: "the_absolute",
|
||||
bountyRunestones: 815,
|
||||
},
|
||||
{
|
||||
id: "eternal_end",
|
||||
@@ -1225,6 +1295,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: [],
|
||||
prestigeRequirement: 83,
|
||||
zoneId: "the_absolute",
|
||||
bountyRunestones: 1080,
|
||||
},
|
||||
{
|
||||
id: "the_absolute_one",
|
||||
@@ -1242,5 +1313,6 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
equipmentRewards: ["absolute_blade", "eternity_plate", "omniversal_core"],
|
||||
prestigeRequirement: 90,
|
||||
zoneId: "the_absolute",
|
||||
bountyRunestones: 1430,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -21,6 +21,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "iron_vanguard",
|
||||
},
|
||||
{
|
||||
id: "enchanted_blade",
|
||||
@@ -42,6 +43,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
owned: false,
|
||||
equipped: false,
|
||||
cost: { gold: 0, essence: 500, crystals: 0 },
|
||||
setId: "shadow_infiltrator",
|
||||
},
|
||||
{
|
||||
id: "flame_lance",
|
||||
@@ -52,6 +54,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 1.7 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "volcanic_forger",
|
||||
},
|
||||
{
|
||||
id: "vorpal_sword",
|
||||
@@ -115,6 +118,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "iron_vanguard",
|
||||
},
|
||||
{
|
||||
id: "hide_armour",
|
||||
@@ -146,6 +150,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
owned: false,
|
||||
equipped: false,
|
||||
cost: { gold: 0, essence: 400, crystals: 0 },
|
||||
setId: "shadow_infiltrator",
|
||||
},
|
||||
{
|
||||
id: "volcanic_plate",
|
||||
@@ -156,6 +161,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 1.65, combatMultiplier: 1.15 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "volcanic_forger",
|
||||
},
|
||||
{
|
||||
id: "dragon_scale",
|
||||
@@ -208,6 +214,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "iron_vanguard",
|
||||
},
|
||||
{
|
||||
id: "frost_rune",
|
||||
@@ -248,6 +255,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 1.55, goldMultiplier: 1.1 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "volcanic_forger",
|
||||
},
|
||||
{
|
||||
id: "void_compass",
|
||||
@@ -259,6 +267,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
owned: false,
|
||||
equipped: false,
|
||||
cost: { gold: 0, essence: 350, crystals: 0 },
|
||||
setId: "shadow_infiltrator",
|
||||
},
|
||||
{
|
||||
id: "frost_crystal",
|
||||
@@ -310,6 +319,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 3.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "celestial_guardian",
|
||||
},
|
||||
{
|
||||
id: "angels_halo",
|
||||
@@ -320,6 +330,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 2.75, goldMultiplier: 1.3 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "celestial_guardian",
|
||||
},
|
||||
{
|
||||
id: "celestial_armour",
|
||||
@@ -330,6 +341,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 2.75 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "celestial_guardian",
|
||||
},
|
||||
{
|
||||
id: "divine_edge",
|
||||
@@ -361,6 +373,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 4.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "abyssal_predator",
|
||||
},
|
||||
{
|
||||
id: "leviathan_eye",
|
||||
@@ -371,6 +384,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 3.0, goldMultiplier: 1.35 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "abyssal_predator",
|
||||
},
|
||||
{
|
||||
id: "pressure_plate",
|
||||
@@ -381,6 +395,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 3.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "abyssal_predator",
|
||||
},
|
||||
{
|
||||
id: "abyssal_edge",
|
||||
@@ -412,6 +427,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 3.75 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "infernal_conqueror",
|
||||
},
|
||||
{
|
||||
id: "hellfire_edge",
|
||||
@@ -422,6 +438,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 5.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "infernal_conqueror",
|
||||
},
|
||||
{
|
||||
id: "soul_gem",
|
||||
@@ -432,6 +449,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 3.25, goldMultiplier: 1.4 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "infernal_conqueror",
|
||||
},
|
||||
{
|
||||
id: "infernal_edge",
|
||||
@@ -463,6 +481,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 6.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "crystal_domain",
|
||||
},
|
||||
{
|
||||
id: "faceted_armour",
|
||||
@@ -473,6 +492,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 4.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "crystal_domain",
|
||||
},
|
||||
{
|
||||
id: "prism_eye",
|
||||
@@ -483,6 +503,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 3.5, goldMultiplier: 1.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "crystal_domain",
|
||||
},
|
||||
{
|
||||
id: "crystal_sovereign_blade",
|
||||
@@ -514,6 +535,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 8.0 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "void_emperor",
|
||||
},
|
||||
{
|
||||
id: "eternal_shroud",
|
||||
@@ -524,6 +546,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 5.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "void_emperor",
|
||||
},
|
||||
{
|
||||
id: "void_heart_gem",
|
||||
@@ -534,6 +557,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 4.0, goldMultiplier: 1.6 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "void_emperor",
|
||||
},
|
||||
{
|
||||
id: "sanctum_breaker",
|
||||
@@ -565,6 +589,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { goldMultiplier: 7.0 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "eternal_throne",
|
||||
},
|
||||
{
|
||||
id: "throne_blade",
|
||||
@@ -575,6 +600,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { combatMultiplier: 10.0 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "eternal_throne",
|
||||
},
|
||||
{
|
||||
id: "apex_sword",
|
||||
@@ -605,6 +631,7 @@ export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
bonus: { clickMultiplier: 5.0, goldMultiplier: 2.0, combatMultiplier: 1.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
setId: "eternal_throne",
|
||||
},
|
||||
// ── Purchasable endgame sinks ─────────────────────────────────────────────
|
||||
{
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { EquipmentSet } from "@elysium/types";
|
||||
|
||||
export const DEFAULT_EQUIPMENT_SETS: EquipmentSet[] = [
|
||||
{
|
||||
id: "iron_vanguard",
|
||||
name: "Iron Vanguard",
|
||||
description: "The armaments of a seasoned guild soldier — proven steel, reliable gold.",
|
||||
pieces: ["iron_sword", "chainmail", "mages_focus"],
|
||||
bonuses: {
|
||||
2: { goldMultiplier: 1.1 },
|
||||
3: { combatMultiplier: 1.1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shadow_infiltrator",
|
||||
name: "Shadow Infiltrator",
|
||||
description: "Gear forged from the Shadow Marshes themselves — unseen, unstoppable.",
|
||||
pieces: ["shadow_dagger", "void_shroud", "void_compass"],
|
||||
bonuses: {
|
||||
2: { goldMultiplier: 1.15 },
|
||||
3: { clickMultiplier: 1.2 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "volcanic_forger",
|
||||
name: "Volcanic Forger",
|
||||
description: "Weapons and armour tempered in the depths of the Volcanic Reaches.",
|
||||
pieces: ["flame_lance", "volcanic_plate", "crystal_shard"],
|
||||
bonuses: {
|
||||
2: { combatMultiplier: 1.15 },
|
||||
3: { goldMultiplier: 1.15 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "celestial_guardian",
|
||||
name: "Celestial Guardian",
|
||||
description: "Relics of the Celestial Reaches — divine power made manifest.",
|
||||
pieces: ["seraph_wing", "celestial_armour", "angels_halo"],
|
||||
bonuses: {
|
||||
2: { combatMultiplier: 1.2 },
|
||||
3: { goldMultiplier: 1.2 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "abyssal_predator",
|
||||
name: "Abyssal Predator",
|
||||
description: "Trophies reclaimed from the deepest trenches of the Abyssal Reaches.",
|
||||
pieces: ["depth_blade", "pressure_plate", "leviathan_eye"],
|
||||
bonuses: {
|
||||
2: { goldMultiplier: 1.2 },
|
||||
3: { clickMultiplier: 1.25 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "infernal_conqueror",
|
||||
name: "Infernal Conqueror",
|
||||
description: "Forged in the heart of the Infernal Court from the essence of the defeated.",
|
||||
pieces: ["hellfire_edge", "demon_hide", "soul_gem"],
|
||||
bonuses: {
|
||||
2: { combatMultiplier: 1.25 },
|
||||
3: { goldMultiplier: 1.25 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "crystal_domain",
|
||||
name: "Crystal Domain",
|
||||
description: "Instruments of the Crystalline Spire — reality refracted into absolute efficiency.",
|
||||
pieces: ["prism_blade", "faceted_armour", "prism_eye"],
|
||||
bonuses: {
|
||||
2: { clickMultiplier: 1.25 },
|
||||
3: { goldMultiplier: 1.25 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "void_emperor",
|
||||
name: "Void Emperor",
|
||||
description: "The regalia of the Void Sanctum's lord — power carved from absolute nothingness.",
|
||||
pieces: ["void_annihilator", "eternal_shroud", "void_heart_gem"],
|
||||
bonuses: {
|
||||
2: { goldMultiplier: 1.3 },
|
||||
3: { combatMultiplier: 1.3 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "eternal_throne",
|
||||
name: "Eternal Throne",
|
||||
description: "The armaments of the Eternal Throne — weapons and armour that have endured all of time.",
|
||||
pieces: ["throne_blade", "eternal_armour", "eternity_stone"],
|
||||
bonuses: {
|
||||
2: { combatMultiplier: 1.35, goldMultiplier: 1.25 },
|
||||
3: { clickMultiplier: 1.35 },
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -1,10 +1,14 @@
|
||||
import type { BossChallengeResponse, GameState } from "@elysium/types";
|
||||
import { computeSetBonuses } from "@elysium/types";
|
||||
import { Hono } from "hono";
|
||||
import type { HonoEnv } from "../types/hono.js";
|
||||
import { prisma } from "../db/client.js";
|
||||
import { DEFAULT_BOSSES } from "../data/bosses.js";
|
||||
import { DEFAULT_EQUIPMENT_SETS } from "../data/equipmentSets.js";
|
||||
import { authMiddleware } from "../middleware/auth.js";
|
||||
import { updateChallengeProgress } from "../services/dailyChallenges.js";
|
||||
|
||||
export const bossRouter = new Hono();
|
||||
export const bossRouter = new Hono<HonoEnv>();
|
||||
|
||||
bossRouter.use("*", authMiddleware);
|
||||
|
||||
@@ -25,6 +29,9 @@ const calculatePartyStats = (
|
||||
.filter((e) => e.equipped && e.bonus.combatMultiplier != null)
|
||||
.reduce((mult, e) => mult * (e.bonus.combatMultiplier ?? 1), 1);
|
||||
|
||||
const equippedItemIds = (state.equipment ?? []).filter((e) => e.equipped).map((e) => e.id);
|
||||
const setCombatMultiplier = computeSetBonuses(equippedItemIds, DEFAULT_EQUIPMENT_SETS).combatMultiplier;
|
||||
|
||||
let partyDPS = 0;
|
||||
let partyMaxHp = 0;
|
||||
|
||||
@@ -52,7 +59,7 @@ const calculatePartyStats = (
|
||||
partyMaxHp += adventurer.level * 50 * adventurer.count;
|
||||
}
|
||||
|
||||
partyDPS *= equipmentCombatMultiplier;
|
||||
partyDPS *= equipmentCombatMultiplier * setCombatMultiplier;
|
||||
|
||||
return { partyDPS, partyMaxHp };
|
||||
};
|
||||
@@ -185,12 +192,18 @@ bossRouter.post("/challenge", async (context) => {
|
||||
state.resources.crystals += crystalsAwarded;
|
||||
}
|
||||
|
||||
// First-kill bounty — look up authoritative bounty from static data
|
||||
const staticBoss = DEFAULT_BOSSES.find((b) => b.id === body.bossId);
|
||||
const bountyRunestones = staticBoss?.bountyRunestones ?? 0;
|
||||
state.prestige.runestones += bountyRunestones;
|
||||
|
||||
rewards = {
|
||||
gold: boss.goldReward,
|
||||
essence: boss.essenceReward,
|
||||
crystals: boss.crystalReward,
|
||||
upgradeIds: boss.upgradeRewards,
|
||||
equipmentIds: equipmentRewards,
|
||||
bountyRunestones,
|
||||
};
|
||||
} else {
|
||||
bossHpAtBattleEnd = Math.max(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import type { GameState, SaveRequest } from "@elysium/types";
|
||||
import { computeSetBonuses } from "@elysium/types";
|
||||
import { createHmac } from "node:crypto";
|
||||
import { Hono } from "hono";
|
||||
import type { HonoEnv } from "../types/hono.js";
|
||||
import { prisma } from "../db/client.js";
|
||||
import { DEFAULT_ACHIEVEMENTS } from "../data/achievements.js";
|
||||
import { DEFAULT_ADVENTURERS } from "../data/adventurers.js";
|
||||
import { DEFAULT_BOSSES } from "../data/bosses.js";
|
||||
import { DEFAULT_EQUIPMENT } from "../data/equipment.js";
|
||||
import { DEFAULT_EQUIPMENT_SETS } from "../data/equipmentSets.js";
|
||||
import { DEFAULT_QUESTS } from "../data/quests.js";
|
||||
import { authMiddleware } from "../middleware/auth.js";
|
||||
import { getOrResetDailyChallenges } from "../services/dailyChallenges.js";
|
||||
@@ -44,6 +47,8 @@ const computeMaxPassiveIncome = (
|
||||
(mult, e) => mult * (e.bonus.goldMultiplier ?? 1),
|
||||
1,
|
||||
);
|
||||
const equippedItemIds = equippedItems.map((e) => e.id);
|
||||
const setGoldMultiplier = computeSetBonuses(equippedItemIds, DEFAULT_EQUIPMENT_SETS).goldMultiplier;
|
||||
const runestonesIncome = state.prestige.runestonesIncomeMultiplier ?? 1;
|
||||
const runestonesEssence = state.prestige.runestonesEssenceMultiplier ?? 1;
|
||||
|
||||
@@ -70,7 +75,8 @@ const computeMaxPassiveIncome = (
|
||||
upgradeMultiplier *
|
||||
prestige *
|
||||
runestonesIncome *
|
||||
equipmentGoldMultiplier;
|
||||
equipmentGoldMultiplier *
|
||||
setGoldMultiplier;
|
||||
|
||||
essencePerSecond +=
|
||||
adventurer.essencePerSecond *
|
||||
@@ -93,9 +99,11 @@ const computeMaxClickGoldPerSecond = (state: GameState): number => {
|
||||
.filter((u) => u.purchased && u.target === "click")
|
||||
.reduce((mult, u) => mult * u.multiplier, 1);
|
||||
|
||||
const equipmentClickMultiplier = (state.equipment ?? [])
|
||||
.filter((e) => e.equipped && e.bonus.clickMultiplier != null)
|
||||
const equippedItems = (state.equipment ?? []).filter((e) => e.equipped);
|
||||
const equipmentClickMultiplier = equippedItems
|
||||
.filter((e) => e.bonus.clickMultiplier != null)
|
||||
.reduce((mult, e) => mult * (e.bonus.clickMultiplier ?? 1), 1);
|
||||
const setClickMultiplier = computeSetBonuses(equippedItems.map((e) => e.id), DEFAULT_EQUIPMENT_SETS).clickMultiplier;
|
||||
|
||||
const runestonesClick = state.prestige.runestonesClickMultiplier ?? 1;
|
||||
|
||||
@@ -104,7 +112,8 @@ const computeMaxClickGoldPerSecond = (state: GameState): number => {
|
||||
clickMultiplier *
|
||||
state.prestige.productionMultiplier *
|
||||
runestonesClick *
|
||||
equipmentClickMultiplier;
|
||||
equipmentClickMultiplier *
|
||||
setClickMultiplier;
|
||||
|
||||
return clickPower * CLICK_BUFFER_CPS;
|
||||
};
|
||||
@@ -284,7 +293,7 @@ const validateAndSanitize = (incoming: GameState, previous: GameState): GameStat
|
||||
return { ...incoming, resources, bosses, quests, achievements, prestige };
|
||||
};
|
||||
|
||||
export const gameRouter = new Hono();
|
||||
export const gameRouter = new Hono<HonoEnv>();
|
||||
|
||||
gameRouter.use("*", authMiddleware);
|
||||
|
||||
@@ -610,8 +619,8 @@ gameRouter.post("/save", async (context) => {
|
||||
|
||||
await prisma.gameState.upsert({
|
||||
where: { discordId },
|
||||
create: { discordId, state: stateToSave, updatedAt: now },
|
||||
update: { state: stateToSave, updatedAt: now },
|
||||
create: { discordId, state: stateToSave as unknown as never, updatedAt: now },
|
||||
update: { state: stateToSave as unknown as never, updatedAt: now },
|
||||
});
|
||||
|
||||
const signature = secret ? computeHmac(JSON.stringify(stateToSave), secret) : undefined;
|
||||
|
||||
Reference in New Issue
Block a user