1
0
Fork 0

Change: Check whether to stay in an extended rail depot or place the train and reverse if appropriate.

pull/8480/head
J0anJosep 2023-04-22 21:29:44 +02:00
parent 0619cb633a
commit dfe6be59f4
4 changed files with 138 additions and 96 deletions

View File

@ -817,7 +817,7 @@ struct DepotWindow : Window {
case WID_D_STOP_ALL: case WID_D_STOP_ALL:
case WID_D_START_ALL: { case WID_D_START_ALL: {
VehicleListIdentifier vli(VL_DEPOT_LIST, this->type, this->owner); VehicleListIdentifier vli(VL_DEPOT_LIST, this->type, this->owner);
Command<CMD_MASS_START_STOP>::Post(tile, widget == WID_D_START_ALL, false, vli); Command<CMD_MASS_START_STOP>::Post(STR_ERROR_CAN_T_START_STOP_VEHICLES, tile, widget == WID_D_START_ALL, false, vli);
break; break;
} }

View File

@ -5160,6 +5160,7 @@ STR_ERROR_DEPOT_TYPE_NOT_AVAILABLE :{WHITE}... depo
STR_ERROR_DEPOT_EXTENDING_PLATFORMS :{WHITE}Extending already reserved depot platforms STR_ERROR_DEPOT_EXTENDING_PLATFORMS :{WHITE}Extending already reserved depot platforms
STR_ERROR_DEPOT_EXTENDED_RAIL_DEPOT_IS_NOT_FREE :{WHITE}Extended rail depot has a reserved tile and can't be converted STR_ERROR_DEPOT_EXTENDED_RAIL_DEPOT_IS_NOT_FREE :{WHITE}Extended rail depot has a reserved tile and can't be converted
STR_ERROR_CAN_T_START_STOP_VEHICLES :{WHITE}Can't start at least one vehicle in the depot...
STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Can't rename depot... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Can't rename depot...
STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot

View File

@ -882,6 +882,10 @@ CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engin
UpdateTrainGroupID(v); UpdateTrainGroupID(v);
CheckConsistencyOfArticulatedVehicle(v); CheckConsistencyOfArticulatedVehicle(v);
TrainPlacement train_placement;
train_placement.LiftTrain(v, flags);
train_placement.PlaceTrain(v, flags);
} }
return CommandCost(); return CommandCost();
@ -1050,82 +1054,6 @@ static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *origina
return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
} }
/**
* Check if a train can be placed in a depot tile.
* @param train The train.
* @param tile The tile to check whether it is possible to place the train.
* @return whether it found a depot tile in which to place the train.
*/
bool CheckPlacement(const Train *train, TileIndex tile)
{
assert(train != nullptr);
assert(IsRailDepotTile(tile));
RailType rt = GetRailType(tile);
for (const Train *t = train; t != nullptr; t = t->Next()) {
RailType rail_type = Engine::Get(t->engine_type)->u.rail.railtype;
if (!IsCompatibleRail(rail_type, rt)) return false;
}
return true;
}
/**
* Find a valid tile before placing a train in the depot.
* @param t The train to place in a rail depot tile.
* @return a compatible tile, if any, preferabily the one the first vehicle is or INVALID_TILE if none found.
*/
TileIndex LookForTileInDepot(const Train *train)
{
assert(train != nullptr);
assert(IsRailDepotTile(train->tile));
TileIndex best_tile = INVALID_TILE;
/* First candidate is the original position of the train. */
if (CheckPlacement(train, train->tile)) {
if (HasPowerOnRail(train->railtype, GetRailType(train->tile))) return train->tile;
best_tile = train->tile;
}
/* Check all depot tiles. */
Depot *depot = Depot::GetByTile(train->tile);
for (std::vector<TileIndex>::iterator it = depot->depot_tiles.begin(); it != depot->depot_tiles.end(); ++it) {
if (CheckPlacement(train, *it)) {
if (HasPowerOnRail(train->railtype, GetRailType(*it))) return *it;
if (best_tile == INVALID_TILE) best_tile = *it;
}
}
return best_tile;
}
/**
* Find an appropriate depot tile for a train and place
* all the vehicle chain in the same depot tile.
* @param train The train to place.
*/
void PlaceOnRailDepot(Train *train)
{
assert(train->First() == train);
TileIndex depot_tile = LookForTileInDepot(train);
assert(depot_tile != INVALID_TILE);
DiagDirection diag_dir = GetRailDepotDirection(depot_tile);
int x = TileX(depot_tile) * TILE_SIZE + _vehicle_initial_x_fract[diag_dir];
int y = TileY(depot_tile) * TILE_SIZE + _vehicle_initial_y_fract[diag_dir];
for (Train *t = train; t != nullptr; t = t->Next()) {
t->tile = depot_tile;
t->direction = DiagDirToDir(diag_dir);
t->vehstatus |= VS_HIDDEN;
t->track = TRACK_BIT_DEPOT;
t->x_pos = x;
t->y_pos = y;
t->z_pos = GetSlopePixelZ(x, y);
t->UpdatePosition();
}
}
/** /**
* Check whether the train parts can be attached. * Check whether the train parts can be attached.
* @param t the train to check * @param t the train to check
@ -1136,7 +1064,9 @@ static CommandCost CheckTrainAttachment(Train *t)
/* No multi-part train, no need to check. */ /* No multi-part train, no need to check. */
if (t == nullptr || t->Next() == nullptr) return CommandCost(); if (t == nullptr || t->Next() == nullptr) return CommandCost();
if (LookForTileInDepot(t) == INVALID_TILE) return_cmd_error(STR_ERROR_INCOMPATIBLE_RAILTYPES_WITH_DEPOT); TrainPlacement tp;
tp.LookForPlaceInDepot(t, false);
if (tp.info == PI_FAILED_PLATFORM_TYPE) return_cmd_error(STR_ERROR_INCOMPATIBLE_RAILTYPES_WITH_DEPOT);
/* The maximum length for a train. For each part we decrease this by one /* The maximum length for a train. For each part we decrease this by one
* and if the result is negative the train is simply too long. */ * and if the result is negative the train is simply too long. */
@ -1414,6 +1344,13 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID
bool original_src_head_front_engine = original_src_head->IsFrontEngine(); bool original_src_head_front_engine = original_src_head->IsFrontEngine();
bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine(); bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine();
TrainPlacement train_placement_src;
TrainPlacement train_placement_dst;
train_placement_src.LiftTrain(src_head, flags);
train_placement_dst.LiftTrain(dst_head, flags);
assert(src_head != nullptr);
/* (Re)arrange the trains in the wanted arrangement. */ /* (Re)arrange the trains in the wanted arrangement. */
ArrangeTrains(&dst_head, dst, &src_head, src, move_chain); ArrangeTrains(&dst_head, dst, &src_head, src, move_chain);
@ -1426,6 +1363,8 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID
/* Restore the train we had. */ /* Restore the train we had. */
RestoreTrainBackup(original_src); RestoreTrainBackup(original_src);
RestoreTrainBackup(original_dst); RestoreTrainBackup(original_dst);
train_placement_src.PlaceTrain(original_src_head, flags & ~DC_EXEC);
if (src_head != dst_head) train_placement_dst.PlaceTrain(original_dst_head, flags & ~DC_EXEC);
return ret; return ret;
} }
} }
@ -1503,15 +1442,14 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID
CheckCargoCapacity(dst_head); CheckCargoCapacity(dst_head);
} }
if (src_head != nullptr) { if (src_head != nullptr) src_head->First()->MarkDirty();
PlaceOnRailDepot(src_head->First()); if (dst_head != nullptr) dst_head->First()->MarkDirty();
src_head->First()->MarkDirty();
}
if (dst_head != nullptr) { bool reverse_emplacement_order = !train_placement_src.placed && train_placement_dst.placed;
PlaceOnRailDepot(dst_head->First());
dst_head->First()->MarkDirty(); if (!reverse_emplacement_order) train_placement_src.PlaceTrain(src_head, flags);
} if (src_head != dst_head) train_placement_dst.PlaceTrain(dst_head, flags);
if (reverse_emplacement_order) train_placement_src.PlaceTrain(src_head, flags);
/* We are undoubtedly changing something in the depot and train list. */ /* We are undoubtedly changing something in the depot and train list. */
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(src->tile)); InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(src->tile));
@ -1520,6 +1458,8 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID
/* We don't want to execute what we're just tried. */ /* We don't want to execute what we're just tried. */
RestoreTrainBackup(original_src); RestoreTrainBackup(original_src);
RestoreTrainBackup(original_dst); RestoreTrainBackup(original_dst);
train_placement_src.PlaceTrain(original_src_head, flags);
if (src_head != dst_head) train_placement_dst.PlaceTrain(original_dst_head, flags);
} }
return CommandCost(); return CommandCost();
@ -1544,6 +1484,9 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, b
if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT); if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
TrainPlacement train_placement;
train_placement.LiftTrain(first, flags);
/* First make a backup of the order of the train. That way we can do /* First make a backup of the order of the train. That way we can do
* whatever we want with the order and later on easily revert. */ * whatever we want with the order and later on easily revert. */
TrainList original; TrainList original;
@ -1561,12 +1504,14 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, b
if (ret.Failed()) { if (ret.Failed()) {
/* Restore the train we had. */ /* Restore the train we had. */
RestoreTrainBackup(original); RestoreTrainBackup(original);
train_placement.PlaceTrain(first, flags);
return ret; return ret;
} }
if (first->orders == nullptr && !OrderList::CanAllocateItem()) { if (first->orders == nullptr && !OrderList::CanAllocateItem()) {
/* Restore the train we had. */ /* Restore the train we had. */
RestoreTrainBackup(original); RestoreTrainBackup(original);
train_placement.PlaceTrain(first, flags);
return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
} }
@ -1596,6 +1541,7 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, b
/* We need to update the information about the train. */ /* We need to update the information about the train. */
NormaliseTrainHead(new_head); NormaliseTrainHead(new_head);
train_placement.PlaceTrain(new_head, flags);
/* We are undoubtedly changing something in the depot and train list. */ /* We are undoubtedly changing something in the depot and train list. */
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile)); InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
@ -1604,8 +1550,9 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, b
/* Actually delete the sold 'goods' */ /* Actually delete the sold 'goods' */
delete sell_head; delete sell_head;
} else { } else {
/* We don't want to execute what we're just tried. */ /* We don't want to execute what we have just tried. */
RestoreTrainBackup(original); RestoreTrainBackup(original);
train_placement.PlaceTrain(first, flags);
} }
return cost; return cost;
@ -2116,7 +2063,11 @@ static bool IsWholeTrainInsideDepot(const Train *v)
void ReverseTrainDirection(Train *v) void ReverseTrainDirection(Train *v)
{ {
if (IsRailDepotTile(v->tile)) { if (IsRailDepotTile(v->tile)) {
if (IsWholeTrainInsideDepot(v)) return; if (IsExtendedDepot(v->tile)) {
if ((v->track & TRACK_BIT_DEPOT) != 0 && (v->track & ~TRACK_BIT_DEPOT) != 0) return;
} else {
if (IsWholeTrainInsideDepot(v)) return;
}
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile)); InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
} }
@ -2230,7 +2181,14 @@ CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool
ToggleBit(v->flags, VRF_REVERSE_DIRECTION); ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
front->ConsistChanged(CCF_ARRANGE); front->ConsistChanged(CCF_ARRANGE);
if (IsRailDepotTile(front->tile)) SetWindowDirty(WC_VEHICLE_DEPOT, GetDepotIndex(front->tile)); if (IsRailDepotTile(front->tile)) {
if (IsExtendedDepot(front->tile)) {
TrainPlacement tp;
tp.LiftTrain(front, flags);
tp.PlaceTrain(front, flags & ~DC_EXEC);
}
SetWindowDirty(WC_VEHICLE_DEPOT, GetDepotIndex(front->tile));
}
SetWindowDirty(WC_VEHICLE_DETAILS, front->index); SetWindowDirty(WC_VEHICLE_DETAILS, front->index);
SetWindowDirty(WC_VEHICLE_VIEW, front->index); SetWindowDirty(WC_VEHICLE_VIEW, front->index);
SetWindowClassesDirty(WC_TRAINS_LIST); SetWindowClassesDirty(WC_TRAINS_LIST);
@ -2240,6 +2198,9 @@ CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool
if (!v->IsPrimaryVehicle()) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR;
if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR; if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
/* Do not reverse while servicing. */
if (IsExtendedRailDepotTile(v->tile) && (v->track & TRACK_BIT_DEPOT) != 0 && (v->track & ~TRACK_BIT_DEPOT) != 0) return CMD_ERROR;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
/* Properly leave the station if we are loading and won't be loading anymore */ /* Properly leave the station if we are loading and won't be loading anymore */
if (v->current_order.IsType(OT_LOADING)) { if (v->current_order.IsType(OT_LOADING)) {
@ -2468,15 +2429,62 @@ static bool CheckTrainStayInDepot(Train *v)
DepotID depot_id = GetDepotIndex(v->tile); DepotID depot_id = GetDepotIndex(v->tile);
if (IsExtendedRailDepot(v->tile)) { if (IsExtendedRailDepot(v->tile)) {
for (Train *u = v; u != nullptr; u = u->Next()) u->track &= ~TRACK_BIT_DEPOT; /* If not placed, try it. If not possible, exit. */
v->cur_speed = 0; if (CheckIfTrainNeedsPlacement(v)) {
/* If stuck, wait a little bit, so we can avoid
* trying placing it as much as we can. */
bool already_stuck = false;
bool send_message = false;
if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
already_stuck = true;
v->wait_counter++;
if (v->wait_counter % (1 << 7) != 0) {
return true;
} else if (v->wait_counter % (1 << 11) == 0) {
send_message = true;
}
ClrBit(v->flags, VRF_TRAIN_STUCK);
}
v->UpdatePosition(); TrainPlacement train_placement;
v->UpdateViewport(true, true); train_placement.LiftTrain(v, DC_EXEC);
train_placement.LookForPlaceInDepot(v, true);
if (train_placement.info < PI_FAILED_END) {
if (send_message) {
ClrBit(v->flags, VRF_TRAIN_STUCK);
/* Show message to player. */
if (_settings_client.gui.lost_vehicle_warn && v->owner == _local_company) {
SetDParam(0, v->index);
AddVehicleAdviceNewsItem(STR_ADVICE_PLATFORM_TYPE + train_placement.info - PI_ERROR_BEGIN, v->index);
}
}
if (already_stuck) {
SetBit(v->flags, VRF_TRAIN_STUCK);
} else {
MarkTrainAsStuck(v);
}
return true;
} else {
VehicleServiceInExtendedDepot(v);
train_placement.PlaceTrain(v, DC_EXEC);
if (!IsExtendedDepot(v->tile)) return true;
}
} else {
VehicleServiceInExtendedDepot(v);
}
for (Train *u = v; u != nullptr; u = u->Next()) u->track &= ~TRACK_BIT_DEPOT;
v->cur_speed = 0;
v->UpdateAcceleration(); v->UpdateAcceleration();
ProcessOrders(v); ProcessOrders(v);
if (CheckReverseTrain(v)) ReverseTrainDirection(v); if (CheckReverseTrain(v)) ReverseTrainDirection(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id); InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id);
/* Check whether it is safe to exit the depot. */
if (UpdateSignalsOnSegment(v->tile, VehicleExitDir(v->direction, v->track), v->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
if (!TryPathReserve(v, true, true)) return true;
}
return false; return false;
} else { } else {
for (const Train *u = v; u != nullptr; u = u->Next()) { for (const Train *u = v; u != nullptr; u = u->Next()) {

View File

@ -38,6 +38,8 @@
#include "train_cmd.h" #include "train_cmd.h"
#include "ship_cmd.h" #include "ship_cmd.h"
#include "depot_base.h" #include "depot_base.h"
#include "train_placement.h"
#include "strings_func.h"
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
@ -523,6 +525,11 @@ std::tuple<CommandCost, uint, uint16_t, CargoArray> CmdRefitVehicle(DoCommandFla
/* For ships and aircraft there is always only one. */ /* For ships and aircraft there is always only one. */
only_this |= front->type == VEH_SHIP || front->type == VEH_AIRCRAFT; only_this |= front->type == VEH_SHIP || front->type == VEH_AIRCRAFT;
/* If it is a train on a depot, lift it. New length of the vehicle won't be checked. */
Train *train = (v->type == VEH_TRAIN && IsDepotTile(front->tile)) ? Train::From(front) : nullptr;
TrainPlacement train_placement;
train_placement.LiftTrain(train, flags);
auto [cost, refit_capacity, mail_capacity, cargo_capacities] = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit); auto [cost, refit_capacity, mail_capacity, cargo_capacities] = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit);
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
@ -560,6 +567,9 @@ std::tuple<CommandCost, uint, uint16_t, CargoArray> CmdRefitVehicle(DoCommandFla
v->InvalidateNewGRFCacheOfChain(); v->InvalidateNewGRFCacheOfChain();
} }
/* If it is a train on an extended depot, try placing it. */
train_placement.PlaceTrain(train, flags);
return { cost, refit_capacity, mail_capacity, cargo_capacities }; return { cost, refit_capacity, mail_capacity, cargo_capacities };
} }
@ -584,9 +594,20 @@ CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool eval
if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED);
switch (v->type) { switch (v->type) {
case VEH_TRAIN: case VEH_TRAIN: {
if ((v->vehstatus & VS_STOPPED) && Train::From(v)->gcache.cached_power == 0) return_cmd_error(STR_ERROR_TRAIN_START_NO_POWER); Train *t = Train::From(v);
if ((v->vehstatus & VS_STOPPED) && t->gcache.cached_power == 0) return_cmd_error(STR_ERROR_TRAIN_START_NO_POWER);
/* Train cannot leave until changing the depot. Stop the train and send a message. */
if (!(flags & DC_AUTOREPLACE) && v->IsStoppedInDepot() && CheckIfTrainNeedsPlacement(t)) {
TrainPlacement train_placement;
if (!train_placement.CanFindAppropriatePlatform(t, (flags & DC_EXEC) != 0)) {
SetDParam(0, v->index);
return_cmd_error(STR_ERROR_CAN_T_START_PLATFORM_TYPE + train_placement.info - PI_FAILED_PLATFORM_TYPE);
}
}
break; break;
}
case VEH_SHIP: case VEH_SHIP:
case VEH_ROAD: case VEH_ROAD:
@ -638,6 +659,11 @@ CommandCost CmdStartStopVehicle(DoCommandFlag flags, VehicleID veh_id, bool eval
/* Unbunching data is no longer valid. */ /* Unbunching data is no longer valid. */
v->ResetDepotUnbunching(); v->ResetDepotUnbunching();
if (v->type == VEH_TRAIN && v->IsInDepot() && IsExtendedDepotTile(v->tile)) {
if ((v->vehstatus & VS_STOPPED) != 0) FreeTrainTrackReservation(Train::From(v));
UpdateExtendedDepotReservation(v, true);
}
v->MarkDirty(); v->MarkDirty();
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
if (IsDepotTile(v->tile)) SetWindowDirty(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile)); if (IsDepotTile(v->tile)) SetWindowDirty(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
@ -677,7 +703,14 @@ CommandCost CmdMassStartStopVehicle(DoCommandFlag flags, TileIndex tile, bool do
if (!vehicle_list_window && !v->IsChainInDepot()) continue; if (!vehicle_list_window && !v->IsChainInDepot()) continue;
/* Just try and don't care if some vehicle's can't be stopped. */ /* Just try and don't care if some vehicle's can't be stopped. */
Command<CMD_START_STOP_VEHICLE>::Do(flags, v->index, false); CommandCost ret = Command<CMD_START_STOP_VEHICLE>::Do(flags, v->index, false);
if (ret.Failed()) {
if (ret.GetErrorMessage() == STR_ERROR_CAN_T_START_PLATFORM_TYPE ||
ret.GetErrorMessage() == STR_ERROR_CAN_T_START_PLATFORM_LONG) {
SetDParam(0, v->index);
return ret;
}
}
} }
return CommandCost(); return CommandCost();