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 274: Line 274:
return nil
return nil
end
end
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


local city = pick(southernTradeCities, seed, "city")
local city = pick(southernTradeCities, seed, "city")
Line 335: Line 356:
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)
local showLocalities = yn(args.localities or args.showlocalities, true)




Line 388: Line 411:
end
end


local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
 
table.insert(out, hr())
local ok, body = safeCall("Module:WarLeagueDivisionOpsBVR", "makeTable", warArgs)
table.insert(out, section("War League Southern Strait deployments", body, collapseSections, startCollapsed))
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
end


Line 409: Line 438:
end
end


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


Line 436: Line 470:
local ok, body = safeCall("Module:MissionaryDailyOpsBVR", "makeTable", missionaryArgs)
local ok, body = safeCall("Module:MissionaryDailyOpsBVR", "makeTable", missionaryArgs)
table.insert(out, hr())
table.insert(out, hr())
table.insert(out, section("Temple Bank Southern Strait missionary operations", body, collapseSections, startCollapsed))
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
end



Revision as of 15:39, 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

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

--------------------------------------------------------------------------------
-- Southern Strait trade-agreement / General Port admission events
--------------------------------------------------------------------------------

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

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"
	}
}

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."
}

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 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



	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


--------------------------------------------------------------------------------
-- 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 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, and Temple Bank missionary operations 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)
		table.insert(out, hr())
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

	----------------------------------------------------------------------------
	-- 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

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."
	}, "\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.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.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.missionary = "yes"
	args.title = args.title or "Temple Bank Southern Strait Missionary Daily Operations"
	return p.makeTable({ args = args })
end

return p