# ๐Ÿ—‚ 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 = " ".repeat(arrowOffset) + "โ–ผ"; return `${line1}
${arrowLine}
`; } // ===== 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) ]) ); } ```