Fix: Don't allow right-click to close world generation progress window. (#13084)
[openttd-github.git] / src / road.cpp
blobf66bedfd654a94455ebbe1faed6fd60d4a8c70ed
1 /*
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/>.
6 */
8 /** @file road.cpp Generic road related functions. */
10 #include "stdafx.h"
11 #include "rail_map.h"
12 #include "road_map.h"
13 #include "water_map.h"
14 #include "genworld.h"
15 #include "company_func.h"
16 #include "company_base.h"
17 #include "engine_base.h"
18 #include "timer/timer_game_calendar.h"
19 #include "landscape.h"
20 #include "road.h"
21 #include "road_func.h"
22 #include "roadveh.h"
24 #include "safeguards.h"
26 /**
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 std::get<0>(GetFoundationSlope(tile)) == SLOPE_FLAT);
41 /**
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:
65 connective = true;
66 break;
68 /* The conditionally connective ones */
69 case MP_TUNNELBRIDGE:
70 case MP_STATION:
71 case MP_ROAD:
72 if (IsNormalRoadTile(neighbor_tile)) {
73 /* Always connective */
74 connective = true;
75 } else {
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;
81 break;
83 case MP_RAILWAY:
84 connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir));
85 break;
87 case MP_WATER:
88 /* Check for real water tile */
89 connective = !IsWater(neighbor_tile);
90 break;
92 /* The definitely not connective ones */
93 default: break;
97 /* If the neighbor tile is inconnective, remove the planned road connection to it */
98 if (!connective) org_rb ^= target_rb;
102 return org_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 const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
115 if (rti->label == 0) return false;
117 /* Not yet introduced at this date. */
118 if (IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base()) && rti->introduction_date > TimerGameCalendar::date) return false;
121 * Do not allow building hidden road types, except when a town may build it.
122 * The GS under deity mode, as well as anybody in the editor builds roads that are
123 * owned by towns. So if a town may build it, it should be buildable by them too.
125 return (rti->flags & ROTFB_HIDDEN) == 0 || (rti->flags & ROTFB_TOWN_BUILD) != 0;
126 } else {
127 const Company *c = Company::GetIfValid(company);
128 if (c == nullptr) return false;
129 return HasBit(c->avail_roadtypes & ~_roadtypes_hidden_mask, roadtype);
133 static RoadTypes GetMaskForRoadTramType(RoadTramType rtt)
135 return rtt == RTT_TRAM ? _roadtypes_type : ~_roadtypes_type;
139 * Test if any buildable RoadType is available for a company.
140 * @param company the company in question
141 * @return true if company has any RoadTypes available
143 bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt)
145 return (Company::Get(company)->avail_roadtypes & ~_roadtypes_hidden_mask & GetMaskForRoadTramType(rtt)) != ROADTYPES_NONE;
149 * Validate functions for rail building.
150 * @param roadtype road type to check.
151 * @return true if the current company may build the road.
153 bool ValParamRoadType(RoadType roadtype)
155 return roadtype < ROADTYPE_END && HasRoadTypeAvail(_current_company, roadtype);
159 * Add the road types that are to be introduced at the given date.
160 * @param rt Roadtype
161 * @param current The currently available roadtypes.
162 * @param date The date for the introduction comparisons.
163 * @return The road types that should be available when date
164 * introduced road types are taken into account as well.
166 RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
168 RoadTypes rts = current;
170 for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
171 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
172 /* Unused road type. */
173 if (rti->label == 0) continue;
175 /* Not date introduced. */
176 if (!IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base())) continue;
178 /* Not yet introduced at this date. */
179 if (rti->introduction_date > date) continue;
181 /* Have we introduced all required roadtypes? */
182 RoadTypes required = rti->introduction_required_roadtypes;
183 if ((rts & required) != required) continue;
185 rts |= rti->introduces_roadtypes;
188 /* When we added roadtypes we need to run this method again; the added
189 * roadtypes might enable more rail types to become introduced. */
190 return rts == current ? rts : AddDateIntroducedRoadTypes(rts, date);
194 * Get the road types the given company can build.
195 * @param company the company to get the road types for.
196 * @param introduces If true, include road types introduced by other road types
197 * @return the road types.
199 RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
201 RoadTypes rts = ROADTYPES_NONE;
203 for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
204 const EngineInfo *ei = &e->info;
206 if (HasBit(ei->climates, _settings_game.game_creation.landscape) &&
207 (HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
208 const RoadVehicleInfo *rvi = &e->u.road;
209 assert(rvi->roadtype < ROADTYPE_END);
210 if (introduces) {
211 rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
212 } else {
213 SetBit(rts, rvi->roadtype);
218 if (introduces) return AddDateIntroducedRoadTypes(rts, TimerGameCalendar::date);
219 return rts;
223 * Get list of road types, regardless of company availability.
224 * @param introduces If true, include road types introduced by other road types
225 * @return the road types.
227 RoadTypes GetRoadTypes(bool introduces)
229 RoadTypes rts = ROADTYPES_NONE;
231 for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
232 const EngineInfo *ei = &e->info;
233 if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
235 const RoadVehicleInfo *rvi = &e->u.road;
236 assert(rvi->roadtype < ROADTYPE_END);
237 if (introduces) {
238 rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
239 } else {
240 SetBit(rts, rvi->roadtype);
244 if (introduces) return AddDateIntroducedRoadTypes(rts, CalendarTime::MAX_DATE);
245 return rts;
249 * Get the road type for a given label.
250 * @param label the roadtype label.
251 * @param allow_alternate_labels Search in the alternate label lists as well.
252 * @return the roadtype.
254 RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
256 if (label == 0) return INVALID_ROADTYPE;
258 /* Loop through each road type until the label is found */
259 for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
260 const RoadTypeInfo *rti = GetRoadTypeInfo(r);
261 if (rti->label == label) return r;
264 if (allow_alternate_labels) {
265 /* Test if any road type defines the label as an alternate. */
266 for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
267 const RoadTypeInfo *rti = GetRoadTypeInfo(r);
268 if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r;
272 /* No matching label was found, so it is invalid */
273 return INVALID_ROADTYPE;