68 ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR, |
68 ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR, |
69 ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG, |
69 ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG, |
70 ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC, |
70 ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC, |
71 }; |
71 }; |
72 |
72 |
73 |
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 */ |
74 void ConvertDateToYMD(Date date, YearMonthDay *ymd) |
83 void ConvertDateToYMD(Date date, YearMonthDay *ymd) |
75 { |
84 { |
76 uint yr = date / (365 + 365 + 365 + 366); |
85 /* |
77 uint rem = date % (365 + 365 + 365 + 366); |
86 * Year determination in multiple steps to account for leap |
78 uint x; |
87 * years. First do the large steps, then the smaller ones. |
79 |
88 */ |
80 yr *= 4; |
89 |
81 |
90 /* There are 97 leap years in 400 years */ |
82 if (rem >= 366) { |
91 Year yr = 400 * (date / (365 * 400 + 97)); |
83 rem--; |
92 int rem = date % (365 * 400 + 97); |
84 do { |
93 uint16 x; |
85 rem -= 365; |
94 |
86 yr++; |
95 /* There are 24 leap years in 100 years */ |
87 } while (rem >= 365); |
96 yr += 100 * (rem / (365 * 100 + 24)); |
88 if (rem >= 31 + 28) rem++; |
97 rem = rem % (365 * 100 + 24); |
89 } |
98 |
90 |
99 /* There is 1 leap year every 4 years */ |
91 ymd->year = BASE_YEAR + yr; |
100 yr += 4 * (rem / (365 * 4 + 1)); |
|
101 rem = rem % (365 * 4 + 1); |
|
102 |
|
103 /* The last (max 3) years to account for; the first one |
|
104 * can be, but is not necessarily a leap year */ |
|
105 while (rem >= (IsLeapYear(yr) ? 366 : 365)) { |
|
106 rem -= IsLeapYear(yr) ? 366 : 365; |
|
107 yr++; |
|
108 } |
|
109 |
|
110 /* Skip the 29th of February in non-leap years */ |
|
111 if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++; |
|
112 |
|
113 ymd->year = yr; |
92 |
114 |
93 x = _month_date_from_year_day[rem]; |
115 x = _month_date_from_year_day[rem]; |
94 ymd->month = x >> 5; |
116 ymd->month = x >> 5; |
95 ymd->day = x & 0x1F; |
117 ymd->day = x & 0x1F; |
96 } |
118 } |
97 |
119 |
98 /** |
120 /** |
99 * Converts a tupe of Year, Month and Day to a Date. |
121 * Converts a tupe of Year, Month and Day to a Date. |
100 * @param year is a number between 0..? |
122 * @param year is a number between 0..MAX_YEAR |
101 * @param month is a number between 0..11 |
123 * @param month is a number between 0..11 |
102 * @param day is a number between 1..31 |
124 * @param day is a number between 1..31 |
103 */ |
125 */ |
104 Date ConvertYMDToDate(Year year, Month month, Day day) |
126 Date ConvertYMDToDate(Year year, Month month, Day day) |
105 { |
127 { |
106 uint rem; |
128 /* |
107 uint yr = year - BASE_YEAR; |
129 * Each passed leap year adds one day to the 'day count'. |
108 |
130 * |
109 /* day in the year */ |
131 * A special case for the year 0 as no year has been passed, |
110 rem = _accum_days_for_month[month] + day - 1; |
132 * but '(year - 1) / 4' does not yield '-1' to counteract the |
111 |
133 * '+1' at the end of the formula as divisions round to zero. |
112 /* remove feb 29 from year 1,2,3 */ |
134 */ |
113 if (yr & 3) rem += (yr & 3) * 365 + (rem < 31 + 29); |
135 int nr_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1); |
114 |
136 |
115 /* base date. */ |
137 /* Day-offset in a leap year */ |
116 return (yr >> 2) * (365 + 365 + 365 + 366) + rem; |
138 int days = _accum_days_for_month[month] + day - 1; |
|
139 |
|
140 /* Account for the missing of the 29th of February in non-leap years */ |
|
141 if (!IsLeapYear(year) && days >= ACCUM_MAR) days--; |
|
142 |
|
143 return year * 365 + nr_of_leap_years + days; |
117 } |
144 } |
118 |
145 |
119 /** Functions used by the IncreaseDate function */ |
146 /** Functions used by the IncreaseDate function */ |
120 |
147 |
121 extern void OnNewDay_Train(Vehicle *v); |
148 extern void OnNewDay_Train(Vehicle *v); |
250 if (_cur_year == _patches.ending_year) { |
277 if (_cur_year == _patches.ending_year) { |
251 ShowEndGameChart(); |
278 ShowEndGameChart(); |
252 /* check if we reached the maximum year, decrement dates by a year */ |
279 /* check if we reached the maximum year, decrement dates by a year */ |
253 } else if (_cur_year == MAX_YEAR + 1) { |
280 } else if (_cur_year == MAX_YEAR + 1) { |
254 Vehicle *v; |
281 Vehicle *v; |
|
282 uint days_this_year; |
255 |
283 |
256 _cur_year--; |
284 _cur_year--; |
257 _date -= 365; |
285 days_this_year = IsLeapYear(_cur_year) ? 366 : 365; |
258 FOR_ALL_VEHICLES(v) { |
286 _date -= days_this_year; |
259 v->date_of_last_service -= 365; |
287 FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year; |
260 } |
|
261 |
288 |
262 /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out |
289 /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out |
263 * all of them if the date is set back, else those messages will hang for ever */ |
290 * all of them if the date is set back, else those messages will hang for ever */ |
264 InitTextMessage(); |
291 InitTextMessage(); |
265 } |
292 } |