(svn r23005) -Fix (r23004): Of course there's still the 16-sprite version for shore...
[openttd/fttd.git] / src / clear_cmd.cpp
blob5106113d374820641392a8cba17bc2cf6f8008b4
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file clear_cmd.cpp Commands related to clear tiles. */
12 #include "stdafx.h"
13 #include "clear_map.h"
14 #include "command_func.h"
15 #include "landscape.h"
16 #include "genworld.h"
17 #include "landscape_type.h"
18 #include "clear_func.h"
19 #include "economy_func.h"
20 #include "viewport_func.h"
21 #include "water.h"
22 #include "core/random_func.hpp"
24 #include "table/strings.h"
25 #include "table/sprites.h"
26 #include "table/clear_land.h"
28 static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags)
30 static const Price clear_price_table[] = {
31 PR_CLEAR_GRASS,
32 PR_CLEAR_ROUGH,
33 PR_CLEAR_ROCKS,
34 PR_CLEAR_FIELDS,
35 PR_CLEAR_ROUGH,
36 PR_CLEAR_ROUGH,
38 CommandCost price(EXPENSES_CONSTRUCTION);
40 if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) {
41 price.AddCost(_price[clear_price_table[GetClearGround(tile)]]);
44 if (flags & DC_EXEC) DoClearSquare(tile);
46 return price;
49 void DrawClearLandTile(const TileInfo *ti, byte set)
51 DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
54 void DrawHillyLandTile(const TileInfo *ti)
56 if (ti->tileh != SLOPE_FLAT) {
57 DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
58 } else {
59 DrawGroundSprite(_landscape_clear_sprites_rough[GB(ti->x ^ ti->y, 4, 3)], PAL_NONE);
63 void DrawClearLandFence(const TileInfo *ti)
65 bool fence_sw = GetFenceSW(ti->tile) != 0;
66 bool fence_se = GetFenceSE(ti->tile) != 0;
68 if (!fence_sw && !fence_se) return;
70 int z = GetSlopeZInCorner(ti->tileh, CORNER_S);
72 if (fence_sw) {
73 DrawGroundSpriteAt(_clear_land_fence_sprites[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh_sw[ti->tileh], PAL_NONE, 0, 0, z);
76 if (fence_se) {
77 DrawGroundSpriteAt(_clear_land_fence_sprites[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_se[ti->tileh], PAL_NONE, 0, 0, z);
81 static void DrawTile_Clear(TileInfo *ti)
83 switch (GetClearGround(ti->tile)) {
84 case CLEAR_GRASS:
85 DrawClearLandTile(ti, GetClearDensity(ti->tile));
86 break;
88 case CLEAR_ROUGH:
89 DrawHillyLandTile(ti);
90 break;
92 case CLEAR_ROCKS:
93 DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
94 break;
96 case CLEAR_FIELDS:
97 DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
98 break;
100 case CLEAR_SNOW:
101 case CLEAR_DESERT:
102 DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
103 break;
106 DrawClearLandFence(ti);
107 DrawBridgeMiddle(ti);
110 static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
112 uint z;
113 Slope tileh = GetTileSlope(tile, &z);
115 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
118 static Foundation GetFoundation_Clear(TileIndex tile, Slope tileh)
120 return FOUNDATION_NONE;
123 void TileLoopClearHelper(TileIndex tile)
125 bool self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
126 bool dirty = false;
128 bool neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
129 if (GetFenceSW(tile) == 0) {
130 if (self != neighbour) {
131 SetFenceSW(tile, 3);
132 dirty = true;
134 } else {
135 if (self == 0 && neighbour == 0) {
136 SetFenceSW(tile, 0);
137 dirty = true;
141 neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
142 if (GetFenceSE(tile) == 0) {
143 if (self != neighbour) {
144 SetFenceSE(tile, 3);
145 dirty = true;
147 } else {
148 if (self == 0 && neighbour == 0) {
149 SetFenceSE(tile, 0);
150 dirty = true;
154 if (dirty) MarkTileDirtyByTile(tile);
158 /** Convert to or from snowy tiles. */
159 static void TileLoopClearAlps(TileIndex tile)
161 int k = GetTileZ(tile) - GetSnowLine() + TILE_HEIGHT;
163 if (k < 0) {
164 /* Below the snow line, do nothing if no snow. */
165 if (!IsSnowTile(tile)) return;
166 } else {
167 /* At or above the snow line, make snow tile if needed. */
168 if (!IsSnowTile(tile)) {
169 MakeSnow(tile);
170 MarkTileDirtyByTile(tile);
171 return;
174 /* Update snow density. */
175 uint curent_density = GetClearDensity(tile);
176 uint req_density = (k < 0) ? 0u : min((uint)k / TILE_HEIGHT, 3);
178 if (curent_density < req_density) {
179 AddClearDensity(tile, 1);
180 } else if (curent_density > req_density) {
181 AddClearDensity(tile, -1);
182 } else {
183 /* Density at the required level. */
184 if (k >= 0) return;
185 ClearSnow(tile);
187 MarkTileDirtyByTile(tile);
191 * Tests if at least one surrounding tile is desert
192 * @param tile tile to check
193 * @return does this tile have at least one desert tile around?
195 static inline bool NeighbourIsDesert(TileIndex tile)
197 return GetTropicZone(tile + TileDiffXY( 1, 0)) == TROPICZONE_DESERT ||
198 GetTropicZone(tile + TileDiffXY( -1, 0)) == TROPICZONE_DESERT ||
199 GetTropicZone(tile + TileDiffXY( 0, 1)) == TROPICZONE_DESERT ||
200 GetTropicZone(tile + TileDiffXY( 0, -1)) == TROPICZONE_DESERT;
203 static void TileLoopClearDesert(TileIndex tile)
205 /* Current desert level - 0 if it is not desert */
206 uint current = 0;
207 if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile);
209 /* Expected desert level - 0 if it shouldn't be desert */
210 uint expected = 0;
211 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
212 expected = 3;
213 } else if (NeighbourIsDesert(tile)) {
214 expected = 1;
217 if (current == expected) return;
219 if (expected == 0) {
220 SetClearGroundDensity(tile, CLEAR_GRASS, 3);
221 } else {
222 /* Transition from clear to desert is not smooth (after clearing desert tile) */
223 SetClearGroundDensity(tile, CLEAR_DESERT, expected);
226 MarkTileDirtyByTile(tile);
229 static void TileLoop_Clear(TileIndex tile)
231 /* If the tile is at any edge flood it to prevent maps without water. */
232 if (_settings_game.construction.freeform_edges && DistanceFromEdge(tile) == 1) {
233 uint z;
234 Slope slope = GetTileSlope(tile, &z);
235 if (z == 0 && slope == SLOPE_FLAT) {
236 DoFloodTile(tile);
237 MarkTileDirtyByTile(tile);
238 return;
241 TileLoopClearHelper(tile);
243 switch (_settings_game.game_creation.landscape) {
244 case LT_TROPIC: TileLoopClearDesert(tile); break;
245 case LT_ARCTIC: TileLoopClearAlps(tile); break;
248 switch (GetClearGround(tile)) {
249 case CLEAR_GRASS:
250 if (GetClearDensity(tile) == 3) return;
252 if (_game_mode != GM_EDITOR) {
253 if (GetClearCounter(tile) < 7) {
254 AddClearCounter(tile, 1);
255 return;
256 } else {
257 SetClearCounter(tile, 0);
258 AddClearDensity(tile, 1);
260 } else {
261 SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
263 break;
265 case CLEAR_FIELDS: {
266 uint field_type;
268 if (_game_mode == GM_EDITOR) return;
270 if (GetClearCounter(tile) < 7) {
271 AddClearCounter(tile, 1);
272 return;
273 } else {
274 SetClearCounter(tile, 0);
277 if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
278 /* This farmfield is no longer farmfield, so make it grass again */
279 MakeClear(tile, CLEAR_GRASS, 2);
280 } else {
281 field_type = GetFieldType(tile);
282 field_type = (field_type < 8) ? field_type + 1 : 0;
283 SetFieldType(tile, field_type);
285 break;
288 default:
289 return;
292 MarkTileDirtyByTile(tile);
295 void GenerateClearTile()
297 uint i, gi;
298 TileIndex tile;
300 /* add rough tiles */
301 i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
302 gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
304 SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
305 do {
306 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
307 tile = RandomTile();
308 if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
309 } while (--i);
311 /* add rocky tiles */
312 i = gi;
313 do {
314 uint32 r = Random();
315 tile = RandomTileSeed(r);
317 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
318 if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
319 uint j = GB(r, 16, 4) + 5;
320 for (;;) {
321 TileIndex tile_new;
323 SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
324 do {
325 if (--j == 0) goto get_out;
326 tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
327 } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
328 tile = tile_new;
330 get_out:;
332 } while (--i);
335 static TrackStatus GetTileTrackStatus_Clear(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
337 return 0;
340 static const StringID _clear_land_str[] = {
341 STR_LAI_CLEAR_DESCRIPTION_GRASS,
342 STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND,
343 STR_LAI_CLEAR_DESCRIPTION_ROCKS,
344 STR_LAI_CLEAR_DESCRIPTION_FIELDS,
345 STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND,
346 STR_LAI_CLEAR_DESCRIPTION_DESERT
349 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
351 if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
352 td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND;
353 } else {
354 td->str = _clear_land_str[GetClearGround(tile)];
356 td->owner[0] = GetTileOwner(tile);
359 static void ChangeTileOwner_Clear(TileIndex tile, Owner old_owner, Owner new_owner)
361 return;
364 void InitializeClearLand()
366 _settings_game.game_creation.snow_line = _settings_game.game_creation.snow_line_height * TILE_HEIGHT;
369 static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
371 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
374 extern const TileTypeProcs _tile_type_clear_procs = {
375 DrawTile_Clear, ///< draw_tile_proc
376 GetSlopeZ_Clear, ///< get_slope_z_proc
377 ClearTile_Clear, ///< clear_tile_proc
378 NULL, ///< add_accepted_cargo_proc
379 GetTileDesc_Clear, ///< get_tile_desc_proc
380 GetTileTrackStatus_Clear, ///< get_tile_track_status_proc
381 NULL, ///< click_tile_proc
382 NULL, ///< animate_tile_proc
383 TileLoop_Clear, ///< tile_loop_clear
384 ChangeTileOwner_Clear, ///< change_tile_owner_clear
385 NULL, ///< add_produced_cargo_proc
386 NULL, ///< vehicle_enter_tile_proc
387 GetFoundation_Clear, ///< get_foundation_proc
388 TerraformTile_Clear, ///< terraform_tile_proc