|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "clear_map.h" |
|
6 #include "rail_map.h" |
|
7 #include "table/strings.h" |
|
8 #include "functions.h" |
|
9 #include "map.h" |
|
10 #include "player.h" |
|
11 #include "tile.h" |
|
12 #include "viewport.h" |
|
13 #include "command.h" |
|
14 #include "tunnel_map.h" |
|
15 #include "bridge_map.h" |
|
16 #include "variables.h" |
|
17 #include "table/sprites.h" |
|
18 #include "unmovable_map.h" |
|
19 #include "genworld.h" |
|
20 #include "industry.h" |
|
21 |
|
22 typedef struct TerraformerHeightMod { |
|
23 TileIndex tile; |
|
24 byte height; |
|
25 } TerraformerHeightMod; |
|
26 |
|
27 typedef struct TerraformerState { |
|
28 int height[4]; |
|
29 uint32 flags; |
|
30 |
|
31 int direction; |
|
32 int modheight_count; |
|
33 int tile_table_count; |
|
34 |
|
35 int32 cost; |
|
36 |
|
37 TileIndex *tile_table; |
|
38 TerraformerHeightMod *modheight; |
|
39 |
|
40 } TerraformerState; |
|
41 |
|
42 static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile) |
|
43 { |
|
44 TileIndex *t; |
|
45 int count; |
|
46 |
|
47 if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1; |
|
48 |
|
49 t = ts->tile_table; |
|
50 for (count = ts->tile_table_count; count != 0; count--, t++) { |
|
51 if (*t == tile) return 0; |
|
52 } |
|
53 |
|
54 return 1; |
|
55 } |
|
56 |
|
57 static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile) |
|
58 { |
|
59 TerraformerHeightMod *mod = ts->modheight; |
|
60 int count; |
|
61 |
|
62 for (count = ts->modheight_count; count != 0; count--, mod++) { |
|
63 if (mod->tile == tile) return mod->height; |
|
64 } |
|
65 |
|
66 return TileHeight(tile); |
|
67 } |
|
68 |
|
69 static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile) |
|
70 { |
|
71 int count; |
|
72 TileIndex *t; |
|
73 |
|
74 count = ts->tile_table_count; |
|
75 |
|
76 if (count >= 625) return; |
|
77 |
|
78 for (t = ts->tile_table; count != 0; count--,t++) { |
|
79 if (*t == tile) return; |
|
80 } |
|
81 |
|
82 ts->tile_table[ts->tile_table_count++] = tile; |
|
83 } |
|
84 |
|
85 static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile) |
|
86 { |
|
87 TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1)); |
|
88 TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1)); |
|
89 TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0)); |
|
90 TerraformAddDirtyTile(ts, tile); |
|
91 } |
|
92 |
|
93 static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode) |
|
94 { |
|
95 int r; |
|
96 int32 ret; |
|
97 |
|
98 assert(tile < MapSize()); |
|
99 |
|
100 r = TerraformAllowTileProcess(ts, tile); |
|
101 if (r <= 0) return r; |
|
102 |
|
103 if (IsTileType(tile, MP_RAILWAY)) { |
|
104 static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT }; |
|
105 static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E }; |
|
106 |
|
107 Slope tileh; |
|
108 uint z; |
|
109 |
|
110 // Nothing could be built at the steep slope - this avoids a bug |
|
111 // when you have a single diagonal track in one corner on a |
|
112 // basement and then you raise/lower the other corner. |
|
113 tileh = GetTileSlope(tile, &z); |
|
114 if (tileh == unsafe_slope[mode] || |
|
115 tileh == ComplementSlope(unsafe_slope[mode])) { |
|
116 _terraform_err_tile = tile; |
|
117 _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK; |
|
118 return -1; |
|
119 } |
|
120 |
|
121 // If we have a single diagonal track there, the other side of |
|
122 // tile can be terraformed. |
|
123 if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) { |
|
124 /* If terraforming downwards prevent damaging a potential tunnel below. |
|
125 * This check is only necessary for flat tiles, because if the tile is |
|
126 * non-flat, then the corner opposing the rail is raised. Only this corner |
|
127 * can be lowered and this is a safe action |
|
128 */ |
|
129 if (tileh == SLOPE_FLAT && |
|
130 ts->direction == -1 && |
|
131 IsTunnelInWay(tile, z - TILE_HEIGHT)) { |
|
132 _terraform_err_tile = tile; |
|
133 _error_message = STR_1002_EXCAVATION_WOULD_DAMAGE; |
|
134 return -1; |
|
135 } |
|
136 return 0; |
|
137 } |
|
138 } |
|
139 |
|
140 ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR); |
|
141 |
|
142 if (CmdFailed(ret)) { |
|
143 _terraform_err_tile = tile; |
|
144 return -1; |
|
145 } |
|
146 |
|
147 ts->cost += ret; |
|
148 |
|
149 if (ts->tile_table_count >= 625) return -1; |
|
150 ts->tile_table[ts->tile_table_count++] = tile; |
|
151 |
|
152 return 0; |
|
153 } |
|
154 |
|
155 static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height) |
|
156 { |
|
157 int nh; |
|
158 TerraformerHeightMod *mod; |
|
159 int count; |
|
160 |
|
161 assert(tile < MapSize()); |
|
162 |
|
163 if (height < 0) { |
|
164 _error_message = STR_1003_ALREADY_AT_SEA_LEVEL; |
|
165 return false; |
|
166 } |
|
167 |
|
168 _error_message = STR_1004_TOO_HIGH; |
|
169 |
|
170 if (height > 15) return false; |
|
171 |
|
172 nh = TerraformGetHeightOfTile(ts, tile); |
|
173 if (nh < 0 || height == nh) return false; |
|
174 |
|
175 if (TerraformProc(ts, tile, 0) < 0) return false; |
|
176 if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false; |
|
177 if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false; |
|
178 if (TerraformProc(ts, tile + TileDiffXY(-1, 0), 3) < 0) return false; |
|
179 |
|
180 mod = ts->modheight; |
|
181 count = ts->modheight_count; |
|
182 |
|
183 for (;;) { |
|
184 if (count == 0) { |
|
185 if (ts->modheight_count >= 576) return false; |
|
186 ts->modheight_count++; |
|
187 break; |
|
188 } |
|
189 if (mod->tile == tile) break; |
|
190 mod++; |
|
191 count--; |
|
192 } |
|
193 |
|
194 mod->tile = tile; |
|
195 mod->height = (byte)height; |
|
196 |
|
197 ts->cost += _price.terraform; |
|
198 |
|
199 { |
|
200 int direction = ts->direction, r; |
|
201 const TileIndexDiffC *ttm; |
|
202 |
|
203 static const TileIndexDiffC _terraform_tilepos[] = { |
|
204 { 1, 0}, |
|
205 {-2, 0}, |
|
206 { 1, 1}, |
|
207 { 0, -2} |
|
208 }; |
|
209 |
|
210 for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) { |
|
211 tile += ToTileIndexDiff(*ttm); |
|
212 |
|
213 r = TerraformGetHeightOfTile(ts, tile); |
|
214 if (r != height && r-direction != height && r+direction != height) { |
|
215 if (!TerraformTileHeight(ts, tile, r+direction)) |
|
216 return false; |
|
217 } |
|
218 } |
|
219 } |
|
220 |
|
221 return true; |
|
222 } |
|
223 |
|
224 /** Terraform land |
|
225 * @param tile tile to terraform |
|
226 * @param p1 corners to terraform. |
|
227 * @param p2 direction; eg up or down |
|
228 */ |
|
229 int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
|
230 { |
|
231 TerraformerState ts; |
|
232 TileIndex t; |
|
233 int direction; |
|
234 |
|
235 TerraformerHeightMod modheight_data[576]; |
|
236 TileIndex tile_table_data[625]; |
|
237 |
|
238 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
239 |
|
240 _terraform_err_tile = 0; |
|
241 |
|
242 ts.direction = direction = p2 ? 1 : -1; |
|
243 ts.flags = flags; |
|
244 ts.modheight_count = ts.tile_table_count = 0; |
|
245 ts.cost = 0; |
|
246 ts.modheight = modheight_data; |
|
247 ts.tile_table = tile_table_data; |
|
248 |
|
249 /* Make an extra check for map-bounds cause we add tiles to the originating tile */ |
|
250 if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR; |
|
251 |
|
252 if (p1 & 1) { |
|
253 t = tile + TileDiffXY(1, 0); |
|
254 if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) { |
|
255 return CMD_ERROR; |
|
256 } |
|
257 } |
|
258 |
|
259 if (p1 & 2) { |
|
260 t = tile + TileDiffXY(1, 1); |
|
261 if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) { |
|
262 return CMD_ERROR; |
|
263 } |
|
264 } |
|
265 |
|
266 if (p1 & 4) { |
|
267 t = tile + TileDiffXY(0, 1); |
|
268 if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) { |
|
269 return CMD_ERROR; |
|
270 } |
|
271 } |
|
272 |
|
273 if (p1 & 8) { |
|
274 t = tile + TileDiffXY(0, 0); |
|
275 if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) { |
|
276 return CMD_ERROR; |
|
277 } |
|
278 } |
|
279 |
|
280 { |
|
281 /* Check if tunnel would take damage */ |
|
282 int count; |
|
283 TileIndex *ti = ts.tile_table; |
|
284 |
|
285 for (count = ts.tile_table_count; count != 0; count--, ti++) { |
|
286 TileIndex tile = *ti; |
|
287 |
|
288 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) { |
|
289 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
290 } |
|
291 |
|
292 if (direction == -1) { |
|
293 uint z, t; |
|
294 |
|
295 z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); |
|
296 t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); |
|
297 if (t <= z) z = t; |
|
298 t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1)); |
|
299 if (t <= z) z = t; |
|
300 t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1)); |
|
301 if (t <= z) z = t; |
|
302 |
|
303 if (IsTunnelInWay(tile, z * TILE_HEIGHT)) { |
|
304 return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE); |
|
305 } |
|
306 } |
|
307 } |
|
308 } |
|
309 |
|
310 if (flags & DC_EXEC) { |
|
311 /* Clear the landscape at the tiles */ |
|
312 { |
|
313 int count; |
|
314 TileIndex *ti = ts.tile_table; |
|
315 for (count = ts.tile_table_count; count != 0; count--, ti++) { |
|
316 DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
317 } |
|
318 } |
|
319 |
|
320 /* change the height */ |
|
321 { |
|
322 int count; |
|
323 TerraformerHeightMod *mod; |
|
324 |
|
325 mod = ts.modheight; |
|
326 for (count = ts.modheight_count; count != 0; count--, mod++) { |
|
327 TileIndex til = mod->tile; |
|
328 |
|
329 SetTileHeight(til, mod->height); |
|
330 TerraformAddDirtyTileAround(&ts, til); |
|
331 } |
|
332 } |
|
333 |
|
334 /* finally mark the dirty tiles dirty */ |
|
335 { |
|
336 int count; |
|
337 TileIndex *ti = ts.tile_table; |
|
338 for (count = ts.tile_table_count; count != 0; count--, ti++) { |
|
339 MarkTileDirtyByTile(*ti); |
|
340 } |
|
341 } |
|
342 } |
|
343 return ts.cost; |
|
344 } |
|
345 |
|
346 |
|
347 /** Levels a selected (rectangle) area of land |
|
348 * @param tile end tile of area-drag |
|
349 * @param p1 start tile of area drag |
|
350 * @param p2 unused |
|
351 */ |
|
352 int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
|
353 { |
|
354 int size_x, size_y; |
|
355 int ex; |
|
356 int ey; |
|
357 int sx, sy; |
|
358 uint h, curh; |
|
359 int32 ret, cost, money; |
|
360 |
|
361 if (p1 >= MapSize()) return CMD_ERROR; |
|
362 |
|
363 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
364 |
|
365 // remember level height |
|
366 h = TileHeight(p1); |
|
367 |
|
368 // make sure sx,sy are smaller than ex,ey |
|
369 ex = TileX(tile); |
|
370 ey = TileY(tile); |
|
371 sx = TileX(p1); |
|
372 sy = TileY(p1); |
|
373 if (ex < sx) intswap(ex, sx); |
|
374 if (ey < sy) intswap(ey, sy); |
|
375 tile = TileXY(sx, sy); |
|
376 |
|
377 size_x = ex-sx+1; |
|
378 size_y = ey-sy+1; |
|
379 |
|
380 money = GetAvailableMoneyForCommand(); |
|
381 cost = 0; |
|
382 |
|
383 BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) { |
|
384 curh = TileHeight(tile2); |
|
385 while (curh != h) { |
|
386 ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND); |
|
387 if (CmdFailed(ret)) break; |
|
388 cost += ret; |
|
389 |
|
390 if (flags & DC_EXEC) { |
|
391 if ((money -= ret) < 0) { |
|
392 _additional_cash_required = ret; |
|
393 return cost - ret; |
|
394 } |
|
395 DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); |
|
396 } |
|
397 |
|
398 curh += (curh > h) ? -1 : 1; |
|
399 } |
|
400 } END_TILE_LOOP(tile2, size_x, size_y, tile) |
|
401 |
|
402 return (cost == 0) ? CMD_ERROR : cost; |
|
403 } |
|
404 |
|
405 /** Purchase a land area. Actually you only purchase one tile, so |
|
406 * the name is a bit confusing ;p |
|
407 * @param tile the tile the player is purchasing |
|
408 * @param p1 unused |
|
409 * @param p2 unused |
|
410 */ |
|
411 int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
|
412 { |
|
413 int32 cost; |
|
414 |
|
415 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
416 |
|
417 if (!EnsureNoVehicle(tile)) return CMD_ERROR; |
|
418 |
|
419 if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) { |
|
420 return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT); |
|
421 } |
|
422 |
|
423 cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
424 if (CmdFailed(cost)) return CMD_ERROR; |
|
425 |
|
426 if (flags & DC_EXEC) { |
|
427 MakeOwnedLand(tile, _current_player); |
|
428 MarkTileDirtyByTile(tile); |
|
429 } |
|
430 |
|
431 return cost + _price.purchase_land * 10; |
|
432 } |
|
433 |
|
434 |
|
435 static int32 ClearTile_Clear(TileIndex tile, byte flags) |
|
436 { |
|
437 static const int32* clear_price_table[] = { |
|
438 &_price.clear_1, |
|
439 &_price.purchase_land, |
|
440 &_price.clear_2, |
|
441 &_price.clear_3, |
|
442 &_price.purchase_land, |
|
443 &_price.purchase_land, |
|
444 &_price.clear_2, // XXX unused? |
|
445 }; |
|
446 int32 price; |
|
447 |
|
448 if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) { |
|
449 price = 0; |
|
450 } else { |
|
451 price = *clear_price_table[GetClearGround(tile)]; |
|
452 } |
|
453 |
|
454 if (flags & DC_EXEC) DoClearSquare(tile); |
|
455 |
|
456 return price; |
|
457 } |
|
458 |
|
459 /** Sell a land area. Actually you only sell one tile, so |
|
460 * the name is a bit confusing ;p |
|
461 * @param tile the tile the player is selling |
|
462 * @param p1 unused |
|
463 * @param p2 unused |
|
464 */ |
|
465 int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
|
466 { |
|
467 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
468 |
|
469 if (!IsOwnedLandTile(tile)) return CMD_ERROR; |
|
470 if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR; |
|
471 |
|
472 |
|
473 if (!EnsureNoVehicle(tile)) return CMD_ERROR; |
|
474 |
|
475 if (flags & DC_EXEC) DoClearSquare(tile); |
|
476 |
|
477 return - _price.purchase_land * 2; |
|
478 } |
|
479 |
|
480 |
|
481 #include "table/clear_land.h" |
|
482 |
|
483 |
|
484 void DrawClearLandTile(const TileInfo *ti, byte set) |
|
485 { |
|
486 DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19); |
|
487 } |
|
488 |
|
489 void DrawHillyLandTile(const TileInfo *ti) |
|
490 { |
|
491 if (ti->tileh != SLOPE_FLAT) { |
|
492 DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]); |
|
493 } else { |
|
494 DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]); |
|
495 } |
|
496 } |
|
497 |
|
498 void DrawClearLandFence(const TileInfo *ti) |
|
499 { |
|
500 byte z = ti->z; |
|
501 |
|
502 if (ti->tileh & SLOPE_S) { |
|
503 z += TILE_HEIGHT; |
|
504 if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT; |
|
505 } |
|
506 |
|
507 if (GetFenceSW(ti->tile) != 0) { |
|
508 DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z); |
|
509 } |
|
510 |
|
511 if (GetFenceSE(ti->tile) != 0) { |
|
512 DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z); |
|
513 } |
|
514 } |
|
515 |
|
516 static void DrawTile_Clear(TileInfo *ti) |
|
517 { |
|
518 switch (GetClearGround(ti->tile)) { |
|
519 case CLEAR_GRASS: |
|
520 DrawClearLandTile(ti, GetClearDensity(ti->tile)); |
|
521 break; |
|
522 |
|
523 case CLEAR_ROUGH: |
|
524 DrawHillyLandTile(ti); |
|
525 break; |
|
526 |
|
527 case CLEAR_ROCKS: |
|
528 DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]); |
|
529 break; |
|
530 |
|
531 case CLEAR_FIELDS: |
|
532 DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]); |
|
533 break; |
|
534 |
|
535 case CLEAR_SNOW: |
|
536 DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]); |
|
537 break; |
|
538 |
|
539 case CLEAR_DESERT: |
|
540 DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]); |
|
541 break; |
|
542 } |
|
543 |
|
544 DrawClearLandFence(ti); |
|
545 DrawBridgeMiddle(ti); |
|
546 } |
|
547 |
|
548 static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y) |
|
549 { |
|
550 uint z; |
|
551 uint tileh = GetTileSlope(tile, &z); |
|
552 |
|
553 return z + GetPartialZ(x & 0xF, y & 0xF, tileh); |
|
554 } |
|
555 |
|
556 static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh) |
|
557 { |
|
558 return tileh; |
|
559 } |
|
560 |
|
561 static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac) |
|
562 { |
|
563 /* unused */ |
|
564 } |
|
565 |
|
566 static void AnimateTile_Clear(TileIndex tile) |
|
567 { |
|
568 /* unused */ |
|
569 } |
|
570 |
|
571 void TileLoopClearHelper(TileIndex tile) |
|
572 { |
|
573 byte self; |
|
574 byte neighbour; |
|
575 TileIndex dirty = INVALID_TILE; |
|
576 |
|
577 self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)); |
|
578 |
|
579 neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS)); |
|
580 if (GetFenceSW(tile) == 0) { |
|
581 if (self != neighbour) { |
|
582 SetFenceSW(tile, 3); |
|
583 dirty = tile; |
|
584 } |
|
585 } else { |
|
586 if (self == 0 && neighbour == 0) { |
|
587 SetFenceSW(tile, 0); |
|
588 dirty = tile; |
|
589 } |
|
590 } |
|
591 |
|
592 neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS)); |
|
593 if (GetFenceSE(tile) == 0) { |
|
594 if (self != neighbour) { |
|
595 SetFenceSE(tile, 3); |
|
596 dirty = tile; |
|
597 } |
|
598 } else { |
|
599 if (self == 0 && neighbour == 0) { |
|
600 SetFenceSE(tile, 0); |
|
601 dirty = tile; |
|
602 } |
|
603 } |
|
604 |
|
605 if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty); |
|
606 } |
|
607 |
|
608 |
|
609 /* convert into snowy tiles */ |
|
610 static void TileLoopClearAlps(TileIndex tile) |
|
611 { |
|
612 int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT; |
|
613 |
|
614 if (k < 0) { // well below the snow line |
|
615 if (!IsClearGround(tile, CLEAR_SNOW)) return; |
|
616 if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3); |
|
617 } else { |
|
618 if (!IsClearGround(tile, CLEAR_SNOW)) { |
|
619 SetClearGroundDensity(tile, CLEAR_SNOW, 0); |
|
620 } else { |
|
621 uint density = min((uint)k / TILE_HEIGHT, 3); |
|
622 |
|
623 if (GetClearDensity(tile) < density) { |
|
624 AddClearDensity(tile, 1); |
|
625 } else if (GetClearDensity(tile) > density) { |
|
626 AddClearDensity(tile, -1); |
|
627 } else { |
|
628 return; |
|
629 } |
|
630 } |
|
631 } |
|
632 |
|
633 MarkTileDirtyByTile(tile); |
|
634 } |
|
635 |
|
636 static void TileLoopClearDesert(TileIndex tile) |
|
637 { |
|
638 if (IsClearGround(tile, CLEAR_DESERT)) return; |
|
639 |
|
640 if (GetTropicZone(tile) == TROPICZONE_DESERT) { |
|
641 SetClearGroundDensity(tile, CLEAR_DESERT, 3); |
|
642 } else { |
|
643 if (GetTropicZone(tile + TileDiffXY( 1, 0)) != TROPICZONE_DESERT && |
|
644 GetTropicZone(tile + TileDiffXY(-1, 0)) != TROPICZONE_DESERT && |
|
645 GetTropicZone(tile + TileDiffXY( 0, 1)) != TROPICZONE_DESERT && |
|
646 GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT) |
|
647 return; |
|
648 SetClearGroundDensity(tile, CLEAR_DESERT, 1); |
|
649 } |
|
650 |
|
651 MarkTileDirtyByTile(tile); |
|
652 } |
|
653 |
|
654 static void TileLoop_Clear(TileIndex tile) |
|
655 { |
|
656 TileLoopClearHelper(tile); |
|
657 |
|
658 switch (_opt.landscape) { |
|
659 case LT_DESERT: TileLoopClearDesert(tile); break; |
|
660 case LT_HILLY: TileLoopClearAlps(tile); break; |
|
661 } |
|
662 |
|
663 switch (GetClearGround(tile)) { |
|
664 case CLEAR_GRASS: |
|
665 if (GetClearDensity(tile) == 3) return; |
|
666 |
|
667 if (_game_mode != GM_EDITOR) { |
|
668 if (GetClearCounter(tile) < 7) { |
|
669 AddClearCounter(tile, 1); |
|
670 return; |
|
671 } else { |
|
672 SetClearCounter(tile, 0); |
|
673 AddClearDensity(tile, 1); |
|
674 } |
|
675 } else { |
|
676 SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3); |
|
677 } |
|
678 break; |
|
679 |
|
680 case CLEAR_FIELDS: { |
|
681 uint field_type; |
|
682 |
|
683 if (_game_mode == GM_EDITOR) return; |
|
684 |
|
685 if (GetClearCounter(tile) < 7) { |
|
686 AddClearCounter(tile, 1); |
|
687 return; |
|
688 } else { |
|
689 SetClearCounter(tile, 0); |
|
690 } |
|
691 |
|
692 if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) { |
|
693 /* This farmfield is no longer farmfield, so make it grass again */ |
|
694 MakeClear(tile, CLEAR_GRASS, 2); |
|
695 } else { |
|
696 field_type = GetFieldType(tile); |
|
697 field_type = (field_type < 8) ? field_type + 1 : 0; |
|
698 SetFieldType(tile, field_type); |
|
699 } |
|
700 break; |
|
701 } |
|
702 |
|
703 default: |
|
704 return; |
|
705 } |
|
706 |
|
707 MarkTileDirtyByTile(tile); |
|
708 } |
|
709 |
|
710 void GenerateClearTile(void) |
|
711 { |
|
712 uint i, gi; |
|
713 TileIndex tile; |
|
714 |
|
715 /* add rough tiles */ |
|
716 i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400); |
|
717 gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80); |
|
718 |
|
719 SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i); |
|
720 do { |
|
721 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); |
|
722 tile = RandomTile(); |
|
723 if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3); |
|
724 } while (--i); |
|
725 |
|
726 /* add rocky tiles */ |
|
727 i = gi; |
|
728 do { |
|
729 uint32 r = Random(); |
|
730 tile = RandomTileSeed(r); |
|
731 |
|
732 IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); |
|
733 if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) { |
|
734 uint j = GB(r, 16, 4) + 5; |
|
735 for (;;) { |
|
736 TileIndex tile_new; |
|
737 |
|
738 SetClearGroundDensity(tile, CLEAR_ROCKS, 3); |
|
739 do { |
|
740 if (--j == 0) goto get_out; |
|
741 tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2)); |
|
742 } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT)); |
|
743 tile = tile_new; |
|
744 } |
|
745 get_out:; |
|
746 } |
|
747 } while (--i); |
|
748 } |
|
749 |
|
750 static void ClickTile_Clear(TileIndex tile) |
|
751 { |
|
752 /* not used */ |
|
753 } |
|
754 |
|
755 static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode) |
|
756 { |
|
757 return 0; |
|
758 } |
|
759 |
|
760 static const StringID _clear_land_str[] = { |
|
761 STR_080D_GRASS, |
|
762 STR_080B_ROUGH_LAND, |
|
763 STR_080A_ROCKS, |
|
764 STR_080E_FIELDS, |
|
765 STR_080F_SNOW_COVERED_LAND, |
|
766 STR_0810_DESERT |
|
767 }; |
|
768 |
|
769 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td) |
|
770 { |
|
771 if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) { |
|
772 td->str = STR_080C_BARE_LAND; |
|
773 } else { |
|
774 td->str = _clear_land_str[GetClearGround(tile)]; |
|
775 } |
|
776 td->owner = GetTileOwner(tile); |
|
777 } |
|
778 |
|
779 static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player) |
|
780 { |
|
781 return; |
|
782 } |
|
783 |
|
784 void InitializeClearLand(void) |
|
785 { |
|
786 _opt.snow_line = _patches.snow_line_height * TILE_HEIGHT; |
|
787 } |
|
788 |
|
789 const TileTypeProcs _tile_type_clear_procs = { |
|
790 DrawTile_Clear, /* draw_tile_proc */ |
|
791 GetSlopeZ_Clear, /* get_slope_z_proc */ |
|
792 ClearTile_Clear, /* clear_tile_proc */ |
|
793 GetAcceptedCargo_Clear, /* get_accepted_cargo_proc */ |
|
794 GetTileDesc_Clear, /* get_tile_desc_proc */ |
|
795 GetTileTrackStatus_Clear, /* get_tile_track_status_proc */ |
|
796 ClickTile_Clear, /* click_tile_proc */ |
|
797 AnimateTile_Clear, /* animate_tile_proc */ |
|
798 TileLoop_Clear, /* tile_loop_clear */ |
|
799 ChangeTileOwner_Clear, /* change_tile_owner_clear */ |
|
800 NULL, /* get_produced_cargo_proc */ |
|
801 NULL, /* vehicle_enter_tile_proc */ |
|
802 GetSlopeTileh_Clear, /* get_slope_tileh_proc */ |
|
803 }; |