date.cpp

Go to the documentation of this file.
00001 /* $Id: date.cpp 18433 2009-12-08 19:59:21Z frosch $ */
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 "variables.h"
00014 #include "network/network.h"
00015 #include "network/network_func.h"
00016 #include "currency.h"
00017 #include "window_func.h"
00018 #include "functions.h"
00019 #include "date_func.h"
00020 #include "vehicle_base.h"
00021 #include "debug.h"
00022 #include "rail_gui.h"
00023 #include "saveload/saveload.h"
00024 
00025 Year      _cur_year;   
00026 Month     _cur_month;  
00027 Date      _date;       
00028 DateFract _date_fract;
00029 
00030 
00031 void SetDate(Date date)
00032 {
00033   YearMonthDay ymd;
00034 
00035   _date = date;
00036   ConvertDateToYMD(date, &ymd);
00037   _cur_year = ymd.year;
00038   _cur_month = ymd.month;
00039 }
00040 
00041 #define M(a, b) ((a << 5) | b)
00042 static const uint16 _month_date_from_year_day[] = {
00043   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),
00044   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),
00045   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),
00046   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),
00047   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),
00048   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),
00049   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),
00050   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),
00051   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),
00052   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),
00053   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),
00054   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),
00055 };
00056 #undef M
00057 
00058 enum {
00059   ACCUM_JAN = 0,
00060   ACCUM_FEB = ACCUM_JAN + 31,
00061   ACCUM_MAR = ACCUM_FEB + 29,
00062   ACCUM_APR = ACCUM_MAR + 31,
00063   ACCUM_MAY = ACCUM_APR + 30,
00064   ACCUM_JUN = ACCUM_MAY + 31,
00065   ACCUM_JUL = ACCUM_JUN + 30,
00066   ACCUM_AUG = ACCUM_JUL + 31,
00067   ACCUM_SEP = ACCUM_AUG + 31,
00068   ACCUM_OCT = ACCUM_SEP + 30,
00069   ACCUM_NOV = ACCUM_OCT + 31,
00070   ACCUM_DEC = ACCUM_NOV + 30,
00071 };
00072 
00073 static const uint16 _accum_days_for_month[] = {
00074   ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
00075   ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
00076   ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
00077 };
00078 
00084 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
00085 {
00086   /*
00087    * Year determination in multiple steps to account for leap
00088    * years. First do the large steps, then the smaller ones.
00089    */
00090 
00091   /* There are 97 leap years in 400 years */
00092   Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
00093   int rem = date % (DAYS_IN_YEAR * 400 + 97);
00094   uint16 x;
00095 
00096   if (rem >= DAYS_IN_YEAR * 100 + 25) {
00097     /* There are 25 leap years in the first 100 years after
00098      * every 400th year, as every 400th year is a leap year */
00099     yr  += 100;
00100     rem -= DAYS_IN_YEAR * 100 + 25;
00101 
00102     /* There are 24 leap years in the next couple of 100 years */
00103     yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
00104     rem = (rem % (DAYS_IN_YEAR * 100 + 24));
00105   }
00106 
00107   if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
00108     /* The first 4 year of the century are not always a leap year */
00109     yr  += 4;
00110     rem -= DAYS_IN_YEAR * 4;
00111   }
00112 
00113   /* There is 1 leap year every 4 years */
00114   yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
00115   rem = rem % (DAYS_IN_YEAR * 4 + 1);
00116 
00117   /* The last (max 3) years to account for; the first one
00118    * can be, but is not necessarily a leap year */
00119   while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
00120     rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00121     yr++;
00122   }
00123 
00124   /* Skip the 29th of February in non-leap years */
00125   if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
00126 
00127   ymd->year = yr;
00128 
00129   x = _month_date_from_year_day[rem];
00130   ymd->month = x >> 5;
00131   ymd->day = x & 0x1F;
00132 }
00133 
00140 Date ConvertYMDToDate(Year year, Month month, Day day)
00141 {
00142   /* Day-offset in a leap year */
00143   int days = _accum_days_for_month[month] + day - 1;
00144 
00145   /* Account for the missing of the 29th of February in non-leap years */
00146   if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
00147 
00148   return DAYS_TILL(year) + days;
00149 }
00150 
00153 extern void EnginesDailyLoop();
00154 extern void DisasterDailyLoop();
00155 extern void IndustryDailyLoop();
00156 extern void CompaniesMonthlyLoop();
00157 extern void EnginesMonthlyLoop();
00158 extern void TownsMonthlyLoop();
00159 extern void IndustryMonthlyLoop();
00160 extern void StationMonthlyLoop();
00161 extern void SubsidyMonthlyLoop();
00162 
00163 extern void CompaniesYearlyLoop();
00164 extern void VehiclesYearlyLoop();
00165 extern void TownsYearlyLoop();
00166 
00167 extern void ShowEndGameChart();
00168 
00169 
00170 static const Month _autosave_months[] = {
00171    0, 
00172    1, 
00173    3, 
00174    6, 
00175   12, 
00176 };
00177 
00181 static void OnNewYear()
00182 {
00183   CompaniesYearlyLoop();
00184   VehiclesYearlyLoop();
00185   TownsYearlyLoop();
00186   InvalidateWindowClassesData(WC_BUILD_STATION);
00187 #ifdef ENABLE_NETWORK
00188   if (_network_server) NetworkServerYearlyLoop();
00189 #endif /* ENABLE_NETWORK */
00190 
00191   if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
00192 
00193   /* check if we reached end of the game */
00194   if (_cur_year == ORIGINAL_END_YEAR) {
00195     ShowEndGameChart();
00196   /* check if we reached the maximum year, decrement dates by a year */
00197   } else if (_cur_year == MAX_YEAR + 1) {
00198     Vehicle *v;
00199     uint days_this_year;
00200 
00201     _cur_year--;
00202     days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
00203     _date -= days_this_year;
00204     FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
00205 
00206 #ifdef ENABLE_NETWORK
00207     /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
00208      *  all of them if the date is set back, else those messages will hang for ever */
00209     NetworkInitChatMessage();
00210 #endif /* ENABLE_NETWORK */
00211   }
00212 
00213   if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
00214 }
00215 
00219 static void OnNewMonth()
00220 {
00221   if (_debug_desync_level > 2) {
00222     char name[MAX_PATH];
00223     snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
00224     SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR);
00225   }
00226 
00227   if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) {
00228     _do_autosave = true;
00229     RedrawAutosave();
00230   }
00231 
00232   SetWindowClassesDirty(WC_CHEATS);
00233   CompaniesMonthlyLoop();
00234   SubsidyMonthlyLoop();
00235   EnginesMonthlyLoop();
00236   TownsMonthlyLoop();
00237   IndustryMonthlyLoop();
00238   StationMonthlyLoop();
00239 #ifdef ENABLE_NETWORK
00240   if (_network_server) NetworkServerMonthlyLoop();
00241 #endif /* ENABLE_NETWORK */
00242 }
00243 
00247 static void OnNewDay()
00248 {
00249 #ifdef ENABLE_NETWORK
00250   NetworkChatMessageDailyLoop();
00251 #endif /* ENABLE_NETWORK */
00252 
00253   DisasterDailyLoop();
00254   IndustryDailyLoop();
00255 
00256   SetWindowWidgetDirty(WC_STATUS_BAR, 0, 0);
00257   EnginesDailyLoop();
00258 
00259   /* Refresh after possible snowline change */
00260   SetWindowClassesDirty(WC_TOWN_VIEW);
00261 }
00262 
00267 void IncreaseDate()
00268 {
00269   /* increase day, and check if a new day is there? */
00270   _tick_counter++;
00271 
00272   if (_game_mode == GM_MENU) return;
00273 
00274   _date_fract++;
00275   if (_date_fract < DAY_TICKS) return;
00276   _date_fract = 0;
00277 
00278   /* increase day counter and call various daily loops */
00279   _date++;
00280   OnNewDay();
00281 
00282   YearMonthDay ymd;
00283 
00284   /* check if we entered a new month? */
00285   ConvertDateToYMD(_date, &ymd);
00286   if (ymd.month == _cur_month) return;
00287 
00288   /* yes, call various monthly loops */
00289   _cur_month = ymd.month;
00290   OnNewMonth();
00291 
00292   /* check if we entered a new year? */
00293   if (ymd.year == _cur_year) return;
00294 
00295   /* yes, call various yearly loops */
00296   _cur_year = ymd.year;
00297   OnNewYear();
00298 }

Generated on Tue Jan 5 21:02:53 2010 for OpenTTD by  doxygen 1.5.6