/** * The main new land generator using Perlin noise. Desert landscape is handled * different to all others to give a desert valley between two high mountains. * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic * areas won't be high enough, and there will be very little tropic on the map. * Thus Tropic works best on Hilly or Mountainous. */ void GenerateTerrainPerlin() { if (!AllocHeightMap()) return; GenerateWorldSetAbortCallback(FreeHeightMap); HeightMapGenerate(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); HeightMapNormalize(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); /* First make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0)); for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y)); } int max_height = H2I(TGPGetMaxHeight()); /* Transfer height map into OTTD map */ for (int y = 0; y < _height_map.size_y; y++) { for (int x = 0; x < _height_map.size_x; x++) { TgenSetTileHeight(TileXY(x, y), Clamp(H2I(_height_map.height(x, y)), 0, max_height)); } } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); FreeHeightMap(); GenerateWorldSetAbortCallback(NULL); }
/** * Place some trees randomly * * This function just place some trees randomly on the map. */ void PlaceTreesRandomly() { uint i, j, ht; i = ScaleByMapSize(DEFAULT_TREE_STEPS); if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV; do { uint32 r = Random(); TileIndex tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_TREE); if (CanPlantTreesOnTile(tile, true)) { PlaceTree(tile, r); if (_settings_game.game_creation.tree_placer != TP_IMPROVED) continue; /* Place a number of trees based on the tile height. * This gives a cool effect of multiple trees close together. * It is almost real life ;) */ ht = GetTileZ(tile); /* The higher we get, the more trees we plant */ j = GetTileZ(tile) / TILE_HEIGHT * 2; /* Above snowline more trees! */ if (_settings_game.game_creation.landscape == LT_ARCTIC && ht > GetSnowLine()) j *= 3; while (j--) { PlaceTreeAtSameHeight(tile, ht); } } } while (--i); /* place extra trees at rainforest area */ if (_settings_game.game_creation.landscape == LT_TROPIC) { i = ScaleByMapSize(DEFAULT_RAINFOREST_TREE_STEPS); if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV; do { uint32 r = Random(); TileIndex tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_TREE); if (GetTropicZone(tile) == TROPICZONE_RAINFOREST && CanPlantTreesOnTile(tile, false)) { PlaceTree(tile, r); } } while (--i); } }
void GenerateClearTile() { uint i, gi; TileIndex tile; /* add rough tiles */ i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400); gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80); SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i); do { IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); tile = RandomTile(); if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3); } while (--i); /* add rocky tiles */ i = gi; do { uint32 r = Random(); tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) { uint j = GB(r, 16, 4) + 5; for (;;) { TileIndex tile_new; SetClearGroundDensity(tile, CLEAR_ROCKS, 3); do { if (--j == 0) goto get_out; tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2)); } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT)); tile = tile_new; } get_out:; } } while (--i); }
/** * The main new land generator using Perlin noise. Desert landscape is handled * different to all others to give a desert valley between two high mountains. * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic * areas wont be high enough, and there will be very little tropic on the map. * Thus Tropic works best on Hilly or Mountainous. */ void GenerateTerrainPerlin() { uint x, y; if (!AllocHeightMap()) return; GenerateWorldSetAbortCallback(FreeHeightMap); HeightMapGenerate(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); HeightMapNormalize(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); /* First make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y); for (x = 0; x < _height_map.size_x; x++) MakeVoid(x); } /* Transfer height map into OTTD map */ for (y = 0; y < _height_map.size_y; y++) { for (x = 0; x < _height_map.size_x; x++) { int height = H2I(_height_map.height(x, y)); if (height < 0) height = 0; if (height > 15) height = 15; TgenSetTileHeight(TileXY(x, y), height); } } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); FreeHeightMap(); GenerateWorldSetAbortCallback(NULL); }
/** * Creates a number of tree groups. * The number of trees in each group depends on how many trees are actually placed around the given tile. * * @param num_groups Number of tree groups to place. */ static void PlaceTreeGroups(uint num_groups) { do { TileIndex center_tile = RandomTile(); for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) { uint32 r = Random(); int x = GB(r, 0, 5) - 16; int y = GB(r, 8, 5) - 16; uint dist = abs(x) + abs(y); TileIndex cur_tile = TileAddWrap(center_tile, x, y); IncreaseGeneratingWorldProgress(GWP_TREE); if (cur_tile != INVALID_TILE && dist <= 13 && CanPlantTreesOnTile(cur_tile, true)) { PlaceTree(cur_tile, r); } } } while (--num_groups); }
/** * 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; } }