feat: implement attunement leveling and debug functions
All checks were successful
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 2m4s
All checks were successful
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 2m4s
- 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
This commit is contained in:
@@ -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<GameStore>()(
|
||||
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<GameStore>()(
|
||||
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',
|
||||
|
||||
Reference in New Issue
Block a user