mirror of https://github.com/OpenTTD/OpenTTD
Change: Buying and controlling road vehicles in extended road depots.
parent
861de832f6
commit
158c46fcd6
|
@ -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...
|
||||
|
||||
|
|
|
@ -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,21 +2477,51 @@ 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;
|
||||
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
if (rv->frame == RVC_DEPOT_STOP_FRAME &&
|
||||
_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) {
|
||||
rv->state = RVSB_IN_DEPOT;
|
||||
rv->vehstatus |= VS_HIDDEN;
|
||||
rv->direction = ReverseDir(rv->direction);
|
||||
if (rv->Next() == nullptr) VehicleEnterDepot(rv->First());
|
||||
rv->tile = tile;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(rv->tile));
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
/* 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) {
|
||||
rv->state = RVSB_IN_DEPOT;
|
||||
rv->vehstatus |= VS_HIDDEN;
|
||||
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;
|
||||
|
|
|
@ -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,23 +270,43 @@ 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();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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.
|
||||
* @param flags type of operation.
|
||||
|
@ -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 (check.Failed()) return check;
|
||||
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 */
|
||||
trackdirs = TRACKDIR_BIT_NONE;
|
||||
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);
|
||||
const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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];
|
||||
|
||||
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)) {
|
||||
VehicleEnterDepot(v);
|
||||
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;
|
||||
|
||||
v->x_pos = x;
|
||||
v->y_pos = y;
|
||||
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,8 +1678,10 @@ 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->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
|
||||
RoadVehLeaveDepot(v->Next(), false);
|
||||
if ((v->Next()->vehstatus & VS_HIDDEN)) {
|
||||
if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
|
||||
RoadVehLeaveDepot(v->Next(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue