Module:AutoUpdateAgPrices

From MicrasWiki
Jump to navigationJump to search

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

---------------------------------------------------------
-- Module:DailyPriceTable
-- Generates a table of daily-updated product prices,
-- with each cell changing automatically once per day.
--
-- Features:
--  • Seeds randomness each day using localTime.year + localTime.yday
--  • No manual intervention required
--  • Tier prices derived from the final adjusted price
--  • Minor event-based price boost for special days
---------------------------------------------------------

local p = {}

---------------------------------------------------------
-- 1. getCurrentDate
--    Determines today's PSSC date and returns:
--      * dateString in "day/month/year [PSSC]"
--      * dayOfMonth (1..61 or 1..61 or 1..61)
--      * month (1=Atosiel, 2=Thalassiel, 3=Opsitheiel)
---------------------------------------------------------
local function getCurrentDate()
    local startDate = os.time({year = 1999, month = 8, day = 6})
    local secondsInDay = 86400
    local daysPerYear = 183

    local currentDate = os.time()
    local totalDaysElapsed = math.floor((currentDate - 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

    return string.format("%d/%d/%d [[PSSC]]", dayOfMonth, month, psscYear), dayOfMonth, month
end

---------------------------------------------------------
-- 2. Product Data
---------------------------------------------------------
local products = {
    {"Rice", "Gladeseed Farmers' Union", 9.00, "tons"},
    {"Edible Algae", "Gladeseed Farmers' Union", 21.00, "tons"},
    {"Shrimp", "Gladeseed Farmers' Union", 15.00, "tons"},
    {"Anterran Spicy Onion", "Gladeseed Farmers' Union", 18.00, "tons"},
    {"Queen's Garlic", "Gladeseed Farmers' Union", 27.00, "tons"},
    {"Morovian Water Buffalo", "Atterian Cattle Drivers", 6.60, "herds"},
    {"Unprocessed Noctic-Rabrev Flower", "Noctic Fleet", 6.00, "bales"},
    {"Processed Noctic Rabrev Flower", "Noctic Fleet", 2.50, "crates"},
    {"Noctic-Rabrev Flower Concentrate", "Noctic Fleet", 3.00, "barrels"},
    {"Unprocessed Noctic-Rabrev Leaf", "Noctic Fleet", 15.00, "bales"},
    {"Processed Noctic-Rabrev Leaf", "Noctic Fleet", 5.79, "crates"},
    {"Unprocessed Noctic-Rabrev Leaf Concentrate", "Noctic Fleet", 6.00, "barrels"},
    {"Processed Noctic-Rabrev Leaf Concentrate", "Noctic Fleet", 3.00, "barrels"},
    {"Manwine", "Jogiani Merchants of Manwine", 2.07, "barrels"},
    {"Milkwine", "Jogiani Merchants of Manwine", 6.00, "barrels"},
    {"Zoe Elm Resin (Unrefined)", "Keepers of the Grove of Zoe Elm", 0.03, "barrels"},
    {"Zoe Elm Resin (Refined)", "Keepers of the Grove of Zoe Elm", 0.04, "barrels"},
    {"Sea Elm Flavored Mead", "Sea-Elm Southern Meadery", 1.11, "barrels"},
    {"Wheat", "Plains of Jogi", 0.30, "tons"},
    {"Oats", "Plains of Jogi", 0.23, "tons"},
    {"Cereal", "Plains of Jogi", 0.52, "pallets"},
    {"Hay", "Plains of Jogi", 0.45, "bales"},
    {"Ale of the Night", "Ale of the Night Central Brewery", 2.43, "barrels"},
    {"Camels", "Camel Herders of the Jangsong Province", 1.04, "herds"},
    {"Camel Meat", "Camel Herders of the Jangsong Province", 34.65, "tons"},
    {"Camel Milk", "Camel Herders of the Jangsong Province", 5.20, "barrels"},
    {"Camel Hump Water", "Camel Herders of the Jangsong Province", 3.47, "barrels"},
    {"Camel Hump Water Tea", "Camel Herders of the Jangsong Province", 0.86, "barrels"},
    {"Pearls", "Anterran Imports and Services", 0.79, "sacks"},
    {"Abalone", "Anterran Imports and Services", 2.64, "crates"},
    {"Opium", "Merchant Guild of the Poppy Goddess", 0.18, "sacks"},
    {"Hash", "Merchant Guild of the Poppy Goddess", 0.17, "sacks"},
    {"Mead", "Grand Cave Bee Meadery", 0.49, "barrels"},
    {"Cinammon", "Cinammon Plains of Roue", 0.45, "tons"},
    {"Velvet Worm Meat", "The Velvet Company", 1.04, "tons"},
    {"Velvet Worm Eggs", "The Velvet Company", 0.35, "crates"},
    {"Silk", "Seamstresses of Rouge", 5.00, "rolls"},
    {"Horehound Mead", "Salurian Temple of Sacred Horehound", 0.05, "barrels"},
    {"Horehound Beer", "Salurian Temple of Sacred Horehound", 0.07, "barrels"},
    {"Sea Cow Beef", "Bulhanu Ranchers' Association", 8.50, "tons"},
    {"Atterian Armored Pufferfish", "Suncliff Fisheries", 3.00, "tons"},
    {"Morovian Saucer Eyed Giant Eel", "Suncliff Fisheries", 7.50, "tons"},
    {"Amina Crab", "Suncliff Fisheries", 6.00, "tons"},
    {"Mugwort Oil", "Ministers of Mistress Mugwort", 0.35, "barrels"},
    {"Ground Mugwort", "Ministers of Mistress Mugwort", 0.75, "sacks"},
    {"Mugwort Tincture", "Ministers of Mistress Mugwort", 0.10, "barrels"},
    {"Blood InfusedRed Wine", "Blood Vineyards of the Far North", 0.39, "barrels"},
    {"Wisp Rice", "Norsolyrian Wisp Rice Farmers Association", 15.00, "tons"},
    {"Giid-Lisea-Eda", "Giid Lisea Ranching Import Company", 0.41, "shipments"},
    {"Vaeringheim Turkey Meat", "Bird Keepers of Saluria", 1.07, "tons"},
    {"Salurian Swamp Quail Eggs", "Bird Keepers of Saluria", 12.00, "crates"},
    {"Giant Fanged Penguin Blubber", "Hunters of the Giant Fanged Penguin", 25.00, "tons"},
    {"Giant Fanged Penguin Blubber Oil Extract", "Hunters of the Giant Fanged Penguin", 5.00, "barrels"},
}

---------------------------------------------------------
-- 3. Special Date Events
---------------------------------------------------------
local events = {
    ["1,6"] = "Bayram al-Nur (Festival of Light) [Vaeringheim]",
    ["1,18"] = "Chag Or Hadash (Festival of New Light) [Luminaria]",
    ["1,30"] = "Symposion Eirinis (Symposium of Harmony) [Serena]",
    ["1,43"] = "Alev Günü (Day of Flame) [Pyralis]",
    ["1,48"] = "Day of Abandonment [Vaeringheim]",
    ["1,55"] = "Tikkun Tzel (Repair of Shadows) [Symphonara]",
    ["2,6"] = "Panegyris Chrysou (Golden Gathering) [Aurelia]",
    ["2,17"] = "Constitution Day [Luminaria]",
    ["2,19"] = "Mehtap Dalgası (Moonlit Tide) [Vaeringheim]",
    ["2,31"] = "Oneiro Foteino (Dream of Illumination) [Somniumpolis]",
    ["2,39"] = "Anniversary of victory in the New South Jangsong Campaign [Nexa]",
    ["2,44"] = "Erev Galgal (Eve of Cycles) [Nexa]",
    ["2,45"] = "Bassaridia Festival [Somniumpolis]",
    ["2,48"] = "Anniversary of victory in the Southern Lake Morovia Campaign [Somniumpolis]",
    ["2,54"] = "Leilat al-Kamar (Night of the Moon) [Lunalis Sancta]",
    ["2,61"] = "Taşrakah (Reverence of the Stone) [Luminaria]",
    ["3,6"] = "Chag Tvuah (Festival of Harvest) [Sylvapolis]",
    ["3,18"] = "Anagenesis Eirmos (Procession of Rebirth) [Acheron]",
    ["3,28"] = "Panagia Therizis (Holy Day of the Reaper) [Sylvapolis]",
    ["3,37"] = "Anniversary of victory in the Morovian Frontier Campaign [Acheron]",
    ["3,43"] = "Karnavali Thysias (Carnival of Celebration) [Erythros]",
    ["3,53"] = "Sefar Yashar (Straight Path Celebration) [Catonis Atrium]",
}

---------------------------------------------------------
-- 4. simulatePriceChange
--    Randomly modifies the base price daily,
--    applying a slight additional boost if
--    a special event occurs on that dateKey.
---------------------------------------------------------
local function simulatePriceChange(basePrice, dayOfMonth, month)
    local dateKey = string.format("%d,%d", month, dayOfMonth)
    local changeFactor = math.random(-20, 20) / 100
    local explanation

    if events[dateKey] then
        explanation = events[dateKey] .. ": Prices influenced by event dynamics."
        changeFactor = changeFactor + 0.05  -- small boost for special events
    else
        explanation = "General market fluctuations."
    end

    local newPrice = math.floor((basePrice * (1 + changeFactor)) * 100) / 100
    return newPrice, changeFactor, explanation
end

---------------------------------------------------------
-- 5. determinePriceLevel
--    Example logic: if adjustedPrice < basePrice => "High"
--    otherwise => "Low".
---------------------------------------------------------
local function determinePriceLevel(basePrice, adjustedPrice)
    if adjustedPrice < basePrice then
        return "High"
    else
        return "Low"
    end
end

---------------------------------------------------------
-- 6. MAIN Table Generation
---------------------------------------------------------
function p.generateTable()
    -------------------------------------------------------
    -- Step A: create a daily seed for randomness
    -- Uses year + yday to ensure each day is unique
    -------------------------------------------------------
    local localTime = os.date("*t")
    local dailySeed = localTime.year * 1000 + localTime.yday
    math.randomseed(dailySeed)

    -- Step B: gather date info
    local dateString, dayOfMonth, month = getCurrentDate()

    -- Step C: build table header
    local wikitable = 
        "{| class=\"wikitable\"\n" ..
        "! Date (Day/Month/Year [[PSSC]]) !! Product !! Producing Company !! Base Price !! Price Level !! Tier III Price !! Tier II Price !! Tier I Price !! Units !! Explanation\n"

    -- We’ll track totals so we can compare average base vs. average new.
    local totalBase, totalNew = 0, 0
    local count = 0

    -- Step D: process each product with new daily random changes
    for _, product in ipairs(products) do
        local name     = product[1]
        local company  = product[2]
        local basePrice= product[3]
        local unit     = product[4]

        -- 1) Adjust price with daily random change
        local newPrice, changeFactor, explanation = simulatePriceChange(basePrice, dayOfMonth, month)

        -- 2) Determine if "High" / "Low" based on basePrice
        local priceLevel = determinePriceLevel(basePrice, newPrice)

        -- 3) Tier prices
        local tierIIIPrice = math.floor((newPrice / 3) * 100) / 100
        local tierIIPrice  = math.floor((newPrice * 2 / 3) * 100) / 100
        local tierIPrice   = newPrice

        -- 4) Accumulate totals for later average
        totalBase = totalBase + basePrice
        totalNew = totalNew + newPrice
        count = count + 1

        -- 5) Insert row
        wikitable = wikitable .. string.format(
            "|-\n| %s || %s || %s || %.2f || %s || %.2f || %.2f || %.2f || %s || %s\n",
            dateString,
            name,
            company,
            basePrice,
            priceLevel,
            tierIIIPrice,
            tierIIPrice,
            tierIPrice,
            unit,
            explanation
        )
    end

    -- Step E: compute average and determine if overall "High" or "Low"
    local avgBase = totalBase / count
    local avgNew = totalNew / count
    -- Reuse the same logic: if adjusted < base => "High" else => "Low"
    local averagePriceLevel
    if avgNew < avgBase then
        averagePriceLevel = "High"
    else
        averagePriceLevel = "Low"
    end

    -- Step F: add a final row at the bottom
    wikitable = wikitable .. string.format(
        "|-\n! colspan=\"10\" | Average adjusted price (%.2f) compared to average base price (%.2f) is **%s**.\n",
        avgNew, avgBase, averagePriceLevel
    )

    -- Close table
    wikitable = wikitable .. "|}"
    return wikitable
end

return p