00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013
00014 #include "blitter/factory.hpp"
00015 #include "sound/sound_driver.hpp"
00016 #include "music/music_driver.hpp"
00017 #include "video/video_driver.hpp"
00018
00019 #include "fontcache.h"
00020 #include "error.h"
00021 #include "gui.h"
00022
00023 #include "base_media_base.h"
00024 #include "saveload/saveload.h"
00025 #include "company_func.h"
00026 #include "command_func.h"
00027 #include "news_func.h"
00028 #include "fios.h"
00029 #include "aircraft.h"
00030 #include "roadveh.h"
00031 #include "train.h"
00032 #include "ship.h"
00033 #include "console_func.h"
00034 #include "screenshot.h"
00035 #include "network/network.h"
00036 #include "network/network_func.h"
00037 #include "ai/ai.hpp"
00038 #include "ai/ai_config.hpp"
00039 #include "settings_func.h"
00040 #include "genworld.h"
00041 #include "progress.h"
00042 #include "strings_func.h"
00043 #include "date_func.h"
00044 #include "vehicle_func.h"
00045 #include "gamelog.h"
00046 #include "animated_tile_func.h"
00047 #include "roadstop_base.h"
00048 #include "elrail_func.h"
00049 #include "rev.h"
00050 #include "highscore.h"
00051 #include "station_base.h"
00052 #include "crashlog.h"
00053 #include "engine_func.h"
00054 #include "core/random_func.hpp"
00055 #include "rail_gui.h"
00056 #include "core/backup_type.hpp"
00057 #include "hotkeys.h"
00058 #include "newgrf.h"
00059 #include "misc/getoptdata.h"
00060 #include "game/game.hpp"
00061 #include "game/game_config.hpp"
00062 #include "town.h"
00063
00064
00065
00066 #include <stdarg.h>
00067
00068
00069 void CallLandscapeTick();
00070 void IncreaseDate();
00071 void DoPaletteAnimations();
00072 void MusicLoop();
00073 void ResetMusic();
00074 void CallWindowTickEvent();
00075 bool HandleBootstrap();
00076
00077 extern void SetDifficultyLevel(int mode, DifficultySettings *gm_opt);
00078 extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
00079 extern void ShowOSErrorBox(const char *buf, bool system);
00080 extern char *_config_file;
00081
00087 void CDECL usererror(const char *s, ...)
00088 {
00089 va_list va;
00090 char buf[512];
00091
00092 va_start(va, s);
00093 vsnprintf(buf, lengthof(buf), s, va);
00094 va_end(va);
00095
00096 ShowOSErrorBox(buf, false);
00097 if (_video_driver != NULL) _video_driver->Stop();
00098
00099 exit(1);
00100 }
00101
00107 void CDECL error(const char *s, ...)
00108 {
00109 va_list va;
00110 char buf[512];
00111
00112 va_start(va, s);
00113 vsnprintf(buf, lengthof(buf), s, va);
00114 va_end(va);
00115
00116 ShowOSErrorBox(buf, true);
00117
00118
00119 CrashLog::SetErrorMessage(buf);
00120 abort();
00121 }
00122
00127 void CDECL ShowInfoF(const char *str, ...)
00128 {
00129 va_list va;
00130 char buf[1024];
00131 va_start(va, str);
00132 vsnprintf(buf, lengthof(buf), str, va);
00133 va_end(va);
00134 ShowInfo(buf);
00135 }
00136
00140 static void ShowHelp()
00141 {
00142 char buf[8192];
00143 char *p = buf;
00144
00145 p += seprintf(p, lastof(buf), "OpenTTD %s\n", _openttd_revision);
00146 p = strecpy(p,
00147 "\n"
00148 "\n"
00149 "Command line options:\n"
00150 " -v drv = Set video driver (see below)\n"
00151 " -s drv = Set sound driver (see below) (param bufsize,hz)\n"
00152 " -m drv = Set music driver (see below)\n"
00153 " -b drv = Set the blitter to use (see below)\n"
00154 " -r res = Set resolution (for instance 800x600)\n"
00155 " -h = Display this help text\n"
00156 " -t year = Set starting year\n"
00157 " -d [[fac=]lvl[,...]]= Debug mode\n"
00158 " -e = Start Editor\n"
00159 " -g [savegame] = Start new/save game immediately\n"
00160 " -G seed = Set random seed\n"
00161 #if defined(ENABLE_NETWORK)
00162 " -n [ip:port#company]= Start networkgame\n"
00163 " -p password = Password to join server\n"
00164 " -P password = Password to join company\n"
00165 " -D [ip][:port] = Start dedicated server\n"
00166 " -l ip[:port] = Redirect DEBUG()\n"
00167 #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
00168 " -f = Fork into the background (dedicated only)\n"
00169 #endif
00170 #endif
00171 " -I graphics_set = Force the graphics set (see below)\n"
00172 " -S sounds_set = Force the sounds set (see below)\n"
00173 " -M music_set = Force the music set (see below)\n"
00174 " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n"
00175 " -x = Do not automatically save to config file on exit\n"
00176 " -q savegame = Write some information about the savegame and exit\n"
00177 "\n",
00178 lastof(buf)
00179 );
00180
00181
00182 p = BaseGraphics::GetSetsList(p, lastof(buf));
00183
00184
00185 p = BaseSounds::GetSetsList(p, lastof(buf));
00186
00187
00188 p = BaseMusic::GetSetsList(p, lastof(buf));
00189
00190
00191 p = VideoDriverFactoryBase::GetDriversInfo(p, lastof(buf));
00192
00193
00194 p = BlitterFactoryBase::GetBlittersInfo(p, lastof(buf));
00195
00196
00197 AI::Initialize();
00198 p = AI::GetConsoleList(p, lastof(buf), true);
00199 AI::Uninitialize(true);
00200
00201
00202 Game::Initialize();
00203 p = Game::GetConsoleList(p, lastof(buf), true);
00204 Game::Uninitialize(true);
00205
00206
00207
00208 #if !defined(WIN32) && !defined(WIN64)
00209 printf("%s\n", buf);
00210 #else
00211 ShowInfo(buf);
00212 #endif
00213 }
00214
00215 static void WriteSavegameInfo(const char *name)
00216 {
00217 extern uint16 _sl_version;
00218 uint32 last_ottd_rev = 0;
00219 byte ever_modified = 0;
00220 bool removed_newgrfs = false;
00221
00222 GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs);
00223
00224 char buf[8192];
00225 char *p = buf;
00226 p += seprintf(p, lastof(buf), "Name: %s\n", name);
00227 p += seprintf(p, lastof(buf), "Savegame ver: %d\n", _sl_version);
00228 p += seprintf(p, lastof(buf), "NewGRF ver: 0x%08X\n", last_ottd_rev);
00229 p += seprintf(p, lastof(buf), "Modified: %d\n", ever_modified);
00230
00231 if (removed_newgrfs) {
00232 p += seprintf(p, lastof(buf), "NewGRFs have been removed\n");
00233 }
00234
00235 p = strecpy(p, "NewGRFs:\n", lastof(buf));
00236 if (_load_check_data.HasNewGrfs()) {
00237 for (GRFConfig *c = _load_check_data.grfconfig; c != NULL; c = c->next) {
00238 char md5sum[33];
00239 md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum);
00240 p += seprintf(p, lastof(buf), "%08X %s %s\n", c->ident.grfid, md5sum, c->filename);
00241 }
00242 }
00243
00244
00245
00246 #if !defined(WIN32) && !defined(WIN64)
00247 printf("%s\n", buf);
00248 #else
00249 ShowInfo(buf);
00250 #endif
00251 }
00252
00253
00260 static void ParseResolution(Dimension *res, const char *s)
00261 {
00262 const char *t = strchr(s, 'x');
00263 if (t == NULL) {
00264 ShowInfoF("Invalid resolution '%s'", s);
00265 return;
00266 }
00267
00268 res->width = max(strtoul(s, NULL, 0), 64UL);
00269 res->height = max(strtoul(t + 1, NULL, 0), 64UL);
00270 }
00271
00272
00277 static void ShutdownGame()
00278 {
00279 IConsoleFree();
00280
00281 if (_network_available) NetworkShutDown();
00282
00283 DriverFactoryBase::ShutdownDrivers();
00284
00285 UnInitWindowSystem();
00286
00287
00288 AI::Uninitialize(false);
00289 Game::Uninitialize(false);
00290
00291
00292 GamelogReset();
00293
00294 #ifdef ENABLE_NETWORK
00295 free(_config_file);
00296 #endif
00297
00298 PoolBase::Clean(PT_ALL);
00299
00300
00301 if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
00302
00303
00304 FioCloseAll();
00305
00306 UninitFreeType();
00307 }
00308
00313 static void LoadIntroGame(bool load_newgrfs = true)
00314 {
00315 _game_mode = GM_MENU;
00316
00317 if (load_newgrfs) ResetGRFConfig(false);
00318
00319
00320 ResetWindowSystem();
00321 SetupColoursAndInitialWindow();
00322
00323
00324 if (SaveOrLoad("opntitle.dat", SL_LOAD, BASESET_DIR) != SL_OK) {
00325 GenerateWorld(GWM_EMPTY, 64, 64);
00326 WaitTillGeneratedWorld();
00327 SetLocalCompany(COMPANY_SPECTATOR);
00328 } else {
00329 SetLocalCompany(COMPANY_FIRST);
00330 }
00331
00332 _pause_mode = PM_UNPAUSED;
00333 _cursor.fix_at = false;
00334
00335 if (load_newgrfs) CheckForMissingSprites();
00336 CheckForMissingGlyphs();
00337
00338
00339 if (_music_driver->IsSongPlaying()) ResetMusic();
00340 }
00341
00342 void MakeNewgameSettingsLive()
00343 {
00344 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00345 if (_settings_game.ai_config[c] != NULL) {
00346 delete _settings_game.ai_config[c];
00347 }
00348 }
00349 if (_settings_game.game_config != NULL) {
00350 delete _settings_game.game_config;
00351 }
00352
00353
00354
00355 _settings_game = _settings_newgame;
00356 _old_vds = _settings_client.company.vehicle;
00357
00358 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00359 _settings_game.ai_config[c] = NULL;
00360 if (_settings_newgame.ai_config[c] != NULL) {
00361 _settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]);
00362 }
00363 }
00364 _settings_game.game_config = NULL;
00365 if (_settings_newgame.game_config != NULL) {
00366 _settings_game.game_config = new GameConfig(_settings_newgame.game_config);
00367 }
00368 }
00369
00370 void OpenBrowser(const char *url)
00371 {
00372
00373 if (strstr(url, "http://") != url && strstr(url, "https://") != url) return;
00374
00375 extern void OSOpenBrowser(const char *url);
00376 OSOpenBrowser(url);
00377 }
00378
00380 struct AfterNewGRFScan : NewGRFScanCallback {
00381 Year startyear;
00382 uint generation_seed;
00383 char *dedicated_host;
00384 uint16 dedicated_port;
00385 char *network_conn;
00386 const char *join_server_password;
00387 const char *join_company_password;
00388 bool *save_config_ptr;
00389 bool save_config;
00390
00396 AfterNewGRFScan(bool *save_config_ptr) :
00397 startyear(INVALID_YEAR), generation_seed(GENERATE_NEW_SEED),
00398 dedicated_host(NULL), dedicated_port(0), network_conn(NULL),
00399 join_server_password(NULL), join_company_password(NULL),
00400 save_config_ptr(save_config_ptr), save_config(true)
00401 {
00402 }
00403
00404 virtual void OnNewGRFsScanned()
00405 {
00406 ResetGRFConfig(false);
00407
00408 TarScanner::DoScan(TarScanner::SCENARIO);
00409
00410 AI::Initialize();
00411 Game::Initialize();
00412
00413
00414 uint last_newgrf_count = _settings_client.gui.last_newgrf_count;
00415 LoadFromConfig();
00416 _settings_client.gui.last_newgrf_count = last_newgrf_count;
00417
00418
00419 UpdateNewGRFConfigPalette();
00420
00421 Game::Uninitialize(true);
00422 AI::Uninitialize(true);
00423 CheckConfig();
00424 LoadFromHighScore();
00425 LoadHotkeysFromConfig();
00426
00427
00428 *save_config_ptr = save_config;
00429
00430
00431 _music_driver->SetVolume(_settings_client.music.music_vol);
00432
00433 if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear;
00434 if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed;
00435
00436 #if defined(ENABLE_NETWORK)
00437 if (dedicated_host != NULL) {
00438 _network_bind_list.Clear();
00439 *_network_bind_list.Append() = strdup(dedicated_host);
00440 }
00441 if (dedicated_port != 0) _settings_client.network.server_port = dedicated_port;
00442 #endif
00443
00444
00445 IConsoleInit();
00446 InitializeGUI();
00447 IConsoleCmdExec("exec scripts/autoexec.scr 0");
00448
00449
00450 if (_switch_mode != SM_NONE) MakeNewgameSettingsLive();
00451
00452 #ifdef ENABLE_NETWORK
00453 if (_network_available && network_conn != NULL) {
00454 const char *port = NULL;
00455 const char *company = NULL;
00456 uint16 rport = NETWORK_DEFAULT_PORT;
00457 CompanyID join_as = COMPANY_NEW_COMPANY;
00458
00459 ParseConnectionString(&company, &port, network_conn);
00460
00461 if (company != NULL) {
00462 join_as = (CompanyID)atoi(company);
00463
00464 if (join_as != COMPANY_SPECTATOR) {
00465 join_as--;
00466 if (join_as >= MAX_COMPANIES) {
00467 delete this;
00468 return;
00469 }
00470 }
00471 }
00472 if (port != NULL) rport = atoi(port);
00473
00474 LoadIntroGame();
00475 _switch_mode = SM_NONE;
00476 NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password);
00477 }
00478 #endif
00479
00480
00481 delete this;
00482 }
00483 };
00484
00485 #if defined(UNIX) && !defined(__MORPHOS__)
00486 extern void DedicatedFork();
00487 #endif
00488
00490 static const OptionData _options[] = {
00491 GETOPT_SHORT_VALUE('I'),
00492 GETOPT_SHORT_VALUE('S'),
00493 GETOPT_SHORT_VALUE('M'),
00494 GETOPT_SHORT_VALUE('m'),
00495 GETOPT_SHORT_VALUE('s'),
00496 GETOPT_SHORT_VALUE('v'),
00497 GETOPT_SHORT_VALUE('b'),
00498 #if defined(ENABLE_NETWORK)
00499 GETOPT_SHORT_OPTVAL('D'),
00500 GETOPT_SHORT_OPTVAL('n'),
00501 GETOPT_SHORT_VALUE('l'),
00502 GETOPT_SHORT_VALUE('p'),
00503 GETOPT_SHORT_VALUE('P'),
00504 #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32)
00505 GETOPT_SHORT_NOVAL('f'),
00506 #endif
00507 #endif
00508 GETOPT_SHORT_VALUE('r'),
00509 GETOPT_SHORT_VALUE('t'),
00510 GETOPT_SHORT_OPTVAL('d'),
00511 GETOPT_SHORT_NOVAL('e'),
00512 GETOPT_SHORT_OPTVAL('g'),
00513 GETOPT_SHORT_VALUE('G'),
00514 GETOPT_SHORT_VALUE('c'),
00515 GETOPT_SHORT_NOVAL('x'),
00516 GETOPT_SHORT_VALUE('q'),
00517 GETOPT_SHORT_NOVAL('h'),
00518 GETOPT_END()
00519 };
00520
00521
00522 int ttd_main(int argc, char *argv[])
00523 {
00524 char *musicdriver = NULL;
00525 char *sounddriver = NULL;
00526 char *videodriver = NULL;
00527 char *blitter = NULL;
00528 char *graphics_set = NULL;
00529 char *sounds_set = NULL;
00530 char *music_set = NULL;
00531 Dimension resolution = {0, 0};
00532
00533 bool save_config = false;
00534 AfterNewGRFScan *scanner = new AfterNewGRFScan(&save_config);
00535 #if defined(ENABLE_NETWORK)
00536 bool dedicated = false;
00537 char *debuglog_conn = NULL;
00538
00539 extern bool _dedicated_forks;
00540 _dedicated_forks = false;
00541 #endif
00542
00543 _game_mode = GM_MENU;
00544 _switch_mode = SM_MENU;
00545 _config_file = NULL;
00546
00547 GetOptData mgo(argc - 1, argv + 1, _options);
00548
00549 int i;
00550 while ((i = mgo.GetOpt()) != -1) {
00551 switch (i) {
00552 case 'I': free(graphics_set); graphics_set = strdup(mgo.opt); break;
00553 case 'S': free(sounds_set); sounds_set = strdup(mgo.opt); break;
00554 case 'M': free(music_set); music_set = strdup(mgo.opt); break;
00555 case 'm': free(musicdriver); musicdriver = strdup(mgo.opt); break;
00556 case 's': free(sounddriver); sounddriver = strdup(mgo.opt); break;
00557 case 'v': free(videodriver); videodriver = strdup(mgo.opt); break;
00558 case 'b': free(blitter); blitter = strdup(mgo.opt); break;
00559 #if defined(ENABLE_NETWORK)
00560 case 'D':
00561 free(musicdriver);
00562 free(sounddriver);
00563 free(videodriver);
00564 free(blitter);
00565 musicdriver = strdup("null");
00566 sounddriver = strdup("null");
00567 videodriver = strdup("dedicated");
00568 blitter = strdup("null");
00569 dedicated = true;
00570 SetDebugString("net=6");
00571 if (mgo.opt != NULL) {
00572
00573
00574 const char *temp = NULL;
00575 const char *port = NULL;
00576 ParseConnectionString(&temp, &port, mgo.opt);
00577 if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt;
00578 if (port != NULL) scanner->dedicated_port = atoi(port);
00579 }
00580 break;
00581 case 'f': _dedicated_forks = true; break;
00582 case 'n':
00583 scanner->network_conn = mgo.opt;
00584 break;
00585 case 'l':
00586 debuglog_conn = mgo.opt;
00587 break;
00588 case 'p':
00589 scanner->join_server_password = mgo.opt;
00590 break;
00591 case 'P':
00592 scanner->join_company_password = mgo.opt;
00593 break;
00594 #endif
00595 case 'r': ParseResolution(&resolution, mgo.opt); break;
00596 case 't': scanner->startyear = atoi(mgo.opt); break;
00597 case 'd': {
00598 #if defined(WIN32)
00599 CreateConsole();
00600 #endif
00601 if (mgo.opt != NULL) SetDebugString(mgo.opt);
00602 break;
00603 }
00604 case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break;
00605 case 'g':
00606 if (mgo.opt != NULL) {
00607 strecpy(_file_to_saveload.name, mgo.opt, lastof(_file_to_saveload.name));
00608 _switch_mode = (_switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_LOAD_GAME);
00609 _file_to_saveload.mode = SL_LOAD;
00610
00611
00612 const char *t = strrchr(_file_to_saveload.name, '.');
00613 if (t != NULL) {
00614 FiosType ft = FiosGetSavegameListCallback(SLD_LOAD_GAME, _file_to_saveload.name, t, NULL, NULL);
00615 if (ft != FIOS_TYPE_INVALID) SetFiosType(ft);
00616 }
00617
00618 break;
00619 }
00620
00621 _switch_mode = SM_NEWGAME;
00622
00623 if (scanner->generation_seed == GENERATE_NEW_SEED) {
00624 scanner->generation_seed = InteractiveRandom();
00625 }
00626 break;
00627 case 'q': {
00628 DeterminePaths(argv[0]);
00629 if (StrEmpty(mgo.opt)) return 1;
00630 char title[80];
00631 title[0] = '\0';
00632 FiosGetSavegameListCallback(SLD_LOAD_GAME, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title));
00633
00634 _load_check_data.Clear();
00635 SaveOrLoadResult res = SaveOrLoad(mgo.opt, SL_LOAD_CHECK, SAVE_DIR, false);
00636 if (res != SL_OK || _load_check_data.HasErrors()) {
00637 fprintf(stderr, "Failed to open savegame\n");
00638 if (_load_check_data.HasErrors()) {
00639 char buf[256];
00640 SetDParamStr(0, _load_check_data.error_data);
00641 GetString(buf, _load_check_data.error, lastof(buf));
00642 fprintf(stderr, "%s\n", buf);
00643 }
00644 return 1;
00645 }
00646
00647 WriteSavegameInfo(title);
00648
00649 return 0;
00650 }
00651 case 'G': scanner->generation_seed = atoi(mgo.opt); break;
00652 case 'c': _config_file = strdup(mgo.opt); break;
00653 case 'x': scanner->save_config = false; break;
00654 case 'h':
00655 i = -2;
00656 break;
00657 }
00658 if (i == -2) break;
00659 }
00660
00661 if (i == -2 || mgo.numleft > 0) {
00662
00663
00664
00665
00666
00667 DeterminePaths(argv[0]);
00668 TarScanner::DoScan(TarScanner::BASESET);
00669 BaseGraphics::FindSets();
00670 BaseSounds::FindSets();
00671 BaseMusic::FindSets();
00672 ShowHelp();
00673 delete scanner;
00674 return 0;
00675 }
00676
00677 #if defined(WINCE) && defined(_DEBUG)
00678
00679 SetDebugString("4");
00680 #endif
00681
00682 DeterminePaths(argv[0]);
00683 TarScanner::DoScan(TarScanner::BASESET);
00684
00685 #if defined(ENABLE_NETWORK)
00686 if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision);
00687 if (_dedicated_forks && !dedicated) _dedicated_forks = false;
00688
00689 #if defined(UNIX) && !defined(__MORPHOS__)
00690
00691 if (_dedicated_forks) DedicatedFork();
00692 #endif
00693 #endif
00694
00695 LoadFromConfig(true);
00696
00697 if (resolution.width != 0) _cur_resolution = resolution;
00698
00699
00700
00701
00702
00703
00704
00705 _cur_resolution.width = ClampU(_cur_resolution.width, 1, UINT16_MAX / 2);
00706 _cur_resolution.height = ClampU(_cur_resolution.height, 1, UINT16_MAX / 2);
00707
00708
00709
00710
00711
00712 _cursor.in_window = true;
00713
00714
00715 InitializeLanguagePacks();
00716
00717
00718 InitFreeType(false);
00719
00720
00721 InitWindowSystem();
00722
00723 BaseGraphics::FindSets();
00724 if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = strdup(BaseGraphics::ini_set);
00725 if (!BaseGraphics::SetSet(graphics_set)) {
00726 if (!StrEmpty(graphics_set)) {
00727 BaseGraphics::SetSet(NULL);
00728
00729 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND);
00730 msg.SetDParamStr(0, graphics_set);
00731 ScheduleErrorMessage(msg);
00732 }
00733 }
00734 free(graphics_set);
00735
00736
00737 GfxInitPalettes();
00738
00739 DEBUG(misc, 1, "Loading blitter...");
00740 if (blitter == NULL && _ini_blitter != NULL) blitter = strdup(_ini_blitter);
00741 _blitter_autodetected = StrEmpty(blitter);
00742
00743 if (!_blitter_autodetected || BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP || BlitterFactoryBase::SelectBlitter("32bpp-anim") == NULL) {
00744 if (BlitterFactoryBase::SelectBlitter(blitter) == NULL) {
00745 StrEmpty(blitter) ?
00746 usererror("Failed to autoprobe blitter") :
00747 usererror("Failed to select requested blitter '%s'; does it exist?", blitter);
00748 }
00749 }
00750 free(blitter);
00751
00752 if (videodriver == NULL && _ini_videodriver != NULL) videodriver = strdup(_ini_videodriver);
00753 _video_driver = (VideoDriver*)VideoDriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO);
00754 if (_video_driver == NULL) {
00755 StrEmpty(videodriver) ?
00756 usererror("Failed to autoprobe video driver") :
00757 usererror("Failed to select requested video driver '%s'", videodriver);
00758 }
00759 free(videodriver);
00760
00761
00762 _screen.zoom = ZOOM_LVL_NORMAL;
00763
00764 NetworkStartUp();
00765
00766 #if defined(ENABLE_NETWORK)
00767 if (debuglog_conn != NULL && _network_available) {
00768 const char *not_used = NULL;
00769 const char *port = NULL;
00770 uint16 rport;
00771
00772 rport = NETWORK_DEFAULT_DEBUGLOG_PORT;
00773
00774 ParseConnectionString(¬_used, &port, debuglog_conn);
00775 if (port != NULL) rport = atoi(port);
00776
00777 NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport));
00778 }
00779 #endif
00780
00781 if (!HandleBootstrap()) goto exit;
00782
00783 _video_driver->ClaimMousePointer();
00784
00785
00786 InitializeScreenshotFormats();
00787
00788 BaseSounds::FindSets();
00789 if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = strdup(BaseSounds::ini_set);
00790 if (!BaseSounds::SetSet(sounds_set)) {
00791 if (StrEmpty(sounds_set) || !BaseSounds::SetSet(NULL)) {
00792 usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of readme.txt.");
00793 } else {
00794 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND);
00795 msg.SetDParamStr(0, sounds_set);
00796 ScheduleErrorMessage(msg);
00797 }
00798 }
00799 free(sounds_set);
00800
00801 BaseMusic::FindSets();
00802 if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = strdup(BaseMusic::ini_set);
00803 if (!BaseMusic::SetSet(music_set)) {
00804 if (StrEmpty(music_set) || !BaseMusic::SetSet(NULL)) {
00805 usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of readme.txt.");
00806 } else {
00807 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND);
00808 msg.SetDParamStr(0, music_set);
00809 ScheduleErrorMessage(msg);
00810 }
00811 }
00812 free(music_set);
00813
00814 if (sounddriver == NULL && _ini_sounddriver != NULL) sounddriver = strdup(_ini_sounddriver);
00815 _sound_driver = (SoundDriver*)SoundDriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND);
00816 if (_sound_driver == NULL) {
00817 StrEmpty(sounddriver) ?
00818 usererror("Failed to autoprobe sound driver") :
00819 usererror("Failed to select requested sound driver '%s'", sounddriver);
00820 }
00821 free(sounddriver);
00822
00823 if (musicdriver == NULL && _ini_musicdriver != NULL) musicdriver = strdup(_ini_musicdriver);
00824 _music_driver = (MusicDriver*)MusicDriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC);
00825 if (_music_driver == NULL) {
00826 StrEmpty(musicdriver) ?
00827 usererror("Failed to autoprobe music driver") :
00828 usererror("Failed to select requested music driver '%s'", musicdriver);
00829 }
00830 free(musicdriver);
00831
00832
00833 _modal_progress_paint_mutex->BeginCritical();
00834 _modal_progress_work_mutex->BeginCritical();
00835
00836 GenerateWorld(GWM_EMPTY, 64, 64);
00837 WaitTillGeneratedWorld();
00838
00839 LoadIntroGame(false);
00840
00841 CheckForMissingGlyphs();
00842
00843 ScanNewGRFFiles(scanner);
00844
00845 _video_driver->MainLoop();
00846
00847 WaitTillSaved();
00848
00849
00850 if (save_config) {
00851 SaveToConfig();
00852 SaveHotkeysToConfig();
00853 SaveToHighScore();
00854 }
00855
00856 exit:
00857
00858 ShutdownGame();
00859
00860 free(BaseGraphics::ini_set);
00861 free(BaseSounds::ini_set);
00862 free(BaseMusic::ini_set);
00863 free(_ini_musicdriver);
00864 free(_ini_sounddriver);
00865 free(_ini_videodriver);
00866 free(_ini_blitter);
00867
00868 return 0;
00869 }
00870
00871 void HandleExitGameRequest()
00872 {
00873 if (_game_mode == GM_MENU || _game_mode == GM_BOOTSTRAP) {
00874 _exit_game = true;
00875 } else if (_settings_client.gui.autosave_on_exit) {
00876 DoExitSave();
00877 _exit_game = true;
00878 } else {
00879 AskExitGame();
00880 }
00881 }
00882
00883 static void MakeNewGameDone()
00884 {
00885 SettingsDisableElrail(_settings_game.vehicle.disable_elrails);
00886
00887
00888 if (!_video_driver->HasGUI()) {
00889 SetLocalCompany(COMPANY_SPECTATOR);
00890 IConsoleCmdExec("exec scripts/game_start.scr 0");
00891 return;
00892 }
00893
00894
00895 DoStartupNewCompany(false);
00896
00897 Company *c = Company::Get(COMPANY_FIRST);
00898 c->settings = _settings_client.company;
00899
00900 IConsoleCmdExec("exec scripts/game_start.scr 0");
00901
00902 SetLocalCompany(COMPANY_FIRST);
00903
00904 InitializeRailGUI();
00905
00906 #ifdef ENABLE_NETWORK
00907
00908
00909 if (_network_server && !StrEmpty(_settings_client.network.default_company_pass)) {
00910 NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass);
00911 }
00912 #endif
00913
00914 if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
00915
00916 MarkWholeScreenDirty();
00917 }
00918
00919 static void MakeNewGame(bool from_heightmap, bool reset_settings)
00920 {
00921 _game_mode = GM_NORMAL;
00922
00923 ResetGRFConfig(true);
00924
00925 GenerateWorldSetCallback(&MakeNewGameDone);
00926 GenerateWorld(from_heightmap ? GWM_HEIGHTMAP : GWM_NEWGAME, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y, reset_settings);
00927 }
00928
00929 static void MakeNewEditorWorldDone()
00930 {
00931 SetLocalCompany(OWNER_NONE);
00932 }
00933
00934 static void MakeNewEditorWorld()
00935 {
00936 _game_mode = GM_EDITOR;
00937
00938 ResetGRFConfig(true);
00939
00940 GenerateWorldSetCallback(&MakeNewEditorWorldDone);
00941 GenerateWorld(GWM_EMPTY, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y);
00942 }
00943
00954 bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL)
00955 {
00956 assert(mode == SL_LOAD || (lf == NULL && mode == SL_OLD_LOAD));
00957 GameMode ogm = _game_mode;
00958
00959 _game_mode = newgm;
00960
00961 switch (lf == NULL ? SaveOrLoad(filename, mode, subdir) : LoadWithFilter(lf)) {
00962 case SL_OK: return true;
00963
00964 case SL_REINIT:
00965 #ifdef ENABLE_NETWORK
00966 if (_network_dedicated) {
00967
00968
00969
00970
00971
00972
00973 DEBUG(net, 0, "Loading game failed, so a new (random) game will be started!");
00974 MakeNewGame(false, true);
00975 return false;
00976 }
00977 if (_network_server) {
00978
00979 NetworkDisconnect();
00980 }
00981 #endif
00982
00983 switch (ogm) {
00984 default:
00985 case GM_MENU: LoadIntroGame(); break;
00986 case GM_EDITOR: MakeNewEditorWorld(); break;
00987 }
00988 return false;
00989
00990 default:
00991 _game_mode = ogm;
00992 return false;
00993 }
00994 }
00995
00996 void SwitchToMode(SwitchMode new_mode)
00997 {
00998 #ifdef ENABLE_NETWORK
00999
01000 if (new_mode != SM_SAVE_GAME) {
01001
01002 if (_networking) {
01003 if (_network_server && (new_mode == SM_LOAD_GAME || new_mode == SM_NEWGAME || new_mode == SM_RESTARTGAME)) {
01004 NetworkReboot();
01005 } else {
01006 NetworkDisconnect();
01007 }
01008 }
01009
01010
01011 if (_is_network_server) {
01012
01013 if (new_mode != SM_MENU) {
01014
01015 if (_settings_client.network.reload_cfg) {
01016 LoadFromConfig();
01017 MakeNewgameSettingsLive();
01018 ResetGRFConfig(false);
01019 }
01020 NetworkServerStart();
01021 } else {
01022
01023 _is_network_server = false;
01024 }
01025 }
01026 }
01027 #endif
01028
01029 if (new_mode != SM_SAVE_GAME) AI::KillAll();
01030
01031 switch (new_mode) {
01032 case SM_EDITOR:
01033 MakeNewEditorWorld();
01034 break;
01035
01036 case SM_RESTARTGAME:
01037 case SM_NEWGAME:
01038 #ifdef ENABLE_NETWORK
01039 if (_network_server) {
01040 snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map");
01041 }
01042 #endif
01043 MakeNewGame(false, new_mode == SM_NEWGAME);
01044 break;
01045
01046 case SM_LOAD_GAME: {
01047 ResetGRFConfig(true);
01048 ResetWindowSystem();
01049
01050 if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) {
01051 SetDParamStr(0, GetSaveLoadErrorString());
01052 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
01053 } else {
01054 if (_saveload_mode == SLD_LOAD_SCENARIO) {
01055 StartupEngines();
01056 }
01057
01058
01059 SetLocalCompany(_network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST);
01060
01061 IConsoleCmdExec("exec scripts/game_start.scr 0");
01062
01063 DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
01064 #ifdef ENABLE_NETWORK
01065 if (_network_server) {
01066 snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title);
01067 }
01068 #endif
01069 }
01070 break;
01071 }
01072
01073 case SM_START_HEIGHTMAP:
01074 #ifdef ENABLE_NETWORK
01075 if (_network_server) {
01076 snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title);
01077 }
01078 #endif
01079 MakeNewGame(true, true);
01080 break;
01081
01082 case SM_LOAD_HEIGHTMAP:
01083 SetLocalCompany(OWNER_NONE);
01084
01085 GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y);
01086 MarkWholeScreenDirty();
01087 break;
01088
01089 case SM_LOAD_SCENARIO: {
01090 if (SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR, NO_DIRECTORY)) {
01091 SetLocalCompany(OWNER_NONE);
01092 _settings_newgame.game_creation.starting_year = _cur_year;
01093
01094 DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
01095 } else {
01096 SetDParamStr(0, GetSaveLoadErrorString());
01097 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
01098 }
01099 break;
01100 }
01101
01102 case SM_MENU:
01103 LoadIntroGame();
01104 if (BaseSounds::ini_set == NULL && BaseSounds::GetUsedSet()->fallback) {
01105 ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL);
01106 BaseSounds::ini_set = strdup(BaseSounds::GetUsedSet()->name);
01107 }
01108 break;
01109
01110 case SM_SAVE_GAME:
01111
01112 if (SaveOrLoad(_file_to_saveload.name, SL_SAVE, NO_DIRECTORY) != SL_OK) {
01113 SetDParamStr(0, GetSaveLoadErrorString());
01114 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
01115 } else {
01116 DeleteWindowById(WC_SAVELOAD, 0);
01117 }
01118 break;
01119
01120 case SM_SAVE_HEIGHTMAP:
01121 MakeHeightmapScreenshot(_file_to_saveload.name);
01122 DeleteWindowById(WC_SAVELOAD, 0);
01123 break;
01124
01125 case SM_GENRANDLAND:
01126 SetLocalCompany(OWNER_NONE);
01127 GenerateWorld(GWM_RANDOM, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y);
01128
01129 MarkWholeScreenDirty();
01130 break;
01131
01132 default: NOT_REACHED();
01133 }
01134 }
01135
01136
01143 static void CheckCaches()
01144 {
01145
01146
01147 if (_debug_desync_level <= 1) return;
01148
01149
01150 SmallVector<TownCache, 4> old_town_caches;
01151 Town *t;
01152 FOR_ALL_TOWNS(t) {
01153 MemCpyT(old_town_caches.Append(), &t->cache);
01154 }
01155
01156 extern void RebuildTownCaches();
01157 RebuildTownCaches();
01158
01159 uint i = 0;
01160 FOR_ALL_TOWNS(t) {
01161 if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) {
01162 DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index);
01163 }
01164 i++;
01165 }
01166
01167
01168 SmallVector<CompanyInfrastructure, 4> old_infrastructure;
01169 Company *c;
01170 FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure);
01171
01172 extern void AfterLoadCompanyStats();
01173 AfterLoadCompanyStats();
01174
01175 i = 0;
01176 FOR_ALL_COMPANIES(c) {
01177 if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) {
01178 DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index);
01179 }
01180 i++;
01181 }
01182
01183
01184 const RoadStop *rs;
01185 FOR_ALL_ROADSTOPS(rs) {
01186 if (IsStandardRoadStopTile(rs->xy)) continue;
01187
01188 assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
01189 rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
01190 rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
01191 }
01192
01193 Vehicle *v;
01194 FOR_ALL_VEHICLES(v) {
01195 extern void FillNewGRFVehicleCache(const Vehicle *v);
01196 if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue;
01197
01198 uint length = 0;
01199 for (const Vehicle *u = v; u != NULL; u = u->Next()) length++;
01200
01201 NewGRFCache *grf_cache = CallocT<NewGRFCache>(length);
01202 VehicleCache *veh_cache = CallocT<VehicleCache>(length);
01203 GroundVehicleCache *gro_cache = CallocT<GroundVehicleCache>(length);
01204 TrainCache *tra_cache = CallocT<TrainCache>(length);
01205
01206 length = 0;
01207 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01208 FillNewGRFVehicleCache(u);
01209 grf_cache[length] = u->grf_cache;
01210 veh_cache[length] = u->vcache;
01211 switch (u->type) {
01212 case VEH_TRAIN:
01213 gro_cache[length] = Train::From(u)->gcache;
01214 tra_cache[length] = Train::From(u)->tcache;
01215 break;
01216 case VEH_ROAD:
01217 gro_cache[length] = RoadVehicle::From(u)->gcache;
01218 break;
01219 default:
01220 break;
01221 }
01222 length++;
01223 }
01224
01225 switch (v->type) {
01226 case VEH_TRAIN: Train::From(v)->ConsistChanged(true); break;
01227 case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break;
01228 case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break;
01229 case VEH_SHIP: Ship::From(v)->UpdateCache(); break;
01230 default: break;
01231 }
01232
01233 length = 0;
01234 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01235 FillNewGRFVehicleCache(u);
01236 if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) {
01237 DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length);
01238 }
01239 if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) {
01240 DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length);
01241 }
01242 switch (u->type) {
01243 case VEH_TRAIN:
01244 if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) {
01245 DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length);
01246 }
01247 if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) {
01248 DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length);
01249 }
01250 break;
01251 case VEH_ROAD:
01252 if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) {
01253 DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length);
01254 }
01255 break;
01256 default:
01257 break;
01258 }
01259 length++;
01260 }
01261
01262 free(grf_cache);
01263 free(veh_cache);
01264 free(gro_cache);
01265 free(tra_cache);
01266 }
01267
01268
01269 FOR_ALL_VEHICLES(v) {
01270 byte buff[sizeof(VehicleCargoList)];
01271 memcpy(buff, &v->cargo, sizeof(VehicleCargoList));
01272 v->cargo.InvalidateCache();
01273 assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0);
01274 }
01275
01276 Station *st;
01277 FOR_ALL_STATIONS(st) {
01278 for (CargoID c = 0; c < NUM_CARGO; c++) {
01279 byte buff[sizeof(StationCargoList)];
01280 memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList));
01281 st->goods[c].cargo.InvalidateCache();
01282 assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0);
01283 }
01284 }
01285 }
01286
01292 void StateGameLoop()
01293 {
01294
01295 if (_pause_mode != PM_UNPAUSED) {
01296 UpdateLandscapingLimits();
01297 Game::GameLoop();
01298 CallWindowTickEvent();
01299 return;
01300 }
01301 if (HasModalProgress()) return;
01302
01303 ClearStorageChanges(false);
01304
01305 if (_game_mode == GM_EDITOR) {
01306 RunTileLoop();
01307 CallVehicleTicks();
01308 CallLandscapeTick();
01309 ClearStorageChanges(true);
01310 UpdateLandscapingLimits();
01311
01312 CallWindowTickEvent();
01313 NewsLoop();
01314 } else {
01315 if (_debug_desync_level > 2 && _date_fract == 0 && (_date & 0x1F) == 0) {
01316
01317 char name[MAX_PATH];
01318 snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
01319 SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false);
01320 }
01321
01322 CheckCaches();
01323
01324
01325
01326 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
01327
01328 AnimateAnimatedTiles();
01329 IncreaseDate();
01330 RunTileLoop();
01331 CallVehicleTicks();
01332 CallLandscapeTick();
01333 ClearStorageChanges(true);
01334
01335 AI::GameLoop();
01336 Game::GameLoop();
01337 UpdateLandscapingLimits();
01338
01339 CallWindowTickEvent();
01340 NewsLoop();
01341 cur_company.Restore();
01342 }
01343
01344 assert(IsLocalCompany());
01345 }
01346
01351 static void DoAutosave()
01352 {
01353 char buf[MAX_PATH];
01354
01355 #if defined(PSP)
01356
01357 if (_networking) return;
01358 #endif
01359
01360 if (_settings_client.gui.keep_all_autosave) {
01361 GenerateDefaultSaveName(buf, lastof(buf));
01362 strecat(buf, ".sav", lastof(buf));
01363 } else {
01364 static int _autosave_ctr = 0;
01365
01366
01367 snprintf(buf, sizeof(buf), "autosave%d.sav", _autosave_ctr);
01368
01369 if (++_autosave_ctr >= _settings_client.gui.max_num_autosaves) _autosave_ctr = 0;
01370 }
01371
01372 DEBUG(sl, 2, "Autosaving to '%s'", buf);
01373 if (SaveOrLoad(buf, SL_SAVE, AUTOSAVE_DIR) != SL_OK) {
01374 ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR);
01375 }
01376 }
01377
01378 void GameLoop()
01379 {
01380 if (_game_mode == GM_BOOTSTRAP) {
01381 #ifdef ENABLE_NETWORK
01382
01383 if (_network_available) NetworkBackgroundLoop();
01384 #endif
01385 InputLoop();
01386 return;
01387 }
01388
01389 ProcessAsyncSaveFinish();
01390
01391
01392 if (_do_autosave) {
01393 _do_autosave = false;
01394 DoAutosave();
01395 SetWindowDirty(WC_STATUS_BAR, 0);
01396 }
01397
01398
01399 if (_switch_mode != SM_NONE && !HasModalProgress()) {
01400 SwitchToMode(_switch_mode);
01401 _switch_mode = SM_NONE;
01402 }
01403
01404 IncreaseSpriteLRU();
01405 InteractiveRandom();
01406
01407 extern int _caret_timer;
01408 _caret_timer += 3;
01409 CursorTick();
01410
01411 #ifdef ENABLE_NETWORK
01412
01413 if (_network_available) NetworkBackgroundLoop();
01414
01415 if (_networking && !HasModalProgress()) {
01416
01417 NetworkGameLoop();
01418 } else {
01419 if (_network_reconnect > 0 && --_network_reconnect == 0) {
01420
01421
01422 NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR);
01423 }
01424
01425 StateGameLoop();
01426 }
01427
01428
01429 static uint check_message = 0;
01430 if (++check_message > 1000 / MILLISECONDS_PER_TICK) {
01431 check_message = 0;
01432 NetworkChatMessageLoop();
01433 }
01434 #else
01435 StateGameLoop();
01436 #endif
01437
01438 if (!_pause_mode && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations();
01439
01440 if (!_pause_mode || _game_mode == GM_EDITOR || _settings_game.construction.command_pause_level > CMDPL_NO_CONSTRUCTION) MoveAllTextEffects();
01441
01442 InputLoop();
01443
01444 _sound_driver->MainLoop();
01445 MusicLoop();
01446 }