|
|
| Line 1: |
Line 1: |
| -- Module:MissionaryDailyOpsBVR (REWRITE + FLAG RESOLVER + CULT ICONS) | | -- Module:WarLeagueDivisionOpsBVR |
| -- Daily (PSSC-calendar keyed) missionary tasking ledger for the Temple Bank of the Reformed Stripping Path. | | -- Daily, in-world War League divisional operations log. |
| -- Deterministic output (no math.random / no os.time seeding). | | -- Integrates Module:BassaridianDailyEvents by parsing today’s city-event/urgency table output. |
| -- | | -- Includes division + city flag icons, with a safe fallback to the Imperial Trade Union flag |
| -- Features:
| | -- (same behavior as Module:MissionaryDailyOpsBVR). |
| -- • City profiles (culture/spiritual tags + per-city order bias)
| |
| -- • Economic signals parsed from General Port of Lake Morovia "Company Table"
| |
| -- (counts by sector + sample HQ companies) and used to bias order + task.
| |
| -- • Optional Threat Watch integration from Module:ReligiousEvents (opt-in).
| |
| -- • City flags: existence-checked; fallback to Imperial Trade Union flag when missing.
| |
| -- • Cult/Order icons: from Module:GeneralPortOperations addLogo(...) mapping. | |
| --
| |
| -- Usage:
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeTable}}
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeTable|region=Core}}
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeTable|includeThreat=yes}}
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeTable|showEcon=yes}}
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeCity|city=Vaeringheim}}
| |
| -- {{#invoke:MissionaryDailyOpsBVR|makeOrder|order=Order of Aurora Mystica}}
| |
|
| |
|
| local p = {} | | local p = {} |
|
| |
| local cal = require('Module:BassaridianCalendar')
| |
| local DAYS_IN_YEAR = 183
| |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 0) SMALL UTILS | | -- (A) PSSC DATE (same logic used by Module:BassaridianDailyEvents) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local function trim(s) | | local function getPSSCDate() |
| if s == nil then return "" end
| | local startDate = os.time({year = 1999, month = 8, day = 6}) |
| s = tostring(s)
| | local secondsInDay = 86400 |
| s = s:gsub("^%s+", ""):gsub("%s+$", "")
| | local daysPerYear = 183 |
| return s
| | local now = os.time() |
| end
| |
| | |
| local function safeTitleContent(titleText) | |
| local ok, t = pcall(mw.title.new, titleText)
| |
| if not ok or not t then return nil end
| |
| local ok2, content = pcall(function() return t:getContent() end)
| |
| if not ok2 then return nil end
| |
| return content
| |
| end
| |
| | |
| local function normalizeSpaces(s)
| |
| return (s or ""):gsub("[%s\u00A0]+", " ")
| |
| end
| |
|
| |
|
| local function stripWiki(s) | | local totalDays = math.floor((now - startDate) / secondsInDay) |
| s = tostring(s or "")
| | local yearFraction = totalDays / daysPerYear |
| -- Remove files/templates quickly
| | local psscYear = math.floor(yearFraction) |
| s = s:gsub("%[%[File:[^%]]+%]%]", "")
| | local dayOfYear = math.floor((yearFraction - psscYear) * daysPerYear) + 1 |
| s = s:gsub("%{%b{}%}", "")
| |
| -- Links: [[A|B]] => B, [[A]] => A
| |
| s = s:gsub("%[%[[^%]|]+|([^%]]+)%]%]", "%1")
| |
| s = s:gsub("%[%[([^%]]+)%]%]", "%1")
| |
| -- Bold/italics
| |
| s = s:gsub("'''''", ""):gsub("'''", ""):gsub("''", "")
| |
| return trim(s)
| |
| end
| |
|
| |
|
| local function containsAny(s, words) | | local month, dayOfMonth |
| s = (s or ""):lower()
| | if dayOfYear <= 61 then |
| for _, w in ipairs(words) do
| | month = 1; dayOfMonth = dayOfYear |
| if s:find(w, 1, true) then return true end
| | elseif dayOfYear <= 122 then |
| end
| | month = 2; dayOfMonth = dayOfYear - 61 |
| return false
| | else |
| end | | month = 3; dayOfMonth = dayOfYear - 122 |
| | end |
|
| |
|
| local function joinTags(tags) | | local dateString = string.format("%d/%d/%d PSSC", dayOfMonth, month, psscYear) |
| if not tags or #tags == 0 then return "" end
| | return { |
| local out = {}
| | text = dateString, |
| for _, t in ipairs(tags) do out[#out+1] = t end
| | year = psscYear, |
| return table.concat(out, ", ")
| | dayOfYear = dayOfYear, |
| | month = month, |
| | dom = dayOfMonth |
| | } |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 1) CALENDAR PARSING | | -- (B) HELPERS |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local function parseCalendarString(s) | | local function pick(t) return t[math.random(#t)] end |
| if type(s) ~= "string" then return nil end
| | |
| local dayOfYear, month, year = s:match("^(%d+),%s+([%a]+)%s+%b()%s*,%s*(%d+)%s+PSSC")
| | local function pickWeighted(list) |
| if dayOfYear and year then
| | local total = 0 |
| return tonumber(year), tonumber(dayOfYear), month
| | for _, it in ipairs(list) do total = total + (it.weight or 1) end |
| end
| | local r = math.random() * total |
| return nil
| | local acc = 0 |
| | for _, it in ipairs(list) do |
| | acc = acc + (it.weight or 1) |
| | if r <= acc then return it end |
| | end |
| | return list[#list] |
| end | | end |
|
| |
|
| local function extractEventText(s) | | local function bulletList(items) |
| if type(s) ~= "string" then return "" end
| | if not items or #items == 0 then return "" end |
| local ev = s:match("PSSC%s+–%s+(.-)%s+–%s+Proverb:")
| | return "<ul><li>" .. table.concat(items, "</li><li>") .. "</li></ul>" |
| return ev or ""
| |
| end | | end |
|
| |
|
| local function doyToMonthDom(doy) | | local function cityLink(cityName, anchorOverride) |
| if doy <= 61 then
| | local anchor = anchorOverride or cityName |
| return 1, doy
| | return string.format("[[List_of_cities_in_Bassaridia_Vaeringheim#%s|%s]]", anchor, cityName) |
| elseif doy <= 122 then
| |
| return 2, doy - 61
| |
| else
| |
| return 3, doy - 122
| |
| end
| |
| end | | end |
|
| |
|
| local function getDateInfo() | | local function opId(di, divCode, idx) |
| local raw = cal.getCurrentDate()
| | return string.format("WL-%03d.%03d-%s-%02d", di.year, di.dayOfYear, divCode, idx) |
| local y, doy = parseCalendarString(raw)
| |
| if not y or not doy then
| |
| y, doy = 0, 1
| |
| raw = tostring(raw or "")
| |
| end
| |
| local m, dom = doyToMonthDom(doy)
| |
| return {
| |
| year = y,
| |
| dayOfYear = doy,
| |
| monthNum = m,
| |
| dom = dom,
| |
| text = string.format("%d/%d/%d PSSC", dom, m, y),
| |
| raw = raw,
| |
| calendarEvent = extractEventText(raw),
| |
| }
| |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 2) DETERMINISTIC RNG | | -- (C) FLAG FALLBACK (matches the "use ITU flag when missing" pattern) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local function hash31(str) | | local DEFAULT_FLAG = "Imperial_Trade_Union_flag.png" |
| local h = 0
| |
| for i = 1, #str do
| |
| h = (h * 131 + str:byte(i)) % 2147483647
| |
| end
| |
| return h
| |
| end
| |
| | |
| local function lcg(seed)
| |
| local s = seed % 2147483647
| |
| if s <= 0 then s = s + 2147483646 end
| |
| return function()
| |
| s = (1103515245 * s + 12345) % 2147483647
| |
| return s
| |
| end
| |
| end
| |
|
| |
|
| local function pickFromList(nextInt, list, avoidValue) | | local function flagIcon(fileName, sizePx) |
| if #list == 0 then return nil end
| | local size = tonumber(sizePx) or 20 |
| if #list == 1 then return list[1] end
| | local f = (fileName and fileName ~= "") and fileName or DEFAULT_FLAG |
| local tries = 0
| | return string.format("[[File:%s|%dpx]]", f, size) |
| while tries < 12 do
| |
| local idx = (nextInt() % #list) + 1
| |
| local v = list[idx]
| |
| if v ~= avoidValue then return v end
| |
| tries = tries + 1
| |
| end
| |
| for _, v in ipairs(list) do
| |
| if v ~= avoidValue then return v end
| |
| end
| |
| return list[1]
| |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 3) COLOR CODING (Hatch-style) | | -- (D) INTEGRATE DAILY EVENTS (parse Module:BassaridianDailyEvents.makeTable()) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local function sevStyle(sev) | | local function buildEventMapForToday() |
| if sev == "red" then
| | local ok, daily = pcall(require, "Module:BassaridianDailyEvents") |
| return ' style="background-color:#f8d7da;"'
| | if not ok or not daily or type(daily.makeTable) ~= "function" then |
| elseif sev == "yellow" then
| | return {}, false |
| return ' style="background-color:#fff3cd;"'
| | end |
| else
| | |
| return ' style="background-color:#d4edda;"'
| | local tbl = daily.makeTable() -- rows: "| date || city || event || urgency" |
| end
| | local eventMap = {} |
| end
| |
|
| |
|
| --------------------------------------------------------------------------------
| | for line in tostring(tbl):gmatch("[^\n]+") do |
| -- 4) CITY NETWORK (canonical list)
| | if line:match("^|%s") and not line:match("^|%-%s*$") then |
| --------------------------------------------------------------------------------
| | local parts = mw.text.split(line:gsub("^|%s*", ""), "%s*||%s*") |
| local function normalizeForFlag(name)
| | if #parts >= 4 then |
| return (name or "")
| | local city = parts[2] |
| :gsub("[%s%-’]", "")
| | local ev = parts[3] |
| :gsub("[Áá]", "A"):gsub("[Éé]", "E")
| | local urg = parts[4] |
| :gsub("[Íí]", "I"):gsub("[Óó]", "O")
| | if city and city ~= "" and not eventMap[city] then |
| :gsub("[Úú]", "U"):gsub("[Ýý]", "Y")
| | eventMap[city] = { desc = ev, urgency = urg } |
| end | | end |
| | end |
| | end |
| | end |
|
| |
|
| local function cityLink(name)
| | return eventMap, true |
| return string.format("[[List of cities in Bassaridia Vaeringheim#%s|%s]]", name, name)
| |
| end | | end |
|
| |
|
| -- 54 canonical cities; tier used for "major city" baseline.
| | local function urgencyScore(urg) |
| local cityOrder = {
| | if urg == "CRITICAL" then return 4 end |
| -- Core majors
| | if urg == "HIGH" then return 3 end |
| {name="Vaeringheim", region="Core", tier="major"},
| | if urg == "MEDIUM" then return 2 end |
| {name="Luminaria", region="Core", tier="major"},
| | if urg == "LOW" then return 1 end |
| {name="Serena", region="Core", tier="major"},
| | return 0 |
| {name="Pyralis", region="Core", tier="major"},
| |
| {name="Symphonara", region="Core", tier="major"},
| |
| {name="Aurelia", region="Core", tier="major"},
| |
| {name="Somniumpolis", region="Core", tier="major"},
| |
| {name="Nexa", region="Core", tier="major"},
| |
| {name="Lunalis Sancta", region="Core", tier="major"},
| |
| {name="Sylvapolis", region="Core", tier="major"},
| |
| | |
| -- Core minors
| |
| {name="Saluria", region="Core", tier="minor"},
| |
| {name="Aetherium", region="Core", tier="minor"},
| |
| {name="Ferrum Citadel", region="Core", tier="minor"},
| |
| {name="Acheron", region="Core", tier="minor"},
| |
| {name="Erythros", region="Core", tier="minor"},
| |
| {name="Catonis Atrium", region="Core", tier="minor"},
| |
| {name="Delphica", region="Core", tier="minor"},
| |
| {name="Koinonía", region="Core", tier="minor"},
| |
| {name="Aureum", region="Core", tier="minor"},
| |
| | |
| -- Alperkin
| |
| {name="The Alpazkigz", region="Alperkin", tier="minor"},
| |
| {name="Odiferia", region="Alperkin", tier="minor"},
| |
| | |
| -- New South Jangsong
| |
| {name="Skýrophos", region="New South Jangsong", tier="major"},
| |
| {name="Bjornopolis", region="New South Jangsong", tier="major"},
| |
| {name="Aegirheim", region="New South Jangsong", tier="major"},
| |
| {name="Norsolyra", region="New South Jangsong", tier="major"},
| |
| {name="Thorsalon", region="New South Jangsong", tier="major"},
| |
| {name="Pelagia", region="New South Jangsong", tier="minor"},
| |
| {name="Myrene", region="New South Jangsong", tier="minor"},
| |
| {name="Thyrea", region="New South Jangsong", tier="minor"},
| |
| {name="Ephyra", region="New South Jangsong", tier="minor"},
| |
| {name="Halicarn", region="New South Jangsong", tier="minor"},
| |
| | |
| -- Haifan Bassaridia
| |
| {name="Keybir-Aviv", region="Haifan Bassaridia", tier="major"},
| |
| {name="Tel-Amin", region="Haifan Bassaridia", tier="major"},
| |
| {name="Diamandis", region="Haifan Bassaridia", tier="major"},
| |
| {name="Jogi", region="Haifan Bassaridia", tier="major"},
| |
| {name="Lewisburg", region="Haifan Bassaridia", tier="major"},
| |
| {name="Thermosalem", region="Haifan Bassaridia", tier="minor"},
| |
| {name="Akróstadium", region="Haifan Bassaridia", tier="minor"},
| |
| {name="Sufriya", region="Haifan Bassaridia", tier="minor"},
| |
| {name="Lykopolis", region="Haifan Bassaridia", tier="minor"},
| |
| | |
| -- Normark
| |
| {name="Ardclach", region="Normark", tier="major"},
| |
| {name="Riddersborg", region="Normark", tier="major"},
| |
| | |
| -- Ouriana
| |
| {name="Bashkim", region="Ouriana", tier="major"},
| |
| {name="Ourid", region="Ouriana", tier="major"},
| |
| {name="Tonar", region="Ouriana", tier="minor"},
| |
| | |
| -- Caledonia
| |
| {name="Fanghorn", region="Caledonia", tier="major"},
| |
| {name="Eikbu", region="Caledonia", tier="major"},
| |
| {name="Galvø", region="Caledonia", tier="major"},
| |
| {name="Sårensby", region="Caledonia", tier="minor"},
| |
| {name="Slevik", region="Caledonia", tier="minor"},
| |
| {name="Sjøsborg", region="Caledonia", tier="minor"},
| |
| {name="Storesund", region="Caledonia", tier="minor"},
| |
| {name="Notranskja", region="Caledonia", tier="minor"},
| |
| {name="Kaledonija", region="Caledonia", tier="minor"},
| |
| }
| |
| | |
| local function regionPass(filter, cityRegion) | |
| if not filter or filter == "" or filter == "All" then return true end
| |
| if filter == "Core" then return cityRegion == "Core" end
| |
| if filter == "NSJ" then return cityRegion == "New South Jangsong" end
| |
| if filter == "Haifan" then return cityRegion == "Haifan Bassaridia" end
| |
| if filter == "Caledonian" then return cityRegion == "Caledonia" end
| |
| return cityRegion == filter
| |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 4.1) CITY FLAGS (existence-checked + fallback) | | -- (E) FORCE ORGANIZATION |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local DEFAULT_CITY_FLAG_FILE = "Imperial Trade Union flag.png" | | local GROUND_ECHELONS = { |
| | | { name="Turmae", weight=5 }, |
| local function asciiNormalizeForFlag(name)
| | { name="Contubernia", weight=5 }, |
| return (name or "")
| | { name="Ordinis", weight=4 }, |
| :gsub("[%s%-’]", "")
| | { name="Manipuli", weight=3 }, |
| :gsub("[ÁáÀàÂâÄäÃãÅåĀā]", "A")
| | { name="Centuriae", weight=2 }, |
| :gsub("[ÉéÈèÊêËëĒē]", "E")
| | { name="Cohortes", weight=1 }, |
| :gsub("[ÍíÌìÎîÏïĪī]", "I")
| |
| :gsub("[ÓóÒòÔôÖöÕõØøŌō]", "O")
| |
| :gsub("[ÚúÙùÛûÜüŪū]", "U")
| |
| :gsub("[ÝýŸÿ]", "Y")
| |
| :gsub("[Ææ]", "AE")
| |
| end
| |
| | |
| local fileExistsCache = {}
| |
| local function fileExists(fileName)
| |
| if not fileName or fileName == "" then return false end
| |
| if fileExistsCache[fileName] ~= nil then return fileExistsCache[fileName] end
| |
| local ok, t = pcall(mw.title.new, "File:" .. fileName)
| |
| local exists = (ok and t and t.exists == true) or false
| |
| fileExistsCache[fileName] = exists
| |
| return exists
| |
| end
| |
| | |
| local citySet = {}
| |
| for _, c in ipairs(cityOrder) do citySet[c.name] = true end
| |
| | |
| -- Explicit odd filenames you noted (plus Skyrophos).
| |
| local cityFlagOverrides = {
| |
| ["Skýrophos"] = "SkyrophosFlag.png",
| |
| ["Sårensby"] = "SårensbyFlag.png",
| |
| ["Slevik"] = "SlevikFlag.png.png",
| |
| ["Kaledonija"]= "KaledonijaFlag.png",
| |
| } | | } |
|
| |
|
| local cityFlagMarkupCache = {} | | local NAVAL_ECHELONS = { |
| local function getCityFlagMarkup(cityName)
| | { name="Birlik-i Gemi (Patrol Element)", weight=5 }, |
| if cityFlagMarkupCache[cityName] then return cityFlagMarkupCache[cityName] end
| | { name="Tabur-i Derya (Task Unit)", weight=3 }, |
| | | { name="Ordu (Task Group)", weight=1 }, |
| -- 1) explicit override
| |
| local override = cityFlagOverrides[cityName]
| |
| if override and fileExists(override) then
| |
| local mk = string.format("[[File:%s|20px]]", override)
| |
| cityFlagMarkupCache[cityName] = mk
| |
| return mk
| |
| end
| |
| | |
| -- 2) try normalized candidates
| |
| local norm = normalizeForFlag(cityName)
| |
| local ascii = asciiNormalizeForFlag(cityName)
| |
| local candidates = {
| |
| norm .. "Flag.png",
| |
| ascii .. "Flag.png",
| |
| }
| |
| | |
| for _, fn in ipairs(candidates) do
| |
| if fileExists(fn) then
| |
| local mk = string.format("[[File:%s|20px]]", fn)
| |
| cityFlagMarkupCache[cityName] = mk
| |
| return mk
| |
| end
| |
| end
| |
| | |
| -- 3) fallback to ITU
| |
| local mk = string.format("[[File:%s|20px]]", DEFAULT_CITY_FLAG_FILE)
| |
| cityFlagMarkupCache[cityName] = mk
| |
| return mk
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- 5) CORRIDORS / ROLE HINTS (hard-coded)
| |
| --------------------------------------------------------------------------------
| |
| local RAIL = {
| |
| ["Lykopolis"]=true, ["Lewisburg"]=true, ["Bashkim"]=true, ["Somniumpolis"]=true,
| |
| ["Erythros"]=true, ["Vaeringheim"]=true, ["Symphonara"]=true, ["Skýrophos"]=true,
| |
| ["Norsolyra"]=true, ["Pelagia"]=true, ["Riddersborg"]=true, ["Sårensby"]=true,
| |
| } | | } |
| local FERRY = {["Jogi"]=true, ["Ardclach"]=true}
| |
|
| |
|
| --------------------------------------------------------------------------------
| | local AIR_ECHELONS = { |
| -- 6) MISSIONARY ORGANIZATION (sizes)
| | { name="Zeygi (Element)", weight=5 }, |
| --------------------------------------------------------------------------------
| | { name="Ptisis (Flight)", weight=3 }, |
| local org = { | | { name="Moira (Squadron)", weight=1 }, |
| Lampade = {size=3, code="L"},
| |
| Hetairoi = {size=6, code="H"},
| |
| Dodekade = {size=12, code="D"},
| |
| Kleisthenes = {size=25, code="K"},
| |
| Stoa = {size=50, code="S"},
| |
| Thiasos = {size=100, code="T"},
| |
| } | | } |
|
| |
|
| local function pickOrgUnit(nextInt, sev) | | local function pickEchelonForUrgency(echelons, uScore) |
| if sev == "green" then
| | local tuned = {} |
| return pickFromList(nextInt, {"Lampade","Hetairoi"}, nil)
| | for _, e in ipairs(echelons) do |
| elseif sev == "yellow" then
| | local w = e.weight or 1 |
| return pickFromList(nextInt, {"Hetairoi","Dodekade","Kleisthenes"}, nil)
| | if uScore >= 3 then |
| else
| | if e.name:match("Cohortes") or e.name:match("Ordu %(") or e.name:match("Moira") then |
| return pickFromList(nextInt, {"Kleisthenes","Stoa","Thiasos"}, nil)
| | w = w + 3 |
| end
| | elseif e.name:match("Centuriae") or e.name:match("Tabur%-i Derya") or e.name:match("Ptisis") then |
| | w = w + 2 |
| | end |
| | elseif uScore == 2 then |
| | if e.name:match("Centuriae") or e.name:match("Tabur%-i Derya") or e.name:match("Ptisis") then |
| | w = w + 1 |
| | end |
| | end |
| | table.insert(tuned, { name = e.name, weight = w }) |
| | end |
| | return pickWeighted(tuned).name |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 7) ORDERS + TASKS (tagged) | | -- (F) FLAGS (only specify known files; everything else auto-falls back to ITU) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local function orderLink(pageTitle, anchor, label) | | local CITY_FLAGS = { |
| return string.format("[[%s#%s|%s]]", pageTitle, anchor, label)
| | -- Vaeringheim investor belt |
| end
| | ["Vaeringheim"] = "VaeringheimFlag.png", |
| | ["Lunalis Sancta"] = "LunalisSanctaFlag.png", |
| | ["Luminaria"] = "LuminariaFlag.png", |
| | ["Serena"] = "SerenaFlag.png", |
| | ["Symphonara"] = "SymphonaraFlag.png", |
| | ["Aurelia"] = "AureliaFlag.png", |
| | ["Sylvapolis"] = "SylvapolisFlag.png", |
| | ["Delphica"] = "DelphicaFlag.png", |
| | ["Catonis Atrium"] = "CatonisAtriumFlag.png", |
| | ["Ferrum Citadel"] = "FerrumCitadelFlag.png", |
|
| |
|
| local function T(text, sev, tags)
| | -- Alpazkigz belt |
| return {text=text, sev=sev, tags=tags or {}}
| | ["Pyralis"] = "PyralisFlag.png", |
| end
| | ["Nexa"] = "NexaFlag.png", |
| | ["Saluria"] = "SaluriaFlag.png", |
| | ["Acheron"] = "AcheronFlag.png", |
| | ["Koinonía"] = "KoinoniaFlag.png", |
| | ["Aureum"] = "AureumFlag.png", |
| | ["Aetherium"] = "AetheriumFlag.png", |
| | ["Erythros"] = "ErythrosFlag.png", |
|
| |
|
| local orders = {
| | -- Odiferia |
| {key="OSI", name="Ordo Solis Invicti",
| | ["Somniumpolis"] = "SomniumpolisFlag.png", |
| link=orderLink("Atos (Reformed Stripping Path)","Ordo_Solis_Invicti","Ordo Solis Invicti"),
| |
| tasks={
| |
| T("Dawn rites and public illumination drill to restore civic clarity and discourage rumor cascades in market wards.","green",{"public","education","service"}),
| |
| T("Temple-school literacy session paired with cosmology instruction and shrine maintenance inspections.","green",{"education","shrine","service"}),
| |
| T("Solar route inspection at major junctions; traffic etiquette posted for pilgrims and commuters.","green",{"transit","rail","public"}),
| |
| T("Sun-pledge renewal for civic clerks; oath sheets sealed and logged with Temple Bank scribes.","green",{"governance","audit","service"}),
| |
| T("Public lamp and beacon blessing for tunnel nodes; wayfinding clarified for night labor shifts.","green",{"infrastructure","transit","industry"}),
| |
| T("Radiance audit of public lamps, mirrored courts, and shrine sightlines; repair orders issued under Temple Bank stipend.","yellow",{"infrastructure","audit","service"}),
| |
| T("Solar Circle consecration for a new neighborhood shrine, with crowd choreography and compliance wardens.","yellow",{"shrine","crowd","public"}),
| |
| T("Counter-broadsheet sermon cycle following unsigned pamphlets; witness interviews conducted with local elders.","yellow",{"heresy","investigation","public"}),
| |
| T("Joint patrol-litany along rail platforms to reduce theft and panic during peak transit hours.","yellow",{"rail","security","crowd"}),
| |
| T("Emergency morale procession after night unrest; hymn leadership and calm restoration at transit choke points.","red",{"unrest","crowd","transit"}),
| |
| }
| |
| },
| |
|
| |
|
| {key="OAM", name="Order of Aurora Mystica",
| | -- Hafaan / Jeseri (if these exist; if not, fallback will apply) |
| link=orderLink("Eos (Reformed Stripping Path)","Order_of_Aurora_Mystica","Order of Aurora Mystica"),
| | ["Hafaan"] = "HafaanFlag.png", |
| tasks={
| | ["Jeseri"] = "JeseriFlag.png", |
| T("Sunrise vigil and reconciliation rite for competing guilds; signed harmony pledges archived by Temple Bank clerks.","green",{"mediation","guild","service"}),
| |
| T("Dawn-watch observatory check and omen bulletin issued to reduce panic and stabilize labor shifts.","green",{"omen","public","service"}),
| |
| T("Quiet home-visits to recent migrants; orientation blessings and sanctioned neighborhood guides issued.","green",{"public","service","mediation"}),
| |
| T("Rooftop shrine upkeep and dawn-banner replacement; civic lanes kept clear for morning processions.","green",{"shrine","infrastructure","public"}),
| |
| T("Pilgrim flow timing review for a dawn festival; route markers placed to prevent crush points.","green",{"festival","crowd","public"}),
| |
| T("Civic blessing for new housing blocks; routing of foot-traffic to prevent crush points and misdirection.","yellow",{"crowd","infrastructure","service"}),
| |
| T("Counter-heresy sermon cycle following illicit broadsides; witness interviews conducted with local elders.","yellow",{"heresy","investigation","public"}),
| |
| T("Dawn mediation under escort after a workplace dispute threatens walkouts; settlement notarized.","yellow",{"mediation","industry","governance"}),
| |
| T("Omen-risk advisory for coastal weather or fog days; port stewards briefed and signage posted.","yellow",{"port","public","service"}),
| |
| T("Rapid-response pacification after arson rumor; dawn procession under guard with emergency stipend release.","red",{"unrest","arson","crowd"}),
| |
| }
| |
| },
| |
|
| |
|
| {key="HSA", name="Harmony Sanctum",
| | -- NSJ |
| link=orderLink("Micras (Reformed Stripping Path)","Harmony_Sanctum","Harmony Sanctum"),
| | ["Skýrophos"] = "SkyrophosFlag.png", |
| tasks={
| | ["Bjornopolis"] = "BjornopolisFlag.png", |
| T("Neighborhood mediation session for family disputes and trade-feud spillover; binding accords notarized.","green",{"mediation","service"}),
| | ["Aegirheim"] = "AegirheimFlag.png", |
| T("Harmony clinic for stress and rumor contagion; quiet-room rotations and guided breathing rites.","green",{"health","rumor","service"}),
| | ["Norsolyra"] = "NorsolyraFlag.png", |
| T("Queue-discipline coaching at relief points; volunteers trained to prevent confrontations.","green",{"order","queue","relief"}),
| | ["Thorsalon"] = "ThorsalonFlag.png", |
| T("Workplace concord circle for service districts; complaint channels clarified and posted.","green",{"service","mediation","governance"}),
| | ["Myrene"] = "MyreneFlag.png", |
| T("Inter-shrine courtesy visit to reduce rivalry; shared calendar commitments established.","green",{"balance","mediation","public"}),
| | ["Ephyra"] = "EphyraFlag.png", |
| T("Loyalty and morale audit of a civic office after complaint surge; corrective training scheduled.","yellow",{"audit","governance","service"}),
| | ["Thyrea"] = "ThyreaFlag.png", |
| T("Containment of a cult schism meeting; supervised dialogue and sanction warnings delivered.","yellow",{"schism","containment","public"}),
| | ["Pelagia"] = "PelagiaFlag.png", |
| T("Rumor forensics on a circulating ‘forbidden rite’ claim; witness tree compiled and forwarded.","yellow",{"rumor","investigation","public"}),
| | ["Halicarn"] = "HalicarnFlag.png", |
| T("Crowd-stabilization drill for festival season; steward assignments and safe exits mapped.","yellow",{"festival","crowd","public"}),
| |
| T("Major crowd-stabilization operation after riot signals; staged dispersal with peace-liturgy and escorts.","red",{"riot","crowd","public"}),
| |
| }
| |
| },
| |
|
| |
|
| {key="IGA", name="Ignis Aeternum",
| | -- Haifan |
| link=orderLink("Pyros (Reformed Stripping Path)","Ignis_Aeternum","Ignis Aeternum"),
| | ["Keybir-Aviv"] = "KeybirAvivFlag.png", |
| tasks={
| | ["Tel-Amin"] = "TelAminFlag.png", |
| T("Controlled fire blessing for workshops; safety rite doubled as inspection of fuel and storage.","green",{"industry","safety"}),
| | ["Jogi"] = "JogiFlag.png", |
| T("Kiln-and-forge consecration for a new artisan street; insurance seals verified.","green",{"industry","infrastructure","service"}),
| | ["Lewisburg"] = "LewisburgFlag.png", |
| T("Firebreak marking for dry-season hills; public notices issued to farmers and herders.","green",{"agri","fire","public"}),
| | ["Diamandis"] = "DiamandisFlag.png", |
| T("Hearth-blessing round for crowded tenements; cooking hazards corrected with wardens.","green",{"public","safety","service"}),
| | ["Thermosalem"] = "ThermosalemFlag.png", |
| T("Candle and incense quality check at shrine vendors; adulterants rejected and logged.","green",{"shrine","audit","service"}),
| | ["Akróstadium"] = "AkrostadiumFlag.png", |
| T("Purification burn at a compromised shrine-store; ash sealed and catalogued for Temple Bank disposal.","yellow",{"contam","shrine","service"}),
| | ["Lykopolis"] = "LykopolisFlag.png", |
| T("Investigation of incendiary threats near a gate-temple; firebreak plan issued to local wardens.","yellow",{"arson","investigation","security"}),
| | ["Sufriya"] = "SufriyaFlag.png", |
| T("Explosive-storage compliance check near port or rail yards; seals renewed and routes revised.","yellow",{"rail","port","security","industry"}),
| |
| T("Emergency response to active arson or explosive rumor; sanctified suppression teams deployed with escorts.","red",{"arson","crisis","security"}),
| |
| T("Post-incident purification circuit across multiple oratories; public confidence restored by nightfall.","red",{"incident","public","crowd"}),
| |
| }
| |
| },
| |
|
| |
|
| {key="CHS", name="Celestial Harmony Sect",
| | -- Normark + Ouriana |
| link=orderLink("Indigo (Reformed Stripping Path)","Celestial_Harmony_Sect","Celestial Harmony Sect"),
| | ["Riddersborg"] = "RiddersborgFlag.png", |
| tasks={
| | ["Ardclach"] = "ArdclachFlag.png", |
| T("Diplomatic courtesy visit to a city council; alignments review and oath renewal with minimal spectacle.","green",{"diplomacy","governance","service"}),
| | ["Ourid"] = "Ouridflag.png", |
| T("Star-chart instruction for apprentices; quiet observatory checks and record sealing.","green",{"education","astronomy","service"}),
| | ["Bashkim"] = "BashkimFlag.png", |
| T("Inter-city liaison packet prepared for corridor towns; travel permissions confirmed.","green",{"rail","service","governance"}),
| | -- Tonar flag may not exist; omit unless you have it |
| T("Boundary-harmony rite at a district line; neighbor shrines exchange tokens under witness.","green",{"balance","public","mediation"}),
| | -- ["Tonar"] = "TonarFlag.png", |
| T("Calm briefing for merchant captains on festival timing; reduce congestion and rumor spread.","green",{"port","service","public"}),
| | } |
| T("Faction-balance mediation between rival shrines; written compromise placed in Temple Bank archive.","yellow",{"balance","mediation","archive"}),
| |
| T("Rumor forensics on ‘forbidden rite’ claims; witness tree compiled and forwarded to Temple authorities.","yellow",{"rumor","investigation","public"}),
| |
| T("Quiet arbitration after contract dispute between a guild and a council office.","yellow",{"service","governance","mediation"}),
| |
| T("Transit coordination for high-profile delegates; platform escorts and crowd lanes established.","yellow",{"rail","crowd","security"}),
| |
| T("High-risk stabilization after cult confrontation; negotiators embedded with escorts to prevent escalation.","red",{"confrontation","crowd","security"}),
| |
| }
| |
| },
| |
| | |
| {key="GGS", name="Guild of Golden Shadows",
| |
| link=orderLink("Chrysos (Reformed Stripping Path)","Guild_of_Golden_Shadows","Guild of Golden Shadows"),
| |
| tasks={
| |
| T("Discrete audit of offertory ledgers and voucher seals; minor variances reconciled quietly.","green",{"finance","audit","service"}),
| |
| T("Merchant vetting interviews for a sensitive consignment; anonymity rites certified.","green",{"merchant","security","service"}),
| |
| T("Port-side seal verification for sacred cargo; chain-of-custody stamped and witnessed.","green",{"port","finance","security"}),
| |
| T("Rail consignment escort paperwork checked; handover points confirmed with station stewards.","green",{"rail","service","security"}),
| |
| T("Quiet fraud-prevention briefing for shrine treasurers; common forgery patterns circulated.","green",{"finance","education","service"}),
| |
| T("Counter-counterfeit sweep targeting forged stamps and false Temple consignments; evidence boxed and logged.","yellow",{"forgery","investigation","finance"}),
| |
| T("Debt dispute arbitration for a sanctioned charity line; terms rewritten and sealed.","yellow",{"finance","mediation","service"}),
| |
| T("Watchlist update for suspected smugglers using festival crowds; surveillance plan filed.","yellow",{"security","crowd","port"}),
| |
| T("Recovery detail for stolen reliquary property; surveillance and lawful seizure under civic warrant.","red",{"theft","security","investigation"}),
| |
| T("Crisis finance stabilization after panic; emergency stipend routing and rumor suppression coordination.","red",{"panic","finance","service"}),
| |
| }
| |
| },
| |
| | |
| {key="ASS", name="Azure Sentinel Sect",
| |
| link=orderLink("Thalassa (Reformed Stripping Path)","Azure_Sentinel_Sect","Azure Sentinel Sect"),
| |
| tasks={
| |
| T("Canal and fountain sanctification circuit; water-quality blessings paired with public reassurance.","green",{"water","public","service"}),
| |
| T("Harbor hygiene briefing for fish markets; cold-chain and wash stations checked.","green",{"port","health","service"}),
| |
| T("Flood-gate inspection rite; maintenance tickets issued and signed by civic stewards.","green",{"infrastructure","water","service"}),
| |
| T("Ferry pier blessing and rope inspection; boarding lines reorganized to reduce accidents.","green",{"ferry","port","public"}),
| |
| T("Reservoir vigil for drought days; ration etiquette posted at distribution points.","green",{"water","relief","public"}),
| |
| T("Harbor-side watch for sabotage indicators; shrine-wardens trained on lock and pier checks.","yellow",{"port","sabotage","security"}),
| |
| T("Storm or flood readiness rite; evacuation hymn routes verified with civic stewards.","yellow",{"flood","infrastructure","public"}),
| |
| T("Waterborne rumor containment bulletin; discourage panic buying and hoarding.","yellow",{"rumor","service","public"}),
| |
| T("Quarantine support for suspected waterborne illness; controlled distribution points blessed and monitored.","red",{"outbreak","water","health"}),
| |
| T("Major incident response: water infrastructure damage; emergency sanctification and ration-order enforcement.","red",{"infrastructure","crisis","public"}),
| |
| }
| |
| },
| |
| | |
| {key="REN", name="Reverie Nebulous",
| |
| link=orderLink("Nephele (Reformed Stripping Path)","Reverie_Nebulous","Reverie Nebulous"),
| |
| tasks={
| |
| T("Dream-interpretation clinic to reduce anxiety; rumor narratives redirected into sanctioned symbolism.","green",{"dream","rumor","service"}),
| |
| T("Nocturne counseling for insomnia cluster; soft-lit rites and chant rotation schedules.","green",{"health","sleep","service"}),
| |
| T("Public guidance sheet on lawful visions vs. sedition pamphlets; distributed at shrines.","green",{"education","public","service"}),
| |
| T("Quiet household visits after a death or displacement; stabilize grief cycles with sanctioned imagery.","green",{"service","health","public"}),
| |
| T("Festival mood stewardship: prevent illicit revel by offering sanctioned evening rites.","green",{"festival","public","morale"}),
| |
| T("Investigation of forbidden homily broadcasts; witness interviews and calm messaging drafted.","yellow",{"broadcast","investigation","service"}),
| |
| T("Rumor cascade mapping in service districts; identify the first carrier nodes.","yellow",{"rumor","investigation","service"}),
| |
| T("Containment of mass-vision panic; staged public reassurance with tightly controlled procession.","red",{"panic","crowd","public"}),
| |
| T("Stabilization after hallucination-linked violence; liaison with Harmony Sanctum for long-tail care.","red",{"violence","health","service"}),
| |
| T("Emergency night curfew-support rite; safe corridors marked to reduce shadow-fear incidents.","yellow",{"security","public","service"}),
| |
| }
| |
| },
| |
| | |
| {key="EOF", name="Eon Fellowship",
| |
| link=orderLink("Glinos (Reformed Stripping Path)","Eon_Fellowship","Eon Fellowship"),
| |
| tasks={
| |
| T("Cold-weather relief checks and ration fairness review; storage seals verified.","green",{"relief","logistics","service"}),
| |
| T("Infrastructure endurance audit: roofs, walls, and bridges; damage triage list issued.","green",{"infrastructure","audit","industry"}),
| |
| T("Shelter staffing rotation planned for storm season; volunteer rosters sealed.","green",{"relief","service","governance"}),
| |
| T("Rail convoy support brief for frontier deliveries; pacing and rest points set.","green",{"rail","logistics","service"}),
| |
| T("Queue discipline at distribution points; conflict triggers reduced through signage.","green",{"order","queue","public"}),
| |
| T("Conflict de-escalation for resource disputes; binding queue rules posted at distribution points.","yellow",{"order","queue","governance"}),
| |
| T("Emergency shelter activation after storm loss; warm-hall rites and controlled entry.","red",{"storm","relief","public"}),
| |
| T("Frontier outpost morale visit; endurance rites and supply accountability review.","yellow",{"frontier","audit","service"}),
| |
| T("Bridge closure coordination after damage report; detours posted and escorted.","yellow",{"infrastructure","transit","public"}),
| |
| T("High-risk escort for frontier convoys under threat; endurance cadres embedded with wardens.","red",{"frontier","security","logistics"}),
| |
| }
| |
| },
| |
| | |
| {key="UOR", name="Order of the Umbral Oracle",
| |
| link=orderLink("Noctis (Reformed Stripping Path)","Order_of_the_Umbral_Oracle","Order of the Umbral Oracle"),
| |
| tasks={
| |
| T("Night watch and omen-reading in the temple quarter; guidance slips sealed for officials.","green",{"omen","security","service"}),
| |
| T("Shadow-lane safety marking near canals and alleys; lantern placement logged.","green",{"public","security","transit"}),
| |
| T("Quiet counsel for a magistrate; truth-testing rite witnessed by two scribes.","green",{"governance","inquiry","service"}),
| |
| T("Missing-persons intake desk hosted at a shrine; reports standardized and forwarded.","green",{"service","investigation","public"}),
| |
| T("Nighttime rumor monitoring in taverns and stations; early interventions logged.","green",{"rumor","rail","service"}),
| |
| T("Discrete consultation for a magistrate; truth-testing rite witnessed by two scribes.","yellow",{"governance","inquiry","audit"}),
| |
| T("Shadow-route mapping after disappearances; safe-path markers installed with civic approval.","yellow",{"security","transit","public"}),
| |
| T("Evidence sealing after a midnight incident; chain-of-custody verified for Temple authorities.","yellow",{"investigation","security","service"}),
| |
| T("Emergency intervention after ‘demonic sign’ sightings; controlled crowd handling and ward placement.","red",{"demonic","panic","crowd"}),
| |
| T("High-risk extraction of a threatened cantor; night escort to secure sanctuary.","red",{"abduction","security","service"}),
| |
| }
| |
| },
| |
| | |
| {key="MVE", name="Mystery of the Verdant Embrace",
| |
| link=orderLink("Opsithe (Reformed Stripping Path)","Mystery_of_the_Verdant_Embrace","Mystery of the Verdant Embrace"),
| |
| tasks={
| |
| T("Harvest blessing and storage rite; spoilage prevention guidance issued to granaries.","green",{"agriculture","harvest","agri"}),
| |
| T("Garden-shrine restoration day with community labor; devotional planting aligned to calendar.","green",{"garden","shrine","agri"}),
| |
| T("Seed and tool stipend audit for smallholders; vouchers revalidated.","green",{"audit","agri","service"}),
| |
| T("Irrigation channel blessing and silt-clearing volunteer day; water etiquette posted.","green",{"water","agri","public"}),
| |
| T("Market stall purity checks for produce; vendors instructed on safe storage.","green",{"public","health","agri"}),
| |
| T("Food shortage mediation and ration arbitration; Temple Bank stipend adjustments proposed.","yellow",{"shortage","logistics","agri"}),
| |
| T("Pest or blight containment rites; field inspections with farmers’ associations.","yellow",{"blight","agriculture","agri"}),
| |
| T("Livestock procession routing for festival markets; prevent crush and theft.","yellow",{"crowd","festival","agri"}),
| |
| T("Famine-risk surge response; emergency distribution queues sanctified and monitored.","red",{"famine","relief","agri"}),
| |
| T("Emergency containment of contaminated grain rumor; sample testing coordinated with Sanctum Vitalis.","yellow",{"rumor","health","agri"}),
| |
| }
| |
| },
| |
| | |
| {key="CIL", name="Conclave Illuminara",
| |
| link=orderLink("Tarsica (Reformed Stripping Path)","Conclave_Illuminara","Conclave Illuminara"),
| |
| tasks={
| |
| T("Moonlit instruction circle; eclipse-watch protocol rehearsed with apprentice scribes.","green",{"lunar","education","service"}),
| |
| T("Night-sky bulletin posted to reduce panic during overcast weeks; lawful interpretations provided.","green",{"public","rumor","service"}),
| |
| T("Observatory instrument check; calibration seals signed and archived.","green",{"archive","audit","service"}),
| |
| T("Lantern route blessing for tunnels and arcades; wayfinding clarified for late shifts.","green",{"transit","public","service"}),
| |
| T("Quiet archive preservation: scroll humidity checks and secure storage review.","green",{"archive","service","audit"}),
| |
| T("Archive sealing of sensitive liturgies; access logs reviewed for anomalies.","yellow",{"archive","audit","security"}),
| |
| T("Public lantern rite to counter rumor cascades; controlled routes and timing set with wardens.","yellow",{"rumor","crowd","public"}),
| |
| T("Transit hub advisory after night panic; crowd lanes re-drawn and posted.","yellow",{"rail","crowd","transit"}),
| |
| T("Emergency omen bulletin after night panic; official statement drafted and delivered.","red",{"panic","public","service"}),
| |
| T("High-risk protection of an observatory site under threat; wards reinforced and watchers stationed.","red",{"threat","security","service"}),
| |
| }
| |
| },
| |
| | |
| {key="SCV", name="Sanctum Vitalis",
| |
| link=orderLink("Plateau (Reformed Stripping Path)","Sanctum_Vitalis","Sanctum Vitalis"),
| |
| tasks={
| |
| T("Clinic day: basic health screenings and hygiene instruction; water points checked.","green",{"health","public","service"}),
| |
| T("Sanctioned healer coordination meeting; triage roles rehearsed for outbreaks.","green",{"training","health","service"}),
| |
| T("Hygiene signage deployment at markets; handwash stations verified.","green",{"public","health","service"}),
| |
| T("Nutrition counseling for ration lines; supplement vouchers distributed under Temple Bank authorization.","green",{"nutrition","relief","service"}),
| |
| T("Quiet home checks for vulnerable households; prevent panic spirals after illness rumors.","green",{"service","health","rumor"}),
| |
| T("Supplement and ration fortification distribution under Temple Bank authorization.","yellow",{"nutrition","relief","service"}),
| |
| T("Outbreak protocol rehearsal with civic healers; spacing rules posted at shrines.","yellow",{"outbreak","training","public"}),
| |
| T("Quarantine lane setup drill at a terminal or station; entry control rehearsed.","yellow",{"rail","security","health"}),
| |
| T("Active outbreak response: triage lanes established; quarantine support and calm messaging.","red",{"outbreak","crisis","public"}),
| |
| T("Mass-casualty contingency drill after violence reports; intake points and transport routes mapped.","red",{"violence","logistics","service"}),
| |
| }
| |
| },
| |
| | |
| {key="ALB", name="Temple Alabaster",
| |
| link=orderLink("Ivory (Reformed Stripping Path)","Temple_Alabaster","Temple Alabaster"),
| |
| tasks={
| |
| T("Purity inspection of ritual vessels and incense stock; minor replacements approved.","green",{"purity","shrine","service"}),
| |
| T("Doctrinal reading circle for novices; sanctioned texts distributed with margin notes.","green",{"education","service","public"}),
| |
| T("Shrine inventory check for relic storage; locks and witness rules enforced.","green",{"security","shrine","audit"}),
| |
| T("Quiet correction of unsanctioned household rites; guidance issued without spectacle.","green",{"service","public","education"}),
| |
| T("Blessing of new white-draped oratory; entry etiquette posted to reduce disorder.","green",{"shrine","public","service"}),
| |
| T("Doctrinal correction session after unsigned broadsides; sanctioned texts distributed.","yellow",{"heresy","education","public"}),
| |
| T("Sanctuary security review for valuables; locking discipline and witness rules enforced.","yellow",{"security","shrine","service"}),
| |
| T("Investigation of tainted incense vendors; samples seized and chain-of-custody logged.","yellow",{"poison","investigation","service"}),
| |
| T("Emergency purification after poisoned incense discovery; wards placed and offenders sought.","red",{"poison","crisis","security"}),
| |
| T("High-risk protection of a central temple during unrest; entry control and calm liturgy.","red",{"unrest","security","crowd"}),
| |
| }
| |
| },
| |
| | |
| {key="CIC", name="Court of the Ironclad",
| |
| link=orderLink("Fenrir (Reformed Stripping Path)","Court_of_the_Ironclad","Court of the Ironclad"),
| |
| tasks={
| |
| T("Discipline drill for shrine wardens; non-lethal control and restraint practices.","green",{"training","security","service"}),
| |
| T("Escort for a threatened courier; route cleared and handover documented.","green",{"escort","security","service"}),
| |
| T("Patrol coordination with civic guards at terminals; hand signals and cordon rules standardized.","green",{"rail","security","service"}),
| |
| T("Gatehouse posture review for festival season; crowd lanes chalked and posted.","green",{"festival","crowd","security"}),
| |
| T("Weapons discipline check for attached wardens; compliance logs signed.","green",{"audit","security","service"}),
| |
| T("Guard coordination in a frontier district; watch rotations synchronized with civic militia.","yellow",{"militia","security","frontier"}),
| |
| T("Immediate reinforcement during riot signals; cordons established and safe egress opened.","red",{"riot","crowd","security"}),
| |
| T("Interdiction rehearsal for barricade incidents; safe corridors mapped.","yellow",{"barricade","security","public"}),
| |
| T("High-risk interdiction support for a seized oratory; secure perimeter until authorities arrive.","red",{"siege","security","public"}),
| |
| T("Protection detail for water or rail infrastructure after sabotage rumor; sentries posted.","yellow",{"sabotage","infrastructure","security"}),
| |
| }
| |
| },
| |
| | |
| {key="ACC", name="Accord Concordia",
| |
| link=orderLink("Lukedu (Reformed Stripping Path)","Accord_Concordia","Accord Concordia"),
| |
| tasks={
| |
| T("Public harmony dialogue; disputants guided to a signed concord recorded by Temple Bank scribes.","green",{"mediation","public","service"}),
| |
| T("Garden pavilion mediation for family inheritance disputes; settlement sealed.","green",{"mediation","service"}),
| |
| T("Civic cooperation workshop for rival guilds; shared calendar commitments set.","green",{"guild","coordination","service"}),
| |
| T("Inter-shrine calendar alignment meeting; procession timings standardized.","green",{"balance","public","service"}),
| |
| T("Quiet counseling for newly formed neighborhood councils; rules of debate issued.","green",{"governance","education","service"}),
| |
| T("Catacomb Harmonic Communion support: logistics, spacing, and participant verification.","yellow",{"rite","logistics","service"}),
| |
| T("Emergency reconciliation after faction clash; mediators embedded with escorts.","red",{"clash","crowd","security"}),
| |
| T("Transit-lane mediation after station dispute; queues reset and monitored.","yellow",{"rail","queue","public"}),
| |
| T("Harmonization response after rumor spike; joint bulletin with Harmony Sanctum circulated.","yellow",{"rumor","service","public"}),
| |
| T("High-risk crowd calming after panic; sound-liturgical dispersal and safe routes enforced.","red",{"panic","crowd","public"}),
| |
| }
| |
| },
| |
|
| |
|
| {key="MSV", name="Mystery of the Stygian Veil",
| | local DIVISION_FLAGS = { |
| link=orderLink("Styx (Reformed Stripping Path)","Mystery_of_the_Stygian_Veil","Mystery of the Stygian Veil"),
| | ["Vaeringheim Division"] = "VaeringheimDivisionFlag.png", |
| tasks={
| | ["Alpazkigz Division"] = "AlpazkigzDivisionFlag.png", |
| T("Funerary liaison and cemetery vigil support; grief rites standardized.","green",{"funeral","public","service"}),
| | ["Hatch Ministry Division"] = "HatchMinistryFlag.png", |
| T("Registry update for burials and memorial offerings; records sealed and witnessed.","green",{"archive","audit","service"}),
| | ["New South Jangsong Division"] = "NewSouthJangsongFlag.png", |
| T("Transition counseling for displaced families; resettlement blessings recorded.","green",{"displacement","relief","service"}),
| | ["Haifan Bassaridia Division"] = "HaifaDivisionFlag.png", |
| T("Cemetery perimeter inspection; prevent vandalism during festival nights.","green",{"security","public","service"}),
| | ["Bassaridian Normark Division"] = "BassaridianNormarkFlagB.png", |
| T("Quiet rites for recovered remains after an accident; soothe panic and rumor.","green",{"public","rumor","service"}),
| | ["Ouriana Division"] = "OurianaFlag.png", |
| T("Investigation of graveyard desecration rumor; ward placement and witness interviews.","yellow",{"desecration","investigation","security"}),
| | -- Odiferia/CKD: if you have division flags, add them; otherwise fallback will apply |
| T("Relic transfer paperwork verified for a shrine move; escorts scheduled.","yellow",{"escort","security","service"}),
| | -- ["Odiferia Division"] = "OdiferiaDivisionFlag.png", |
| T("Emergency containment after death-cult provocation; controlled rites to prevent escalation.","red",{"provocation","crowd","security"}),
| | -- ["Council of Kings Division"] = "CouncilOfKingsDivisionFlag.png", |
| T("High-risk escort of relics through hostile streets; secure route planning with wardens.","red",{"escort","security","public"}),
| |
| T("Post-violence reconciliation vigil at a canal memorial; prevent retaliation cycles.","yellow",{"violence","public","mediation"}),
| |
| }
| |
| },
| |
| | |
| {key="SYF", name="Sylvan Fellowship",
| |
| link=orderLink("Faun (Reformed Stripping Path)","Sylvan_Fellowship","Sylvan Fellowship"),
| |
| tasks={
| |
| T("Forest-edge shrine maintenance and trail safety check; minor repairs logged.","green",{"trail","shrine","agri"}),
| |
| T("Ecology rite with farmers: pest balance and water stewardship guidance.","green",{"ecology","agri","service"}),
| |
| T("Wildlife boundary notices posted; discourage poaching near sacred groves.","green",{"public","security","agri"}),
| |
| T("Community foraging orientation; prevent poisoning and rumor spirals.","green",{"education","health","agri"}),
| |
| T("Riverbank cleanup day; improve water flow and reduce disease risk.","green",{"water","health","public"}),
| |
| T("Containment of illegal logging or poaching rumor; community patrol coordination.","yellow",{"poaching","security","investigation"}),
| |
| T("Fire season preparedness for woodland towns; firebreak rites and evacuation path marking.","yellow",{"wildfire","public","security"}),
| |
| T("Blight liaison with Verdant Embrace; field sampling routes scheduled.","yellow",{"blight","agri","service"}),
| |
| T("Emergency response to wildfire risk; firebreak rites and evacuation path marking.","red",{"wildfire","crisis","public"}),
| |
| T("High-risk protection for a threatened grove shrine; cordon and ward reinforcement.","red",{"threat","security","public"}),
| |
| }
| |
| },
| |
| | |
| {key="MRM", name="Mystery of Red Mirth",
| |
| link=orderLink("Silenus (Reformed Stripping Path)","Myster_of_Red_Mirth","Mystery of Red Mirth"),
| |
| tasks={
| |
| T("Morale rite and sanctioned celebration oversight; prevent disorder while restoring joy.","green",{"morale","public","service"}),
| |
| T("Festival logistics support; safe routes and water points verified with civic stewards.","green",{"festival","crowd","public"}),
| |
| T("Sanctioned tavern-chaplain circuit; reduce brawls and theft through presence.","green",{"public","security","service"}),
| |
| T("Reconciliation feast for rival crews; agreements sealed before witnesses.","green",{"mediation","festival","service"}),
| |
| T("Public song-rotation at market hours; discourage rumor panic with sanctioned refrains.","green",{"rumor","public","service"}),
| |
| T("Containment of illicit revel causing unrest; correction by sanctioned rite and fines.","yellow",{"illicit","order","security"}),
| |
| T("Crowd-density enforcement for a stadium day; steward posts assigned.","yellow",{"crowd","festival","security"}),
| |
| T("Emergency morale stabilization after violence; controlled gatherings and escorts.","red",{"violence","crowd","public"}),
| |
| T("High-risk de-escalation during riot-prone festival; staged dispersal and peace hymns.","red",{"riot","crowd","security"}),
| |
| T("Post-panic comfort rites near transit hubs; prevent stampedes and retaliatory fights.","yellow",{"panic","rail","crowd"}),
| |
| }
| |
| },
| |
| | |
| {key="RCA", name="Rex Catonis",
| |
| link=orderLink("Cato (Reformed Stripping Path)","Rex_Catonis","Rex Catonis"),
| |
| tasks={
| |
| T("Civic order inspection: queue rules, market discipline, and shrine traffic flow.","green",{"order","queue","public"}),
| |
| T("Courtroom courtesy briefing; witness etiquette and silence rules reinforced.","green",{"governance","public","service"}),
| |
| T("Market weights-and-measures rite; deter fraud and stabilize pricing disputes.","green",{"audit","service","public"}),
| |
| T("Transit node discipline review; platform lines repainted and stewards assigned.","green",{"rail","order","transit"}),
| |
| T("Curfew signage and quiet-hours enforcement brief; reduce night disturbances.","green",{"security","public","service"}),
| |
| T("Administrative compliance review after complaints; corrective edicts posted.","yellow",{"compliance","governance","service"}),
| |
| T("Guard liaison for a threatened civic hall; protocol rehearsal and watch rotation.","yellow",{"security","governance","service"}),
| |
| T("Emergency restoration of order after mob action; escorted dispersal and curfew-litany.","red",{"mob","crowd","security"}),
| |
| T("High-risk support to authorities during barricade incident; perimeter discipline enforced.","red",{"barricade","security","public"}),
| |
| T("Port and rail dispute arbitration; enforce lawful priority lanes for relief cargo.","yellow",{"port","rail","order","relief"}),
| |
| }
| |
| },
| |
| | |
| {key="SDL", name="Sanctum Delphica",
| |
| link=orderLink("Sisera (Reformed Stripping Path)","Sanctum_Delphica","Sanctum Delphica"),
| |
| tasks={
| |
| T("Oracle consultation clinic for officials; questions logged and sealed.","green",{"oracle","governance","service"}),
| |
| T("Archive and library integrity check; catalog drift corrected and access verified.","green",{"archive","audit","service"}),
| |
| T("Public instruction on lawful prophecy vs. pamphlet fraud; leaflets distributed.","green",{"education","public","service"}),
| |
| T("Scribe training session; improve recordkeeping for relief and stipend flows.","green",{"education","audit","service"}),
| |
| T("Observatory-liaison briefing with Conclave Illuminara; shared bulletins standardized.","green",{"service","archive","public"}),
| |
| T("Investigation of forged prophecy pamphlets; counterfeit sources traced.","yellow",{"forgery","investigation","service"}),
| |
| T("Archive sealing of a sensitive docket after unrest; access reduced and witnessed.","yellow",{"security","archive","service"}),
| |
| T("Emergency counter-homily after loudspeaker seizure; sanctioned address delivered.","red",{"broadcast","crisis","public"}),
| |
| T("High-risk protection for a key temple scholar; escort and secure lodging arranged.","red",{"threat","security","service"}),
| |
| T("Transit bulletin for corridor cities after omen panic; prevent stampedes and conspiracies.","yellow",{"rail","panic","public"}),
| |
| }
| |
| },
| |
| | |
| {key="OAI", name="Ordo Amicitia",
| |
| link=orderLink("Erasmus (Reformed Stripping Path)","Ordo_Amicitia","Ordo Amicitia"),
| |
| tasks={
| |
| T("Charity distribution and household check-ins; kindness register updated for stipend support.","green",{"charity","relief","service"}),
| |
| T("Food-line volunteer training; prevent cutting and fights through posted rules.","green",{"relief","queue","public"}),
| |
| T("Shelter visitation for displaced workers; job referrals routed through civic offices.","green",{"service","relief","governance"}),
| |
| T("Agri stipend review for smallholders; vouchers revalidated and extensions logged.","green",{"agri","audit","service"}),
| |
| T("Compassion circuit to hospitals and clinics; morale support and supply notes recorded.","green",{"health","service","relief"}),
| |
| T("Offering logistics for a major rite; livestock and treasure accounted and sealed.","yellow",{"offering","audit","service"}),
| |
| T("Mediation for neighborhood poverty disputes; aid allocations made transparent.","yellow",{"aid","mediation","service"}),
| |
| T("Emergency relief surge after incident; soup lines sanctified and guarded.","red",{"relief","crowd","public"}),
| |
| T("High-risk protection for a vulnerable procession route; escorts and safe shelters staged.","red",{"procession","security","public"}),
| |
| T("Port-side charity intake after a ferry accident; registries updated and families notified.","yellow",{"port","relief","service"}),
| |
| }
| |
| },
| |
| | |
| {key="TIL", name="Temple Illuminata",
| |
| link=orderLink("Nikolaj (Reformed Stripping Path)","Temple_Illuminata","Temple Illuminata"),
| |
| tasks={
| |
| T("Lamp and beacon maintenance blessing; public wayfinding clarity restored.","green",{"beacon","transit","service"}),
| |
| T("Infrastructure illumination audit for tunnels and transit nodes; repair notices issued.","green",{"infrastructure","transit","industry"}),
| |
| T("Rail signal blessing at key junctions; reduce accidents and rumor panic.","green",{"rail","transit","public"}),
| |
| T("Workshop visit: lantern production quality review; defective stock quarantined.","green",{"industry","audit","service"}),
| |
| T("Public lantern-route map refreshed for festival season; prevent crush points.","green",{"festival","crowd","public"}),
| |
| T("Investigation of signal tampering near a transport hub; seals replaced and watchers posted.","yellow",{"tamper","security","transit"}),
| |
| T("Emergency lighting deployment after sabotage; temporary beacons installed with escorts.","red",{"sabotage","crisis","security"}),
| |
| T("High-risk stabilization at a transport hub after panic; controlled flow and sanctuary lanes.","red",{"panic","crowd","transit"}),
| |
| T("Port navigation-light inspection for fog days; harbor masters briefed.","yellow",{"port","infrastructure","service"}),
| |
| T("Tunnel crowd-discipline drill; stewards assigned and entry metering practiced.","yellow",{"crowd","infrastructure","transit"}),
| |
| }
| |
| },
| |
| } | | } |
|
| |
|
| |
| local orderByKey, orderByName, orderKeys, orderNames = {}, {}, {}, {}
| |
| for _, o in ipairs(orders) do
| |
| orderByKey[o.key] = o
| |
| orderByName[o.name] = o
| |
| orderKeys[#orderKeys+1] = o.key
| |
| orderNames[#orderNames+1] = o.name
| |
| end
| |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 7.1) ORDER ICONS (from Module:GeneralPortOperations addLogo mapping) | | -- (G) DIVISIONS + CITY POOLS |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local orderIconFile = { | | local DIVISIONS = { |
| ["Order of Aurora Mystica"] = "Auroramystica.png",
| | { name="Vaeringheim Division", link="[[Vaeringheim Division]]", code="VAE", weight=5, |
| ["Harmony Sanctum"] = "Harmonysanctum.png",
| | cities={"Vaeringheim","Luminaria","Serena","Symphonara","Aurelia","Somniumpolis","Nexa","Lunalis Sancta","Sylvapolis","Delphica","Catonis Atrium","Ferrum Citadel"} }, |
| ["Ignis Aeternum"] = "Ignis Aeternum.png",
| | { name="Alpazkigz Division", link="[[Alpazkigz Division]]", code="ALP", weight=4, |
| ["Celestial Harmony Sect"] = "HarmonySect.png",
| | cities={"Pyralis","Nexa","Saluria","Acheron","Koinonía","Aureum","Aetherium","Erythros", |
| ["Guild of Golden Shadows"] = "GoldenShadows.png",
| | "Fanghorn","Eikbu","Galvø","Sårensby","Slevik","Sjøsborg","Storesund","Notranskja","Kaledonija"} }, |
| ["Azure Sentinel Sect"] = "AzureSentinel.png",
| | { name="Odiferia Division", link="[[Odiferia Division]]", code="ODF", weight=3, |
| ["Reverie Nebulous"] = "RevNeb.png",
| | cities={"Odiferia","Somniumpolis","Aetherium","Ferrum Citadel","Aurelia","Symphonara"} }, |
| ["Eon Fellowship"] = "EonFel.png",
| | { name="Hatch Ministry Division", link="[[Hatch Ministry Division]]", code="HAT", weight=3, |
| ["Order of the Umbral Oracle"] = "Umbral.png",
| | cities={"Lewisburg","Lykopolis","Jogi","Keybir-Aviv","Tel-Amin","Diamandis","Thermosalem","Akróstadium","Sufriya"} }, |
| ["Mystery of the Verdant Embrace"] = "Verdant.png",
| | { name="New South Jangsong Division", link="[[New South Jangsong Division]]", code="NSJ", weight=3, |
| ["Conclave Illuminara"] = "Conclave.png",
| | cities={"Skýrophos","Bjornopolis","Aegirheim","Norsolyra","Thorsalon","Pelagia","Myrene","Thyrea","Ephyra","Halicarn"} }, |
| ["Sanctum Vitalis"] = "Vitalis.png",
| | { name="Haifan Bassaridia Division", link="[[Haifan Bassaridia Division]]", code="HFA", weight=3, |
| ["Temple Alabaster"] = "Alabaster.png",
| | cities={"Keybir-Aviv","Tel-Amin","Diamandis","Jogi","Lewisburg","Thermosalem","Akróstadium","Sufriya","Lykopolis"} }, |
| ["Court of the Ironclad"] = "Ironclad.png",
| | { name="Bassaridian Normark Division",link="[[Bassaridian Normark Division]]",code="BNO",weight=2, |
| ["Accord Concordia"] = "Concordia.png",
| | cities={"Ardclach","Riddersborg"} }, |
| ["Mystery of the Stygian Veil"] = "StygianVe.png",
| | { name="Ouriana Division", link="[[Ouriana Division]]", code="OUR", weight=2, |
| ["Sylvan Fellowship"] = "Sylvan.png",
| | cities={"Bashkim","Ourid","Tonar"} }, |
| ["Mystery of Red Mirth"] = "MirthFlag.png",
| | { name="Council of Kings Division", link="[[Council of Kings Division]]", code="CKD", weight=1, |
| ["Rex Catonis"] = "Catonis.png",
| | cities={"Vaeringheim","Bashkim","Ourid","Tonar"} }, |
| ["Sanctum Delphica"] = "SanctumDel.png",
| |
| ["Ordo Amicitia"] = "OrdoFl.png",
| |
| ["Temple Illuminata"] = "AureumFlag.png",
| |
| } | | } |
|
| |
| local function getOrderIconMarkup(orderName)
| |
| local fn = orderIconFile[orderName]
| |
| if fn and fileExists(fn) then
| |
| return string.format("[[File:%s|20px]] ", fn)
| |
| end
| |
| return ""
| |
| end
| |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 8) CITY PROFILES (complete) | | -- (H) OPERATION TYPES |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local cityProfiles = { | | local OP_GROUND = { |
| -- =========================
| | { name="corridor security (rail / canal / road checkpointing)", weight=4 }, |
| -- CORE MAJORS
| | { name="urban stabilization (cordon / curfew enforcement)", weight=3 }, |
| -- =========================
| | { name="anti-smuggling interdiction / contraband seizure", weight=3 }, |
| ["Vaeringheim"] = {
| | { name="infrastructure protection (port/bridge/aqueduct)", weight=3 }, |
| tags={"capital","admin","port","templebank","canals"},
| | { name="counter-insurgency sweep (cell disruption)", weight=2 }, |
| weights={GGS=4,HSA=3,RCA=3,ASS=2,CIL=2,CHS=2,OSI=1},
| | { name="hazard response (evacuation / debris clearance)", weight=2 }, |
| },
| | { name="convoy escort (supply / detainee / artifact transfer)", weight=2 }, |
| ["Luminaria"] = {
| | } |
| tags={"industry","rollingstock","innovation","dawn","infrastructure"},
| |
| weights={TIL=4,OAM=3,EOF=2,IGA=2,OSI=1,GGS=1},
| |
| },
| |
| ["Serena"] = {
| |
| tags={"civic","lake","hospitality","public"},
| |
| weights={HSA=3,ACC=2,OAI=2,ASS=1,CHS=1,OSI=1},
| |
| },
| |
| ["Pyralis"] = {
| |
| tags={"volcanic","hazard","fire","reconstruction"},
| |
| weights={IGA=4,ASS=2,SCV=2,EOF=1,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Symphonara"] = {
| |
| tags={"civic","arts","festival","public"},
| |
| weights={MRM=3,ACC=2,OSI=2,OAM=2,HSA=1,RCA=1},
| |
| },
| |
| ["Aurelia"] = {
| |
| tags={"civic","trade","public"},
| |
| weights={HSA=2,CHS=2,GGS=2,ACC=1,OSI=1},
| |
| },
| |
| ["Somniumpolis"] = {
| |
| tags={"finance","dream","rumorcontrol","noctic"},
| |
| weights={REN=3,GGS=3,HSA=2,UOR=2,CIL=2,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Nexa"] = {
| |
| tags={"market","trade","logistics"},
| |
| weights={GGS=3,HSA=2,CHS=2,RCA=1,ASS=1,ACC=1},
| |
| },
| |
| ["Lunalis Sancta"] = {
| |
| tags={"lunar","archives","pilgrimage","omens"},
| |
| weights={CIL=4,REN=2,UOR=2,SDL=1,HSA=1},
| |
| },
| |
| ["Sylvapolis"] = {
| |
| tags={"forest","garden","ecology","shrinework"},
| |
| weights={SYF=3,MVE=3,OAI=1,HSA=1,ASS=1},
| |
| },
| |
|
| |
|
| -- =========================
| | local OP_NAVAL = { |
| -- CORE MINORS
| | { name="maritime escort / lake patrol routing", weight=3 }, |
| -- =========================
| | { name="VBSS / interdiction / contraband boarding", weight=3 }, |
| ["Saluria"] = {
| | { name="blockade enforcement / straits compliance sweep", weight=2 }, |
| tags={"civic","artisan","wildlife"},
| | { name="harbor security (lock-gates / inner basin patrol)", weight=2 }, |
| weights={SYF=2,CHS=2,ACC=1,HSA=1,OAI=1},
| | } |
| },
| |
| ["Aetherium"] = {
| |
| tags={"sky","omens","education"},
| |
| weights={CIL=2,OAM=2,CHS=2,OSI=1},
| |
| },
| |
| ["Ferrum Citadel"] = {
| |
| tags={"fortress","industry","security","infrastructure"},
| |
| weights={CIC=3,RCA=2,TIL=2,EOF=1,IGA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Acheron"] = {
| |
| tags={"frontier","containment","mines","security"},
| |
| weights={CIC=3,EOF=2,MSV=1,UOR=1,IGA=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Erythros"] = {
| |
| tags={"corridor","trade","security"},
| |
| weights={GGS=2,RCA=2,TIL=2,ASS=1,IGA=1},
| |
| },
| |
| ["Catonis Atrium"] = {
| |
| tags={"civic","law","order"},
| |
| weights={RCA=4,HSA=1,CHS=1,ACC=1},
| |
| },
| |
| ["Delphica"] = {
| |
| tags={"oracle","archives","scholarship"},
| |
| weights={SDL=4,CIL=2,CHS=1,HSA=1},
| |
| },
| |
| ["Koinonía"] = {
| |
| tags={"harmony","mediation","civic"},
| |
| weights={ACC=3,HSA=3,CHS=1,OAI=1},
| |
| },
| |
| ["Aureum"] = {
| |
| tags={"wealth","craft","trade","finance"},
| |
| weights={GGS=4,HSA=1,RCA=1,ALB=1},
| |
| },
| |
|
| |
|
| -- =========================
| | local OP_AIR = { |
| -- ALPERKIN
| | { name="ISR overwatch / route scanning", weight=4 }, |
| -- =========================
| | { name="rapid extraction / medevac lift", weight=2 }, |
| ["The Alpazkigz"] = {
| | { name="strike deterrence package (show of force)", weight=1 }, |
| tags={"tribal","festival","intercession","mediation"},
| |
| weights={ACC=3,HSA=2,CHS=2,OAI=1,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Odiferia"] = {
| |
| tags={"noctic","rumorcontrol","dream","folk"},
| |
| weights={REN=3,HSA=2,GGS=2,UOR=2,MSV=1},
| |
| baseSev="yellow",
| |
| },
| |
| | |
| -- =========================
| |
| -- NEW SOUTH JANGSONG (MAJOR)
| |
| -- =========================
| |
| ["Skýrophos"] = {
| |
| tags={"integration","civic","corridor","governance"},
| |
| weights={CHS=2,HSA=2,RCA=2,TIL=2,EOF=2,ACC=1},
| |
| },
| |
| ["Bjornopolis"] = {
| |
| tags={"north","fortified","industry","civic"},
| |
| weights={EOF=3,CIC=2,TIL=2,ASS=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Aegirheim"] = {
| |
| tags={"north","coastal","harbor","watch"},
| |
| weights={ASS=3,EOF=2,CIC=1,TIL=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Norsolyra"] = {
| |
| tags={"agriculture","wetlands","river","supply"},
| |
| weights={MVE=3,ASS=2,SYF=2,OAI=1,SCV=1},
| |
| },
| |
| ["Thorsalon"] = {
| |
| tags={"north","vineyards","festival","supply"},
| |
| weights={MVE=2,MRM=2,EOF=2,OAI=1,ASS=1},
| |
| baseSev="yellow",
| |
| },
| |
| | |
| -- =========================
| |
| -- NEW SOUTH JANGSONG (MINOR)
| |
| -- =========================
| |
| ["Pelagia"] = {
| |
| tags={"coastal","distribution","water","relief"},
| |
| weights={ASS=3,SCV=2,HSA=1,EOF=1},
| |
| },
| |
| ["Myrene"] = {
| |
| tags={"coastal","civic","trade"},
| |
| weights={ASS=2,HSA=2,CHS=1,ACC=1},
| |
| },
| |
| ["Thyrea"] = {
| |
| tags={"agriculture","market","relief"},
| |
| weights={MVE=3,OAI=2,SYF=1,HSA=1},
| |
| },
| |
| ["Ephyra"] = {
| |
| tags={"forest","frontier","watch","omens"},
| |
| weights={SYF=3,UOR=2,EOF=1,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Halicarn"] = {
| |
| tags={"archives","scholarship","civic"},
| |
| weights={SDL=3,CIL=2,CHS=1,HSA=1},
| |
| },
| |
| | |
| -- =========================
| |
| -- HAIFAN BASSARIDIA (MAJOR)
| |
| -- =========================
| |
| ["Keybir-Aviv"] = {
| |
| tags={"port","trade","gateway","security"},
| |
| weights={ASS=3,GGS=2,HSA=2,RCA=1,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Tel-Amin"] = {
| |
| tags={"plantation","coffee","trade","agriculture"},
| |
| weights={MVE=3,OAI=2,SYF=2,GGS=1,ASS=1},
| |
| },
| |
| ["Diamandis"] = {
| |
| tags={"luxury","trade","vaulting","security"},
| |
| weights={GGS=4,RCA=2,ALB=1,HSA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Jogi"] = {
| |
| tags={"agroprocessing","market","ferry","trade"},
| |
| weights={MVE=3,OAI=2,ASS=2,SYF=1,GGS=1},
| |
| },
| |
| ["Lewisburg"] = {
| |
| tags={"rail","hub","logistics","governance"},
| |
| weights={TIL=4,RCA=3,GGS=2,HSA=1,EOF=1,ASS=1},
| |
| baseSev="yellow",
| |
| },
| |
| | |
| -- =========================
| |
| -- HAIFAN BASSARIDIA (MINOR)
| |
| -- =========================
| |
| ["Thermosalem"] = {
| |
| tags={"healing","resort","water","crowd"},
| |
| weights={SCV=3,ASS=2,HSA=2,ACC=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Akróstadium"] = {
| |
| tags={"stadium","festival","crowd","public"},
| |
| weights={MRM=3,OSI=2,ACC=2,HSA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Sufriya"] = {
| |
| tags={"terminal","security","port","logistics"},
| |
| weights={ASS=3,GGS=2,CIC=2,RCA=1,TIL=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Lykopolis"] = {
| |
| tags={"rail","corridor","security","logistics"},
| |
| weights={TIL=4,RCA=2,EOF=2,CIC=1,GGS=1},
| |
| baseSev="yellow",
| |
| },
| |
| | |
| -- =========================
| |
| -- NORMARK
| |
| -- =========================
| |
| ["Ardclach"] = {
| |
| tags={"north","ferry","coastal","watch"},
| |
| weights={ASS=3,EOF=2,CIC=1,GGS=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Riddersborg"] = {
| |
| tags={"north","rail","corridor","storm"},
| |
| weights={EOF=3,TIL=2,CIC=2,ASS=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| | |
| -- =========================
| |
| -- OURIANA
| |
| -- =========================
| |
| ["Bashkim"] = {
| |
| tags={"rail","corridor","agriculture","logistics"},
| |
| weights={MVE=2,TIL=3,RCA=2,OAI=1,EOF=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Ourid"] = {
| |
| tags={"river","fisheries","supply","trade"},
| |
| weights={ASS=3,MVE=2,OAI=2,HSA=1},
| |
| },
| |
| ["Tonar"] = {
| |
| tags={"quarantine","doctrine","containment","security"},
| |
| weights={ALB=3,CIC=3,RCA=2,HSA=1,SDL=1},
| |
| baseSev="red",
| |
| },
| |
| | |
| -- =========================
| |
| -- CALEDONIAN DEPENDENCIES
| |
| -- =========================
| |
| ["Fanghorn"] = {
| |
| tags={"frontier","forests","security","watch"},
| |
| weights={EOF=3,CIC=2,SYF=2,UOR=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Eikbu"] = {
| |
| tags={"ranching","agriculture","trail","supply"},
| |
| weights={MVE=3,SYF=2,OAI=2,EOF=1},
| |
| },
| |
| ["Galvø"] = {
| |
| tags={"island","coastal","port","storm"},
| |
| weights={ASS=3,EOF=2,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Sårensby"] = {
| |
| tags={"rail","corridor","industry","civic"},
| |
| weights={TIL=3,EOF=2,RCA=2,GGS=1,ASS=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Slevik"] = {
| |
| tags={"north","security","civic"},
| |
| weights={EOF=3,CIC=2,ASS=1,RCA=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Sjøsborg"] = {
| |
| tags={"coastal","port","trade","watch"},
| |
| weights={ASS=3,EOF=2,GGS=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Storesund"] = {
| |
| tags={"coastal","trade","storm"},
| |
| weights={ASS=3,EOF=2,CIC=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Notranskja"] = {
| |
| tags={"north","frontier","watch","omens"},
| |
| weights={EOF=2,CIC=2,UOR=2,ASS=1},
| |
| baseSev="yellow",
| |
| },
| |
| ["Kaledonija"] = {
| |
| tags={"regionalhub","governance","trade","civic"},
| |
| weights={RCA=3,EOF=2,GGS=2,HSA=1,ASS=1},
| |
| baseSev="yellow",
| |
| },
| |
| } | | } |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 9) ECONOMIC SIGNALS: parse "Company Table" on General Port page | | -- (I) OVERSIGHT + COMPLIANCE |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| local econCache = nil | | local OVERSIGHT = { |
| | | { label="Senate of Elders liaison", weight=3 }, |
| local function sectorOf(industryCell)
| | { label="Port compliance inspector (HCE)", weight=4 }, |
| local s = (industryCell or ""):lower()
| | { label="Temple Aprobelle social-harmony auditor", weight=3 }, |
| if s:find("agric", 1, true) then return "Agricultural" end
| | { label="Straits Convention monitor (civilian)", weight=3 }, |
| if s:find("service", 1, true) then return "Service" end
| | { label="No observer (weather delay)", weight=1 }, |
| if s:find("manufact", 1, true) or s:find("mining", 1, true) or s:find("energy", 1, true) then
| | } |
| return "Industry"
| |
| end
| |
| return "Other"
| |
| end
| |
|
| |
|
| local function extractCompanyName(cell) | | local COMPLIANCE = { |
| local n = cell:match("'''(.-)'''")
| | { label="Deployment verified; corridor routing approved; ledger notes filed same-day", weight=6 }, |
| if n and n ~= "" then return stripWiki(n) end
| | { label="Minor variance corrected; revised routing issued with escort buffer", weight=2 }, |
| n = cell:match("%*%*(.-)%*%*")
| | { label="Weather delay; holding pattern under local command until visibility improves", weight=1 }, |
| if n and n ~= "" then return stripWiki(n) end
| | { label="Mission deferred (no-go); export-control check triggered by false manifest", weight=1 }, |
| n = stripWiki(cell)
| | { label="Export request refused (constitutional prohibition); material retained under Council custody", weight=1 }, |
| if #n > 80 then n = n:sub(1, 80) .. "…" end
| |
| return n
| |
| end
| |
| | |
| local function extractHQ(cell)
| |
| local s = stripWiki(cell)
| |
| if s == "" then return nil end
| |
| if s:lower():find("fleet", 1, true) then return nil end
| |
| if s:lower():find("no fixed", 1, true) then return nil end
| |
| s = s:gsub("%s*;%s*.*$", "")
| |
| s = s:gsub("%s*%b()%s*", " ")
| |
| s = normalizeSpaces(s)
| |
| s = trim(s)
| |
| if citySet[s] then return s end
| |
| return nil
| |
| end
| |
| | |
| local function parseCompanyTable(wikitext)
| |
| local signals = {}
| |
| for cname, _ in pairs(citySet) do
| |
| signals[cname] = {Agricultural=0, Service=0, Industry=0, Other=0, samples={}}
| |
| end
| |
| if type(wikitext) ~= "string" then return signals end
| |
| | |
| local startPos = wikitext:find("====%s*Company Table%s*====")
| |
| if not startPos then startPos = wikitext:find("####%s*Company Table") end
| |
| if not startPos then return signals end
| |
| | |
| local tablePos = wikitext:find("{|", startPos)
| |
| if not tablePos then return signals end
| |
| local endPos = wikitext:find("|}", tablePos)
| |
| if not endPos then return signals end
| |
| | |
| local tableText = wikitext:sub(tablePos, endPos + 1)
| |
| | |
| local rows = {}
| |
| for chunk in tableText:gmatch("\n|%-%s*\n(.-)\n|%-%s*\n") do
| |
| rows[#rows+1] = chunk
| |
| end
| |
| local lastChunk = tableText:match("\n|%-%s*\n(.-)\n|%}")
| |
| if lastChunk then rows[#rows+1] = lastChunk end
| |
| | |
| for _, row in ipairs(rows) do
| |
| if not row:match("^%s*!") then
| |
| local line = normalizeSpaces(row:gsub("\n", " "))
| |
| line = line:gsub("^%s*|%s*", "")
| |
| | |
| local cells = {}
| |
| for cell in line:gmatch("([^|]-)%s*||%s*") do
| |
| cells[#cells+1] = trim(cell)
| |
| end
| |
| local tail = line:match("||%s*([^|].-)%s*$")
| |
| if tail and tail ~= "" then
| |
| if #cells == 0 or cells[#cells] ~= trim(tail) then
| |
| cells[#cells+1] = trim(tail)
| |
| end
| |
| end
| |
| | |
| local industryCell = ""
| |
| for _, c in ipairs(cells) do
| |
| if containsAny(c, {"agric", "service", "manufact", "mining", "energy"}) then
| |
| industryCell = c
| |
| break
| |
| end
| |
| end
| |
| local sector = sectorOf(industryCell)
| |
| | |
| local hqCell = cells[#cells] or ""
| |
| local hq = extractHQ(hqCell)
| |
| if hq and signals[hq] then
| |
| signals[hq][sector] = (signals[hq][sector] or 0) + 1
| |
| local nameCell = cells[3] or cells[2] or cells[1] or ""
| |
| local companyName = extractCompanyName(nameCell)
| |
| if companyName ~= "" and #signals[hq].samples < 2 then
| |
| signals[hq].samples[#signals[hq].samples+1] = companyName
| |
| end
| |
| end
| |
| end
| |
| end
| |
| | |
| return signals
| |
| end
| |
| | |
| local function getEconSignals()
| |
| if econCache then return econCache end
| |
| local content = safeTitleContent("General Port of Lake Morovia")
| |
| econCache = parseCompanyTable(content)
| |
| return econCache
| |
| end
| |
| | |
| local function dominantSector(sig)
| |
| if not sig then return "Other" end
| |
| local best, bestN = "Other", -1
| |
| for _, k in ipairs({"Agricultural","Industry","Service","Other"}) do
| |
| local n = sig[k] or 0
| |
| if n > bestN then best, bestN = k, n end
| |
| end
| |
| return best
| |
| end
| |
| | |
| local function econTagFromSector(sec)
| |
| if sec == "Agricultural" then return "agri" end
| |
| if sec == "Industry" then return "industry" end
| |
| if sec == "Service" then return "service" end
| |
| return "mixed"
| |
| end
| |
| | |
| local function econSummary(sig)
| |
| if not sig then return "n/a" end
| |
| local a = sig.Agricultural or 0
| |
| local i = sig.Industry or 0
| |
| local s = sig.Service or 0
| |
| local o = sig.Other or 0
| |
| local dom = dominantSector(sig)
| |
| local samp = (sig.samples and #sig.samples > 0) and ("; e.g., " .. table.concat(sig.samples, ", ")) or ""
| |
| return string.format("%s (%d agri / %d ind / %d serv / %d other)%s", dom, a, i, s, o, samp)
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- 10) OPTIONAL: Threat Watch integration from Module:ReligiousEvents
| |
| --------------------------------------------------------------------------------
| |
| local function parseReligiousEventsTable(wikitext)
| |
| local out = {}
| |
| if type(wikitext) ~= "string" then return out end
| |
| for line in wikitext:gmatch("[^\n]+") do
| |
| if line:match("^|%s*%d+/%d+/%d+%s+PSSC") then
| |
| local date, city, event, urg = line:match("^|%s*(.-)%s*||%s*(.-)%s*||%s*(.-)%s*||%s*(.-)%s*$")
| |
| if city and urg then
| |
| out[stripWiki(city)] = {urg=trim(urg), event=stripWiki(event or "")}
| |
| end
| |
| end
| |
| end
| |
| return out
| |
| end
| |
| | |
| local function threatSev(th)
| |
| if not th or not th.urg then return nil end
| |
| local u = (th.urg or ""):upper()
| |
| if u == "N/A" or u == "LOW" then return "green" end
| |
| if u == "MEDIUM" then return "yellow" end
| |
| if u == "HIGH" or u == "CRITICAL" then return "red" end
| |
| return "yellow"
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- 11) WEIGHTED ORDER PICK + TASK PICK
| |
| --------------------------------------------------------------------------------
| |
| local function weightedPickKey(nextInt, weights)
| |
| local total = 0
| |
| for _, ok in ipairs(orderKeys) do
| |
| total = total + (weights[ok] or 0)
| |
| end
| |
| if total <= 0 then
| |
| return pickFromList(nextInt, orderKeys, nil)
| |
| end
| |
| local r = (nextInt() % total) + 1
| |
| local acc = 0
| |
| for _, ok in ipairs(orderKeys) do
| |
| acc = acc + (weights[ok] or 0)
| |
| if r <= acc then return ok end
| |
| end
| |
| return orderKeys[1]
| |
| end
| |
| | |
| local function buildTagSet(tags)
| |
| local set = {}
| |
| for _, t in ipairs(tags or {}) do set[t] = true end
| |
| return set
| |
| end
| |
| | |
| local function pickTaskForCity(nextInt, taskList, tagSet)
| |
| local candidates = {}
| |
| for _, task in ipairs(taskList or {}) do
| |
| local ok = false
| |
| for _, tg in ipairs(task.tags or {}) do
| |
| if tagSet[tg] then ok = true break end
| |
| end
| |
| if ok then candidates[#candidates+1] = task end
| |
| end
| |
| if #candidates > 0 then
| |
| return pickFromList(nextInt, candidates, nil)
| |
| end
| |
| return pickFromList(nextInt, taskList, nil)
| |
| end
| |
| | |
| local function baseWeights()
| |
| local w = {}
| |
| for _, ok in ipairs(orderKeys) do w[ok] = 1 end
| |
| return w
| |
| end
| |
| | |
| local function applyWeights(w, add)
| |
| if not add then return end
| |
| for k, v in pairs(add) do
| |
| if orderByKey[k] then
| |
| w[k] = (w[k] or 0) + tonumber(v or 0)
| |
| end
| |
| end
| |
| end
| |
| | |
| local function biasFromEcon(w, econTag)
| |
| if econTag == "agri" then
| |
| applyWeights(w, {MVE=3,SYF=2,OAI=2,ASS=1})
| |
| elseif econTag == "industry" then
| |
| applyWeights(w, {TIL=3,EOF=2,IGA=2,CIC=1,RCA=1})
| |
| elseif econTag == "service" then
| |
| applyWeights(w, {GGS=3,HSA=2,RCA=2,CIL=1,CHS=1})
| |
| else
| |
| applyWeights(w, {CHS=1,HSA=1,ASS=1})
| |
| end
| |
| end
| |
| | |
| local function biasFromCorridor(w, isRail, isFerry)
| |
| if isRail then applyWeights(w, {TIL=2,RCA=2,GGS=1,EOF=1,ASS=1}) end
| |
| if isFerry then applyWeights(w, {ASS=2,GGS=1,RCA=1}) end
| |
| end
| |
| | |
| local function biasFromTier(w, tier)
| |
| if tier == "major" then
| |
| applyWeights(w, {HSA=1,RCA=1,CIL=1,CHS=1})
| |
| end
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- 12) TEMPLE BANK NOTES
| |
| --------------------------------------------------------------------------------
| |
| local bankNotes = {
| |
| "Temple Bank stipend verified; local shrine receipts reconciled; next audit window scheduled.",
| |
| "Voucher authorizations issued for ritual materials; chain-of-custody notes logged for any seized items.",
| |
| "Investor liaison note filed; payroll routing confirmed for the deployed unit; compliance clerk assigned.",
| |
| "Donation flow stabilized; offertory seals inspected; variance thresholds set for the next three days.",
| |
| "Emergency stipend line opened for crowd-control and relief logistics; disbursement witnessed by two scribes.",
| |
| } | | } |
|
| |
|
| --------------------------------------------------------------------------------
| | local function rowColor(obs, comp, uScore) |
| -- 13) BUILD ONE CITY ROW
| | local o = (obs or ""):lower() |
| --------------------------------------------------------------------------------
| | local c = (comp or ""):lower() |
| local function inferSeverity(cityProfile, econTag, taskSev, threatLevel) | | if o:match("weather delay") then |
| local sev = taskSev or "green"
| | return ' style="background-color:#fff3cd;"' |
| | | end |
| if cityProfile and cityProfile.baseSev then
| | if c:match("minor variance") then |
| sev = cityProfile.baseSev
| | return ' style="background-color:#fff3cd;"' |
| end
| | end |
| | | if c:match("export request refused") or c:match("mission deferred") then |
| if econTag == "industry" or econTag == "service" then
| | return ' style="background-color:#f8d7da;"' |
| if sev == "green" then sev = "yellow" end
| | end |
| end
| | if uScore >= 3 then |
| | | return ' style="background-color:#f8d7da;"' |
| if threatLevel == "yellow" and sev == "green" then sev = "yellow" end
| | end |
| if threatLevel == "red" and sev ~= "red" then sev = "red" end
| | return ' style="background-color:#d4edda;"' |
| | |
| return sev
| |
| end | |
| | |
| local function buildCityRow(di, c, econSignals, threatMap, includeThreat, showEcon)
| |
| local cityName, cityRegion, tier = c.name, c.region, c.tier
| |
| local seedStr = string.format("%d:%03d:%s", di.year, di.dayOfYear, cityName)
| |
| local nextInt = lcg(hash31(seedStr))
| |
| | |
| local profile = cityProfiles[cityName] or {tags={}, weights=nil}
| |
| local tags = {}
| |
| | |
| for _, t in ipairs(profile.tags or {}) do tags[#tags+1] = t end
| |
| if RAIL[cityName] then tags[#tags+1] = "rail" end
| |
| if FERRY[cityName] then tags[#tags+1] = "ferry" end
| |
| | |
| local sig = econSignals and econSignals[cityName] or nil
| |
| local dom = dominantSector(sig)
| |
| local econTag = econTagFromSector(dom)
| |
| tags[#tags+1] = econTag
| |
| | |
| local tagSet = buildTagSet(tags)
| |
| | |
| local th = includeThreat and threatMap and threatMap[cityName] or nil
| |
| local tSev = threatSev(th)
| |
| | |
| local w = baseWeights()
| |
| biasFromTier(w, tier)
| |
| biasFromEcon(w, econTag)
| |
| biasFromCorridor(w, RAIL[cityName], FERRY[cityName])
| |
| applyWeights(w, profile.weights)
| |
| | |
| local orderKey = weightedPickKey(nextInt, w)
| |
| local o = orderByKey[orderKey] or orders[1]
| |
| local task = pickTaskForCity(nextInt, o.tasks, tagSet)
| |
| | |
| local sev = inferSeverity(profile, econTag, task.sev, tSev)
| |
| | |
| local unitName = pickOrgUnit(nextInt, sev)
| |
| local unitMeta = org[unitName]
| |
| local unitIndex = (nextInt() % 12) + 1
| |
| local unitCode = string.format("%s-%s%d", o.key, unitMeta.code, unitIndex)
| |
| local headcount = unitMeta.size
| |
| | |
| local bank = pickFromList(nextInt, bankNotes, nil)
| |
| | |
| local threatText, threatUrg = "", ""
| |
| if includeThreat and th then
| |
| threatText = th.event or ""
| |
| threatUrg = th.urg or ""
| |
| end
| |
| | |
| return {
| |
| style = sevStyle(sev),
| |
| date = di.text,
| |
| region = cityRegion,
| |
| city = string.format("%s %s", getCityFlagMarkup(cityName), cityLink(cityName)),
| |
| order = getOrderIconMarkup(o.name) .. o.link,
| |
| unit = string.format("%s (%d) [%s]", unitName, headcount, unitCode),
| |
| task = task.text,
| |
| tags = joinTags(tags),
| |
| econ = (showEcon and sig) and econSummary(sig) or "",
| |
| bank = bank,
| |
| threat = threatText,
| |
| threatUrg = threatUrg,
| |
| sev = sev,
| |
| }
| |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 14) MAIN TABLE | | -- (J) MAIN TABLE (Flags: unknown -> ITU flag) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| function p.makeTable(frame) | | function p.makeTable(frame) |
| local args = (frame and frame.args) or {}
| | local di = getPSSCDate() |
| local regionFilter = tostring(args.region or "All")
| | local args = frame and frame.args or {} |
| local showLegend = tostring(args.showlegend or "yes"):lower() ~= "no"
| |
| local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
| |
| local showEcon = tostring(args.showEcon or "no"):lower() == "yes"
| |
| local limit = tonumber(args.limit or "")
| |
|
| |
|
| local di = getDateInfo()
| | local rows = tonumber(args.rows) or 36 |
| local econSignals = getEconSignals()
| | local showLegend = tostring(args.showlegend or "yes"):lower() ~= "no" |
| | local flagSize = tonumber(args.flagsize) or 20 |
|
| |
|
| local threatMap = {}
| | local eventMap, hasEvents = buildEventMapForToday() |
| if includeThreat then
| |
| local ok, rel = pcall(require, "Module:ReligiousEvents")
| |
| if ok and rel and type(rel.makeTable) == "function" then
| |
| threatMap = parseReligiousEventsTable(rel.makeTable())
| |
| end
| |
| end
| |
|
| |
|
| local out = {}
| | local seed = tonumber(args.seed) or (di.year * 1000 + di.dayOfYear) |
| table.insert(out, "{| class='wikitable sortable'")
| | math.randomseed(seed) |
| local header = "! style='white-space:nowrap;' | Date !! City !! Region !! Cult Order !! Unit !! Tasking"
| |
| if showEcon then header = header .. " !! Economic signal" end
| |
| header = header .. " !! Temple Bank Notes"
| |
| if includeThreat then header = header .. " !! Threat Watch" end
| |
| header = header .. " !! Severity"
| |
| table.insert(out, header)
| |
|
| |
|
| local count = 0
| | local divFilter = tostring(args.division or ""):lower() |
| for _, c in ipairs(cityOrder) do
| | local divPool = {} |
| if regionPass(regionFilter, c.region) then
| | if divFilter ~= "" then |
| local row = buildCityRow(di, c, econSignals, threatMap, includeThreat, showEcon)
| | for _, d in ipairs(DIVISIONS) do |
| table.insert(out, "|-" .. row.style)
| | if d.name:lower():find(divFilter, 1, true) or d.code:lower():find(divFilter, 1, true) then |
| | table.insert(divPool, d) |
| | end |
| | end |
| | if #divPool == 0 then divPool = DIVISIONS end |
| | else |
| | divPool = DIVISIONS |
| | end |
|
| |
|
| local line = string.format("| %s || %s || %s || %s || %s || %s",
| | local out = {} |
| row.date, row.city, row.region, row.order, row.unit, row.task
| | table.insert(out, "{| class='wikitable sortable'") |
| )
| | table.insert(out, |
| if showEcon then
| | "! style='white-space:nowrap;' | Date" .. |
| line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a")
| | " !! Division" .. |
| end
| | " !! City / Node" .. |
| line = line .. " || " .. row.bank
| | " !! Daily event trigger" .. |
| if includeThreat then
| | " !! Urgency" .. |
| local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
| | " !! Operation" .. |
| line = line .. " || " .. threatCell
| | " !! Ground Forces" .. |
| end
| | " !! Naval Forces" .. |
| line = line .. " || " .. row.sev
| | " !! Aerial Forces" .. |
| | " !! Oversight" .. |
| | " !! Compliance / Notes" |
| | ) |
|
| |
|
| table.insert(out, line)
| | for i = 1, rows do |
| | local div = pickWeighted(divPool) |
| | local cityName = pick(div.cities) |
|
| |
|
| count = count + 1
| | local divFlag = flagIcon(DIVISION_FLAGS[div.name], flagSize) |
| if limit and count >= limit then break end
| | local divCell = string.format("%s %s", divFlag, div.link) |
| end
| |
| end
| |
|
| |
|
| table.insert(out, "|}")
| | local cityFlag = flagIcon(CITY_FLAGS[cityName], flagSize) |
| | local cityCell = string.format("%s %s", cityFlag, cityLink(cityName, cityName)) |
|
| |
|
| if showLegend then
| | local ev = eventMap[cityName] |
| table.insert(out, "\n<div style='margin-top:0.5em; font-size:90%%;'>")
| | local evDesc = ev and ev.desc or (hasEvents and "No reports" or "Events module unavailable") |
| table.insert(out, "<b>Legend:</b> ")
| | local urg = ev and ev.urgency or "N/A" |
| table.insert(out, "<span style='background:#d4edda;padding:2px 6px;border:1px solid #c3e6cb;'>Green</span> = Routine rites / civic support ")
| | local uScore = urgencyScore(urg) |
| table.insert(out, "<span style='background:#fff3cd;padding:2px 6px;border:1px solid #ffeeba;'>Yellow</span> = Heightened oversight / rumor control / targeted intervention ")
| |
| table.insert(out, "<span style='background:#f8d7da;padding:2px 6px;border:1px solid #f5c6cb;'>Red</span> = Crisis response / unrest / outbreak / high-risk operations")
| |
| table.insert(out, "</div>")
| |
| end
| |
|
| |
|
| if di.calendarEvent and di.calendarEvent ~= "" then
| | local primary = pickWeighted({ |
| table.insert(out, string.format("\n<div style='margin-top:0.5em; font-size:90%%;'><b>Calendar note:</b> %s</div>", di.calendarEvent))
| | { name="ground", weight = 6 }, |
| end
| | { name="naval", weight = (div.code == "HAT" or div.code == "HFA") and 5 or 2 }, |
| | { name="air", weight = 2 + uScore }, |
| | }).name |
|
| |
|
| return table.concat(out, "\n")
| | local op = (primary == "naval") and pickWeighted(OP_NAVAL) |
| end
| | or (primary == "air") and pickWeighted(OP_AIR) |
| | or pickWeighted(OP_GROUND) |
|
| |
|
| --------------------------------------------------------------------------------
| | local ground, naval, air = "—","—","—" |
| -- 15) SINGLE CITY VIEW
| |
| --------------------------------------------------------------------------------
| |
| function p.makeCity(frame)
| |
| local args = (frame and frame.args) or {}
| |
| local city = tostring(args.city or "")
| |
| if city == "" then return "''Error: city parameter required.''" end
| |
| if not citySet[city] then return "''Error: unknown city (must match canonical name).''" end
| |
|
| |
|
| local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
| | if not (primary == "air" and uScore <= 1 and math.random() < 0.35) then |
| local showEcon = tostring(args.showEcon or "no"):lower() == "yes"
| | local gE = pickEchelonForUrgency(GROUND_ECHELONS, uScore) |
| | ground = string.format("%s (%s-%02d)", gE, div.code, math.random(1, 24)) |
| | end |
|
| |
|
| local di = getDateInfo()
| | if primary == "naval" or (div.code == "HAT" and math.random() < 0.55) or (uScore >= 3 and math.random() < 0.35) then |
| local econSignals = getEconSignals()
| | local nE = pickEchelonForUrgency(NAVAL_ECHELONS, uScore) |
| | naval = string.format("%s (%s-N%02d)", nE, div.code, math.random(1, 12)) |
| | end |
|
| |
|
| local threatMap = {}
| | if primary == "air" or (uScore >= 2 and math.random() < 0.55) then |
| if includeThreat then
| | local aE = pickEchelonForUrgency(AIR_ECHELONS, uScore) |
| local ok, rel = pcall(require, "Module:ReligiousEvents")
| | air = string.format("%s (%s-A%02d)", aE, div.code, math.random(1, 18)) |
| if ok and rel and type(rel.makeTable) == "function" then
| | end |
| threatMap = parseReligiousEventsTable(rel.makeTable())
| |
| end
| |
| end
| |
|
| |
|
| local region, tier = "Core", "minor"
| | local obs = pickWeighted(OVERSIGHT).label |
| for _, c in ipairs(cityOrder) do
| | local comp = pickWeighted(COMPLIANCE).label |
| if c.name == city then region, tier = c.region, c.tier break end
| | local notes = bulletList({ "Op-ID: " .. opId(di, div.code, i) }) |
| end
| | local style = rowColor(obs, comp, uScore) |
|
| |
|
| local row = buildCityRow(di, {name=city, region=region, tier=tier}, econSignals, threatMap, includeThreat, showEcon)
| | table.insert(out, "|-" .. style) |
| | table.insert(out, string.format( |
| | "| %s || %s || %s || %s || %s || %s || %s || %s || %s || %s || %s", |
| | di.text, divCell, cityCell, evDesc, urg, op.name, ground, naval, air, obs, bulletList({ comp, notes }) |
| | )) |
| | end |
|
| |
|
| local out = {}
| | table.insert(out, "|}") |
| table.insert(out, "{| class='wikitable'")
| |
| local header = "! Date !! City !! Region !! Cult Order !! Unit !! Tasking"
| |
| if showEcon then header = header .. " !! Economic signal" end
| |
| header = header .. " !! Temple Bank Notes"
| |
| if includeThreat then header = header .. " !! Threat Watch" end
| |
| header = header .. " !! Severity"
| |
| table.insert(out, header)
| |
| table.insert(out, "|-" .. row.style)
| |
|
| |
|
| local line = string.format("| %s || %s || %s || %s || %s || %s",
| | if showLegend then |
| row.date, row.city, row.region, row.order, row.unit, row.task
| | table.insert(out, "\n<div style='margin-top:0.5em; font-size:90%;'>") |
| )
| | table.insert(out, "<b>Legend:</b> ") |
| if showEcon then line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a") end
| | table.insert(out, "<span style='background:#d4edda;padding:2px 6px;border:1px solid #c3e6cb;'>Green</span> = routine/compliant ") |
| line = line .. " || " .. row.bank
| | table.insert(out, "<span style='background:#fff3cd;padding:2px 6px;border:1px solid #ffeeba;'>Yellow</span> = variance/adjustment/weather ") |
| if includeThreat then
| | table.insert(out, "<span style='background:#f8d7da;padding:2px 6px;border:1px solid #f5c6cb;'>Red</span> = HIGH/CRITICAL or export-control/deferment") |
| local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
| | table.insert(out, "</div>") |
| line = line .. " || " .. threatCell
| | end |
| end
| |
| line = line .. " || " .. row.sev
| |
| table.insert(out, line)
| |
|
| |
|
| table.insert(out, "|}")
| | return table.concat(out, "\n") |
| return table.concat(out, "\n")
| |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- 16) ORDER-ONLY VIEW | | -- (K) OPTIONAL: show org ladders (for documentation / page footer) |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| function p.makeOrder(frame) | | function p.showOrganization() |
| local args = (frame and frame.args) or {}
| | return table.concat({ |
| local wanted = tostring(args.order or "")
| | '{| class="wikitable" style="width:100%;"', |
| if wanted == "" then
| | '! Branch !! Smallest → Largest', |
| return "''Error: order parameter required (use exact order name).''"
| | '|-', |
| end
| | '| Ground || Turmae → Contubernia → Ordinis → Manipuli → Centuriae → Cohortes', |
| local wantedOrder = orderByName[wanted]
| | '|-', |
| if not wantedOrder then
| | '| Naval || Birlik-i Gemi (Patrol Element) → Tabur-i Derya (Task Unit) → Ordu (Task Group)', |
| return "''Error: unknown order name (must match module order names).''"
| | '|-', |
| end
| | '| Aerial || Zeygi (Element) → Ptisis (Flight) → Moira (Squadron)', |
| | | '|}', |
| local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
| | }, "\n") |
| local showEcon = tostring(args.showEcon or "no"):lower() == "yes"
| |
| | |
| local di = getDateInfo()
| |
| local econSignals = getEconSignals()
| |
| | |
| local threatMap = {}
| |
| if includeThreat then
| |
| local ok, rel = pcall(require, "Module:ReligiousEvents")
| |
| if ok and rel and type(rel.makeTable) == "function" then
| |
| threatMap = parseReligiousEventsTable(rel.makeTable())
| |
| end
| |
| end
| |
| | |
| local out = {}
| |
| table.insert(out, "{| class='wikitable sortable'")
| |
| local header = "! Date !! City !! Region !! Unit !! Tasking"
| |
| if showEcon then header = header .. " !! Economic signal" end
| |
| header = header .. " !! Temple Bank Notes"
| |
| if includeThreat then header = header .. " !! Threat Watch" end
| |
| header = header .. " !! Severity"
| |
| table.insert(out, header)
| |
| | |
| for _, c in ipairs(cityOrder) do
| |
| local row = buildCityRow(di, c, econSignals, threatMap, includeThreat, showEcon)
| |
| if row.order:find(wantedOrder.link, 1, true) then
| |
| table.insert(out, "|-" .. row.style)
| |
| local line = string.format("| %s || %s || %s || %s || %s",
| |
| row.date, row.city, row.region, row.unit, row.task
| |
| )
| |
| if showEcon then line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a") end
| |
| line = line .. " || " .. row.bank
| |
| if includeThreat then
| |
| local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
| |
| line = line .. " || " .. threatCell
| |
| end
| |
| line = line .. " || " .. row.sev
| |
| table.insert(out, line)
| |
| end
| |
| end
| |
| | |
| table.insert(out, "|}")
| |
| return table.concat(out, "\n")
| |
| end | | end |
|
| |
|
| return p | | return p |