Last active
May 4, 2024 11:04
-
-
Save ljosberinn/f7117e5833e365afe91b0ba8e5b1993c to your computer and use it in GitHub Desktop.
Umbreskul's Fractured Heart - DF S4 Report Component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const itemId = 212684; | |
const dotId = 433522; | |
const executeSpell = 433549; | |
const title = `<ItemIcon id="${itemId}" icon="inv_elemental_eternal_air" type="4">Umbrelskul's Fractured Heart</ItemIcon>`; | |
getComponent = () => { | |
const actors = {}; | |
const actorsById = {}; | |
for (const actor of reportGroup.actors) { | |
actorsById[actor.id] = actor; | |
} | |
for (const fight of reportGroup.fights) { | |
for (const combatantInfoEvent of fight.combatantInfoEvents) { | |
for (const item of combatantInfoEvent.gear) { | |
if (item.id === itemId) { | |
const actor = actorsById[combatantInfoEvent.source.id]; | |
const spec = fight.specForPlayer(actor); | |
actors[combatantInfoEvent.source.id] = { | |
dot: 0, | |
instakill: 0, | |
title: `<ActorIcon type="${combatantInfoEvent.source.subType}-${spec}">${combatantInfoEvent.source.name}</ActorIcon>`, | |
allDamageDone: 0, | |
}; | |
break; | |
} | |
} | |
} | |
/** @type Record<number, number> */ | |
const instakillCandidates = {}; | |
for (const event of fight.allEvents) { | |
if (event.type === "damage") { | |
if (event.source.type !== "Player") { | |
continue; | |
} | |
const key = `${event.target.id}-${event.targetInstanceId}`; | |
const totalForEvent = | |
event.amount + (event.absorbed ?? 0) - (event.overkill ?? 0); | |
if (event.ability?.id === dotId) { | |
actors[event.source.id].dot += totalForEvent; | |
// initialize watching the debuffed target | |
instakillCandidates[key] = 0; | |
// setup actor in case of missing combatant info | |
if (!(event.source.id in actors)) { | |
const actor = actorsById[event.source.id]; | |
const spec = fight.specForPlayer(actor); | |
actors[event.source.id] = { | |
dot: 0, | |
instakill: 0, | |
title: `<ActorIcon type="${event.source.subType}-${spec}">${event.source.name}</ActorIcon>`, | |
allDamageDone: 0, | |
}; | |
} | |
} | |
if (event.source.id in actors) { | |
actors[event.source.id].allDamageDone += totalForEvent; | |
} | |
// remember last seen hit points per afflicted target | |
if (key in instakillCandidates && event.targetResources) { | |
instakillCandidates[key] = event.targetResources.hitPoints; | |
} | |
continue; | |
} | |
if ( | |
event.type === "instakill" && | |
event.source.id in actors && | |
event.ability?.id === executeSpell | |
) { | |
const key = `${event.target.id}-${event.targetInstanceId}`; | |
if (!(key in instakillCandidates)) { | |
continue; | |
} | |
actors[event.source.id].instakill += instakillCandidates[key]; | |
// cleanup for memory | |
delete instakillCandidates[key]; | |
} | |
} | |
} | |
const data = []; | |
for (const actorId in actors) { | |
const actor = actors[actorId]; | |
const total = actor.dot + actor.instakill; | |
const dataset = { | |
name: actor.title, | |
dot: format(actor.dot), | |
instakill: format(actor.instakill), | |
total: format(total), | |
percentage: ((actor.instakill / total) * 100).toFixed(2) + "%", | |
overallPercentage: | |
format((total / actor.allDamageDone) * 100).toFixed(2) + "%", | |
}; | |
data.push(dataset); | |
} | |
if (data.length === 0) { | |
return { | |
component: "EnhancedMarkdown", | |
props: { | |
content: `Nobody was seen using ${title}`, | |
}, | |
}; | |
} | |
return { | |
component: "Table", | |
props: { | |
columns: { | |
title: { | |
header: title, | |
columns: { | |
name: { | |
header: "Name", | |
}, | |
dot: { | |
header: "DoT", | |
textAlign: "right", | |
}, | |
instakill: { | |
header: "Execute", | |
textAlign: "right", | |
}, | |
total: { | |
header: "Total", | |
textAlign: "right", | |
}, | |
percentage: { | |
header: "Instakill %", | |
textAlign: "right", | |
}, | |
overallPercentage: { | |
header: "Overall %", | |
textAlign: "right", | |
}, | |
}, | |
}, | |
}, | |
data: data.sort((a, b) => a.total > b.total), | |
}, | |
}; | |
}; | |
// no Intl.NumberFormatter available :sadge: | |
function format(number) { | |
if (number < 1000) { | |
return number; | |
} | |
if (number >= 1000 && number < 1_000_000) { | |
return (number / 1000).toFixed(12) + "K"; | |
} | |
if (number >= 1_000_000 && number < 1_000_000_000) { | |
return (number / 1000000).toFixed(2) + "M"; | |
} | |
if (number >= 1000000000 && number < 1000000000000) { | |
return (number / 1000000000).toFixed(2) + "B"; | |
} | |
if (number >= 1000000000000 && number < 1000000000000000) { | |
return (number / 1000000000000).toFixed(2) + "T"; | |
} | |
} |
@quentiamem
https://twitter.com/xepher1s/status/1773713050048070018?t=AGrY0kJHdm7xHwM7uHE2_Q&s=19 context here, if you have access to report components then yes you can use it!
alternatively, here's a weakauras version https://wago.io/lXT9wfXYl
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
what exactly does it do? Can I use it?