diff --git a/static/script.js b/static/script.js index da359a1a..f7518b6f 100644 --- a/static/script.js +++ b/static/script.js @@ -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) => `${text}`; const labelCell = (text) => `${text}`; const headerCell = (text) => `${text}`; const statLabel = (text) => `${text}`; + const sepCell = ``; let html = ''; - // Header - html += `${headerCell('Mel/Msl')}${headerCell('Magic')}${statLabel('Attacks')}${rightCell(totalAttacks > 0 ? `${fmtN(totalAttacks)} (${hitRate}%)` : '')}`; - 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 += `${headerCell('Given M/M')}${headerCell('Given Mag')}${sepCell}${headerCell('Recv M/M')}${headerCell('Recv Mag')}${sepCell}${statLabel('Attacks')}${rightCell(totalAttacks > 0 ? `${fmtN(totalAttacks)} (${hitRate}%)` : '')}`; + + // 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 += `${labelCell(el)}${rightCell(fmtN(defDmgMM[el]))}${rightCell(fmtN(defDmgMag[el]))}${statLabelText ? statLabel(statLabelText) : ''}${rightCell(statValue)}`; + const rs = rightStats[i] || ['', () => '']; + html += `${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]) : ''}${rightCell(rs[1]())}`; } // Crit Avg/Max row - html += `${statLabel('Av/Mx')}${rightCell(avgCrit > 0 ? `${fmtN(avgCrit)} / ${fmtN(offAll.maxCritDamage)}` : '')}`; + html += `${sepCell}${sepCell}${statLabel('Av/Mx')}${rightCell(avgCrit > 0 ? `${fmtN(avgCrit)} / ${fmtN(offAll.maxCritDamage)}` : '')}`; // Blank row - html += ''; + html += ``; // Total row - html += `${labelCell('Total')}${rightCell(fmtN(totalDefMM))}${rightCell(fmtN(totalDefMag))}${statLabel('Total')}${rightCell(fmtN(totalDmgGiven))}`; + html += `${labelCell('Total')}${rightCell(fmtN(totalOffMM))}${rightCell(fmtN(totalOffMag))}${sepCell}${rightCell(fmtN(totalDefMM))}${rightCell(fmtN(totalDefMag))}${sepCell}${statLabel('Total')}${rightCell(fmtN(totalDmgGiven))}`; html += '
'; grid.innerHTML = html;