/** * Conversion utilities for transforming database types to battle engine types */ import type { PicletInstance } from '$lib/db/schema'; import type { PicletDefinition, Move, BaseStats, SpecialAbility } from '$lib/battle-engine/types'; import type { PicletStats } from '$lib/types'; import { PicletType } from '$lib/types/picletTypes'; import { recalculatePicletStats } from '$lib/services/levelingService'; import { getUnlockedMoves, isSpecialAbilityUnlocked } from '$lib/services/unlockLevels'; /** * Convert PicletInstance to PicletDefinition for battle engine use * Uses levelingService to ensure stats are properly calculated for current level */ export function picletInstanceToBattleDefinition(instance: PicletInstance): PicletDefinition { // First ensure stats are up-to-date for current level and nature const updatedInstance = recalculatePicletStats(instance); // Use the calculated stats directly (no need for complex reverse formulas) const baseStats: BaseStats = { hp: updatedInstance.maxHp, // Pokemon-calculated HP attack: updatedInstance.attack, // Includes level scaling and nature modifiers defense: updatedInstance.defense, // Includes level scaling and nature modifiers speed: updatedInstance.speed // Includes level scaling and nature modifiers }; // Only include unlocked moves - BattleMove now contains complete Move data const unlockedMoves = getUnlockedMoves(instance.moves, updatedInstance.level); const movepool: Move[] = unlockedMoves.map(move => ({ name: move.name, type: move.type, power: move.power, accuracy: move.accuracy, pp: move.pp, priority: move.priority, flags: move.flags, effects: move.effects })); // Ensure at least one move is available (first move should always be unlocked at level 1) if (movepool.length === 0) { console.warn(`Piclet ${instance.nickname} has no unlocked moves at level ${updatedInstance.level}!`); // Emergency fallback - unlock first move if (instance.moves.length > 0) { const firstMove = instance.moves[0]; movepool.push({ name: firstMove.name, type: firstMove.type, power: firstMove.power, accuracy: firstMove.accuracy, pp: firstMove.pp, priority: firstMove.priority, flags: firstMove.flags, effects: firstMove.effects }); } } // All Piclets must now have special abilities if (!instance.specialAbility) { throw new Error('Piclet must have a special ability.'); } // Only include special ability if unlocked let specialAbility: SpecialAbility | undefined; if (isSpecialAbilityUnlocked(instance.specialAbilityUnlockLevel, updatedInstance.level)) { specialAbility = instance.specialAbility; } else { // Create a placeholder ability for locked special abilities specialAbility = { name: "Locked Ability", description: `Unlocks at level ${instance.specialAbilityUnlockLevel}`, effects: [] }; } // Determine tier based on BST (Base Stat Total) const bst = baseStats.hp + baseStats.attack + baseStats.defense + baseStats.speed; let tier: 'low' | 'medium' | 'high' | 'legendary'; if (bst <= 300) tier = 'low'; else if (bst <= 400) tier = 'medium'; else if (bst <= 500) tier = 'high'; else tier = 'legendary'; return { name: instance.nickname || instance.typeId, // Keep original name - we'll add prefixes in battle engine description: instance.concept, tier, primaryType: instance.primaryType, secondaryType: instance.secondaryType, baseStats, nature: instance.nature, specialAbility: specialAbility!, movepool }; } /** * Convert battle engine BattlePiclet back to PicletInstance for state updates */ export function battlePicletToInstance(battlePiclet: any, originalInstance: PicletInstance): PicletInstance { return { ...originalInstance, currentHp: battlePiclet.currentHp, level: battlePiclet.level, attack: battlePiclet.attack, defense: battlePiclet.defense, speed: battlePiclet.speed, // Update moves with current PP moves: battlePiclet.moves.map((moveData: any, index: number) => ({ ...originalInstance.moves[index], currentPp: moveData.currentPP })) }; } /** * Convert PicletStats (from generation) to PicletDefinition for battle engine */ export function picletStatsToBattleDefinition(stats: PicletStats, name: string, concept: string): PicletDefinition { return { name: stats.name || name, description: stats.description || concept, tier: stats.tier, primaryType: stats.primaryType as PicletType, secondaryType: stats.secondaryType as PicletType || undefined, baseStats: stats.baseStats, nature: stats.nature, specialAbility: { ...stats.specialAbility, description: `Special ability of ${stats.name || name}` // Add description since it's removed from generation } as any, movepool: stats.movepool as any }; } /** * Strip internal battle prefixes from piclet names for display purposes * Removes "player-" and "enemy-" prefixes that are used internally for animation targeting */ export function stripBattlePrefix(name: string): string { if (name.startsWith('player-')) { return name.substring('player-'.length); } if (name.startsWith('enemy-')) { return name.substring('enemy-'.length); } return name; }