140 lines
4.6 KiB
JavaScript
140 lines
4.6 KiB
JavaScript
/**
|
|
* npc-card.js
|
|
* Data model constants and static helper class for NPC Quick Cards.
|
|
* No instantiation needed — use NPCCardData static methods throughout.
|
|
*/
|
|
|
|
export const MODULE_ID = "npc-quick-cards";
|
|
export const FLAG_KEY = "cardData";
|
|
|
|
// ── Speech quirk options ───────────────────────────────────────────────────────
|
|
export const SPEECH_QUIRKS = [
|
|
{ value: "never-answers-directly", label: "Never answers directly" },
|
|
{ value: "speaks-in-questions", label: "Speaks in questions" },
|
|
{ value: "excessive-use-of-titles", label: "Excessive use of titles" },
|
|
{ value: "repeats-last-word", label: "Repeats last word" },
|
|
{ value: "long-pauses", label: "Long pauses" },
|
|
{ value: "talks-over-people", label: "Talks over people" },
|
|
{ value: "whisperer", label: "Whisperer" },
|
|
{ value: "overly-formal", label: "Overly formal" },
|
|
{ value: "custom", label: "Custom..." },
|
|
];
|
|
|
|
// ── Personality tag categories ─────────────────────────────────────────────────
|
|
export const TAG_CATEGORIES = [
|
|
{ value: "motivation", label: "Motivation (amber)" },
|
|
{ value: "relationship", label: "Relationship (blue)" },
|
|
{ value: "knowledge", label: "Knowledge (green)" },
|
|
{ value: "danger", label: "Danger (red)" },
|
|
{ value: "other", label: "Other (grey)" },
|
|
];
|
|
|
|
// ── Static data helpers ────────────────────────────────────────────────────────
|
|
export class NPCCardData {
|
|
/**
|
|
* Read card data flags from an actor with safe defaults.
|
|
* Always returns a deep clone so callers can mutate freely.
|
|
* @param {Actor} actor
|
|
* @returns {object}
|
|
*/
|
|
static getFlags(actor) {
|
|
return foundry.utils.deepClone(
|
|
actor.getFlag(MODULE_ID, FLAG_KEY) ?? {}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Persist card data flags to an actor.
|
|
* @param {Actor} actor
|
|
* @param {object} data
|
|
* @returns {Promise}
|
|
*/
|
|
static async setFlags(actor, data) {
|
|
return actor.setFlag(MODULE_ID, FLAG_KEY, data);
|
|
}
|
|
|
|
/**
|
|
* Return true if this actor has any card data saved.
|
|
* @param {Actor} actor
|
|
* @returns {boolean}
|
|
*/
|
|
static hasCardData(actor) {
|
|
const flags = actor.getFlag(MODULE_ID, FLAG_KEY);
|
|
return flags !== undefined && flags !== null;
|
|
}
|
|
|
|
/**
|
|
* Create a fresh, empty card data object.
|
|
* @returns {object}
|
|
*/
|
|
static empty() {
|
|
return {
|
|
accent: "",
|
|
speechQuirk: "",
|
|
speechQuirkCustom: "",
|
|
mannerNote: "",
|
|
tags: [],
|
|
attitudes: {},
|
|
secrets: [],
|
|
linkedJournalId: null,
|
|
lastSceneId: null,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate a short random ID suitable for secret entries.
|
|
* @returns {string}
|
|
*/
|
|
static generateId() {
|
|
return foundry.utils.randomID(10);
|
|
}
|
|
|
|
/**
|
|
* Look up the display label for a speech quirk value.
|
|
* @param {string} value
|
|
* @returns {string}
|
|
*/
|
|
static quirkLabel(value) {
|
|
if (!value) return "";
|
|
return SPEECH_QUIRKS.find(q => q.value === value)?.label ?? value;
|
|
}
|
|
|
|
/**
|
|
* Resolve the effective speech quirk display string for a card's flags.
|
|
* Falls back to the custom text when quirk === "custom".
|
|
* @param {object} flags
|
|
* @returns {string}
|
|
*/
|
|
static resolvedQuirk(flags) {
|
|
if (!flags.speechQuirk) return "";
|
|
if (flags.speechQuirk === "custom") return flags.speechQuirkCustom || "Custom";
|
|
return NPCCardData.quirkLabel(flags.speechQuirk);
|
|
}
|
|
|
|
/**
|
|
* Build an attitudes array (sorted by PC name) suitable for template iteration.
|
|
* Avoids the Handlebars {{lookup}} helper.
|
|
* @param {object} attitudesObj - raw attitudes map { actorId: number }
|
|
* @param {object[]} playerActors - [{ id, name }]
|
|
* @returns {{ pcId: string, pcName: string, value: number }[]}
|
|
*/
|
|
static buildAttitudesArray(attitudesObj, playerActors) {
|
|
return playerActors.map(pc => ({
|
|
pcId: pc.id,
|
|
pcName: pc.name,
|
|
value: attitudesObj?.[pc.id] ?? 0,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Return a CSS class string describing an attitude value.
|
|
* @param {number} value -3 to +3
|
|
* @returns {string}
|
|
*/
|
|
static attitudeClass(value) {
|
|
if (value >= 2) return "attitude-trusted";
|
|
if (value <= -2) return "attitude-hostile";
|
|
return "attitude-neutral";
|
|
}
|
|
}
|