Module:SouthernStraitCorridorOps: Difference between revisions

From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs)
Undo revision 404300 by NewZimiaGov (talk)
Tag: Undo
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 5: Line 6:
-- 2) HatchMinistryDailyOps
-- 2) HatchMinistryDailyOps
-- 3) MissionaryDailyOpsBVR
-- 3) MissionaryDailyOpsBVR
--
-- Also adds:
-- 4) Rare Southern Strait trade-agreement / General Port admission events
-- 5) Extended Southern Strait locality focus lines


local p = {}
local p = {}
Line 37: Line 42:
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 70: Line 74:
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 83: Line 86:
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 91: Line 93:


local collapseClass = collapsed and "mw-collapsible mw-collapsed" or "mw-collapsible"
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 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="font-weight:bold; padding:0.35em 0.6em; background:#eaecf0;">' .. safeTitle .. '</div>')
Line 105: Line 106:
return "\n----\n"
return "\n----\n"
end
end
--------------------------------------------------------------------------------
-- Southern Strait trade-agreement / General Port admission events
--------------------------------------------------------------------------------


local function hashString(s)
local function hashString(s)
Line 135: Line 132:
return tostring(label or "")
return tostring(label or "")
end
end
--------------------------------------------------------------------------------
-- Extended Southern Strait / Eastern Mykonos / Snowholme locality list
--------------------------------------------------------------------------------


local southernTradeCities = {
local southernTradeCities = {
Line 194: Line 195:
}
}
}
}
--------------------------------------------------------------------------------
-- Cult sign-off list for trade agreements
--------------------------------------------------------------------------------


local tradeSigningCults = {
local tradeSigningCults = {
Line 255: Line 260:
"Trade agreement filed without public ceremony; company admitted through ordinary registry channels to avoid inflaming corridor tensions."
"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 function tradeAgreementEvent(args)
Line 313: Line 322:
end
end


--------------------------------------------------------------------------------
-- Locality focus lines for all Southern Strait sections
--------------------------------------------------------------------------------
local function corridorLocalityFocus(args, channel)
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-LOCALITY:" .. tostring(channel or "") .. ":" .. tostring(year) .. ":" .. tostring(day)
local city = pick(southernTradeCities, seed, "locality")
if not city then return "" end
local channelText = {
war = "War League corridor activity",
hatch = "Hatch Ministry privateering and registry activity",
missionary = "Temple Bank missionary activity"
}
return "''Southern Strait locality focus: " .. city.city .. " (" .. city.region .. ") — " ..
(channelText[channel] or "Corridor activity") ..
" is treated as extending through this settlement's trade routes, inspection points, service offices, or inland approaches for this reporting cycle.''\n\n"
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 321: Line 352:
local args = (frame and frame.args) or {}
local args = (frame and frame.args) or {}


local showIntro  = yn(args.intro, false)
local showIntro  = yn(args.intro, false)
local showTitle  = yn(args.showtitle or args.titleline, false)
local showTitle  = yn(args.showtitle or args.titleline, false)
local showLegend = yn(args.legend or args.showlegend, false)
local showLegend = yn(args.legend or args.showlegend, false)


-- Collapsible section controls.
-- Collapsible section controls.
-- collapsible=no disables collapsible boxes.
-- collapsible=no disables collapsible boxes.
-- collapsed=no keeps them open by default.
-- collapsed=no keeps them open by default.
local collapseSections = yn(args.collapsible, true)
local collapseSections = yn(args.collapsible, true)
local startCollapsed = yn(args.collapsed, true)
local startCollapsed = yn(args.collapsed, true)


local includeWar    = yn(args.war or args.warleague, true)
local includeWar    = yn(args.war or args.warleague, true)
local includeHatch  = yn(args.hatch or args.hatchministry, true)
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  = yn(args.trade or args.tradeagreements or args.tradeagreement, true)
local includeTrade  = yn(args.trade or args.tradeagreements or args.tradeagreement, true)


-- localities=no hides the extended locality focus lines.
local showLocalities = yn(args.localities or args.showlocalities, true)


local year = args.year or args.psscyear
local year = args.year or args.psscyear
Line 345: Line 378:
local out = {}
local out = {}


if showTitle then
if showTitle then
table.insert(out, "==" .. title .. "==")
table.insert(out, "==" .. title .. "==")
end
end


if showIntro then
if showIntro then
Line 355: Line 388:
))
))
table.insert(out, "")
table.insert(out, "")
table.insert(out, "This display combines War League deployments, Hatch Ministry privateer activity, and Temple Bank missionary operations while excluding unrelated regional rows.")
table.insert(out, "This display combines War League deployments, Hatch Ministry privateer activity, Temple Bank missionary operations, rare General Port trade-agreement sign-offs, and extended Southern Strait locality focus lines while excluding unrelated regional rows.")
end
end


Line 363: Line 396:


if includeWar then
if includeWar then
local warArgs = {
local warArgs = {
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",
scanrows = args.warscanrows or args.scanrows or "160",


-- rows = number of Southern Strait rows to display.
showlegend = showLegend and "yes" or "no",
-- scanrows = number of original War League rows to scan while preserving
flagsize = args.flagsize or "20",
-- original Op-ID/type data from the source War League generation.
zone = "SouthernStrait",
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",
}


if args.division and tostring(args.division) ~= "" then
if args.division and tostring(args.division) ~= "" then
Line 389: Line 421:


local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
if showLocalities then
body = corridorLocalityFocus(args, "war") .. body
end
table.insert(out, hr())
table.insert(out, hr())
table.insert(out, section("War League Southern Strait deployments", body, collapseSections, startCollapsed))
table.insert(out, section("War League Southern Strait deployments", body, collapseSections, startCollapsed))
Line 410: Line 445:


local ok, body = safeCall("Module:HatchMinistryDailyOps", "dailyReport", hatchArgs)
local ok, body = safeCall("Module:HatchMinistryDailyOps", "dailyReport", hatchArgs)
if showLocalities then
body = corridorLocalityFocus(args, "hatch") .. body
end
table.insert(out, hr())
table.insert(out, hr())
table.insert(out, section("Hatch Ministry Southern Strait privateer operations", body, collapseSections, startCollapsed))
table.insert(out, section("Hatch Ministry Southern Strait privateer operations", body, collapseSections, startCollapsed))
Line 435: Line 473:


local ok, body = safeCall("Module:MissionaryDailyOpsBVR", "makeTable", missionaryArgs)
local ok, body = safeCall("Module:MissionaryDailyOpsBVR", "makeTable", missionaryArgs)
if showLocalities then
body = corridorLocalityFocus(args, "missionary") .. body
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 440: Line 481:


----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- Trade-agreement / General Port admission events
-- Rare trade-agreement / General Port admission events
----------------------------------------------------------------------------
----------------------------------------------------------------------------
if includeTrade then
if includeTrade then
local tradeBody = tradeAgreementEvent(args)
local tradeBody = tradeAgreementEvent(args)
Line 450: Line 492:
end
end


if showLegend then
----------------------------------------------------------------------------
local legendBody = table.concat({
-- Combined legend
"* '''War League Southern Strait deployments''' show Haifan Bassaridian / former Maritime Markets security rows only.",
----------------------------------------------------------------------------
"* '''Hatch Ministry Southern Strait privateer operations''' show Haifan home-port privateers only.",
"* '''Temple Bank Southern Strait missionary operations''' show Haifan Bassaridian missionary rows only."
}, "\n")


table.insert(out, hr())
if showLegend then
table.insert(out, section("Combined legend", legendBody, collapseSections, startCollapsed))
local legendBody = table.concat({
end
"* '''War League Southern Strait deployments''' show Haifan Bassaridian / former Maritime Markets security rows only.",
"* '''Hatch Ministry Southern Strait privateer operations''' show Haifan home-port privateers only.",
"* '''Temple Bank Southern Strait missionary operations''' show Haifan Bassaridian missionary rows only.",
"* '''Southern Strait locality focus''' lines assign one extended Southern Strait, Eastern Mykonos Desert, or eastern Snowholme foothill settlement to each War League, Hatch Ministry, and Temple Bank reporting section.",
"* '''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."
}, "\n")
table.insert(out, hr())
table.insert(out, section("Combined legend", legendBody, collapseSections, startCollapsed))
end


return table.concat(out, "\n")
return table.concat(out, "\n")
Line 478: Line 525:
args.hatch = "no"
args.hatch = "no"
args.missionary = "no"
args.missionary = "no"
args.trade = "no"
args.war = "yes"
args.war = "yes"
args.title = args.title or "War League Southern Strait Daily Operations"
args.title = args.title or "War League Southern Strait Daily Operations"
Line 487: Line 535:
args.war = "no"
args.war = "no"
args.missionary = "no"
args.missionary = "no"
args.trade = "no"
args.hatch = "yes"
args.hatch = "yes"
args.title = args.title or "Hatch Ministry Southern Strait Daily Operations"
args.title = args.title or "Hatch Ministry Southern Strait Daily Operations"
Line 496: Line 545:
args.war = "no"
args.war = "no"
args.hatch = "no"
args.hatch = "no"
args.trade = "no"
args.missionary = "yes"
args.missionary = "yes"
args.title = args.title or "Temple Bank Southern Strait Missionary Daily Operations"
args.title = args.title or "Temple Bank Southern Strait Missionary Daily Operations"

Revision as of 15:44, 2 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) Extended Southern Strait locality focus lines

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 melons, dryland cucumbers, seed oil, and preserved desert fruit"
	},
	{
		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, and cargo-padding material"
	},
	{
		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, and highland fodder"
	},
	{
		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, and cold-storage greens"
	},
	{
		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, and lime mortar"
	},
	{
		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, and weatherproof signal equipment"
	},
	{
		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, and pilgrimage-office services"
	}
}

--------------------------------------------------------------------------------
-- 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",
		"! Cult sign-off",
		"! Outcome",
		"|-",
		"| " .. dateLabel(args),
		"| " .. tradeId,
		"| " .. city.city .. "<br><small>" .. city.region .. "</small>",
		"| " .. city.company,
		"| " .. city.category,
		"| " .. city.resource,
		"| " .. flagLabel(cult.flag, cult.label) .. "<br><small>Sign-off code: '''" .. signCode .. "'''</small>",
		"| " .. outcome,
		"|}"
	}, "\n")
end

--------------------------------------------------------------------------------
-- Locality focus lines for all Southern Strait sections
--------------------------------------------------------------------------------

local function corridorLocalityFocus(args, channel)
	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-LOCALITY:" .. tostring(channel or "") .. ":" .. tostring(year) .. ":" .. tostring(day)

	local city = pick(southernTradeCities, seed, "locality")
	if not city then return "" end

	local channelText = {
		war = "War League corridor activity",
		hatch = "Hatch Ministry privateering and registry activity",
		missionary = "Temple Bank missionary activity"
	}

	return "''Southern Strait locality focus: " .. city.city .. " (" .. city.region .. ") — " ..
		(channelText[channel] or "Corridor activity") ..
		" is treated as extending through this settlement's trade routes, inspection points, service offices, or inland approaches for this reporting cycle.''\n\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)

	-- localities=no hides the extended locality focus lines.
	local showLocalities = yn(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 War League deployments, Hatch Ministry privateer activity, Temple Bank missionary operations, rare General Port trade-agreement sign-offs, and extended Southern Strait locality focus lines 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",
		}

		if args.division and tostring(args.division) ~= "" then
			warArgs.division = args.division
		elseif args.wardivision and tostring(args.wardivision) ~= "" then
			warArgs.division = args.wardivision
		end

		if args.seed and tostring(args.seed) ~= "" then
			warArgs.seed = args.seed
		end

		local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
		if showLocalities then
			body = corridorLocalityFocus(args, "war") .. body
		end
		table.insert(out, hr())
		table.insert(out, section("War League 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 showLocalities then
			body = corridorLocalityFocus(args, "hatch") .. body
		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 showLocalities then
			body = corridorLocalityFocus(args, "missionary") .. body
		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

	----------------------------------------------------------------------------
	-- Combined legend
	----------------------------------------------------------------------------

	if showLegend then
		local legendBody = table.concat({
			"* '''War League Southern Strait deployments''' show Haifan Bassaridian / former Maritime Markets security rows only.",
			"* '''Hatch Ministry Southern Strait privateer operations''' show Haifan home-port privateers only.",
			"* '''Temple Bank Southern Strait missionary operations''' show Haifan Bassaridian missionary rows only.",
			"* '''Southern Strait locality focus''' lines assign one extended Southern Strait, Eastern Mykonos Desert, or eastern Snowholme foothill settlement to each War League, Hatch Ministry, and Temple Bank reporting section.",
			"* '''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."
		}, "\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.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.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.missionary = "yes"
	args.title = args.title or "Temple Bank Southern Strait Missionary Daily Operations"
	return p.makeTable({ args = args })
end

return p