* Tries to build a house at this tile. * @param t The town the house will belong to. * @param tile The tile to try building on. * @return false iff no house can be built on this tile. */
| 2812 | * @return false iff no house can be built on this tile. |
| 2813 | */ |
| 2814 | static bool TryBuildTownHouse(Town *t, TileIndex tile, TownExpandModes modes) |
| 2815 | { |
| 2816 | /* forbidden building here by town layout */ |
| 2817 | if (!TownLayoutAllowsHouseHere(t, tile, modes)) return false; |
| 2818 | |
| 2819 | /* no house allowed at all, bail out */ |
| 2820 | if (!CanBuildHouseHere(tile, false)) return false; |
| 2821 | |
| 2822 | Slope slope = GetTileSlope(tile); |
| 2823 | int maxz = GetTileMaxZ(tile); |
| 2824 | |
| 2825 | /* Get the town zone type of the current tile, as well as the climate. |
| 2826 | * This will allow to easily compare with the specs of the new house to build */ |
| 2827 | HouseZones zones = GetTownRadiusGroup(t, tile); |
| 2828 | |
| 2829 | switch (_settings_game.game_creation.landscape) { |
| 2830 | case LandscapeType::Temperate: zones.Set(HouseZone::ClimateTemperate); break; |
| 2831 | case LandscapeType::Arctic: zones.Set(maxz > HighestSnowLine() ? HouseZone::ClimateSubarcticAboveSnow : HouseZone::ClimateSubarcticBelowSnow); break; |
| 2832 | case LandscapeType::Tropic: zones.Set(HouseZone::ClimateSubtropic); break; |
| 2833 | case LandscapeType::Toyland: zones.Set(HouseZone::ClimateToyland); break; |
| 2834 | } |
| 2835 | |
| 2836 | /* bits 0-4 are used |
| 2837 | * bits 11-15 are used |
| 2838 | * bits 5-10 are not used. */ |
| 2839 | static std::vector<std::pair<HouseID, uint>> probs; |
| 2840 | probs.clear(); |
| 2841 | |
| 2842 | uint probability_max = 0; |
| 2843 | |
| 2844 | /* Generate a list of all possible houses that can be built. */ |
| 2845 | for (const auto &hs : HouseSpec::Specs()) { |
| 2846 | /* Verify that the candidate house spec matches the current tile status */ |
| 2847 | if (!hs.building_availability.All(zones) || !hs.enabled || hs.grf_prop.override_id != INVALID_HOUSE_ID) continue; |
| 2848 | |
| 2849 | /* Don't let these counters overflow. Global counters are 32bit, there will never be that many houses. */ |
| 2850 | if (hs.class_id != HOUSE_NO_CLASS) { |
| 2851 | /* id_count is always <= class_count, so it doesn't need to be checked */ |
| 2852 | if (t->cache.building_counts.class_count[hs.class_id] == UINT16_MAX) continue; |
| 2853 | } else { |
| 2854 | /* If the house has no class, check id_count instead */ |
| 2855 | if (t->cache.building_counts.id_count[hs.Index()] == UINT16_MAX) continue; |
| 2856 | } |
| 2857 | |
| 2858 | uint cur_prob = hs.probability; |
| 2859 | probability_max += cur_prob; |
| 2860 | probs.emplace_back(hs.Index(), cur_prob); |
| 2861 | } |
| 2862 | |
| 2863 | TileIndex base_tile = tile; |
| 2864 | |
| 2865 | while (probability_max > 0) { |
| 2866 | /* Building a multitile building can change the location of tile. |
| 2867 | * The building would still be built partially on that tile, but |
| 2868 | * its northern tile would be elsewhere. However, if the callback |
| 2869 | * fails we would be basing further work from the changed tile. |
| 2870 | * So a next 1x1 tile building could be built on the wrong tile. */ |
| 2871 | tile = base_tile; |
no test coverage detected