1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
|
/* $Id$ */
/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/
/** @file ai_rail.hpp Everything to query and build rails. */
#ifndef AI_RAIL_HPP
#define AI_RAIL_HPP
#include "ai_tile.hpp"
/**
* Class that handles all rail related functions.
*/
class AIRail : public AIObject {
public:
/** Get the name of this class to identify it towards squirrel. */
static const char *GetClassName() { return "AIRail"; }
/**
* All rail related error messages.
*/
enum ErrorMessages {
/** Base for rail building / maintaining errors */
ERR_RAIL_BASE = AIError::ERR_CAT_RAIL << AIError::ERR_CAT_BIT_SIZE,
/** One-way roads cannot have crossings */
ERR_CROSSING_ON_ONEWAY_ROAD, // [STR_ERROR_CROSSING_ON_ONEWAY_ROAD]
/** Track not suitable for signals */
ERR_UNSUITABLE_TRACK, // [STR_ERROR_NO_SUITABLE_RAILROAD_TRACK]
/** This railtype cannot have crossings */
ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED]
};
/**
* Types of rail known to the game.
*/
enum RailType {
/* Note: the values _are_ important as they represent an in-game value */
RAILTYPE_INVALID = 0xFF, ///< Invalid RailType.
};
/**
* A bitmap with all possible rail tracks on a tile.
*/
enum RailTrack {
/* Note: the values _are_ important as they represent an in-game value */
RAILTRACK_NE_SW = 1 << 0, ///< Track along the x-axis (north-east to south-west).
RAILTRACK_NW_SE = 1 << 1, ///< Track along the y-axis (north-west to south-east).
RAILTRACK_NW_NE = 1 << 2, ///< Track in the upper corner of the tile (north).
RAILTRACK_SW_SE = 1 << 3, ///< Track in the lower corner of the tile (south).
RAILTRACK_NW_SW = 1 << 4, ///< Track in the left corner of the tile (west).
RAILTRACK_NE_SE = 1 << 5, ///< Track in the right corner of the tile (east).
RAILTRACK_INVALID = 0xFF, ///< Flag for an invalid track.
};
/**
* Types of signal known to the game.
*/
enum SignalType {
/* Note: the values _are_ important as they represent an in-game value */
SIGNALTYPE_NORMAL = 0, ///< Normal signal.
SIGNALTYPE_ENTRY = 1, ///< Entry presignal.
SIGNALTYPE_EXIT = 2, ///< Exit signal.
SIGNALTYPE_COMBO = 3, ///< Combo signal.
SIGNALTYPE_PBS = 4, ///< Normal PBS signal.
SIGNALTYPE_PBS_ONEWAY = 5, ///< No-entry PBS signal.
SIGNALTYPE_TWOWAY = 8, ///< Bit mask for twoway signal.
SIGNALTYPE_NORMAL_TWOWAY = SIGNALTYPE_NORMAL | SIGNALTYPE_TWOWAY, ///< Normal twoway signal.
SIGNALTYPE_ENTRY_TWOWAY = SIGNALTYPE_ENTRY | SIGNALTYPE_TWOWAY, ///< Entry twoway signal.
SIGNALTYPE_EXIT_TWOWAY = SIGNALTYPE_EXIT | SIGNALTYPE_TWOWAY, ///< Exit twoway signal.
SIGNALTYPE_COMBO_TWOWAY = SIGNALTYPE_COMBO | SIGNALTYPE_TWOWAY, ///< Combo twoway signal.
SIGNALTYPE_NONE = 0xFF, ///< No signal.
};
/**
* Types of rail-related objects in the game.
*/
enum BuildType {
BT_TRACK, ///< Build a track
BT_SIGNAL, ///< Build a signal
BT_DEPOT, ///< Build a depot
BT_STATION, ///< Build a station
BT_WAYPOINT, ///< Build a rail waypoint
};
/**
* Get the name of a rail type.
* @param rail_type The rail type to get the name of.
* @pre IsRailTypeAvailable(rail_type).
* @return The name the rail type has.
* @note Since there is no string with only the name of the track, the text which
* is shown in the dropdown where you can chose a track type is returned. This
* means that the name could be something like "Maglev construction" instead
* of just "Maglev".
*/
static char *GetName(RailType rail_type);
/**
* Checks whether the given tile is actually a tile with rail that can be
* used to traverse a tile. This excludes rail depots but includes
* stations and waypoints.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has rail.
*/
static bool IsRailTile(TileIndex tile);
/**
* Checks whether there is a road / rail crossing on a tile.
* @param tile The tile to check.
* @return True if and only if there is a road / rail crossing.
*/
static bool IsLevelCrossingTile(TileIndex tile);
/**
* Checks whether the given tile is actually a tile with a rail depot.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has a rail depot.
*/
static bool IsRailDepotTile(TileIndex tile);
/**
* Checks whether the given tile is actually a tile with a rail station.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has a rail station.
*/
static bool IsRailStationTile(TileIndex tile);
/**
* Checks whether the given tile is actually a tile with a rail waypoint.
* @param tile The tile to check.
* @pre AIMap::IsValidTile(tile).
* @return True if and only if the tile has a rail waypoint.
*/
static bool IsRailWaypointTile(TileIndex tile);
/**
* Check if a given RailType is available.
* @param rail_type The RailType to check for.
* @return True if this RailType can be used.
*/
static bool IsRailTypeAvailable(RailType rail_type);
/**
* Get the current RailType set for all AIRail functions.
* @return The RailType currently set.
*/
static RailType GetCurrentRailType();
/**
* Set the RailType for all further AIRail functions.
* @param rail_type The RailType to set.
*/
static void SetCurrentRailType(RailType rail_type);
/**
* Check if a train build for a rail type can run on another rail type.
* @param engine_rail_type The rail type the train is build for.
* @param track_rail_type The type you want to check.
* @pre AIRail::IsRailTypeAvailable(engine_rail_type).
* @pre AIRail::IsRailTypeAvailable(track_rail_type).
* @return Whether a train build for 'engine_rail_type' can run on 'track_rail_type'.
* @note Even if a train can run on a RailType that doesn't mean that it'll be
* able to power the train. Use TrainHasPowerOnRail for that.
*/
static bool TrainCanRunOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type);
/**
* Check if a train build for a rail type has power on another rail type.
* @param engine_rail_type The rail type the train is build for.
* @param track_rail_type The type you want to check.
* @pre AIRail::IsRailTypeAvailable(engine_rail_type).
* @pre AIRail::IsRailTypeAvailable(track_rail_type).
* @return Whether a train build for 'engine_rail_type' has power on 'track_rail_type'.
*/
static bool TrainHasPowerOnRail(AIRail::RailType engine_rail_type, AIRail::RailType track_rail_type);
/**
* Get the RailType that is used on a tile.
* @param tile The tile to check.
* @pre AITile::HasTransportType(tile, AITile.TRANSPORT_RAIL).
* @return The RailType that is used on a tile.
*/
static RailType GetRailType(TileIndex tile);
/**
* Convert the tracks on all tiles within a rectangle to another RailType.
* @param start_tile One corner of the rectangle.
* @param end_tile The opposite corner of the rectangle.
* @param convert_to The RailType you want to convert the rails to.
* @pre AIMap::IsValidTile(start_tile).
* @pre AIMap::IsValidTile(end_tile).
* @pre IsRailTypeAvailable(convert_to).
* @exception AIRail::ERR_UNSUITABLE_TRACK
* @return Whether at least some rail has been converted successfully.
*/
static bool ConvertRailType(TileIndex start_tile, TileIndex end_tile, AIRail::RailType convert_to);
/**
* Gets the tile in front of a rail depot.
* @param depot The rail depot tile.
* @pre IsRailDepotTile(depot).
* @return The tile in front of the depot.
*/
static TileIndex GetRailDepotFrontTile(TileIndex depot);
/**
* Gets the direction of a rail station tile.
* @param tile The rail station tile.
* @pre IsRailStationTile(tile).
* @return The direction of the station (either RAILTRACK_NE_SW or RAILTRACK_NW_SE).
*/
static RailTrack GetRailStationDirection(TileIndex tile);
/**
* Builds a rail depot.
* @param tile Place to build the depot.
* @param front The tile exactly in front of the depot.
* @pre AIMap::IsValidTile(tile).
* @pre AIMap::IsValidTile(front).
* @pre 'tile' is not equal to 'front', but in a straight line of it.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @exception AIError::ERR_AREA_NOT_CLEAR
* @return Whether the rail depot has been/can be build or not.
*/
static bool BuildRailDepot(TileIndex tile, TileIndex front);
/**
* Build a rail station.
* @param tile Place to build the station.
* @param direction The direction to build the station.
* @param num_platforms The number of platforms to build.
* @param platform_length The length of each platform.
* @param station_id The station to join, AIStation::STATION_NEW or AIStation::STATION_JOIN_ADJACENT.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @pre AIMap::IsValidTile(tile).
* @pre direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW.
* @pre num_platforms > 0 && num_platforms <= 255.
* @pre platform_length > 0 && platform_length <= 255.
* @pre station_id == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id).
* @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @exception AIStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
* @exception AIStation::ERR_STATION_TOO_MANY_STATIONS
* @exception AIStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
* @return Whether the station has been/can be build or not.
*/
static bool BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id);
/**
* Build a NewGRF rail station. This calls callback 18 to let a NewGRF
* provide the station class / id to build, so we don't end up with
* only the default stations on the map.
* @param tile Place to build the station.
* @param direction The direction to build the station.
* @param num_platforms The number of platforms to build.
* @param platform_length The length of each platform.
* @param station_id The station to join, AIStation::STATION_NEW or AIStation::STATION_JOIN_ADJACENT.
* @param cargo_id The CargoID of the cargo that will be transported from / to this station.
* @param source_industry The IndustryType of the industry you'll transport goods from, AIIndustryType::INDUSTRYTYPE_UNKNOWN or AIIndustryType::INDUSTRYTYPE_TOWN.
* @param goal_industry The IndustryType of the industry you'll transport goods to, AIIndustryType::INDUSTRYTYPE_UNKNOWN or AIIndustryType::INDUSTRYTYPE_TOWN.
* @param distance The manhattan distance you'll transport the cargo over.
* @param source_station True if this is the source station, false otherwise.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @pre AIMap::IsValidTile(tile).
* @pre direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW.
* @pre num_platforms > 0 && num_platforms <= 255.
* @pre platform_length > 0 && platform_length <= 255.
* @pre station_id == AIStation::STATION_NEW || station_id == AIStation::STATION_JOIN_ADJACENT || AIStation::IsValidStation(station_id).
* @pre AICargo::IsValidCargo(cargo_type)
* @pre source_industry == AIIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == AIIndustryType::INDUSTRYTYPE_TOWN || AIIndustryType::IsValidIndustryType(source_industry).
* @pre goal_industry == AIIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == AIIndustryType::INDUSTRYTYPE_TOWN || AIIndustryType::IsValidIndustryType(goal_industry).
* @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @exception AIStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
* @exception AIStation::ERR_STATION_TOO_MANY_STATIONS
* @exception AIStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
* @return Whether the station has been/can be build or not.
*/
static bool BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station);
/**
* Build a rail waypoint.
* @param tile Place to build the waypoint.
* @pre AIMap::IsValidTile(tile).
* @pre IsRailTile(tile).
* @pre GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @exception AIError::ERR_FLAT_LAND_REQUIRED
* @return Whether the rail waypoint has been/can be build or not.
*/
static bool BuildRailWaypoint(TileIndex tile);
/**
* Remove all rail waypoint pieces within a rectangle on the map.
* @param tile One corner of the rectangle to clear.
* @param tile2 The oppposite corner.
* @param keep_rail Whether to keep the rail after removal.
* @pre IsValidTile(tile).
* @pre IsValidTile(tile2).
* @return Whether at least one tile has been/can be cleared or not.
*/
static bool RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail);
/**
* Remove all rail station platform pieces within a rectangle on the map.
* @param tile One corner of the rectangle to clear.
* @param tile2 The oppposite corner.
* @param keep_rail Whether to keep the rail after removal.
* @pre IsValidTile(tile).
* @pre IsValidTile(tile2).
* @return Whether at least one tile has been/can be cleared or not.
*/
static bool RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail);
/**
* Get all RailTracks on the given tile.
* @note A depot has no railtracks.
* @param tile The tile to check.
* @pre IsRailTile(tile).
* @return A bitmask of RailTrack with all RailTracks on the tile.
*/
static uint GetRailTracks(TileIndex tile);
/**
* Build rail on the given tile.
* @param tile The tile to build on.
* @param rail_track The RailTrack to build.
* @pre AIMap::IsValidTile(tile).
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_LAND_SLOPED_WRONG
* @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS
* @exception AIRail::ERR_CROSSING_ON_ONEWAY_ROAD
* @exception AIError::ERR_ALREADY_BUILT
* @return Whether the rail has been/can be build or not.
* @note You can only build a single track with this function so do not
* use the values from RailTrack as bitmask.
*/
static bool BuildRailTrack(TileIndex tile, RailTrack rail_track);
/**
* Remove rail on the given tile.
* @param tile The tile to remove rail from.
* @param rail_track The RailTrack to remove.
* @pre AIMap::IsValidTile(tile).
* @pre (GetRailTracks(tile) & rail_track) != 0.
* @return Whether the rail has been/can be removed or not.
* @note You can only remove a single track with this function so do not
* use the values from RailTrack as bitmask.
*/
static bool RemoveRailTrack(TileIndex tile, RailTrack rail_track);
/**
* Check if a tile connects two adjacent tiles.
* @param from The first tile to connect.
* @param tile The tile that is checked.
* @param to The second tile to connect.
* @pre from != to.
* @pre AIMap::DistanceManhattan(from, tile) == 1.
* @pre AIMap::DistanceManhattan(to, tile) == 1.
* @return True if 'tile' connects 'from' and 'to'.
*/
static bool AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to);
/**
* Build a rail connection between two tiles.
* @param from The tile just before the tile to build on.
* @param tile The first tile to build on.
* @param to The tile just after the last tile to build on.
* @pre from != to.
* @pre AIMap::DistanceManhattan(from, tile) == 1.
* @pre AIMap::DistanceManhattan(to, tile) >= 1.
* @pre (abs(abs(AIMap::GetTileX(to) - AIMap::GetTileX(tile)) -
* abs(AIMap::GetTileY(to) - AIMap::GetTileY(tile))) <= 1) ||
* (AIMap::GetTileX(from) == AIMap::GetTileX(tile) && AIMap::GetTileX(tile) == AIMap::GetTileX(to)) ||
* (AIMap::GetTileY(from) == AIMap::GetTileY(tile) && AIMap::GetTileY(tile) == AIMap::GetTileY(to)).
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @exception AIError::ERR_AREA_NOT_CLEAR
* @exception AIError::ERR_LAND_SLOPED_WRONG
* @exception AIRail::ERR_CROSSING_ON_ONEWAY_ROAD
* @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS
* @exception AIError::ERR_ALREADY_BUILT
* @note Construction will fail if an obstacle is found between the start and end tiles.
* @return Whether the rail has been/can be build or not.
*/
static bool BuildRail(TileIndex from, TileIndex tile, TileIndex to);
/**
* Remove a rail connection between two tiles.
* @param from The tile just before the tile to remove rail from.
* @param tile The first tile to remove rail from.
* @param to The tile just after the last tile to remove rail from.
* @pre from != to.
* @pre AIMap::DistanceManhattan(from, tile) == 1.
* @pre AIMap::DistanceManhattan(to, tile) >= 1.
* @pre (abs(abs(AIMap::GetTileX(to) - AIMap::GetTileX(tile)) -
* abs(AIMap::GetTileY(to) - AIMap::GetTileY(tile))) <= 1) ||
* (AIMap::GetTileX(from) == AIMap::GetTileX(tile) && AIMap::GetTileX(tile) == AIMap::GetTileX(to)) ||
* (AIMap::GetTileY(from) == AIMap::GetTileY(tile) && AIMap::GetTileY(tile) == AIMap::GetTileY(to)).
* @return Whether the rail has been/can be removed or not.
*/
static bool RemoveRail(TileIndex from, TileIndex tile, TileIndex to);
/**
* Get the SignalType of the signal on a tile or SIGNALTYPE_NONE if there is no signal.
* @pre AIMap::DistanceManhattan(tile, front) == 1.
* @param tile The tile that might have a signal.
* @param front The tile in front of 'tile'.
* @return The SignalType of the signal on 'tile' facing to 'front'.
*/
static SignalType GetSignalType(TileIndex tile, TileIndex front);
/**
* Build a signal on a tile.
* @param tile The tile to build on.
* @param front The tile in front of the signal.
* @param signal The SignalType to build.
* @pre AIMap::DistanceManhattan(tile, front) == 1.
* @pre IsRailTile(tile) && !IsRailStationTile(tile) && !IsRailWaypointTile(tile).
* @exception AIRail::ERR_UNSUITABLE_TRACK
* @return Whether the signal has been/can be build or not.
*/
static bool BuildSignal(TileIndex tile, TileIndex front, SignalType signal);
/**
* Remove a signal.
* @param tile The tile to remove the signal from.
* @param front The tile in front of the signal.
* @pre AIMap::DistanceManhattan(tile, front) == 1.
* @pre GetSignalType(tile, front) != SIGNALTYPE_NONE.
* @return Whether the signal has been/can be removed or not.
*/
static bool RemoveSignal(TileIndex tile, TileIndex front);
/**
* Get the baseprice of building a rail-related object.
* @param railtype the railtype that is build (on)
* @param build_type the type of object to build
* @pre IsRailTypeAvailable(railtype)
* @return The baseprice of building the given object.
*/
static Money GetBuildCost(RailType railtype, BuildType build_type);
/**
* Get the maximum speed of trains running on this railtype.
* @param railtype The railtype to get the maximum speed of.
* @pre IsRailTypeAvailable(railtype)
* @return The maximum speed trains can run on this railtype
* or 0 if there is no limit.
* @note The speed is in OpenTTD's internal speed unit.
* This is mph / 1.6, which is roughly km/h.
* To get km/h multiply this number by 1.00584.
*/
static int32 GetMaxSpeed(RailType railtype);
};
#endif /* AI_RAIL_HPP */
|