generated from nhcarrigan/template
feat: add equipment, achievements, and visual polish
- Equipment system: 12 items across weapon/armour/trinket slots with common/rare/epic/legendary rarities; starter commons auto-equipped, higher tiers drop from boss victories - Achievement system: 15 milestones with typed conditions; checked each tick and crystal rewards applied automatically - Achievement toast: slide-in notification, auto-dismisses after 4s - Floating click text: +X gold floats on each manual click - Expanded quests (9 total) and upgrades (12 total) - Upgrade panel now shows locked upgrades so players can see their progression path - formatNumber utility (K/M/B/T) used consistently across all panels - Backfill logic for existing saves to add new content gracefully - types package now emits .d.ts declarations
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import type { Achievement } from "@elysium/types";
|
||||
|
||||
export const DEFAULT_ACHIEVEMENTS: Achievement[] = [
|
||||
{
|
||||
id: "first_click",
|
||||
name: "First Strike",
|
||||
description: "Click the Guild Hall for the first time.",
|
||||
icon: "👆",
|
||||
condition: { type: "totalClicks", amount: 1 },
|
||||
reward: { crystals: 5 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "click_enthusiast",
|
||||
name: "Click Enthusiast",
|
||||
description: "Click the Guild Hall 100 times.",
|
||||
icon: "🖱️",
|
||||
condition: { type: "totalClicks", amount: 100 },
|
||||
reward: { crystals: 25 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "click_master",
|
||||
name: "Click Master",
|
||||
description: "Click the Guild Hall 1,000 times.",
|
||||
icon: "⚡",
|
||||
condition: { type: "totalClicks", amount: 1_000 },
|
||||
reward: { crystals: 100 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "first_gold",
|
||||
name: "First Gold",
|
||||
description: "Earn your first 100 gold.",
|
||||
icon: "🪙",
|
||||
condition: { type: "totalGoldEarned", amount: 100 },
|
||||
reward: { crystals: 5 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "wealthy",
|
||||
name: "Wealthy",
|
||||
description: "Earn 10,000 gold in total.",
|
||||
icon: "💰",
|
||||
condition: { type: "totalGoldEarned", amount: 10_000 },
|
||||
reward: { crystals: 25 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "rich",
|
||||
name: "Rich",
|
||||
description: "Earn 1,000,000 gold in total.",
|
||||
icon: "👑",
|
||||
condition: { type: "totalGoldEarned", amount: 1_000_000 },
|
||||
reward: { crystals: 100 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "billionaire",
|
||||
name: "Billionaire",
|
||||
description: "Earn 1,000,000,000 gold in total.",
|
||||
icon: "🏦",
|
||||
condition: { type: "totalGoldEarned", amount: 1_000_000_000 },
|
||||
reward: { crystals: 500 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "first_quest",
|
||||
name: "Adventurous Spirit",
|
||||
description: "Complete your first quest.",
|
||||
icon: "📜",
|
||||
condition: { type: "questsCompleted", amount: 1 },
|
||||
reward: { crystals: 10 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "quest_veteran",
|
||||
name: "Quest Veteran",
|
||||
description: "Complete 5 quests.",
|
||||
icon: "📚",
|
||||
condition: { type: "questsCompleted", amount: 5 },
|
||||
reward: { crystals: 50 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "boss_slayer",
|
||||
name: "Boss Slayer",
|
||||
description: "Defeat your first boss.",
|
||||
icon: "⚔️",
|
||||
condition: { type: "bossesDefeated", amount: 1 },
|
||||
reward: { crystals: 25 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "legendary_hunter",
|
||||
name: "Legendary Hunter",
|
||||
description: "Defeat all four bosses.",
|
||||
icon: "🏆",
|
||||
condition: { type: "bossesDefeated", amount: 4 },
|
||||
reward: { crystals: 200 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "guild_master",
|
||||
name: "Guild Master",
|
||||
description: "Recruit a total of 50 adventurers.",
|
||||
icon: "🏰",
|
||||
condition: { type: "adventurerTotal", amount: 50 },
|
||||
reward: { crystals: 50 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "army_commander",
|
||||
name: "Army Commander",
|
||||
description: "Recruit a total of 500 adventurers.",
|
||||
icon: "🛡️",
|
||||
condition: { type: "adventurerTotal", amount: 500 },
|
||||
reward: { crystals: 200 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "first_prestige",
|
||||
name: "Born Again",
|
||||
description: "Prestige for the first time.",
|
||||
icon: "⭐",
|
||||
condition: { type: "prestigeCount", amount: 1 },
|
||||
reward: { crystals: 100 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
{
|
||||
id: "collector",
|
||||
name: "Collector",
|
||||
description: "Acquire your first piece of boss-dropped equipment.",
|
||||
icon: "🎒",
|
||||
condition: { type: "equipmentOwned", amount: 4 },
|
||||
reward: { crystals: 10 },
|
||||
unlockedAt: null,
|
||||
},
|
||||
];
|
||||
@@ -8,6 +8,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 1,
|
||||
goldPerSecond: 0.1,
|
||||
essencePerSecond: 0,
|
||||
combatPower: 1,
|
||||
count: 0,
|
||||
unlocked: true,
|
||||
},
|
||||
@@ -18,6 +19,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 2,
|
||||
goldPerSecond: 0.5,
|
||||
essencePerSecond: 0,
|
||||
combatPower: 3,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -28,6 +30,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 3,
|
||||
goldPerSecond: 1.5,
|
||||
essencePerSecond: 0.01,
|
||||
combatPower: 8,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -38,6 +41,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 4,
|
||||
goldPerSecond: 4,
|
||||
essencePerSecond: 0.02,
|
||||
combatPower: 20,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -48,6 +52,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 5,
|
||||
goldPerSecond: 10,
|
||||
essencePerSecond: 0.05,
|
||||
combatPower: 50,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -58,6 +63,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 6,
|
||||
goldPerSecond: 25,
|
||||
essencePerSecond: 0.1,
|
||||
combatPower: 120,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -68,6 +74,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 7,
|
||||
goldPerSecond: 75,
|
||||
essencePerSecond: 0.2,
|
||||
combatPower: 300,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -78,6 +85,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 8,
|
||||
goldPerSecond: 200,
|
||||
essencePerSecond: 0.5,
|
||||
combatPower: 800,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -88,6 +96,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 9,
|
||||
goldPerSecond: 600,
|
||||
essencePerSecond: 1,
|
||||
combatPower: 2000,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
@@ -98,6 +107,7 @@ export const DEFAULT_ADVENTURERS: Adventurer[] = [
|
||||
level: 10,
|
||||
goldPerSecond: 2000,
|
||||
essencePerSecond: 3,
|
||||
combatPower: 6000,
|
||||
count: 0,
|
||||
unlocked: false,
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
essenceReward: 25,
|
||||
crystalReward: 0,
|
||||
upgradeRewards: ["click_2"],
|
||||
equipmentRewards: ["iron_sword", "chainmail", "mages_focus"],
|
||||
prestigeRequirement: 0,
|
||||
},
|
||||
{
|
||||
@@ -29,6 +30,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
essenceReward: 200,
|
||||
crystalReward: 10,
|
||||
upgradeRewards: ["global_2"],
|
||||
equipmentRewards: ["enchanted_blade", "plate_armour", "arcane_orb"],
|
||||
prestigeRequirement: 0,
|
||||
},
|
||||
{
|
||||
@@ -44,6 +46,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
essenceReward: 1_000,
|
||||
crystalReward: 50,
|
||||
upgradeRewards: ["click_3"],
|
||||
equipmentRewards: ["vorpal_sword", "dragon_scale"],
|
||||
prestigeRequirement: 1,
|
||||
},
|
||||
{
|
||||
@@ -59,6 +62,7 @@ export const DEFAULT_BOSSES: Boss[] = [
|
||||
essenceReward: 5_000,
|
||||
crystalReward: 200,
|
||||
upgradeRewards: [],
|
||||
equipmentRewards: ["philosophers_stone"],
|
||||
prestigeRequirement: 3,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import type { Equipment } from "@elysium/types";
|
||||
|
||||
export const DEFAULT_EQUIPMENT: Equipment[] = [
|
||||
// Weapons — drop from bosses; common starts owned
|
||||
{
|
||||
id: "rusty_sword",
|
||||
name: "Rusty Sword",
|
||||
description: "A battered blade, but still sharp enough to draw blood.",
|
||||
type: "weapon",
|
||||
rarity: "common",
|
||||
bonus: { combatMultiplier: 1.1 },
|
||||
owned: true,
|
||||
equipped: true,
|
||||
},
|
||||
{
|
||||
id: "iron_sword",
|
||||
name: "Iron Sword",
|
||||
description: "A sturdy weapon issued to veterans of the guild.",
|
||||
type: "weapon",
|
||||
rarity: "rare",
|
||||
bonus: { combatMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "enchanted_blade",
|
||||
name: "Enchanted Blade",
|
||||
description: "A sword imbued with ancient magic that makes every strike count.",
|
||||
type: "weapon",
|
||||
rarity: "epic",
|
||||
bonus: { combatMultiplier: 1.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "vorpal_sword",
|
||||
name: "Vorpal Sword",
|
||||
description: "A legendary blade that severs even the strongest bonds.",
|
||||
type: "weapon",
|
||||
rarity: "legendary",
|
||||
bonus: { combatMultiplier: 2.0 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
// Armour — drop from bosses; common starts owned
|
||||
{
|
||||
id: "leather_armour",
|
||||
name: "Leather Armour",
|
||||
description: "Simple protection that keeps your adventurers moving efficiently.",
|
||||
type: "armour",
|
||||
rarity: "common",
|
||||
bonus: { goldMultiplier: 1.1 },
|
||||
owned: true,
|
||||
equipped: true,
|
||||
},
|
||||
{
|
||||
id: "chainmail",
|
||||
name: "Chainmail",
|
||||
description: "Interlocked rings that guard against most mundane threats.",
|
||||
type: "armour",
|
||||
rarity: "rare",
|
||||
bonus: { goldMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "plate_armour",
|
||||
name: "Plate Armour",
|
||||
description: "Full plate protection that inspires confidence — and gold.",
|
||||
type: "armour",
|
||||
rarity: "epic",
|
||||
bonus: { goldMultiplier: 1.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "dragon_scale",
|
||||
name: "Dragon Scale Armour",
|
||||
description: "Armour forged from the scales of a defeated elder dragon.",
|
||||
type: "armour",
|
||||
rarity: "legendary",
|
||||
bonus: { goldMultiplier: 2.0 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
// Trinkets — drop from bosses; common starts owned
|
||||
{
|
||||
id: "lucky_coin",
|
||||
name: "Lucky Coin",
|
||||
description: "A coin that always lands on the side you need.",
|
||||
type: "trinket",
|
||||
rarity: "common",
|
||||
bonus: { clickMultiplier: 1.1 },
|
||||
owned: true,
|
||||
equipped: true,
|
||||
},
|
||||
{
|
||||
id: "mages_focus",
|
||||
name: "Mage's Focus",
|
||||
description: "A crystal lens that sharpens magical precision.",
|
||||
type: "trinket",
|
||||
rarity: "rare",
|
||||
bonus: { clickMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "arcane_orb",
|
||||
name: "Arcane Orb",
|
||||
description: "An orb humming with concentrated arcane energy.",
|
||||
type: "trinket",
|
||||
rarity: "epic",
|
||||
bonus: { clickMultiplier: 1.5 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
{
|
||||
id: "philosophers_stone",
|
||||
name: "Philosopher's Stone",
|
||||
description: "The legendary stone that grants mastery over gold and combat alike.",
|
||||
type: "trinket",
|
||||
rarity: "legendary",
|
||||
bonus: { clickMultiplier: 2.0, goldMultiplier: 1.25 },
|
||||
owned: false,
|
||||
equipped: false,
|
||||
},
|
||||
];
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { GameState, Player, PrestigeData } from "@elysium/types";
|
||||
import { DEFAULT_ACHIEVEMENTS } from "./achievements.js";
|
||||
import { DEFAULT_ADVENTURERS } from "./adventurers.js";
|
||||
import { DEFAULT_BOSSES } from "./bosses.js";
|
||||
import { DEFAULT_EQUIPMENT } from "./equipment.js";
|
||||
import { DEFAULT_QUESTS } from "./quests.js";
|
||||
import { DEFAULT_UPGRADES } from "./upgrades.js";
|
||||
|
||||
@@ -28,6 +30,8 @@ export const INITIAL_GAME_STATE = (player: Player, characterName: string): GameS
|
||||
upgrades: structuredClone(DEFAULT_UPGRADES),
|
||||
quests: structuredClone(DEFAULT_QUESTS),
|
||||
bosses: structuredClone(DEFAULT_BOSSES),
|
||||
equipment: structuredClone(DEFAULT_EQUIPMENT),
|
||||
achievements: structuredClone(DEFAULT_ACHIEVEMENTS),
|
||||
prestige: INITIAL_PRESTIGE,
|
||||
baseClickPower: 1,
|
||||
lastTickAt: Date.now(),
|
||||
|
||||
@@ -34,6 +34,20 @@ export const DEFAULT_QUESTS: Quest[] = [
|
||||
],
|
||||
prerequisiteIds: ["goblin_camp"],
|
||||
},
|
||||
{
|
||||
id: "necromancer_tower",
|
||||
name: "Necromancer's Tower",
|
||||
description:
|
||||
"A rogue necromancer has raised an army of skeletons near the city. Silence him before the dead overrun us.",
|
||||
status: "locked",
|
||||
durationSeconds: 25 * 60,
|
||||
rewards: [
|
||||
{ type: "gold", amount: 15_000 },
|
||||
{ type: "essence", amount: 20 },
|
||||
{ type: "upgrade", targetId: "cleric_1" },
|
||||
],
|
||||
prerequisiteIds: ["haunted_mine"],
|
||||
},
|
||||
{
|
||||
id: "ancient_ruins",
|
||||
name: "Ancient Ruins",
|
||||
@@ -46,6 +60,19 @@ export const DEFAULT_QUESTS: Quest[] = [
|
||||
],
|
||||
prerequisiteIds: ["haunted_mine"],
|
||||
},
|
||||
{
|
||||
id: "shadow_mere",
|
||||
name: "The Shadow Mere",
|
||||
description:
|
||||
"A cursed lake shrouded in permanent twilight. Strange energies pulse beneath its surface.",
|
||||
status: "locked",
|
||||
durationSeconds: 45 * 60,
|
||||
rewards: [
|
||||
{ type: "essence", amount: 150 },
|
||||
{ type: "upgrade", targetId: "scout_1" },
|
||||
],
|
||||
prerequisiteIds: ["ancient_ruins"],
|
||||
},
|
||||
{
|
||||
id: "dragon_lair",
|
||||
name: "Dragon's Lair",
|
||||
@@ -60,4 +87,32 @@ export const DEFAULT_QUESTS: Quest[] = [
|
||||
],
|
||||
prerequisiteIds: ["ancient_ruins"],
|
||||
},
|
||||
{
|
||||
id: "frozen_wastes",
|
||||
name: "The Frozen Wastes",
|
||||
description:
|
||||
"A tundra at the edge of the world, home to creatures that have never seen the sun. Rumours speak of artefacts buried in the permafrost.",
|
||||
status: "locked",
|
||||
durationSeconds: 2 * 60 * 60,
|
||||
rewards: [
|
||||
{ type: "gold", amount: 2_000_000 },
|
||||
{ type: "crystals", amount: 150 },
|
||||
{ type: "upgrade", targetId: "global_3" },
|
||||
],
|
||||
prerequisiteIds: ["dragon_lair"],
|
||||
},
|
||||
{
|
||||
id: "void_rift",
|
||||
name: "Void Rift",
|
||||
description:
|
||||
"A tear in reality itself. What lies beyond defies description — but the power within is unlike anything of this world.",
|
||||
status: "locked",
|
||||
durationSeconds: 4 * 60 * 60,
|
||||
rewards: [
|
||||
{ type: "crystals", amount: 500 },
|
||||
{ type: "essence", amount: 5_000 },
|
||||
{ type: "upgrade", targetId: "knight_1" },
|
||||
],
|
||||
prerequisiteIds: ["frozen_wastes"],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -58,6 +58,17 @@ export const DEFAULT_UPGRADES: Upgrade[] = [
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
id: "global_3",
|
||||
name: "Royal Patronage",
|
||||
description: "The king himself backs your guild. All income doubled.",
|
||||
target: "global",
|
||||
multiplier: 2,
|
||||
costGold: 1_000_000,
|
||||
costEssence: 100,
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
// Adventurer-specific upgrades
|
||||
{
|
||||
id: "peasant_1",
|
||||
@@ -95,4 +106,40 @@ export const DEFAULT_UPGRADES: Upgrade[] = [
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
id: "cleric_1",
|
||||
name: "Holy Rites",
|
||||
description: "Sacred ceremonies double the output of your clerics.",
|
||||
target: "adventurer",
|
||||
adventurerId: "acolyte",
|
||||
multiplier: 2,
|
||||
costGold: 8_000,
|
||||
costEssence: 3,
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
id: "scout_1",
|
||||
name: "Stealth Training",
|
||||
description: "Advanced scouting techniques double ranger effectiveness.",
|
||||
target: "adventurer",
|
||||
adventurerId: "ranger",
|
||||
multiplier: 2,
|
||||
costGold: 15_000,
|
||||
costEssence: 5,
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
id: "knight_1",
|
||||
name: "Tempered Steel",
|
||||
description: "Superior forging techniques double the output of your knights.",
|
||||
target: "adventurer",
|
||||
adventurerId: "knight",
|
||||
multiplier: 2,
|
||||
costGold: 50_000,
|
||||
costEssence: 10,
|
||||
purchased: false,
|
||||
unlocked: false,
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user