# landscape.cpp

Go to the documentation of this file.

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