1
0
Fork 0

Codechange: Adapt some functions that located the depot with its tile.

pull/9577/head
J0anJosep 2023-05-10 20:22:04 +02:00
parent 373f9fe5ef
commit f8bc259ec0
9 changed files with 137 additions and 24 deletions

View File

@ -519,6 +519,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
{
Vehicle *old_head = *chain;
assert(old_head->IsPrimaryVehicle());
TileIndex tile = old_head->tile;
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
@ -661,6 +662,9 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head);
}
assert(IsValidTile(tile));
if (!HasCompatibleDepotTile(tile, Train::From(new_head))) cost.MakeError(STR_ERROR_UNABLE_TO_FIND_APPROPRIATE_DEPOT_TILE);
/* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles.
* We do this from back to front, so that the head of the temporary vehicle chain does not change all the time.
* Note: The vehicle attach callback is disabled here :) */

View File

@ -16,6 +16,7 @@
#include "vehicle_gui.h"
#include "vehiclelist.h"
#include "command_func.h"
#include "vehicle_base.h"
#include "safeguards.h"
@ -41,6 +42,15 @@ Depot::~Depot()
/* Clear the order backup. */
OrderBackup::Reset(this->index, false);
/* Make sure no vehicle is going to the old depot. */
for (Vehicle *v : Vehicle::Iterate()) {
if (v->First() != v) continue;
if (!v->current_order.IsType(OT_GOTO_DEPOT)) continue;
if (v->current_order.GetDestination() != this->index) continue;
v->current_order.MakeDummy();
}
/* Clear the depot from all order-lists */
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
@ -53,6 +63,29 @@ Depot::~Depot()
this->veh_type, this->owner, this->index).Pack());
}
/**
* Of all the depot parts a depot has, return the best destination for a vehicle.
* @param v The vehicle.
* @param dep The depot vehicle \a v is heading for.
* @return The closest part of depot to vehicle v.
*/
TileIndex Depot::GetBestDepotTile(Vehicle *v) const
{
assert(this->veh_type == v->type);
TileIndex best_depot = INVALID_TILE;
uint best_distance = UINT_MAX;
for (const auto &tile : this->depot_tiles) {
uint new_distance = DistanceManhattan(v->tile, tile);
if (new_distance < best_distance) {
best_depot = tile;
best_distance = new_distance;
}
}
return best_depot;
}
/**
* Check we can add some tiles to this depot.
* @param ta The affected tile area.

View File

@ -28,6 +28,7 @@ typedef Pool<Depot, DepotID, 64, MAX_DEPOTS> DepotPool;
extern DepotPool _depot_pool;
class CommandCost;
struct Vehicle;
struct Depot : DepotPool::PoolItem<&_depot_pool> {
/* DepotID index member of DepotPool is 2 bytes. */
@ -64,6 +65,8 @@ struct Depot : DepotPool::PoolItem<&_depot_pool> {
return Depot::Get(GetDepotIndex(tile));
}
TileIndex GetBestDepotTile(Vehicle *v) const;
/**
* Is the "type" of depot the same as the given depot,
* i.e. are both a rail, road or ship depots?

View File

@ -5146,6 +5146,7 @@ STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Can't mo
STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}The rear engine will always follow its front counterpart
STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Unable to find route to local depot
STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Unable to find local depot
STR_ERROR_UNABLE_TO_FIND_APPROPRIATE_DEPOT_TILE :{WHITE}Unable to find appropriate depot tile
STR_ERROR_DEPOT_TOO_SPREAD_OUT :{WHITE}... depot too spread out
STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Wrong depot type

View File

@ -2033,7 +2033,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
v->IncrementRealOrderIndex();
} else {
if (v->type != VEH_AIRCRAFT) {
v->SetDestTile(Depot::Get(order->GetDestination())->xy);
v->SetDestTile(Depot::Get(order->GetDestination())->GetBestDepotTile(v));
} else {
Aircraft *a = Aircraft::From(v);
DestinationID destination_depot = a->current_order.GetDestination();

View File

@ -1056,7 +1056,9 @@ bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
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) && v->tile == v->dest_tile) {
if (v->current_order.IsType(OT_GOTO_DEPOT) &&
IsRoadDepotTile(v->tile) &&
v->current_order.GetDestination() == GetDepotIndex(v->tile)) {
VehicleEnterDepot(v);
return true;
}

View File

@ -187,14 +187,14 @@ static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance)
const Depot *best_depot = nullptr;
uint best_dist_sq = std::numeric_limits<uint>::max();
for (const Depot *depot : Depot::Iterate()) {
if (depot->veh_type != VEH_SHIP || depot->owner != v->owner) continue;
const TileIndex tile = depot->xy;
if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
const uint dist_sq = DistanceSquare(tile, v->tile);
if (dist_sq < best_dist_sq && dist_sq <= max_distance * max_distance &&
visited_patch_hashes.count(CalculateWaterRegionPatchHash(GetWaterRegionPatchInfo(tile))) > 0) {
best_dist_sq = dist_sq;
best_depot = depot;
}
const uint dist_sq = DistanceSquare(tile, v->tile);
if (dist_sq < best_dist_sq && dist_sq <= max_distance * max_distance &&
visited_patch_hashes.count(CalculateWaterRegionPatchHash(GetWaterRegionPatchInfo(tile))) > 0) {
best_dist_sq = dist_sq;
best_depot = depot;
}
}
@ -222,7 +222,7 @@ static void CheckIfShipNeedsService(Vehicle *v)
}
v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
v->SetDestTile(depot->xy);
v->SetDestTile(depot->GetBestDepotTile(v));
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
}
@ -962,5 +962,5 @@ ClosestDepot Ship::FindClosestDepot()
const Depot *depot = FindClosestShipDepot(this, MAX_SHIP_DEPOT_SEARCH_DISTANCE);
if (depot == nullptr) return ClosestDepot();
return ClosestDepot(depot->xy, depot->index);
return ClosestDepot(depot->GetBestDepotTile(this), depot->index);
}

View File

@ -353,4 +353,6 @@ protected: // These functions should not be called outside acceleration code.
}
};
bool HasCompatibleDepotTile(TileIndex tile, const Train *t);
#endif /* TRAIN_H */

View File

@ -7,6 +7,7 @@
/** @file train_cmd.cpp Handling of trains. */
#include "depot_map.h"
#include "stdafx.h"
#include "error.h"
#include "articulated_vehicles.h"
@ -38,6 +39,7 @@
#include "misc_cmd.h"
#include "timer/timer_game_calendar.h"
#include "timer/timer_game_economy.h"
#include "depot_base.h"
#include "table/strings.h"
#include "table/train_sprites.h"
@ -604,6 +606,65 @@ void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs,
}
}
/**
* Check if a train chain is compatible with a depot tile.
* @param tile Tile to check.
* @param t Train chain to check.
* @return Whether the full train chain is compatible with this tile.
*/
bool IsVehicleCompatibleWithDepotTile(TileIndex tile, const Train *t)
{
assert(IsRailDepotTile(tile));
for (const Train *u = t; u != nullptr; u = u->Next()) {
RailType rail_type = Engine::Get(u->engine_type)->u.rail.railtype;
if (!IsCompatibleRail(rail_type, GetRailType(tile))) return false;
}
return true;
}
/**
* Check if a depot has a tile where a train chain can be stored.
* @param tile A tile of the depot.
* @param t The train to check.
* @return True iff the depot has a tile compatible with the chain.
*/
bool HasCompatibleDepotTile(TileIndex tile, const Train *t)
{
assert(IsRailDepotTile(tile));
Depot *dep = Depot::GetByTile(tile);
for (auto &depot_tile : dep->depot_tiles) {
if (IsVehicleCompatibleWithDepotTile(depot_tile, t)) return true;
}
return false;
}
/**
* Find a tile of a depot compatible with the rail type of a rail vehicle.
* @param depot_id Index of the depot.
* @param rail_type Rail type of the new vehicle.
* @param is_engine Whether the vehicle is an engine.
* @return A compatible tile of the depot or INVALID_TILE if no compatible tile is found.
*/
TileIndex FindCompatibleDepotTile(DepotID depot_id, RailType rail_type, bool is_engine)
{
assert(Depot::IsValidID(depot_id));
Depot *depot = Depot::Get(depot_id);
for (auto &dep_tile : depot->depot_tiles) {
if (is_engine) {
if (HasPowerOnRail(rail_type, GetRailType(dep_tile))) return dep_tile;
} else {
if (IsCompatibleRail(rail_type, GetRailType(dep_tile))) return dep_tile;
}
}
return INVALID_TILE;
}
/**
* Build a railroad wagon.
* @param flags type of operation.
@ -616,9 +677,11 @@ static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const
{
const RailVehicleInfo *rvi = &e->u.rail;
assert(IsRailDepotTile(tile));
DepotID depot_id = GetDepotIndex(tile);
/* Check that the wagon can drive on the track in question */
if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
/* Find a good tile to place the wagon. */
tile = FindCompatibleDepotTile(depot_id, rvi->railtype, false);
if (tile == INVALID_TILE) return CMD_ERROR;
if (flags & DC_EXEC) {
Train *v = new Train();
@ -646,7 +709,7 @@ static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const
v->SetWagon();
v->SetFreeWagon();
InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(tile));
InvalidateWindowData(WC_VEHICLE_DEPOT, depot_id);
v->cargo_type = e->GetDefaultCargoType();
assert(IsValidCargoID(v->cargo_type));
@ -674,7 +737,8 @@ static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const
/* Try to connect the vehicle to one of free chains of wagons. */
for (Train *w : Train::Iterate()) {
if (w->tile == tile && ///< Same depot
if (!IsRailDepotTile(w->tile)) continue;
if (GetDepotIndex(w->tile) == depot_id && ///< Same depot
w->IsFreeWagon() && ///< A free wagon chain
w->engine_type == e->index && ///< Same type
w->First() != v && ///< Don't connect to ourself
@ -693,9 +757,10 @@ static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const
void NormalizeTrainVehInDepot(const Train *u)
{
assert(u->IsEngine());
DepotID dep_id = GetDepotIndex(u->tile);
for (const Train *v : Train::Iterate()) {
if (v->IsFreeWagon() && v->tile == u->tile &&
v->track == TRACK_BIT_DEPOT) {
if (v->IsFreeWagon() && v->IsInDepot() &&
GetDepotIndex(v->tile) == dep_id) {
if (Command<CMD_MOVE_RAIL_VEHICLE>::Do(DC_EXEC, v->index, u->index, true).Failed()) {
break;
}
@ -749,13 +814,14 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
*/
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
{
assert(IsRailDepotTile(tile));
const RailVehicleInfo *rvi = &e->u.rail;
if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(flags, tile, e, ret);
/* Check if depot and new engine uses the same kind of tracks *
* We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */
if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
/* Find a good tile to place the engine and get power on it. */
tile = FindCompatibleDepotTile(GetDepotIndex(tile), rvi->railtype, true);
if (tile == INVALID_TILE) return CMD_ERROR;
if (flags & DC_EXEC) {
DiagDirection dir = GetRailDepotDirection(tile);
@ -825,10 +891,10 @@ CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engin
static Train *FindGoodVehiclePos(const Train *src)
{
EngineID eng = src->engine_type;
TileIndex tile = src->tile;
DepotID dep_id = GetDepotIndex(src->tile);
for (Train *dst : Train::Iterate()) {
if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED)) {
if (dst->IsFreeWagon() && !(dst->vehstatus & VS_CRASHED) && GetDepotIndex(dst->tile) == dep_id) {
/* check so all vehicles in the line have the same engine. */
Train *t = dst;
while (t->engine_type == eng) {
@ -1230,7 +1296,7 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID
Train *dst_head;
if (dst != nullptr) {
dst_head = dst->First();
if (dst_head->tile != src_head->tile) return CMD_ERROR;
if (GetDepotIndex(dst_head->tile) != GetDepotIndex(src_head->tile)) return CMD_ERROR;
/* Now deal with articulated part of destination wagon */
dst = dst->GetLastEnginePart();
} else {
@ -2303,7 +2369,9 @@ static bool CheckTrainStayInDepot(Train *v)
}
/* We are leaving a depot, but have to go to the exact same one; re-enter. */
if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
if (v->current_order.IsType(OT_GOTO_DEPOT) &&
IsRailDepotTile(v->tile) &&
v->current_order.GetDestination() == GetDepotIndex(v->tile)) {
/* Service when depot has no reservation. */
if (!HasDepotReservation(v->tile)) VehicleEnterDepot(v);
return true;