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" truelight@0: truelight@0: #define VARDEF Darkvater@1891: #include "openttd.h" tron@2163: #include "functions.h" tron@1496: #include "mixer.h" tron@1349: #include "spritecache.h" truelight@0: #include "gfx.h" tron@2340: #include "gfxinit.h" truelight@0: #include "gui.h" truelight@0: #include "station.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" truelight@0: truelight@0: #include truelight@0: truelight@2033: #ifdef GPMI truelight@2033: #include truelight@2033: #include truelight@2033: #endif /* GPMI */ truelight@2033: ludde@2051: void GenerateWorld(int mode, uint size_x, uint size_y); 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: truelight@0: bool LoadSavegame(const char *filename); truelight@0: truelight@0: bool _dbg_screen_rect; 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: tron@2639: 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); truelight@0: vsprintf(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); truelight@0: vsprintf(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: { truelight@0: char buf[4096], *p; truelight@0: truelight@193: p = strecpy(buf, 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" truelight@543: " -t date = Set starting date\n" pasky@1440: " -d [[fac=]lvl[,...]]= Debug mode\n" truelight@543: " -l lng = Select Language\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" bjarni@770: #if !defined(__MORPHOS__) && !defined(__AMIGA__) truelight@704: " -f = Fork into the background (dedicated only)\n" bjarni@770: #endif dominik@614: " -i = Force to use the DOS palette (use this if you see a lot of pink)\n" Darkvater@1482: " -p #player = Player as #player (deprecated) (network only)\n" Darkvater@1482: " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n", tron@1317: lastof(buf) truelight@0: ); truelight@0: tron@2171: GetDriverList(p); 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: tron@2548: 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: _station_sort = NULL; truelight@1267: _vehicle_sort = NULL; 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... */ truelight@1260: CleanPool(&_town_pool); truelight@1267: CleanPool(&_industry_pool); truelight@1272: CleanPool(&_station_pool); truelight@1279: CleanPool(&_vehicle_pool); truelight@1283: CleanPool(&_sign_pool); truelight@1314: CleanPool(&_order_pool); truelight@1260: truelight@919: free(_station_sort); truelight@919: free(_vehicle_sort); truelight@919: free(_town_sort); truelight@919: free(_industry_sort); truelight@919: } truelight@919: Darkvater@1474: static void UnInitializeGame(void) Darkvater@1474: { Darkvater@1474: UnInitWindowSystem(); Darkvater@1474: UnInitNewgrEngines(); 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; truelight@543: truelight@543: GfxLoadSprites(); truelight@543: LoadStringWidthTable(); truelight@543: truelight@543: // Setup main window Darkvater@1474: ResetWindowSystem(); truelight@543: SetupColorsAndInitialWindow(); truelight@543: truelight@543: // Generate a world. truelight@543: sprintf(filename, "%sopntitle.dat", _path.data_dir); tron@921: if (SaveOrLoad(filename, SL_LOAD) != SL_OK) { bjarni@561: #if defined SECOND_DATA_DIR bjarni@561: sprintf(filename, "%sopntitle.dat", _path.second_data_dir); bjarni@561: if (SaveOrLoad(filename, SL_LOAD) != SL_OK) bjarni@561: #endif ludde@2051: GenerateWorld(1, 64, 64); // if failed loading, make empty world. tron@921: } truelight@543: truelight@543: _pause = 0; truelight@543: _local_player = 0; 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 tron@1093: extern void CheckExternalFiles(void); truelight@704: truelight@0: int ttd_main(int argc, char* argv[]) truelight@0: { truelight@0: MyGetOptData mgo; truelight@0: int i; truelight@543: bool network = false; truelight@0: char *network_conn = NULL; truelight@0: char *language = NULL; tron@1010: const char *optformat; truelight@469: char musicdriver[16], sounddriver[16], videodriver[16]; truelight@0: int resolution[2] = {0,0}; truelight@0: uint startdate = -1; tron@1406: bool dedicated; 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; tron@1406: dedicated = 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) truelight@1478: #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) Darkvater@1482: optformat = "m:s:v:hDfn::l:eit:d::r:g::G:p:c:"; bjarni@770: #else Darkvater@1482: optformat = "m:s:v:hDn::l:eit:d::r:g::G:p:c:"; // no fork option bjarni@770: #endif bjarni@770: bjarni@770: MyGetOptInit(&mgo, argc-1, argv+1, optformat); truelight@0: while ((i = MyGetOpt(&mgo)) != -1) { truelight@0: switch(i) { truelight@0: case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break; truelight@0: case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break; truelight@0: case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break; truelight@543: case 'D': { tron@2639: strcpy(musicdriver, "null"); tron@2639: strcpy(sounddriver, "null"); tron@2639: strcpy(videodriver, "dedicated"); tron@1406: dedicated = true; truelight@543: } break; truelight@704: case 'f': { truelight@704: _dedicated_forks = true; truelight@704: }; break; darkvater@1: case 'n': { truelight@543: network = true; truelight@543: if (mgo.opt) truelight@543: // Optional, you can give an IP truelight@193: network_conn = mgo.opt; darkvater@1: else darkvater@1: network_conn = NULL; darkvater@1: } break; truelight@0: case 'r': ParseResolution(resolution, mgo.opt); break; tron@2639: case 'l': language = mgo.opt; break; tron@2639: case 't': startdate = 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; truelight@0: } else truelight@0: _switch_mode = SM_NEWGAME; truelight@0: break; truelight@0: case 'G': signde@206: _random_seeds[0][0] = atoi(mgo.opt); truelight@0: break; truelight@0: case 'p': { truelight@0: int i = atoi(mgo.opt); truelight@543: // Play as an other player in network games truelight@543: if (IS_INT_INSIDE(i, 1, MAX_PLAYERS)) _network_playas = i; truelight@0: break; truelight@0: } Darkvater@1482: case 'c': Darkvater@1482: _config_file = strdup(mgo.opt); Darkvater@1482: 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@2033: #ifdef GPMI truelight@2033: /* Set the debug proc */ truelight@2033: gpmi_debug_proc = &gpmi_debug_openttd; truelight@2033: truelight@2033: /* Initialize GPMI */ truelight@2033: gpmi_init(); truelight@2033: truelight@2033: /* Add our paths so we can find our own packages */ truelight@2033: gpmi_path_append(&gpmi_path_modules, "gpmi/modules"); truelight@2033: gpmi_path_append(&gpmi_path_packages, "gpmi/packages"); truelight@2033: #endif /* GPMI */ truelight@2033: 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]; } truelight@990: if (startdate != (uint)-1) _patches.starting_date = startdate; truelight@0: tron@1406: if (_dedicated_forks && !dedicated) truelight@704: _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 truelight@0: DEBUG(misc, 1) ("Loading sound effects..."); tron@1496: MxInitialize(11025); tron@1496: SoundInitialize("sample.cat"); truelight@0: truelight@0: // This must be done early, since functions use the InvalidateWindow* calls truelight@139: InitWindowSystem(); truelight@0: truelight@0: GfxLoadSprites(); truelight@0: LoadStringWidthTable(); truelight@0: truelight@0: DEBUG(misc, 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: truelight@543: #ifdef ENABLE_NETWORK truelight@543: // initialize network-core truelight@543: NetworkStartUp(); truelight@543: #endif /* ENABLE_NETWORK */ truelight@543: Darkvater@1500: _opt_ptr = &_opt_newgame; truelight@193: Darkvater@1500: /* XXX - ugly hack, if diff_level is 9, it means we got no setting from the config file */ Darkvater@1500: if (_opt_newgame.diff_level == 9) Darkvater@1500: SetDifficultyLevel(0, &_opt_newgame); truelight@0: truelight@139: // initialize the ingame console truelight@139: IConsoleInit(); darkvater@1246: InitializeGUI(); dominik@644: IConsoleCmdExec("exec scripts/autoexec.scr 0"); truelight@656: ludde@2051: GenerateWorld(1, 64, 64); // Make the viewport initialization happy truelight@1268: truelight@543: #ifdef ENABLE_NETWORK truelight@543: 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; truelight@543: truelight@543: ParseConnectionString(&player, &port, network_conn); truelight@543: truelight@543: if (player != NULL) _network_playas = atoi(player); 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: truelight@543: #ifdef ENABLE_NETWORK dominik@105: if (_network_available) { truelight@543: // Shut down the network and close any open connections truelight@543: NetworkDisconnect(); truelight@543: NetworkUDPClose(); truelight@543: NetworkShutDown(); truelight@543: } truelight@543: #endif /* ENABLE_NETWORK */ 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: Darkvater@2380: /** Mutex so that only one thread can communicate with the main program Darkvater@2380: * at any given time */ Darkvater@2380: static ThreadMsg _message = 0; Darkvater@2380: Darkvater@2380: static inline void OTTD_ReleaseMutex(void) {_message = 0;} 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; Darkvater@2380: while (_message != 0) 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: */ Darkvater@2380: void ProcessSentMessage(ThreadMsg message) Darkvater@2380: { Darkvater@2380: switch (message) { Darkvater@2380: case MSG_OTTD_SAVETHREAD_START: SaveFileStart(); break; 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: tron@1095: static void MakeNewGame(void) truelight@0: { truelight@0: _game_mode = GM_NORMAL; truelight@0: truelight@0: // Copy in game options Darkvater@1500: _opt_ptr = &_opt; tron@2639: memcpy(_opt_ptr, &_opt_newgame, sizeof(*_opt_ptr)); truelight@0: truelight@0: GfxLoadSprites(); truelight@0: dominik@136: // Reinitialize windows Darkvater@1474: ResetWindowSystem(); truelight@0: LoadStringWidthTable(); truelight@0: truelight@0: SetupColorsAndInitialWindow(); truelight@0: truelight@0: // Randomize world ludde@2051: GenerateWorld(0, 1<<_patches.map_x, 1<<_patches.map_y); truelight@0: truelight@543: // In a dedicated server, the server does not play truelight@543: if (_network_dedicated) { truelight@543: _local_player = OWNER_SPECTATOR; tron@2026: } else { truelight@543: // Create a single player truelight@543: DoStartupNewPlayer(false); truelight@193: truelight@543: _local_player = 0; bjarni@2293: _current_player = _local_player; bjarni@2293: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_REPLACE_VEHICLE); truelight@543: } 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: truelight@0: // Copy in game options Darkvater@1500: _opt_ptr = &_opt; Darkvater@1500: memcpy(_opt_ptr, &_opt_newgame, sizeof(GameOptions)); truelight@193: truelight@0: GfxLoadSprites(); truelight@0: dominik@136: // Re-init the windowing system Darkvater@1474: ResetWindowSystem(); truelight@0: truelight@0: // Create toolbars truelight@0: SetupColorsAndInitialWindow(); truelight@0: truelight@0: // Startup the game system tron@2639: GenerateWorld(1, 1 << _patches.map_x, 1 << _patches.map_y); truelight@0: truelight@0: _local_player = OWNER_NONE; truelight@0: MarkWholeScreenDirty(); truelight@0: } truelight@0: tron@1093: void StartupPlayers(void); tron@1093: void StartupDisasters(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) { truelight@0: printf("Savegame is obsolete or invalid format: %s\n", _file_to_saveload.name); truelight@0: ShowErrorMessage(_error_message, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: _game_mode = GM_MENU; truelight@0: return; truelight@0: } truelight@0: truelight@0: GfxLoadSprites(); truelight@0: dominik@136: // Reinitialize windows Darkvater@1474: ResetWindowSystem(); truelight@0: LoadStringWidthTable(); truelight@0: truelight@0: SetupColorsAndInitialWindow(); truelight@0: truelight@0: // Load game truelight@0: if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode) != SL_OK) { truelight@0: LoadIntroGame(); truelight@0: ShowErrorMessage(_error_message, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: } truelight@0: Darkvater@1501: _opt_ptr = &_opt; Darkvater@1501: memcpy(&_opt_ptr->diff, &_opt_newgame.diff, sizeof(GameDifficulty)); Darkvater@1501: _opt.diff_level = _opt_newgame.diff_level; Darkvater@1500: dominik@115: // Inititalize data dominik@115: StartupPlayers(); dominik@115: StartupEngines(); dominik@115: StartupDisasters(); dominik@115: truelight@0: _local_player = 0; bjarni@2293: _current_player = _local_player; bjarni@2293: DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_REPLACE_VEHICLE); 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: int r; truelight@0: truelight@0: _game_mode = newgm; truelight@0: r = SaveOrLoad(filename, mode); truelight@0: if (r == SL_REINIT) { tron@2631: switch (ogm) { tron@2631: case GM_MENU: LoadIntroGame(); break; tron@2631: case GM_EDITOR: MakeNewEditorWorld(); break; tron@2631: default: MakeNewGame(); break; tron@2631: } truelight@0: return false; truelight@0: } else if (r != SL_OK) { truelight@0: _game_mode = ogm; truelight@193: return false; tron@2639: } else { truelight@0: return true; 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 truelight@543: if (_network_server) Darkvater@2100: snprintf(_network_game_info.map_name, NETWORK_NAME_LENGTH, "Random Map"); truelight@630: #endif /* ENABLE_NETWORK */ truelight@0: MakeNewGame(); truelight@0: break; truelight@0: Darkvater@1500: case SM_START_SCENARIO: /* New Game --> Choose one of the preset scenarios */ Darkvater@2100: #ifdef ENABLE_NETWORK Darkvater@2100: if (_network_server) Darkvater@2100: snprintf(_network_game_info.map_name, NETWORK_NAME_LENGTH, "%s (Loaded scenario)", _file_to_saveload.title); Darkvater@2100: #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; truelight@0: truelight@0: _error_message = INVALID_STRING_ID; truelight@0: if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) { truelight@942: LoadIntroGame(); truelight@0: ShowErrorMessage(_error_message, STR_4009_GAME_LOAD_FAILED, 0, 0); truelight@0: } else { truelight@0: _local_player = 0; truelight@0: DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // decrease pause counter (was increased from opening load dialog) truelight@630: #ifdef ENABLE_NETWORK truelight@543: if (_network_server) Darkvater@2100: snprintf(_network_game_info.map_name, NETWORK_NAME_LENGTH, "%s (Loaded game)", _file_to_saveload.title); truelight@630: #endif /* ENABLE_NETWORK */ truelight@0: } truelight@0: break; truelight@0: } truelight@0: 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)) { tron@2634: PlayerID i; truelight@0: Darkvater@1500: _opt_ptr = &_opt; truelight@0: truelight@0: _local_player = OWNER_NONE; truelight@0: _generating_world = true; truelight@0: // delete all players. Darkvater@1500: for (i = 0; i != MAX_PLAYERS; i++) { tron@2469: ChangeOwnershipOfPlayerItems(i, OWNER_SPECTATOR); truelight@0: _players[i].is_active = false; truelight@0: } truelight@0: _generating_world = false; 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: 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 */ ludde@2051: GenerateWorld(2, 1<<_patches.map_x, 1<<_patches.map_y); truelight@0: // XXX: set date truelight@0: _local_player = OWNER_NONE; truelight@0: MarkWholeScreenDirty(); truelight@0: break; truelight@0: } truelight@193: Darkvater@1500: if (_switch_mode_errorstr != INVALID_STRING_ID) darkvater@172: ShowErrorMessage(INVALID_STRING_ID,_switch_mode_errorstr,0,0); 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; darkvater@213: truelight@543: // _frame_counter is increased somewhere else when in network-mode truelight@543: // Sidenote: _frame_counter is ONLY used for _savedump in non-MP-games truelight@543: // Should that not be deleted? If so, the next 2 lines can also be deleted tron@2639: if (!_networking) _frame_counter++; truelight@0: truelight@193: if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) { truelight@193: char buf[100]; truelight@193: sprintf(buf, "%s%.5d.sav", _savedump_path, _frame_counter); truelight@193: SaveOrLoad(buf, SL_SAVE); truelight@0: if ((uint)_frame_counter >= _savedump_last) exit(1); truelight@0: } truelight@0: 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@1: if (_patches.keep_all_autosave && _local_player != OWNER_SPECTATOR) { celestar@1962: const Player *p = GetPlayer(_local_player); truelight@0: char *s; truelight@0: sprintf(buf, "%s%s", _path.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@1500: s = (char*)GetString(buf + strlen(_path.autosave_dir) + strlen(PATHSEP), STR_4004); truelight@0: strcpy(s, ".sav"); Darkvater@1500: } else { /* Save a maximum of 15 autosaves */ truelight@0: int n = _autosave_ctr; truelight@0: _autosave_ctr = (_autosave_ctr + 1) & 15; truelight@0: sprintf(buf, "%s%sautosave%d.sav", _path.autosave_dir, PATHSEP, n); truelight@0: } truelight@0: darkvater@557: DEBUG(misc, 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: { Darkvater@1397: 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] = { Darkvater@1397: { 0, 0}, Darkvater@1397: {-2, 0}, // 1:left Darkvater@1397: { 0,-2}, // 2:up Darkvater@1397: {-2,-1}, // 3:left + up Darkvater@1397: { 2, 0}, // 4:right Darkvater@1397: { 0, 0}, // 5:left + right Darkvater@1397: { 2,-1}, // 6:right + up Darkvater@1397: { 0,-2}, // 7:left + right + up = up Darkvater@1397: { 0 ,2}, // 8:down Darkvater@1397: {-2 ,1}, // 9:down+left Darkvater@1397: { 0, 0}, // 10:impossible Darkvater@1397: {-2, 0}, // 11:left + up + down = left Darkvater@1397: { 2, 1}, // 12:down+right Darkvater@1397: { 0, 2}, // 13:left + right + down = down Darkvater@1397: { 0,-2}, // 14:left + right + up = up Darkvater@1397: { 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: { truelight@0: int m; 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 dominik@1199: if (_dirkeys) HandleKeyScrolling(); dominik@1199: truelight@0: // make a screenshot? truelight@0: if ((m=_make_screenshot) != 0) { truelight@0: _make_screenshot = 0; truelight@0: switch(m) { truelight@0: case 1: // make small screenshot truelight@0: UndrawMouseCursor(); truelight@0: ShowScreenshotResult(MakeScreenshot()); truelight@0: break; truelight@0: case 2: // make large screenshot peter1138@2437: ShowScreenshotResult(MakeWorldScreenshot(-(int)MapMaxX() * TILE_PIXELS, 0, (MapMaxX() + MapMaxY()) * TILE_PIXELS, (MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1, 0)); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: // switch game mode? truelight@0: if ((m=_switch_mode) != SM_NONE) { truelight@0: _switch_mode = SM_NONE; truelight@0: SwitchMode(m); 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 truelight@543: NetworkUDPGameLoop(); truelight@0: truelight@543: if (_networking) { 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: { truelight@0: Window *w = FindWindowById(WC_MAIN_WINDOW, 0); truelight@0: darkvater@983: if (w != NULL) { darkvater@983: _saved_scrollpos_x = WP(w,vp_d).scrollpos_x; darkvater@983: _saved_scrollpos_y = WP(w,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@1035: if (IsTileType(tile, MP_STREET)) { tron@2639: if (IsLevelCrossing(tile) && _m[tile].m3 & 0x80) _m[tile].m3 = OWNER_TOWN; truelight@0: tron@2360: if (_m[tile].m1 & 0x80) SetTileOwner(tile, OWNER_TOWN); tron@1035: } else if (IsTileType(tile, MP_TUNNELBRIDGE)) { tron@2360: if (_m[tile].m1 & 0x80) SetTileOwner(tile, OWNER_TOWN); 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: { tron@2639: 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: { tron@2639: Town* t; tron@2639: tron@2639: FOR_ALL_TOWNS(t) { tron@2639: if (t->xy != 0) 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) dominik@121: could be implemented this way: dominik@121: 1.) Go through all stations dominik@121: Build an array town_blocked[ town_id ][ player_id ] dominik@121: that stores if at least one station in that town is blocked for a player dominik@121: 2.) Go through that array, if you find a town that is not blocked for tron@2026: one player, but for all others, then give him exclusivity. dominik@121: */ dominik@121: } dominik@121: Darkvater@1500: 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@1181: for (i = 0; i < MapMaxY(); ++i) tron@1181: SetTileType(i * MapSizeX() + MapMaxX(), MP_VOID); tron@1181: for (i = 0; i < MapSizeX(); ++i) tron@1181: SetTileType(MapSizeX() * MapMaxY() + i, MP_VOID); 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: { dominik@1165: SignStruct *ss; tron@2639: tron@2639: FOR_ALL_SIGNS(ss) ss->owner = OWNER_NONE; dominik@1165: } dominik@1165: celestar@950: extern void UpdateOldAircraft( void ); celestar@950: extern void UpdateOilRig( void ); truelight@0: truelight@0: bool AfterLoadGame(uint version) 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. tron@2639: if (version <= 0x200) ConvertTownOwner(); truelight@0: dominik@121: // from version 4.1 of the savegame, exclusive rights are stored at towns tron@2639: if (version <= 0x400) UpdateExclusiveRights(); truelight@193: dominik@762: // from version 4.2 of the savegame, currencies are in a different order tron@2639: if (version <= 0x401) UpdateCurrencies(); dominik@762: dominik@1165: // from version 6.0 of the savegame, signs have an "owner" tron@2639: if (version <= 0x600) 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@831: (0x402) version, so I just check when versions are older, and then truelight@831: walk through the whole map.. */ truelight@831: if (version <= 0x402) { 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: truelight@0: // Load the sprites truelight@0: GfxLoadSprites(); truelight@0: truelight@0: // Update current year truelight@0: SetDate(_date); truelight@0: 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 tron@2639: if (version < 0x0C00) FixOldWaypoints(); truelight@1542: truelight@1542: UpdateAllWaypointSigns(); truelight@1542: truelight@0: // in version 2.2 of the savegame, we have new airports tron@2639: if (version <= 0x201) 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@0: // in version 4.0 of the savegame, is_active was introduced to determine truelight@0: // if a player does exist, rather then checking name_1 tron@2639: if (version <= 0x400) CheckIsPlayerActive(); truelight@193: dominik@929: // the void tiles on the southern border used to belong to a wrong class. tron@2639: if (version <= 0x402) 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: celestar@950: //In 5.1, Oilrigs have been moved (again) tron@2639: if (version <= 0x500) UpdateOilRig(); celestar@950: celestar@1264: if (version <= 0x600) { celestar@1264: BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) { celestar@1264: if (IsTileType(tile, MP_HOUSE)) { tron@2049: _m[tile].m4 = _m[tile].m2; celestar@1264: //XXX magic celestar@1264: SetTileType(tile, MP_VOID); tron@2049: _m[tile].m2 = ClosestTownFromTile(tile,(uint)-1)->index; celestar@1264: SetTileType(tile, MP_HOUSE); celestar@1264: } else if (IsTileType(tile, MP_STREET)) { celestar@1264: //XXX magic tron@2049: _m[tile].m4 |= (_m[tile].m2 << 4); tron@1901: if (IsTileOwner(tile, OWNER_TOWN)) { tron@1901: SetTileType(tile, MP_VOID); tron@2049: _m[tile].m2 = ClosestTownFromTile(tile,(uint)-1)->index; tron@1901: SetTileType(tile, MP_STREET); tron@1901: } else { tron@2049: _m[tile].m2 = 0; tron@1901: } celestar@1264: } celestar@1264: } END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0); celestar@1264: } celestar@1264: celestar@1377: if (version < 0x900) { celestar@1377: Town *t; tron@2639: FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); celestar@1377: } celestar@1377: celestar@1993: if (version < 0xF00) { celestar@1993: BEGIN_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0) { tron@2049: if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile) && HASBIT(_m[tile].m4, 2)) { tron@2049: CLRBIT(_m[tile].m4, 2); tron@2049: SETBIT(_m[tile].m4, 3); celestar@1993: } peter1138@2620: // Clear possible junk data in PBS bits. peter1138@2620: if (IsTileType(tile, MP_RAILWAY) && !HASBIT(_m[tile].m5, 7)) peter1138@2620: SB(_m[tile].m4, 4, 4, 0); celestar@1993: } END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0); celestar@1993: } celestar@1993: bjarni@2293: if (version < 0x1000) { bjarni@2293: FOR_ALL_PLAYERS(p) { tron@2634: EngineID i; tron@2634: peter1138@2572: for (i = 0; i < TOTAL_NUM_ENGINES; i++) { bjarni@2293: p->engine_replacement[i] = INVALID_ENGINE; bjarni@2293: } bjarni@2293: p->engine_renew = false; bjarni@2293: p->engine_renew_months = -6; bjarni@2293: p->engine_renew_money = 100000; bjarni@2293: } bjarni@2322: if (_local_player < MAX_PLAYERS) { bjarni@2322: // Set the human controlled player to the patch settings bjarni@2322: // Scenario editor do not have any companies bjarni@2322: p = GetPlayer(_local_player); bjarni@2322: p->engine_renew = _patches.autorenew; bjarni@2322: p->engine_renew_months = _patches.autorenew_months; bjarni@2322: p->engine_renew_money = _patches.autorenew_money; bjarni@2322: } bjarni@2293: } bjarni@2293: bjarni@2617: /* In version 16.1 of the savegame, trains became aware of station lengths bjarni@2617: need to initialized to the invalid state bjarni@2617: players needs to set renew_keep_length too */ bjarni@2617: if (version < 0x1001) { bjarni@2617: Vehicle *v; bjarni@2617: FOR_ALL_PLAYERS(p) { bjarni@2617: p->renew_keep_length = false; bjarni@2617: } bjarni@2617: bjarni@2617: FOR_ALL_VEHICLES(v) { bjarni@2617: if (v->type == VEH_Train) { bjarni@2617: v->u.rail.shortest_platform[0] = 255; bjarni@2617: v->u.rail.shortest_platform[1] = 0; bjarni@2617: } bjarni@2617: } bjarni@2617: } bjarni@2617: tron@2639: FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index); celestar@2147: truelight@0: return true; truelight@0: }