date.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "network/network.h"
00014 #include "network/network_func.h"
00015 #include "currency.h"
00016 #include "window_func.h"
00017 #include "settings_type.h"
00018 #include "date_func.h"
00019 #include "vehicle_base.h"
00020 #include "rail_gui.h"
00021 #include "saveload/saveload.h"
00022 
00023 Year      _cur_year;   
00024 Month     _cur_month;  
00025 Date      _date;       
00026 DateFract _date_fract; 
00027 uint16 _tick_counter;  
00028 
00034 void SetDate(Date date, DateFract fract)
00035 {
00036   assert(fract < DAY_TICKS);
00037 
00038   YearMonthDay ymd;
00039 
00040   _date = date;
00041   _date_fract = fract;
00042   ConvertDateToYMD(date, &ymd);
00043   _cur_year = ymd.year;
00044   _cur_month = ymd.month;
00045 }
00046 
00047 #define M(a, b) ((a << 5) | b)
00048 static const uint16 _month_date_from_year_day[] = {
00049   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),
00050   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),
00051   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),
00052   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),
00053   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),
00054   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),
00055   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),
00056   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),
00057   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),
00058   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),
00059   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),
00060   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),
00061 };
00062 #undef M
00063 
00064 enum DaysTillMonth {
00065   ACCUM_JAN = 0,
00066   ACCUM_FEB = ACCUM_JAN + 31,
00067   ACCUM_MAR = ACCUM_FEB + 29,
00068   ACCUM_APR = ACCUM_MAR + 31,
00069   ACCUM_MAY = ACCUM_APR + 30,
00070   ACCUM_JUN = ACCUM_MAY + 31,
00071   ACCUM_JUL = ACCUM_JUN + 30,
00072   ACCUM_AUG = ACCUM_JUL + 31,
00073   ACCUM_SEP = ACCUM_AUG + 31,
00074   ACCUM_OCT = ACCUM_SEP + 30,
00075   ACCUM_NOV = ACCUM_OCT + 31,
00076   ACCUM_DEC = ACCUM_NOV + 30,
00077 };
00078 
00080 static const uint16 _accum_days_for_month[] = {
00081   ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
00082   ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
00083   ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
00084 };
00085 
00091 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
00092 {
00093   /* Year determination in multiple steps to account for leap
00094    * years. First do the large steps, then the smaller ones.
00095    */
00096 
00097   /* There are 97 leap years in 400 years */
00098   Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
00099   int rem = date % (DAYS_IN_YEAR * 400 + 97);
00100   uint16 x;
00101 
00102   if (rem >= DAYS_IN_YEAR * 100 + 25) {
00103     /* There are 25 leap years in the first 100 years after
00104      * every 400th year, as every 400th year is a leap year */
00105     yr  += 100;
00106     rem -= DAYS_IN_YEAR * 100 + 25;
00107 
00108     /* There are 24 leap years in the next couple of 100 years */
00109     yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
00110     rem = (rem % (DAYS_IN_YEAR * 100 + 24));
00111   }
00112 
00113   if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
00114     /* The first 4 year of the century are not always a leap year */
00115     yr  += 4;
00116     rem -= DAYS_IN_YEAR * 4;
00117   }
00118 
00119   /* There is 1 leap year every 4 years */
00120   yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
00121   rem = rem % (DAYS_IN_YEAR * 4 + 1);
00122 
00123   /* The last (max 3) years to account for; the first one
00124    * can be, but is not necessarily a leap year */
00125   while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
00126     rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00127     yr++;
00128   }
00129 
00130   /* Skip the 29th of February in non-leap years */
00131   if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
00132 
00133   ymd->year = yr;
00134 
00135   x = _month_date_from_year_day[rem];
00136   ymd->month = x >> 5;
00137   ymd->day = x & 0x1F;
00138 }
00139 
00146 Date ConvertYMDToDate(Year year, Month month, Day day)
00147 {
00148   /* Day-offset in a leap year */
00149   int days = _accum_days_for_month[month] + day - 1;
00150 
00151   /* Account for the missing of the 29th of February in non-leap years */
00152   if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
00153 
00154   return DAYS_TILL(year) + days;
00155 }
00156 
00159 extern void EnginesDailyLoop();
00160 extern void DisasterDailyLoop();
00161 extern void IndustryDailyLoop();
00162 
00163 extern void CompaniesMonthlyLoop();
00164 extern void EnginesMonthlyLoop();
00165 extern void TownsMonthlyLoop();
00166 extern void IndustryMonthlyLoop();
00167 extern void StationMonthlyLoop();
00168 extern void SubsidyMonthlyLoop();
00169 
00170 extern void CompaniesYearlyLoop();
00171 extern void VehiclesYearlyLoop();
00172 extern void TownsYearlyLoop();
00173 
00174 extern void ShowEndGameChart();
00175 
00176 
00178 static const Month _autosave_months[] = {
00179    0, 
00180    1, 
00181    3, 
00182    6, 
00183   12, 
00184 };
00185 
00189 static void OnNewYear()
00190 {
00191   CompaniesYearlyLoop();
00192   VehiclesYearlyLoop();
00193   TownsYearlyLoop();
00194   InvalidateWindowClassesData(WC_BUILD_STATION);
00195 #ifdef ENABLE_NETWORK
00196   if (_network_server) NetworkServerYearlyLoop();
00197 #endif /* ENABLE_NETWORK */
00198 
00199   if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
00200 
00201   /* check if we reached end of the game */
00202   if (_cur_year == ORIGINAL_END_YEAR) {
00203     ShowEndGameChart();
00204   /* check if we reached the maximum year, decrement dates by a year */
00205   } else if (_cur_year == MAX_YEAR + 1) {
00206     Vehicle *v;
00207     uint days_this_year;
00208 
00209     _cur_year--;
00210     days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00211     _date -= days_this_year;
00212     FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
00213 
00214 #ifdef ENABLE_NETWORK
00215     /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
00216      *  all of them if the date is set back, else those messages will hang for ever */
00217     NetworkInitChatMessage();
00218 #endif /* ENABLE_NETWORK */
00219   }
00220 
00221   if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
00222 }
00223 
00227 static void OnNewMonth()
00228 {
00229   if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) {
00230     _do_autosave = true;
00231     SetWindowDirty(WC_STATUS_BAR, 0);
00232   }
00233 
00234   SetWindowClassesDirty(WC_CHEATS);
00235   CompaniesMonthlyLoop();
00236   EnginesMonthlyLoop();
00237   TownsMonthlyLoop();
00238   IndustryMonthlyLoop();
00239   SubsidyMonthlyLoop();
00240   StationMonthlyLoop();
00241 #ifdef ENABLE_NETWORK
00242   if (_network_server) NetworkServerMonthlyLoop();
00243 #endif /* ENABLE_NETWORK */
00244 }
00245 
00249 static void OnNewDay()
00250 {
00251 #ifdef ENABLE_NETWORK
00252   if (_network_server) NetworkServerDailyLoop();
00253 #endif /* ENABLE_NETWORK */
00254 
00255   DisasterDailyLoop();
00256   IndustryDailyLoop();
00257 
00258   SetWindowWidgetDirty(WC_STATUS_BAR, 0, 0);
00259   EnginesDailyLoop();
00260 
00261   /* Refresh after possible snowline change */
00262   SetWindowClassesDirty(WC_TOWN_VIEW);
00263 }
00264 
00269 void IncreaseDate()
00270 {
00271   /* increase day, and check if a new day is there? */
00272   _tick_counter++;
00273 
00274   if (_game_mode == GM_MENU) return;
00275 
00276   _date_fract++;
00277   if (_date_fract < DAY_TICKS) return;
00278   _date_fract = 0;
00279 
00280   /* increase day counter and call various daily loops */
00281   _date++;
00282   OnNewDay();
00283 
00284   YearMonthDay ymd;
00285 
00286   /* check if we entered a new month? */
00287   ConvertDateToYMD(_date, &ymd);
00288   if (ymd.month == _cur_month) return;
00289 
00290   /* yes, call various monthly loops */
00291   _cur_month = ymd.month;
00292   OnNewMonth();
00293 
00294   /* check if we entered a new year? */
00295   if (ymd.year == _cur_year) return;
00296 
00297   /* yes, call various yearly loops */
00298   _cur_year = ymd.year;
00299   OnNewYear();
00300 }