Module:GeneralPortOperations: Difference between revisions
From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs) No edit summary |
NewZimiaGov (talk | contribs) No edit summary |
||
| Line 7: | Line 7: | ||
-- 0) Daily tonnage cap | -- 0) Daily tonnage cap | ||
local MAX_DAILY_TONNAGE = 1359348.096 | local MAX_DAILY_TONNAGE = 1359348.096 | ||
-- 1) Date logic | -- 1) Date logic | ||
| Line 159: | Line 50: | ||
-- override for Skýrophos | -- override for Skýrophos | ||
cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]" | cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]" | ||
-- 3b) Region mapping for the fixed home-city set | |||
local cityRegion = { | |||
["Aegirheim"] = "New South Jangsong", | |||
["Skýrophos"] = "New South Jangsong", | |||
["Bjornopolis"] = "New South Jangsong", | |||
["Norsolyra"] = "New South Jangsong", | |||
["Ephyra"] = "New South Jangsong", | |||
["Symphonara"] = "Core", | |||
["Delphica"] = "Core", | |||
["Vaeringheim"] = "Core", | |||
["Somniumpolis"] = "Core", | |||
["Keybir-Aviv"] = "Haifan Bassaridia", | |||
["Sufriya"] = "Haifan Bassaridia", | |||
["Jogi"] = "Haifan Bassaridia", | |||
["Ardclach"] = "Bassaridian Normark", | |||
["Riddersborg"] = "Bassaridian Normark", | |||
} | |||
-- 4) Vessel & cargo types | -- 4) Vessel & cargo types | ||
| Line 212: | Line 121: | ||
"Trans-Rodinian Granite Agency", "Amber Ports of Slevik", "Thesean Iron Exports", | "Trans-Rodinian Granite Agency", "Amber Ports of Slevik", "Thesean Iron Exports", | ||
"Fanghorn Highland Gas Company","Gadial Oil", | "Fanghorn Highland Gas Company","Gadial Oil", | ||
} | } | ||
local serviceCompanies = { | local serviceCompanies = { | ||
"Ergonian Spy Agency", | "Ergonian Spy Agency", | ||
"Temple Bank of the Reformed Stripping Path", | "Temple Bank of the Reformed Stripping Path", | ||
| Line 231: | Line 138: | ||
"Sårensby Depot*", | "Sårensby Depot*", | ||
} | } | ||
-- ─── Restrict which cargo‐companies can appear ──────────────────────────────────── | -- ─── Restrict which cargo‐companies can appear ──────────────────────────────────── | ||
local privateerCompanies = { | local privateerCompanies = { | ||
"Lake Morovia Blockade Fund", | "Lake Morovia Blockade Fund", | ||
"Baratar Corporation", | "Baratar Corporation", | ||
} | } | ||
local hatchMinistryCompanies = { | local hatchMinistryCompanies = { | ||
"Hatch Ministry" | "Hatch Ministry" | ||
} | |||
-- 5b) Company classification + single-region manifest metadata | |||
local companyMeta = { | |||
-- Agriculture | |||
["Gladeseed Farmers' Union"] = {class="Agricultural", subtype="grain", region="Core"}, | |||
["Atterian Cattle Drivers"] = {class="Agricultural", subtype="livestock", region="New South Jangsong"}, | |||
["Jogiani Merchants of Manwine"] = {class="Agricultural", subtype="wine_spirits", region="Haifan Bassaridia"}, | |||
["Keepers of the Grove of Zoe Elm"] = {class="Agricultural", subtype="forest_products", region="Core"}, | |||
["Plains of Jogi"] = {class="Agricultural", subtype="grain", region="Haifan Bassaridia"}, | |||
["Ale of the Night Central Brewery"] = {class="Agricultural", subtype="wine_spirits", region="Core"}, | |||
["Camel Herders of the Jangsong Province"] = {class="Agricultural", subtype="livestock", region="New South Jangsong"}, | |||
["Anterran Imports and Services"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"}, | |||
["Merchant Guild of the Poppy Goddess"] = {class="Agricultural", subtype="herbs", region="Core"}, | |||
["Grand Cave Bee Meadery"] = {class="Agricultural", subtype="mead_spirits", region="Core"}, | |||
["Cinammon Plains of Rouge"] = {class="Agricultural", subtype="spices", region="Core"}, | |||
["The Velvet Company"] = {class="Agricultural", subtype="textiles_raw", region="Core"}, | |||
["Seamstresses of Rouge"] = {class="Agricultural", subtype="textiles_raw", region="Core"}, | |||
["Salurian Temple of Sacred Horehound"] = {class="Agricultural", subtype="herbs", region="Core"}, | |||
["Bulhanu Ranchers' Association"] = {class="Agricultural", subtype="livestock", region="Core"}, | |||
["Suncliff Fisheries"] = {class="Agricultural", subtype="fish", region="Core"}, | |||
["Ministers of Mistress Mugwort"] = {class="Agricultural", subtype="herbs", region="Core"}, | |||
["Blood Vineyards of the Far North"] = {class="Agricultural", subtype="wine_spirits", region="New South Jangsong"}, | |||
["Norsolyrian Wisp Rice Farmers Association"] = {class="Agricultural", subtype="grain", region="New South Jangsong"}, | |||
["Giid-Lisea Ranching Import Company"] = {class="Agricultural", subtype="livestock", region="Core"}, | |||
["Bird Keepers of Saluria"] = {class="Agricultural", subtype="animal_products", region="Core"}, | |||
["Hunters of the Giant Fanged Penguin"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"}, | |||
["Knights Castle Reindeer Herders"] = {class="Agricultural", subtype="livestock", region="Bassaridian Normark"}, | |||
["Lindley Whaling Company"] = {class="Agricultural", subtype="marine_oil", region="Bassaridian Normark"}, | |||
["Aminian Coffee Company"] = {class="Agricultural", subtype="coffee", region="Haifan Bassaridia"}, | |||
["Granadita Collective"] = {class="Agricultural", subtype="fruit", region="Haifan Bassaridia"}, | |||
["Herd Caton"] = {class="Agricultural", subtype="livestock", region="Core"}, | |||
["Wasp Hunters of the Austral Isles"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"}, | |||
["Sea Elm Southern Meadery"] = {class="Agricultural", subtype="mead_spirits", region="Core"}, | |||
["Nefel Village"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"}, | |||
["Diamonia Sugar Cooperatives"] = {class="Agricultural", subtype="sugar", region="Haifan Bassaridia"}, | |||
["Ouriana Lowlands Farmers' Association"] = {class="Agricultural", subtype="grain", region="Ouriana Province"}, | |||
["Ouriad River Fisheries Cooperative"] = {class="Agricultural", subtype="fish", region="Ouriana Province"}, | |||
["Caspazani Livestock Company"] = {class="Agricultural", subtype="livestock", region="Ouriana Province"}, | |||
["White Ruby Communes"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"}, | |||
["Fange Velvet"] = {class="Agricultural", subtype="textiles_raw", region="Bassaridian Normark"}, | |||
["Port of Corumia"] = {class="Agricultural", subtype="fish", region="Core"}, | |||
["Lamian Ward"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"}, | |||
["Sleva Farming Supplies Cooperative"] = {class="Agricultural", subtype="farm_inputs", region="Bassaridian Normark"}, | |||
["Hrimmanes Woolhorse Company"] = {class="Agricultural", subtype="livestock", region="Bassaridian Normark"}, | |||
[" King's Home Fur Trappers' Cooperative"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"}, | |||
["Caledonj Bay Fishermen’s’ Cooperatives"] = {class="Agricultural", subtype="fish", region="Bassaridian Normark"}, | |||
-- Mining / Manufacturing / Energy | |||
["Roving Wind Farm Corporation"] = {class="Mining/Manufacturing", subtype="energy", region="Core"}, | |||
["Thalassian Temple Granite Export Cooperative"] = {class="Mining/Manufacturing", subtype="stone", region="Core"}, | |||
["East Keltian Iron Company"] = {class="Mining/Manufacturing", subtype="metals", region="Core"}, | |||
["Mylecian Coal Ports"] = {class="Mining/Manufacturing", subtype="coal", region="Core"}, | |||
["Merchants of the Valley of Diamonds"] = {class="Mining/Manufacturing", subtype="gemstones", region="Haifan Bassaridia"}, | |||
["East Keltian Timber Company"] = {class="Mining/Manufacturing", subtype="timber", region="Core"}, | |||
["Onceanic Boot Company"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="Core"}, | |||
["Commune of the Garganid Apostles"] = {class="Mining/Manufacturing", subtype="stone", region="Core"}, | |||
["Shï Collective"] = {class="Mining/Manufacturing", subtype="luxury_goods", region="Core"}, | |||
["Order of the Sphinx"] = {class="Mining/Manufacturing", subtype="luxury_goods", region="Haifan Bassaridia"}, | |||
["Market Hanavusu"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="New South Jangsong"}, | |||
["Somniant Stock Fund"] = {class="Mining/Manufacturing", subtype="arms_industrial", region="Core"}, | |||
["Copper Mines of Southern Jogi"] = {class="Mining/Manufacturing", subtype="metals", region="Haifan Bassaridia"}, | |||
["Horned Bear Timber Company"] = {class="Mining/Manufacturing", subtype="timber", region="New South Jangsong"}, | |||
["Federation of North Brabipant"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="Bassaridian Normark"}, | |||
["Southern Strait Preservation Corporation"] = {class="Mining/Manufacturing", subtype="marine_materials", region="Haifan Bassaridia"}, | |||
["Eosphorus Motor Company"] = {class="Mining/Manufacturing", subtype="vehicles", region="Core"}, | |||
["Vortelin Electronics"] = {class="Mining/Manufacturing", subtype="electronics", region="Core"}, | |||
["Thyrsiad Rubber Company"] = {class="Mining/Manufacturing", subtype="rubber", region="Haifan Bassaridia"}, | |||
["Stygium Mines of Acheron"] = {class="Mining/Manufacturing", subtype="metals", region="Core"}, | |||
["Trans-Rodinian Granite Agency"] = {class="Mining/Manufacturing", subtype="stone", region="Core"}, | |||
["Amber Ports of Slevik"] = {class="Mining/Manufacturing", subtype="amber", region="Bassaridian Normark"}, | |||
["Thesean Iron Exports"] = {class="Mining/Manufacturing", subtype="metals", region="Ouriana Province"}, | |||
["Fanghorn Highland Gas Company"] = {class="Mining/Manufacturing", subtype="gas", region="Bassaridian Normark"}, | |||
["Gadial Oil"] = {class="Mining/Manufacturing", subtype="oil", region="Core"}, | |||
-- Services | |||
["Ergonian Spy Agency"] = {class="Services", subtype="intelligence", region="Core"}, | |||
["Temple Bank of the Reformed Stripping Path"] = {class="Services", subtype="finance", region="Core"}, | |||
["Temple University of Delphica"] = {class="Services", subtype="education", region="Core"}, | |||
["La Sái Ebile"] = {class="Services", subtype="commerce", region="Haifan Bassaridia"}, | |||
["Pharmacon Sect"] = {class="Services", subtype="medical", region="Core"}, | |||
["Skyrophian Security Contractors"] = {class="Services", subtype="security", region="New South Jangsong"}, | |||
["Haifadora Postal Service"] = {class="Services", subtype="courier", region="Haifan Bassaridia"}, | |||
["Fleet of Rouge Divers"] = {class="Services", subtype="marine_services", region="Core"}, | |||
["Merchant Caravans of the Candy Kingdom"] = {class="Services", subtype="logistics", region="Core"}, | |||
["Hellhound Breeders of Dragevik"] = {class="Services", subtype="animal_services", region="Bassaridian Normark"}, | |||
["Noctic Fleet"] = {class="Services", subtype="marine_services", region="Core"}, | |||
["Maritime Guild of the Cult of Maskmakers"] = {class="Services", subtype="marine_services", region="Core"}, | |||
["Couriers of the Lizard Queen"] = {class="Services", subtype="courier", region="Core"}, | |||
["Temple of Aprobelle"] = {class="Services", subtype="security", region="Core"}, | |||
["Sårensby Depot*"] = {class="Services", subtype="logistics", region="Bassaridian Normark"}, | |||
-- Special pools | |||
["Lake Morovia Blockade Fund"] = {class="Services", subtype="security", region="Core"}, | |||
["Baratar Corporation"] = {class="Mining/Manufacturing", subtype="arms_industrial", region="Haifan Bassaridia"}, | |||
["Hatch Ministry"] = {class="Services", subtype="security", region="Core"}, | |||
} | } | ||
| Line 259: | Line 261: | ||
end | end | ||
local function getCompanyMeta(name) | |||
local function pickCargoCompanies(vt, owner, ct, count) | return companyMeta[name] or {class="Unspecified", subtype="mixed", region="Core"} | ||
end | |||
local function buildPoolByClassSubtypeRegion(className, subtype, region) | |||
local base = ({ | |||
Agricultural = agriCompanies, | |||
["Mining/Manufacturing"] = miningCompanies, | |||
Services = serviceCompanies | |||
})[className] or {} | |||
local pool = {} | |||
for _, name in ipairs(base) do | |||
if name ~= "Hatch Ministry" then | |||
local isPri = false | |||
for _, pr in ipairs(privateerCompanies) do | |||
if name == pr then isPri = true break end | |||
end | |||
if not isPri then | |||
local meta = getCompanyMeta(name) | |||
if meta.class == className and meta.subtype == subtype and meta.region == region then | |||
table.insert(pool, name) | |||
end | |||
end | |||
end | |||
end | |||
return pool | |||
end | |||
local function buildGeneralPoolBySubtypeRegion(subtype, region) | |||
local pool = {} | |||
for _, name in ipairs(generalPools) do | |||
local meta = getCompanyMeta(name) | |||
if meta.subtype == subtype and meta.region == region then | |||
table.insert(pool, name) | |||
end | |||
end | |||
return pool | |||
end | |||
local function chooseManifestProfile(vt, ct) | |||
if vt == "Privateer" then | |||
return "security", "Core" | |||
elseif vt == "Military" then | |||
local subtype = randomChoice({"security","arms_industrial","medical","logistics"}) | |||
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"}) | |||
return subtype, region | |||
elseif vt == "Ritual" then | |||
local subtype = randomChoice({"finance","medical","courier","security","education","logistics"}) | |||
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark"}) | |||
return subtype, region | |||
elseif ct == "Agricultural" then | |||
local subtype = randomChoice({ | |||
"grain","livestock","wine_spirits","forest_products","herbs", | |||
"mead_spirits","spices","textiles_raw","fish","animal_products", | |||
"marine_oil","coffee","fruit","sugar","mixed_foodstuffs","farm_inputs" | |||
}) | |||
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"}) | |||
return subtype, region | |||
elseif ct == "Mining/Manufacturing" then | |||
local subtype = randomChoice({ | |||
"energy","stone","metals","coal","gemstones","timber","consumer_goods", | |||
"luxury_goods","arms_industrial","marine_materials","vehicles", | |||
"electronics","rubber","amber","gas","oil" | |||
}) | |||
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"}) | |||
return subtype, region | |||
elseif ct == "Services" then | |||
local subtype = randomChoice({ | |||
"intelligence","finance","education","commerce","medical", | |||
"security","courier","marine_services","logistics","animal_services" | |||
}) | |||
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark"}) | |||
return subtype, region | |||
else | |||
local source = randomChoice(generalPools) | |||
local meta = getCompanyMeta(source) | |||
return meta.subtype, meta.region | |||
end | |||
end | |||
local function pickCargoCompanies(vt, owner, ct, subtype, region, count) | |||
if vt == "Privateer" then | if vt == "Privateer" then | ||
return randomN(privateerCompanies, count) | return randomN(privateerCompanies, count) | ||
| Line 266: | Line 348: | ||
return randomN(hatchMinistryCompanies, count) | return randomN(hatchMinistryCompanies, count) | ||
elseif ct == "Unspecified" then | elseif ct == "Unspecified" then | ||
return randomN( | local pool = buildGeneralPoolBySubtypeRegion(subtype, region) | ||
if #pool == 0 then | |||
local fallback = {} | |||
for _, name in ipairs(generalPools) do | |||
local meta = getCompanyMeta(name) | |||
if meta.region == region then | |||
table.insert(fallback, name) | |||
end | |||
end | |||
pool = fallback | |||
end | |||
return randomN(pool, count) | |||
else | else | ||
local base = ({ | local pool = buildPoolByClassSubtypeRegion(ct, subtype, region) | ||
if #pool == 0 then | |||
local fallback = {} | |||
local base = ({ | |||
Agricultural = agriCompanies, | |||
["Mining/Manufacturing"] = miningCompanies, | |||
Services = serviceCompanies | |||
})[ct] or {} | |||
for _, name in ipairs(base) do | |||
if name ~= "Hatch Ministry" then | |||
local isPri = false | |||
for _, pr in ipairs(privateerCompanies) do | |||
if name == pr then isPri = true break end | |||
end | |||
if not isPri then | |||
local meta = getCompanyMeta(name) | |||
if meta.region == region then | |||
table.insert(fallback, name) | |||
end | |||
end | |||
end | end | ||
end | end | ||
pool = fallback | |||
end | end | ||
return randomN(pool, count) | return randomN(pool, count) | ||
| Line 378: | Line 478: | ||
addLogo("Caledonj Bay Fishermen’s’ Cooperatives","CaledonjBayLogo.png") | addLogo("Caledonj Bay Fishermen’s’ Cooperatives","CaledonjBayLogo.png") | ||
addLogo("Gadial Oil","GadialOilLogoB.png") | addLogo("Gadial Oil","GadialOilLogoB.png") | ||
addLogo("Alpazkigz Division", "AlpazkigzDivisionFlag.png") | addLogo("Alpazkigz Division", "AlpazkigzDivisionFlag.png") | ||
addLogo("Odiferia Division", "OdiferiaFlag.png") | addLogo("Odiferia Division", "OdiferiaFlag.png") | ||
| Line 388: | Line 486: | ||
addLogo("New South Jangsong Division","NewSouthJangsongFlag.png") | addLogo("New South Jangsong Division","NewSouthJangsongFlag.png") | ||
addLogo("Haifan Bassaridia Division", "HaifaDivisionFlag.png") | addLogo("Haifan Bassaridia Division", "HaifaDivisionFlag.png") | ||
addLogo("Order of Aurora Mystica", "Auroramystica.png") | addLogo("Order of Aurora Mystica", "Auroramystica.png") | ||
addLogo("Harmony Sanctum", "Harmonysanctum.png") | addLogo("Harmony Sanctum", "Harmonysanctum.png") | ||
| Line 445: | Line 542: | ||
{first="Thorne", last="Noctis", nick="Mainomenos"} | {first="Thorne", last="Noctis", nick="Mainomenos"} | ||
} | } | ||
local function getRandomPrivateer() | local function getRandomPrivateer() | ||
local c = randomChoice(privateers) | local c = randomChoice(privateers) | ||
| Line 455: | Line 551: | ||
end | end | ||
end | end | ||
-- 8) Determine Owner/Operator | -- 8) Determine Owner/Operator | ||
local function getOwner(vt, ct) | local function getOwner(vt, ct, subtype, region) | ||
if vt == "Ritual" then | if vt == "Ritual" then | ||
return randomChoice(ritualCults) | return randomChoice(ritualCults) | ||
| Line 468: | Line 562: | ||
elseif vt == "Cargo" then | elseif vt == "Cargo" then | ||
if ct == "Agricultural" then | if ct == "Agricultural" then | ||
return randomChoice(agriCompanies) | local pool = buildPoolByClassSubtypeRegion("Agricultural", subtype, region) | ||
return randomChoice(pool) or randomChoice(agriCompanies) | |||
elseif ct == "Mining/Manufacturing" then | elseif ct == "Mining/Manufacturing" then | ||
return randomChoice(miningCompanies) | local pool = buildPoolByClassSubtypeRegion("Mining/Manufacturing", subtype, region) | ||
return randomChoice(pool) or randomChoice(miningCompanies) | |||
elseif ct == "Services" then | elseif ct == "Services" then | ||
return randomChoice(serviceCompanies) | local pool = buildPoolByClassSubtypeRegion("Services", subtype, region) | ||
return randomChoice(pool) or randomChoice(serviceCompanies) | |||
elseif ct == "Unspecified" then | |||
local pool = buildGeneralPoolBySubtypeRegion(subtype, region) | |||
return randomChoice(pool) or "Independent Consortium" | |||
end | end | ||
end | end | ||
| Line 496: | Line 596: | ||
end | end | ||
-- track accumulated tonnage | |||
local totalTonnage = 0 | |||
local ships = {} | local ships = {} | ||
-- generate between 50 and 80 vessels (will break early if cap reached) | |||
for i = 1, math.random(50, 80) do | for i = 1, math.random(50, 80) do | ||
-- timestamp | |||
local hr, mn = math.random(0, 23), math.random(0, 59) | local hr, mn = math.random(0, 23), math.random(0, 59) | ||
-- type & manifest profile | |||
local vt, ct = randomChoice(vesselTypes), randomChoice(cargoTypes) | local vt, ct = randomChoice(vesselTypes), randomChoice(cargoTypes) | ||
local owner = getOwner(vt, ct) or "Independent Consortium" | local subtype, sourceRegion = chooseManifestProfile(vt, ct) | ||
-- owner | |||
local owner = getOwner(vt, ct, subtype, sourceRegion) or "Independent Consortium" | |||
local ownerLogo = companyLogo[owner] and ("[[File:" .. companyLogo[owner] .. "|20px]] ") or "" | local ownerLogo = companyLogo[owner] and ("[[File:" .. companyLogo[owner] .. "|20px]] ") or "" | ||
-- home port (unchanged fixed home-city list) | |||
local home = randomChoice(cities) | local home = randomChoice(cities) | ||
-- select companies | -- select companies: one subtype + one region only | ||
local count = math.random(3, 4) | local count = math.random(3, 4) | ||
local picks = | local picks = pickCargoCompanies(vt, owner, ct, subtype, sourceRegion, count) | ||
if ct == "Unspecified" then | |||
-- fallback if a very narrow subtype/region pairing is sparse | |||
if #picks == 0 then | |||
if ct == "Unspecified" then | |||
local regionalPool = {} | |||
for _, name in ipairs(generalPools) do | |||
local meta = getCompanyMeta(name) | |||
if meta.region == sourceRegion then | |||
table.insert(regionalPool, name) | |||
end | |||
end | |||
picks = randomN(regionalPool, count) | |||
else | |||
local regionalPool = {} | |||
for _, name in ipairs(poolMap[ct] or {}) do | |||
local meta = getCompanyMeta(name) | |||
if meta.region == sourceRegion then | |||
table.insert(regionalPool, name) | |||
end | |||
end | |||
picks = randomN(regionalPool, count) | |||
end | |||
end | end | ||
| Line 520: | Line 650: | ||
compCell = compCell .. "</ul>" | compCell = compCell .. "</ul>" | ||
local errList = { | -- possible error | ||
local errList = {"Cargo Mislabeling","Improper Documentation","Surveillance Anomaly","Inspection Failure","Unregistered Ritual Cargo"} | |||
local err = math.random() < 0.2 and randomChoice(errList) or "None" | local err = math.random() < 0.2 and randomChoice(errList) or "None" | ||
-- **tonnage clamp** so we never exceed the daily cap | |||
local rawT = math.random() * 19000 + 1000 | |||
local allowedT = math.min(rawT, MAX_DAILY_TONNAGE - totalTonnage) | |||
totalTonnage = totalTonnage + allowedT | |||
-- assemble ship record | |||
table.insert(ships, { | table.insert(ships, { | ||
date = string.format("Day %d, Y.%d", d, y), | date = string.format("Day %d, Y.%d", d, y), | ||
| Line 535: | Line 668: | ||
typ = vt, | typ = vt, | ||
ownerCell = ownerLogo .. owner, | ownerCell = ownerLogo .. owner, | ||
cargotype = ct, | cargotype = string.format("%s / %s / %s", ct, subtype, sourceRegion), | ||
cargoCompanies = compCell, | cargoCompanies = compCell, | ||
berth = math.random(1, 124), | berth = math.random(1, 124), | ||
teus = math.random(100, 1000), | teus = math.random(100, 1000), | ||
tonnage = string.format("%.2f", | tonnage = string.format("%.2f", allowedT), | ||
queue = string.format("%.2f", math.random() * 5.5 + 0.5), | queue = string.format("%.2f", math.random() * 5.5 + 0.5), | ||
turnaround = string.format("%.2f", math.random() * 32 + 4), | turnaround = string.format("%.2f", math.random() * 32 + 4), | ||
error = err | error = err | ||
}) | }) | ||
-- stop generating once we've hit the cap | |||
if totalTonnage >= MAX_DAILY_TONNAGE then | |||
break | |||
end | |||
end | end | ||
-- sort by time | |||
table.sort(ships, function(a, b) return a.sort < b.sort end) | table.sort(ships, function(a, b) return a.sort < b.sort end) | ||
-- build wiki table | |||
local out = { | local out = { | ||
'{| class="wikitable sortable"', | '{| class="wikitable sortable"', | ||
| Line 570: | Line 710: | ||
table.insert(out, "* '''Inspection Failure:''' Customs/hatch failure") | table.insert(out, "* '''Inspection Failure:''' Customs/hatch failure") | ||
table.insert(out, "* '''Unregistered Ritual Cargo:''' Not pre-cleared by Temple Bank") | table.insert(out, "* '''Unregistered Ritual Cargo:''' Not pre-cleared by Temple Bank") | ||
return table.concat(out, "\n") | return table.concat(out, "\n") | ||
end | end | ||
Revision as of 19:21, 20 March 2026
Documentation for this module may be created at Module:GeneralPortOperations/doc
-- Module:GeneralPortDailyLog
local p = {}
-- compatibility shim for unpack
local unpack = table.unpack or unpack
-- 0) Daily tonnage cap
local MAX_DAILY_TONNAGE = 1359348.096
-- 1) Date logic
function p.getCurrentDate()
local start = os.time{year=1999, month=8, day=6}
local elapsed = math.floor((os.time() - start) / 86400)
local year = math.floor(elapsed / 183)
local day = (elapsed % 183) + 1
return year, day
end
-- 2) Random helpers
local function randomChoice(tbl)
if type(tbl) ~= "table" or #tbl == 0 then return nil end
return tbl[math.random(#tbl)]
end
local function randomN(tbl, n)
if type(tbl) ~= "table" or n < 1 then return {} end
local copy, out = {unpack(tbl)}, {}
for i = 1, math.min(n, #copy) do
local idx = math.random(#copy)
table.insert(out, table.remove(copy, idx))
end
return out
end
-- 3) Home ports + flags
local cities = {
"Aegirheim","Skýrophos","Bjornopolis","Norsolyra","Ephyra",
"Symphonara","Delphica","Vaeringheim","Somniumpolis",
"Keybir-Aviv","Sufriya","Jogi" , "Ardclach" , "Riddersborg"
}
local cityFlag = {}
for _, name in ipairs(cities) do
local norm = name
:gsub("[%s%-’]", "")
:gsub("[Áá]", "A"):gsub("[Éé]", "E")
:gsub("[Íí]", "I"):gsub("[Óó]", "O")
:gsub("[Úú]", "U"):gsub("[Ýý]", "Y")
cityFlag[name] = string.format("[[File:%sFlag.png|20px]]", norm)
end
-- override for Skýrophos
cityFlag["Skýrophos"] = "[[File:SkyrophosFlag.png|20px]]"
-- 3b) Region mapping for the fixed home-city set
local cityRegion = {
["Aegirheim"] = "New South Jangsong",
["Skýrophos"] = "New South Jangsong",
["Bjornopolis"] = "New South Jangsong",
["Norsolyra"] = "New South Jangsong",
["Ephyra"] = "New South Jangsong",
["Symphonara"] = "Core",
["Delphica"] = "Core",
["Vaeringheim"] = "Core",
["Somniumpolis"] = "Core",
["Keybir-Aviv"] = "Haifan Bassaridia",
["Sufriya"] = "Haifan Bassaridia",
["Jogi"] = "Haifan Bassaridia",
["Ardclach"] = "Bassaridian Normark",
["Riddersborg"] = "Bassaridian Normark",
}
-- 4) Vessel & cargo types
local vesselTypes = {"Cargo","Military","Ritual","Privateer"}
local cargoTypes = {"Agricultural","Mining/Manufacturing","Services","Unspecified"}
-- 5) Owner pools
local ritualCults = {
"Order of Aurora Mystica","Harmony Sanctum",
"Ignis Aeternum","Celestial Harmony Sect","Guild of Golden Shadows",
"Azure Sentinel Sect","Reverie Nebulous","Eon Fellowship",
"Order of the Umbral Oracle","Mystery of the Verdant Embrace",
"Conclave Illuminara","Sanctum Vitalis","Temple Alabaster",
"Court of the Ironclad","Accord Concordia","Mystery of the Stygian Veil",
"Sylvan Fellowship","Mystery of Red Mirth","Rex Catonis",
"Sanctum Delphica","Ordo Amicitia","Temple Illuminata"
}
local militaryDivs = {
"Alpazkigz Division","Odiferia Division","Vaeringheim Division",
"Haifa Division","Jeseri Division","Hatch Ministry Division",
"New South Jangsong Division","Haifan Bassaridia Division"
}
local agriCompanies = {
"Gladeseed Farmers' Union","Atterian Cattle Drivers",
"Jogiani Merchants of Manwine","Keepers of the Grove of Zoe Elm",
"Plains of Jogi","Ale of the Night Central Brewery",
"Camel Herders of the Jangsong Province","Anterran Imports and Services",
"Merchant Guild of the Poppy Goddess","Grand Cave Bee Meadery",
"Cinammon Plains of Rouge","The Velvet Company","Seamstresses of Rouge",
"Salurian Temple of Sacred Horehound","Bulhanu Ranchers' Association",
"Suncliff Fisheries","Ministers of Mistress Mugwort",
"Blood Vineyards of the Far North",
"Norsolyrian Wisp Rice Farmers Association",
"Giid-Lisea Ranching Import Company","Bird Keepers of Saluria",
"Hunters of the Giant Fanged Penguin","Knights Castle Reindeer Herders",
"Lindley Whaling Company","Aminian Coffee Company","Granadita Collective",
"Herd Caton","Wasp Hunters of the Austral Isles", "Sea Elm Southern Meadery",
"Nefel Village","Diamonia Sugar Cooperatives", "Ouriana Lowlands Farmers' Association",
"Nefel Village", "Ouriad River Fisheries Cooperative", "Caspazani Livestock Company",
"White Ruby Communes", "Fange Velvet", "Port of Corumia", "Lamian Ward", "Sleva Farming Supplies Cooperative",
"Hrimmanes Woolhorse Company"," King's Home Fur Trappers' Cooperative", "Caledonj Bay Fishermen’s’ Cooperatives",
}
local miningCompanies = {
"Roving Wind Farm Corporation",
"Thalassian Temple Granite Export Cooperative","East Keltian Iron Company",
"Mylecian Coal Ports","Merchants of the Valley of Diamonds",
"East Keltian Timber Company","Onceanic Boot Company",
"Commune of the Garganid Apostles","Shï Collective","Order of the Sphinx",
"Market Hanavusu","Somniant Stock Fund","Copper Mines of Southern Jogi",
"Horned Bear Timber Company","Federation of North Brabipant",
"Southern Strait Preservation Corporation","Eosphorus Motor Company",
"Vortelin Electronics", "Thyrsiad Rubber Company","Stygium Mines of Acheron",
"Trans-Rodinian Granite Agency", "Amber Ports of Slevik", "Thesean Iron Exports",
"Fanghorn Highland Gas Company","Gadial Oil",
}
local serviceCompanies = {
"Ergonian Spy Agency",
"Temple Bank of the Reformed Stripping Path",
"Temple University of Delphica","La Sái Ebile",
"Pharmacon Sect",
"Skyrophian Security Contractors",
"Haifadora Postal Service",
"Fleet of Rouge Divers",
"Merchant Caravans of the Candy Kingdom",
"Hellhound Breeders of Dragevik",
"Noctic Fleet",
"Maritime Guild of the Cult of Maskmakers",
"Couriers of the Lizard Queen",
"Temple of Aprobelle",
"Sårensby Depot*",
}
-- ─── Restrict which cargo‐companies can appear ────────────────────────────────────
local privateerCompanies = {
"Lake Morovia Blockade Fund",
"Baratar Corporation",
}
local hatchMinistryCompanies = {
"Hatch Ministry"
}
-- 5b) Company classification + single-region manifest metadata
local companyMeta = {
-- Agriculture
["Gladeseed Farmers' Union"] = {class="Agricultural", subtype="grain", region="Core"},
["Atterian Cattle Drivers"] = {class="Agricultural", subtype="livestock", region="New South Jangsong"},
["Jogiani Merchants of Manwine"] = {class="Agricultural", subtype="wine_spirits", region="Haifan Bassaridia"},
["Keepers of the Grove of Zoe Elm"] = {class="Agricultural", subtype="forest_products", region="Core"},
["Plains of Jogi"] = {class="Agricultural", subtype="grain", region="Haifan Bassaridia"},
["Ale of the Night Central Brewery"] = {class="Agricultural", subtype="wine_spirits", region="Core"},
["Camel Herders of the Jangsong Province"] = {class="Agricultural", subtype="livestock", region="New South Jangsong"},
["Anterran Imports and Services"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"},
["Merchant Guild of the Poppy Goddess"] = {class="Agricultural", subtype="herbs", region="Core"},
["Grand Cave Bee Meadery"] = {class="Agricultural", subtype="mead_spirits", region="Core"},
["Cinammon Plains of Rouge"] = {class="Agricultural", subtype="spices", region="Core"},
["The Velvet Company"] = {class="Agricultural", subtype="textiles_raw", region="Core"},
["Seamstresses of Rouge"] = {class="Agricultural", subtype="textiles_raw", region="Core"},
["Salurian Temple of Sacred Horehound"] = {class="Agricultural", subtype="herbs", region="Core"},
["Bulhanu Ranchers' Association"] = {class="Agricultural", subtype="livestock", region="Core"},
["Suncliff Fisheries"] = {class="Agricultural", subtype="fish", region="Core"},
["Ministers of Mistress Mugwort"] = {class="Agricultural", subtype="herbs", region="Core"},
["Blood Vineyards of the Far North"] = {class="Agricultural", subtype="wine_spirits", region="New South Jangsong"},
["Norsolyrian Wisp Rice Farmers Association"] = {class="Agricultural", subtype="grain", region="New South Jangsong"},
["Giid-Lisea Ranching Import Company"] = {class="Agricultural", subtype="livestock", region="Core"},
["Bird Keepers of Saluria"] = {class="Agricultural", subtype="animal_products", region="Core"},
["Hunters of the Giant Fanged Penguin"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"},
["Knights Castle Reindeer Herders"] = {class="Agricultural", subtype="livestock", region="Bassaridian Normark"},
["Lindley Whaling Company"] = {class="Agricultural", subtype="marine_oil", region="Bassaridian Normark"},
["Aminian Coffee Company"] = {class="Agricultural", subtype="coffee", region="Haifan Bassaridia"},
["Granadita Collective"] = {class="Agricultural", subtype="fruit", region="Haifan Bassaridia"},
["Herd Caton"] = {class="Agricultural", subtype="livestock", region="Core"},
["Wasp Hunters of the Austral Isles"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"},
["Sea Elm Southern Meadery"] = {class="Agricultural", subtype="mead_spirits", region="Core"},
["Nefel Village"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"},
["Diamonia Sugar Cooperatives"] = {class="Agricultural", subtype="sugar", region="Haifan Bassaridia"},
["Ouriana Lowlands Farmers' Association"] = {class="Agricultural", subtype="grain", region="Ouriana Province"},
["Ouriad River Fisheries Cooperative"] = {class="Agricultural", subtype="fish", region="Ouriana Province"},
["Caspazani Livestock Company"] = {class="Agricultural", subtype="livestock", region="Ouriana Province"},
["White Ruby Communes"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"},
["Fange Velvet"] = {class="Agricultural", subtype="textiles_raw", region="Bassaridian Normark"},
["Port of Corumia"] = {class="Agricultural", subtype="fish", region="Core"},
["Lamian Ward"] = {class="Agricultural", subtype="mixed_foodstuffs", region="Core"},
["Sleva Farming Supplies Cooperative"] = {class="Agricultural", subtype="farm_inputs", region="Bassaridian Normark"},
["Hrimmanes Woolhorse Company"] = {class="Agricultural", subtype="livestock", region="Bassaridian Normark"},
[" King's Home Fur Trappers' Cooperative"] = {class="Agricultural", subtype="animal_products", region="Bassaridian Normark"},
["Caledonj Bay Fishermen’s’ Cooperatives"] = {class="Agricultural", subtype="fish", region="Bassaridian Normark"},
-- Mining / Manufacturing / Energy
["Roving Wind Farm Corporation"] = {class="Mining/Manufacturing", subtype="energy", region="Core"},
["Thalassian Temple Granite Export Cooperative"] = {class="Mining/Manufacturing", subtype="stone", region="Core"},
["East Keltian Iron Company"] = {class="Mining/Manufacturing", subtype="metals", region="Core"},
["Mylecian Coal Ports"] = {class="Mining/Manufacturing", subtype="coal", region="Core"},
["Merchants of the Valley of Diamonds"] = {class="Mining/Manufacturing", subtype="gemstones", region="Haifan Bassaridia"},
["East Keltian Timber Company"] = {class="Mining/Manufacturing", subtype="timber", region="Core"},
["Onceanic Boot Company"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="Core"},
["Commune of the Garganid Apostles"] = {class="Mining/Manufacturing", subtype="stone", region="Core"},
["Shï Collective"] = {class="Mining/Manufacturing", subtype="luxury_goods", region="Core"},
["Order of the Sphinx"] = {class="Mining/Manufacturing", subtype="luxury_goods", region="Haifan Bassaridia"},
["Market Hanavusu"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="New South Jangsong"},
["Somniant Stock Fund"] = {class="Mining/Manufacturing", subtype="arms_industrial", region="Core"},
["Copper Mines of Southern Jogi"] = {class="Mining/Manufacturing", subtype="metals", region="Haifan Bassaridia"},
["Horned Bear Timber Company"] = {class="Mining/Manufacturing", subtype="timber", region="New South Jangsong"},
["Federation of North Brabipant"] = {class="Mining/Manufacturing", subtype="consumer_goods", region="Bassaridian Normark"},
["Southern Strait Preservation Corporation"] = {class="Mining/Manufacturing", subtype="marine_materials", region="Haifan Bassaridia"},
["Eosphorus Motor Company"] = {class="Mining/Manufacturing", subtype="vehicles", region="Core"},
["Vortelin Electronics"] = {class="Mining/Manufacturing", subtype="electronics", region="Core"},
["Thyrsiad Rubber Company"] = {class="Mining/Manufacturing", subtype="rubber", region="Haifan Bassaridia"},
["Stygium Mines of Acheron"] = {class="Mining/Manufacturing", subtype="metals", region="Core"},
["Trans-Rodinian Granite Agency"] = {class="Mining/Manufacturing", subtype="stone", region="Core"},
["Amber Ports of Slevik"] = {class="Mining/Manufacturing", subtype="amber", region="Bassaridian Normark"},
["Thesean Iron Exports"] = {class="Mining/Manufacturing", subtype="metals", region="Ouriana Province"},
["Fanghorn Highland Gas Company"] = {class="Mining/Manufacturing", subtype="gas", region="Bassaridian Normark"},
["Gadial Oil"] = {class="Mining/Manufacturing", subtype="oil", region="Core"},
-- Services
["Ergonian Spy Agency"] = {class="Services", subtype="intelligence", region="Core"},
["Temple Bank of the Reformed Stripping Path"] = {class="Services", subtype="finance", region="Core"},
["Temple University of Delphica"] = {class="Services", subtype="education", region="Core"},
["La Sái Ebile"] = {class="Services", subtype="commerce", region="Haifan Bassaridia"},
["Pharmacon Sect"] = {class="Services", subtype="medical", region="Core"},
["Skyrophian Security Contractors"] = {class="Services", subtype="security", region="New South Jangsong"},
["Haifadora Postal Service"] = {class="Services", subtype="courier", region="Haifan Bassaridia"},
["Fleet of Rouge Divers"] = {class="Services", subtype="marine_services", region="Core"},
["Merchant Caravans of the Candy Kingdom"] = {class="Services", subtype="logistics", region="Core"},
["Hellhound Breeders of Dragevik"] = {class="Services", subtype="animal_services", region="Bassaridian Normark"},
["Noctic Fleet"] = {class="Services", subtype="marine_services", region="Core"},
["Maritime Guild of the Cult of Maskmakers"] = {class="Services", subtype="marine_services", region="Core"},
["Couriers of the Lizard Queen"] = {class="Services", subtype="courier", region="Core"},
["Temple of Aprobelle"] = {class="Services", subtype="security", region="Core"},
["Sårensby Depot*"] = {class="Services", subtype="logistics", region="Bassaridian Normark"},
-- Special pools
["Lake Morovia Blockade Fund"] = {class="Services", subtype="security", region="Core"},
["Baratar Corporation"] = {class="Mining/Manufacturing", subtype="arms_industrial", region="Haifan Bassaridia"},
["Hatch Ministry"] = {class="Services", subtype="security", region="Core"},
}
-- build a “general” pool excluding those six
local generalPools = {}
for _, list in ipairs({agriCompanies, miningCompanies, serviceCompanies}) do
for _, name in ipairs(list) do
if name ~= "Hatch Ministry" then
local isPri = false
for _, pr in ipairs(privateerCompanies) do
if name == pr then isPri = true break end
end
if not isPri then
table.insert(generalPools, name)
end
end
end
end
local function getCompanyMeta(name)
return companyMeta[name] or {class="Unspecified", subtype="mixed", region="Core"}
end
local function buildPoolByClassSubtypeRegion(className, subtype, region)
local base = ({
Agricultural = agriCompanies,
["Mining/Manufacturing"] = miningCompanies,
Services = serviceCompanies
})[className] or {}
local pool = {}
for _, name in ipairs(base) do
if name ~= "Hatch Ministry" then
local isPri = false
for _, pr in ipairs(privateerCompanies) do
if name == pr then isPri = true break end
end
if not isPri then
local meta = getCompanyMeta(name)
if meta.class == className and meta.subtype == subtype and meta.region == region then
table.insert(pool, name)
end
end
end
end
return pool
end
local function buildGeneralPoolBySubtypeRegion(subtype, region)
local pool = {}
for _, name in ipairs(generalPools) do
local meta = getCompanyMeta(name)
if meta.subtype == subtype and meta.region == region then
table.insert(pool, name)
end
end
return pool
end
local function chooseManifestProfile(vt, ct)
if vt == "Privateer" then
return "security", "Core"
elseif vt == "Military" then
local subtype = randomChoice({"security","arms_industrial","medical","logistics"})
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"})
return subtype, region
elseif vt == "Ritual" then
local subtype = randomChoice({"finance","medical","courier","security","education","logistics"})
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark"})
return subtype, region
elseif ct == "Agricultural" then
local subtype = randomChoice({
"grain","livestock","wine_spirits","forest_products","herbs",
"mead_spirits","spices","textiles_raw","fish","animal_products",
"marine_oil","coffee","fruit","sugar","mixed_foodstuffs","farm_inputs"
})
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"})
return subtype, region
elseif ct == "Mining/Manufacturing" then
local subtype = randomChoice({
"energy","stone","metals","coal","gemstones","timber","consumer_goods",
"luxury_goods","arms_industrial","marine_materials","vehicles",
"electronics","rubber","amber","gas","oil"
})
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark","Ouriana Province"})
return subtype, region
elseif ct == "Services" then
local subtype = randomChoice({
"intelligence","finance","education","commerce","medical",
"security","courier","marine_services","logistics","animal_services"
})
local region = randomChoice({"Core","New South Jangsong","Haifan Bassaridia","Bassaridian Normark"})
return subtype, region
else
local source = randomChoice(generalPools)
local meta = getCompanyMeta(source)
return meta.subtype, meta.region
end
end
local function pickCargoCompanies(vt, owner, ct, subtype, region, count)
if vt == "Privateer" then
return randomN(privateerCompanies, count)
elseif owner == "Hatch Ministry Division" then
return randomN(hatchMinistryCompanies, count)
elseif ct == "Unspecified" then
local pool = buildGeneralPoolBySubtypeRegion(subtype, region)
if #pool == 0 then
local fallback = {}
for _, name in ipairs(generalPools) do
local meta = getCompanyMeta(name)
if meta.region == region then
table.insert(fallback, name)
end
end
pool = fallback
end
return randomN(pool, count)
else
local pool = buildPoolByClassSubtypeRegion(ct, subtype, region)
if #pool == 0 then
local fallback = {}
local base = ({
Agricultural = agriCompanies,
["Mining/Manufacturing"] = miningCompanies,
Services = serviceCompanies
})[ct] or {}
for _, name in ipairs(base) do
if name ~= "Hatch Ministry" then
local isPri = false
for _, pr in ipairs(privateerCompanies) do
if name == pr then isPri = true break end
end
if not isPri then
local meta = getCompanyMeta(name)
if meta.region == region then
table.insert(fallback, name)
end
end
end
end
pool = fallback
end
return randomN(pool, count)
end
end
-- 6) Company logos mapping
local companyLogo = {}
local function addLogo(name,file) companyLogo[name]=file end
addLogo("Lake Morovia Blockade Fund","BlockadeFund420.png")
addLogo("Gladeseed Farmers' Union","Gladeseed420.png")
addLogo("Atterian Cattle Drivers","Atterian420.png")
addLogo("Noctic Fleet","Noctic420.png")
addLogo("Jogiani Merchants of Manwine","Jogiani420.png")
addLogo("Keepers of the Grove of Zoe Elm","KeepersoftheGrove.png")
addLogo("Plains of Jogi","PlainsofJogi.png")
addLogo("Ale of the Night Central Brewery","AleofNight420.png")
addLogo("Camel Herders of the Jangsong Province","CamelHerders420.png")
addLogo("Thalassian Temple Granite Export Cooperative","ThalassianGranite420.png")
addLogo("East Keltian Iron Company","EKIron420.png")
addLogo("Mylecian Coal Ports","CoalPorts420.png")
addLogo("Merchants of the Valley of Diamonds","ValleyofDiamonds420.png")
addLogo("Baratar Corporation","Baratar420.png")
addLogo("Roving Wind Farm Corporation","RovingWind420.png")
addLogo("Grand Cave Bee Meadery","GrandCave420.png")
addLogo("Merchant Guild of the Poppy Goddess","PoppyGoddess420.png")
addLogo("Cinammon Plains of Rouge","CinammonPlains420.png")
addLogo("The Velvet Company","VelvetHome420.png")
addLogo("Seamstresses of Rouge","Seamstresses420.png")
addLogo("Salurian Temple of Sacred Horehound","SalurianTemple421.png")
addLogo("Bulhanu Ranchers' Association","Bulhanu421.png")
addLogo("Suncliff Fisheries","Suncliff421.png")
addLogo("Ministers of Mistress Mugwort","Mugwort421.png")
addLogo("Blood Vineyards of the Far North","BloodVineyards421.png")
addLogo("Norsolyrian Wisp Rice Farmers Association","Norsolyrian421.png")
addLogo("Giid-Lisea Ranching Import Company","GiidLisea421.png")
addLogo("Bird Keepers of Saluria","SaluriaBK421.png")
addLogo("Knights Castle Reindeer Herders","KnightsCastle421.png")
addLogo("Lindley Whaling Company","LindleyWhalingCompany.png")
addLogo("Aminian Coffee Company","Aminian421.png")
addLogo("Commune of the Garganid Apostles","Garganid421.png")
addLogo("Onceanic Boot Company","OnceanicBoot421.png")
addLogo("Maritime Guild of the Cult of Maskmakers","MaritimeGuild420.png")
addLogo("Ergonian Spy Agency","ErgonianSpy421.png")
addLogo("Temple Bank of the Reformed Stripping Path","TempleBankCrest.png")
addLogo("Couriers of the Lizard Queen","LizardQueen421.png")
addLogo("Temple University of Delphica","TempleUniversity421.png")
addLogo("Shï Collective","ShiCollective421.png")
addLogo("Order of the Sphinx","OrderofSphinx421.png")
addLogo("Market Hanavusu","MarketHanavusu421.png")
addLogo("Somniant Stock Fund","SomniantStockFund.png")
addLogo("Hatch Ministry","HatchMinistry420.png")
addLogo("Anterran Imports and Services","AnterranImports420.png")
addLogo("East Keltian Timber Company","EKTimber420.png")
addLogo("Hellhound Breeders of Dragevik","Dragevik421.png")
addLogo("La Sái Ebile","LaSie421.png")
addLogo("Hunters of the Giant Fanged Penguin","FangedPenguin421.png")
addLogo("Commune of the Garganid Apostles","Garganid421.png")
addLogo("Copper Mines of Southern Jogi","CopperMinesLogoC.png")
addLogo("Horned Bear Timber Company","HornedBearTimberLogo.png")
addLogo("Granadita Collective","GranaditaCollectiveLogo.png")
addLogo("Pharmacon Sect","PharmaconSect.png")
addLogo("Skyrophian Security Contractors","SkyrophianSecurity.png")
addLogo("Haifadora Postal Service","HaifadoraPostalLogo.png")
addLogo("Herd Caton","HerdCatonLogo.png")
addLogo("Wasp Hunters of the Austral Isles","WaspHuntersLogo.png")
addLogo("Fleet of Rouge Divers","RougeDiversLogo.png")
addLogo("Sea Elm Southern Meadery","SeaElmLogo.png")
addLogo("Candy Merchants of the Candy Kingdom","Candymerchantslogo.png")
addLogo("Federation of North Brabipant","NorthBrabipantlogo.png")
addLogo("Southern Strait Preservation Corporation","SouthernStraitPreservationLogo.png")
addLogo("Eosphorus Motor Company","EosphorusLogo.png")
addLogo("Vortelin Electronics","VortelinElectronicsLogo.png")
addLogo("Thyrsiad Rubber Company","ThyrsiadRubberLogo.png")
addLogo("Nefel Village","NefelVillageLogo.png")
addLogo("Stygium Mines of Acheron","StygiumMinesLogo.png")
addLogo("Temple of Aprobelle","TempleAprobelleLogo.png")
addLogo("Diamonia Sugar Cooperatives","DiamoniaSugarLogo.png")
addLogo("Ouriana Lowlands Farmers' Association","OurianaLowlandsLogo.png")
addLogo("Ouriad River Fisheries Cooperative","OuriadRiverLogo.png")
addLogo("Caspazani Livestock Company","CaspazaniLogo.png")
addLogo("Trans-Rodinian Granite Agency","TransRodinanLogo.png")
addLogo("White Ruby Communes","WhiteRubyLogo.png")
addLogo("Fange Velvet","FangeVelvetLogo.png")
addLogo("Sårensby Depot","SårensbyDepotLogo.png")
addLogo("Amber Ports of Slevik","AmberPortsLogo2.png")
addLogo("Port of Corumia","PortofCorumiaLogo.png.png")
addLogo("Lamian Ward","LamianWardLogo.png")
addLogo("Sleva Farming Supplies Cooperatives","SlevaFarmingLogo.png")
addLogo("Hrimmanes Woolhorse Company","HrimmanesLogoB.png.png")
addLogo("Thesean Iron Exports","TheseanIronExports.png")
addLogo("King's Home Fur Trappers' Cooperative","KingsHomeCoLogo.png.png")
addLogo("Fanghorn Highland Gas Company","FanghornGasLogo.png")
addLogo("Caledonj Bay Fishermen’s’ Cooperatives","CaledonjBayLogo.png")
addLogo("Gadial Oil","GadialOilLogoB.png")
addLogo("Alpazkigz Division", "AlpazkigzDivisionFlag.png")
addLogo("Odiferia Division", "OdiferiaFlag.png")
addLogo("Vaeringheim Division", "VaeringheimDivisionFlag.png")
addLogo("Haifa Division", "HafaanFlag.png")
addLogo("Jeseri Division", "JeseriFlag.png")
addLogo("Hatch Ministry Division", "HatchMinistryFlag.png")
addLogo("New South Jangsong Division","NewSouthJangsongFlag.png")
addLogo("Haifan Bassaridia Division", "HaifaDivisionFlag.png")
addLogo("Order of Aurora Mystica", "Auroramystica.png")
addLogo("Harmony Sanctum", "Harmonysanctum.png")
addLogo("Ignis Aeternum", "Ignis Aeternum.png")
addLogo("Celestial Harmony Sect", "HarmonySect.png")
addLogo("Guild of Golden Shadows", "GoldenShadows.png")
addLogo("Azure Sentinel Sect", "AzureSentinel.png")
addLogo("Reverie Nebulous","RevNeb.png")
addLogo("Eon Fellowship", "EonFel.png")
addLogo("Order of the Umbral Oracle", "Umbral.png")
addLogo("Mystery of the Verdant Embrace", "Verdant.png")
addLogo("Conclave Illuminara", "Conclave.png")
addLogo("Sanctum Vitalis", "Vitalis.png")
addLogo("Temple Alabaster", "Alabaster.png")
addLogo("Court of the Ironclad", "Ironclad.png")
addLogo("Accord Concordia", "Concordia.png")
addLogo("Mystery of the Stygian Veil", "StygianVe.png")
addLogo("Sylvan Fellowship", "Sylvan.png")
addLogo("Mystery of Red Mirth", "MirthFlag.png")
addLogo("Rex Catonis", "Catonis.png")
addLogo("Sanctum Delphica", "SanctumDel.png")
addLogo("Ordo Amicitia", "OrdoFl.png")
addLogo("Temple Illuminata", "AureumFlag.png")
-- 7) Privateer flags + helper
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"},
{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 getRandomPrivateer()
local c = randomChoice(privateers)
local flag = string.format("[[File:%s.png|20px]] ", c.last)
if c.nick and math.random() < 0.20 then
return string.format("%sCaptain %s ‘%s’ %s", flag, c.first, c.nick, c.last)
else
return string.format("%sCaptain %s %s", flag, c.first, c.last)
end
end
-- 8) Determine Owner/Operator
local function getOwner(vt, ct, subtype, region)
if vt == "Ritual" then
return randomChoice(ritualCults)
elseif vt == "Military" then
return randomChoice(militaryDivs)
elseif vt == "Privateer" then
return getRandomPrivateer()
elseif vt == "Cargo" then
if ct == "Agricultural" then
local pool = buildPoolByClassSubtypeRegion("Agricultural", subtype, region)
return randomChoice(pool) or randomChoice(agriCompanies)
elseif ct == "Mining/Manufacturing" then
local pool = buildPoolByClassSubtypeRegion("Mining/Manufacturing", subtype, region)
return randomChoice(pool) or randomChoice(miningCompanies)
elseif ct == "Services" then
local pool = buildPoolByClassSubtypeRegion("Services", subtype, region)
return randomChoice(pool) or randomChoice(serviceCompanies)
elseif ct == "Unspecified" then
local pool = buildGeneralPoolBySubtypeRegion(subtype, region)
return randomChoice(pool) or "Independent Consortium"
end
end
return "Independent Consortium"
end
-- 9) Build the table
function p.generateShipTable()
math.randomseed(os.time())
local y, d = p.getCurrentDate()
-- pools
local poolMap = {
Agricultural = agriCompanies,
["Mining/Manufacturing"] = miningCompanies,
Services = serviceCompanies
}
local allPools = {}
for _, list in pairs(poolMap) do
for _, name in ipairs(list) do
table.insert(allPools, name)
end
end
-- track accumulated tonnage
local totalTonnage = 0
local ships = {}
-- generate between 50 and 80 vessels (will break early if cap reached)
for i = 1, math.random(50, 80) do
-- timestamp
local hr, mn = math.random(0, 23), math.random(0, 59)
-- type & manifest profile
local vt, ct = randomChoice(vesselTypes), randomChoice(cargoTypes)
local subtype, sourceRegion = chooseManifestProfile(vt, ct)
-- owner
local owner = getOwner(vt, ct, subtype, sourceRegion) or "Independent Consortium"
local ownerLogo = companyLogo[owner] and ("[[File:" .. companyLogo[owner] .. "|20px]] ") or ""
-- home port (unchanged fixed home-city list)
local home = randomChoice(cities)
-- select companies: one subtype + one region only
local count = math.random(3, 4)
local picks = pickCargoCompanies(vt, owner, ct, subtype, sourceRegion, count)
-- fallback if a very narrow subtype/region pairing is sparse
if #picks == 0 then
if ct == "Unspecified" then
local regionalPool = {}
for _, name in ipairs(generalPools) do
local meta = getCompanyMeta(name)
if meta.region == sourceRegion then
table.insert(regionalPool, name)
end
end
picks = randomN(regionalPool, count)
else
local regionalPool = {}
for _, name in ipairs(poolMap[ct] or {}) do
local meta = getCompanyMeta(name)
if meta.region == sourceRegion then
table.insert(regionalPool, name)
end
end
picks = randomN(regionalPool, count)
end
end
local compCell = "<ul>"
for _, nm in ipairs(picks) do
local logo = companyLogo[nm] and ("[[File:" .. companyLogo[nm] .. "|20px]] ") or ""
compCell = compCell .. string.format("<li>%s%s</li>", logo, nm)
end
compCell = compCell .. "</ul>"
-- possible error
local errList = {"Cargo Mislabeling","Improper Documentation","Surveillance Anomaly","Inspection Failure","Unregistered Ritual Cargo"}
local err = math.random() < 0.2 and randomChoice(errList) or "None"
-- **tonnage clamp** so we never exceed the daily cap
local rawT = math.random() * 19000 + 1000
local allowedT = math.min(rawT, MAX_DAILY_TONNAGE - totalTonnage)
totalTonnage = totalTonnage + allowedT
-- assemble ship record
table.insert(ships, {
date = string.format("Day %d, Y.%d", d, y),
time = string.format("%02d:%02d", hr, mn),
sort = hr * 60 + mn,
vid = "VM-" .. math.random(10000, 99999),
home = cityFlag[home] .. " " .. home,
typ = vt,
ownerCell = ownerLogo .. owner,
cargotype = string.format("%s / %s / %s", ct, subtype, sourceRegion),
cargoCompanies = compCell,
berth = math.random(1, 124),
teus = math.random(100, 1000),
tonnage = string.format("%.2f", allowedT),
queue = string.format("%.2f", math.random() * 5.5 + 0.5),
turnaround = string.format("%.2f", math.random() * 32 + 4),
error = err
})
-- stop generating once we've hit the cap
if totalTonnage >= MAX_DAILY_TONNAGE then
break
end
end
-- sort by time
table.sort(ships, function(a, b) return a.sort < b.sort end)
-- build wiki table
local out = {
'{| class="wikitable sortable"',
'! Date !! Time !! Vessel ID !! Home City !! Type !! Owner/Operator !! Cargo Type !! Companies',
'!! Berth !! TEUs !! Tonnage (t) !! Queue (hrs) !! Turnaround (hrs) !! Error'
}
for _, s in ipairs(ships) do
local row = (s.error ~= "None") and '|- bgcolor="#ffcccc"' or '|-'
table.insert(out, row)
table.insert(out, table.concat({
'|', s.date, '||', s.time, '||', s.vid, '||', s.home, '||', s.typ,
'||', s.ownerCell, '||', s.cargotype, '||', s.cargoCompanies,
'||', s.berth, '||', s.teus, '||', s.tonnage, '||', s.queue,
'||', s.turnaround, '||', s.error
}, ' '))
end
table.insert(out, '|}')
table.insert(out, "'''Error Key:'''")
table.insert(out, "* '''Cargo Mislabeling:''' Manifest ≠ actual goods")
table.insert(out, "* '''Improper Documentation:''' Missing or outdated papers")
table.insert(out, "* '''Surveillance Anomaly:''' Unexpected heat/motion")
table.insert(out, "* '''Inspection Failure:''' Customs/hatch failure")
table.insert(out, "* '''Unregistered Ritual Cargo:''' Not pre-cleared by Temple Bank")
return table.concat(out, "\n")
end
function p.dailyReport()
local y, d = p.getCurrentDate()
return string.format(
"'''General Port of Lake Morovia: Operational Log – Day %d, Year %d PSSC'''",
d, y
) .. "\n" .. p.generateShipTable()
end
return p