4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file rail.cpp Implementation of rail specific functions. */
13 #include "map/depot.h"
15 #include "date_func.h"
16 #include "company_func.h"
17 #include "company_base.h"
18 #include "engine_base.h"
20 /* Maps a diagonal direction to the all trackdirs that are connected to any
21 * track entering in this direction (including those making 90 degree turns)
23 extern const TrackdirBits _exitdir_reaches_trackdirs
[] = {
24 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_LOWER_E
| TRACKDIR_BIT_LEFT_N
, // DIAGDIR_NE
25 TRACKDIR_BIT_Y_SE
| TRACKDIR_BIT_LEFT_S
| TRACKDIR_BIT_UPPER_E
, // DIAGDIR_SE
26 TRACKDIR_BIT_X_SW
| TRACKDIR_BIT_UPPER_W
| TRACKDIR_BIT_RIGHT_S
, // DIAGDIR_SW
27 TRACKDIR_BIT_Y_NW
| TRACKDIR_BIT_RIGHT_N
| TRACKDIR_BIT_LOWER_W
// DIAGDIR_NW
30 extern const Trackdir _next_trackdir
[TRACKDIR_END
] = {
31 TRACKDIR_X_NE
, TRACKDIR_Y_SE
, TRACKDIR_LOWER_E
, TRACKDIR_UPPER_E
, TRACKDIR_RIGHT_S
, TRACKDIR_LEFT_S
, INVALID_TRACKDIR
, INVALID_TRACKDIR
,
32 TRACKDIR_X_SW
, TRACKDIR_Y_NW
, TRACKDIR_LOWER_W
, TRACKDIR_UPPER_W
, TRACKDIR_RIGHT_N
, TRACKDIR_LEFT_N
35 /* Maps a trackdir to all trackdirs that make 90 deg turns with it. */
36 extern const TrackdirBits _track_crosses_trackdirs
[TRACK_END
] = {
37 TRACKDIR_BIT_Y_SE
| TRACKDIR_BIT_Y_NW
, // TRACK_X
38 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_X_SW
, // TRACK_Y
39 TRACKDIR_BIT_RIGHT_N
| TRACKDIR_BIT_RIGHT_S
| TRACKDIR_BIT_LEFT_N
| TRACKDIR_BIT_LEFT_S
, // TRACK_UPPER
40 TRACKDIR_BIT_RIGHT_N
| TRACKDIR_BIT_RIGHT_S
| TRACKDIR_BIT_LEFT_N
| TRACKDIR_BIT_LEFT_S
, // TRACK_LOWER
41 TRACKDIR_BIT_UPPER_W
| TRACKDIR_BIT_UPPER_E
| TRACKDIR_BIT_LOWER_W
| TRACKDIR_BIT_LOWER_E
, // TRACK_LEFT
42 TRACKDIR_BIT_UPPER_W
| TRACKDIR_BIT_UPPER_E
| TRACKDIR_BIT_LOWER_W
| TRACKDIR_BIT_LOWER_E
// TRACK_RIGHT
45 /* Maps a track to all tracks that make 90 deg turns with it. */
46 extern const TrackBits _track_crosses_tracks
[] = {
47 TRACK_BIT_Y
, // TRACK_X
48 TRACK_BIT_X
, // TRACK_Y
49 TRACK_BIT_VERT
, // TRACK_UPPER
50 TRACK_BIT_VERT
, // TRACK_LOWER
51 TRACK_BIT_HORZ
, // TRACK_LEFT
52 TRACK_BIT_HORZ
// TRACK_RIGHT
55 /* Maps a trackdir to the (4-way) direction the tile is exited when following
57 extern const DiagDirection _trackdir_to_exitdir
[TRACKDIR_END
] = {
58 DIAGDIR_NE
, DIAGDIR_SE
, DIAGDIR_NE
, DIAGDIR_SE
, DIAGDIR_SW
, DIAGDIR_SE
, DIAGDIR_SW
, DIAGDIR_NW
,
59 DIAGDIR_SW
, DIAGDIR_NW
, DIAGDIR_NW
, DIAGDIR_SW
, DIAGDIR_NW
, DIAGDIR_NE
, DIAGDIR_NE
, DIAGDIR_SE
,
62 extern const Trackdir _track_exitdir_to_trackdir
[][DIAGDIR_END
] = {
63 {TRACKDIR_X_NE
, INVALID_TRACKDIR
, TRACKDIR_X_SW
, INVALID_TRACKDIR
},
64 {INVALID_TRACKDIR
, TRACKDIR_Y_SE
, INVALID_TRACKDIR
, TRACKDIR_Y_NW
},
65 {TRACKDIR_UPPER_E
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_UPPER_W
},
66 {INVALID_TRACKDIR
, TRACKDIR_LOWER_E
, TRACKDIR_LOWER_W
, INVALID_TRACKDIR
},
67 {INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_LEFT_S
, TRACKDIR_LEFT_N
},
68 {TRACKDIR_RIGHT_N
, TRACKDIR_RIGHT_S
, INVALID_TRACKDIR
, INVALID_TRACKDIR
}
71 extern const Trackdir _track_enterdir_to_trackdir
[][DIAGDIR_END
] = {
72 {TRACKDIR_X_NE
, INVALID_TRACKDIR
, TRACKDIR_X_SW
, INVALID_TRACKDIR
},
73 {INVALID_TRACKDIR
, TRACKDIR_Y_SE
, INVALID_TRACKDIR
, TRACKDIR_Y_NW
},
74 {INVALID_TRACKDIR
, TRACKDIR_UPPER_E
, TRACKDIR_UPPER_W
, INVALID_TRACKDIR
},
75 {TRACKDIR_LOWER_E
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_LOWER_W
},
76 {TRACKDIR_LEFT_N
, TRACKDIR_LEFT_S
, INVALID_TRACKDIR
, INVALID_TRACKDIR
},
77 {INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_RIGHT_S
, TRACKDIR_RIGHT_N
}
80 extern const Trackdir _track_direction_to_trackdir
[][DIR_END
] = {
81 {INVALID_TRACKDIR
, TRACKDIR_X_NE
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_X_SW
, INVALID_TRACKDIR
, INVALID_TRACKDIR
},
82 {INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_Y_SE
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_Y_NW
},
83 {INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_UPPER_E
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_UPPER_W
, INVALID_TRACKDIR
},
84 {INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_LOWER_E
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_LOWER_W
, INVALID_TRACKDIR
},
85 {TRACKDIR_LEFT_N
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_LEFT_S
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
},
86 {TRACKDIR_RIGHT_N
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, TRACKDIR_RIGHT_S
, INVALID_TRACKDIR
, INVALID_TRACKDIR
, INVALID_TRACKDIR
}
89 extern const Trackdir _enterdir_exitdir_to_trackdir
[DIAGDIR_END
][DIAGDIR_END
] = {
90 {TRACKDIR_X_NE
, TRACKDIR_LOWER_E
, TRACKDIR_RVREV_NE
, TRACKDIR_LEFT_N
},
91 {TRACKDIR_UPPER_E
, TRACKDIR_Y_SE
, TRACKDIR_LEFT_S
, TRACKDIR_RVREV_SE
},
92 {TRACKDIR_RVREV_SW
, TRACKDIR_RIGHT_S
, TRACKDIR_X_SW
, TRACKDIR_UPPER_W
},
93 {TRACKDIR_RIGHT_N
, TRACKDIR_RVREV_NW
, TRACKDIR_LOWER_W
, TRACKDIR_Y_NW
},
96 extern const Trackdir _dir_to_diag_trackdir
[] = {
97 TRACKDIR_X_NE
, TRACKDIR_Y_SE
, TRACKDIR_X_SW
, TRACKDIR_Y_NW
,
100 extern const TrackBits _corner_to_trackbits
[] = {
101 TRACK_BIT_LEFT
, TRACK_BIT_LOWER
, TRACK_BIT_RIGHT
, TRACK_BIT_UPPER
,
104 extern const TrackdirBits _uphill_trackdirs
[] = {
105 TRACKDIR_BIT_NONE
, ///< 0 SLOPE_FLAT
106 TRACKDIR_BIT_X_SW
| TRACKDIR_BIT_Y_NW
, ///< 1 SLOPE_W -> inclined for diagonal track
107 TRACKDIR_BIT_X_SW
| TRACKDIR_BIT_Y_SE
, ///< 2 SLOPE_S -> inclined for diagonal track
108 TRACKDIR_BIT_X_SW
, ///< 3 SLOPE_SW
109 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_Y_SE
, ///< 4 SLOPE_E -> inclined for diagonal track
110 TRACKDIR_BIT_NONE
, ///< 5 SLOPE_EW
111 TRACKDIR_BIT_Y_SE
, ///< 6 SLOPE_SE
112 TRACKDIR_BIT_NONE
, ///< 7 SLOPE_WSE -> leveled
113 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_Y_NW
, ///< 8 SLOPE_N -> inclined for diagonal track
114 TRACKDIR_BIT_Y_NW
, ///< 9 SLOPE_NW
115 TRACKDIR_BIT_NONE
, ///< 10 SLOPE_NS
116 TRACKDIR_BIT_NONE
, ///< 11 SLOPE_NWS -> leveled
117 TRACKDIR_BIT_X_NE
, ///< 12 SLOPE_NE
118 TRACKDIR_BIT_NONE
, ///< 13 SLOPE_ENW -> leveled
119 TRACKDIR_BIT_NONE
, ///< 14 SLOPE_SEN -> leveled
120 TRACKDIR_BIT_NONE
, ///< 15 invalid
121 TRACKDIR_BIT_NONE
, ///< 16 invalid
122 TRACKDIR_BIT_NONE
, ///< 17 invalid
123 TRACKDIR_BIT_NONE
, ///< 18 invalid
124 TRACKDIR_BIT_NONE
, ///< 19 invalid
125 TRACKDIR_BIT_NONE
, ///< 20 invalid
126 TRACKDIR_BIT_NONE
, ///< 21 invalid
127 TRACKDIR_BIT_NONE
, ///< 22 invalid
128 TRACKDIR_BIT_X_SW
| TRACKDIR_BIT_Y_SE
, ///< 23 SLOPE_STEEP_S -> inclined for diagonal track
129 TRACKDIR_BIT_NONE
, ///< 24 invalid
130 TRACKDIR_BIT_NONE
, ///< 25 invalid
131 TRACKDIR_BIT_NONE
, ///< 26 invalid
132 TRACKDIR_BIT_X_SW
| TRACKDIR_BIT_Y_NW
, ///< 27 SLOPE_STEEP_W -> inclined for diagonal track
133 TRACKDIR_BIT_NONE
, ///< 28 invalid
134 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_Y_NW
, ///< 29 SLOPE_STEEP_N -> inclined for diagonal track
135 TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_Y_SE
, ///< 30 SLOPE_STEEP_E -> inclined for diagonal track
139 * Finds out if a company has a certain railtype available
140 * @param company the company in question
141 * @param railtype requested RailType
142 * @return true if company has requested RailType available
144 bool HasRailtypeAvail(const CompanyID company
, const RailType railtype
)
146 return HasBit(Company::Get(company
)->avail_railtypes
, railtype
);
150 * Validate functions for rail building.
151 * @param rail the railtype to check.
152 * @return true if the current company may build the rail.
154 bool ValParamRailtype(const RailType rail
)
156 return rail
< RAILTYPE_END
&& HasRailtypeAvail(_current_company
, rail
);
160 * Returns the "best" railtype a company can build.
161 * As the AI doesn't know what the BEST one is, we have our own priority list
162 * here. When adding new railtypes, modify this function
163 * @param company the company "in action"
164 * @return The "best" railtype a company has available
166 RailType
GetBestRailtype(const CompanyID company
)
168 if (HasRailtypeAvail(company
, RAILTYPE_MAGLEV
)) return RAILTYPE_MAGLEV
;
169 if (HasRailtypeAvail(company
, RAILTYPE_MONO
)) return RAILTYPE_MONO
;
170 if (HasRailtypeAvail(company
, RAILTYPE_ELECTRIC
)) return RAILTYPE_ELECTRIC
;
171 return RAILTYPE_RAIL
;
175 * Add the rail types that are to be introduced at the given date.
176 * @param current The currently available railtypes.
177 * @param date The date for the introduction comparisons.
178 * @return The rail types that should be available when date
179 * introduced rail types are taken into account as well.
181 RailTypes
AddDateIntroducedRailTypes(RailTypes current
, Date date
)
183 RailTypes rts
= current
;
185 for (RailType rt
= RAILTYPE_BEGIN
; rt
!= RAILTYPE_END
; rt
++) {
186 const RailtypeInfo
*rti
= GetRailTypeInfo(rt
);
187 /* Unused rail type. */
188 if (rti
->label
== 0) continue;
190 /* Not date introduced. */
191 if (!IsInsideMM(rti
->introduction_date
, 0, MAX_DAY
)) continue;
193 /* Not yet introduced at this date. */
194 if (rti
->introduction_date
> date
) continue;
196 /* Have we introduced all required railtypes? */
197 RailTypes required
= rti
->introduction_required_railtypes
;
198 if ((rts
& required
) != required
) continue;
200 rts
|= rti
->introduces_railtypes
;
203 /* When we added railtypes we need to run this method again; the added
204 * railtypes might enable more rail types to become introduced. */
205 return rts
== current
? rts
: AddDateIntroducedRailTypes(rts
, date
);
209 * Get the rail types the given company can build.
210 * @param c the company to get the rail types for.
211 * @return the rail types.
213 RailTypes
GetCompanyRailtypes(CompanyID company
)
215 RailTypes rts
= RAILTYPES_NONE
;
218 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_TRAIN
) {
219 const EngineInfo
*ei
= &e
->info
;
221 if (HasBit(ei
->climates
, _settings_game
.game_creation
.landscape
) &&
222 (HasBit(e
->company_avail
, company
) || _date
>= e
->intro_date
+ DAYS_IN_YEAR
)) {
223 const RailVehicleInfo
*rvi
= &e
->u
.rail
;
225 if (rvi
->railveh_type
!= RAILVEH_WAGON
) {
226 assert(rvi
->railtype
< RAILTYPE_END
);
227 rts
|= GetRailTypeInfo(rvi
->railtype
)->introduces_railtypes
;
232 return AddDateIntroducedRailTypes(rts
, _date
);
236 * Get the rail type for a given label.
237 * @param label the railtype label.
238 * @param allow_alternate_labels Search in the alternate label lists as well.
239 * @return the railtype.
241 RailType
GetRailTypeByLabel(RailTypeLabel label
, bool allow_alternate_labels
)
243 /* Loop through each rail type until the label is found */
244 for (RailType r
= RAILTYPE_BEGIN
; r
!= RAILTYPE_END
; r
++) {
245 const RailtypeInfo
*rti
= GetRailTypeInfo(r
);
246 if (rti
->label
== label
) return r
;
249 if (allow_alternate_labels
) {
250 /* Test if any rail type defines the label as an alternate. */
251 for (RailType r
= RAILTYPE_BEGIN
; r
!= RAILTYPE_END
; r
++) {
252 const RailtypeInfo
*rti
= GetRailTypeInfo(r
);
253 if (rti
->alternate_labels
.Contains(label
)) return r
;
257 /* No matching label was found, so it is invalid */
258 return INVALID_RAILTYPE
;