Module:HatchMinistryDailyOps: Difference between revisions

From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs)
No edit summary
NewZimiaGov (talk | contribs)
No edit summary
Line 3: Line 3:
-- Deterministic per-day output (no math.random / no os.time seeding).
-- Deterministic per-day output (no math.random / no os.time seeding).
--
--
-- Calendar:
-- Color coding: row background reflects task urgency (Green/Yellow/Red),
-- Module:BassaridianCalendar (returns a formatted date string; we parse year/dayOfYear)
-- matching the palette used in Module:StraitsDaily.


local p = {}
local p = {}
Line 33: Line 33:
   cityFlag[name] = string.format("[[File:%sFlag.png|20px]]", normalizeForFlag(name))
   cityFlag[name] = string.format("[[File:%sFlag.png|20px]]", normalizeForFlag(name))
end
end
-- explicit override used elsewhere on your wiki
cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]"
cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]"


Line 109: Line 108:
   local y, doy, month = parseCalendarString(s)
   local y, doy, month = parseCalendarString(s)
   if not y or not doy then
   if not y or not doy then
    -- If your calendar string format ever changes, this prevents hard-failure.
     y, doy, month = 0, 1, ""
     y, doy, month = 0, 1, ""
     s = tostring(s or "")
     s = tostring(s or "")
Line 120: Line 118:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function hash31(str)
local function hash31(str)
  -- rolling hash mod 2^31-1 (safe integer range in Lua double)
   local h = 0
   local h = 0
   for i = 1, #str do
   for i = 1, #str do
Line 177: Line 174:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- 5) TASK LIBRARY (EXPANDED: 20 per pool)
-- 5) COLOR CODING (same palette logic used in StraitsDaily)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function sevStyle(sev)
  if sev == "red" then
    return ' style="background-color:#f8d7da;"'
  elseif sev == "yellow" then
    return ' style="background-color:#fff3cd;"'
  else
    return ' style="background-color:#d4edda;"'
  end
end
local function bumpSev(sev)
  if sev == "green" then return "yellow" end
  if sev == "yellow" then return "red" end
  return "red"
end
--------------------------------------------------------------------------------
-- 6) TASK LIBRARY (20 per pool; each task has an urgency tier)
--------------------------------------------------------------------------------
local function T(text, sev) return {text=text, sev=sev} end
local tasks_general = {
local tasks_general = {
   "Convoy escort and corridor clearing for registered merchant traffic, enforcing registry sequence and predictable passage.",
   T("Convoy escort and corridor clearing for registered merchant traffic, enforcing registry sequence and predictable passage.","green"),
   "VBSS surge and manifest verification, with heightened scrutiny for cargo mislabeling, forged papers, and transshipment laundering.",
   T("VBSS surge and manifest verification, with heightened scrutiny for cargo mislabeling, forged papers, and transshipment laundering.","yellow"),
   "Interdiction patrol against small-craft logistics supporting anti-corridor insurgent networks, with evidence handling and detainee processing discipline.",
   T("Interdiction patrol against small-craft logistics supporting anti-corridor insurgent networks, with evidence handling and detainee processing discipline.","yellow"),
   "Lane assurance work in the approaches and harbor margins, including buoy checks, beacon verification, and channel safety enforcement.",
   T("Lane assurance work in the approaches and harbor margins, including buoy checks, beacon verification, and channel safety enforcement.","green"),
   "Counter-smuggling sweep focused on contraband arms, unregistered ritual cargo, and false-cleared Temple consignments.",
   T("Counter-smuggling sweep focused on contraband arms, unregistered ritual cargo, and false-cleared Temple consignments.","yellow"),
   "Rapid-response security support to local authorities for port unrest, quarantine enforcement, and rumor-driven crowd surges.",
   T("Rapid-response security support to local authorities for port unrest, quarantine enforcement, and rumor-driven crowd surges.","red"),
   "Search-and-rescue readiness patrol with debris clearance coordination and temporary berth control during incidents.",
   T("Search-and-rescue readiness patrol with debris clearance coordination and temporary berth control during incidents.","red"),
   "Liaison rotation with Temple and civic screening teams for morale discipline, rumor containment, and compliance reinforcement.",
   T("Liaison rotation with Temple and civic screening teams for morale discipline, rumor containment, and compliance reinforcement.","yellow"),
   "Night interception detail targeting unlit runners and coastal-shadowing craft attempting to bypass inspection windows.",
   T("Night interception detail targeting unlit runners and coastal-shadowing craft attempting to bypass inspection windows.","yellow"),
   "Port-entry queue control and traffic metering to prevent berth chaos, including stand-off enforcement for noncompliant hulls.",
   T("Port-entry queue control and traffic metering to prevent berth chaos, including stand-off enforcement for noncompliant hulls.","green"),
   "Evidence convoy to a War League intake point, transporting seized cargo under chain-of-custody doctrine.",
   T("Evidence convoy to a War League intake point, transporting seized cargo under chain-of-custody doctrine.","yellow"),
   "Inspection of fishery convoys and cold-chain cargo for hidden compartments, false ice loads, and counterfeit seals.",
   T("Inspection of fishery convoys and cold-chain cargo for hidden compartments, false ice loads, and counterfeit seals.","yellow"),
   "Anti-piracy deterrence sweep against unaffiliated raiders operating outside the registry, with warning demonstrations and capture mandates.",
   T("Anti-piracy deterrence sweep against unaffiliated raiders operating outside the registry, with warning demonstrations and capture mandates.","yellow"),
   "Boarding-team readiness cycle and small-arms drill day, with emphasis on non-lethal deck control and restraint discipline.",
   T("Boarding-team readiness cycle and small-arms drill day, with emphasis on non-lethal deck control and restraint discipline.","green"),
   "Escort for diplomatic or Temple couriers transiting the corridor, with counter-ambush screening at chokepoints.",
   T("Escort for diplomatic or Temple couriers transiting the corridor, with counter-ambush screening at chokepoints.","yellow"),
   "Counterfeit voucher and registry-stamp crackdown, coordinating with port clerks to identify forged paperwork patterns.",
   T("Counterfeit voucher and registry-stamp crackdown, coordinating with port clerks to identify forged paperwork patterns.","yellow"),
   "Harbor-mouth overwatch with spotters to track suspicious loitering and false distress signaling near approach lanes.",
   T("Harbor-mouth overwatch with spotters to track suspicious loitering and false distress signaling near approach lanes.","green"),
   "Quarantine cordon support for a suspected outbreak vessel, enforcing isolation lanes and controlled disembarkation sequencing.",
   T("Quarantine cordon support for a suspected outbreak vessel, enforcing isolation lanes and controlled disembarkation sequencing.","red"),
   "Canal approach patrol to prevent sabotage against locks, piers, and water infrastructure serving major quay districts.",
   T("Canal approach patrol to prevent sabotage against locks, piers, and water infrastructure serving major quay districts.","red"),
   "Training cruise with junior crews to certify boarding compliance, medical triage procedure, and detainee handling standards."
   T("Training cruise with junior crews to certify boarding compliance, medical triage procedure, and detainee handling standards.","green")
}
}


local tasks_north = {
local tasks_north = {
   "Cold-water frontier patrol emphasizing raider deterrence, route denial, and winter-route landing site reconnaissance.",
   T("Cold-water frontier patrol emphasizing raider deterrence, route denial, and winter-route landing site reconnaissance.","yellow"),
   "Joint boarding drills and seizure-readiness for difficult-weather VBSS operations near northern chokepoints.",
   T("Joint boarding drills and seizure-readiness for difficult-weather VBSS operations near northern chokepoints.","green"),
   "Coastal reconnaissance for hidden coves, improvised piers, and suspected insurgent resupply anchorages.",
   T("Coastal reconnaissance for hidden coves, improvised piers, and suspected insurgent resupply anchorages.","yellow"),
   "Ice-margin escort for timber and ore traffic, enforcing safe-lane passage through fog and drift hazards.",
   T("Ice-margin escort for timber and ore traffic, enforcing safe-lane passage through fog and drift hazards.","green"),
   "Night watch against ghost-ship imitation tactics, verifying hull identity and rejecting falsified light codes.",
   T("Night watch against ghost-ship imitation tactics, verifying hull identity and rejecting falsified light codes.","yellow"),
   "Shoreline sweep for signal cairns and illicit beacon fires used to guide runners into protected inlets.",
   T("Shoreline sweep for signal cairns and illicit beacon fires used to guide runners into protected inlets.","yellow"),
   "Interdiction of smugglers using river-mouth approaches to bypass port control, with shallow-draft pursuit elements.",
   T("Interdiction of smugglers using river-mouth approaches to bypass port control, with shallow-draft pursuit elements.","yellow"),
   "Storm-surge response patrol supporting stranded craft, hauling wreckage clear and securing debris fields.",
   T("Storm-surge response patrol supporting stranded craft, hauling wreckage clear and securing debris fields.","red"),
   "Border-proximity deterrence demonstration near contested approaches, emphasizing corridor sovereignty by presence.",
   T("Border-proximity deterrence demonstration near contested approaches, emphasizing corridor sovereignty by presence.","yellow"),
   "Winter-route courier interception, targeting clandestine messages and route-maps carried by sled-ship tenders.",
   T("Winter-route courier interception, targeting clandestine messages and route-maps carried by sled-ship tenders.","yellow"),
   "Harbor freeze management patrol, coordinating icebreaking assistance and preventing dock congestion escalation.",
   T("Harbor freeze management patrol, coordinating icebreaking assistance and preventing dock congestion escalation.","red"),
   "Recon of abandoned fortlets and cliff ladders used as clandestine landing infrastructure during past campaigns.",
   T("Recon of abandoned fortlets and cliff ladders used as clandestine landing infrastructure during past campaigns.","yellow"),
   "Counter-insurgent sweep for hidden fuel caches, rope ladders, and cliff-staged supply bundles along rugged coasts.",
   T("Counter-insurgent sweep for hidden fuel caches, rope ladders, and cliff-staged supply bundles along rugged coasts.","yellow"),
   "Escort for refugee or evacuation flotillas under strict sequencing, preventing infiltration by hostile agents.",
   T("Escort for refugee or evacuation flotillas under strict sequencing, preventing infiltration by hostile agents.","red"),
   "Mine-scare verification patrol, conducting lane checks after rumor events to restore merchant confidence.",
   T("Mine-scare verification patrol, conducting lane checks after rumor events to restore merchant confidence.","red"),
   "Long-range patrol to discourage unaffiliated privateer predation in the far approaches, enforcing registry legitimacy.",
   T("Long-range patrol to discourage unaffiliated privateer predation in the far approaches, enforcing registry legitimacy.","yellow"),
   "Cooperation drill with local militia garrisons, practicing shore-to-ship handover for detainees and seized cargo.",
   T("Cooperation drill with local militia garrisons, practicing shore-to-ship handover for detainees and seized cargo.","green"),
   "Watch for cult-linked winter rites that trigger crowd movement to the waterfront, providing calm enforcement presence.",
   T("Watch for cult-linked winter rites that trigger crowd movement to the waterfront, providing calm enforcement presence.","yellow"),
   "Signal interception and direction-finding patrol to locate clandestine transmitters along ridge or lighthouse ruins.",
   T("Signal interception and direction-finding patrol to locate clandestine transmitters along ridge or lighthouse ruins.","yellow"),
   "Post-incident audit run, rechecking logs and witness statements after a northern skirmish to prevent rumor spirals."
   T("Post-incident audit run, rechecking logs and witness statements after a northern skirmish to prevent rumor spirals.","yellow")
}
}


local tasks_south = {
local tasks_south = {
   "Southern straits checkpoint enforcement with ro-ro ramp inspections and explosive-risk screening of container traffic.",
   T("Southern straits checkpoint enforcement with ro-ro ramp inspections and explosive-risk screening of container traffic.","red"),
   "Interdiction of fast skiffs and disguised cargo dhows, prioritizing weapons leakage and clandestine courier movement.",
   T("Interdiction of fast skiffs and disguised cargo dhows, prioritizing weapons leakage and clandestine courier movement.","yellow"),
   "Escort for high-value shipments transiting the southern corridor under strict queue and inspection timing.",
   T("Escort for high-value shipments transiting the southern corridor under strict queue and inspection timing.","yellow"),
   "Harbor perimeter patrol to prevent diver sabotage and underwater placement of charges near pylons and ramps.",
   T("Harbor perimeter patrol to prevent diver sabotage and underwater placement of charges near pylons and ramps.","red"),
   "Container seal audit and weigh-station verification to catch false tare weights, decoy loads, and swapped manifests.",
   T("Container seal audit and weigh-station verification to catch false tare weights, decoy loads, and swapped manifests.","yellow"),
   "Crowd-control augmentation during market surges, keeping inspection lanes clear and preventing quay-side crush incidents.",
   T("Crowd-control augmentation during market surges, keeping inspection lanes clear and preventing quay-side crush incidents.","red"),
   "Escort of fuel barges and repair tenders supporting corridor craft, with anti-ambush screen along shallow approaches.",
   T("Escort of fuel barges and repair tenders supporting corridor craft, with anti-ambush screen along shallow approaches.","yellow"),
   "Contraband sweep for dream-lure substances moving through coastal markets, enforcing seizure doctrine.",
   T("Contraband sweep for dream-lure substances moving through coastal markets, enforcing seizure doctrine.","yellow"),
   "Anti-bribery integrity patrol, rotating boarding teams and recording interactions to deter corrupt gatekeeping.",
   T("Anti-bribery integrity patrol, rotating boarding teams and recording interactions to deter corrupt gatekeeping.","yellow"),
   "Recon of mangrove or reed margins used for low-visibility transfers, with shallow pursuit and night optics.",
   T("Recon of mangrove or reed margins used for low-visibility transfers, with shallow pursuit and night optics.","yellow"),
   "VBSS focus on ro-ro decks and vehicle bays, inspecting hidden compartments, false bulkheads, and modified ramps.",
   T("VBSS focus on ro-ro decks and vehicle bays, inspecting hidden compartments, false bulkheads, and modified ramps.","yellow"),
   "Disruption of staged distress calls used to pull patrols off-lane, verifying authenticity before committing assets.",
   T("Disruption of staged distress calls used to pull patrols off-lane, verifying authenticity before committing assets.","yellow"),
   "Escort of pilgrim or festival traffic through the southern corridor, enforcing timed windows and calm procedure.",
   T("Escort of pilgrim or festival traffic through the southern corridor, enforcing timed windows and calm procedure.","yellow"),
   "Coastal deterrence posture near known runner routes, signaling denial without escalation to open combat.",
   T("Coastal deterrence posture near known runner routes, signaling denial without escalation to open combat.","yellow"),
   "Port-rail interface security support, screening containers that transfer directly from quay to inland corridors.",
   T("Port-rail interface security support, screening containers that transfer directly from quay to inland corridors.","yellow"),
   "Undercover observation run in nearshore traffic, tracking suspected broker craft coordinating smuggling rendezvous.",
   T("Undercover observation run in nearshore traffic, tracking suspected broker craft coordinating smuggling rendezvous.","yellow"),
   "EOD stand-by and cordon enforcement after discovery of suspect packages at ramps or quayside warehouses.",
   T("EOD stand-by and cordon enforcement after discovery of suspect packages at ramps or quayside warehouses.","red"),
   "Inspection of refrigerated cargo for false panels and hidden stowaways, coordinating safe medical screening.",
   T("Inspection of refrigerated cargo for false panels and hidden stowaways, coordinating safe medical screening.","yellow"),
   "Short-notice escort requested by port authorities after a threat bulletin, maintaining corridor credibility by response speed.",
   T("Short-notice escort requested by port authorities after a threat bulletin, maintaining corridor credibility by response speed.","red"),
   "Post-seizure handling and auction transfer escort, moving confiscated goods to authorized holdings under paperwork discipline."
   T("Post-seizure handling and auction transfer escort, moving confiscated goods to authorized holdings under paperwork discipline.","yellow")
}
}


local tasks_central = {
local tasks_central = {
   "Canal and harbor security rotation supporting administrative traffic and registry enforcement near central corridor hubs.",
   T("Canal and harbor security rotation supporting administrative traffic and registry enforcement near central corridor hubs.","green"),
   "Inspection coordination with port clerks and Temple auditors to reduce queue-time without relaxing compliance standards.",
   T("Inspection coordination with port clerks and Temple auditors to reduce queue-time without relaxing compliance standards.","yellow"),
   "Ritual cargo verification support with enforcement of pre-clearance doctrine and holding protocols.",
   T("Ritual cargo verification support with enforcement of pre-clearance doctrine and holding protocols.","yellow"),
   "Canal-lock security sweep to deter sabotage of gates, chains, and control houses serving high-traffic waterways.",
   T("Canal-lock security sweep to deter sabotage of gates, chains, and control houses serving high-traffic waterways.","red"),
   "Escort for administrative barges and registry couriers moving between major quays and oversight offices.",
   T("Escort for administrative barges and registry couriers moving between major quays and oversight offices.","green"),
   "Dockside patrol targeting petty theft rings and counterfeit stamp sellers preying on merchant queues.",
   T("Dockside patrol targeting petty theft rings and counterfeit stamp sellers preying on merchant queues.","yellow"),
   "Controlled berth allocation support during peak arrivals, enforcing order of entry and preventing berth disputes.",
   T("Controlled berth allocation support during peak arrivals, enforcing order of entry and preventing berth disputes.","green"),
   "Liaison patrol with Temple Bank clerks for high-value transfers, verifying seals and escorting to secure vault quays.",
   T("Liaison patrol with Temple Bank clerks for high-value transfers, verifying seals and escorting to secure vault quays.","yellow"),
   "Canal bridge and tunnel perimeter check, preventing illicit transfers from underpasses into restricted wharf zones.",
   T("Canal bridge and tunnel perimeter check, preventing illicit transfers from underpasses into restricted wharf zones.","yellow"),
   "Rapid-response run to a canal incident, establishing cordons, clearing debris, and restoring navigation sequencing.",
   T("Rapid-response run to a canal incident, establishing cordons, clearing debris, and restoring navigation sequencing.","red"),
   "Inspection of passenger ferries and canal shuttles for clandestine couriers, false identities, and concealed satchels.",
   T("Inspection of passenger ferries and canal shuttles for clandestine couriers, false identities, and concealed satchels.","yellow"),
   "Citywatch coordination day, aligning waterfront patrol routes with civic policing to prevent gaps and overlaps.",
   T("Citywatch coordination day, aligning waterfront patrol routes with civic policing to prevent gaps and overlaps.","green"),
   "Harbor-mouth overwatch with spotters to identify loitering craft attempting to time entries between inspection rotations.",
   T("Harbor-mouth overwatch with spotters to identify loitering craft attempting to time entries between inspection rotations.","green"),
   "Detainee transfer and intake coordination to a designated holding site, emphasizing calm procedure and record integrity.",
   T("Detainee transfer and intake coordination to a designated holding site, emphasizing calm procedure and record integrity.","yellow"),
   "Compliance education pass, issuing warnings and standard notices to repeat offenders before escalatory seizure.",
   T("Compliance education pass, issuing warnings and standard notices to repeat offenders before escalatory seizure.","green"),
   "Audit of registry anomalies flagged by clerks, conducting targeted re-boards of vessels with inconsistent logs.",
   T("Audit of registry anomalies flagged by clerks, conducting targeted re-boards of vessels with inconsistent logs.","yellow"),
   "Escort for repair barges and dredging crews, maintaining safety perimeters while channel work proceeds.",
   T("Escort for repair barges and dredging crews, maintaining safety perimeters while channel work proceeds.","yellow"),
   "Canal-side rumor containment presence after an incident bulletin, stabilizing crowd behavior through visible order.",
   T("Canal-side rumor containment presence after an incident bulletin, stabilizing crowd behavior through visible order.","yellow"),
   "Verification of shrine-licensed ceremonial shipments, ensuring listed rites match cargo declarations and timing windows.",
   T("Verification of shrine-licensed ceremonial shipments, ensuring listed rites match cargo declarations and timing windows.","yellow"),
   "Training day for boarding teams in narrow-watercraft maneuvering, canal interdiction, and non-lethal deck control."
   T("Training day for boarding teams in narrow-watercraft maneuvering, canal interdiction, and non-lethal deck control.","green")
}
}


Line 284: Line 302:
   end
   end


   return pickFromList(nextInt, pool, nil) or "Standard patrol and compliance enforcement."
   return pickFromList(nextInt, pool, nil) or T("Standard patrol and compliance enforcement.","green")
end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- 6) ASSIGNMENT MODEL (station blocks of 7–14 days)
-- 7) ASSIGNMENT MODEL (station blocks of 7–14 days)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function homeCityForCaptain(cap)
local function homeCityForCaptain(cap)
Line 329: Line 347:
   local station = stationForBlock(cap, blockIndex)
   local station = stationForBlock(cap, blockIndex)
   local nextInt = lcg(hash31(string.format("task|%s|%s|%d", cap.last or "", cap.first or "", absDay)))
   local nextInt = lcg(hash31(string.format("task|%s|%s|%d", cap.last or "", cap.first or "", absDay)))
   local task = pickTask(nextInt, station)
   local taskEntry = pickTask(nextInt, station)
 
  local text = taskEntry.text
  local sev  = taskEntry.sev or "green"


   if dayInBlock == 1 then
   if dayInBlock == 1 then
     task = "Redeployment and patrol initiation: " .. task
     text = "Redeployment and patrol initiation: " .. text
   elseif dayInBlock == blockLen then
   elseif dayInBlock == blockLen then
     task = "Handover and corridor reset: " .. task
     text = "Handover and corridor reset: " .. text
   end
   end


Line 340: Line 361:
     local tag = "%[" .. station:gsub("(%W)","%%%1") .. "%]"
     local tag = "%[" .. station:gsub("(%W)","%%%1") .. "%]"
     if eventText:match(tag) then
     if eventText:match(tag) then
       task = task .. " Festival and crowd-control augmentation in support of scheduled civic observances."
       text = text .. " Festival and crowd-control augmentation in support of scheduled civic observances."
      sev = bumpSev(sev)
     end
     end
   end
   end


   if cap.last == "Urbanus" and cap.first == "Cornelia" then
   if cap.last == "Urbanus" and cap.first == "Cornelia" then
     task = "Minister-Captain coordination: liaison with port clerks and Temple auditors; " .. task
     text = "Minister-Captain coordination: liaison with port clerks and Temple auditors; " .. text
    if sev == "green" then sev = "yellow" end
   end
   end


Line 353: Line 376:
     blockLen = blockLen,
     blockLen = blockLen,
     dayInBlock = dayInBlock,
     dayInBlock = dayInBlock,
     task = task
     task = text,
    sev = sev
   }
   }
end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- 7) OUTPUT
-- 8) OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function p.dailyReport(frame)
function p.dailyReport(frame)
Line 370: Line 394:
       y, doy = yy, dd
       y, doy = yy, dd
     end
     end
  end
  local showLegend = true
  if args.legend ~= nil then
    local v = tostring(args.legend):lower()
    showLegend = not (v == "0" or v == "no" or v == "false")
   end
   end


Line 384: Line 414:
     local a = todaysAssignment(cap, y, doy, eventText)
     local a = todaysAssignment(cap, y, doy, eventText)


    local rowStyle = sevStyle(a.sev)
     local pFlag = privateerFlag(cap.last)
     local pFlag = privateerFlag(cap.last)
     local name = privateerNameRow(cap)
     local name = privateerNameRow(cap)
Line 391: Line 422:
     local rot = string.format("%d/%d", a.dayInBlock, a.blockLen)
     local rot = string.format("%d/%d", a.dayInBlock, a.blockLen)


     table.insert(out, '|-')
     table.insert(out, "|-" .. rowStyle)
     table.insert(out, string.format('| %s || %s || %s || %s || %s || %s', pFlag, name, homeCell, stationCell, rot, a.task))
     table.insert(out, string.format('| %s || %s || %s || %s || %s || %s', pFlag, name, homeCell, stationCell, rot, a.task))
   end
   end


   table.insert(out, '|}')
   table.insert(out, "|}")
 
  if showLegend then
    table.insert(out, "\n<div style='margin-top:0.5em; font-size:90%;'>")
    table.insert(out, "<b>Legend:</b> ")
    table.insert(out, "<span style='background:#d4edda;padding:2px 6px;border:1px solid #c3e6cb;'>Green</span> = Routine / Standard &nbsp; ")
    table.insert(out, "<span style='background:#fff3cd;padding:2px 6px;border:1px solid #ffeeba;'>Yellow</span> = Elevated / Enforcement &nbsp; ")
    table.insert(out, "<span style='background:#f8d7da;padding:2px 6px;border:1px solid #f5c6cb;'>Red</span> = Urgent / High-Risk / Incident")
    table.insert(out, "</div>")
  end
 
   return table.concat(out, "\n")
   return table.concat(out, "\n")
end
end


return p
return p

Revision as of 00:25, 30 December 2025

Documentation for this module may be created at Module:HatchMinistryDailyOps/doc

-- Module:HatchMinistryDailyOps
-- Daily (PSSC-calendar keyed) ops schedule for Hatch Ministry privateers.
-- Deterministic per-day output (no math.random / no os.time seeding).
--
-- Color coding: row background reflects task urgency (Green/Yellow/Red),
-- matching the palette used in Module:StraitsDaily.

local p = {}

local cal = require('Module:BassaridianCalendar')

local DAYS_IN_YEAR = 183

--------------------------------------------------------------------------------
-- 0) COASTAL CITIES (mirrors Module:GeneralPortOperations)
--------------------------------------------------------------------------------
local cities = {
  "Aegirheim","Skýrophos","Bjornopolis","Norsolyra","Ephyra",
  "Symphonara","Delphica","Vaeringheim","Somniumpolis",
  "Keybir-Aviv","Sufriya","Jogi","Ardclach","Riddersborg"
}

local function normalizeForFlag(name)
  return (name or "")
    :gsub("[%s%-’]", "")
    :gsub("[Áá]", "A"):gsub("[Éé]", "E")
    :gsub("[Íí]", "I"):gsub("[Óó]", "O")
    :gsub("[Úú]", "U"):gsub("[Ýý]", "Y")
end

local cityFlag = {}
for _, name in ipairs(cities) do
  cityFlag[name] = string.format("[[File:%sFlag.png|20px]]", normalizeForFlag(name))
end
cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]"

local function cityLink(name)
  return string.format("[[List of cities in Bassaridia Vaeringheim#%s|%s]]", name, name)
end

--------------------------------------------------------------------------------
-- 1) ACTIVE PRIVATEERS (mirrors Module:GeneralPortOperations)
--------------------------------------------------------------------------------
local privateers = {
  {first="Arion",     last="Theron"},
  {first="Cassius",   last="Valerus"},
  {first="Nefra",     last="Sekeri",    nick="Sekhem"},
  {first="Lysander",  last="Pallas"},
  {first="Marwan",    last="Othman"},
  {first="Octavia",   last="Marcellus"},
  {first="Amenhotep", last="Ankhu"},
  {first="Thalia",    last="Chrysos"},
  {first="Demetrius", last="Gravis"},
  {first="Selim",     last="Bey"},
  {first="Julius",    last="Drusus"},
  {first="Leyla",     last="Han"},
  {first="Marcus",    last="Flavianus"},
  {first="Fatima",    last="Pasha"},
  {first="Cornelia",  last="Urbanus"}, -- Minister-Captain
  {first="Eudora",    last="Merit"},
  {first="Perseus",   last="Phoebus"},
  {first="Khepri",    last="Sobek"},
  {first="Lucius",    last="Aurelian"},
  {first="Aisha",     last="Dinar"},
  {first="Gaius",     last="Cassianus"},
  {first="Selene",    last="Argus"},
  {first="Arsinoe",   last="Menkaure"},
  {first="Omar",      last="Zahir"},
  {first="Dorian",    last="Grimm"},
  {first="Quintus",   last="Nero"},
  {first="Zainab",    last="Sultan"},
  {first="Cassian",   last="Corinth"},
  {first="Valeria",   last="Maximus",   nick="Ferox"},
  {first="Thorne",    last="Noctis",    nick="Mainomenos"}
}

local function privateerFlag(last)
  return string.format("[[File:%s.png|20px]]", last)
end

local function privateerNameRow(c)
  if c.nick then
    return string.format("Captain %s ''‘%s’'' %s", c.first, c.nick, c.last)
  end
  return string.format("Captain %s %s", c.first, c.last)
end

--------------------------------------------------------------------------------
-- 2) CALENDAR PARSING
--------------------------------------------------------------------------------
local function parseCalendarString(s)
  if type(s) ~= "string" then return nil end
  local dayOfYear, month, year = s:match("^(%d+),%s+([%a]+)%s+%b()%s*,%s*(%d+)%s+PSSC")
  if dayOfYear and year then
    return tonumber(year), tonumber(dayOfYear), month
  end
  return nil
end

local function extractEventText(s)
  if type(s) ~= "string" then return "" end
  local ev = s:match("PSSC%s+–%s+(.-)%s+–%s+Proverb:")
  return ev or ""
end

local function getCurrentYDOY()
  local s = cal.getCurrentDate()
  local y, doy, month = parseCalendarString(s)
  if not y or not doy then
    y, doy, month = 0, 1, ""
    s = tostring(s or "")
  end
  return y, doy, month, s, extractEventText(s)
end

--------------------------------------------------------------------------------
-- 3) DETERMINISTIC HASH + RNG (NO bit32)
--------------------------------------------------------------------------------
local function hash31(str)
  local h = 0
  for i = 1, #str do
    h = (h * 131 + str:byte(i)) % 2147483647
  end
  return h
end

local function lcg(seed)
  local s = seed % 2147483647
  if s <= 0 then s = s + 2147483646 end
  return function()
    s = (1103515245 * s + 12345) % 2147483647
    return s
  end
end

local function rand01(nextInt)
  return nextInt() / 2147483647
end

local function pickFromList(nextInt, list, avoidValue)
  if #list == 0 then return nil end
  if #list == 1 then return list[1] end
  local tries = 0
  while tries < 12 do
    local idx = (nextInt() % #list) + 1
    local v = list[idx]
    if v ~= avoidValue then return v end
    tries = tries + 1
  end
  for _, v in ipairs(list) do
    if v ~= avoidValue then return v end
  end
  return list[1]
end

--------------------------------------------------------------------------------
-- 4) REGIONAL CLUSTERS (bias “near home”)
--------------------------------------------------------------------------------
local clusters = {
  North   = {"Aegirheim","Bjornopolis","Norsolyra","Ephyra","Ardclach","Riddersborg"},
  Central = {"Symphonara","Delphica","Vaeringheim","Somniumpolis"},
  South   = {"Keybir-Aviv","Sufriya","Jogi"},
  Jangsong= {"Skýrophos","Jogi","Ardclach","Riddersborg"}
}

local function clusterForCity(city)
  for cname, list in pairs(clusters) do
    for _, v in ipairs(list) do
      if v == city then return cname end
    end
  end
  return "Central"
end

--------------------------------------------------------------------------------
-- 5) COLOR CODING (same palette logic used in StraitsDaily)
--------------------------------------------------------------------------------
local function sevStyle(sev)
  if sev == "red" then
    return ' style="background-color:#f8d7da;"'
  elseif sev == "yellow" then
    return ' style="background-color:#fff3cd;"'
  else
    return ' style="background-color:#d4edda;"'
  end
end

local function bumpSev(sev)
  if sev == "green" then return "yellow" end
  if sev == "yellow" then return "red" end
  return "red"
end

--------------------------------------------------------------------------------
-- 6) TASK LIBRARY (20 per pool; each task has an urgency tier)
--------------------------------------------------------------------------------
local function T(text, sev) return {text=text, sev=sev} end

local tasks_general = {
  T("Convoy escort and corridor clearing for registered merchant traffic, enforcing registry sequence and predictable passage.","green"),
  T("VBSS surge and manifest verification, with heightened scrutiny for cargo mislabeling, forged papers, and transshipment laundering.","yellow"),
  T("Interdiction patrol against small-craft logistics supporting anti-corridor insurgent networks, with evidence handling and detainee processing discipline.","yellow"),
  T("Lane assurance work in the approaches and harbor margins, including buoy checks, beacon verification, and channel safety enforcement.","green"),
  T("Counter-smuggling sweep focused on contraband arms, unregistered ritual cargo, and false-cleared Temple consignments.","yellow"),
  T("Rapid-response security support to local authorities for port unrest, quarantine enforcement, and rumor-driven crowd surges.","red"),
  T("Search-and-rescue readiness patrol with debris clearance coordination and temporary berth control during incidents.","red"),
  T("Liaison rotation with Temple and civic screening teams for morale discipline, rumor containment, and compliance reinforcement.","yellow"),
  T("Night interception detail targeting unlit runners and coastal-shadowing craft attempting to bypass inspection windows.","yellow"),
  T("Port-entry queue control and traffic metering to prevent berth chaos, including stand-off enforcement for noncompliant hulls.","green"),
  T("Evidence convoy to a War League intake point, transporting seized cargo under chain-of-custody doctrine.","yellow"),
  T("Inspection of fishery convoys and cold-chain cargo for hidden compartments, false ice loads, and counterfeit seals.","yellow"),
  T("Anti-piracy deterrence sweep against unaffiliated raiders operating outside the registry, with warning demonstrations and capture mandates.","yellow"),
  T("Boarding-team readiness cycle and small-arms drill day, with emphasis on non-lethal deck control and restraint discipline.","green"),
  T("Escort for diplomatic or Temple couriers transiting the corridor, with counter-ambush screening at chokepoints.","yellow"),
  T("Counterfeit voucher and registry-stamp crackdown, coordinating with port clerks to identify forged paperwork patterns.","yellow"),
  T("Harbor-mouth overwatch with spotters to track suspicious loitering and false distress signaling near approach lanes.","green"),
  T("Quarantine cordon support for a suspected outbreak vessel, enforcing isolation lanes and controlled disembarkation sequencing.","red"),
  T("Canal approach patrol to prevent sabotage against locks, piers, and water infrastructure serving major quay districts.","red"),
  T("Training cruise with junior crews to certify boarding compliance, medical triage procedure, and detainee handling standards.","green")
}

local tasks_north = {
  T("Cold-water frontier patrol emphasizing raider deterrence, route denial, and winter-route landing site reconnaissance.","yellow"),
  T("Joint boarding drills and seizure-readiness for difficult-weather VBSS operations near northern chokepoints.","green"),
  T("Coastal reconnaissance for hidden coves, improvised piers, and suspected insurgent resupply anchorages.","yellow"),
  T("Ice-margin escort for timber and ore traffic, enforcing safe-lane passage through fog and drift hazards.","green"),
  T("Night watch against ghost-ship imitation tactics, verifying hull identity and rejecting falsified light codes.","yellow"),
  T("Shoreline sweep for signal cairns and illicit beacon fires used to guide runners into protected inlets.","yellow"),
  T("Interdiction of smugglers using river-mouth approaches to bypass port control, with shallow-draft pursuit elements.","yellow"),
  T("Storm-surge response patrol supporting stranded craft, hauling wreckage clear and securing debris fields.","red"),
  T("Border-proximity deterrence demonstration near contested approaches, emphasizing corridor sovereignty by presence.","yellow"),
  T("Winter-route courier interception, targeting clandestine messages and route-maps carried by sled-ship tenders.","yellow"),
  T("Harbor freeze management patrol, coordinating icebreaking assistance and preventing dock congestion escalation.","red"),
  T("Recon of abandoned fortlets and cliff ladders used as clandestine landing infrastructure during past campaigns.","yellow"),
  T("Counter-insurgent sweep for hidden fuel caches, rope ladders, and cliff-staged supply bundles along rugged coasts.","yellow"),
  T("Escort for refugee or evacuation flotillas under strict sequencing, preventing infiltration by hostile agents.","red"),
  T("Mine-scare verification patrol, conducting lane checks after rumor events to restore merchant confidence.","red"),
  T("Long-range patrol to discourage unaffiliated privateer predation in the far approaches, enforcing registry legitimacy.","yellow"),
  T("Cooperation drill with local militia garrisons, practicing shore-to-ship handover for detainees and seized cargo.","green"),
  T("Watch for cult-linked winter rites that trigger crowd movement to the waterfront, providing calm enforcement presence.","yellow"),
  T("Signal interception and direction-finding patrol to locate clandestine transmitters along ridge or lighthouse ruins.","yellow"),
  T("Post-incident audit run, rechecking logs and witness statements after a northern skirmish to prevent rumor spirals.","yellow")
}

local tasks_south = {
  T("Southern straits checkpoint enforcement with ro-ro ramp inspections and explosive-risk screening of container traffic.","red"),
  T("Interdiction of fast skiffs and disguised cargo dhows, prioritizing weapons leakage and clandestine courier movement.","yellow"),
  T("Escort for high-value shipments transiting the southern corridor under strict queue and inspection timing.","yellow"),
  T("Harbor perimeter patrol to prevent diver sabotage and underwater placement of charges near pylons and ramps.","red"),
  T("Container seal audit and weigh-station verification to catch false tare weights, decoy loads, and swapped manifests.","yellow"),
  T("Crowd-control augmentation during market surges, keeping inspection lanes clear and preventing quay-side crush incidents.","red"),
  T("Escort of fuel barges and repair tenders supporting corridor craft, with anti-ambush screen along shallow approaches.","yellow"),
  T("Contraband sweep for dream-lure substances moving through coastal markets, enforcing seizure doctrine.","yellow"),
  T("Anti-bribery integrity patrol, rotating boarding teams and recording interactions to deter corrupt gatekeeping.","yellow"),
  T("Recon of mangrove or reed margins used for low-visibility transfers, with shallow pursuit and night optics.","yellow"),
  T("VBSS focus on ro-ro decks and vehicle bays, inspecting hidden compartments, false bulkheads, and modified ramps.","yellow"),
  T("Disruption of staged distress calls used to pull patrols off-lane, verifying authenticity before committing assets.","yellow"),
  T("Escort of pilgrim or festival traffic through the southern corridor, enforcing timed windows and calm procedure.","yellow"),
  T("Coastal deterrence posture near known runner routes, signaling denial without escalation to open combat.","yellow"),
  T("Port-rail interface security support, screening containers that transfer directly from quay to inland corridors.","yellow"),
  T("Undercover observation run in nearshore traffic, tracking suspected broker craft coordinating smuggling rendezvous.","yellow"),
  T("EOD stand-by and cordon enforcement after discovery of suspect packages at ramps or quayside warehouses.","red"),
  T("Inspection of refrigerated cargo for false panels and hidden stowaways, coordinating safe medical screening.","yellow"),
  T("Short-notice escort requested by port authorities after a threat bulletin, maintaining corridor credibility by response speed.","red"),
  T("Post-seizure handling and auction transfer escort, moving confiscated goods to authorized holdings under paperwork discipline.","yellow")
}

local tasks_central = {
  T("Canal and harbor security rotation supporting administrative traffic and registry enforcement near central corridor hubs.","green"),
  T("Inspection coordination with port clerks and Temple auditors to reduce queue-time without relaxing compliance standards.","yellow"),
  T("Ritual cargo verification support with enforcement of pre-clearance doctrine and holding protocols.","yellow"),
  T("Canal-lock security sweep to deter sabotage of gates, chains, and control houses serving high-traffic waterways.","red"),
  T("Escort for administrative barges and registry couriers moving between major quays and oversight offices.","green"),
  T("Dockside patrol targeting petty theft rings and counterfeit stamp sellers preying on merchant queues.","yellow"),
  T("Controlled berth allocation support during peak arrivals, enforcing order of entry and preventing berth disputes.","green"),
  T("Liaison patrol with Temple Bank clerks for high-value transfers, verifying seals and escorting to secure vault quays.","yellow"),
  T("Canal bridge and tunnel perimeter check, preventing illicit transfers from underpasses into restricted wharf zones.","yellow"),
  T("Rapid-response run to a canal incident, establishing cordons, clearing debris, and restoring navigation sequencing.","red"),
  T("Inspection of passenger ferries and canal shuttles for clandestine couriers, false identities, and concealed satchels.","yellow"),
  T("Citywatch coordination day, aligning waterfront patrol routes with civic policing to prevent gaps and overlaps.","green"),
  T("Harbor-mouth overwatch with spotters to identify loitering craft attempting to time entries between inspection rotations.","green"),
  T("Detainee transfer and intake coordination to a designated holding site, emphasizing calm procedure and record integrity.","yellow"),
  T("Compliance education pass, issuing warnings and standard notices to repeat offenders before escalatory seizure.","green"),
  T("Audit of registry anomalies flagged by clerks, conducting targeted re-boards of vessels with inconsistent logs.","yellow"),
  T("Escort for repair barges and dredging crews, maintaining safety perimeters while channel work proceeds.","yellow"),
  T("Canal-side rumor containment presence after an incident bulletin, stabilizing crowd behavior through visible order.","yellow"),
  T("Verification of shrine-licensed ceremonial shipments, ensuring listed rites match cargo declarations and timing windows.","yellow"),
  T("Training day for boarding teams in narrow-watercraft maneuvering, canal interdiction, and non-lethal deck control.","green")
}

local function pickTask(nextInt, station)
  local pool = {}
  for _, t in ipairs(tasks_general) do table.insert(pool, t) end

  local cl = clusterForCity(station)
  if cl == "North" or cl == "Jangsong" then
    for _, t in ipairs(tasks_north) do table.insert(pool, t) end
  elseif cl == "South" then
    for _, t in ipairs(tasks_south) do table.insert(pool, t) end
  else
    for _, t in ipairs(tasks_central) do table.insert(pool, t) end
  end

  return pickFromList(nextInt, pool, nil) or T("Standard patrol and compliance enforcement.","green")
end

--------------------------------------------------------------------------------
-- 7) ASSIGNMENT MODEL (station blocks of 7–14 days)
--------------------------------------------------------------------------------
local function homeCityForCaptain(cap)
  local key = (cap.last or "") .. "|" .. (cap.first or "")
  local idx = (hash31(key) % #cities) + 1
  return cities[idx]
end

local function blockLenForCaptain(cap)
  local key = "len|" .. (cap.last or "") .. "|" .. (cap.first or "")
  return 7 + (hash31(key) % 8) -- 7..14
end

local function stationForBlock(cap, blockIndex)
  local key = string.format("station|%s|%s|%d", cap.last or "", cap.first or "", blockIndex)
  local nextInt = lcg(hash31(key))

  local home = homeCityForCaptain(cap)
  local cl = clusterForCity(home)
  local localList = clusters[cl] or clusters.Central

  local r = rand01(nextInt)
  if r < 0.65 then
    return home
  elseif r < 0.92 then
    return pickFromList(nextInt, localList, home) or home
  else
    return pickFromList(nextInt, cities, home) or home
  end
end

local function todaysAssignment(cap, year, dayOfYear, eventText)
  local absDay = year * DAYS_IN_YEAR + dayOfYear

  local blockLen = blockLenForCaptain(cap)
  local offset = hash31("off|" .. (cap.last or "") .. "|" .. (cap.first or "")) % blockLen
  local blockIndex = math.floor((absDay + offset) / blockLen)
  local dayInBlock = ((absDay + offset) % blockLen) + 1

  local station = stationForBlock(cap, blockIndex)
  local nextInt = lcg(hash31(string.format("task|%s|%s|%d", cap.last or "", cap.first or "", absDay)))
  local taskEntry = pickTask(nextInt, station)

  local text = taskEntry.text
  local sev  = taskEntry.sev or "green"

  if dayInBlock == 1 then
    text = "Redeployment and patrol initiation: " .. text
  elseif dayInBlock == blockLen then
    text = "Handover and corridor reset: " .. text
  end

  if eventText and eventText ~= "" then
    local tag = "%[" .. station:gsub("(%W)","%%%1") .. "%]"
    if eventText:match(tag) then
      text = text .. " Festival and crowd-control augmentation in support of scheduled civic observances."
      sev = bumpSev(sev)
    end
  end

  if cap.last == "Urbanus" and cap.first == "Cornelia" then
    text = "Minister-Captain coordination: liaison with port clerks and Temple auditors; " .. text
    if sev == "green" then sev = "yellow" end
  end

  return {
    home = homeCityForCaptain(cap),
    station = station,
    blockLen = blockLen,
    dayInBlock = dayInBlock,
    task = text,
    sev = sev
  }
end

--------------------------------------------------------------------------------
-- 8) OUTPUT
--------------------------------------------------------------------------------
function p.dailyReport(frame)
  local args = (frame and frame.args) or {}
  local y, doy, month, calStr, eventText = getCurrentYDOY()

  if args.year and args.day then
    local yy = tonumber(args.year)
    local dd = tonumber(args.day)
    if yy and dd and dd >= 1 and dd <= DAYS_IN_YEAR then
      y, doy = yy, dd
    end
  end

  local showLegend = true
  if args.legend ~= nil then
    local v = tostring(args.legend):lower()
    showLegend = not (v == "0" or v == "no" or v == "false")
  end

  local out = {}
  table.insert(out, string.format("'''Hatch Ministry Daily Operations – Day %d, Year %d PSSC'''", doy, y))
  if calStr and calStr ~= "" then
    table.insert(out, "''Calendar:'' " .. calStr)
  end

  table.insert(out, '{| class="wikitable sortable"')
  table.insert(out, '! Privateer Flag !! Captain !! Home City !! Current Station !! Rotation !! Today\'s Activity')

  for _, cap in ipairs(privateers) do
    local a = todaysAssignment(cap, y, doy, eventText)

    local rowStyle = sevStyle(a.sev)
    local pFlag = privateerFlag(cap.last)
    local name = privateerNameRow(cap)

    local homeCell = (cityFlag[a.home] or "") .. " " .. cityLink(a.home)
    local stationCell = (cityFlag[a.station] or "") .. " " .. cityLink(a.station)
    local rot = string.format("%d/%d", a.dayInBlock, a.blockLen)

    table.insert(out, "|-" .. rowStyle)
    table.insert(out, string.format('| %s || %s || %s || %s || %s || %s', pFlag, name, homeCell, stationCell, rot, a.task))
  end

  table.insert(out, "|}")

  if showLegend then
    table.insert(out, "\n<div style='margin-top:0.5em; font-size:90%;'>")
    table.insert(out, "<b>Legend:</b> ")
    table.insert(out, "<span style='background:#d4edda;padding:2px 6px;border:1px solid #c3e6cb;'>Green</span> = Routine / Standard &nbsp; ")
    table.insert(out, "<span style='background:#fff3cd;padding:2px 6px;border:1px solid #ffeeba;'>Yellow</span> = Elevated / Enforcement &nbsp; ")
    table.insert(out, "<span style='background:#f8d7da;padding:2px 6px;border:1px solid #f5c6cb;'>Red</span> = Urgent / High-Risk / Incident")
    table.insert(out, "</div>")
  end

  return table.concat(out, "\n")
end

return p