28 #include "water_map.h" |
28 #include "water_map.h" |
29 #include "industry_map.h" |
29 #include "industry_map.h" |
30 #include "newgrf.h" |
30 #include "newgrf.h" |
31 #include "newgrf_canal.h" |
31 #include "newgrf_canal.h" |
32 #include "misc/autoptr.hpp" |
32 #include "misc/autoptr.hpp" |
33 |
33 #include "transparency.h" |
|
34 |
|
35 /** Array for the shore sprites */ |
34 static const SpriteID _water_shore_sprites[] = { |
36 static const SpriteID _water_shore_sprites[] = { |
35 0, |
37 0, |
36 SPR_SHORE_TILEH_1, |
38 SPR_SHORE_TILEH_1, // SLOPE_W |
37 SPR_SHORE_TILEH_2, |
39 SPR_SHORE_TILEH_2, // SLOPE_S |
38 SPR_SHORE_TILEH_3, |
40 SPR_SHORE_TILEH_3, // SLOPE_SW |
39 SPR_SHORE_TILEH_4, |
41 SPR_SHORE_TILEH_4, // SLOPE_E |
40 0, |
42 0, |
41 SPR_SHORE_TILEH_6, |
43 SPR_SHORE_TILEH_6, // SLOPE_SE |
42 0, |
44 0, |
43 SPR_SHORE_TILEH_8, |
45 SPR_SHORE_TILEH_8, // SLOPE_N |
44 SPR_SHORE_TILEH_9, |
46 SPR_SHORE_TILEH_9, // SLOPE_NW |
45 0, |
47 0, |
46 0, |
48 0, |
47 SPR_SHORE_TILEH_12, |
49 SPR_SHORE_TILEH_12, // SLOPE_NE |
48 0, |
50 0, |
49 0 |
51 0 |
50 }; |
52 }; |
51 |
53 |
52 |
54 |
53 static Vehicle *FindFloodableVehicleOnTile(TileIndex tile); |
55 static Vehicle *FindFloodableVehicleOnTile(TileIndex tile); |
54 static void FloodVehicle(Vehicle *v); |
56 static void FloodVehicle(Vehicle *v); |
|
57 |
|
58 /** |
|
59 * Makes a tile canal or water depending on the surroundings. |
|
60 * This as for example docks and shipdepots do not store |
|
61 * whether the tile used to be canal or 'normal' water. |
|
62 * @param t the tile to change. |
|
63 * @param o the owner of the new tile. |
|
64 */ |
|
65 void MakeWaterOrCanalDependingOnSurroundings(TileIndex t, Owner o) |
|
66 { |
|
67 assert(GetTileSlope(t, NULL) == SLOPE_FLAT); |
|
68 |
|
69 /* Non-sealevel -> canal */ |
|
70 if (TileHeight(t) != 0) { |
|
71 MakeCanal(t, o); |
|
72 return; |
|
73 } |
|
74 |
|
75 bool has_water = false; |
|
76 bool has_canal = false; |
|
77 |
|
78 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { |
|
79 TileIndex neighbour = TileAddByDiagDir(t, dir); |
|
80 if (IsTileType(neighbour, MP_WATER)) { |
|
81 has_water |= IsSea(neighbour) || IsCoast(neighbour); |
|
82 has_canal |= IsCanal(neighbour); |
|
83 } |
|
84 } |
|
85 if (has_canal || !has_water) { |
|
86 MakeCanal(t, o); |
|
87 } else { |
|
88 MakeWater(t); |
|
89 } |
|
90 MarkTileDirtyByTile(t); |
|
91 } |
|
92 |
55 |
93 |
56 /** Build a ship depot. |
94 /** Build a ship depot. |
57 * @param tile tile where ship depot is built |
95 * @param tile tile where ship depot is built |
58 * @param flags type of operation |
96 * @param flags type of operation |
59 * @param p1 bit 0 depot orientation (Axis) |
97 * @param p1 bit 0 depot orientation (Axis) |
261 if (GetTileSlope(tile, NULL) != SLOPE_FLAT) { |
299 if (GetTileSlope(tile, NULL) != SLOPE_FLAT) { |
262 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
300 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
263 } |
301 } |
264 |
302 |
265 /* can't make water of water! */ |
303 /* can't make water of water! */ |
266 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) continue; |
304 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HasBit(p2, 0))) continue; |
267 |
305 |
268 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
306 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
269 if (CmdFailed(ret)) return ret; |
307 if (CmdFailed(ret)) return ret; |
270 cost.AddCost(ret); |
308 cost.AddCost(ret); |
271 |
309 |
272 if (flags & DC_EXEC) { |
310 if (flags & DC_EXEC) { |
273 if (TileHeight(tile) == 0 && HASBIT(p2, 0)) { |
311 if (TileHeight(tile) == 0 && HasBit(p2, 0)) { |
274 MakeWater(tile); |
312 MakeWater(tile); |
275 } else { |
313 } else { |
276 MakeCanal(tile, _current_player); |
314 MakeCanal(tile, _current_player); |
277 } |
315 } |
278 MarkTileDirtyByTile(tile); |
316 MarkTileDirtyByTile(tile); |
294 switch (GetWaterTileType(tile)) { |
332 switch (GetWaterTileType(tile)) { |
295 case WATER_TILE_CLEAR: |
333 case WATER_TILE_CLEAR: |
296 if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); |
334 if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); |
297 |
335 |
298 /* Make sure it's not an edge tile. */ |
336 /* Make sure it's not an edge tile. */ |
299 if (!IS_INT_INSIDE(TileX(tile), 1, MapMaxX() - 1) || |
337 if (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) || |
300 !IS_INT_INSIDE(TileY(tile), 1, MapMaxY() - 1)) { |
338 !IsInsideMM(TileY(tile), 1, MapMaxY() - 1)) { |
301 return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP); |
339 return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP); |
302 } |
340 } |
303 |
341 |
304 /* Make sure no vehicle is on the tile */ |
342 /* Make sure no vehicle is on the tile */ |
305 if (!EnsureNoVehicle(tile)) return CMD_ERROR; |
343 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; |
306 |
344 |
307 if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR; |
345 if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR; |
308 |
346 |
309 if (flags & DC_EXEC) DoClearSquare(tile); |
347 if (flags & DC_EXEC) DoClearSquare(tile); |
310 return CommandCost(_price.clear_water); |
348 return CommandCost(_price.clear_water); |
311 |
349 |
312 case WATER_TILE_COAST: { |
350 case WATER_TILE_COAST: { |
313 Slope slope = GetTileSlope(tile, NULL); |
351 Slope slope = GetTileSlope(tile, NULL); |
314 |
352 |
315 /* Make sure no vehicle is on the tile */ |
353 /* Make sure no vehicle is on the tile */ |
316 if (!EnsureNoVehicle(tile)) return CMD_ERROR; |
354 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; |
317 |
355 |
318 if (flags & DC_EXEC) DoClearSquare(tile); |
356 if (flags & DC_EXEC) DoClearSquare(tile); |
319 if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) { |
357 if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) { |
320 return CommandCost(_price.clear_water); |
358 return CommandCost(_price.clear_water); |
321 } else { |
359 } else { |
322 return CommandCost(_price.purchase_land); |
360 return CommandCost(_price.clear_roughland); |
323 } |
361 } |
324 } |
362 } |
325 |
363 |
326 case WATER_TILE_LOCK: { |
364 case WATER_TILE_LOCK: { |
327 static const TileIndexDiffC _shiplift_tomiddle_offs[] = { |
365 static const TileIndexDiffC _shiplift_tomiddle_offs[] = { |
446 for (; wdts->delta_x != 0x80; wdts++) { |
484 for (; wdts->delta_x != 0x80; wdts++) { |
447 AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette, |
485 AddSortableSpriteToDraw(wdts->image + base + ((wdts->image < 24) ? locks_base : 0), palette, |
448 ti->x + wdts->delta_x, ti->y + wdts->delta_y, |
486 ti->x + wdts->delta_x, ti->y + wdts->delta_y, |
449 wdts->width, wdts->height, |
487 wdts->width, wdts->height, |
450 wdts->unk, ti->z + wdts->delta_z, |
488 wdts->unk, ti->z + wdts->delta_z, |
451 HASBIT(_transparent_opt, TO_BUILDINGS)); |
489 IsTransparencySet(TO_BUILDINGS)); |
452 } |
490 } |
453 } |
491 } |
454 |
492 |
455 static void DrawTile_Water(TileInfo *ti) |
493 static void DrawTile_Water(TileInfo *ti) |
456 { |
494 { |
457 switch (GetWaterTileType(ti->tile)) { |
495 switch (GetWaterTileType(ti->tile)) { |
458 case WATER_TILE_CLEAR: |
496 case WATER_TILE_CLEAR: |
459 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); |
497 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); |
460 if (ti->z != 0 || !IsTileOwner(ti->tile, OWNER_WATER)) DrawCanalWater(ti->tile); |
498 if (IsCanal(ti->tile)) DrawCanalWater(ti->tile); |
461 DrawBridgeMiddle(ti); |
499 DrawBridgeMiddle(ti); |
462 break; |
500 break; |
463 |
501 |
464 case WATER_TILE_COAST: |
502 case WATER_TILE_COAST: |
465 assert(!IsSteepSlope(ti->tileh)); |
503 assert(!IsSteepSlope(ti->tileh)); |
466 if (_coast_base != 0) { |
504 if (_loaded_newgrf_features.has_newwater) { |
467 DrawGroundSprite(_coast_base + ti->tileh, PAL_NONE); |
505 DrawGroundSprite(_coast_base + ti->tileh, PAL_NONE); |
468 } else { |
506 } else { |
469 DrawGroundSprite(_water_shore_sprites[ti->tileh], PAL_NONE); |
507 DrawGroundSprite(_water_shore_sprites[ti->tileh], PAL_NONE); |
470 } |
508 } |
471 DrawBridgeMiddle(ti); |
509 DrawBridgeMiddle(ti); |
535 static void AnimateTile_Water(TileIndex tile) |
573 static void AnimateTile_Water(TileIndex tile) |
536 { |
574 { |
537 /* not used */ |
575 /* not used */ |
538 } |
576 } |
539 |
577 |
|
578 /** |
|
579 * Floods neighboured floodable tiles |
|
580 * |
|
581 * @param tile The water source tile that causes the flooding. |
|
582 * @param offs[0] Destination tile to flood. |
|
583 * @param offs[1] First corner of edge between source and dest tile. |
|
584 * @param offs[2] Second corder of edge between source and dest tile. |
|
585 * @param offs[3] Third corner of dest tile. |
|
586 * @param offs[4] Fourth corner of dest tile. |
|
587 */ |
540 static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) |
588 static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) |
541 { |
589 { |
542 TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0])); |
590 TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0])); |
543 |
591 |
544 /* type of this tile mustn't be water already. */ |
592 /* type of this tile mustn't be water already. */ |
545 if (IsTileType(target, MP_WATER)) return; |
593 if (IsTileType(target, MP_WATER)) return; |
546 |
594 |
547 /* Ensure sea-level FSMports do not flood */ |
595 /* Ensure sea-level FSMports do not flood */ |
548 if ((IsTileType(target, MP_STATION))) |
596 if (IsTileType(target, MP_STATION) && GetStationByTile(target)->FSMport_flood_protected) return; |
549 { |
597 |
550 if (GetStationByTile(target)->FSMport_flood_protected) return; |
598 /* Are both corners of the edge between source and dest on height 0 ? */ |
551 } |
|
552 |
|
553 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 || |
599 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 || |
554 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) { |
600 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) { |
555 return; |
601 return; |
556 } |
602 } |
557 |
603 |
|
604 /* Is any corner of the dest tile raised? (First two corners already checked above. */ |
558 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 || |
605 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 || |
559 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) { |
606 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) { |
560 /* make coast.. */ |
607 /* make coast.. */ |
561 switch (GetTileType(target)) { |
608 switch (GetTileType(target)) { |
562 case MP_RAILWAY: { |
609 case MP_RAILWAY: { |
563 TrackBits tracks; |
|
564 Slope slope; |
|
565 |
|
566 if (!IsPlainRailTile(target)) break; |
610 if (!IsPlainRailTile(target)) break; |
567 |
611 |
568 tracks = GetTrackBits(target); |
612 FloodHalftile(target); |
569 slope = GetTileSlope(target, NULL); |
|
570 if (!( |
|
571 (slope == SLOPE_W && tracks == TRACK_BIT_RIGHT) || |
|
572 (slope == SLOPE_S && tracks == TRACK_BIT_UPPER) || |
|
573 (slope == SLOPE_E && tracks == TRACK_BIT_LEFT) || |
|
574 (slope == SLOPE_N && tracks == TRACK_BIT_LOWER) |
|
575 )) { |
|
576 break; |
|
577 } |
|
578 |
613 |
579 Vehicle *v = FindFloodableVehicleOnTile(target); |
614 Vehicle *v = FindFloodableVehicleOnTile(target); |
580 if (v != NULL) FloodVehicle(v); |
615 if (v != NULL) FloodVehicle(v); |
581 } |
616 |
582 /* FALLTHROUGH */ |
617 break; |
|
618 } |
583 |
619 |
584 case MP_CLEAR: |
620 case MP_CLEAR: |
585 case MP_TREES: |
621 case MP_TREES: |
586 _current_player = OWNER_WATER; |
622 _current_player = OWNER_WATER; |
587 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
623 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
716 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); |
754 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); |
717 SndPlayVehicleFx(SND_12_EXPLOSION, v); |
755 SndPlayVehicleFx(SND_12_EXPLOSION, v); |
718 } |
756 } |
719 } |
757 } |
720 |
758 |
721 /** called from tunnelbridge_cmd, and by TileLoop_Industry() */ |
759 /** |
|
760 * Let a water tile floods its diagonal adjoining tiles |
|
761 * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track() |
|
762 * |
|
763 * @param tile the water/shore tile that floods |
|
764 */ |
722 void TileLoop_Water(TileIndex tile) |
765 void TileLoop_Water(TileIndex tile) |
723 { |
766 { |
724 static const TileIndexDiffC _tile_loop_offs_array[][5] = { |
767 static const TileIndexDiffC _tile_loop_offs_array[][5] = { |
725 // tile to mod shore? shore? |
768 // tile to mod shore? shore? |
726 {{-1, 0}, {0, 0}, {0, 1}, {-1, 0}, {-1, 1}}, |
769 {{-1, 0}, {0, 0}, {0, 1}, {-1, 0}, {-1, 1}}, |
727 {{ 0, 1}, {0, 1}, {1, 1}, { 0, 2}, { 1, 2}}, |
770 {{ 0, 1}, {0, 1}, {1, 1}, { 0, 2}, { 1, 2}}, |
728 {{ 1, 0}, {1, 0}, {1, 1}, { 2, 0}, { 2, 1}}, |
771 {{ 1, 0}, {1, 0}, {1, 1}, { 2, 0}, { 2, 1}}, |
729 {{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}} |
772 {{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}} |
730 }; |
773 }; |
731 |
774 |
732 /* Ensure sea-level canals and buoys on canal borders do not flood */ |
775 /* Ensure buoys on canal borders do not flood */ |
733 if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && !IsTileOwner(tile, OWNER_WATER)) return; |
776 if (IsCanalBuoyTile(tile)) return; |
734 |
777 /* Ensure only sea and coast floods, not canals or rivers */ |
735 if (IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1) && |
778 if (IsTileType(tile, MP_WATER) && !(IsSea(tile) || IsCoast(tile))) return; |
736 IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { |
779 |
|
780 /* floods in all four diagonal directions with the exception of the edges */ |
|
781 if (IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1) && |
|
782 IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { |
737 uint i; |
783 uint i; |
738 |
784 |
739 for (i = 0; i != lengthof(_tile_loop_offs_array); i++) { |
785 for (i = 0; i != lengthof(_tile_loop_offs_array); i++) { |
740 TileLoopWaterHelper(tile, _tile_loop_offs_array[i]); |
786 TileLoopWaterHelper(tile, _tile_loop_offs_array[i]); |
741 } |
787 } |
742 } |
788 } |
|
789 |
743 /* _current_player can be changed by TileLoopWaterHelper.. reset it back here */ |
790 /* _current_player can be changed by TileLoopWaterHelper.. reset it back here */ |
744 _current_player = OWNER_NONE; |
791 _current_player = OWNER_NONE; |
745 |
792 |
746 /* edges */ |
793 /* edges */ |
747 if (TileX(tile) == 0 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE |
794 if (TileX(tile) == 0 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE |
748 TileLoopWaterHelper(tile, _tile_loop_offs_array[2]); |
795 TileLoopWaterHelper(tile, _tile_loop_offs_array[2]); |
749 } |
796 } |
750 |
797 |
751 if (TileX(tile) == MapSizeX() - 2 && IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW |
798 if (TileX(tile) == MapSizeX() - 2 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW |
752 TileLoopWaterHelper(tile, _tile_loop_offs_array[0]); |
799 TileLoopWaterHelper(tile, _tile_loop_offs_array[0]); |
753 } |
800 } |
754 |
801 |
755 if (TileY(tile) == 0 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW |
802 if (TileY(tile) == 0 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW |
756 TileLoopWaterHelper(tile, _tile_loop_offs_array[1]); |
803 TileLoopWaterHelper(tile, _tile_loop_offs_array[1]); |
757 } |
804 } |
758 |
805 |
759 if (TileY(tile) == MapSizeY() - 2 && IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE |
806 if (TileY(tile) == MapSizeY() - 2 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE |
760 TileLoopWaterHelper(tile, _tile_loop_offs_array[3]); |
807 TileLoopWaterHelper(tile, _tile_loop_offs_array[3]); |
761 } |
808 } |
762 } |
809 } |
763 |
810 |
764 static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode) |
811 static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode) |