clear_cmd.cpp

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