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 script_road.cpp Implementation of ScriptRoad. */
10 #include "../../stdafx.h"
11 #include "script_map.hpp"
12 #include "script_station.hpp"
13 #include "script_cargo.hpp"
14 #include "../../station_base.h"
15 #include "../../landscape_cmd.h"
16 #include "../../road_cmd.h"
17 #include "../../station_cmd.h"
18 #include "../../newgrf_roadstop.h"
19 #include "../../script/squirrel_helper_type.hpp"
21 #include "../../safeguards.h"
23 /* static */ ScriptRoad::RoadVehicleType
ScriptRoad::GetRoadVehicleTypeForCargo(CargoID cargo_type
)
25 return ScriptCargo::HasCargoClass(cargo_type
, ScriptCargo::CC_PASSENGERS
) ? ROADVEHTYPE_BUS
: ROADVEHTYPE_TRUCK
;
28 /* static */ std::optional
<std::string
> ScriptRoad::GetName(RoadType road_type
)
30 if (!IsRoadTypeAvailable(road_type
)) return std::nullopt
;
32 return GetString(GetRoadTypeInfo((::RoadType
)road_type
)->strings
.name
);
35 /* static */ bool ScriptRoad::IsRoadTile(TileIndex tile
)
37 if (!::IsValidTile(tile
)) return false;
39 return (::IsTileType(tile
, MP_ROAD
) && ::GetRoadTileType(tile
) != ROAD_TILE_DEPOT
) ||
40 IsDriveThroughRoadStationTile(tile
);
43 /* static */ bool ScriptRoad::IsRoadDepotTile(TileIndex tile
)
45 if (!::IsValidTile(tile
)) return false;
46 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
48 return ::IsTileType(tile
, MP_ROAD
) && ::GetRoadTileType(tile
) == ROAD_TILE_DEPOT
&&
49 HasBit(::GetPresentRoadTypes(tile
), (::RoadType
)GetCurrentRoadType());
52 /* static */ bool ScriptRoad::IsRoadStationTile(TileIndex tile
)
54 if (!::IsValidTile(tile
)) return false;
55 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
57 return ::IsStationRoadStopTile(tile
) && HasBit(::GetPresentRoadTypes(tile
), (::RoadType
)GetCurrentRoadType());
60 /* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile
)
62 if (!::IsValidTile(tile
)) return false;
63 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
65 return ::IsDriveThroughStopTile(tile
) && HasBit(::GetPresentRoadTypes(tile
), (::RoadType
)GetCurrentRoadType());
68 /* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type
)
70 EnforceDeityOrCompanyModeValid(false);
71 return (::RoadType
)road_type
< ROADTYPE_END
&& ::HasRoadTypeAvail(ScriptObject::GetCompany(), (::RoadType
)road_type
);
74 /* static */ ScriptRoad::RoadType
ScriptRoad::GetCurrentRoadType()
76 return (RoadType
)ScriptObject::GetRoadType();
79 /* static */ void ScriptRoad::SetCurrentRoadType(RoadType road_type
)
81 if (!IsRoadTypeAvailable(road_type
)) return;
83 ScriptObject::SetRoadType((::RoadType
)road_type
);
86 /* static */ bool ScriptRoad::RoadVehCanRunOnRoad(RoadType engine_road_type
, RoadType road_road_type
)
88 return RoadVehHasPowerOnRoad(engine_road_type
, road_road_type
);
91 /* static */ bool ScriptRoad::RoadVehHasPowerOnRoad(RoadType engine_road_type
, RoadType road_road_type
)
93 if (!IsRoadTypeAvailable(engine_road_type
)) return false;
94 if (!IsRoadTypeAvailable(road_road_type
)) return false;
96 return ::HasPowerOnRoad((::RoadType
)engine_road_type
, (::RoadType
)road_road_type
);
99 /* static */ bool ScriptRoad::HasRoadType(TileIndex tile
, RoadType road_type
)
101 if (!ScriptMap::IsValidTile(tile
)) return false;
102 if (!IsRoadTypeAvailable(road_type
)) return false;
103 return ::MayHaveRoad(tile
) && HasBit(::GetPresentRoadTypes(tile
), (::RoadType
)road_type
);
106 /* static */ bool ScriptRoad::AreRoadTilesConnected(TileIndex t1
, TileIndex t2
)
108 if (!::IsValidTile(t1
)) return false;
109 if (!::IsValidTile(t2
)) return false;
110 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
112 /* Tiles not neighbouring */
113 if ((abs((int)::TileX(t1
) - (int)::TileX(t2
)) + abs((int)::TileY(t1
) - (int)::TileY(t2
))) != 1) return false;
115 RoadTramType rtt
= ::GetRoadTramType(ScriptObject::GetRoadType());
116 RoadBits r1
= ::GetAnyRoadBits(t1
, rtt
); // TODO
117 RoadBits r2
= ::GetAnyRoadBits(t2
, rtt
); // TODO
119 uint dir_1
= (::TileX(t1
) == ::TileX(t2
)) ? (::TileY(t1
) < ::TileY(t2
) ? 2 : 0) : (::TileX(t1
) < ::TileX(t2
) ? 1 : 3);
120 uint dir_2
= 2 ^ dir_1
;
122 DisallowedRoadDirections drd2
= IsNormalRoadTile(t2
) ? GetDisallowedRoadDirections(t2
) : DRD_NONE
;
124 return HasBit(r1
, dir_1
) && HasBit(r2
, dir_2
) && drd2
!= DRD_BOTH
&& drd2
!= (dir_1
> dir_2
? DRD_SOUTHBOUND
: DRD_NORTHBOUND
);
127 /* static */ bool ScriptRoad::ConvertRoadType(TileIndex start_tile
, TileIndex end_tile
, RoadType road_type
)
129 EnforceCompanyModeValid(false);
130 EnforcePrecondition(false, ::IsValidTile(start_tile
));
131 EnforcePrecondition(false, ::IsValidTile(end_tile
));
132 EnforcePrecondition(false, IsRoadTypeAvailable(road_type
));
134 return ScriptObject::Command
<CMD_CONVERT_ROAD
>::Do(start_tile
, end_tile
, (::RoadType
)road_type
);
137 /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */
140 * Check whether the given existing bits the start and end part can be build.
141 * As the function assumes the bits being build on a slope that does not
142 * allow level foundations all of the existing parts will always be in
143 * a straight line. This also needs to hold for the start and end parts,
144 * otherwise it is for sure not valid. Finally a check will be done to
145 * determine whether the existing road parts match the to-be-build parts.
146 * As they can only be placed in one direction, just checking the start
147 * part with the first existing part is enough.
148 * @param existing The existing road parts.
149 * @param start The part that should be build first.
150 * @param end The part that will be build second.
151 * @return True if and only if the road bits can be build.
153 static bool CheckAutoExpandedRoadBits(const Array
<> &existing
, int32_t start
, int32_t end
)
155 return (start
+ end
== 0) && (existing
.empty() || existing
[0] == start
|| existing
[0] == end
);
159 * Lookup function for building road parts when building on slopes is disabled.
160 * @param slope The slope of the tile to examine.
161 * @param existing The existing road parts.
162 * @param start The part that should be build first.
163 * @param end The part that will be build second.
164 * @return 0 when the build parts do not connect, 1 when they do connect once
165 * they are build or 2 when building the first part automatically
166 * builds the second part.
168 static int32_t LookupWithoutBuildOnSlopes(::Slope slope
, const Array
<> &existing
, int32_t start
, int32_t end
)
171 /* Flat slopes can always be build. */
175 /* Only 4 of the slopes can be build upon. Testing the existing bits is
176 * necessary because these bits can be something else when the settings
177 * in the game have been changed.
179 case SLOPE_NE
: case SLOPE_SW
:
180 return (CheckAutoExpandedRoadBits(existing
, start
, end
) && (start
== 1 || end
== 1)) ? (existing
.empty() ? 2 : 1) : 0;
181 case SLOPE_SE
: case SLOPE_NW
:
182 return (CheckAutoExpandedRoadBits(existing
, start
, end
) && (start
!= 1 && end
!= 1)) ? (existing
.empty() ? 2 : 1) : 0;
184 /* Any other tile cannot be built on. */
191 * Rotate a neighbour bit a single time clockwise.
192 * @param neighbour The neighbour.
193 * @return The rotate neighbour data.
195 static int32_t RotateNeighbour(int32_t neighbour
)
202 default: NOT_REACHED();
207 * Convert a neighbour to a road bit representation for easy internal use.
208 * @param neighbour The neighbour.
209 * @return The bits representing the direction.
211 static RoadBits
NeighbourToRoadBits(int32_t neighbour
)
214 case -2: return ROAD_NW
;
215 case -1: return ROAD_NE
;
216 case 2: return ROAD_SE
;
217 case 1: return ROAD_SW
;
218 default: NOT_REACHED();
223 * Lookup function for building road parts when building on slopes is enabled.
224 * @param slope The slope of the tile to examine.
225 * @param existing The existing neighbours.
226 * @param start The part that should be build first.
227 * @param end The part that will be build second.
228 * @return 0 when the build parts do not connect, 1 when they do connect once
229 * they are build or 2 when building the first part automatically
230 * builds the second part.
232 static int32_t LookupWithBuildOnSlopes(::Slope slope
, const Array
<> &existing
, int32_t start
, int32_t end
)
234 /* Steep slopes behave the same as slopes with one corner raised. */
235 if (IsSteepSlope(slope
)) {
236 slope
= SlopeWithOneCornerRaised(GetHighestSlopeCorner(slope
));
239 /* The slope is not steep. Furthermore lots of slopes are generally the
240 * same but are only rotated. So to reduce the amount of lookup work that
241 * needs to be done the data is made uniform. This means rotating the
242 * existing parts and updating the slope. */
243 static const ::Slope base_slopes
[] = {
244 SLOPE_FLAT
, SLOPE_W
, SLOPE_W
, SLOPE_SW
,
245 SLOPE_W
, SLOPE_EW
, SLOPE_SW
, SLOPE_WSE
,
246 SLOPE_W
, SLOPE_SW
, SLOPE_EW
, SLOPE_WSE
,
247 SLOPE_SW
, SLOPE_WSE
, SLOPE_WSE
};
248 static const uint8_t base_rotates
[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1};
250 if (slope
>= (::Slope
)lengthof(base_slopes
)) {
251 /* This slope is an invalid slope, so ignore it. */
254 uint8_t base_rotate
= base_rotates
[slope
];
255 slope
= base_slopes
[slope
];
257 /* Some slopes don't need rotating, so return early when we know we do
258 * not need to rotate. */
261 /* Flat slopes can always be build. */
266 /* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause
267 * foundations which makes them accessible from all sides. */
272 /* A slope for which we need perform some calculations. */
276 /* An invalid slope. */
280 /* Now perform the actual rotation. */
281 for (int j
= 0; j
< base_rotate
; j
++) {
282 start
= RotateNeighbour(start
);
283 end
= RotateNeighbour(end
);
286 /* Create roadbits out of the data for easier handling. */
287 RoadBits start_roadbits
= NeighbourToRoadBits(start
);
288 RoadBits new_roadbits
= start_roadbits
| NeighbourToRoadBits(end
);
289 RoadBits existing_roadbits
= ROAD_NONE
;
290 for (int32_t neighbour
: existing
) {
291 for (int j
= 0; j
< base_rotate
; j
++) {
292 neighbour
= RotateNeighbour(neighbour
);
294 existing_roadbits
|= NeighbourToRoadBits(neighbour
);
299 /* A slope similar to a SLOPE_W. */
300 switch (new_roadbits
) {
304 /* Cannot build anything with a turn from the low side. */
309 /* A 'sloped' tile is going to be build. */
310 if ((existing_roadbits
| new_roadbits
) != new_roadbits
) {
311 /* There is already a foundation on the tile, or at least
312 * another slope that is not compatible with the new one. */
315 /* If the start is in the low part, it is automatically
316 * building the second part too. */
317 return ((start_roadbits
& ROAD_E
) && !(existing_roadbits
& ROAD_W
)) ? 2 : 1;
320 /* Roadbits causing a foundation are going to be build.
321 * When the existing roadbits are slopes (the lower bits
322 * are used), this cannot be done. */
323 if ((existing_roadbits
| new_roadbits
) == new_roadbits
) return 1;
324 return (existing_roadbits
& ROAD_E
) ? 0 : 1;
328 /* A slope similar to a SLOPE_SW. */
329 switch (new_roadbits
) {
332 /* Cannot build anything with a turn from the low side. */
336 /* A 'sloped' tile is going to be build. */
337 if ((existing_roadbits
| new_roadbits
) != new_roadbits
) {
338 /* There is already a foundation on the tile, or at least
339 * another slope that is not compatible with the new one. */
342 /* If the start is in the low part, it is automatically
343 * building the second part too. */
344 return ((start_roadbits
& ROAD_NE
) && !(existing_roadbits
& ROAD_SW
)) ? 2 : 1;
347 /* Roadbits causing a foundation are going to be build.
348 * When the existing roadbits are slopes (the lower bits
349 * are used), this cannot be done. */
350 return (existing_roadbits
& ROAD_NE
) ? 0 : 1;
359 * Normalise all input data so we can easily handle it without needing
360 * to call the API lots of times or create large if-elseif-elseif-else
362 * In this case it means that a TileXY(0, -1) becomes -2 and TileXY(0, 1)
363 * becomes 2. TileXY(-1, 0) and TileXY(1, 0) stay respectively -1 and 1.
364 * Any other value means that it is an invalid tile offset.
365 * @param tile The tile to normalise.
366 * @return True if and only if the tile offset is valid.
368 static bool NormaliseTileOffset(int32_t *tile
)
370 if (*tile
== 1 || *tile
== -1) return true;
371 if (*tile
== ::TileDiffXY(0, -1)) {
375 if (*tile
== ::TileDiffXY(0, 1)) {
382 /* static */ SQInteger
ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_
, Array
<> &&existing
, TileIndex start_
, TileIndex end_
)
384 ::Slope slope
= (::Slope
)slope_
;
385 int32_t start
= start_
.base();
386 int32_t end
= end_
.base();
388 /* The start tile and end tile cannot be the same tile either. */
389 if (start
== end
) return -1;
391 for (size_t i
= 0; i
< existing
.size(); i
++) {
392 if (!NormaliseTileOffset(&existing
[i
])) return -1;
395 if (!NormaliseTileOffset(&start
)) return -1;
396 if (!NormaliseTileOffset(&end
)) return -1;
398 /* Without build on slopes the characteristics are vastly different, so use
399 * a different helper function (one that is much simpler). */
400 return _settings_game
.construction
.build_on_slopes
? LookupWithBuildOnSlopes(slope
, existing
, start
, end
) : LookupWithoutBuildOnSlopes(slope
, existing
, start
, end
);
403 /* static */ SQInteger
ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile
, TileIndex start
, TileIndex end
)
405 if (!::IsValidTile(tile
) || !::IsValidTile(start
) || !::IsValidTile(end
)) return -1;
406 if (::DistanceManhattan(tile
, start
) != 1 || ::DistanceManhattan(tile
, end
) != 1) return -1;
408 /* ROAD_NW ROAD_SW ROAD_SE ROAD_NE */
409 const TileIndexDiff neighbours
[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)};
411 ::RoadBits rb
= ::ROAD_NONE
;
412 if (::IsNormalRoadTile(tile
)) {
413 rb
= ::GetAllRoadBits(tile
);
415 rb
= ::GetAnyRoadBits(tile
, RTT_ROAD
) | ::GetAnyRoadBits(tile
, RTT_TRAM
);
419 for (uint i
= 0; i
< lengthof(neighbours
); i
++) {
420 if (HasBit(rb
, i
)) existing
.emplace_back(neighbours
[i
]);
423 return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile
), std::move(existing
), start
- tile
, end
- tile
);
427 * Check whether one can reach (possibly by building) a road piece the center
428 * of the neighbouring tile. This includes roads and (drive through) stations.
429 * @param rt The road type we want to know reachability for
430 * @param start_tile The tile to "enter" the neighbouring tile.
431 * @param neighbour The direction to the neighbouring tile to "enter".
432 * @return true if and only if the tile is reachable.
434 static bool NeighbourHasReachableRoad(::RoadType rt
, TileIndex start_tile
, DiagDirection neighbour
)
436 TileIndex neighbour_tile
= ::TileAddByDiagDir(start_tile
, neighbour
);
437 if (!HasBit(::GetPresentRoadTypes(neighbour_tile
), rt
)) return false;
439 switch (::GetTileType(neighbour_tile
)) {
441 return (::GetRoadTileType(neighbour_tile
) != ROAD_TILE_DEPOT
);
444 if (::IsDriveThroughStopTile(neighbour_tile
)) {
445 return (::DiagDirToAxis(neighbour
) == ::DiagDirToAxis(::GetRoadStopDir(neighbour_tile
)));
454 /* static */ SQInteger
ScriptRoad::GetNeighbourRoadCount(TileIndex tile
)
456 if (!::IsValidTile(tile
)) return -1;
457 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return -1;
459 ::RoadType rt
= (::RoadType
)GetCurrentRoadType();
460 int32_t neighbour
= 0;
462 if (TileX(tile
) > 0 && NeighbourHasReachableRoad(rt
, tile
, DIAGDIR_NE
)) neighbour
++;
463 if (NeighbourHasReachableRoad(rt
, tile
, DIAGDIR_SE
)) neighbour
++;
464 if (NeighbourHasReachableRoad(rt
, tile
, DIAGDIR_SW
)) neighbour
++;
465 if (TileY(tile
) > 0 && NeighbourHasReachableRoad(rt
, tile
, DIAGDIR_NW
)) neighbour
++;
470 /* static */ TileIndex
ScriptRoad::GetRoadDepotFrontTile(TileIndex depot
)
472 if (!IsRoadDepotTile(depot
)) return INVALID_TILE
;
474 return depot
+ ::TileOffsByDiagDir(::GetRoadDepotDirection(depot
));
477 /* static */ TileIndex
ScriptRoad::GetRoadStationFrontTile(TileIndex station
)
479 if (!IsRoadStationTile(station
)) return INVALID_TILE
;
481 return station
+ ::TileOffsByDiagDir(::GetRoadStopDir(station
));
484 /* static */ TileIndex
ScriptRoad::GetDriveThroughBackTile(TileIndex station
)
486 if (!IsDriveThroughRoadStationTile(station
)) return INVALID_TILE
;
488 return station
+ ::TileOffsByDiagDir(::ReverseDiagDir(::GetRoadStopDir(station
)));
491 /* static */ bool ScriptRoad::_BuildRoadInternal(TileIndex start
, TileIndex end
, bool one_way
, bool full
)
493 EnforceDeityOrCompanyModeValid(false);
494 EnforcePrecondition(false, start
!= end
);
495 EnforcePrecondition(false, ::IsValidTile(start
));
496 EnforcePrecondition(false, ::IsValidTile(end
));
497 EnforcePrecondition(false, ::TileX(start
) == ::TileX(end
) || ::TileY(start
) == ::TileY(end
));
498 EnforcePrecondition(false, !one_way
|| RoadTypeIsRoad(ScriptObject::GetRoadType()));
499 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
501 Axis axis
= ::TileY(start
) != ::TileY(end
) ? AXIS_Y
: AXIS_X
;
502 return ScriptObject::Command
<CMD_BUILD_LONG_ROAD
>::Do(end
, start
, ScriptObject::GetRoadType(), axis
, one_way
? DRD_NORTHBOUND
: DRD_NONE
, (start
< end
) == !full
, (start
< end
) != !full
, true);
505 /* static */ bool ScriptRoad::BuildRoad(TileIndex start
, TileIndex end
)
507 return _BuildRoadInternal(start
, end
, false, false);
510 /* static */ bool ScriptRoad::BuildOneWayRoad(TileIndex start
, TileIndex end
)
512 EnforceCompanyModeValid(false);
513 return _BuildRoadInternal(start
, end
, true, false);
516 /* static */ bool ScriptRoad::BuildRoadFull(TileIndex start
, TileIndex end
)
518 return _BuildRoadInternal(start
, end
, false, true);
521 /* static */ bool ScriptRoad::BuildOneWayRoadFull(TileIndex start
, TileIndex end
)
523 EnforceCompanyModeValid(false);
524 return _BuildRoadInternal(start
, end
, true, true);
527 /* static */ bool ScriptRoad::BuildRoadDepot(TileIndex tile
, TileIndex front
)
529 EnforceCompanyModeValid(false);
530 EnforcePrecondition(false, tile
!= front
);
531 EnforcePrecondition(false, ::IsValidTile(tile
));
532 EnforcePrecondition(false, ::IsValidTile(front
));
533 EnforcePrecondition(false, ::TileX(tile
) == ::TileX(front
) || ::TileY(tile
) == ::TileY(front
));
534 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
536 DiagDirection entrance_dir
= (::TileX(tile
) == ::TileX(front
)) ? (::TileY(tile
) < ::TileY(front
) ? DIAGDIR_SE
: DIAGDIR_NW
) : (::TileX(tile
) < ::TileX(front
) ? DIAGDIR_SW
: DIAGDIR_NE
);
538 return ScriptObject::Command
<CMD_BUILD_ROAD_DEPOT
>::Do(tile
, ScriptObject::GetRoadType(), entrance_dir
);
541 /* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile
, TileIndex front
, RoadVehicleType road_veh_type
, bool drive_through
, StationID station_id
)
543 EnforceCompanyModeValid(false);
544 EnforcePrecondition(false, tile
!= front
);
545 EnforcePrecondition(false, ::IsValidTile(tile
));
546 EnforcePrecondition(false, ::IsValidTile(front
));
547 EnforcePrecondition(false, ::TileX(tile
) == ::TileX(front
) || ::TileY(tile
) == ::TileY(front
));
548 EnforcePrecondition(false, station_id
== ScriptStation::STATION_NEW
|| station_id
== ScriptStation::STATION_JOIN_ADJACENT
|| ScriptStation::IsValidStation(station_id
));
549 EnforcePrecondition(false, road_veh_type
== ROADVEHTYPE_BUS
|| road_veh_type
== ROADVEHTYPE_TRUCK
);
550 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
552 DiagDirection entrance_dir
= DiagdirBetweenTiles(tile
, front
);
553 RoadStopType stop_type
= road_veh_type
== ROADVEHTYPE_TRUCK
? ROADSTOP_TRUCK
: ROADSTOP_BUS
;
554 StationID to_join
= ScriptStation::IsValidStation(station_id
) ? station_id
: INVALID_STATION
;
555 return ScriptObject::Command
<CMD_BUILD_ROAD_STOP
>::Do(tile
, 1, 1, stop_type
, drive_through
, entrance_dir
, ScriptObject::GetRoadType(), ROADSTOP_CLASS_DFLT
, 0, to_join
, station_id
!= ScriptStation::STATION_JOIN_ADJACENT
);
558 /* static */ bool ScriptRoad::BuildRoadStation(TileIndex tile
, TileIndex front
, RoadVehicleType road_veh_type
, StationID station_id
)
560 return _BuildRoadStationInternal(tile
, front
, road_veh_type
, false, station_id
);
563 /* static */ bool ScriptRoad::BuildDriveThroughRoadStation(TileIndex tile
, TileIndex front
, RoadVehicleType road_veh_type
, StationID station_id
)
565 return _BuildRoadStationInternal(tile
, front
, road_veh_type
, true, station_id
);
568 /* static */ bool ScriptRoad::RemoveRoad(TileIndex start
, TileIndex end
)
570 EnforceCompanyModeValid(false);
571 EnforcePrecondition(false, start
!= end
);
572 EnforcePrecondition(false, ::IsValidTile(start
));
573 EnforcePrecondition(false, ::IsValidTile(end
));
574 EnforcePrecondition(false, ::TileX(start
) == ::TileX(end
) || ::TileY(start
) == ::TileY(end
));
575 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
577 return ScriptObject::Command
<CMD_REMOVE_LONG_ROAD
>::Do(end
, start
, ScriptObject::GetRoadType(), ::TileY(start
) != ::TileY(end
) ? AXIS_Y
: AXIS_X
, start
< end
, start
>= end
);
580 /* static */ bool ScriptRoad::RemoveRoadFull(TileIndex start
, TileIndex end
)
582 EnforceCompanyModeValid(false);
583 EnforcePrecondition(false, start
!= end
);
584 EnforcePrecondition(false, ::IsValidTile(start
));
585 EnforcePrecondition(false, ::IsValidTile(end
));
586 EnforcePrecondition(false, ::TileX(start
) == ::TileX(end
) || ::TileY(start
) == ::TileY(end
));
587 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
589 return ScriptObject::Command
<CMD_REMOVE_LONG_ROAD
>::Do(end
, start
, ScriptObject::GetRoadType(), ::TileY(start
) != ::TileY(end
) ? AXIS_Y
: AXIS_X
, start
>= end
, start
< end
);
592 /* static */ bool ScriptRoad::RemoveRoadDepot(TileIndex tile
)
594 EnforceCompanyModeValid(false);
595 EnforcePrecondition(false, ::IsValidTile(tile
));
596 EnforcePrecondition(false, IsTileType(tile
, MP_ROAD
))
597 EnforcePrecondition(false, GetRoadTileType(tile
) == ROAD_TILE_DEPOT
);
599 return ScriptObject::Command
<CMD_LANDSCAPE_CLEAR
>::Do(tile
);
602 /* static */ bool ScriptRoad::RemoveRoadStation(TileIndex tile
)
604 EnforceCompanyModeValid(false);
605 EnforcePrecondition(false, ::IsValidTile(tile
));
606 EnforcePrecondition(false, IsTileType(tile
, MP_STATION
));
607 EnforcePrecondition(false, IsStationRoadStop(tile
));
609 return ScriptObject::Command
<CMD_REMOVE_ROAD_STOP
>::Do(tile
, 1, 1, GetRoadStopType(tile
), false);
612 /* static */ Money
ScriptRoad::GetBuildCost(RoadType roadtype
, BuildType build_type
)
614 if (!ScriptRoad::IsRoadTypeAvailable(roadtype
)) return -1;
616 switch (build_type
) {
617 case BT_ROAD
: return ::RoadBuildCost((::RoadType
)roadtype
);
618 case BT_DEPOT
: return ::GetPrice(PR_BUILD_DEPOT_ROAD
, 1, nullptr);
619 case BT_BUS_STOP
: return ::GetPrice(PR_BUILD_STATION_BUS
, 1, nullptr);
620 case BT_TRUCK_STOP
: return ::GetPrice(PR_BUILD_STATION_TRUCK
, 1, nullptr);
625 /* static */ ScriptRoad::RoadTramTypes
ScriptRoad::GetRoadTramType(RoadType roadtype
)
627 return (RoadTramTypes
)(1 << ::GetRoadTramType((::RoadType
)roadtype
));
630 /* static */ SQInteger
ScriptRoad::GetMaxSpeed(RoadType road_type
)
632 if (!ScriptRoad::IsRoadTypeAvailable(road_type
)) return -1;
634 return GetRoadTypeInfo((::RoadType
)road_type
)->max_speed
;
637 /* static */ SQInteger
ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype
)
639 if (!ScriptRoad::IsRoadTypeAvailable(roadtype
)) return 0;
641 return GetRoadTypeInfo((::RoadType
)roadtype
)->maintenance_multiplier
;