# genworld.cpp

Go to the documentation of this file.

    00001 /* $Id: genworld.cpp 26371 2014-02-23 22:03:08Z frosch $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "landscape.h"
    00014 #include "company_func.h"
    00015 #include "genworld.h"
    00016 #include "gfxinit.h"
    00017 #include "window_func.h"
    00018 #include "network/network.h"
    00019 #include "heightmap.h"
    00020 #include "viewport_func.h"
    00021 #include "date_func.h"
    00022 #include "engine_func.h"
    00023 #include "water.h"
    00024 #include "video/video_driver.hpp"
    00025 #include "tilehighlight_func.h"
    00026 #include "saveload/saveload.h"
    00027 #include "void_map.h"
    00028 #include "town.h"
    00029 #include "newgrf.h"
    00030 #include "core/random_func.hpp"
    00031 #include "core/backup_type.hpp"
    00032 #include "progress.h"
    00033 #include "error.h"
    00034 #include "game/game.hpp"
    00035 #include "game/game_instance.hpp"
    00036
    00037
    00038 void GenerateClearTile();
    00039 void GenerateIndustries();
    00040 void GenerateObjects();
    00041 void GenerateTrees();
    00042
    00043 void StartupEconomy();
    00044 void StartupCompanies();
    00045 void StartupDisasters();
    00046
    00047 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
    00048
    00055 GenWorldInfo _gw;
    00056
    00058 bool _generating_world;
    00059
    00064 bool IsGenerateWorldThreaded()
    00065 {
    00066   return _gw.threaded && !_gw.quit_thread;
    00067 }
    00068
    00073 static void CleanupGeneration()
    00074 {
    00075   _generating_world = false;
    00076
    00077   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
    00078   /* Show all vital windows again, because we have hidden them */
    00079   if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
    00080   SetModalProgress(false);
    00081   _gw.proc     = NULL;
    00082   _gw.abortp   = NULL;
    00083   _gw.threaded = false;
    00084
    00085   DeleteWindowByClass(WC_MODAL_PROGRESS);
    00086   ShowFirstError();
    00087   MarkWholeScreenDirty();
    00088 }
    00089
    00093 static void _GenerateWorld(void *)
    00094 {
    00095   /* Make sure everything is done via OWNER_NONE. */
    00096   Backup<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
    00097
    00098   try {
    00099     _generating_world = true;
    00100     _modal_progress_work_mutex->BeginCritical();
    00101     if (_network_dedicated) DEBUG(net, 0, "Generating map, please wait...");
    00102     /* Set the Random() seed to generation_seed so we produce the same map with the same seed */
    00103     if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom();
    00104     _random.SetSeed(_settings_game.game_creation.generation_seed);
    00105     SetGeneratingWorldProgress(GWP_MAP_INIT, 2);
    00106     SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
    00107
    00108     BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
    00109
    00110     IncreaseGeneratingWorldProgress(GWP_MAP_INIT);
    00111     /* Must start economy early because of the costs. */
    00112     StartupEconomy();
    00113
    00114     /* Don't generate landscape items when in the scenario editor. */
    00115     if (_gw.mode == GWM_EMPTY) {
    00116       SetGeneratingWorldProgress(GWP_OBJECT, 1);
    00117
    00118       /* Make sure the tiles at the north border are void tiles if needed. */
    00119       if (_settings_game.construction.freeform_edges) {
    00120         for (uint row = 0; row < MapSizeY(); row++) MakeVoid(TileXY(0, row));
    00121         for (uint col = 0; col < MapSizeX(); col++) MakeVoid(TileXY(col, 0));
    00122       }
    00123
    00124       /* Make the map the height of the setting */
    00125       if (_game_mode != GM_MENU) FlatEmptyWorld(_settings_game.game_creation.se_flat_world_height);
    00126
    00127       ConvertGroundTilesIntoWaterTiles();
    00128       IncreaseGeneratingWorldProgress(GWP_OBJECT);
    00129     } else {
    00130       GenerateLandscape(_gw.mode);
    00131       GenerateClearTile();
    00132
    00133       /* only generate towns, tree and industries in newgame mode. */
    00134       if (_game_mode != GM_EDITOR) {
    00135         if (!GenerateTowns(_settings_game.economy.town_layout)) {
    00136           _cur_company.Restore();
    00137           HandleGeneratingWorldAbortion();
    00138           return;
    00139         }
    00140         GenerateIndustries();
    00141         GenerateObjects();
    00142         GenerateTrees();
    00143       }
    00144     }
    00145
    00146     /* These are probably pointless when inside the scenario editor. */
    00147     SetGeneratingWorldProgress(GWP_GAME_INIT, 3);
    00148     StartupCompanies();
    00149     IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
    00150     StartupEngines();
    00151     IncreaseGeneratingWorldProgress(GWP_GAME_INIT);
    00152     StartupDisasters();
    00153     _generating_world = false;
    00154
    00155     /* No need to run the tile loop in the scenario editor. */
    00156     if (_gw.mode != GWM_EMPTY) {
    00157       uint i;
    00158
    00159       SetGeneratingWorldProgress(GWP_RUNTILELOOP, 0x500);
    00160       for (i = 0; i < 0x500; i++) {
    00161         RunTileLoop();
    00162         _tick_counter++;
    00163         IncreaseGeneratingWorldProgress(GWP_RUNTILELOOP);
    00164       }
    00165
    00166       if (_game_mode != GM_EDITOR) {
    00167         Game::StartNew();
    00168
    00169         if (Game::GetInstance() != NULL) {
    00170           SetGeneratingWorldProgress(GWP_RUNSCRIPT, 2500);
    00171           _generating_world = true;
    00172           for (i = 0; i < 2500; i++) {
    00173             Game::GameLoop();
    00174             IncreaseGeneratingWorldProgress(GWP_RUNSCRIPT);
    00175             if (Game::GetInstance()->IsSleeping()) break;
    00176           }
    00177           _generating_world = false;
    00178         }
    00179       }
    00180     }
    00181
    00182     BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP);
    00183
    00184     ResetObjectToPlace();
    00185     _cur_company.Trash();
    00186     _current_company = _local_company = _gw.lc;
    00187
    00188     SetGeneratingWorldProgress(GWP_GAME_START, 1);
    00189     /* Call any callback */
    00190     if (_gw.proc != NULL) _gw.proc();
    00191     IncreaseGeneratingWorldProgress(GWP_GAME_START);
    00192
    00193     CleanupGeneration();
    00194     _modal_progress_work_mutex->EndCritical();
    00195
    00196     ShowNewGRFError();
    00197
    00198     if (_network_dedicated) DEBUG(net, 0, "Map generated, starting game");
    00199     DEBUG(desync, 1, "new_map: %08x", _settings_game.game_creation.generation_seed);
    00200
    00201     if (_debug_desync_level > 0) {
    00202       char name[MAX_PATH];
    00203       snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
    00204       SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false);
    00205     }
    00206   } catch (...) {
    00207     BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
    00208     if (_cur_company.IsValid()) _cur_company.Restore();
    00209     _generating_world = false;
    00210     _modal_progress_work_mutex->EndCritical();
    00211     throw;
    00212   }
    00213 }
    00214
    00220 void GenerateWorldSetCallback(GWDoneProc *proc)
    00221 {
    00222   _gw.proc = proc;
    00223 }
    00224
    00230 void GenerateWorldSetAbortCallback(GWAbortProc *proc)
    00231 {
    00232   _gw.abortp = proc;
    00233 }
    00234
    00239 void WaitTillGeneratedWorld()
    00240 {
    00241   if (_gw.thread == NULL) return;
    00242
    00243   _modal_progress_work_mutex->EndCritical();
    00244   _modal_progress_paint_mutex->EndCritical();
    00245   _gw.quit_thread = true;
    00246   _gw.thread->Join();
    00247   delete _gw.thread;
    00248   _gw.thread   = NULL;
    00249   _gw.threaded = false;
    00250   _modal_progress_work_mutex->BeginCritical();
    00251   _modal_progress_paint_mutex->BeginCritical();
    00252 }
    00253
    00257 void AbortGeneratingWorld()
    00258 {
    00259   _gw.abort = true;
    00260 }
    00261
    00266 bool IsGeneratingWorldAborted()
    00267 {
    00268   return _gw.abort;
    00269 }
    00270
    00274 void HandleGeneratingWorldAbortion()
    00275 {
    00276   /* Clean up - in SE create an empty map, otherwise, go to intro menu */
    00277   _switch_mode = (_game_mode == GM_EDITOR) ? SM_EDITOR : SM_MENU;
    00278
    00279   if (_gw.abortp != NULL) _gw.abortp();
    00280
    00281   CleanupGeneration();
    00282
    00283   if (_gw.thread != NULL) _gw.thread->Exit();
    00284
    00285   SwitchToMode(_switch_mode);
    00286 }
    00287
    00295 void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_settings)
    00296 {
    00297   if (HasModalProgress()) return;
    00298   _gw.mode   = mode;
    00299   _gw.size_x = size_x;
    00300   _gw.size_y = size_y;
    00301   SetModalProgress(true);
    00302   _gw.abort  = false;
    00303   _gw.abortp = NULL;
    00304   _gw.lc     = _local_company;
    00305   _gw.quit_thread   = false;
    00306   _gw.threaded      = true;
    00307
    00308   /* This disables some commands and stuff */
    00309   SetLocalCompany(COMPANY_SPECTATOR);
    00310
    00311   InitializeGame(_gw.size_x, _gw.size_y, true, reset_settings);
    00312   PrepareGenerateWorldProgress();
    00313
    00314   /* Load the right landscape stuff, and the NewGRFs! */
    00315   GfxLoadSprites();
    00316   LoadStringWidthTable();
    00317
    00318   /* Re-init the windowing system */
    00319   ResetWindowSystem();
    00320
    00321   /* Create toolbars */
    00322   SetupColoursAndInitialWindow();
    00323   SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
    00324
    00325   if (_gw.thread != NULL) {
    00326     _gw.thread->Join();
    00327     delete _gw.thread;
    00328     _gw.thread = NULL;
    00329   }
    00330
    00331   if (!_video_driver->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread)) {
    00332     DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
    00333     _gw.threaded = false;
    00334     _modal_progress_work_mutex->EndCritical();
    00335     _GenerateWorld(NULL);
    00336     _modal_progress_work_mutex->BeginCritical();
    00337     return;
    00338   }
    00339
    00340   UnshowCriticalError();
    00341   /* Remove any open window */
    00342   DeleteAllNonVitalWindows();
    00343   /* Hide vital windows, because we don't allow to use them */
    00344   HideVitalWindows();
    00345
    00346   /* Don't show the dialog if we don't have a thread */
    00347   ShowGenerateWorldProgress();
    00348
    00349   /* Centre the view on the map */
    00350   if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) {
    00351     ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
    00352   }
    00353 }