OpenTTD Source 20241222-master-gc72542431a
timer_game_calendar.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
23#include "../stdafx.h"
24#include "../openttd.h"
25#include "timer.h"
26#include "timer_game_calendar.h"
27#include "../vehicle_base.h"
28
29#include "../safeguards.h"
30
33TimerGameCalendar::Date TimerGameCalendar::date = {};
36
42/* static */ TimerGameCalendar::YearMonthDay TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date)
43{
44 /* This wrapper function only exists because economy time sometimes does things differently, when using wallclock units. */
46}
47
56{
57 /* This wrapper function only exists because economy time sometimes does things differently, when using wallclock units. */
59}
60
67{
68 assert(fract < Ticks::DAY_TICKS);
69
72 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
73 TimerGameCalendar::year = ymd.year;
74 TimerGameCalendar::month = ymd.month;
75}
76
77template<>
78void IntervalTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
79{
80 if (trigger == this->period.trigger) {
81 this->callback(1);
82 }
83}
84
85template<>
86void TimeoutTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
87{
88 if (this->fired) return;
89
90 if (trigger == this->period.trigger) {
91 this->callback();
92 this->fired = true;
93 }
94}
95
96template<>
97bool TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar::TElapsed delta)
98{
99 assert(delta == 1);
100
101 if (_game_mode == GM_MENU) return false;
102
103 /* If calendar day progress is frozen, don't try to advance time. */
104 if (_settings_game.economy.minutes_per_calendar_year == CalendarTime::FROZEN_MINUTES_PER_YEAR) return false;
105
106 /* If we are using a non-default calendar progression speed, we need to check the sub_date_fract before updating date_fract. */
107 if (_settings_game.economy.minutes_per_calendar_year != CalendarTime::DEF_MINUTES_PER_YEAR) {
109
110 /* Check if we are ready to increment date_fract */
111 const uint16_t threshold = (_settings_game.economy.minutes_per_calendar_year * Ticks::DAY_TICKS) / CalendarTime::DEF_MINUTES_PER_YEAR;
112 if (TimerGameCalendar::sub_date_fract < threshold) return false;
113
115 }
116
118
119 /* Check if we entered a new day. */
123
124 /* Increase day counter. */
126
127 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
128
129 /* Check if we entered a new month. */
130 bool new_month = ymd.month != TimerGameCalendar::month;
131
132 /* Check if we entered a new year. */
133 bool new_year = ymd.year != TimerGameCalendar::year;
134
135 /* Update internal variables before calling the daily/monthly/yearly loops. */
136 TimerGameCalendar::month = ymd.month;
137 TimerGameCalendar::year = ymd.year;
138
139 /* Make a temporary copy of the timers, as a timer's callback might add/remove other timers. */
141
142 for (auto timer : timers) {
143 timer->Elapsed(TimerGameCalendar::DAY);
144 }
145
146 if (new_month) {
147 for (auto timer : timers) {
148 timer->Elapsed(TimerGameCalendar::MONTH);
149 }
150 }
151
152 if (new_year) {
153 for (auto timer : timers) {
154 timer->Elapsed(TimerGameCalendar::YEAR);
155 }
156 }
157
158 /* If we reached the maximum year, decrement dates by a year. */
160 int days_this_year;
161
164 TimerGameCalendar::date -= days_this_year;
165 }
166
167 return true;
168}
169
170#ifdef WITH_ASSERT
171template<>
172void TimerManager<TimerGameCalendar>::Validate(TimerGameCalendar::TPeriod period)
173{
174 if (period.priority == TimerGameCalendar::Priority::NONE) return;
175
176 /* Validate we didn't make a developer error and scheduled more than one
177 * entry on the same priority/trigger. There can only be one timer on
178 * a specific trigger/priority, to ensure we are deterministic. */
179 for (const auto &timer : TimerManager<TimerGameCalendar>::GetTimers()) {
180 if (timer->period.trigger != period.trigger) continue;
181
182 assert(timer->period.priority != period.priority);
183 }
184}
185#endif /* WITH_ASSERT */
void Elapsed(TElapsed count) override
Called by the timer manager to notify the timer that the given amount of time has elapsed.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
void Elapsed(TElapsed count) override
Called by the timer manager to notify the timer that the given amount of time has elapsed.
Timer that is increased every 27ms, and counts towards ticks / days / months / years.
static uint16_t sub_date_fract
Subpart of date_fract that we use when calendar days are slower than economy days.
static Month month
Current month (0..11).
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static void SetDate(Date date, DateFract fract)
Set the date.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static DateFract date_fract
Fractional part of the day.
static constexpr int DAYS_IN_YEAR
days per year
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static YearMonthDay CalendarConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
uint16_t DateFract
The fraction of a date we're in, i.e.
static Date CalendarConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
uint8_t Day
Type for the day of the month, note: 1 based, first day of a month is 1.
uint8_t Month
Type for the month, note: 0 based, i.e.
static constexpr bool IsLeapYear(Year year)
Checks whether the given year is a leap year or not.
The TimerManager manages a single Timer-type.
static std::set< BaseTimer< TTimerType > *, base_timer_sorter > & GetTimers()
Singleton list, to store all the active timers.
static bool Elapsed(TElapsed value)
Called when time for this timer elapsed.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
uint16_t minutes_per_calendar_year
minutes per calendar year. Special value 0 means that calendar time is frozen.
EconomySettings economy
settings to change the economy
Templated helper to make a type-safe 'typedef' representing a single POD value.
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.