# landscape.cpp

Go to the documentation of this file.

    00001 /* $Id: landscape.cpp 19857 2010-05-18 21:44:47Z rubidium $ */
    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 "variables.h"
    00022 #include "void_map.h"
    00023 #include "tgp.h"
    00024 #include "genworld.h"
    00025 #include "fios.h"
    00026 #include "functions.h"
    00027 #include "date_func.h"
    00028 #include "water.h"
    00029 #include "effectvehicle_func.h"
    00030 #include "landscape_type.h"
    00031 #include "animated_tile_func.h"
    00032 #include "core/random_func.hpp"
    00033
    00034 #include "table/sprites.h"
    00035
    00036 extern const TileTypeProcs
    00037   _tile_type_clear_procs,
    00038   _tile_type_rail_procs,
    00039   _tile_type_road_procs,
    00040   _tile_type_town_procs,
    00041   _tile_type_trees_procs,
    00042   _tile_type_station_procs,
    00043   _tile_type_water_procs,
    00044   _tile_type_dummy_procs,
    00045   _tile_type_industry_procs,
    00046   _tile_type_tunnelbridge_procs,
    00047   _tile_type_unmovable_procs;
    00048
    00052 const TileTypeProcs * const _tile_type_procs[16] = {
    00053   &_tile_type_clear_procs,
    00054   &_tile_type_rail_procs,
    00055   &_tile_type_road_procs,
    00056   &_tile_type_town_procs,
    00057   &_tile_type_trees_procs,
    00058   &_tile_type_station_procs,
    00059   &_tile_type_water_procs,
    00060   &_tile_type_dummy_procs,
    00061   &_tile_type_industry_procs,
    00062   &_tile_type_tunnelbridge_procs,
    00063   &_tile_type_unmovable_procs,
    00064 };
    00065
    00066 /* landscape slope => sprite */
    00067 const byte _tileh_to_sprite[32] = {
    00068   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
    00069   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
    00070 };
    00071
    00079 static SnowLine *_snow_line = NULL;
    00080
    00089 uint ApplyFoundationToSlope(Foundation f, Slope *s)
    00090 {
    00091   if (!IsFoundation(f)) return 0;
    00092
    00093   if (IsLeveledFoundation(f)) {
    00094     uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
    00095     *s = SLOPE_FLAT;
    00096     return dz;
    00097   }
    00098
    00099   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
    00100     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
    00101     return 0;
    00102   }
    00103
    00104   if (IsSpecialRailFoundation(f)) {
    00105     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
    00106     return 0;
    00107   }
    00108
    00109   uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
    00110   Corner highest_corner = GetHighestSlopeCorner(*s);
    00111
    00112   switch (f) {
    00113     case FOUNDATION_INCLINED_X:
    00114       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
    00115       break;
    00116
    00117     case FOUNDATION_INCLINED_Y:
    00118       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
    00119       break;
    00120
    00121     case FOUNDATION_STEEP_LOWER:
    00122       *s = SlopeWithOneCornerRaised(highest_corner);
    00123       break;
    00124
    00125     case FOUNDATION_STEEP_BOTH:
    00126       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
    00127       break;
    00128
    00129     default: NOT_REACHED();
    00130   }
    00131   return dz;
    00132 }
    00133
    00134
    00142 uint GetPartialZ(int x, int y, Slope corners)
    00143 {
    00144   if (IsHalftileSlope(corners)) {
    00145     switch (GetHalftileSlopeCorner(corners)) {
    00146       case CORNER_W:
    00147         if (x - y >= 0) return GetSlopeMaxZ(corners);
    00148         break;
    00149
    00150       case CORNER_S:
    00151         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
    00152         break;
    00153
    00154       case CORNER_E:
    00155         if (y - x >= 0) return GetSlopeMaxZ(corners);
    00156         break;
    00157
    00158       case CORNER_N:
    00159         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
    00160         break;
    00161
    00162       default: NOT_REACHED();
    00163     }
    00164   }
    00165
    00166   int z = 0;
    00167
    00168   switch (RemoveHalftileSlope(corners)) {
    00169     case SLOPE_W:
    00170       if (x - y >= 0) {
    00171         z = (x - y) >> 1;
    00172       }
    00173       break;
    00174
    00175     case SLOPE_S:
    00176       y ^= 0xF;
    00177       if ((x - y) >= 0) {
    00178         z = (x - y) >> 1;
    00179       }
    00180       break;
    00181
    00182     case SLOPE_SW:
    00183       z = (x >> 1) + 1;
    00184       break;
    00185
    00186     case SLOPE_E:
    00187       if (y - x >= 0) {
    00188         z = (y - x) >> 1;
    00189       }
    00190       break;
    00191
    00192     case SLOPE_EW:
    00193     case SLOPE_NS:
    00194     case SLOPE_ELEVATED:
    00195       z = 4;
    00196       break;
    00197
    00198     case SLOPE_SE:
    00199       z = (y >> 1) + 1;
    00200       break;
    00201
    00202     case SLOPE_WSE:
    00203       z = 8;
    00204       y ^= 0xF;
    00205       if (x - y < 0) {
    00206         z += (x - y) >> 1;
    00207       }
    00208       break;
    00209
    00210     case SLOPE_N:
    00211       y ^= 0xF;
    00212       if (y - x >= 0) {
    00213         z = (y - x) >> 1;
    00214       }
    00215       break;
    00216
    00217     case SLOPE_NW:
    00218       z = (y ^ 0xF) >> 1;
    00219       break;
    00220
    00221     case SLOPE_NWS:
    00222       z = 8;
    00223       if (x - y < 0) {
    00224         z += (x - y) >> 1;
    00225       }
    00226       break;
    00227
    00228     case SLOPE_NE:
    00229       z = (x ^ 0xF) >> 1;
    00230       break;
    00231
    00232     case SLOPE_ENW:
    00233       z = 8;
    00234       y ^= 0xF;
    00235       if (y - x < 0) {
    00236         z += (y - x) >> 1;
    00237       }
    00238       break;
    00239
    00240     case SLOPE_SEN:
    00241       z = 8;
    00242       if (y - x < 0) {
    00243         z += (y - x) >> 1;
    00244       }
    00245       break;
    00246
    00247     case SLOPE_STEEP_S:
    00248       z = 1 + ((x + y) >> 1);
    00249       break;
    00250
    00251     case SLOPE_STEEP_W:
    00252       z = 1 + ((x + (y ^ 0xF)) >> 1);
    00253       break;
    00254
    00255     case SLOPE_STEEP_N:
    00256       z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
    00257       break;
    00258
    00259     case SLOPE_STEEP_E:
    00260       z = 1 + (((x ^ 0xF) + y) >> 1);
    00261       break;
    00262
    00263     default: break;
    00264   }
    00265
    00266   return z;
    00267 }
    00268
    00269 uint GetSlopeZ(int x, int y)
    00270 {
    00271   TileIndex tile = TileVirtXY(x, y);
    00272
    00273   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
    00274 }
    00275
    00285 int GetSlopeZInCorner(Slope tileh, Corner corner)
    00286 {
    00287   assert(!IsHalftileSlope(tileh));
    00288   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
    00289 }
    00290
    00303 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
    00304 {
    00305   static const Slope corners[4][4] = {
    00306     /*    corner     |          steep slope
    00307      *  z1      z2   |       z1             z2        */
    00308     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
    00309     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
    00310     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
    00311     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
    00312   };
    00313
    00314   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
    00315   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
    00316   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
    00317
    00318   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
    00319   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
    00320   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
    00321   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
    00322 }
    00323
    00332 Slope GetFoundationSlope(TileIndex tile, uint *z)
    00333 {
    00334   Slope tileh = GetTileSlope(tile, z);
    00335   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
    00336   uint z_inc = ApplyFoundationToSlope(f, &tileh);
    00337   if (z != NULL) *z += z_inc;
    00338   return tileh;
    00339 }
    00340
    00341
    00342 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
    00343 {
    00344   uint z;
    00345
    00346   int z_W_here = z_here;
    00347   int z_N_here = z_here;
    00348   GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
    00349
    00350   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
    00351   int z_W = z;
    00352   int z_N = z;
    00353   GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
    00354
    00355   return (z_N_here > z_N) || (z_W_here > z_W);
    00356 }
    00357
    00358
    00359 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
    00360 {
    00361   uint z;
    00362
    00363   int z_E_here = z_here;
    00364   int z_N_here = z_here;
    00365   GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
    00366
    00367   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
    00368   int z_E = z;
    00369   int z_N = z;
    00370   GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
    00371
    00372   return (z_N_here > z_N) || (z_E_here > z_E);
    00373 }
    00374
    00380 void DrawFoundation(TileInfo *ti, Foundation f)
    00381 {
    00382   if (!IsFoundation(f)) return;
    00383
    00384   /* Two part foundations must be drawn separately */
    00385   assert(f != FOUNDATION_STEEP_BOTH);
    00386
    00387   uint sprite_block = 0;
    00388   uint z;
    00389   Slope slope = GetFoundationSlope(ti->tile, &z);
    00390
    00391   /* Select the needed block of foundations sprites
    00392    * Block 0: Walls at NW and NE edge
    00393    * Block 1: Wall  at        NE edge
    00394    * Block 2: Wall  at NW        edge
    00395    * Block 3: No walls at NW or NE edge
    00396    */
    00397   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
    00398   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
    00399
    00400   /* Use the original slope sprites if NW and NE borders should be visible */
    00401   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
    00402   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
    00403   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
    00404
    00405   if (IsSteepSlope(ti->tileh)) {
    00406     if (!IsNonContinuousFoundation(f)) {
    00407       /* Lower part of foundation */
    00408       AddSortableSpriteToDraw(
    00409         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
    00410       );
    00411     }
    00412
    00413     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
    00414     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00415
    00416     if (IsInclinedFoundation(f)) {
    00417       /* inclined foundation */
    00418       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00419
    00420       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00421         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00422         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00423         TILE_HEIGHT, ti->z
    00424       );
    00425       OffsetGroundSprite(31, 9);
    00426     } else if (IsLeveledFoundation(f)) {
    00427       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
    00428       OffsetGroundSprite(31, 1);
    00429     } else if (f == FOUNDATION_STEEP_LOWER) {
    00430       /* one corner raised */
    00431       OffsetGroundSprite(31, 1);
    00432     } else {
    00433       /* halftile foundation */
    00434       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
    00435       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
    00436
    00437       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
    00438       OffsetGroundSprite(31, 9);
    00439     }
    00440   } else {
    00441     if (IsLeveledFoundation(f)) {
    00442       /* leveled foundation */
    00443       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00444       OffsetGroundSprite(31, 1);
    00445     } else if (IsNonContinuousFoundation(f)) {
    00446       /* halftile foundation */
    00447       Corner halftile_corner = GetHalftileFoundationCorner(f);
    00448       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
    00449       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
    00450
    00451       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
    00452       OffsetGroundSprite(31, 9);
    00453     } else if (IsSpecialRailFoundation(f)) {
    00454       /* anti-zig-zag foundation */
    00455       SpriteID spr;
    00456       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
    00457         /* half of leveled foundation under track corner */
    00458         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
    00459       } else {
    00460         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
    00461         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
    00462       }
    00463       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00464       OffsetGroundSprite(31, 9);
    00465     } else {
    00466       /* inclined foundation */
    00467       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00468
    00469       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00470         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00471         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00472         TILE_HEIGHT, ti->z
    00473       );
    00474       OffsetGroundSprite(31, 9);
    00475     }
    00476     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00477   }
    00478 }
    00479
    00480 void DoClearSquare(TileIndex tile)
    00481 {
    00482   /* If the tile can have animation and we clear it, delete it from the animated tile list. */
    00483   if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
    00484
    00485   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
    00486   MarkTileDirtyByTile(tile);
    00487 }
    00488
    00498 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00499 {
    00500   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
    00501 }
    00502
    00509 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
    00510 {
    00511   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
    00512 }
    00513
    00514 void GetTileDesc(TileIndex tile, TileDesc *td)
    00515 {
    00516   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
    00517 }
    00518
    00524 bool IsSnowLineSet()
    00525 {
    00526   return _snow_line != NULL;
    00527 }
    00528
    00534 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
    00535 {
    00536   _snow_line = CallocT<SnowLine>(1);
    00537   _snow_line->lowest_value = 0xFF;
    00538   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
    00539
    00540   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
    00541     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
    00542       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
    00543       _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
    00544     }
    00545   }
    00546 }
    00547
    00553 byte GetSnowLine()
    00554 {
    00555   if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
    00556
    00557   YearMonthDay ymd;
    00558   ConvertDateToYMD(_date, &ymd);
    00559   return _snow_line->table[ymd.month][ymd.day];
    00560 }
    00561
    00567 byte HighestSnowLine()
    00568 {
    00569   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
    00570 }
    00571
    00577 byte LowestSnowLine()
    00578 {
    00579   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->lowest_value;
    00580 }
    00581
    00586 void ClearSnowLine()
    00587 {
    00588   free(_snow_line);
    00589   _snow_line = NULL;
    00590 }
    00591
    00600 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00601 {
    00602   return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
    00603 }
    00604
    00613 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00614 {
    00615   if (p1 >= MapSize()) return CMD_ERROR;
    00616
    00617   /* make sure sx,sy are smaller than ex,ey */
    00618   int ex = TileX(tile);
    00619   int ey = TileY(tile);
    00620   int sx = TileX(p1);
    00621   int sy = TileY(p1);
    00622   if (ex < sx) Swap(ex, sx);
    00623   if (ey < sy) Swap(ey, sy);
    00624
    00625   Money money = GetAvailableMoneyForCommand();
    00626   CommandCost cost(EXPENSES_CONSTRUCTION);
    00627   bool success = false;
    00628
    00629   for (int x = sx; x <= ex; ++x) {
    00630     for (int y = sy; y <= ey; ++y) {
    00631       CommandCost ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
    00632       if (ret.Failed()) continue;
    00633       success = true;
    00634
    00635       if (flags & DC_EXEC) {
    00636         money -= ret.GetCost();
    00637         if (ret.GetCost() > 0 && money < 0) {
    00638           _additional_cash_required = ret.GetCost();
    00639           return cost;
    00640         }
    00641         DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00642
    00643         /* draw explosion animation... */
    00644         if ((x == sx || x == ex) && (y == sy || y == ey)) {
    00645           /* big explosion in each corner, or small explosion for single tiles */
    00646           CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
    00647             sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
    00648           );
    00649         }
    00650       }
    00651       cost.AddCost(ret);
    00652     }
    00653   }
    00654
    00655   return (success) ? cost : CMD_ERROR;
    00656 }
    00657
    00658
    00659 TileIndex _cur_tileloop_tile;
    00660 #define TILELOOP_BITS 4
    00661 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
    00662 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
    00663 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
    00664
    00665 void RunTileLoop()
    00666 {
    00667   TileIndex tile = _cur_tileloop_tile;
    00668
    00669   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00670   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
    00671   do {
    00672     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
    00673
    00674     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
    00675       tile += TILELOOP_SIZE; // no overflow
    00676     } else {
    00677       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
    00678     }
    00679   } while (--count != 0);
    00680   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00681
    00682   tile += 9;
    00683   if (tile & TILELOOP_CHKMASK) {
    00684     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
    00685   }
    00686   _cur_tileloop_tile = tile;
    00687 }
    00688
    00689 void InitializeLandscape()
    00690 {
    00691   uint maxx = MapMaxX();
    00692   uint maxy = MapMaxY();
    00693   uint sizex = MapSizeX();
    00694
    00695   uint y;
    00696   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
    00697     uint x;
    00698     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
    00699       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
    00700       SetTileHeight(sizex * y + x, 0);
    00701       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
    00702       ClearBridgeMiddle(sizex * y + x);
    00703     }
    00704     MakeVoid(sizex * y + x);
    00705   }
    00706   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
    00707 }
    00708
    00709 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
    00710 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
    00711
    00712 static void GenerateTerrain(int type, uint flag)
    00713 {
    00714   uint32 r = Random();
    00715
    00716   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
    00717
    00718   uint x = r & MapMaxX();
    00719   uint y = (r >> MapLogX()) & MapMaxY();
    00720
    00721   if (x < 2 || y < 2) return;
    00722
    00723   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
    00724   uint w = templ->width;
    00725   uint h = templ->height;
    00726
    00727   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
    00728
    00729   const byte *p = templ->data;
    00730
    00731   if ((flag & 4) != 0) {
    00732     uint xw = x * MapSizeY();
    00733     uint yw = y * MapSizeX();
    00734     uint bias = (MapSizeX() + MapSizeY()) * 16;
    00735
    00736     switch (flag & 3) {
    00737       default: NOT_REACHED();
    00738       case 0:
    00739         if (xw + yw > MapSize() - bias) return;
    00740         break;
    00741
    00742       case 1:
    00743         if (yw < xw + bias) return;
    00744         break;
    00745
    00746       case 2:
    00747         if (xw + yw < MapSize() + bias) return;
    00748         break;
    00749
    00750       case 3:
    00751         if (xw < yw + bias) return;
    00752         break;
    00753     }
    00754   }
    00755
    00756   if (x + w >= MapMaxX() - 1) return;
    00757   if (y + h >= MapMaxY() - 1) return;
    00758
    00759   Tile *tile = &_m[TileXY(x, y)];
    00760
    00761   switch (direction) {
    00762     default: NOT_REACHED();
    00763     case DIAGDIR_NE:
    00764       do {
    00765         Tile *tile_cur = tile;
    00766
    00767         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00768           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
    00769           p++;
    00770           tile_cur++;
    00771         }
    00772         tile += TileDiffXY(0, 1);
    00773       } while (--h != 0);
    00774       break;
    00775
    00776     case DIAGDIR_SE:
    00777       do {
    00778         Tile *tile_cur = tile;
    00779
    00780         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00781           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
    00782           p++;
    00783           tile_cur += TileDiffXY(0, 1);
    00784         }
    00785         tile += TileDiffXY(1, 0);
    00786       } while (--w != 0);
    00787       break;
    00788
    00789     case DIAGDIR_SW:
    00790       tile += TileDiffXY(w - 1, 0);
    00791       do {
    00792         Tile *tile_cur = tile;
    00793
    00794         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00795           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
    00796           p++;
    00797           tile_cur--;
    00798         }
    00799         tile += TileDiffXY(0, 1);
    00800       } while (--h != 0);
    00801       break;
    00802
    00803     case DIAGDIR_NW:
    00804       tile += TileDiffXY(0, h - 1);
    00805       do {
    00806         Tile *tile_cur = tile;
    00807
    00808         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00809           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
    00810           p++;
    00811           tile_cur -= TileDiffXY(0, 1);
    00812         }
    00813         tile += TileDiffXY(1, 0);
    00814       } while (--w != 0);
    00815       break;
    00816   }
    00817 }
    00818
    00819
    00820 #include "table/genland.h"
    00821
    00822 static void CreateDesertOrRainForest()
    00823 {
    00824   TileIndex update_freq = MapSize() / 4;
    00825   const TileIndexDiffC *data;
    00826
    00827   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00828     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00829
    00830     if (!IsValidTile(tile)) continue;
    00831
    00832     for (data = _make_desert_or_rainforest_data;
    00833         data != endof(_make_desert_or_rainforest_data); ++data) {
    00834       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
    00835       if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
    00836     }
    00837     if (data == endof(_make_desert_or_rainforest_data))
    00838       SetTropicZone(tile, TROPICZONE_DESERT);
    00839   }
    00840
    00841   for (uint i = 0; i != 256; i++) {
    00842     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00843
    00844     RunTileLoop();
    00845   }
    00846
    00847   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00848     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00849
    00850     if (!IsValidTile(tile)) continue;
    00851
    00852     for (data = _make_desert_or_rainforest_data;
    00853         data != endof(_make_desert_or_rainforest_data); ++data) {
    00854       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
    00855       if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
    00856     }
    00857     if (data == endof(_make_desert_or_rainforest_data))
    00858       SetTropicZone(tile, TROPICZONE_RAINFOREST);
    00859   }
    00860 }
    00861
    00862 void GenerateLandscape(byte mode)
    00863 {
    00865   enum GenLandscapeSteps {
    00866     GLS_HEIGHTMAP    =  3,
    00867     GLS_TERRAGENESIS =  5,
    00868     GLS_ORIGINAL     =  2,
    00869     GLS_TROPIC       = 12,
    00870     GLS_OTHER        =  0,
    00871   };
    00872   uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
    00873
    00874   if (mode == GWM_HEIGHTMAP) {
    00875     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
    00876     LoadHeightmap(_file_to_saveload.name);
    00877     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00878   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
    00879     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
    00880     GenerateTerrainPerlin();
    00881   } else {
    00882     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
    00883     if (_settings_game.construction.freeform_edges) {
    00884       for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
    00885       for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
    00886     }
    00887     switch (_settings_game.game_creation.landscape) {
    00888       case LT_ARCTIC: {
    00889         uint32 r = Random();
    00890
    00891         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
    00892           GenerateTerrain(2, 0);
    00893         }
    00894
    00895         uint flag = GB(r, 7, 2) | 4;
    00896         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
    00897           GenerateTerrain(4, flag);
    00898         }
    00899       } break;
    00900
    00901       case LT_TROPIC: {
    00902         uint32 r = Random();
    00903
    00904         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
    00905           GenerateTerrain(0, 0);
    00906         }
    00907
    00908         uint flag = GB(r, 7, 2) | 4;
    00909         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
    00910           GenerateTerrain(0, flag);
    00911         }
    00912
    00913         flag ^= 2;
    00914
    00915         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
    00916           GenerateTerrain(3, flag);
    00917         }
    00918       } break;
    00919
    00920       default: {
    00921         uint32 r = Random();
    00922
    00923         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
    00924         for (; i != 0; --i) {
    00925           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
    00926         }
    00927       } break;
    00928     }
    00929   }
    00930
    00931   /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
    00932    * it allows screen redraw. Drawing of broken slopes crashes the game */
    00933   FixSlopes();
    00934   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00935   ConvertGroundTilesIntoWaterTiles();
    00936   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00937
    00938   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
    00939 }
    00940
    00941 void OnTick_Town();
    00942 void OnTick_Trees();
    00943 void OnTick_Station();
    00944 void OnTick_Industry();
    00945
    00946 void OnTick_Companies();
    00947
    00948 void CallLandscapeTick()
    00949 {
    00950   OnTick_Town();
    00951   OnTick_Trees();
    00952   OnTick_Station();
    00953   OnTick_Industry();
    00954
    00955   OnTick_Companies();
    00956 }