Module:IriniaCalendar: Difference between revisions
From DSRPG
No edit summary Tag: Manual revert |
No edit summary |
||
| Line 518: | Line 518: | ||
-- Calculate a person's age given their birth date | -- Calculate a person's age given their birth date | ||
function p.calculateAge(frame) | function p.calculateAge(frame) | ||
local args = frame.args | local args = frame.args or {} | ||
local parentArgs = (frame.getParent and frame:getParent().args) or {} | |||
-- pull each field, preferring the named arg in frame.args | |||
local birthDay = tonumber(args.day or parentArgs.day) or 1 | |||
local birthMonth = tonumber(args.month or parentArgs.month) or 1 | |||
local birthYear = tonumber(args.year or parentArgs.year) or 0 | |||
local birthDay = tonumber(args.day) or 1 | |||
local birthMonth = tonumber(args.month) or 1 | |||
local birthYear = tonumber(args.year) or 0 | |||
local birthDate = { | local birthDate = { | ||
day = birthDay, | day = birthDay, | ||
month = birthMonth, | month = birthMonth, | ||
year = birthYear | year = birthYear | ||
} | } | ||
local age = p.dateDifference(birthDate, calendar.current) | local age = p.dateDifference(birthDate, calendar.current) | ||
local years = string.match(age, "^(%d+) years?") | local years = string.match(age, "^(%d+) years?") | ||
return years or "0" | |||
end | end | ||
-- Calculate how long ago an event occurred | -- Calculate how long ago an event occurred | ||
Revision as of 18:58, 4 May 2025
Documentation for this module may be created at Module:IriniaCalendar/doc
-- Module:IriniaCalendar
-- A module for handling the custom calendar of Irinia
local p = {}
-- Configurable variables for the calendar system
local calendar = {
-- Current date in the world (can be updated as game progresses)
current = {
day = 4,
month = 5, -- Bloom Moon
year = 1236, -- AE (After Establishment)
},
-- Month names in order
months = {
[1] = "Frost Moon",
[2] = "Shadow Moon",
[3] = "Storm Moon",
[4] = "Mist Moon",
[5] = "Bloom Moon",
[6] = "Sun Moon",
[7] = "Thunder Moon",
[8] = "Harvest Moon",
[9] = "Ember Moon",
[10] = "Frost Moon",
[11] = "Twilight Moon",
[12] = "Star Moon"
},
-- Days in each month (adjust as needed for your calendar)
days_in_month = {
[1] = 30, -- Frost Moon
[2] = 28, -- Shadow Moon
[3] = 30, -- Storm Moon
[4] = 29, -- Mist Moon
[5] = 31, -- Bloom Moon
[6] = 31, -- Sun Moon
[7] = 30, -- Thunder Moon
[8] = 31, -- Harvest Moon
[9] = 30, -- Ember Moon
[10] = 31, -- Frost Moon
[11] = 28, -- Twilight Moon
[12] = 30 -- Star Moon
},
-- Days of the week (if your calendar uses a weekly cycle)
weekdays = {
[1] = "Silverday",
[2] = "Brassday",
[3] = "Woodday",
[4] = "Stoneday",
[5] = "Glassday",
[6] = "Steamday",
[7] = "Gearsday"
},
-- Seasons (useful for some calendar displays)
seasons = {
[1] = "Winter", -- Frost Moon, Shadow Moon
[2] = "Winter",
[3] = "Spring", -- Storm Moon, Mist Moon, Bloom Moon
[4] = "Spring",
[5] = "Spring",
[6] = "Summer", -- Sun Moon, Thunder Moon, Harvest Moon
[7] = "Summer",
[8] = "Summer",
[9] = "Autumn", -- Ember Moon, Frost Moon, Twilight Moon
[10] = "Autumn",
[11] = "Autumn",
[12] = "Winter", -- Star Moon
},
-- Era name (e.g., "AE" for "After Establishment")
era = "AE",
-- Days in a year
days_in_year = 359 -- Sum of all month days above
}
-- Update the current date (can be called from other modules or templates)
function p.updateCurrentDate(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
-- Get the new current date
calendar.current.day = tonumber(args.day) or calendar.current.day
calendar.current.month = tonumber(args.month) or calendar.current.month
calendar.current.year = tonumber(args.year) or calendar.current.year
-- Return confirmation
return "Current date updated to " .. p.formatDate(calendar.current)
end
-- Get the current date
function p.getCurrentDate(frame)
local args = frame.args
local format = "full"
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
-- Get format parameter if provided
if args.format then
format = args.format
end
-- Format and return the current date
return p.formatDate(calendar.current, format)
end
-- Convert numerical month to name
function p.getMonthName(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local month = tonumber(args.month) or 1
-- Ensure month is in valid range
if month < 1 or month > #calendar.months then
month = ((month - 1) % #calendar.months) + 1
end
return calendar.months[month]
end
-- Format a date according to the specified format
function p.formatDate(date, format)
format = format or "full"
local day = date.day or 1
local month = date.month or 1
local year = date.year or 0
-- Ensure month is in valid range
if month < 1 or month > #calendar.months then
month = ((month - 1) % #calendar.months) + 1
end
local monthName = calendar.months[month]
-- Different format options
if format == "full" then
return day .. " " .. monthName .. ", " .. year .. " " .. calendar.era
elseif format == "short" then
return day .. " " .. monthName .. ", " .. year
elseif format == "month-year" then
return monthName .. ", " .. year .. " " .. calendar.era
elseif format == "day-month" then
return day .. " " .. monthName
elseif format == "numeric" then
return day .. "/" .. month .. "/" .. year .. " " .. calendar.era
else
return day .. " " .. monthName .. ", " .. year .. " " .. calendar.era
end
end
-- Parse a date string into a date object
function p.parseDate(dateStr)
local day, monthName, year = string.match(dateStr, "(%d+)%s+(%a+%s*%a*),%s*(%d+)")
if not day or not monthName or not year then
return nil
end
-- Find the month number from the name
local month = nil
for i, name in ipairs(calendar.months) do
if string.lower(name) == string.lower(monthName) then
month = i
break
end
end
if not month then
return nil
end
return {
day = tonumber(day),
month = month,
year = tonumber(year)
}
end
-- Calculate total days from year 0
function p.totalDays(date)
if not date or not date.day or not date.month or not date.year then
return 0
end
local total = 0
-- Add days from complete years
total = total + date.year * calendar.days_in_year
-- Add days from complete months in current year
for i = 1, date.month - 1 do
total = total + calendar.days_in_month[i]
end
-- Add days in current month
total = total + date.day
return total
end
-- Calculate how many years, months, and days between two dates
function p.dateDifference(date1, date2)
-- If date2 is before date1, swap them and set a negative flag
local negative = false
if p.compareDate(date1, date2) > 0 then
date1, date2 = date2, date1
negative = true
end
-- Initialize with zeros
local years = 0
local months = 0
local days = 0
-- Start with the difference in years
years = date2.year - date1.year
-- Now calculate months and days, adjusting as needed
if date2.month > date1.month then
months = date2.month - date1.month
elseif date2.month < date1.month then
years = years - 1
months = 12 - date1.month + date2.month
else -- Same month
months = 0
end
-- Calculate days
if date2.day >= date1.day then
days = date2.day - date1.day
else
-- Need to borrow from months
if months > 0 then
months = months - 1
else
-- Need to borrow from years
if years > 0 then
years = years - 1
months = 11 -- We're setting to 11 because we'll add one below
end
end
-- Add one month (now that we've borrowed)
months = months + 1
-- Calculate the days, considering the length of the previous month
local prevMonth = date2.month - 1
if prevMonth < 1 then prevMonth = 12 end
days = calendar.days_in_month[prevMonth] - date1.day + date2.day
end
-- Format the result
local result = {}
if years ~= 0 then
table.insert(result, years .. " year" .. (years ~= 1 and "s" or ""))
end
if months ~= 0 then
table.insert(result, months .. " month" .. (months ~= 1 and "s" or ""))
end
if days ~= 0 or #result == 0 then
table.insert(result, days .. " day" .. (days ~= 1 and "s" or ""))
end
local output = table.concat(result, ", ")
-- Replace the last comma with "and" if there's more than one element
if #result > 1 then
output = string.gsub(output, ", ([^,]*)$", " and %1")
end
if negative then
output = output .. " ago"
end
return output
end
-- Compare two dates: returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2
function p.compareDate(date1, date2)
if date1.year < date2.year then return -1 end
if date1.year > date2.year then return 1 end
-- Same year, check month
if date1.month < date2.month then return -1 end
if date1.month > date2.month then return 1 end
-- Same year and month, check day
if date1.day < date2.day then return -1 end
if date1.day > date2.day then return 1 end
-- Dates are equal
return 0
end
-- Calculate time since a given date, relative to the current date
function p.timeSince(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local day = tonumber(args.day) or 1
local month = tonumber(args.month) or 1
local year = tonumber(args.year) or 0
local date = {
day = day,
month = month,
year = year
}
-- Calculate the difference between the provided date and the current date
return p.dateDifference(date, calendar.current)
end
-- Calculate time until a given date, relative to the current date
function p.timeUntil(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local day = tonumber(args.day) or 1
local month = tonumber(args.month) or 1
local year = tonumber(args.year) or 0
local date = {
day = day,
month = month,
year = year
}
-- Calculate the difference between the current date and the provided date
return p.dateDifference(calendar.current, date)
end
-- Format a timeline entry with a specific date and event text
function p.timelineEntry(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local day = tonumber(args.day) or 1
local month = tonumber(args.month) or 1
local year = tonumber(args.year) or 0
local text = args.text or ""
local format = args.format or "full"
local date = {
day = day,
month = month,
year = year
}
-- Format the date according to the specified format
local dateStr = p.formatDate(date, format)
-- Calculate how long ago this date was
local timeAgo = p.dateDifference(date, calendar.current)
-- Format the timeline entry
return "<div class='timeline-entry'><span class='timeline-date'>" .. dateStr .. "</span> <span class='timeline-ago'>(" .. timeAgo .. " ago)</span>: <span class='timeline-text'>" .. text .. "</span></div>"
end
-- Generate a calendar display for a specific month and year
function p.calendarDisplay(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local month = tonumber(args.month) or calendar.current.month
local year = tonumber(args.year) or calendar.current.year
-- Ensure month is in valid range
if month < 1 or month > #calendar.months then
month = ((month - 1) % #calendar.months) + 1
end
local daysInMonth = calendar.days_in_month[month]
local monthName = calendar.months[month]
-- Start building the calendar table
local output = "<table class='calendar-table'>\n"
output = output .. "<caption>" .. monthName .. " " .. year .. " " .. calendar.era .. "</caption>\n"
-- Add weekday headers
output = output .. "<tr class='calendar-header'>\n"
for _, dayName in ipairs(calendar.weekdays) do
output = output .. "<th>" .. dayName .. "</th>\n"
end
output = output .. "</tr>\n"
-- Calculate the weekday of the first day of the month
-- This is a simplified calculation assuming the first day of year 0 was weekday 1
local totalDays = p.totalDays({day = 1, month = month, year = year}) - 1
local firstWeekday = (totalDays % #calendar.weekdays) + 1
-- Start the first week
output = output .. "<tr>\n"
-- Add empty cells for days before the first of the month
for i = 1, firstWeekday - 1 do
output = output .. "<td class='calendar-empty'></td>\n"
end
-- Add the days of the month
local currentWeekday = firstWeekday
for day = 1, daysInMonth do
-- Check if this day is the current date
local isCurrentDate = (day == calendar.current.day and month == calendar.current.month and year == calendar.current.year)
local cellClass = isCurrentDate and "calendar-current-day" or "calendar-day"
output = output .. "<td class='" .. cellClass .. "'>" .. day .. "</td>\n"
-- Move to the next weekday
currentWeekday = currentWeekday + 1
-- Start a new week if necessary
if currentWeekday > #calendar.weekdays and day < daysInMonth then
output = output .. "</tr>\n<tr>\n"
currentWeekday = 1
end
end
-- Add empty cells for days after the end of the month
for i = currentWeekday, #calendar.weekdays do
output = output .. "<td class='calendar-empty'></td>\n"
end
-- Close the final week and the table
output = output .. "</tr>\n</table>"
return output
end
-- Generate an annual calendar display
function p.yearCalendar(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local year = tonumber(args.year) or calendar.current.year
-- Start building the year calendar
local output = "<div class='year-calendar'>\n"
output = output .. "<h2>Calendar for Year " .. year .. " " .. calendar.era .. "</h2>\n"
-- Add each month
for month = 1, #calendar.months do
output = output .. "<div class='month-calendar'>\n"
-- Create arguments for the month calendar
local monthArgs = {
month = month,
year = year
}
-- Generate the calendar for this month
output = output .. p.calendarDisplay({ args = monthArgs })
output = output .. "</div>\n"
end
output = output .. "</div>"
return output
end
-- Get the season for a given month
function p.getSeason(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local month = tonumber(args.month) or calendar.current.month
-- Ensure month is in valid range
if month < 1 or month > #calendar.months then
month = ((month - 1) % #calendar.months) + 1
end
return calendar.seasons[month]
end
-- Calculate a person's age given their birth date
function p.calculateAge(frame)
local args = frame.args or {}
local parentArgs = (frame.getParent and frame:getParent().args) or {}
-- pull each field, preferring the named arg in frame.args
local birthDay = tonumber(args.day or parentArgs.day) or 1
local birthMonth = tonumber(args.month or parentArgs.month) or 1
local birthYear = tonumber(args.year or parentArgs.year) or 0
local birthDate = {
day = birthDay,
month = birthMonth,
year = birthYear
}
local age = p.dateDifference(birthDate, calendar.current)
local years = string.match(age, "^(%d+) years?")
return years or "0"
end
-- Calculate how long ago an event occurred
function p.eventTimeAgo(frame)
local args = frame.args
-- If called via #invoke, get the args from the parent frame
if not args or not args[1] then
args = frame:getParent().args
end
local eventDay = tonumber(args.day) or 1
local eventMonth = tonumber(args.month) or 1
local eventYear = tonumber(args.year) or 0
local prefix = args.prefix or ""
local suffix = args.suffix or " ago"
local eventDate = {
day = eventDay,
month = eventMonth,
year = eventYear
}
-- Calculate the difference between the event date and the current date
local timeAgo = p.dateDifference(eventDate, calendar.current)
return prefix .. timeAgo .. suffix
end
return p