src/date.c
changeset 5584 1111b4d36e35
parent 5583 136d8764c7e6
child 5585 189f096bc9a3
equal deleted inserted replaced
5583:136d8764c7e6 5584:1111b4d36e35
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "date.h"
       
     6 #include "variables.h"
       
     7 #include "macros.h"
       
     8 #include "vehicle.h"
       
     9 #include "network/network.h"
       
    10 #include "network/network_data.h"
       
    11 #include "network/network_server.h"
       
    12 #include "functions.h"
       
    13 #include "currency.h"
       
    14 
       
    15 Year      _cur_year;
       
    16 Month     _cur_month;
       
    17 Date      _date;
       
    18 DateFract _date_fract;
       
    19 
       
    20 
       
    21 void SetDate(Date date)
       
    22 {
       
    23 	YearMonthDay ymd;
       
    24 
       
    25 	_date = date;
       
    26 	ConvertDateToYMD(date, &ymd);
       
    27 	_cur_year = ymd.year;
       
    28 	_cur_month = ymd.month;
       
    29 #ifdef ENABLE_NETWORK
       
    30 	_network_last_advertise_frame = 0;
       
    31 	_network_need_advertise = true;
       
    32 #endif /* ENABLE_NETWORK */
       
    33 }
       
    34 
       
    35 #define M(a, b) ((a << 5) | b)
       
    36 static const uint16 _month_date_from_year_day[] = {
       
    37 	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),
       
    38 	M( 1, 1), M( 1, 2), M( 1, 3), M( 1, 4), M( 1, 5), M( 1, 6), M( 1, 7), M( 1, 8), M( 1, 9), M( 1, 10), M( 1, 11), M( 1, 12), M( 1, 13), M( 1, 14), M( 1, 15), M( 1, 16), M( 1, 17), M( 1, 18), M( 1, 19), M( 1, 20), M( 1, 21), M( 1, 22), M( 1, 23), M( 1, 24), M( 1, 25), M( 1, 26), M( 1, 27), M( 1, 28), M( 1, 29),
       
    39 	M( 2, 1), M( 2, 2), M( 2, 3), M( 2, 4), M( 2, 5), M( 2, 6), M( 2, 7), M( 2, 8), M( 2, 9), M( 2, 10), M( 2, 11), M( 2, 12), M( 2, 13), M( 2, 14), M( 2, 15), M( 2, 16), M( 2, 17), M( 2, 18), M( 2, 19), M( 2, 20), M( 2, 21), M( 2, 22), M( 2, 23), M( 2, 24), M( 2, 25), M( 2, 26), M( 2, 27), M( 2, 28), M( 2, 29), M( 2, 30), M( 2, 31),
       
    40 	M( 3, 1), M( 3, 2), M( 3, 3), M( 3, 4), M( 3, 5), M( 3, 6), M( 3, 7), M( 3, 8), M( 3, 9), M( 3, 10), M( 3, 11), M( 3, 12), M( 3, 13), M( 3, 14), M( 3, 15), M( 3, 16), M( 3, 17), M( 3, 18), M( 3, 19), M( 3, 20), M( 3, 21), M( 3, 22), M( 3, 23), M( 3, 24), M( 3, 25), M( 3, 26), M( 3, 27), M( 3, 28), M( 3, 29), M( 3, 30),
       
    41 	M( 4, 1), M( 4, 2), M( 4, 3), M( 4, 4), M( 4, 5), M( 4, 6), M( 4, 7), M( 4, 8), M( 4, 9), M( 4, 10), M( 4, 11), M( 4, 12), M( 4, 13), M( 4, 14), M( 4, 15), M( 4, 16), M( 4, 17), M( 4, 18), M( 4, 19), M( 4, 20), M( 4, 21), M( 4, 22), M( 4, 23), M( 4, 24), M( 4, 25), M( 4, 26), M( 4, 27), M( 4, 28), M( 4, 29), M( 4, 30), M( 4, 31),
       
    42 	M( 5, 1), M( 5, 2), M( 5, 3), M( 5, 4), M( 5, 5), M( 5, 6), M( 5, 7), M( 5, 8), M( 5, 9), M( 5, 10), M( 5, 11), M( 5, 12), M( 5, 13), M( 5, 14), M( 5, 15), M( 5, 16), M( 5, 17), M( 5, 18), M( 5, 19), M( 5, 20), M( 5, 21), M( 5, 22), M( 5, 23), M( 5, 24), M( 5, 25), M( 5, 26), M( 5, 27), M( 5, 28), M( 5, 29), M( 5, 30),
       
    43 	M( 6, 1), M( 6, 2), M( 6, 3), M( 6, 4), M( 6, 5), M( 6, 6), M( 6, 7), M( 6, 8), M( 6, 9), M( 6, 10), M( 6, 11), M( 6, 12), M( 6, 13), M( 6, 14), M( 6, 15), M( 6, 16), M( 6, 17), M( 6, 18), M( 6, 19), M( 6, 20), M( 6, 21), M( 6, 22), M( 6, 23), M( 6, 24), M( 6, 25), M( 6, 26), M( 6, 27), M( 6, 28), M( 6, 29), M( 6, 30), M( 6, 31),
       
    44 	M( 7, 1), M( 7, 2), M( 7, 3), M( 7, 4), M( 7, 5), M( 7, 6), M( 7, 7), M( 7, 8), M( 7, 9), M( 7, 10), M( 7, 11), M( 7, 12), M( 7, 13), M( 7, 14), M( 7, 15), M( 7, 16), M( 7, 17), M( 7, 18), M( 7, 19), M( 7, 20), M( 7, 21), M( 7, 22), M( 7, 23), M( 7, 24), M( 7, 25), M( 7, 26), M( 7, 27), M( 7, 28), M( 7, 29), M( 7, 30), M( 7, 31),
       
    45 	M( 8, 1), M( 8, 2), M( 8, 3), M( 8, 4), M( 8, 5), M( 8, 6), M( 8, 7), M( 8, 8), M( 8, 9), M( 8, 10), M( 8, 11), M( 8, 12), M( 8, 13), M( 8, 14), M( 8, 15), M( 8, 16), M( 8, 17), M( 8, 18), M( 8, 19), M( 8, 20), M( 8, 21), M( 8, 22), M( 8, 23), M( 8, 24), M( 8, 25), M( 8, 26), M( 8, 27), M( 8, 28), M( 8, 29), M( 8, 30),
       
    46 	M( 9, 1), M( 9, 2), M( 9, 3), M( 9, 4), M( 9, 5), M( 9, 6), M( 9, 7), M( 9, 8), M( 9, 9), M( 9, 10), M( 9, 11), M( 9, 12), M( 9, 13), M( 9, 14), M( 9, 15), M( 9, 16), M( 9, 17), M( 9, 18), M( 9, 19), M( 9, 20), M( 9, 21), M( 9, 22), M( 9, 23), M( 9, 24), M( 9, 25), M( 9, 26), M( 9, 27), M( 9, 28), M( 9, 29), M( 9, 30), M( 9, 31),
       
    47 	M(10, 1), M(10, 2), M(10, 3), M(10, 4), M(10, 5), M(10, 6), M(10, 7), M(10, 8), M(10, 9), M(10, 10), M(10, 11), M(10, 12), M(10, 13), M(10, 14), M(10, 15), M(10, 16), M(10, 17), M(10, 18), M(10, 19), M(10, 20), M(10, 21), M(10, 22), M(10, 23), M(10, 24), M(10, 25), M(10, 26), M(10, 27), M(10, 28), M(10, 29), M(10, 30),
       
    48 	M(11, 1), M(11, 2), M(11, 3), M(11, 4), M(11, 5), M(11, 6), M(11, 7), M(11, 8), M(11, 9), M(11, 10), M(11, 11), M(11, 12), M(11, 13), M(11, 14), M(11, 15), M(11, 16), M(11, 17), M(11, 18), M(11, 19), M(11, 20), M(11, 21), M(11, 22), M(11, 23), M(11, 24), M(11, 25), M(11, 26), M(11, 27), M(11, 28), M(11, 29), M(11, 30), M(11, 31),
       
    49 };
       
    50 #undef M
       
    51 
       
    52 enum {
       
    53 	ACCUM_JAN = 0,
       
    54 	ACCUM_FEB = ACCUM_JAN + 31,
       
    55 	ACCUM_MAR = ACCUM_FEB + 29,
       
    56 	ACCUM_APR = ACCUM_MAR + 31,
       
    57 	ACCUM_MAY = ACCUM_APR + 30,
       
    58 	ACCUM_JUN = ACCUM_MAY + 31,
       
    59 	ACCUM_JUL = ACCUM_JUN + 30,
       
    60 	ACCUM_AUG = ACCUM_JUL + 31,
       
    61 	ACCUM_SEP = ACCUM_AUG + 31,
       
    62 	ACCUM_OCT = ACCUM_SEP + 30,
       
    63 	ACCUM_NOV = ACCUM_OCT + 31,
       
    64 	ACCUM_DEC = ACCUM_NOV + 30,
       
    65 };
       
    66 
       
    67 static const uint16 _accum_days_for_month[] = {
       
    68 	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
       
    69 	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
       
    70 	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
       
    71 };
       
    72 
       
    73 static inline bool IsLeapYear(Year yr)
       
    74 {
       
    75 	return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
       
    76 }
       
    77 
       
    78 /**
       
    79  * Converts a Date to a Year, Month & Day.
       
    80  * @param date the date to convert from
       
    81  * @param ymd  the year, month and day to write to
       
    82  */
       
    83 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
       
    84 {
       
    85 	/*
       
    86 	 * Year determination in multiple steps to account for leap
       
    87 	 * years. First do the large steps, then the smaller ones.
       
    88 	 */
       
    89 
       
    90 	/* There are 97 leap years in 400 years */
       
    91 	Year yr = 400 * (date / (365 * 400 + 97));
       
    92 	int rem = date % (365 * 400 + 97);
       
    93 	uint16 x;
       
    94 
       
    95 	if (rem >= 365 * 100 + 25) {
       
    96 		/* There are 25 leap years in the first 100 years after
       
    97 		 * every 400th year, as every 400th year is a leap year */
       
    98 		yr  += 100;
       
    99 		rem -= 365 * 100 + 25;
       
   100 
       
   101 		/* There are 24 leap years in the next couple of 100 years */
       
   102 		yr += 100 * (rem / (365 * 100 + 24));
       
   103 		rem = (rem % (365 * 100 + 24));
       
   104 	}
       
   105 
       
   106 	if (!IsLeapYear(yr) && rem >= 365 * 4) {
       
   107 		/* The first 4 year of the century are not always a leap year */
       
   108 		yr  += 4;
       
   109 		rem -= 365 * 4;
       
   110 	}
       
   111 
       
   112 	/* There is 1 leap year every 4 years */
       
   113 	yr += 4 * (rem / (365 * 4 + 1));
       
   114 	rem = rem % (365 * 4 + 1);
       
   115 
       
   116 	/* The last (max 3) years to account for; the first one
       
   117 	 * can be, but is not necessarily a leap year */
       
   118 	while (rem >= (IsLeapYear(yr) ? 366 : 365)) {
       
   119 		rem -= IsLeapYear(yr) ? 366 : 365;
       
   120 		yr++;
       
   121 	}
       
   122 
       
   123 	/* Skip the 29th of February in non-leap years */
       
   124 	if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
       
   125 
       
   126 	ymd->year = yr;
       
   127 
       
   128 	x = _month_date_from_year_day[rem];
       
   129 	ymd->month = x >> 5;
       
   130 	ymd->day = x & 0x1F;
       
   131 }
       
   132 
       
   133 /**
       
   134  * Converts a tupe of Year, Month and Day to a Date.
       
   135  * @param year  is a number between 0..MAX_YEAR
       
   136  * @param month is a number between 0..11
       
   137  * @param day   is a number between 1..31
       
   138  */
       
   139 Date ConvertYMDToDate(Year year, Month month, Day day)
       
   140 {
       
   141 	/*
       
   142 	 * Each passed leap year adds one day to the 'day count'.
       
   143 	 *
       
   144 	 * A special case for the year 0 as no year has been passed,
       
   145 	 * but '(year - 1) / 4' does not yield '-1' to counteract the
       
   146 	 * '+1' at the end of the formula as divisions round to zero.
       
   147 	 */
       
   148 	int nr_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1);
       
   149 
       
   150 	/* Day-offset in a leap year */
       
   151 	int days = _accum_days_for_month[month] + day - 1;
       
   152 
       
   153 	/* Account for the missing of the 29th of February in non-leap years */
       
   154 	if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
       
   155 
       
   156 	return year * 365 + nr_of_leap_years + days;
       
   157 }
       
   158 
       
   159 /** Functions used by the IncreaseDate function */
       
   160 
       
   161 extern void OnNewDay_Train(Vehicle *v);
       
   162 extern void OnNewDay_RoadVeh(Vehicle *v);
       
   163 extern void OnNewDay_Aircraft(Vehicle *v);
       
   164 extern void OnNewDay_Ship(Vehicle *v);
       
   165 static void OnNewDay_EffectVehicle(Vehicle *v) { /* empty */ }
       
   166 extern void OnNewDay_DisasterVehicle(Vehicle *v);
       
   167 
       
   168 typedef void OnNewVehicleDayProc(Vehicle *v);
       
   169 
       
   170 static OnNewVehicleDayProc * _on_new_vehicle_day_proc[] = {
       
   171 	OnNewDay_Train,
       
   172 	OnNewDay_RoadVeh,
       
   173 	OnNewDay_Ship,
       
   174 	OnNewDay_Aircraft,
       
   175 	OnNewDay_EffectVehicle,
       
   176 	OnNewDay_DisasterVehicle,
       
   177 };
       
   178 
       
   179 extern void WaypointsDailyLoop(void);
       
   180 extern void TextMessageDailyLoop(void);
       
   181 extern void EnginesDailyLoop(void);
       
   182 extern void DisasterDailyLoop(void);
       
   183 
       
   184 extern void PlayersMonthlyLoop(void);
       
   185 extern void EnginesMonthlyLoop(void);
       
   186 extern void TownsMonthlyLoop(void);
       
   187 extern void IndustryMonthlyLoop(void);
       
   188 extern void StationMonthlyLoop(void);
       
   189 
       
   190 extern void PlayersYearlyLoop(void);
       
   191 extern void TrainsYearlyLoop(void);
       
   192 extern void RoadVehiclesYearlyLoop(void);
       
   193 extern void AircraftYearlyLoop(void);
       
   194 extern void ShipsYearlyLoop(void);
       
   195 
       
   196 extern void ShowEndGameChart(void);
       
   197 
       
   198 
       
   199 static const Month _autosave_months[] = {
       
   200 	 0, // never
       
   201 	 1, // every month
       
   202 	 3, // every 3 months
       
   203 	 6, // every 6 months
       
   204 	12, // every 12 months
       
   205 };
       
   206 
       
   207 /**
       
   208  * Runs the day_proc for every DAY_TICKS vehicle starting at daytick.
       
   209  */
       
   210 static void RunVehicleDayProc(uint daytick)
       
   211 {
       
   212 	uint total = GetMaxVehicleIndex() + 1;
       
   213 	uint i;
       
   214 
       
   215 	for (i = daytick; i < total; i += DAY_TICKS) {
       
   216 		Vehicle *v = GetVehicle(i);
       
   217 
       
   218 		if (IsValidVehicle(v)) _on_new_vehicle_day_proc[v->type - 0x10](v);
       
   219 	}
       
   220 }
       
   221 
       
   222 void IncreaseDate(void)
       
   223 {
       
   224 	YearMonthDay ymd;
       
   225 
       
   226 	if (_game_mode == GM_MENU) {
       
   227 		_tick_counter++;
       
   228 		return;
       
   229 	}
       
   230 
       
   231 	RunVehicleDayProc(_date_fract);
       
   232 
       
   233 	/* increase day, and check if a new day is there? */
       
   234 	_tick_counter++;
       
   235 
       
   236 	_date_fract++;
       
   237 	if (_date_fract < DAY_TICKS) return;
       
   238 	_date_fract = 0;
       
   239 
       
   240 	/* yeah, increase day counter and call various daily loops */
       
   241 	_date++;
       
   242 
       
   243 	TextMessageDailyLoop();
       
   244 
       
   245 	DisasterDailyLoop();
       
   246 	WaypointsDailyLoop();
       
   247 
       
   248 	if (_game_mode != GM_MENU) {
       
   249 		InvalidateWindowWidget(WC_STATUS_BAR, 0, 0);
       
   250 		EnginesDailyLoop();
       
   251 	}
       
   252 
       
   253 	/* check if we entered a new month? */
       
   254 	ConvertDateToYMD(_date, &ymd);
       
   255 	if (ymd.month == _cur_month) return;
       
   256 	_cur_month = ymd.month;
       
   257 
       
   258 	/* yes, call various monthly loops */
       
   259 	if (_game_mode != GM_MENU) {
       
   260 		if (_opt.autosave != 0 && (_cur_month % _autosave_months[_opt.autosave]) == 0) {
       
   261 			_do_autosave = true;
       
   262 			RedrawAutosave();
       
   263 		}
       
   264 
       
   265 		PlayersMonthlyLoop();
       
   266 		EnginesMonthlyLoop();
       
   267 		TownsMonthlyLoop();
       
   268 		IndustryMonthlyLoop();
       
   269 		StationMonthlyLoop();
       
   270 		if (_network_server) NetworkServerMonthlyLoop();
       
   271 	}
       
   272 
       
   273 	/* check if we entered a new year? */
       
   274 	if (ymd.year == _cur_year) return;
       
   275 	_cur_year = ymd.year;
       
   276 
       
   277 	/* yes, call various yearly loops */
       
   278 	PlayersYearlyLoop();
       
   279 	TrainsYearlyLoop();
       
   280 	RoadVehiclesYearlyLoop();
       
   281 	AircraftYearlyLoop();
       
   282 	ShipsYearlyLoop();
       
   283 	if (_network_server) NetworkServerYearlyLoop();
       
   284 
       
   285 	/* check if we reached end of the game */
       
   286 	if (_cur_year == _patches.ending_year) {
       
   287 			ShowEndGameChart();
       
   288 	/* check if we reached the maximum year, decrement dates by a year */
       
   289 	} else if (_cur_year == MAX_YEAR + 1) {
       
   290 		Vehicle *v;
       
   291 		uint days_this_year;
       
   292 
       
   293 		_cur_year--;
       
   294 		days_this_year = IsLeapYear(_cur_year) ? 366 : 365;
       
   295 		_date -= days_this_year;
       
   296 		FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
       
   297 
       
   298 		/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
       
   299 		 *  all of them if the date is set back, else those messages will hang for ever */
       
   300 		InitTextMessage();
       
   301 	}
       
   302 
       
   303 	if (_patches.auto_euro) CheckSwitchToEuro();
       
   304 }