import React, { useMemo } from 'react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, Legend, } from 'recharts'; import type { CharacterState } from '../../types'; interface Props { characters: Map; } const ELEMENT_COLORS: Record = { Slash: '#cc4444', Pierce: '#44cc44', Bludgeon: '#888888', Fire: '#ff6622', Cold: '#4488ff', Acid: '#44cc44', Electric: '#ffcc00', Typeless: '#aa66cc', }; export const CombatTab: React.FC = ({ characters }) => { // Kill rate per character const killData = useMemo(() => { return Array.from(characters.values()) .filter(c => c.telemetry) .map(c => ({ name: c.name.length > 18 ? c.name.slice(0, 16) + '..' : c.name, fullName: c.name, killsPerHour: parseInt(c.telemetry!.kills_per_hour) || 0, totalKills: c.telemetry!.kills || 0, })) .sort((a, b) => b.killsPerHour - a.killsPerHour) .slice(0, 30); }, [characters]); // Damage given per character (from combat stats) const damageData = useMemo(() => { return Array.from(characters.values()) .filter(c => c.combat?.session) .map(c => ({ name: c.name.length > 18 ? c.name.slice(0, 16) + '..' : c.name, fullName: c.name, damage: c.combat!.session!.total_damage_given, })) .sort((a, b) => b.damage - a.damage) .slice(0, 30); }, [characters]); // Aggregate element breakdown across all characters const elementData = useMemo(() => { const totals: Record = {}; for (const ch of characters.values()) { const session = ch.combat?.session; if (!session?.monsters) continue; for (const mon of Object.values(session.monsters)) { if (!mon.offense) continue; for (const byEl of Object.values(mon.offense)) { for (const [el, stats] of Object.entries(byEl)) { if (el === 'None' || el === 'Unknown') continue; totals[el] = (totals[el] || 0) + (stats.damage || 0); } } } } return Object.entries(totals) .map(([name, value]) => ({ name, value })) .filter(d => d.value > 0) .sort((a, b) => b.value - a.value); }, [characters]); return (

Kills per Hour

[v.toLocaleString(), 'Kills/hr']} labelFormatter={(l, payload) => payload?.[0]?.payload?.fullName || l} />
{damageData.length > 0 && (

Total Damage (Session)

[v.toLocaleString(), 'Damage']} labelFormatter={(l, payload) => payload?.[0]?.payload?.fullName || l} />
)} {elementData.length > 0 && (

Damage by Element (All Characters)

`${name} ${(percent * 100).toFixed(0)}%`} labelLine={true} fontSize={12} > {elementData.map((d) => ( ))} v.toLocaleString()} />
)}
); };