piclets / src /lib /utils /battleConversion.ts
Fraser's picture
rm spec ab stuff
0959fa0
/**
* 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;
}