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 #include "economy_func.h"
00023 #ifdef _DEBUG
00024 #include "industry.h"
00025 #include "town.h"
00026 #include "station_base.h"
00027 #include "map_func.h"
00028 #endif
00029 
00030 Year      _cur_year;   
00031 Month     _cur_month;  
00032 Date      _date;       
00033 DateFract _date_fract; 
00034 uint16 _tick_counter;  
00035 
00041 void SetDate(Date date, DateFract fract)
00042 {
00043   assert(fract < DAY_TICKS);
00044 
00045   YearMonthDay ymd;
00046 
00047   _date = date;
00048   _date_fract = fract;
00049   ConvertDateToYMD(date, &ymd);
00050   _cur_year = ymd.year;
00051   _cur_month = ymd.month;
00052 }
00053 
00054 #define M(a, b) ((a << 5) | b)
00055 static const uint16 _month_date_from_year_day[] = {
00056   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),
00057   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),
00058   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),
00059   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),
00060   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),
00061   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),
00062   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),
00063   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),
00064   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),
00065   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),
00066   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),
00067   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),
00068 };
00069 #undef M
00070 
00071 enum DaysTillMonth {
00072   ACCUM_JAN = 0,
00073   ACCUM_FEB = ACCUM_JAN + 31,
00074   ACCUM_MAR = ACCUM_FEB + 29,
00075   ACCUM_APR = ACCUM_MAR + 31,
00076   ACCUM_MAY = ACCUM_APR + 30,
00077   ACCUM_JUN = ACCUM_MAY + 31,
00078   ACCUM_JUL = ACCUM_JUN + 30,
00079   ACCUM_AUG = ACCUM_JUL + 31,
00080   ACCUM_SEP = ACCUM_AUG + 31,
00081   ACCUM_OCT = ACCUM_SEP + 30,
00082   ACCUM_NOV = ACCUM_OCT + 31,
00083   ACCUM_DEC = ACCUM_NOV + 30,
00084 };
00085 
00087 static const uint16 _accum_days_for_month[] = {
00088   ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
00089   ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
00090   ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
00091 };
00092 
00098 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
00099 {
00100   /* Year determination in multiple steps to account for leap
00101    * years. First do the large steps, then the smaller ones.
00102    */
00103 
00104   /* There are 97 leap years in 400 years */
00105   Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
00106   int rem = date % (DAYS_IN_YEAR * 400 + 97);
00107   uint16 x;
00108 
00109   if (rem >= DAYS_IN_YEAR * 100 + 25) {
00110     /* There are 25 leap years in the first 100 years after
00111      * every 400th year, as every 400th year is a leap year */
00112     yr  += 100;
00113     rem -= DAYS_IN_YEAR * 100 + 25;
00114 
00115     /* There are 24 leap years in the next couple of 100 years */
00116     yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
00117     rem = (rem % (DAYS_IN_YEAR * 100 + 24));
00118   }
00119 
00120   if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
00121     /* The first 4 year of the century are not always a leap year */
00122     yr  += 4;
00123     rem -= DAYS_IN_YEAR * 4;
00124   }
00125 
00126   /* There is 1 leap year every 4 years */
00127   yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
00128   rem = rem % (DAYS_IN_YEAR * 4 + 1);
00129 
00130   /* The last (max 3) years to account for; the first one
00131    * can be, but is not necessarily a leap year */
00132   while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
00133     rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00134     yr++;
00135   }
00136 
00137   /* Skip the 29th of February in non-leap years */
00138   if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
00139 
00140   ymd->year = yr;
00141 
00142   x = _month_date_from_year_day[rem];
00143   ymd->month = x >> 5;
00144   ymd->day = x & 0x1F;
00145 }
00146 
00153 Date ConvertYMDToDate(Year year, Month month, Day day)
00154 {
00155   /* Day-offset in a leap year */
00156   int days = _accum_days_for_month[month] + day - 1;
00157 
00158   /* Account for the missing of the 29th of February in non-leap years */
00159   if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
00160 
00161   return DAYS_TILL(year) + days;
00162 }
00163 
00166 extern void EnginesDailyLoop();
00167 extern void DisasterDailyLoop();
00168 extern void IndustryDailyLoop();
00169 
00170 extern void CompaniesMonthlyLoop();
00171 extern void EnginesMonthlyLoop();
00172 extern void TownsMonthlyLoop();
00173 extern void IndustryMonthlyLoop();
00174 extern void StationMonthlyLoop();
00175 extern void SubsidyMonthlyLoop();
00176 
00177 extern void CompaniesYearlyLoop();
00178 extern void VehiclesYearlyLoop();
00179 extern void TownsYearlyLoop();
00180 
00181 extern void ShowEndGameChart();
00182 
00183 
00185 static const Month _autosave_months[] = {
00186    0, 
00187    1, 
00188    3, 
00189    6, 
00190   12, 
00191 };
00192 
00196 static void OnNewYear()
00197 {
00198   CompaniesYearlyLoop();
00199   VehiclesYearlyLoop();
00200   TownsYearlyLoop();
00201   InvalidateWindowClassesData(WC_BUILD_STATION);
00202 #ifdef ENABLE_NETWORK
00203   if (_network_server) NetworkServerYearlyLoop();
00204 #endif /* ENABLE_NETWORK */
00205 
00206   if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
00207 
00208   /* check if we reached end of the game */
00209   if (_cur_year == ORIGINAL_END_YEAR) {
00210     ShowEndGameChart();
00211   /* check if we reached the maximum year, decrement dates by a year */
00212   } else if (_cur_year == MAX_YEAR + 1) {
00213     Vehicle *v;
00214     uint days_this_year;
00215 
00216     _cur_year--;
00217     days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00218     _date -= days_this_year;
00219     FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
00220 
00221 #ifdef ENABLE_NETWORK
00222     /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
00223      *  all of them if the date is set back, else those messages will hang for ever */
00224     NetworkInitChatMessage();
00225 #endif /* ENABLE_NETWORK */
00226   }
00227 
00228   if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
00229 }
00230 
00234 static void OnNewMonth()
00235 {
00236   if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) {
00237     _do_autosave = true;
00238     SetWindowDirty(WC_STATUS_BAR, 0);
00239   }
00240 
00241   SetWindowClassesDirty(WC_CHEATS);
00242   CompaniesMonthlyLoop();
00243   EnginesMonthlyLoop();
00244   BEGIN_HEAD_TO_HEAD() {
00245     TownsMonthlyLoop();
00246     IndustryMonthlyLoop();
00247     StationMonthlyLoop();
00248   } END_HEAD_TO_HEAD()
00249   SubsidyMonthlyLoop(); // TODO: subsidies are not per h2h area yet
00250 #ifdef ENABLE_NETWORK
00251   if (_network_server) NetworkServerMonthlyLoop();
00252 #endif /* ENABLE_NETWORK */
00253 }
00254 
00258 static void OnNewDay()
00259 {
00260 #ifdef ENABLE_NETWORK
00261   if (_network_server) NetworkServerDailyLoop();
00262 #endif /* ENABLE_NETWORK */
00263 
00264   DisasterDailyLoop();
00265   int32 backup_dcc = _economy.industry_daily_change_counter;
00266   BEGIN_HEAD_TO_HEAD() {
00267     _economy.industry_daily_change_counter = backup_dcc;
00268     IndustryDailyLoop();
00269   } END_HEAD_TO_HEAD()
00270 
00271   SetWindowWidgetDirty(WC_STATUS_BAR, 0, 0);
00272   EnginesDailyLoop();
00273 
00274   /* Refresh after possible snowline change */
00275   SetWindowClassesDirty(WC_TOWN_VIEW);
00276 }
00277 
00282 void IncreaseDate()
00283 {
00284   /* increase day, and check if a new day is there? */
00285   _tick_counter++;
00286 
00287   if (_game_mode == GM_MENU) return;
00288 
00289   _date_fract++;
00290   if (_date_fract < DAY_TICKS) return;
00291   _date_fract = 0;
00292 
00293   /* increase day counter and call various daily loops */
00294   _date++;
00295   OnNewDay();
00296 
00297   YearMonthDay ymd;
00298 
00299   /* check if we entered a new month? */
00300   ConvertDateToYMD(_date, &ymd);
00301   if (ymd.month == _cur_month) return;
00302 
00303   /* yes, call various monthly loops */
00304   _cur_month = ymd.month;
00305   OnNewMonth();
00306 
00307   /* check if we entered a new year? */
00308   if (ymd.year == _cur_year) return;
00309 
00310   /* yes, call various yearly loops */
00311   _cur_year = ymd.year;
00312   OnNewYear();
00313 }