tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file openttd.cpp Functions related to starting OpenTTD. */ belugas@6351: truelight@0: #include "stdafx.h" rubidium@8788: rubidium@5587: #define VARDEF rubidium@8788: #include "variables.h" rubidium@8788: #undef VARDEF truelight@0: Darkvater@1891: #include "openttd.h" rubidium@8788: rubidium@8788: #include "driver.h" rubidium@8788: #include "blitter/factory.hpp" rubidium@8788: #include "sound/sound_driver.hpp" rubidium@8788: #include "music/music_driver.hpp" rubidium@8788: #include "video/video_driver.hpp" rubidium@8788: rubidium@8788: #include "fontcache.h" tron@2340: #include "gfxinit.h" rubidium@8788: #include "gfx_func.h" truelight@0: #include "gui.h" rubidium@8788: #include "mixer.h" rubidium@8788: #include "sound_func.h" rubidium@8107: #include "window_func.h" rubidium@8788: rubidium@8788: #include "debug.h" rubidium@8788: #include "saveload.h" rubidium@8788: #include "landscape.h" rubidium@10208: #include "company_func.h" rubidium@10208: #include "company_base.h" rubidium@8116: #include "command_func.h" truelight@0: #include "town.h" truelight@0: #include "industry.h" rubidium@8763: #include "news_func.h" rubidium@10039: #include "fileio_func.h" belugas@8151: #include "fios.h" truelight@0: #include "airport.h" celestar@6193: #include "aircraft.h" rubidium@9336: #include "console_func.h" tron@430: #include "screenshot.h" rubidium@5469: #include "network/network.h" rubidium@9428: #include "network/network_func.h" rubidium@8790: #include "signs_base.h" rubidium@8790: #include "signs_func.h" truelight@1542: #include "waypoint.h" truelight@2395: #include "ai/ai.h" bjarni@2855: #include "train.h" KUDr@3900: #include "yapf/yapf.h" rubidium@8208: #include "settings_func.h" truelight@4300: #include "genworld.h" rubidium@10208: #include "company_manager_face.h" rubidium@8788: #include "group.h" rubidium@8788: #include "strings_func.h" rubidium@8788: #include "date_func.h" rubidium@8788: #include "vehicle_func.h" smatz@9457: #include "gamelog.h" rubidium@8965: #include "cheat_func.h" rubidium@9005: #include "animated_tile_func.h" rubidium@9006: #include "functions.h" smatz@9154: #include "elrail_func.h" smatz@9085: #include "rev.h" rubidium@8788: peter1138@6451: #include "newgrf.h" peter1138@5228: #include "newgrf_config.h" maedhros@6332: #include "newgrf_house.h" belugas@6629: #include "newgrf_commons.h" rubidium@8787: #include "newgrf_station.h" truelight@0: celestar@5385: #include "clear_map.h" rubidium@8787: #include "tree_map.h" celestar@5385: #include "rail_map.h" celestar@5385: #include "road_map.h" rubidium@10289: #include "road_cmd.h" rubidium@8787: #include "station_map.h" rubidium@8787: #include "town_map.h" rubidium@5436: #include "industry_map.h" truelight@6257: #include "unmovable_map.h" rubidium@8787: #include "tunnel_map.h" rubidium@8787: #include "bridge_map.h" rubidium@8787: #include "water_map.h" smatz@8083: #include "tunnelbridge_map.h" rubidium@8108: #include "void_map.h" peter1138@8471: #include "water.h" celestar@5385: truelight@0: #include truelight@0: rubidium@8264: #include "table/strings.h" rubidium@8264: rubidium@8973: StringID _switch_mode_errorstr; rubidium@8973: rubidium@6247: void CallLandscapeTick(); rubidium@6247: void IncreaseDate(); rubidium@6247: void DoPaletteAnimations(); rubidium@6247: void MusicLoop(); rubidium@6247: void ResetMusic(); rubidium@8987: void ResetOldNames(); rubidium@8989: void ProcessAsyncSaveFinish(); rubidium@9161: void CallWindowTickEvent(); truelight@0: rubidium@9358: extern void SetDifficultyLevel(int mode, DifficultySettings *gm_opt); rubidium@10207: extern Company *DoStartupNewCompany(bool is_ai); glx@9470: extern void ShowOSErrorBox(const char *buf, bool system); smatz@8809: extern void InitializeRailGUI(); truelight@0: rubidium@9069: /** glx@9470: * Error handling for fatal user errors. glx@9470: * @param s the string to print. glx@9470: * @note Does NEVER return. glx@9470: */ glx@9470: void CDECL usererror(const char *s, ...) glx@9470: { glx@9470: va_list va; glx@9470: char buf[512]; glx@9470: glx@9470: va_start(va, s); glx@9470: vsnprintf(buf, lengthof(buf), s, va); glx@9470: va_end(va); glx@9470: glx@9470: ShowOSErrorBox(buf, false); glx@9470: if (_video_driver != NULL) _video_driver->Stop(); glx@9470: glx@9470: exit(1); glx@9470: } glx@9470: glx@9470: /** glx@9470: * Error handling for fatal non-user errors. rubidium@9069: * @param s the string to print. rubidium@9069: * @note Does NEVER return. rubidium@9069: */ 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: glx@9470: ShowOSErrorBox(buf, true); peter1138@7170: if (_video_driver != NULL) _video_driver->Stop(); truelight@0: truelight@0: assert(0); truelight@0: exit(1); truelight@0: } truelight@0: rubidium@9069: /** rubidium@9069: * Shows some information on the console/a popup box depending on the OS. rubidium@9069: * @param str the text to show. rubidium@9069: */ 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: rubidium@9069: /** rubidium@9069: * Show the help message when someone passed a wrong parameter. rubidium@9069: */ rubidium@9069: static void ShowHelp() truelight@0: { rubidium@9069: char buf[4096]; rubidium@9069: char *p = buf; truelight@2831: rubidium@10299: p += seprintf(p, lastof(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@5885: " -s drv = Set sound driver (see below) (param bufsize,hz)\n" truelight@543: " -m drv = Set music driver (see below)\n" truelight@6852: " -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@5692: #if defined(ENABLE_NETWORK) rubidium@10207: " -n [ip:port#company]= Start networkgame\n" rubidium@5508: " -D [ip][:port] = Start dedicated server\n" truelight@5959: " -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@5692: #endif /* ENABLE_NETWORK */ frosch@10296: " -i palette = Force to use the DOS (0) or Windows (1) palette\n" frosch@10296: " (defines default setting when adding newgrfs)\n" smatz@10361: " Default value (2) lets OpenTTD use the palette\n" smatz@10361: " specified in graphics set file (see below)\n" rubidium@9994: " -I graphics_set = Force the graphics set (see below)\n" truelight@2831: " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" rubidium@9994: " -x = Do not automatically save to config file on exit\n" rubidium@9994: "\n", Darkvater@5170: lastof(buf) truelight@0: ); truelight@0: rubidium@9994: /* List the graphics packs */ rubidium@9994: p = GetGraphicsSetsList(p, lastof(buf)); rubidium@9994: peter1138@7170: /* List the drivers */ peter1138@7170: p = VideoDriverFactoryBase::GetDriversInfo(p, lastof(buf)); truelight@0: truelight@6852: /* List the blitters */ truelight@6852: p = BlitterFactoryBase::GetBlittersInfo(p, lastof(buf)); truelight@6852: Darkvater@5723: /* ShowInfo put output to stderr, but version information should go Darkvater@5723: * to stdout; this is the only exception */ Darkvater@5723: #if !defined(WIN32) && !defined(WIN64) Darkvater@5723: printf("%s\n", buf); Darkvater@5723: #else truelight@0: ShowInfo(buf); Darkvater@5723: #endif truelight@0: } truelight@0: truelight@0: rubidium@5587: struct MyGetOptData { truelight@0: char *opt; truelight@0: int numleft; truelight@0: char **argv; truelight@0: const char *options; rubidium@5587: const char *cont; truelight@0: rubidium@5587: MyGetOptData(int argc, char **argv, const char *options) rubidium@5587: { rubidium@5587: opt = NULL; rubidium@5587: numleft = argc; rubidium@5587: this->argv = argv; rubidium@5587: this->options = options; rubidium@5587: cont = NULL; rubidium@5587: } rubidium@5587: }; truelight@0: truelight@0: static int MyGetOpt(MyGetOptData *md) truelight@0: { rubidium@5587: 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@6351: /* Found argument, try to locate it in options. */ truelight@0: if (*s == ':' || (r = strchr(md->options, *s)) == NULL) { belugas@6351: /* ERROR! */ truelight@0: return -2; truelight@0: } truelight@0: if (r[1] == ':') { belugas@6351: /* Item wants an argument. Check if the argument follows, or if it comes as a separate arg. */ truelight@0: if (!*(t = s + 1)) { belugas@6351: /* It comes as a separate arg. Check if out of args? */ truelight@0: if (--md->numleft < 0 || *(t = *md->argv) == '-') { belugas@6351: /* 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@5587: 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@6351: /* This is currently not supported. */ truelight@0: return -2; truelight@0: } truelight@0: } truelight@0: } truelight@0: rubidium@9069: /** rubidium@9069: * Extract the resolution from the given string and store rubidium@9069: * it in the 'res' parameter. rubidium@9069: * @param res variable to store the resolution in. rubidium@9069: * @param s the string to decompose. rubidium@9069: */ smatz@9533: static void ParseResolution(Dimension *res, const char *s) truelight@0: { rubidium@5587: 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: smatz@9533: res->width = max(strtoul(s, NULL, 0), 64UL); smatz@9533: res->height = max(strtoul(t + 1, NULL, 0), 64UL); truelight@193: } truelight@0: rubidium@6247: static void InitializeDynamicVariables() truelight@919: { truelight@919: /* Dynamic stuff needs to be initialized somewhere... */ belugas@7152: _industry_mngr.ResetMapping(); belugas@7152: _industile_mngr.ResetMapping(); rubidium@10207: _Company_pool.AddBlockToPool(); truelight@919: } truelight@919: Darkvater@5659: smatz@9159: /** Unitializes drivers, frees allocated memory, cleans pools, ... smatz@9159: * Generally, prepares the game for shutting down smatz@9159: */ smatz@9159: static void ShutdownGame() truelight@919: { smatz@9159: /* stop the AI */ smatz@9159: AI_Uninitialize(); smatz@9159: smatz@9159: IConsoleFree(); smatz@9159: smatz@9159: if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections smatz@9159: smatz@9159: DriverFactoryBase::ShutdownDrivers(); smatz@9159: Darkvater@5659: UnInitWindowSystem(); Darkvater@5659: Darkvater@5659: /* Uninitialize airport state machines */ Darkvater@5659: UnInitializeAirports(); Darkvater@5659: Darkvater@5659: /* Uninitialize variables that are allocated dynamically */ smatz@9457: GamelogReset(); rubidium@7401: _Town_pool.CleanPool(); rubidium@7401: _Industry_pool.CleanPool(); rubidium@7401: _Station_pool.CleanPool(); rubidium@7401: _Vehicle_pool.CleanPool(); rubidium@7401: _Sign_pool.CleanPool(); rubidium@7401: _Order_pool.CleanPool(); rubidium@7401: _Group_pool.CleanPool(); rubidium@7401: _CargoPacket_pool.CleanPool(); peter1138@9070: _Engine_pool.CleanPool(); rubidium@10207: _Company_pool.CleanPool(); truelight@1260: Darkvater@1482: free(_config_file); smatz@9159: smatz@9159: /* Close all and any open filehandles */ smatz@9159: FioCloseAll(); Darkvater@1474: } truelight@919: rubidium@6247: static void LoadIntroGame() truelight@543: { truelight@543: _game_mode = GM_MENU; peter1138@6427: peter1138@5228: ResetGRFConfig(false); truelight@543: belugas@6351: /* Setup main window */ Darkvater@1474: ResetWindowSystem(); truelight@543: SetupColorsAndInitialWindow(); truelight@543: rubidium@6929: /* Load the default opening screen savegame */ rubidium@6929: 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(); rubidium@10207: SetLocalCompany(COMPANY_SPECTATOR); smatz@10152: } else { rubidium@10207: SetLocalCompany(COMPANY_FIRST); tron@921: } truelight@543: truelight@6231: _pause_game = 0; truelight@4336: _cursor.fix_at = false; truelight@543: MarkWholeScreenDirty(); truelight@543: rubidium@8085: CheckForMissingGlyphsInLoadedLanguagePack(); rubidium@8085: belugas@6351: /* Play main theme */ peter1138@7170: if (_music_driver->IsSongPlaying()) ResetMusic(); truelight@543: } truelight@543: rubidium@8268: byte _savegame_sort_order; truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) rubidium@6247: 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; rubidium@9994: char musicdriver[32], sounddriver[32], videodriver[32], blitter[32], graphics_set[32]; smatz@9533: Dimension resolution = {0, 0}; rubidium@4293: Year startyear = INVALID_YEAR; truelight@4300: uint generation_seed = GENERATE_NEW_SEED; bjarni@5692: bool save_config = true; bjarni@5692: #if defined(ENABLE_NETWORK) Darkvater@3058: bool dedicated = false; Darkvater@3058: bool network = false; Darkvater@3058: char *network_conn = NULL; truelight@5959: char *debuglog_conn = NULL; rubidium@5508: char *dedicated_host = NULL; rubidium@5508: uint16 dedicated_port = 0; bjarni@5692: #endif /* ENABLE_NETWORK */ tron@1406: rubidium@9994: musicdriver[0] = sounddriver[0] = videodriver[0] = blitter[0] = graphics_set[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@6351: /* The last param of the following function means this: belugas@6351: * a letter means: it accepts that param (e.g.: -h) belugas@6351: * a ':' behind it means: it need a param (e.g.: -m) belugas@6351: * a '::' behind it means: it can optional have a param (e.g.: -d) */ rubidium@9994: optformat = "m:s:v:b:hD::n::ei::I:t: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@6491: MyGetOptData mgo(argc - 1, argv + 1, optformat); rubidium@5587: truelight@0: while ((i = MyGetOpt(&mgo)) != -1) { tron@2951: switch (i) { skidd13@10310: case 'I': strecpy(graphics_set, mgo.opt, lastof(graphics_set)); break; skidd13@10310: case 'm': strecpy(musicdriver, mgo.opt, lastof(musicdriver)); break; skidd13@10310: case 's': strecpy(sounddriver, mgo.opt, lastof(sounddriver)); break; skidd13@10310: case 'v': strecpy(videodriver, mgo.opt, lastof(videodriver)); break; skidd13@10310: case 'b': strecpy(blitter, mgo.opt, lastof(blitter)); break; bjarni@5692: #if defined(ENABLE_NETWORK) Darkvater@3058: case 'D': Darkvater@3058: strcpy(musicdriver, "null"); Darkvater@3058: strcpy(sounddriver, "null"); Darkvater@3058: strcpy(videodriver, "dedicated"); truelight@6878: strcpy(blitter, "null"); Darkvater@3058: dedicated = true; Darkvater@5885: if (mgo.opt != NULL) { rubidium@5508: /* Use the existing method for parsing (openttd -n). rubidium@10207: * However, we do ignore the #company part. */ rubidium@5508: const char *temp = NULL; rubidium@5508: const char *port = NULL; rubidium@5508: ParseConnectionString(&temp, &port, mgo.opt); Darkvater@5885: if (!StrEmpty(mgo.opt)) dedicated_host = mgo.opt; rubidium@5508: if (port != NULL) dedicated_port = atoi(port); rubidium@5508: } 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@5959: case 'l': truelight@5959: debuglog_conn = mgo.opt; truelight@5959: break; bjarni@5692: #endif /* ENABLE_NETWORK */ smatz@9533: 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; smatz@10361: case 'i': smatz@10361: /* there is an argument, it is not empty, and it is exactly 1 char long */ smatz@10361: if (!StrEmpty(mgo.opt) && mgo.opt[1] == '\0') { smatz@10361: _use_palette = (PaletteType)(mgo.opt[0] - '0'); smatz@10361: if (_use_palette <= MAX_PAL) break; smatz@10361: } smatz@10361: usererror("Valid value for '-i' is 0, 1 or 2"); truelight@193: case 'g': tron@2639: if (mgo.opt != NULL) { skidd13@10310: strecpy(_file_to_saveload.name, mgo.opt, lastof(_file_to_saveload.name)); truelight@0: _switch_mode = SM_LOAD; smatz@9730: _file_to_saveload.mode = SL_LOAD; smatz@9730: smatz@9730: /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ smatz@9730: const char *t = strrchr(_file_to_saveload.name, '.'); smatz@9730: if (t != NULL) { smatz@9730: FiosType ft = FiosGetSavegameListCallback(SLD_LOAD_GAME, _file_to_saveload.name, t, NULL); smatz@9730: if (ft != FIOS_TYPE_INVALID) SetFiosType(ft); smatz@9730: } smatz@9730: smatz@9730: break; tron@4077: } smatz@9730: smatz@9730: _switch_mode = SM_NEWGAME; glx@10195: /* Give a random map if no seed has been given */ glx@10195: if (generation_seed == GENERATE_NEW_SEED) { glx@10195: generation_seed = InteractiveRandom(); glx@10195: } truelight@0: break; truelight@4300: case 'G': generation_seed = atoi(mgo.opt); break; Darkvater@3058: case 'c': _config_file = strdup(mgo.opt); break; rubidium@5507: case 'x': save_config = false; break; truelight@0: case -2: tron@2026: case 'h': rubidium@9994: /* The next two functions are needed to list the graphics sets. rubidium@9994: * We can't do them earlier because then we can't show it on rubidium@9994: * the debug console as that hasn't been configured yet. */ rubidium@9994: DeterminePaths(argv[0]); rubidium@9994: FindGraphicsSets(); rubidium@9069: ShowHelp(); truelight@0: return 0; truelight@0: } truelight@0: } truelight@0: truelight@7408: #if defined(WINCE) && defined(_DEBUG) truelight@7408: /* 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@7408: SetDebugString("4"); truelight@7408: #endif truelight@7408: rubidium@6317: DeterminePaths(argv[0]); rubidium@9994: FindGraphicsSets(); truelight@704: truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) belugas@6351: /* 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: rubidium@10037: belugas@6351: /* override config? */ skidd13@10310: if (!StrEmpty(graphics_set)) strecpy(_ini_graphics_set, graphics_set, lastof(_ini_graphics_set)); skidd13@10310: if (!StrEmpty(musicdriver)) strecpy(_ini_musicdriver, musicdriver, lastof(_ini_musicdriver)); skidd13@10310: if (!StrEmpty(sounddriver)) strecpy(_ini_sounddriver, sounddriver, lastof(_ini_sounddriver)); skidd13@10310: if (!StrEmpty(videodriver)) strecpy(_ini_videodriver, videodriver, lastof(_ini_videodriver)); skidd13@10310: if (!StrEmpty(blitter)) strecpy(_ini_blitter, blitter, lastof(_ini_blitter)); smatz@9533: if (resolution.width != 0) { _cur_resolution = resolution; } rubidium@9354: if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear; rubidium@9354: if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; truelight@0: rubidium@6892: /* The width and height must be at least 1 pixel, this rubidium@6892: * way all internal drawing routines work correctly. */ smatz@9533: if (_cur_resolution.width <= 0) _cur_resolution.width = 1; smatz@9533: if (_cur_resolution.height <= 0) _cur_resolution.height = 1; rubidium@6892: bjarni@5692: #if defined(ENABLE_NETWORK) rubidium@9420: if (dedicated_host) snprintf(_settings_client.network.server_bind_ip, sizeof(_settings_client.network.server_bind_ip), "%s", dedicated_host); rubidium@9420: if (dedicated_port) _settings_client.network.server_port = dedicated_port; tron@2951: if (_dedicated_forks && !dedicated) _dedicated_forks = false; bjarni@5692: #endif /* ENABLE_NETWORK */ truelight@704: belugas@6351: /* enumerate language files */ truelight@0: InitializeLanguagePacks(); truelight@0: belugas@6351: /* initialize screenshot formats */ truelight@0: InitializeScreenshotFormats(); truelight@0: belugas@6351: /* initialize airport state machines */ dominik@105: InitializeAirports(); truelight@193: truelight@919: /* initialize all variables that are allocated dynamically */ truelight@919: InitializeDynamicVariables(); truelight@919: belugas@6351: /* Sample catalogue */ Darkvater@5380: 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@6351: /* This must be done early, since functions use the InvalidateWindow* calls */ truelight@139: InitWindowSystem(); truelight@0: rubidium@10037: if (!SetGraphicsSet(_ini_graphics_set)) { rubidium@10037: StrEmpty(_ini_graphics_set) ? rubidium@9994: usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD.") : rubidium@10037: usererror("Failed to select requested graphics set '%s'", _ini_graphics_set); rubidium@9994: } rubidium@9994: peter1138@5166: /* Initialize game palette */ peter1138@5166: GfxInitPalettes(); peter1138@5166: truelight@7567: DEBUG(misc, 1, "Loading blitter..."); truelight@7567: if (BlitterFactoryBase::SelectBlitter(_ini_blitter) == NULL) truelight@7567: StrEmpty(_ini_blitter) ? glx@9470: usererror("Failed to autoprobe blitter") : glx@9470: usererror("Failed to select requested blitter '%s'; does it exist?", _ini_blitter); peter1138@7170: Darkvater@5380: DEBUG(driver, 1, "Loading drivers..."); peter1138@7170: peter1138@7170: _sound_driver = (SoundDriver*)SoundDriverFactoryBase::SelectDriver(_ini_sounddriver, Driver::DT_SOUND); peter1138@7170: if (_sound_driver == NULL) { peter1138@7170: StrEmpty(_ini_sounddriver) ? glx@9470: usererror("Failed to autoprobe sound driver") : glx@9470: usererror("Failed to select requested sound driver '%s'", _ini_sounddriver); peter1138@7170: } peter1138@7170: peter1138@7170: _music_driver = (MusicDriver*)MusicDriverFactoryBase::SelectDriver(_ini_musicdriver, Driver::DT_MUSIC); peter1138@7170: if (_music_driver == NULL) { peter1138@7170: StrEmpty(_ini_musicdriver) ? glx@9470: usererror("Failed to autoprobe music driver") : glx@9470: usererror("Failed to select requested music driver '%s'", _ini_musicdriver); peter1138@7170: } peter1138@7170: peter1138@7170: _video_driver = (VideoDriver*)VideoDriverFactoryBase::SelectDriver(_ini_videodriver, Driver::DT_VIDEO); peter1138@7170: if (_video_driver == NULL) { peter1138@7170: StrEmpty(_ini_videodriver) ? glx@9470: usererror("Failed to autoprobe video driver") : glx@9470: usererror("Failed to select requested video driver '%s'", _ini_videodriver); peter1138@7170: } peter1138@7170: tron@2526: _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; truelight@6654: /* Initialize the zoom level of the screen to normal */ truelight@6654: _screen.zoom = ZOOM_LVL_NORMAL; truelight@0: belugas@6351: /* restore saved music volume */ peter1138@7170: _music_driver->SetVolume(msf.music_vol); glx@3678: Darkvater@4830: NetworkStartUp(); // initialize network-core truelight@543: truelight@5959: #if defined(ENABLE_NETWORK) truelight@5959: if (debuglog_conn != NULL && _network_available) { truelight@5959: const char *not_used = NULL; truelight@5959: const char *port = NULL; truelight@5959: uint16 rport; truelight@5959: truelight@5959: rport = NETWORK_DEFAULT_DEBUGLOG_PORT; truelight@5959: truelight@5959: ParseConnectionString(¬_used, &port, debuglog_conn); truelight@5959: if (port != NULL) rport = atoi(port); truelight@5959: truelight@5959: NetworkStartDebugLog(debuglog_conn, rport); truelight@5959: } truelight@5959: #endif /* ENABLE_NETWORK */ truelight@5959: peter1138@5228: ScanNewGRFFiles(); peter1138@5228: 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 */ rubidium@9358: if (_settings_newgame.difficulty.diff_level == 9) SetDifficultyLevel(0, &_settings_newgame.difficulty); truelight@0: rubidium@9373: /* Make sure _settings is filled with _settings_newgame if we switch to a game directly */ rubidium@9413: if (_switch_mode != SM_NONE) _settings_game = _settings_newgame; truelight@4300: belugas@6351: /* 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; rubidium@10207: const char *company = NULL; truelight@543: uint16 rport; truelight@543: truelight@543: rport = NETWORK_DEFAULT_PORT; rubidium@10207: _network_playas = COMPANY_NEW_COMPANY; truelight@543: rubidium@10207: ParseConnectionString(&company, &port, network_conn); Darkvater@4878: rubidium@10207: if (company != NULL) { rubidium@10207: _network_playas = (CompanyID)atoi(company); rubidium@10207: rubidium@10207: if (_network_playas != COMPANY_SPECTATOR) { Darkvater@4880: _network_playas--; rubidium@10207: if (_network_playas >= MAX_COMPANIES) 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@7170: _video_driver->MainLoop(); truelight@139: tron@2285: WaitTillSaved(); truelight@0: rubidium@5507: /* only save config if we have to */ rubidium@5507: if (save_config) { rubidium@5507: SaveToConfig(); rubidium@5507: SaveToHighScore(); rubidium@5507: } truelight@0: smatz@9159: /* Reset windowing system, stop drivers, free used memory, ... */ smatz@9159: ShutdownGame(); darkvater@1036: truelight@0: return 0; truelight@0: } truelight@0: rubidium@6247: 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@9413: } else if (_settings_client.gui.autosave_on_exit) { rubidium@4548: DoExitSave(); rubidium@4548: _exit_game = true; rubidium@4548: } else { rubidium@4548: AskExitGame(); rubidium@4548: } rubidium@4548: } rubidium@4548: 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@6247: static void MakeNewGameDone() truelight@4300: { rubidium@9617: SettingsDisableElrail(_settings_game.vehicle.disable_elrails); rubidium@9617: truelight@4300: /* In a dedicated server, the server does not play */ truelight@4300: if (_network_dedicated) { rubidium@10207: SetLocalCompany(COMPANY_SPECTATOR); truelight@4300: return; truelight@4300: } truelight@4300: rubidium@10207: /* Create a single company */ rubidium@10207: DoStartupNewCompany(false); truelight@4300: rubidium@10207: SetLocalCompany(COMPANY_FIRST); rubidium@10207: _current_company = _local_company; rubidium@9413: DoCommandP(0, (_settings_client.gui.autorenew << 15 ) | (_settings_client.gui.autorenew_months << 16) | 4, _settings_client.gui.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@4300: smatz@8809: InitializeRailGUI(); KUDr@5116: rubidium@8247: #ifdef ENABLE_NETWORK rubidium@10207: /* We are the server, we start a new company (not dedicated), rubidium@7998: * so set the default password *if* needed. */ rubidium@9420: if (_network_server && !StrEmpty(_settings_client.network.default_company_pass)) { rubidium@9420: char *password = _settings_client.network.default_company_pass; rubidium@7998: NetworkChangeCompanyPassword(1, &password); rubidium@7998: } rubidium@8247: #endif /* ENABLE_NETWORK */ rubidium@7998: 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@6629: _house_mngr.ResetMapping(); belugas@7152: _industile_mngr.ResetMapping(); belugas@7152: _industry_mngr.ResetMapping(); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewGameDone); rubidium@9413: GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); truelight@4300: } truelight@0: rubidium@6247: static void MakeNewEditorWorldDone() truelight@4300: { rubidium@10207: SetLocalCompany(OWNER_NONE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: rubidium@6247: static void MakeNewEditorWorld() truelight@0: { truelight@0: _game_mode = GM_EDITOR; truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewEditorWorldDone); rubidium@9413: GenerateWorld(GW_EMPTY, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); truelight@0: } truelight@0: rubidium@10207: void StartupCompanies(); rubidium@6247: void StartupDisasters(); rubidium@6247: 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@6247: static void StartScenario() truelight@0: { truelight@0: _game_mode = GM_NORMAL; truelight@0: belugas@6351: /* invalid type */ truelight@0: if (_file_to_saveload.mode == SL_INVALID) { Darkvater@5380: DEBUG(sl, 0, "Savegame is obsolete or invalid format: '%s'", _file_to_saveload.name); rubidium@9648: SetDParam(0, STR_JUST_RAW_STRING); rubidium@9648: SetDParamStr(1, GetSaveLoadErrorString()); rubidium@7036: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); truelight@0: _game_mode = GM_MENU; truelight@0: return; truelight@0: } truelight@0: belugas@6351: /* Reinitialize windows */ Darkvater@1474: ResetWindowSystem(); truelight@0: truelight@0: SetupColorsAndInitialWindow(); truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: belugas@6351: /* Load game */ rubidium@6929: if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, SCENARIO_DIR) != SL_OK) { truelight@0: LoadIntroGame(); rubidium@9648: SetDParam(0, STR_JUST_RAW_STRING); rubidium@9648: SetDParamStr(1, GetSaveLoadErrorString()); rubidium@7036: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); truelight@0: } truelight@0: rubidium@9413: _settings_game.difficulty = _settings_newgame.difficulty; Darkvater@1500: belugas@6351: /* Inititalize data */ Darkvater@3891: StartupEconomy(); rubidium@10207: StartupCompanies(); dominik@115: StartupEngines(); dominik@115: StartupDisasters(); dominik@115: rubidium@10207: SetLocalCompany(COMPANY_FIRST); rubidium@10207: _current_company = _local_company; rubidium@9413: DoCommandP(0, (_settings_client.gui.autorenew << 15 ) | (_settings_client.gui.autorenew_months << 16) | 4, _settings_client.gui.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: rubidium@6929: /** Load the specified savegame but on error do different things. rubidium@6929: * If loading fails due to corrupt savegame, bad version, etc. go back to rubidium@6929: * a previous correct state. In the menu for example load the intro game again. rubidium@6929: * @param filename file to be loaded rubidium@6929: * @param mode mode of loading, either SL_LOAD or SL_OLD_LOAD rubidium@6929: * @param newgm switch to this mode of loading fails due to some unknown error rubidium@9069: * @param subdir default directory to look for filename, set to 0 if not needed rubidium@9069: */ rubidium@6929: 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@6929: assert(mode == SL_LOAD || mode == SL_OLD_LOAD); rubidium@6929: switch (SaveOrLoad(filename, mode, subdir)) { tron@3024: case SL_OK: return true; tron@3024: tron@3024: case SL_REINIT: tron@3024: switch (ogm) { peter1138@8619: default: tron@3024: case GM_MENU: LoadIntroGame(); break; tron@3024: case GM_EDITOR: MakeNewEditorWorld(); 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@6351: /* If we are saving something, the network stays in his current state */ truelight@543: if (new_mode != SM_SAVE) { belugas@6351: /* 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(); truelight@543: } else { truelight@543: NetworkDisconnect(); truelight@543: } truelight@543: } truelight@543: belugas@6351: /* If we are a server, we restart the server */ truelight@543: if (_is_network_server) { belugas@6351: /* But not if we are going to the menu */ truelight@543: if (new_mode != SM_MENU) { rubidium@8265: /* check if we should reload the config */ rubidium@9420: if (_settings_client.network.reload_cfg) { rubidium@8265: LoadFromConfig(); rubidium@9413: _settings_game = _settings_newgame; rubidium@8265: ResetGRFConfig(false); rubidium@8265: } truelight@543: NetworkServerStart(); truelight@543: } else { belugas@6351: /* 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) { rubidium@9069: case SM_EDITOR: /* Switch to scenario editor */ rubidium@9069: MakeNewEditorWorld(); rubidium@9069: break; truelight@0: rubidium@9069: case SM_NEWGAME: /* New Game --> 'Random game' */ truelight@630: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { rubidium@9069: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map"); tron@2951: } truelight@630: #endif /* ENABLE_NETWORK */ rubidium@9069: MakeNewGame(false); rubidium@9069: break; truelight@0: rubidium@9069: case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */ truelight@4300: #ifdef ENABLE_NETWORK rubidium@9069: if (_network_server) { rubidium@9069: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title); rubidium@9069: } truelight@4300: #endif /* ENABLE_NETWORK */ rubidium@9069: StartScenario(); rubidium@9069: break; truelight@4300: rubidium@9069: case SM_LOAD: { /* Load game, Play Scenario */ rubidium@9069: ResetGRFConfig(true); rubidium@9069: ResetWindowSystem(); truelight@4300: rubidium@9069: if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) { rubidium@9069: LoadIntroGame(); rubidium@9648: SetDParam(0, STR_JUST_RAW_STRING); rubidium@9648: SetDParamStr(1, GetSaveLoadErrorString()); rubidium@9069: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); rubidium@9069: } else { rubidium@9089: if (_saveload_mode == SLD_LOAD_SCENARIO) { rubidium@9089: StartupEngines(); rubidium@9089: } rubidium@10207: /* Update the local company for a loaded game. It is either always rubidium@10207: * company #1 (eg 0) or in the case of a dedicated server a spectator */ rubidium@10207: SetLocalCompany(_network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST); rubidium@9069: /* Decrease pause counter (was increased from opening load dialog) */ rubidium@9069: DoCommandP(0, 0, 0, NULL, CMD_PAUSE); rubidium@9069: #ifdef ENABLE_NETWORK rubidium@9069: if (_network_server) { rubidium@9069: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); rubidium@9069: } rubidium@9069: #endif /* ENABLE_NETWORK */ rubidium@9069: } rubidium@9069: break; rubidium@9069: } truelight@0: rubidium@9069: case SM_START_HEIGHTMAP: /* Load a heightmap and start a new game from it */ rubidium@9069: #ifdef ENABLE_NETWORK rubidium@9069: if (_network_server) { rubidium@9069: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); rubidium@9069: } rubidium@9069: #endif /* ENABLE_NETWORK */ rubidium@9069: MakeNewGame(true); rubidium@9069: break; rubidium@9069: rubidium@9069: case SM_LOAD_HEIGHTMAP: /* Load heightmap from scenario editor */ rubidium@10207: SetLocalCompany(OWNER_NONE); truelight@0: rubidium@9413: GenerateWorld(GW_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); rubidium@9069: MarkWholeScreenDirty(); rubidium@9069: break; rubidium@9069: rubidium@9069: case SM_LOAD_SCENARIO: { /* Load scenario from scenario editor */ rubidium@9069: if (SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR, NO_DIRECTORY)) { rubidium@10207: SetLocalCompany(OWNER_NONE); rubidium@9354: _settings_newgame.game_creation.starting_year = _cur_year; rubidium@9069: } else { rubidium@9648: SetDParam(0, STR_JUST_RAW_STRING); rubidium@9648: SetDParamStr(1, GetSaveLoadErrorString()); rubidium@9069: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); rubidium@9069: } rubidium@9069: break; tron@2639: } truelight@0: rubidium@9069: case SM_MENU: /* Switch to game intro menu */ rubidium@9069: LoadIntroGame(); rubidium@9069: break; rubidium@9069: rubidium@9069: case SM_SAVE: /* Save game */ rubidium@9069: /* Make network saved games on pause compatible to singleplayer */ rubidium@9069: if (_networking && _pause_game == 1) _pause_game = 2; rubidium@9069: if (SaveOrLoad(_file_to_saveload.name, SL_SAVE, NO_DIRECTORY) != SL_OK) { rubidium@9648: SetDParam(0, STR_JUST_RAW_STRING); rubidium@9648: SetDParamStr(1, GetSaveLoadErrorString()); rubidium@9069: ShowErrorMessage(INVALID_STRING_ID, STR_012D, 0, 0); rubidium@9069: } else { rubidium@9069: DeleteWindowById(WC_SAVELOAD, 0); rubidium@9069: } rubidium@9069: if (_networking && _pause_game == 2) _pause_game = 1; rubidium@9069: break; rubidium@9069: rubidium@9069: case SM_GENRANDLAND: /* Generate random land within scenario editor */ rubidium@10207: SetLocalCompany(OWNER_NONE); rubidium@9413: GenerateWorld(GW_RANDOM, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); rubidium@9069: /* XXX: set date */ rubidium@9069: MarkWholeScreenDirty(); rubidium@9069: 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: rubidium@9069: /** rubidium@9069: * State controlling game loop. rubidium@9069: * The state must not be changed from anywhere but here. rubidium@9069: * That check is enforced in DoCommand. rubidium@9069: */ rubidium@6247: void StateGameLoop() truelight@0: { belugas@6351: /* dont execute the state loop during pause */ peter1138@8179: if (_pause_game) { peter1138@8179: CallWindowTickEvent(); peter1138@8179: return; peter1138@8179: } truelight@4300: if (IsGeneratingWorld()) return; darkvater@213: rubidium@8303: ClearStorageChanges(false); rubidium@8303: truelight@0: if (_game_mode == GM_EDITOR) { truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); rubidium@8303: ClearStorageChanges(true); rubidium@8303: truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); truelight@0: } else { rubidium@9039: #ifdef DEBUG_DUMP_COMMANDS rubidium@9039: Vehicle *v; rubidium@9039: FOR_ALL_VEHICLES(v) { rubidium@9039: if (v != v->First()) continue; rubidium@9039: rubidium@9039: switch (v->type) { rubidium@9039: case VEH_ROAD: { rubidium@9039: extern byte GetRoadVehLength(const Vehicle *v); rubidium@9039: if (GetRoadVehLength(v) != v->u.road.cached_veh_length) { rubidium@10207: printf("cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); rubidium@9039: } rubidium@9039: } break; rubidium@9039: rubidium@9039: case VEH_TRAIN: { rubidium@9039: uint length = 0; rubidium@9039: for (Vehicle *u = v; u != NULL; u = u->Next()) length++; rubidium@9039: rubidium@9039: VehicleRail *wagons = MallocT(length); rubidium@9039: length = 0; rubidium@9039: for (Vehicle *u = v; u != NULL; u = u->Next()) wagons[length++] = u->u.rail; rubidium@9039: smatz@9704: TrainConsistChanged(v, true); rubidium@9039: rubidium@9039: length = 0; rubidium@9039: for (Vehicle *u = v; u != NULL; u = u->Next()) { rubidium@9039: if (memcmp(&wagons[length], &u->u.rail, sizeof(VehicleRail)) != 0) { rubidium@10207: printf("cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length); rubidium@9039: } rubidium@9039: length++; rubidium@9039: } rubidium@9039: rubidium@9039: free(wagons); rubidium@9039: } break; rubidium@9039: rubidium@9039: case VEH_AIRCRAFT: { rubidium@9039: uint speed = v->u.air.cached_max_speed; rubidium@9039: UpdateAircraftCache(v); rubidium@9039: if (speed != v->u.air.cached_max_speed) { rubidium@10207: printf("cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); rubidium@9039: } rubidium@9039: } break; rubidium@9039: rubidium@9039: default: rubidium@9039: break; rubidium@9039: } rubidium@9039: } rubidium@9039: #endif rubidium@9039: belugas@6351: /* All these actions has to be done from OWNER_NONE belugas@6351: * for multiplayer compatibility */ rubidium@10207: CompanyID old_company = _current_company; rubidium@10207: _current_company = OWNER_NONE; signde@206: truelight@0: AnimateAnimatedTiles(); truelight@0: IncreaseDate(); truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); rubidium@8303: ClearStorageChanges(true); truelight@0: truelight@2395: AI_RunGameLoop(); truelight@0: truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); rubidium@10207: _current_company = old_company; truelight@0: } truelight@0: } truelight@0: rubidium@6929: /** Create an autosave. The default name is "autosave#.sav". However with rubidium@6929: * the patch setting 'keep_all_autosave' the name defaults to company-name + date */ rubidium@6247: static void DoAutosave() truelight@0: { rubidium@6929: char buf[MAX_PATH]; truelight@193: truelight@5977: #if defined(PSP) truelight@5977: /* Autosaving in networking is too time expensive for the PSP */ rubidium@9069: if (_networking) return; truelight@5977: #endif /* PSP */ truelight@5977: rubidium@10207: if (_settings_client.gui.keep_all_autosave && _local_company != COMPANY_SPECTATOR) { rubidium@10207: SetDParam(0, _local_company); peter1138@7058: SetDParam(1, _date); rubidium@6929: GetString(buf, STR_4004, lastof(buf)); skidd13@10310: strecat(buf, ".sav", lastof(buf)); rubidium@6929: } else { rubidium@9413: /* generate a savegame name and number according to _settings_client.gui.max_num_autosaves */ rubidium@6929: snprintf(buf, sizeof(buf), "autosave%d.sav", _autosave_ctr); bjarni@2672: rubidium@9413: if (++_autosave_ctr >= _settings_client.gui.max_num_autosaves) _autosave_ctr = 0; truelight@0: } truelight@0: Darkvater@5380: DEBUG(sl, 2, "Autosaving to '%s'", buf); rubidium@9069: if (SaveOrLoad(buf, SL_SAVE, AUTOSAVE_DIR) != SL_OK) { truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_AUTOSAVE_FAILED, 0, 0); rubidium@9069: } truelight@0: } truelight@0: rubidium@6247: void GameLoop() truelight@0: { rubidium@8989: ProcessAsyncSaveFinish(); truelight@0: belugas@6351: /* autosave game? */ truelight@0: if (_do_autosave) { truelight@0: _do_autosave = false; truelight@0: DoAutosave(); truelight@0: RedrawAutosave(); truelight@0: } truelight@0: belugas@6351: /* make a screenshot? */ belugas@4184: if (IsScreenshotRequested()) ShowScreenshotResult(MakeScreenshot()); truelight@0: belugas@6351: /* 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: truelight@0: _caret_timer += 3; truelight@7018: _palette_animation_counter += 8; truelight@0: CursorTick(); truelight@0: truelight@543: #ifdef ENABLE_NETWORK belugas@6351: /* Check for UDP stuff */ Darkvater@4830: if (_network_available) NetworkUDPGameLoop(); truelight@0: truelight@4300: if (_networking && !IsGeneratingWorld()) { belugas@6351: /* Multiplayer */ truelight@543: NetworkGameLoop(); truelight@543: } else { truelight@543: if (_network_reconnect > 0 && --_network_reconnect == 0) { belugas@6351: /* This means that we want to reconnect to the last host belugas@6351: * We do this here, because it means that the network is really closed */ rubidium@9420: NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port); signde@206: } belugas@6351: /* Singleplayer */ darkvater@213: StateGameLoop(); truelight@0: } truelight@543: #else truelight@543: StateGameLoop(); truelight@543: #endif /* ENABLE_NETWORK */ truelight@0: skidd13@7928: if (!_pause_game && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); truelight@0: truelight@6231: if (!_pause_game || _cheats.build_in_pause.value) MoveAllTextEffects(); truelight@0: pasky@1570: InputLoop(); truelight@0: rubidium@10380: _sound_driver->MainLoop(); tron@1608: MusicLoop(); truelight@0: } truelight@0: rubidium@6247: static void ConvertTownOwner() truelight@0: { rubidium@9069: for (TileIndex tile = 0; tile != MapSize(); tile++) { tron@4000: switch (GetTileType(tile)) { rubidium@7370: case MP_ROAD: rubidium@10167: if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) { rubidium@10167: _m[tile].m3 = 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@6351: /* since savegame version 4.1, exclusive transport rights are stored at towns */ rubidium@6247: static void UpdateExclusiveRights() dominik@121: { belugas@4171: Town *t; tron@2639: tron@2639: FOR_ALL_TOWNS(t) { rubidium@10207: t->exclusivity = INVALID_COMPANY; 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@10207: * Build an array town_blocked[ town_id ][ company_id ] rubidium@10207: * that stores if at least one station in that town is blocked for a company rubidium@4549: * 2.) Go through that array, if you find a town that is not blocked for rubidium@10207: * one company, 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@6351: /* since savegame version 4.2 the currencies are arranged differently */ rubidium@6247: static void UpdateCurrencies() dominik@762: { rubidium@9466: _settings_game.locale.currency = convert_currency[_settings_game.locale.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@6247: 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@6351: /* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */ rubidium@6247: 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@6247: 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@7981: /** rubidium@7981: * Initialization of the windows and several kinds of caches. rubidium@7981: * This is not done directly in AfterLoadGame because these rubidium@7981: * functions require that all saveload conversions have been rubidium@7981: * done. As people tend to add savegame conversion stuff after rubidium@7981: * the intialization of the windows and caches quite some bugs rubidium@7981: * had been made. rubidium@7981: * Moving this out of there is both cleaner and less bug-prone. rubidium@7981: * rubidium@7981: * @return true if everything went according to plan, otherwise false. rubidium@7981: */ rubidium@7981: static bool InitializeWindowsAndCaches() rubidium@7981: { rubidium@7981: /* Initialize windows */ rubidium@7981: ResetWindowSystem(); rubidium@7981: SetupColorsAndInitialWindow(); rubidium@7981: rubidium@9410: extern void ResetViewportAfterLoadGame(); rubidium@9410: ResetViewportAfterLoadGame(); rubidium@7981: rubidium@7981: /* Update coordinates of the signs. */ rubidium@7981: UpdateAllStationVirtCoord(); rubidium@7981: UpdateAllSignVirtCoords(); rubidium@7981: UpdateAllTownVirtCoords(); rubidium@7981: UpdateAllWaypointSigns(); rubidium@7981: rubidium@10207: Company *c; rubidium@10207: FOR_ALL_COMPANIES(c) { rubidium@10207: /* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it rubidium@10207: * accordingly if it is not the case. No need to set it on companies that are not been used already, smatz@9211: * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ rubidium@10207: if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) { rubidium@10207: c->inaugurated_year = _cur_year; rubidium@7981: } rubidium@7981: } rubidium@7981: smatz@9211: SetCachedEngineCounts(); rubidium@7981: belugas@9334: /* Towns have a noise controlled number of airports system belugas@9334: * So each airport's noise value must be added to the town->noise_reached value belugas@9334: * Reset each town's noise_reached value to '0' before. */ belugas@9334: UpdateAirportsNoise(); belugas@9334: smatz@9704: CheckTrainsLengths(); smatz@9704: rubidium@7981: return true; rubidium@7981: } rubidium@7981: rubidium@6247: bool AfterLoadGame() truelight@0: { tron@5706: TileIndex map_size = MapSize(); rubidium@10207: Company *c; truelight@988: smatz@9457: if (CheckSavegameVersion(98)) GamelogOldver(); smatz@9457: smatz@9457: GamelogTestRevision(); smatz@9457: GamelogTestMode(); smatz@9457: smatz@9457: if (CheckSavegameVersion(98)) GamelogGRFAddList(_grfconfig); smatz@9457: belugas@6351: /* in version 2.1 of the savegame, town owner was unified. */ truelight@2685: if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner(); truelight@0: belugas@6351: /* from version 4.1 of the savegame, exclusive rights are stored at towns */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights(); truelight@193: belugas@6351: /* from version 4.2 of the savegame, currencies are in a different order */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies(); dominik@762: belugas@6351: /* 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 skidd13@8707: * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current skidd13@8707: * (4.3) version, so I just check when versions are older, and then skidd13@8707: * walk through the whole map.. */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 3)) { tron@5706: for (TileIndex t = 0; t < map_size; t++) { rubidium@10207: if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) { tron@5706: SetTileOwner(t, OWNER_WATER); tron@5706: } tron@5706: } truelight@831: } truelight@831: peter1138@8258: if (CheckSavegameVersion(84)) { rubidium@10207: FOR_ALL_COMPANIES(c) { rubidium@10207: c->name = CopyFromOldName(c->name_1); rubidium@10207: if (c->name != NULL) c->name_1 = STR_SV_UNNAMED; rubidium@10207: c->president_name = CopyFromOldName(c->president_name_1); rubidium@10207: if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME; peter1138@8258: } peter1138@8258: peter1138@8258: Station *st; peter1138@8258: FOR_ALL_STATIONS(st) { peter1138@8258: st->name = CopyFromOldName(st->string_id); smatz@10150: /* generating new name would be too much work for little effect, use the station name fallback */ smatz@10150: if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK; peter1138@8258: } peter1138@8258: peter1138@8258: Town *t; peter1138@8258: FOR_ALL_TOWNS(t) { peter1138@8258: t->name = CopyFromOldName(t->townnametype); rubidium@9413: if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; peter1138@8258: } peter1138@8258: peter1138@8258: Waypoint *wp; peter1138@8258: FOR_ALL_WAYPOINTS(wp) { peter1138@8258: wp->name = CopyFromOldName(wp->string); peter1138@8258: wp->string = STR_EMPTY; peter1138@8258: } smatz@10153: smatz@10153: for (uint i = 0; i < GetSignPoolSize(); i++) { rubidium@10207: /* invalid signs are determined by si->ower == INVALID_COMPANY now */ smatz@10153: Sign *si = GetSign(i); smatz@10153: if (!si->IsValid() && si->name != NULL) { smatz@10153: si->owner = OWNER_NONE; smatz@10153: } smatz@10153: } peter1138@8258: } peter1138@8258: rubidium@8987: /* From this point the old names array is cleared. */ rubidium@8987: ResetOldNames(); rubidium@8987: belugas@6351: /* convert road side to my format. */ rubidium@9413: if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1; truelight@0: Darkvater@5647: /* Check if all NewGRFs are present, we are very strict in MP mode */ maedhros@6229: GRFListCompatibility gcf_res = IsGoodGRFConfigList(); rubidium@7036: if (_networking && gcf_res != GLC_ALL_GOOD) { rubidium@7036: SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH); rubidium@7036: return false; rubidium@7036: } Darkvater@5647: Darkvater@5647: switch (gcf_res) { maedhros@6229: case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break; peter1138@8670: case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = -1; break; glx@5652: default: break; Darkvater@5647: } 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: peter1138@9070: /* Force dynamic engines off when loading older savegames */ rubidium@9413: if (CheckSavegameVersion(95)) _settings_game.vehicle.dynamic_engines = 0; peter1138@9070: belugas@6351: /* Load the sprites */ truelight@0: GfxLoadSprites(); peter1138@5155: LoadStringWidthTable(); truelight@0: peter1138@9070: /* Copy temporary data to Engine pool */ peter1138@9070: CopyTempEngineData(); peter1138@9070: 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@6351: /* reinit the landscape variables (landscape might have changed) */ truelight@0: InitializeLandscapeVariables(true); truelight@193: belugas@6351: /* Update all vehicles */ peter1138@8172: AfterLoadVehicles(true); truelight@1542: belugas@6351: /* Update all waypoints */ truelight@2685: if (CheckSavegameVersion(12)) FixOldWaypoints(); truelight@1542: belugas@6351: /* 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@6351: /* make sure there is a town in the game */ rubidium@10236: if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) { rubidium@7036: SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO); truelight@0: return false; truelight@0: } truelight@0: smatz@8513: /* The void tiles on the southern border used to belong to a wrong class (pre 4.3). smatz@8513: * This problem appears in savegame version 21 too, see r3455. But after loading the smatz@8513: * savegame and saving again, the buggy map array could be converted to new savegame smatz@8513: * version. It didn't show up before r12070. */ smatz@8513: if (CheckSavegameVersion(87)) UpdateVoidTiles(); dominik@929: belugas@6351: /* If Load Scenario / New (Scenario) Game is used, rubidium@10207: * a company does not exist yet. So create one here. rubidium@10207: * 1 exeption: network-games. Those can have 0 companies glx@6574: * But this exeption is not true for non dedicated network_servers! */ rubidium@10207: if (!IsValidCompanyID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated))) rubidium@10207: DoStartupNewCompany(false); truelight@0: rubidium@7272: if (CheckSavegameVersion(72)) { rubidium@7272: /* Locks/shiplifts in very old savegames had OWNER_WATER as owner */ rubidium@7272: for (TileIndex t = 0; t < MapSize(); t++) { rubidium@7272: switch (GetTileType(t)) { rubidium@7272: default: break; rubidium@7272: rubidium@7272: case MP_WATER: rubidium@7272: if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); rubidium@7272: break; rubidium@7272: rubidium@7272: case MP_STATION: { skidd13@7931: if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2); rubidium@7272: StationGfx gfx = GetStationGfx(t); rubidium@7272: StationType st; skidd13@7954: if ( IsInsideMM(gfx, 0, 8)) { // Railway station rubidium@7272: st = STATION_RAIL; rubidium@7272: SetStationGfx(t, gfx - 0); skidd13@7954: } else if (IsInsideMM(gfx, 8, 67)) { // Airport rubidium@7272: st = STATION_AIRPORT; rubidium@7272: SetStationGfx(t, gfx - 8); skidd13@7954: } else if (IsInsideMM(gfx, 67, 71)) { // Truck rubidium@7272: st = STATION_TRUCK; rubidium@7272: SetStationGfx(t, gfx - 67); skidd13@7954: } else if (IsInsideMM(gfx, 71, 75)) { // Bus rubidium@7272: st = STATION_BUS; rubidium@7272: SetStationGfx(t, gfx - 71); rubidium@7272: } else if (gfx == 75) { // Oil rig rubidium@7272: st = STATION_OILRIG; rubidium@7272: SetStationGfx(t, gfx - 75); skidd13@7954: } else if (IsInsideMM(gfx, 76, 82)) { // Dock rubidium@7272: st = STATION_DOCK; rubidium@7272: SetStationGfx(t, gfx - 76); rubidium@7272: } else if (gfx == 82) { // Buoy rubidium@7272: st = STATION_BUOY; rubidium@7272: SetStationGfx(t, gfx - 82); skidd13@7954: } else if (IsInsideMM(gfx, 83, 168)) { // Extended airport rubidium@7272: st = STATION_AIRPORT; rubidium@7272: SetStationGfx(t, gfx - 83 + 67 - 8); skidd13@7954: } else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck rubidium@7272: st = STATION_TRUCK; rubidium@7272: SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); skidd13@7954: } else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus rubidium@7272: st = STATION_BUS; rubidium@7272: SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); rubidium@7272: } else { rubidium@7272: return false; rubidium@7272: } rubidium@7272: SB(_m[t].m6, 3, 3, st); rubidium@7272: } break; rubidium@7272: } rubidium@7272: } rubidium@7272: } rubidium@7272: tron@5880: for (TileIndex t = 0; t < map_size; t++) { tron@5880: switch (GetTileType(t)) { tron@6093: case MP_STATION: { tron@6093: Station *st = GetStationByTile(t); tron@6093: frosch@10262: /* Set up station spread; buoys do not have one */ frosch@10262: if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE); tron@6093: tron@5880: switch (GetStationType(t)) { tron@5880: case STATION_TRUCK: tron@5880: case STATION_BUS: tron@5880: if (CheckSavegameVersion(6)) { tron@6093: /* From this version on there can be multiple road stops of the tron@6093: * same type per station. Convert the existing stops to the new tron@6093: * internal data structure. */ tron@5880: RoadStop *rs = new RoadStop(t); tron@5880: if (rs == NULL) error("Too many road stops in savegame"); tron@5879: tron@5880: RoadStop **head = tron@5880: IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; tron@5880: *head = rs; tron@5880: } tron@5880: break; tron@5880: tron@5884: case STATION_OILRIG: { tron@5884: /* Very old savegames sometimes have phantom oil rigs, i.e. tron@5884: * an oil rig which got shut down, but not completly removed from tron@5884: * the map tron@5884: */ glx@7740: TileIndex t1 = TILE_ADDXY(t, 0, 1); tron@5886: if (IsTileType(t1, MP_INDUSTRY) && glx@7740: GetIndustryGfx(t1) == GFX_OILRIG_1) { tron@5886: /* The internal encoding of oil rigs was changed twice. tron@5886: * It was 3 (till 2.2) and later 5 (till 5.1). tron@5886: * Setting it unconditionally does not hurt. tron@5886: */ tron@5886: GetStationByTile(t)->airport_type = AT_OILRIG; tron@5886: } else { tron@5884: DeleteOilRig(t); tron@5884: } tron@5884: break; tron@5884: } tron@5884: tron@5880: default: break; tron@5880: } tron@5880: break; tron@6093: } tron@5880: tron@5880: default: break; tron@5879: } tron@5879: } tron@5879: 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@5706: for (TileIndex t = 0; t < map_size; t++) { tron@5706: switch (GetTileType(t)) { tron@3983: case MP_HOUSE: tron@5706: _m[t].m4 = _m[t].m2; rubidium@10236: SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); tron@3983: break; tron@3983: rubidium@7370: case MP_ROAD: tron@5706: _m[t].m4 |= (_m[t].m2 << 4); rubidium@10167: if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) { rubidium@10236: SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); tron@3983: } else { tron@5706: SetTownIndex(t, 0); tron@3983: } tron@3983: break; tron@3983: tron@3983: default: break; celestar@1264: } tron@5706: } 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)) { rubidium@10207: FOR_ALL_COMPANIES(c) { rubidium@10207: c->engine_renew_list = NULL; rubidium@10207: c->engine_renew = false; rubidium@10207: c->engine_renew_months = -6; rubidium@10207: c->engine_renew_money = 100000; bjarni@2293: } rubidium@5376: rubidium@10207: /* When loading a game, _local_company is not yet set to the correct value. rubidium@5376: * However, in a dedicated server we are a spectator, so nothing needs to rubidium@10207: * happen. In case we are not a dedicated server, the local company always rubidium@10207: * becomes company 0, unless we are in the scenario editor where all the rubidium@10207: * companies are 'invalid'. rubidium@5376: */ rubidium@10207: if (!_network_dedicated && IsValidCompanyID(COMPANY_FIRST)) { rubidium@10207: c = GetCompany(COMPANY_FIRST); rubidium@10207: c->engine_renew = _settings_client.gui.autorenew; rubidium@10207: c->engine_renew_months = _settings_client.gui.autorenew_months; rubidium@10207: c->engine_renew_money = _settings_client.gui.autorenew_money; bjarni@2322: } bjarni@2293: } bjarni@2293: rubidium@6661: if (CheckSavegameVersion(48)) { rubidium@6661: for (TileIndex t = 0; t < map_size; t++) { rubidium@6661: switch (GetTileType(t)) { rubidium@6661: case MP_RAILWAY: rubidium@6661: if (IsPlainRailTile(t)) { rubidium@6661: /* Swap ground type and signal type for plain rail tiles, so the rubidium@6661: * ground type uses the same bits as for depots and waypoints. */ rubidium@6661: uint tmp = GB(_m[t].m4, 0, 4); rubidium@6661: SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); rubidium@6661: SB(_m[t].m2, 0, 4, tmp); skidd13@7928: } else if (HasBit(_m[t].m5, 2)) { rubidium@6661: /* Split waypoint and depot rail type and remove the subtype. */ skidd13@7929: ClrBit(_m[t].m5, 2); skidd13@7929: ClrBit(_m[t].m5, 6); rubidium@6661: } rubidium@6661: break; rubidium@6661: rubidium@7370: case MP_ROAD: rubidium@6661: /* Swap m3 and m4, so the track type for rail crossings is the rubidium@6661: * same as for normal rail. */ rubidium@6661: Swap(_m[t].m3, _m[t].m4); rubidium@6661: break; rubidium@6661: rubidium@6661: default: break; rubidium@6661: } rubidium@6661: } rubidium@6661: } rubidium@6661: rubidium@6661: if (CheckSavegameVersion(61)) { rubidium@6661: /* Added the RoadType */ rubidium@6738: bool old_bridge = CheckSavegameVersion(42); rubidium@6661: for (TileIndex t = 0; t < map_size; t++) { rubidium@6661: switch(GetTileType(t)) { rubidium@7370: case MP_ROAD: rubidium@6661: SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); rubidium@6661: switch (GetRoadTileType(t)) { rubidium@6661: default: NOT_REACHED(); rubidium@6661: case ROAD_TILE_NORMAL: rubidium@6661: SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); rubidium@6661: SB(_m[t].m4, 4, 4, 0); rubidium@6661: SB(_m[t].m6, 2, 4, 0); rubidium@6661: break; rubidium@6661: case ROAD_TILE_CROSSING: rubidium@6661: SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); rubidium@6661: break; rubidium@6661: case ROAD_TILE_DEPOT: break; rubidium@6661: } rubidium@6661: SetRoadTypes(t, ROADTYPES_ROAD); rubidium@6661: break; rubidium@6661: rubidium@6661: case MP_STATION: rubidium@6661: if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); rubidium@6661: break; rubidium@6661: rubidium@6661: case MP_TUNNELBRIDGE: rubidium@6738: /* Middle part of "old" bridges */ smatz@8390: if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; smatz@8390: if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { rubidium@6661: SetRoadTypes(t, ROADTYPES_ROAD); rubidium@6661: } rubidium@6661: break; rubidium@6661: rubidium@6661: default: break; rubidium@6661: } rubidium@6661: } rubidium@6661: } rubidium@6661: celestar@5385: if (CheckSavegameVersion(42)) { celestar@5385: Vehicle* v; celestar@5385: tron@5706: for (TileIndex t = 0; t < map_size; t++) { tron@5706: if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t); tron@5706: if (IsBridgeTile(t)) { skidd13@7928: if (HasBit(_m[t].m5, 6)) { // middle part tron@5706: Axis axis = (Axis)GB(_m[t].m5, 0, 1); celestar@5385: skidd13@7928: if (HasBit(_m[t].m5, 5)) { // transport route under bridge? tron@5706: if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { celestar@5385: MakeRailNormal( tron@5706: t, tron@5706: GetTileOwner(t), celestar@5385: axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, tron@5706: GetRailType(t) celestar@5385: ); celestar@5385: } else { rubidium@10236: TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; celestar@5385: celestar@5385: MakeRoadNormal( tron@5706: t, celestar@5385: axis == AXIS_X ? ROAD_Y : ROAD_X, rubidium@6661: ROADTYPES_ROAD, rubidium@6661: town, rubidium@6661: GetTileOwner(t), OWNER_NONE, OWNER_NONE celestar@5385: ); celestar@5385: } celestar@5385: } else { tron@5706: if (GB(_m[t].m5, 3, 2) == 0) { tron@5706: MakeClear(t, CLEAR_GRASS, 3); celestar@5385: } else { frosch@8404: if (GetTileSlope(t, NULL) != SLOPE_FLAT) { frosch@8404: MakeShore(t); frosch@8404: } else { frosch@8404: if (GetTileOwner(t) == OWNER_WATER) { frosch@8404: MakeWater(t); frosch@8404: } else { frosch@8404: MakeCanal(t, GetTileOwner(t), Random()); frosch@8404: } frosch@8404: } celestar@5385: } celestar@5385: } tron@5706: SetBridgeMiddle(t, axis); celestar@5385: } else { // ramp tron@5706: Axis axis = (Axis)GB(_m[t].m5, 0, 1); tron@5706: uint north_south = GB(_m[t].m5, 5, 1); celestar@5385: DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); tron@5706: TransportType type = (TransportType)GB(_m[t].m5, 1, 2); celestar@5385: tron@5706: _m[t].m5 = 1 << 7 | type << 2 | dir; celestar@5385: } celestar@5385: } celestar@5385: } celestar@5385: celestar@5385: FOR_ALL_VEHICLES(v) { rubidium@6259: if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue; celestar@5385: if (IsBridgeTile(v->tile)) { smatz@8083: DiagDirection dir = GetTunnelBridgeDirection(v->tile); celestar@5385: celestar@5385: if (dir != DirToDiagDir(v->direction)) continue; celestar@5385: switch (dir) { celestar@5385: default: NOT_REACHED(); celestar@5385: case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; celestar@5385: case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; celestar@5385: case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; celestar@5385: case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; celestar@5385: } celestar@5385: } else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) { celestar@5385: v->tile = GetNorthernBridgeEnd(v->tile); celestar@5385: } else { celestar@5385: continue; celestar@5385: } rubidium@6259: if (v->type == VEH_TRAIN) { rubidium@5587: v->u.rail.track = TRACK_BIT_WORMHOLE; celestar@5385: } else { rubidium@6000: v->u.road.state = RVSB_WORMHOLE; celestar@5385: } celestar@5385: } celestar@5385: } celestar@5385: 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@6259: if (v->type == VEH_TRAIN) { tron@5823: 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@5706: 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@7370: case MP_ROAD: tron@3656: if (IsLevelCrossing(t)) { rubidium@6172: 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@8088: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { smatz@8088: 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) { smatz@9704: if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true); celestar@3355: } celestar@3355: celestar@3355: } celestar@3355: rubidium@10207: /* In version 16.1 of the savegame a company 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)) { rubidium@10207: FOR_ALL_COMPANIES(c) c->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@7928: 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@6451: wp->grfid = statspec->grffile->grfid; belugas@3676: wp->localidx = statspec->localidx; peter1138@2670: } else { belugas@6351: /* 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@6351: /* Move ground type bits from m2 to m4. */ peter1138@2670: _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); belugas@6351: /* 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@5706: for (TileIndex t = 0; t < map_size; t++) { tron@5707: switch (GetTileType(t)) { tron@5707: case MP_RAILWAY: tron@5707: if (HasSignals(t)) { belugas@6351: /* convert PBS signals to combo-signals */ skidd13@7928: if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO); Darkvater@2916: belugas@6351: /* move the signal variant back */ skidd13@7928: SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); skidd13@7929: ClrBit(_m[t].m2, 3); tron@5707: } tron@5707: belugas@6351: /* Clear PBS reservation on track */ smatz@8961: if (!IsRailDepotTile(t)) { tron@5707: SB(_m[t].m4, 4, 4, 0); tron@5707: } else { skidd13@7929: ClrBit(_m[t].m3, 6); tron@5707: } tron@5707: break; tron@5707: rubidium@7370: case MP_ROAD: /* Clear PBS reservation on crossing */ skidd13@7929: if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0); tron@5707: break; tron@5707: belugas@6351: case MP_STATION: /* Clear PBS reservation on station */ skidd13@7929: ClrBit(_m[t].m3, 6); tron@5707: break; Darkvater@2916: tron@5707: default: break; tron@5707: } tron@5706: } Darkvater@2916: } Darkvater@2916: celestar@3431: if (CheckSavegameVersion(25)) { celestar@3431: Vehicle *v; celestar@3431: FOR_ALL_VEHICLES(v) { rubidium@6259: 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@5677: } else { rubidium@5677: Vehicle *v; rubidium@5677: FOR_ALL_VEHICLES(v) { rubidium@6259: if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++; rubidium@5677: } celestar@3431: } celestar@3431: celestar@3580: if (CheckSavegameVersion(26)) { celestar@3580: Station *st; celestar@3580: FOR_ALL_STATIONS(st) { rubidium@6259: st->last_vehicle_type = VEH_INVALID; celestar@3580: } celestar@3580: } celestar@3580: KUDr@3900: YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); KUDr@3900: rubidium@10207: if (CheckSavegameVersion(34)) FOR_ALL_COMPANIES(c) ResetCompanyLivery(c); peter1138@4603: rubidium@10207: FOR_ALL_COMPANIES(c) { rubidium@10207: c->avail_railtypes = GetCompanyRailtypes(c->index); rubidium@10207: c->avail_roadtypes = GetCompanyRoadtypes(c->index); rubidium@6685: } 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: 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@10207: FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@10207: FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@10207: FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@10207: FOR_ALL_COMPANIES(c) c->inaugurated_year += ORIGINAL_BASE_YEAR; rubidium@10207: 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@5706: for (TileIndex t = 0; t < map_size; t++) { tron@5706: if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) { smatz@8811: /* remove fields */ tron@5706: MakeClear(t, CLEAR_GRASS, 3); smatz@8811: } else if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) { smatz@8811: /* remove fences around fields */ smatz@8811: SetFenceSE(t, 0); smatz@8811: SetFenceSW(t, 0); truelight@4328: } tron@5706: } truelight@4328: truelight@4328: FOR_ALL_INDUSTRIES(i) { truelight@4328: uint j; truelight@4328: belugas@6757: 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) { rubidium@8838: order->SetRefit(CT_NO_REFIT); bjarni@4712: } bjarni@4712: bjarni@4712: FOR_ALL_VEHICLES(v) { rubidium@8838: v->current_order.SetRefit(CT_NO_REFIT); bjarni@4712: } bjarni@4712: } bjarni@4712: rubidium@9622: /* from version 38 we have optional elrails, since we cannot know the rubidium@9622: * preference of a user, let elrails enabled; it can be disabled manually */ rubidium@9622: if (CheckSavegameVersion(38)) _settings_game.vehicle.disable_elrails = false; rubidium@9622: /* do the same as when elrails were enabled/disabled manually just now */ rubidium@9622: SettingsDisableElrail(_settings_game.vehicle.disable_elrails); rubidium@9622: InitializeRailGUI(); rubidium@9622: maedhros@6333: /* From version 53, the map array was changed for house tiles to allow maedhros@6332: * space for newhouses grf features. A new byte, m7, was also added. */ maedhros@6333: if (CheckSavegameVersion(53)) { maedhros@6332: for (TileIndex t = 0; t < map_size; t++) { maedhros@6332: if (IsTileType(t, MP_HOUSE)) { maedhros@6332: if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { maedhros@6332: /* Move the construction stage from m3[7..6] to m5[5..4]. maedhros@6332: * The construction counter does not have to move. */ maedhros@6332: SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2)); maedhros@6332: SB(_m[t].m3, 6, 2, 0); maedhros@6332: maedhros@6332: /* The "house is completed" bit is now in m6[2]. */ maedhros@6332: SetHouseCompleted(t, false); maedhros@6332: } else { maedhros@6332: /* The "lift has destination" bit has been moved from maedhros@6332: * m5[7] to m7[0]. */ skidd13@7928: SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7)); skidd13@7929: ClrBit(_m[t].m5, 7); maedhros@6332: maedhros@6332: /* The "lift is moving" bit has been removed, as it does maedhros@6332: * the same job as the "lift has destination" bit. */ skidd13@7929: ClrBit(_m[t].m1, 7); maedhros@6332: maedhros@6332: /* The position of the lift goes from m1[7..0] to m6[7..2], maedhros@6332: * making m1 totally free, now. The lift position does not maedhros@6332: * have to be a full byte since the maximum value is 36. */ maedhros@6332: SetLiftPosition(t, GB(_m[t].m1, 0, 6 )); maedhros@6332: maedhros@6332: _m[t].m1 = 0; maedhros@6332: _m[t].m3 = 0; maedhros@6332: SetHouseCompleted(t, true); maedhros@6332: } maedhros@6332: } maedhros@6332: } maedhros@6332: } maedhros@6332: skidd13@8707: /* Check and update house and town values */ skidd13@8707: UpdateHousesAndTowns(); maedhros@6332: rubidium@5436: if (CheckSavegameVersion(43)) { tron@5706: for (TileIndex t = 0; t < map_size; t++) { tron@5706: if (IsTileType(t, MP_INDUSTRY)) { tron@5706: switch (GetIndustryGfx(t)) { rubidium@5436: case GFX_POWERPLANT_SPARKS: tron@5706: SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5)); rubidium@5436: break; rubidium@5436: rubidium@5436: case GFX_OILWELL_ANIMATED_1: rubidium@5436: case GFX_OILWELL_ANIMATED_2: rubidium@5436: case GFX_OILWELL_ANIMATED_3: tron@5706: SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2)); rubidium@5436: break; rubidium@5436: rubidium@5436: case GFX_COAL_MINE_TOWER_ANIMATED: rubidium@5436: case GFX_COPPER_MINE_TOWER_ANIMATED: rubidium@5436: case GFX_GOLD_MINE_TOWER_ANIMATED: tron@5706: SetIndustryAnimationState(t, _m[t].m1); rubidium@5436: break; rubidium@5436: rubidium@5436: default: /* No animation states to change */ rubidium@5436: break; rubidium@5436: } rubidium@5436: } tron@5706: } rubidium@5436: } rubidium@5436: celestar@5683: if (CheckSavegameVersion(44)) { celestar@5683: Vehicle *v; celestar@5683: /* If we remove a station while cargo from it is still enroute, payment calculation will assume rubidium@7010: * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy celestar@5683: * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded rubidium@7010: * where this situation exists, the cargo-source information is lost. in this case, we set the source celestar@5683: * to the current tile of the vehicle to prevent excessive profits celestar@5683: */ celestar@5683: FOR_ALL_VEHICLES(v) { rubidium@7010: const CargoList::List *packets = v->cargo.Packets(); rubidium@7010: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7010: CargoPacket *cp = *it; rubidium@7010: cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile; rubidium@7010: cp->loaded_at_xy = cp->source_xy; rubidium@7010: } rubidium@7010: v->cargo.InvalidateCache(); celestar@5683: } peter1138@6304: peter1138@6304: /* Store position of the station where the goods come from, so there peter1138@6304: * are no very high payments when stations get removed. However, if the peter1138@6304: * station where the goods came from is already removed, the source peter1138@6304: * information is lost. In that case we set it to the position of this peter1138@6304: * station */ peter1138@6304: Station *st; peter1138@6304: FOR_ALL_STATIONS(st) { peter1138@6304: for (CargoID c = 0; c < NUM_CARGO; c++) { peter1138@6304: GoodsEntry *ge = &st->goods[c]; peter1138@6304: rubidium@7010: const CargoList::List *packets = ge->cargo.Packets(); rubidium@7010: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7010: CargoPacket *cp = *it; rubidium@7010: cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy; rubidium@7010: cp->loaded_at_xy = cp->source_xy; peter1138@6304: } peter1138@6304: } peter1138@6304: } celestar@5683: } celestar@5683: maedhros@5888: if (CheckSavegameVersion(45)) { maedhros@5888: Vehicle *v; maedhros@5888: /* Originally just the fact that some cargo had been paid for was maedhros@5888: * stored to stop people cheating and cashing in several times. This maedhros@5888: * wasn't enough though as it was cleared when the vehicle started maedhros@5888: * loading again, even if it didn't actually load anything, so now the maedhros@5888: * amount of cargo that has been paid for is stored. */ maedhros@5888: FOR_ALL_VEHICLES(v) { rubidium@7010: const CargoList::List *packets = v->cargo.Packets(); rubidium@7010: for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { rubidium@7010: CargoPacket *cp = *it; skidd13@7928: cp->paid_for = HasBit(v->vehicle_flags, 2); maedhros@5888: } skidd13@7929: ClrBit(v->vehicle_flags, 2); rubidium@7010: v->cargo.InvalidateCache(); maedhros@5888: } maedhros@5888: } maedhros@5888: rubidium@5986: /* Buoys do now store the owner of the previous water tile, which can never rubidium@5986: * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ rubidium@5986: if (CheckSavegameVersion(46)) { rubidium@5986: Station *st; rubidium@5986: FOR_ALL_STATIONS(st) { rubidium@7788: if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); rubidium@5986: } rubidium@5986: } rubidium@5986: celestar@6193: if (CheckSavegameVersion(50)) { celestar@6193: Vehicle *v; celestar@6193: /* Aircraft units changed from 8 mph to 1 km/h */ celestar@6193: FOR_ALL_VEHICLES(v) { rubidium@6259: if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) { celestar@6193: const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); celestar@6193: v->cur_speed *= 129; celestar@6193: v->cur_speed /= 10; celestar@6193: v->max_speed = avi->max_speed; celestar@6193: v->acceleration = avi->acceleration; celestar@6193: } celestar@6193: } celestar@6193: } celestar@6193: rubidium@10207: if (CheckSavegameVersion(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face); rubidium@6190: truelight@6257: if (CheckSavegameVersion(52)) { truelight@6257: for (TileIndex t = 0; t < map_size; t++) { truelight@6257: if (IsStatueTile(t)) { rubidium@10236: _m[t].m2 = CalcClosestTownFromTile(t, UINT_MAX)->index; truelight@6257: } truelight@6257: } truelight@6257: } truelight@6257: maedhros@6486: /* A patch option containing the proportion of towns that grow twice as maedhros@6486: * fast was added in version 54. From version 56 this is now saved in the maedhros@6486: * town as cities can be built specifically in the scenario editor. */ maedhros@6486: if (CheckSavegameVersion(56)) { maedhros@6486: Town *t; maedhros@6486: maedhros@6486: FOR_ALL_TOWNS(t) { rubidium@9413: if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) { maedhros@6486: t->larger_town = true; maedhros@6486: } maedhros@6486: } maedhros@6486: } maedhros@6486: rubidium@6500: if (CheckSavegameVersion(57)) { rubidium@6500: Vehicle *v; rubidium@6500: /* Added a FIFO queue of vehicles loading at stations */ rubidium@6500: FOR_ALL_VEHICLES(v) { rubidium@6500: if ((v->type != VEH_TRAIN || IsFrontEngine(v)) && // for all locs rubidium@6500: !(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed rubidium@8836: v->current_order.IsType(OT_LOADING)) { // loading rubidium@6500: GetStation(v->last_station_visited)->loading_vehicles.push_back(v); rubidium@6619: rubidium@6619: /* The loading finished flag is *only* set when actually completely rubidium@6619: * finished. Because the vehicle is loading, it is not finished. */ skidd13@7929: ClrBit(v->vehicle_flags, VF_LOADING_FINISHED); rubidium@6500: } rubidium@6500: } rubidium@7475: } else if (CheckSavegameVersion(59)) { rubidium@7475: /* For some reason non-loading vehicles could be in the station's loading vehicle list */ rubidium@7475: rubidium@7475: Station *st; rubidium@7475: FOR_ALL_STATIONS(st) { rubidium@7475: std::list::iterator iter; rubidium@7475: for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) { rubidium@7475: Vehicle *v = *iter; rubidium@7475: iter++; rubidium@8836: if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v); rubidium@7475: } rubidium@7475: } rubidium@6500: } rubidium@6500: belugas@6560: if (CheckSavegameVersion(58)) { belugas@9950: /* patch difficulty number_industries other than zero get bumped to +1 belugas@6560: * since a new option (very low at position1) has been added */ rubidium@9413: if (_settings_game.difficulty.number_industries > 0) { rubidium@9413: _settings_game.difficulty.number_industries++; belugas@6560: } belugas@6560: belugas@6560: /* Same goes for number of towns, although no test is needed, just an increment */ rubidium@9413: _settings_game.difficulty.number_towns++; belugas@6560: } belugas@6560: glx@6770: if (CheckSavegameVersion(64)) { glx@6770: /* copy the signal type/variant and move signal states bits */ glx@6770: for (TileIndex t = 0; t < map_size; t++) { glx@6770: if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) { glx@6770: SetSignalStates(t, GB(_m[t].m2, 4, 4)); glx@6770: SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X)); glx@6770: SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X)); skidd13@7929: ClrBit(_m[t].m2, 7); glx@6770: } glx@6770: } glx@6770: } glx@6770: rubidium@7012: if (CheckSavegameVersion(69)) { rubidium@7012: /* In some old savegames a bit was cleared when it should not be cleared */ rubidium@7012: Vehicle *v; rubidium@7012: FOR_ALL_VEHICLES(v) { rubidium@7012: if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) { skidd13@7931: SetBit(v->u.road.state, RVS_IS_STOPPING); rubidium@7012: } rubidium@7012: } rubidium@7012: } rubidium@7012: rubidium@7186: if (CheckSavegameVersion(70)) { rubidium@7186: /* Added variables to support newindustries */ rubidium@7186: Industry *i; rubidium@7186: FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE; rubidium@7186: } rubidium@7186: rubidium@7739: /* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported. rubidium@7739: Replace the owner for those by OWNER_NONE. */ rubidium@7739: if (CheckSavegameVersion(82)) { rubidium@7739: for (TileIndex t = 0; t < map_size; t++) { rubidium@7739: if (IsTileType(t, MP_WATER) && rubidium@7739: GetWaterTileType(t) == WATER_TILE_CLEAR && rubidium@7739: GetTileOwner(t) == OWNER_WATER && rubidium@7739: TileHeight(t) != 0) { rubidium@7739: SetTileOwner(t, OWNER_NONE); rubidium@7739: } rubidium@7739: } rubidium@7739: } rubidium@7739: rubidium@8029: /* rubidium@8029: * Add the 'previous' owner to the ship depots so we can reset it with rubidium@8029: * the correct values when it gets destroyed. This prevents that rubidium@8029: * someone can remove canals owned by somebody else and it prevents rubidium@8029: * making floods using the removal of ship depots. rubidium@8029: */ rubidium@8029: if (CheckSavegameVersion(83)) { rubidium@8029: for (TileIndex t = 0; t < map_size; t++) { rubidium@8029: if (IsTileType(t, MP_WATER) && IsShipDepot(t)) { rubidium@8029: _m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE; rubidium@8029: } rubidium@8029: } rubidium@8029: } rubidium@8029: rubidium@7515: if (CheckSavegameVersion(74)) { rubidium@7515: Station *st; rubidium@7515: FOR_ALL_STATIONS(st) { rubidium@7515: for (CargoID c = 0; c < NUM_CARGO; c++) { rubidium@7515: st->goods[c].last_speed = 0; skidd13@7931: if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP); rubidium@7515: } rubidium@7515: } rubidium@7515: } rubidium@7515: glx@7645: if (CheckSavegameVersion(78)) { glx@7645: Industry *i; glx@7645: uint j; glx@7645: FOR_ALL_INDUSTRIES(i) { glx@7645: const IndustrySpec *indsp = GetIndustrySpec(i->type); glx@7645: for (j = 0; j < lengthof(i->produced_cargo); j++) { glx@7645: i->produced_cargo[j] = indsp->produced_cargo[j]; glx@7645: } glx@7645: for (j = 0; j < lengthof(i->accepts_cargo); j++) { glx@7645: i->accepts_cargo[j] = indsp->accepts_cargo[j]; glx@7645: } glx@7645: } glx@7645: } rubidium@6643: truelight@7710: /* Before version 81, the density of grass was always stored as zero, and truelight@7710: * grassy trees were always drawn fully grassy. Furthermore, trees on rough truelight@7710: * land used to have zero density, now they have full density. Therefore, truelight@7710: * make all grassy/rough land trees have a density of 3. */ truelight@7710: if (CheckSavegameVersion(81)) { truelight@7710: for (TileIndex t = 0; t < map_size; t++) { truelight@7710: if (GetTileType(t) == MP_TREES) { truelight@7710: TreeGround groundType = GetTreeGround(t); truelight@7710: if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3); truelight@7710: } truelight@7710: } truelight@7710: } truelight@7710: rubidium@8926: rubidium@8926: if (CheckSavegameVersion(93)) { rubidium@8926: /* Rework of orders. */ rubidium@8926: Order *order; rubidium@8926: FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame(); rubidium@8926: rubidium@8926: Vehicle *v; rubidium@8926: FOR_ALL_VEHICLES(v) { rubidium@8926: if (v->orders != NULL && !v->orders->IsValid()) v->orders = NULL; rubidium@8926: rubidium@8926: v->current_order.ConvertFromOldSavegame(); rubidium@9941: if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) { rubidium@8926: FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); rubidium@8926: } rubidium@8926: } rubidium@8926: } else if (CheckSavegameVersion(94)) { rubidium@8926: /* Unload and transfer are now mutual exclusive. */ rubidium@8926: Order *order; rubidium@8926: FOR_ALL_ORDERS(order) { rubidium@8926: if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { rubidium@8926: order->SetUnloadType(OUFB_TRANSFER); rubidium@8926: order->SetLoadType(OLFB_NO_LOAD); rubidium@8926: } rubidium@8926: } rubidium@8926: rubidium@8926: Vehicle *v; rubidium@8926: FOR_ALL_VEHICLES(v) { rubidium@8926: if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { rubidium@8926: v->current_order.SetUnloadType(OUFB_TRANSFER); rubidium@8926: v->current_order.SetLoadType(OLFB_NO_LOAD); rubidium@8926: } rubidium@8926: } rubidium@8926: } rubidium@8926: glx@8057: if (CheckSavegameVersion(84)) { smatz@8155: /* Update go to buoy orders because they are just waypoints */ glx@8057: Order *order; glx@8057: FOR_ALL_ORDERS(order) { rubidium@8840: if (order->IsType(OT_GOTO_STATION) && GetStation(order->GetDestination())->IsBuoy()) { rubidium@8855: order->SetLoadType(OLF_LOAD_IF_POSSIBLE); rubidium@8855: order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); glx@8057: } glx@8057: } smatz@8155: rubidium@10207: /* Set all share owners to INVALID_COMPANY for rubidium@10207: * 1) all inactive companies rubidium@10207: * (when inactive companies were stored in the savegame - TTD, TTDP and some rubidium@10207: * *really* old revisions of OTTD; else it is already set in InitializeCompanies()) rubidium@10207: * 2) shares that are owned by inactive companies or self rubidium@10207: * (caused by cheating clients in earlier revisions) */ rubidium@10207: FOR_ALL_COMPANIES(c) { rubidium@9659: for (uint i = 0; i < 4; i++) { rubidium@10207: CompanyID company = c->share_owners[i]; rubidium@10207: if (company == INVALID_COMPANY) continue; rubidium@10207: if (!IsValidCompanyID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY; smatz@8155: } smatz@8155: } glx@8057: } glx@8057: smatz@8342: if (CheckSavegameVersion(86)) { smatz@8342: for (TileIndex t = 0; t < map_size; t++) { peter1138@8471: /* Move river flag and update canals to use water class */ peter1138@8471: if (IsTileType(t, MP_WATER)) { rubidium@9200: if (GetWaterClass(t) != WATER_CLASS_RIVER) { frosch@8495: if (IsWater(t)) { frosch@8495: Owner o = GetTileOwner(t); frosch@8495: if (o == OWNER_WATER) { frosch@8495: MakeWater(t); frosch@8495: } else { frosch@8495: MakeCanal(t, o, Random()); frosch@8495: } frosch@8495: } else if (IsShipDepot(t)) { frosch@8495: Owner o = (Owner)_m[t].m4; // Original water owner frosch@8495: SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL); peter1138@8471: } peter1138@8471: } peter1138@8471: } peter1138@8471: } peter1138@8471: peter1138@8471: /* Update locks, depots, docks and buoys to have a water class based peter1138@8471: * on its neighbouring tiles. Done after river and canal updates to peter1138@8471: * ensure neighbours are correct. */ peter1138@8471: for (TileIndex t = 0; t < map_size; t++) { peter1138@8471: if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue; peter1138@8471: frosch@9718: if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false); frosch@9718: if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false); smatz@8342: } smatz@8342: } smatz@8342: smatz@8521: if (CheckSavegameVersion(87)) { smatz@8521: for (TileIndex t = 0; t < map_size; t++) { smatz@8613: /* skip oil rigs at borders! */ smatz@8613: if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) && smatz@8613: (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) { smatz@8525: /* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy). smatz@8525: * This conversion has to be done before buoys with invalid owner are removed. */ smatz@8525: SetWaterClass(t, WATER_CLASS_SEA); smatz@8525: } smatz@8525: smatz@8521: if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { smatz@8521: Owner o = GetTileOwner(t); rubidium@10207: if (o < MAX_COMPANIES && !IsValidCompanyID(o)) { rubidium@10207: _current_company = o; rubidium@10207: ChangeTileOwner(t, o, INVALID_OWNER); smatz@8521: } smatz@8521: if (IsBuoyTile(t)) { smatz@8521: /* reset buoy owner to OWNER_NONE in the station struct rubidium@10207: * (even if it is owned by active company) */ smatz@8521: GetStationByTile(t)->owner = OWNER_NONE; smatz@8521: } smatz@8521: } else if (IsTileType(t, MP_ROAD)) { smatz@8521: /* works for all RoadTileType */ smatz@8521: for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { smatz@8521: /* update even non-existing road types to update tile owner too */ smatz@8521: Owner o = GetRoadOwner(t, rt); rubidium@10207: if (o < MAX_COMPANIES && !IsValidCompanyID(o)) SetRoadOwner(t, rt, OWNER_NONE); smatz@8521: } frosch@8563: if (IsLevelCrossing(t)) { smatz@8521: Owner o = GetTileOwner(t); rubidium@10207: if (!IsValidCompanyID(o)) { smatz@8521: /* remove leftover rail piece from crossing (from very old savegames) */ rubidium@10207: _current_company = o; smatz@8598: DoCommand(t, 0, GetCrossingRailTrack(t), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL); smatz@8521: } smatz@8521: } smatz@8521: } smatz@8521: } smatz@8551: smatz@8551: /* Convert old PF settings to new */ rubidium@9413: if (_settings_game.pf.yapf.rail_use_yapf || CheckSavegameVersion(28)) { rubidium@9413: _settings_game.pf.pathfinder_for_trains = VPF_YAPF; smatz@8551: } else { rubidium@9413: _settings_game.pf.pathfinder_for_trains = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_NTP); smatz@8551: } smatz@8551: rubidium@9413: if (_settings_game.pf.yapf.road_use_yapf || CheckSavegameVersion(28)) { rubidium@9413: _settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF; smatz@8551: } else { rubidium@9413: _settings_game.pf.pathfinder_for_roadvehs = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); smatz@8551: } smatz@8551: rubidium@9413: if (_settings_game.pf.yapf.ship_use_yapf) { rubidium@9413: _settings_game.pf.pathfinder_for_ships = VPF_YAPF; smatz@8551: } else { rubidium@9413: _settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); smatz@8551: } smatz@8521: } smatz@8521: smatz@8556: if (CheckSavegameVersion(88)) { smatz@8556: /* Profits are now with 8 bit fract */ smatz@8556: Vehicle *v; smatz@8556: FOR_ALL_VEHICLES(v) { smatz@8556: v->profit_this_year <<= 8; smatz@8556: v->profit_last_year <<= 8; smatz@8556: v->running_ticks = 0; smatz@8556: } smatz@8556: } smatz@8556: frosch@8681: if (CheckSavegameVersion(91)) { frosch@8681: /* Increase HouseAnimationFrame from 5 to 7 bits */ frosch@8681: for (TileIndex t = 0; t < map_size; t++) { frosch@8681: if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) { frosch@8681: SetHouseAnimationFrame(t, GB(_m[t].m6, 3, 5)); frosch@8681: } frosch@8681: } frosch@8681: } frosch@8681: smatz@9057: if (CheckSavegameVersion(62)) { smatz@9057: /* Remove all trams from savegames without tram support. smatz@9057: * There would be trams without tram track under causing crashes sooner or later. */ smatz@9057: Vehicle *v; smatz@9057: FOR_ALL_VEHICLES(v) { smatz@9057: if (v->type == VEH_ROAD && v->First() == v && smatz@9057: HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { smatz@9057: if (_switch_mode_errorstr == INVALID_STRING_ID || _switch_mode_errorstr == STR_NEWGRF_COMPATIBLE_LOAD_WARNING) { smatz@9057: _switch_mode_errorstr = STR_LOADGAME_REMOVED_TRAMS; smatz@9057: } smatz@9057: delete v; smatz@9057: } smatz@9057: } smatz@9057: } smatz@9057: frosch@9718: if (CheckSavegameVersion(99)) { frosch@9718: for (TileIndex t = 0; t < map_size; t++) { frosch@10360: /* Set newly introduced WaterClass of industry tiles */ frosch@9718: if (IsTileType(t, MP_STATION) && IsOilRig(t)) { frosch@9718: SetWaterClassDependingOnSurroundings(t, true); frosch@9718: } frosch@9718: if (IsTileType(t, MP_INDUSTRY)) { frosch@9718: if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) { frosch@9718: SetWaterClassDependingOnSurroundings(t, true); frosch@9718: } else { frosch@9718: SetWaterClass(t, WATER_CLASS_INVALID); frosch@9718: } frosch@9718: } frosch@10360: frosch@10360: /* Replace "house construction year" with "house age" */ frosch@10360: if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) { frosch@10360: _m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF); frosch@10360: } frosch@9718: } frosch@9718: } frosch@9718: rubidium@9790: /* Move the signal variant back up one bit for PBS. We don't convert the old PBS rubidium@9790: * format here, as an old layout wouldn't work properly anyway. To be safe, we rubidium@9790: * clear any possible PBS reservations as well. */ rubidium@9790: if (CheckSavegameVersion(100)) { rubidium@9790: for (TileIndex t = 0; t < map_size; t++) { rubidium@9790: switch (GetTileType(t)) { rubidium@9790: case MP_RAILWAY: rubidium@9790: if (HasSignals(t)) { rubidium@9790: /* move the signal variant */ rubidium@9790: SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC); rubidium@9790: SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC); rubidium@9790: ClrBit(_m[t].m2, 2); rubidium@9790: ClrBit(_m[t].m2, 6); rubidium@9790: } rubidium@9790: rubidium@9790: /* Clear PBS reservation on track */ rubidium@9790: if (IsRailDepot(t) ||IsRailWaypoint(t)) { rubidium@9790: SetDepotWaypointReservation(t, false); rubidium@9790: } else { rubidium@9790: SetTrackReservation(t, TRACK_BIT_NONE); rubidium@9790: } rubidium@9790: break; rubidium@9790: rubidium@9790: case MP_ROAD: /* Clear PBS reservation on crossing */ rubidium@9790: if (IsLevelCrossing(t)) SetCrossingReservation(t, false); rubidium@9790: break; rubidium@9790: rubidium@9790: case MP_STATION: /* Clear PBS reservation on station */ rubidium@9790: if (IsRailwayStation(t)) SetRailwayStationReservation(t, false); rubidium@9790: break; rubidium@9790: rubidium@9790: case MP_TUNNELBRIDGE: /* Clear PBS reservation on tunnels/birdges */ rubidium@9790: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false); rubidium@9790: break; rubidium@9790: rubidium@9790: default: break; rubidium@9790: } rubidium@9790: } rubidium@9790: } rubidium@9790: rubidium@9888: /* Reserve all tracks trains are currently on. */ rubidium@9888: if (CheckSavegameVersion(101)) { rubidium@9888: Vehicle *v; rubidium@9888: FOR_ALL_VEHICLES(v) { rubidium@9888: if (v->type == VEH_TRAIN) { rubidium@9888: if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) { rubidium@9888: TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile))); rubidium@9888: } else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) { rubidium@9888: TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track)); rubidium@9888: } rubidium@9888: } rubidium@9888: } belugas@9978: belugas@9978: /* Give owners to waypoints, based on rail tracks it is sitting on. belugas@9978: * If none is available, specify OWNER_NONE */ belugas@9978: Waypoint *wp; belugas@9978: FOR_ALL_WAYPOINTS(wp) { smatz@10099: Owner owner = (IsRailWaypointTile(wp->xy) ? GetTileOwner(wp->xy) : OWNER_NONE); rubidium@10207: wp->owner = IsValidCompanyID(owner) ? owner : OWNER_NONE; belugas@9978: } rubidium@9888: } rubidium@9888: smatz@10106: if (CheckSavegameVersion(102)) { smatz@10106: for (TileIndex t = 0; t < map_size; t++) { smatz@10106: /* Now all crossings should be in correct state */ smatz@10106: if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false); smatz@10106: } smatz@10106: } smatz@10106: smatz@10158: if (CheckSavegameVersion(103)) { rubidium@10289: /* Non-town-owned roads now store the closest town */ smatz@10340: UpdateNearestTownForRoadTiles(false); rubidium@10289: smatz@10158: /* signs with invalid owner left from older savegames */ smatz@10158: Sign *si; smatz@10158: FOR_ALL_SIGNS(si) { rubidium@10207: if (si->owner != OWNER_NONE && !IsValidCompanyID(si->owner)) si->owner = OWNER_NONE; smatz@10158: } rubidium@10347: rubidium@10347: /* Station can get named based on an industry type, but the current ones rubidium@10347: * are not, so mark them as if they are not named by an industry. */ rubidium@10347: Station *st; rubidium@10347: FOR_ALL_STATIONS(st) { rubidium@10347: st->indtype = IT_INVALID; rubidium@10347: } smatz@10158: } smatz@10106: smatz@9655: GamelogPrintDebug(1); smatz@9457: rubidium@7981: 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@6247: void ReloadNewGRFData() Darkvater@5352: { Darkvater@5352: /* reload grf data */ Darkvater@5352: GfxLoadSprites(); Darkvater@5352: LoadStringWidthTable(); peter1138@9717: ResetEconomy(); Darkvater@5352: /* reload vehicles */ Darkvater@5352: ResetVehiclePosHash(); peter1138@8172: AfterLoadVehicles(false); Darkvater@6196: StartupEngines(); smatz@9220: SetCachedEngineCounts(); Darkvater@5352: /* update station and waypoint graphics */ Darkvater@5352: AfterLoadWaypoints(); Darkvater@5352: AfterLoadStations(); skidd13@8707: /* Check and update house and town values */ skidd13@8707: UpdateHousesAndTowns(); glx@9230: /* Update livery selection windows */ rubidium@10207: for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOR, i, _loaded_newgrf_features.has_2CC); Darkvater@5352: /* redraw the whole screen */ Darkvater@5352: MarkWholeScreenDirty(); smatz@9704: CheckTrainsLengths(); Darkvater@5352: }