Module:SouthernStraitCorridorOps: Difference between revisions
From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs) No edit summary |
NewZimiaGov (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
-- Module:SouthernStraitCorridorOps | -- Module:SouthernStraitCorridorOps | ||
-- Southern Strait-only daily operations wrapper. | -- Southern Strait-only daily operations wrapper. | ||
| Line 48: | Line 49: | ||
return false, "''" .. err .. ".''" | return false, "''" .. err .. ".''" | ||
end | end | ||
if type(mod[funcName]) ~= "function" then | if type(mod[funcName]) ~= "function" then | ||
return false, "''" .. tostring(moduleName) .. " has no public function named " .. tostring(funcName) .. ".''" | return false, "''" .. tostring(moduleName) .. " has no public function named " .. tostring(funcName) .. ".''" | ||
| Line 80: | Line 82: | ||
local y = tonumber(args.year or args.psscyear) | local y = tonumber(args.year or args.psscyear) | ||
local d = tonumber(args.day or args.dayofyear) | local d = tonumber(args.day or args.dayofyear) | ||
if y and d then | if y and d then | ||
local m, dom = doyToMonthDom(d) | local m, dom = doyToMonthDom(d) | ||
| Line 92: | Line 95: | ||
local safeTitle = tostring(title or "Operations") | local safeTitle = tostring(title or "Operations") | ||
local content = tostring(body or "''No output.''") | local content = tostring(body or "''No output.''") | ||
if not collapsible then | if not collapsible then | ||
table.insert(out, "===" .. safeTitle .. "===") | table.insert(out, "===" .. safeTitle .. "===") | ||
| Line 217: | Line 221: | ||
return "Southern Strait corridor" | return "Southern Strait corridor" | ||
end | end | ||
local year = tonumber(args.year or args.psscyear) or 0 | local year = tonumber(args.year or args.psscyear) or 0 | ||
local day = tonumber(args.day or args.dayofyear) or 0 | local day = tonumber(args.day or args.dayofyear) or 0 | ||
| Line 224: | Line 229: | ||
local idx = ((tonumber(rowNumber) or 1) - 1 + offset) % #southernTradeCities + 1 | local idx = ((tonumber(rowNumber) or 1) - 1 + offset) % #southernTradeCities + 1 | ||
local loc = southernTradeCities[idx] | local loc = southernTradeCities[idx] | ||
return loc.city .. "<br><small>" .. loc.region .. "</small>" | return loc.city .. "<br><small>" .. loc.region .. "</small>" | ||
end | end | ||
| Line 241: | Line 247: | ||
local headerInserted = false | local headerInserted = false | ||
local rowNumber = 0 | local rowNumber = 0 | ||
for _, line in ipairs(lines) do | for _, line in ipairs(lines) do | ||
if line:match("^%s*{|") then | if line:match("^%s*{|") then | ||
| Line 343: | Line 350: | ||
if chance < 0 then chance = 0 end | if chance < 0 then chance = 0 end | ||
if chance > 100 then chance = 100 end | if chance > 100 then chance = 100 end | ||
local showNoEvent = yn(args.showTradeNoEvent or args.showtradenoevent, false) | local showNoEvent = yn(args.showTradeNoEvent or args.showtradenoevent, false) | ||
| Line 348: | Line 356: | ||
local day = tonumber(args.day or args.dayofyear) or 0 | local day = tonumber(args.day or args.dayofyear) or 0 | ||
local seed = tostring(args.seed or "") .. ":SS-TRADE:" .. tostring(year) .. ":" .. tostring(day) | local seed = tostring(args.seed or "") .. ":SS-TRADE:" .. tostring(year) .. ":" .. tostring(day) | ||
local roll = pctFromSeed(seed, "roll") + 1 | local roll = pctFromSeed(seed, "roll") + 1 | ||
if roll > chance then | if roll > chance then | ||
| Line 360: | Line 369: | ||
local outcome = pick(tradeOutcomes, seed, "outcome") | local outcome = pick(tradeOutcomes, seed, "outcome") | ||
if not city or not cult then return nil end | if not city or not cult then return nil end | ||
local seq = (pctFromSeed(seed, "seq") % 20) + 1 | local seq = (pctFromSeed(seed, "seq") % 20) + 1 | ||
local tradeId | local tradeId | ||
| Line 370: | Line 380: | ||
local signCode = string.format("%s-TA%02d", cult.code or "CUL", seq) | local signCode = string.format("%s-TA%02d", cult.code or "CUL", seq) | ||
return table.concat({ | return table.concat({ | ||
"{| class=\"wikitable sortable\"", | "{| class=\"wikitable sortable\"", | ||
| Line 550: | Line 561: | ||
local startCollapsed = yn(args.collapsed, true) | local startCollapsed = yn(args.collapsed, true) | ||
local includeWar | local includeWar = yn(args.war or args.warleague, true) | ||
local includeHatch | local includeHatch = yn(args.hatch or args.hatchministry, true) | ||
local includeMission = yn(args.missionary or args.templebank, true) | local includeMission = yn(args.missionary or args.templebank, true) | ||
local includeTrade | local includeTrade = yn(args.trade or args.tradeagreements or args.tradeagreement, true) | ||
local includeRebellion = yn(args.rebellion or args.rebellions or args.unrest or args.uprising, true) | local includeRebellion = yn(args.rebellion or args.rebellions or args.unrest or args.uprising, true) | ||
-- rowlocalities=no hides the row-level locality focus column. | -- rowlocalities=no hides the row-level locality focus column. | ||
local showRowLocalities = yn(args.rowlocalities or args.localities or args.showlocalities, true) | local showRowLocalities = yn(args.rowlocalities or args.localities or args.showlocalities, true) | ||
local year = args.year or args.psscyear | local year = args.year or args.psscyear | ||
local day = args.day or args.dayofyear | local day = args.day or args.dayofyear | ||
| Line 587: | Line 599: | ||
year = year, | year = year, | ||
day = day, | day = day, | ||
-- rows = number of Southern Strait rows to display. | |||
-- scanrows = number of original War League rows to scan while preserving | |||
-- original Op-ID/type data from the source War League generation. | |||
rows = args.warrows or args.rows or "24", | rows = args.warrows or args.rows or "24", | ||
scanrows = args.warscanrows or args.scanrows or "160", | scanrows = args.warscanrows or args.scanrows or "160", | ||
showlegend = showLegend and "yes" or "no", | showlegend = showLegend and "yes" or "no", | ||
flagsize = args.flagsize or "20", | flagsize = args.flagsize or "20", | ||
zone = "SouthernStrait", | zone = "SouthernStrait", | ||
-- Southern Strait Corridor wrapper | -- Southern Strait Corridor wrapper shows only Council of Kings | ||
-- Division rows for War League deployments. | -- Division rows for War League deployments. | ||
division = "Council of Kings Division", | division = "Council of Kings Division", | ||
| Line 603: | Line 620: | ||
local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs) | local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs) | ||
if showRowLocalities then | if showRowLocalities then | ||
body = addRowLocalities(body, { year = year, day = day, seed = args.seed }, "war") | body = addRowLocalities(body, { year = year, day = day, seed = args.seed }, "war") | ||
| Line 626: | Line 644: | ||
hatchArgs.captain = args.captain | hatchArgs.captain = args.captain | ||
end | end | ||
local ok, body = safeCall("Module:HatchMinistryDailyOps", "dailyReport", hatchArgs) | local ok, body = safeCall("Module:HatchMinistryDailyOps", "dailyReport", hatchArgs) | ||
| Line 649: | Line 668: | ||
showEcon = args.showEcon or args.showecon or "no", | showEcon = args.showEcon or args.showecon or "no", | ||
} | } | ||
if args.missionarylimit and tostring(args.missionarylimit) ~= "" then | if args.missionarylimit and tostring(args.missionarylimit) ~= "" then | ||
missionaryArgs.limit = args.missionarylimit | missionaryArgs.limit = args.missionarylimit | ||
| Line 660: | Line 680: | ||
body = addRowLocalities(body, args, "missionary") | body = addRowLocalities(body, args, "missionary") | ||
end | end | ||
table.insert(out, hr()) | table.insert(out, hr()) | ||
table.insert(out, section("Temple Bank Southern Strait missionary operations", body, collapseSections, startCollapsed)) | table.insert(out, section("Temple Bank Southern Strait missionary operations", body, collapseSections, startCollapsed)) | ||
| Line 702: | Line 723: | ||
"* '''Economic lineage''' notes describe how the newer locality economies are influenced by the historic port economies of [[Blore Heath]], [[Jogi]], and [[Mylecia]] without directly copying their companies, commodities, or institutions." | "* '''Economic lineage''' notes describe how the newer locality economies are influenced by the historic port economies of [[Blore Heath]], [[Jogi]], and [[Mylecia]] without directly copying their companies, commodities, or institutions." | ||
}, "\n") | }, "\n") | ||
table.insert(out, hr()) | table.insert(out, hr()) | ||
table.insert(out, section("Combined legend", legendBody, collapseSections, startCollapsed)) | table.insert(out, section("Combined legend", legendBody, collapseSections, startCollapsed)) | ||
Revision as of 20:28, 4 June 2026
Documentation for this module may be created at Module:SouthernStraitCorridorOps/doc
-- Module:SouthernStraitCorridorOps
-- Southern Strait-only daily operations wrapper.
-- Shows only Haifan Bassaridian / Southern Strait entries from:
-- 1) WarLeagueDivisionOpsBVR
-- 2) HatchMinistryDailyOps
-- 3) MissionaryDailyOpsBVR
--
-- Also adds:
-- 4) Rare Southern Strait trade-agreement / General Port admission events
-- 5) Row-level locality focus column for extended Southern Strait,
-- Eastern Mykonos Desert, and eastern Snowholme foothill settlements
-- 6) Rare rebellion-type / corridor unrest alerts
--
-- Economic design note:
-- Southern Strait and Eastern Mykonos localities are written as grounded
-- successor/satellite economies influenced by the historic port economies of
-- Blore Heath, Jogi, and Mylecia, without copying those ports directly.
local p = {}
--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local function yn(value, default)
local v = tostring(value or ""):lower()
if v == "" then return default end
if v == "no" or v == "n" or v == "0" or v == "false" then return false end
if v == "yes" or v == "y" or v == "1" or v == "true" then return true end
return default
end
local function makeFrame(args)
return { args = args or {} }
end
local function safeRequire(moduleName)
local ok, mod = pcall(require, moduleName)
if ok and mod then
return mod, nil
end
return nil, "Could not load " .. tostring(moduleName)
end
local function safeCall(moduleName, funcName, args)
local mod, err = safeRequire(moduleName)
if not mod then
return false, "''" .. err .. ".''"
end
if type(mod[funcName]) ~= "function" then
return false, "''" .. tostring(moduleName) .. " has no public function named " .. tostring(funcName) .. ".''"
end
local ok, result = pcall(function()
return mod[funcName](makeFrame(args))
end)
if not ok then
return false, "''Error while invoking " .. tostring(moduleName) .. "." .. tostring(funcName) .. ": " .. tostring(result) .. "''"
end
return true, tostring(result or "")
end
local function doyToMonthDom(doy)
doy = tonumber(doy) or 1
if doy < 1 then doy = 1 end
if doy > 183 then doy = 183 end
if doy <= 61 then
return 1, doy
elseif doy <= 122 then
return 2, doy - 61
else
return 3, doy - 122
end
end
local function dateLabel(args)
local y = tonumber(args.year or args.psscyear)
local d = tonumber(args.day or args.dayofyear)
if y and d then
local m, dom = doyToMonthDom(d)
return string.format("%d/%d/%d PSSC", dom, m, y)
end
return "current PSSC date"
end
local function section(title, body, collapsible, collapsed)
local out = {}
local safeTitle = tostring(title or "Operations")
local content = tostring(body or "''No output.''")
if not collapsible then
table.insert(out, "===" .. safeTitle .. "===")
table.insert(out, content)
return table.concat(out, "\n")
end
local collapseClass = collapsed and "mw-collapsible mw-collapsed" or "mw-collapsible"
table.insert(out, '<div class="' .. collapseClass .. '" style="border:1px solid #a2a9b1; margin:0.6em 0; background:#f8f9fa;">')
table.insert(out, '<div style="font-weight:bold; padding:0.35em 0.6em; background:#eaecf0;">' .. safeTitle .. '</div>')
table.insert(out, '<div style="padding:0.5em 0.6em;">')
table.insert(out, content)
table.insert(out, '</div>')
table.insert(out, '</div>')
return table.concat(out, "\n")
end
local function hr()
return "\n----\n"
end
local function hashString(s)
s = tostring(s or "")
local h = 0
for i = 1, #s do
h = (h * 31 + string.byte(s, i)) % 1000003
end
return h
end
local function pick(list, seed, salt)
if not list or #list == 0 then return nil end
local idx = (hashString(tostring(seed or "") .. ":" .. tostring(salt or "")) % #list) + 1
return list[idx]
end
local function pctFromSeed(seed, salt)
return hashString(tostring(seed or "") .. ":" .. tostring(salt or "")) % 100
end
local function flagLabel(file, label)
if file and tostring(file) ~= "" then
return "{{flagicon image|" .. file .. "|200px}} " .. tostring(label or "")
end
return tostring(label or "")
end
--------------------------------------------------------------------------------
-- Extended Southern Strait / Eastern Mykonos / Snowholme locality list
--------------------------------------------------------------------------------
local southernTradeCities = {
{
code = "MIR",
city = "[[Mirovia]]",
region = "[[Eastern Mykonos]] Desert",
category = "Agriculture",
company = "[[Mirovian Cistern Growers' Syndicate]]",
resource = "cistern-grown melons, dryland cucumbers, preserved desert fruit, seed oil, packed caravan rations, and water-accounted produce consignments",
lineage = "Desert provisioning economy influenced by [[Jogi]]'s food-market role and [[Mylecia]]'s caravan-facing trade networks; adapted to cistern agriculture, water claims, and dry-route supply rather than beer, grain, or ritual crops"
},
{
code = "SAR",
city = "[[Saruq Thyrsa]]",
region = "Southern Strait coast",
category = "Agriculture",
company = "[[Saruq Thyrsa Reedcutters' Guild]]",
resource = "coastal reed, cane fiber, packing straw, ferry mats, cargo-padding material, rope backing, warehouse thatch, and crate-lining bundles",
lineage = "Harbor-materials economy influenced by [[Blore Heath]]'s shipping brokerage and [[Jogi]]'s quay-market supply system; focused on practical cargo handling, ferry shelters, and packing materials rather than piracy or cult goods"
},
{
code = "AYS",
city = "[[Ayllu Nysara]]",
region = "Eastern foothills of the [[Snowholme Range]]",
category = "Agriculture",
company = "[[Nysaran Terrace Farmers' Ayllu]]",
resource = "terrace beans, cold-weather tubers, sheep wool, highland fodder, pack-animal feed, preserved root stores, and mule-train provisions",
lineage = "Foothill supply economy influenced only indirectly by the Maritime Markets; tied more closely to Snowholme terrace farming, upland food storage, wool traffic, and pass-road provisioning"
},
{
code = "THQ",
city = "[[Thal Qencha]]",
region = "Eastern foothills of the [[Snowholme Range]]",
category = "Agriculture",
company = "[[Thal Qencha Springkeepers' Cooperative]]",
resource = "spring-fed watercress, trout ponds, smoked fish, cold-storage greens, inspected mountain food shipments, packed ice-box produce, and road-market fish consignments",
lineage = "Foothill water-and-food economy tied to Snowholme springs and pass roads; comparable to older Maritime Markets food distribution only in its role as a regulated supplier to travelers, markets, and route offices"
},
{
code = "RUK",
city = "[[Rumi-Kefaya]]",
region = "[[Eastern Mykonos]] Desert",
category = "Mining / Manufacturing / Energy",
company = "[[Rumi-Kefaya Stone and Lime Works]]",
resource = "basalt, limestone, paving stone, railway ballast, drainage tile, lime mortar, culvert blocks, harbor repair stone, quay coping, and storm-route masonry",
lineage = "Infrastructure economy influenced by [[Mylecia]]'s coal-and-works tradition and Southern Strait coastal preservation activity; focused on roads, quays, culverts, retaining walls, and storm-damage repair rather than extractive wealth"
},
{
code = "HAY",
city = "[[Hayr Chaskal]]",
region = "Southern Strait coast",
category = "Mining / Manufacturing / Energy",
company = "[[Hayr Chaskal Glass and Signal Works]]",
resource = "beacon glass, telegraph insulators, lighthouse lenses, lamp glass, storm panes, signal mirrors, buoy lenses, and weatherproof signal housings",
lineage = "Signal-and-navigation economy influenced by [[Blore Heath]]'s shipping control and [[Mylecia]]'s coastal works; supports ferry warnings, lighthouse maintenance, telegraph lines, and Hatch Ministry watch posts without copying older pirate or brokerage firms"
},
{
code = "QSE",
city = "[[Qhapaq Selen]]",
region = "Eastern foothills of the [[Snowholme Range]]",
category = "Services",
company = "[[Qhapaq Selen Route Registry Office]]",
resource = "night-road registry, caravan lodging, pass permits, route insurance, guide licensing, cargo-route papers, missing-traveler filings, and bonded transit records",
lineage = "Foothill route-service economy influenced by [[Mylecia]]'s caravan-facing commerce and [[Jogi]]'s intelligence-and-paperwork traditions; adapted to Snowholme pass roads, guide houses, lodging records, and insurance claims"
}
}
--------------------------------------------------------------------------------
-- Row-level locality focus helper
--------------------------------------------------------------------------------
local function rowLocality(args, channel, rowNumber)
if not southernTradeCities or #southernTradeCities == 0 then
return "Southern Strait corridor"
end
local year = tonumber(args.year or args.psscyear) or 0
local day = tonumber(args.day or args.dayofyear) or 0
local seed = tostring(args.seed or "") .. ":SS-ROW-LOCALITY:" .. tostring(channel or "") .. ":" .. tostring(year) .. ":" .. tostring(day)
local offset = hashString(seed) % #southernTradeCities
local idx = ((tonumber(rowNumber) or 1) - 1 + offset) % #southernTradeCities + 1
local loc = southernTradeCities[idx]
return loc.city .. "<br><small>" .. loc.region .. "</small>"
end
local function addRowLocalities(body, args, channel)
body = tostring(body or "")
-- Only try to modify wikitable output.
if not body:find("{|", 1, true) then
return body
end
local lines = mw.text.split(body, "\n", true)
local out = {}
local inTable = false
local headerInserted = false
local rowNumber = 0
for _, line in ipairs(lines) do
if line:match("^%s*{|") then
inTable = true
headerInserted = false
table.insert(out, line)
elseif inTable and not headerInserted and line:match("^%s*!") then
-- Put Locality focus as the first column.
table.insert(out, "! Locality focus")
headerInserted = true
table.insert(out, line)
elseif inTable and line:match("^%s*|%-") then
rowNumber = rowNumber + 1
table.insert(out, line)
table.insert(out, "| " .. rowLocality(args, channel, rowNumber))
elseif inTable and line:match("^%s*|}") then
inTable = false
table.insert(out, line)
else
table.insert(out, line)
end
end
return table.concat(out, "\n")
end
--------------------------------------------------------------------------------
-- Cult sign-off list for trade agreements
--------------------------------------------------------------------------------
local tradeSigningCults = {
{
code = "UMB",
flag = "UmbOracle.png",
label = "[[Noctis (Reformed Stripping Path)#Order of the Umbral Oracle|Order of the Umbral Oracle]]"
},
{
code = "GGS",
flag = "GoldenShadows.png",
label = "[[Chrysos (Reformed Stripping Path)#Guild of Golden Shadows|Guild of Golden Shadows]]"
},
{
code = "AZS",
flag = "AzureSentinel.png",
label = "[[Thalassa (Reformed Stripping Path)#Azure Sentinel Sect|Azure Sentinel Sect]]"
},
{
code = "HAR",
flag = "Harmonysanctum.png",
label = "[[Micras (Reformed Stripping Path)#Harmony Sanctum|Harmony Sanctum]]"
},
{
code = "VIT",
flag = "Vitalis.png",
label = "[[Plateau (Reformed Stripping Path)#Sanctum Vitalis|Sanctum Vitalis]]"
},
{
code = "AUR",
flag = "Auroramystica.png",
label = "[[Eos (Reformed Stripping Path)#Order of Aurora Mystica|Order of Aurora Mystica]]"
},
{
code = "DEL",
flag = "SanctumDel.png",
label = "[[Sisera (Reformed Stripping Path)#Sanctum Delphica|Sanctum Delphica]]"
},
{
code = "CAT",
flag = "Catonis.png",
label = "[[Cato (Reformed Stripping Path)#Rex Catonis|Rex Catonis]]"
},
{
code = "CON",
flag = "Concordia.png",
label = "[[Lukedu (Reformed Stripping Path)#Accord Concordia|Accord Concordia]]"
},
{
code = "STY",
flag = "StygianVe.png",
label = "[[Styx (Reformed Stripping Path)#Mystery of the Stygian Veil|Mystery of the Stygian Veil]]"
}
}
local tradeOutcomes = {
"Trade agreement countersigned; company cleared for addition to the appropriate [[General Port of Lake Morovia]] ledger pending ordinary page update.",
"Provisional General Port admission recommended; company papers transmitted to the Merchant General's audit desk for category placement.",
"Conditional trade window approved; first-cycle output, route papers, and stipend-voucher handling placed under Port review.",
"Company charter accepted for corridor listing; local cult sign-off attached to the General Port admission file.",
"Trade agreement filed without public ceremony; company admitted through ordinary registry channels to avoid inflaming corridor tensions."
}
--------------------------------------------------------------------------------
-- Rare Southern Strait trade-agreement / General Port admission events
--------------------------------------------------------------------------------
local function tradeAgreementEvent(args)
local chance = tonumber(args.tradechance or args.tradeChance) or 8
if chance < 0 then chance = 0 end
if chance > 100 then chance = 100 end
local showNoEvent = yn(args.showTradeNoEvent or args.showtradenoevent, false)
local year = tonumber(args.year or args.psscyear) or 0
local day = tonumber(args.day or args.dayofyear) or 0
local seed = tostring(args.seed or "") .. ":SS-TRADE:" .. tostring(year) .. ":" .. tostring(day)
local roll = pctFromSeed(seed, "roll") + 1
if roll > chance then
if showNoEvent then
return "''No new Southern Strait trade-agreement sign-off recorded for " .. dateLabel(args) .. ".''"
end
return nil
end
local city = pick(southernTradeCities, seed, "city")
local cult = pick(tradeSigningCults, seed, "cult")
local outcome = pick(tradeOutcomes, seed, "outcome")
if not city or not cult then return nil end
local seq = (pctFromSeed(seed, "seq") % 20) + 1
local tradeId
if year > 0 and day > 0 then
tradeId = string.format("GP-SS-%03d.%03d-%s-%02d", year, day, city.code or "GEN", seq)
else
tradeId = string.format("GP-SS-%s-%02d", city.code or "GEN", seq)
end
local signCode = string.format("%s-TA%02d", cult.code or "CUL", seq)
return table.concat({
"{| class=\"wikitable sortable\"",
"! Date",
"! Trade-ID",
"! Settlement",
"! Company",
"! General Port category",
"! Resource focus",
"! Economic lineage",
"! Cult sign-off",
"! Outcome",
"|-",
"| " .. dateLabel(args),
"| " .. tradeId,
"| " .. city.city .. "<br><small>" .. city.region .. "</small>",
"| " .. city.company,
"| " .. city.category,
"| " .. city.resource,
"| " .. (city.lineage or "Local economy tied to Southern Strait corridor trade and General Port admission review."),
"| " .. flagLabel(cult.flag, cult.label) .. "<br><small>Sign-off code: '''" .. signCode .. "'''</small>",
"| " .. outcome,
"|}"
}, "\n")
end
--------------------------------------------------------------------------------
-- Rare Southern Strait rebellion-type / corridor unrest events
--------------------------------------------------------------------------------
local rebellionProfiles = {
{
label = "Confederacy-adjacent courier screen",
description = "Deniable couriers and false-route messengers suspected of testing Southern Strait inspection gaps without openly declaring affiliation."
},
{
label = "Former Maritime Markets broker faction",
description = "Old broker-house retainers resisting General Port documentation, bonded cargo controls, and Straits Convention inspection routines."
},
{
label = "Anti-registry dock syndicate",
description = "Dockside labor and warehouse intermediaries opposing ledger seizures, voucher discipline, and cargo-chain reconciliation."
},
{
label = "False-proclamation circle",
description = "Pamphlet writers, rumor-carriers, and tavern readers circulating forged civic orders or anti-Bassaridian proclamations."
},
{
label = "Route-barricade committee",
description = "Local agitators using market wagons, mule trains, shrine queues, or ferry crowds to obstruct inspection lanes and delay lawful passage."
},
{
label = "Dispossessed-sympathetic quay cell",
description = "A loose waterfront cell suspected of copying Confederacy-style financing, couriering, and intimidation habits without confirmed command linkage."
}
}
local rebellionTriggers = {
"Forged levy notice circulated near ferry queues and cargo offices.",
"Masked speakers attempted to redirect caravan traffic away from inspection lanes.",
"Warehouse clerks reported missing seals, altered registry slips, and coordinated refusal to present ledgers.",
"Dockside crowd formed around rumors of unlawful seizure and demanded release of bonded cargo.",
"Signal-post watchers reported tampered lantern schedules and false storm-delay messages.",
"Pass-office runners carried conflicting route orders bearing copied civic marks.",
"Food, reed, glass, or stone consignments were delayed by a coordinated paper strike.",
"Temple Bank stewards reported anti-Bassaridian chants moving with clinic, ferry, or pilgrimage queues.",
"Privateer observers identified repeated courier handoffs around old Maritime Markets broker lanes.",
"General Port inspectors found matching false manifests across separate caravan and quay records."
}
local rebellionActions = {
"Council of Kings cordon established; Hatch Ministry observers preserved evidence for prize-court and registry review.",
"Temple Bank stewards opened rumor-control desks while lawful passage lanes were marked and guarded.",
"Suspect ledgers, copied seals, courier notes, and witness names were sealed under dual custody.",
"Privateer screen shifted to stand-off posture; noncritical boardings deferred while crowd pressure was reduced.",
"Route clerks reissued pass papers under direct supervision and voided suspect civic marks.",
"Harbor wardens separated lawful cargo from disputed loads and moved detainee interviews away from public queues.",
"Missionary cadre mediated household, dockworker, and caravan disputes while CKD patrols kept inspection lanes open.",
"Signal offices issued corrected notices and logged all false warnings for Straits Convention review.",
"General Port registry desk opened a temporary audit lane for affected cargo houses.",
"War League liaison classified the incident as contained unrest rather than open revolt, pending further intelligence review."
}
local rebellionNotes = {
"Incident treated as rebellion-type agitation, not general uprising.",
"Confederacy linkage unconfirmed; method resembled Dispossessed-adjacent courier and financing practice.",
"Former Maritime Markets habits assessed as enabling condition.",
"No change to ordinary lawful passage, but inspection lanes remained under watch.",
"Cult stewards instructed to separate rumor carriers from ordinary pilgrims and market traffic.",
"Public explanation emphasized document correction, cargo safety, and neutral passage.",
"Follow-up review assigned to General Port, Hatch Ministry, and Temple Bank clerks.",
"Locality focus retained for subsequent reporting cycle.",
"Event logged as corridor unrest with possible escalation if repeated.",
"Evidence preserved for comparison against future forged-paper or broker-cell incidents."
}
local rebellionRisks = {
"Low",
"Moderate",
"High",
"Contained",
"Escalating"
}
local function rebellionEvent(args)
local chance = tonumber(args.rebellionchance or args.rebellionChance or args.unrestchance or args.unrestChance) or 6
if chance < 0 then chance = 0 end
if chance > 100 then chance = 100 end
local showNoEvent = yn(args.showRebellionNoEvent or args.showrebellionnoevent or args.showUnrestNoEvent or args.showunrestnoevent, false)
local year = tonumber(args.year or args.psscyear) or 0
local day = tonumber(args.day or args.dayofyear) or 0
local seed = tostring(args.seed or "") .. ":SS-REBELLION:" .. tostring(year) .. ":" .. tostring(day)
local roll = pctFromSeed(seed, "roll") + 1
if roll > chance then
if showNoEvent then
return "''No rebellion-type corridor unrest recorded for " .. dateLabel(args) .. ".''"
end
return nil
end
local city = pick(southernTradeCities, seed, "city")
local profile = pick(rebellionProfiles, seed, "profile")
local trigger = pick(rebellionTriggers, seed, "trigger")
local action = pick(rebellionActions, seed, "action")
local note = pick(rebellionNotes, seed, "note")
local risk = pick(rebellionRisks, seed, "risk")
if not city or not profile then return nil end
local seq = (pctFromSeed(seed, "seq") % 20) + 1
local eventId
if year > 0 and day > 0 then
eventId = string.format("SS-RB-%03d.%03d-%s-%02d", year, day, city.code or "GEN", seq)
else
eventId = string.format("SS-RB-%s-%02d", city.code or "GEN", seq)
end
return table.concat({
"{| class=\"wikitable sortable\"",
"! Date",
"! Event-ID",
"! Locality focus",
"! Rebellion-type profile",
"! Trigger",
"! Risk",
"! Response",
"! Notes",
"|-",
"| " .. dateLabel(args),
"| " .. eventId,
"| " .. city.city .. "<br><small>" .. city.region .. "</small>",
"| '''" .. profile.label .. "'''<br><small>" .. profile.description .. "</small>",
"| " .. trigger,
"| " .. risk,
"| " .. action,
"| " .. note,
"|}"
}, "\n")
end
--------------------------------------------------------------------------------
-- Main Southern Strait-only view
--------------------------------------------------------------------------------
function p.makeTable(frame)
local args = (frame and frame.args) or {}
local showIntro = yn(args.intro, false)
local showTitle = yn(args.showtitle or args.titleline, false)
local showLegend = yn(args.legend or args.showlegend, false)
-- Collapsible section controls.
-- collapsible=no disables collapsible boxes.
-- collapsed=no keeps them open by default.
local collapseSections = yn(args.collapsible, true)
local startCollapsed = yn(args.collapsed, true)
local includeWar = yn(args.war or args.warleague, true)
local includeHatch = yn(args.hatch or args.hatchministry, true)
local includeMission = yn(args.missionary or args.templebank, true)
local includeTrade = yn(args.trade or args.tradeagreements or args.tradeagreement, true)
local includeRebellion = yn(args.rebellion or args.rebellions or args.unrest or args.uprising, true)
-- rowlocalities=no hides the row-level locality focus column.
local showRowLocalities = yn(args.rowlocalities or args.localities or args.showlocalities, true)
local year = args.year or args.psscyear
local day = args.day or args.dayofyear
local title = args.title or "Southern Strait Corridor Daily Operations"
local label = dateLabel(args)
local out = {}
if showTitle then
table.insert(out, "==" .. title .. "==")
end
if showIntro then
table.insert(out, string.format(
"''Southern Strait-only operational display for %s, limited to Haifan Bassaridian / former Maritime Markets corridor entries.''",
label
))
table.insert(out, "")
table.insert(out, "This display combines Council of Kings deployments, Hatch Ministry privateer activity, Temple Bank missionary operations, rare General Port trade-agreement sign-offs, rare rebellion-type corridor unrest alerts, and row-level Southern Strait locality focus columns while excluding unrelated regional rows.")
end
----------------------------------------------------------------------------
-- War League: Southern Strait-only
----------------------------------------------------------------------------
if includeWar then
local warArgs = {
year = year,
day = day,
-- rows = number of Southern Strait rows to display.
-- scanrows = number of original War League rows to scan while preserving
-- original Op-ID/type data from the source War League generation.
rows = args.warrows or args.rows or "24",
scanrows = args.warscanrows or args.scanrows or "160",
showlegend = showLegend and "yes" or "no",
flagsize = args.flagsize or "20",
zone = "SouthernStrait",
-- Southern Strait Corridor wrapper shows only Council of Kings
-- Division rows for War League deployments.
division = "Council of Kings Division",
}
if args.seed and tostring(args.seed) ~= "" then
warArgs.seed = args.seed
end
local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
if showRowLocalities then
body = addRowLocalities(body, { year = year, day = day, seed = args.seed }, "war")
end
table.insert(out, hr())
table.insert(out, section("Council of Kings Southern Strait deployments", body, collapseSections, startCollapsed))
end
----------------------------------------------------------------------------
-- Hatch Ministry: Southern Strait-only
----------------------------------------------------------------------------
if includeHatch then
local hatchArgs = {
year = year,
day = day,
legend = showLegend and "yes" or "no",
zone = "SouthernStrait",
}
if args.captain and tostring(args.captain) ~= "" then
hatchArgs.captain = args.captain
end
local ok, body = safeCall("Module:HatchMinistryDailyOps", "dailyReport", hatchArgs)
if showRowLocalities then
body = addRowLocalities(body, args, "hatch")
end
table.insert(out, hr())
table.insert(out, section("Hatch Ministry Southern Strait privateer operations", body, collapseSections, startCollapsed))
end
----------------------------------------------------------------------------
-- Temple Bank / Missionary Operations: Haifan only
----------------------------------------------------------------------------
if includeMission then
local missionaryArgs = {
year = year,
day = day,
region = "Haifan",
showlegend = showLegend and "yes" or "no",
includeThreat = args.includeThreat or args.includethreat or "no",
showEcon = args.showEcon or args.showecon or "no",
}
if args.missionarylimit and tostring(args.missionarylimit) ~= "" then
missionaryArgs.limit = args.missionarylimit
elseif args.limit and tostring(args.limit) ~= "" then
missionaryArgs.limit = args.limit
end
local ok, body = safeCall("Module:MissionaryDailyOpsBVR", "makeTable", missionaryArgs)
if showRowLocalities then
body = addRowLocalities(body, args, "missionary")
end
table.insert(out, hr())
table.insert(out, section("Temple Bank Southern Strait missionary operations", body, collapseSections, startCollapsed))
end
----------------------------------------------------------------------------
-- Rare trade-agreement / General Port admission events
----------------------------------------------------------------------------
if includeTrade then
local tradeBody = tradeAgreementEvent(args)
if tradeBody and tostring(tradeBody) ~= "" then
table.insert(out, hr())
table.insert(out, section("Southern Strait trade-agreement sign-offs", tradeBody, collapseSections, startCollapsed))
end
end
----------------------------------------------------------------------------
-- Rare rebellion-type / corridor unrest events
----------------------------------------------------------------------------
if includeRebellion then
local rebellionBody = rebellionEvent(args)
if rebellionBody and tostring(rebellionBody) ~= "" then
table.insert(out, hr())
table.insert(out, section("Southern Strait rebellion-type unrest alerts", rebellionBody, collapseSections, startCollapsed))
end
end
----------------------------------------------------------------------------
-- Combined legend
----------------------------------------------------------------------------
if showLegend then
local legendBody = table.concat({
"* '''Council of Kings Southern Strait deployments''' show only Council of Kings Division War League rows for the Southern Strait corridor.",
"* '''Hatch Ministry Southern Strait privateer operations''' show Haifan home-port privateers only.",
"* '''Temple Bank Southern Strait missionary operations''' show Haifan Bassaridian missionary rows only.",
"* '''Locality focus''' columns assign one extended Southern Strait, Eastern Mykonos Desert, or eastern Snowholme foothill settlement to each generated row when row-level localities are enabled.",
"* '''Southern Strait trade-agreement sign-offs''' are rare or uncommon events allowing companies in Southern Strait, Eastern Mykonos Desert, and eastern Snowholme foothill settlements to be admitted to the appropriate [[General Port of Lake Morovia]] ledger after cult sign-off.",
"* '''Southern Strait rebellion-type unrest alerts''' are rare events representing contained agitation, forged proclamations, broker-cell activity, route barricades, false orders, or Dispossessed-adjacent courier behavior within the extended corridor.",
"* '''Economic lineage''' notes describe how the newer locality economies are influenced by the historic port economies of [[Blore Heath]], [[Jogi]], and [[Mylecia]] without directly copying their companies, commodities, or institutions."
}, "\n")
table.insert(out, hr())
table.insert(out, section("Combined legend", legendBody, collapseSections, startCollapsed))
end
return table.concat(out, "\n")
end
--------------------------------------------------------------------------------
-- Shortcut views
--------------------------------------------------------------------------------
function p.southernStrait(frame)
local args = (frame and frame.args) or {}
args.title = args.title or "Southern Strait Corridor Daily Operations"
return p.makeTable({ args = args })
end
function p.warOnly(frame)
local args = (frame and frame.args) or {}
args.hatch = "no"
args.missionary = "no"
args.trade = "no"
args.rebellion = "no"
args.war = "yes"
args.title = args.title or "War League Southern Strait Daily Operations"
return p.makeTable({ args = args })
end
function p.hatchOnly(frame)
local args = (frame and frame.args) or {}
args.war = "no"
args.missionary = "no"
args.trade = "no"
args.rebellion = "no"
args.hatch = "yes"
args.title = args.title or "Hatch Ministry Southern Strait Daily Operations"
return p.makeTable({ args = args })
end
function p.missionaryOnly(frame)
local args = (frame and frame.args) or {}
args.war = "no"
args.hatch = "no"
args.trade = "no"
args.rebellion = "no"
args.missionary = "yes"
args.title = args.title or "Temple Bank Southern Strait Missionary Daily Operations"
return p.makeTable({ args = args })
end
return p