/** * Append a song to a custom playlist. * Always adds to the currently active playlist. * @param song_index Index of song in the current music set to add */ void MusicSystem::PlaylistAdd(size_t song_index) { if (!this->IsCustomPlaylist()) return; /* Pick out song from the music set */ if (song_index >= this->music_set.size()) return; PlaylistEntry entry = this->music_set[song_index]; /* Check for maximum length */ if (this->standard_playlists[this->selected_playlist].size() >= NUM_SONGS_PLAYLIST) return; /* Add it to the appropriate playlist, and the display */ this->standard_playlists[this->selected_playlist].push_back(entry); this->displayed_playlist.push_back(entry); /* Add it to the active playlist, if playback is shuffled select a random position to add at */ if (this->active_playlist.empty()) { this->active_playlist.push_back(entry); if (this->IsPlaying()) this->Play(); } else if (this->IsShuffle()) { /* Generate a random position between 0 and n (inclusive, new length) to insert at */ size_t maxpos = this->displayed_playlist.size(); size_t newpos = InteractiveRandom() % maxpos; this->active_playlist.insert(this->active_playlist.begin() + newpos, entry); /* Make sure to shift up the current playback position if the song was inserted before it */ if ((int)newpos <= this->playlist_position) this->playlist_position++; } else { this->active_playlist.push_back(entry); } this->SaveCustomPlaylist(this->selected_playlist); InvalidateWindowData(WC_MUSIC_TRACK_SELECTION, 0); }
static void SelectSongToPlay() { uint i = 0; uint j = 0; memset(_cur_playlist, 0, sizeof(_cur_playlist)); do { const char *filename = BaseMusic::GetUsedSet()->files[_playlists[_msf.playlist][i] - 1].filename; /* We are now checking for the existence of that file prior * to add it to the list of available songs */ if (!StrEmpty(filename) && FioCheckFileExists(filename, GM_DIR)) { _cur_playlist[j] = _playlists[_msf.playlist][i]; j++; } } while (_playlists[_msf.playlist][++i] != 0 && j < lengthof(_cur_playlist) - 1); /* Do not shuffle when on the intro-start window, as the song to play has to be the original TTD Theme*/ if (_msf.shuffle && _game_mode != GM_MENU) { i = 500; do { uint32 r = InteractiveRandom(); byte *a = &_cur_playlist[GB(r, 0, 5)]; byte *b = &_cur_playlist[GB(r, 8, 5)]; if (*a != 0 && *b != 0) { byte t = *a; *a = *b; *b = t; } } while (--i); } }
void GameLoop() { ProcessAsyncSaveFinish(); /* autosave game? */ if (_do_autosave) { _do_autosave = false; DoAutosave(); SetWindowDirty(WC_STATUS_BAR, 0); } /* switch game mode? */ if (_switch_mode != SM_NONE) { SwitchToMode(_switch_mode); _switch_mode = SM_NONE; } IncreaseSpriteLRU(); InteractiveRandom(); extern int _caret_timer; _caret_timer += 3; CursorTick(); #ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkUDPGameLoop(); if (_networking && !IsGeneratingWorld()) { /* Multiplayer */ NetworkGameLoop(); } else { if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); } /* Check chat messages roughly once a second. */ static uint check_message = 0; if (++check_message > 1000 / MILLISECONDS_PER_TICK) { check_message = 0; NetworkChatMessageLoop(); } #else StateGameLoop(); #endif /* ENABLE_NETWORK */ if (!_pause_mode && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); if (!_pause_mode || _game_mode == GM_EDITOR || _settings_game.construction.command_pause_level > CMDPL_NO_CONSTRUCTION) MoveAllTextEffects(); InputLoop(); _sound_driver->MainLoop(); MusicLoop(); }
/** Enable shuffle mode and restart playback */ void MusicSystem::Shuffle() { _settings_client.music.shuffle = true; this->active_playlist = this->displayed_playlist; for (size_t i = 0; i < this->active_playlist.size(); i++) { size_t shuffle_index = InteractiveRandom() % (this->active_playlist.size() - i); std::swap(this->active_playlist[i], this->active_playlist[i + shuffle_index]); } if (_settings_client.music.playing) this->Play(); InvalidateWindowData(WC_MUSIC_WINDOW, 0); }
Sprite *Blitter_8bppDebug::Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) { Sprite *dest_sprite; dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + sprite->height * sprite->width); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; /* Write a random colour as sprite; this makes debugging really easy */ uint colour = InteractiveRandom() % 150 + 2; for (int i = 0; i < sprite->height * sprite->width; i++) { dest_sprite->data[i] = (sprite->data[i].m == 0) ? 0 : colour; } return dest_sprite; }
/** * Generates valid town name. * @param townnameparts if a name is generated, it's stored there * @param town_names if a name is generated, check its uniqueness with the set * @return true iff a name was generated */ bool GenerateTownName(uint32 *townnameparts, TownNames *town_names) { /* Do not set too low tries, since when we run out of names, we loop * for #tries only one time anyway - then we stop generating more * towns. Do not show it too high neither, since looping through all * the other towns may take considerable amount of time (10000 is * too much). */ TownNameParams par(_settings_game.game_creation.town_name); /* This function is called very often without entering the gameloop * inbetween. So reset layout cache to prevent it from growing too big. */ Layouter::ReduceLineCache(); for (int i = 1000; i != 0; i--) { uint32 r = _generating_world ? Random() : InteractiveRandom(); if (!VerifyTownName(r, &par, town_names)) continue; *townnameparts = r; return true; } return false; }
static void SelectSongToPlay() { uint i = 0; uint j = 0; memset(_cur_playlist, 0, sizeof(_cur_playlist)); do { /* File is the index into the file table of the music set. The play list uses 0 as 'no entry', * so we need to subtract 1. In case of 'no entry' (file = -1), just skip adding it outright. */ int file = _playlists[_settings_client.music.playlist][i] - 1; if (file >= 0) { const char *filename = BaseMusic::GetUsedSet()->files[file].filename; /* We are now checking for the existence of that file prior * to add it to the list of available songs */ if (!StrEmpty(filename) && FioCheckFileExists(filename, BASESET_DIR)) { _cur_playlist[j] = _playlists[_settings_client.music.playlist][i]; j++; } } } while (_playlists[_settings_client.music.playlist][++i] != 0 && j < lengthof(_cur_playlist) - 1); /* Do not shuffle when on the intro-start window, as the song to play has to be the original TTD Theme*/ if (_settings_client.music.shuffle && _game_mode != GM_MENU) { i = 500; do { uint32 r = InteractiveRandom(); byte *a = &_cur_playlist[GB(r, 0, 5)]; byte *b = &_cur_playlist[GB(r, 8, 5)]; if (*a != 0 && *b != 0) { byte t = *a; *a = *b; *b = t; } } while (--i); } }
void VideoDriver_SDL::MainLoop() { uint32 cur_ticks = SDL_CALL SDL_GetTicks(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; uint32 mod; int numkeys; Uint8 *keys; CheckPaletteAnim(); if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ _draw_mutex = ThreadMutex::New(); if (_draw_mutex == NULL) { _draw_threaded = false; } else { _draw_mutex->BeginCritical(); _draw_continue = true; _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { _draw_mutex->EndCritical(); delete _draw_mutex; _draw_mutex = NULL; } else { /* Wait till the draw mutex has started itself. */ _draw_mutex->WaitForSignal(); } } } DEBUG(driver, 1, "SDL: using %sthreads", _draw_threaded ? "" : "no "); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness while (PollEvent() == -1) {} if (_exit_game) break; mod = SDL_CALL SDL_GetModState(); #if SDL_VERSION_ATLEAST(1, 3, 0) keys = SDL_CALL SDL_GetKeyboardState(&numkeys); #else keys = SDL_CALL SDL_GetKeyState(&numkeys); #endif #if defined(_DEBUG) if (_shift_pressed) #else /* Speedup when pressing tab, except when using ALT+TAB * to switch to another application */ #if SDL_VERSION_ATLEAST(1, 3, 0) if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0) #else if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0) #endif /* SDL_VERSION_ATLEAST(1, 3, 0) */ #endif /* defined(_DEBUG) */ { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = SDL_CALL SDL_GetTicks(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = !!(mod & KMOD_CTRL); _shift_pressed = !!(mod & KMOD_SHIFT); /* determine which directional keys are down */ _dirkeys = #if SDL_VERSION_ATLEAST(1, 3, 0) (keys[SDL_SCANCODE_LEFT] ? 1 : 0) | (keys[SDL_SCANCODE_UP] ? 2 : 0) | (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) | (keys[SDL_SCANCODE_DOWN] ? 8 : 0); #else (keys[SDLK_LEFT] ? 1 : 0) | (keys[SDLK_UP] ? 2 : 0) | (keys[SDLK_RIGHT] ? 4 : 0) | (keys[SDLK_DOWN] ? 8 : 0); #endif if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); /* The gameloop is the part that can run asynchronously. The rest * except sleeping can't. */ if (_draw_mutex != NULL) _draw_mutex->EndCritical(); GameLoop(); if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); UpdateWindows(); _local_palette = _cur_palette; } else { /* Release the thread while sleeping */ if (_draw_mutex != NULL) _draw_mutex->EndCritical(); CSleep(1); if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); NetworkDrawChatMessage(); DrawMouseCursor(); } /* End of the critical part. */ if (_draw_mutex != NULL && !HasModalProgress()) { _draw_mutex->SendSignal(); } else { /* Oh, we didn't have threads, then just draw unthreaded */ CheckPaletteAnim(); DrawSurfaceToScreen(); } } if (_draw_mutex != NULL) { _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ _draw_mutex->SendSignal(); _draw_mutex->EndCritical(); _draw_thread->Join(); delete _draw_mutex; delete _draw_thread; _draw_mutex = NULL; _draw_thread = NULL; } }
/** * Main entry point for this lovely game. * @param argc The number of arguments passed to this game. * @param argv The values of the arguments. * @return 0 when there is no error. */ int openttd_main(int argc, char *argv[]) { char *musicdriver = NULL; char *sounddriver = NULL; char *videodriver = NULL; char *blitter = NULL; char *graphics_set = NULL; char *sounds_set = NULL; char *music_set = NULL; Dimension resolution = {0, 0}; /* AfterNewGRFScan sets save_config to true after scanning completed. */ bool save_config = false; AfterNewGRFScan *scanner = new AfterNewGRFScan(&save_config); #if defined(ENABLE_NETWORK) bool dedicated = false; char *debuglog_conn = NULL; extern bool _dedicated_forks; _dedicated_forks = false; #endif /* ENABLE_NETWORK */ _game_mode = GM_MENU; _switch_mode = SM_MENU; _config_file = NULL; GetOptData mgo(argc - 1, argv + 1, _options); int ret = 0; int i; while ((i = mgo.GetOpt()) != -1) { switch (i) { case 'I': free(graphics_set); graphics_set = stredup(mgo.opt); break; case 'S': free(sounds_set); sounds_set = stredup(mgo.opt); break; case 'M': free(music_set); music_set = stredup(mgo.opt); break; case 'm': free(musicdriver); musicdriver = stredup(mgo.opt); break; case 's': free(sounddriver); sounddriver = stredup(mgo.opt); break; case 'v': free(videodriver); videodriver = stredup(mgo.opt); break; case 'b': free(blitter); blitter = stredup(mgo.opt); break; #if defined(ENABLE_NETWORK) case 'D': free(musicdriver); free(sounddriver); free(videodriver); free(blitter); musicdriver = stredup("null"); sounddriver = stredup("null"); videodriver = stredup("dedicated"); blitter = stredup("null"); dedicated = true; SetDebugString("net=6"); if (mgo.opt != NULL) { /* Use the existing method for parsing (openttd -n). * However, we do ignore the #company part. */ const char *temp = NULL; const char *port = NULL; ParseConnectionString(&temp, &port, mgo.opt); if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt; if (port != NULL) scanner->dedicated_port = atoi(port); } break; case 'f': _dedicated_forks = true; break; case 'n': scanner->network_conn = mgo.opt; // optional IP parameter, NULL if unset break; case 'l': debuglog_conn = mgo.opt; break; case 'p': scanner->join_server_password = mgo.opt; break; case 'P': scanner->join_company_password = mgo.opt; break; #endif /* ENABLE_NETWORK */ case 'r': ParseResolution(&resolution, mgo.opt); break; case 't': scanner->startyear = atoi(mgo.opt); break; case 'd': { #if defined(WIN32) CreateConsole(); #endif if (mgo.opt != NULL) SetDebugString(mgo.opt); break; } case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break; case 'g': if (mgo.opt != NULL) { _file_to_saveload.SetName(mgo.opt); bool is_scenario = _switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO; _switch_mode = is_scenario ? SM_LOAD_SCENARIO : SM_LOAD_GAME; _file_to_saveload.SetMode(SLO_LOAD, is_scenario ? FT_SCENARIO : FT_SAVEGAME, DFT_GAME_FILE); /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ const char *t = strrchr(_file_to_saveload.name, '.'); if (t != NULL) { FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, t, NULL, NULL); if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft); } break; } _switch_mode = SM_NEWGAME; /* Give a random map if no seed has been given */ if (scanner->generation_seed == GENERATE_NEW_SEED) { scanner->generation_seed = InteractiveRandom(); } break; case 'q': { DeterminePaths(argv[0]); if (StrEmpty(mgo.opt)) { ret = 1; goto exit_noshutdown; } char title[80]; title[0] = '\0'; FiosGetSavegameListCallback(SLO_LOAD, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title)); _load_check_data.Clear(); SaveOrLoadResult res = SaveOrLoad(mgo.opt, SLO_CHECK, DFT_GAME_FILE, SAVE_DIR, false); if (res != SL_OK || _load_check_data.HasErrors()) { fprintf(stderr, "Failed to open savegame\n"); if (_load_check_data.HasErrors()) { char buf[256]; SetDParamStr(0, _load_check_data.error_data); GetString(buf, _load_check_data.error, lastof(buf)); fprintf(stderr, "%s\n", buf); } goto exit_noshutdown; } WriteSavegameInfo(title); goto exit_noshutdown; } case 'G': scanner->generation_seed = atoi(mgo.opt); break; case 'c': free(_config_file); _config_file = stredup(mgo.opt); break; case 'x': scanner->save_config = false; break; case 'h': i = -2; // Force printing of help. break; } if (i == -2) break; } if (i == -2 || mgo.numleft > 0) { /* Either the user typed '-h', he made an error, or he added unrecognized command line arguments. * In all cases, print the help, and exit. * * The next two functions are needed to list the graphics sets. We can't do them earlier * because then we cannot show it on the debug console as that hasn't been configured yet. */ DeterminePaths(argv[0]); TarScanner::DoScan(TarScanner::BASESET); BaseGraphics::FindSets(); BaseSounds::FindSets(); BaseMusic::FindSets(); ShowHelp(); goto exit_noshutdown; } DeterminePaths(argv[0]); TarScanner::DoScan(TarScanner::BASESET); #if defined(ENABLE_NETWORK) if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision); if (_dedicated_forks && !dedicated) _dedicated_forks = false; #if defined(UNIX) && !defined(__MORPHOS__) /* We must fork here, or we'll end up without some resources we need (like sockets) */ if (_dedicated_forks) DedicatedFork(); #endif #endif LoadFromConfig(true); if (resolution.width != 0) _cur_resolution = resolution; /* * The width and height must be at least 1 pixel and width times * height times bytes per pixel must still fit within a 32 bits * integer, even for 32 bpp video modes. This way all internal * drawing routines work correctly. */ _cur_resolution.width = ClampU(_cur_resolution.width, 1, UINT16_MAX / 2); _cur_resolution.height = ClampU(_cur_resolution.height, 1, UINT16_MAX / 2); /* Assume the cursor starts within the game as not all video drivers * get an event that the cursor is within the window when it is opened. * Saying the cursor is there makes no visible difference as it would * just be out of the bounds of the window. */ _cursor.in_window = true; /* enumerate language files */ InitializeLanguagePacks(); /* Initialize the regular font for FreeType */ InitFreeType(false); /* This must be done early, since functions use the SetWindowDirty* calls */ InitWindowSystem(); BaseGraphics::FindSets(); if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = stredup(BaseGraphics::ini_set); if (!BaseGraphics::SetSet(graphics_set)) { if (!StrEmpty(graphics_set)) { BaseGraphics::SetSet(NULL); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); msg.SetDParamStr(0, graphics_set); ScheduleErrorMessage(msg); } } free(graphics_set); /* Initialize game palette */ GfxInitPalettes(); DEBUG(misc, 1, "Loading blitter..."); if (blitter == NULL && _ini_blitter != NULL) blitter = stredup(_ini_blitter); _blitter_autodetected = StrEmpty(blitter); /* Activate the initial blitter. * This is only some initial guess, after NewGRFs have been loaded SwitchNewGRFBlitter may switch to a different one. * - Never guess anything, if the user specified a blitter. (_blitter_autodetected) * - Use 32bpp blitter if baseset or 8bpp-support settings says so. * - Use 8bpp blitter otherwise. */ if (!_blitter_autodetected || (_support8bpp != S8BPP_NONE && (BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP)) || BlitterFactory::SelectBlitter("32bpp-anim") == NULL) { if (BlitterFactory::SelectBlitter(blitter) == NULL) { StrEmpty(blitter) ? usererror("Failed to autoprobe blitter") : usererror("Failed to select requested blitter '%s'; does it exist?", blitter); } } free(blitter); if (videodriver == NULL && _ini_videodriver != NULL) videodriver = stredup(_ini_videodriver); DriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO); free(videodriver); InitializeSpriteSorter(); /* Initialize the zoom level of the screen to normal */ _screen.zoom = ZOOM_LVL_NORMAL; NetworkStartUp(); // initialize network-core #if defined(ENABLE_NETWORK) if (debuglog_conn != NULL && _network_available) { const char *not_used = NULL; const char *port = NULL; uint16 rport; rport = NETWORK_DEFAULT_DEBUGLOG_PORT; ParseConnectionString(¬_used, &port, debuglog_conn); if (port != NULL) rport = atoi(port); NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); } #endif /* ENABLE_NETWORK */ if (!HandleBootstrap()) { ShutdownGame(); goto exit_bootstrap; } VideoDriver::GetInstance()->ClaimMousePointer(); /* initialize screenshot formats */ InitializeScreenshotFormats(); BaseSounds::FindSets(); if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = stredup(BaseSounds::ini_set); if (!BaseSounds::SetSet(sounds_set)) { if (StrEmpty(sounds_set) || !BaseSounds::SetSet(NULL)) { usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); msg.SetDParamStr(0, sounds_set); ScheduleErrorMessage(msg); } } free(sounds_set); BaseMusic::FindSets(); if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = stredup(BaseMusic::ini_set); if (!BaseMusic::SetSet(music_set)) { if (StrEmpty(music_set) || !BaseMusic::SetSet(NULL)) { usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); msg.SetDParamStr(0, music_set); ScheduleErrorMessage(msg); } } free(music_set); if (sounddriver == NULL && _ini_sounddriver != NULL) sounddriver = stredup(_ini_sounddriver); DriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); free(sounddriver); if (musicdriver == NULL && _ini_musicdriver != NULL) musicdriver = stredup(_ini_musicdriver); DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); free(musicdriver); /* Take our initial lock on whatever we might want to do! */ _modal_progress_paint_mutex->BeginCritical(); _modal_progress_work_mutex->BeginCritical(); GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy WaitTillGeneratedWorld(); LoadIntroGame(false); CheckForMissingGlyphs(); /* ScanNewGRFFiles now has control over the scanner. */ ScanNewGRFFiles(scanner); scanner = NULL; VideoDriver::GetInstance()->MainLoop(); WaitTillSaved(); /* only save config if we have to */ if (save_config) { SaveToConfig(); SaveHotkeysToConfig(); WindowDesc::SaveToConfig(); SaveToHighScore(); } /* Reset windowing system, stop drivers, free used memory, ... */ ShutdownGame(); goto exit_normal; exit_noshutdown: /* These three are normally freed before bootstrap. */ free(graphics_set); free(videodriver); free(blitter); exit_bootstrap: /* These are normally freed before exit, but after bootstrap. */ free(sounds_set); free(music_set); free(musicdriver); free(sounddriver); exit_normal: free(BaseGraphics::ini_set); free(BaseSounds::ini_set); free(BaseMusic::ini_set); free(_ini_musicdriver); free(_ini_sounddriver); free(_ini_videodriver); free(_ini_blitter); delete scanner; #ifdef ENABLE_NETWORK extern FILE *_log_fd; if (_log_fd != NULL) { fclose(_log_fd); } #endif /* ENABLE_NETWORK */ return ret; }
void VideoDriver_Allegro::MainLoop() { uint32 cur_ticks = GetTime(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; CheckPaletteAnim(); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness PollEvent(); if (_exit_game) return; #if defined(_DEBUG) if (_shift_pressed) #else /* Speedup when pressing tab, except when using ALT+TAB * to switch to another application */ if (key[KEY_TAB] && (key_shifts & KB_ALT_FLAG) == 0) #endif { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = GetTime(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = !!(key_shifts & KB_CTRL_FLAG); _shift_pressed = !!(key_shifts & KB_SHIFT_FLAG); /* determine which directional keys are down */ _dirkeys = (key[KEY_LEFT] ? 1 : 0) | (key[KEY_UP] ? 2 : 0) | (key[KEY_RIGHT] ? 4 : 0) | (key[KEY_DOWN] ? 8 : 0); if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); GameLoop(); UpdateWindows(); CheckPaletteAnim(); DrawSurfaceToScreen(); } else { CSleep(1); NetworkDrawChatMessage(); DrawMouseCursor(); DrawSurfaceToScreen(); } } }
/** * The internal, real, generate function. */ static void _GenerateWorld(void *) { /* Make sure everything is done via OWNER_NONE. */ Backup<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE); try { _generating_world = true; _modal_progress_work_mutex->BeginCritical(); if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait..."); /* Set the Random() seed to generation_seed so we produce the same map with the same seed */ if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom(); _random.SetSeed(_settings_game.game_creation.generation_seed); SetGeneratingWorldProgress(GWP_MAP_INIT, 2); SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); IncreaseGeneratingWorldProgress(GWP_MAP_INIT); /* Must start economy early because of the costs. */ StartupEconomy(); /* Don't generate landscape items when in the scenario editor. */ if (_gw.mode == GWM_EMPTY) { SetGeneratingWorldProgress(GWP_OBJECT, 1); /* Make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (uint row = 0; row < MapSizeY(); row++) MakeVoid(TileXY(0, row)); for (uint col = 0; col < MapSizeX(); col++) MakeVoid(TileXY(col, 0)); } /* Make the map the height of the setting */ if (_game_mode != GM_MENU) FlatEmptyWorld(_settings_game.game_creation.se_flat_world_height); ConvertGroundTilesIntoWaterTiles(); IncreaseGeneratingWorldProgress(GWP_OBJECT); } else { GenerateLandscape(_gw.mode); GenerateClearTile(); /* only generate towns, tree and industries in newgame mode. */ if (_game_mode != GM_EDITOR) { if (!GenerateTowns(_settings_game.economy.town_layout)) { _cur_company.Restore(); HandleGeneratingWorldAbortion(); return; } GenerateIndustries(); GenerateObjects(); GenerateTrees(); } } /* These are probably pointless when inside the scenario editor. */ SetGeneratingWorldProgress(GWP_GAME_INIT, 3); StartupCompanies(); IncreaseGeneratingWorldProgress(GWP_GAME_INIT); StartupEngines(); IncreaseGeneratingWorldProgress(GWP_GAME_INIT); StartupDisasters(); _generating_world = false; /* No need to run the tile loop in the scenario editor. */ if (_gw.mode != GWM_EMPTY) { uint i; SetGeneratingWorldProgress(GWP_RUNTILELOOP, 0x500); for (i = 0; i < 0x500; i++) { RunTileLoop(); _tick_counter++; IncreaseGeneratingWorldProgress(GWP_RUNTILELOOP); } if (_game_mode != GM_EDITOR) { Game::StartNew(); if (Game::GetInstance() != NULL) { SetGeneratingWorldProgress(GWP_RUNSCRIPT, 2500); _generating_world = true; for (i = 0; i < 2500; i++) { Game::GameLoop(); IncreaseGeneratingWorldProgress(GWP_RUNSCRIPT); if (Game::GetInstance()->IsSleeping()) break; } _generating_world = false; } } } BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP); ResetObjectToPlace(); _cur_company.Trash(); _current_company = _local_company = _gw.lc; SetGeneratingWorldProgress(GWP_GAME_START, 1); /* Call any callback */ if (_gw.proc != NULL) _gw.proc(); IncreaseGeneratingWorldProgress(GWP_GAME_START); CleanupGeneration(); _modal_progress_work_mutex->EndCritical(); ShowNewGRFError(); if (_network_dedicated) DEBUG(net, 1, "Map generated, starting game"); DEBUG(desync, 1, "new_map: %08x", _settings_game.game_creation.generation_seed); if (_debug_desync_level > 0) { char name[MAX_PATH]; seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date); SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false); } } catch (...) { BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true); if (_cur_company.IsValid()) _cur_company.Restore(); _generating_world = false; _modal_progress_work_mutex->EndCritical(); throw; } }
void VideoDriver_Dedicated::MainLoop() { uint32 cur_ticks = GetTime(); uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; /* Signal handlers */ #if defined(UNIX) || defined(PSP) signal(SIGTERM, DedicatedSignalHandler); signal(SIGINT, DedicatedSignalHandler); signal(SIGQUIT, DedicatedSignalHandler); #endif /* Load the dedicated server stuff */ _is_network_server = true; _network_dedicated = true; _current_company = _local_company = COMPANY_SPECTATOR; /* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */ if (_switch_mode != SM_LOAD_GAME) { StartNewGameWithoutGUI(GENERATE_NEW_SEED); SwitchToMode(_switch_mode); _switch_mode = SM_NONE; } else { _switch_mode = SM_NONE; /* First we need to test if the savegame can be loaded, else we will end up playing the * intro game... */ if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, BASE_DIR)) { /* Loading failed, pop out.. */ DEBUG(net, 0, "Loading requested map failed, aborting"); _networking = false; } else { /* We can load this game, so go ahead */ SwitchToMode(SM_LOAD_GAME); } } /* Done loading, start game! */ if (!_networking) { DEBUG(net, 0, "Dedicated server could not be started, aborting"); return; } while (!_exit_game) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness if (!_dedicated_forks) DedicatedHandleKeyInput(); cur_ticks = GetTime(); _realtime_tick += cur_ticks - prev_cur_ticks; if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks || _ddc_fastforward) { next_tick = cur_ticks + MILLISECONDS_PER_TICK; GameLoop(); UpdateWindows(); } /* Don't sleep when fast forwarding (for desync debugging) */ if (!_ddc_fastforward) CSleep(1); } }
int ttd_main(int argc, char *argv[]) { int i; const char *optformat; char *musicdriver = NULL; char *sounddriver = NULL; char *videodriver = NULL; char *blitter = NULL; char *graphics_set = NULL; char *sounds_set = NULL; char *music_set = NULL; Dimension resolution = {0, 0}; Year startyear = INVALID_YEAR; uint generation_seed = GENERATE_NEW_SEED; bool save_config = true; #if defined(ENABLE_NETWORK) bool dedicated = false; bool network = false; char *network_conn = NULL; char *debuglog_conn = NULL; char *dedicated_host = NULL; uint16 dedicated_port = 0; char *join_server_password = NULL; char *join_company_password = NULL; extern bool _dedicated_forks; _dedicated_forks = false; #endif /* ENABLE_NETWORK */ _game_mode = GM_MENU; _switch_mode = SM_MENU; _switch_mode_errorstr = INVALID_STRING_ID; _config_file = NULL; /* The last param of the following function means this: * a letter means: it accepts that param (e.g.: -h) * a ':' behind it means: it need a param (e.g.: -m<driver>) * a '::' behind it means: it can optional have a param (e.g.: -d<debug>) */ optformat = "m:s:v:b:hD::n::ei::I:S:M:t:d::r:g::G:c:xl:p:P:" #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) "f" #endif ; MyGetOptData mgo(argc - 1, argv + 1, optformat); while ((i = MyGetOpt(&mgo)) != -1) { switch (i) { case 'I': free(graphics_set); graphics_set = strdup(mgo.opt); break; case 'S': free(sounds_set); sounds_set = strdup(mgo.opt); break; case 'M': free(music_set); music_set = strdup(mgo.opt); break; case 'm': free(musicdriver); musicdriver = strdup(mgo.opt); break; case 's': free(sounddriver); sounddriver = strdup(mgo.opt); break; case 'v': free(videodriver); videodriver = strdup(mgo.opt); break; case 'b': free(blitter); blitter = strdup(mgo.opt); break; #if defined(ENABLE_NETWORK) case 'D': free(musicdriver); free(sounddriver); free(videodriver); free(blitter); musicdriver = strdup("null"); sounddriver = strdup("null"); videodriver = strdup("dedicated"); blitter = strdup("null"); dedicated = true; SetDebugString("net=6"); if (mgo.opt != NULL) { /* Use the existing method for parsing (openttd -n). * However, we do ignore the #company part. */ const char *temp = NULL; const char *port = NULL; ParseConnectionString(&temp, &port, mgo.opt); if (!StrEmpty(mgo.opt)) dedicated_host = mgo.opt; if (port != NULL) dedicated_port = atoi(port); } break; case 'f': _dedicated_forks = true; break; case 'n': network = true; network_conn = mgo.opt; // optional IP parameter, NULL if unset break; case 'l': debuglog_conn = mgo.opt; break; case 'p': join_server_password = mgo.opt; break; case 'P': join_company_password = mgo.opt; break; #endif /* ENABLE_NETWORK */ case 'r': ParseResolution(&resolution, mgo.opt); break; case 't': startyear = atoi(mgo.opt); break; case 'd': { #if defined(WIN32) CreateConsole(); #endif if (mgo.opt != NULL) SetDebugString(mgo.opt); break; } case 'e': _switch_mode = SM_EDITOR; break; case 'i': /* there is an argument, it is not empty, and it is exactly 1 char long */ if (!StrEmpty(mgo.opt) && mgo.opt[1] == '\0') { _use_palette = (PaletteType)(mgo.opt[0] - '0'); if (_use_palette <= MAX_PAL) break; } usererror("Valid value for '-i' is 0, 1 or 2"); case 'g': if (mgo.opt != NULL) { strecpy(_file_to_saveload.name, mgo.opt, lastof(_file_to_saveload.name)); _switch_mode = SM_LOAD; _file_to_saveload.mode = SL_LOAD; /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ const char *t = strrchr(_file_to_saveload.name, '.'); if (t != NULL) { FiosType ft = FiosGetSavegameListCallback(SLD_LOAD_GAME, _file_to_saveload.name, t, NULL, NULL); if (ft != FIOS_TYPE_INVALID) SetFiosType(ft); } break; } _switch_mode = SM_NEWGAME; /* Give a random map if no seed has been given */ if (generation_seed == GENERATE_NEW_SEED) { generation_seed = InteractiveRandom(); } break; case 'G': generation_seed = atoi(mgo.opt); break; case 'c': _config_file = strdup(mgo.opt); break; case 'x': save_config = false; break; case -2: case 'h': /* The next two functions are needed to list the graphics sets. * We can't do them earlier because then we can't show it on * the debug console as that hasn't been configured yet. */ DeterminePaths(argv[0]); BaseGraphics::FindSets(); BaseSounds::FindSets(); BaseMusic::FindSets(); ShowHelp(); return 0; } } #if defined(WINCE) && defined(_DEBUG) /* Switch on debug lvl 4 for WinCE if Debug release, as you can't give params, and you most likely do want this information */ SetDebugString("4"); #endif DeterminePaths(argv[0]); BaseGraphics::FindSets(); BaseSounds::FindSets(); BaseMusic::FindSets(); #if defined(ENABLE_NETWORK) && defined(UNIX) && !defined(__MORPHOS__) /* We must fork here, or we'll end up without some resources we need (like sockets) */ if (_dedicated_forks) DedicatedFork(); #endif TarScanner::DoScan(); AI::Initialize(); LoadFromConfig(); AI::Uninitialize(true); CheckConfig(); LoadFromHighScore(); LoadHotkeysFromConfig(); if (resolution.width != 0) { _cur_resolution = resolution; } if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear; if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; /* * The width and height must be at least 1 pixel and width times * height times bytes per pixel must still fit within a 32 bits * integer, even for 32 bpp video modes. This way all internal * drawing routines work correctly. */ _cur_resolution.width = ClampU(_cur_resolution.width, 1, UINT16_MAX / 2); _cur_resolution.height = ClampU(_cur_resolution.height, 1, UINT16_MAX / 2); #if defined(ENABLE_NETWORK) if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision); if (dedicated_host) { _network_bind_list.Clear(); *_network_bind_list.Append() = strdup(dedicated_host); } if (dedicated_port) _settings_client.network.server_port = dedicated_port; if (_dedicated_forks && !dedicated) _dedicated_forks = false; #endif /* ENABLE_NETWORK */ /* enumerate language files */ InitializeLanguagePacks(); /* initialize screenshot formats */ InitializeScreenshotFormats(); /* Initialize FreeType */ InitFreeType(); /* This must be done early, since functions use the SetWindowDirty* calls */ InitWindowSystem(); /* Look for the sounds before the graphics. Otherwise none would be set and * the first initialisation of the video happens on the wrong data. Now it * can do the first initialisation right. */ if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = strdup(BaseSounds::ini_set); if (!BaseSounds::SetSet(sounds_set)) { StrEmpty(sounds_set) ? usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of readme.txt.") : usererror("Failed to select requested sounds set '%s'", sounds_set); } free(sounds_set); if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = strdup(BaseGraphics::ini_set); if (!BaseGraphics::SetSet(graphics_set)) { StrEmpty(graphics_set) ? usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt.") : usererror("Failed to select requested graphics set '%s'", graphics_set); } free(graphics_set); if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = strdup(BaseMusic::ini_set); if (!BaseMusic::SetSet(music_set)) { StrEmpty(music_set) ? usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of readme.txt.") : usererror("Failed to select requested music set '%s'", music_set); } free(music_set); /* Initialize game palette */ GfxInitPalettes(); DEBUG(misc, 1, "Loading blitter..."); if (blitter == NULL && _ini_blitter != NULL) blitter = strdup(_ini_blitter); if (BlitterFactoryBase::SelectBlitter(blitter) == NULL) { StrEmpty(blitter) ? usererror("Failed to autoprobe blitter") : usererror("Failed to select requested blitter '%s'; does it exist?", blitter); } free(blitter); DEBUG(driver, 1, "Loading drivers..."); if (sounddriver == NULL && _ini_sounddriver != NULL) sounddriver = strdup(_ini_sounddriver); _sound_driver = (SoundDriver*)SoundDriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); if (_sound_driver == NULL) { StrEmpty(sounddriver) ? usererror("Failed to autoprobe sound driver") : usererror("Failed to select requested sound driver '%s'", sounddriver); } free(sounddriver); if (videodriver == NULL && _ini_videodriver != NULL) videodriver = strdup(_ini_videodriver); _video_driver = (VideoDriver*)VideoDriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO); if (_video_driver == NULL) { StrEmpty(videodriver) ? usererror("Failed to autoprobe video driver") : usererror("Failed to select requested video driver '%s'", videodriver); } free(videodriver); if (musicdriver == NULL && _ini_musicdriver != NULL) musicdriver = strdup(_ini_musicdriver); _music_driver = (MusicDriver*)MusicDriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); if (_music_driver == NULL) { StrEmpty(musicdriver) ? usererror("Failed to autoprobe music driver") : usererror("Failed to select requested music driver '%s'", musicdriver); } free(musicdriver); /* Initialize the zoom level of the screen to normal */ _screen.zoom = ZOOM_LVL_NORMAL; /* restore saved music volume */ _music_driver->SetVolume(_msf.music_vol); NetworkStartUp(); // initialize network-core #if defined(ENABLE_NETWORK) if (debuglog_conn != NULL && _network_available) { const char *not_used = NULL; const char *port = NULL; uint16 rport; rport = NETWORK_DEFAULT_DEBUGLOG_PORT; ParseConnectionString(¬_used, &port, debuglog_conn); if (port != NULL) rport = atoi(port); NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); } #endif /* ENABLE_NETWORK */ ScanNewGRFFiles(); ResetGRFConfig(false); /* Make sure _settings is filled with _settings_newgame if we switch to a game directly */ if (_switch_mode != SM_NONE) MakeNewgameSettingsLive(); /* initialize the ingame console */ IConsoleInit(); _cursor.in_window = true; InitializeGUI(); IConsoleCmdExec("exec scripts/autoexec.scr 0"); /* Take our initial lock on whatever we might want to do! */ _genworld_paint_mutex->BeginCritical(); _genworld_mapgen_mutex->BeginCritical(); GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy WaitTillGeneratedWorld(); CheckForMissingGlyphsInLoadedLanguagePack(); #ifdef ENABLE_NETWORK if (network && _network_available) { if (network_conn != NULL) { const char *port = NULL; const char *company = NULL; uint16 rport = NETWORK_DEFAULT_PORT; CompanyID join_as = COMPANY_NEW_COMPANY; ParseConnectionString(&company, &port, network_conn); if (company != NULL) { join_as = (CompanyID)atoi(company); if (join_as != COMPANY_SPECTATOR) { join_as--; if (join_as >= MAX_COMPANIES) return false; } } if (port != NULL) rport = atoi(port); LoadIntroGame(); _switch_mode = SM_NONE; NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password); } } #endif /* ENABLE_NETWORK */ _video_driver->MainLoop(); WaitTillSaved(); /* only save config if we have to */ if (save_config) { SaveToConfig(); SaveHotkeysToConfig(); SaveToHighScore(); } /* Reset windowing system, stop drivers, free used memory, ... */ ShutdownGame(); free(const_cast<char *>(BaseGraphics::ini_set)); free(const_cast<char *>(BaseSounds::ini_set)); free(const_cast<char *>(BaseMusic::ini_set)); free(_ini_musicdriver); free(_ini_sounddriver); free(_ini_videodriver); free(_ini_blitter); return 0; }