Initial commit
This commit is contained in:
645
src/lib/game/crafting-slice.ts
Executable file
645
src/lib/game/crafting-slice.ts
Executable file
@@ -0,0 +1,645 @@
|
||||
// ─── Crafting Store Slice ─────────────────────────────────────────────────────────
|
||||
// Handles equipment and enchantment system: design, prepare, apply stages
|
||||
|
||||
import type { GameState, EquipmentInstance, AppliedEnchantment, EnchantmentDesign, DesignEffect, EquipmentSlot } from './types';
|
||||
import { EQUIPMENT_TYPES, type EquipmentCategory } from './data/equipment';
|
||||
import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from './data/enchantment-effects';
|
||||
import { SPELLS_DEF } from './constants';
|
||||
|
||||
// ─── Helper Functions ─────────────────────────────────────────────────────────
|
||||
|
||||
function generateInstanceId(): string {
|
||||
return `equip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
// Get equipment category from type
|
||||
function getEquipmentCategory(typeId: string): EquipmentCategory | null {
|
||||
const type = EQUIPMENT_TYPES[typeId];
|
||||
return type?.category || null;
|
||||
}
|
||||
|
||||
// Calculate total capacity cost for a design
|
||||
function calculateDesignCapacityCost(effects: DesignEffect[], efficiencyBonus: number = 0): number {
|
||||
return effects.reduce((total, eff) => total + calculateEffectCapacityCost(eff.effectId, eff.stacks, efficiencyBonus), 0);
|
||||
}
|
||||
|
||||
// Calculate design time based on number and complexity of effects
|
||||
function calculateDesignTime(effects: DesignEffect[]): number {
|
||||
// Base 1 hour + 0.5 hours per effect stack
|
||||
let time = 1;
|
||||
for (const eff of effects) {
|
||||
const effectDef = ENCHANTMENT_EFFECTS[eff.effectId];
|
||||
if (effectDef) {
|
||||
time += 0.5 * eff.stacks;
|
||||
}
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
// Calculate preparation time based on equipment capacity
|
||||
function calculatePrepTime(equipmentCapacity: number): number {
|
||||
// Base 2 hours + 1 hour per 50 capacity
|
||||
return 2 + Math.floor(equipmentCapacity / 50);
|
||||
}
|
||||
|
||||
// Calculate preparation mana cost
|
||||
function calculatePrepManaCost(equipmentCapacity: number): number {
|
||||
// 10 mana per capacity point
|
||||
return equipmentCapacity * 10;
|
||||
}
|
||||
|
||||
// Calculate application time based on design complexity
|
||||
function calculateApplicationTime(design: EnchantmentDesign): number {
|
||||
// 2 hours base + 1 hour per effect stack
|
||||
return 2 + design.effects.reduce((total, eff) => total + eff.stacks, 0);
|
||||
}
|
||||
|
||||
// Calculate application mana cost per hour
|
||||
function calculateApplicationManaPerHour(design: EnchantmentDesign): number {
|
||||
// 20 mana per hour base + 5 per effect stack
|
||||
return 20 + design.effects.reduce((total, eff) => total + eff.stacks * 5, 0);
|
||||
}
|
||||
|
||||
// ─── Crafting Actions Interface ───────────────────────────────────────────────
|
||||
|
||||
export interface CraftingActions {
|
||||
// Equipment management
|
||||
createEquipmentInstance: (typeId: string) => string | null;
|
||||
equipItem: (instanceId: string, slot: EquipmentSlot) => boolean;
|
||||
unequipItem: (slot: EquipmentSlot) => void;
|
||||
deleteEquipmentInstance: (instanceId: string) => void;
|
||||
|
||||
// Enchantment design
|
||||
startDesigningEnchantment: (name: string, equipmentTypeId: string, effects: DesignEffect[]) => boolean;
|
||||
cancelDesign: () => void;
|
||||
saveDesign: (design: EnchantmentDesign) => void;
|
||||
deleteDesign: (designId: string) => void;
|
||||
|
||||
// Enchantment preparation
|
||||
startPreparing: (equipmentInstanceId: string) => boolean;
|
||||
cancelPreparation: () => void;
|
||||
|
||||
// Enchantment application
|
||||
startApplying: (equipmentInstanceId: string, designId: string) => boolean;
|
||||
pauseApplication: () => void;
|
||||
resumeApplication: () => void;
|
||||
cancelApplication: () => void;
|
||||
|
||||
// Disenchanting
|
||||
disenchantEquipment: (instanceId: string) => void;
|
||||
|
||||
// Computed getters
|
||||
getEquipmentSpells: () => string[];
|
||||
getEquipmentEffects: () => Record<string, number>;
|
||||
getAvailableCapacity: (instanceId: string) => number;
|
||||
}
|
||||
|
||||
// ─── Initial Equipment Setup ───────────────────────────────────────────────────
|
||||
|
||||
export function createStartingEquipment(): {
|
||||
equippedInstances: Record<string, string | null>;
|
||||
equipmentInstances: Record<string, EquipmentInstance>;
|
||||
} {
|
||||
// Create starting staff with Mana Bolt enchantment
|
||||
const staffId = generateInstanceId();
|
||||
const staffInstance: EquipmentInstance = {
|
||||
instanceId: staffId,
|
||||
typeId: 'basicStaff',
|
||||
name: 'Basic Staff',
|
||||
enchantments: [
|
||||
{ effectId: 'spell_manaBolt', stacks: 1, actualCost: 50 }
|
||||
],
|
||||
usedCapacity: 50,
|
||||
totalCapacity: 50,
|
||||
rarity: 'common',
|
||||
quality: 100,
|
||||
};
|
||||
|
||||
// Create starting clothes
|
||||
const shirtId = generateInstanceId();
|
||||
const shirtInstance: EquipmentInstance = {
|
||||
instanceId: shirtId,
|
||||
typeId: 'civilianShirt',
|
||||
name: 'Civilian Shirt',
|
||||
enchantments: [],
|
||||
usedCapacity: 0,
|
||||
totalCapacity: 30,
|
||||
rarity: 'common',
|
||||
quality: 100,
|
||||
};
|
||||
|
||||
const shoesId = generateInstanceId();
|
||||
const shoesInstance: EquipmentInstance = {
|
||||
instanceId: shoesId,
|
||||
typeId: 'civilianShoes',
|
||||
name: 'Civilian Shoes',
|
||||
enchantments: [],
|
||||
usedCapacity: 0,
|
||||
totalCapacity: 15,
|
||||
rarity: 'common',
|
||||
quality: 100,
|
||||
};
|
||||
|
||||
return {
|
||||
equippedInstances: {
|
||||
mainHand: staffId,
|
||||
offHand: null,
|
||||
head: null,
|
||||
body: shirtId,
|
||||
hands: null,
|
||||
feet: shoesId,
|
||||
accessory1: null,
|
||||
accessory2: null,
|
||||
},
|
||||
equipmentInstances: {
|
||||
[staffId]: staffInstance,
|
||||
[shirtId]: shirtInstance,
|
||||
[shoesId]: shoesInstance,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Crafting Store Extensions ─────────────────────────────────────────────────
|
||||
|
||||
export function createCraftingSlice(
|
||||
set: (fn: (state: GameState) => Partial<GameState>) => void,
|
||||
get: () => GameState & CraftingActions
|
||||
): CraftingActions {
|
||||
return {
|
||||
// ─── Equipment Management ─────────────────────────────────────────────────
|
||||
|
||||
createEquipmentInstance: (typeId: string) => {
|
||||
const type = EQUIPMENT_TYPES[typeId];
|
||||
if (!type) return null;
|
||||
|
||||
const instanceId = generateInstanceId();
|
||||
const instance: EquipmentInstance = {
|
||||
instanceId,
|
||||
typeId,
|
||||
name: type.name,
|
||||
enchantments: [],
|
||||
usedCapacity: 0,
|
||||
totalCapacity: type.baseCapacity,
|
||||
rarity: 'common',
|
||||
quality: 100,
|
||||
};
|
||||
|
||||
set((state) => ({
|
||||
equipmentInstances: {
|
||||
...state.equipmentInstances,
|
||||
[instanceId]: instance,
|
||||
},
|
||||
}));
|
||||
|
||||
return instanceId;
|
||||
},
|
||||
|
||||
equipItem: (instanceId: string, slot: EquipmentSlot) => {
|
||||
const state = get();
|
||||
const instance = state.equipmentInstances[instanceId];
|
||||
if (!instance) return false;
|
||||
|
||||
const type = EQUIPMENT_TYPES[instance.typeId];
|
||||
if (!type) return false;
|
||||
|
||||
// Check if equipment can go in this slot
|
||||
const validSlots = type.category === 'accessory'
|
||||
? ['accessory1', 'accessory2']
|
||||
: [type.slot];
|
||||
|
||||
if (!validSlots.includes(slot)) return false;
|
||||
|
||||
// Check if slot is occupied
|
||||
const currentEquipped = state.equippedInstances[slot];
|
||||
if (currentEquipped === instanceId) return true; // Already equipped here
|
||||
|
||||
// If this item is equipped elsewhere, unequip it first
|
||||
let newEquipped = { ...state.equippedInstances };
|
||||
for (const [s, id] of Object.entries(newEquipped)) {
|
||||
if (id === instanceId) {
|
||||
newEquipped[s as EquipmentSlot] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Equip to new slot
|
||||
newEquipped[slot] = instanceId;
|
||||
|
||||
set(() => ({ equippedInstances: newEquipped }));
|
||||
return true;
|
||||
},
|
||||
|
||||
unequipItem: (slot: EquipmentSlot) => {
|
||||
set((state) => ({
|
||||
equippedInstances: {
|
||||
...state.equippedInstances,
|
||||
[slot]: null,
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
deleteEquipmentInstance: (instanceId: string) => {
|
||||
set((state) => {
|
||||
// First unequip if equipped
|
||||
let newEquipped = { ...state.equippedInstances };
|
||||
for (const [slot, id] of Object.entries(newEquipped)) {
|
||||
if (id === instanceId) {
|
||||
newEquipped[slot as EquipmentSlot] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from instances
|
||||
const newInstances = { ...state.equipmentInstances };
|
||||
delete newInstances[instanceId];
|
||||
|
||||
return {
|
||||
equippedInstances: newEquipped,
|
||||
equipmentInstances: newInstances,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// ─── Enchantment Design ─────────────────────────────────────────────────
|
||||
|
||||
startDesigningEnchantment: (name: string, equipmentTypeId: string, effects: DesignEffect[]) => {
|
||||
const state = get();
|
||||
|
||||
// Check if player has enchanting skill
|
||||
const enchantingLevel = state.skills.enchanting || 0;
|
||||
if (enchantingLevel < 1) return false;
|
||||
|
||||
// Validate effects for equipment category
|
||||
const category = getEquipmentCategory(equipmentTypeId);
|
||||
if (!category) return false;
|
||||
|
||||
for (const eff of effects) {
|
||||
const effectDef = ENCHANTMENT_EFFECTS[eff.effectId];
|
||||
if (!effectDef) return false;
|
||||
if (!effectDef.allowedEquipmentCategories.includes(category)) return false;
|
||||
if (eff.stacks > effectDef.maxStacks) return false;
|
||||
}
|
||||
|
||||
// Calculate capacity cost
|
||||
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
|
||||
const totalCapacityCost = calculateDesignCapacityCost(effects, efficiencyBonus);
|
||||
|
||||
// Create design
|
||||
const designTime = calculateDesignTime(effects);
|
||||
const design: EnchantmentDesign = {
|
||||
id: `design_${Date.now()}`,
|
||||
name,
|
||||
equipmentType: equipmentTypeId,
|
||||
effects,
|
||||
totalCapacityUsed: totalCapacityCost,
|
||||
designTime,
|
||||
created: Date.now(),
|
||||
};
|
||||
|
||||
set(() => ({
|
||||
currentAction: 'design',
|
||||
designProgress: {
|
||||
designId: design.id,
|
||||
progress: 0,
|
||||
required: designTime,
|
||||
},
|
||||
}));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
cancelDesign: () => {
|
||||
set(() => ({
|
||||
currentAction: 'meditate',
|
||||
designProgress: null,
|
||||
}));
|
||||
},
|
||||
|
||||
saveDesign: (design: EnchantmentDesign) => {
|
||||
set((state) => ({
|
||||
enchantmentDesigns: [...state.enchantmentDesigns, design],
|
||||
designProgress: null,
|
||||
currentAction: 'meditate',
|
||||
}));
|
||||
},
|
||||
|
||||
deleteDesign: (designId: string) => {
|
||||
set((state) => ({
|
||||
enchantmentDesigns: state.enchantmentDesigns.filter(d => d.id !== designId),
|
||||
}));
|
||||
},
|
||||
|
||||
// ─── Enchantment Preparation ─────────────────────────────────────────────
|
||||
|
||||
startPreparing: (equipmentInstanceId: string) => {
|
||||
const state = get();
|
||||
const instance = state.equipmentInstances[equipmentInstanceId];
|
||||
if (!instance) return false;
|
||||
|
||||
const prepTime = calculatePrepTime(instance.totalCapacity);
|
||||
const manaCost = calculatePrepManaCost(instance.totalCapacity);
|
||||
|
||||
if (state.rawMana < manaCost) return false;
|
||||
|
||||
set(() => ({
|
||||
currentAction: 'prepare',
|
||||
preparationProgress: {
|
||||
equipmentInstanceId,
|
||||
progress: 0,
|
||||
required: prepTime,
|
||||
manaCostPaid: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
cancelPreparation: () => {
|
||||
set(() => ({
|
||||
currentAction: 'meditate',
|
||||
preparationProgress: null,
|
||||
}));
|
||||
},
|
||||
|
||||
// ─── Enchantment Application ─────────────────────────────────────────────
|
||||
|
||||
startApplying: (equipmentInstanceId: string, designId: string) => {
|
||||
const state = get();
|
||||
const instance = state.equipmentInstances[equipmentInstanceId];
|
||||
const design = state.enchantmentDesigns.find(d => d.id === designId);
|
||||
|
||||
if (!instance || !design) return false;
|
||||
|
||||
// Check capacity
|
||||
if (instance.usedCapacity + design.totalCapacityUsed > instance.totalCapacity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const applicationTime = calculateApplicationTime(design);
|
||||
const manaPerHour = calculateApplicationManaPerHour(design);
|
||||
|
||||
set(() => ({
|
||||
currentAction: 'enchant',
|
||||
applicationProgress: {
|
||||
equipmentInstanceId,
|
||||
designId,
|
||||
progress: 0,
|
||||
required: applicationTime,
|
||||
manaPerHour,
|
||||
paused: false,
|
||||
manaSpent: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
pauseApplication: () => {
|
||||
set((state) => {
|
||||
if (!state.applicationProgress) return {};
|
||||
return {
|
||||
applicationProgress: {
|
||||
...state.applicationProgress,
|
||||
paused: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
resumeApplication: () => {
|
||||
set((state) => {
|
||||
if (!state.applicationProgress) return {};
|
||||
return {
|
||||
applicationProgress: {
|
||||
...state.applicationProgress,
|
||||
paused: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
cancelApplication: () => {
|
||||
set(() => ({
|
||||
currentAction: 'meditate',
|
||||
applicationProgress: null,
|
||||
}));
|
||||
},
|
||||
|
||||
// ─── Disenchanting ─────────────────────────────────────────────────────────
|
||||
|
||||
disenchantEquipment: (instanceId: string) => {
|
||||
const state = get();
|
||||
const instance = state.equipmentInstances[instanceId];
|
||||
if (!instance || instance.enchantments.length === 0) return;
|
||||
|
||||
const disenchantLevel = state.skills.disenchanting || 0;
|
||||
const recoveryRate = 0.1 + disenchantLevel * 0.2; // 10% base + 20% per level
|
||||
|
||||
let totalRecovered = 0;
|
||||
for (const ench of instance.enchantments) {
|
||||
totalRecovered += Math.floor(ench.actualCost * recoveryRate);
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
rawMana: state.rawMana + totalRecovered,
|
||||
equipmentInstances: {
|
||||
...state.equipmentInstances,
|
||||
[instanceId]: {
|
||||
...instance,
|
||||
enchantments: [],
|
||||
usedCapacity: 0,
|
||||
},
|
||||
},
|
||||
log: [`✨ Disenchanted ${instance.name}, recovered ${totalRecovered} mana.`, ...state.log.slice(0, 49)],
|
||||
}));
|
||||
},
|
||||
|
||||
// ─── Computed Getters ─────────────────────────────────────────────────────
|
||||
|
||||
getEquipmentSpells: () => {
|
||||
const state = get();
|
||||
const spells: string[] = [];
|
||||
|
||||
for (const instanceId of Object.values(state.equippedInstances)) {
|
||||
if (!instanceId) continue;
|
||||
const instance = state.equipmentInstances[instanceId];
|
||||
if (!instance) continue;
|
||||
|
||||
for (const ench of instance.enchantments) {
|
||||
const effectDef = ENCHANTMENT_EFFECTS[ench.effectId];
|
||||
if (effectDef?.effect.type === 'spell' && effectDef.effect.spellId) {
|
||||
spells.push(effectDef.effect.spellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...new Set(spells)]; // Remove duplicates
|
||||
},
|
||||
|
||||
getEquipmentEffects: () => {
|
||||
const state = get();
|
||||
const effects: Record<string, number> = {};
|
||||
|
||||
for (const instanceId of Object.values(state.equippedInstances)) {
|
||||
if (!instanceId) continue;
|
||||
const instance = state.equipmentInstances[instanceId];
|
||||
if (!instance) continue;
|
||||
|
||||
for (const ench of instance.enchantments) {
|
||||
const effectDef = ENCHANTMENT_EFFECTS[ench.effectId];
|
||||
if (!effectDef) continue;
|
||||
|
||||
if (effectDef.effect.type === 'bonus' && effectDef.effect.stat && effectDef.effect.value) {
|
||||
effects[effectDef.effect.stat] = (effects[effectDef.effect.stat] || 0) + effectDef.effect.value * ench.stacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return effects;
|
||||
},
|
||||
|
||||
getAvailableCapacity: (instanceId: string) => {
|
||||
const state = get();
|
||||
const instance = state.equipmentInstances[instanceId];
|
||||
if (!instance) return 0;
|
||||
return instance.totalCapacity - instance.usedCapacity;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Tick Processing for Crafting ─────────────────────────────────────────────
|
||||
|
||||
export function processCraftingTick(
|
||||
state: GameState,
|
||||
effects: { rawMana: number; log: string[] }
|
||||
): Partial<GameState> {
|
||||
const { rawMana, log } = effects;
|
||||
let updates: Partial<GameState> = {};
|
||||
|
||||
// Process design progress
|
||||
if (state.currentAction === 'design' && state.designProgress) {
|
||||
const progress = state.designProgress.progress + 0.04; // HOURS_PER_TICK
|
||||
if (progress >= state.designProgress.required) {
|
||||
// Design complete - but we need the design data to save it
|
||||
// This will be handled by the UI calling saveDesign
|
||||
updates = {
|
||||
...updates,
|
||||
log: ['✅ Enchantment design complete!', ...log],
|
||||
};
|
||||
} else {
|
||||
updates = {
|
||||
...updates,
|
||||
designProgress: {
|
||||
...state.designProgress,
|
||||
progress,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Process preparation progress
|
||||
if (state.currentAction === 'prepare' && state.preparationProgress) {
|
||||
const prep = state.preparationProgress;
|
||||
const manaPerHour = calculatePrepManaCost(
|
||||
state.equipmentInstances[prep.equipmentInstanceId]?.totalCapacity || 50
|
||||
) / prep.required;
|
||||
const manaCost = manaPerHour * 0.04; // HOURS_PER_TICK
|
||||
|
||||
if (rawMana >= manaCost) {
|
||||
const progress = prep.progress + 0.04;
|
||||
const manaCostPaid = prep.manaCostPaid + manaCost;
|
||||
|
||||
if (progress >= prep.required) {
|
||||
updates = {
|
||||
...updates,
|
||||
rawMana: rawMana - manaCost,
|
||||
preparationProgress: null,
|
||||
currentAction: 'meditate',
|
||||
log: ['✅ Equipment prepared for enchanting!', ...log],
|
||||
};
|
||||
} else {
|
||||
updates = {
|
||||
...updates,
|
||||
rawMana: rawMana - manaCost,
|
||||
preparationProgress: {
|
||||
...prep,
|
||||
progress,
|
||||
manaCostPaid,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process application progress
|
||||
if (state.currentAction === 'enchant' && state.applicationProgress && !state.applicationProgress.paused) {
|
||||
const app = state.applicationProgress;
|
||||
const manaCost = app.manaPerHour * 0.04; // HOURS_PER_TICK
|
||||
|
||||
if (rawMana >= manaCost) {
|
||||
const progress = app.progress + 0.04;
|
||||
const manaSpent = app.manaSpent + manaCost;
|
||||
|
||||
if (progress >= app.required) {
|
||||
// Apply the enchantment!
|
||||
const instance = state.equipmentInstances[app.equipmentInstanceId];
|
||||
const design = state.enchantmentDesigns.find(d => d.id === app.designId);
|
||||
|
||||
if (instance && design) {
|
||||
const newEnchantments: AppliedEnchantment[] = design.effects.map(eff => ({
|
||||
effectId: eff.effectId,
|
||||
stacks: eff.stacks,
|
||||
actualCost: eff.capacityCost,
|
||||
}));
|
||||
|
||||
updates = {
|
||||
...updates,
|
||||
rawMana: rawMana - manaCost,
|
||||
applicationProgress: null,
|
||||
currentAction: 'meditate',
|
||||
equipmentInstances: {
|
||||
...state.equipmentInstances,
|
||||
[app.equipmentInstanceId]: {
|
||||
...instance,
|
||||
enchantments: [...instance.enchantments, ...newEnchantments],
|
||||
usedCapacity: instance.usedCapacity + design.totalCapacityUsed,
|
||||
},
|
||||
},
|
||||
log: [`✨ Enchantment "${design.name}" applied to ${instance.name}!`, ...log],
|
||||
};
|
||||
}
|
||||
} else {
|
||||
updates = {
|
||||
...updates,
|
||||
rawMana: rawMana - manaCost,
|
||||
applicationProgress: {
|
||||
...app,
|
||||
progress,
|
||||
manaSpent,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updates;
|
||||
}
|
||||
|
||||
// ─── Export helper to get equipment instance spells ─────────────────────────────
|
||||
|
||||
export function getSpellsFromEquipment(instances: Record<string, EquipmentInstance>, equippedIds: (string | null)[]): string[] {
|
||||
const spells: string[] = [];
|
||||
|
||||
for (const id of equippedIds) {
|
||||
if (!id) continue;
|
||||
const instance = instances[id];
|
||||
if (!instance) continue;
|
||||
|
||||
for (const ench of instance.enchantments) {
|
||||
const effectDef = ENCHANTMENT_EFFECTS[ench.effectId];
|
||||
if (effectDef?.effect.type === 'spell' && effectDef.effect.spellId) {
|
||||
spells.push(effectDef.effect.spellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...new Set(spells)];
|
||||
}
|
||||
Reference in New Issue
Block a user