File size: 5,872 Bytes
4c208f2 e8aa797 74f8c2c 4c208f2 e8aa797 4c208f2 e8aa797 4c208f2 e8aa797 4c208f2 74f8c2c 4c208f2 4256f70 1f2c086 4256f70 74f8c2c 4c208f2 a6cc65f 4c208f2 e3f93ae 4c208f2 e3f93ae 4c208f2 a6cc65f 4c208f2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
/**
* Conversion utilities for transforming database types to battle engine types
*/
import type { PicletInstance, BattleMove } from '$lib/db/schema';
import type { PicletDefinition, Move, BaseStats, SpecialAbility } from '$lib/battle-engine/types';
import type { PicletStats, BattleEffect, AbilityTrigger } from '$lib/types';
import { PicletType, AttackType } 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
const unlockedMoves = getUnlockedMoves(instance.moves, updatedInstance.level);
const movepool: Move[] = unlockedMoves.map(move => convertBattleMoveToMove(move, instance.primaryType));
// 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 = convertBattleMoveToMove(instance.moves[0], instance.primaryType);
movepool.push(firstMove);
}
}
// 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}`,
trigger: "onBattleStart" as any,
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,
movepool
};
}
/**
* Convert BattleMove to full Move for battle engine
*/
function convertBattleMoveToMove(battleMove: BattleMove, primaryType: PicletType): Move {
// Create basic effects based on move properties
const effects: any[] = [];
if (battleMove.power > 0) {
effects.push({
type: 'damage',
target: 'opponent',
amount: battleMove.power >= 80 ? 'strong' :
battleMove.power >= 60 ? 'normal' : 'weak'
});
}
// Add status or stat effects for non-damaging moves
if (battleMove.power === 0) {
effects.push({
type: 'modifyStats',
target: 'self',
stats: { attack: 'increase' }
});
}
return {
name: battleMove.name,
type: battleMove.type,
power: battleMove.power,
accuracy: battleMove.accuracy,
pp: battleMove.pp,
priority: 0,
flags: battleMove.power > 0 && battleMove.name.toLowerCase().includes('tackle') ? ['contact'] : [],
effects
};
}
/**
* 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,
secondaryType: stats.secondaryType || undefined,
baseStats: stats.baseStats,
nature: stats.nature,
specialAbility: stats.specialAbility,
movepool: stats.movepool
};
}
/**
* 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;
} |