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

87 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🗂 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?)
```dataview
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)
```dataviewjs
// ===== 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)
])
);
}
```