Mercurial > hg > openttd
comparison src/town_cmd.cpp @ 6571:6777295c2328 draft
(svn r9779) -Feature: Add the possiblity to choose different road patterns for towns to use.
Possible patterns are :
No Road (not available in scenario editor)
Original (for the nostalgics)
Better Roads (same as original, but based on distance of 2 tiles instead of one)
2x2 grids
3x3 grids
Patch by skiddl13
author | belugas <belugas@openttd.org> |
---|---|
date | Fri, 04 May 2007 16:27:13 +0000 |
parents | 838badc858d3 |
children | c3aef1e6e3e1 |
comparison
equal
deleted
inserted
replaced
6570:eacaf5f73afd | 6571:6777295c2328 |
---|---|
553 { 0, -1}, | 553 { 0, -1}, |
554 { 1, 0}, | 554 { 1, 0}, |
555 { 0, 1} | 555 { 0, 1} |
556 }; | 556 }; |
557 | 557 |
558 /** | |
559 * Distance multiplyer | |
560 * Defines the possible distances between 2 road tiles | |
561 */ | |
562 enum RoadBlockTitleDistance { | |
563 RB_TILE_DIST1 = 1, ///< 1 tile between | |
564 RB_TILE_DIST2, ///< 2 tiles between | |
565 }; | |
558 | 566 |
559 static bool GrowTown(Town *t); | 567 static bool GrowTown(Town *t); |
560 | 568 |
561 static void TownTickHandler(Town *t) | 569 static void TownTickHandler(Town *t) |
562 { | 570 { |
603 if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW; | 611 if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW; |
604 if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW; | 612 if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW; |
605 if (b & TRACK_BIT_LEFT) r |= ROAD_NW | ROAD_SW; | 613 if (b & TRACK_BIT_LEFT) r |= ROAD_NW | ROAD_SW; |
606 if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE; | 614 if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE; |
607 return r; | 615 return r; |
616 } | |
617 | |
618 /** | |
619 * Check if a neighboring tile has a road | |
620 * | |
621 * @param tile curent tile | |
622 * @param dir target direction | |
623 * @param dist_multi distance multiplyer | |
624 * @return true if one of the neighboring tiles at the | |
625 * given distance is a road tile else | |
626 */ | |
627 static bool NeighborIsRoadTile(TileIndex tile, int dir, RoadBlockTitleDistance dist_multi) | |
628 { | |
629 return (HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * ToTileIndexDiff(_roadblock_tileadd[dir + 1]))), dir ^ 2) || | |
630 HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * ToTileIndexDiff(_roadblock_tileadd[dir + 3]))), dir ^ 2) || | |
631 HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * (ToTileIndexDiff(_roadblock_tileadd[dir + 1]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2])))), dir) || | |
632 HASBIT(GetTownRoadMask(TILE_ADD(tile, dist_multi * (ToTileIndexDiff(_roadblock_tileadd[dir + 3]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2])))), dir)); | |
608 } | 633 } |
609 | 634 |
610 static bool IsRoadAllowedHere(TileIndex tile, int dir) | 635 static bool IsRoadAllowedHere(TileIndex tile, int dir) |
611 { | 636 { |
612 Slope k; | 637 Slope k; |
628 } | 653 } |
629 | 654 |
630 slope = GetTileSlope(tile, NULL); | 655 slope = GetTileSlope(tile, NULL); |
631 if (slope == SLOPE_FLAT) { | 656 if (slope == SLOPE_FLAT) { |
632 no_slope: | 657 no_slope: |
633 /* Tile has no slope | 658 /* Tile has no slope */ |
634 * Disallow the road if any neighboring tile has a road. */ | 659 switch (_patches.town_layout) { |
635 if (HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 1]))), dir ^ 2) || | 660 default: NOT_REACHED(); |
636 HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 3]))), dir ^ 2) || | 661 |
637 HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 1]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2]))), dir) || | 662 case TL_ORIGINAL: /* Disallow the road if any neighboring tile has a road (distance: 1) */ |
638 HASBIT(GetTownRoadMask(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[dir + 3]) + ToTileIndexDiff(_roadblock_tileadd[dir + 2]))), dir)) | 663 return !NeighborIsRoadTile(tile, dir, RB_TILE_DIST1); |
639 return false; | 664 |
640 | 665 case TL_BETTER_ROADS: /* Disallow the road if any neighboring tile has a road (distance: 1 and 2). */ |
641 /* Otherwise allow */ | 666 return !(NeighborIsRoadTile(tile, dir, RB_TILE_DIST1) || |
642 return true; | 667 NeighborIsRoadTile(tile, dir, RB_TILE_DIST2)); |
668 } | |
643 } | 669 } |
644 | 670 |
645 /* If the tile is not a slope in the right direction, then | 671 /* If the tile is not a slope in the right direction, then |
646 * maybe terraform some. */ | 672 * maybe terraform some. */ |
647 k = (dir & 1) ? SLOPE_NE : SLOPE_NW; | 673 k = (dir & 1) ? SLOPE_NE : SLOPE_NW; |
696 if (!TerraformTownTile(tile, ~tileh & 0xF, 1)) { | 722 if (!TerraformTownTile(tile, ~tileh & 0xF, 1)) { |
697 TerraformTownTile(tile, tileh & 0xF, 0); | 723 TerraformTownTile(tile, tileh & 0xF, 0); |
698 } | 724 } |
699 } | 725 } |
700 | 726 |
727 /** | |
728 * Generate the RoadBits of a grid tile | |
729 * | |
730 * @param t current town | |
731 * @param tile tile in reference to the town | |
732 * @return the RoadBit of the current tile regarding | |
733 * the selected town layout | |
734 */ | |
735 static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile) | |
736 { | |
737 /* align the grid to the downtown */ | |
738 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); ///< Vector from downtown to the tile | |
739 | |
740 /* lx, ly description: | |
741 * @li lx and ly are true if the tile is a crossing tile. | |
742 * @li lx xor ly are true if the tile is a straight road tile. | |
743 * @li lx and ly are false if the tile is a house tile. | |
744 */ | |
745 bool lx, ly; | |
746 | |
747 switch (_patches.town_layout) { | |
748 default: NOT_REACHED(); | |
749 | |
750 case TL_2X2_GRID: | |
751 lx = ((grid_pos.x % 3) == 0); | |
752 ly = ((grid_pos.y % 3) == 0); | |
753 break; | |
754 | |
755 case TL_3X3_GRID: | |
756 lx = ((grid_pos.x % 4) == 0); | |
757 ly = ((grid_pos.y % 4) == 0); | |
758 break; | |
759 } | |
760 | |
761 /* generate the basic grid structure */ | |
762 if (!lx && !ly) { ///< It is a house tile | |
763 return ROAD_NONE; | |
764 } else if (lx && !ly) { ///< It is a Y-dir road tile | |
765 return ROAD_Y; | |
766 } else if (!lx && ly) { ///< It is a X-dir road tile | |
767 return ROAD_X; | |
768 } else { ///< It is a crossing tile | |
769 /* Presets for junctions on slopes | |
770 * not nice :( */ | |
771 switch (GetTileSlope(tile, NULL)) { | |
772 case SLOPE_W: | |
773 return ROAD_NW | ROAD_SW; | |
774 case SLOPE_S: | |
775 return ROAD_SE | ROAD_SW; | |
776 case SLOPE_SW: | |
777 return ROAD_Y | ROAD_SW; | |
778 case SLOPE_E: | |
779 return ROAD_NE | ROAD_SE; | |
780 case SLOPE_SE: | |
781 return ROAD_X | ROAD_SE; | |
782 case SLOPE_N: | |
783 return ROAD_NW | ROAD_NE; | |
784 case SLOPE_NW: | |
785 return ROAD_X | ROAD_NW; | |
786 case SLOPE_NE: | |
787 return ROAD_Y | ROAD_NE; | |
788 case SLOPE_STEEP_W: | |
789 case SLOPE_STEEP_N: | |
790 return ROAD_X; | |
791 case SLOPE_STEEP_S: | |
792 case SLOPE_STEEP_E: | |
793 return ROAD_Y; | |
794 default: | |
795 return ROAD_ALL; | |
796 } | |
797 } | |
798 } | |
799 | |
800 /** | |
801 * Check there are enougth neighbor house tiles next to the current tile | |
802 * | |
803 * @param tile current tile | |
804 * @return true if there are more than 2 house tiles next | |
805 * to the current one | |
806 */ | |
807 static bool NeighborsAreHouseTiles(TileIndex tile) | |
808 { | |
809 uint counter = 0; ///< counts the house neighbor tiles | |
810 | |
811 /* We can't look further than that. */ | |
812 if (TileX(tile) < 1 || TileY(tile) < 1) { | |
813 return false; | |
814 } | |
815 | |
816 /* Check the tiles E,N,W and S of the current tile. */ | |
817 for (uint i = 0; i < 4; i++) { | |
818 if (IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i])), MP_HOUSE)) { | |
819 counter++; | |
820 } | |
821 | |
822 /* If there are enougth neighbor's stop it here */ | |
823 if (counter >= 3) { | |
824 return true; | |
825 } | |
826 } | |
827 return false; | |
828 } | |
829 | |
830 /** | |
831 * Grows the given town. | |
832 * There are at the moment 3 possible way's for | |
833 * the town expansion: | |
834 * @li Generate a random tile and check if there is a road allowed | |
835 * @li TL_ORIGINAL | |
836 * @li TL_BETTER_ROADS | |
837 * @li Check if the town geometry allows a road and which one | |
838 * @li TL_2X2_GRID | |
839 * @li TL_3X3_GRID | |
840 * @li Forbid roads, only build houses | |
841 * @li TL_NO_ROADS | |
842 * | |
843 * @param tile_ptr current tile | |
844 * @param mask current tiles RoadBits | |
845 * @param block road block | |
846 * @param t1 current town | |
847 */ | |
701 static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1) | 848 static void GrowTownInTile(TileIndex* tile_ptr, RoadBits mask, int block, Town* t1) |
702 { | 849 { |
703 RoadBits rcmd; | 850 RoadBits rcmd; |
704 TileIndex tmptile; | 851 TileIndex tmptile; |
705 DiagDirection i; | 852 DiagDirection i; |
718 | 865 |
719 /* Remove hills etc */ | 866 /* Remove hills etc */ |
720 LevelTownLand(tile); | 867 LevelTownLand(tile); |
721 | 868 |
722 /* Is a road allowed here? */ | 869 /* Is a road allowed here? */ |
723 if (!IsRoadAllowedHere(tile, block)) return; | 870 switch (_patches.town_layout) { |
724 | 871 default: NOT_REACHED(); |
725 /* Randomize new road block numbers */ | 872 |
726 a = block; | 873 case TL_NO_ROADS: /* Disallow Roads */ |
727 b = block ^ 2; | |
728 if (CHANCE16(1, 4)) { | |
729 do { | |
730 a = GB(Random(), 0, 2); | |
731 } while (a == b); | |
732 } | |
733 | |
734 if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) { | |
735 /* A road is not allowed to continue the randomized road, | |
736 * return if the road we're trying to build is curved. */ | |
737 if (a != (b ^ 2)) return; | |
738 | |
739 /* Return if neither side of the new road is a house */ | |
740 if (!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 1])), MP_HOUSE) && | |
741 !IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 3])), MP_HOUSE)) | |
742 return; | 874 return; |
743 | 875 |
744 /* That means that the road is only allowed if there is a house | 876 case TL_3X3_GRID: |
745 * at any side of the new road. */ | 877 case TL_2X2_GRID: |
746 } | 878 rcmd = GetTownRoadGridElement(t1, tile); |
747 rcmd = (RoadBits)((1 << a) + (1 << b)); | 879 if (rcmd == ROAD_NONE) { |
880 return; | |
881 } | |
882 break; | |
883 | |
884 case TL_BETTER_ROADS: | |
885 case TL_ORIGINAL: | |
886 if (!IsRoadAllowedHere(tile, block)) { | |
887 return; | |
888 } | |
889 | |
890 /* Randomize new road block numbers */ | |
891 a = block; | |
892 b = block ^ 2; | |
893 if (CHANCE16(1, 4)) { | |
894 do { | |
895 a = GB(Random(), 0, 2); | |
896 } while (a == b); | |
897 } | |
898 | |
899 if (!IsRoadAllowedHere(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a])), a)) { | |
900 /* A road is not allowed to continue the randomized road, | |
901 * return if the road we're trying to build is curved. */ | |
902 if (a != (b ^ 2)) { | |
903 return; | |
904 } | |
905 | |
906 /* Return if neither side of the new road is a house */ | |
907 if (!IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 1])), MP_HOUSE) && | |
908 !IsTileType(TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[a + 3])), MP_HOUSE)) { | |
909 return; | |
910 } | |
911 | |
912 /* That means that the road is only allowed if there is a house | |
913 * at any side of the new road. */ | |
914 } | |
915 | |
916 rcmd = (RoadBits)((1 << a) + (1 << b)); | |
917 break; | |
918 } | |
748 | 919 |
749 } else if (block < 5 && !HASBIT(mask, block ^ 2)) { | 920 } else if (block < 5 && !HASBIT(mask, block ^ 2)) { |
750 /* Continue building on a partial road. | 921 /* Continue building on a partial road. |
751 * Always OK. */ | 922 * Always OK. */ |
752 _grow_town_result = 0; | 923 _grow_town_result = 0; |
753 rcmd = (RoadBits)(1 << (block ^ 2)); | 924 |
925 switch (_patches.town_layout) { | |
926 default: NOT_REACHED(); | |
927 | |
928 case TL_NO_ROADS: /* Disallow Roads */ | |
929 return; | |
930 | |
931 case TL_3X3_GRID: | |
932 case TL_2X2_GRID: | |
933 rcmd = GetTownRoadGridElement(t1, tile); | |
934 break; | |
935 | |
936 case TL_BETTER_ROADS: | |
937 case TL_ORIGINAL: | |
938 rcmd = (RoadBits)(1 << (block ^ 2)); | |
939 break; | |
940 } | |
754 } else { | 941 } else { |
755 int i; | 942 int i; |
943 bool allow_house = false; | |
944 TileIndex tmptile2; | |
756 | 945 |
757 /* Reached a tunnel/bridge? Then continue at the other side of it. */ | 946 /* Reached a tunnel/bridge? Then continue at the other side of it. */ |
758 if (IsTileType(tile, MP_TUNNELBRIDGE)) { | 947 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
759 if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) { | 948 if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) { |
760 *tile_ptr = GetOtherTunnelEnd(tile); | 949 *tile_ptr = GetOtherTunnelEnd(tile); |
773 tmptile = TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i])); | 962 tmptile = TILE_ADD(tile, ToTileIndexDiff(_roadblock_tileadd[i])); |
774 | 963 |
775 /* Don't do it if it reaches to water. */ | 964 /* Don't do it if it reaches to water. */ |
776 if (IsClearWaterTile(tmptile)) return; | 965 if (IsClearWaterTile(tmptile)) return; |
777 | 966 |
778 /* Build a house at the edge. 60% chance or | 967 switch (_patches.town_layout) { |
779 * always ok if no road allowed. */ | 968 default: NOT_REACHED(); |
780 if (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10)) { | 969 |
781 /* But not if there already is a house there. */ | 970 case TL_NO_ROADS: |
971 allow_house = true; | |
972 break; | |
973 | |
974 case TL_3X3_GRID: /* Use 2x2 grid afterwards! */ | |
975 /* Fill gap if house has enougth neighbors */ | |
976 tmptile2 = TILE_ADD(tmptile, ToTileIndexDiff(_roadblock_tileadd[i])); | |
977 if (NeighborsAreHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) { | |
978 _grow_town_result = -1; | |
979 } | |
980 | |
981 case TL_2X2_GRID: | |
982 rcmd = GetTownRoadGridElement(t1, tmptile); | |
983 allow_house = (rcmd == ROAD_NONE); | |
984 break; | |
985 | |
986 case TL_BETTER_ROADS: /* Use original afterwards! */ | |
987 /* Fill gap if house has enougth neighbors */ | |
988 tmptile2 = TILE_ADD(tmptile, ToTileIndexDiff(_roadblock_tileadd[i])); | |
989 if (NeighborsAreHouseTiles(tmptile2) && BuildTownHouse(t1, tmptile2)) { | |
990 _grow_town_result = -1; | |
991 } | |
992 | |
993 case TL_ORIGINAL: | |
994 /* Allow a house at the edge. 60% chance or | |
995 * always ok if no road allowed. */ | |
996 allow_house = (!IsRoadAllowedHere(tmptile, i) || CHANCE16(6, 10)); | |
997 break; | |
998 } | |
999 | |
1000 | |
1001 if (allow_house) { | |
1002 /* Build a house, but not if there already is a house there. */ | |
782 if (!IsTileType(tmptile, MP_HOUSE)) { | 1003 if (!IsTileType(tmptile, MP_HOUSE)) { |
783 /* Level the land if possible */ | 1004 /* Level the land if possible */ |
784 LevelTownLand(tmptile); | 1005 LevelTownLand(tmptile); |
785 | 1006 |
786 /* And build a house. | 1007 /* And build a house. |
787 * Set result to -1 if we managed to build it. */ | 1008 * Set result to -1 if we managed to build it. */ |
788 if (BuildTownHouse(t1, tmptile)) _grow_town_result = -1; | 1009 if (BuildTownHouse(t1, tmptile)) { |
1010 _grow_town_result = -1; | |
1011 } | |
789 } | 1012 } |
790 return; | 1013 return; |
791 } | 1014 } |
792 | 1015 |
793 _grow_town_result = 0; | 1016 _grow_town_result = 0; |
809 build_road_and_exit: | 1032 build_road_and_exit: |
810 if (!CmdFailed(DoCommand(tile, rcmd, t1->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) { | 1033 if (!CmdFailed(DoCommand(tile, rcmd, t1->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) { |
811 _grow_town_result = -1; | 1034 _grow_town_result = -1; |
812 } | 1035 } |
813 return; | 1036 return; |
1037 } | |
1038 | |
1039 /* Check if the bridge is in the right direction */ | |
1040 if ((rcmd == ROAD_X && (i == DIAGDIR_NW || i == DIAGDIR_SE)) || | |
1041 (rcmd == ROAD_Y && (i == DIAGDIR_NE || i == DIAGDIR_SW))) { | |
1042 goto build_road_and_exit; | |
814 } | 1043 } |
815 | 1044 |
816 tmptile = tile; | 1045 tmptile = tile; |
817 | 1046 |
818 /* Now it contains the direction of the slope */ | 1047 /* Now it contains the direction of the slope */ |
853 { | 1082 { |
854 int block = 5; // special case | 1083 int block = 5; // special case |
855 | 1084 |
856 TILE_ASSERT(tile); | 1085 TILE_ASSERT(tile); |
857 | 1086 |
858 /* Number of times to search. */ | 1087 /* Number of times to search. |
859 _grow_town_result = 10 + t->num_houses * 4 / 9; | 1088 * Better roads, 2X2 and 3X3 grid grow quite fast so we give |
1089 * them a little handicap. */ | |
1090 switch (_patches.town_layout) { | |
1091 case TL_BETTER_ROADS: | |
1092 _grow_town_result = 10 + t->num_houses * 2 / 9; | |
1093 break; | |
1094 | |
1095 case TL_3X3_GRID: | |
1096 case TL_2X2_GRID: | |
1097 _grow_town_result = 10 + t->num_houses * 1 / 9; | |
1098 break; | |
1099 | |
1100 default: | |
1101 _grow_town_result = 10 + t->num_houses * 4 / 9; | |
1102 break; | |
1103 } | |
860 | 1104 |
861 do { | 1105 do { |
862 /* Get a bitmask of the road blocks on a tile */ | 1106 /* Get a bitmask of the road blocks on a tile */ |
863 RoadBits mask = GetTownRoadMask(tile); | 1107 RoadBits mask = GetTownRoadMask(tile); |
864 | 1108 |
927 {-2, 2}, | 1171 {-2, 2}, |
928 { 2, 2}, | 1172 { 2, 2}, |
929 { 2, -2}, | 1173 { 2, -2}, |
930 { 0, 0} | 1174 { 0, 0} |
931 }; | 1175 }; |
1176 | |
1177 /* Let the town be a ghost town | |
1178 * The player wanted it in such a way. Thus there he has it. ;) | |
1179 * Never reached in editor mode. */ | |
1180 if (_patches.town_layout == TL_NO_ROADS) { | |
1181 return false; | |
1182 } | |
932 | 1183 |
933 /* Current player is a town */ | 1184 /* Current player is a town */ |
934 old_player = _current_player; | 1185 old_player = _current_player; |
935 _current_player = OWNER_TOWN; | 1186 _current_player = OWNER_TOWN; |
936 | 1187 |