From 4548195be096bb24e8a71d64385b0b160acebe5d Mon Sep 17 00:00:00 2001 From: Sundava Date: Wed, 23 Feb 2022 15:54:22 +0100 Subject: [PATCH] feat: Effective healing and absorptions For #191 --- config/index.html | 30 +++++++++++++++ overlay/css/table.css | 89 +++++++++++++++++++++++-------------------- overlay/lib/listen.js | 44 +++++++++++++++++---- share/lang/cn.json | 9 ++++- share/lang/de.json | 9 ++++- share/lang/en.json | 9 ++++- share/lang/fr.json | 11 +++++- share/lang/ja.json | 9 ++++- share/lang/ko.json | 9 ++++- share/lib/config.js | 47 ++++++++++++++++++++++- 10 files changed, 208 insertions(+), 58 deletions(-) diff --git a/config/index.html b/config/index.html index 5968a11..3e895c2 100644 --- a/config/index.html +++ b/config/index.html @@ -410,6 +410,36 @@

min="0" step="1" max="2" value="0" />

+

+ + + + + +

+

+ + + + + +

diff --git a/overlay/css/table.css b/overlay/css/table.css index 2221fbc..c61dbe1 100644 --- a/overlay/css/table.css +++ b/overlay/css/table.css @@ -18,48 +18,53 @@ flex-grow: 10; flex-basis: 0%; } -.flex-column-i-class { width: var(--_i-class)rem; } /* replace-hack only */ -.flex-column-i-rank { width: var(--_i-rank)rem; } -.flex-column-i-owner { width: var(--_i-owner)rem; } -.flex-column-i-name { width: var(--_i-name)rem; } -.flex-column-deal-total { width: var(--_deal-total)rem; } -.flex-column-deal-per-second { width: var(--_deal-per_second)rem; } -.flex-column-deal-pct { width: var(--_deal-pct)rem; } -.flex-column-deal-failure { width: var(--_deal-failure)rem; } -.flex-column-deal-accuracy { width: var(--_deal-accuracy)rem; } -.flex-column-deal-swing { width: var(--_deal-swing)rem; } -.flex-column-deal-miss { width: var(--_deal-miss)rem; } -.flex-column-deal-hitfail { width: var(--_deal-hitfail)rem; } -.flex-column-deal-critical { width: var(--_deal-critical)rem; } -.flex-column-deal-direct { width: var(--_deal-direct)rem; } -.flex-column-deal-crit-direct { width: var(--_deal-crit_direct)rem; } -.flex-column-deal-crittypes { width: var(--_deal-crittypes)rem; } -.flex-column-deal-critpcts { width: var(--_deal-critpcts)rem; } -.flex-column-deal-max { width: var(--_deal-max)rem; } -.flex-column-deal-maxhit { width: var(--_deal-maxhit)rem; } -.flex-column-deal-maxskill { width: var(--_deal-maxskill)rem; } -.flex-column-deal-last10 { width: var(--_deal-last10)rem; } -.flex-column-deal-last30 { width: var(--_deal-last30)rem; } -.flex-column-deal-last60 { width: var(--_deal-last60)rem; } -.flex-column-deal-last180 { width: var(--_deal-last180)rem; } -.flex-column-tank-damage { width: var(--_tank-damage)rem; } -.flex-column-tank-parry { width: var(--_tank-parry)rem; } -.flex-column-tank-heal { width: var(--_tank-heal)rem; } -.flex-column-tank-block { width: var(--_tank-block)rem; } -.flex-column-tank-threat-delta { width: var(--_tank-threat_delta)rem; } -.flex-column-heal-per-second { width: var(--_heal-per_second)rem; } -.flex-column-heal-pct { width: var(--_heal-pct)rem; } -.flex-column-heal-total { width: var(--_heal-total)rem; } -.flex-column-heal-swing { width: var(--_heal-swing)rem; } -.flex-column-heal-over { width: var(--_heal-over)rem; } -.flex-column-heal-cure { width: var(--_heal-cure)rem; } -.flex-column-heal-critical { width: var(--_heal-critical)rem; } -.flex-column-heal-max { width: var(--_heal-max)rem; } -.flex-column-heal-maxhit { width: var(--_heal-maxhit)rem; } -.flex-column-heal-maxskill { width: var(--_heal-maxskill)rem; } -.flex-column-etc-powerdrain { width: var(--_etc-powerdrain)rem; } -.flex-column-etc-death { width: var(--_etc-death)rem; } -.flex-column-etc-powerheal { width: var(--_etc-powerheal)rem; } +.flex-column-i-class { width: var(--_i-class)rem; } /* replace-hack only */ +.flex-column-i-rank { width: var(--_i-rank)rem; } +.flex-column-i-owner { width: var(--_i-owner)rem; } +.flex-column-i-name { width: var(--_i-name)rem; } +.flex-column-deal-total { width: var(--_deal-total)rem; } +.flex-column-deal-per-second { width: var(--_deal-per_second)rem; } +.flex-column-deal-pct { width: var(--_deal-pct)rem; } +.flex-column-deal-failure { width: var(--_deal-failure)rem; } +.flex-column-deal-accuracy { width: var(--_deal-accuracy)rem; } +.flex-column-deal-swing { width: var(--_deal-swing)rem; } +.flex-column-deal-miss { width: var(--_deal-miss)rem; } +.flex-column-deal-hitfail { width: var(--_deal-hitfail)rem; } +.flex-column-deal-critical { width: var(--_deal-critical)rem; } +.flex-column-deal-direct { width: var(--_deal-direct)rem; } +.flex-column-deal-crit-direct { width: var(--_deal-crit_direct)rem; } +.flex-column-deal-crittypes { width: var(--_deal-crittypes)rem; } +.flex-column-deal-critpcts { width: var(--_deal-critpcts)rem; } +.flex-column-deal-max { width: var(--_deal-max)rem; } +.flex-column-deal-maxhit { width: var(--_deal-maxhit)rem; } +.flex-column-deal-maxskill { width: var(--_deal-maxskill)rem; } +.flex-column-deal-last10 { width: var(--_deal-last10)rem; } +.flex-column-deal-last30 { width: var(--_deal-last30)rem; } +.flex-column-deal-last60 { width: var(--_deal-last60)rem; } +.flex-column-deal-last180 { width: var(--_deal-last180)rem; } +.flex-column-tank-damage { width: var(--_tank-damage)rem; } +.flex-column-tank-parry { width: var(--_tank-parry)rem; } +.flex-column-tank-heal { width: var(--_tank-heal)rem; } +.flex-column-tank-block { width: var(--_tank-block)rem; } +.flex-column-tank-threat-delta { width: var(--_tank-threat_delta)rem; } +.flex-column-heal-per-second { width: var(--_heal-per_second)rem; } +.flex-column-heal-pct { width: var(--_heal-pct)rem; } +.flex-column-heal-total { width: var(--_heal-total)rem; } +.flex-column-heal-effective-per-second { width: var(--_heal-effective_per_second)rem; } +.flex-column-heal-effective-pct { width: var(--_heal-effective_pct)rem; } +.flex-column-heal-effective-total { width: var(--_heal-effective_total)rem; } +.flex-column-heal-absorb-pct { width: var(--_heal-absorb_pct)rem; } +.flex-column-heal-absorb-total { width: var(--_heal-absorb_total)rem; } +.flex-column-heal-swing { width: var(--_heal-swing)rem; } +.flex-column-heal-over { width: var(--_heal-over)rem; } +.flex-column-heal-cure { width: var(--_heal-cure)rem; } +.flex-column-heal-critical { width: var(--_heal-critical)rem; } +.flex-column-heal-max { width: var(--_heal-max)rem; } +.flex-column-heal-maxhit { width: var(--_heal-maxhit)rem; } +.flex-column-heal-maxskill { width: var(--_heal-maxskill)rem; } +.flex-column-etc-powerdrain { width: var(--_etc-powerdrain)rem; } +.flex-column-etc-death { width: var(--_etc-death)rem; } +.flex-column-etc-powerheal { width: var(--_etc-powerheal)rem; } .pet-merged .flex-column-i-owner { display: none !important; diff --git a/overlay/lib/listen.js b/overlay/lib/listen.js index 23e3d39..b9d67de 100644 --- a/overlay/lib/listen.js +++ b/overlay/lib/listen.js @@ -13,6 +13,7 @@ SORTABLE[k] = o.v || o }) + class Data { constructor(data) { @@ -25,9 +26,9 @@ update(data) { this.isActive = data.isActive + this.calculateHealingValues(data) this.header = data.Encounter this.data = toArray(data.Combatant) - this.calculateMax(data.Combatant) } get(sort, merged) { @@ -93,21 +94,48 @@ } sort(key, target) { - let d = (('+-'.indexOf(key[0]))+1 || 1) * 2 - 3 - let k = SORTABLE[key.substr('+-'.indexOf(key[0]) >= 0)] - ;(target || this.data).sort((a, b) => (pFloat(a[k]) - pFloat(b[k])) * d) + let order = (('+-'.indexOf(key[0]))+1 || 1) * 2 - 3 // 1:asc, -1:desc + let sort_by = SORTABLE[key.substr('+-'.indexOf(key[0]) >= 0)] + if (typeof sort_by == "string") { + (target || this.data).sort((a, b) => (pFloat(a[sort_by]) - pFloat(b[sort_by])) * order) + } else if (typeof sort_by == "function") { + (target || this.data).sort((a, b) => (sort_by(a) - sort_by(b)) * order) + } if(target) return target } + // Calculate additional healing values and store them in the Combatant or Encounter + calculateHealingValues(data) { + let rhealing_effective = 0; + let rabsorb_healing = 0; + for (let i in data.Combatant) { + let player = data.Combatant[i]; + let effective = parseInt(player.healed) - parseInt(player.overHeal); + // Inject the calculated effective healing into the player data, while we're at it + player.effective_healing = effective; + rhealing_effective += effective; + rabsorb_healing += parseInt(player.absorbHeal) + } + // Inject into the Encounter data for later use + data.Encounter.rhealing_effective = rhealing_effective + data.Encounter.rabsorb_healing = rabsorb_healing + // Calculate the pct now that we have the total values + for (let i in data.Combatant) { + let player = data.Combatant[i]; + player.effective_pct = player.effective_healing / rhealing_effective * 100 + player.absorb_pct = player.absorbHeal / rabsorb_healing * 100 + } + } + calculateMax(combatant) { let max = {} - for(let k in SORTABLE) { let v = SORTABLE[k] - max[k] = Math.max.apply( - Math, Object.keys(combatant).map(_ => combatant[_][v]) - ) + if (typeof v == "string") + max[k] = Math.max.apply(Math, Object.keys(combatant).map(_ => combatant[_][v])) + else if (typeof v == "function") + max[k] = Math.max.apply(Math, combatant.map(_ => v(_))) } return max diff --git a/share/lang/cn.json b/share/lang/cn.json index 07af0ad..db120e6 100644 --- a/share/lang/cn.json +++ b/share/lang/cn.json @@ -218,7 +218,9 @@ "damage": "Damage", "hps": "HPS", "accuracy": "命中率", - "critical": "伤害和治疗百分比" + "critical": "伤害和治疗百分比", + "effective_pct": "% of total effective healing", + "absorb_pct": "% of total absorb healing" }, "thousands_separator": { "_": "Thousands separator", @@ -284,6 +286,11 @@ "per_second": ["HPS", "每秒治疗量"], "pct": ["H%", "治疗比率%"], "total": ["总治疗", "总治疗量"], + "effective_per_second" : ["Eff. HPS", "per Second effective"], + "effective_pct" : ["Eff. H%", "Effective healing %"], + "effective_total": ["Eff. H.", "Effective"], + "absorb_pct": ["Abs. %", "Absorption %"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["过量%", "过量治疗"], "swing": ["次数", "治疗次数"], "critical": ["H暴%", "治疗暴击率%"], diff --git a/share/lang/de.json b/share/lang/de.json index c631781..f261f98 100644 --- a/share/lang/de.json +++ b/share/lang/de.json @@ -218,7 +218,9 @@ "damage": "Damage", "hps": "HPS", "accuracy": "Fehlschlag (Verfehlt / Angriffe)", - "critical": "% der kritischen Treffer/Heilungen" + "critical": "% der kritischen Treffer/Heilungen", + "effective_pct": "% of total effective healing", + "absorb_pct": "% of total absorb healing" }, "thousands_separator": { "_": "Thousands separator", @@ -284,6 +286,11 @@ "per_second": ["HPS", "Heilung pro Sekunde"], "pct": ["H%", "% der Gesamtheilung"], "total": ["H.Ges.", "Gesamtheilung"], + "effective_per_second" : ["Eff. HPS", "per Second effective"], + "effective_pct" : ["Eff. H%", "Effective healing %"], + "effective_total": ["Eff. H.", "Effective"], + "absorb_pct": ["Abs. %", "Absorption %"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["OvrH", "Overheal"], "swing": ["Heilungen", "Anzahl der Heilungen"], "critical": ["HCrit", "Kritischer Trefferchance"], diff --git a/share/lang/en.json b/share/lang/en.json index 0832780..a391fe2 100644 --- a/share/lang/en.json +++ b/share/lang/en.json @@ -218,7 +218,9 @@ "damage": "Damage", "hps": "HPS", "accuracy": "Failure (Miss / Swing)", - "critical": "% of Critical hits/heals" + "critical": "% of Critical hits/heals", + "effective_pct": "% of total effective healing", + "absorb_pct": "% of total absorb healing" }, "thousands_separator": { "_": "Thousands separator", @@ -284,6 +286,11 @@ "per_second": ["HPS", "per Second"], "pct": ["H%", "Heal %"], "total": ["H.Tot", "Total"], + "effective_per_second" : ["Eff. HPS", "per Second effective"], + "effective_pct" : ["Eff. H%", "Effective healing %"], + "effective_total": ["Eff. H.", "Effective"], + "absorb_pct": ["Abs. %", "Absorption %"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["OvH%", "Overheal"], "swing": ["Swing", "Swings"], "critical": ["HCrit", "Critical%"], diff --git a/share/lang/fr.json b/share/lang/fr.json index b0b9f52..0727b7e 100644 --- a/share/lang/fr.json +++ b/share/lang/fr.json @@ -218,7 +218,9 @@ "damage": "Dégâts totaux", "hps": "Soins par seconde (HPS)", "accuracy": "Taux de précision", - "critical": "Taux de critique" + "critical": "Taux de critique", + "effective_pct": "% des soins effectifs", + "absorb_pct": "% d'absorption" }, "thousands_separator": { "_": "Séparateur de milliers", @@ -282,8 +284,13 @@ "heal": { "_": "Soin", "per_second": ["HPS", "Par seconde"], - "pct": ["H%", "Soin %"], + "pct": ["H%", "% des soins"], "total": ["H.Tot", "Total"], + "effective_per_second" : ["Eff. HPS", "Par seconde effectif"], + "effective_pct" : ["Eff. H%", "% des soins effectifs"], + "effective_total": ["Eff. H.", "Effectif"], + "absorb_pct": ["Abs. %", "% d'absorption"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["OvH%", "Overheal"], "swing": ["Esquive", "Esquives"], "critical": ["HCrit", "Critique%"], diff --git a/share/lang/ja.json b/share/lang/ja.json index 2e155f1..4602615 100644 --- a/share/lang/ja.json +++ b/share/lang/ja.json @@ -218,7 +218,9 @@ "hps": "HPS", "damage": "ダメージ値", "accuracy": "命中率", - "critical": "クリティカル" + "critical": "クリティカル", + "effective_pct": "% of total effective healing", + "absorb_pct": "% of total absorb healing" }, "thousands_separator": { "_": "千単位の区切り文字", @@ -284,6 +286,11 @@ "per_second": ["HPS", "HPS"], "pct": ["H%", "寄与率"], "total": ["H合", "合計"], + "effective_per_second" : ["Eff. HPS", "per Second effective"], + "effective_pct" : ["Eff. H%", "Effective healing %"], + "effective_total": ["Eff. H.", "Effective"], + "absorb_pct": ["Abs. %", "Absorption %"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["Ovr+", "オーバーヒール"], "swing": ["Swing", "詠唱回数"], "critical": ["HCrit", "Critical%"], diff --git a/share/lang/ko.json b/share/lang/ko.json index 2e96715..93da066 100644 --- a/share/lang/ko.json +++ b/share/lang/ko.json @@ -218,7 +218,9 @@ "hps": "HPS", "damage": "대미지 값", "accuracy": "실패율 (미스 수 / 타격 수)", - "critical": "극대화 비율" + "critical": "극대화 비율", + "effective_pct": "% of total effective healing", + "absorb_pct": "% of total absorb healing" }, "thousands_separator": { "_": "천 단위 구분자", @@ -284,6 +286,11 @@ "per_second": ["HPS", "HPS"], "pct": ["힐%", "기여율"], "total": ["힐 합계", "합계"], + "effective_per_second" : ["Eff. HPS", "per Second effective"], + "effective_pct" : ["Eff. H%", "Effective healing %"], + "effective_total": ["Eff. H.", "Effective"], + "absorb_pct": ["Abs. %", "Absorption %"], + "absorb_total": ["Abs. H.", "Absorption"], "over": ["Ovr+", "오버힐"], "swing": ["타격", "타격 횟수"], "critical": ["+극대", "극대화 비율"], diff --git a/share/lib/config.js b/share/lib/config.js index 7f22032..489f0ae 100644 --- a/share/lib/config.js +++ b/share/lib/config.js @@ -122,6 +122,11 @@ const CONFIG_DEFAULT = { '_heal-per_second': 3, '_heal-pct': 2, '_heal-total': 4, + '_heal-effective_per_second': 3, + '_heal-effective_pct': 3, + '_heal-effective_total': 4, + '_heal-absorb_pct': 3, + '_heal-absorb_total': 4, '_heal-swing': 2, '_heal-over': 2, '_heal-cure': 2, @@ -167,7 +172,9 @@ const CONFIG_DEFAULT = { damage: 0, hps: 0, accuracy: 0, - critical: 0 + critical: 0, + effective_pct: 0, + absorb_pct: 0 }, thousands_separator: '', merge_pet: true, @@ -230,6 +237,9 @@ const COLUMN_SORTABLE = [ 'tank.heal', 'heal.per_second', 'heal.total', + 'heal.effective_per_second', + 'heal.effective_total', + 'heal.absorb_total', '-etc.death' ] const COLUMN_MERGEABLE = [ @@ -515,6 +525,41 @@ const COLUMN_INDEX = { v: _ => _['OverHealPct'], f: _ => _ && _.replace? _.replace('%', '%') : '---' }, + effective_per_second: { + v: _ => { + return _['enchps'] * (1 - parseInt(_['OverHealPct']) / 100) + }, + f: (_, conf) => { + _ = pFloat(_) + return isNaN(_)? + '0' + : formatDps(_, conf.format, 'hps') + } + }, + effective_pct: { + v: 'effective_pct', + f: (_, conf) => { + if(isNaN(_)) return '---' + else if(_ >= 100) return '100' + else return (_).toFixed(conf.format.significant_digit.effective_pct) + (conf.format.use_tailing_pct? '%' : '') + } + }, + effective_total: { + v: 'effective_healing', // Calculated and injected Data.update() + f: (_, conf) => formatDps(_, conf.format, 'damage', true) + }, + absorb_pct: { + v: 'absorb_pct', + f: (_, conf) => { + if(isNaN(_)) return '---' + else if(_ >= 100) return '100' + else return (_).toFixed(conf.format.significant_digit.absorb_pct) + (conf.format.use_tailing_pct? '%' : '') + } + }, + absorb_total: { + v: 'absorbHeal', + f:(_, conf) => formatDps(_, conf.format, 'damage', true) + }, swing: 'heals', critical: { v: _ => (parseInt(_.critheals) || 0) / (parseInt(_.heals) || 1) * 100,