feat(gowlers-tracking-ledger): add detailed source info and damage breakdown tooltips

- Source column now shows attacker name and item: "Damage (Chyvvom, Binding Contracts)"
- Add damage breakdown detection from pf1DamageData
- Add hover tooltips to delta (Δ) column showing damage/healing breakdown
- Extract damage types and values: "5 physical, 5 fire" etc.
- Store damageBreakdown field in history entries
- Support tooltips for HP and XP changes
- Update version to 0.1.13

Now you can see detailed damage types and amounts by hovering over the delta column,
and source column shows exactly who dealt the damage and with what ability.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
centron\schwoerer
2025-11-20 11:05:43 +01:00
parent dcbd76adb8
commit 0ed21afba9
2 changed files with 56 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
const MODULE_ID = "gowlers-tracking-ledger";
const MODULE_VERSION = "0.1.12";
const MODULE_VERSION = "0.1.13";
const TRACK_SETTING = "actorSettings";
const FLAG_SCOPE = "world";
const MAX_HISTORY_ROWS = 100;
@@ -430,7 +430,11 @@ function buildHistoryContent(actor, tabArg) {
columns: [
{ label: "Timestamp", render: (entry) => formatDate(entry.timestamp) },
{ label: "HP", render: (entry) => entry.value },
{ label: "Δ", render: (entry) => entry.diff },
{
label: "Δ",
render: (entry) => entry.diff,
getTitle: (entry) => entry.damageBreakdown ? `${entry.damageBreakdown}` : ""
},
{ label: "Source", render: (entry) => entry.source ?? "Manual" },
{ label: "Encounter", render: (entry) => entry.encounterId ? entry.encounterId.slice(0, 8) : "N/A" },
],
@@ -442,7 +446,11 @@ function buildHistoryContent(actor, tabArg) {
columns: [
{ label: "Timestamp", render: (entry) => formatDate(entry.timestamp) },
{ label: "XP", render: (entry) => entry.value },
{ label: "Δ", render: (entry) => entry.diff },
{
label: "Δ",
render: (entry) => entry.diff,
getTitle: (entry) => entry.damageBreakdown ? `${entry.damageBreakdown}` : ""
},
{ label: "Source", render: (entry) => entry.source ?? "Manual" },
{ label: "Encounter", render: (entry) => entry.encounterId ? entry.encounterId.slice(0, 8) : "N/A" },
],
@@ -526,7 +534,12 @@ function renderHistoryTable(entries, columns, id) {
.map(
(entry) => `
<tr>
${columns.map((col) => `<td>${col.render(entry) ?? ""}</td>`).join("")}
${columns.map((col) => {
const cellContent = col.render(entry) ?? "";
const title = col.getTitle ? col.getTitle(entry) : "";
const titleAttr = title ? ` title="${title}"` : "";
return `<td${titleAttr}>${cellContent}</td>`;
}).join("")}
</tr>`
)
.join("");
@@ -564,14 +577,42 @@ async function recordHistoryEntry(actor, statId, previous, nextValue, userId, op
}
}
// Detect source of the change
// Detect source of the change with actor and item details
let source = "Manual";
let sourceDetails = "";
let damageBreakdown = "";
if (options?.pf1DamageData) {
source = "Attack";
// Try to get attacker actor and item information
const attackerName = options?.pf1?.attackerName || "Unknown";
const itemName = options?.pf1?.itemName || "Attack";
source = "Damage";
sourceDetails = `${attackerName}, ${itemName}`;
// Extract damage breakdown if available
if (options?.pf1DamageData?.rolls) {
const damageRolls = options.pf1DamageData.rolls;
const breakdown = [];
let total = 0;
for (const roll of damageRolls) {
if (roll.damageType && roll.value) {
breakdown.push(`${roll.value} ${roll.damageType}`);
total += parseInt(roll.value) || 0;
}
}
if (breakdown.length > 0) {
damageBreakdown = breakdown.join(", ");
}
}
} else if (options?.healing) {
const healerName = options?.pf1?.healerName || "Unknown";
const itemName = options?.pf1?.itemName || "Healing";
source = "Healing";
sourceDetails = `${healerName}, ${itemName}`;
damageBreakdown = `Healed for ${Math.abs(diffValue)} HP`;
} else if (options?.pf1?.actionType === "spell") {
source = "Spell";
sourceDetails = options?.pf1?.itemName || "Spell";
} else if (statId === "xp" && diffValue > 0) {
source = "XP Award";
} else if (statId === "hp") {
@@ -579,11 +620,18 @@ async function recordHistoryEntry(actor, statId, previous, nextValue, userId, op
const hpDiff = parseInt(diffValue);
if (hpDiff < 0) {
source = "Damage";
damageBreakdown = `${Math.abs(hpDiff)} damage`;
} else if (hpDiff > 0) {
source = "Healing";
damageBreakdown = `${hpDiff} healing`;
}
}
// Format source with details if available
if (sourceDetails) {
source = `${source} (${sourceDetails})`;
}
const entry = {
timestamp: Date.now(),
value: config.formatValue(nextValue),
@@ -591,6 +639,7 @@ async function recordHistoryEntry(actor, statId, previous, nextValue, userId, op
user: game.users.get(userId)?.name ?? "System",
source: source,
encounterId: encounterId,
damageBreakdown: damageBreakdown,
};
console.log(`[GowlersTracking] History entry created for ${statId}:`, entry);

View File

@@ -3,7 +3,7 @@
"type": "module",
"title": "Gowler's Tracking Ledger",
"description": "Adds HP/XP/Currency log buttons to PF1 sheets and opens the tracking dialog preloaded with the actor's logs.",
"version": "0.1.12",
"version": "0.1.13",
"authors": [
{ "name": "Gowler", "url": "https://foundryvtt.com" }
],