From 4748b81fe68bd412a002cfca978de2890a62ec58 Mon Sep 17 00:00:00 2001 From: zhipu Date: Fri, 27 Mar 2026 18:55:22 +0000 Subject: [PATCH] feat: implement attunement leveling and debug functions - Add attunement XP system with level-scaled progression (100 * 3^(level-2) XP per level) - Add addAttunementXP function with automatic level-up handling - Add debug functions: debugUnlockAttunement, debugAddElementalMana, debugSetTime, debugAddAttunementXP, debugSetFloor - Update attunement conversion to use level-scaled conversion rate - Import getAttunementConversionRate, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL in store --- src/lib/game/store.ts | 151 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts index ff661b6..0c37af6 100755 --- a/src/lib/game/store.ts +++ b/src/lib/game/store.ts @@ -39,7 +39,7 @@ import { } from './crafting-slice'; import { EQUIPMENT_TYPES } from './data/equipment'; import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from './data/enchantment-effects'; -import { ATTUNEMENTS_DEF, getTotalAttunementRegen } from './data/attunements'; +import { ATTUNEMENTS_DEF, getTotalAttunementRegen, getAttunementConversionRate, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } from './data/attunements'; // Default empty effects for when effects aren't provided const DEFAULT_EFFECTS: ComputedEffects = { @@ -568,6 +568,16 @@ interface GameStore extends GameState, CraftingActions { commitSkillUpgrades: (skillId: string, upgradeIds: string[]) => void; tierUpSkill: (skillId: string) => void; + // Attunement XP and leveling + addAttunementXP: (attunementId: string, amount: number) => void; + + // Debug functions + debugUnlockAttunement: (attunementId: string) => void; + debugAddElementalMana: (element: string, amount: number) => void; + debugSetTime: (day: number, hour: number) => void; + debugAddAttunementXP: (attunementId: string, amount: number) => void; + debugSetFloor: (floor: number) => void; + // Computed getters getMaxMana: () => number; getRegen: () => number; @@ -679,8 +689,11 @@ export const useGameStore = create()( const elem = elements[attDef.primaryManaType]; if (!elem || !elem.unlocked) return; + // Get level-scaled conversion rate + const scaledConversionRate = getAttunementConversionRate(attId, attState.level || 1); + // Convert raw mana to primary type - const conversionAmount = attDef.conversionRate * HOURS_PER_TICK; + const conversionAmount = scaledConversionRate * HOURS_PER_TICK; const actualConversion = Math.min(conversionAmount, rawMana, elem.max - elem.current); if (actualConversion > 0) { @@ -1668,6 +1681,140 @@ export const useGameStore = create()( if (!instance) return 0; return instance.totalCapacity - instance.usedCapacity; }, + + // Attunement XP and leveling + addAttunementXP: (attunementId: string, amount: number) => { + const state = get(); + const attState = state.attunements[attunementId]; + if (!attState?.active) return; + + let newXP = attState.experience + amount; + let newLevel = attState.level; + + // Check for level ups + while (newLevel < MAX_ATTUNEMENT_LEVEL) { + const xpNeeded = getAttunementXPForLevel(newLevel + 1); + if (newXP >= xpNeeded) { + newXP -= xpNeeded; + newLevel++; + } else { + break; + } + } + + // Cap XP at max level + if (newLevel >= MAX_ATTUNEMENT_LEVEL) { + newXP = 0; + } + + set({ + attunements: { + ...state.attunements, + [attunementId]: { + ...attState, + level: newLevel, + experience: newXP, + }, + }, + log: newLevel > attState.level + ? [`🌟 ${attunementId} attunement reached Level ${newLevel}!`, ...state.log.slice(0, 49)] + : state.log, + }); + }, + + // Debug functions + debugUnlockAttunement: (attunementId: string) => { + const state = get(); + const def = ATTUNEMENTS_DEF[attunementId]; + if (!def) return; + + set({ + attunements: { + ...state.attunements, + [attunementId]: { + id: attunementId, + active: true, + level: 1, + experience: 0, + }, + }, + // Unlock the primary mana type if applicable + elements: def.primaryManaType && state.elements[def.primaryManaType] + ? { + ...state.elements, + [def.primaryManaType]: { + ...state.elements[def.primaryManaType], + unlocked: true, + }, + } + : state.elements, + log: [`🔓 Debug: Unlocked ${def.name} attunement!`, ...state.log.slice(0, 49)], + }); + }, + + debugAddElementalMana: (element: string, amount: number) => { + const state = get(); + const elem = state.elements[element]; + if (!elem?.unlocked) return; + + set({ + elements: { + ...state.elements, + [element]: { + ...elem, + current: Math.min(elem.current + amount, elem.max * 10), // Allow overflow + }, + }, + }); + }, + + debugSetTime: (day: number, hour: number) => { + set({ + day, + hour, + incursionStrength: getIncursionStrength(day, hour), + }); + }, + + debugAddAttunementXP: (attunementId: string, amount: number) => { + const state = get(); + const attState = state.attunements[attunementId]; + if (!attState) return; + + let newXP = attState.experience + amount; + let newLevel = attState.level; + + while (newLevel < MAX_ATTUNEMENT_LEVEL) { + const xpNeeded = getAttunementXPForLevel(newLevel + 1); + if (newXP >= xpNeeded) { + newXP -= xpNeeded; + newLevel++; + } else { + break; + } + } + + set({ + attunements: { + ...state.attunements, + [attunementId]: { + ...attState, + level: newLevel, + experience: newXP, + }, + }, + }); + }, + + debugSetFloor: (floor: number) => { + const state = get(); + set({ + currentFloor: floor, + floorHP: getFloorMaxHP(floor), + floorMaxHP: getFloorMaxHP(floor), + maxFloorReached: Math.max(state.maxFloorReached, floor), + }); + }, }), { name: 'mana-loop-storage',