Module:BassaridMarketActivity
From MicrasWiki
Jump to navigationJump to search
Documentation for this module may be created at Module:BassaridMarketActivity/doc
--------------------------------------------------------- -- Module: BassaridiaDailyInvestorTable -- Generates a daily table of investor stock activity -- with half increasing, half decreasing. No investor -- can gain or lose more than 30% from their start. -- Reasons are unique per investor per day. --------------------------------------------------------- local p = {} --------------------------------------------------------- -- 1. getCurrentDate: returns "DD/MM/YYYY PSSC" + dayOfYear --------------------------------------------------------- local function getCurrentDate() local startDate = os.time({year = 1999, month = 8, day = 6}) local secondsInDay = 86400 local daysPerYear = 183 local now = os.time() local totalDaysElapsed = math.floor((now - startDate) / secondsInDay) local yearFraction = totalDaysElapsed / daysPerYear local psscYear = math.floor(yearFraction) local dayOfYear = math.floor((yearFraction - psscYear) * daysPerYear) + 1 -- simplistic approach: 3 "months" in the 183-day year local month, dayOfMonth if dayOfYear <= 61 then month = 1 dayOfMonth = dayOfYear elseif dayOfYear <= 122 then month = 2 dayOfMonth = dayOfYear - 61 else month = 3 dayOfMonth = dayOfYear - 122 end local dateString = string.format("%d/%d/%d PSSC", dayOfMonth, month, psscYear) return dateString, dayOfYear end --------------------------------------------------------- -- 2. Investor Data --------------------------------------------------------- local investors = { { name = "Vaeringheim Regional Investor", stocks = 17424 }, { name = "Alpazkigz Regional Investor", stocks = 16214 }, { name = "Odiferia Regional Investor", stocks = 14718 }, { name = "Hafaan Regional Investor", stocks = 3630 }, { name = "Jeseri Regional Investor", stocks = 1870 }, { name = "Hatch Ministry Regional Investor", stocks = 7810 }, { name = "New South Jangsong Division", stocks = 11085 }, { name = "Haifan Bassaridia Division", stocks = 12500 }, } --------------------------------------------------------- -- 3. Reasons for Increase / Decrease --------------------------------------------------------- local increaseReasons = { "Improved logistics at the General Port attracted new investors.", "An influx of goods from Delphica boosted trade volume at the port.", "High demand for Noctic-Rabrev exports raised investor confidence.", "Completion of a new shipping lane connecting Nexa increased activity.", "Successful negotiations with Erythros merchants expanded trade.", "Festival of Light in Vaeringheim drove significant port activity.", "High attendance at the Bassaridia Trade Symposium enhanced reputation.", "Discovery of new mineral resources near Acheron increased export potential.", "A surge in ceremonial wine exports from the Blood Vineyards bolstered ops.", "Efficient cargo handling improvements boosted investor sentiment.", "Seasonal agricultural exports from Jogi saw a sharp increase.", "High sales of pearl and abalone products boosted port traffic.", "Luxury goods from Tel-Amin attracted new high-end investors.", "Port capacity expansion in Suncliff improved competitiveness.", "Improved relations with Maskmakers Guild stabilized trade routes.", "Increased fishing yields around Lake Morovia led to more port activity.", "Enhanced security measures at the Port reduced piracy concerns.", "Cultural appreciation for Horehound exports boosted confidence.", "Trade deals with Saluria expanded port usage significantly.", "Demand for silk from the Seamstresses of Rouge improved port revenue.", "Moonlit Tide celebrations increased ceremonial goods traffic.", "Launch of new Garganid fertilizer shipments attracted agriculture investors.", "Global interest in sacred resin exports enhanced shipments.", "Marketing campaign highlighted the Port's strategic location.", "Completion of high-speed rail connections boosted trade efficiency." } local decreaseReasons = { "Pirate raids in the Strait of Haifa disrupted shipments to the Port.", "Unfavorable weather delayed agriculture exports from Plains of Jogi.", "Labor shortages in the Port caused cargo-handling delays.", "A major fire in Salurian sacred groves reduced resin exports.", "Rising costs of Noctic-Rabrev cultivation hurt confidence.", "Unrest in Jangsong Province disrupted camel meat shipments.", "Currency fluctuations in Vaeringheim affected stability.", "Economic sanctions on neighbors reduced export activity.", "Decline in ceremonial artifact production lowered traffic.", "Cultural disputes over Horehound caused export delays.", "Counterfeit relics in Nexa harmed the port's reputation.", "Fishing yields were outpaced by demand, reducing shipments.", "Decline in pearl quality from Anterran sources lowered interest.", "Shortage of ceremonial wine from Blood Vineyards cut exports.", "Unrest among Maskmaker merchants disrupted trade agreements.", "Less demand for silk from Seamstresses of Rouge impacted flows.", "Collapse of trade agreement with Tel-Amin lowered volume.", "Seasonal labor shortages shrank port shipments significantly.", "Disruptions in Suncliff Fisheries slowed aquatic exports.", "Alternative shipping routes bypassed the Port altogether.", "Economic downturn in Lunalis Sancta reduced investor interest.", "Lingering piracy concerns in Haifan waters harmed confidence.", "Failure at Bassaridia Trade Symposium lowered traffic.", "Natural disasters near Acheron destroyed key routes.", "Sabotage of port infrastructure caused shipping delays." } --------------------------------------------------------- -- 4. Utility for Unique Reasons --------------------------------------------------------- local function popUniqueReason(list) if #list == 0 then return "No reason available (out of reasons)." end local rnd = math.random(#list) local chosen = list[rnd] table.remove(list, rnd) return chosen end --------------------------------------------------------- -- 5. Force half Inc, half Dec --------------------------------------------------------- local function assignUpDown(count) local half = math.floor(count / 2) local arr = {} for i = 1, half do arr[i] = "Inc" end for i = half+1, count do arr[i] = "Dec" end -- shuffle for i = #arr, 2, -1 do local j = math.random(i) arr[i], arr[j] = arr[j], arr[i] end return arr end --------------------------------------------------------- -- 6. Main generator --------------------------------------------------------- function p.generateTable(frame) -- Date-based seed local dateString, dayOfYear = getCurrentDate() local localTime = os.date("*t") local dailySeed = localTime.year * 1000 + localTime.yday math.randomseed(dailySeed) local stockPrice = 30 local n = #investors local updown = assignUpDown(n) -- Copy reason arrays so we can remove used ones local incPool = {} for _, r in ipairs(increaseReasons) do incPool[#incPool+1] = r end local decPool = {} for _, r in ipairs(decreaseReasons) do decPool[#decPool+1] = r end -- Table header local out = {} table.insert(out, '{| class="wikitable" style="text-align:center; width:100%;"') table.insert(out, "|-") table.insert(out, "! Date") table.insert(out, "! Investor") table.insert(out, "! Stocks at Start") table.insert(out, "! Stocks Bought") table.insert(out, "! Stocks Sold") table.insert(out, "! Stocks at End") table.insert(out, "! Value at Start (Polis)") table.insert(out, "! Value at End (Polis)") table.insert(out, "! Change") table.insert(out, "! Reason") local totalStartValue = 0 local totalEndValue = 0 -- For each investor for i, inv in ipairs(investors) do local stocksStart = inv.stocks local label = updown[i] -- "Inc" or "Dec" -- ensure final net won't exceed 30% from start local maxDelta = math.floor(stocksStart * 0.3) if maxDelta < 1 then maxDelta = 1 end local buy=0 local sell=0 if label == "Inc" then buy = math.random(1, maxDelta) sell = math.random(0, buy-1) else sell = math.random(1, maxDelta) buy = math.random(0, sell-1) end local stocksEnd = stocksStart + buy - sell local valueStart = stocksStart * stockPrice local valueEnd = stocksEnd * stockPrice totalStartValue = totalStartValue + valueStart totalEndValue = totalEndValue + valueEnd local changeWord if stocksEnd > stocksStart then changeWord = "Increased" elseif stocksEnd < stocksStart then changeWord = "Decreased" else changeWord = "No Change" end local reason if changeWord == "Increased" then reason = popUniqueReason(incPool) elseif changeWord == "Decreased" then reason = popUniqueReason(decPool) else -- If No Change, we can draw from either pool -- to avoid duplication, let's pick from incPool reason = popUniqueReason(incPool) end table.insert(out, "|-") table.insert(out, string.format("| %s", dateString)) table.insert(out, string.format("| %s", inv.name)) table.insert(out, string.format("| %d", stocksStart)) table.insert(out, string.format("| %d", buy)) table.insert(out, string.format("| %d", sell)) table.insert(out, string.format("| %d", stocksEnd)) table.insert(out, string.format("| %d", valueStart)) table.insert(out, string.format("| %d", valueEnd)) table.insert(out, string.format("| %s", changeWord)) table.insert(out, string.format("| %s", reason)) end -- Totals row table.insert(out, "|-") table.insert(out, string.format("| colspan=\"6\" | Totals")) table.insert(out, string.format("| %d", totalStartValue)) table.insert(out, string.format("| %d", totalEndValue)) table.insert(out, "| ") table.insert(out, "| ") table.insert(out, "|}") return table.concat(out, "\n") end return p