Module:Lab Rotation: Difference between revisions
From IdleOn MMO Wiki
No edit summary |
mNo edit summary |
||
(5 intermediate revisions by one other user not shown) | |||
Line 10: | Line 10: | ||
--- The format to display dates in. | --- The format to display dates in. | ||
local DATE_FORMAT = ' | local DATE_FORMAT = '%x' | ||
local CHIP_PREFIX = 'Lab | local CHIP_PREFIX = 'Lab - ' | ||
local JEWEL_PREFIX = 'Console Jewel ' | local JEWEL_PREFIX = 'Console Jewel ' | ||
Line 52: | Line 52: | ||
--- Formats a week into its date string. | --- Formats a week into its date string. | ||
--- @param week integer | --- @param week integer | ||
--- @return string | --- @return string | ||
local function formatDate(week) | local function formatDate(week) | ||
local day = tonumber(os.date("%d", week * SECONDS_PER_WEEK)) | |||
local month = os.date("%B", week * SECONDS_PER_WEEK) | |||
local year = os.date("%Y", week * SECONDS_PER_WEEK) | |||
local suffix | |||
if day == 1 or day == 21 or day == 31 then | |||
suffix = "st" | |||
elseif day == 2 or day == 22 then | |||
suffix = "nd" | |||
elseif day == 3 or day == 23 then | |||
suffix = "rd" | |||
else | |||
suffix = "th" | |||
end | |||
return string.format("%d%s %s, %d", day, suffix, month, year) | |||
end | end | ||
Line 126: | Line 141: | ||
local items = p._getItem(week + offset, slot) | local items = p._getItem(week + offset, slot) | ||
for _, item in ipairs(items) do | for _, item in ipairs(items) do | ||
local content = '[[File:' .. prefix .. item .. '.png]]' .. item | local content = '[[File:' .. prefix .. item .. '.png|32px]] ' .. item | ||
ret:tag('span'):addClass('lab-rotation-item'):wikitext(content) | ret:tag('span'):addClass('lab-rotation-item'):wikitext(content) | ||
Line 155: | Line 170: | ||
local items = p._getItem(week, slot) | local items = p._getItem(week, slot) | ||
if contains(items, item) then | if contains(items, item) then | ||
return formatDate(week) | local ret = mw.html.create('div') | ||
ret:tag('div'):wikitext(formatDate(week)) | |||
if week == getCurrentWeek() then | |||
ret:tag('div'):wikitext('Currently Available') | |||
else | |||
ret:tag('span'): | |||
tag('span'): | |||
wikitext('(in '):done(): | |||
tag('time'): | |||
addClass('countdown-timer'): | |||
attr('data-timestamp', week * SECONDS_PER_WEEK): | |||
attr('data-mode', 'labeled'): | |||
attr('data-min-unit', 'd'): | |||
done(): | |||
tag('span'): | |||
wikitext(')') | |||
end | |||
return tostring(ret); | |||
-- week is the time! | |||
-- <div> | |||
-- <span>formatDate(week)</span> | |||
-- <time data-timestamp="week*></time> | |||
-- </div> | |||
-- return formatDate(week) | |||
end | end | ||
end | end |
Latest revision as of 17:56, 7 October 2024
Documentation for this module may be created at Module:Lab Rotation/doc
require('strict')
local Random = require('Module:Random')
local Data = require('Module:Lab Rotation/Data')
local p = {}
--- The number of seconds in a week.
local SECONDS_PER_WEEK = 604800
--- The format to display dates in.
local DATE_FORMAT = '%x'
local CHIP_PREFIX = 'Lab - '
local JEWEL_PREFIX = 'Console Jewel '
--- Gets the current week
--- @return integer
local function getCurrentWeek()
return math.floor(os.time() / SECONDS_PER_WEEK)
end
--- Checks whether the table contains the item.
--- @generic T
--- @param tbl T[] The table
--- @param item T The item to search for
--- @return boolean
local function contains(tbl, item)
item = item:lower()
for _, e in ipairs(tbl) do
if item == e:lower() then
return true
end
end
return false
end
--- Checks whether the item is a chip.
--- @param item string The item to check
--- @return boolean
local function isChip(item)
return contains(Data.chips, item)
end
--- Checks whether the item is a jewel.
--- @param item string The item to check
--- @return boolean
local function isJewel(item)
return contains(Data.jewels, item)
end
--- Formats a week into its date string.
--- @param week integer
--- @return string
local function formatDate(week)
local day = tonumber(os.date("%d", week * SECONDS_PER_WEEK))
local month = os.date("%B", week * SECONDS_PER_WEEK)
local year = os.date("%Y", week * SECONDS_PER_WEEK)
local suffix
if day == 1 or day == 21 or day == 31 then
suffix = "st"
elseif day == 2 or day == 22 then
suffix = "nd"
elseif day == 3 or day == 23 then
suffix = "rd"
else
suffix = "th"
end
return string.format("%d%s %s, %d", day, suffix, month, year)
end
--- Generates a random number.
--- @param seed integer The seed
--- @param upper_bound integer The upper bound
--- @return integer
local function generateRandomNumber(seed, upper_bound)
local random = math.floor(Random:new(seed):rand() * 1000)
return upper_bound and (random % upper_bound) or random
end
--- Gets the item that appears in the specified slot during the specified week.
--- @param week integer The week
--- @param slot integer The item slot
function p._getItem(week, slot)
local choices = (slot == 3) and Data.jewels or Data.chips
local numChoices = (slot == 1) and #choices - 10 or #choices
local seed = week + ((slot - 1) * 500)
local item = generateRandomNumber(seed, numChoices)
local prevItem = generateRandomNumber(seed - 1, numChoices)
if prevItem == item then
local nextItem = generateRandomNumber(seed + 1, numChoices)
while item == prevItem or item == nextItem do
seed = seed + 765
item = generateRandomNumber(seed, numChoices)
end
end
-- Lua indices start at 1
item = item + 1
local ret = {}
-- Generate alternative items for Jade Emporium-exclusive jewels.
--
-- Note: The game currently has a bug which causes chips to be rerolled
-- as well as jewels if the bonus isn't unlocked. Once the bug is fixed,
-- remove the commented from the line below and delete this note.
if item >= 19 and item <= 21 --[[and slot == 2]] then
table.insert(ret, 1, choices[item - 10])
end
table.insert(ret, choices[item])
return ret
end
--- Template entry point for querying what items are currently in the shop.
--- @param frame table
--- @return string
function p.what(frame)
return p._what(frame.args)
end
--- Module entry point for querying what items are currently in the shop.
--- @param args { slot: integer, week?: integer, offset?: integer }
--- @return string
function p._what(args)
local offset = tonumber(args.offset) or 0
local week = tonumber(args.week) or getCurrentWeek()
local slot = tonumber(args.slot) or 1
local prefix = (slot == 3) and JEWEL_PREFIX or CHIP_PREFIX
assert(slot ~= nil, '"slot" is undefined')
local ret = mw.html.create('div')
local items = p._getItem(week + offset, slot)
for _, item in ipairs(items) do
local content = '[[File:' .. prefix .. item .. '.png|32px]] ' .. item
ret:tag('span'):addClass('lab-rotation-item'):wikitext(content)
end
return tostring(ret)
end
--- Template entry point for querying when an item will be available next.
--- @param frame table
--- @return string|osdate
function p.when(frame)
return p._when(frame.args)
end
--- Module entry point for querying when an item will be available next.
--- @param args { [1]: string }
--- @return string|osdate
function p._when(args)
local item = args[1]:lower()
local slots = isChip(item) and { 1, 2 } or isJewel(item) and { 3 } or nil
assert(slots ~= nil, 'Invalid item name: ' .. item)
local week = getCurrentWeek()
while true do
for _, slot in ipairs(slots) do
local items = p._getItem(week, slot)
if contains(items, item) then
local ret = mw.html.create('div')
ret:tag('div'):wikitext(formatDate(week))
if week == getCurrentWeek() then
ret:tag('div'):wikitext('Currently Available')
else
ret:tag('span'):
tag('span'):
wikitext('(in '):done():
tag('time'):
addClass('countdown-timer'):
attr('data-timestamp', week * SECONDS_PER_WEEK):
attr('data-mode', 'labeled'):
attr('data-min-unit', 'd'):
done():
tag('span'):
wikitext(')')
end
return tostring(ret);
-- week is the time!
-- <div>
-- <span>formatDate(week)</span>
-- <time data-timestamp="week*></time>
-- </div>
-- return formatDate(week)
end
end
week = week + 1
end
end
--- Module entry point for querying when an item will be available next.
--- @param frame table The template frame
--- @return string|osdate
function p.date(frame)
return p._date(frame.args)
end
--- Template entry point for querying when an item will be available next.
--- @param args { week?: integer, offset?: integer }
--- @return string|osdate
function p._date(args)
local week = tonumber(args.week) or getCurrentWeek()
local offset = tonumber(args.offset) or 0
return formatDate(week + offset)
end
return p