diff --git a/src/components/game/SpellsTab.tsx b/src/components/game/SpellsTab.tsx
index f62e554..ae0a68a 100755
--- a/src/components/game/SpellsTab.tsx
+++ b/src/components/game/SpellsTab.tsx
@@ -102,7 +102,10 @@ export function SpellsTab() {
{def.effects.map((eff, i) => (
- {eff.type === 'lifesteal' && `🩸 ${Math.round(eff.value * 100)}% lifesteal`}
+ {eff.type === 'burn' && `🔥 Burn`}
+ {eff.type === 'stun' && `⚡ Stun`}
+ {eff.type === 'pierce' && `🎯 Pierce`}
+ {eff.type === 'multicast' && `✨ Multicast`}
))}
diff --git a/src/components/game/tabs/SpireTab.tsx b/src/components/game/tabs/SpireTab.tsx
index dc3c3cf..b47113e 100755
--- a/src/components/game/tabs/SpireTab.tsx
+++ b/src/components/game/tabs/SpireTab.tsx
@@ -380,9 +380,10 @@ export function SpireTab({ store }: SpireTabProps) {
{spellDef.effects.map((eff, i) => (
- {eff.type === 'lifesteal' && `🩸 ${Math.round(eff.value * 100)}%`}
{eff.type === 'burn' && `🔥 Burn`}
- {eff.type === 'freeze' && `❄️ Freeze`}
+ {eff.type === 'stun' && `⚡ Stun`}
+ {eff.type === 'pierce' && `🎯 Pierce`}
+ {eff.type === 'multicast' && `✨ Multicast`}
))}
diff --git a/src/lib/game/constants.ts b/src/lib/game/constants.ts
index 18b30b5..0e53cda 100755
--- a/src/lib/game/constants.ts
+++ b/src/lib/game/constants.ts
@@ -74,7 +74,7 @@ export const GUARDIANS: Record = {
],
pactCost: 1000,
pactTime: 4,
- uniquePerk: "Water spells have 10% lifesteal"
+ uniquePerk: "Water spells have 10% chance to cast twice"
},
30: {
name: "Ventus Rex", element: "air", hp: 30000, barrier: 15000, pact: 2.0, color: "#00D4FF",
@@ -114,7 +114,7 @@ export const GUARDIANS: Record = {
],
pactCost: 15000,
pactTime: 12,
- uniquePerk: "Dark spells have 20% lifesteal"
+ uniquePerk: "Dark spells have 25% crit chance"
},
70: {
name: "Vita Sempiterna", element: "life", hp: 180000, barrier: 90000, pact: 3.0, color: "#2ECC71",
@@ -124,7 +124,7 @@ export const GUARDIANS: Record = {
],
pactCost: 25000,
pactTime: 14,
- uniquePerk: "Life spells heal for 30% of damage dealt"
+ uniquePerk: "Life spells restore 30% of damage dealt as mana"
},
80: {
name: "Mors Ultima", element: "death", hp: 250000, barrier: 125000, pact: 3.25, color: "#778CA3",
@@ -134,7 +134,7 @@ export const GUARDIANS: Record = {
],
pactCost: 40000,
pactTime: 16,
- uniquePerk: "Death spells execute enemies below 20% HP"
+ uniquePerk: "Death spells deal +50% damage to enemies below 50% HP"
},
90: {
name: "Primordialis", element: "void", hp: 400000, barrier: 200000, pact: 4.0, color: "#4A235A",
@@ -323,14 +323,13 @@ export const SPELLS_DEF: Record = {
drain: {
name: "Drain",
elem: "death",
- dmg: 10,
+ dmg: 12,
cost: elemCost("death", 2),
tier: 1,
castSpeed: 2,
unlock: 150,
studyTime: 3,
- desc: "Drain life force from your enemy.",
- effects: [{ type: 'lifesteal', value: 0.2 }]
+ desc: "Drain essence from your enemy, restoring mana."
},
rotTouch: {
name: "Rot Touch",
@@ -346,14 +345,13 @@ export const SPELLS_DEF: Record = {
lifeTap: {
name: "Life Tap",
elem: "life",
- dmg: 8,
+ dmg: 10,
cost: elemCost("life", 1),
tier: 1,
castSpeed: 3,
unlock: 100,
studyTime: 2,
- desc: "Tap into life energy for a weak attack.",
- effects: [{ type: 'lifesteal', value: 0.3 }]
+ desc: "Tap into life energy for a quick attack."
},
thornWhip: {
name: "Thorn Whip",
@@ -503,14 +501,13 @@ export const SPELLS_DEF: Record = {
soulRend: {
name: "Soul Rend",
elem: "death",
- dmg: 50,
+ dmg: 55,
cost: elemCost("death", 7),
tier: 2,
castSpeed: 1.1,
unlock: 1100,
studyTime: 9,
- desc: "Tear at the enemy's soul.",
- effects: [{ type: 'lifesteal', value: 0.25 }]
+ desc: "Tear at the enemy's soul."
},
entangle: {
name: "Entangle",
@@ -594,26 +591,24 @@ export const SPELLS_DEF: Record = {
deathMark: {
name: "Death Mark",
elem: "death",
- dmg: 200,
+ dmg: 220,
cost: elemCost("death", 20),
tier: 3,
castSpeed: 0.7,
unlock: 10000,
studyTime: 24,
- desc: "Mark for death.",
- effects: [{ type: 'lifesteal', value: 0.35 }]
+ desc: "Mark for death, dealing massive damage."
},
worldTree: {
name: "World Tree",
elem: "life",
- dmg: 180,
+ dmg: 200,
cost: elemCost("life", 18),
tier: 3,
castSpeed: 0.75,
unlock: 9000,
studyTime: 22,
- desc: "Power of the world tree itself.",
- effects: [{ type: 'lifesteal', value: 0.4 }]
+ desc: "Power of the world tree itself."
},
// Tier 4 - Legendary Spells (40-60 hours study, require exotic elements)
@@ -673,7 +668,6 @@ export const SKILLS_DEF: Record = {
quickLearner: { name: "Quick Learner", desc: "+10% study speed", cat: "study", max: 10, base: 250, studyTime: 4 },
focusedMind: { name: "Focused Mind", desc: "-5% study mana cost", cat: "study", max: 10, base: 300, studyTime: 5 },
meditation: { name: "Meditation Focus", desc: "Up to 2.5x regen after 4hrs meditating", cat: "study", max: 1, base: 400, studyTime: 6 },
- knowledgeRetention: { name: "Knowledge Retention", desc: "+20% study progress saved on cancel", cat: "study", max: 3, base: 350, studyTime: 5 },
deepTrance: { name: "Deep Trance", desc: "Extend meditation to 6hrs for 3x", cat: "study", max: 1, base: 900, studyTime: 48, req: { meditation: 1 } },
voidMeditation:{ name: "Void Meditation", desc: "Extend meditation to 8hrs for 5x", cat: "study", max: 1, base: 1500, studyTime: 72, req: { deepTrance: 1 } },
@@ -698,8 +692,8 @@ export const SKILLS_DEF: Record = {
crystalEmbedding: { name: "Crystal Embedding", desc: "Embed elemental crystals in golems for variants", cat: "enchant", attunement: 'enchanter', attunementLevel: 3, max: 1, base: 600, studyTime: 12, req: { enchanting: 4 } },
// Master Enchanting (Lv 5+)
- soulBinding: { name: "Soul Binding", desc: "Enchantments persist through loops", cat: "enchant", attunement: 'enchanter', attunementLevel: 5, max: 2, base: 1500, studyTime: 24, req: { essenceRefining: 3 } },
- ancientEcho: { name: "Ancient Echo", desc: "+1 enchantment capacity per 2 Enchanter levels", cat: "enchant", attunement: 'enchanter', attunementLevel: 5, max: 5, base: 1000, studyTime: 16 },
+ ancientEcho: { name: "Ancient Echo", desc: "+1 enchantment capacity per Enchanter level", cat: "enchant", attunement: 'enchanter', attunementLevel: 5, max: 3, base: 1000, studyTime: 16 },
+ soulBinding: { name: "Soul Binding", desc: "Bind a defeated guardian's essence to equipment for unique effects", cat: "enchant", attunement: 'enchanter', attunementLevel: 5, max: 2, base: 1500, studyTime: 24, req: { essenceRefining: 3 } },
// Effect Research (Lv 2+)
researchManaSpells: { name: "Mana Spell Research", desc: "Unlock Mana Strike spell enchantment", cat: "effectResearch", attunement: 'enchanter', attunementLevel: 1, max: 1, base: 200, studyTime: 4, req: { enchanting: 1 } },
@@ -905,7 +899,7 @@ export const EFFECT_RESEARCH_MAPPING: Record = {
researchUtilityEffects: ['meditate_10', 'study_10', 'insight_5'],
// Special Effect Research
- researchSpecialEffects: ['spell_echo_10', 'lifesteal_5', 'guardian_dmg_10'],
+ researchSpecialEffects: ['spell_echo_10', 'mana_siphon_5', 'guardian_dmg_10'],
researchOverpower: ['overpower_80'],
};
diff --git a/src/lib/game/data/enchantment-effects.ts b/src/lib/game/data/enchantment-effects.ts
index 4ce053a..3b8ae8d 100755
--- a/src/lib/game/data/enchantment-effects.ts
+++ b/src/lib/game/data/enchantment-effects.ts
@@ -143,7 +143,7 @@ export const ENCHANTMENT_EFFECTS: Record = {
spell_drain: {
id: 'spell_drain',
name: 'Drain',
- description: 'Grants the ability to cast Drain (10 death damage, 20% lifesteal)',
+ description: 'Grants the ability to cast Drain (12 death damage)',
category: 'spell',
baseCapacityCost: 85,
maxStacks: 1,
@@ -153,7 +153,7 @@ export const ENCHANTMENT_EFFECTS: Record = {
spell_lifeTap: {
id: 'spell_lifeTap',
name: 'Life Tap',
- description: 'Grants the ability to cast Life Tap (8 life damage, 30% lifesteal)',
+ description: 'Grants the ability to cast Life Tap (10 life damage, fast cast)',
category: 'spell',
baseCapacityCost: 70,
maxStacks: 1,
@@ -538,15 +538,15 @@ export const ENCHANTMENT_EFFECTS: Record = {
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'special', specialId: 'spellEcho10' }
},
- lifesteal_5: {
- id: 'lifesteal_5',
- name: 'Siphoning',
+ mana_siphon_5: {
+ id: 'mana_siphon_5',
+ name: 'Mana Siphon',
description: '5% of damage dealt is returned as mana',
category: 'special',
baseCapacityCost: 45,
maxStacks: 2,
allowedEquipmentCategories: CASTER_AND_HANDS,
- effect: { type: 'special', specialId: 'lifesteal5' }
+ effect: { type: 'special', specialId: 'manaSiphon5' }
},
guardian_dmg_10: {
id: 'guardian_dmg_10',
diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts
index 03b5c81..ed9bf3e 100755
--- a/src/lib/game/store.ts
+++ b/src/lib/game/store.ts
@@ -45,7 +45,7 @@ import {
import { EQUIPMENT_TYPES } from './data/equipment';
import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from './data/enchantment-effects';
import { ATTUNEMENTS_DEF, getTotalAttunementRegen, getAttunementConversionRate, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } from './data/attunements';
-import { getGuardianPerks, type GuardianPerks } from './utils';
+import { getGuardianPerks, getFloorArmor, type GuardianPerks } from './utils';
// Default empty effects for when effects aren't provided
const DEFAULT_EFFECTS: ComputedEffects = {
@@ -1010,9 +1010,31 @@ export const useGameStore = create()(
// Apply upgrade damage multipliers and bonuses
dmg = dmg * effects.baseDamageMultiplier + effects.baseDamageBonus;
- // Death execute perk: instant kill below 20% HP
- if (spellDef.elem === 'death' && guardianPerks.deathExecute > 0 && floorHP / floorMaxHP < guardianPerks.deathExecute && floorBarrier <= 0) {
- dmg = floorHP; // Execute
+ // Death perk: +50% damage when enemy is below 50% HP
+ if (spellDef.elem === 'death' && guardianPerks.deathLowHpDmg > 0 && floorHP / floorMaxHP < 0.5 && floorBarrier <= 0) {
+ dmg *= (1 + guardianPerks.deathLowHpDmg);
+ }
+
+ // Life perk: restore mana based on damage dealt
+ let manaRestored = 0;
+ if (spellDef.elem === 'life' && guardianPerks.lifeManaRestore > 0) {
+ manaRestored = dmg * guardianPerks.lifeManaRestore;
+ }
+
+ // Water perk: chance to cast twice
+ if (spellDef.elem === 'water' && guardianPerks.waterDoubleCast > 0 && Math.random() < guardianPerks.waterDoubleCast) {
+ dmg *= 2;
+ log = [`🌊 Water Echo! Double damage!`, ...log.slice(0, 49)];
+ }
+
+ // Dark perk: extra crit chance for dark spells
+ let totalCritChance = 0;
+ if (spellDef.elem === 'dark' && guardianPerks.darkCritChance > 0) {
+ totalCritChance += guardianPerks.darkCritChance;
+ }
+ if (Math.random() < totalCritChance) {
+ dmg *= 1.5;
+ log = ['💥 Critical hit!', ...log.slice(0, 49)];
}
// Executioner: +100% damage to enemies below 25% HP (only on main HP, not barrier)
@@ -1032,35 +1054,24 @@ export const useGameStore = create()(
log = [`✨ Spell Echo! Double damage!`, ...log.slice(0, 49)];
}
- // Lifesteal effect from spell
- const spellLifesteal = spellDef.effects?.find(e => e.type === 'lifesteal');
- let totalLifesteal = spellLifesteal?.value || 0;
-
- // Add guardian perk lifesteal for specific elements
- if (spellDef.elem === 'water' && guardianPerks.waterLifesteal > 0) {
- totalLifesteal += guardianPerks.waterLifesteal;
- }
- if (spellDef.elem === 'dark' && guardianPerks.darkLifesteal > 0) {
- totalLifesteal += guardianPerks.darkLifesteal;
- }
- if (spellDef.elem === 'life' && guardianPerks.lifeHealRatio > 0) {
- totalLifesteal += guardianPerks.lifeHealRatio;
+ // Restore mana from life perk
+ if (manaRestored > 0) {
+ rawMana = Math.min(rawMana + manaRestored, maxMana);
}
- if (totalLifesteal > 0) {
- const healAmount = dmg * totalLifesteal;
- rawMana = Math.min(rawMana + healAmount, maxMana);
- }
+ // Apply floor armor (flat damage reduction)
+ const floorArmor = getFloorArmor(currentFloor);
+ const effectiveDmg = Math.max(1, dmg - floorArmor);
// Apply damage to barrier first (if guardian floor)
if (isGuardianFloor && floorBarrier > 0) {
- floorBarrier = Math.max(0, floorBarrier - dmg);
+ floorBarrier = Math.max(0, floorBarrier - effectiveDmg);
if (floorBarrier <= 0) {
log = [`🛡️ Guardian barrier shattered!`, ...log.slice(0, 49)];
}
} else {
// Apply damage to main HP
- floorHP = Math.max(0, floorHP - dmg);
+ floorHP = Math.max(0, floorHP - effectiveDmg);
}
// Reduce cast progress by 1 (one cast completed)
@@ -1361,12 +1372,8 @@ export const useGameStore = create()(
const state = get();
if (!state.currentStudyTarget) return;
- // Knowledge retention bonus
- const retentionBonus = 1 + (state.skills.knowledgeRetention || 0) * 0.2;
- const savedProgress = Math.min(
- state.currentStudyTarget.progress,
- state.currentStudyTarget.required * retentionBonus
- );
+ // Progress is always saved when pausing study - no penalty
+ const savedProgress = state.currentStudyTarget.progress;
// Save progress
if (state.currentStudyTarget.type === 'skill') {
@@ -1377,7 +1384,7 @@ export const useGameStore = create()(
...state.skillProgress,
[state.currentStudyTarget.id]: savedProgress,
},
- log: [`📖 Study interrupted. Progress saved.`, ...state.log.slice(0, 49)],
+ log: [`📖 Study paused. Progress saved.`, ...state.log.slice(0, 49)],
});
} else if (state.currentStudyTarget.type === 'spell') {
set({
@@ -1390,7 +1397,7 @@ export const useGameStore = create()(
studyProgress: savedProgress,
},
},
- log: [`📖 Study interrupted. Progress saved.`, ...state.log.slice(0, 49)],
+ log: [`📖 Study paused. Progress saved.`, ...state.log.slice(0, 49)],
});
}
},
diff --git a/src/lib/game/store/combatSlice.ts b/src/lib/game/store/combatSlice.ts
index 25a1e4c..61c6254 100755
--- a/src/lib/game/store/combatSlice.ts
+++ b/src/lib/game/store/combatSlice.ts
@@ -116,13 +116,6 @@ export const createCombatSlice = (
log.unshift('✨ Spell Echo! Double damage!');
}
- // Lifesteal effect
- const lifestealEffect = spellDef.effects?.find(e => e.type === 'lifesteal');
- if (lifestealEffect) {
- const healAmount = dmg * lifestealEffect.value;
- rawMana = Math.min(rawMana + healAmount, maxMana);
- }
-
// Apply damage
floorHP = Math.max(0, floorHP - dmg);
castProgress -= 1;
diff --git a/src/lib/game/stores/combatStore.ts b/src/lib/game/stores/combatStore.ts
index b0d250e..ec8d146 100755
--- a/src/lib/game/stores/combatStore.ts
+++ b/src/lib/game/stores/combatStore.ts
@@ -197,13 +197,6 @@ export const useCombatStore = create()(
floorHP = Math.max(0, floorHP - damage);
castProgress -= 1;
- // Handle lifesteal
- const lifestealEffect = spellDef.effects?.find(e => e.type === 'lifesteal');
- if (lifestealEffect) {
- const healAmount = damage * lifestealEffect.value;
- rawMana = Math.min(rawMana + healAmount, maxMana);
- }
-
// Check if floor is cleared
if (floorHP <= 0) {
const wasGuardian = GUARDIANS[currentFloor];
diff --git a/src/lib/game/stores/gameStore.ts b/src/lib/game/stores/gameStore.ts
index 4c4701e..7ae0546 100755
--- a/src/lib/game/stores/gameStore.ts
+++ b/src/lib/game/stores/gameStore.ts
@@ -278,13 +278,6 @@ export const useGameStore = create()(
addLog(`✨ Spell Echo! Double damage!`);
}
- // Lifesteal effect
- const lifestealEffect = spellDef.effects?.find(e => e.type === 'lifesteal');
- if (lifestealEffect) {
- const healAmount = dmg * lifestealEffect.value;
- rawMana = Math.min(rawMana + healAmount, maxMana);
- }
-
// Apply damage
floorHP = Math.max(0, floorHP - dmg);
castProgress -= 1;
diff --git a/src/lib/game/types.ts b/src/lib/game/types.ts
index 3bcebd1..e177113 100755
--- a/src/lib/game/types.ts
+++ b/src/lib/game/types.ts
@@ -88,7 +88,7 @@ export interface SpellDef {
}
export interface SpellEffect {
- type: 'lifesteal' | 'burn' | 'freeze' | 'stun' | 'pierce' | 'multicast' | 'shield' | 'buff';
+ type: 'burn' | 'stun' | 'pierce' | 'multicast' | 'buff';
value: number; // Effect potency
duration?: number; // Duration in hours for timed effects
}
diff --git a/src/lib/game/utils.ts b/src/lib/game/utils.ts
index 3345c5b..235f60c 100755
--- a/src/lib/game/utils.ts
+++ b/src/lib/game/utils.ts
@@ -41,6 +41,21 @@ export function getFloorElement(floor: number): string {
return FLOOR_ELEM_CYCLE[(floor - 1) % 8];
}
+// Get floor armor (flat damage reduction)
+// Higher floors have more armor to make them harder to damage
+// Guardian floors have significantly more armor
+export function getFloorArmor(floor: number): number {
+ const isGuardianFloor = !!GUARDIANS[floor];
+
+ // Base armor scales with floor
+ // Non-guardian: 0-10 armor (linear scaling)
+ // Guardian: 5-50 armor (much higher)
+ if (isGuardianFloor) {
+ return Math.floor(5 + floor * 0.5);
+ }
+ return Math.floor(floor * 0.1);
+}
+
// ─── Computed Stats Functions ─────────────────────────────────────────────────
export function computeMaxMana(
@@ -227,13 +242,13 @@ export function getBoonBonuses(signedPacts: number[]): {
// Each guardian grants a unique perk when pact is signed
export interface GuardianPerks {
fireSpellSpeed: number; // Floor 10: Fire spells cast 10% faster
- waterLifesteal: number; // Floor 20: Water spells have 10% lifesteal
+ waterDoubleCast: number; // Floor 20: Water spells have 10% chance to cast twice
airCritChance: number; // Floor 30: Air spells have 15% crit chance
earthGuardianDmg: number; // Floor 40: Earth spells deal +25% damage to guardians
lightDmgBonus: number; // Floor 50: Light spells deal +20% damage
- darkLifesteal: number; // Floor 60: Dark spells have 20% lifesteal
- lifeHealRatio: number; // Floor 70: Life spells heal 30% of damage
- deathExecute: number; // Floor 80: Death spells execute below 20% HP
+ darkCritChance: number; // Floor 60: Dark spells have 25% crit chance
+ lifeManaRestore: number; // Floor 70: Life spells restore 30% of damage as mana
+ deathLowHpDmg: number; // Floor 80: Death spells deal +50% damage to enemies below 50% HP
voidPierce: number; // Floor 90: Void spells ignore 30% resistance
stellarAllDmg: number; // Floor 100: All spells deal +50% damage
stellarSpeed: number; // Floor 100: All spells cast 25% faster
@@ -242,13 +257,13 @@ export interface GuardianPerks {
export function getGuardianPerks(signedPacts: number[]): GuardianPerks {
const perks: GuardianPerks = {
fireSpellSpeed: 0,
- waterLifesteal: 0,
+ waterDoubleCast: 0,
airCritChance: 0,
earthGuardianDmg: 0,
lightDmgBonus: 0,
- darkLifesteal: 0,
- lifeHealRatio: 0,
- deathExecute: 0,
+ darkCritChance: 0,
+ lifeManaRestore: 0,
+ deathLowHpDmg: 0,
voidPierce: 0,
stellarAllDmg: 0,
stellarSpeed: 0,
@@ -257,13 +272,13 @@ export function getGuardianPerks(signedPacts: number[]): GuardianPerks {
for (const floor of signedPacts) {
switch (floor) {
case 10: perks.fireSpellSpeed = 0.10; break; // Fire spells cast 10% faster
- case 20: perks.waterLifesteal = 0.10; break; // Water spells have 10% lifesteal
+ case 20: perks.waterDoubleCast = 0.10; break; // Water spells 10% chance to cast twice
case 30: perks.airCritChance = 0.15; break; // Air spells have 15% crit chance
case 40: perks.earthGuardianDmg = 0.25; break; // Earth spells +25% dmg to guardians
case 50: perks.lightDmgBonus = 0.20; break; // Light spells +20% damage
- case 60: perks.darkLifesteal = 0.20; break; // Dark spells have 20% lifesteal
- case 70: perks.lifeHealRatio = 0.30; break; // Life spells heal 30% of damage
- case 80: perks.deathExecute = 0.20; break; // Death spells execute below 20% HP
+ case 60: perks.darkCritChance = 0.25; break; // Dark spells have 25% crit chance
+ case 70: perks.lifeManaRestore = 0.30; break; // Life spells restore 30% dmg as mana
+ case 80: perks.deathLowHpDmg = 0.50; break; // Death spells +50% dmg to low HP
case 90: perks.voidPierce = 0.30; break; // Void spells ignore 30% resistance
case 100:
perks.stellarAllDmg = 0.50; // All spells +50% damage