# landscape.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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
    00014 #include "stdafx.h"
    00015 #include "heightmap.h"
    00016 #include "clear_map.h"
    00017 #include "spritecache.h"
    00018 #include "viewport_func.h"
    00019 #include "command_func.h"
    00020 #include "landscape.h"
    00021 #include "void_map.h"
    00022 #include "tgp.h"
    00023 #include "genworld.h"
    00024 #include "fios.h"
    00025 #include "date_func.h"
    00026 #include "water.h"
    00027 #include "effectvehicle_func.h"
    00028 #include "landscape_type.h"
    00029 #include "animated_tile_func.h"
    00030 #include "core/random_func.hpp"
    00031 #include "object_base.h"
    00032 #include "company_func.h"
    00033 #include "pathfinder/npf/aystar.h"
    00034 #include <list>
    00035
    00036 #include "table/strings.h"
    00037 #include "table/sprites.h"
    00038
    00039 extern const TileTypeProcs
    00040   _tile_type_clear_procs,
    00041   _tile_type_rail_procs,
    00042   _tile_type_road_procs,
    00043   _tile_type_town_procs,
    00044   _tile_type_trees_procs,
    00045   _tile_type_station_procs,
    00046   _tile_type_water_procs,
    00047   _tile_type_void_procs,
    00048   _tile_type_industry_procs,
    00049   _tile_type_tunnelbridge_procs,
    00050   _tile_type_object_procs;
    00051
    00057 const TileTypeProcs * const _tile_type_procs[16] = {
    00058   &_tile_type_clear_procs,
    00059   &_tile_type_rail_procs,
    00060   &_tile_type_road_procs,
    00061   &_tile_type_town_procs,
    00062   &_tile_type_trees_procs,
    00063   &_tile_type_station_procs,
    00064   &_tile_type_water_procs,
    00065   &_tile_type_void_procs,
    00066   &_tile_type_industry_procs,
    00067   &_tile_type_tunnelbridge_procs,
    00068   &_tile_type_object_procs,
    00069 };
    00070
    00072 extern const byte _slope_to_sprite_offset[32] = {
    00073   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
    00074   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
    00075 };
    00076
    00085 static SnowLine *_snow_line = NULL;
    00086
    00095 uint ApplyFoundationToSlope(Foundation f, Slope *s)
    00096 {
    00097   if (!IsFoundation(f)) return 0;
    00098
    00099   if (IsLeveledFoundation(f)) {
    00100     uint dz = 1 + (IsSteepSlope(*s) ? 1 : 0);
    00101     *s = SLOPE_FLAT;
    00102     return dz;
    00103   }
    00104
    00105   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
    00106     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
    00107     return 0;
    00108   }
    00109
    00110   if (IsSpecialRailFoundation(f)) {
    00111     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
    00112     return 0;
    00113   }
    00114
    00115   uint dz = IsSteepSlope(*s) ? 1 : 0;
    00116   Corner highest_corner = GetHighestSlopeCorner(*s);
    00117
    00118   switch (f) {
    00119     case FOUNDATION_INCLINED_X:
    00120       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
    00121       break;
    00122
    00123     case FOUNDATION_INCLINED_Y:
    00124       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
    00125       break;
    00126
    00127     case FOUNDATION_STEEP_LOWER:
    00128       *s = SlopeWithOneCornerRaised(highest_corner);
    00129       break;
    00130
    00131     case FOUNDATION_STEEP_BOTH:
    00132       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
    00133       break;
    00134
    00135     default: NOT_REACHED();
    00136   }
    00137   return dz;
    00138 }
    00139
    00140
    00148 uint GetPartialPixelZ(int x, int y, Slope corners)
    00149 {
    00150   if (IsHalftileSlope(corners)) {
    00151     switch (GetHalftileSlopeCorner(corners)) {
    00152       case CORNER_W:
    00153         if (x - y >= 0) return GetSlopeMaxPixelZ(corners);
    00154         break;
    00155
    00156       case CORNER_S:
    00157         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxPixelZ(corners);
    00158         break;
    00159
    00160       case CORNER_E:
    00161         if (y - x >= 0) return GetSlopeMaxPixelZ(corners);
    00162         break;
    00163
    00164       case CORNER_N:
    00165         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxPixelZ(corners);
    00166         break;
    00167
    00168       default: NOT_REACHED();
    00169     }
    00170   }
    00171
    00172   int z = 0;
    00173
    00174   switch (RemoveHalftileSlope(corners)) {
    00175     case SLOPE_W:
    00176       if (x - y >= 0) {
    00177         z = (x - y) >> 1;
    00178       }
    00179       break;
    00180
    00181     case SLOPE_S:
    00182       y ^= 0xF;
    00183       if ((x - y) >= 0) {
    00184         z = (x - y) >> 1;
    00185       }
    00186       break;
    00187
    00188     case SLOPE_SW:
    00189       z = (x >> 1) + 1;
    00190       break;
    00191
    00192     case SLOPE_E:
    00193       if (y - x >= 0) {
    00194         z = (y - x) >> 1;
    00195       }
    00196       break;
    00197
    00198     case SLOPE_EW:
    00199     case SLOPE_NS:
    00200     case SLOPE_ELEVATED:
    00201       z = 4;
    00202       break;
    00203
    00204     case SLOPE_SE:
    00205       z = (y >> 1) + 1;
    00206       break;
    00207
    00208     case SLOPE_WSE:
    00209       z = 8;
    00210       y ^= 0xF;
    00211       if (x - y < 0) {
    00212         z += (x - y) >> 1;
    00213       }
    00214       break;
    00215
    00216     case SLOPE_N:
    00217       y ^= 0xF;
    00218       if (y - x >= 0) {
    00219         z = (y - x) >> 1;
    00220       }
    00221       break;
    00222
    00223     case SLOPE_NW:
    00224       z = (y ^ 0xF) >> 1;
    00225       break;
    00226
    00227     case SLOPE_NWS:
    00228       z = 8;
    00229       if (x - y < 0) {
    00230         z += (x - y) >> 1;
    00231       }
    00232       break;
    00233
    00234     case SLOPE_NE:
    00235       z = (x ^ 0xF) >> 1;
    00236       break;
    00237
    00238     case SLOPE_ENW:
    00239       z = 8;
    00240       y ^= 0xF;
    00241       if (y - x < 0) {
    00242         z += (y - x) >> 1;
    00243       }
    00244       break;
    00245
    00246     case SLOPE_SEN:
    00247       z = 8;
    00248       if (y - x < 0) {
    00249         z += (y - x) >> 1;
    00250       }
    00251       break;
    00252
    00253     case SLOPE_STEEP_S:
    00254       z = 1 + ((x + y) >> 1);
    00255       break;
    00256
    00257     case SLOPE_STEEP_W:
    00258       z = 1 + ((x + (y ^ 0xF)) >> 1);
    00259       break;
    00260
    00261     case SLOPE_STEEP_N:
    00262       z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
    00263       break;
    00264
    00265     case SLOPE_STEEP_E:
    00266       z = 1 + (((x ^ 0xF) + y) >> 1);
    00267       break;
    00268
    00269     default: break;
    00270   }
    00271
    00272   return z;
    00273 }
    00274
    00275 int GetSlopePixelZ(int x, int y)
    00276 {
    00277   TileIndex tile = TileVirtXY(x, y);
    00278
    00279   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
    00280 }
    00281
    00291 int GetSlopeZInCorner(Slope tileh, Corner corner)
    00292 {
    00293   assert(!IsHalftileSlope(tileh));
    00294   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? 1 : 0) + (tileh == SteepSlope(corner) ? 1 : 0);
    00295 }
    00296
    00309 void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
    00310 {
    00311   static const Slope corners[4][4] = {
    00312     /*    corner     |          steep slope
    00313      *  z1      z2   |       z1             z2        */
    00314     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
    00315     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
    00316     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
    00317     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
    00318   };
    00319
    00320   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
    00321   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
    00322   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
    00323
    00324   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
    00325   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
    00326   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
    00327   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
    00328 }
    00329
    00338 Slope GetFoundationSlope(TileIndex tile, int *z)
    00339 {
    00340   Slope tileh = GetTileSlope(tile, z);
    00341   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
    00342   uint z_inc = ApplyFoundationToSlope(f, &tileh);
    00343   if (z != NULL) *z += z_inc;
    00344   return tileh;
    00345 }
    00346
    00347
    00348 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
    00349 {
    00350   int z;
    00351
    00352   int z_W_here = z_here;
    00353   int z_N_here = z_here;
    00354   GetSlopePixelZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
    00355
    00356   Slope slope = GetFoundationPixelSlope(TILE_ADDXY(tile, 0, -1), &z);
    00357   int z_W = z;
    00358   int z_N = z;
    00359   GetSlopePixelZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
    00360
    00361   return (z_N_here > z_N) || (z_W_here > z_W);
    00362 }
    00363
    00364
    00365 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
    00366 {
    00367   int z;
    00368
    00369   int z_E_here = z_here;
    00370   int z_N_here = z_here;
    00371   GetSlopePixelZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
    00372
    00373   Slope slope = GetFoundationPixelSlope(TILE_ADDXY(tile, -1, 0), &z);
    00374   int z_E = z;
    00375   int z_N = z;
    00376   GetSlopePixelZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
    00377
    00378   return (z_N_here > z_N) || (z_E_here > z_E);
    00379 }
    00380
    00386 void DrawFoundation(TileInfo *ti, Foundation f)
    00387 {
    00388   if (!IsFoundation(f)) return;
    00389
    00390   /* Two part foundations must be drawn separately */
    00391   assert(f != FOUNDATION_STEEP_BOTH);
    00392
    00393   uint sprite_block = 0;
    00394   int z;
    00395   Slope slope = GetFoundationPixelSlope(ti->tile, &z);
    00396
    00397   /* Select the needed block of foundations sprites
    00398    * Block 0: Walls at NW and NE edge
    00399    * Block 1: Wall  at        NE edge
    00400    * Block 2: Wall  at NW        edge
    00401    * Block 3: No walls at NW or NE edge
    00402    */
    00403   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
    00404   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
    00405
    00406   /* Use the original slope sprites if NW and NE borders should be visible */
    00407   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
    00408   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
    00409   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
    00410
    00411   if (IsSteepSlope(ti->tileh)) {
    00412     if (!IsNonContinuousFoundation(f)) {
    00413       /* Lower part of foundation */
    00414       AddSortableSpriteToDraw(
    00415         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
    00416       );
    00417     }
    00418
    00419     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
    00420     ti->z += ApplyPixelFoundationToSlope(f, &ti->tileh);
    00421
    00422     if (IsInclinedFoundation(f)) {
    00423       /* inclined foundation */
    00424       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00425
    00426       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00427         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00428         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00429         TILE_HEIGHT, ti->z
    00430       );
    00431       OffsetGroundSprite(31, 9);
    00432     } else if (IsLeveledFoundation(f)) {
    00433       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
    00434       OffsetGroundSprite(31, 1);
    00435     } else if (f == FOUNDATION_STEEP_LOWER) {
    00436       /* one corner raised */
    00437       OffsetGroundSprite(31, 1);
    00438     } else {
    00439       /* halftile foundation */
    00440       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
    00441       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
    00442
    00443       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
    00444       OffsetGroundSprite(31, 9);
    00445     }
    00446   } else {
    00447     if (IsLeveledFoundation(f)) {
    00448       /* leveled foundation */
    00449       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00450       OffsetGroundSprite(31, 1);
    00451     } else if (IsNonContinuousFoundation(f)) {
    00452       /* halftile foundation */
    00453       Corner halftile_corner = GetHalftileFoundationCorner(f);
    00454       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
    00455       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
    00456
    00457       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
    00458       OffsetGroundSprite(31, 9);
    00459     } else if (IsSpecialRailFoundation(f)) {
    00460       /* anti-zig-zag foundation */
    00461       SpriteID spr;
    00462       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
    00463         /* half of leveled foundation under track corner */
    00464         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
    00465       } else {
    00466         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
    00467         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
    00468       }
    00469       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00470       OffsetGroundSprite(31, 9);
    00471     } else {
    00472       /* inclined foundation */
    00473       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00474
    00475       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00476         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00477         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00478         TILE_HEIGHT, ti->z
    00479       );
    00480       OffsetGroundSprite(31, 9);
    00481     }
    00482     ti->z += ApplyPixelFoundationToSlope(f, &ti->tileh);
    00483   }
    00484 }
    00485
    00486 void DoClearSquare(TileIndex tile)
    00487 {
    00488   /* If the tile can have animation and we clear it, delete it from the animated tile list. */
    00489   if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
    00490
    00491   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
    00492   MarkTileDirtyByTile(tile);
    00493 }
    00494
    00505 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00506 {
    00507   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
    00508 }
    00509
    00516 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
    00517 {
    00518   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
    00519 }
    00520
    00521 void GetTileDesc(TileIndex tile, TileDesc *td)
    00522 {
    00523   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
    00524 }
    00525
    00531 bool IsSnowLineSet()
    00532 {
    00533   return _snow_line != NULL;
    00534 }
    00535
    00541 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
    00542 {
    00543   _snow_line = CallocT<SnowLine>(1);
    00544   _snow_line->lowest_value = 0xFF;
    00545   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
    00546
    00547   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
    00548     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
    00549       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
    00550       _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
    00551     }
    00552   }
    00553 }
    00554
    00560 byte GetSnowLine()
    00561 {
    00562   if (_snow_line == NULL) return _settings_game.game_creation.snow_line_height;
    00563
    00564   YearMonthDay ymd;
    00565   ConvertDateToYMD(_date, &ymd);
    00566   return _snow_line->table[ymd.month][ymd.day];
    00567 }
    00568
    00574 byte HighestSnowLine()
    00575 {
    00576   return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value;
    00577 }
    00578
    00584 byte LowestSnowLine()
    00585 {
    00586   return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value;
    00587 }
    00588
    00593 void ClearSnowLine()
    00594 {
    00595   free(_snow_line);
    00596   _snow_line = NULL;
    00597 }
    00598
    00608 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00609 {
    00610   CommandCost cost(EXPENSES_CONSTRUCTION);
    00611   bool do_clear = false;
    00612   /* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
    00613   if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
    00614     if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
    00615     do_clear = true;
    00616     cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
    00617   }
    00618
    00619   Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
    00620   if (c != NULL && (int)GB(c->clear_limit, 16, 16) < 1) {
    00621     return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED);
    00622   }
    00623
    00624   const ClearedObjectArea *coa = FindClearedObject(tile);
    00625
    00626   /* If this tile was the first tile which caused object destruction, always
    00627    * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
    00628   if (coa != NULL && coa->first_tile != tile) {
    00629     /* If this tile belongs to an object which was already cleared via another tile, pretend it has been
    00630      * already removed.
    00631      * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
    00632
    00633     /* If a object is removed, it leaves either bare land or water. */
    00634     if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
    00635       return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
    00636     }
    00637   } else {
    00638     cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
    00639   }
    00640
    00641   if (flags & DC_EXEC) {
    00642     if (c != NULL) c->clear_limit -= 1 << 16;
    00643     if (do_clear) DoClearSquare(tile);
    00644   }
    00645   return cost;
    00646 }
    00647
    00658 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00659 {
    00660   if (p1 >= MapSize()) return CMD_ERROR;
    00661
    00662   Money money = GetAvailableMoneyForCommand();
    00663   CommandCost cost(EXPENSES_CONSTRUCTION);
    00664   CommandCost last_error = CMD_ERROR;
    00665   bool had_success = false;
    00666
    00667   const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
    00668   int limit = (c == NULL ? INT32_MAX : GB(c->clear_limit, 16, 16));
    00669
    00670   TileArea ta(tile, p1);
    00671   TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
    00672   for (; *iter != INVALID_TILE; ++(*iter)) {
    00673     TileIndex t = *iter;
    00674     CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
    00675     if (ret.Failed()) {
    00676       last_error = ret;
    00677
    00678       /* We may not clear more tiles. */
    00679       if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break;
    00680       continue;
    00681     }
    00682
    00683     had_success = true;
    00684     if (flags & DC_EXEC) {
    00685       money -= ret.GetCost();
    00686       if (ret.GetCost() > 0 && money < 0) {
    00687         _additional_cash_required = ret.GetCost();
    00688         delete iter;
    00689         return cost;
    00690       }
    00691       DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00692
    00693       /* draw explosion animation...
    00694        * Disable explosions when game is paused. Looks silly and blocks the view. */
    00695       TileIndex off = t - ta.tile;
    00696       if ((TileX(off) == 0 || TileX(off) == ta.w - 1U) && (TileY(off) == 0 || TileY(off) == ta.h - 1U) && _pause_mode == PM_UNPAUSED) {
    00697         /* big explosion in each corner, or small explosion for single tiles */
    00698         CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
    00699           ta.w == 1 && ta.h == 1 ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
    00700         );
    00701       }
    00702     } else {
    00703       /* When we're at the clearing limit we better bail (unneed) testing as well. */
    00704       if (ret.GetCost() != 0 && --limit <= 0) break;
    00705     }
    00706     cost.AddCost(ret);
    00707   }
    00708
    00709   delete iter;
    00710   return had_success ? cost : last_error;
    00711 }
    00712
    00713
    00714 TileIndex _cur_tileloop_tile;
    00715 #define TILELOOP_BITS 4
    00716 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
    00717 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
    00718 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
    00719
    00720 void RunTileLoop()
    00721 {
    00722   TileIndex tile = _cur_tileloop_tile;
    00723
    00724   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00725   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
    00726   do {
    00727     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
    00728
    00729     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
    00730       tile += TILELOOP_SIZE; // no overflow
    00731     } else {
    00732       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
    00733     }
    00734   } while (--count != 0);
    00735   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00736
    00737   tile += 9;
    00738   if (tile & TILELOOP_CHKMASK) {
    00739     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
    00740   }
    00741   _cur_tileloop_tile = tile;
    00742 }
    00743
    00744 void InitializeLandscape()
    00745 {
    00746   uint maxx = MapMaxX();
    00747   uint maxy = MapMaxY();
    00748   uint sizex = MapSizeX();
    00749
    00750   uint y;
    00751   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
    00752     uint x;
    00753     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
    00754       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
    00755       SetTileHeight(sizex * y + x, 0);
    00756       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
    00757       ClearBridgeMiddle(sizex * y + x);
    00758     }
    00759     MakeVoid(sizex * y + x);
    00760   }
    00761   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
    00762 }
    00763
    00764 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
    00765 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
    00766
    00767 static void GenerateTerrain(int type, uint flag)
    00768 {
    00769   uint32 r = Random();
    00770
    00771   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
    00772
    00773   uint x = r & MapMaxX();
    00774   uint y = (r >> MapLogX()) & MapMaxY();
    00775
    00776   if (x < 2 || y < 2) return;
    00777
    00778   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
    00779   uint w = templ->width;
    00780   uint h = templ->height;
    00781
    00782   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
    00783
    00784   const byte *p = templ->data;
    00785
    00786   if ((flag & 4) != 0) {
    00787     uint xw = x * MapSizeY();
    00788     uint yw = y * MapSizeX();
    00789     uint bias = (MapSizeX() + MapSizeY()) * 16;
    00790
    00791     switch (flag & 3) {
    00792       default: NOT_REACHED();
    00793       case 0:
    00794         if (xw + yw > MapSize() - bias) return;
    00795         break;
    00796
    00797       case 1:
    00798         if (yw < xw + bias) return;
    00799         break;
    00800
    00801       case 2:
    00802         if (xw + yw < MapSize() + bias) return;
    00803         break;
    00804
    00805       case 3:
    00806         if (xw < yw + bias) return;
    00807         break;
    00808     }
    00809   }
    00810
    00811   if (x + w >= MapMaxX() - 1) return;
    00812   if (y + h >= MapMaxY() - 1) return;
    00813
    00814   TileIndex tile = TileXY(x, y);
    00815
    00816   switch (direction) {
    00817     default: NOT_REACHED();
    00818     case DIAGDIR_NE:
    00819       do {
    00820         TileIndex tile_cur = tile;
    00821
    00822         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00823           if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
    00824           p++;
    00825           tile_cur++;
    00826         }
    00827         tile += TileDiffXY(0, 1);
    00828       } while (--h != 0);
    00829       break;
    00830
    00831     case DIAGDIR_SE:
    00832       do {
    00833         TileIndex tile_cur = tile;
    00834
    00835         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00836           if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
    00837           p++;
    00838           tile_cur += TileDiffXY(0, 1);
    00839         }
    00840         tile += TileDiffXY(1, 0);
    00841       } while (--w != 0);
    00842       break;
    00843
    00844     case DIAGDIR_SW:
    00845       tile += TileDiffXY(w - 1, 0);
    00846       do {
    00847         TileIndex tile_cur = tile;
    00848
    00849         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00850           if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
    00851           p++;
    00852           tile_cur--;
    00853         }
    00854         tile += TileDiffXY(0, 1);
    00855       } while (--h != 0);
    00856       break;
    00857
    00858     case DIAGDIR_NW:
    00859       tile += TileDiffXY(0, h - 1);
    00860       do {
    00861         TileIndex tile_cur = tile;
    00862
    00863         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00864           if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
    00865           p++;
    00866           tile_cur -= TileDiffXY(0, 1);
    00867         }
    00868         tile += TileDiffXY(1, 0);
    00869       } while (--w != 0);
    00870       break;
    00871   }
    00872 }
    00873
    00874
    00875 #include "table/genland.h"
    00876
    00877 static void CreateDesertOrRainForest()
    00878 {
    00879   TileIndex update_freq = MapSize() / 4;
    00880   const TileIndexDiffC *data;
    00881
    00882   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00883     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00884
    00885     if (!IsValidTile(tile)) continue;
    00886
    00887     for (data = _make_desert_or_rainforest_data;
    00888         data != endof(_make_desert_or_rainforest_data); ++data) {
    00889       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
    00890       if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
    00891     }
    00892     if (data == endof(_make_desert_or_rainforest_data)) {
    00893       SetTropicZone(tile, TROPICZONE_DESERT);
    00894     }
    00895   }
    00896
    00897   for (uint i = 0; i != 256; i++) {
    00898     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00899
    00900     RunTileLoop();
    00901   }
    00902
    00903   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00904     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00905
    00906     if (!IsValidTile(tile)) continue;
    00907
    00908     for (data = _make_desert_or_rainforest_data;
    00909         data != endof(_make_desert_or_rainforest_data); ++data) {
    00910       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
    00911       if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
    00912     }
    00913     if (data == endof(_make_desert_or_rainforest_data)) {
    00914       SetTropicZone(tile, TROPICZONE_RAINFOREST);
    00915     }
    00916   }
    00917 }
    00918
    00925 static bool FindSpring(TileIndex tile, void *user_data)
    00926 {
    00927   int referenceHeight;
    00928   Slope s = GetTileSlope(tile, &referenceHeight);
    00929   if (s != SLOPE_FLAT || IsWaterTile(tile)) return false;
    00930
    00931   /* In the tropics rivers start in the rainforest. */
    00932   if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
    00933
    00934   /* Are there enough higher tiles to warrant a 'spring'? */
    00935   uint num = 0;
    00936   for (int dx = -1; dx <= 1; dx++) {
    00937     for (int dy = -1; dy <= 1; dy++) {
    00938       TileIndex t = TileAddWrap(tile, dx, dy);
    00939       if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight) num++;
    00940     }
    00941   }
    00942
    00943   if (num < 4) return false;
    00944
    00945   /* Are we near the top of a hill? */
    00946   for (int dx = -16; dx <= 16; dx++) {
    00947     for (int dy = -16; dy <= 16; dy++) {
    00948       TileIndex t = TileAddWrap(tile, dx, dy);
    00949       if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight + 2) return false;
    00950     }
    00951   }
    00952
    00953   return true;
    00954 }
    00955
    00962 static bool MakeLake(TileIndex tile, void *user_data)
    00963 {
    00964   uint height = *(uint*)user_data;
    00965   if (!IsValidTile(tile) || TileHeight(tile) != height || GetTileSlope(tile) != SLOPE_FLAT) return false;
    00966   if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
    00967
    00968   for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
    00969     TileIndex t2 = tile + TileOffsByDiagDir(d);
    00970     if (IsWaterTile(t2)) {
    00971       MakeRiver(tile, Random());
    00972       return false;
    00973     }
    00974   }
    00975
    00976   return false;
    00977 }
    00978
    00985 static bool FlowsDown(TileIndex begin, TileIndex end)
    00986 {
    00987   assert(DistanceManhattan(begin, end) == 1);
    00988
    00989   int heightBegin;
    00990   int heightEnd;
    00991   Slope slopeBegin = GetTileSlope(begin, &heightBegin);
    00992   Slope slopeEnd   = GetTileSlope(end, &heightEnd);
    00993
    00994   return heightEnd <= heightBegin &&
    00995       /* Slope either is inclined or flat; rivers don't support other slopes. */
    00996       (slopeEnd == SLOPE_FLAT || IsInclinedSlope(slopeEnd)) &&
    00997       /* Slope continues, then it must be lower... or either end must be flat. */
    00998       ((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || slopeBegin == SLOPE_FLAT);
    00999 }
    01000
    01001 /* AyStar callback for checking whether we reached our destination. */
    01002 static int32 River_EndNodeCheck(AyStar *aystar, OpenListNode *current)
    01003 {
    01004   return current->path.node.tile == *(TileIndex*)aystar->user_target ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
    01005 }
    01006
    01007 /* AyStar callback for getting the cost of the current node. */
    01008 static int32 River_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
    01009 {
    01010   return 1 + RandomRange(_settings_game.game_creation.river_route_random);
    01011 }
    01012
    01013 /* AyStar callback for getting the estimated cost to the destination. */
    01014 static int32 River_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
    01015 {
    01016   return DistanceManhattan(*(TileIndex*)aystar->user_target, current->tile);
    01017 }
    01018
    01019 /* AyStar callback for getting the neighbouring nodes of the given node. */
    01020 static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
    01021 {
    01022   TileIndex tile = current->path.node.tile;
    01023
    01024   aystar->num_neighbours = 0;
    01025   for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
    01026     TileIndex t2 = tile + TileOffsByDiagDir(d);
    01027     if (IsValidTile(t2) && FlowsDown(tile, t2)) {
    01028       aystar->neighbours[aystar->num_neighbours].tile = t2;
    01029       aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
    01030       aystar->num_neighbours++;
    01031     }
    01032   }
    01033 }
    01034
    01035 /* AyStar callback when an route has been found. */
    01036 static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
    01037 {
    01038   for (PathNode *path = &current->path; path != NULL; path = path->parent) {
    01039     TileIndex tile = path->node.tile;
    01040     if (!IsWaterTile(tile)) {
    01041       MakeRiver(tile, Random());
    01042       /* Remove desert directly around the river tile. */
    01043       CircularTileSearch(&tile, 5, RiverModifyDesertZone, NULL);
    01044     }
    01045   }
    01046 }
    01047
    01048 static const uint RIVER_HASH_SIZE = 8;
    01049
    01056 static uint River_Hash(uint tile, uint dir)
    01057 {
    01058   return GB(TileHash(TileX(tile), TileY(tile)), 0, RIVER_HASH_SIZE);
    01059 }
    01060
    01066 static void BuildRiver(TileIndex begin, TileIndex end)
    01067 {
    01068   AyStar finder;
    01069   MemSetT(&finder, 0);
    01070   finder.CalculateG = River_CalculateG;
    01071   finder.CalculateH = River_CalculateH;
    01072   finder.GetNeighbours = River_GetNeighbours;
    01073   finder.EndNodeCheck = River_EndNodeCheck;
    01074   finder.FoundEndNode = River_FoundEndNode;
    01075   finder.user_target = &end;
    01076
    01077   finder.Init(River_Hash, 1 << RIVER_HASH_SIZE);
    01078
    01079   AyStarNode start;
    01080   start.tile = begin;
    01081   start.direction = INVALID_TRACKDIR;
    01082   finder.AddStartNode(&start, 0);
    01083   finder.Main();
    01084   finder.Free();
    01085 }
    01086
    01094 static bool FlowRiver(bool *marks, TileIndex spring, TileIndex begin)
    01095 {
    01096   uint height = TileHeight(begin);
    01097   if (IsWaterTile(begin)) return DistanceManhattan(spring, begin) > _settings_game.game_creation.min_river_length;
    01098
    01099   MemSetT(marks, 0, MapSize());
    01100   marks[begin] = true;
    01101
    01102   /* Breadth first search for the closest tile we can flow down to. */
    01103   std::list<TileIndex> queue;
    01104   queue.push_back(begin);
    01105
    01106   bool found = false;
    01107   uint count = 0; // Number of tiles considered; to be used for lake location guessing.
    01108   TileIndex end;
    01109   do {
    01110     end = queue.front();
    01111     queue.pop_front();
    01112
    01113     uint height2 = TileHeight(end);
    01114     if (GetTileSlope(end) == SLOPE_FLAT && (height2 < height || (height2 == height && IsWaterTile(end)))) {
    01115       found = true;
    01116       break;
    01117     }
    01118
    01119     for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
    01120       TileIndex t2 = end + TileOffsByDiagDir(d);
    01121       if (IsValidTile(t2) && !marks[t2] && FlowsDown(end, t2)) {
    01122         marks[t2] = true;
    01123         count++;
    01124         queue.push_back(t2);
    01125       }
    01126     }
    01127   } while (!queue.empty());
    01128
    01129   if (found) {
    01130     /* Flow further down hill. */
    01131     found = FlowRiver(marks, spring, end);
    01132   } else if (count > 32) {
    01133     /* Maybe we can make a lake. Find the Nth of the considered tiles. */
    01134     TileIndex lakeCenter = 0;
    01135     for (int i = RandomRange(count - 1); i != 0; lakeCenter++) {
    01136       if (marks[lakeCenter]) i--;
    01137     }
    01138
    01139     if (IsValidTile(lakeCenter) &&
    01140         /* A river, or lake, can only be built on flat slopes. */
    01141         GetTileSlope(lakeCenter) == SLOPE_FLAT &&
    01142         /* We want the lake to be built at the height of the river. */
    01143         TileHeight(begin) == TileHeight(lakeCenter) &&
    01144         /* We don't want the lake at the entry of the valley. */
    01145         lakeCenter != begin &&
    01146         /* We don't want lakes in the desert. */
    01147         (_settings_game.game_creation.landscape != LT_TROPIC || GetTropicZone(lakeCenter) != TROPICZONE_DESERT) &&
    01148         /* We only want a lake if the river is long enough. */
    01149         DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
    01150       end = lakeCenter;
    01151       MakeRiver(lakeCenter, Random());
    01152       uint range = RandomRange(8) + 3;
    01153       CircularTileSearch(&lakeCenter, range, MakeLake, &height);
    01154       /* Call the search a second time so artefacts from going circular in one direction get (mostly) hidden. */
    01155       lakeCenter = end;
    01156       CircularTileSearch(&lakeCenter, range, MakeLake, &height);
    01157       found = true;
    01158     }
    01159   }
    01160
    01161   if (found) BuildRiver(begin, end);
    01162   return found;
    01163 }
    01164
    01168 static void CreateRivers()
    01169 {
    01170   int amount = _settings_game.game_creation.amount_of_rivers;
    01171   if (amount == 0) return;
    01172
    01173   uint wells = ScaleByMapSize(4 << _settings_game.game_creation.amount_of_rivers);
    01174   SetGeneratingWorldProgress(GWP_RIVER, wells + 256 / 64); // Include the tile loop calls below.
    01175   bool *marks = CallocT<bool>(MapSize());
    01176
    01177   for (; wells != 0; wells--) {
    01178     IncreaseGeneratingWorldProgress(GWP_RIVER);
    01179     for (int tries = 0; tries < 128; tries++) {
    01180       TileIndex t = RandomTile();
    01181       if (!CircularTileSearch(&t, 8, FindSpring, NULL)) continue;
    01182       if (FlowRiver(marks, t, t)) break;
    01183     }
    01184   }
    01185
    01186   free(marks);
    01187
    01188   /* Run tile loop to update the ground density. */
    01189   for (uint i = 0; i != 256; i++) {
    01190     if (i % 64 == 0) IncreaseGeneratingWorldProgress(GWP_RIVER);
    01191     RunTileLoop();
    01192   }
    01193 }
    01194
    01195 void GenerateLandscape(byte mode)
    01196 {
    01198   enum GenLandscapeSteps {
    01199     GLS_HEIGHTMAP    =  3,
    01200     GLS_TERRAGENESIS =  5,
    01201     GLS_ORIGINAL     =  2,
    01202     GLS_TROPIC       = 12,
    01203     GLS_OTHER        =  0,
    01204   };
    01205   uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
    01206
    01207   if (mode == GWM_HEIGHTMAP) {
    01208     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
    01209     LoadHeightmap(_file_to_saveload.name);
    01210     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    01211   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
    01212     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
    01213     GenerateTerrainPerlin();
    01214   } else {
    01215     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
    01216     if (_settings_game.construction.freeform_edges) {
    01217       for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
    01218       for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
    01219     }
    01220     switch (_settings_game.game_creation.landscape) {
    01221       case LT_ARCTIC: {
    01222         uint32 r = Random();
    01223
    01224         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
    01225           GenerateTerrain(2, 0);
    01226         }
    01227
    01228         uint flag = GB(r, 7, 2) | 4;
    01229         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
    01230           GenerateTerrain(4, flag);
    01231         }
    01232         break;
    01233       }
    01234
    01235       case LT_TROPIC: {
    01236         uint32 r = Random();
    01237
    01238         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
    01239           GenerateTerrain(0, 0);
    01240         }
    01241
    01242         uint flag = GB(r, 7, 2) | 4;
    01243         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
    01244           GenerateTerrain(0, flag);
    01245         }
    01246
    01247         flag ^= 2;
    01248
    01249         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
    01250           GenerateTerrain(3, flag);
    01251         }
    01252         break;
    01253       }
    01254
    01255       default: {
    01256         uint32 r = Random();
    01257
    01258         assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
    01259         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
    01260         for (; i != 0; --i) {
    01261           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
    01262         }
    01263         break;
    01264       }
    01265     }
    01266   }
    01267
    01268   /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
    01269    * it allows screen redraw. Drawing of broken slopes crashes the game */
    01270   FixSlopes();
    01271   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    01272   ConvertGroundTilesIntoWaterTiles();
    01273   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    01274
    01275   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
    01276
    01277   CreateRivers();
    01278 }
    01279
    01280 void OnTick_Town();
    01281 void OnTick_Trees();
    01282 void OnTick_Station();
    01283 void OnTick_Industry();
    01284
    01285 void OnTick_Companies();
    01286 void OnTick_LinkGraph();
    01287
    01288 void CallLandscapeTick()
    01289 {
    01290   OnTick_Town();
    01291   OnTick_Trees();
    01292   OnTick_Station();
    01293   OnTick_Industry();
    01294
    01295   OnTick_Companies();
    01296   OnTick_LinkGraph();
    01297 }