import { useState } from 'react'; import { Plus, Trash2, Shuffle, Zap, Search } from 'lucide-react'; import type { NPCConfiguration, NPCPartyProvider, SimplePartyProvider, PoolPartyProvider, PoolEntry } from '../types/npc'; import { pokemonApi } from '../services/pokemonApi'; import { PokemonFormSelector } from './PokemonFormSelector'; interface NPCPartyBuilderProps { config: NPCConfiguration; onChange: (config: NPCConfiguration) => void; } export function NPCPartyBuilder({ config, onChange }: NPCPartyBuilderProps) { const [partyType, setPartyType] = useState<'simple' | 'pool' | 'script'>(config.party?.type || 'simple'); const [showPokemonFormSelector, setShowPokemonFormSelector] = useState(false); const [selectedPokemonIndex, setSelectedPokemonIndex] = useState(-1); const [isGenerating, setIsGenerating] = useState(false); const handlePartyChange = (party: NPCPartyProvider) => { onChange({ ...config, party }); }; const handlePartyTypeChange = (type: 'simple' | 'pool' | 'script') => { setPartyType(type); switch (type) { case 'simple': handlePartyChange({ type: 'simple', pokemon: [''] }); break; case 'pool': handlePartyChange({ type: 'pool', pool: [{ pokemon: '', weight: 1 }] }); break; case 'script': handlePartyChange({ type: 'script', script: '' }); break; } }; const generateRandomTeam = async (teamSize: number = 6) => { setIsGenerating(true); try { const team = await pokemonApi.generateRandomTeam(teamSize); const pokemonStrings = team.map(pokemon => pokemonApi.formatToCobblemonString(pokemon)); if (partyType === 'simple') { handlePartyChange({ type: 'simple', pokemon: pokemonStrings, isStatic: (config.party as SimplePartyProvider)?.isStatic }); } } catch (error) { console.error('Failed to generate random team:', error); } finally { setIsGenerating(false); } }; const generateTeamByType = async (type: string, teamSize: number = 6) => { setIsGenerating(true); try { const team = await pokemonApi.generateTeamByType(type, teamSize); const pokemonStrings = team.map(pokemon => pokemonApi.formatToCobblemonString(pokemon)); if (partyType === 'simple') { handlePartyChange({ type: 'simple', pokemon: pokemonStrings, isStatic: (config.party as SimplePartyProvider)?.isStatic }); } } catch (error) { console.error(`Failed to generate ${type} team:`, error); } finally { setIsGenerating(false); } }; const openPokemonFormSelector = (index: number) => { setSelectedPokemonIndex(index); setShowPokemonFormSelector(true); }; const handlePokemonFormSelect = (pokemonString: string) => { if (partyType === 'simple') { const party = config.party as SimplePartyProvider; const newPokemon = [...party.pokemon]; newPokemon[selectedPokemonIndex] = pokemonString; handlePartyChange({ ...party, pokemon: newPokemon }); } setShowPokemonFormSelector(false); setSelectedPokemonIndex(-1); }; const renderSimpleParty = () => { const party = config.party as SimplePartyProvider; if (!party || !party.pokemon) { return null; } const addPokemon = () => { handlePartyChange({ ...party, pokemon: [...party.pokemon, ''] }); }; const removePokemon = (index: number) => { handlePartyChange({ ...party, pokemon: party.pokemon.filter((_, i) => i !== index) }); }; const updatePokemon = (index: number, value: string) => { const newPokemon = [...party.pokemon]; newPokemon[index] = value; handlePartyChange({ ...party, pokemon: newPokemon }); }; return (

Pokemon List

{/* Team Generation Tools */}
Team Generation
{party.pokemon.map((pokemon, index) => (
updatePokemon(index, e.target.value)} className="flex-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm" placeholder="pikachu level=50 moves=thunderbolt,quick-attack" />
))}

If true, party won't change between battles

); }; const renderPoolParty = () => { const party = config.party as PoolPartyProvider; const addPoolEntry = () => { handlePartyChange({ ...party, pool: [...party.pool, { pokemon: '', weight: 1 }] }); }; const removePoolEntry = (index: number) => { handlePartyChange({ ...party, pool: party.pool.filter((_, i) => i !== index) }); }; const updatePoolEntry = (index: number, field: keyof PoolEntry, value: any) => { const newPool = [...party.pool]; newPool[index] = { ...newPool[index], [field]: value }; handlePartyChange({ ...party, pool: newPool }); }; return (
handlePartyChange({ ...party, minPokemon: parseInt(e.target.value) })} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
handlePartyChange({ ...party, maxPokemon: parseInt(e.target.value) })} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />

Pool Entries

{party.pool.map((entry, index) => (
Entry {index + 1}
updatePoolEntry(index, 'pokemon', e.target.value)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm" placeholder="pikachu level=50" />
updatePoolEntry(index, 'weight', parseFloat(e.target.value))} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm" />
updatePoolEntry(index, 'selectableTimes', e.target.value ? parseInt(e.target.value) : undefined)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm" />
updatePoolEntry(index, 'levelVariation', e.target.value ? parseInt(e.target.value) : undefined)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm" />
))}
); }; const renderScriptParty = () => { const party = config.party as { type: 'script'; script: string; isStatic?: boolean }; return (
handlePartyChange({ ...party, script: e.target.value })} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" placeholder="cobblemon:party_script" />
); }; if (!config.battleConfiguration?.canChallenge) { return (

Pokemon Party

Enable battle configuration to set up a party

); } return ( <>

Pokemon Party

{(['simple', 'pool', 'script'] as const).map((type) => ( ))}
{partyType === 'simple' && renderSimpleParty()} {partyType === 'pool' && renderPoolParty()} {partyType === 'script' && renderScriptParty()}
setShowPokemonFormSelector(false)} /> ); }