Codechange: Move date consts and functions to CalendarTime and TimerGameCalendar classes

This commit is contained in:
Tyler Trahan
2023-08-16 09:43:31 -04:00
parent fca2b37726
commit 77173a6a10
66 changed files with 400 additions and 393 deletions

View File

@@ -68,42 +68,42 @@ static const uint16_t _accum_days_for_month[] = {
* @param date the date to convert from
* @param ymd the year, month and day to write to
*/
/* static */ void TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date, YearMonthDay *ymd)
/* static */ void TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date, TimerGameCalendar::YearMonthDay *ymd)
{
/* Year determination in multiple steps to account for leap
* years. First do the large steps, then the smaller ones.
*/
/* There are 97 leap years in 400 years */
TimerGameCalendar::Year yr = 400 * (static_cast<int32_t>(date) / (DAYS_IN_YEAR * 400 + 97));
int rem = static_cast<int32_t>(date) % (DAYS_IN_YEAR * 400 + 97);
TimerGameCalendar::Year yr = 400 * (static_cast<int32_t>(date) / (CalendarTime::DAYS_IN_YEAR * 400 + 97));
int rem = static_cast<int32_t>(date) % (CalendarTime::DAYS_IN_YEAR * 400 + 97);
uint16_t x;
if (rem >= DAYS_IN_YEAR * 100 + 25) {
if (rem >= CalendarTime::DAYS_IN_YEAR * 100 + 25) {
/* There are 25 leap years in the first 100 years after
* every 400th year, as every 400th year is a leap year */
yr += 100;
rem -= DAYS_IN_YEAR * 100 + 25;
rem -= CalendarTime::DAYS_IN_YEAR * 100 + 25;
/* There are 24 leap years in the next couple of 100 years */
yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
rem = (rem % (DAYS_IN_YEAR * 100 + 24));
yr += 100 * (rem / (CalendarTime::DAYS_IN_YEAR * 100 + 24));
rem = (rem % (CalendarTime::DAYS_IN_YEAR * 100 + 24));
}
if (!TimerGameCalendar::IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
if (!TimerGameCalendar::IsLeapYear(yr) && rem >= CalendarTime::DAYS_IN_YEAR * 4) {
/* The first 4 year of the century are not always a leap year */
yr += 4;
rem -= DAYS_IN_YEAR * 4;
rem -= CalendarTime::DAYS_IN_YEAR * 4;
}
/* There is 1 leap year every 4 years */
yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
rem = rem % (DAYS_IN_YEAR * 4 + 1);
yr += 4 * (rem / (CalendarTime::DAYS_IN_YEAR * 4 + 1));
rem = rem % (CalendarTime::DAYS_IN_YEAR * 4 + 1);
/* The last (max 3) years to account for; the first one
* can be, but is not necessarily a leap year */
while (rem >= (TimerGameCalendar::IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
rem -= TimerGameCalendar::IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
while (rem >= (TimerGameCalendar::IsLeapYear(yr) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR)) {
rem -= TimerGameCalendar::IsLeapYear(yr) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
yr++;
}
@@ -131,7 +131,7 @@ static const uint16_t _accum_days_for_month[] = {
/* Account for the missing of the 29th of February in non-leap years */
if (!TimerGameCalendar::IsLeapYear(year) && days >= ACCUM_MAR) days--;
return DateAtStartOfYear(year) + days;
return TimerGameCalendar::DateAtStartOfYear(year) + days;
}
/**
@@ -153,7 +153,7 @@ static const uint16_t _accum_days_for_month[] = {
{
assert(fract < Ticks::DAY_TICKS);
YearMonthDay ymd;
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::date = date;
TimerGameCalendar::date_fract = fract;
@@ -240,11 +240,11 @@ void TimerManager<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed delta)
}
/* check if we reached the maximum year, decrement dates by a year */
if (TimerGameCalendar::year == MAX_YEAR + 1) {
if (TimerGameCalendar::year == CalendarTime::MAX_YEAR + 1) {
int days_this_year;
TimerGameCalendar::year--;
days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
TimerGameCalendar::date -= days_this_year;
for (Vehicle *v : Vehicle::Iterate()) v->ShiftDates(-days_this_year);
for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(-days_this_year);

View File

@@ -33,6 +33,29 @@
*/
class TimerGameCalendar {
public:
/** The type to store our dates in. */
using Date = StrongType::Typedef<int32_t, struct DateTag, StrongType::Compare, StrongType::Integer>;
/** The fraction of a date we're in, i.e. the number of ticks since the last date changeover. */
using DateFract = uint16_t;
/** Type for the year, note: 0 based, i.e. starts at the year 0. */
using Year = StrongType::Typedef<int32_t, struct YearTag, StrongType::Compare, StrongType::Integer>;
/** Type for the month, note: 0 based, i.e. 0 = January, 11 = December. */
using Month = uint8_t;
/** Type for the day of the month, note: 1 based, first day of a month is 1. */
using Day = uint8_t;
/**
* Data structure to convert between Date and triplet (year, month, and day).
* @see TimerGameCalendar::ConvertDateToYMD(), TimerGameCalendar::ConvertYMDToDate()
*/
struct YearMonthDay {
Year year; ///< Year (0...)
Month month; ///< Month (0..11)
Day day; ///< Day (1..31)
};
enum Trigger {
DAY,
WEEK,
@@ -77,33 +100,35 @@ public:
struct TStorage {
};
/** The type to store our dates in. */
using Date = StrongType::Typedef<int32_t, struct DateTag, StrongType::Compare, StrongType::Integer>;
/** The fraction of a date we're in, i.e. the number of ticks since the last date changeover. */
using DateFract = uint16_t;
/** Type for the year, note: 0 based, i.e. starts at the year 0. */
using Year = StrongType::Typedef<int32_t, struct YearTag, StrongType::Compare, StrongType::Integer>;
/** Type for the month, note: 0 based, i.e. 0 = January, 11 = December. */
using Month = uint8_t;
/** Type for the day of the month, note: 1 based, first day of a month is 1. */
using Day = uint8_t;
static bool IsLeapYear(Year yr);
static void ConvertDateToYMD(Date date, YearMonthDay * ymd);
static Date ConvertYMDToDate(Year year, Month month, Day day);
static void SetDate(Date date, DateFract fract);
/**
* Data structure to convert between Date and triplet (year, month, and day).
* @see TimerGameCalendar::ConvertDateToYMD(), TimerGameCalendar::ConvertYMDToDate()
*/
struct YearMonthDay {
Year year; ///< Year (0...)
Month month; ///< Month (0..11)
Day day; ///< Day (1..31)
};
* Calculate the year of a given date.
* @param date The date to consider.
* @return the year.
*/
static constexpr Year DateToYear(Date date)
{
/* Hardcode the number of days in a year because we can't access CalendarTime from here. */
return static_cast<int32_t>(date) / 366;
}
static bool IsLeapYear(TimerGameCalendar::Year yr);
static void ConvertDateToYMD(TimerGameCalendar::Date date, YearMonthDay *ymd);
static TimerGameCalendar::Date ConvertYMDToDate(TimerGameCalendar::Year year, TimerGameCalendar::Month month, TimerGameCalendar::Day day);
static void SetDate(TimerGameCalendar::Date date, TimerGameCalendar::DateFract fract);
/**
* Calculate the date of the first day of a given year.
* @param year the year to get the first day of.
* @return the date.
*/
static constexpr Date DateAtStartOfYear(Year year)
{
int32_t year_as_int = static_cast<int32_t>(year);
uint number_of_leap_years = (year == 0) ? 0 : ((year_as_int - 1) / 4 - (year_as_int - 1) / 100 + (year_as_int - 1) / 400 + 1);
/* Hardcode the number of days in a year because we can't access CalendarTime from here. */
return (365 * year_as_int) + number_of_leap_years;
}
static Year year; ///< Current year, starting at 0.
static Month month; ///< Current month (0..11).
@@ -111,4 +136,53 @@ public:
static DateFract date_fract; ///< Fractional part of the day.
};
/**
* Storage class for Calendar time constants.
*/
class CalendarTime {
public:
static constexpr int DAYS_IN_YEAR = 365; ///< days per year
static constexpr int DAYS_IN_LEAP_YEAR = 366; ///< sometimes, you need one day more...
static constexpr int MONTHS_IN_YEAR = 12; ///< months per year
static constexpr int SECONDS_PER_DAY = 2; ///< approximate seconds per day, not for precise calculations
/*
* ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR and DAYS_TILL_ORIGINAL_BASE_YEAR are
* primarily used for loading newgrf and savegame data and returning some
* newgrf (callback) functions that were in the original (TTD) inherited
* format, where 'TimerGameCalendar::date == 0' meant that it was 1920-01-01.
*/
/** The minimum starting year/base year of the original TTD */
static constexpr TimerGameCalendar::Year ORIGINAL_BASE_YEAR = 1920;
/** The original ending year */
static constexpr TimerGameCalendar::Year ORIGINAL_END_YEAR = 2051;
/** The maximum year of the original TTD */
static constexpr TimerGameCalendar::Year ORIGINAL_MAX_YEAR = 2090;
/** The absolute minimum & maximum years in OTTD */
static constexpr TimerGameCalendar::Year MIN_YEAR = 0;
/** The default starting year */
static constexpr TimerGameCalendar::Year DEF_START_YEAR = 1950;
/** The default scoring end year */
static constexpr TimerGameCalendar::Year DEF_END_YEAR = ORIGINAL_END_YEAR - 1;
/**
* MAX_YEAR, nicely rounded value of the number of years that can
* be encoded in a single 32 bits date, about 2^31 / 366 years.
*/
static constexpr TimerGameCalendar::Year MAX_YEAR = 5000000;
/** The date of the first day of the original base year. */
static constexpr TimerGameCalendar::Date DAYS_TILL_ORIGINAL_BASE_YEAR = TimerGameCalendar::DateAtStartOfYear(ORIGINAL_BASE_YEAR);
/** The date of the last day of the max year. */
static constexpr TimerGameCalendar::Date MAX_DATE = TimerGameCalendar::DateAtStartOfYear(CalendarTime::MAX_YEAR + 1) - 1;
static constexpr TimerGameCalendar::Year INVALID_YEAR = -1; ///< Representation of an invalid year
static constexpr TimerGameCalendar::Date INVALID_DATE = -1; ///< Representation of an invalid date
};
#endif /* TIMER_GAME_CALENDAR_H */