Update: Translations from eints
[openttd-github.git] / src / script / api / script_road.cpp
blob06879a4e57ea5976cf152d0666be470d9daa08eb
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 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 * Enumeration or the orientations of road parts.
142 * Technically DiagDirection could be used, but that allows simple conversions to/from integer. In this case that is not wanted.
144 enum class RoadPartOrientation {
145 NW, NE, SW, SE
149 * Check whether the two given orientations combined are a straight road.
150 * @param start The part that should be build first.
151 * @param end The part that will be build second.
152 * @return True iff start and end combined describe a straight road (ROAD_X or ROAD_Y).
154 static bool IsStraight(RoadPartOrientation start, RoadPartOrientation end)
156 switch (start) {
157 case RoadPartOrientation::NW: return end == RoadPartOrientation::SE;
158 case RoadPartOrientation::NE: return end == RoadPartOrientation::SW;
159 case RoadPartOrientation::SW: return end == RoadPartOrientation::NE;
160 case RoadPartOrientation::SE: return end == RoadPartOrientation::NW;
161 default: NOT_REACHED();
166 * Check whether the given existing bits the start and end part can be build.
167 * As the function assumes the bits being build on a slope that does not
168 * allow level foundations all of the existing parts will always be in
169 * a straight line. This also needs to hold for the start and end parts,
170 * otherwise it is for sure not valid. Finally a check will be done to
171 * determine whether the existing road parts match the to-be-build parts.
172 * As they can only be placed in one direction, just checking the start
173 * part with the first existing part is enough.
174 * @param existing The existing road parts.
175 * @param start The part that should be build first.
176 * @param end The part that will be build second.
177 * @return True if and only if the road bits can be build.
179 static bool CheckAutoExpandedRoadBits(const Array<RoadPartOrientation> &existing, RoadPartOrientation start, RoadPartOrientation end)
181 return IsStraight(start, end) && (existing.empty() || existing[0] == start || existing[0] == end);
185 * Lookup function for building road parts when building on slopes is disabled.
186 * @param slope The slope of the tile to examine.
187 * @param existing The existing road parts.
188 * @param start The part that should be build first.
189 * @param end The part that will be build second.
190 * @return 0 when the build parts do not connect, 1 when they do connect once
191 * they are build or 2 when building the first part automatically
192 * builds the second part.
194 static int32_t LookupWithoutBuildOnSlopes(::Slope slope, const Array<RoadPartOrientation> &existing, RoadPartOrientation start, RoadPartOrientation end)
196 switch (slope) {
197 /* Flat slopes can always be build. */
198 case SLOPE_FLAT:
199 return 1;
201 /* Only 4 of the slopes can be build upon. Testing the existing bits is
202 * necessary because these bits can be something else when the settings
203 * in the game have been changed.
205 case SLOPE_NE: case SLOPE_SW:
206 return (CheckAutoExpandedRoadBits(existing, start, end) && (start == RoadPartOrientation::SW || end == RoadPartOrientation::SW)) ? (existing.empty() ? 2 : 1) : 0;
207 case SLOPE_SE: case SLOPE_NW:
208 return (CheckAutoExpandedRoadBits(existing, start, end) && (start != RoadPartOrientation::SW && end != RoadPartOrientation::SW)) ? (existing.empty() ? 2 : 1) : 0;
210 /* Any other tile cannot be built on. */
211 default:
212 return 0;
217 * Rotate a neighbour bit a single time clockwise.
218 * @param neighbour The neighbour.
219 * @return The rotate neighbour data.
221 static RoadPartOrientation RotateNeighbour(RoadPartOrientation neighbour)
223 switch (neighbour) {
224 case RoadPartOrientation::NW: return RoadPartOrientation::NE;
225 case RoadPartOrientation::NE: return RoadPartOrientation::SE;
226 case RoadPartOrientation::SE: return RoadPartOrientation::SW;
227 case RoadPartOrientation::SW: return RoadPartOrientation::NW;
228 default: NOT_REACHED();
233 * Convert a neighbour to a road bit representation for easy internal use.
234 * @param neighbour The neighbour.
235 * @return The bits representing the direction.
237 static RoadBits NeighbourToRoadBits(RoadPartOrientation neighbour)
239 switch (neighbour) {
240 case RoadPartOrientation::NW: return ROAD_NW;
241 case RoadPartOrientation::NE: return ROAD_NE;
242 case RoadPartOrientation::SE: return ROAD_SE;
243 case RoadPartOrientation::SW: return ROAD_SW;
244 default: NOT_REACHED();
249 * Lookup function for building road parts when building on slopes is enabled.
250 * @param slope The slope of the tile to examine.
251 * @param existing The existing neighbours.
252 * @param start The part that should be build first.
253 * @param end The part that will be build second.
254 * @return 0 when the build parts do not connect, 1 when they do connect once
255 * they are build or 2 when building the first part automatically
256 * builds the second part.
258 static int32_t LookupWithBuildOnSlopes(::Slope slope, const Array<RoadPartOrientation> &existing, RoadPartOrientation start, RoadPartOrientation end)
260 /* Steep slopes behave the same as slopes with one corner raised. */
261 if (IsSteepSlope(slope)) {
262 slope = SlopeWithOneCornerRaised(GetHighestSlopeCorner(slope));
265 /* The slope is not steep. Furthermore lots of slopes are generally the
266 * same but are only rotated. So to reduce the amount of lookup work that
267 * needs to be done the data is made uniform. This means rotating the
268 * existing parts and updating the slope. */
269 static const ::Slope base_slopes[] = {
270 SLOPE_FLAT, SLOPE_W, SLOPE_W, SLOPE_SW,
271 SLOPE_W, SLOPE_EW, SLOPE_SW, SLOPE_WSE,
272 SLOPE_W, SLOPE_SW, SLOPE_EW, SLOPE_WSE,
273 SLOPE_SW, SLOPE_WSE, SLOPE_WSE};
274 static const uint8_t base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1};
276 if (slope >= (::Slope)lengthof(base_slopes)) {
277 /* This slope is an invalid slope, so ignore it. */
278 return -1;
280 uint8_t base_rotate = base_rotates[slope];
281 slope = base_slopes[slope];
283 /* Some slopes don't need rotating, so return early when we know we do
284 * not need to rotate. */
285 switch (slope) {
286 case SLOPE_FLAT:
287 /* Flat slopes can always be build. */
288 return 1;
290 case SLOPE_EW:
291 case SLOPE_WSE:
292 /* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause
293 * foundations which makes them accessible from all sides. */
294 return 1;
296 case SLOPE_W:
297 case SLOPE_SW:
298 /* A slope for which we need perform some calculations. */
299 break;
301 default:
302 /* An invalid slope. */
303 return -1;
306 /* Now perform the actual rotation. */
307 for (int j = 0; j < base_rotate; j++) {
308 start = RotateNeighbour(start);
309 end = RotateNeighbour(end);
312 /* Create roadbits out of the data for easier handling. */
313 RoadBits start_roadbits = NeighbourToRoadBits(start);
314 RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end);
315 RoadBits existing_roadbits = ROAD_NONE;
316 for (RoadPartOrientation neighbour : existing) {
317 for (int j = 0; j < base_rotate; j++) {
318 neighbour = RotateNeighbour(neighbour);
320 existing_roadbits |= NeighbourToRoadBits(neighbour);
323 switch (slope) {
324 case SLOPE_W:
325 /* A slope similar to a SLOPE_W. */
326 switch (new_roadbits) {
327 case ROAD_N:
328 case ROAD_E:
329 case ROAD_S:
330 /* Cannot build anything with a turn from the low side. */
331 return 0;
333 case ROAD_X:
334 case ROAD_Y:
335 /* A 'sloped' tile is going to be build. */
336 if ((existing_roadbits | new_roadbits) != new_roadbits) {
337 /* There is already a foundation on the tile, or at least
338 * another slope that is not compatible with the new one. */
339 return 0;
341 /* If the start is in the low part, it is automatically
342 * building the second part too. */
343 return ((start_roadbits & ROAD_E) && !(existing_roadbits & ROAD_W)) ? 2 : 1;
345 default:
346 /* Roadbits causing a foundation are going to be build.
347 * When the existing roadbits are slopes (the lower bits
348 * are used), this cannot be done. */
349 if ((existing_roadbits | new_roadbits) == new_roadbits) return 1;
350 return (existing_roadbits & ROAD_E) ? 0 : 1;
353 case SLOPE_SW:
354 /* A slope similar to a SLOPE_SW. */
355 switch (new_roadbits) {
356 case ROAD_N:
357 case ROAD_E:
358 /* Cannot build anything with a turn from the low side. */
359 return 0;
361 case ROAD_X:
362 /* A 'sloped' tile is going to be build. */
363 if ((existing_roadbits | new_roadbits) != new_roadbits) {
364 /* There is already a foundation on the tile, or at least
365 * another slope that is not compatible with the new one. */
366 return 0;
368 /* If the start is in the low part, it is automatically
369 * building the second part too. */
370 return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1;
372 default:
373 /* Roadbits causing a foundation are going to be build.
374 * When the existing roadbits are slopes (the lower bits
375 * are used), this cannot be done. */
376 return (existing_roadbits & ROAD_NE) ? 0 : 1;
379 default:
380 NOT_REACHED();
385 * Normalise all input data (tile indices) so we can easily handle it without needing
386 * to call the API lots of times or create large if-elseif-elseif-else constructs.
387 * @param tile The tile to get the orientation from.
388 * @return The orientation or an empty optional when the input is invalid..
390 static std::optional<RoadPartOrientation> ToRoadPartOrientation(const TileIndex &tile)
392 if (tile == ScriptMap::GetTileIndex(0, -1)) return RoadPartOrientation::NW;
393 if (tile == ScriptMap::GetTileIndex(1, 0)) return RoadPartOrientation::SW;
394 if (tile == ScriptMap::GetTileIndex(0, 1)) return RoadPartOrientation::SE;
395 if (tile == ScriptMap::GetTileIndex(-1, 0)) return RoadPartOrientation::NE;
396 return std::nullopt;
399 /* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<TileIndex> &&existing, TileIndex start, TileIndex end)
401 ::Slope slope = (::Slope)slope_;
403 /* The start tile and end tile cannot be the same tile either. */
404 if (start == end) return -1;
406 std::vector<RoadPartOrientation> existing_orientations;
407 existing_orientations.reserve(existing.size());
408 for (const auto &t : existing) {
409 auto orientation = ToRoadPartOrientation(t);
410 if (!orientation) return -1;
411 existing_orientations.push_back(*orientation);
414 auto start_orientation = ToRoadPartOrientation(start);
415 auto end_orientation = ToRoadPartOrientation(end);
416 if (!start_orientation || !end_orientation) return -1;
418 /* Without build on slopes the characteristics are vastly different, so use
419 * a different helper function (one that is much simpler). */
420 return _settings_game.construction.build_on_slopes ?
421 LookupWithBuildOnSlopes(slope, existing_orientations, *start_orientation, *end_orientation) :
422 LookupWithoutBuildOnSlopes(slope, existing_orientations, *start_orientation, *end_orientation);
425 /* static */ SQInteger ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end)
427 if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1;
428 if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1;
430 const TileIndex neighbours[] = {
431 ScriptMap::GetTileIndex(0, -1), // ROAD_NW
432 ScriptMap::GetTileIndex(1, 0), // ROAD_SW
433 ScriptMap::GetTileIndex(0, 1), // ROAD_SE
434 ScriptMap::GetTileIndex(-1, 0), // ROAD_NE
437 ::RoadBits rb = ::ROAD_NONE;
438 if (::IsNormalRoadTile(tile)) {
439 rb = ::GetAllRoadBits(tile);
440 } else {
441 rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM);
444 Array<TileIndex> existing;
445 for (uint i = 0; i < lengthof(neighbours); i++) {
446 if (HasBit(rb, i)) existing.emplace_back(neighbours[i]);
449 return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), std::move(existing), start - tile, end - tile);
453 * Check whether one can reach (possibly by building) a road piece the center
454 * of the neighbouring tile. This includes roads and (drive through) stations.
455 * @param rt The road type we want to know reachability for
456 * @param start_tile The tile to "enter" the neighbouring tile.
457 * @param neighbour The direction to the neighbouring tile to "enter".
458 * @return true if and only if the tile is reachable.
460 static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagDirection neighbour)
462 TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour);
463 if (!HasBit(::GetPresentRoadTypes(neighbour_tile), rt)) return false;
465 switch (::GetTileType(neighbour_tile)) {
466 case MP_ROAD:
467 return (::GetRoadTileType(neighbour_tile) != ROAD_TILE_DEPOT);
469 case MP_STATION:
470 if (::IsDriveThroughStopTile(neighbour_tile)) {
471 return ::DiagDirToAxis(neighbour) == ::GetDriveThroughStopAxis(neighbour_tile);
473 return false;
475 default:
476 return false;
480 /* static */ SQInteger ScriptRoad::GetNeighbourRoadCount(TileIndex tile)
482 if (!::IsValidTile(tile)) return -1;
483 if (!IsRoadTypeAvailable(GetCurrentRoadType())) return -1;
485 ::RoadType rt = (::RoadType)GetCurrentRoadType();
486 int32_t neighbour = 0;
488 if (TileX(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NE)) neighbour++;
489 if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SE)) neighbour++;
490 if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SW)) neighbour++;
491 if (TileY(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NW)) neighbour++;
493 return neighbour;
496 /* static */ TileIndex ScriptRoad::GetRoadDepotFrontTile(TileIndex depot)
498 if (!IsRoadDepotTile(depot)) return INVALID_TILE;
500 return depot + ::TileOffsByDiagDir(::GetRoadDepotDirection(depot));
503 /* static */ TileIndex ScriptRoad::GetRoadStationFrontTile(TileIndex station)
505 if (!IsRoadStationTile(station)) return INVALID_TILE;
507 if (::IsBayRoadStopTile(station)) return station + ::TileOffsByDiagDir(::GetBayRoadStopDir(station));
509 return station - ::TileOffsByAxis(::GetDriveThroughStopAxis(station));
512 /* static */ TileIndex ScriptRoad::GetDriveThroughBackTile(TileIndex station)
514 if (!IsDriveThroughRoadStationTile(station)) return INVALID_TILE;
516 return station + ::TileOffsByAxis(::GetDriveThroughStopAxis(station));
519 /* static */ bool ScriptRoad::_BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full)
521 EnforceDeityOrCompanyModeValid(false);
522 EnforcePrecondition(false, start != end);
523 EnforcePrecondition(false, ::IsValidTile(start));
524 EnforcePrecondition(false, ::IsValidTile(end));
525 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
526 EnforcePrecondition(false, !one_way || RoadTypeIsRoad(ScriptObject::GetRoadType()));
527 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
529 Axis axis = ::TileY(start) != ::TileY(end) ? AXIS_Y : AXIS_X;
530 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);
533 /* static */ bool ScriptRoad::BuildRoad(TileIndex start, TileIndex end)
535 return _BuildRoadInternal(start, end, false, false);
538 /* static */ bool ScriptRoad::BuildOneWayRoad(TileIndex start, TileIndex end)
540 EnforceCompanyModeValid(false);
541 return _BuildRoadInternal(start, end, true, false);
544 /* static */ bool ScriptRoad::BuildRoadFull(TileIndex start, TileIndex end)
546 return _BuildRoadInternal(start, end, false, true);
549 /* static */ bool ScriptRoad::BuildOneWayRoadFull(TileIndex start, TileIndex end)
551 EnforceCompanyModeValid(false);
552 return _BuildRoadInternal(start, end, true, true);
555 /* static */ bool ScriptRoad::BuildRoadDepot(TileIndex tile, TileIndex front)
557 EnforceCompanyModeValid(false);
558 EnforcePrecondition(false, tile != front);
559 EnforcePrecondition(false, ::IsValidTile(tile));
560 EnforcePrecondition(false, ::IsValidTile(front));
561 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
562 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
564 DiagDirection entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? DIAGDIR_SE : DIAGDIR_NW) : (::TileX(tile) < ::TileX(front) ? DIAGDIR_SW : DIAGDIR_NE);
566 return ScriptObject::Command<CMD_BUILD_ROAD_DEPOT>::Do(tile, ScriptObject::GetRoadType(), entrance_dir);
569 /* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
571 EnforceCompanyModeValid(false);
572 EnforcePrecondition(false, tile != front);
573 EnforcePrecondition(false, ::IsValidTile(tile));
574 EnforcePrecondition(false, ::IsValidTile(front));
575 EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front));
576 EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
577 EnforcePrecondition(false, road_veh_type == ROADVEHTYPE_BUS || road_veh_type == ROADVEHTYPE_TRUCK);
578 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
580 DiagDirection entrance_dir = DiagdirBetweenTiles(tile, front);
581 RoadStopType stop_type = road_veh_type == ROADVEHTYPE_TRUCK ? ROADSTOP_TRUCK : ROADSTOP_BUS;
582 StationID to_join = ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION;
583 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);
586 /* static */ bool ScriptRoad::BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
588 return _BuildRoadStationInternal(tile, front, road_veh_type, false, station_id);
591 /* static */ bool ScriptRoad::BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
593 return _BuildRoadStationInternal(tile, front, road_veh_type, true, station_id);
596 /* static */ bool ScriptRoad::RemoveRoad(TileIndex start, TileIndex end)
598 EnforceCompanyModeValid(false);
599 EnforcePrecondition(false, start != end);
600 EnforcePrecondition(false, ::IsValidTile(start));
601 EnforcePrecondition(false, ::IsValidTile(end));
602 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
603 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
605 return ScriptObject::Command<CMD_REMOVE_LONG_ROAD>::Do(end, start, ScriptObject::GetRoadType(), ::TileY(start) != ::TileY(end) ? AXIS_Y : AXIS_X, start < end, start >= end);
608 /* static */ bool ScriptRoad::RemoveRoadFull(TileIndex start, TileIndex end)
610 EnforceCompanyModeValid(false);
611 EnforcePrecondition(false, start != end);
612 EnforcePrecondition(false, ::IsValidTile(start));
613 EnforcePrecondition(false, ::IsValidTile(end));
614 EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end));
615 EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType()));
617 return ScriptObject::Command<CMD_REMOVE_LONG_ROAD>::Do(end, start, ScriptObject::GetRoadType(), ::TileY(start) != ::TileY(end) ? AXIS_Y : AXIS_X, start >= end, start < end);
620 /* static */ bool ScriptRoad::RemoveRoadDepot(TileIndex tile)
622 EnforceCompanyModeValid(false);
623 EnforcePrecondition(false, ::IsValidTile(tile));
624 EnforcePrecondition(false, IsTileType(tile, MP_ROAD))
625 EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT);
627 return ScriptObject::Command<CMD_LANDSCAPE_CLEAR>::Do(tile);
630 /* static */ bool ScriptRoad::RemoveRoadStation(TileIndex tile)
632 EnforceCompanyModeValid(false);
633 EnforcePrecondition(false, ::IsValidTile(tile));
634 EnforcePrecondition(false, IsTileType(tile, MP_STATION));
635 EnforcePrecondition(false, IsStationRoadStop(tile));
637 return ScriptObject::Command<CMD_REMOVE_ROAD_STOP>::Do(tile, 1, 1, GetRoadStopType(tile), false);
640 /* static */ Money ScriptRoad::GetBuildCost(RoadType roadtype, BuildType build_type)
642 if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return -1;
644 switch (build_type) {
645 case BT_ROAD: return ::RoadBuildCost((::RoadType)roadtype);
646 case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, nullptr);
647 case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, nullptr);
648 case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, nullptr);
649 default: return -1;
653 /* static */ ScriptRoad::RoadTramTypes ScriptRoad::GetRoadTramType(RoadType roadtype)
655 return (RoadTramTypes)(1 << ::GetRoadTramType((::RoadType)roadtype));
658 /* static */ SQInteger ScriptRoad::GetMaxSpeed(RoadType road_type)
660 if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return -1;
662 return GetRoadTypeInfo((::RoadType)road_type)->max_speed;
665 /* static */ SQInteger ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype)
667 if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0;
669 return GetRoadTypeInfo((::RoadType)roadtype)->maintenance_multiplier;