From 93e41cfc765e92542f4f4538f7a16d49e2bcffa6 Mon Sep 17 00:00:00 2001 From: zhipu Date: Fri, 27 Mar 2026 15:54:13 +0000 Subject: [PATCH] feat: Add attunement system foundation - Create attunements.ts with 7 attunement types: - Enchanter (right hand) - Transference mana, enchanting - Caster (left hand) - Form mana, spell damage - Seer (head) - Vision mana, critical hits - Warden (back) - Barrier mana, defense - Invoker (chest) - Guardian pact mana types - Strider (left leg) - Flow mana, speed - Anchor (right leg) - Stability mana, max mana - Add AttunementState, ManaType types - Add attunement fields to GameState - Update SkillDef to include attunement field --- src/lib/game/attunements.ts | 567 ++++++++++++++++++++++++++++++++++++ src/lib/game/types.ts | 15 + 2 files changed, 582 insertions(+) create mode 100644 src/lib/game/attunements.ts diff --git a/src/lib/game/attunements.ts b/src/lib/game/attunements.ts new file mode 100644 index 0000000..5ccddde --- /dev/null +++ b/src/lib/game/attunements.ts @@ -0,0 +1,567 @@ +// ─── Attunement System ───────────────────────────────────────────────────────── +// Attunements are powerful magical bonds tied to specific body locations +// Each grants a unique capability, primary mana type, and skill tree + +import type { SkillDef } from './types'; + +// ─── Body Slots ─────────────────────────────────────────────────────────────── + +export type AttunementSlot = + | 'rightHand' + | 'leftHand' + | 'head' + | 'back' + | 'chest' + | 'leftLeg' + | 'rightLeg'; + +export const ATTUNEMENT_SLOTS: AttunementSlot[] = [ + 'rightHand', + 'leftHand', + 'head', + 'back', + 'chest', + 'leftLeg', + 'rightLeg', +]; + +// Slot display names +export const ATTUNEMENT_SLOT_NAMES: Record = { + rightHand: 'Right Hand', + leftHand: 'Left Hand', + head: 'Head', + back: 'Back', + chest: 'Heart', + leftLeg: 'Left Leg', + rightLeg: 'Right Leg', +}; + +// ─── Mana Types ─────────────────────────────────────────────────────────────── + +export type ManaType = + // Primary mana types from attunements + | 'transference' // Enchanter - moving/enchanting + | 'form' // Caster - shaping spells + | 'vision' // Seer - perception/revelation + | 'barrier' // Warden - protection/defense + | 'flow' // Strider - movement/swiftness + | 'stability' // Anchor - grounding/endurance + // Guardian pact types (Invoker) + | 'fire' + | 'water' + | 'earth' + | 'air' + | 'light' + | 'dark' + | 'life' + | 'death' + // Raw mana + | 'raw'; + +// ─── Attunement Types ───────────────────────────────────────────────────────── + +export type AttunementType = + | 'enchanter' + | 'caster' + | 'seer' + | 'warden' + | 'invoker' + | 'strider' + | 'anchor'; + +// ─── Attunement Definition ──────────────────────────────────────────────────── + +export interface AttunementDef { + id: AttunementType; + name: string; + slot: AttunementSlot; + description: string; + capability: string; // What this attunement unlocks + primaryManaType: ManaType | null; // null for Invoker (uses guardian types) + rawManaRegen: number; // Base raw mana regen bonus + autoConvertRate: number; // Raw mana -> primary mana per hour + skills: Record; // Attunement-specific skills + icon: string; // Lucide icon name + color: string; // Theme color +} + +// ─── Attunement State ───────────────────────────────────────────────────────── + +export interface AttunementState { + unlocked: boolean; + level: number; // Attunement level (from challenges) + manaPool: number; // Current primary mana + maxMana: number; // Max primary mana pool +} + +// ─── Attunement Definitions ─────────────────────────────────────────────────── + +export const ATTUNEMENTS: Record = { + // ═══════════════════════════════════════════════════════════════════════════ + // ENCHANTER - Right Hand + // The starting attunement. Grants access to enchanting and transference magic. + // ═══════════════════════════════════════════════════════════════════════════ + enchanter: { + id: 'enchanter', + name: 'Enchanter', + slot: 'rightHand', + description: 'Channel mana through your right hand to imbue equipment with magical properties.', + capability: 'Unlock enchanting. Apply enchantments using transference mana.', + primaryManaType: 'transference', + rawManaRegen: 0.5, + autoConvertRate: 0.2, // 0.2 transference per hour per raw regen + icon: 'Wand2', + color: '#8B5CF6', // Purple + skills: { + // Core enchanting skills + enchanting: { + name: 'Enchanting', + desc: 'Apply magical effects to equipment', + cat: 'enchanter', + max: 10, + base: 100, + studyTime: 8, + }, + efficientEnchant: { + name: 'Efficient Enchanting', + desc: 'Reduce enchantment mana costs', + cat: 'enchanter', + max: 5, + base: 200, + studyTime: 12, + req: { enchanting: 3 }, + }, + disenchanting: { + name: 'Disenchanting', + desc: 'Remove enchantments and recover some mana', + cat: 'enchanter', + max: 5, + base: 150, + studyTime: 10, + req: { enchanting: 2 }, + }, + enchantSpeed: { + name: 'Swift Enchanting', + desc: 'Faster enchantment application', + cat: 'enchanter', + max: 5, + base: 175, + studyTime: 10, + req: { enchanting: 2 }, + }, + transferenceMastery: { + name: 'Transference Mastery', + desc: 'Increased transference mana pool and regen', + cat: 'enchanter', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // CASTER - Left Hand + // Shapes raw mana into spell patterns. Enhanced spell damage. + // ═══════════════════════════════════════════════════════════════════════════ + caster: { + id: 'caster', + name: 'Caster', + slot: 'leftHand', + description: 'Shape mana into devastating spell patterns through your left hand.', + capability: 'Form mana shaping. +25% spell damage bonus.', + primaryManaType: 'form', + rawManaRegen: 0.3, + autoConvertRate: 0.15, + icon: 'Hand', + color: '#3B82F6', // Blue + skills: { + spellShaping: { + name: 'Spell Shaping', + desc: 'Increase spell damage and efficiency', + cat: 'caster', + max: 10, + base: 100, + studyTime: 8, + }, + quickCast: { + name: 'Quick Cast', + desc: 'Faster spell casting speed', + cat: 'caster', + max: 10, + base: 120, + studyTime: 8, + }, + spellEcho: { + name: 'Spell Echo', + desc: 'Chance to cast spells twice', + cat: 'caster', + max: 5, + base: 300, + studyTime: 15, + req: { spellShaping: 5 }, + }, + formMastery: { + name: 'Form Mastery', + desc: 'Increased form mana pool and regen', + cat: 'caster', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // SEER - Head + // Perception and revelation. Critical hit bonus and weakness detection. + // ═══════════════════════════════════════════════════════════════════════════ + seer: { + id: 'seer', + name: 'Seer', + slot: 'head', + description: 'See beyond the veil. Reveal hidden truths and enemy weaknesses.', + capability: 'Reveal floor weaknesses. +20% critical hit chance.', + primaryManaType: 'vision', + rawManaRegen: 0.2, + autoConvertRate: 0.1, + icon: 'Eye', + color: '#F59E0B', // Amber + skills: { + insight: { + name: 'Insight', + desc: 'Increased critical hit chance', + cat: 'seer', + max: 10, + base: 100, + studyTime: 8, + }, + revealWeakness: { + name: 'Reveal Weakness', + desc: 'Show enemy elemental weaknesses', + cat: 'seer', + max: 5, + base: 200, + studyTime: 12, + }, + foresight: { + name: 'Foresight', + desc: 'Chance to anticipate and dodge attacks', + cat: 'seer', + max: 5, + base: 250, + studyTime: 15, + req: { insight: 5 }, + }, + visionMastery: { + name: 'Vision Mastery', + desc: 'Increased vision mana pool and regen', + cat: 'seer', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // WARDEN - Back + // Protection and defense. Damage reduction and shields. + // ═══════════════════════════════════════════════════════════════════════════ + warden: { + id: 'warden', + name: 'Warden', + slot: 'back', + description: 'Shield yourself with protective wards and barriers.', + capability: 'Generate protective shields. -10% damage taken.', + primaryManaType: 'barrier', + rawManaRegen: 0.25, + autoConvertRate: 0.12, + icon: 'Shield', + color: '#10B981', // Green + skills: { + warding: { + name: 'Warding', + desc: 'Generate protective shields', + cat: 'warden', + max: 10, + base: 100, + studyTime: 8, + }, + fortitude: { + name: 'Fortitude', + desc: 'Reduce damage taken', + cat: 'warden', + max: 10, + base: 150, + studyTime: 10, + }, + reflection: { + name: 'Reflection', + desc: 'Chance to reflect damage to attacker', + cat: 'warden', + max: 5, + base: 300, + studyTime: 15, + req: { warding: 5 }, + }, + barrierMastery: { + name: 'Barrier Mastery', + desc: 'Increased barrier mana pool and regen', + cat: 'warden', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // INVOKER - Chest/Heart + // Pact with guardians. No primary mana - uses guardian elemental types. + // ═══════════════════════════════════════════════════════════════════════════ + invoker: { + id: 'invoker', + name: 'Invoker', + slot: 'chest', + description: 'Form pacts with spire guardians and channel their elemental power.', + capability: 'Pact with guardians. Gain mana types from pacted guardians.', + primaryManaType: null, // Uses guardian types instead + rawManaRegen: 0.4, + autoConvertRate: 0, // No auto-convert; mana comes from guardian pacts + icon: 'Heart', + color: '#EF4444', // Red + skills: { + pactMaking: { + name: 'Pact Making', + desc: 'Form stronger pacts with guardians', + cat: 'invoker', + max: 10, + base: 100, + studyTime: 8, + }, + guardianChannel: { + name: 'Guardian Channeling', + desc: 'Channel guardian powers more effectively', + cat: 'invoker', + max: 10, + base: 150, + studyTime: 10, + }, + elementalBurst: { + name: 'Elemental Burst', + desc: 'Unleash stored guardian energy', + cat: 'invoker', + max: 5, + base: 300, + studyTime: 15, + req: { pactMaking: 5, guardianChannel: 3 }, + }, + soulResonance: { + name: 'Soul Resonance', + desc: 'Deep bond with pacted guardians', + cat: 'invoker', + max: 5, + base: 400, + studyTime: 20, + req: { pactMaking: 8 }, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // STRIDER - Left Leg + // Movement and swiftness. Attack speed and mobility. + // ═══════════════════════════════════════════════════════════════════════════ + strider: { + id: 'strider', + name: 'Strider', + slot: 'leftLeg', + description: 'Move with supernatural speed and grace.', + capability: 'Enhanced mobility. +15% attack speed.', + primaryManaType: 'flow', + rawManaRegen: 0.3, + autoConvertRate: 0.15, + icon: 'Zap', + color: '#06B6D4', // Cyan + skills: { + swiftness: { + name: 'Swiftness', + desc: 'Increased attack and movement speed', + cat: 'strider', + max: 10, + base: 100, + studyTime: 8, + }, + evasive: { + name: 'Evasive', + desc: 'Chance to avoid damage', + cat: 'strider', + max: 5, + base: 200, + studyTime: 12, + }, + momentum: { + name: 'Momentum', + desc: 'Build speed over consecutive attacks', + cat: 'strider', + max: 5, + base: 250, + studyTime: 15, + req: { swiftness: 5 }, + }, + flowMastery: { + name: 'Flow Mastery', + desc: 'Increased flow mana pool and regen', + cat: 'strider', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // ANCHOR - Right Leg + // Stability and endurance. Max mana and knockback resistance. + // ═══════════════════════════════════════════════════════════════════════════ + anchor: { + id: 'anchor', + name: 'Anchor', + slot: 'rightLeg', + description: 'Stand firm against any force. Your foundation is unshakeable.', + capability: 'Increased stability. +100 max mana.', + primaryManaType: 'stability', + rawManaRegen: 0.35, + autoConvertRate: 0.18, + icon: 'Mountain', + color: '#78716C', // Stone gray + skills: { + grounding: { + name: 'Grounding', + desc: 'Increased max mana and stability', + cat: 'anchor', + max: 10, + base: 100, + studyTime: 8, + }, + endurance: { + name: 'Endurance', + desc: 'Reduced mana costs when below 50% mana', + cat: 'anchor', + max: 5, + base: 200, + studyTime: 12, + }, + ironWill: { + name: 'Iron Will', + desc: 'Prevent mana drain effects', + cat: 'anchor', + max: 5, + base: 250, + studyTime: 15, + req: { grounding: 5 }, + }, + stabilityMastery: { + name: 'Stability Mastery', + desc: 'Increased stability mana pool and regen', + cat: 'anchor', + max: 10, + base: 250, + studyTime: 15, + }, + }, + }, +}; + +// ─── Helper Functions ───────────────────────────────────────────────────────── + +/** + * Get the attunement for a specific body slot + */ +export function getAttunementForSlot(slot: AttunementSlot): AttunementDef | undefined { + return Object.values(ATTUNEMENTS).find(a => a.slot === slot); +} + +/** + * Get the starting attunement (Enchanter - right hand) + */ +export function getStartingAttunement(): AttunementDef { + return ATTUNEMENTS.enchanter; +} + +/** + * Check if an attunement is unlocked for the player + */ +export function isAttunementUnlocked( + attunementStates: Record, + attunementType: AttunementType +): boolean { + return attunementStates[attunementType]?.unlocked ?? false; +} + +/** + * Get total raw mana regen from all unlocked attunements + */ +export function getTotalAttunementRegen( + attunementStates: Record +): number { + let total = 0; + for (const [type, state] of Object.entries(attunementStates)) { + if (state.unlocked) { + const def = ATTUNEMENTS[type as AttunementType]; + if (def) { + total += def.rawManaRegen * (1 + state.level * 0.1); // +10% per level + } + } + } + return total; +} + +/** + * Get mana type display name + */ +export function getManaTypeName(type: ManaType): string { + const names: Record = { + raw: 'Raw Mana', + transference: 'Transference', + form: 'Form', + vision: 'Vision', + barrier: 'Barrier', + flow: 'Flow', + stability: 'Stability', + fire: 'Fire', + water: 'Water', + earth: 'Earth', + air: 'Air', + light: 'Light', + dark: 'Dark', + life: 'Life', + death: 'Death', + }; + return names[type] || type; +} + +/** + * Get mana type color + */ +export function getManaTypeColor(type: ManaType): string { + const colors: Record = { + raw: '#A78BFA', // Light purple + transference: '#8B5CF6', // Purple + form: '#3B82F6', // Blue + vision: '#F59E0B', // Amber + barrier: '#10B981', // Green + flow: '#06B6D4', // Cyan + stability: '#78716C', // Stone + fire: '#EF4444', // Red + water: '#3B82F6', // Blue + earth: '#A16207', // Brown + air: '#94A3B8', // Slate + light: '#FCD34D', // Yellow + dark: '#6B7280', // Gray + life: '#22C55E', // Green + death: '#7C3AED', // Violet + }; + return colors[type] || '#A78BFA'; +} diff --git a/src/lib/game/types.ts b/src/lib/game/types.ts index 3fbcb24..e159dbc 100755 --- a/src/lib/game/types.ts +++ b/src/lib/game/types.ts @@ -1,5 +1,11 @@ // ─── Game Types ─────────────────────────────────────────────────────────────── +import type { AttunementType, AttunementState, ManaType } from './attunements'; + +// Re-export attunement types +export type { AttunementType, AttunementState, ManaType, AttunementSlot } from './attunements'; +export { ATTUNEMENT_SLOTS } from './attunements'; + export type ElementCategory = 'base' | 'utility' | 'composite' | 'exotic'; // Equipment slots for the equipment system @@ -86,6 +92,8 @@ export interface SkillDef { tierUp?: string; // Skill ID this evolves into at max level baseSkill?: string; // Original skill ID this evolved from tierMultiplier?: number; // Multiplier for each tier (default 2) + attunement?: AttunementType; // Which attunement this skill belongs to (if any) + manaType?: ManaType; // Primary mana type used (if attunement-specific) } // Skill upgrade choices at milestones (level 5 and level 10) @@ -423,6 +431,13 @@ export interface GameState { memorySlots: number; memories: string[]; + // Attunement System + attunements: Record; // Attunement unlock and state + attunementSkills: Record; // Attunement-specific skill levels + attunementSkillProgress: Record; // Progress for attunement skills + primaryMana: Record; // Primary mana pools by type + primaryManaMax: Record; // Max primary mana by type + // Incursion incursionStrength: number; containmentWards: number;