Files
a-legacy-forged-obsid-sync/Dungeons and Dragons/A Legacy Forged/Factions and Relationships/NPCs/NPC Dashboard.md
T

2.6 KiB
Raw Blame History

🗂 NPC Influence Dashboard

Scale: 10 … 0 … +10 (0 = Neutral; positive = more influential, negative = less)
Source: #npc • Excluding: NPC Template.md (change the name below if yours differs)


🧾 SMH Index (who calls it what?)

TABLE rows.file.link AS NPCs, rows.Faction AS Factions
FROM #npc
WHERE file.name != "NPC Template" AND SMH_Acronym
GROUP BY SMH_Acronym
SORT SMH_Acronym ASC

📊 Visual Bands (Emoji + Bipolar Progress Bars)

// ===== Source (tag-based; exclude template by name) =====
const PAGES = dv.pages('#npc')
  .where(p => p.file.name != "NPC Template")
  .where(p => Number.isFinite(+p.Level_of_Influence))
  .map(p => ({
    name: p.file.link,
    faction: p.Faction ?? "—",
    score: +p.Level_of_Influence
  }));

const MAX = 10;             // absolute ends: -10 .. +10
const WIDTH = 21;           // must be 2*MAX+1 to center on 0
const CENTER = 10;          // index of the 0 mark (10 for WIDTH=21)

// ===== Helpers =====
function tier(s) {
  if (s === 0) return "😐 Neutral";
  if (s <= -7) return "😡 Hostile";
  if (s <= -1) return "😕 Unfriendly";
  if (s >= 7)  return "🛡 Allied";
  return "🙂 Friendly";
}

// Build a centered gauge line like:  −10 ───────┼──────── +10
// and a second line placing a ▼ under the current position.
function gauge(score) {
  const idx = Math.max(0, Math.min(WIDTH - 1, Math.round(score + MAX)));
  const ticks = Array(WIDTH).fill("─");
  ticks[CENTER] = "┼"; // zero mark
  const bar = ticks.join("");

  const leftLabel = "10 ";
  const rightLabel = " +10";
  const line1 = `${leftLabel}${bar}${rightLabel}`;

  // Use nbsp so alignment holds inside tables
  const arrowOffset = leftLabel.length + idx;
  const arrowLine = "&nbsp;".repeat(arrowOffset) + "▼";

  return `<code>${line1}<br>${arrowLine}</code>`;
}

// ===== Groups =====
const groups = {
  "😡 Hostile (10 to 7)":   PAGES.filter(p => p.score <= -7),
  "😕 Unfriendly (6 to 1)": PAGES.filter(p => p.score >= -6 && p.score <= -1),
  "😐 Neutral (0)":           PAGES.filter(p => p.score === 0),
  "🙂 Friendly (+1 to +6)":   PAGES.filter(p => p.score >= 1 && p.score <= 6),
  "🛡 Allied (+7 to +10)":    PAGES.filter(p => p.score >= 7)
};

// ===== Render =====
for (const [title, rows] of Object.entries(groups)) {
  dv.header(2, title);
  if (!rows.length) { dv.paragraph("_None yet._"); continue; }
  dv.table(
    ["NPC", "Faction", "Score", "Gauge", "Tier"],
    rows.map(r => [
      r.name,
      r.faction,
      r.score,
      dv.span(gauge(r.score)),
      tier(r.score)
    ])
  );
}