tron@2186: /* $Id$ */ tron@2186: belugas@6677: /** @file openttd.cpp */ belugas@6677: truelight@0: #include "stdafx.h" rubidium@5838: #define VARDEF tron@1299: #include "debug.h" tron@2171: #include "driver.h" tron@2162: #include "saveload.h" truelight@0: Darkvater@1891: #include "openttd.h" tron@3367: #include "bridge_map.h" tron@1496: #include "mixer.h" tron@1349: #include "spritecache.h" tron@2340: #include "gfxinit.h" truelight@0: #include "gui.h" maedhros@6949: #include "landscape.h" truelight@0: #include "station.h" tron@3367: #include "station_map.h" tron@3558: #include "town_map.h" tron@3367: #include "tunnel_map.h" rubidium@8720: #include "viewport_func.h" rubidium@8720: #include "gfx_func.h" rubidium@8603: #include "window_func.h" rubidium@8602: #include "window_gui.h" rubidium@8750: #include "player_func.h" rubidium@8750: #include "player_base.h" rubidium@8612: #include "command_func.h" truelight@0: #include "town.h" truelight@0: #include "industry.h" truelight@0: #include "news.h" truelight@0: #include "engine.h" truelight@0: #include "fileio.h" belugas@8647: #include "fios.h" truelight@0: #include "airport.h" celestar@6519: #include "aircraft.h" dominik@126: #include "console.h" tron@430: #include "screenshot.h" rubidium@5720: #include "network/network.h" rubidium@8772: #include "network/network_internal.h" truelight@988: #include "signs.h" truelight@1313: #include "depot.h" truelight@1542: #include "waypoint.h" truelight@2395: #include "ai/ai.h" bjarni@2855: #include "train.h" KUDr@3900: #include "yapf/yapf.h" rubidium@8704: #include "settings_func.h" truelight@4300: #include "genworld.h" truelight@4328: #include "clear_map.h" peter1138@5108: #include "fontcache.h" peter1138@6947: #include "newgrf.h" peter1138@5228: #include "newgrf_config.h" maedhros@6658: #include "newgrf_house.h" belugas@7125: #include "newgrf_commons.h" rubidium@8105: #include "newgrf_storage.h" rubidium@6516: #include "player_face.h" rubidium@7139: #include "group.h" truelight@7433: #include "blitter/factory.hpp" peter1138@7666: #include "sound/sound_driver.hpp" peter1138@7666: #include "music/music_driver.hpp" peter1138@7666: #include "video/video_driver.hpp" rubidium@8610: #include "strings_func.h" rubidium@8619: #include "zoom_func.h" rubidium@8636: #include "date_func.h" rubidium@8640: #include "vehicle_func.h" rubidium@8653: #include "sound_func.h" rubidium@8707: #include "variables.h" smatz@8838: #include "road_func.h" truelight@0: celestar@5573: #include "bridge_map.h" celestar@5573: #include "clear_map.h" celestar@5573: #include "rail_map.h" celestar@5573: #include "road_map.h" celestar@5573: #include "water_map.h" rubidium@5687: #include "industry_map.h" truelight@6583: #include "unmovable_map.h" truelight@8206: #include "tree_map.h" smatz@8579: #include "tunnelbridge_map.h" rubidium@8604: #include "void_map.h" peter1138@8967: #include "water.h" celestar@5573: truelight@0: #include truelight@0: rubidium@8760: #include "table/strings.h" rubidium@8760: rubidium@6573: void CallLandscapeTick(); rubidium@6573: void IncreaseDate(); rubidium@6573: void DoPaletteAnimations(); rubidium@6573: void MusicLoop(); rubidium@6573: void ResetMusic(); truelight@0: truelight@0: extern void SetDifficultyLevel(int mode, GameOptions *gm_opt); rubidium@5838: extern Player* DoStartupNewPlayer(bool is_ai); truelight@0: extern void ShowOSErrorBox(const char *buf); rubidium@7560: extern void SetDefaultRailGui(); truelight@0: pasky@1436: /* TODO: usrerror() for errors which are not of an internal nature but pasky@1436: * caused by the user, i.e. missing files or fatal configuration errors. pasky@1436: * Post-0.4.0 since Celestar doesn't want this in SVN before. --pasky */ pasky@1436: belugas@4171: void CDECL error(const char *s, ...) tron@2639: { truelight@0: va_list va; truelight@0: char buf[512]; tron@2639: truelight@0: va_start(va, s); Darkvater@5170: vsnprintf(buf, lengthof(buf), s, va); truelight@0: va_end(va); truelight@193: truelight@0: ShowOSErrorBox(buf); peter1138@7666: if (_video_driver != NULL) _video_driver->Stop(); truelight@0: truelight@0: assert(0); truelight@0: exit(1); truelight@0: } truelight@0: truelight@0: void CDECL ShowInfoF(const char *str, ...) truelight@0: { truelight@0: va_list va; truelight@0: char buf[1024]; truelight@0: va_start(va, str); Darkvater@5170: vsnprintf(buf, lengthof(buf), str, va); truelight@0: va_end(va); truelight@0: ShowInfo(buf); truelight@0: } truelight@0: truelight@0: rubidium@5838: extern const char _openttd_revision[]; rubidium@6573: static void showhelp() truelight@0: { truelight@0: char buf[4096], *p; truelight@0: Darkvater@5170: p = buf; truelight@2831: Darkvater@5170: p += snprintf(p, lengthof(buf), "OpenTTD %s\n", _openttd_revision); Darkvater@5170: p = strecpy(p, truelight@2831: "\n" truelight@2831: "\n" truelight@0: "Command line options:\n" truelight@543: " -v drv = Set video driver (see below)\n" Darkvater@6136: " -s drv = Set sound driver (see below) (param bufsize,hz)\n" truelight@543: " -m drv = Set music driver (see below)\n" truelight@7348: " -b drv = Set the blitter to use (see below)\n" truelight@543: " -r res = Set resolution (for instance 800x600)\n" truelight@543: " -h = Display this help text\n" rubidium@4285: " -t year = Set starting year\n" pasky@1440: " -d [[fac=]lvl[,...]]= Debug mode\n" truelight@543: " -e = Start Editor\n" truelight@543: " -g [savegame] = Start new/save game immediately\n" truelight@543: " -G seed = Set random seed\n" bjarni@5943: #if defined(ENABLE_NETWORK) rubidium@5676: " -n [ip:port#player] = Start networkgame\n" rubidium@5759: " -D [ip][:port] = Start dedicated server\n" truelight@6210: " -l ip[:port] = Redirect DEBUG()\n" tron@4077: #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) truelight@704: " -f = Fork into the background (dedicated only)\n" tron@4077: #endif bjarni@5943: #endif /* ENABLE_NETWORK */ truelight@2831: " -i = Force to use the DOS palette\n" truelight@2831: " (use this if you see a lot of pink)\n" truelight@2831: " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" Darkvater@5827: " -x = Do not automatically save to config file on exit\n", Darkvater@5170: lastof(buf) truelight@0: ); truelight@0: peter1138@7666: /* List the drivers */ peter1138@7666: p = VideoDriverFactoryBase::GetDriversInfo(p, lastof(buf)); truelight@0: truelight@7348: /* List the blitters */ truelight@7348: p = BlitterFactoryBase::GetBlittersInfo(p, lastof(buf)); truelight@7348: Darkvater@5974: /* ShowInfo put output to stderr, but version information should go Darkvater@5974: * to stdout; this is the only exception */ Darkvater@5974: #if !defined(WIN32) && !defined(WIN64) Darkvater@5974: printf("%s\n", buf); Darkvater@5974: #else truelight@0: ShowInfo(buf); Darkvater@5974: #endif truelight@0: } truelight@0: truelight@0: rubidium@5838: struct MyGetOptData { truelight@0: char *opt; truelight@0: int numleft; truelight@0: char **argv; truelight@0: const char *options; rubidium@5838: const char *cont; truelight@0: rubidium@5838: MyGetOptData(int argc, char **argv, const char *options) rubidium@5838: { rubidium@5838: opt = NULL; rubidium@5838: numleft = argc; rubidium@5838: this->argv = argv; rubidium@5838: this->options = options; rubidium@5838: cont = NULL; rubidium@5838: } rubidium@5838: }; truelight@0: truelight@0: static int MyGetOpt(MyGetOptData *md) truelight@0: { rubidium@5838: const char *s,*r,*t; truelight@0: tron@2639: s = md->cont; tron@2639: if (s != NULL) truelight@0: goto md_continue_here; truelight@0: tron@2639: for (;;) { tron@2639: if (--md->numleft < 0) return -1; truelight@0: truelight@0: s = *md->argv++; truelight@0: if (*s == '-') { truelight@0: md_continue_here:; truelight@0: s++; truelight@0: if (*s != 0) { belugas@6677: /* Found argument, try to locate it in options. */ truelight@0: if (*s == ':' || (r = strchr(md->options, *s)) == NULL) { belugas@6677: /* ERROR! */ truelight@0: return -2; truelight@0: } truelight@0: if (r[1] == ':') { belugas@6677: /* Item wants an argument. Check if the argument follows, or if it comes as a separate arg. */ truelight@0: if (!*(t = s + 1)) { belugas@6677: /* It comes as a separate arg. Check if out of args? */ truelight@0: if (--md->numleft < 0 || *(t = *md->argv) == '-') { belugas@6677: /* Check if item is optional? */ truelight@0: if (r[2] != ':') truelight@0: return -2; truelight@0: md->numleft++; truelight@0: t = NULL; truelight@0: } else { truelight@0: md->argv++; truelight@0: } truelight@0: } rubidium@5838: md->opt = (char*)t; truelight@0: md->cont = NULL; truelight@0: return *s; truelight@0: } truelight@0: md->opt = NULL; truelight@0: md->cont = s; truelight@0: return *s; truelight@0: } truelight@0: } else { belugas@6677: /* This is currently not supported. */ truelight@0: return -2; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: belugas@4171: static void ParseResolution(int res[2], const char *s) truelight@0: { rubidium@5838: const char *t = strchr(s, 'x'); truelight@0: if (t == NULL) { truelight@0: ShowInfoF("Invalid resolution '%s'", s); truelight@0: return; truelight@0: } truelight@0: skidd13@8418: res[0] = Clamp(strtoul(s, NULL, 0), 64, MAX_SCREEN_WIDTH); skidd13@8418: res[1] = Clamp(strtoul(t + 1, NULL, 0), 64, MAX_SCREEN_HEIGHT); truelight@193: } truelight@0: rubidium@6573: static void InitializeDynamicVariables() truelight@919: { truelight@919: /* Dynamic stuff needs to be initialized somewhere... */ truelight@1267: _town_sort = NULL; truelight@919: _industry_sort = NULL; belugas@7648: _industry_mngr.ResetMapping(); belugas@7648: _industile_mngr.ResetMapping(); truelight@919: } truelight@919: Darkvater@5910: rubidium@6573: static void UnInitializeGame() truelight@919: { Darkvater@5910: UnInitWindowSystem(); Darkvater@5910: Darkvater@5910: /* Uninitialize airport state machines */ Darkvater@5910: UnInitializeAirports(); Darkvater@5910: Darkvater@5910: /* Uninitialize variables that are allocated dynamically */ rubidium@7897: _Town_pool.CleanPool(); rubidium@7897: _Industry_pool.CleanPool(); rubidium@7897: _Station_pool.CleanPool(); rubidium@7897: _Vehicle_pool.CleanPool(); rubidium@7897: _Sign_pool.CleanPool(); rubidium@7897: _Order_pool.CleanPool(); rubidium@7897: _Group_pool.CleanPool(); rubidium@7897: _CargoPacket_pool.CleanPool(); truelight@1260: tron@4277: free((void*)_town_sort); tron@4277: free((void*)_industry_sort); Darkvater@1482: Darkvater@1482: free(_config_file); Darkvater@1474: } truelight@919: rubidium@6573: static void LoadIntroGame() truelight@543: { truelight@543: _game_mode = GM_MENU; peter1138@6923: Darkvater@1500: _opt_ptr = &_opt_newgame; peter1138@5228: ResetGRFConfig(false); truelight@543: belugas@6677: /* Setup main window */ Darkvater@1474: ResetWindowSystem(); truelight@543: SetupColorsAndInitialWindow(); truelight@543: rubidium@7425: /* Load the default opening screen savegame */ rubidium@7425: if (SaveOrLoad("opntitle.dat", SL_LOAD, DATA_DIR) != SL_OK) { tron@3033: GenerateWorld(GW_EMPTY, 64, 64); // if failed loading, make empty world. truelight@4300: WaitTillGeneratedWorld(); tron@921: } truelight@543: truelight@6557: _pause_game = 0; rubidium@5838: SetLocalPlayer(PLAYER_FIRST); truelight@4336: /* Make sure you can't scroll in the menu */ truelight@4336: _scrolling_viewport = 0; truelight@4336: _cursor.fix_at = false; truelight@543: MarkWholeScreenDirty(); truelight@543: rubidium@8581: CheckForMissingGlyphsInLoadedLanguagePack(); rubidium@8581: belugas@6677: /* Play main theme */ peter1138@7666: if (_music_driver->IsSongPlaying()) ResetMusic(); truelight@543: } truelight@543: rubidium@8764: byte _no_scroll; rubidium@8764: byte _savegame_sort_order; truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) rubidium@6573: extern void DedicatedFork(); truelight@2290: #endif truelight@704: belugas@4171: int ttd_main(int argc, char *argv[]) truelight@0: { truelight@0: int i; tron@1010: const char *optformat; truelight@7348: char musicdriver[32], sounddriver[32], videodriver[32], blitter[32]; rubidium@6987: int resolution[2] = {0, 0}; rubidium@4293: Year startyear = INVALID_YEAR; truelight@4300: uint generation_seed = GENERATE_NEW_SEED; bjarni@5943: bool save_config = true; bjarni@5943: #if defined(ENABLE_NETWORK) Darkvater@3058: bool dedicated = false; Darkvater@3058: bool network = false; Darkvater@3058: char *network_conn = NULL; truelight@6210: char *debuglog_conn = NULL; rubidium@5759: char *dedicated_host = NULL; rubidium@5759: uint16 dedicated_port = 0; bjarni@5943: #endif /* ENABLE_NETWORK */ tron@1406: truelight@7348: musicdriver[0] = sounddriver[0] = videodriver[0] = blitter[0] = '\0'; truelight@0: truelight@0: _game_mode = GM_MENU; truelight@0: _switch_mode = SM_MENU; darkvater@172: _switch_mode_errorstr = INVALID_STRING_ID; truelight@704: _dedicated_forks = false; Darkvater@1482: _config_file = NULL; truelight@0: belugas@6677: /* The last param of the following function means this: belugas@6677: * a letter means: it accepts that param (e.g.: -h) belugas@6677: * a ':' behind it means: it need a param (e.g.: -m) belugas@6677: * a '::' behind it means: it can optional have a param (e.g.: -d) */ truelight@7348: optformat = "m:s:v:b:hD::n::eit:d::r:g::G:c:xl:" tron@4077: #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) tron@4077: "f" tron@4077: #endif tron@4077: ; bjarni@770: rubidium@6987: MyGetOptData mgo(argc - 1, argv + 1, optformat); rubidium@5838: truelight@0: while ((i = MyGetOpt(&mgo)) != -1) { tron@2951: switch (i) { truelight@0: case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break; truelight@0: case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break; truelight@0: case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break; truelight@7348: case 'b': ttd_strlcpy(blitter, mgo.opt, sizeof(blitter)); break; bjarni@5943: #if defined(ENABLE_NETWORK) Darkvater@3058: case 'D': Darkvater@3058: strcpy(musicdriver, "null"); Darkvater@3058: strcpy(sounddriver, "null"); Darkvater@3058: strcpy(videodriver, "dedicated"); truelight@7374: strcpy(blitter, "null"); Darkvater@3058: dedicated = true; Darkvater@6136: if (mgo.opt != NULL) { rubidium@5759: /* Use the existing method for parsing (openttd -n). rubidium@5759: * However, we do ignore the #player part. */ rubidium@5759: const char *temp = NULL; rubidium@5759: const char *port = NULL; rubidium@5759: ParseConnectionString(&temp, &port, mgo.opt); Darkvater@6136: if (!StrEmpty(mgo.opt)) dedicated_host = mgo.opt; rubidium@5759: if (port != NULL) dedicated_port = atoi(port); rubidium@5759: } Darkvater@3058: break; Darkvater@3058: case 'f': _dedicated_forks = true; break; Darkvater@3058: case 'n': Darkvater@3058: network = true; Darkvater@3059: network_conn = mgo.opt; // optional IP parameter, NULL if unset Darkvater@3058: break; truelight@6210: case 'l': truelight@6210: debuglog_conn = mgo.opt; truelight@6210: break; bjarni@5943: #endif /* ENABLE_NETWORK */ truelight@0: case 'r': ParseResolution(resolution, mgo.opt); break; rubidium@4285: case 't': startyear = atoi(mgo.opt); break; truelight@0: case 'd': { truelight@0: #if defined(WIN32) truelight@0: CreateConsole(); truelight@0: #endif tron@2639: if (mgo.opt != NULL) SetDebugString(mgo.opt); truelight@0: } break; truelight@0: case 'e': _switch_mode = SM_EDITOR; break; dominik@614: case 'i': _use_dos_palette = true; break; truelight@193: case 'g': tron@2639: if (mgo.opt != NULL) { truelight@0: strcpy(_file_to_saveload.name, mgo.opt); truelight@0: _switch_mode = SM_LOAD; tron@4077: } else { truelight@0: _switch_mode = SM_NEWGAME; truelight@6635: /* Give a random map */ truelight@6635: generation_seed = InteractiveRandom(); tron@4077: } truelight@0: break; truelight@4300: case 'G': generation_seed = atoi(mgo.opt); break; Darkvater@3058: case 'c': _config_file = strdup(mgo.opt); break; rubidium@5758: case 'x': save_config = false; break; truelight@0: case -2: tron@2026: case 'h': truelight@0: showhelp(); truelight@0: return 0; truelight@0: } truelight@0: } truelight@0: truelight@7904: #if defined(WINCE) && defined(_DEBUG) truelight@7904: /* Switch on debug lvl 4 for WinCE if Debug release, as you can't give params, and you most likely do want this information */ truelight@7904: SetDebugString("4"); truelight@7904: #endif truelight@7904: rubidium@6643: DeterminePaths(argv[0]); dominik@961: CheckExternalFiles(); truelight@704: truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) belugas@6677: /* We must fork here, or we'll end up without some resources we need (like sockets) */ truelight@704: if (_dedicated_forks) truelight@704: DedicatedFork(); truelight@704: #endif truelight@704: truelight@0: LoadFromConfig(); Darkvater@1688: CheckConfig(); darkvater@983: LoadFromHighScore(); truelight@0: belugas@6677: /* override config? */ Darkvater@6136: if (!StrEmpty(musicdriver)) ttd_strlcpy(_ini_musicdriver, musicdriver, sizeof(_ini_musicdriver)); Darkvater@6136: if (!StrEmpty(sounddriver)) ttd_strlcpy(_ini_sounddriver, sounddriver, sizeof(_ini_sounddriver)); Darkvater@6136: if (!StrEmpty(videodriver)) ttd_strlcpy(_ini_videodriver, videodriver, sizeof(_ini_videodriver)); truelight@8063: if (!StrEmpty(blitter)) ttd_strlcpy(_ini_blitter, blitter, sizeof(_ini_blitter)); Darkvater@6136: if (resolution[0] != 0) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; } rubidium@4293: if (startyear != INVALID_YEAR) _patches_newgame.starting_year = startyear; truelight@4300: if (generation_seed != GENERATE_NEW_SEED) _patches_newgame.generation_seed = generation_seed; truelight@0: rubidium@7388: /* The width and height must be at least 1 pixel, this rubidium@7388: * way all internal drawing routines work correctly. */ rubidium@7388: if (_cur_resolution[0] == 0) _cur_resolution[0] = 1; rubidium@7388: if (_cur_resolution[1] == 0) _cur_resolution[1] = 1; rubidium@7388: bjarni@5943: #if defined(ENABLE_NETWORK) rubidium@5759: if (dedicated_host) snprintf(_network_server_bind_ip_host, NETWORK_HOSTNAME_LENGTH, "%s", dedicated_host); rubidium@5759: if (dedicated_port) _network_server_port = dedicated_port; tron@2951: if (_dedicated_forks && !dedicated) _dedicated_forks = false; bjarni@5943: #endif /* ENABLE_NETWORK */ truelight@704: belugas@6677: /* enumerate language files */ truelight@0: InitializeLanguagePacks(); truelight@0: belugas@6677: /* initialize screenshot formats */ truelight@0: InitializeScreenshotFormats(); truelight@0: belugas@6677: /* initialize airport state machines */ dominik@105: InitializeAirports(); truelight@193: truelight@919: /* initialize all variables that are allocated dynamically */ truelight@919: InitializeDynamicVariables(); truelight@919: truelight@2395: /* start the AI */ truelight@2395: AI_Initialize(); truelight@2395: belugas@6677: /* Sample catalogue */ Darkvater@5568: DEBUG(misc, 1, "Loading sound effects..."); tron@1496: MxInitialize(11025); tron@1496: SoundInitialize("sample.cat"); truelight@0: peter1138@5108: /* Initialize FreeType */ peter1138@5108: InitFreeType(); peter1138@5108: belugas@6677: /* This must be done early, since functions use the InvalidateWindow* calls */ truelight@139: InitWindowSystem(); truelight@0: peter1138@5166: /* Initialize game palette */ peter1138@5166: GfxInitPalettes(); peter1138@5166: truelight@8063: DEBUG(misc, 1, "Loading blitter..."); truelight@8063: if (BlitterFactoryBase::SelectBlitter(_ini_blitter) == NULL) truelight@8063: StrEmpty(_ini_blitter) ? truelight@8063: error("Failed to autoprobe blitter") : truelight@8063: error("Failed to select requested blitter '%s'; does it exist?", _ini_blitter); peter1138@7666: Darkvater@5568: DEBUG(driver, 1, "Loading drivers..."); peter1138@7666: peter1138@7666: _sound_driver = (SoundDriver*)SoundDriverFactoryBase::SelectDriver(_ini_sounddriver, Driver::DT_SOUND); peter1138@7666: if (_sound_driver == NULL) { peter1138@7666: StrEmpty(_ini_sounddriver) ? peter1138@7666: error("Failed to autoprobe sound driver") : peter1138@7666: error("Failed to select requested sound driver '%s'", _ini_sounddriver); peter1138@7666: } peter1138@7666: peter1138@7666: _music_driver = (MusicDriver*)MusicDriverFactoryBase::SelectDriver(_ini_musicdriver, Driver::DT_MUSIC); peter1138@7666: if (_music_driver == NULL) { peter1138@7666: StrEmpty(_ini_musicdriver) ? peter1138@7666: error("Failed to autoprobe music driver") : peter1138@7666: error("Failed to select requested music driver '%s'", _ini_musicdriver); peter1138@7666: } peter1138@7666: peter1138@7666: _video_driver = (VideoDriver*)VideoDriverFactoryBase::SelectDriver(_ini_videodriver, Driver::DT_VIDEO); peter1138@7666: if (_video_driver == NULL) { peter1138@7666: StrEmpty(_ini_videodriver) ? peter1138@7666: error("Failed to autoprobe video driver") : peter1138@7666: error("Failed to select requested video driver '%s'", _ini_videodriver); peter1138@7666: } peter1138@7666: tron@2526: _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; truelight@7150: /* Initialize the zoom level of the screen to normal */ truelight@7150: _screen.zoom = ZOOM_LVL_NORMAL; truelight@0: belugas@6677: /* restore saved music volume */ peter1138@7666: _music_driver->SetVolume(msf.music_vol); glx@3678: Darkvater@4830: NetworkStartUp(); // initialize network-core truelight@543: truelight@6210: #if defined(ENABLE_NETWORK) truelight@6210: if (debuglog_conn != NULL && _network_available) { truelight@6210: const char *not_used = NULL; truelight@6210: const char *port = NULL; truelight@6210: uint16 rport; truelight@6210: truelight@6210: rport = NETWORK_DEFAULT_DEBUGLOG_PORT; truelight@6210: truelight@6210: ParseConnectionString(¬_used, &port, debuglog_conn); truelight@6210: if (port != NULL) rport = atoi(port); truelight@6210: truelight@6210: NetworkStartDebugLog(debuglog_conn, rport); truelight@6210: } truelight@6210: #endif /* ENABLE_NETWORK */ truelight@6210: peter1138@5228: ScanNewGRFFiles(); peter1138@5228: Darkvater@1500: _opt_ptr = &_opt_newgame; peter1138@5228: ResetGRFConfig(false); truelight@193: Darkvater@1500: /* XXX - ugly hack, if diff_level is 9, it means we got no setting from the config file */ tron@2951: if (_opt_newgame.diff_level == 9) SetDifficultyLevel(0, &_opt_newgame); truelight@0: truelight@4300: /* Make sure _patches is filled with _patches_newgame if we switch to a game directly */ truelight@4300: if (_switch_mode != SM_NONE) { tron@5024: _opt = _opt_newgame; truelight@4300: UpdatePatches(); truelight@4300: } truelight@4300: belugas@6677: /* initialize the ingame console */ truelight@139: IConsoleInit(); Darkvater@3312: _cursor.in_window = true; darkvater@1246: InitializeGUI(); dominik@644: IConsoleCmdExec("exec scripts/autoexec.scr 0"); truelight@656: truelight@2828: GenerateWorld(GW_EMPTY, 64, 64); // Make the viewport initialization happy truelight@4300: WaitTillGeneratedWorld(); truelight@1268: truelight@543: #ifdef ENABLE_NETWORK tron@2951: if (network && _network_available) { truelight@543: if (network_conn != NULL) { tron@1329: const char *port = NULL; tron@1329: const char *player = NULL; truelight@543: uint16 rport; truelight@543: truelight@543: rport = NETWORK_DEFAULT_PORT; Darkvater@4878: _network_playas = PLAYER_NEW_COMPANY; truelight@543: truelight@543: ParseConnectionString(&player, &port, network_conn); truelight@543: Darkvater@4861: if (player != NULL) { rubidium@5838: _network_playas = (PlayerID)atoi(player); Darkvater@4878: Darkvater@4880: if (_network_playas != PLAYER_SPECTATOR) { Darkvater@4880: _network_playas--; Darkvater@4878: if (!IsValidPlayer(_network_playas)) return false; Darkvater@4878: } Darkvater@4861: } truelight@543: if (port != NULL) rport = atoi(port); truelight@543: truelight@543: LoadIntroGame(); truelight@543: _switch_mode = SM_NONE; truelight@543: NetworkClientConnectGame(network_conn, rport); tron@1109: } truelight@543: } truelight@543: #endif /* ENABLE_NETWORK */ truelight@543: peter1138@7666: _video_driver->MainLoop(); truelight@139: tron@2285: WaitTillSaved(); truelight@139: IConsoleFree(); truelight@0: Darkvater@4830: if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections truelight@0: peter1138@7666: _video_driver->Stop(); peter1138@7666: _music_driver->Stop(); peter1138@7666: _sound_driver->Stop(); truelight@0: rubidium@5758: /* only save config if we have to */ rubidium@5758: if (save_config) { rubidium@5758: SaveToConfig(); rubidium@5758: SaveToHighScore(); rubidium@5758: } truelight@0: Darkvater@5910: /* Reset windowing system and free config file */ Darkvater@5910: UnInitializeGame(); truelight@919: truelight@2395: /* stop the AI */ truelight@2395: AI_Uninitialize(); truelight@2395: darkvater@1036: /* Close all and any open filehandles */ darkvater@1036: FioCloseAll(); darkvater@1036: truelight@0: return 0; truelight@0: } truelight@0: rubidium@6573: void HandleExitGameRequest() rubidium@4548: { rubidium@4548: if (_game_mode == GM_MENU) { // do not ask to quit on the main screen rubidium@4548: _exit_game = true; rubidium@4548: } else if (_patches.autosave_on_exit) { rubidium@4548: DoExitSave(); rubidium@4548: _exit_game = true; rubidium@4548: } else { rubidium@4548: AskExitGame(); rubidium@4548: } rubidium@4548: } rubidium@4548: rubidium@4548: Darkvater@2380: /** Mutex so that only one thread can communicate with the main program Darkvater@2380: * at any given time */ truelight@4323: static ThreadMsg _message = MSG_OTTD_NO_MESSAGE; Darkvater@2380: rubidium@6573: static inline void OTTD_ReleaseMutex() {_message = MSG_OTTD_NO_MESSAGE;} rubidium@6573: static inline ThreadMsg OTTD_PollThreadEvent() {return _message;} Darkvater@2380: Darkvater@2380: /** Called by running thread to execute some action in the main game. Darkvater@2380: * It will stall as long as the mutex is not freed (handled) by the game */ Darkvater@2380: void OTTD_SendThreadMessage(ThreadMsg msg) Darkvater@2380: { Darkvater@2383: if (_exit_game) return; truelight@4323: while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10); Darkvater@2380: Darkvater@2380: _message = msg; Darkvater@2380: } Darkvater@2380: Darkvater@2380: Darkvater@2380: /** Handle the user-messages sent to us Darkvater@2380: * @param message message sent Darkvater@2380: */ tron@2817: static void ProcessSentMessage(ThreadMsg message) Darkvater@2380: { Darkvater@2380: switch (message) { Darkvater@2380: case MSG_OTTD_SAVETHREAD_DONE: SaveFileDone(); break; Darkvater@2380: case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break; Darkvater@2380: default: NOT_REACHED(); Darkvater@2380: } Darkvater@2380: Darkvater@2380: OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled Darkvater@2380: } Darkvater@2380: truelight@0: static void ShowScreenshotResult(bool b) truelight@0: { truelight@0: if (b) { ludde@2055: SetDParamStr(0, _screenshot_name); truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_031B_SCREENSHOT_SUCCESSFULLY, 0, 0); truelight@0: } else { truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_031C_SCREENSHOT_FAILED, 0, 0); truelight@0: } truelight@0: truelight@0: } truelight@0: rubidium@6573: static void MakeNewGameDone() truelight@4300: { truelight@4300: /* In a dedicated server, the server does not play */ truelight@4300: if (_network_dedicated) { rubidium@5564: SetLocalPlayer(PLAYER_SPECTATOR); truelight@4300: return; truelight@4300: } truelight@4300: truelight@4300: /* Create a single player */ truelight@4300: DoStartupNewPlayer(false); truelight@4300: rubidium@5838: SetLocalPlayer(PLAYER_FIRST); truelight@4300: _current_player = _local_player; peter1138@4661: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@4300: KUDr@5116: SettingsDisableElrail(_patches.disable_elrails); rubidium@7560: SetDefaultRailGui(); KUDr@5116: rubidium@8743: #ifdef ENABLE_NETWORK rubidium@8494: /* We are the server, we start a new player (not dedicated), rubidium@8494: * so set the default password *if* needed. */ rubidium@8494: if (_network_server && !StrEmpty(_network_default_company_pass)) { rubidium@8494: char *password = _network_default_company_pass; rubidium@8494: NetworkChangeCompanyPassword(1, &password); rubidium@8494: } rubidium@8743: #endif /* ENABLE_NETWORK */ rubidium@8494: truelight@4300: MarkWholeScreenDirty(); truelight@4300: } truelight@4300: truelight@4300: static void MakeNewGame(bool from_heightmap) truelight@0: { truelight@0: _game_mode = GM_NORMAL; truelight@0: peter1138@5313: ResetGRFConfig(true); belugas@7125: _house_mngr.ResetMapping(); belugas@7648: _industile_mngr.ResetMapping(); belugas@7648: _industry_mngr.ResetMapping(); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewGameDone); truelight@4300: GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _patches.map_x, 1 << _patches.map_y); truelight@4300: } truelight@0: rubidium@6573: static void MakeNewEditorWorldDone() truelight@4300: { rubidium@5564: SetLocalPlayer(OWNER_NONE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: rubidium@6573: static void MakeNewEditorWorld() truelight@0: { truelight@0: _game_mode = GM_EDITOR; truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewEditorWorldDone); truelight@2828: GenerateWorld(GW_EMPTY, 1 << _patches.map_x, 1 << _patches.map_y); truelight@0: } truelight@0: rubidium@6573: void StartupPlayers(); rubidium@6573: void StartupDisasters(); rubidium@6573: extern void StartupEconomy(); dominik@116: Darkvater@1500: /** Darkvater@1500: * Start Scenario starts a new game based on a scenario. Darkvater@1500: * Eg 'New Game' --> select a preset scenario Darkvater@1501: * This starts a scenario based on your current difficulty settings Darkvater@1500: */ rubidium@6573: static void StartScenario() truelight@0: { truelight@0: _game_mode = GM_NORMAL; truelight@0: belugas@6677: /* invalid type */ truelight@0: if (_file_to_saveload.mode == SL_INVALID) { Darkvater@5568: DEBUG(sl, 0, "Savegame is obsolete or invalid format: '%s'", _file_to_saveload.name); rubidium@7532: SetDParamStr(0, GetSaveLoadErrorString()); rubidium@7532: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); truelight@0: _game_mode = GM_MENU; truelight@0: return; truelight@0: } truelight@0: belugas@6677: /* Reinitialize windows */ Darkvater@1474: ResetWindowSystem(); truelight@0: truelight@0: SetupColorsAndInitialWindow(); truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: belugas@6677: /* Load game */ rubidium@7425: if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, SCENARIO_DIR) != SL_OK) { truelight@0: LoadIntroGame(); rubidium@7532: SetDParamStr(0, GetSaveLoadErrorString()); rubidium@7532: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); truelight@0: } truelight@0: Darkvater@1501: _opt_ptr = &_opt; tron@5024: _opt_ptr->diff = _opt_newgame.diff; Darkvater@1501: _opt.diff_level = _opt_newgame.diff_level; Darkvater@1500: belugas@6677: /* Inititalize data */ Darkvater@3891: StartupEconomy(); dominik@115: StartupPlayers(); dominik@115: StartupEngines(); dominik@115: StartupDisasters(); dominik@115: rubidium@5838: SetLocalPlayer(PLAYER_FIRST); bjarni@2293: _current_player = _local_player; peter1138@4661: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: rubidium@7425: /** Load the specified savegame but on error do different things. rubidium@7425: * If loading fails due to corrupt savegame, bad version, etc. go back to rubidium@7425: * a previous correct state. In the menu for example load the intro game again. rubidium@7425: * @param filename file to be loaded rubidium@7425: * @param mode mode of loading, either SL_LOAD or SL_OLD_LOAD rubidium@7425: * @param newgm switch to this mode of loading fails due to some unknown error rubidium@7425: * @param subdir default directory to look for filename, set to 0 if not needed */ rubidium@7425: bool SafeSaveOrLoad(const char *filename, int mode, int newgm, Subdirectory subdir) truelight@0: { truelight@0: byte ogm = _game_mode; truelight@0: truelight@0: _game_mode = newgm; rubidium@7425: assert(mode == SL_LOAD || mode == SL_OLD_LOAD); rubidium@7425: switch (SaveOrLoad(filename, mode, subdir)) { tron@3024: case SL_OK: return true; tron@3024: tron@3024: case SL_REINIT: tron@3024: switch (ogm) { tron@3024: case GM_MENU: LoadIntroGame(); break; tron@3024: case GM_EDITOR: MakeNewEditorWorld(); break; truelight@4300: default: MakeNewGame(false); break; tron@3024: } tron@3024: return false; tron@3024: tron@3024: default: tron@3024: _game_mode = ogm; tron@3024: return false; tron@2639: } truelight@0: } truelight@0: truelight@543: void SwitchMode(int new_mode) truelight@0: { truelight@543: #ifdef ENABLE_NETWORK belugas@6677: /* If we are saving something, the network stays in his current state */ truelight@543: if (new_mode != SM_SAVE) { belugas@6677: /* If the network is active, make it not-active */ truelight@543: if (_networking) { truelight@543: if (_network_server && (new_mode == SM_LOAD || new_mode == SM_NEWGAME)) { truelight@543: NetworkReboot(); rubidium@5870: NetworkUDPCloseAll(); truelight@543: } else { truelight@543: NetworkDisconnect(); rubidium@5870: NetworkUDPCloseAll(); truelight@543: } truelight@543: } truelight@543: belugas@6677: /* If we are a server, we restart the server */ truelight@543: if (_is_network_server) { belugas@6677: /* But not if we are going to the menu */ truelight@543: if (new_mode != SM_MENU) { rubidium@8761: /* check if we should reload the config */ rubidium@8761: if (_network_reload_cfg) { rubidium@8761: LoadFromConfig(); rubidium@8761: _patches = _patches_newgame; rubidium@8761: _opt = _opt_newgame; rubidium@8761: ResetGRFConfig(false); rubidium@8761: } truelight@543: NetworkServerStart(); truelight@543: } else { belugas@6677: /* This client no longer wants to be a network-server */ truelight@543: _is_network_server = false; truelight@543: } truelight@543: } truelight@543: } truelight@543: #endif /* ENABLE_NETWORK */ truelight@543: Darkvater@1500: switch (new_mode) { Darkvater@1500: case SM_EDITOR: /* Switch to scenario editor */ truelight@0: MakeNewEditorWorld(); truelight@0: break; truelight@0: Darkvater@1500: case SM_NEWGAME: /* New Game --> 'Random game' */ truelight@630: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map"); tron@2951: } truelight@630: #endif /* ENABLE_NETWORK */ truelight@4300: MakeNewGame(false); truelight@0: break; truelight@0: Darkvater@1500: case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */ tron@2951: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title); tron@2951: } tron@2951: #endif /* ENABLE_NETWORK */ truelight@543: StartScenario(); truelight@543: break; truelight@543: Darkvater@1500: case SM_LOAD: { /* Load game, Play Scenario */ Darkvater@1500: _opt_ptr = &_opt; peter1138@5228: ResetGRFConfig(true); glx@8508: ResetWindowSystem(); truelight@0: rubidium@7431: if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) { truelight@942: LoadIntroGame(); rubidium@7532: SetDParamStr(0, GetSaveLoadErrorString()); rubidium@7532: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); truelight@0: } else { Darkvater@5197: /* Update the local player for a loaded game. It is either always Darkvater@5197: * player #1 (eg 0) or in the case of a dedicated server a spectator */ rubidium@5838: SetLocalPlayer(_network_dedicated ? PLAYER_SPECTATOR : PLAYER_FIRST); skidd13@8561: /* Decrease pause counter (was increased from opening load dialog) */ skidd13@8561: DoCommandP(0, 0, 0, NULL, CMD_PAUSE); truelight@630: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); tron@2951: } truelight@630: #endif /* ENABLE_NETWORK */ truelight@0: } truelight@0: break; truelight@0: } truelight@0: truelight@4300: case SM_START_HEIGHTMAP: /* Load a heightmap and start a new game from it */ truelight@4300: #ifdef ENABLE_NETWORK truelight@4300: if (_network_server) { truelight@4300: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); truelight@4300: } truelight@4300: #endif /* ENABLE_NETWORK */ truelight@4300: MakeNewGame(true); truelight@4300: break; truelight@4300: truelight@4300: case SM_LOAD_HEIGHTMAP: /* Load heightmap from scenario editor */ rubidium@5564: SetLocalPlayer(OWNER_NONE); truelight@4300: truelight@4300: GenerateWorld(GW_HEIGHTMAP, 1 << _patches.map_x, 1 << _patches.map_y); truelight@4300: MarkWholeScreenDirty(); truelight@4300: break; truelight@4300: Darkvater@1500: case SM_LOAD_SCENARIO: { /* Load scenario from scenario editor */ rubidium@7431: if (SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR, NO_DIRECTORY)) { Darkvater@1500: _opt_ptr = &_opt; truelight@0: rubidium@5564: SetLocalPlayer(OWNER_NONE); rubidium@4537: _patches_newgame.starting_year = _cur_year; tron@2639: } else { rubidium@7532: SetDParamStr(0, GetSaveLoadErrorString()); rubidium@7532: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); tron@2639: } truelight@0: break; truelight@0: } truelight@0: Darkvater@1500: case SM_MENU: /* Switch to game intro menu */ truelight@0: LoadIntroGame(); truelight@0: break; truelight@0: Darkvater@1500: case SM_SAVE: /* Save game */ skidd13@8561: /* Make network saved games on pause compatible to singleplayer */ skidd13@8561: if (_networking && _pause_game == 1) _pause_game = 2; rubidium@7431: if (SaveOrLoad(_file_to_saveload.name, SL_SAVE, NO_DIRECTORY) != SL_OK) { rubidium@7532: SetDParamStr(0, GetSaveLoadErrorString()); rubidium@7532: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); tron@2639: } else { truelight@0: DeleteWindowById(WC_SAVELOAD, 0); tron@2639: } skidd13@8561: if (_networking && _pause_game == 2) _pause_game = 1; truelight@0: break; truelight@0: Darkvater@1500: case SM_GENRANDLAND: /* Generate random land within scenario editor */ rubidium@5564: SetLocalPlayer(OWNER_NONE); tron@2951: GenerateWorld(GW_RANDOM, 1 << _patches.map_x, 1 << _patches.map_y); belugas@6677: /* XXX: set date */ truelight@0: MarkWholeScreenDirty(); truelight@0: break; truelight@0: } truelight@193: tron@2951: if (_switch_mode_errorstr != INVALID_STRING_ID) { tron@2951: ShowErrorMessage(INVALID_STRING_ID, _switch_mode_errorstr, 0, 0); tron@2951: } truelight@0: } truelight@0: truelight@0: belugas@6677: /* State controlling game loop. belugas@6677: * The state must not be changed from anywhere belugas@6677: * but here. belugas@6677: * That check is enforced in DoCommand. */ rubidium@6573: void StateGameLoop() truelight@0: { belugas@6677: /* dont execute the state loop during pause */ peter1138@8675: if (_pause_game) { peter1138@8675: CallWindowTickEvent(); peter1138@8675: return; peter1138@8675: } truelight@4300: if (IsGeneratingWorld()) return; darkvater@213: rubidium@8799: ClearStorageChanges(false); rubidium@8799: truelight@0: if (_game_mode == GM_EDITOR) { truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); rubidium@8799: ClearStorageChanges(true); rubidium@8799: truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); truelight@0: } else { belugas@6677: /* All these actions has to be done from OWNER_NONE belugas@6677: * for multiplayer compatibility */ tron@2498: PlayerID p = _current_player; signde@206: _current_player = OWNER_NONE; signde@206: truelight@0: AnimateAnimatedTiles(); truelight@0: IncreaseDate(); truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); rubidium@8799: ClearStorageChanges(true); truelight@0: truelight@2395: AI_RunGameLoop(); truelight@0: truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); signde@206: _current_player = p; truelight@0: } truelight@0: } truelight@0: rubidium@7425: /** Create an autosave. The default name is "autosave#.sav". However with rubidium@7425: * the patch setting 'keep_all_autosave' the name defaults to company-name + date */ rubidium@6573: static void DoAutosave() truelight@0: { rubidium@7425: char buf[MAX_PATH]; truelight@193: truelight@6228: #if defined(PSP) truelight@6228: /* Autosaving in networking is too time expensive for the PSP */ truelight@6228: if (_networking) truelight@6228: return; truelight@6228: #endif /* PSP */ truelight@6228: Darkvater@4848: if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) { peter1138@7554: SetDParam(0, _local_player); peter1138@7554: SetDParam(1, _date); rubidium@7425: GetString(buf, STR_4004, lastof(buf)); rubidium@7910: ttd_strlcat(buf, ".sav", lengthof(buf)); rubidium@7425: } else { rubidium@7425: /* generate a savegame name and number according to _patches.max_num_autosaves */ rubidium@7425: snprintf(buf, sizeof(buf), "autosave%d.sav", _autosave_ctr); bjarni@2672: rubidium@7425: if (++_autosave_ctr >= _patches.max_num_autosaves) _autosave_ctr = 0; truelight@0: } truelight@0: Darkvater@5568: DEBUG(sl, 2, "Autosaving to '%s'", buf); rubidium@7425: if (SaveOrLoad(buf, SL_SAVE, AUTOSAVE_DIR) != SL_OK) truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_AUTOSAVE_FAILED, 0, 0); truelight@0: } truelight@0: Darkvater@1397: static void ScrollMainViewport(int x, int y) Darkvater@1397: { rubidium@4536: if (_game_mode != GM_MENU) { Darkvater@1397: Window *w = FindWindowById(WC_MAIN_WINDOW, 0); Darkvater@1397: assert(w); Darkvater@1397: rubidium@8578: WP(w, vp_d).dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); rubidium@8578: WP(w, vp_d).dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); Darkvater@1397: } Darkvater@1397: } belugas@8559: /** belugas@8559: * Describes all the different arrow key combinations the game allows belugas@8559: * when it is in scrolling mode. belugas@8559: * The real arrow keys are bitwise numbered as belugas@8559: * 1 = left belugas@8559: * 2 = up belugas@8559: * 4 = right belugas@8559: * 8 = down belugas@8559: */ Darkvater@1397: static const int8 scrollamt[16][2] = { belugas@8559: { 0, 0}, ///< no key specified belugas@6677: {-2, 0}, ///< 1 : left belugas@6677: { 0, -2}, ///< 2 : up belugas@8559: {-2, -1}, ///< 3 : left + up belugas@6677: { 2, 0}, ///< 4 : right belugas@8559: { 0, 0}, ///< 5 : left + right = nothing belugas@6677: { 2, -1}, ///< 6 : right + up belugas@8559: { 0, -2}, ///< 7 : right + left + up = up belugas@6677: { 0 ,2}, ///< 8 : down belugas@8559: {-2 ,1}, ///< 9 : down + left belugas@8559: { 0, 0}, ///< 10 : down + up = nothing belugas@8559: {-2, 0}, ///< 11 : left + up + down = left belugas@8559: { 2, 1}, ///< 12 : down + right belugas@8559: { 0, 2}, ///< 13 : left + right + down = down belugas@8559: { 2, 0}, ///< 14 : right + up + down = right belugas@8559: { 0, 0}, ///< 15 : left + up + right + down = nothing Darkvater@1397: }; Darkvater@1397: rubidium@6573: static void HandleKeyScrolling() Darkvater@1397: { Darkvater@1397: if (_dirkeys && !_no_scroll) { Darkvater@1397: int factor = _shift_pressed ? 50 : 10; Darkvater@1397: ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); Darkvater@1397: } Darkvater@1397: } dominik@1199: rubidium@6573: void GameLoop() truelight@0: { Darkvater@2380: ThreadMsg message; Darkvater@2380: Darkvater@2380: if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message); truelight@0: belugas@6677: /* autosave game? */ truelight@0: if (_do_autosave) { truelight@0: _do_autosave = false; truelight@0: DoAutosave(); truelight@0: RedrawAutosave(); truelight@0: } truelight@0: belugas@6677: /* handle scrolling of the main window */ tron@4502: HandleKeyScrolling(); dominik@1199: belugas@6677: /* make a screenshot? */ belugas@4184: if (IsScreenshotRequested()) ShowScreenshotResult(MakeScreenshot()); truelight@0: belugas@6677: /* switch game mode? */ tron@3024: if (_switch_mode != SM_NONE) { tron@3024: SwitchMode(_switch_mode); truelight@0: _switch_mode = SM_NONE; truelight@0: } truelight@0: truelight@0: IncreaseSpriteLRU(); truelight@0: InteractiveRandom(); truelight@0: tron@2639: if (_scroller_click_timeout > 3) { truelight@0: _scroller_click_timeout -= 3; tron@2639: } else { truelight@0: _scroller_click_timeout = 0; tron@2639: } truelight@0: truelight@0: _caret_timer += 3; truelight@7514: _palette_animation_counter += 8; truelight@0: CursorTick(); truelight@0: truelight@543: #ifdef ENABLE_NETWORK belugas@6677: /* Check for UDP stuff */ Darkvater@4830: if (_network_available) NetworkUDPGameLoop(); truelight@0: truelight@4300: if (_networking && !IsGeneratingWorld()) { belugas@6677: /* Multiplayer */ truelight@543: NetworkGameLoop(); truelight@543: } else { truelight@543: if (_network_reconnect > 0 && --_network_reconnect == 0) { belugas@6677: /* This means that we want to reconnect to the last host belugas@6677: * We do this here, because it means that the network is really closed */ truelight@543: NetworkClientConnectGame(_network_last_host, _network_last_port); signde@206: } belugas@6677: /* Singleplayer */ darkvater@213: StateGameLoop(); truelight@0: } truelight@543: #else truelight@543: StateGameLoop(); truelight@543: #endif /* ENABLE_NETWORK */ truelight@0: skidd13@8424: if (!_pause_game && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); truelight@0: truelight@6557: if (!_pause_game || _cheats.build_in_pause.value) MoveAllTextEffects(); truelight@0: pasky@1570: InputLoop(); truelight@0: tron@1608: MusicLoop(); truelight@0: } truelight@0: rubidium@6573: void BeforeSaveGame() truelight@0: { belugas@4171: const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); truelight@0: darkvater@983: if (w != NULL) { tron@2643: _saved_scrollpos_x = WP(w, const vp_d).scrollpos_x; tron@2643: _saved_scrollpos_y = WP(w, const vp_d).scrollpos_y; darkvater@983: _saved_scrollpos_zoom = w->viewport->zoom; darkvater@983: } truelight@0: } truelight@0: rubidium@6573: static void ConvertTownOwner() truelight@0: { tron@1977: TileIndex tile; truelight@0: tron@863: for (tile = 0; tile != MapSize(); tile++) { tron@4000: switch (GetTileType(tile)) { rubidium@7866: case MP_ROAD: skidd13@8424: if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m4, 7)) { rubidium@7157: _m[tile].m4 = OWNER_TOWN; tron@4000: } tron@4000: /* FALLTHROUGH */ truelight@0: tron@4000: case MP_TUNNELBRIDGE: tron@4000: if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN); tron@4000: break; tron@4000: tron@4000: default: break; truelight@0: } truelight@0: } truelight@0: } truelight@0: belugas@6677: /* before savegame version 4, the name of the company determined if it existed */ rubidium@6573: static void CheckIsPlayerActive() truelight@0: { belugas@4171: Player *p; tron@2639: truelight@0: FOR_ALL_PLAYERS(p) { tron@2639: if (p->name_1 != 0) p->is_active = true; truelight@0: } truelight@0: } truelight@0: belugas@6677: /* since savegame version 4.1, exclusive transport rights are stored at towns */ rubidium@6573: static void UpdateExclusiveRights() dominik@121: { belugas@4171: Town *t; tron@2639: tron@2639: FOR_ALL_TOWNS(t) { rubidium@5838: t->exclusivity = INVALID_PLAYER; dominik@121: } truelight@193: dominik@123: /* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete) rubidium@4549: * could be implemented this way: rubidium@4549: * 1.) Go through all stations rubidium@4549: * Build an array town_blocked[ town_id ][ player_id ] rubidium@4549: * that stores if at least one station in that town is blocked for a player rubidium@4549: * 2.) Go through that array, if you find a town that is not blocked for rubidium@4549: * one player, but for all others, then give him exclusivity. rubidium@4549: */ dominik@121: } dominik@121: tron@2756: static const byte convert_currency[] = { dominik@762: 0, 1, 12, 8, 3, dominik@762: 10, 14, 19, 4, 5, dominik@762: 9, 11, 13, 6, 17, dominik@762: 16, 22, 21, 7, 15, dominik@762: 18, 2, 20, }; dominik@762: belugas@6677: /* since savegame version 4.2 the currencies are arranged differently */ rubidium@6573: static void UpdateCurrencies() dominik@762: { dominik@768: _opt.currency = convert_currency[_opt.currency]; dominik@762: } dominik@762: tron@1181: /* Up to revision 1413 the invisible tiles at the southern border have not been tron@1181: * MP_VOID, even though they should have. This is fixed by this function tron@1181: */ rubidium@6573: static void UpdateVoidTiles() dominik@929: { tron@959: uint i; tron@1181: tron@3075: for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX()); tron@3075: for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i); dominik@929: } dominik@929: belugas@6677: /* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */ rubidium@6573: static void UpdateSignOwner() dominik@1165: { truelight@4349: Sign *si; tron@2639: truelight@4349: FOR_ALL_SIGNS(si) si->owner = OWNER_NONE; dominik@1165: } dominik@1165: rubidium@6573: extern void UpdateOldAircraft(); truelight@0: tron@3656: tron@3656: static inline RailType UpdateRailType(RailType rt, RailType min) tron@3656: { tron@3656: return rt >= min ? (RailType)(rt + 1): rt; tron@3656: } tron@3656: rubidium@8477: /** rubidium@8477: * Initialization of the windows and several kinds of caches. rubidium@8477: * This is not done directly in AfterLoadGame because these rubidium@8477: * functions require that all saveload conversions have been rubidium@8477: * done. As people tend to add savegame conversion stuff after rubidium@8477: * the intialization of the windows and caches quite some bugs rubidium@8477: * had been made. rubidium@8477: * Moving this out of there is both cleaner and less bug-prone. rubidium@8477: * rubidium@8477: * @return true if everything went according to plan, otherwise false. rubidium@8477: */ rubidium@8477: static bool InitializeWindowsAndCaches() rubidium@8477: { rubidium@8477: /* Initialize windows */ rubidium@8477: ResetWindowSystem(); rubidium@8477: SetupColorsAndInitialWindow(); rubidium@8477: rubidium@8477: Window *w = FindWindowById(WC_MAIN_WINDOW, 0); rubidium@8477: rubidium@8477: WP(w, vp_d).scrollpos_x = _saved_scrollpos_x; rubidium@8477: WP(w, vp_d).scrollpos_y = _saved_scrollpos_y; rubidium@8477: WP(w, vp_d).dest_scrollpos_x = _saved_scrollpos_x; rubidium@8477: WP(w, vp_d).dest_scrollpos_y = _saved_scrollpos_y; rubidium@8477: rubidium@8477: ViewPort *vp = w->viewport; smatz@8591: vp->zoom = min(_saved_scrollpos_zoom, ZOOM_LVL_MAX); rubidium@8477: vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); rubidium@8477: vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); rubidium@8477: rubidium@8477: DoZoomInOutWindow(ZOOM_NONE, w); // update button status rubidium@8477: MarkWholeScreenDirty(); rubidium@8477: rubidium@8477: /* Update coordinates of the signs. */ rubidium@8477: UpdateAllStationVirtCoord(); rubidium@8477: UpdateAllSignVirtCoords(); rubidium@8477: UpdateAllTownVirtCoords(); rubidium@8477: UpdateAllWaypointSigns(); rubidium@8477: rubidium@8477: /* Recalculate */ rubidium@8477: Group *g; rubidium@8477: FOR_ALL_GROUPS(g) { rubidium@8477: const Vehicle *v; rubidium@8477: FOR_ALL_VEHICLES(v) { rubidium@8477: if (!IsEngineCountable(v)) continue; rubidium@8477: rubidium@8477: if (v->group_id != g->index || v->type != g->vehicle_type || v->owner != g->owner) continue; rubidium@8477: rubidium@8477: g->num_engines[v->engine_type]++; rubidium@8477: } rubidium@8477: } rubidium@8477: rubidium@8477: /* Set up the engine count for all players */ rubidium@8477: Player *players[MAX_PLAYERS]; rubidium@8477: const Vehicle *v; rubidium@8477: belugas@8648: for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) { belugas@8648: players[i] = GetPlayer(i); belugas@8648: belugas@8648: /* For each player, verify (while loading a scenario) that the inauguration date is the current year and set it belugas@8648: * accordingly if it is not the case. No need to set it on players that are not been used already, belugas@8648: * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ belugas@8648: if (_file_to_saveload.filetype == FT_SCENARIO && players[i]->inaugurated_year != MIN_YEAR) belugas@8648: players[i]->inaugurated_year = _cur_year; belugas@8648: } rubidium@8477: rubidium@8477: FOR_ALL_VEHICLES(v) { rubidium@8477: if (!IsEngineCountable(v)) continue; rubidium@8477: players[v->owner]->num_engines[v->engine_type]++; rubidium@8477: } rubidium@8477: rubidium@8477: return true; rubidium@8477: } rubidium@8477: rubidium@6573: bool AfterLoadGame() truelight@0: { tron@5957: TileIndex map_size = MapSize(); celestar@2147: Player *p; truelight@988: belugas@6677: /* in version 2.1 of the savegame, town owner was unified. */ truelight@2685: if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner(); truelight@0: belugas@6677: /* from version 4.1 of the savegame, exclusive rights are stored at towns */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights(); truelight@193: belugas@6677: /* from version 4.2 of the savegame, currencies are in a different order */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies(); dominik@762: belugas@6677: /* from version 6.1 of the savegame, signs have an "owner" */ truelight@2685: if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner(); dominik@1165: truelight@831: /* In old version there seems to be a problem that water is owned by truelight@831: OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current truelight@2685: (4.3) version, so I just check when versions are older, and then truelight@831: walk through the whole map.. */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 3)) { tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5957: if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_PLAYERS) { tron@5957: SetTileOwner(t, OWNER_WATER); tron@5957: } tron@5957: } truelight@831: } truelight@831: peter1138@8754: if (CheckSavegameVersion(84)) { peter1138@8754: Player *p; peter1138@8754: FOR_ALL_PLAYERS(p) { peter1138@8754: p->name = CopyFromOldName(p->name_1); peter1138@8754: if (p->name != NULL) p->name_1 = STR_SV_UNNAMED; peter1138@8754: p->president_name = CopyFromOldName(p->president_name_1); peter1138@8754: if (p->president_name != NULL) p->president_name_1 = SPECSTR_PRESIDENT_NAME; peter1138@8754: } peter1138@8754: peter1138@8754: Station *st; peter1138@8754: FOR_ALL_STATIONS(st) { peter1138@8754: st->name = CopyFromOldName(st->string_id); peter1138@8754: if (st->name != NULL) st->string_id = STR_EMPTY; peter1138@8754: } peter1138@8754: peter1138@8754: Town *t; peter1138@8754: FOR_ALL_TOWNS(t) { peter1138@8754: t->name = CopyFromOldName(t->townnametype); peter1138@8754: if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name; peter1138@8754: } peter1138@8754: peter1138@8754: Waypoint *wp; peter1138@8754: FOR_ALL_WAYPOINTS(wp) { peter1138@8754: wp->name = CopyFromOldName(wp->string); peter1138@8754: wp->string = STR_EMPTY; peter1138@8754: } peter1138@8754: } peter1138@8754: belugas@6677: /* convert road side to my format. */ truelight@0: if (_opt.road_side) _opt.road_side = 1; truelight@0: Darkvater@5898: /* Check if all NewGRFs are present, we are very strict in MP mode */ maedhros@6555: GRFListCompatibility gcf_res = IsGoodGRFConfigList(); rubidium@7532: if (_networking && gcf_res != GLC_ALL_GOOD) { rubidium@7532: SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH); rubidium@7532: return false; rubidium@7532: } Darkvater@5898: Darkvater@5898: switch (gcf_res) { maedhros@6555: case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break; rubidium@8509: case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = (byte)-1; break; glx@5903: default: break; Darkvater@5898: } peter1138@5228: glx@5340: /* Update current year glx@5340: * must be done before loading sprites as some newgrfs check it */ glx@5340: SetDate(_date); glx@5340: belugas@6677: /* Load the sprites */ truelight@0: GfxLoadSprites(); peter1138@5155: LoadStringWidthTable(); truelight@0: peter1138@2814: /* Connect front and rear engines of multiheaded trains and converts peter1138@2814: * subtype to the new format */ peter1138@2814: if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew(); peter1138@2814: bjarni@2928: /* Connect front and rear engines of multiheaded trains */ bjarni@2928: ConnectMultiheadedTrains(); bjarni@2855: belugas@6677: /* reinit the landscape variables (landscape might have changed) */ truelight@0: InitializeLandscapeVariables(true); truelight@193: belugas@6677: /* Update all vehicles */ peter1138@8668: AfterLoadVehicles(true); truelight@1542: belugas@6677: /* Update all waypoints */ truelight@2685: if (CheckSavegameVersion(12)) FixOldWaypoints(); truelight@1542: belugas@6677: /* in version 2.2 of the savegame, we have new airports */ truelight@2685: if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft(); truelight@0: truelight@0: AfterLoadTown(); truelight@0: belugas@6677: /* make sure there is a town in the game */ tron@2639: if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, (uint)-1)) { rubidium@7532: SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO); truelight@0: return false; truelight@0: } truelight@0: belugas@6677: /* in version 4.1 of the savegame, is_active was introduced to determine belugas@6677: * if a player does exist, rather then checking name_1 */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 1)) CheckIsPlayerActive(); truelight@193: smatz@9009: /* The void tiles on the southern border used to belong to a wrong class (pre 4.3). smatz@9009: * This problem appears in savegame version 21 too, see r3455. But after loading the smatz@9009: * savegame and saving again, the buggy map array could be converted to new savegame smatz@9009: * version. It didn't show up before r12070. */ smatz@9009: if (CheckSavegameVersion(87)) UpdateVoidTiles(); dominik@929: belugas@6677: /* If Load Scenario / New (Scenario) Game is used, belugas@6677: * a player does not exist yet. So create one here. belugas@6677: * 1 exeption: network-games. Those can have 0 players glx@7070: * But this exeption is not true for non dedicated network_servers! */ glx@7070: if (!_players[0].is_active && (!_networking || (_networking && _network_server && !_network_dedicated))) truelight@139: DoStartupNewPlayer(false); truelight@0: rubidium@7768: if (CheckSavegameVersion(72)) { rubidium@7768: /* Locks/shiplifts in very old savegames had OWNER_WATER as owner */ rubidium@7768: for (TileIndex t = 0; t < MapSize(); t++) { rubidium@7768: switch (GetTileType(t)) { rubidium@7768: default: break; rubidium@7768: rubidium@7768: case MP_WATER: rubidium@7768: if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); rubidium@7768: break; rubidium@7768: rubidium@7768: case MP_STATION: { skidd13@8427: if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2); rubidium@7768: StationGfx gfx = GetStationGfx(t); rubidium@7768: StationType st; skidd13@8450: if ( IsInsideMM(gfx, 0, 8)) { // Railway station rubidium@7768: st = STATION_RAIL; rubidium@7768: SetStationGfx(t, gfx - 0); skidd13@8450: } else if (IsInsideMM(gfx, 8, 67)) { // Airport rubidium@7768: st = STATION_AIRPORT; rubidium@7768: SetStationGfx(t, gfx - 8); skidd13@8450: } else if (IsInsideMM(gfx, 67, 71)) { // Truck rubidium@7768: st = STATION_TRUCK; rubidium@7768: SetStationGfx(t, gfx - 67); skidd13@8450: } else if (IsInsideMM(gfx, 71, 75)) { // Bus rubidium@7768: st = STATION_BUS; rubidium@7768: SetStationGfx(t, gfx - 71); rubidium@7768: } else if (gfx == 75) { // Oil rig rubidium@7768: st = STATION_OILRIG; rubidium@7768: SetStationGfx(t, gfx - 75); skidd13@8450: } else if (IsInsideMM(gfx, 76, 82)) { // Dock rubidium@7768: st = STATION_DOCK; rubidium@7768: SetStationGfx(t, gfx - 76); rubidium@7768: } else if (gfx == 82) { // Buoy rubidium@7768: st = STATION_BUOY; rubidium@7768: SetStationGfx(t, gfx - 82); skidd13@8450: } else if (IsInsideMM(gfx, 83, 168)) { // Extended airport rubidium@7768: st = STATION_AIRPORT; rubidium@7768: SetStationGfx(t, gfx - 83 + 67 - 8); skidd13@8450: } else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck rubidium@7768: st = STATION_TRUCK; rubidium@7768: SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); skidd13@8450: } else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus rubidium@7768: st = STATION_BUS; rubidium@7768: SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); rubidium@7768: } else { rubidium@7768: return false; rubidium@7768: } rubidium@7768: SB(_m[t].m6, 3, 3, st); rubidium@7768: } break; rubidium@7768: } rubidium@7768: } rubidium@7768: } rubidium@7768: tron@6131: for (TileIndex t = 0; t < map_size; t++) { tron@6131: switch (GetTileType(t)) { tron@6419: case MP_STATION: { tron@6419: Station *st = GetStationByTile(t); tron@6419: tron@6419: st->rect.BeforeAddTile(t, StationRect::ADD_FORCE); tron@6419: tron@6131: switch (GetStationType(t)) { tron@6131: case STATION_TRUCK: tron@6131: case STATION_BUS: tron@6131: if (CheckSavegameVersion(6)) { tron@6419: /* From this version on there can be multiple road stops of the tron@6419: * same type per station. Convert the existing stops to the new tron@6419: * internal data structure. */ tron@6131: RoadStop *rs = new RoadStop(t); tron@6131: if (rs == NULL) error("Too many road stops in savegame"); tron@6130: tron@6131: RoadStop **head = tron@6131: IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; tron@6131: *head = rs; tron@6131: } tron@6131: break; tron@6131: tron@6135: case STATION_OILRIG: { tron@6135: /* Very old savegames sometimes have phantom oil rigs, i.e. tron@6135: * an oil rig which got shut down, but not completly removed from tron@6135: * the map tron@6135: */ glx@8236: TileIndex t1 = TILE_ADDXY(t, 0, 1); tron@6137: if (IsTileType(t1, MP_INDUSTRY) && glx@8236: GetIndustryGfx(t1) == GFX_OILRIG_1) { tron@6137: /* The internal encoding of oil rigs was changed twice. tron@6137: * It was 3 (till 2.2) and later 5 (till 5.1). tron@6137: * Setting it unconditionally does not hurt. tron@6137: */ tron@6137: GetStationByTile(t)->airport_type = AT_OILRIG; tron@6137: } else { tron@6135: DeleteOilRig(t); tron@6135: } tron@6135: break; tron@6135: } tron@6135: tron@6131: default: break; tron@6131: } tron@6131: break; tron@6419: } tron@6131: tron@6131: default: break; tron@6130: } tron@6130: } tron@6130: truelight@2685: /* In version 6.1 we put the town index in the map-array. To do this, we need truelight@2685: * to use m2 (16bit big), so we need to clean m2, and that is where this is truelight@2685: * all about ;) */ truelight@2685: if (CheckSavegameVersionOldStyle(6, 1)) { tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5957: switch (GetTileType(t)) { tron@3983: case MP_HOUSE: tron@5957: _m[t].m4 = _m[t].m2; tron@5957: SetTownIndex(t, CalcClosestTownFromTile(t, (uint)-1)->index); tron@3983: break; tron@3983: rubidium@7866: case MP_ROAD: tron@5957: _m[t].m4 |= (_m[t].m2 << 4); tron@5957: if (IsTileOwner(t, OWNER_TOWN)) { tron@5957: SetTownIndex(t, CalcClosestTownFromTile(t, (uint)-1)->index); tron@3983: } else { tron@5957: SetTownIndex(t, 0); tron@3983: } tron@3983: break; tron@3983: tron@3983: default: break; celestar@1264: } tron@5957: } celestar@1264: } celestar@1264: truelight@2685: /* From version 9.0, we update the max passengers of a town (was sometimes negative truelight@2685: * before that. */ truelight@2685: if (CheckSavegameVersion(9)) { celestar@1377: Town *t; tron@2639: FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); celestar@1377: } celestar@1377: truelight@2685: /* From version 16.0, we included autorenew on engines, which are now saved, but truelight@2685: * of course, we do need to initialize them for older savegames. */ truelight@2685: if (CheckSavegameVersion(16)) { bjarni@2293: FOR_ALL_PLAYERS(p) { rubidium@5564: p->engine_renew_list = NULL; rubidium@5564: p->engine_renew = false; bjarni@2293: p->engine_renew_months = -6; rubidium@5564: p->engine_renew_money = 100000; bjarni@2293: } rubidium@5564: rubidium@5564: /* When loading a game, _local_player is not yet set to the correct value. rubidium@5564: * However, in a dedicated server we are a spectator, so nothing needs to rubidium@5564: * happen. In case we are not a dedicated server, the local player always rubidium@5564: * becomes player 0, unless we are in the scenario editor where all the rubidium@5564: * players are 'invalid'. rubidium@5564: */ rubidium@5838: if (!_network_dedicated && IsValidPlayer(PLAYER_FIRST)) { rubidium@5838: p = GetPlayer(PLAYER_FIRST); rubidium@5564: p->engine_renew = _patches.autorenew; bjarni@2322: p->engine_renew_months = _patches.autorenew_months; rubidium@5564: p->engine_renew_money = _patches.autorenew_money; bjarni@2322: } bjarni@2293: } bjarni@2293: rubidium@7157: if (CheckSavegameVersion(48)) { rubidium@7157: for (TileIndex t = 0; t < map_size; t++) { rubidium@7157: switch (GetTileType(t)) { rubidium@7157: case MP_RAILWAY: rubidium@7157: if (IsPlainRailTile(t)) { rubidium@7157: /* Swap ground type and signal type for plain rail tiles, so the rubidium@7157: * ground type uses the same bits as for depots and waypoints. */ rubidium@7157: uint tmp = GB(_m[t].m4, 0, 4); rubidium@7157: SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); rubidium@7157: SB(_m[t].m2, 0, 4, tmp); skidd13@8424: } else if (HasBit(_m[t].m5, 2)) { rubidium@7157: /* Split waypoint and depot rail type and remove the subtype. */ skidd13@8425: ClrBit(_m[t].m5, 2); skidd13@8425: ClrBit(_m[t].m5, 6); rubidium@7157: } rubidium@7157: break; rubidium@7157: rubidium@7866: case MP_ROAD: rubidium@7157: /* Swap m3 and m4, so the track type for rail crossings is the rubidium@7157: * same as for normal rail. */ rubidium@7157: Swap(_m[t].m3, _m[t].m4); rubidium@7157: break; rubidium@7157: rubidium@7157: default: break; rubidium@7157: } rubidium@7157: } rubidium@7157: } rubidium@7157: rubidium@7157: if (CheckSavegameVersion(61)) { rubidium@7157: /* Added the RoadType */ rubidium@7234: bool old_bridge = CheckSavegameVersion(42); rubidium@7157: for (TileIndex t = 0; t < map_size; t++) { rubidium@7157: switch(GetTileType(t)) { rubidium@7866: case MP_ROAD: rubidium@7157: SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); rubidium@7157: switch (GetRoadTileType(t)) { rubidium@7157: default: NOT_REACHED(); rubidium@7157: case ROAD_TILE_NORMAL: rubidium@7157: SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); rubidium@7157: SB(_m[t].m4, 4, 4, 0); rubidium@7157: SB(_m[t].m6, 2, 4, 0); rubidium@7157: break; rubidium@7157: case ROAD_TILE_CROSSING: rubidium@7157: SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); rubidium@7157: break; rubidium@7157: case ROAD_TILE_DEPOT: break; rubidium@7157: } rubidium@7157: SetRoadTypes(t, ROADTYPES_ROAD); rubidium@7157: break; rubidium@7157: rubidium@7157: case MP_STATION: rubidium@7157: if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); rubidium@7157: break; rubidium@7157: rubidium@7157: case MP_TUNNELBRIDGE: rubidium@7234: /* Middle part of "old" bridges */ smatz@8886: if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; smatz@8886: if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { rubidium@7157: SetRoadTypes(t, ROADTYPES_ROAD); rubidium@7157: } rubidium@7157: break; rubidium@7157: rubidium@7157: default: break; rubidium@7157: } rubidium@7157: } rubidium@7157: } rubidium@7157: celestar@5573: if (CheckSavegameVersion(42)) { celestar@5573: Vehicle* v; celestar@5573: tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5957: if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t); tron@5957: if (IsBridgeTile(t)) { skidd13@8424: if (HasBit(_m[t].m5, 6)) { // middle part tron@5957: Axis axis = (Axis)GB(_m[t].m5, 0, 1); celestar@5573: skidd13@8424: if (HasBit(_m[t].m5, 5)) { // transport route under bridge? tron@5957: if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { celestar@5573: MakeRailNormal( tron@5957: t, tron@5957: GetTileOwner(t), celestar@5573: axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, tron@5957: GetRailType(t) celestar@5573: ); celestar@5573: } else { tron@5957: TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, (uint)-1)->index : 0; celestar@5573: celestar@5573: MakeRoadNormal( tron@5957: t, celestar@5573: axis == AXIS_X ? ROAD_Y : ROAD_X, rubidium@7157: ROADTYPES_ROAD, rubidium@7157: town, rubidium@7157: GetTileOwner(t), OWNER_NONE, OWNER_NONE celestar@5573: ); celestar@5573: } celestar@5573: } else { tron@5957: if (GB(_m[t].m5, 3, 2) == 0) { tron@5957: MakeClear(t, CLEAR_GRASS, 3); celestar@5573: } else { frosch@8900: if (GetTileSlope(t, NULL) != SLOPE_FLAT) { frosch@8900: MakeShore(t); frosch@8900: } else { frosch@8900: if (GetTileOwner(t) == OWNER_WATER) { frosch@8900: MakeWater(t); frosch@8900: } else { frosch@8900: MakeCanal(t, GetTileOwner(t), Random()); frosch@8900: } frosch@8900: } celestar@5573: } celestar@5573: } tron@5957: SetBridgeMiddle(t, axis); celestar@5573: } else { // ramp tron@5957: Axis axis = (Axis)GB(_m[t].m5, 0, 1); tron@5957: uint north_south = GB(_m[t].m5, 5, 1); celestar@5573: DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); tron@5957: TransportType type = (TransportType)GB(_m[t].m5, 1, 2); celestar@5573: tron@5957: _m[t].m5 = 1 << 7 | type << 2 | dir; celestar@5573: } celestar@5573: } celestar@5573: } celestar@5573: celestar@5573: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue; celestar@5573: if (IsBridgeTile(v->tile)) { smatz@8579: DiagDirection dir = GetTunnelBridgeDirection(v->tile); celestar@5573: celestar@5573: if (dir != DirToDiagDir(v->direction)) continue; celestar@5573: switch (dir) { celestar@5573: default: NOT_REACHED(); celestar@5573: case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; celestar@5573: case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; celestar@5573: case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; celestar@5573: case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; celestar@5573: } celestar@5573: } else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) { celestar@5573: v->tile = GetNorthernBridgeEnd(v->tile); celestar@5573: } else { celestar@5573: continue; celestar@5573: } rubidium@6585: if (v->type == VEH_TRAIN) { rubidium@5838: v->u.rail.track = TRACK_BIT_WORMHOLE; celestar@5573: } else { rubidium@6326: v->u.road.state = RVSB_WORMHOLE; celestar@5573: } celestar@5573: } celestar@5573: } celestar@5573: celestar@3355: /* Elrails got added in rev 24 */ celestar@3355: if (CheckSavegameVersion(24)) { belugas@4171: Vehicle *v; tron@3656: RailType min_rail = RAILTYPE_ELECTRIC; celestar@3355: celestar@3355: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type == VEH_TRAIN) { tron@6074: RailType rt = RailVehInfo(v->engine_type)->railtype; celestar@3355: celestar@3355: v->u.rail.railtype = rt; tron@3656: if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL; celestar@3355: } celestar@3355: } celestar@3355: celestar@3355: /* .. so we convert the entire map from normal to elrail (so maintain "fairness") */ tron@5957: for (TileIndex t = 0; t < map_size; t++) { celestar@3355: switch (GetTileType(t)) { celestar@3355: case MP_RAILWAY: tron@3656: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); celestar@3355: break; celestar@3355: rubidium@7866: case MP_ROAD: tron@3656: if (IsLevelCrossing(t)) { rubidium@6498: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); tron@3656: } celestar@3355: break; celestar@3355: celestar@3355: case MP_STATION: tron@4077: if (IsRailwayStation(t)) { tron@3656: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); tron@3656: } celestar@3355: break; celestar@3355: celestar@3355: case MP_TUNNELBRIDGE: smatz@8584: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { smatz@8584: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); celestar@3355: } celestar@3355: break; celestar@3355: celestar@3355: default: celestar@3355: break; celestar@3355: } celestar@3355: } celestar@3355: celestar@3355: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v); celestar@3355: } celestar@3355: celestar@3355: } celestar@3355: tron@2805: /* In version 16.1 of the savegame a player can decide if trains, which get tron@2805: * replaced, shall keep their old length. In all prior versions, just default tron@2805: * to false */ truelight@2685: if (CheckSavegameVersionOldStyle(16, 1)) { tron@4077: FOR_ALL_PLAYERS(p) p->renew_keep_length = false; bjarni@2617: } bjarni@2617: peter1138@2670: /* In version 17, ground type is moved from m2 to m4 for depots and peter1138@2670: * waypoints to make way for storing the index in m2. The custom graphics peter1138@2670: * id which was stored in m4 is now saved as a grf/id reference in the peter1138@2670: * waypoint struct. */ truelight@2685: if (CheckSavegameVersion(17)) { peter1138@2670: Waypoint *wp; peter1138@2670: peter1138@2670: FOR_ALL_WAYPOINTS(wp) { truelight@4346: if (wp->deleted == 0) { belugas@3676: const StationSpec *statspec = NULL; peter1138@2670: skidd13@8424: if (HasBit(_m[wp->xy].m3, 4)) belugas@3676: statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); peter1138@2670: belugas@3676: if (statspec != NULL) { peter1138@2670: wp->stat_id = _m[wp->xy].m4 + 1; peter1138@6947: wp->grfid = statspec->grffile->grfid; belugas@3676: wp->localidx = statspec->localidx; peter1138@2670: } else { belugas@6677: /* No custom graphics set, so set to default. */ peter1138@2670: wp->stat_id = 0; peter1138@2670: wp->grfid = 0; peter1138@2670: wp->localidx = 0; peter1138@2670: } peter1138@2670: belugas@6677: /* Move ground type bits from m2 to m4. */ peter1138@2670: _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); belugas@6677: /* Store waypoint index in the tile. */ peter1138@2670: _m[wp->xy].m2 = wp->index; peter1138@2670: } peter1138@2670: } peter1138@2670: } else { peter1138@2670: /* As of version 17, we recalculate the custom graphic ID of waypoints peter1138@2670: * from the GRF ID / station index. */ Darkvater@5350: AfterLoadWaypoints(); peter1138@2670: } peter1138@2670: Darkvater@2916: /* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making Darkvater@2916: * room for PBS. Now in version 21 move it back :P. */ Darkvater@2916: if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) { tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5958: switch (GetTileType(t)) { tron@5958: case MP_RAILWAY: tron@5958: if (HasSignals(t)) { belugas@6677: /* convert PBS signals to combo-signals */ skidd13@8424: if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO); Darkvater@2916: belugas@6677: /* move the signal variant back */ skidd13@8424: SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); skidd13@8425: ClrBit(_m[t].m2, 3); tron@5958: } tron@5958: belugas@6677: /* Clear PBS reservation on track */ tron@5958: if (!IsTileDepotType(t, TRANSPORT_RAIL)) { tron@5958: SB(_m[t].m4, 4, 4, 0); tron@5958: } else { skidd13@8425: ClrBit(_m[t].m3, 6); tron@5958: } tron@5958: break; tron@5958: rubidium@7866: case MP_ROAD: /* Clear PBS reservation on crossing */ skidd13@8425: if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0); tron@5958: break; tron@5958: belugas@6677: case MP_STATION: /* Clear PBS reservation on station */ skidd13@8425: ClrBit(_m[t].m3, 6); tron@5958: break; Darkvater@2916: tron@5958: default: break; tron@5958: } tron@5957: } Darkvater@2916: } Darkvater@2916: Darkvater@3121: if (CheckSavegameVersion(22)) UpdatePatches(); Darkvater@3121: celestar@3431: if (CheckSavegameVersion(25)) { celestar@3431: Vehicle *v; celestar@3431: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type == VEH_ROAD) { celestar@3431: v->vehstatus &= ~0x40; celestar@3431: v->u.road.slot = NULL; celestar@3431: v->u.road.slot_age = 0; celestar@3431: } celestar@3431: } rubidium@5928: } else { rubidium@5928: Vehicle *v; rubidium@5928: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++; rubidium@5928: } celestar@3431: } celestar@3431: celestar@3580: if (CheckSavegameVersion(26)) { celestar@3580: Station *st; celestar@3580: FOR_ALL_STATIONS(st) { rubidium@6585: st->last_vehicle_type = VEH_INVALID; celestar@3580: } celestar@3580: } celestar@3580: KUDr@3900: YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); KUDr@3900: peter1138@4603: if (CheckSavegameVersion(34)) FOR_ALL_PLAYERS(p) ResetPlayerLivery(p); peter1138@4603: rubidium@7181: FOR_ALL_PLAYERS(p) { rubidium@7181: p->avail_railtypes = GetPlayerRailtypes(p->index); rubidium@7181: p->avail_roadtypes = GetPlayerRoadtypes(p->index); rubidium@7181: } celestar@2147: peter1138@3765: if (!CheckSavegameVersion(27)) AfterLoadStations(); peter1138@3765: rubidium@4326: /* Time starts at 0 instead of 1920. rubidium@4326: * Account for this in older games by adding an offset */ rubidium@4326: if (CheckSavegameVersion(31)) { rubidium@4326: Station *st; rubidium@4326: Waypoint *wp; rubidium@4326: Engine *e; rubidium@4326: Player *player; rubidium@4326: Industry *i; rubidium@4326: Vehicle *v; rubidium@4326: rubidium@4326: _date += DAYS_TILL_ORIGINAL_BASE_YEAR; truelight@4383: _cur_year += ORIGINAL_BASE_YEAR; rubidium@4326: rubidium@4326: FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_PLAYERS(player) player->inaugurated_year += ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_INDUSTRIES(i) i->last_prod_year += ORIGINAL_BASE_YEAR; rubidium@4326: rubidium@4326: FOR_ALL_VEHICLES(v) { rubidium@4326: v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: v->build_year += ORIGINAL_BASE_YEAR; rubidium@4326: } rubidium@4326: } rubidium@4326: truelight@4328: /* From 32 on we save the industry who made the farmland. truelight@4328: * To give this prettyness to old savegames, we remove all farmfields and truelight@4328: * plant new ones. */ truelight@4328: if (CheckSavegameVersion(32)) { truelight@4328: Industry *i; truelight@4328: tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5957: if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) { tron@5957: MakeClear(t, CLEAR_GRASS, 3); truelight@4328: } tron@5957: } truelight@4328: truelight@4328: FOR_ALL_INDUSTRIES(i) { truelight@4328: uint j; truelight@4328: belugas@7253: if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { truelight@4328: for (j = 0; j != 50; j++) PlantRandomFarmField(i); truelight@4328: } truelight@4328: } truelight@4328: } truelight@4328: bjarni@4712: /* Setting no refit flags to all orders in savegames from before refit in orders were added */ bjarni@4712: if (CheckSavegameVersion(36)) { bjarni@4712: Order *order; bjarni@4712: Vehicle *v; bjarni@4712: bjarni@4712: FOR_ALL_ORDERS(order) { bjarni@4712: order->refit_cargo = CT_NO_REFIT; bjarni@4712: order->refit_subtype = CT_NO_REFIT; bjarni@4712: } bjarni@4712: bjarni@4712: FOR_ALL_VEHICLES(v) { bjarni@4712: v->current_order.refit_cargo = CT_NO_REFIT; bjarni@4712: v->current_order.refit_subtype = CT_NO_REFIT; bjarni@4712: } bjarni@4712: } bjarni@4712: Darkvater@5314: /* from version 38 we have optional elrails, since we cannot know the Darkvater@5314: * preference of a user, let elrails enabled; it can be disabled manually */ tron@6099: if (CheckSavegameVersion(38)) _patches.disable_elrails = false; tron@6099: /* do the same as when elrails were enabled/disabled manually just now */ tron@6099: SettingsDisableElrail(_patches.disable_elrails); rubidium@7560: SetDefaultRailGui(); KUDr@5116: maedhros@6659: /* From version 53, the map array was changed for house tiles to allow maedhros@6658: * space for newhouses grf features. A new byte, m7, was also added. */ maedhros@6659: if (CheckSavegameVersion(53)) { maedhros@6658: for (TileIndex t = 0; t < map_size; t++) { maedhros@6658: if (IsTileType(t, MP_HOUSE)) { maedhros@6658: if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { maedhros@6658: /* Move the construction stage from m3[7..6] to m5[5..4]. maedhros@6658: * The construction counter does not have to move. */ maedhros@6658: SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2)); maedhros@6658: SB(_m[t].m3, 6, 2, 0); maedhros@6658: maedhros@6658: /* The "house is completed" bit is now in m6[2]. */ maedhros@6658: SetHouseCompleted(t, false); maedhros@6658: } else { maedhros@6658: /* The "lift has destination" bit has been moved from maedhros@6658: * m5[7] to m7[0]. */ skidd13@8424: SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7)); skidd13@8425: ClrBit(_m[t].m5, 7); maedhros@6658: maedhros@6658: /* The "lift is moving" bit has been removed, as it does maedhros@6658: * the same job as the "lift has destination" bit. */ skidd13@8425: ClrBit(_m[t].m1, 7); maedhros@6658: maedhros@6658: /* The position of the lift goes from m1[7..0] to m6[7..2], maedhros@6658: * making m1 totally free, now. The lift position does not maedhros@6658: * have to be a full byte since the maximum value is 36. */ maedhros@6658: SetLiftPosition(t, GB(_m[t].m1, 0, 6 )); maedhros@6658: maedhros@6658: _m[t].m1 = 0; maedhros@6658: _m[t].m3 = 0; maedhros@6658: SetHouseCompleted(t, true); maedhros@6658: } maedhros@6658: } maedhros@6658: } maedhros@6658: } maedhros@6658: glx@8787: /* Check that house ids are still valid. */ glx@8787: CheckHouseIDs(); maedhros@6658: rubidium@5687: if (CheckSavegameVersion(43)) { tron@5957: for (TileIndex t = 0; t < map_size; t++) { tron@5957: if (IsTileType(t, MP_INDUSTRY)) { tron@5957: switch (GetIndustryGfx(t)) { rubidium@5687: case GFX_POWERPLANT_SPARKS: tron@5957: SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5)); rubidium@5687: break; rubidium@5687: rubidium@5687: case GFX_OILWELL_ANIMATED_1: rubidium@5687: case GFX_OILWELL_ANIMATED_2: rubidium@5687: case GFX_OILWELL_ANIMATED_3: tron@5957: SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2)); rubidium@5687: break; rubidium@5687: rubidium@5687: case GFX_COAL_MINE_TOWER_ANIMATED: rubidium@5687: case GFX_COPPER_MINE_TOWER_ANIMATED: rubidium@5687: case GFX_GOLD_MINE_TOWER_ANIMATED: tron@5957: SetIndustryAnimationState(t, _m[t].m1); rubidium@5687: break; rubidium@5687: rubidium@5687: default: /* No animation states to change */ rubidium@5687: break; rubidium@5687: } rubidium@5687: } tron@5957: } rubidium@5687: } rubidium@5687: celestar@5934: if (CheckSavegameVersion(44)) { celestar@5934: Vehicle *v; celestar@5934: /* If we remove a station while cargo from it is still enroute, payment calculation will assume rubidium@7506: * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy celestar@5934: * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded rubidium@7506: * where this situation exists, the cargo-source information is lost. in this case, we set the source celestar@5934: * to the current tile of the vehicle to prevent excessive profits celestar@5934: */ celestar@5934: FOR_ALL_VEHICLES(v) { rubidium@7506: const CargoList::List *packets = v->cargo.Packets(); rubidium@7506: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7506: CargoPacket *cp = *it; rubidium@7506: cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile; rubidium@7506: cp->loaded_at_xy = cp->source_xy; rubidium@7506: } rubidium@7506: v->cargo.InvalidateCache(); celestar@5934: } peter1138@6630: peter1138@6630: /* Store position of the station where the goods come from, so there peter1138@6630: * are no very high payments when stations get removed. However, if the peter1138@6630: * station where the goods came from is already removed, the source peter1138@6630: * information is lost. In that case we set it to the position of this peter1138@6630: * station */ peter1138@6630: Station *st; peter1138@6630: FOR_ALL_STATIONS(st) { peter1138@6630: for (CargoID c = 0; c < NUM_CARGO; c++) { peter1138@6630: GoodsEntry *ge = &st->goods[c]; peter1138@6630: rubidium@7506: const CargoList::List *packets = ge->cargo.Packets(); rubidium@7506: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7506: CargoPacket *cp = *it; rubidium@7506: cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy; rubidium@7506: cp->loaded_at_xy = cp->source_xy; peter1138@6630: } peter1138@6630: } peter1138@6630: } celestar@5934: } celestar@5934: maedhros@6139: if (CheckSavegameVersion(45)) { maedhros@6139: Vehicle *v; maedhros@6139: /* Originally just the fact that some cargo had been paid for was maedhros@6139: * stored to stop people cheating and cashing in several times. This maedhros@6139: * wasn't enough though as it was cleared when the vehicle started maedhros@6139: * loading again, even if it didn't actually load anything, so now the maedhros@6139: * amount of cargo that has been paid for is stored. */ maedhros@6139: FOR_ALL_VEHICLES(v) { rubidium@7506: const CargoList::List *packets = v->cargo.Packets(); rubidium@7506: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7506: CargoPacket *cp = *it; skidd13@8424: cp->paid_for = HasBit(v->vehicle_flags, 2); maedhros@6139: } skidd13@8425: ClrBit(v->vehicle_flags, 2); rubidium@7506: v->cargo.InvalidateCache(); maedhros@6139: } maedhros@6139: } maedhros@6139: rubidium@6312: /* Buoys do now store the owner of the previous water tile, which can never rubidium@6312: * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ rubidium@6312: if (CheckSavegameVersion(46)) { rubidium@6312: Station *st; rubidium@6312: FOR_ALL_STATIONS(st) { rubidium@8284: if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); rubidium@6312: } rubidium@6312: } rubidium@6312: celestar@6519: if (CheckSavegameVersion(50)) { celestar@6519: Vehicle *v; celestar@6519: /* Aircraft units changed from 8 mph to 1 km/h */ celestar@6519: FOR_ALL_VEHICLES(v) { rubidium@6585: if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) { celestar@6519: const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); celestar@6519: v->cur_speed *= 129; celestar@6519: v->cur_speed /= 10; celestar@6519: v->max_speed = avi->max_speed; celestar@6519: v->acceleration = avi->acceleration; celestar@6519: } celestar@6519: } celestar@6519: } celestar@6519: rubidium@6516: if (CheckSavegameVersion(49)) FOR_ALL_PLAYERS(p) p->face = ConvertFromOldPlayerFace(p->face); rubidium@6516: truelight@6583: if (CheckSavegameVersion(52)) { truelight@6583: for (TileIndex t = 0; t < map_size; t++) { truelight@6583: if (IsStatueTile(t)) { truelight@6583: _m[t].m2 = CalcClosestTownFromTile(t, (uint)-1)->index; truelight@6583: } truelight@6583: } truelight@6583: } truelight@6583: maedhros@6982: /* A patch option containing the proportion of towns that grow twice as maedhros@6982: * fast was added in version 54. From version 56 this is now saved in the maedhros@6982: * town as cities can be built specifically in the scenario editor. */ maedhros@6982: if (CheckSavegameVersion(56)) { maedhros@6982: Town *t; maedhros@6982: maedhros@6982: FOR_ALL_TOWNS(t) { maedhros@6982: if (_patches.larger_towns != 0 && (t->index % _patches.larger_towns) == 0) { maedhros@6982: t->larger_town = true; maedhros@6982: } maedhros@6982: } maedhros@6982: } maedhros@6982: rubidium@6996: if (CheckSavegameVersion(57)) { rubidium@6996: Vehicle *v; rubidium@6996: /* Added a FIFO queue of vehicles loading at stations */ rubidium@6996: FOR_ALL_VEHICLES(v) { rubidium@6996: if ((v->type != VEH_TRAIN || IsFrontEngine(v)) && // for all locs rubidium@6996: !(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed rubidium@6996: v->current_order.type == OT_LOADING) { // loading rubidium@6996: GetStation(v->last_station_visited)->loading_vehicles.push_back(v); rubidium@7115: rubidium@7115: /* The loading finished flag is *only* set when actually completely rubidium@7115: * finished. Because the vehicle is loading, it is not finished. */ skidd13@8425: ClrBit(v->vehicle_flags, VF_LOADING_FINISHED); rubidium@6996: } rubidium@6996: } rubidium@7971: } else if (CheckSavegameVersion(59)) { rubidium@7971: /* For some reason non-loading vehicles could be in the station's loading vehicle list */ rubidium@7971: rubidium@7971: Station *st; rubidium@7971: FOR_ALL_STATIONS(st) { rubidium@7971: std::list::iterator iter; rubidium@7971: for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) { rubidium@7971: Vehicle *v = *iter; rubidium@7971: iter++; rubidium@7971: if (v->current_order.type != OT_LOADING) st->loading_vehicles.remove(v); rubidium@7971: } rubidium@7971: } rubidium@6996: } rubidium@6996: belugas@7056: if (CheckSavegameVersion(58)) { belugas@7056: /* patch difficulty number_industries other then zero get bumped to +1 belugas@7056: * since a new option (very low at position1) has been added */ belugas@7056: if (_opt.diff.number_industries > 0) { belugas@7056: _opt.diff.number_industries++; belugas@7056: } belugas@7056: belugas@7056: /* Same goes for number of towns, although no test is needed, just an increment */ belugas@7056: _opt.diff.number_towns++; belugas@7056: } belugas@7056: glx@7266: if (CheckSavegameVersion(64)) { glx@7266: /* copy the signal type/variant and move signal states bits */ glx@7266: for (TileIndex t = 0; t < map_size; t++) { glx@7266: if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) { glx@7266: SetSignalStates(t, GB(_m[t].m2, 4, 4)); glx@7266: SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X)); glx@7266: SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X)); skidd13@8425: ClrBit(_m[t].m2, 7); glx@7266: } glx@7266: } glx@7266: } glx@7266: rubidium@7508: if (CheckSavegameVersion(69)) { rubidium@7508: /* In some old savegames a bit was cleared when it should not be cleared */ rubidium@7508: Vehicle *v; rubidium@7508: FOR_ALL_VEHICLES(v) { rubidium@7508: if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) { skidd13@8427: SetBit(v->u.road.state, RVS_IS_STOPPING); rubidium@7508: } rubidium@7508: } rubidium@7508: } rubidium@7508: rubidium@7682: if (CheckSavegameVersion(70)) { rubidium@7682: /* Added variables to support newindustries */ rubidium@7682: Industry *i; rubidium@7682: FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE; rubidium@7682: } rubidium@7682: rubidium@8235: /* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported. rubidium@8235: Replace the owner for those by OWNER_NONE. */ rubidium@8235: if (CheckSavegameVersion(82)) { rubidium@8235: for (TileIndex t = 0; t < map_size; t++) { rubidium@8235: if (IsTileType(t, MP_WATER) && rubidium@8235: GetWaterTileType(t) == WATER_TILE_CLEAR && rubidium@8235: GetTileOwner(t) == OWNER_WATER && rubidium@8235: TileHeight(t) != 0) { rubidium@8235: SetTileOwner(t, OWNER_NONE); rubidium@8235: } rubidium@8235: } rubidium@8235: } rubidium@8235: rubidium@8525: /* rubidium@8525: * Add the 'previous' owner to the ship depots so we can reset it with rubidium@8525: * the correct values when it gets destroyed. This prevents that rubidium@8525: * someone can remove canals owned by somebody else and it prevents rubidium@8525: * making floods using the removal of ship depots. rubidium@8525: */ rubidium@8525: if (CheckSavegameVersion(83)) { rubidium@8525: for (TileIndex t = 0; t < map_size; t++) { rubidium@8525: if (IsTileType(t, MP_WATER) && IsShipDepot(t)) { rubidium@8525: _m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE; rubidium@8525: } rubidium@8525: } rubidium@8525: } rubidium@8525: rubidium@8011: if (CheckSavegameVersion(74)) { rubidium@8011: Station *st; rubidium@8011: FOR_ALL_STATIONS(st) { rubidium@8011: for (CargoID c = 0; c < NUM_CARGO; c++) { rubidium@8011: st->goods[c].last_speed = 0; skidd13@8427: if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP); rubidium@8011: } rubidium@8011: } rubidium@8011: } rubidium@8011: glx@8141: if (CheckSavegameVersion(78)) { glx@8141: Industry *i; glx@8141: uint j; glx@8141: FOR_ALL_INDUSTRIES(i) { glx@8141: const IndustrySpec *indsp = GetIndustrySpec(i->type); glx@8141: for (j = 0; j < lengthof(i->produced_cargo); j++) { glx@8141: i->produced_cargo[j] = indsp->produced_cargo[j]; glx@8141: } glx@8141: for (j = 0; j < lengthof(i->accepts_cargo); j++) { glx@8141: i->accepts_cargo[j] = indsp->accepts_cargo[j]; glx@8141: } glx@8141: } glx@8141: } rubidium@7139: truelight@8206: /* Before version 81, the density of grass was always stored as zero, and truelight@8206: * grassy trees were always drawn fully grassy. Furthermore, trees on rough truelight@8206: * land used to have zero density, now they have full density. Therefore, truelight@8206: * make all grassy/rough land trees have a density of 3. */ truelight@8206: if (CheckSavegameVersion(81)) { truelight@8206: for (TileIndex t = 0; t < map_size; t++) { truelight@8206: if (GetTileType(t) == MP_TREES) { truelight@8206: TreeGround groundType = GetTreeGround(t); truelight@8206: if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3); truelight@8206: } truelight@8206: } truelight@8206: } truelight@8206: glx@8553: if (CheckSavegameVersion(84)) { smatz@8651: /* Update go to buoy orders because they are just waypoints */ glx@8553: Order *order; glx@8553: FOR_ALL_ORDERS(order) { glx@8553: if (order->type == OT_GOTO_STATION && GetStation(order->dest)->IsBuoy()) { glx@8553: order->flags = 0; glx@8553: } glx@8553: } smatz@8651: smatz@8651: /* Set all share owners to PLAYER_SPECTATOR for smatz@8651: * 1) all inactive players smatz@8651: * (when inactive players were stored in the savegame - TTD, TTDP and some smatz@8651: * *really* old revisions of OTTD; else it is already set in InitializePlayers()) smatz@8651: * 2) shares that are owned by inactive players or self smatz@8651: * (caused by cheating players in earlier revisions) */ smatz@8651: Player *p; smatz@8651: FOR_ALL_PLAYERS(p) { smatz@8651: if (!p->is_active) { smatz@8651: for (uint i = 0; i < 4; i++) { p->share_owners[i] = PLAYER_SPECTATOR; } smatz@8651: } else { smatz@8651: for (uint i = 0; i < 4; i++) { smatz@8651: PlayerID o = p->share_owners[i]; smatz@8651: if (o == PLAYER_SPECTATOR) continue; smatz@8651: if (!IsValidPlayer(o) || o == p->index || !GetPlayer(o)->is_active) p->share_owners[i] = PLAYER_SPECTATOR; smatz@8651: } smatz@8651: } smatz@8651: } glx@8553: } glx@8553: smatz@8838: if (CheckSavegameVersion(86)) { smatz@8838: for (TileIndex t = 0; t < map_size; t++) { peter1138@8967: /* Now all crossings should be in correct state */ smatz@8840: if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false); peter1138@8967: peter1138@8967: /* Move river flag and update canals to use water class */ peter1138@8967: if (IsTileType(t, MP_WATER)) { peter1138@8967: if (_m[t].m5 == 2) { peter1138@8967: MakeRiver(t, Random()); peter1138@8967: } else { frosch@8991: if (IsWater(t)) { frosch@8991: Owner o = GetTileOwner(t); frosch@8991: if (o == OWNER_WATER) { frosch@8991: MakeWater(t); frosch@8991: } else { frosch@8991: MakeCanal(t, o, Random()); frosch@8991: } frosch@8991: } else if (IsShipDepot(t)) { frosch@8991: Owner o = (Owner)_m[t].m4; // Original water owner frosch@8991: SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL); peter1138@8967: } peter1138@8967: } peter1138@8967: } peter1138@8967: } peter1138@8967: peter1138@8967: /* Update locks, depots, docks and buoys to have a water class based peter1138@8967: * on its neighbouring tiles. Done after river and canal updates to peter1138@8967: * ensure neighbours are correct. */ peter1138@8967: for (TileIndex t = 0; t < map_size; t++) { peter1138@8967: if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue; peter1138@8967: frosch@8991: if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t); peter1138@8967: if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t); smatz@8838: } smatz@8838: } smatz@8838: rubidium@8477: return InitializeWindowsAndCaches(); truelight@0: } Darkvater@5352: Darkvater@5352: /** Reload all NewGRF files during a running game. This is a cut-down Darkvater@5352: * version of AfterLoadGame(). Darkvater@5352: * XXX - We need to reset the vehicle position hash because with a non-empty Darkvater@5352: * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles() Darkvater@5352: * to recalculate vehicle data as some NewGRF vehicle sets could have been Darkvater@5352: * removed or added and changed statistics */ rubidium@6573: void ReloadNewGRFData() Darkvater@5352: { Darkvater@5352: /* reload grf data */ Darkvater@5352: GfxLoadSprites(); Darkvater@5352: LoadStringWidthTable(); Darkvater@5352: /* reload vehicles */ Darkvater@5352: ResetVehiclePosHash(); peter1138@8668: AfterLoadVehicles(false); Darkvater@6522: StartupEngines(); Darkvater@5352: /* update station and waypoint graphics */ Darkvater@5352: AfterLoadWaypoints(); Darkvater@5352: AfterLoadStations(); maedhros@6658: /* check that house ids are still valid */ maedhros@6658: CheckHouseIDs(); Darkvater@5352: /* redraw the whole screen */ Darkvater@5352: MarkWholeScreenDirty(); Darkvater@5352: }