Update: Translations from eints
[openttd-github.git] / src / timer / timer_game_calendar.cpp
blob30f938464cce9e44245700e55b0901aabf3267b9
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 */
8 /**
9 * @file timer_game_calendar.cpp
10 * This file implements the timer logic for the game-calendar-timer.
13 /**
14 * Calendar time is used for technology and time-of-year changes, including:
15 * - Vehicle, airport, station, object introduction and obsolescence
16 * - Vehicle and engine age
17 * - NewGRF variables for visual styles or behavior based on year or time of year (e.g. variable snow line)
18 * - Inflation, since it is tied to original game years. One interpretation of inflation is that it compensates for faster and higher capacity vehicles,
19 * another is that it compensates for more established companies. Each of these point to a different choice of calendar versus economy time, but we have to pick one
20 * so we follow a previous decision to tie inflation to original TTD game years.
23 #include "../stdafx.h"
24 #include "../openttd.h"
25 #include "timer.h"
26 #include "timer_game_calendar.h"
27 #include "../vehicle_base.h"
29 #include "../safeguards.h"
31 TimerGameCalendar::Year TimerGameCalendar::year = {};
32 TimerGameCalendar::Month TimerGameCalendar::month = {};
33 TimerGameCalendar::Date TimerGameCalendar::date = {};
34 TimerGameCalendar::DateFract TimerGameCalendar::date_fract = {};
35 uint16_t TimerGameCalendar::sub_date_fract = {};
37 /**
38 * Converts a Date to a Year, Month & Day.
39 * @param date the date to convert from
40 * @returns YearMonthDay representation of the Date.
42 /* static */ TimerGameCalendar::YearMonthDay TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date)
44 /* This wrapper function only exists because economy time sometimes does things differently, when using wallclock units. */
45 return CalendarConvertDateToYMD(date);
48 /**
49 * Converts a tuple of Year, Month and Day to a Date.
50 * @param year is a number between 0..MAX_YEAR
51 * @param month is a number between 0..11
52 * @param day is a number between 1..31
53 * @returns The equivalent date.
55 /* static */ TimerGameCalendar::Date TimerGameCalendar::ConvertYMDToDate(TimerGameCalendar::Year year, TimerGameCalendar::Month month, TimerGameCalendar::Day day)
57 /* This wrapper function only exists because economy time sometimes does things differently, when using wallclock units. */
58 return CalendarConvertYMDToDate(year, month, day);
61 /**
62 * Set the date.
63 * @param date New date
64 * @param fract The number of ticks that have passed on this date.
66 /* static */ void TimerGameCalendar::SetDate(TimerGameCalendar::Date date, TimerGameCalendar::DateFract fract)
68 assert(fract < Ticks::DAY_TICKS);
70 TimerGameCalendar::date = date;
71 TimerGameCalendar::date_fract = fract;
72 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
73 TimerGameCalendar::year = ymd.year;
74 TimerGameCalendar::month = ymd.month;
77 template<>
78 void IntervalTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
80 if (trigger == this->period.trigger) {
81 this->callback(1);
85 template<>
86 void TimeoutTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
88 if (this->fired) return;
90 if (trigger == this->period.trigger) {
91 this->callback();
92 this->fired = true;
96 template<>
97 bool TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar::TElapsed delta)
99 assert(delta == 1);
101 if (_game_mode == GM_MENU) return false;
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;
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) {
108 TimerGameCalendar::sub_date_fract += Ticks::DAY_TICKS;
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;
114 TimerGameCalendar::sub_date_fract = std::min<uint16_t>(TimerGameCalendar::sub_date_fract - threshold, Ticks::DAY_TICKS - 1);
117 TimerGameCalendar::date_fract++;
119 /* Check if we entered a new day. */
120 if (TimerGameCalendar::date_fract < Ticks::DAY_TICKS) return true;
121 TimerGameCalendar::date_fract = 0;
122 TimerGameCalendar::sub_date_fract = 0;
124 /* Increase day counter. */
125 TimerGameCalendar::date++;
127 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
129 /* Check if we entered a new month. */
130 bool new_month = ymd.month != TimerGameCalendar::month;
132 /* Check if we entered a new year. */
133 bool new_year = ymd.year != TimerGameCalendar::year;
135 /* Update internal variables before calling the daily/monthly/yearly loops. */
136 TimerGameCalendar::month = ymd.month;
137 TimerGameCalendar::year = ymd.year;
139 /* Make a temporary copy of the timers, as a timer's callback might add/remove other timers. */
140 auto timers = TimerManager<TimerGameCalendar>::GetTimers();
142 for (auto timer : timers) {
143 timer->Elapsed(TimerGameCalendar::DAY);
146 if (new_month) {
147 for (auto timer : timers) {
148 timer->Elapsed(TimerGameCalendar::MONTH);
152 if (new_year) {
153 for (auto timer : timers) {
154 timer->Elapsed(TimerGameCalendar::YEAR);
158 /* If we reached the maximum year, decrement dates by a year. */
159 if (TimerGameCalendar::year == CalendarTime::MAX_YEAR + 1) {
160 int days_this_year;
162 TimerGameCalendar::year--;
163 days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
164 TimerGameCalendar::date -= days_this_year;
167 return true;
170 #ifdef WITH_ASSERT
171 template<>
172 void TimerManager<TimerGameCalendar>::Validate(TimerGameCalendar::TPeriod period)
174 if (period.priority == TimerGameCalendar::Priority::NONE) return;
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;
182 assert(timer->period.priority != period.priority);
185 #endif /* WITH_ASSERT */