clear_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: clear_cmd.cpp 25852 2013-10-12 22:23:43Z zuu $ */
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   uint fence_nw = GetFence(ti->tile, DIAGDIR_NW);
00069   if (fence_nw != 0) {
00070     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
00071     SpriteID sprite = _clear_land_fence_sprites[fence_nw - 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   uint fence_ne = GetFence(ti->tile, DIAGDIR_NE);
00076   if (fence_ne != 0) {
00077     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
00078     SpriteID sprite = _clear_land_fence_sprites[fence_ne - 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   uint fence_sw = GetFence(ti->tile, DIAGDIR_SW);
00083   uint fence_se = GetFence(ti->tile, DIAGDIR_SE);
00084 
00085   if (fence_sw != 0 || fence_se != 0) {
00086     int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
00087 
00088     if (fence_sw != 0) {
00089       SpriteID sprite = _clear_land_fence_sprites[fence_sw - 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 != 0) {
00094       SpriteID sprite = _clear_land_fence_sprites[fence_se - 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 && GetFence(tile, DIAGDIR_SW) == 0) {
00150     SetFence(tile, DIAGDIR_SW, 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 && GetFence(tile, DIAGDIR_SE) == 0) {
00156     SetFence(tile, DIAGDIR_SE, 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 && GetFence(tile, DIAGDIR_NE) == 0) {
00162     SetFence(tile, DIAGDIR_NE, 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 && GetFence(tile, DIAGDIR_NW) == 0) {
00168     SetFence(tile, DIAGDIR_NW, 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     if (IsTileFlat(tile, &z) && z == 0) {
00253       DoFloodTile(tile);
00254       MarkTileDirtyByTile(tile);
00255       return;
00256     }
00257   }
00258   AmbientSoundEffect(tile);
00259 
00260   switch (_settings_game.game_creation.landscape) {
00261     case LT_TROPIC: TileLoopClearDesert(tile); break;
00262     case LT_ARCTIC: TileLoopClearAlps(tile);   break;
00263   }
00264 
00265   switch (GetClearGround(tile)) {
00266     case CLEAR_GRASS:
00267       if (GetClearDensity(tile) == 3) return;
00268 
00269       if (_game_mode != GM_EDITOR) {
00270         if (GetClearCounter(tile) < 7) {
00271           AddClearCounter(tile, 1);
00272           return;
00273         } else {
00274           SetClearCounter(tile, 0);
00275           AddClearDensity(tile, 1);
00276         }
00277       } else {
00278         SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
00279       }
00280       break;
00281 
00282     case CLEAR_FIELDS:
00283       UpdateFences(tile);
00284 
00285       if (_game_mode == GM_EDITOR) return;
00286 
00287       if (GetClearCounter(tile) < 7) {
00288         AddClearCounter(tile, 1);
00289         return;
00290       } else {
00291         SetClearCounter(tile, 0);
00292       }
00293 
00294       if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
00295         /* This farmfield is no longer farmfield, so make it grass again */
00296         MakeClear(tile, CLEAR_GRASS, 2);
00297       } else {
00298         uint field_type = GetFieldType(tile);
00299         field_type = (field_type < 8) ? field_type + 1 : 0;
00300         SetFieldType(tile, field_type);
00301       }
00302       break;
00303 
00304     default:
00305       return;
00306   }
00307 
00308   MarkTileDirtyByTile(tile);
00309 }
00310 
00311 void GenerateClearTile()
00312 {
00313   uint i, gi;
00314   TileIndex tile;
00315 
00316   /* add rough tiles */
00317   i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
00318   gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
00319 
00320   SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
00321   do {
00322     IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
00323     tile = RandomTile();
00324     if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
00325   } while (--i);
00326 
00327   /* add rocky tiles */
00328   i = gi;
00329   do {
00330     uint32 r = Random();
00331     tile = RandomTileSeed(r);
00332 
00333     IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
00334     if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
00335       uint j = GB(r, 16, 4) + 5;
00336       for (;;) {
00337         TileIndex tile_new;
00338 
00339         SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
00340         do {
00341           if (--j == 0) goto get_out;
00342           tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
00343         } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
00344         tile = tile_new;
00345       }
00346 get_out:;
00347     }
00348   } while (--i);
00349 }
00350 
00351 static TrackStatus GetTileTrackStatus_Clear(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00352 {
00353   return 0;
00354 }
00355 
00356 static const StringID _clear_land_str[] = {
00357   STR_LAI_CLEAR_DESCRIPTION_GRASS,
00358   STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND,
00359   STR_LAI_CLEAR_DESCRIPTION_ROCKS,
00360   STR_LAI_CLEAR_DESCRIPTION_FIELDS,
00361   STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND,
00362   STR_LAI_CLEAR_DESCRIPTION_DESERT
00363 };
00364 
00365 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
00366 {
00367   if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
00368     td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND;
00369   } else {
00370     td->str = _clear_land_str[GetClearGround(tile)];
00371   }
00372   td->owner[0] = GetTileOwner(tile);
00373 }
00374 
00375 static void ChangeTileOwner_Clear(TileIndex tile, Owner old_owner, Owner new_owner)
00376 {
00377   return;
00378 }
00379 
00380 static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
00381 {
00382   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00383 }
00384 
00385 extern const TileTypeProcs _tile_type_clear_procs = {
00386   DrawTile_Clear,           
00387   GetSlopePixelZ_Clear,     
00388   ClearTile_Clear,          
00389   NULL,                     
00390   GetTileDesc_Clear,        
00391   GetTileTrackStatus_Clear, 
00392   NULL,                     
00393   NULL,                     
00394   TileLoop_Clear,           
00395   ChangeTileOwner_Clear,    
00396   NULL,                     
00397   NULL,                     
00398   GetFoundation_Clear,      
00399   TerraformTile_Clear,      
00400 };