tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" tron@1317: #include "string.h" tron@507: #include "table/strings.h" tron@1299: #include "debug.h" tron@2171: #include "driver.h" tron@2162: #include "saveload.h" tron@1309: #include "strings.h" tron@679: #include "map.h" tron@1209: #include "tile.h" tron@3144: #include "void_map.h" truelight@0: truelight@0: #define VARDEF Darkvater@1891: #include "openttd.h" tron@3367: #include "bridge_map.h" tron@2163: #include "functions.h" tron@1496: #include "mixer.h" tron@1349: #include "spritecache.h" Darkvater@4912: #include "strings.h" truelight@0: #include "gfx.h" tron@2340: #include "gfxinit.h" truelight@0: #include "gui.h" truelight@0: #include "station.h" tron@3367: #include "station_map.h" tron@3558: #include "town_map.h" tron@3367: #include "tunnel_map.h" truelight@0: #include "vehicle.h" truelight@0: #include "viewport.h" truelight@0: #include "window.h" truelight@0: #include "player.h" truelight@0: #include "command.h" truelight@0: #include "town.h" truelight@0: #include "industry.h" truelight@0: #include "news.h" truelight@0: #include "engine.h" truelight@0: #include "sound.h" truelight@0: #include "economy.h" truelight@0: #include "fileio.h" truelight@0: #include "hal.h" truelight@0: #include "airport.h" dominik@126: #include "console.h" tron@430: #include "screenshot.h" truelight@543: #include "network.h" truelight@988: #include "signs.h" truelight@1313: #include "depot.h" truelight@1542: #include "waypoint.h" truelight@2395: #include "ai/ai.h" bjarni@2855: #include "train.h" KUDr@3900: #include "yapf/yapf.h" rubidium@3889: #include "settings.h" truelight@4300: #include "genworld.h" rubidium@4261: #include "date.h" truelight@4328: #include "clear_map.h" peter1138@5108: #include "fontcache.h" peter1138@5228: #include "newgrf_config.h" truelight@0: celestar@5385: #include "bridge_map.h" celestar@5385: #include "clear_map.h" celestar@5385: #include "rail_map.h" celestar@5385: #include "road_map.h" celestar@5385: #include "water_map.h" celestar@5385: truelight@0: #include truelight@0: tron@1093: void CallLandscapeTick(void); tron@1093: void IncreaseDate(void); tron@1093: void DoPaletteAnimations(void); tron@1093: void MusicLoop(void); tron@1093: void ResetMusic(void); tron@1093: void InitializeStations(void); tron@1093: void DeleteAllPlayerStations(void); truelight@0: truelight@0: extern void SetDifficultyLevel(int mode, GameOptions *gm_opt); truelight@0: extern void DoStartupNewPlayer(bool is_ai); truelight@0: extern void ShowOSErrorBox(const char *buf); truelight@0: pasky@1436: /* TODO: usrerror() for errors which are not of an internal nature but pasky@1436: * caused by the user, i.e. missing files or fatal configuration errors. pasky@1436: * Post-0.4.0 since Celestar doesn't want this in SVN before. --pasky */ pasky@1436: belugas@4171: void CDECL error(const char *s, ...) tron@2639: { truelight@0: va_list va; truelight@0: char buf[512]; tron@2639: truelight@0: va_start(va, s); Darkvater@5170: vsnprintf(buf, lengthof(buf), s, va); truelight@0: va_end(va); truelight@193: truelight@0: ShowOSErrorBox(buf); tron@2639: if (_video_driver != NULL) _video_driver->stop(); truelight@0: truelight@0: assert(0); truelight@0: exit(1); truelight@0: } truelight@0: truelight@0: void CDECL ShowInfoF(const char *str, ...) truelight@0: { truelight@0: va_list va; truelight@0: char buf[1024]; truelight@0: va_start(va, str); Darkvater@5170: vsnprintf(buf, lengthof(buf), str, va); truelight@0: va_end(va); truelight@0: ShowInfo(buf); truelight@0: } truelight@0: truelight@0: tron@1310: void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) truelight@0: { truelight@0: FILE *in; tron@1105: byte *mem; truelight@0: size_t len; truelight@0: truelight@0: in = fopen(filename, "rb"); tron@2639: if (in == NULL) return NULL; truelight@0: truelight@0: fseek(in, 0, SEEK_END); truelight@0: len = ftell(in); truelight@0: fseek(in, 0, SEEK_SET); tron@1105: if (len > maxsize || (mem = malloc(len + 1)) == NULL) { truelight@0: fclose(in); truelight@0: return NULL; truelight@0: } tron@1105: mem[len] = 0; truelight@0: if (fread(mem, len, 1, in) != 1) { truelight@0: fclose(in); truelight@0: free(mem); truelight@0: return NULL; truelight@0: } truelight@0: fclose(in); truelight@0: truelight@0: *lenp = len; truelight@0: return mem; truelight@0: } truelight@0: tron@1093: static void showhelp(void) truelight@0: { Darkvater@4840: extern const char _openttd_revision[]; truelight@0: char buf[4096], *p; truelight@0: Darkvater@5170: p = buf; truelight@2831: Darkvater@5170: p += snprintf(p, lengthof(buf), "OpenTTD %s\n", _openttd_revision); Darkvater@5170: p = strecpy(p, truelight@2831: "\n" truelight@2831: "\n" truelight@0: "Command line options:\n" truelight@543: " -v drv = Set video driver (see below)\n" truelight@543: " -s drv = Set sound driver (see below)\n" truelight@543: " -m drv = Set music driver (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" truelight@543: " -n [ip#player:port] = Start networkgame\n" truelight@543: " -D = Start dedicated server\n" tron@4077: #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) truelight@704: " -f = Fork into the background (dedicated only)\n" tron@4077: #endif truelight@2831: " -i = Force to use the DOS palette\n" truelight@2831: " (use this if you see a lot of pink)\n" truelight@2831: " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" Darkvater@5170: "\n", Darkvater@5170: lastof(buf) truelight@0: ); truelight@0: Darkvater@5170: p = GetDriverList(p, lastof(buf)); truelight@0: truelight@0: ShowInfo(buf); truelight@0: } truelight@0: truelight@0: truelight@0: typedef struct { truelight@0: char *opt; truelight@0: int numleft; truelight@0: char **argv; truelight@0: const char *options; truelight@0: char *cont; truelight@0: } MyGetOptData; truelight@0: truelight@0: static void MyGetOptInit(MyGetOptData *md, int argc, char **argv, const char *options) truelight@0: { truelight@0: md->cont = NULL; truelight@0: md->numleft = argc; truelight@0: md->argv = argv; truelight@0: md->options = options; truelight@0: } truelight@0: truelight@0: static int MyGetOpt(MyGetOptData *md) truelight@0: { truelight@0: 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) { truelight@0: // Found argument, try to locate it in options. truelight@0: if (*s == ':' || (r = strchr(md->options, *s)) == NULL) { truelight@0: // ERROR! truelight@0: return -2; truelight@0: } truelight@0: if (r[1] == ':') { truelight@0: // Item wants an argument. Check if the argument follows, or if it comes as a separate arg. truelight@0: if (!*(t = s + 1)) { truelight@0: // It comes as a separate arg. Check if out of args? truelight@0: if (--md->numleft < 0 || *(t = *md->argv) == '-') { truelight@0: // 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: } truelight@0: md->opt = 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 { truelight@0: // This is currently not supported. truelight@0: return -2; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: belugas@4171: static void ParseResolution(int res[2], const char *s) truelight@0: { truelight@0: char *t = strchr(s, 'x'); truelight@0: if (t == NULL) { truelight@0: ShowInfoF("Invalid resolution '%s'", s); truelight@0: return; truelight@0: } truelight@0: Darkvater@1764: res[0] = clamp(strtoul(s, NULL, 0), 64, MAX_SCREEN_WIDTH); Darkvater@1764: res[1] = clamp(strtoul(t + 1, NULL, 0), 64, MAX_SCREEN_HEIGHT); truelight@193: } truelight@0: truelight@919: static void InitializeDynamicVariables(void) truelight@919: { truelight@919: /* Dynamic stuff needs to be initialized somewhere... */ truelight@1267: _town_sort = NULL; truelight@919: _industry_sort = NULL; truelight@919: } truelight@919: truelight@919: static void UnInitializeDynamicVariables(void) truelight@919: { truelight@919: /* Dynamic stuff needs to be free'd somewhere... */ tron@4983: CleanPool(&_Town_pool); tron@4976: CleanPool(&_Industry_pool); tron@4980: CleanPool(&_Station_pool); tron@4972: CleanPool(&_Vehicle_pool); tron@4979: CleanPool(&_Sign_pool); tron@4977: CleanPool(&_Order_pool); truelight@1260: tron@4277: free((void*)_town_sort); tron@4277: free((void*)_industry_sort); truelight@919: } truelight@919: Darkvater@1474: static void UnInitializeGame(void) Darkvater@1474: { Darkvater@1474: UnInitWindowSystem(); Darkvater@1482: Darkvater@1482: free(_config_file); Darkvater@1474: } truelight@919: tron@1095: static void LoadIntroGame(void) truelight@543: { truelight@543: char filename[256]; Darkvater@1500: truelight@543: _game_mode = GM_MENU; Darkvater@1500: CLRBITS(_display_opt, DO_TRANS_BUILDINGS); // don't make buildings transparent in intro Darkvater@1500: _opt_ptr = &_opt_newgame; peter1138@5228: ResetGRFConfig(false); truelight@543: truelight@543: // Setup main window Darkvater@1474: ResetWindowSystem(); truelight@543: SetupColorsAndInitialWindow(); truelight@543: truelight@543: // Generate a world. Darkvater@5296: snprintf(filename, lengthof(filename), "%sopntitle.dat", _paths.data_dir); tron@3033: #if defined SECOND_DATA_DIR tron@921: if (SaveOrLoad(filename, SL_LOAD) != SL_OK) { Darkvater@5296: snprintf(filename, lengthof(filename), "%sopntitle.dat", _paths.second_data_dir); tron@3033: } bjarni@561: #endif tron@3033: if (SaveOrLoad(filename, SL_LOAD) != SL_OK) { tron@3033: GenerateWorld(GW_EMPTY, 64, 64); // if failed loading, make empty world. truelight@4300: WaitTillGeneratedWorld(); tron@921: } truelight@543: truelight@543: _pause = 0; rubidium@5376: SetLocalPlayer(0); truelight@4336: /* Make sure you can't scroll in the menu */ truelight@4336: _scrolling_viewport = 0; truelight@4336: _cursor.fix_at = false; truelight@543: MarkWholeScreenDirty(); truelight@543: truelight@543: // Play main theme truelight@543: if (_music_driver->is_song_playing()) ResetMusic(); truelight@543: } truelight@543: truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) darkvater@774: extern void DedicatedFork(void); truelight@2290: #endif truelight@704: belugas@4171: int ttd_main(int argc, char *argv[]) truelight@0: { truelight@0: MyGetOptData mgo; truelight@0: int i; tron@1010: const char *optformat; truelight@469: char musicdriver[16], sounddriver[16], videodriver[16]; truelight@0: int resolution[2] = {0,0}; rubidium@4293: Year startyear = INVALID_YEAR; truelight@4300: uint generation_seed = GENERATE_NEW_SEED; Darkvater@3058: bool dedicated = false; Darkvater@3058: bool network = false; Darkvater@3058: char *network_conn = NULL; tron@1406: truelight@0: musicdriver[0] = sounddriver[0] = videodriver[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: truelight@543: // The last param of the following function means this: truelight@543: // a letter means: it accepts that param (e.g.: -h) truelight@543: // a ':' behind it means: it need a param (e.g.: -m) truelight@543: // a '::' behind it means: it can optional have a param (e.g.: -d) Darkvater@4854: optformat = "m:s:v:hDn::eit:d::r:g::G:c:" tron@4077: #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) tron@4077: "f" tron@4077: #endif tron@4077: ; bjarni@770: bjarni@770: MyGetOptInit(&mgo, argc-1, argv+1, optformat); truelight@0: while ((i = MyGetOpt(&mgo)) != -1) { tron@2951: switch (i) { truelight@0: case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break; truelight@0: case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break; truelight@0: case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break; Darkvater@3058: case 'D': Darkvater@3058: strcpy(musicdriver, "null"); Darkvater@3058: strcpy(sounddriver, "null"); Darkvater@3058: strcpy(videodriver, "dedicated"); Darkvater@3058: dedicated = true; 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@0: case 'r': ParseResolution(resolution, mgo.opt); break; rubidium@4285: case 't': startyear = atoi(mgo.opt); break; truelight@0: case 'd': { truelight@0: #if defined(WIN32) truelight@0: CreateConsole(); truelight@0: #endif tron@2639: if (mgo.opt != NULL) SetDebugString(mgo.opt); truelight@0: } break; truelight@0: case 'e': _switch_mode = SM_EDITOR; break; dominik@614: case 'i': _use_dos_palette = true; break; truelight@193: case 'g': tron@2639: if (mgo.opt != NULL) { truelight@0: strcpy(_file_to_saveload.name, mgo.opt); truelight@0: _switch_mode = SM_LOAD; tron@4077: } else { truelight@0: _switch_mode = SM_NEWGAME; tron@4077: } truelight@0: break; truelight@4300: case 'G': generation_seed = atoi(mgo.opt); break; Darkvater@3058: case 'c': _config_file = strdup(mgo.opt); break; truelight@0: case -2: tron@2026: case 'h': truelight@0: showhelp(); truelight@0: return 0; truelight@0: } truelight@0: } truelight@0: truelight@0: DeterminePaths(); dominik@961: CheckExternalFiles(); truelight@704: truelight@2290: #if defined(UNIX) && !defined(__MORPHOS__) truelight@704: // 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: truelight@0: // override config? truelight@469: if (musicdriver[0]) ttd_strlcpy(_ini_musicdriver, musicdriver, sizeof(_ini_musicdriver)); truelight@469: if (sounddriver[0]) ttd_strlcpy(_ini_sounddriver, sounddriver, sizeof(_ini_sounddriver)); truelight@469: if (videodriver[0]) ttd_strlcpy(_ini_videodriver, videodriver, sizeof(_ini_videodriver)); truelight@0: if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; } rubidium@4293: if (startyear != INVALID_YEAR) _patches_newgame.starting_year = startyear; truelight@4300: if (generation_seed != GENERATE_NEW_SEED) _patches_newgame.generation_seed = generation_seed; truelight@0: tron@2951: if (_dedicated_forks && !dedicated) _dedicated_forks = false; truelight@704: truelight@0: // enumerate language files truelight@0: InitializeLanguagePacks(); truelight@0: truelight@0: // initialize screenshot formats truelight@0: InitializeScreenshotFormats(); truelight@0: dominik@105: // initialize airport state machines dominik@105: InitializeAirports(); truelight@193: truelight@919: /* initialize all variables that are allocated dynamically */ truelight@919: InitializeDynamicVariables(); truelight@919: truelight@2395: /* start the AI */ truelight@2395: AI_Initialize(); truelight@2395: truelight@0: // 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: truelight@0: // This must be done early, since functions use the InvalidateWindow* calls truelight@139: InitWindowSystem(); truelight@0: peter1138@5166: /* Initialize game palette */ peter1138@5166: GfxInitPalettes(); peter1138@5166: Darkvater@5380: DEBUG(driver, 1, "Loading drivers..."); truelight@0: LoadDriver(SOUND_DRIVER, _ini_sounddriver); truelight@0: LoadDriver(MUSIC_DRIVER, _ini_musicdriver); truelight@0: LoadDriver(VIDEO_DRIVER, _ini_videodriver); // load video last, to prevent an empty window while sound and music loads tron@2526: _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; truelight@0: glx@3678: // restore saved music volume glx@3678: _music_driver->set_volume(msf.music_vol); glx@3678: Darkvater@4830: NetworkStartUp(); // initialize network-core truelight@543: peter1138@5228: ScanNewGRFFiles(); peter1138@5228: Darkvater@1500: _opt_ptr = &_opt_newgame; peter1138@5228: ResetGRFConfig(false); truelight@193: Darkvater@1500: /* XXX - ugly hack, if diff_level is 9, it means we got no setting from the config file */ tron@2951: if (_opt_newgame.diff_level == 9) SetDifficultyLevel(0, &_opt_newgame); truelight@0: truelight@4300: /* Make sure _patches is filled with _patches_newgame if we switch to a game directly */ truelight@4300: if (_switch_mode != SM_NONE) { tron@5024: _opt = _opt_newgame; truelight@4300: UpdatePatches(); truelight@4300: } truelight@4300: truelight@139: // initialize the ingame console truelight@139: IConsoleInit(); Darkvater@3312: _cursor.in_window = true; darkvater@1246: InitializeGUI(); dominik@644: IConsoleCmdExec("exec scripts/autoexec.scr 0"); truelight@656: truelight@2828: GenerateWorld(GW_EMPTY, 64, 64); // Make the viewport initialization happy truelight@4300: WaitTillGeneratedWorld(); truelight@1268: truelight@543: #ifdef ENABLE_NETWORK tron@2951: if (network && _network_available) { truelight@543: if (network_conn != NULL) { tron@1329: const char *port = NULL; tron@1329: const char *player = NULL; truelight@543: uint16 rport; truelight@543: truelight@543: rport = NETWORK_DEFAULT_PORT; Darkvater@4878: _network_playas = PLAYER_NEW_COMPANY; truelight@543: truelight@543: ParseConnectionString(&player, &port, network_conn); truelight@543: Darkvater@4861: if (player != NULL) { Darkvater@4861: _network_playas = atoi(player); Darkvater@4878: Darkvater@4880: if (_network_playas != PLAYER_SPECTATOR) { Darkvater@4880: _network_playas--; Darkvater@4878: if (!IsValidPlayer(_network_playas)) return false; Darkvater@4878: } Darkvater@4861: } truelight@543: if (port != NULL) rport = atoi(port); truelight@543: truelight@543: LoadIntroGame(); truelight@543: _switch_mode = SM_NONE; truelight@543: NetworkClientConnectGame(network_conn, rport); tron@1109: } truelight@543: } truelight@543: #endif /* ENABLE_NETWORK */ truelight@543: tron@2228: _video_driver->main_loop(); truelight@139: tron@2285: WaitTillSaved(); truelight@139: IConsoleFree(); truelight@0: Darkvater@4830: if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections truelight@0: truelight@0: _video_driver->stop(); truelight@0: _music_driver->stop(); truelight@0: _sound_driver->stop(); truelight@0: truelight@0: SaveToConfig(); darkvater@983: SaveToHighScore(); truelight@0: dominik@105: // uninitialize airport state machines dominik@105: UnInitializeAirports(); truelight@0: truelight@919: /* uninitialize variables that are allocated dynamic */ truelight@919: UnInitializeDynamicVariables(); truelight@919: truelight@2395: /* stop the AI */ truelight@2395: AI_Uninitialize(); truelight@2395: darkvater@1036: /* Close all and any open filehandles */ darkvater@1036: FioCloseAll(); Darkvater@1474: UnInitializeGame(); darkvater@1036: truelight@0: return 0; truelight@0: } truelight@0: rubidium@4548: void HandleExitGameRequest(void) rubidium@4548: { rubidium@4548: if (_game_mode == GM_MENU) { // do not ask to quit on the main screen rubidium@4548: _exit_game = true; rubidium@4548: } else if (_patches.autosave_on_exit) { rubidium@4548: DoExitSave(); rubidium@4548: _exit_game = true; rubidium@4548: } else { rubidium@4548: AskExitGame(); rubidium@4548: } rubidium@4548: } rubidium@4548: rubidium@4548: Darkvater@2380: /** Mutex so that only one thread can communicate with the main program Darkvater@2380: * at any given time */ truelight@4323: static ThreadMsg _message = MSG_OTTD_NO_MESSAGE; Darkvater@2380: truelight@4323: static inline void OTTD_ReleaseMutex(void) {_message = MSG_OTTD_NO_MESSAGE;} Darkvater@2380: static inline ThreadMsg OTTD_PollThreadEvent(void) {return _message;} Darkvater@2380: Darkvater@2380: /** Called by running thread to execute some action in the main game. Darkvater@2380: * It will stall as long as the mutex is not freed (handled) by the game */ Darkvater@2380: void OTTD_SendThreadMessage(ThreadMsg msg) Darkvater@2380: { Darkvater@2383: if (_exit_game) return; truelight@4323: while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10); Darkvater@2380: Darkvater@2380: _message = msg; Darkvater@2380: } Darkvater@2380: Darkvater@2380: Darkvater@2380: /** Handle the user-messages sent to us Darkvater@2380: * @param message message sent Darkvater@2380: */ tron@2817: static void ProcessSentMessage(ThreadMsg message) Darkvater@2380: { Darkvater@2380: switch (message) { Darkvater@2380: case MSG_OTTD_SAVETHREAD_DONE: SaveFileDone(); break; Darkvater@2380: case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break; Darkvater@2380: default: NOT_REACHED(); Darkvater@2380: } Darkvater@2380: Darkvater@2380: OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled Darkvater@2380: } Darkvater@2380: truelight@0: static void ShowScreenshotResult(bool b) truelight@0: { truelight@0: if (b) { ludde@2055: SetDParamStr(0, _screenshot_name); truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_031B_SCREENSHOT_SUCCESSFULLY, 0, 0); truelight@0: } else { truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_031C_SCREENSHOT_FAILED, 0, 0); truelight@0: } truelight@0: truelight@0: } truelight@0: truelight@4300: static void MakeNewGameDone(void) truelight@4300: { truelight@4300: /* In a dedicated server, the server does not play */ truelight@4300: if (_network_dedicated) { rubidium@5376: SetLocalPlayer(PLAYER_SPECTATOR); truelight@4300: return; truelight@4300: } truelight@4300: truelight@4300: /* Create a single player */ truelight@4300: DoStartupNewPlayer(false); truelight@4300: rubidium@5376: SetLocalPlayer(0); truelight@4300: _current_player = _local_player; peter1138@4661: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@4300: KUDr@5116: SettingsDisableElrail(_patches.disable_elrails); KUDr@5116: 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); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewGameDone); truelight@4300: GenerateWorld(from_heightmap ? GW_HEIGHTMAP : GW_NEWGAME, 1 << _patches.map_x, 1 << _patches.map_y); truelight@4300: } truelight@0: truelight@4300: static void MakeNewEditorWorldDone(void) truelight@4300: { rubidium@5376: SetLocalPlayer(OWNER_NONE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: tron@1093: static void MakeNewEditorWorld(void) truelight@0: { truelight@0: _game_mode = GM_EDITOR; truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: truelight@4300: GenerateWorldSetCallback(&MakeNewEditorWorldDone); truelight@2828: GenerateWorld(GW_EMPTY, 1 << _patches.map_x, 1 << _patches.map_y); truelight@0: } truelight@0: tron@1093: void StartupPlayers(void); tron@1093: void StartupDisasters(void); Darkvater@3891: extern void StartupEconomy(void); 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: */ tron@1095: static void StartScenario(void) truelight@0: { truelight@0: _game_mode = GM_NORMAL; truelight@0: truelight@0: // 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); Darkvater@2749: ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: _game_mode = GM_MENU; truelight@0: return; truelight@0: } truelight@0: dominik@136: // Reinitialize windows Darkvater@1474: ResetWindowSystem(); truelight@0: truelight@0: SetupColorsAndInitialWindow(); truelight@0: peter1138@5313: ResetGRFConfig(true); peter1138@5313: truelight@0: // Load game truelight@0: if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode) != SL_OK) { truelight@0: LoadIntroGame(); Darkvater@2749: ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: } truelight@0: Darkvater@1501: _opt_ptr = &_opt; tron@5024: _opt_ptr->diff = _opt_newgame.diff; Darkvater@1501: _opt.diff_level = _opt_newgame.diff_level; Darkvater@1500: dominik@115: // Inititalize data Darkvater@3891: StartupEconomy(); dominik@115: StartupPlayers(); dominik@115: StartupEngines(); dominik@115: StartupDisasters(); dominik@115: rubidium@5376: SetLocalPlayer(0); bjarni@2293: _current_player = _local_player; peter1138@4661: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE); truelight@0: truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: truelight@543: bool SafeSaveOrLoad(const char *filename, int mode, int newgm) truelight@0: { truelight@0: byte ogm = _game_mode; truelight@0: truelight@0: _game_mode = newgm; tron@3024: switch (SaveOrLoad(filename, mode)) { tron@3024: case SL_OK: return true; tron@3024: tron@3024: case SL_REINIT: tron@3024: switch (ogm) { tron@3024: case GM_MENU: LoadIntroGame(); break; tron@3024: case GM_EDITOR: MakeNewEditorWorld(); break; truelight@4300: default: MakeNewGame(false); break; tron@3024: } tron@3024: return false; tron@3024: tron@3024: default: tron@3024: _game_mode = ogm; tron@3024: return false; tron@2639: } truelight@0: } truelight@0: truelight@543: void SwitchMode(int new_mode) truelight@0: { truelight@543: #ifdef ENABLE_NETWORK truelight@543: // If we are saving something, the network stays in his current state truelight@543: if (new_mode != SM_SAVE) { truelight@543: // 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: NetworkUDPClose(); truelight@543: } else { truelight@543: NetworkDisconnect(); truelight@543: NetworkUDPClose(); truelight@543: } truelight@543: } truelight@543: truelight@543: // If we are a server, we restart the server truelight@543: if (_is_network_server) { truelight@543: // But not if we are going to the menu truelight@543: if (new_mode != SM_MENU) { truelight@543: NetworkServerStart(); truelight@543: } else { truelight@543: // This client no longer wants to be a network-server truelight@543: _is_network_server = false; truelight@543: } truelight@543: } truelight@543: } truelight@543: #endif /* ENABLE_NETWORK */ truelight@543: Darkvater@1500: switch (new_mode) { Darkvater@1500: case SM_EDITOR: /* Switch to scenario editor */ truelight@0: MakeNewEditorWorld(); truelight@0: break; truelight@0: Darkvater@1500: case SM_NEWGAME: /* New Game --> 'Random game' */ truelight@630: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "Random Map"); tron@2951: } truelight@630: #endif /* ENABLE_NETWORK */ truelight@4300: MakeNewGame(false); truelight@0: break; truelight@0: Darkvater@1500: case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */ tron@2951: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded scenario)", _file_to_saveload.title); tron@2951: } tron@2951: #endif /* ENABLE_NETWORK */ truelight@543: StartScenario(); truelight@543: break; truelight@543: Darkvater@1500: case SM_LOAD: { /* Load game, Play Scenario */ Darkvater@1500: _opt_ptr = &_opt; peter1138@5228: ResetGRFConfig(true); truelight@0: truelight@0: if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) { truelight@942: LoadIntroGame(); Darkvater@2749: ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: } else { Darkvater@5197: /* Update the local player for a loaded game. It is either always Darkvater@5197: * player #1 (eg 0) or in the case of a dedicated server a spectator */ rubidium@5376: SetLocalPlayer(_network_dedicated ? PLAYER_SPECTATOR : 0); truelight@0: DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // decrease pause counter (was increased from opening load dialog) truelight@630: #ifdef ENABLE_NETWORK tron@2951: if (_network_server) { tron@2989: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); tron@2951: } truelight@630: #endif /* ENABLE_NETWORK */ truelight@0: } truelight@0: break; truelight@0: } truelight@0: truelight@4300: case SM_START_HEIGHTMAP: /* Load a heightmap and start a new game from it */ truelight@4300: #ifdef ENABLE_NETWORK truelight@4300: if (_network_server) { truelight@4300: snprintf(_network_game_info.map_name, lengthof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); truelight@4300: } truelight@4300: #endif /* ENABLE_NETWORK */ truelight@4300: MakeNewGame(true); truelight@4300: break; truelight@4300: truelight@4300: case SM_LOAD_HEIGHTMAP: /* Load heightmap from scenario editor */ rubidium@5376: SetLocalPlayer(OWNER_NONE); truelight@4300: truelight@4300: GenerateWorld(GW_HEIGHTMAP, 1 << _patches.map_x, 1 << _patches.map_y); truelight@4300: MarkWholeScreenDirty(); truelight@4300: break; truelight@4300: Darkvater@1500: case SM_LOAD_SCENARIO: { /* Load scenario from scenario editor */ tron@2634: if (SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR)) { Darkvater@4260: Player *p; truelight@0: Darkvater@1500: _opt_ptr = &_opt; truelight@0: rubidium@5376: SetLocalPlayer(OWNER_NONE); truelight@0: _generating_world = true; Darkvater@4260: /* Delete all players */ Darkvater@4260: FOR_ALL_PLAYERS(p) { Darkvater@4260: if (p->is_active) { Darkvater@4848: ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR); Darkvater@4260: p->is_active = false; Darkvater@4260: } truelight@0: } truelight@0: _generating_world = false; rubidium@4537: _patches_newgame.starting_year = _cur_year; truelight@0: // delete all stations owned by a player truelight@0: DeleteAllPlayerStations(); tron@2639: } else { truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0); tron@2639: } truelight@0: break; truelight@0: } truelight@0: Darkvater@1500: case SM_MENU: /* Switch to game intro menu */ truelight@0: LoadIntroGame(); truelight@0: break; truelight@0: Darkvater@1500: case SM_SAVE: /* Save game */ tron@2639: if (SaveOrLoad(_file_to_saveload.name, SL_SAVE) != SL_OK) { truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_4007_GAME_SAVE_FAILED, 0, 0); tron@2639: } else { truelight@0: DeleteWindowById(WC_SAVELOAD, 0); tron@2639: } truelight@0: break; truelight@0: Darkvater@1500: case SM_GENRANDLAND: /* Generate random land within scenario editor */ rubidium@5376: SetLocalPlayer(OWNER_NONE); tron@2951: GenerateWorld(GW_RANDOM, 1 << _patches.map_x, 1 << _patches.map_y); truelight@0: // XXX: set date truelight@0: MarkWholeScreenDirty(); truelight@0: break; truelight@0: } truelight@193: tron@2951: if (_switch_mode_errorstr != INVALID_STRING_ID) { tron@2951: ShowErrorMessage(INVALID_STRING_ID, _switch_mode_errorstr, 0, 0); tron@2951: } truelight@0: } truelight@0: truelight@0: truelight@0: // State controlling game loop. truelight@0: // The state must not be changed from anywhere truelight@0: // but here. truelight@0: // That check is enforced in DoCommand. tron@1093: void StateGameLoop(void) truelight@0: { darkvater@213: // dont execute the state loop during pause darkvater@213: if (_pause) return; truelight@4300: if (IsGeneratingWorld()) return; darkvater@213: truelight@0: if (_game_mode == GM_EDITOR) { truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); truelight@0: } else { signde@206: // All these actions has to be done from OWNER_NONE signde@206: // for multiplayer compatibility tron@2498: PlayerID p = _current_player; signde@206: _current_player = OWNER_NONE; signde@206: truelight@0: AnimateAnimatedTiles(); truelight@0: IncreaseDate(); truelight@0: RunTileLoop(); truelight@0: CallVehicleTicks(); truelight@0: CallLandscapeTick(); truelight@0: truelight@2395: AI_RunGameLoop(); truelight@0: truelight@0: CallWindowTickEvent(); truelight@0: NewsLoop(); signde@206: _current_player = p; truelight@0: } truelight@0: } truelight@0: tron@1093: static void DoAutosave(void) truelight@0: { truelight@0: char buf[200]; truelight@193: Darkvater@4848: if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) { celestar@1962: const Player *p = GetPlayer(_local_player); Darkvater@4912: char* s = buf; Darkvater@4912: Darkvater@5296: s += snprintf(buf, lengthof(buf), "%s%s", _paths.autosave_dir, PATHSEP); Darkvater@1500: tron@534: SetDParam(0, p->name_1); tron@534: SetDParam(1, p->name_2); tron@534: SetDParam(2, _date); Darkvater@4912: s = GetString(s, STR_4004, lastof(buf)); Darkvater@4912: strecpy(s, ".sav", lastof(buf)); bjarni@2672: } else { /* generate a savegame name and number according to _patches.max_num_autosaves */ Darkvater@5296: snprintf(buf, lengthof(buf), "%s%sautosave%d.sav", _paths.autosave_dir, PATHSEP, _autosave_ctr); bjarni@2672: bjarni@2672: _autosave_ctr++; bjarni@2672: if (_autosave_ctr >= _patches.max_num_autosaves) { bjarni@2672: // we reached the limit for numbers of autosaves. We will start over bjarni@2672: _autosave_ctr = 0; bjarni@2672: } truelight@0: } truelight@0: Darkvater@5380: DEBUG(sl, 2, "Autosaving to '%s'", buf); truelight@0: if (SaveOrLoad(buf, SL_SAVE) != SL_OK) truelight@0: ShowErrorMessage(INVALID_STRING_ID, STR_AUTOSAVE_FAILED, 0, 0); truelight@0: } truelight@0: Darkvater@1397: static void ScrollMainViewport(int x, int y) Darkvater@1397: { rubidium@4536: if (_game_mode != GM_MENU) { Darkvater@1397: Window *w = FindWindowById(WC_MAIN_WINDOW, 0); Darkvater@1397: assert(w); Darkvater@1397: Darkvater@1397: WP(w,vp_d).scrollpos_x += x << w->viewport->zoom; Darkvater@1397: WP(w,vp_d).scrollpos_y += y << w->viewport->zoom; Darkvater@1397: } Darkvater@1397: } Darkvater@1397: Darkvater@1397: static const int8 scrollamt[16][2] = { rubidium@4344: { 0, 0}, rubidium@4344: {-2, 0}, // 1 : left rubidium@4344: { 0, -2}, // 2 : up rubidium@4344: {-2, -1}, // 3 : left + up rubidium@4344: { 2, 0}, // 4 : right rubidium@4344: { 0, 0}, // 5 : left + right rubidium@4344: { 2, -1}, // 6 : right + up rubidium@4344: { 0, -2}, // 7 : left + right + up = up rubidium@4344: { 0 ,2}, // 8 : down rubidium@4344: {-2 ,1}, // 9 : down+left rubidium@4344: { 0, 0}, // 10 : impossible rubidium@4344: {-2, 0}, // 11 : left + up + down = left rubidium@4344: { 2, 1}, // 12 : down+right rubidium@4344: { 0, 2}, // 13 : left + right + down = down rubidium@4344: { 0, -2}, // 14 : left + right + up = up rubidium@4344: { 0, 0}, // 15 : impossible Darkvater@1397: }; Darkvater@1397: Darkvater@1397: static void HandleKeyScrolling(void) Darkvater@1397: { Darkvater@1397: if (_dirkeys && !_no_scroll) { Darkvater@1397: int factor = _shift_pressed ? 50 : 10; Darkvater@1397: ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); Darkvater@1397: } Darkvater@1397: } dominik@1199: tron@1093: void GameLoop(void) truelight@0: { Darkvater@2380: ThreadMsg message; Darkvater@2380: Darkvater@2380: if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message); truelight@0: truelight@0: // autosave game? truelight@0: if (_do_autosave) { truelight@0: _do_autosave = false; truelight@0: DoAutosave(); truelight@0: RedrawAutosave(); truelight@0: } truelight@0: dominik@1199: // handle scrolling of the main window tron@4502: HandleKeyScrolling(); dominik@1199: truelight@0: // make a screenshot? belugas@4184: if (IsScreenshotRequested()) ShowScreenshotResult(MakeScreenshot()); truelight@0: truelight@0: // switch game mode? tron@3024: if (_switch_mode != SM_NONE) { tron@3024: SwitchMode(_switch_mode); truelight@0: _switch_mode = SM_NONE; truelight@0: } truelight@0: truelight@0: IncreaseSpriteLRU(); truelight@0: InteractiveRandom(); truelight@0: tron@2639: if (_scroller_click_timeout > 3) { truelight@0: _scroller_click_timeout -= 3; tron@2639: } else { truelight@0: _scroller_click_timeout = 0; tron@2639: } truelight@0: truelight@0: _caret_timer += 3; tron@2639: _timer_counter += 8; truelight@0: CursorTick(); truelight@0: truelight@543: #ifdef ENABLE_NETWORK truelight@543: // Check for UDP stuff Darkvater@4830: if (_network_available) NetworkUDPGameLoop(); truelight@0: truelight@4300: if (_networking && !IsGeneratingWorld()) { truelight@543: // Multiplayer truelight@543: NetworkGameLoop(); truelight@543: } else { truelight@543: if (_network_reconnect > 0 && --_network_reconnect == 0) { truelight@543: // This means that we want to reconnect to the last host truelight@543: // We do this here, because it means that the network is really closed truelight@543: NetworkClientConnectGame(_network_last_host, _network_last_port); signde@206: } truelight@543: // Singleplayer darkvater@213: StateGameLoop(); truelight@0: } truelight@543: #else truelight@543: StateGameLoop(); truelight@543: #endif /* ENABLE_NETWORK */ truelight@0: tron@2639: if (!_pause && _display_opt & DO_FULL_ANIMATION) DoPaletteAnimations(); truelight@0: tron@2639: if (!_pause || _cheats.build_in_pause.value) MoveAllTextEffects(); truelight@0: pasky@1570: InputLoop(); truelight@0: tron@1608: MusicLoop(); truelight@0: } truelight@0: tron@1093: void BeforeSaveGame(void) truelight@0: { belugas@4171: const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); truelight@0: darkvater@983: if (w != NULL) { tron@2643: _saved_scrollpos_x = WP(w, const vp_d).scrollpos_x; tron@2643: _saved_scrollpos_y = WP(w, const vp_d).scrollpos_y; darkvater@983: _saved_scrollpos_zoom = w->viewport->zoom; darkvater@983: } truelight@0: } truelight@0: tron@1095: static void ConvertTownOwner(void) truelight@0: { tron@1977: TileIndex tile; truelight@0: tron@863: for (tile = 0; tile != MapSize(); tile++) { tron@4000: switch (GetTileType(tile)) { tron@4000: case MP_STREET: tron@4000: if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) & 0x80) { tron@4000: SetCrossingRoadOwner(tile, 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: truelight@0: // before savegame version 4, the name of the company determined if it existed tron@1095: static void CheckIsPlayerActive(void) truelight@0: { belugas@4171: Player *p; tron@2639: truelight@0: FOR_ALL_PLAYERS(p) { tron@2639: if (p->name_1 != 0) p->is_active = true; truelight@0: } truelight@0: } truelight@0: dominik@121: // since savegame version 4.1, exclusive transport rights are stored at towns tron@1095: static void UpdateExclusiveRights(void) dominik@121: { belugas@4171: Town *t; tron@2639: tron@2639: FOR_ALL_TOWNS(t) { truelight@4346: t->exclusivity = (byte)-1; dominik@121: } truelight@193: dominik@123: /* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete) rubidium@4549: * could be implemented this way: rubidium@4549: * 1.) Go through all stations rubidium@4549: * Build an array town_blocked[ town_id ][ player_id ] rubidium@4549: * that stores if at least one station in that town is blocked for a player rubidium@4549: * 2.) Go through that array, if you find a town that is not blocked for rubidium@4549: * one player, but for all others, then give him exclusivity. rubidium@4549: */ dominik@121: } dominik@121: tron@2756: static const byte convert_currency[] = { dominik@762: 0, 1, 12, 8, 3, dominik@762: 10, 14, 19, 4, 5, dominik@762: 9, 11, 13, 6, 17, dominik@762: 16, 22, 21, 7, 15, dominik@762: 18, 2, 20, }; dominik@762: dominik@762: // since savegame version 4.2 the currencies are arranged differently tron@1095: static void UpdateCurrencies(void) dominik@762: { dominik@768: _opt.currency = convert_currency[_opt.currency]; dominik@762: } dominik@762: tron@1181: /* Up to revision 1413 the invisible tiles at the southern border have not been tron@1181: * MP_VOID, even though they should have. This is fixed by this function tron@1181: */ tron@1095: static void UpdateVoidTiles(void) 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: dominik@1165: // since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) dominik@1165: static void UpdateSignOwner(void) dominik@1165: { truelight@4349: Sign *si; tron@2639: truelight@4349: FOR_ALL_SIGNS(si) si->owner = OWNER_NONE; dominik@1165: } dominik@1165: celestar@950: extern void UpdateOldAircraft( void ); celestar@950: extern void UpdateOilRig( void ); 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: peter1138@2808: bool AfterLoadGame(void) truelight@0: { truelight@0: Window *w; truelight@0: ViewPort *vp; celestar@2147: Player *p; truelight@988: truelight@0: // in version 2.1 of the savegame, town owner was unified. truelight@2685: if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner(); truelight@0: dominik@121: // from version 4.1 of the savegame, exclusive rights are stored at towns truelight@2685: if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights(); truelight@193: dominik@762: // from version 4.2 of the savegame, currencies are in a different order truelight@2685: if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies(); dominik@762: truelight@2685: // from version 6.1 of the savegame, signs have an "owner" truelight@2685: if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner(); dominik@1165: truelight@831: /* In old version there seems to be a problem that water is owned by truelight@831: OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current truelight@2685: (4.3) version, so I just check when versions are older, and then truelight@831: walk through the whole map.. */ truelight@2685: if (CheckSavegameVersionOldStyle(4, 3)) { tron@1981: TileIndex tile = TileXY(0, 0); truelight@831: uint w = MapSizeX(); truelight@831: uint h = MapSizeY(); truelight@831: truelight@831: BEGIN_TILE_LOOP(tile_cur, w, h, tile) tron@1901: if (IsTileType(tile_cur, MP_WATER) && GetTileOwner(tile_cur) >= MAX_PLAYERS) tron@1902: SetTileOwner(tile_cur, OWNER_WATER); truelight@831: END_TILE_LOOP(tile_cur, w, h, tile) truelight@831: } truelight@831: truelight@0: // convert road side to my format. truelight@0: if (_opt.road_side) _opt.road_side = 1; truelight@0: peter1138@5228: /* Check all NewGRFs are present */ peter1138@5228: if (!IsGoodGRFConfigList()) return false; 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: truelight@0: // Load the sprites truelight@0: GfxLoadSprites(); peter1138@5155: LoadStringWidthTable(); truelight@0: peter1138@2814: /* Connect front and rear engines of multiheaded trains and converts peter1138@2814: * subtype to the new format */ peter1138@2814: if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew(); peter1138@2814: bjarni@2928: /* Connect front and rear engines of multiheaded trains */ bjarni@2928: ConnectMultiheadedTrains(); bjarni@2855: truelight@0: // reinit the landscape variables (landscape might have changed) truelight@0: InitializeLandscapeVariables(true); truelight@193: truelight@0: // Update all vehicles truelight@0: AfterLoadVehicles(); truelight@1542: truelight@1542: // Update all waypoints truelight@2685: if (CheckSavegameVersion(12)) FixOldWaypoints(); truelight@1542: truelight@1542: UpdateAllWaypointSigns(); truelight@1542: truelight@0: // in version 2.2 of the savegame, we have new airports truelight@2685: if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft(); truelight@0: truelight@0: UpdateAllStationVirtCoord(); truelight@0: truelight@0: // Setup town coords truelight@0: AfterLoadTown(); truelight@0: UpdateAllSignVirtCoords(); truelight@0: truelight@0: // make sure there is a town in the game tron@2639: if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, (uint)-1)) { truelight@0: _error_message = STR_NO_TOWN_IN_SCENARIO; truelight@0: return false; truelight@0: } truelight@0: truelight@0: // Initialize windows Darkvater@1474: ResetWindowSystem(); truelight@0: SetupColorsAndInitialWindow(); truelight@0: truelight@0: w = FindWindowById(WC_MAIN_WINDOW, 0); truelight@0: truelight@0: WP(w,vp_d).scrollpos_x = _saved_scrollpos_x; truelight@0: WP(w,vp_d).scrollpos_y = _saved_scrollpos_y; truelight@193: truelight@0: vp = w->viewport; truelight@0: vp->zoom = _saved_scrollpos_zoom; truelight@0: vp->virtual_width = vp->width << vp->zoom; truelight@0: vp->virtual_height = vp->height << vp->zoom; truelight@0: truelight@2685: // in version 4.1 of the savegame, is_active was introduced to determine truelight@0: // if a player does exist, rather then checking name_1 truelight@2685: if (CheckSavegameVersionOldStyle(4, 1)) CheckIsPlayerActive(); truelight@193: truelight@2685: // the void tiles on the southern border used to belong to a wrong class (pre 4.3). truelight@2685: if (CheckSavegameVersionOldStyle(4, 3)) UpdateVoidTiles(); dominik@929: truelight@193: // If Load Scenario / New (Scenario) Game is used, truelight@139: // a player does not exist yet. So create one here. truelight@543: // 1 exeption: network-games. Those can have 0 players truelight@543: // But this exeption is not true for network_servers! truelight@543: if (!_players[0].is_active && (!_networking || (_networking && _network_server))) truelight@139: DoStartupNewPlayer(false); truelight@0: darkvater@152: DoZoomInOutWindow(ZOOM_NONE, w); // update button status truelight@0: MarkWholeScreenDirty(); truelight@0: truelight@2685: // In 5.1, Oilrigs have been moved (again) truelight@2685: if (CheckSavegameVersionOldStyle(5, 1)) UpdateOilRig(); celestar@950: 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)) { celestar@1264: BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) { tron@3983: switch (GetTileType(tile)) { tron@3983: case MP_HOUSE: tron@3983: _m[tile].m4 = _m[tile].m2; tron@3983: SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index); tron@3983: break; tron@3983: tron@3983: case MP_STREET: tron@3983: _m[tile].m4 |= (_m[tile].m2 << 4); tron@3983: if (IsTileOwner(tile, OWNER_TOWN)) { tron@3983: SetTownIndex(tile, CalcClosestTownFromTile(tile, (uint)-1)->index); tron@3983: } else { tron@3983: SetTownIndex(tile, 0); tron@3983: } tron@3983: break; tron@3983: tron@3983: default: break; celestar@1264: } celestar@1264: } END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0); celestar@1264: } celestar@1264: truelight@2685: /* From version 9.0, we update the max passengers of a town (was sometimes negative truelight@2685: * before that. */ truelight@2685: if (CheckSavegameVersion(9)) { celestar@1377: Town *t; tron@2639: FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); celestar@1377: } celestar@1377: truelight@2685: /* From version 16.0, we included autorenew on engines, which are now saved, but truelight@2685: * of course, we do need to initialize them for older savegames. */ truelight@2685: if (CheckSavegameVersion(16)) { bjarni@2293: FOR_ALL_PLAYERS(p) { rubidium@5376: p->engine_renew_list = NULL; rubidium@5376: p->engine_renew = false; bjarni@2293: p->engine_renew_months = -6; rubidium@5376: p->engine_renew_money = 100000; bjarni@2293: } rubidium@5376: rubidium@5376: /* When loading a game, _local_player is not yet set to the correct value. rubidium@5376: * However, in a dedicated server we are a spectator, so nothing needs to rubidium@5376: * happen. In case we are not a dedicated server, the local player always rubidium@5376: * becomes player 0, unless we are in the scenario editor where all the rubidium@5376: * players are 'invalid'. rubidium@5376: */ rubidium@5376: if (!_network_dedicated && IsValidPlayer(0)) { rubidium@5376: p = GetPlayer(0); rubidium@5376: p->engine_renew = _patches.autorenew; bjarni@2322: p->engine_renew_months = _patches.autorenew_months; rubidium@5376: p->engine_renew_money = _patches.autorenew_money; bjarni@2322: } bjarni@2293: } bjarni@2293: celestar@5385: if (CheckSavegameVersion(42)) { celestar@5385: TileIndex map_end = MapSize(); celestar@5385: TileIndex tile; celestar@5385: Vehicle* v; celestar@5385: celestar@5385: for (tile = 0; tile != map_end; tile++) { celestar@5385: if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile); celestar@5385: if (IsBridgeTile(tile)) { celestar@5385: if (HASBIT(_m[tile].m5, 6)) { // middle part celestar@5385: Axis axis = (Axis)GB(_m[tile].m5, 0, 1); celestar@5385: celestar@5385: if (HASBIT(_m[tile].m5, 5)) { // transport route under bridge? celestar@5385: if (GB(_m[tile].m5, 3, 2) == TRANSPORT_RAIL) { celestar@5385: MakeRailNormal( celestar@5385: tile, celestar@5385: GetTileOwner(tile), celestar@5385: axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, celestar@5385: GetRailType(tile) celestar@5385: ); celestar@5385: } else { celestar@5385: TownID town = IsTileOwner(tile, OWNER_TOWN) ? ClosestTownFromTile(tile, (uint)-1)->index : 0; celestar@5385: celestar@5385: MakeRoadNormal( celestar@5385: tile, celestar@5385: GetTileOwner(tile), celestar@5385: axis == AXIS_X ? ROAD_Y : ROAD_X, celestar@5385: town celestar@5385: ); celestar@5385: } celestar@5385: } else { celestar@5385: if (GB(_m[tile].m5, 3, 2) == 0) { celestar@5385: MakeClear(tile, CLEAR_GRASS, 3); celestar@5385: } else { celestar@5385: MakeCanal(tile, GetTileOwner(tile)); celestar@5385: } celestar@5385: } celestar@5385: SetBridgeMiddle(tile, axis); celestar@5385: } else { // ramp celestar@5385: Axis axis = (Axis)GB(_m[tile].m5, 0, 1); celestar@5385: uint north_south = GB(_m[tile].m5, 5, 1); celestar@5385: DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); celestar@5385: TransportType type = (TransportType)GB(_m[tile].m5, 1, 2); celestar@5385: celestar@5385: _m[tile].m5 = 1 << 7 | type << 2 | dir; celestar@5385: } celestar@5385: } celestar@5385: } celestar@5385: celestar@5385: FOR_ALL_VEHICLES(v) { celestar@5385: if (v->type != VEH_Train && v->type != VEH_Road) continue; celestar@5385: if (IsBridgeTile(v->tile)) { celestar@5385: DiagDirection dir = GetBridgeRampDirection(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: } celestar@5385: if (v->type == VEH_Train) { celestar@5385: v->u.rail.track = 0x40; celestar@5385: } else { celestar@5385: v->u.road.state = 0xFF; 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; celestar@3355: uint i; celestar@3355: TileIndex t; tron@3656: RailType min_rail = RAILTYPE_ELECTRIC; celestar@3355: celestar@3355: for (i = 0; i < lengthof(_engines); i++) { belugas@4171: Engine *e = GetEngine(i); celestar@3355: if (e->type == VEH_Train && celestar@3355: (e->railtype != RAILTYPE_RAIL || RailVehInfo(i)->engclass == 2)) { celestar@3355: e->railtype++; celestar@3355: } celestar@3355: } celestar@3355: celestar@3355: FOR_ALL_VEHICLES(v) { celestar@3355: if (v->type == VEH_Train) { celestar@3355: RailType rt = GetEngine(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") */ celestar@3355: for (t = 0; t < MapSize(); 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: celestar@3355: case MP_STREET: tron@3656: if (IsLevelCrossing(t)) { tron@3656: SetRailTypeCrossing(t, UpdateRailType(GetRailTypeCrossing(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: tron@3367: if (IsTunnel(t)) { tron@3367: if (GetTunnelTransportType(t) == TRANSPORT_RAIL) { tron@3656: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); celestar@3355: } celestar@3355: } else { tron@3367: if (GetBridgeTransportType(t) == TRANSPORT_RAIL) { tron@3656: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); celestar@3355: } 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) { celestar@3355: if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v); celestar@3355: } celestar@3355: celestar@3355: } celestar@3355: tron@2805: /* In version 16.1 of the savegame a player can decide if trains, which get tron@2805: * replaced, shall keep their old length. In all prior versions, just default tron@2805: * to false */ truelight@2685: if (CheckSavegameVersionOldStyle(16, 1)) { tron@4077: FOR_ALL_PLAYERS(p) p->renew_keep_length = false; bjarni@2617: } bjarni@2617: peter1138@2670: /* In version 17, ground type is moved from m2 to m4 for depots and peter1138@2670: * waypoints to make way for storing the index in m2. The custom graphics peter1138@2670: * id which was stored in m4 is now saved as a grf/id reference in the peter1138@2670: * waypoint struct. */ truelight@2685: if (CheckSavegameVersion(17)) { peter1138@2670: Waypoint *wp; peter1138@2670: peter1138@2670: FOR_ALL_WAYPOINTS(wp) { truelight@4346: if (wp->deleted == 0) { belugas@3676: const StationSpec *statspec = NULL; peter1138@2670: peter1138@2670: 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; belugas@3676: wp->grfid = statspec->grfid; belugas@3676: wp->localidx = statspec->localidx; peter1138@2670: } else { peter1138@2670: // 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: peter1138@2670: // Move ground type bits from m2 to m4. peter1138@2670: _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); peter1138@2670: // 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)) { Darkvater@2916: BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) { Darkvater@2916: if (IsTileType(tile, MP_RAILWAY)) { Darkvater@2916: if (HasSignals(tile)) { Darkvater@2916: // convert PBS signals to combo-signals tron@3984: if (HASBIT(_m[tile].m4, 2)) SetSignalType(tile, SIGTYPE_COMBO); Darkvater@2916: tron@3984: // move the signal variant back tron@3984: SetSignalVariant(tile, HASBIT(_m[tile].m4, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); Darkvater@2916: CLRBIT(_m[tile].m4, 3); Darkvater@2916: } Darkvater@2916: Darkvater@2916: // Clear PBS reservation on track tron@4077: if (!IsTileDepotType(tile, TRANSPORT_RAIL)) { Darkvater@2916: SB(_m[tile].m4, 4, 4, 0); tron@4077: } else { Darkvater@2916: CLRBIT(_m[tile].m3, 6); tron@4077: } Darkvater@2916: } Darkvater@2916: Darkvater@2916: // Clear PBS reservation on crossing Darkvater@2916: if (IsTileType(tile, MP_STREET) && IsLevelCrossing(tile)) Darkvater@2916: CLRBIT(_m[tile].m5, 0); Darkvater@2916: Darkvater@2916: // Clear PBS reservation on station Darkvater@2929: if (IsTileType(tile, MP_STATION)) Darkvater@2916: CLRBIT(_m[tile].m3, 6); Darkvater@2916: } END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0); Darkvater@2916: } Darkvater@2916: Darkvater@3121: if (CheckSavegameVersion(22)) UpdatePatches(); Darkvater@3121: celestar@3431: if (CheckSavegameVersion(25)) { celestar@3431: Vehicle *v; celestar@3431: FOR_ALL_VEHICLES(v) { celestar@3431: 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: } celestar@3431: } celestar@3431: celestar@3580: if (CheckSavegameVersion(26)) { celestar@3580: Station *st; celestar@3580: FOR_ALL_STATIONS(st) { celestar@3580: st->last_vehicle_type = VEH_Invalid; celestar@3580: } celestar@3580: } celestar@3580: KUDr@3900: YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); KUDr@3900: peter1138@4603: if (CheckSavegameVersion(34)) FOR_ALL_PLAYERS(p) ResetPlayerLivery(p); peter1138@4603: tron@2639: FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index); celestar@2147: peter1138@3765: if (!CheckSavegameVersion(27)) AfterLoadStations(); peter1138@3765: bjarni@4574: { bjarni@4574: /* Set up the engine count for all players */ bjarni@4574: Player *players[MAX_PLAYERS]; bjarni@4574: int i; bjarni@4574: const Vehicle *v; bjarni@4574: bjarni@4574: for (i = 0; i < MAX_PLAYERS; i++) players[i] = GetPlayer(i); bjarni@4574: bjarni@4574: FOR_ALL_VEHICLES(v) { bjarni@4574: if (!IsEngineCountable(v)) continue; bjarni@4574: players[v->owner]->num_engines[v->engine_type]++; bjarni@4574: } bjarni@4574: } bjarni@4574: rubidium@4326: /* Time starts at 0 instead of 1920. rubidium@4326: * Account for this in older games by adding an offset */ rubidium@4326: if (CheckSavegameVersion(31)) { rubidium@4326: Station *st; rubidium@4326: Waypoint *wp; rubidium@4326: Engine *e; rubidium@4326: Player *player; rubidium@4326: Industry *i; rubidium@4326: Vehicle *v; rubidium@4326: rubidium@4326: _date += DAYS_TILL_ORIGINAL_BASE_YEAR; truelight@4383: _cur_year += ORIGINAL_BASE_YEAR; rubidium@4326: rubidium@4326: FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_PLAYERS(player) player->inaugurated_year += ORIGINAL_BASE_YEAR; rubidium@4326: FOR_ALL_INDUSTRIES(i) i->last_prod_year += ORIGINAL_BASE_YEAR; rubidium@4326: rubidium@4326: FOR_ALL_VEHICLES(v) { rubidium@4326: v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR; rubidium@4326: v->build_year += ORIGINAL_BASE_YEAR; rubidium@4326: } rubidium@4326: } rubidium@4326: truelight@4328: /* From 32 on we save the industry who made the farmland. truelight@4328: * To give this prettyness to old savegames, we remove all farmfields and truelight@4328: * plant new ones. */ truelight@4328: if (CheckSavegameVersion(32)) { truelight@4328: Industry *i; truelight@4328: truelight@4328: BEGIN_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) { truelight@4328: if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS)) { truelight@4328: MakeClear(tile_cur, CLEAR_GRASS, 3); truelight@4328: } truelight@4328: } END_TILE_LOOP(tile_cur, MapSizeX(), MapSizeY(), 0) truelight@4328: truelight@4328: FOR_ALL_INDUSTRIES(i) { truelight@4328: uint j; truelight@4328: truelight@4328: if (i->type == IT_FARM || i->type == IT_FARM_2) { truelight@4328: for (j = 0; j != 50; j++) PlantRandomFarmField(i); truelight@4328: } truelight@4328: } truelight@4328: } truelight@4328: bjarni@4712: /* Setting no refit flags to all orders in savegames from before refit in orders were added */ bjarni@4712: if (CheckSavegameVersion(36)) { bjarni@4712: Order *order; bjarni@4712: Vehicle *v; bjarni@4712: bjarni@4712: FOR_ALL_ORDERS(order) { bjarni@4712: order->refit_cargo = CT_NO_REFIT; bjarni@4712: order->refit_subtype = CT_NO_REFIT; bjarni@4712: } bjarni@4712: bjarni@4712: FOR_ALL_VEHICLES(v) { bjarni@4712: v->current_order.refit_cargo = CT_NO_REFIT; bjarni@4712: v->current_order.refit_subtype = CT_NO_REFIT; bjarni@4712: } bjarni@4712: } bjarni@4712: peter1138@5108: if (CheckSavegameVersion(37)) { peter1138@5108: ConvertNameArray(); peter1138@5108: } peter1138@5108: Darkvater@5314: /* from version 38 we have optional elrails, since we cannot know the Darkvater@5314: * preference of a user, let elrails enabled; it can be disabled manually */ KUDr@5116: if (CheckSavegameVersion(38)) { Darkvater@5314: _patches.disable_elrails = false; // enable elrails Darkvater@5314: /* do the same as when elrails were enabled/disabled manually just now */ Darkvater@5314: SettingsDisableElrail(_patches.disable_elrails); KUDr@5116: } KUDr@5116: truelight@0: return true; 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 */ Darkvater@5352: void ReloadNewGRFData(void) Darkvater@5352: { Darkvater@5352: /* reload grf data */ Darkvater@5352: GfxLoadSprites(); Darkvater@5352: LoadStringWidthTable(); Darkvater@5352: /* reload vehicles */ Darkvater@5352: ResetVehiclePosHash(); Darkvater@5352: AfterLoadVehicles(); Darkvater@5352: /* update station and waypoint graphics */ Darkvater@5352: AfterLoadWaypoints(); Darkvater@5352: AfterLoadStations(); Darkvater@5352: /* redraw the whole screen */ Darkvater@5352: MarkWholeScreenDirty(); Darkvater@5352: }