@@ -20,7 +20,7 @@
#include "strings_func.h"
#include "command_func.h"
#include "window_func.h"
#include "date_func.h"
#include "timer/timer_game_calendar.h"
#include "vehicle_func.h"
#include "sound_func.h"
#include "cheat_type.h"
@@ -337,8 +337,8 @@ CommandCost CmdBuildAircraft(DoCommandFl
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
v->date_of_last_service = _date;
v->build_year = u->build_year = _cur_year;
v->date_of_last_service = TimerGameCalendar::date;
v->build_year = u->build_year = TimerGameCalendar::year;
v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
@@ -1555,7 +1555,7 @@ static void AircraftEventHandler_AtTermi
if (_settings_game.order.serviceathelipad) {
if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) {
/* an excerpt of ServiceAircraft, without the invisibility stuff */
v->breakdowns_since_last_service = 0;
v->reliability = v->GetEngine()->reliability;
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
@@ -106,18 +106,18 @@ static int32 ClickChangeDateCheat(int32
{
/* Don't allow changing to an invalid year, or the current year. */
new_value = Clamp(new_value, MIN_YEAR, MAX_YEAR);
if (new_value == _cur_year) return _cur_year;
if (new_value == TimerGameCalendar::year) return TimerGameCalendar::year;
YearMonthDay ymd;
ConvertDateToYMD(_date, &ymd);
ConvertDateToYMD(TimerGameCalendar::date, &ymd);
Date new_date = ConvertYMDToDate(new_value, ymd.month, ymd.day);
/* Change the date. */
SetDate(new_date, _date_fract);
TimerGameCalendar::SetDate(new_date, TimerGameCalendar::date_fract);
/* Shift cached dates. */
for (auto v : Vehicle::Iterate()) v->ShiftDates(new_date - _date);
LinkGraphSchedule::instance.ShiftDates(new_date - _date);
for (auto v : Vehicle::Iterate()) v->ShiftDates(new_date - TimerGameCalendar::date);
LinkGraphSchedule::instance.ShiftDates(new_date - TimerGameCalendar::date);
EnginesMonthlyLoop();
SetWindowDirty(WC_STATUS_BAR, 0);
@@ -126,7 +126,7 @@ static int32 ClickChangeDateCheat(int32
InvalidateWindowClassesData(WC_TRUCK_STATION, 0);
InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
ResetSignalVariant();
return _cur_year;
return TimerGameCalendar::year;
}
/**
@@ -202,7 +202,7 @@ static const CheatEntry _cheats_ui[] = {
{SLE_BOOL, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, nullptr },
{SLE_BOOL, STR_CHEAT_SETUP_PROD, &_cheats.setup_prod.value, &_cheats.setup_prod.been_used, &ClickSetProdCheat },
{SLE_UINT8, STR_CHEAT_EDIT_MAX_HL, &_settings_game.construction.map_height_limit, &_cheats.edit_max_hl.been_used, &ClickChangeMaxHlCheat },
{SLE_INT32, STR_CHEAT_CHANGE_DATE, &_cur_year, &_cheats.change_date.been_used, &ClickChangeDateCheat },
{SLE_INT32, STR_CHEAT_CHANGE_DATE, &TimerGameCalendar::year, &_cheats.change_date.been_used, &ClickChangeDateCheat },
};
static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui));
@@ -281,7 +281,7 @@ struct CheatWindow : Window {
switch (ce->str) {
/* Display date for change date cheat */
case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
case STR_CHEAT_CHANGE_DATE: SetDParam(0, TimerGameCalendar::date); break;
/* Draw coloured flag for change company cheat */
case STR_CHEAT_CHANGE_COMPANY: {
@@ -18,7 +18,7 @@
#include "texteff.hpp"
#include "town.h"
#include "company_func.h"
#include "company_base.h"
#include "signal_func.h"
@@ -276,7 +276,7 @@ void CommandHelperBase::InternalPostResu
/** Helper to make a desync log for a command. */
void CommandHelperBase::LogCommandExecution(Commands cmd, StringID err_message, TileIndex tile, const CommandDataBuffer &args, bool failed)
Debug(desync, 1, "{}: {:08x}; {:02x}; {:02x}; {:08x}; {:08x}; {:06x}; {} ({})", failed ? "cmdf" : "cmd", _date, _date_fract, (int)_current_company, cmd, err_message, tile, FormatArrayAsHex(args), GetCommandName(cmd));
Debug(desync, 1, "{}: {:08x}; {:02x}; {:02x}; {:08x}; {:08x}; {:06x}; {} ({})", failed ? "cmdf" : "cmd", TimerGameCalendar::date, TimerGameCalendar::date_fract, (int)_current_company, cmd, err_message, tile, FormatArrayAsHex(args), GetCommandName(cmd));
@@ -23,7 +23,6 @@
#include "company_manager_face.h"
#include "rail.h"
#include "core/pool_func.hpp"
@@ -570,7 +569,7 @@ Company *DoStartupNewCompany(bool is_ai,
c->avail_railtypes = GetCompanyRailtypes(c->index);
c->avail_roadtypes = GetCompanyRoadTypes(c->index);
c->inaugurated_year = _cur_year;
c->inaugurated_year = TimerGameCalendar::year;
/* If starting a player company in singleplayer and a favorite company manager face is selected, choose it. Otherwise, use a random face.
* In a network game, we'll choose the favorite face later in CmdCompanyCtrl to sync it to all clients. */
@@ -22,7 +22,7 @@
#include "newgrf.h"
#include "widgets/dropdown_type.h"
#include "tilehighlight_func.h"
@@ -434,10 +434,10 @@ struct CompanyFinancesWindow : Window {
case WID_CF_EXPS_PRICE2:
case WID_CF_EXPS_PRICE3: {
const Company *c = Company::Get((CompanyID)this->window_number);
int age = std::min(_cur_year - c->inaugurated_year, 2);
int age = std::min(TimerGameCalendar::year - c->inaugurated_year, 2);
int wid_offset = widget - WID_CF_EXPS_PRICE1;
if (wid_offset <= age) {
DrawYearColumn(r, _cur_year - (age - wid_offset), c->yearly_expenses[age - wid_offset]);
DrawYearColumn(r, TimerGameCalendar::year - (age - wid_offset), c->yearly_expenses[age - wid_offset]);
break;
@@ -30,6 +30,7 @@
#include "viewport_func.h"
#include "gamelog.h"
#include "ai/ai.hpp"
@@ -1451,7 +1452,7 @@ DEF_CONSOLE_CMD(ConGetDate)
IConsolePrint(CC_DEFAULT, "Date: {:04d}-{:02d}-{:02d}", ymd.year, ymd.month + 1, ymd.day);
return true;
@@ -2290,7 +2291,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
IConsolePrint(CC_DEBUG, "Started profiling for GRFID{} {}.", (started > 1) ? "s" : "", grfids);
if (argc >= 3) {
int days = std::max(atoi(argv[2]), 1);
_newgrf_profile_end_date = _date + days;
_newgrf_profile_end_date = TimerGameCalendar::date + days;
char datestrbuf[32]{ 0 };
SetDParam(0, _newgrf_profile_end_date);
@@ -17,7 +17,7 @@
#include "../network/network_internal.h"
#include "../company_func.h"
#include "../fileio_func.h"
#include "../date_func.h"
#include "../timer/timer_game_calendar.h"
#endif /* RANDOM_DEBUG */
#include "../safeguards.h"
@@ -72,7 +72,7 @@ void SetRandomSeed(uint32 seed)
uint32 DoRandom(int line, const char *file)
if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", _date, _date_fract, _frame_counter, (byte)_current_company, file, line);
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameCalendar::date, TimerGameCalendar::date_fract, _frame_counter, (byte)_current_company, file, line);
return _random.Next();
@@ -11,6 +11,7 @@
#include "crashlog.h"
#include "map_func.h"
#include "rev.h"
@@ -357,8 +358,8 @@ char *CrashLog::FillCrashLog(char *buffe
buffer += UTCTime::Format(buffer, last, "Crash at: %Y-%m-%d %H:%M:%S (UTC)\n");
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i)\n\n", ymd.year, ymd.month + 1, ymd.day, _date_fract);
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i)\n\n", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::date_fract);
buffer = this->LogError(buffer, last, CrashLog::message.c_str());
buffer = this->LogOpenTTDVersion(buffer, last);
@@ -13,7 +13,6 @@
#include "currency.h"
#include "news_func.h"
#include "settings_type.h"
#include "string_type.h"
#include "timer/timer.h"
@@ -129,8 +128,8 @@ uint64 GetMaskOfAllowedCurrencies()
for (i = 0; i < CURRENCY_END; i++) {
Year to_euro = _currency_specs[i].to_euro;
if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue;
if (to_euro == CF_ISEURO && _cur_year < 2000) continue;
if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && TimerGameCalendar::year >= to_euro) continue;
if (to_euro == CF_ISEURO && TimerGameCalendar::year < 2000) continue;
SetBit(mask, i);
SetBit(mask, CURRENCY_CUSTOM); // always allow custom currency
@@ -144,7 +143,7 @@ static IntervalTimer<TimerGameCalendar>
if (_currency_specs[_settings_game.locale.currency].to_euro != CF_NOEURO &&
_currency_specs[_settings_game.locale.currency].to_euro != CF_ISEURO &&
_cur_year >= _currency_specs[_settings_game.locale.currency].to_euro) {
TimerGameCalendar::year >= _currency_specs[_settings_game.locale.currency].to_euro) {
_settings_game.locale.currency = 2; // this is the index of euro above.
AddNewsItem(STR_NEWS_EURO_INTRODUCTION, NT_ECONOMY, NF_NORMAL);
@@ -25,30 +25,8 @@
#include "safeguards.h"
Year _cur_year; ///< Current year, starting at 0
Month _cur_month; ///< Current month (0..11)
Date _date; ///< Current date in days (day counter)
DateFract _date_fract; ///< Fractional part of the day.
uint64 _tick_counter; ///< Ever incrementing tick counter for setting off various events
* Set the date.
* @param date New date
* @param fract The number of ticks that have passed on this date.
*/
void SetDate(Date date, DateFract fract)
assert(fract < DAY_TICKS);
_date = date;
_date_fract = fract;
ConvertDateToYMD(date, &ymd);
_cur_year = ymd.year;
_cur_month = ymd.month;
#define M(a, b) ((a << 5) | b)
static const uint16 _month_date_from_year_day[] = {
M( 0, 1), M( 0, 2), M( 0, 3), M( 0, 4), M( 0, 5), M( 0, 6), M( 0, 7), M( 0, 8), M( 0, 9), M( 0, 10), M( 0, 11), M( 0, 12), M( 0, 13), M( 0, 14), M( 0, 15), M( 0, 16), M( 0, 17), M( 0, 18), M( 0, 19), M( 0, 20), M( 0, 21), M( 0, 22), M( 0, 23), M( 0, 24), M( 0, 25), M( 0, 26), M( 0, 27), M( 0, 28), M( 0, 29), M( 0, 30), M( 0, 31),
@@ -12,13 +12,8 @@
#include "date_type.h"
extern Year _cur_year;
extern Month _cur_month;
extern Date _date;
extern DateFract _date_fract;
extern uint64 _tick_counter;
void SetDate(Date date, DateFract fract);
void ConvertDateToYMD(Date date, YearMonthDay *ymd);
Date ConvertYMDToDate(Year year, Month month, Day day);
@@ -10,6 +10,7 @@
#include "stdafx.h"
#include "window_gui.h"
#include "date_gui.h"
@@ -50,7 +51,7 @@ struct SetDateWindow : Window {
this->parent = parent;
this->InitNested(window_number);
if (initial_date == 0) initial_date = _date;
if (initial_date == 0) initial_date = TimerGameCalendar::date;
ConvertDateToYMD(initial_date, &this->date);
this->date.year = Clamp(this->date.year, min_year, max_year);
@@ -20,7 +20,7 @@ typedef uint8 Month; ///< Type for the
typedef uint8 Day; ///< Type for the day of the month, note: 1 based, first day of a month is 1.
* 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On
* 1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16 and incremented by 885. On
* an overflow the new day begun and 65535 / 885 = 74.
* 1 tick is approximately 27 ms.
* 1 day is thus about 2 seconds (74 * 27 = 1998) on a machine that can run OpenTTD normally
@@ -45,7 +45,7 @@ static const int INDUSTRY_CUT_TREE_TICKS
* 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 '_date == 0' meant that it was 1920-01-01.
* format, where 'TimerGameCalendar::date == 0' meant that it was 1920-01-01.
/** The minimum starting year/base year of the original TTD */
@@ -77,7 +77,7 @@ static const Year ORIGINAL_MAX_YEAR = 2
#define DAYS_TILL(year) (DAYS_IN_YEAR * (year) + LEAP_YEARS_TILL(year))
* The offset in days from the '_date == 0' till
* The offset in days from the 'TimerGameCalendar::date == 0' till
* 'ConvertYMDToDate(ORIGINAL_BASE_YEAR, 0, 1)'
#define DAYS_TILL_ORIGINAL_BASE_YEAR DAYS_TILL(ORIGINAL_BASE_YEAR)
@@ -34,7 +34,6 @@
@@ -923,7 +922,7 @@ static void DoDisaster()
byte j = 0;
for (size_t i = 0; i != lengthof(_disasters); i++) {
if (_cur_year >= _disasters[i].min_year && _cur_year < _disasters[i].max_year) buf[j++] = (byte)i;
if (TimerGameCalendar::year >= _disasters[i].min_year && TimerGameCalendar::year < _disasters[i].max_year) buf[j++] = (byte)i;
if (j == 0) return;
@@ -29,7 +29,6 @@
#include "newgrf_roadstop.h"
#include "object.h"
#include "autoreplace_func.h"
@@ -693,7 +692,7 @@ static void CompaniesGenStatistics()
cur_company.Restore();
/* Only run the economic statics and update company stats every 3rd month (1st of quarter). */
if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month)) return;
if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, TimerGameCalendar::month)) return;
for (Company *c : Company::Iterate()) {
/* Drop the oldest history off the end */
@@ -737,7 +736,7 @@ bool AddInflation(bool check_year)
* inflation doesn't add anything after that either; it even makes playing
* it impossible due to the diverging cost and income rates.
if (check_year && (_cur_year < ORIGINAL_BASE_YEAR || _cur_year >= ORIGINAL_MAX_YEAR)) return true;
if (check_year && (TimerGameCalendar::year < ORIGINAL_BASE_YEAR || TimerGameCalendar::year >= ORIGINAL_MAX_YEAR)) return true;
if (_economy.inflation_prices == MAX_INFLATION || _economy.inflation_payment == MAX_INFLATION) return true;
@@ -846,8 +845,8 @@ static void CompaniesPayInterest()
if (c->money < 0) {
yearly_fee += -c->money *_economy.interest_rate / 100;
Money up_to_previous_month = yearly_fee * _cur_month / 12;
Money up_to_this_month = yearly_fee * (_cur_month + 1) / 12;
Money up_to_previous_month = yearly_fee * TimerGameCalendar::month / 12;
Money up_to_this_month = yearly_fee * (TimerGameCalendar::month + 1) / 12;
SubtractMoneyFromCompany(CommandCost(EXPENSES_LOAN_INTEREST, up_to_this_month - up_to_previous_month));
@@ -930,7 +929,7 @@ void StartupEconomy()
if (_settings_game.economy.inflation) {
/* Apply inflation that happened before our game start year. */
int months = (std::min(_cur_year, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR) * 12;
int months = (std::min(TimerGameCalendar::year, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR) * 12;
for (int i = 0; i < months; i++) {
AddInflation(false);
@@ -1082,7 +1081,7 @@ static uint DeliverGoodsToIndustry(const
uint amount = std::min(num_pieces, 0xFFFFu - ind->incoming_cargo_waiting[cargo_index]);
ind->incoming_cargo_waiting[cargo_index] += amount;
ind->last_cargo_accepted_at[cargo_index] = _date;
ind->last_cargo_accepted_at[cargo_index] = TimerGameCalendar::date;
num_pieces -= amount;
accepted += amount;
@@ -1778,7 +1777,7 @@ static void LoadUnloadVehicle(Vehicle *f
/* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
ge->last_speed = std::min(t, 255);
ge->last_age = std::min(_cur_year - front->build_year, 255);
ge->last_age = std::min(TimerGameCalendar::year - front->build_year, 255);
assert(v->cargo_cap >= v->cargo.StoredCount());
/* Capacity available for loading more cargo. */
@@ -2048,7 +2047,7 @@ CommandCost CmdBuyShareInCompany(DoComma
if (c == nullptr || !_settings_game.economy.allow_shares || _current_company == target_company) return CMD_ERROR;
/* Protect new companies from hostile takeovers */
if (_cur_year - c->inaugurated_year < _settings_game.economy.min_years_for_shares) return_cmd_error(STR_ERROR_PROTECTED);
if (TimerGameCalendar::year - c->inaugurated_year < _settings_game.economy.min_years_for_shares) return_cmd_error(STR_ERROR_PROTECTED);
/* Those lines are here for network-protection (clients can be slow) */
if (GetAmountOwnedBy(c, INVALID_OWNER) == 0) return cost;
@@ -675,7 +675,7 @@ void StartupOneEngine(Engine *e, Date ag
* of engines in early starting games.
* Note: TTDP uses fixed 1922 */
e->intro_date = ei->base_intro <= ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
if (e->intro_date <= _date) {
if (e->intro_date <= TimerGameCalendar::date) {
e->age = (aging_date - e->intro_date) >> 5;
e->company_avail = MAX_UVALUE(CompanyMask);
e->flags |= ENGINE_AVAILABLE;
@@ -721,7 +721,7 @@ void StartupOneEngine(Engine *e, Date ag
void StartupEngines()
/* Aging of vehicles stops, so account for that when starting late */
const Date aging_date = std::min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
const Date aging_date = std::min(TimerGameCalendar::date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
uint32 seed = Random();
for (Engine *e : Engine::Iterate()) {
@@ -883,11 +883,11 @@ static bool IsVehicleTypeDisabled(Vehicl
static IntervalTimer<TimerGameCalendar> _engines_daily({TimerGameCalendar::DAY, TimerGameCalendar::Priority::ENGINE}, [](auto)
c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date);
c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, _date);
c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
if (_cur_year >= _year_engine_aging_stops) return;
if (TimerGameCalendar::year >= _year_engine_aging_stops) return;
EngineID i = e->index;
@@ -1038,11 +1038,11 @@ static void NewVehicleAvailable(Engine *
if (e->type == VEH_TRAIN) {
/* maybe make another rail type available */
assert(e->u.rail.railtype < RAILTYPE_END);
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, TimerGameCalendar::date);
} else if (e->type == VEH_ROAD) {
/* maybe make another road type available */
assert(e->u.road.roadtype < ROADTYPE_END);
for (Company* c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date);
for (Company* c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, TimerGameCalendar::date);
/* Only broadcast event if AIs are able to build this vehicle type. */
@@ -1067,7 +1067,7 @@ static void NewVehicleAvailable(Engine *
/** Monthly update of the availability, reliability, and preview offers of the engines. */
void EnginesMonthlyLoop()
if (_cur_year < _year_engine_aging_stops) {
if (TimerGameCalendar::year < _year_engine_aging_stops) {
bool refresh = false;
/* Age the vehicle */
@@ -1080,10 +1080,10 @@ void EnginesMonthlyLoop()
/* Do not introduce invalid engines */
if (!e->IsEnabled()) continue;
if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) {
if (!(e->flags & ENGINE_AVAILABLE) && TimerGameCalendar::date >= (e->intro_date + DAYS_IN_YEAR)) {
/* Introduce it to all companies */
NewVehicleAvailable(e);
} else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
} else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && TimerGameCalendar::date >= e->intro_date) {
/* Introduction date has passed...
* Check if it is allowed to build this vehicle type at all
* based on the current game settings. If not, it does not
@@ -17,6 +17,7 @@
#include "heightmap.h"
#include "engine_func.h"
#include "water.h"
#include "video/video_driver.hpp"
@@ -193,7 +194,7 @@ static void _GenerateWorld()
if (_debug_desync_level > 0) {
char name[MAX_PATH];
seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, TimerGameCalendar::date);
SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
} catch (AbortGenerateWorldSignal&) {
@@ -12,7 +12,6 @@
#include "gui.h"
#include "goal_base.h"
@@ -16,7 +16,7 @@
#include "cargotype.h"
#include "gfx_func.h"
#include "core/geometry_func.hpp"
@@ -581,8 +581,8 @@ public:
nums = std::min(this->num_vert_lines, std::max(nums, c->num_valid_stat_ent));
int mo = (_cur_month / 3 - nums) * 3;
int yr = _cur_year;
int mo = (TimerGameCalendar::month / 3 - nums) * 3;
int yr = TimerGameCalendar::year;
while (mo < 0) {
yr--;
mo += 12;
@@ -24,7 +24,6 @@
#include "misc_cmd.h"
#include "widgets/highscore_widget.h"
@@ -260,7 +259,7 @@ static IntervalTimer<TimerGameCalendar>
if (_settings_game.game_creation.ending_year == 0) return;
/* Show the end-game chart at the end of the ending year (hence the + 1). */
if (_cur_year == _settings_game.game_creation.ending_year + 1) {
if (TimerGameCalendar::year == _settings_game.game_creation.ending_year + 1) {
ShowEndGameChart();
});
@@ -1796,11 +1796,11 @@ static void DoCreateNewIndustry(Industry
i->counter = GB(r, 4, 12);
i->random = initial_random_bits;
i->was_cargo_delivered = false;
i->last_prod_year = _cur_year;
i->last_prod_year = TimerGameCalendar::year;
i->founder = founder;
i->ctlflags = INDCTL_NONE;
i->construction_date = _date;
i->construction_date = TimerGameCalendar::date;
i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
(_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
@@ -2246,8 +2246,8 @@ static uint16 GetIndustryGamePlayProbabi
const IndustrySpec *ind_spc = GetIndustrySpec(it);
byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
if (!ind_spc->enabled || ind_spc->layouts.empty() ||
((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && TimerGameCalendar::year > 1950) ||
((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && TimerGameCalendar::year < 1960) ||
(chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
*min_number = 0;
return 0;
@@ -2421,7 +2421,7 @@ static void UpdateIndustryStatistics(Ind
if (i->produced_cargo[j] != CT_INVALID) {
byte pct = 0;
if (i->this_month_production[j] != 0) {
pct = std::min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
i->last_month_pct_transported[j] = pct;
@@ -2856,7 +2856,7 @@ static void ChangeIndustryProduction(Ind
if ((i->ctlflags & INDCTL_NO_PRODUCTION_INCREASE) && (mul > 0 || increment > 0)) return;
if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, original_economy ? 2 : 180)) {
if ( (byte)(TimerGameCalendar::year - i->last_prod_year) >= 5 && Chance16(1, original_economy ? 2 : 180)) {
closeit = true;
@@ -21,6 +21,7 @@
#include "genworld.h"
#include "fios.h"
#include "effectvehicle_func.h"
#include "landscape_type.h"
@@ -611,7 +612,7 @@ byte GetSnowLine()
if (_snow_line == nullptr) return _settings_game.game_creation.snow_line_height;
return _snow_line->table[ymd.month][ymd.day];
@@ -65,7 +65,7 @@ void LinkGraph::ShiftDates(int interval)
void LinkGraph::Compress()
this->last_compression = (_date + this->last_compression) / 2;
this->last_compression = (TimerGameCalendar::date + this->last_compression) / 2;
for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
this->nodes[node1].supply /= 2;
for (BaseEdge &edge : this->nodes[node1].edges) {
@@ -89,8 +89,8 @@ void LinkGraph::Compress()
void LinkGraph::Merge(LinkGraph *other)
Date age = _date - this->last_compression + 1;
Date other_age = _date - other->last_compression + 1;
Date age = TimerGameCalendar::date - this->last_compression + 1;
Date other_age = TimerGameCalendar::date - other->last_compression + 1;
NodeID first = this->Size();
for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
Station *st = Station::Get(other->nodes[node1].station);
@@ -172,8 +172,8 @@ void LinkGraph::BaseNode::AddEdge(NodeID
edge.capacity = capacity;
edge.usage = usage;
edge.travel_time_sum = static_cast<uint64>(travel_time) * capacity;
if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date;
if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date;
if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = TimerGameCalendar::date;
if (mode & EUM_RESTRICTED) edge.last_restricted_update = TimerGameCalendar::date;
@@ -239,8 +239,8 @@ void LinkGraph::BaseEdge::Update(uint ca
this->usage = std::max(this->usage, usage);
if (mode & EUM_UNRESTRICTED) this->last_unrestricted_update = _date;
if (mode & EUM_RESTRICTED) this->last_restricted_update = _date;
if (mode & EUM_UNRESTRICTED) this->last_unrestricted_update = TimerGameCalendar::date;
if (mode & EUM_RESTRICTED) this->last_restricted_update = TimerGameCalendar::date;
@@ -14,7 +14,7 @@
#include "../core/smallmap_type.hpp"
#include "../station_base.h"
#include "../cargotype.h"
#include "../saveload/saveload.h"
#include "linkgraph_type.h"
#include <utility>
@@ -106,7 +106,7 @@ public:
void UpdateSupply(uint supply)
this->supply += supply;
this->last_update = _date;
this->last_update = TimerGameCalendar::date;
@@ -195,7 +195,7 @@ public:
* Real constructor.
* @param cargo Cargo the link graph is about.
LinkGraph(CargoID cargo) : cargo(cargo), last_compression(_date) {}
LinkGraph(CargoID cargo) : cargo(cargo), last_compression(TimerGameCalendar::date) {}
void Init(uint size);
void ShiftDates(int interval);
@@ -249,7 +249,7 @@ public:
inline uint Monthly(uint base) const
return base * 30 / (_date - this->last_compression + 1);
return base * 30 / (TimerGameCalendar::date - this->last_compression + 1);
NodeID AddNode(const Station *st);
@@ -37,7 +37,7 @@ LinkGraphJob::LinkGraphJob(const LinkGra
* This is on purpose. */
link_graph(orig),
settings(_settings_game.linkgraph),
join_date(_date + (_settings_game.linkgraph.recalc_time / SECONDS_PER_DAY)),
join_date(TimerGameCalendar::date + (_settings_game.linkgraph.recalc_time / SECONDS_PER_DAY)),
job_completed(false),
job_aborted(false)
@@ -212,7 +212,7 @@ public:
* Check if job is supposed to be finished.
* @return True if job should be finished by now, false if not.
inline bool IsScheduledToBeJoined() const { return this->join_date <= _date; }
inline bool IsScheduledToBeJoined() const { return this->join_date <= TimerGameCalendar::date; }
* Get the date when the job should be finished.
@@ -163,10 +163,10 @@ LinkGraphSchedule::~LinkGraphSchedule()
* Pause the game if in 2 _date_fract ticks, we would do a join with the next
* Pause the game if in 2 TimerGameCalendar::date_fract ticks, we would do a join with the next
* link graph job, but it is still running.
* The check is done 2 _date_fract ticks early instead of 1, as in multiplayer
* calls to DoCommandP are executed after a delay of 1 _date_fract tick.
* The check is done 2 TimerGameCalendar::date_fract ticks early instead of 1, as in multiplayer
* calls to DoCommandP are executed after a delay of 1 TimerGameCalendar::date_fract tick.
* If we previously paused, unpause if the job is now ready to be joined with.
void StateGameLoop_LinkGraphPauseControl()
@@ -177,10 +177,10 @@ void StateGameLoop_LinkGraphPauseControl
Command<CMD_PAUSE>::Post(PM_PAUSED_LINK_GRAPH, false);
} else if (_pause_mode == PM_UNPAUSED &&
_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
_date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2 &&
TimerGameCalendar::date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
TimerGameCalendar::date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2 &&
LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
/* Perform check two _date_fract ticks before we would join, to make
/* Perform check two TimerGameCalendar::date_fract ticks before we would join, to make
* sure it also works in multiplayer. */
Command<CMD_PAUSE>::Post(PM_PAUSED_LINK_GRAPH, true);
@@ -204,8 +204,8 @@ void AfterLoad_LinkGraphPauseControl()
void OnTick_LinkGraph()
if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
Date offset = _date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY);
if (TimerGameCalendar::date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
Date offset = TimerGameCalendar::date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY);
if (offset == 0) {
LinkGraphSchedule::instance.SpawnNext();
} else if (offset == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2) {
@@ -73,7 +73,7 @@ void InitializeGame(uint size_x, uint si
_newgrf_profilers.clear();
if (reset_date) {
SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
TimerGameCalendar::SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
InitializeOldNames();
@@ -14,6 +14,7 @@
#include "../../core/bitmath_func.hpp"
#include "../../company_base.h"
#include "../../date_func.h"
#include "../../timer/timer_game_calendar.h"
#include "../../debug.h"
#include "../../map_func.h"
#include "../../game/game.hpp"
@@ -149,7 +150,7 @@ const NetworkServerGameInfo *GetCurrentN
_network_game_info.companies_on = (byte)Company::GetNumItems();
_network_game_info.spectators_on = NetworkSpectatorCount();
_network_game_info.game_date = _date;
_network_game_info.game_date = TimerGameCalendar::date;
return &_network_game_info;
@@ -11,7 +11,7 @@
#include "../strings_func.h"
#include "../command_func.h"
#include "network_admin.h"
#include "network_client.h"
#include "network_query.h"
@@ -263,7 +263,7 @@ void NetworkTextMessage(NetworkAction ac
char *msg_ptr = message + Utf8Encode(message, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
GetString(msg_ptr, strid, lastof(message));
Debug(desync, 1, "msg: {:08x}; {:02x}; {}", _date, _date_fract, message);
Debug(desync, 1, "msg: {:08x}; {:02x}; {}", TimerGameCalendar::date, TimerGameCalendar::date_fract, message);
IConsolePrint(colour, message);
NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
@@ -1038,12 +1038,12 @@ void NetworkGameLoop()
if (_network_server) {
/* Log the sync state to check for in-syncedness of replays. */
if (_date_fract == 0) {
if (TimerGameCalendar::date_fract == 0) {
/* We don't want to log multiple times if paused. */
static Date last_log;
if (last_log != _date) {
Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", _date, _date_fract, _random.state[0], _random.state[1]);
last_log = _date;
if (last_log != TimerGameCalendar::date) {
Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", TimerGameCalendar::date, TimerGameCalendar::date_fract, _random.state[0], _random.state[1]);
last_log = TimerGameCalendar::date;
@@ -1061,19 +1061,19 @@ void NetworkGameLoop()
while (f != nullptr && !feof(f)) {
if (_date == next_date && _date_fract == next_date_fract) {
if (TimerGameCalendar::date == next_date && TimerGameCalendar::date_fract == next_date_fract) {
if (cp != nullptr) {
NetworkSendCommand(cp->cmd, cp->err_msg, nullptr, cp->company, cp->data);
Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {:06x}; {} ({})", _date, _date_fract, (int)_current_company, cp->cmd, cp->tile, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {:06x}; {} ({})", TimerGameCalendar::date, TimerGameCalendar::date_fract, (int)_current_company, cp->cmd, cp->tile, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
delete cp;
cp = nullptr;
if (check_sync_state) {
if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", _date, _date_fract);
Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", TimerGameCalendar::date, TimerGameCalendar::date_fract);
} else {
Debug(desync, 0, "Sync check: {:08x}; {:02x}; mismatch expected {{{:08x}, {:08x}}}, got {{{:08x}, {:08x}}}",
_date, _date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
TimerGameCalendar::date, TimerGameCalendar::date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
NOT_REACHED();
check_sync_state = false;
#include "../stdafx.h"
#include "core/game_info.h"
#include "network_base.h"
@@ -207,7 +208,7 @@ NetworkRecvStatus ServerNetworkAdminSock
Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE);
p->Send_uint32(_date);
p->Send_uint32(TimerGameCalendar::date);
this->SendPacket(p);
return NETWORK_RECV_STATUS_OKAY;
#include "../company_gui.h"
#include "../company_cmd.h"
#include "../core/random_func.hpp"
#include "../gfx_func.h"
#include "../error.h"
#include "../rev.h"
@@ -277,7 +277,7 @@ void ClientNetworkGameSocketHandler::Cli
if (_sync_seed_1 != _random.state[0]) {
#endif
ShowNetworkError(STR_NETWORK_ERROR_DESYNC);
Debug(desync, 1, "sync_err: {:08x}; {:02x}", _date, _date_fract);
Debug(desync, 1, "sync_err: {:08x}; {:02x}", TimerGameCalendar::date, TimerGameCalendar::date_fract);
Debug(net, 0, "Sync error detected");
my_client->ClientError(NETWORK_RECV_STATUS_DESYNC);
return false;
@@ -9,7 +9,6 @@
#include "network_server.h"
@@ -882,10 +881,10 @@ NetworkRecvStatus ServerNetworkGameSocke
assert(NetworkClientInfo::CanAllocateItem());
NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
this->SetInfo(ci);
ci->join_date = _date;
ci->join_date = TimerGameCalendar::date;
ci->client_name = client_name;
ci->client_playas = playas;
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", _date, _date_fract, (int)ci->client_playas, (int)ci->index);
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameCalendar::date, TimerGameCalendar::date_fract, (int)ci->client_playas, (int)ci->index);
/* Make sure companies to which people try to join are not autocleaned */
if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
@@ -1479,7 +1478,7 @@ void NetworkUpdateClientInfo(ClientID cl
if (ci == nullptr) return;
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", _date, _date_fract, (int)ci->client_playas, client_id);
Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", TimerGameCalendar::date, TimerGameCalendar::date_fract, (int)ci->client_playas, client_id);
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
@@ -1493,8 +1492,8 @@ void NetworkUpdateClientInfo(ClientID cl
/** Check if we want to restart the map */
static void NetworkCheckRestartMap()
if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
Debug(net, 3, "Auto-restarting map: year {} reached", _cur_year);
if (_settings_client.network.restart_game_year != 0 && TimerGameCalendar::year >= _settings_client.network.restart_game_year) {
Debug(net, 3, "Auto-restarting map: year {} reached", TimerGameCalendar::year);
_settings_newgame.game_creation.generation_seed = GENERATE_NEW_SEED;
switch(_file_to_saveload.abstract_ftype) {
@@ -1829,7 +1828,7 @@ static IntervalTimer<TimerGameCalendar>
NetworkAutoCleanCompanies();
NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);
if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);
if ((TimerGameCalendar::month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);
/** Daily "callback". Called whenever the date changes. */
@@ -1838,7 +1837,7 @@ static IntervalTimer<TimerGameCalendar>
if (!_network_server) return;
NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);
if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
if ((TimerGameCalendar::date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
@@ -6498,18 +6498,18 @@ bool GetGlobalVariable(byte param, uint3
switch (param) {
case 0x00: // current date
*value = std::max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
*value = std::max(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
case 0x01: // current year
*value = Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
*value = Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24)
Date start_of_year = ConvertYMDToDate(ymd.year, 0, 1);
*value = ymd.month | (ymd.day - 1) << 8 | (IsLeapYear(ymd.year) ? 1 << 15 : 0) | (_date - start_of_year) << 16;
*value = ymd.month | (ymd.day - 1) << 8 | (IsLeapYear(ymd.year) ? 1 << 15 : 0) | (TimerGameCalendar::date - start_of_year) << 16;
@@ -6522,7 +6522,7 @@ bool GetGlobalVariable(byte param, uint3
case 0x09: // date fraction
*value = _date_fract * 885;
*value = TimerGameCalendar::date_fract * 885;
case 0x0A: // animation counter
@@ -6615,11 +6615,11 @@ bool GetGlobalVariable(byte param, uint3
case 0x23: // long format date
*value = _date;
*value = TimerGameCalendar::date;
case 0x24: // long format year
*value = _cur_year;
*value = TimerGameCalendar::year;
default: return false;
@@ -9939,16 +9939,16 @@ void LoadNewGRF(uint load_index, uint nu
* so all NewGRFs are loaded equally. For this we use the
* start date of the game and we set the counters, etc. to
* 0 so they're the same too. */
Date date = _date;
Year year = _cur_year;
DateFract date_fract = _date_fract;
Date date = TimerGameCalendar::date;
Year year = TimerGameCalendar::year;
DateFract date_fract = TimerGameCalendar::date_fract;
uint64 tick_counter = _tick_counter;
byte display_opt = _display_opt;
if (_networking) {
_cur_year = _settings_game.game_creation.starting_year;
_date = ConvertYMDToDate(_cur_year, 0, 1);
_date_fract = 0;
TimerGameCalendar::year = _settings_game.game_creation.starting_year;
TimerGameCalendar::date = ConvertYMDToDate(TimerGameCalendar::year, 0, 1);
TimerGameCalendar::date_fract = 0;
_tick_counter = 0;
_display_opt = 0;
@@ -10043,9 +10043,9 @@ void LoadNewGRF(uint load_index, uint nu
AfterLoadGRFs();
/* Now revert back to the original situation */
_cur_year = year;
_date_fract = date_fract;
TimerGameCalendar::year = year;
TimerGameCalendar::date = date;
TimerGameCalendar::date_fract = date_fract;
_tick_counter = tick_counter;
_display_opt = display_opt;
@@ -9,7 +9,7 @@
#include "debug.h"
#include "newgrf_spritegroup.h"
#include "newgrf_text.h"
#include "station_base.h"
@@ -124,9 +124,9 @@ AirportSpec AirportSpec::specs[NUM_AIRPO
bool AirportSpec::IsAvailable() const
if (!this->enabled) return false;
if (_cur_year < this->min_year) return false;
if (TimerGameCalendar::year < this->min_year) return false;
if (_settings_game.station.never_expire_airports) return true;
return _cur_year <= this->max_year;
return TimerGameCalendar::year <= this->max_year;
#include "newgrf_cargo.h"
#include "core/random_func.hpp"
#include "aircraft.h"
@@ -971,11 +971,11 @@ static uint32 VehicleGetVariable(Vehicle
case 0x48: return Engine::Get(this->self_type)->flags; // Vehicle Type Info
case 0x49: return _cur_year; // 'Long' format build year
case 0x4B: return _date; // Long date of last service
case 0x92: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); // Date of last service
case 0x93: return GB(Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8);
case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year
case 0x49: return TimerGameCalendar::year; // 'Long' format build year
case 0x4B: return TimerGameCalendar::date; // Long date of last service
case 0x92: return Clamp(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); // Date of last service
case 0x93: return GB(Clamp(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8);
case 0xC4: return Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year
case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
case 0xDA: return INVALID_VEHICLE; // Next vehicle
#include "newgrf_sound.h"
#include "object_base.h"
#include "object_map.h"
#include "tile_cmd.h"
@@ -82,7 +83,7 @@ bool ObjectSpec::IsEverAvailable() const
bool ObjectSpec::WasEverAvailable() const
return this->IsEverAvailable() && _date > this->introduction_date;
return this->IsEverAvailable() && TimerGameCalendar::date > this->introduction_date;
@@ -92,7 +93,7 @@ bool ObjectSpec::WasEverAvailable() cons
bool ObjectSpec::IsAvailable() const
return this->WasEverAvailable() &&
(_date < this->end_of_life_date || this->end_of_life_date < this->introduction_date + 365);
(TimerGameCalendar::date < this->end_of_life_date || this->end_of_life_date < this->introduction_date + 365);
@@ -276,7 +277,7 @@ static uint32 GetCountAndDistanceOfClose
/* Construction date */
case 0x42: return _date;
case 0x42: return TimerGameCalendar::date;
/* Object founder information */
case 0x44: return _current_company;
@@ -166,7 +166,7 @@ uint32 NewGRFProfiler::FinishAll()
static IntervalTimer<TimerGameCalendar> _check_profiling_finished({TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [](auto)
if (_newgrf_profilers.empty() || _newgrf_profile_end_date > _date) return;
if (_newgrf_profilers.empty() || _newgrf_profile_end_date > TimerGameCalendar::date) return;
NewGRFProfiler::FinishAll();
@@ -10,7 +10,7 @@
#include "newgrf_railtype.h"
#include "depot_base.h"
@@ -29,7 +29,7 @@
case 0x40: return 0;
case 0x41: return 0;
case 0x42: return 0;
case 0x43: return _date;
case 0x43: return TimerGameCalendar::date;
case 0x44: return HZB_TOWN_EDGE;
@@ -40,7 +40,7 @@
case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile);
case 0x43:
if (IsRailDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date;
return _date;
return TimerGameCalendar::date;
case 0x44: {
const Town *t = nullptr;
if (IsRailDepotTile(this->tile)) {
@@ -19,7 +19,7 @@
#include "road.h"
#include "window_type.h"
#include "newgrf_animation_base.h"
@@ -176,7 +176,7 @@ uint32 RoadStopScopeResolver::GetVariabl
case 0xF0: return this->st == nullptr ? 0 : this->st->facilities; // facilities
case 0xFA: return Clamp((this->st == nullptr ? _date : this->st->build_date) - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // build date
case 0xFA: return Clamp((this->st == nullptr ? TimerGameCalendar::date : this->st->build_date) - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // build date
if (this->st != nullptr) return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
#include "newgrf_roadtype.h"
if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date;
if (IsRoadDepotTile(this->tile)) {
@@ -23,6 +23,7 @@
#include "tunnelbridge_map.h"
#include "newgrf_class_func.h"
@@ -293,7 +294,7 @@ TownScopeResolver *StationResolverObject
case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value
case 0xFA: return Clamp(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value
*available = false;
@@ -13,6 +13,7 @@
#include "vehicle_base.h"
#include "vehicle_gui.h"
@@ -686,7 +687,7 @@ static void MoveToNextTickerItem()
const NewsType type = ni->type;
/* check the date, don't show too old items */
if (_date - _news_type_data[type].age > ni->date) continue;
if (TimerGameCalendar::date - _news_type_data[type].age > ni->date) continue;
switch (_news_type_data[type].GetDisplay()) {
default: NOT_REACHED();
@@ -723,7 +724,7 @@ static void MoveToNextNewsItem()
@@ -800,10 +801,10 @@ static void DeleteNewsItem(NewsItem *ni)
* @see NewsSubtype
NewsItem::NewsItem(StringID string_id, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, const NewsAllocatedData *data) :
string_id(string_id), date(_date), type(type), flags(flags), reftype1(reftype1), reftype2(reftype2), ref1(ref1), ref2(ref2), data(data)
string_id(string_id), date(TimerGameCalendar::date), type(type), flags(flags), reftype1(reftype1), reftype2(reftype2), ref1(ref1), ref2(ref2), data(data)
/* show this news message in colour? */
if (_cur_year >= _settings_client.gui.coloured_news_year) this->flags |= NF_INCOLOUR;
if (TimerGameCalendar::year >= _settings_client.gui.coloured_news_year) this->flags |= NF_INCOLOUR;
CopyOutDParam(this->params, 0, lengthof(this->params));
@@ -983,7 +984,7 @@ static void RemoveOldNewsItems()
NewsItem *next;
for (NewsItem *cur = _oldest_news; _total_news > MIN_NEWS_AMOUNT && cur != nullptr; cur = next) {
next = cur->next;
if (_date - _news_type_data[cur->type].age * _settings_client.gui.news_message_timeout > cur->date) DeleteNewsItem(cur);
if (TimerGameCalendar::date - _news_type_data[cur->type].age * _settings_client.gui.news_message_timeout > cur->date) DeleteNewsItem(cur);
@@ -1009,9 +1010,9 @@ void NewsLoop()
static byte _last_clean_month = 0;
if (_last_clean_month != _cur_month) {
if (_last_clean_month != TimerGameCalendar::month) {
RemoveOldNewsItems();
_last_clean_month = _cur_month;
_last_clean_month = TimerGameCalendar::month;
if (ReadyForNextTickerItem()) MoveToNextTickerItem();
#include "newgrf_config.h"
#include "newgrf_object.h"
#include "newgrf_debug.h"
#include "station_func.h"
@@ -92,7 +92,7 @@ void BuildObject(ObjectType type, TileIn
o->type = type;
o->location = ta;
o->town = town == nullptr ? CalcClosestTownFromTile(tile) : town;
o->build_date = _date;
o->build_date = TimerGameCalendar::date;
o->view = view;
/* If nothing owns the object, the colour will be random. Otherwise
@@ -39,7 +39,6 @@
#include "progress.h"
#include "animated_tile_func.h"
@@ -852,7 +851,7 @@ static void OnStartScenario()
/* Make sure all industries were built "this year", to avoid too early closures. (#9918) */
for (Industry *i : Industry::Iterate()) {
@@ -1106,7 +1105,7 @@ void SwitchToMode(SwitchMode new_mode)
case SM_LOAD_SCENARIO: { // Load scenario from scenario editor
if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_EDITOR, NO_DIRECTORY)) {
SetLocalCompany(OWNER_NONE);
_settings_newgame.game_creation.starting_year = _cur_year;
_settings_newgame.game_creation.starting_year = TimerGameCalendar::year;
/* Cancel the saveload pausing */
Command<CMD_PAUSE>::Post(PM_PAUSED_SAVELOAD, false);
@@ -1390,10 +1389,10 @@ void StateGameLoop()
CallWindowGameTickEvent();
NewsLoop();
if (_debug_desync_level > 2 && _date_fract == 0 && (_date & 0x1F) == 0) {
if (_debug_desync_level > 2 && TimerGameCalendar::date_fract == 0 && (TimerGameCalendar::date & 0x1F) == 0) {
/* Save the desync savegame if needed. */
@@ -1432,7 +1431,7 @@ void StateGameLoop()
static IntervalTimer<TimerGameCalendar> _autosave_interval({TimerGameCalendar::MONTH, TimerGameCalendar::Priority::AUTOSAVE}, [](auto)
if (_settings_client.gui.autosave == 0) return;
if ((_cur_month % _autosave_months[_settings_client.gui.autosave]) != 0) return;
if ((TimerGameCalendar::month % _autosave_months[_settings_client.gui.autosave]) != 0) return;
_do_autosave = true;
#include "station_map.h"
#include "engine_base.h"
@@ -256,7 +256,7 @@ RailTypes GetCompanyRailtypes(CompanyID
const EngineInfo *ei = &e->info;
if (HasBit(ei->climates, _settings_game.game_creation.landscape) &&
(HasBit(e->company_avail, company) || _date >= e->intro_date + DAYS_IN_YEAR)) {
(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + DAYS_IN_YEAR)) {
const RailVehicleInfo *rvi = &e->u.rail;
if (rvi->railveh_type != RAILVEH_WAGON) {
@@ -270,7 +270,7 @@ RailTypes GetCompanyRailtypes(CompanyID
if (introduces) return AddDateIntroducedRailTypes(rts, _date);
if (introduces) return AddDateIntroducedRailTypes(rts, TimerGameCalendar::date);
return rts;
@@ -26,7 +26,7 @@
#include "pbs.h"
#include "core/backup_type.hpp"
#include "company_gui.h"
@@ -997,7 +997,7 @@ CommandCost CmdBuildTrainDepot(DoCommand
if (flags & DC_EXEC) {
Depot *d = new Depot(tile);
d->build_date = _date;
d->build_date = TimerGameCalendar::date;
MakeRailDepot(tile, _current_company, d->index, dir, railtype);
MarkTileDirtyByTile(tile);
@@ -19,7 +19,6 @@
@@ -250,7 +249,7 @@ static void GenericPlaceSignals(TileInde
Command<CMD_BUILD_SIGNALS>::Post(_convert_signal_button ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
tile, track, _cur_signal_type, _cur_signal_variant, _convert_signal_button, false, _ctrl_pressed, cycle_start, SIGTYPE_LAST, 0, 0);
SignalVariant sigvar = _cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC;
SignalVariant sigvar = TimerGameCalendar::year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC;
Command<CMD_BUILD_SIGNALS>::Post(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
tile, track, _settings_client.gui.default_signal_type, sigvar, false, false, _ctrl_pressed, cycle_start, SIGTYPE_LAST, 0, 0);
@@ -399,7 +398,7 @@ static void HandleAutoSignalPlacement()
bool sig_gui = FindWindowById(WC_BUILD_SIGNAL, 0) != nullptr;
SignalType sigtype = sig_gui ? _cur_signal_type : _settings_client.gui.default_signal_type;
SignalVariant sigvar = sig_gui ? _cur_signal_variant : (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
SignalVariant sigvar = sig_gui ? _cur_signal_variant : (TimerGameCalendar::year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
Command<CMD_BUILD_SIGNAL_TRACK>::Post(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), track, sigtype, sigvar, false, _ctrl_pressed, !_settings_client.gui.drag_signals_fixed_distance, _settings_client.gui.drag_signals_density);
@@ -2195,7 +2194,7 @@ static void SetDefaultRailGui()
void ResetSignalVariant(int32 new_value)
SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
SignalVariant new_variant = (TimerGameCalendar::year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
if (new_variant != _cur_signal_variant) {
Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
@@ -2209,7 +2208,7 @@ void ResetSignalVariant(int32 new_value)
static IntervalTimer<TimerGameCalendar> _check_reset_signal({TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [](auto)
if (_cur_year != _settings_client.gui.semaphore_build_before) return;
if (TimerGameCalendar::year != _settings_client.gui.semaphore_build_before) return;
@@ -15,7 +15,7 @@
#include "landscape.h"
#include "road_func.h"
@@ -194,7 +194,7 @@ RoadTypes GetCompanyRoadTypes(CompanyID
const RoadVehicleInfo *rvi = &e->u.road;
assert(rvi->roadtype < ROADTYPE_END);
if (introduces) {
@@ -205,7 +205,7 @@ RoadTypes GetCompanyRoadTypes(CompanyID
if (introduces) return AddDateIntroducedRoadTypes(rts, _date);
if (introduces) return AddDateIntroducedRoadTypes(rts, TimerGameCalendar::date);
@@ -33,7 +33,7 @@
@@ -1171,7 +1171,7 @@ CommandCost CmdBuildRoadDepot(DoCommandF
Depot *dep = new Depot(tile);
dep->build_date = _date;
dep->build_date = TimerGameCalendar::date;
/* A road depot has two road bits. */
UpdateCompanyRoadInfrastructure(rt, _current_company, ROAD_DEPOT_TRACKBIT_FACTOR);
@@ -30,7 +30,6 @@
#include "station_cmd.h"
#include "road_cmd.h"
#include "tunnelbridge_cmd.h"
@@ -1875,7 +1874,7 @@ DropDownList GetRoadTypeDropDownList(Roa
DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts)
RoadTypes avail_roadtypes = GetRoadTypes(false);
avail_roadtypes = AddDateIntroducedRoadTypes(avail_roadtypes, _date);
avail_roadtypes = AddDateIntroducedRoadTypes(avail_roadtypes, TimerGameCalendar::date);
RoadTypes used_roadtypes = GetRoadTypes(true);
/* Filter listed road types */
#include "pathfinder/yapf/yapf.h"
@@ -298,8 +298,8 @@ CommandCost CmdBuildRoadVehicle(DoComman
v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
v->build_year = _cur_year;
v->build_year = TimerGameCalendar::year;
v->random_bits = VehicleRandomBits();
@@ -260,7 +260,7 @@ static void InitializeWindowsAndCaches()
* accordingly if it is not the case. No need to set it on companies that are not been used already,
* thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
@@ -748,12 +748,12 @@ bool AfterLoadGame()
default: break;
/* The value of _date_fract got divided, so make sure that old games are converted correctly. */
if (IsSavegameVersionBefore(SLV_11, 1) || (IsSavegameVersionBefore(SLV_147) && _date_fract > DAY_TICKS)) _date_fract /= 885;
/* The value of TimerGameCalendar::date_fract got divided, so make sure that old games are converted correctly. */
if (IsSavegameVersionBefore(SLV_11, 1) || (IsSavegameVersionBefore(SLV_147) && TimerGameCalendar::date_fract > DAY_TICKS)) TimerGameCalendar::date_fract /= 885;
/* Update current year
* must be done before loading sprites as some newgrfs check it */
SetDate(_date, _date_fract);
TimerGameCalendar::SetDate(TimerGameCalendar::date, TimerGameCalendar::date_fract);
/*
* Force the old behaviour for compatibility reasons with old savegames. As new
@@ -1444,8 +1444,8 @@ bool AfterLoadGame()
/* Time starts at 0 instead of 1920.
* Account for this in older games by adding an offset */
if (IsSavegameVersionBefore(SLV_31)) {
_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
_cur_year += ORIGINAL_BASE_YEAR;
TimerGameCalendar::date += DAYS_TILL_ORIGINAL_BASE_YEAR;
TimerGameCalendar::year += ORIGINAL_BASE_YEAR;
for (Station *st : Station::Iterate()) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
for (Waypoint *wp : Waypoint::Iterate()) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
@@ -1960,7 +1960,7 @@ bool AfterLoadGame()
/* Replace "house construction year" with "house age" */
if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) {
t.m5() = Clamp(_cur_year - (t.m5() + ORIGINAL_BASE_YEAR), 0, 0xFF);
t.m5() = Clamp(TimerGameCalendar::year - (t.m5() + ORIGINAL_BASE_YEAR), 0, 0xFF);
@@ -2108,7 +2108,7 @@ bool AfterLoadGame()
o->location.tile = (TileIndex)t;
o->location.w = size;
o->location.h = size;
o->town = type == OBJECT_STATUE ? Town::Get(t.m2()) : CalcClosestTownFromTile(t, UINT_MAX);
t.m2() = o->index;
Object::IncTypeCount(type);
@@ -2437,7 +2437,7 @@ bool AfterLoadGame()
if (IsSavegameVersionBefore(SLV_142)) {
for (Depot *d : Depot::Iterate()) d->build_date = _date;
for (Depot *d : Depot::Iterate()) d->build_date = TimerGameCalendar::date;
/* In old versions it was possible to remove an airport while a plane was
#include "compat/misc_sl_compat.h"
#include "../zoom_func.h"
#include "../window_gui.h"
#include "../window_func.h"
@@ -72,9 +73,9 @@ byte _age_cargo_skip_counter; ///< Skip
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
static const SaveLoad _date_desc[] = {
SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", _date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR("date_fract", _date_fract, SLE_UINT16),
SLEG_CONDVAR("date", TimerGameCalendar::date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", TimerGameCalendar::date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR("date_fract", TimerGameCalendar::date_fract, SLE_UINT16),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_CONDVAR("age_cargo_skip_counter", _age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162),
#include "../debug.h"
#include "../depot_base.h"
#include "../vehicle_func.h"
#include "../effectvehicle_base.h"
#include "../engine_func.h"
@@ -398,7 +399,7 @@ static bool FixTTOEngines()
for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_AIRCRAFT, i);
Date aging_date = std::min(_date + DAYS_TILL_ORIGINAL_BASE_YEAR, ConvertYMDToDate(2050, 0, 1));
Date aging_date = std::min(TimerGameCalendar::date + DAYS_TILL_ORIGINAL_BASE_YEAR, ConvertYMDToDate(2050, 0, 1));
for (EngineID i = 0; i < 256; i++) {
int oi = ttd_to_tto[i];
@@ -406,17 +407,17 @@ static bool FixTTOEngines()
if (oi == 255) {
/* Default engine is used */
StartupOneEngine(e, aging_date, 0);
CalcEngineReliability(e, false);
e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
_date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
TimerGameCalendar::date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
/* Make sure for example monorail and maglev are available when they should be */
if (_date >= e->intro_date && HasBit(e->info.climates, 0)) {
if (TimerGameCalendar::date >= e->intro_date && HasBit(e->info.climates, 0)) {
e->age = _date > e->intro_date ? (_date - e->intro_date) / 30 : 0;
e->age = TimerGameCalendar::date > e->intro_date ? (TimerGameCalendar::date - e->intro_date) / 30 : 0;
/* Using data from TTO savegame */
@@ -846,7 +847,7 @@ static bool LoadOldIndustry(LoadgameStat
if (i->type == 0x0A) i->type = 0x12; // Iron Ore Mine has different ID
i->last_prod_year = ymd.year;
i->random_colour = RemapTTOColour(i->random_colour);
@@ -1580,8 +1581,8 @@ extern uint8 _old_units;
static const OldChunks main_chunk[] = {
OCL_ASSERT( OC_TTD, 0 ),
OCL_ASSERT( OC_TTO, 0 ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
OCL_VAR ( OC_UINT16, 1, &_date_fract ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &TimerGameCalendar::date ),
OCL_VAR ( OC_UINT16, 1, &TimerGameCalendar::date_fract ),
OCL_NULL( 600 ), ///< TextEffects
OCL_VAR ( OC_UINT32, 2, &_random.state ),
@@ -3281,7 +3281,7 @@ SaveOrLoadResult SaveOrLoad(const std::s
if (fop == SLO_SAVE) { // SAVE game
Debug(desync, 1, "save: {:08x}; {:02x}; {}", _date, _date_fract, filename);
Debug(desync, 1, "save: {:08x}; {:02x}; {}", TimerGameCalendar::date, TimerGameCalendar::date_fract, filename);
if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
return DoSave(new FileWriter(fh), threaded);
@@ -3359,7 +3359,7 @@ void GenerateDefaultSaveName(char *buf,
case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
SetDParam(2, _date);
SetDParam(2, TimerGameCalendar::date);
/* Get the correct string (special string for when there's not company) */
GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
@@ -13,17 +13,17 @@
#include "../script_instance.hpp"
#include "../../bridge_map.h"
#include "../../strings_func.h"
#include "../../landscape_cmd.h"
#include "../../road_cmd.h"
#include "../../tunnelbridge_cmd.h"
#include "table/strings.h"
#include "../../safeguards.h"
/* static */ bool ScriptBridge::IsValidBridge(BridgeID bridge_id)
return bridge_id < MAX_BRIDGES && ::GetBridgeSpec(bridge_id)->avail_year <= _cur_year;
return bridge_id < MAX_BRIDGES && ::GetBridgeSpec(bridge_id)->avail_year <= TimerGameCalendar::year;
/* static */ bool ScriptBridge::IsBridgeTile(TileIndex tile)
#include "../../stdafx.h"
#include "script_date.hpp"
#include <time.h>
@@ -22,7 +23,7 @@
/* static */ ScriptDate::Date ScriptDate::GetCurrentDate()
return (ScriptDate::Date)_date;
return (ScriptDate::Date)TimerGameCalendar::date;
/* static */ SQInteger ScriptDate::GetYear(ScriptDate::Date date)
#include "spritecache.h"
@@ -891,8 +891,8 @@ CommandCost CmdBuildShip(DoCommandFlag f
v->state = TRACK_BIT_DEPOT;
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships);
#include "roadveh.h"
#include "viewport_kdtree.h"
@@ -234,7 +233,7 @@ void Station::AddFacility(StationFacilit
this->facilities |= new_facility_bit;
this->owner = _current_company;
this->build_date = _date;
this->build_date = TimerGameCalendar::date;
@@ -3807,9 +3807,9 @@ void DeleteStaleLinks(Station *from)
for (Edge &edge : (*lg)[ge.node].edges) {
Station *to = Station::Get((*lg)[edge.dest_node].station);
assert(to->goods[c].node == edge.dest_node);
assert(_date >= edge.LastUpdate());
assert(TimerGameCalendar::date >= edge.LastUpdate());
uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3);
if ((uint)(_date - edge.LastUpdate()) > timeout) {
if ((uint)(TimerGameCalendar::date - edge.LastUpdate()) > timeout) {
bool updated = false;
if (auto_distributed) {
@@ -3837,11 +3837,11 @@ void DeleteStaleLinks(Station *from)
while (iter != vehicles.end()) {
Vehicle *v = *iter;
/* Do not refresh links of vehicles that have been stopped in depot for a long time. */
if (!v->IsStoppedInDepot() || static_cast<uint>(_date - v->date_of_last_service) <=
if (!v->IsStoppedInDepot() || static_cast<uint>(TimerGameCalendar::date - v->date_of_last_service) <=
LinkGraph::STALE_LINK_DEPOT_TIMEOUT) {
LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted.
if (edge.LastUpdate() == _date) {
if (edge.LastUpdate() == TimerGameCalendar::date) {
updated = true;
@@ -3864,19 +3864,19 @@ void DeleteStaleLinks(Station *from)
ge.flows.DeleteFlows(to->index);
RerouteCargo(from, c, to->index, from->index);
} else if (edge.last_unrestricted_update != INVALID_DATE && (uint)(_date - edge.last_unrestricted_update) > timeout) {
} else if (edge.last_unrestricted_update != INVALID_DATE && (uint)(TimerGameCalendar::date - edge.last_unrestricted_update) > timeout) {
edge.Restrict();
ge.flows.RestrictFlows(to->index);
} else if (edge.last_restricted_update != INVALID_DATE && (uint)(_date - edge.last_restricted_update) > timeout) {
} else if (edge.last_restricted_update != INVALID_DATE && (uint)(TimerGameCalendar::date - edge.last_restricted_update) > timeout) {
edge.Release();
/* Remove dead edges. */
for (NodeID r : to_remove) (*lg)[ge.node].RemoveEdge(r);
assert(_date >= lg->LastCompression());
if ((uint)(_date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) {
assert(TimerGameCalendar::date >= lg->LastCompression());
if ((uint)(TimerGameCalendar::date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) {
lg->Compress();
@@ -4304,7 +4304,7 @@ void BuildOilRig(TileIndex tile)
st->airport.Add(tile);
st->ship_station.Add(tile);
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
st->build_date = _date;
st->build_date = TimerGameCalendar::date;
UpdateStationDockingTiles(st);
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
@@ -138,7 +137,7 @@ struct StatusBarWindow : Window {
switch (widget) {
case WID_S_LEFT:
/* Draw the date */
SetDParam(0, _date);
SetDParam(0, TimerGameCalendar::date);
DrawString(tr, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
#include "string_func.h"
#include "tile_map.h"
#include "goal_type.h"
@@ -218,7 +218,7 @@ std::tuple<CommandCost, StoryPageID> Cmd
StoryPage *s = new StoryPage();
s->sort_value = _story_page_next_sort_value;
s->date = _date;
s->date = TimerGameCalendar::date;
s->company = company;
if (text.empty()) {
s->title = nullptr;
@@ -10,7 +10,6 @@
#include "story_base.h"
#include "subsidy_func.h"
@@ -143,7 +144,7 @@ struct SubsidyListWindow : Window {
if (widget != WID_SUL_PANEL) return;
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
@@ -160,7 +161,7 @@ struct SubsidyListWindow : Window {
if (IsInsideMM(pos, 0, cap)) {
/* Displays the two offered towns */
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
SetDParam(7, _date - ymd.day + s->remaining * 32);
SetDParam(7, TimerGameCalendar::date - ymd.day + s->remaining * 32);
DrawString(tr.left, tr.right, tr.top + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_OFFERED_FROM_TO);
pos++;
@@ -184,7 +185,7 @@ struct SubsidyListWindow : Window {
SetDParam(7, s->awarded);
SetDParam(8, _date - ymd.day + s->remaining * 32);
SetDParam(8, TimerGameCalendar::date - ymd.day + s->remaining * 32);
/* Displays the two connected stations */
DrawString(tr.left, tr.right, tr.top + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_SUBSIDISED_FROM_TO);
@@ -20,6 +20,29 @@
Year TimerGameCalendar::year = {};
Month TimerGameCalendar::month = {};
Date TimerGameCalendar::date = {};
DateFract TimerGameCalendar::date_fract = {};
/* static */ void TimerGameCalendar::SetDate(Date date, DateFract fract)
TimerGameCalendar::date_fract = fract;
TimerGameCalendar::year = ymd.year;
TimerGameCalendar::month = ymd.month;
template<>
void IntervalTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
@@ -48,25 +71,25 @@ void TimerManager<TimerGameCalendar>::El
if (_game_mode == GM_MENU) return;
_date_fract++;
if (_date_fract < DAY_TICKS) return;
TimerGameCalendar::date_fract++;
if (TimerGameCalendar::date_fract < DAY_TICKS) return;
/* increase day counter */
_date++;
TimerGameCalendar::date++;
/* check if we entered a new month? */
bool new_month = ymd.month != _cur_month;
bool new_month = ymd.month != TimerGameCalendar::month;
/* check if we entered a new year? */
bool new_year = ymd.year != _cur_year;
bool new_year = ymd.year != TimerGameCalendar::year;
/* update internal variables before calling the daily/monthly/yearly loops */
/* Make a temporary copy of the timers, as a timer's callback might add/remove other timers. */
auto timers = TimerManager<TimerGameCalendar>::GetTimers();
@@ -88,12 +111,12 @@ void TimerManager<TimerGameCalendar>::El
/* check if we reached the maximum year, decrement dates by a year */
if (_cur_year == MAX_YEAR + 1) {
if (TimerGameCalendar::year == MAX_YEAR + 1) {
int days_this_year;
_cur_year--;
days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
_date -= days_this_year;
TimerGameCalendar::year--;
days_this_year = IsLeapYear(TimerGameCalendar::year) ? DAYS_IN_LEAP_YEAR : 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);
@@ -10,6 +10,8 @@
#ifndef TIMER_GAME_CALENDAR_H
#define TIMER_GAME_CALENDAR_H
#include "../date_type.h"
* Timer that is increased every 27ms, and counts towards ticks / days / months / years.
*
@@ -72,6 +74,13 @@ public:
using TElapsed = uint;
struct TStorage {
static void SetDate(Date date, DateFract fract);
static Year year; ///< Current year, starting at 0.
static Month month; ///< Current month (0..11).
static Date date; ///< Current date in days (day counter).
static DateFract date_fract; ///< Fractional part of the day.
#endif /* TIMER_GAME_CALENDAR_H */
#include "timetable_cmd.h"
@@ -304,8 +304,8 @@ CommandCost CmdSetTimetableStart(DoComma
/* Don't let a timetable start more than 15 years into the future or 1 year in the past. */
if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
if (start_date - _date > MAX_TIMETABLE_START_YEARS * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (start_date - TimerGameCalendar::date > MAX_TIMETABLE_START_YEARS * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (TimerGameCalendar::date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (timetable_all && !v->orders->IsCompleteTimetable()) return CommandCost(STR_ERROR_TIMETABLE_INCOMPLETE);
if (timetable_all && start_date + total_duration / DAY_TICKS > MAX_DAY) return CMD_ERROR;
@@ -426,7 +426,7 @@ void UpdateVehicleTimetable(Vehicle *v,
just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
if (v->timetable_start != 0) {
v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract;
v->lateness_counter = (TimerGameCalendar::date - v->timetable_start) * DAY_TICKS + TimerGameCalendar::date_fract;
v->timetable_start = 0;
@@ -185,7 +185,7 @@ struct TimetableWindow : Window {
assert(HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED));
bool travelling = (!v->current_order.IsType(OT_LOADING) || v->current_order.GetNonStopType() == ONSF_STOP_EVERYWHERE);
Ticks start_time = _date_fract - v->current_order_time;
Ticks start_time = TimerGameCalendar::date_fract - v->current_order_time;
FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time);
@@ -474,7 +474,7 @@ struct TimetableWindow : Window {
/* Now actually draw the arrival time. */
SetDParam(0, _date + (arr_dep[i / 2].arrival + this_offset) / DAY_TICKS);
SetDParam(0, TimerGameCalendar::date + (arr_dep[i / 2].arrival + this_offset) / DAY_TICKS);
DrawString(time.left, time.right, tr.top, STR_JUST_DATE_TINY, colour);
@@ -482,7 +482,7 @@ struct TimetableWindow : Window {
if (arr_dep[i / 2].departure != INVALID_TICKS) {
DrawString(abbr.left, abbr.right, tr.top, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK);
TextColour colour = show_late ? TC_RED : (i == selected ? TC_WHITE : TC_BLACK);
SetDParam(0, _date + (arr_dep[i / 2].departure + offset) / DAY_TICKS);
SetDParam(0, TimerGameCalendar::date + (arr_dep[i / 2].departure + offset) / DAY_TICKS);
@@ -572,7 +572,7 @@ struct TimetableWindow : Window {
case WID_VT_START_DATE: // Change the date that the timetable starts.
ShowSetDateWindow(this, v->index, _date, _cur_year, _cur_year + MAX_TIMETABLE_START_YEARS, ChangeTimetableStartCallback, reinterpret_cast<void *>(static_cast<uintptr_t>(_ctrl_pressed)));
ShowSetDateWindow(this, v->index, TimerGameCalendar::date, TimerGameCalendar::year, TimerGameCalendar::year + MAX_TIMETABLE_START_YEARS, ChangeTimetableStartCallback, reinterpret_cast<void *>(static_cast<uintptr_t>(_ctrl_pressed)));
case WID_VT_CHANGE_TIME: { // "Wait For" button.
@@ -1149,8 +1149,8 @@ void SetStartingYear(Year year)
_settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
/* If you open a savegame as scenario there may already be link graphs.*/
SetDate(new_date, 0);
TimerGameCalendar::SetDate(new_date, 0);
@@ -873,7 +873,7 @@ RoadType GetTownRoadType(const Town *t)
if (!HasBit(rti->flags, ROTF_TOWN_BUILD)) continue;
/* Not yet introduced at this date. */
if (IsInsideMM(rti->introduction_date, 0, MAX_DAY) && rti->introduction_date > _date) continue;
if (IsInsideMM(rti->introduction_date, 0, MAX_DAY) && rti->introduction_date > TimerGameCalendar::date) continue;
if (best != nullptr) {
if ((rti->max_speed == 0 ? assume_max_speed : rti->max_speed) < (best->max_speed == 0 ? assume_max_speed : best->max_speed)) continue;
@@ -2632,7 +2632,7 @@ static bool BuildTownHouse(Town *t, Tile
continue;
if (_cur_year < hs->min_year || _cur_year > hs->max_year) continue;
if (TimerGameCalendar::year < hs->min_year || TimerGameCalendar::year > hs->max_year) continue;
/* Special houses that there can be only one of. */
uint oneof = 0;
@@ -36,6 +36,7 @@
#include "framerate_type.h"
#include "train_cmd.h"
#include "table/train_sprites.h"
@@ -651,8 +652,8 @@ static CommandCost CmdBuildRailWagon(DoC
v->railtype = rvi->railtype;
@@ -781,8 +782,8 @@ CommandCost CmdBuildRailVehicle(DoComman
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
@@ -24,7 +24,7 @@
#include "autoslope.h"
#include "clear_func.h"
@@ -206,7 +206,7 @@ CommandCost CheckBridgeAvailability(Brid
if (bridge_type >= MAX_BRIDGES) return CMD_ERROR;
const BridgeSpec *b = GetBridgeSpec(bridge_type);
if (b->avail_year > _cur_year) return CMD_ERROR;
if (b->avail_year > TimerGameCalendar::year) return CMD_ERROR;
uint max = std::min(b->max_length, _settings_game.construction.max_bridge_length);
@@ -168,7 +168,7 @@ void VehicleServiceInDepot(Vehicle *v)
SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
do {
/* Prevent vehicles from breaking down directly after exiting the depot. */
@@ -194,7 +194,7 @@ bool Vehicle::NeedsServicing() const
const Company *c = Company::Get(this->owner);
if (this->ServiceIntervalIsPercent() ?
(this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
(this->date_of_last_service + this->GetServiceInterval() >= _date)) {
(this->date_of_last_service + this->GetServiceInterval() >= TimerGameCalendar::date)) {
@@ -920,15 +920,15 @@ void VehicleEnteredDepotThisTick(Vehicle
* Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
* Each tick, it processes vehicles with "index % DAY_TICKS == _date_fract",
* Each tick, it processes vehicles with "index % DAY_TICKS == TimerGameCalendar::date_fract",
* so each day, all vehicles are processes in DAY_TICKS steps.
static void RunVehicleDayProc()
if (_game_mode != GM_NORMAL) return;
/* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
/* Run the day_proc for every DAY_TICKS vehicle starting at TimerGameCalendar::date_fract. */
for (size_t i = TimerGameCalendar::date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
Vehicle *v = Vehicle::Get(i);
if (v == nullptr) continue;
@@ -32,7 +32,7 @@
#include "game/game.hpp"
#include "newgrf_generic.h"
@@ -134,7 +134,7 @@ CommandCost CmdBuildShipDepot(DoCommandF
Depot *depot = new Depot(tile);
depot->build_date = _date;
depot->build_date = TimerGameCalendar::date;
uint new_water_infra = 2 * LOCK_DEPOT_TILE_FACTOR;
/* Update infrastructure counts after the tile clears earlier.
@@ -248,7 +248,7 @@ CommandCost CmdBuildRailWaypoint(DoComma
wp->delete_ctr = 0;
wp->facilities |= FACIL_TRAIN;
wp->build_date = _date;
wp->build_date = TimerGameCalendar::date;
wp->string_id = STR_SV_STNAME_WAYPOINT;
wp->train_station = new_location;
@@ -329,7 +329,7 @@ CommandCost CmdBuildBuoy(DoCommandFlag f
wp->facilities |= FACIL_DOCK;
wp->owner = OWNER_NONE;
if (wp->town == nullptr) MakeDefaultName(wp);
Status change: