# clear_cmd.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
    00012 #include "stdafx.h"
    00013 #include "clear_map.h"
    00014 #include "command_func.h"
    00015 #include "landscape.h"
    00016 #include "genworld.h"
    00017 #include "viewport_func.h"
    00018 #include "water.h"
    00019 #include "core/random_func.hpp"
    00020 #include "newgrf_generic.h"
    00021
    00022 #include "table/strings.h"
    00023 #include "table/sprites.h"
    00024 #include "table/clear_land.h"
    00025
    00026 static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags)
    00027 {
    00028   static const Price clear_price_table[] = {
    00029     PR_CLEAR_GRASS,
    00030     PR_CLEAR_ROUGH,
    00031     PR_CLEAR_ROCKS,
    00032     PR_CLEAR_FIELDS,
    00033     PR_CLEAR_ROUGH,
    00034     PR_CLEAR_ROUGH,
    00035   };
    00036   CommandCost price(EXPENSES_CONSTRUCTION);
    00037
    00038   if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) {
    00039     price.AddCost(_price[clear_price_table[GetClearGround(tile)]]);
    00040   }
    00041
    00042   if (flags & DC_EXEC) DoClearSquare(tile);
    00043
    00044   return price;
    00045 }
    00046
    00047 void DrawClearLandTile(const TileInfo *ti, byte set)
    00048 {
    00049   DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
    00050 }
    00051
    00052 void DrawHillyLandTile(const TileInfo *ti)
    00053 {
    00054   if (ti->tileh != SLOPE_FLAT) {
    00055     DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
    00056   } else {
    00057     DrawGroundSprite(_landscape_clear_sprites_rough[GB(ti->x ^ ti->y, 4, 3)], PAL_NONE);
    00058   }
    00059 }
    00060
    00061 static void DrawClearLandFence(const TileInfo *ti)
    00062 {
    00063   /* combine fences into one sprite object */
    00064   StartSpriteCombine();
    00065
    00066   int maxz = GetSlopeMaxPixelZ(ti->tileh);
    00067
    00068   bool fence_nw = GetFenceNW(ti->tile) != 0;
    00069   if (fence_nw) {
    00070     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
    00071     SpriteID sprite = _clear_land_fence_sprites[GetFenceNW(ti->tile) - 1] + _fence_mod_by_tileh_nw[ti->tileh];
    00072     AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 15, 16, 31, maxz - z + 4, ti->z + z, false, 0, 15, -z);
    00073   }
    00074
    00075   bool fence_ne = GetFenceNE(ti->tile) != 0;
    00076   if (fence_ne) {
    00077     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
    00078     SpriteID sprite = _clear_land_fence_sprites[GetFenceNE(ti->tile) - 1] + _fence_mod_by_tileh_ne[ti->tileh];
    00079     AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 15, ti->y, 31, 16, maxz - z + 4, ti->z + z, false, 15, 0, -z);
    00080   }
    00081
    00082   bool fence_sw = GetFenceSW(ti->tile) != 0;
    00083   bool fence_se = GetFenceSE(ti->tile) != 0;
    00084
    00085   if (fence_sw || fence_se) {
    00086     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
    00087
    00088     if (fence_sw) {
    00089       SpriteID sprite = _clear_land_fence_sprites[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh_sw[ti->tileh];
    00090       AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
    00091     }
    00092
    00093     if (fence_se) {
    00094       SpriteID sprite = _clear_land_fence_sprites[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_se[ti->tileh];
    00095       AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
    00096     }
    00097   }
    00098   EndSpriteCombine();
    00099 }
    00100
    00101 static void DrawTile_Clear(TileInfo *ti)
    00102 {
    00103   switch (GetClearGround(ti->tile)) {
    00104     case CLEAR_GRASS:
    00105       DrawClearLandTile(ti, GetClearDensity(ti->tile));
    00106       break;
    00107
    00108     case CLEAR_ROUGH:
    00109       DrawHillyLandTile(ti);
    00110       break;
    00111
    00112     case CLEAR_ROCKS:
    00113       DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
    00114       break;
    00115
    00116     case CLEAR_FIELDS:
    00117       DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
    00118       DrawClearLandFence(ti);
    00119       break;
    00120
    00121     case CLEAR_SNOW:
    00122     case CLEAR_DESERT:
    00123       DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
    00124       break;
    00125   }
    00126
    00127   DrawBridgeMiddle(ti);
    00128 }
    00129
    00130 static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y)
    00131 {
    00132   int z;
    00133   Slope tileh = GetTilePixelSlope(tile, &z);
    00134
    00135   return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
    00136 }
    00137
    00138 static Foundation GetFoundation_Clear(TileIndex tile, Slope tileh)
    00139 {
    00140   return FOUNDATION_NONE;
    00141 }
    00142
    00143 static void UpdateFences(TileIndex tile)
    00144 {
    00145   assert(IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
    00146   bool dirty = false;
    00147
    00148   bool neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
    00149   if (!neighbour && GetFenceSW(tile) == 0) {
    00150     SetFenceSW(tile, 3);
    00151     dirty = true;
    00152   }
    00153
    00154   neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
    00155   if (!neighbour && GetFenceSE(tile) == 0) {
    00156     SetFenceSE(tile, 3);
    00157     dirty = true;
    00158   }
    00159
    00160   neighbour = (IsTileType(TILE_ADDXY(tile, -1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, -1, 0), CLEAR_FIELDS));
    00161   if (!neighbour && GetFenceNE(tile) == 0) {
    00162     SetFenceNE(tile, 3);
    00163     dirty = true;
    00164   }
    00165
    00166   neighbour = (IsTileType(TILE_ADDXY(tile, 0, -1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, -1), CLEAR_FIELDS));
    00167   if (!neighbour && GetFenceNW(tile) == 0) {
    00168     SetFenceNW(tile, 3);
    00169     dirty = true;
    00170   }
    00171
    00172   if (dirty) MarkTileDirtyByTile(tile);
    00173 }
    00174
    00175
    00177 static void TileLoopClearAlps(TileIndex tile)
    00178 {
    00179   int k = GetTileZ(tile) - GetSnowLine() + 1;
    00180
    00181   if (k < 0) {
    00182     /* Below the snow line, do nothing if no snow. */
    00183     if (!IsSnowTile(tile)) return;
    00184   } else {
    00185     /* At or above the snow line, make snow tile if needed. */
    00186     if (!IsSnowTile(tile)) {
    00187       MakeSnow(tile);
    00188       MarkTileDirtyByTile(tile);
    00189       return;
    00190     }
    00191   }
    00192   /* Update snow density. */
    00193   uint current_density = GetClearDensity(tile);
    00194   uint req_density = (k < 0) ? 0u : min((uint)k, 3);
    00195
    00196   if (current_density < req_density) {
    00197     AddClearDensity(tile, 1);
    00198   } else if (current_density > req_density) {
    00199     AddClearDensity(tile, -1);
    00200   } else {
    00201     /* Density at the required level. */
    00202     if (k >= 0) return;
    00203     ClearSnow(tile);
    00204   }
    00205   MarkTileDirtyByTile(tile);
    00206 }
    00207
    00213 static inline bool NeighbourIsDesert(TileIndex tile)
    00214 {
    00215   return GetTropicZone(tile + TileDiffXY(  1,  0)) == TROPICZONE_DESERT ||
    00216       GetTropicZone(tile + TileDiffXY( -1,  0)) == TROPICZONE_DESERT ||
    00217       GetTropicZone(tile + TileDiffXY(  0,  1)) == TROPICZONE_DESERT ||
    00218       GetTropicZone(tile + TileDiffXY(  0, -1)) == TROPICZONE_DESERT;
    00219 }
    00220
    00221 static void TileLoopClearDesert(TileIndex tile)
    00222 {
    00223   /* Current desert level - 0 if it is not desert */
    00224   uint current = 0;
    00225   if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile);
    00226
    00227   /* Expected desert level - 0 if it shouldn't be desert */
    00228   uint expected = 0;
    00229   if (GetTropicZone(tile) == TROPICZONE_DESERT) {
    00230     expected = 3;
    00231   } else if (NeighbourIsDesert(tile)) {
    00232     expected = 1;
    00233   }
    00234
    00235   if (current == expected) return;
    00236
    00237   if (expected == 0) {
    00238     SetClearGroundDensity(tile, CLEAR_GRASS, 3);
    00239   } else {
    00240     /* Transition from clear to desert is not smooth (after clearing desert tile) */
    00241     SetClearGroundDensity(tile, CLEAR_DESERT, expected);
    00242   }
    00243
    00244   MarkTileDirtyByTile(tile);
    00245 }
    00246
    00247 static void TileLoop_Clear(TileIndex tile)
    00248 {
    00249   /* If the tile is at any edge flood it to prevent maps without water. */
    00250   if (_settings_game.construction.freeform_edges && DistanceFromEdge(tile) == 1) {
    00251     int z;
    00252     Slope slope = GetTileSlope(tile, &z);
    00253     if (z == 0 && slope == SLOPE_FLAT) {
    00254       DoFloodTile(tile);
    00255       MarkTileDirtyByTile(tile);
    00256       return;
    00257     }
    00258   }
    00259   AmbientSoundEffect(tile);
    00260
    00261   switch (_settings_game.game_creation.landscape) {
    00262     case LT_TROPIC: TileLoopClearDesert(tile); break;
    00263     case LT_ARCTIC: TileLoopClearAlps(tile);   break;
    00264   }
    00265
    00266   switch (GetClearGround(tile)) {
    00267     case CLEAR_GRASS:
    00268       if (GetClearDensity(tile) == 3) return;
    00269
    00270       if (_game_mode != GM_EDITOR) {
    00271         if (GetClearCounter(tile) < 7) {
    00272           AddClearCounter(tile, 1);
    00273           return;
    00274         } else {
    00275           SetClearCounter(tile, 0);
    00276           AddClearDensity(tile, 1);
    00277         }
    00278       } else {
    00279         SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
    00280       }
    00281       break;
    00282
    00283     case CLEAR_FIELDS:
    00284       UpdateFences(tile);
    00285
    00286       if (_game_mode == GM_EDITOR) return;
    00287
    00288       if (GetClearCounter(tile) < 7) {
    00289         AddClearCounter(tile, 1);
    00290         return;
    00291       } else {
    00292         SetClearCounter(tile, 0);
    00293       }
    00294
    00295       if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
    00296         /* This farmfield is no longer farmfield, so make it grass again */
    00297         MakeClear(tile, CLEAR_GRASS, 2);
    00298       } else {
    00299         uint field_type = GetFieldType(tile);
    00300         field_type = (field_type < 8) ? field_type + 1 : 0;
    00301         SetFieldType(tile, field_type);
    00302       }
    00303       break;
    00304
    00305     default:
    00306       return;
    00307   }
    00308
    00309   MarkTileDirtyByTile(tile);
    00310 }
    00311
    00312 void GenerateClearTile()
    00313 {
    00314   uint i, gi;
    00315   TileIndex tile;
    00316
    00317   /* add rough tiles */
    00318   i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
    00319   gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
    00320
    00321   SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
    00322   do {
    00323     IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
    00324     tile = RandomTile();
    00325     if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
    00326   } while (--i);
    00327
    00328   /* add rocky tiles */
    00329   i = gi;
    00330   do {
    00331     uint32 r = Random();
    00332     tile = RandomTileSeed(r);
    00333
    00334     IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
    00335     if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
    00336       uint j = GB(r, 16, 4) + 5;
    00337       for (;;) {
    00338         TileIndex tile_new;
    00339
    00340         SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
    00341         do {
    00342           if (--j == 0) goto get_out;
    00343           tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
    00344         } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
    00345         tile = tile_new;
    00346       }
    00347 get_out:;
    00348     }
    00349   } while (--i);
    00350 }
    00351
    00352 static TrackStatus GetTileTrackStatus_Clear(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00353 {
    00354   return 0;
    00355 }
    00356
    00357 static const StringID _clear_land_str[] = {
    00358   STR_LAI_CLEAR_DESCRIPTION_GRASS,
    00359   STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND,
    00360   STR_LAI_CLEAR_DESCRIPTION_ROCKS,
    00361   STR_LAI_CLEAR_DESCRIPTION_FIELDS,
    00362   STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND,
    00363   STR_LAI_CLEAR_DESCRIPTION_DESERT
    00364 };
    00365
    00366 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
    00367 {
    00368   if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
    00369     td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND;
    00370   } else {
    00371     td->str = _clear_land_str[GetClearGround(tile)];
    00372   }
    00373   td->owner[0] = GetTileOwner(tile);
    00374 }
    00375
    00376 static void ChangeTileOwner_Clear(TileIndex tile, Owner old_owner, Owner new_owner)
    00377 {
    00378   return;
    00379 }
    00380
    00381 static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
    00382 {
    00383   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00384 }
    00385
    00386 extern const TileTypeProcs _tile_type_clear_procs = {
    00387   DrawTile_Clear,
    00388   GetSlopePixelZ_Clear,
    00389   ClearTile_Clear,
    00390   NULL,
    00391   GetTileDesc_Clear,
    00392   GetTileTrackStatus_Clear,
    00393   NULL,
    00394   NULL,
    00395   TileLoop_Clear,
    00396   ChangeTileOwner_Clear,
    00397   NULL,
    00398   NULL,
    00399   GetFoundation_Clear,
    00400   TerraformTile_Clear,
    00401 };