Module:HostStars

From MicrasWiki
Revision as of 06:46, 27 December 2024 by NewZimiaGov (talk | contribs) (Created page with "--------------------------------------------------------- -- Module: HostStars_Midnight -- Purpose: Provide a "starsForTonight" function that: -- 1) Uses Micras' 183-day orbit, 24-hour day, 22.5° tilt, -- 2) Approximates day length (~9..15 hours) with a sine wave, -- 3) Assigns random star rise/set times within the night, -- 4) Checks if each star is visible at EXACTLY midnight (00:00). -- -- Usage: -- {{#invoke:HostStars_Midnight|starsForTonight}} -----------...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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

---------------------------------------------------------
-- Module: HostStars_Midnight
-- Purpose: Provide a "starsForTonight" function that:
--   1) Uses Micras' 183-day orbit, 24-hour day, 22.5° tilt,
--   2) Approximates day length (~9..15 hours) with a sine wave,
--   3) Assigns random star rise/set times within the night,
--   4) Checks if each star is visible at EXACTLY midnight (00:00).
--
-- Usage:
--   {{#invoke:HostStars_Midnight|starsForTonight}}
---------------------------------------------------------

local p = {}

---------------------------------------------------------
-- 1. dayOfYear (Micras-based)
--    183-day orbit, start date=6 Aug 1999 => day=0
---------------------------------------------------------
local function getDayOfYearForPSSC()
    local startDate   = os.time({year = 1999, month = 8, day = 6})
    local secPerDay   = 86400
    local daysPerYear = 183

    local currentTime = os.time()
    local totalDays   = math.floor((currentTime - startDate) / secPerDay)

    -- fractional year
    local yearFrac    = totalDays / daysPerYear
    local psscYear    = math.floor(yearFrac)
    local dayOfYear   = math.floor((yearFrac - psscYear) * daysPerYear) + 1
    return dayOfYear
end

---------------------------------------------------------
-- 2. Sine-based day length at latitude=44°, tilt=22.5°
--    We'll approximate day length from ~9h to ~15h:
--      dayLength = base + amplitude * sin(2π*(dayOfYear - offset)/183)
--    where base=12, amplitude=3 => range [9..15].
--    offset=81 => "longest day" near day 81, purely by choice.
---------------------------------------------------------
local function getApproxDayLength(dayOfYear)
    local base      = 12   -- 12h is average day length
    local amplitude = 3    -- ±3 => from 9 to 15
    local offset    = 81   -- shift so max day ~ mid-year

    local sineTerm  = math.sin( (2 * math.pi / 183) * (dayOfYear - offset) )
    local length    = base + amplitude * sineTerm
    return length  -- hours
end

---------------------------------------------------------
-- 3. Star Data (from "Top Image," Northern Hemisphere)
---------------------------------------------------------
local starDataNorth = {
    { name="Agave",     starClass="M",       latitude=29.5 },
    { name="Amaäz",     starClass="K",       latitude=31   },
    { name="Amáenu",    starClass="G",       latitude=45   },
    { name="Amap",      starClass="A",       latitude=55   },
    { name="Amazä",     starClass="F",       latitude=39   },
    { name="Atämios",   starClass="F",       latitude=56   },
    { name="Aprobelle", starClass="A",       latitude=59   },
    { name="Azos",      starClass="Galaxy",  latitude=60   },
    { name="Bebeakaus", starClass="K",       latitude=30.5 },
    { name="Bulhanu",   starClass="A",       latitude=40   },
    { name="Crösacío",  starClass="K",       latitude=17   },
    { name="Danaß",     starClass="A",       latitude=67   },
    { name="Dilëtaz",   starClass="G",       latitude=36   },
    { name="Dranamos",  starClass="A",       latitude=58   },
    { name="Gaht",      starClass="G",       latitude=29   },
    { name="Häpi",      starClass="F",       latitude=78   },
    { name="Hazaméos",  starClass="A",       latitude=72   },
    { name="Liléigos",  starClass="F",       latitude=18   },
    { name="Nyama",     starClass="F",       latitude=64   },
    { name="Ocananus",  starClass="F",       latitude=60.5 },
    { name="Orebele",   starClass="F",       latitude=22   },
    { name="Osiríos",   starClass="G",       latitude=53   },
    { name="Pythe",     starClass="A",       latitude=45   },
    { name="Sanashalo", starClass="G",       latitude=27   },
    { name="Tä",        starClass="F",       latitude=39.5 },
    { name="Vï",        starClass="A",       latitude=46   },
    { name="Wedíos",    starClass="A",       latitude=54   },
}

---------------------------------------------------------
-- 4. Convert decimal hours to "HH:MM"
---------------------------------------------------------
local function hourToHM(decimalHour)
    local hh = math.floor(decimalHour)
    local mm = math.floor((decimalHour - hh) * 60 + 0.5)
    hh = hh % 24
    return string.format("%02d:%02d", hh, mm)
end

---------------------------------------------------------
-- 5. MAIN: starsForTonight
--    1) dayOfYear => approximate dayLen => nightLen=24-dayLen
--    2) define sunrise, sunset
--    3) star rise in [sunset..(sunset+some fraction)], set later
--    4) check if star is visible at midnight (00:00 local).
---------------------------------------------------------
function p.starsForTonight(frame)
    local dayOfYear = getDayOfYearForPSSC()
    local dailySeed = (os.date("*t").year * 1000) + dayOfYear
    math.randomseed(dailySeed)

    local dayLen  = getApproxDayLength(dayOfYear)   -- ~9..15
    local nightLen= 24 - dayLen

    -- We'll assume "sunrise = 12 - dayLen/2"
    -- so day centered around ~noon. Then "sunset = sunrise + dayLen"
    local sunrise = 12 - (dayLen/2)
    local sunset  = sunrise + dayLen

    -- We'll define star rise times after sunset, up until well into night
    local nightStart = sunset
    local nightEnd   = math.min(sunset + nightLen, 24)  -- clamp to midnight if needed

    local queryTime  = 0.0  -- EXACT midnight local time

    local out = {}
    table.insert(out, "=== Host Stars Visible at Midnight (Vaeringheim ~44°N) ===\n")
    table.insert(out, string.format(
        "''DayOfYear=%d, Approx. DayLen=%.1fh, Sunrise=%.2f, Sunset=%.2f''\n\n",
        dayOfYear, dayLen, sunrise, sunset
    ))

    table.insert(out, '{| class="wikitable" style="width:100%; text-align:left;"\n')
    table.insert(out, "! Star Name || Star Class || Rise Time || Set Time || Visible @ 00:00?\n")

    for _, star in ipairs(starDataNorth) do
        -------------------------------------------------------
        -- random star rise in the evening or late night
        -------------------------------------------------------
        local rise = nightStart + math.random()*(nightLen*0.5)
        if rise>24 then
            rise = rise - 24  -- crosses midnight
        end

        -- star set: some random fraction after rise
        local starSet = rise + math.random()*(nightLen*0.5 + 1.0)
        if starSet>24 then
            starSet = starSet -24
        end

        -- Format times
        local riseStr = hourToHM(rise)
        local setStr  = hourToHM(starSet)

        -- is star up at midnight?
        local isVisible
        if rise < starSet then
            -- typical (doesn't cross midnight)
            if (rise <= queryTime) and (queryTime < starSet) then
                isVisible = "Yes"
            else
                isVisible = "No"
            end
        else
            -- star crosses midnight
            if (queryTime >= rise) or (queryTime < starSet) then
                isVisible = "Yes"
            else
                isVisible = "No"
            end
        end

        table.insert(out, "|-\n")
        table.insert(out, string.format("| %s || %s || %s || %s || %s\n",
            star.name, star.starClass, riseStr, setStr, isVisible))
    end

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

return p