Module:BassaridiaForecast: 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: | -- Module:BassaridiaForecast | ||
-- Provides a daily | -- Provides a daily forecast table for Bassaridia with: | ||
-- | -- • PSSC date logic (Atosiel, Thalassiel, Opsitheiel) | ||
-- | -- • Color-coded climate cells (per your table) | ||
-- | -- • Color-coded “Today’s Weather” cells by event keywords | ||
-- • Natural disaster advisories in red if triggered | |||
-- • Checks for numeric highC | |||
-- • Wind direction & speed | |||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 50: | Line 53: | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- 3. Weather Events (10 per climate-season) | -- 3. Weather Events (10 per climate-season) | ||
-- (Paste your full sets of 10 events per climate-season here.) | |||
--------------------------------------------------------- | --------------------------------------------------------- | ||
local climateEvents = { | local climateEvents = { | ||
-- Example partial data for demonstration: | |||
["Humid Subtropical"] = { | ["Humid Subtropical"] = { | ||
Atosiel = { | Atosiel = { | ||
| Line 91: | Line 96: | ||
} | } | ||
}, | }, | ||
-- And so on for "Oceanic," "Subpolar Oceanic," "Mediterranean (Hot Summer)," etc. | |||
} | |||
--------------------------------------------------------- | |||
-- 4. Ranges for Temperature, Humidity, Rain | |||
-- (Paste your climateTemperature table with hiMin, hiMax, etc.) | |||
--------------------------------------------------------- | |||
local climateTemperature = { | |||
-- Example partial data for demonstration: | |||
["Humid Subtropical"] = { | |||
Atosiel = { hiMin=18, hiMax=26, loMin=10, loMax=16, humMin=60, humMax=80, crMin=20, crMax=50, rfMin=1, rfMax=10 }, | |||
Thalassiel = { hiMin=25, hiMax=34, loMin=19, loMax=24, humMin=65, humMax=90, crMin=30, crMax=70, rfMin=2, rfMax=15 }, | |||
Opsitheiel = { hiMin=20, hiMax=28, loMin=12, loMax=18, humMin=50, humMax=75, crMin=15, crMax=40, rfMin=1, rfMax=8 } | |||
[" | |||
Atosiel = { | |||
Thalassiel = { | |||
Opsitheiel = { | |||
}, | }, | ||
-- And so on for your other climates... | |||
} | } | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- 5. | -- 5. Color-Coding "Today’s Weather" (getEventColor) | ||
--------------------------------------------------------- | |||
local function getEventColor(eventText) | |||
local textLower = eventText:lower() | |||
if textLower:find("thunder") or textLower:find("storm") then | |||
return "#FFC0C0" -- moderate pinkish-red for storms | |||
elseif textLower:find("snow") or textLower:find("sleet") or textLower:find("flurries") then | |||
return "#CCE6FF" -- moderate blue for snow | |||
elseif textLower:find("rain") or textLower:find("drizzle") or textLower:find("downpour") then | |||
return "#CCEEFF" -- soft aqua for rain | |||
elseif textLower:find("dust") or textLower:find("desert") then | |||
return "#FFFACD" -- lemon chiffon for dust | |||
elseif textLower:find("hail") then | |||
return "#E0FFFF" -- light cyan for hail | |||
else | |||
return "#F8F8F8" -- default light gray | |||
end | |||
end | |||
--------------------------------------------------------- | |||
-- 6. Color-Code Climate Cells from your table | |||
-- e.g. if spelled-out name is "Humid Subtropical," color #FFE4C4 | |||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 378: | Line 155: | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 7. Disaster Profiles | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 384: | Line 161: | ||
["Vaeringheim"] = {"flood", "heatwave", "thunderstorm"}, | ["Vaeringheim"] = {"flood", "heatwave", "thunderstorm"}, | ||
["Luminaria"] = {"flood", "landslide"}, | ["Luminaria"] = {"flood", "landslide"}, | ||
-- ... etc. (Paste your entire cityDisasterProfiles table here) | |||
} | } | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 8. Advisory Logic (red if triggered) | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 437: | Line 179: | ||
end | end | ||
elseif disasterType == "heatwave" then | elseif disasterType == "heatwave" then | ||
if type(highC) == "number" and highC >= 32 then | if type(highC) == "number" and highC >= 32 then | ||
table.insert(advisories, "Heatwave Warning") | table.insert(advisories, "Heatwave Warning") | ||
| Line 484: | Line 225: | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 9. Random Weather Stats (wind direction, speed) | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 492: | Line 233: | ||
local data = climateTemperature[climate] and climateTemperature[climate][season] | local data = climateTemperature[climate] and climateTemperature[climate][season] | ||
if not data then | if not data then | ||
-- Return numeric 0 | -- Return numeric 0 to avoid comparing number with string | ||
return { | return { | ||
highC=0, lowC=0, humidity=0, | highC=0, lowC=0, humidity=0, | ||
| Line 511: | Line 252: | ||
local wDir = windDirections[math.random(#windDirections)] | local wDir = windDirections[math.random(#windDirections)] | ||
local wSpd = math.random(0, 50) | local wSpd = math.random(0, 50) | ||
return { | return { | ||
highC = hiC, | highC = hiC, | ||
lowC | lowC = loC, | ||
humidity = hum, | humidity = hum, | ||
chanceOfRain = cRain, | chanceOfRain = cRain, | ||
| Line 525: | Line 266: | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 10. Celsius to Fahrenheit | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 533: | Line 274: | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 11. Full City List | ||
-- (Paste your entire cityData table here) | |||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 539: | Line 281: | ||
{city = "Vaeringheim", climate = "Humid Subtropical"}, | {city = "Vaeringheim", climate = "Humid Subtropical"}, | ||
{city = "Luminaria", climate = "Humid Subtropical"}, | {city = "Luminaria", climate = "Humid Subtropical"}, | ||
-- ... etc. for all major/minor cities... | |||
} | } | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
-- | -- 12. Main Weather Forecast Table | ||
--------------------------------------------------------- | --------------------------------------------------------- | ||
| Line 600: | Line 302: | ||
)) | )) | ||
-- | -- Wiki table header | ||
table.insert(out, '{| class="wikitable sortable" style="width:100%; text-align:left;"\n') | table.insert(out, '{| class="wikitable sortable" style="width:100%; text-align:left;"\n') | ||
table.insert(out, | table.insert(out, | ||
| Line 607: | Line 309: | ||
) | ) | ||
-- Loop | -- Loop over all cities | ||
for _, cityEntry in ipairs(cityData) do | for _, cityEntry in ipairs(cityData) do | ||
local cityName = cityEntry.city | local cityName = cityEntry.city | ||
local climateName = cityEntry.climate | local climateName = cityEntry.climate | ||
-- (A) Pick | -- (A) Pick random event | ||
local cTable = climateEvents[climateName] | local cTable = climateEvents[climateName] | ||
local sTable = cTable and cTable[seasonName] | local sTable = cTable and cTable[seasonName] | ||
local forecast = "No data" | local forecast = "No data" | ||
if sTable and #sTable > 0 then | if sTable and #sTable > 0 then | ||
| Line 620: | Line 322: | ||
end | end | ||
-- (B) Color for | -- (B) Color for "Today’s Weather" cell | ||
local weatherColor = getEventColor(forecast) | local weatherColor = getEventColor(forecast) | ||
| Line 633: | Line 335: | ||
local wSpd = stats.windSpeed | local wSpd = stats.windSpeed | ||
-- Convert hiC, loC to Fahrenheit | -- Convert hiC, loC to Fahrenheit if numeric | ||
local hiF = (type(hiC)=="number") and cToF(hiC) or "N/A" | local hiF = (type(hiC)=="number") and cToF(hiC) or "N/A" | ||
local loF = (type(loC)=="number") and cToF(loC) or "N/A" | local loF = (type(loC)=="number") and cToF(loC) or "N/A" | ||
-- (D) | -- (D) Advisory | ||
local advisory = getDisasterAdvisory( | local advisory = getDisasterAdvisory( | ||
cityName, forecast, cRain, pRain, | cityName, forecast, cRain, pRain, | ||
(type(hiC)=="number" and hiC or 0) | (type(hiC)=="number" and hiC or 0) | ||
) | ) | ||
-- Red cell if advisory != "No Advisory" | |||
local advisoryCell | local advisoryCell | ||
if advisory ~= "No Advisory" then | if advisory ~= "No Advisory" then | ||
| Line 649: | Line 352: | ||
end | end | ||
-- (E) Climate cell color | -- (E) Climate cell color | ||
local climateBG = getClimateBGColor(climateName) | local climateBG = getClimateBGColor(climateName) | ||
local climateCell = string.format( | local climateCell = string.format( | ||
Revision as of 03:54, 26 December 2024
Documentation for this module may be created at Module:BassaridiaForecast/doc
---------------------------------------------------------
-- Module:BassaridiaForecast
-- Provides a daily forecast table for Bassaridia with:
-- • PSSC date logic (Atosiel, Thalassiel, Opsitheiel)
-- • Color-coded climate cells (per your table)
-- • Color-coded “Today’s Weather” cells by event keywords
-- • Natural disaster advisories in red if triggered
-- • Checks for numeric highC
-- • Wind direction & speed
---------------------------------------------------------
local p = {}
---------------------------------------------------------
-- 1. Calendar System
---------------------------------------------------------
local function getCurrentDateInfo()
local startDate = os.time({year = 1999, month = 8, day = 6})
local secondsInDay = 86400
local daysPerYear = 183
local currentTime = os.time()
local totalDaysElapsed = math.floor((currentTime - startDate) / secondsInDay)
local yearFraction = totalDaysElapsed / daysPerYear
local psscYear = math.floor(yearFraction)
local dayOfYear = math.floor((yearFraction - psscYear) * daysPerYear) + 1
return {
psscYear = psscYear,
dayOfYear = dayOfYear
}
end
---------------------------------------------------------
-- 2. Determine the Season
-- 1..61 => Atosiel
-- 62..122 => Thalassiel
-- 123..183 => Opsitheiel
---------------------------------------------------------
local function getSeasonName(dayOfYear)
if dayOfYear <= 61 then
return "Atosiel"
elseif dayOfYear <= 122 then
return "Thalassiel"
else
return "Opsitheiel"
end
end
---------------------------------------------------------
-- 3. Weather Events (10 per climate-season)
-- (Paste your full sets of 10 events per climate-season here.)
---------------------------------------------------------
local climateEvents = {
-- Example partial data for demonstration:
["Humid Subtropical"] = {
Atosiel = {
"Morning drizzle and warm afternoon sunshine",
"Mild thunderstorm building by midday",
"Patchy fog at dawn, clearing toward lunch",
"Light rain with sunny breaks after noon",
"Gentle breezes, blossoming warmth, low humidity",
"Scattered clouds with a brief shower by dusk",
"Humid sunrise, comfortable high around midday",
"Overcast for part of the day, mild temperatures",
"Warm breezes carrying faint floral scents",
"Partial sun, warm with a slight chance of rain"
},
Thalassiel = {
"Hot, steamy day with intense midday heat",
"Tropical-like humidity, afternoon thunder possible",
"Intermittent heavy downpours, muggy evenings",
"High humidity and patchy thunderstorms late",
"Sun-scorched morning, scattered storms by dusk",
"Hazy sunshine, extremely warm all day",
"Thick humidity, chance of lightning late evening",
"Sticky air, short downpours in isolated spots",
"Heat advisory with only brief cooling at night",
"Nighttime storms lingering into early morning"
},
Opsitheiel = {
"Warm daytime, gentle evening breezes",
"Occasional rain, otherwise mild temperatures",
"Late-season warmth, scattered rain after sunset",
"Cooler mornings, returning to warmth by midday",
"Sparse cloud cover, tranquil weather overall",
"Fog at dawn, warm midday, pleasant night",
"Partial sun, comfortable humidity levels",
"Evening drizzle with mild breezes",
"Patchy haze, moderate warmth throughout the day",
"Short-lived shower, then clearing skies"
}
},
-- And so on for "Oceanic," "Subpolar Oceanic," "Mediterranean (Hot Summer)," etc.
}
---------------------------------------------------------
-- 4. Ranges for Temperature, Humidity, Rain
-- (Paste your climateTemperature table with hiMin, hiMax, etc.)
---------------------------------------------------------
local climateTemperature = {
-- Example partial data for demonstration:
["Humid Subtropical"] = {
Atosiel = { hiMin=18, hiMax=26, loMin=10, loMax=16, humMin=60, humMax=80, crMin=20, crMax=50, rfMin=1, rfMax=10 },
Thalassiel = { hiMin=25, hiMax=34, loMin=19, loMax=24, humMin=65, humMax=90, crMin=30, crMax=70, rfMin=2, rfMax=15 },
Opsitheiel = { hiMin=20, hiMax=28, loMin=12, loMax=18, humMin=50, humMax=75, crMin=15, crMax=40, rfMin=1, rfMax=8 }
},
-- And so on for your other climates...
}
---------------------------------------------------------
-- 5. Color-Coding "Today’s Weather" (getEventColor)
---------------------------------------------------------
local function getEventColor(eventText)
local textLower = eventText:lower()
if textLower:find("thunder") or textLower:find("storm") then
return "#FFC0C0" -- moderate pinkish-red for storms
elseif textLower:find("snow") or textLower:find("sleet") or textLower:find("flurries") then
return "#CCE6FF" -- moderate blue for snow
elseif textLower:find("rain") or textLower:find("drizzle") or textLower:find("downpour") then
return "#CCEEFF" -- soft aqua for rain
elseif textLower:find("dust") or textLower:find("desert") then
return "#FFFACD" -- lemon chiffon for dust
elseif textLower:find("hail") then
return "#E0FFFF" -- light cyan for hail
else
return "#F8F8F8" -- default light gray
end
end
---------------------------------------------------------
-- 6. Color-Code Climate Cells from your table
-- e.g. if spelled-out name is "Humid Subtropical," color #FFE4C4
---------------------------------------------------------
local function getClimateBGColor(climateName)
local map = {
["Humid Subtropical"] = "#FFE4C4", -- Cfa
["Oceanic"] = "#CCE5FF", -- Cfb
["Subpolar Oceanic"] = "#CCFFFF", -- Cfc
["Mediterranean (Hot Summer)"]= "#FFE4C4", -- Csa
["Hot Steppe"] = "#FFDFAF", -- BSh
["Hot Desert"] = "#FFD1DC", -- BWh
["Cold Steppe"] = "#FFECB3", -- BSk
["Subarctic"] = "#CAB3FF" -- Dfc
}
return map[climateName] or "#F8F8F8"
end
---------------------------------------------------------
-- 7. Disaster Profiles
---------------------------------------------------------
local cityDisasterProfiles = {
["Vaeringheim"] = {"flood", "heatwave", "thunderstorm"},
["Luminaria"] = {"flood", "landslide"},
-- ... etc. (Paste your entire cityDisasterProfiles table here)
}
---------------------------------------------------------
-- 8. Advisory Logic (red if triggered)
---------------------------------------------------------
local function getDisasterAdvisory(cityName, eventText, chanceOfRain, predictedRain, highC)
local disasterList = cityDisasterProfiles[cityName] or {}
local textLower = eventText:lower()
local advisories = {}
for _, disasterType in ipairs(disasterList) do
if disasterType == "flood" then
if chanceOfRain > 60 or textLower:find("heavy downpours") then
table.insert(advisories, "Flood Advisory")
end
elseif disasterType == "heatwave" then
if type(highC) == "number" and highC >= 32 then
table.insert(advisories, "Heatwave Warning")
end
elseif disasterType == "thunderstorm" then
if textLower:find("thunder") or textLower:find("storm") then
table.insert(advisories, "Thunderstorm Alert")
end
elseif disasterType == "snowstorm" then
if textLower:find("snow") or textLower:find("sleet") then
table.insert(advisories, "Snowstorm Warning")
end
elseif disasterType == "landslide" then
if chanceOfRain > 50 or textLower:find("heavy rain") or textLower:find("thunderstorm") then
table.insert(advisories, "Landslide Risk")
end
elseif disasterType == "forest fire" then
if textLower:find("hot") or chanceOfRain < 10 then
table.insert(advisories, "Forest Fire Risk")
end
elseif disasterType == "drought" then
if chanceOfRain < 5 then
table.insert(advisories, "Drought Alert")
end
elseif disasterType == "blizzard" then
if textLower:find("snow") or textLower:find("flurries") then
table.insert(advisories, "Blizzard Warning")
end
elseif disasterType == "dust storm" then
if textLower:find("dust") then
table.insert(advisories, "Dust Storm Advisory")
end
elseif disasterType == "coastal storm" then
if textLower:find("storm") then
table.insert(advisories, "Coastal Storm Alert")
end
end
end
if #advisories == 0 then
return "No Advisory"
else
return table.concat(advisories, "; ")
end
end
---------------------------------------------------------
-- 9. Random Weather Stats (wind direction, speed)
---------------------------------------------------------
local windDirections = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}
local function getRandomWeatherStats(climate, season)
local data = climateTemperature[climate] and climateTemperature[climate][season]
if not data then
-- Return numeric 0 to avoid comparing number with string
return {
highC=0, lowC=0, humidity=0,
chanceOfRain=0, predictedRain=0,
windDir="N/A", windSpeed=0
}
end
local hiC = math.random(data.hiMin, data.hiMax)
local loC = math.random(data.loMin, data.loMax)
local hum = math.random(data.humMin, data.humMax)
local cRain = math.random(data.crMin, data.crMax)
local pRain = 0
if cRain > 0 then
pRain = math.random(data.rfMin, data.rfMax)
end
local wDir = windDirections[math.random(#windDirections)]
local wSpd = math.random(0, 50)
return {
highC = hiC,
lowC = loC,
humidity = hum,
chanceOfRain = cRain,
predictedRain= pRain,
windDir = wDir,
windSpeed = wSpd
}
end
---------------------------------------------------------
-- 10. Celsius to Fahrenheit
---------------------------------------------------------
local function cToF(c)
return math.floor(c * 9/5 + 32 + 0.5)
end
---------------------------------------------------------
-- 11. Full City List
-- (Paste your entire cityData table here)
---------------------------------------------------------
local cityData = {
{city = "Vaeringheim", climate = "Humid Subtropical"},
{city = "Luminaria", climate = "Humid Subtropical"},
-- ... etc. for all major/minor cities...
}
---------------------------------------------------------
-- 12. Main Weather Forecast Table
---------------------------------------------------------
function p.weatherForecast(frame)
local dateInfo = getCurrentDateInfo()
local dayOfYear = dateInfo.dayOfYear
local yearNum = dateInfo.psscYear
local seasonName= getSeasonName(dayOfYear)
local out = {}
table.insert(out, "== Daily Weather Forecast ==\n")
table.insert(out, string.format(
"''(Day %d of Year %d PSSC, %s)''\n\n",
dayOfYear, yearNum, seasonName
))
-- Wiki table header
table.insert(out, '{| class="wikitable sortable" style="width:100%; text-align:left;"\n')
table.insert(out,
[[! City !! Climate !! Season !! High °C (°F) !! Low °C (°F) !! Humidity (%) !! Chance of Rain (%) !! Rainfall (mm) !! Wind Dir !! Wind Speed (km/h) !! Today's Weather !! Advisory
]]
)
-- Loop over all cities
for _, cityEntry in ipairs(cityData) do
local cityName = cityEntry.city
local climateName = cityEntry.climate
-- (A) Pick random event
local cTable = climateEvents[climateName]
local sTable = cTable and cTable[seasonName]
local forecast = "No data"
if sTable and #sTable > 0 then
forecast = sTable[math.random(#sTable)]
end
-- (B) Color for "Today’s Weather" cell
local weatherColor = getEventColor(forecast)
-- (C) Random stats
local stats = getRandomWeatherStats(climateName, seasonName)
local hiC = stats.highC
local loC = stats.lowC
local hum = stats.humidity
local cRain = stats.chanceOfRain
local pRain = stats.predictedRain
local wDir = stats.windDir
local wSpd = stats.windSpeed
-- Convert hiC, loC to Fahrenheit if numeric
local hiF = (type(hiC)=="number") and cToF(hiC) or "N/A"
local loF = (type(loC)=="number") and cToF(loC) or "N/A"
-- (D) Advisory
local advisory = getDisasterAdvisory(
cityName, forecast, cRain, pRain,
(type(hiC)=="number" and hiC or 0)
)
-- Red cell if advisory != "No Advisory"
local advisoryCell
if advisory ~= "No Advisory" then
advisoryCell = 'style="background-color:#FFBABA" | ' .. advisory
else
advisoryCell = advisory
end
-- (E) Climate cell color
local climateBG = getClimateBGColor(climateName)
local climateCell = string.format(
'style="background-color:%s" | %s',
climateBG, climateName
)
table.insert(out, "|-\n")
table.insert(out, string.format(
[[| %s || %s || %s || %s (%s) || %s (%s) || %s || %s || %s || %s || %s || style="background-color:%s" | %s || %s
]],
cityName,
climateCell,
seasonName,
tostring(hiC), tostring(hiF),
tostring(loC), tostring(loF),
tostring(hum),
tostring(cRain),
tostring(pRain),
wDir,
tostring(wSpd),
weatherColor, forecast,
advisoryCell
))
end
table.insert(out, "|}\n")
return table.concat(out)
end
return p