// Roll the sidecar's raw presence.online `byRegion` map (many named ServUO // regions) up into a handful of labelled display buckets for the "Players Online" // widget. This is the ONE place to retune the grouping — edit BUCKETS (order + // membership) and the widget follows. Anything not matched lands in "Wilderness" // so the bucket counts always reconcile to the true total. // Ordered list of buckets. `label` shows in the widget; `match(region)` decides // membership. First matching bucket wins; the last bucket is the catch-all. export const BUCKETS = [ { id: 'britain', label: 'Britain', // Passthrough for the capital + its immediate surrounds. match: (r) => /^britain/i.test(r), }, { id: 'towns', label: 'Towns', // The other named cities/towns. match: (r) => /^(moonglow|minoc|trinsic|jhelom|yew|skara ?brae|magincia|new ?magincia|vesper|nujelm|cove|ocllo|serpent'?s? hold|wind|delucia|papua)/i.test( r, ), }, { id: 'dungeons', label: 'Dungeons', match: (r) => /(despise|destard|deceit|shame|hythloth|covetous|wrong|terathan|fire|ice|orc cave|dungeon|abyss|doom|khaldun|wrong|blackthorn|exodus|labyrinth|underworld)/i.test( r, ), }, { id: 'housing', label: 'Housing', // House regions expose themselves as named house/townhouse regions. match: (r) => /(house|townhouse|homestead|tent)/i.test(r), }, { id: 'wilderness', label: 'Wilderness', // Catch-all: the unnamed "Wilderness" region + anything unmatched above. match: () => true, }, ] // Given a raw { region: count } map, return [{ id, label, count }] in BUCKETS // order, dropping empty buckets, with the summed total also returned. export function bucketize(byRegion = {}) { const totals = new Map(BUCKETS.map((b) => [b.id, 0])) let total = 0 for (const [region, n] of Object.entries(byRegion || {})) { const count = Number(n) || 0 total += count const bucket = BUCKETS.find((b) => b.match(String(region))) || BUCKETS[BUCKETS.length - 1] totals.set(bucket.id, totals.get(bucket.id) + count) } const rows = BUCKETS.map((b) => ({ id: b.id, label: b.label, count: totals.get(b.id) })).filter( (r) => r.count > 0, ) return { rows, total } }