2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 /** @file road.cpp Generic road related functions. */
13 #include "water_map.h"
15 #include "company_func.h"
16 #include "company_base.h"
17 #include "engine_base.h"
18 #include "date_func.h"
19 #include "landscape.h"
21 #include "road_func.h"
24 #include "safeguards.h"
27 * Return if the tile is a valid tile for a crossing.
29 * @param tile the current tile
30 * @param ax the axis of the road over the rail
31 * @return true if it is a valid tile
33 static bool IsPossibleCrossing(const TileIndex tile
, Axis ax
)
35 return (IsTileType(tile
, MP_RAILWAY
) &&
36 GetRailTileType(tile
) == RAIL_TILE_NORMAL
&&
37 GetTrackBits(tile
) == (ax
== AXIS_X
? TRACK_BIT_Y
: TRACK_BIT_X
) &&
38 GetFoundationSlope(tile
) == SLOPE_FLAT
);
42 * Clean up unnecessary RoadBits of a planned tile.
43 * @param tile current tile
44 * @param org_rb planned RoadBits
45 * @return optimised RoadBits
47 RoadBits
CleanUpRoadBits(const TileIndex tile
, RoadBits org_rb
)
49 if (!IsValidTile(tile
)) return ROAD_NONE
;
50 for (DiagDirection dir
= DIAGDIR_BEGIN
; dir
< DIAGDIR_END
; dir
++) {
51 const TileIndex neighbor_tile
= TileAddByDiagDir(tile
, dir
);
53 /* Get the Roadbit pointing to the neighbor_tile */
54 const RoadBits target_rb
= DiagDirToRoadBits(dir
);
56 /* If the roadbit is in the current plan */
57 if (org_rb
& target_rb
) {
58 bool connective
= false;
59 const RoadBits mirrored_rb
= MirrorRoadBits(target_rb
);
61 if (IsValidTile(neighbor_tile
)) {
62 switch (GetTileType(neighbor_tile
)) {
63 /* Always connective ones */
64 case MP_CLEAR
: case MP_TREES
:
68 /* The conditionally connective ones */
72 if (IsNormalRoadTile(neighbor_tile
)) {
73 /* Always connective */
76 const RoadBits neighbor_rb
= GetAnyRoadBits(neighbor_tile
, RTT_ROAD
) | GetAnyRoadBits(neighbor_tile
, RTT_TRAM
);
78 /* Accept only connective tiles */
79 connective
= (neighbor_rb
& mirrored_rb
) != ROAD_NONE
;
84 connective
= IsPossibleCrossing(neighbor_tile
, DiagDirToAxis(dir
));
88 /* Check for real water tile */
89 connective
= !IsWater(neighbor_tile
);
92 /* The definitely not connective ones */
97 /* If the neighbor tile is inconnective, remove the planned road connection to it */
98 if (!connective
) org_rb
^= target_rb
;
106 * Finds out, whether given company has a given RoadType available for construction.
107 * @param company ID of company
108 * @param roadtypet RoadType to test
109 * @return true if company has the requested RoadType available
111 bool HasRoadTypeAvail(const CompanyID company
, RoadType roadtype
)
113 if (company
== OWNER_DEITY
|| company
== OWNER_TOWN
|| _game_mode
== GM_EDITOR
|| _generating_world
) {
114 return true; // TODO: should there be a proper check?
116 const Company
*c
= Company::GetIfValid(company
);
117 if (c
== nullptr) return false;
118 return HasBit(c
->avail_roadtypes
& ~_roadtypes_hidden_mask
, roadtype
);
122 static RoadTypes
GetMaskForRoadTramType(RoadTramType rtt
)
124 return rtt
== RTT_TRAM
? _roadtypes_type
: ~_roadtypes_type
;
128 * Test if any buildable RoadType is available for a company.
129 * @param company the company in question
130 * @return true if company has any RoadTypes available
132 bool HasAnyRoadTypesAvail(CompanyID company
, RoadTramType rtt
)
134 return (Company::Get(company
)->avail_roadtypes
& ~_roadtypes_hidden_mask
& GetMaskForRoadTramType(rtt
)) != ROADTYPES_NONE
;
138 * Validate functions for rail building.
139 * @param roadtype road type to check.
140 * @return true if the current company may build the road.
142 bool ValParamRoadType(RoadType roadtype
)
144 return roadtype
!= INVALID_ROADTYPE
&& HasRoadTypeAvail(_current_company
, roadtype
);
148 * Add the road types that are to be introduced at the given date.
150 * @param current The currently available roadtypes.
151 * @param date The date for the introduction comparisons.
152 * @return The road types that should be available when date
153 * introduced road types are taken into account as well.
155 RoadTypes
AddDateIntroducedRoadTypes(RoadTypes current
, Date date
)
157 RoadTypes rts
= current
;
159 for (RoadType rt
= ROADTYPE_BEGIN
; rt
!= ROADTYPE_END
; rt
++) {
160 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
161 /* Unused road type. */
162 if (rti
->label
== 0) continue;
164 /* Not date introduced. */
165 if (!IsInsideMM(rti
->introduction_date
, 0, MAX_DAY
)) continue;
167 /* Not yet introduced at this date. */
168 if (rti
->introduction_date
> date
) continue;
170 /* Have we introduced all required roadtypes? */
171 RoadTypes required
= rti
->introduction_required_roadtypes
;
172 if ((rts
& required
) != required
) continue;
174 rts
|= rti
->introduces_roadtypes
;
177 /* When we added roadtypes we need to run this method again; the added
178 * roadtypes might enable more rail types to become introduced. */
179 return rts
== current
? rts
: AddDateIntroducedRoadTypes(rts
, date
);
183 * Get the road types the given company can build.
184 * @param company the company to get the road types for.
185 * @param introduces If true, include road types introduced by other road types
186 * @return the road types.
188 RoadTypes
GetCompanyRoadTypes(CompanyID company
, bool introduces
)
190 RoadTypes rts
= ROADTYPES_NONE
;
192 for (const Engine
*e
: Engine::IterateType(VEH_ROAD
)) {
193 const EngineInfo
*ei
= &e
->info
;
195 if (HasBit(ei
->climates
, _settings_game
.game_creation
.landscape
) &&
196 (HasBit(e
->company_avail
, company
) || _date
>= e
->intro_date
+ DAYS_IN_YEAR
)) {
197 const RoadVehicleInfo
*rvi
= &e
->u
.road
;
198 assert(rvi
->roadtype
< ROADTYPE_END
);
200 rts
|= GetRoadTypeInfo(rvi
->roadtype
)->introduces_roadtypes
;
202 SetBit(rts
, rvi
->roadtype
);
207 if (introduces
) return AddDateIntroducedRoadTypes(rts
, _date
);
212 * Get list of road types, regardless of company availability.
213 * @param introduces If true, include road types introduced by other road types
214 * @return the road types.
216 RoadTypes
GetRoadTypes(bool introduces
)
218 RoadTypes rts
= ROADTYPES_NONE
;
220 for (const Engine
*e
: Engine::IterateType(VEH_ROAD
)) {
221 const EngineInfo
*ei
= &e
->info
;
222 if (!HasBit(ei
->climates
, _settings_game
.game_creation
.landscape
)) continue;
224 const RoadVehicleInfo
*rvi
= &e
->u
.road
;
225 assert(rvi
->roadtype
< ROADTYPE_END
);
227 rts
|= GetRoadTypeInfo(rvi
->roadtype
)->introduces_roadtypes
;
229 SetBit(rts
, rvi
->roadtype
);
233 if (introduces
) return AddDateIntroducedRoadTypes(rts
, MAX_DAY
);
238 * Get the road type for a given label.
239 * @param label the roadtype label.
240 * @param allow_alternate_labels Search in the alternate label lists as well.
241 * @return the roadtype.
243 RoadType
GetRoadTypeByLabel(RoadTypeLabel label
, bool allow_alternate_labels
)
245 /* Loop through each road type until the label is found */
246 for (RoadType r
= ROADTYPE_BEGIN
; r
!= ROADTYPE_END
; r
++) {
247 const RoadTypeInfo
*rti
= GetRoadTypeInfo(r
);
248 if (rti
->label
== label
) return r
;
251 if (allow_alternate_labels
) {
252 /* Test if any road type defines the label as an alternate. */
253 for (RoadType r
= ROADTYPE_BEGIN
; r
!= ROADTYPE_END
; r
++) {
254 const RoadTypeInfo
*rti
= GetRoadTypeInfo(r
);
255 if (std::find(rti
->alternate_labels
.begin(), rti
->alternate_labels
.end(), label
) != rti
->alternate_labels
.end()) return r
;
259 /* No matching label was found, so it is invalid */
260 return INVALID_ROADTYPE
;
264 * Returns the available RoadSubTypes for the provided RoadType
265 * If the given company is valid then will be returned a list of the available sub types at the current date, while passing
266 * a deity company will make all the sub types available
267 * @param rt the RoadType to filter
268 * @param c the company ID to check the roadtype against
269 * @param any_date whether to return only currently introduced roadtypes or also future ones
270 * @returns the existing RoadSubTypes
272 RoadTypes
ExistingRoadTypes(CompanyID c
)
274 /* Check only players which can actually own vehicles, editor and gamescripts are considered deities */
276 const Company
*company
= Company::GetIfValid(c
);
277 if (company
!= nullptr) return company
->avail_roadtypes
;
280 RoadTypes known_roadtypes
= ROADTYPES_NONE
;
282 /* Find used roadtypes */
283 for (Engine
*e
: Engine::IterateType(VEH_ROAD
)) {
284 /* Check if the roadtype can be used in the current climate */
285 if (!HasBit(e
->info
.climates
, _settings_game
.game_creation
.landscape
)) continue;
287 /* Check whether available for all potential companies */
288 if (e
->company_avail
!= (CompanyMask
)-1) continue;
290 known_roadtypes
|= GetRoadTypeInfo(e
->u
.road
.roadtype
)->introduces_roadtypes
;
293 /* Get the date introduced roadtypes as well. */
294 known_roadtypes
= AddDateIntroducedRoadTypes(known_roadtypes
, MAX_DAY
);
296 return known_roadtypes
;