diff --git a/docs/project-structure.txt b/docs/project-structure.txt index c7a7dcd..2cdcd72 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -246,6 +246,9 @@ Mana-Loop/ │ │ ├── data/ │ │ │ ├── disciplines/ │ │ │ │ ├── base.ts +│ │ │ │ ├── enchanter-special.ts +│ │ │ │ ├── enchanter-spells.ts +│ │ │ │ ├── enchanter-utility.ts │ │ │ │ ├── enchanter.ts │ │ │ │ ├── fabricator.ts │ │ │ │ ├── index.ts diff --git a/src/lib/game/data/disciplines/enchanter-special.ts b/src/lib/game/data/disciplines/enchanter-special.ts new file mode 100644 index 0000000..f209a48 --- /dev/null +++ b/src/lib/game/data/disciplines/enchanter-special.ts @@ -0,0 +1,70 @@ +// ─── Enchanter Special Disciplines ───────────────────────────────────────────── +// Disciplines for unlocking unique and powerful special enchantment effects + +import type { DisciplineDefinition } from '../../types/disciplines'; + +export const enchanterSpecialDisciplines: DisciplineDefinition[] = [ + { + id: 'study-special-enchantments', + name: 'Study Special Enchantments', + attunement: 'enchanter', + manaType: 'death', + baseCost: 22, + description: 'Learn to enchant equipment with unique and powerful effects.', + statBonus: { stat: 'enchantPower', baseValue: 5 }, + difficultyFactor: 220, + scalingFactor: 130, + drainBase: 4, + requires: ['study-advanced-weapon-enchantments'], + perks: [ + { + id: 'special-spell-echo', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Echo Chamber enchantment', + unlocksEffects: ['spell_echo_10'], + }, + { + id: 'special-guardian-dmg', + type: 'once', + threshold: 80, + value: 0, + description: 'Unlock Bane enchantment', + unlocksEffects: ['guardian_dmg_10'], + }, + { + id: 'special-overpower', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Overpower enchantment', + unlocksEffects: ['overpower_80'], + }, + { + id: 'special-first-strike', + type: 'once', + threshold: 120, + value: 0, + description: 'Unlock First Strike enchantment', + unlocksEffects: ['first_strike'], + }, + { + id: 'special-combo-master', + type: 'once', + threshold: 200, + value: 0, + description: 'Unlock Combo Master enchantment', + unlocksEffects: ['combo_master'], + }, + { + id: 'special-adrenaline-rush', + type: 'once', + threshold: 180, + value: 0, + description: 'Unlock Adrenaline Rush enchantment', + unlocksEffects: ['adrenaline_rush'], + }, + ], + }, +]; diff --git a/src/lib/game/data/disciplines/enchanter-spells.ts b/src/lib/game/data/disciplines/enchanter-spells.ts new file mode 100644 index 0000000..e907a7d --- /dev/null +++ b/src/lib/game/data/disciplines/enchanter-spells.ts @@ -0,0 +1,243 @@ +// ─── Enchanter Spell Disciplines ─────────────────────────────────────────────── +// Disciplines for unlocking spell enchantment effects on casters + +import type { DisciplineDefinition } from '../../types/disciplines'; + +export const enchanterSpellDisciplines: DisciplineDefinition[] = [ + { + id: 'study-basic-spell-enchantments', + name: 'Study Basic Spell Enchantments', + attunement: 'enchanter', + manaType: 'air', + baseCost: 18, + description: 'Learn to enchant casters with basic spell effects.', + statBonus: { stat: 'enchantPower', baseValue: 4 }, + difficultyFactor: 160, + scalingFactor: 100, + drainBase: 3, + perks: [ + { + id: 'spell-mana-bolt', + type: 'once', + threshold: 50, + value: 0, + description: 'Unlock Mana Bolt spell enchant', + unlocksEffects: ['spell_manaBolt'], + }, + { + id: 'spell-fireball', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Fireball spell enchant', + unlocksEffects: ['spell_fireball'], + }, + { + id: 'spell-water-jet', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Water Jet spell enchant', + unlocksEffects: ['spell_waterJet'], + }, + { + id: 'spell-gust', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Gust spell enchant', + unlocksEffects: ['spell_gust'], + }, + { + id: 'spell-stone-bullet', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Stone Bullet spell enchant', + unlocksEffects: ['spell_stoneBullet'], + }, + { + id: 'spell-light-lance', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Light Lance spell enchant', + unlocksEffects: ['spell_lightLance'], + }, + { + id: 'spell-shadow-bolt', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Shadow Bolt spell enchant', + unlocksEffects: ['spell_shadowBolt'], + }, + { + id: 'spell-drain', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Drain spell enchant', + unlocksEffects: ['spell_drain'], + }, + ], + }, + { + id: 'study-intermediate-spell-enchantments', + name: 'Study Intermediate Spell Enchantments', + attunement: 'enchanter', + manaType: 'earth', + baseCost: 25, + description: 'Learn to enchant casters with intermediate and compound spell effects.', + statBonus: { stat: 'enchantPower', baseValue: 6 }, + difficultyFactor: 250, + scalingFactor: 150, + drainBase: 5, + requires: ['study-basic-spell-enchantments'], + perks: [ + { + id: 'spell-inferno', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Inferno spell enchant', + unlocksEffects: ['spell_inferno'], + }, + { + id: 'spell-tidal-wave', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Tidal Wave spell enchant', + unlocksEffects: ['spell_tidalWave'], + }, + { + id: 'spell-earthquake', + type: 'once', + threshold: 120, + value: 0, + description: 'Unlock Earthquake spell enchant', + unlocksEffects: ['spell_earthquake'], + }, + { + id: 'spell-chain-lightning', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Chain Lightning spell enchant', + unlocksEffects: ['spell_chainLightning'], + }, + { + id: 'spell-metal-shard', + type: 'once', + threshold: 80, + value: 0, + description: 'Unlock Metal Shard spell enchant', + unlocksEffects: ['spell_metalShard'], + }, + { + id: 'spell-sand-blast', + type: 'once', + threshold: 80, + value: 0, + description: 'Unlock Sand Blast spell enchant', + unlocksEffects: ['spell_sandBlast'], + }, + ], + }, + { + id: 'study-advanced-spell-enchantments', + name: 'Study Advanced Spell Enchantments', + attunement: 'enchanter', + manaType: 'dark', + baseCost: 35, + description: 'Learn to enchant casters with master and exotic spell effects.', + statBonus: { stat: 'enchantPower', baseValue: 10 }, + difficultyFactor: 350, + scalingFactor: 200, + drainBase: 7, + requires: ['study-intermediate-spell-enchantments'], + perks: [ + { + id: 'spell-pyroclasm', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Pyroclasm spell enchant', + unlocksEffects: ['spell_pyroclasm'], + }, + { + id: 'spell-tsunami', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Tsunami spell enchant', + unlocksEffects: ['spell_tsunami'], + }, + { + id: 'spell-meteor-strike', + type: 'once', + threshold: 120, + value: 0, + description: 'Unlock Meteor Strike spell enchant', + unlocksEffects: ['spell_meteorStrike'], + }, + { + id: 'spell-heaven-light', + type: 'once', + threshold: 100, + value: 0, + description: "Unlock Heaven's Light spell enchant", + unlocksEffects: ['spell_heavenLight'], + }, + { + id: 'spell-oblivion', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Oblivion spell enchant', + unlocksEffects: ['spell_oblivion'], + }, + { + id: 'spell-furnace-blast', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Furnace Blast spell enchant', + unlocksEffects: ['spell_furnaceBlast'], + }, + { + id: 'spell-dune-collapse', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Dune Collapse spell enchant', + unlocksEffects: ['spell_duneCollapse'], + }, + { + id: 'spell-stellar-nova', + type: 'once', + threshold: 200, + value: 0, + description: 'Unlock Stellar Nova spell enchant', + unlocksEffects: ['spell_stellarNova'], + }, + { + id: 'spell-void-collapse', + type: 'once', + threshold: 180, + value: 0, + description: 'Unlock Void Collapse spell enchant', + unlocksEffects: ['spell_voidCollapse'], + }, + { + id: 'spell-crystal-shatter', + type: 'once', + threshold: 160, + value: 0, + description: 'Unlock Crystal Shatter spell enchant', + unlocksEffects: ['spell_crystalShatter'], + }, + ], + }, +]; diff --git a/src/lib/game/data/disciplines/enchanter-utility.ts b/src/lib/game/data/disciplines/enchanter-utility.ts new file mode 100644 index 0000000..a0760de --- /dev/null +++ b/src/lib/game/data/disciplines/enchanter-utility.ts @@ -0,0 +1,107 @@ +// ─── Enchanter Utility & Mana Disciplines ────────────────────────────────────── +// Disciplines for unlocking utility and mana enchantment effects + +import type { DisciplineDefinition } from '../../types/disciplines'; + +export const enchanterUtilityDisciplines: DisciplineDefinition[] = [ + { + id: 'study-utility-enchantments', + name: 'Study Utility Enchantments', + attunement: 'enchanter', + manaType: 'light', + baseCost: 8, + description: 'Learn to enchant equipment with utility effects.', + statBonus: { stat: 'studySpeed', baseValue: 0.05 }, + difficultyFactor: 80, + scalingFactor: 60, + drainBase: 2, + perks: [ + { + id: 'utility-meditate', + type: 'once', + threshold: 50, + value: 0, + description: 'Unlock Meditative Focus enchantment', + unlocksEffects: ['meditate_10'], + }, + { + id: 'utility-study', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Quick Study enchantment', + unlocksEffects: ['study_10'], + }, + { + id: 'utility-insight', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Insightful enchantment', + unlocksEffects: ['insight_5'], + }, + ], + }, + { + id: 'study-mana-enchantments', + name: 'Study Mana Enchantments', + attunement: 'enchanter', + manaType: 'water', + baseCost: 15, + description: 'Learn to enchant equipment with mana-boosting effects.', + statBonus: { stat: 'maxMana', baseValue: 10 }, + difficultyFactor: 150, + scalingFactor: 100, + drainBase: 3, + perks: [ + { + id: 'mana-cap-50', + type: 'once', + threshold: 75, + value: 0, + description: 'Unlock Mana Reserve enchantment', + unlocksEffects: ['mana_cap_50'], + }, + { + id: 'mana-cap-100', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Mana Reservoir enchantment', + unlocksEffects: ['mana_cap_100'], + }, + { + id: 'mana-regen-1', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Trickle enchantment', + unlocksEffects: ['mana_regen_1'], + }, + { + id: 'mana-regen-2', + type: 'once', + threshold: 200, + value: 0, + description: 'Unlock Stream enchantment', + unlocksEffects: ['mana_regen_2'], + }, + { + id: 'click-mana-1', + type: 'once', + threshold: 125, + value: 0, + description: 'Unlock Mana Tap enchantment', + unlocksEffects: ['click_mana_1'], + }, + { + id: 'click-mana-3', + type: 'once', + threshold: 225, + value: 0, + description: 'Unlock Mana Surge enchantment', + unlocksEffects: ['click_mana_3'], + }, + ], + }, +]; diff --git a/src/lib/game/data/disciplines/enchanter.ts b/src/lib/game/data/disciplines/enchanter.ts index 8148572..2399989 100644 --- a/src/lib/game/data/disciplines/enchanter.ts +++ b/src/lib/game/data/disciplines/enchanter.ts @@ -1,5 +1,5 @@ -// ─── Enchanter Discipline Files ────────────────────────────────────────────── -// Attunement-focused disciplines for Enchanter role +// ─── Enchanter Disciplines ──────────────────────────────────────────────────── +// Core enchanter disciplines and weapon enchantment studies import type { DisciplineDefinition } from '../../types/disciplines'; @@ -53,4 +53,89 @@ export const enchanterDisciplines: DisciplineDefinition[] = [ }, ], }, -]; \ No newline at end of file + { + id: 'study-basic-weapon-enchantments', + name: 'Study Basic Weapon Enchantments', + attunement: 'enchanter', + manaType: 'fire', + baseCost: 10, + description: 'Learn to enchant weapons with basic elemental effects.', + statBonus: { stat: 'enchantPower', baseValue: 3 }, + difficultyFactor: 100, + scalingFactor: 80, + drainBase: 2, + perks: [ + { + id: 'basic-weapon-fire', + type: 'once', + threshold: 50, + value: 0, + description: 'Unlock Fire Enchant for weapons', + unlocksEffects: ['sword_fire'], + }, + { + id: 'basic-weapon-frost', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Frost Enchant for weapons', + unlocksEffects: ['sword_frost'], + }, + { + id: 'basic-weapon-lightning', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Lightning Enchant for weapons', + unlocksEffects: ['sword_lightning'], + }, + ], + }, + { + id: 'study-advanced-weapon-enchantments', + name: 'Study Advanced Weapon Enchantments', + attunement: 'enchanter', + manaType: 'dark', + baseCost: 20, + description: 'Learn to enchant weapons with exotic and combat effects.', + statBonus: { stat: 'enchantPower', baseValue: 5 }, + difficultyFactor: 200, + scalingFactor: 120, + drainBase: 4, + requires: ['study-basic-weapon-enchantments'], + perks: [ + { + id: 'advanced-weapon-void', + type: 'once', + threshold: 100, + value: 0, + description: 'Unlock Void Enchant for weapons', + unlocksEffects: ['sword_void'], + }, + { + id: 'advanced-weapon-damage-5', + type: 'once', + threshold: 150, + value: 0, + description: 'Unlock Minor Power enchantment', + unlocksEffects: ['damage_5'], + }, + { + id: 'advanced-weapon-crit', + type: 'once', + threshold: 200, + value: 0, + description: 'Unlock Sharp Edge enchantment', + unlocksEffects: ['crit_5'], + }, + { + id: 'advanced-weapon-attack-speed', + type: 'once', + threshold: 250, + value: 0, + description: 'Unlock Swift Casting enchantment', + unlocksEffects: ['attack_speed_10'], + }, + ], + }, +]; diff --git a/src/lib/game/data/disciplines/index.ts b/src/lib/game/data/disciplines/index.ts index 8c6ced1..58645f8 100644 --- a/src/lib/game/data/disciplines/index.ts +++ b/src/lib/game/data/disciplines/index.ts @@ -3,6 +3,9 @@ import { baseDisciplines } from './base'; import { enchanterDisciplines } from './enchanter'; +import { enchanterUtilityDisciplines } from './enchanter-utility'; +import { enchanterSpellDisciplines } from './enchanter-spells'; +import { enchanterSpecialDisciplines } from './enchanter-special'; import { fabricatorDisciplines } from './fabricator'; import { invokerDisciplines } from './invoker'; import type { DisciplineDefinition } from '../../types/disciplines'; @@ -10,11 +13,17 @@ import type { DisciplineDefinition } from '../../types/disciplines'; export const ALL_DISCIPLINES: DisciplineDefinition[] = [ ...baseDisciplines, ...enchanterDisciplines, + ...enchanterUtilityDisciplines, + ...enchanterSpellDisciplines, + ...enchanterSpecialDisciplines, ...fabricatorDisciplines, ...invokerDisciplines, ]; export { baseDisciplines } from './base'; export { enchanterDisciplines } from './enchanter'; +export { enchanterUtilityDisciplines } from './enchanter-utility'; +export { enchanterSpellDisciplines } from './enchanter-spells'; +export { enchanterSpecialDisciplines } from './enchanter-special'; export { fabricatorDisciplines } from './fabricator'; export { invokerDisciplines } from './invoker'; diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index cb9277f..191ce02 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -335,6 +335,21 @@ export const useCraftingStore = create()( unequipItem: (slot: EquipmentSlot) => { unequipItemAction(slot, set); }, + + unlockEffects: (effectIds: string[]) => { + set((state) => { + const existing = new Set(state.unlockedEffects); + let changed = false; + for (const id of effectIds) { + if (!existing.has(id)) { + existing.add(id); + changed = true; + } + } + if (!changed) return state; + return { unlockedEffects: Array.from(existing) }; + }); + }, }; }, { diff --git a/src/lib/game/stores/craftingStore.types.ts b/src/lib/game/stores/craftingStore.types.ts index 944631f..71a3f79 100644 --- a/src/lib/game/stores/craftingStore.types.ts +++ b/src/lib/game/stores/craftingStore.types.ts @@ -69,6 +69,7 @@ export interface CraftingActions { setSelectedEquipmentInstance: (id: string | null) => void; resetEnchantmentSelection: () => void; clearLastError: () => void; + unlockEffects: (effectIds: string[]) => void; } export type CraftingStore = CraftingState & CraftingActions; diff --git a/src/lib/game/stores/discipline-slice.ts b/src/lib/game/stores/discipline-slice.ts index 239b497..70d235d 100644 --- a/src/lib/game/stores/discipline-slice.ts +++ b/src/lib/game/stores/discipline-slice.ts @@ -7,9 +7,13 @@ import { calculateManaDrain, calculateStatBonus, canProceedDiscipline, + getUnlockedPerks, } from '../utils/discipline-math'; import { baseDisciplines } from '../data/disciplines/base'; import { enchanterDisciplines } from '../data/disciplines/enchanter'; +import { enchanterUtilityDisciplines } from '../data/disciplines/enchanter-utility'; +import { enchanterSpellDisciplines } from '../data/disciplines/enchanter-spells'; +import { enchanterSpecialDisciplines } from '../data/disciplines/enchanter-special'; import { fabricatorDisciplines } from '../data/disciplines/fabricator'; import { invokerDisciplines } from '../data/disciplines/invoker'; import { MAX_CONCURRENT_DISCIPLINES } from '../types/disciplines'; @@ -17,6 +21,9 @@ import { MAX_CONCURRENT_DISCIPLINES } from '../types/disciplines'; const ALL_DISCIPLINES = [ ...baseDisciplines, ...enchanterDisciplines, + ...enchanterUtilityDisciplines, + ...enchanterSpellDisciplines, + ...enchanterSpecialDisciplines, ...fabricatorDisciplines, ...invokerDisciplines, ]; @@ -27,6 +34,7 @@ export interface DisciplineStoreState { activeIds: string[]; concurrentLimit: number; totalXP: number; + processedPerks: string[]; } export interface DisciplineStoreActions { @@ -35,6 +43,7 @@ export interface DisciplineStoreActions { processTick: (mana: { rawMana: number; elements: Record }) => { rawMana: number; elements: Record; + unlockedEffects: string[]; }; } @@ -47,6 +56,7 @@ export const useDisciplineStore = create()( activeIds: [], concurrentLimit: MAX_CONCURRENT_DISCIPLINES, totalXP: 0, + processedPerks: [], activate(id, gameState) { set((s) => { @@ -95,6 +105,8 @@ export const useDisciplineStore = create()( const elements = { ...mana.elements }; let newXP = s.totalXP; const newDisciplines = { ...s.disciplines }; + const newUnlockedEffects: string[] = []; + const newProcessedPerks = [...s.processedPerks]; for (const id of s.activeIds) { const disc = newDisciplines[id]; @@ -122,8 +134,25 @@ export const useDisciplineStore = create()( }; } + const oldXP = disc.xp; newDisciplines[id] = { ...disc, xp: disc.xp + 1 }; newXP += 1; + + // Check for newly unlocked perks that unlock effects + if (def.perks.length > 0) { + const oldPerks = getUnlockedPerks(def, oldXP); + const newPerks = getUnlockedPerks(def, disc.xp + 1); + const oldPerkIds = new Set(oldPerks.map(p => p.id)); + for (const perk of newPerks) { + if (!oldPerkIds.has(perk.id) && perk.unlocksEffects) { + const perkKey = `${id}:${perk.id}`; + if (!newProcessedPerks.includes(perkKey)) { + newUnlockedEffects.push(...perk.unlocksEffects); + newProcessedPerks.push(perkKey); + } + } + } + } } const newLimit = Math.min( @@ -135,9 +164,10 @@ export const useDisciplineStore = create()( disciplines: newDisciplines, totalXP: newXP, concurrentLimit: Math.max(s.concurrentLimit, newLimit), + processedPerks: newProcessedPerks, }); - return { rawMana, elements }; + return { rawMana, elements, unlockedEffects: newUnlockedEffects }; }, }), { storage: createSafeStorage(), name: 'mana-loop-discipline-store' } diff --git a/src/lib/game/stores/gameStore.ts b/src/lib/game/stores/gameStore.ts index 2dfb225..3d1772e 100755 --- a/src/lib/game/stores/gameStore.ts +++ b/src/lib/game/stores/gameStore.ts @@ -267,6 +267,14 @@ export const useGameStore = create()( rawMana = disciplineResult.rawMana; elements = disciplineResult.elements; + // Unlock enchantment effects from newly unlocked discipline perks + if (disciplineResult.unlockedEffects.length > 0) { + useCraftingStore.getState().unlockEffects(disciplineResult.unlockedEffects); + for (const effectId of disciplineResult.unlockedEffects) { + addLog(`✨ Discipline insight unlocked: ${effectId}`); + } + } + // Combat — delegate to combatStore if (ctx.combat.currentAction === 'climb') { const combatResult = useCombatStore.getState().processCombatTick( diff --git a/src/lib/game/types/disciplines.ts b/src/lib/game/types/disciplines.ts index 0610e42..dff90e7 100644 --- a/src/lib/game/types/disciplines.ts +++ b/src/lib/game/types/disciplines.ts @@ -19,6 +19,7 @@ export interface DisciplinePerk { threshold: number; value: number; description: string; + unlocksEffects?: string[]; } // ─── Discipline Definition ────────────────────────────────────────────────────