OpenTTD Source 20250908-master-g16cd420e4c
timer_game_economy.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
26#include "../stdafx.h"
27#include "../openttd.h"
28#include "timer.h"
29#include "timer_game_economy.h"
30#include "timer_game_tick.h"
31#include "../vehicle_base.h"
32#include "../linkgraph/linkgraph.h"
33
34#include "../safeguards.h"
35
41
47/* static */ TimerGameEconomy::YearMonthDay TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::Date date)
48{
49 /* If we're not using wallclock units, we keep the economy date in sync with the calendar. */
51
52 /* If we're using wallclock units, economy months have 30 days and an economy year has 360 days. */
53 TimerGameEconomy::YearMonthDay ymd;
54 ymd.year = Year{date.base() / EconomyTime::DAYS_IN_ECONOMY_YEAR};
56 ymd.day = (date.base() % EconomyTime::DAYS_IN_ECONOMY_MONTH) + 1;
57 return ymd;
58}
59
68{
69 /* If we're not using wallclock units, we keep the economy date in sync with the calendar. */
71
72 /* If we're using wallclock units, economy months have 30 days and an economy year has 360 days. */
73 const int total_months = (year.base() * EconomyTime::MONTHS_IN_YEAR) + month;
74 return TimerGameEconomy::Date{(total_months * EconomyTime::DAYS_IN_ECONOMY_MONTH) + day - 1}; // Day is 1-indexed but Date is 0-indexed, hence the - 1.
75}
76
83{
84 assert(fract < Ticks::DAY_TICKS);
85
88 TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(date);
89 TimerGameEconomy::year = ymd.year;
90 TimerGameEconomy::month = ymd.month;
91}
92
98/* static */ bool TimerGameEconomy::UsingWallclockUnits(bool newgame)
99{
100 if (newgame) return (_settings_newgame.economy.timekeeping_units == TKU_WALLCLOCK);
101
102 return (_settings_game.economy.timekeeping_units == TKU_WALLCLOCK);
103}
104
105template <>
106void IntervalTimer<TimerGameEconomy>::Elapsed(TimerGameEconomy::TElapsed trigger)
107{
108 if (trigger == this->period.trigger) {
109 this->callback(1);
110 }
111}
112
113template <>
114void TimeoutTimer<TimerGameEconomy>::Elapsed(TimerGameEconomy::TElapsed trigger)
115{
116 if (this->fired) return;
117
118 if (trigger == this->period.trigger) {
119 this->callback();
120 this->fired = true;
121 }
122}
123
124template <>
125bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::TElapsed delta)
126{
127 assert(delta == 1);
128
129 if (_game_mode == GM_MENU) return false;
130
134
135 /* increase day counter */
138
139 TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
140
141 /* check if we entered a new month? */
142 bool new_month = ymd.month != TimerGameEconomy::month;
143
144 /* check if we entered a new year? */
145 bool new_year = ymd.year != TimerGameEconomy::year;
146
147 /* update internal variables before calling the daily/monthly/yearly loops */
148 TimerGameEconomy::month = ymd.month;
149 TimerGameEconomy::year = ymd.year;
150
151 /* Make a temporary copy of the timers, as a timer's callback might add/remove other timers. */
153
154 for (auto timer : timers) {
155 timer->Elapsed(TimerGameEconomy::DAY);
156 }
157
158 if ((TimerGameEconomy::date.base() % 7) == 3) {
159 for (auto timer : timers) {
160 timer->Elapsed(TimerGameEconomy::WEEK);
161 }
162 }
163
164 if (new_month) {
165 for (auto timer : timers) {
166 timer->Elapsed(TimerGameEconomy::MONTH);
167 }
168
169 if ((TimerGameEconomy::month % 3) == 0) {
170 for (auto timer : timers) {
171 timer->Elapsed(TimerGameEconomy::QUARTER);
172 }
173 }
174 }
175
176 if (new_year) {
177 for (auto timer : timers) {
178 timer->Elapsed(TimerGameEconomy::YEAR);
179 }
180 }
181
183
184 /* check if we reached the maximum year, decrement dates by a year */
189 for (Vehicle *v : Vehicle::Iterate()) v->ShiftDates(TimerGameEconomy::Date{-days_this_year});
190 for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(TimerGameEconomy::Date{-days_this_year});
191 }
192
193 return true;
194}
195
196#ifdef WITH_ASSERT
197template <>
198void TimerManager<TimerGameEconomy>::Validate(TimerGameEconomy::TPeriod period)
199{
200 if (period.priority == TimerGameEconomy::Priority::NONE) return;
201
202 /* Validate we didn't make a developer error and scheduled more than one
203 * entry on the same priority/trigger. There can only be one timer on
204 * a specific trigger/priority, to ensure we are deterministic. */
205 for (const auto &timer : TimerManager<TimerGameEconomy>::GetTimers()) {
206 if (timer->period.trigger != period.trigger) continue;
207
208 assert(timer->period.priority != period.priority);
209 }
210}
211#endif /* WITH_ASSERT */
static constexpr int DAYS_IN_ECONOMY_MONTH
Days in an economy month, when in wallclock timekeeping mode.
static constexpr int DAYS_IN_ECONOMY_YEAR
Days in an economy year, when in wallclock timekeeping mode.
void Elapsed(TElapsed count) override
Called by the timer manager to notify the timer that the given amount of time has elapsed.
A connected component of a link graph.
Definition linkgraph.h:37
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.
static constexpr int MONTHS_IN_YEAR
months per year
static constexpr int DAYS_IN_YEAR
days per year
static constexpr TimerGame< struct Economy >::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...
Timer that is increased every 27ms, and counts towards economy time units, expressed in days / months...
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static Month month
Current month (0..11).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static void SetDate(Date date, DateFract fract)
Set the date.
static uint days_since_last_month
Number of days that have elapsed since the last month.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
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:61
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:62
TimekeepingUnits timekeeping_units
time units to use for the game economy, either calendar or wallclock
EconomySettings economy
settings to change the economy
Templated helper to make a type-safe 'typedef' representing a single POD value.
Vehicle data structure.
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.