Module:StraitsDaily: Difference between revisions
From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs) No edit summary |
NewZimiaGov (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
-- Module: StraitsDaily | -- Module: StraitsDaily | ||
-- Purpose: Daily, in-world report of Strait of Haifa enforcement | -- Purpose: Daily, in-world report of Strait of Haifa enforcement | ||
| Line 40: | Line 39: | ||
} | } | ||
local flags = { | local flags = { | ||
{name="Bassaridian-flag", weight=6, risky=false}, | {name="Bassaridian-flag", weight=6, risky=false}, | ||
{name="Moorland", weight=2, risky=false}, | {name="Moorland", weight=2, risky=false}, | ||
{name="Imperial Federation", weight=5, risky=true}, | {name="Imperial Federation", weight=5, risky=true}, | ||
{name="Matamoros (IF)", weight=2, risky=true}, | {name="Matamoros (IF)", weight=2, risky=true}, | ||
{name="Neutral Merchant", weight=4, risky=false}, | {name="Neutral Merchant", weight=4, risky=false}, | ||
{name="Distant Partner (Euranidom)", weight=3, risky=true}, | {name="Distant Partner (Euranidom)", weight=3, risky=true}, | ||
| Line 51: | Line 49: | ||
{name="Distant Partner (Southern Keltiania)", weight=3, risky=true}, | {name="Distant Partner (Southern Keltiania)", weight=3, risky=true}, | ||
{name="Consortium Registry", weight=2, risky=true}, | {name="Consortium Registry", weight=2, risky=true}, | ||
{name="Other Coastal State", weight=7, risky=false} | {name="Other Coastal State", weight=7, risky=false} | ||
} | } | ||
| Line 59: | Line 57: | ||
} | } | ||
local cargoTypes = { | local cargoTypes = { | ||
{name="Medical reagents (dual-use precursors)", weight=3, risk=0.14, dual=true}, | {name="Medical reagents (dual-use precursors)", weight=3, risk=0.14, dual=true}, | ||
| Line 66: | Line 63: | ||
{name="Encrypted electronics & comms modules (dual-use)",weight=2, risk=0.17, dual=true}, | {name="Encrypted electronics & comms modules (dual-use)",weight=2, risk=0.17, dual=true}, | ||
{name="Satellite components / sensors (dual-use)", weight=1, risk=0.18, dual=true}, | {name="Satellite components / sensors (dual-use)", weight=1, risk=0.18, dual=true}, | ||
{name="Aviation fuels & additives", | {name="Industrial fasteners (coded)", weight=2, risk=0.12, dual=true}, | ||
{name="Refined petroleum products", | {name="Hydraulic lubricants (dual-use)", weight=2, risk=0.13, dual=true}, | ||
{name="Relief supplies (mixed pallets)", | {name="High-frequency alloys (coded)", weight=1, risk=0.14, dual=true}, | ||
{name="Agricultural commodities", | {name="Aviation fuels & additives", weight=3, risk=0.12, dual=false}, | ||
{name="Finished consumer goods", | {name="Refined petroleum products", weight=4, risk=0.08, dual=false}, | ||
{name="Relief supplies (mixed pallets)", weight=5, risk=0.06, dual=false}, | |||
{name="Agricultural commodities", weight=5, risk=0.04, dual=false}, | |||
{name="Finished consumer goods", weight=6, risk=0.03, dual=false} | |||
} | } | ||
local cargoTags = { | local cargoTags = { | ||
{name="standard", weight=6, risk=0.00}, | {name="standard", weight=6, risk=0.00}, | ||
{name="expedited", weight=3, risk=0.05}, | {name="expedited", weight=3, risk=0.05}, | ||
{name="emergency", weight=2, risk=0.07} | {name="emergency", weight=2, risk=0.07}, | ||
{name="perishable", weight=2, risk=0.06} | |||
} | } | ||
local partnerProfiles = { | local partnerProfiles = { | ||
{code="P-07", weight=4, risk=0.00}, | {code="P-07", weight=4, risk=0.00}, | ||
{code="P-12", weight=3, risk=0.03}, | {code="P-12", weight=3, risk=0.03}, | ||
{code="P-17", weight= | {code="P-17", weight=3, risk=0.12}, | ||
{code="P-22", weight= | {code="P-22", weight=3, risk=0.14}, | ||
{code="P-31", weight=3, risk=0.05}, | {code="P-31", weight=3, risk=0.05}, | ||
{code="P-38", weight=2, risk=0.10}, | {code="P-38", weight=2, risk=0.10}, | ||
{code="P-44", weight=4, risk=0.02}, | {code="P-44", weight=4, risk=0.02}, | ||
{code="P-53", weight=3, risk=0.04} | {code="P-53", weight=3, risk=0.04} | ||
} | } | ||
| Line 145: | Line 106: | ||
local function pick(list) return list[math.random(#list)] end | local function pick(list) return list[math.random(#list)] end | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- (D) ENFORCEMENT | -- (D) ENFORCEMENT LOGIC | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
local function baseProb(flag, sector, cargo, tag, partner) | local function baseProb(flag, sector, cargo, tag, partner) | ||
| Line 157: | Line 114: | ||
if flag.risky then p = p + 0.06 end | if flag.risky then p = p + 0.06 end | ||
if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then p = p + 0.08 end | if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then p = p + 0.08 end | ||
p = p + (cargo and (cargo.risk or 0) or 0) | p = p + (cargo and (cargo.risk or 0) or 0) | ||
if cargo and cargo.dual then p = p + 0.03 end | if cargo and cargo.dual then p = p + 0.03 end | ||
p = p + (tag and (tag.risk or 0) or 0) | p = p + (tag and (tag.risk or 0) or 0) | ||
p = p + (partner and (partner.risk or 0) or 0) | p = p + (partner and (partner.risk or 0) or 0) | ||
if p > 0.72 then p = 0.72 end | if p > 0.72 then p = 0.72 end | ||
return p | return p | ||
end | end | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- (E) EVENT GENERATION | -- (E) MAIN EVENT GENERATION | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
function p.makeTable(frame) | function p.makeTable(frame) | ||
| Line 296: | Line 134: | ||
table.insert(out, '! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Notes') | table.insert(out, '! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Notes') | ||
local maxPerFlag = math.max(1, math.ceil(ROWS * 0.35)) | local maxPerFlag = math.max(1, math.ceil(ROWS * 0.35)) | ||
local state = { | local state = { | ||
strongCount = 0, | strongCount = 0, strongCap = 3, flagCounts = {}, lastFlag = nil, | ||
enfCount = 0, maxPerFlag = maxPerFlag | |||
enfCount | |||
} | } | ||
local | local function makeEvent(dateText) | ||
local sector = pick(sectors) | |||
local | local flag = pickWeighted(flags) | ||
local vessel = pick(vessels) | |||
local cargo = pickWeighted(cargoTypes) | |||
local tag = pickWeighted(cargoTags) | |||
local partner = pickWeighted(partnerProfiles) | |||
local prob = baseProb(flag, sector, cargo, tag, partner) | |||
if math.random() > prob then | |||
return {date=dateText, sector=sector, vessel=vessel.." ("..flag.name..")", | |||
action="Routine transit", legal="N/A", outcome="No reports", | |||
notes="Cargo: "..cargo.name.." ["..tag.name.."]; Partner: "..partner.code.." — Compliant passage"} | |||
end | |||
local action = pickWeighted(actions) | |||
local legal = action.basis.." — "..(clauses[action.basis] or "SC §—") | |||
local outcome = pick(outcomes) | |||
local riskPush = 0 | |||
if flag.name:match("Imperial Federation") or flag.name:match("Matamoros") then riskPush = riskPush + 1 end | |||
if cargo.dual or (cargo.risk >= 0.12) then riskPush = riskPush + 1 end | |||
if tag.name ~= "standard" then riskPush = riskPush + 1 end | |||
if partner.risk >= 0.09 then riskPush = riskPush + 1 end | |||
if riskPush >= 2 and math.random() < 0.65 then | |||
local delays = { | |||
"Random audit hold; clearance pending procedural update", | |||
"Documentation harmonization hold (routine)", | |||
"Administrative notice issued; monitoring" | |||
} | |||
outcome = delays[math.random(#delays)] | |||
end | |||
if outcome:match("anchorage") or outcome:match("Denied entry") then | |||
if state.strongCount >= state.strongCap then | |||
outcome = "Administrative notice issued; monitoring" | |||
else | |||
state.strongCount = state.strongCount + 1 | |||
if | |||
end | end | ||
end | end | ||
if (flag.name == "Imperial Federation" or flag.name == "Matamoros (IF)") and | |||
(outcome:match("audit hold") or outcome:match("harmonization")) then | |||
outcome = outcome .. " [Extended regulatory review]" | |||
end | |||
state.enfCount = state.enfCount + 1 | |||
local note = "Cargo: "..cargo.name.." ["..tag.name.."]; Partner: "..partner.code | |||
return {date=dateText, sector=sector, vessel=vessel.." ("..flag.name..")", | |||
action=action.name, legal=legal, outcome=outcome, notes=note} | |||
end | end | ||
for | for i=1, ROWS do | ||
local ev = makeEvent(dateInfo.text) | |||
table.insert(out, "|-") | table.insert(out, "|-") | ||
table.insert(out, "| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes) | table.insert(out, "| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes) | ||
| Line 338: | Line 201: | ||
table.insert(out, '|}') | table.insert(out, '|}') | ||
table.insert(out, '<!-- StraitsDaily | table.insert(out, '<!-- StraitsDaily v5.0: Shelf-life tags, military-adjacent profiling, enhanced IF/Matamoros visibility -->') | ||
return table.concat(out, "\n") | return table.concat(out, "\n") | ||
end | end | ||
return p | return p | ||
Revision as of 16:48, 6 September 2025
Documentation for this module may be created at Module:StraitsDaily/doc
-- Module: StraitsDaily
-- Purpose: Daily, in-world report of Strait of Haifa enforcement
local p = {}
-------------------------------------------------------------------------------
-- (A) PSSC DATE
-------------------------------------------------------------------------------
local function getPSSCDate()
local startDate = os.time({year = 1999, month = 8, day = 6})
local secondsInDay = 86400
local daysPerYear = 183
local now = os.time()
local totalDaysElapsed = math.floor((now - startDate) / secondsInDay)
local yearFraction = totalDaysElapsed / daysPerYear
local psscYear = math.floor(yearFraction)
local dayOfYear = math.floor((yearFraction - psscYear) * daysPerYear) + 1
local month, dayOfMonth
if dayOfYear <= 61 then
month = 1; dayOfMonth = dayOfYear
elseif dayOfYear <= 122 then
month = 2; dayOfMonth = dayOfYear - 61
else
month = 3; dayOfMonth = dayOfYear - 122
end
local dateString = string.format("%d/%d/%d PSSC", dayOfMonth, month, psscYear)
return { text = dateString, year = psscYear, dayOfYear = dayOfYear }
end
-------------------------------------------------------------------------------
-- (B) STATIC DATA
-------------------------------------------------------------------------------
local sectors = {
"Strait South Inbound","Strait South Outbound","Strait North Inbound","Strait North Outbound",
"Archipelago Zone","Sacred Buffer Approaches","Environmental Buffer","Northern Approach TSS","Southern Approach TSS"
}
local flags = {
{name="Bassaridian-flag", weight=6, risky=false},
{name="Moorland", weight=2, risky=false},
{name="Imperial Federation", weight=5, risky=true},
{name="Matamoros (IF)", weight=2, risky=true},
{name="Neutral Merchant", weight=4, risky=false},
{name="Distant Partner (Euranidom)", weight=3, risky=true},
{name="Distant Partner (Corumia)", weight=3, risky=true},
{name="Distant Partner (Southern Keltiania)", weight=3, risky=true},
{name="Consortium Registry", weight=2, risky=true},
{name="Other Coastal State", weight=7, risky=false}
}
local vessels = {
"Handymax bulker","Product tanker","General cargo ship","Container feeder",
"Ro-Ro ferry","Research craft","Declared submarine","Undeclared submarine"
}
local cargoTypes = {
{name="Medical reagents (dual-use precursors)", weight=3, risk=0.14, dual=true},
{name="Industrial oxidizers / nitrates (dual-use)", weight=2, risk=0.16, dual=true},
{name="Precision machine tools & CNC spares (dual-use)", weight=3, risk=0.15, dual=true},
{name="Encrypted electronics & comms modules (dual-use)",weight=2, risk=0.17, dual=true},
{name="Satellite components / sensors (dual-use)", weight=1, risk=0.18, dual=true},
{name="Industrial fasteners (coded)", weight=2, risk=0.12, dual=true},
{name="Hydraulic lubricants (dual-use)", weight=2, risk=0.13, dual=true},
{name="High-frequency alloys (coded)", weight=1, risk=0.14, dual=true},
{name="Aviation fuels & additives", weight=3, risk=0.12, dual=false},
{name="Refined petroleum products", weight=4, risk=0.08, dual=false},
{name="Relief supplies (mixed pallets)", weight=5, risk=0.06, dual=false},
{name="Agricultural commodities", weight=5, risk=0.04, dual=false},
{name="Finished consumer goods", weight=6, risk=0.03, dual=false}
}
local cargoTags = {
{name="standard", weight=6, risk=0.00},
{name="expedited", weight=3, risk=0.05},
{name="emergency", weight=2, risk=0.07},
{name="perishable", weight=2, risk=0.06}
}
local partnerProfiles = {
{code="P-07", weight=4, risk=0.00},
{code="P-12", weight=3, risk=0.03},
{code="P-17", weight=3, risk=0.12},
{code="P-22", weight=3, risk=0.14},
{code="P-31", weight=3, risk=0.05},
{code="P-38", weight=2, risk=0.10},
{code="P-44", weight=4, risk=0.02},
{code="P-53", weight=3, risk=0.04}
}
-------------------------------------------------------------------------------
-- (C) UTILITIES
-------------------------------------------------------------------------------
local function pickWeighted(list)
local total=0
for _,item in ipairs(list) do total=total+(item.weight or 1) end
local roll,cumul=math.random(total),0
for _,item in ipairs(list) do
cumul=cumul+(item.weight or 1)
if roll<=cumul then return item end
end
return list[#list]
end
local function pick(list) return list[math.random(#list)] end
-------------------------------------------------------------------------------
-- (D) ENFORCEMENT LOGIC
-------------------------------------------------------------------------------
local function baseProb(flag, sector, cargo, tag, partner)
local p = 0.28
if flag.risky then p = p + 0.06 end
if sector=="Sacred Buffer Approaches" or sector=="Environmental Buffer" then p = p + 0.08 end
p = p + (cargo and (cargo.risk or 0) or 0)
if cargo and cargo.dual then p = p + 0.03 end
p = p + (tag and (tag.risk or 0) or 0)
p = p + (partner and (partner.risk or 0) or 0)
if p > 0.72 then p = 0.72 end
return p
end
-------------------------------------------------------------------------------
-- (E) MAIN EVENT GENERATION
-------------------------------------------------------------------------------
function p.makeTable(frame)
local dateInfo = getPSSCDate()
math.randomseed(dateInfo.year*1000 + dateInfo.dayOfYear)
local ROWS = tonumber(frame and frame.args and frame.args.rows) or 18
local out = {}
table.insert(out, '{| class="wikitable sortable"')
table.insert(out, '! Date !! Sector !! Vessel/Flag !! Action !! Legal Basis !! Outcome !! Notes')
local maxPerFlag = math.max(1, math.ceil(ROWS * 0.35))
local state = {
strongCount = 0, strongCap = 3, flagCounts = {}, lastFlag = nil,
enfCount = 0, maxPerFlag = maxPerFlag
}
local function makeEvent(dateText)
local sector = pick(sectors)
local flag = pickWeighted(flags)
local vessel = pick(vessels)
local cargo = pickWeighted(cargoTypes)
local tag = pickWeighted(cargoTags)
local partner = pickWeighted(partnerProfiles)
local prob = baseProb(flag, sector, cargo, tag, partner)
if math.random() > prob then
return {date=dateText, sector=sector, vessel=vessel.." ("..flag.name..")",
action="Routine transit", legal="N/A", outcome="No reports",
notes="Cargo: "..cargo.name.." ["..tag.name.."]; Partner: "..partner.code.." — Compliant passage"}
end
local action = pickWeighted(actions)
local legal = action.basis.." — "..(clauses[action.basis] or "SC §—")
local outcome = pick(outcomes)
local riskPush = 0
if flag.name:match("Imperial Federation") or flag.name:match("Matamoros") then riskPush = riskPush + 1 end
if cargo.dual or (cargo.risk >= 0.12) then riskPush = riskPush + 1 end
if tag.name ~= "standard" then riskPush = riskPush + 1 end
if partner.risk >= 0.09 then riskPush = riskPush + 1 end
if riskPush >= 2 and math.random() < 0.65 then
local delays = {
"Random audit hold; clearance pending procedural update",
"Documentation harmonization hold (routine)",
"Administrative notice issued; monitoring"
}
outcome = delays[math.random(#delays)]
end
if outcome:match("anchorage") or outcome:match("Denied entry") then
if state.strongCount >= state.strongCap then
outcome = "Administrative notice issued; monitoring"
else
state.strongCount = state.strongCount + 1
end
end
if (flag.name == "Imperial Federation" or flag.name == "Matamoros (IF)") and
(outcome:match("audit hold") or outcome:match("harmonization")) then
outcome = outcome .. " [Extended regulatory review]"
end
state.enfCount = state.enfCount + 1
local note = "Cargo: "..cargo.name.." ["..tag.name.."]; Partner: "..partner.code
return {date=dateText, sector=sector, vessel=vessel.." ("..flag.name..")",
action=action.name, legal=legal, outcome=outcome, notes=note}
end
for i=1, ROWS do
local ev = makeEvent(dateInfo.text)
table.insert(out, "|-")
table.insert(out, "| "..ev.date.." || "..ev.sector.." || "..ev.vessel.." || "..ev.action.." || "..ev.legal.." || "..ev.outcome.." || "..ev.notes)
end
table.insert(out, '|}')
table.insert(out, '<!-- StraitsDaily v5.0: Shelf-life tags, military-adjacent profiling, enhanced IF/Matamoros visibility -->')
return table.concat(out, "\n")
end
return p