1
0
Fork 0

Change: Buying and controlling road vehicles in extended road depots.

pull/8480/head
J0anJosep 2023-08-26 19:55:15 +02:00
parent 861de832f6
commit 158c46fcd6
4 changed files with 309 additions and 97 deletions

View File

@ -5378,6 +5378,7 @@ STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a
STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger...
STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train...
STR_ERROR_TRAIN_START_NO_POWER :Train has no power
STR_ERROR_ROAD_VEHICLE_START_NO_POWER :Road vehicle has no power
STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Can't make road vehicle turn around...

View File

@ -42,6 +42,7 @@
#include "road_cmd.h"
#include "landscape_cmd.h"
#include "rail_cmd.h"
#include "platform_func.h"
#include "table/strings.h"
#include "table/roadtypes.h"
@ -2476,10 +2477,40 @@ static const uint8_t _roadveh_enter_depot_dir[4] = {
TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE
};
static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int, int)
static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
{
if (GetRoadTileType(tile) != ROAD_TILE_DEPOT || v->type != VEH_ROAD) return VETSB_CONTINUE;
if (IsExtendedRoadDepot(tile)) {
v = v->First();
if (!IsExtendedRoadDepotTile(v->tile)) return VETSB_CONTINUE;
DepotID depot_id = GetDepotIndex(v->tile);
if (!v->current_order.IsType(OT_GOTO_DEPOT) ||
v->current_order.GetDestination() != depot_id) {
return VETSB_CONTINUE;
}
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
if (!IsExtendedRoadDepotTile(u->tile) || GetDepotIndex(u->tile) != depot_id) return VETSB_CONTINUE;
if (!IsDiagonalDirection(u->direction)) return VETSB_CONTINUE;
if (DiagDirToAxis(DirToDiagDir(u->direction)) !=
DiagDirToAxis(GetRoadDepotDirection(v->tile))) {
return VETSB_CONTINUE;
}
}
/* Stop position on platform is half the front vehicle length of the road vehicle. */
int stop_pos = RoadVehicle::From(v)->gcache.cached_veh_length / 2;
DiagDirection dir = DirToDiagDir(v->direction);
int depot_ahead = (GetPlatformLength(tile, dir, GetRoadTramType(RoadVehicle::From(v)->roadtype)) - 1) * TILE_SIZE;
if (depot_ahead > stop_pos) return VETSB_CONTINUE;
x = v->x_pos & 0xF;
y = v->y_pos & 0xF;
if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
if (dir == DIAGDIR_SE || dir == DIAGDIR_SW) x = TILE_SIZE - x;
if (abs(stop_pos - x) <= 1) return VETSB_ENTERED_DEPOT_PLATFORM;
} else {
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->frame == RVC_DEPOT_STOP_FRAME &&
_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) {
@ -2488,10 +2519,10 @@ static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int,
rv->direction = ReverseDir(rv->direction);
if (rv->Next() == nullptr) VehicleEnterDepot(rv->First());
rv->tile = tile;
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(rv->tile));
return VETSB_ENTERED_WORMHOLE;
}
}
return VETSB_CONTINUE;
}

View File

@ -254,11 +254,12 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
/**
* Find an adequate tile for placing an engine.
* @param[in,out] tile A tile of the depot.
* @param[in,out] is_exit_facing_south Whether the depot tile is facing south.
* @param e Engine to be built.
* @param flags Flags of the command.
* @return CommandCost() or an error message if the depot is not appropriate.
* @param already_built Whether the vehicle already exists (for vehicle replacement).
* @return CommandCost() or an error message if the depot has no appropriate tiles.
*/
CommandCost FindDepotTileForPlacingEngine(TileIndex &tile, const Engine *e, DoCommandFlag flags)
CommandCost FindDepotTileForPlacingEngine(TileIndex &tile, bool &is_exit_facing_south, const Engine *e, bool already_built)
{
assert(IsRoadDepotTile(tile));
@ -269,22 +270,42 @@ CommandCost FindDepotTileForPlacingEngine(TileIndex &tile, const Engine *e, DoCo
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
if ((dep->r_types.road_types & rti->powered_roadtypes) == 0) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
/* Use same tile if possible when replacing. */
if (flags & DC_AUTOREPLACE) {
/* Use same tile if possible when replacing. */
if (HasTileAnyRoadType(tile, rti->powered_roadtypes)) return CommandCost();
}
/* Use same tile if possible when replacing or trying to leave the depot. */
if (HasTileAnyRoadType(tile, rti->powered_roadtypes) && already_built) return CommandCost();
tile = INVALID_TILE;
for (auto &depot_tile : dep->depot_tiles) {
if (!HasTileAnyRoadType(depot_tile, rti->powered_roadtypes)) continue;
tile = depot_tile;
break;
}
assert(tile != INVALID_TILE);
for (auto t : dep->depot_tiles) {
if (!HasTileAnyRoadType(t, rti->powered_roadtypes)) continue;
if (!IsExtendedDepot(t)) return CommandCost();
if (GetDepotReservation(t, is_exit_facing_south) == DEPOT_RESERVATION_EMPTY) {
tile = t;
return CommandCost();
} else if (GetDepotReservation(t, !is_exit_facing_south) == DEPOT_RESERVATION_EMPTY) {
is_exit_facing_south = !is_exit_facing_south;
tile = t;
return CommandCost();
}
}
return_cmd_error(STR_ERROR_DEPOT_FULL_DEPOT);
}
DiagDirection GetRoadDepotExit(TileIndex tile, RoadTramType rtt, DiagDirection dir)
{
assert(IsRoadDepot(tile));
RoadBits rb = GetRoadBits(tile, rtt);
if ((rb & DiagDirToRoadBits(dir)) != ROAD_NONE) return dir;
if (rb & ROAD_SE) return DIAGDIR_SE;
if (rb & ROAD_SW) return DIAGDIR_SW;
if (rb & ROAD_NE) return DIAGDIR_NE;
if (rb & ROAD_NW) return DIAGDIR_NW;
return INVALID_DIAGDIR;
}
struct RoadDriveEntry {
uint8_t x, y;
};
#include "table/roadveh_movement.h"
/**
* Build a road vehicle.
@ -299,24 +320,36 @@ CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engin
assert(IsRoadDepotTile(tile));
RoadType rt = e->u.road.roadtype;
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
DiagDirection dir = GetRoadDepotExit(tile, RoadTramType(rt), GetRoadDepotDirection(tile));
bool facing_south = IsValidDiagDirection(dir) ? IsDiagDirFacingSouth(dir) : false;
CommandCost check = FindDepotTileForPlacingEngine(tile, e, flags);
if ((flags & DC_AUTOREPLACE) == 0) {
CommandCost check = FindDepotTileForPlacingEngine(tile, facing_south, e, false);
if (check.Failed()) return check;
dir = GetRoadDepotExit(tile, RoadTramType(rt), GetRoadDepotDirection(tile));
}
if (IsExtendedRoadDepotTile(tile) && facing_south != IsDiagDirFacingSouth(dir)) dir = ReverseDiagDir(dir);
if (flags & DC_EXEC) {
const RoadVehicleInfo *rvi = &e->u.road;
RoadVehicle *v = new RoadVehicle();
*ret = v;
v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
v->direction = DiagDirToDir(dir);
v->owner = _current_company;
v->tile = tile;
int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
v->x_pos = x;
v->y_pos = y;
v->z_pos = GetSlopePixelZ(x, y, true);
if (IsExtendedRoadDepotTile(tile)) {
const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(rt)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + DiagDirToDiagTrackdir(dir)];
v->frame = RVC_DEPOT_START_FRAME;
v->x_pos = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
v->y_pos = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
} else {
v->x_pos = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
v->y_pos = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
}
v->z_pos = GetSlopePixelZ(v->x_pos, v->y_pos, true);
v->state = RVSB_IN_DEPOT;
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
@ -360,6 +393,7 @@ CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engin
for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
u->refit_cap = 0;
u->state = RVSB_IN_DEPOT;
v->InvalidateNewGRFCache();
u->InvalidateNewGRFCache();
}
@ -369,6 +403,12 @@ CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engin
v->UpdatePosition();
if (IsExtendedDepot(v->tile) && (flags & DC_AUTOREPLACE) == 0) {
v->vehstatus &= ~VS_HIDDEN;
UpdateExtendedDepotReservation(v, true);
v->UpdateViewport(true, true);
}
CheckConsistencyOfArticulatedVehicle(v);
}
@ -654,7 +694,7 @@ struct RoadVehFindData {
static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
{
if (v->type != VEH_ROAD || v->IsInDepot()) return nullptr;
if (v->type != VEH_ROAD || (v->vehstatus & VS_HIDDEN) == 0) return nullptr;
RoadVehFindData *rvf = (RoadVehFindData*)data;
@ -843,7 +883,7 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
{
const OvertakeData *od = (OvertakeData*)data;
return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : nullptr;
return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v && ((v->vehstatus & VS_HIDDEN) == 0)) ? v : nullptr;
}
/**
@ -880,6 +920,9 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
/* Don't overtake in stations */
if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
/* Don't overtake in road depot platforms. */
if (IsExtendedRoadDepotTile(v->tile)) return;
/* For now, articulated road vehicles can't overtake anything. */
if (v->HasArticulatedPart()) return;
@ -961,9 +1004,17 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection
TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
if (IsTileType(tile, MP_ROAD)) {
if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) {
/* Road depot owned by another company or with the wrong orientation */
if (IsRoadDepot(tile)) {
if (!IsTileOwner(tile, v->owner)) {
trackdirs = TRACKDIR_BIT_NONE;
} else if (IsExtendedRoadDepotTile(tile)) {
if (tile != v->tile) {
RoadBits rb = GetRoadBits(tile, GetRoadTramType(v->roadtype)) & DiagDirToRoadBits(ReverseDiagDir(enterdir));
if (rb == ROAD_NONE) trackdirs = TRACKDIR_BIT_NONE;
}
} else if (GetRoadDepotDirection(tile) == enterdir) { // Standard depot
trackdirs = TRACKDIR_BIT_NONE;
}
}
} else if (IsTileType(tile, MP_STATION) && IsBayRoadStopTile(tile)) {
/* Standard road stop (drive-through stops are treated as normal road) */
@ -1065,60 +1116,118 @@ found_best_track:;
return best_track;
}
struct RoadDriveEntry {
uint8_t x, y;
};
void HandleRoadVehicleEnterDepot(RoadVehicle *v)
{
assert(IsRoadDepotTile(v->tile));
#include "table/roadveh_movement.h"
if (IsExtendedRoadDepot(v->tile)) {
assert(v == v->First());
for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
assert(u->direction == v->direction);
assert(IsExtendedRoadDepotTile(u->tile));
assert(GetDepotIndex(u->tile) == GetDepotIndex(v->tile));
u->state = RVSB_IN_DEPOT;
u->cur_speed = 0;
u->UpdateViewport(true, true); // revise: probably unneded
}
v->StartService();
UpdateExtendedDepotReservation(v, true);
SetWindowClassesDirty(WC_ROADVEH_LIST);
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
} else {
VehicleEnterDepot(v);
}
}
bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
{
/* Don't leave unless v and following wagons are in the depot. */
for (const RoadVehicle *u = v; u != nullptr; u = u->Next()) {
if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
if (!u->IsInDepot()) return false;
}
DiagDirection dir = GetRoadDepotDirection(v->tile);
v->direction = DiagDirToDir(dir);
bool visible_vehicle = first && (v->vehstatus & VS_HIDDEN) == 0;
Trackdir tdir = DiagDirToDiagTrackdir(dir);
if (first && (v->vehstatus & VS_HIDDEN) != 0) {
TileIndex new_tile = v->tile;
bool facing_south = IsDiagDirFacingSouth(DirToDiagDir(v->direction));
if (FindDepotTileForPlacingEngine(new_tile, facing_south, Engine::Get(v->engine_type), true).Failed()) return false;
if (IsExtendedDepot(v->tile)) {
UpdateExtendedDepotReservation(v, false);
v->tile = new_tile;
UpdateExtendedDepotReservation(v, true);
}
DiagDirection dir = GetRoadDepotExit(v->tile, RoadTramType(v->roadtype), DirToDiagDir(v->direction));
if (facing_south != IsDiagDirFacingSouth(dir)) dir = ReverseDiagDir(dir);
assert(dir != INVALID_DIAGDIR);
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->direction = DiagDirToDir(dir);
u->tile = v->tile;
}
}
int x = v->x_pos;
int y = v->y_pos;
Trackdir tdir = v->GetVehicleTrackdir();
if ((v->vehstatus & VS_HIDDEN) != 0) {
const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
}
if (first) {
/* We are leaving a depot, but have to go to the exact same one; re-enter */
if (v->current_order.IsType(OT_GOTO_DEPOT) &&
IsRoadDepotTile(v->tile) &&
v->current_order.GetDestination() == GetDepotIndex(v->tile)) {
if (IsExtendedRoadDepot(v->tile)) {
v->StartService();
} else {
VehicleEnterDepot(v);
}
return true;
}
if (RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true;
if ((v->vehstatus & VS_HIDDEN) != 0 && RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true;
VehicleServiceInDepot(v);
v->LeaveUnbunchingDepot();
StartRoadVehSound(v);
/* Vehicle is about to leave a depot */
/* Vehicle is about to leave a depot. */
v->cur_speed = 0;
}
v->vehstatus &= ~VS_HIDDEN;
v->state = tdir;
v->frame = RVC_DEPOT_START_FRAME;
if ((v->vehstatus & VS_HIDDEN) != 0) {
v->vehstatus &= ~VS_HIDDEN;
v->x_pos = x;
v->y_pos = y;
v->frame = RVC_DEPOT_START_FRAME;
} else if (v->Next() != nullptr && (v->Next()->vehstatus & VS_HIDDEN) == 0){
for (RoadVehicle *u = v->Next(); u != nullptr; u = u->Next()) {
u->state = DiagDirToDiagTrackdir(DirToDiagDir(u->direction));
u->UpdatePosition();
u->UpdateInclination(true, true);
}
}
v->UpdatePosition();
v->UpdateInclination(true, true);
if (first && IsExtendedDepot(v->tile)) {
UpdateExtendedDepotReservation(v, false);
}
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
return true;
return !visible_vehicle;
}
static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
@ -1138,7 +1247,7 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
diag_dir = GetTunnelBridgeDirection(tile);
} else if (IsRoadDepotTile(tile)) {
diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
diag_dir = ReverseDiagDir(IsExtendedRoadDepot(tile) ? DirToDiagDir(v->direction) : GetRoadDepotDirection(tile));
}
if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
@ -1206,6 +1315,53 @@ static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadB
return ret.Succeeded();
}
/** Check whether there is a close vehicle ahead and act as needed.
* @param v Moving vehicle
* @param x x coordinate to check
* @param y y coordinate to check
* @param dir direction of the vehicle
* @return whether a close vehicle is found.
*/
bool CheckCloseVehicle(RoadVehicle *v, int x, int y, Direction dir)
{
if (!v->IsFrontEngine() || IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) return false;
/* Vehicle is not in a road stop.
* Check for another vehicle to overtake */
RoadVehicle *u = RoadVehFindCloseTo(v, x, y, dir);
if (u == nullptr) return false;
assert(u == u->First());
/* There is a vehicle in front overtake it if possible */
if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
if (v->overtaking == 0) v->cur_speed = u->cur_speed;
/* In case we are in a road depot platform, why not try to start servicing? */
if (IsExtendedRoadDepotTile(v->tile) && v->current_order.IsType(OT_GOTO_DEPOT)) {
DepotID depot_id = GetDepotIndex(v->tile);
if (v->current_order.GetDestination() != depot_id) return true;
if (!u->IsInDepot() || GetDepotIndex(u->tile) != depot_id) return true;
for (u = v; u != nullptr; u = u->Next()) {
if (!IsExtendedRoadDepotTile(u->tile) || GetDepotIndex(u->tile) != depot_id) return true;
if (v->direction != u->direction) return true;
}
HandleRoadVehicleEnterDepot(v);
return true;
}
/* In case an RV is stopped in a road stop, why not try to load? */
if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
Station *st = Station::GetByTile(v->tile);
v->last_station_visited = st->index;
RoadVehArrivesAt(v, st);
v->BeginLoading();
}
return true;
}
bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
{
if (v->overtaking != 0) {
@ -1264,18 +1420,21 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
if (rd.x & RDE_NEXT_TILE) {
TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
DiagDirection diag_dir = (DiagDirection)(rd.x & 3);
TileIndex tile = v->tile + TileOffsByDiagDir(diag_dir);
Trackdir dir;
bool extended_depot_turn = IsExtendedRoadDepotTile(v->tile) &&
(GetRoadBits(v->tile, GetRoadTramType(v->roadtype)) & DiagDirToRoadBits(diag_dir)) == ROAD_NONE;
if (v->IsFrontEngine()) {
/* If this is the front engine, look for the right path. */
if (HasTileAnyRoadType(tile, v->compatible_roadtypes)) {
dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
if (HasTileAnyRoadType(tile, v->compatible_roadtypes) && !extended_depot_turn) {
dir = RoadFindPathToDest(v, tile, diag_dir);
} else {
dir = _road_reverse_table[(DiagDirection)(rd.x & 3)];
dir = _road_reverse_table[diag_dir];
}
} else {
dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
dir = FollowPreviousRoadVehicle(v, prev, tile, diag_dir, false);
}
if (dir == INVALID_TRACKDIR) {
@ -1302,7 +1461,10 @@ again:
case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
}
if ((v->Previous() != nullptr && v->Previous()->tile == tile) ||
if (extended_depot_turn) {
tile = v->tile;
start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
} else if ((v->Previous() != nullptr && v->Previous()->tile == tile) ||
(v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
HasTileAnyRoadType(tile, v->compatible_roadtypes) &&
(needed & GetRoadBits(tile, RTT_TRAM)) != ROAD_NONE)) {
@ -1319,8 +1481,9 @@ again:
} else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, v->roadtype, needed) || ((~needed & GetAnyRoadBits(v->tile, RTT_TRAM, false)) == ROAD_NONE)) {
/*
* Taking the 'small' corner for trams only happens when:
* - We are not the from vehicle of an articulated tram.
* - We are not the front vehicle of an articulated tram.
* - Or when the company cannot build on the next tile.
* - Or when the extended depot doesn't have the appropriate tram bit to continue.
*
* The 'small' corner means that the vehicle is on the end of a
* tram track and needs to start turning there. To do this properly
@ -1363,6 +1526,11 @@ again:
}
uint32_t r = VehicleEnterTile(v, tile, x, y);
if (HasBit(r, VETS_ENTERED_DEPOT_PLATFORM) && v->Next() == nullptr && v == v->First()) {
HandleRoadVehicleEnterDepot(RoadVehicle::From(v));
return false;
}
if (HasBit(r, VETS_CANNOT_ENTER)) {
if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
v->cur_speed = 0;
@ -1419,6 +1587,9 @@ again:
}
v->x_pos = x;
v->y_pos = y;
if (prev != nullptr && prev->IsInDepot() && (prev->vehstatus & VS_HIDDEN) == 0) {
v->state = RVSB_IN_DEPOT;
}
v->UpdatePosition();
RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
return true;
@ -1429,7 +1600,7 @@ again:
Trackdir dir;
uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, RTT_TRAM, true))) {
if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && !IsExtendedRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, RTT_TRAM, true))) {
/*
* The tram is turning around with one tram 'roadbit'. This means that
* it is using the 'big' corner 'drive data'. However, to support the
@ -1495,6 +1666,9 @@ again:
v->x_pos = x;
v->y_pos = y;
if (prev != nullptr && prev->IsInDepot() && (prev->vehstatus & VS_HIDDEN) == 0) {
v->state = RVSB_IN_DEPOT;
}
v->UpdatePosition();
RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
return true;
@ -1504,10 +1678,12 @@ again:
* it's on a depot tile, check if it's time to activate the next vehicle in
* the chain yet. */
if (v->Next() != nullptr && IsRoadDepotTile(v->tile)) {
if ((v->Next()->vehstatus & VS_HIDDEN)) {
if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
RoadVehLeaveDepot(v->Next(), false);
}
}
}
/* Calculate new position for the vehicle */
int x = (v->x_pos & ~15) + (rd.x & 15);
@ -1515,30 +1691,7 @@ again:
Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
/* Vehicle is not in a road stop.
* Check for another vehicle to overtake */
RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
if (u != nullptr) {
assert(u == u->First());
/* There is a vehicle in front overtake it if possible */
if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
if (v->overtaking == 0) v->cur_speed = u->cur_speed;
/* In case an RV is stopped in a road stop, why not try to load? */
if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
Station *st = Station::GetByTile(v->tile);
v->last_station_visited = st->index;
RoadVehArrivesAt(v, st);
v->BeginLoading();
}
return false;
}
}
if (CheckCloseVehicle(v, x, y, new_dir)) return false;
Direction old_dir = v->direction;
if (new_dir != old_dir) {
@ -1634,6 +1787,16 @@ again:
v->y_pos = y;
v->UpdatePosition();
RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
/* After updating the position, check whether the vehicle can stop in a depot platform. */
if (IsExtendedRoadDepotTile(v->tile) && v->Next() == nullptr) {
RoadVehicle *first = RoadVehicle::From(v)->First();
if (HasBit(VehicleEnterTile(first, first->tile, first->x_pos, first->y_pos), VETS_ENTERED_DEPOT_PLATFORM)) {
HandleRoadVehicleEnterDepot(first);
return false;
}
}
return true;
}
@ -1655,6 +1818,8 @@ static bool RoadVehController(RoadVehicle *v)
return true;
}
if (v->ContinueServicing()) return true;
ProcessOrders(v);
v->HandleLoading();
@ -1816,6 +1981,9 @@ Trackdir RoadVehicle::GetVehicleTrackdir() const
if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
if (this->IsInDepot()) {
if (IsExtendedRoadDepot(this->tile)) {
return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
}
/* We'll assume the road vehicle is facing outwards */
return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
}

View File

@ -253,6 +253,9 @@ CommandCost CmdSellVehicle(DoCommandFlag flags, VehicleID v_id, bool sell_chain,
ret = CommandCost(EXPENSES_NEW_VEHICLES, -front->value);
if (flags & DC_EXEC) {
if (front->type == VEH_ROAD && IsExtendedDepot(v->tile) && (flags & DC_AUTOREPLACE) == 0) {
UpdateExtendedDepotReservation(v, false);
}
if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id);
delete front;
}
@ -610,7 +613,16 @@ CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool eval
}
case VEH_SHIP:
break;
case VEH_ROAD:
if ((v->vehstatus & VS_STOPPED) && !(flags & DC_AUTOREPLACE) && v->IsStoppedInDepot()) {
Depot *dep = Depot:: GetByTile(v->tile);
/* Check that the vehicle can drive on some tile of the depot */
RoadType rt = Engine::Get(v->engine_type)->u.road.roadtype;
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
if ((dep->r_types.road_types & rti->powered_roadtypes) == 0) return_cmd_error(STR_ERROR_ROAD_VEHICLE_START_NO_POWER);
}
break;
case VEH_AIRCRAFT: {