fix: SLOT_NAMES export and refactor: split crafting-slice.ts into modules
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m51s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m51s
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
// ─── Crafting Application System ────────────────────────────────────────────
|
||||
// Application system functions extracted from crafting-slice.ts
|
||||
|
||||
import type { EquipmentInstance, AppliedEnchantment, EnchantmentDesign, ApplicationProgress } from './types';
|
||||
import { calculateApplicationTime, calculateApplicationManaPerHour } from './crafting-utils';
|
||||
import { hasSpecial, SPECIAL_EFFECTS } from './special-effects';
|
||||
import { computeEffects } from './upgrade-effects';
|
||||
import type { AttunementState } from './types';
|
||||
import { calculateEnchantingXP } from './data/attunements';
|
||||
import { ENCHANTMENT_EFFECTS } from './data/enchantment-effects';
|
||||
|
||||
// ─── Application Validation ─────────────────────────────────────────────────
|
||||
|
||||
// Check if enchantment application can start
|
||||
export function canApplyEnchantment(
|
||||
instance: EquipmentInstance | undefined,
|
||||
design: EnchantmentDesign | undefined,
|
||||
currentAction: string
|
||||
): { canApply: boolean; reason?: string } {
|
||||
if (!instance) {
|
||||
return { canApply: false, reason: 'Equipment instance not found' };
|
||||
}
|
||||
|
||||
if (!design) {
|
||||
return { canApply: false, reason: 'Enchantment design not found' };
|
||||
}
|
||||
|
||||
if (currentAction !== 'meditate') {
|
||||
return { canApply: false, reason: 'Must be in meditate state' };
|
||||
}
|
||||
|
||||
if (!instance.tags?.includes('Ready for Enchantment')) {
|
||||
return { canApply: false, reason: 'Equipment must be prepared for enchanting' };
|
||||
}
|
||||
|
||||
if (instance.usedCapacity + design.totalCapacityUsed > instance.totalCapacity) {
|
||||
return { canApply: false, reason: 'Not enough capacity on equipment' };
|
||||
}
|
||||
|
||||
return { canApply: true };
|
||||
}
|
||||
|
||||
// ─── Application Resource Calculation ────────────────────────────────────────
|
||||
|
||||
export interface ApplicationCosts {
|
||||
time: number;
|
||||
manaPerHour: number;
|
||||
manaPerTick: number;
|
||||
}
|
||||
|
||||
export function calculateApplicationCosts(design: EnchantmentDesign): ApplicationCosts {
|
||||
const time = calculateApplicationTime(design);
|
||||
const manaPerHour = calculateApplicationManaPerHour(design);
|
||||
const manaPerTick = manaPerHour * 0.04; // HOURS_PER_TICK
|
||||
|
||||
return { time, manaPerHour, manaPerTick };
|
||||
}
|
||||
|
||||
// ─── Application Progress ───────────────────────────────────────────────────
|
||||
|
||||
// Initialize application progress
|
||||
export function initializeApplicationProgress(
|
||||
equipmentInstanceId: string,
|
||||
designId: string,
|
||||
design: EnchantmentDesign
|
||||
): ApplicationProgress {
|
||||
const costs = calculateApplicationCosts(design);
|
||||
|
||||
return {
|
||||
equipmentInstanceId,
|
||||
designId,
|
||||
progress: 0,
|
||||
required: costs.time,
|
||||
manaPerHour: costs.manaPerHour,
|
||||
paused: false,
|
||||
manaSpent: 0,
|
||||
};
|
||||
}
|
||||
|
||||
// Calculate application progress after a tick
|
||||
export interface ApplicationTickResult {
|
||||
progress: number;
|
||||
manaSpent: number;
|
||||
manaConsumed: number;
|
||||
isComplete: boolean;
|
||||
triggeredFreeEnchant: boolean;
|
||||
}
|
||||
|
||||
export function calculateApplicationTick(
|
||||
currentProgress: number,
|
||||
required: number,
|
||||
currentManaSpent: number,
|
||||
manaPerTick: number,
|
||||
computedEffects: any
|
||||
): ApplicationTickResult {
|
||||
let progress = currentProgress + 0.04;
|
||||
let manaSpent = currentManaSpent + manaPerTick;
|
||||
let manaConsumed = manaPerTick;
|
||||
let triggeredFreeEnchant = false;
|
||||
|
||||
let freeEnchantChance = 0;
|
||||
if (hasSpecial(computedEffects, SPECIAL_EFFECTS.ENCHANT_PRESERVATION)) {
|
||||
freeEnchantChance += 0.25;
|
||||
}
|
||||
if (hasSpecial(computedEffects, SPECIAL_EFFECTS.THRIFTY_ENCHANTER)) {
|
||||
freeEnchantChance += 0.10;
|
||||
}
|
||||
if (hasSpecial(computedEffects, SPECIAL_EFFECTS.OPTIMIZED_ENCHANTING)) {
|
||||
freeEnchantChance += 0.25;
|
||||
}
|
||||
|
||||
if (freeEnchantChance > 0 && Math.random() < freeEnchantChance) {
|
||||
progress = required;
|
||||
manaConsumed = 0;
|
||||
manaSpent = currentManaSpent;
|
||||
triggeredFreeEnchant = true;
|
||||
}
|
||||
|
||||
return {
|
||||
progress,
|
||||
manaSpent,
|
||||
manaConsumed,
|
||||
isComplete: progress >= required,
|
||||
triggeredFreeEnchant,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Enchantment Application ────────────────────────────────────────────────
|
||||
|
||||
// Apply enchantments to equipment instance
|
||||
export function applyEnchantments(
|
||||
instance: EquipmentInstance,
|
||||
design: EnchantmentDesign,
|
||||
computedEffects: any
|
||||
): {
|
||||
updatedInstance: EquipmentInstance;
|
||||
xpGained: number;
|
||||
logMessage: string;
|
||||
} {
|
||||
const isPureEssenceActive = hasSpecial(computedEffects, SPECIAL_EFFECTS.PURE_ESSENCE);
|
||||
|
||||
const newEnchantments: AppliedEnchantment[] = design.effects.map(eff => {
|
||||
let stacks = eff.stacks;
|
||||
let actualCost = eff.capacityCost;
|
||||
|
||||
const effectDef = ENCHANTMENT_EFFECTS[eff.effectId];
|
||||
if (isPureEssenceActive && effectDef && effectDef.baseCapacityCost < 100) {
|
||||
stacks = Math.ceil(stacks * 1.25);
|
||||
}
|
||||
|
||||
return {
|
||||
effectId: eff.effectId,
|
||||
stacks,
|
||||
actualCost,
|
||||
};
|
||||
});
|
||||
|
||||
const xpGained = calculateEnchantingXP(design.totalCapacityUsed);
|
||||
|
||||
const updatedInstance: EquipmentInstance = {
|
||||
...instance,
|
||||
enchantments: [...instance.enchantments, ...newEnchantments],
|
||||
usedCapacity: instance.usedCapacity + design.totalCapacityUsed,
|
||||
};
|
||||
|
||||
return {
|
||||
updatedInstance,
|
||||
xpGained,
|
||||
logMessage: `✨ Enchantment "${design.name}" applied to ${instance.name}! (+${xpGained} Enchanter XP)`,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Attunement XP Updates ──────────────────────────────────────────────────
|
||||
|
||||
export function updateEnchanterAttunement(
|
||||
attunements: Record<string, AttunementState>,
|
||||
xpGained: number
|
||||
): Record<string, AttunementState> {
|
||||
if (!attunements?.enchanter?.active || xpGained <= 0) {
|
||||
return attunements;
|
||||
}
|
||||
|
||||
const enchanterState = attunements.enchanter;
|
||||
let newXP = enchanterState.experience + xpGained;
|
||||
let newLevel = enchanterState.level;
|
||||
|
||||
const { getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } = require('./data/attunements');
|
||||
|
||||
while (newLevel < MAX_ATTUNEMENT_LEVEL) {
|
||||
const xpNeeded = getAttunementXPForLevel(newLevel + 1);
|
||||
if (newXP >= xpNeeded) {
|
||||
newXP -= xpNeeded;
|
||||
newLevel++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...attunements,
|
||||
enchanter: {
|
||||
...enchanterState,
|
||||
level: newLevel,
|
||||
experience: newXP,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Application Cancellation ────────────────────────────────────────────────
|
||||
|
||||
export function cancelApplication() {
|
||||
return { logMessage: 'Enchantment application cancelled.' };
|
||||
}
|
||||
|
||||
export function pauseApplication() {
|
||||
return { logMessage: 'Enchantment application paused.' };
|
||||
}
|
||||
|
||||
export function resumeApplication() {
|
||||
return { logMessage: 'Enchantment application resumed.' };
|
||||
}
|
||||
|
||||
// ─── Progress Calculations ──────────────────────────────────────────────────
|
||||
|
||||
export function getApplicationManaCostForTick(manaPerHour: number): number {
|
||||
return manaPerHour * 0.04;
|
||||
}
|
||||
|
||||
export function getApplicationRemainingTime(currentProgress: number, required: number): number {
|
||||
return Math.max(0, required - currentProgress);
|
||||
}
|
||||
|
||||
export function getApplicationCompletionPercent(currentProgress: number, required: number): number {
|
||||
return Math.min(100, Math.floor((currentProgress / required) * 100));
|
||||
}
|
||||
Reference in New Issue
Block a user