fix(combat): show offense + defense damage by element in grid
The element breakdown grid previously only showed damage RECEIVED (defense) in the Mel/Msl and Magic columns, which was mostly empty for characters who evade/resist everything. Now shows both: - Given M/M + Given Mag: damage dealt by element (offense) - Recv M/M + Recv Mag: damage taken by element (defense) This makes the element breakdown immediately useful — you can see that you're dealing Slash damage via melee, for example. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c03b1c19f2
commit
ee30ad2636
1 changed files with 27 additions and 51 deletions
|
|
@ -4810,85 +4810,61 @@ function renderCombatStatsContent(win, charName) {
|
|||
const avgNormal = normalHits > 0 ? Math.round(offAll.totalNormalDamage / normalHits) : 0;
|
||||
const avgCrit = crits > 0 ? Math.round(offAll.totalCritDamage / crits) : 0;
|
||||
|
||||
// Damage received by element
|
||||
const defDmgMM = {}, defDmgMag = {};
|
||||
let totalDefMM = 0, totalDefMag = 0;
|
||||
// Damage by element — offense (given) and defense (received)
|
||||
const offDmgMM = {}, offDmgMag = {}, defDmgMM = {}, defDmgMag = {};
|
||||
let totalOffMM = 0, totalOffMag = 0, totalDefMM = 0, totalDefMag = 0;
|
||||
DAMAGE_ELEMENTS.forEach(el => {
|
||||
offDmgMM[el] = getDefDmg(offense, 'MeleeMissile', el);
|
||||
offDmgMag[el] = getDefDmg(offense, 'Magic', el);
|
||||
defDmgMM[el] = getDefDmg(defense, 'MeleeMissile', el);
|
||||
defDmgMag[el] = getDefDmg(defense, 'Magic', el);
|
||||
totalOffMM += offDmgMM[el];
|
||||
totalOffMag += offDmgMag[el];
|
||||
totalDefMM += defDmgMM[el];
|
||||
totalDefMag += defDmgMag[el];
|
||||
});
|
||||
|
||||
const totalDmgGiven = offAll.totalNormalDamage + offAll.totalCritDamage;
|
||||
|
||||
// Build the grid HTML — matches Mag-Tools CombatTrackerGUIInfo layout
|
||||
// Build the grid HTML
|
||||
const fmtN = n => n === 0 ? '' : n.toLocaleString();
|
||||
const rightCell = (text) => `<td style="text-align:right;padding:1px 4px;font-size:0.75rem;color:#ccc;">${text}</td>`;
|
||||
const labelCell = (text) => `<td style="padding:1px 4px;font-size:0.75rem;color:#aaa;">${text}</td>`;
|
||||
const headerCell = (text) => `<td style="text-align:right;padding:1px 4px;font-size:0.72rem;color:#888;font-weight:bold;">${text}</td>`;
|
||||
const statLabel = (text) => `<td style="padding:1px 4px;font-size:0.72rem;color:#888;font-weight:bold;">${text}</td>`;
|
||||
const sepCell = `<td style="width:4px;"></td>`;
|
||||
|
||||
let html = '<table style="width:100%;border-collapse:collapse;">';
|
||||
// Header
|
||||
html += `<tr><td></td>${headerCell('Mel/Msl')}${headerCell('Magic')}${statLabel('Attacks')}${rightCell(totalAttacks > 0 ? `${fmtN(totalAttacks)} (${hitRate}%)` : '')}</tr>`;
|
||||
|
||||
const statRows = [
|
||||
['Typeless', 'Attacks', () => totalAttacks > 0 ? `${fmtN(totalAttacks)} (${hitRate}%)` : ''],
|
||||
['Slash', 'Evades', () => totalMeleeDefends > 0 ? `${fmtN(totalMeleeDefends)} (${evadeRate}%)` : ''],
|
||||
['Pierce', 'Resists', () => totalMagicDefends > 0 ? `${fmtN(totalMagicDefends)} (${resistRate}%)` : ''],
|
||||
['Bludgeon', 'A.Surges', () => totalAethSurges > 0 ? `${fmtN(totalAethSurges)} (${aethRate}%)` : ''],
|
||||
['Fire', 'C.Surges', () => totalCloakSurges > 0 ? `${fmtN(totalCloakSurges)} (${cloakRate}%)` : ''],
|
||||
['Cold', '', () => ''],
|
||||
['Acid', 'Av/Mx', () => avgNormal > 0 ? `${fmtN(avgNormal)} / ${fmtN(offAll.maxNormalDamage)}` : ''],
|
||||
['Electric', 'Crits', () => crits > 0 ? `${fmtN(crits)} (${critRate}%)` : ''],
|
||||
// Column headers: Element | Dmg Given (M/M, Mag) | Dmg Recv (M/M, Mag) | Stats
|
||||
html += `<tr><td></td>${headerCell('Given M/M')}${headerCell('Given Mag')}${sepCell}${headerCell('Recv M/M')}${headerCell('Recv Mag')}${sepCell}${statLabel('Attacks')}${rightCell(totalAttacks > 0 ? `${fmtN(totalAttacks)} (${hitRate}%)` : '')}</tr>`;
|
||||
|
||||
// Stats to show on the right side of each element row
|
||||
const rightStats = [
|
||||
['Evades', () => totalMeleeDefends > 0 ? `${fmtN(totalMeleeDefends)} (${evadeRate}%)` : ''],
|
||||
['Resists', () => totalMagicDefends > 0 ? `${fmtN(totalMagicDefends)} (${resistRate}%)` : ''],
|
||||
['A.Surges', () => totalAethSurges > 0 ? `${fmtN(totalAethSurges)} (${aethRate}%)` : ''],
|
||||
['C.Surges', () => totalCloakSurges > 0 ? `${fmtN(totalCloakSurges)} (${cloakRate}%)` : ''],
|
||||
['', () => ''],
|
||||
['', () => ''],
|
||||
['Av/Mx', () => avgNormal > 0 ? `${fmtN(avgNormal)} / ${fmtN(offAll.maxNormalDamage)}` : ''],
|
||||
['Crits', () => crits > 0 ? `${fmtN(crits)} (${critRate}%)` : ''],
|
||||
];
|
||||
|
||||
// First row already printed above as header. Now element rows:
|
||||
for (let i = 0; i < DAMAGE_ELEMENTS.length; i++) {
|
||||
const el = DAMAGE_ELEMENTS[i];
|
||||
const sr = statRows[i];
|
||||
let statLabelText = sr ? sr[1] : '';
|
||||
let statValue = sr ? sr[2]() : '';
|
||||
|
||||
// Skip the duplicate "Attacks" row — it's already in the header
|
||||
if (i === 0) {
|
||||
statLabelText = 'Evades';
|
||||
statValue = totalMeleeDefends > 0 ? `${fmtN(totalMeleeDefends)} (${evadeRate}%)` : '';
|
||||
} else if (i === 1) {
|
||||
statLabelText = 'Resists';
|
||||
statValue = totalMagicDefends > 0 ? `${fmtN(totalMagicDefends)} (${resistRate}%)` : '';
|
||||
} else if (i === 2) {
|
||||
statLabelText = 'A.Surges';
|
||||
statValue = totalAethSurges > 0 ? `${fmtN(totalAethSurges)} (${aethRate}%)` : '';
|
||||
} else if (i === 3) {
|
||||
statLabelText = 'C.Surges';
|
||||
statValue = totalCloakSurges > 0 ? `${fmtN(totalCloakSurges)} (${cloakRate}%)` : '';
|
||||
} else if (i === 4) {
|
||||
statLabelText = '';
|
||||
statValue = '';
|
||||
} else if (i === 5) {
|
||||
statLabelText = '';
|
||||
statValue = '';
|
||||
} else if (i === 6) {
|
||||
statLabelText = 'Av/Mx';
|
||||
statValue = avgNormal > 0 ? `${fmtN(avgNormal)} / ${fmtN(offAll.maxNormalDamage)}` : '';
|
||||
} else if (i === 7) {
|
||||
statLabelText = 'Crits';
|
||||
statValue = crits > 0 ? `${fmtN(crits)} (${critRate}%)` : '';
|
||||
}
|
||||
|
||||
html += `<tr>${labelCell(el)}${rightCell(fmtN(defDmgMM[el]))}${rightCell(fmtN(defDmgMag[el]))}${statLabelText ? statLabel(statLabelText) : '<td></td>'}${rightCell(statValue)}</tr>`;
|
||||
const rs = rightStats[i] || ['', () => ''];
|
||||
html += `<tr>${labelCell(el)}${rightCell(fmtN(offDmgMM[el]))}${rightCell(fmtN(offDmgMag[el]))}${sepCell}${rightCell(fmtN(defDmgMM[el]))}${rightCell(fmtN(defDmgMag[el]))}${sepCell}${rs[0] ? statLabel(rs[0]) : '<td></td>'}${rightCell(rs[1]())}</tr>`;
|
||||
}
|
||||
|
||||
// Crit Avg/Max row
|
||||
html += `<tr><td></td><td></td><td></td>${statLabel('Av/Mx')}${rightCell(avgCrit > 0 ? `${fmtN(avgCrit)} / ${fmtN(offAll.maxCritDamage)}` : '')}</tr>`;
|
||||
html += `<tr><td></td><td></td><td></td>${sepCell}<td></td><td></td>${sepCell}${statLabel('Av/Mx')}${rightCell(avgCrit > 0 ? `${fmtN(avgCrit)} / ${fmtN(offAll.maxCritDamage)}` : '')}</tr>`;
|
||||
|
||||
// Blank row
|
||||
html += '<tr><td colspan="5" style="height:6px;"></td></tr>';
|
||||
html += `<tr><td colspan="9" style="height:6px;"></td></tr>`;
|
||||
|
||||
// Total row
|
||||
html += `<tr>${labelCell('Total')}${rightCell(fmtN(totalDefMM))}${rightCell(fmtN(totalDefMag))}${statLabel('Total')}${rightCell(fmtN(totalDmgGiven))}</tr>`;
|
||||
html += `<tr>${labelCell('Total')}${rightCell(fmtN(totalOffMM))}${rightCell(fmtN(totalOffMag))}${sepCell}${rightCell(fmtN(totalDefMM))}${rightCell(fmtN(totalDefMag))}${sepCell}${statLabel('Total')}${rightCell(fmtN(totalDmgGiven))}</tr>`;
|
||||
|
||||
html += '</table>';
|
||||
grid.innerHTML = html;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue