feat(gowlers-tracking-ledger): improve damage source extraction with proper metadata resolution
- Implement resolveActorFromMetadata() to extract attacker from message metadata UUID - Implement resolveItemFromMetadata() to extract weapon/ability from attacker's inventory - Change label format from "Damage (Actor, Weapon)" to "Actor -> Weapon" (e.g., "Goblin -> Scimitar Slash") - Add support for identifiedInfo, metadata, flavor text, and speaker.alias in priority order - Add support for Critical and Nonlethal damage modifiers - Update version to 0.1.19 This properly resolves WHO did the damage (attacker name) and WHAT was used (weapon/ability name), addressing the missing damage details. Format matches reference macros (macro_activate-hp-tracking.js). 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
|
||||
const MODULE_ID = "gowlers-tracking-ledger";
|
||||
const MODULE_VERSION = "0.1.18";
|
||||
const MODULE_VERSION = "0.1.19";
|
||||
const TRACK_SETTING = "actorSettings";
|
||||
const FLAG_SCOPE = "world";
|
||||
const MAX_HISTORY_ROWS = 100;
|
||||
@@ -283,10 +283,11 @@ async function initializeModule() {
|
||||
Hooks.on("updateCombat", (combat) => onCombatUpdate(combat));
|
||||
|
||||
// Helper: Build source label from damage/healing context
|
||||
function buildSourceLabel(value, options) {
|
||||
// Order of precedence (per Manual_dmgtracking.md):
|
||||
// 1. identifiedInfo from chat message
|
||||
// 2. Chat card metadata (actor/item)
|
||||
// Format: "ActorName -> ActionName" (e.g., "Goblin -> Scimitar Slash")
|
||||
function buildSourceLabel(value, options = {}) {
|
||||
// Order of precedence (per reference macros and Manual_dmgtracking.md):
|
||||
// 1. identifiedInfo from chat message (action name, item name)
|
||||
// 2. Chat card metadata (actor/item UUIDs) - resolve to documents
|
||||
// 3. Chat card flavor text
|
||||
// 4. Fallbacks
|
||||
|
||||
@@ -296,55 +297,65 @@ async function initializeModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("[GowlersTracking] buildSourceLabel: Processing damage value:", value);
|
||||
console.log("[GowlersTracking] buildSourceLabel: Message flags:", message.flags);
|
||||
const info = message.flags?.pf1?.identifiedInfo ?? {};
|
||||
const metadata = message.flags?.pf1?.metadata ?? {};
|
||||
const fromChatFlavor = message.flavor?.trim();
|
||||
|
||||
// Check for identifiedInfo (action name, item name)
|
||||
if (message.flags?.pf1?.identifiedInfo) {
|
||||
const identified = message.flags.pf1.identifiedInfo;
|
||||
const actionName = identified.action || identified.actionName || identified.itemName;
|
||||
const actorName = identified.actorName || "Unknown";
|
||||
console.log("[GowlersTracking] Found identifiedInfo:", identified);
|
||||
if (actionName) {
|
||||
const label = value < 0 ? `Damage (${actorName}, ${actionName})` : `Healing (${actionName})`;
|
||||
console.log("[GowlersTracking] Using identifiedInfo label:", label);
|
||||
// Try to resolve the actor document from metadata
|
||||
const actorDoc = resolveActorFromMetadata(metadata);
|
||||
// Try to resolve the item document from the actor
|
||||
const itemDoc = actorDoc ? resolveItemFromMetadata(actorDoc, metadata) : null;
|
||||
|
||||
// Build actor name from multiple sources in order of preference
|
||||
const actorName = actorDoc?.name ??
|
||||
info.actorName ??
|
||||
message.speaker?.alias ??
|
||||
null;
|
||||
|
||||
// Build action/item name from multiple sources
|
||||
const actionName = info.actionName ??
|
||||
info.name ??
|
||||
itemDoc?.name ??
|
||||
fromChatFlavor ??
|
||||
null;
|
||||
|
||||
// Build final label with format "ActorName -> ActionName"
|
||||
let label = null;
|
||||
if (actorName && actionName) label = `${actorName} -> ${actionName}`;
|
||||
else if (actionName) label = actionName;
|
||||
else if (actorName) label = actorName;
|
||||
else label = value < 0 ? "Damage" : "Healing";
|
||||
|
||||
// Add special modifiers
|
||||
if (options.isCritical) label += " (Critical)";
|
||||
if (options.asNonlethal) label += " [Nonlethal]";
|
||||
|
||||
console.log("[GowlersTracking] buildSourceLabel resolved to:", label);
|
||||
return label;
|
||||
}
|
||||
|
||||
// Helper: Resolve actor from metadata UUID
|
||||
function resolveActorFromMetadata(metadata = {}) {
|
||||
if (!metadata.actor) return null;
|
||||
|
||||
try {
|
||||
if (typeof fromUuidSync === "function") {
|
||||
const doc = fromUuidSync(metadata.actor);
|
||||
if (doc instanceof Actor) return doc;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("[GowlersTracking] Failed to resolve actor UUID:", metadata.actor, err);
|
||||
}
|
||||
|
||||
// Check for chat card metadata (actor + item responsible)
|
||||
if (message.flags?.pf1?.metadata) {
|
||||
const meta = message.flags.pf1.metadata;
|
||||
const actorName = meta.actor?.name || meta.actorName || "Unknown";
|
||||
const itemName = meta.item?.name || meta.itemName || "Attack";
|
||||
console.log("[GowlersTracking] Found metadata:", meta);
|
||||
if (value < 0) {
|
||||
const label = `Damage (${actorName}, ${itemName})`;
|
||||
console.log("[GowlersTracking] Using metadata label:", label);
|
||||
return label;
|
||||
} else {
|
||||
const label = `Healing (${itemName})`;
|
||||
console.log("[GowlersTracking] Using metadata healing label:", label);
|
||||
return label;
|
||||
}
|
||||
// Fallback: extract actor ID from UUID and look up
|
||||
const id = String(metadata.actor).split(".").pop();
|
||||
return game.actors.get(id) ?? null;
|
||||
}
|
||||
|
||||
// Check for flavor text (custom macros may only have flavor)
|
||||
if (message.flavor) {
|
||||
// Try to parse flavor for action names
|
||||
const flavorMatch = message.flavor.match(/\*\*(.*?)\*\*|<strong>(.*?)<\/strong>/);
|
||||
if (flavorMatch) {
|
||||
const actionName = flavorMatch[1] || flavorMatch[2];
|
||||
const label = value < 0 ? `Damage (${actionName})` : `Healing (${actionName})`;
|
||||
console.log("[GowlersTracking] Using flavor text label:", label);
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallbacks
|
||||
const fallback = value < 0 ? "Damage" : "Healing";
|
||||
console.log("[GowlersTracking] Using fallback label:", fallback);
|
||||
return fallback;
|
||||
// Helper: Resolve item from actor's inventory using metadata UUID
|
||||
function resolveItemFromMetadata(actor, metadata = {}) {
|
||||
if (!metadata.item || !(actor?.items instanceof Collection)) return null;
|
||||
return actor.items.get(metadata.item) ?? null;
|
||||
}
|
||||
|
||||
// Helper: Record damage source for later consumption
|
||||
|
||||
@@ -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.18",
|
||||
"version": "0.1.19",
|
||||
"authors": [
|
||||
{ "name": "Gowler", "url": "https://foundryvtt.com" }
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user