From 08f4ae4b3d1aeacf21c41601db93a0640ab410a4 Mon Sep 17 00:00:00 2001 From: J0anJosep Date: Sat, 27 Mar 2021 13:51:37 +0100 Subject: [PATCH] Add: Add and adapt some functions for extended depots. --- src/depot.cpp | 14 ++++- src/depot_map.h | 92 ++++++++++++++++++++++++++++++++ src/depot_type.h | 8 +++ src/lang/english.txt | 1 + src/pathfinder/pathfinder_func.h | 11 +++- src/vehicle.cpp | 16 ++++++ 6 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/depot.cpp b/src/depot.cpp index 894fa1138e..3a900988eb 100644 --- a/src/depot.cpp +++ b/src/depot.cpp @@ -112,19 +112,29 @@ void Depot::Disuse() * 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. + * @return The free and closest (if none is free, just closest) part of depot to vehicle v. */ TileIndex Depot::GetBestDepotTile(Vehicle *v) const { assert(this->veh_type == v->type); TileIndex best_depot = INVALID_TILE; + DepotReservation best_found_type = DEPOT_RESERVATION_END; uint best_distance = UINT_MAX; for (const auto &tile : this->depot_tiles) { + bool check_south = v->type == VEH_ROAD; uint new_distance = DistanceManhattan(v->tile, tile); - if (new_distance < best_distance) { +again: + DepotReservation depot_reservation = GetDepotReservation(tile, check_south); + if (((best_found_type == depot_reservation) && new_distance < best_distance) || (depot_reservation < best_found_type)) { best_depot = tile; best_distance = new_distance; + best_found_type = depot_reservation; + } + if (check_south) { + /* For road vehicles, check north direction as well. */ + check_south = false; + goto again; } } diff --git a/src/depot_map.h b/src/depot_map.h index 51639a3b41..18d172fbeb 100644 --- a/src/depot_map.h +++ b/src/depot_map.h @@ -83,4 +83,96 @@ inline VehicleType GetDepotVehicleType(Tile t) } } +/** Return true if a tile belongs to an extended depot. */ +static inline bool IsExtendedDepot(Tile tile) { + assert(IsValidTile(tile)); + assert(IsDepotTile(tile)); + if (IsAirportTile(tile)) return false; + return HasBit(tile.m5(), 5); +} + +/** Return true if a tile belongs to an extended depot. */ +static inline bool IsExtendedDepotTile(TileIndex tile) { + if (!IsValidTile(tile)) return false; + if (!IsDepotTile(tile)) return false; + return IsExtendedDepot(tile); +} + +/** + * Has this depot some vehicle servicing or stopped inside? + * @param tile tile of the depot. + * @param south_dir In case of road transport, return reservation facing south if true. + * @return The type of reservation on this tile (empty, servicing or occupied). + * @pre is a depot tile + */ +static inline DepotReservation GetDepotReservation(Tile t, bool south_dir = false) +{ + assert(IsDepotTile(t)); + if (!IsExtendedDepot(t)) return DEPOT_RESERVATION_EMPTY; + if (south_dir) { + assert(GetDepotVehicleType(t) == VEH_ROAD); + return (DepotReservation)GB(t.m6(), 4, 2); + } + return (DepotReservation)GB(t.m4(), 6, 2); +} + +/** + * Is this a platform/depot tile full with stopped vehicles? + * @param tile tile of the depot. + * @param south_dir In case of road transport, check reservation facing south if true. + * @return the type of reservation of the depot. + * @pre is a depot tile + */ +static inline bool IsDepotFullWithStoppedVehicles(TileIndex t, bool south_dir = false) +{ + assert(IsDepotTile(t)); + if (!IsExtendedDepot(t)) return false; + return GetDepotReservation(t, south_dir) == DEPOT_RESERVATION_FULL_STOPPED_VEH; +} + + +/** + * Has this depot tile/platform some vehicle inside? + * @param tile tile of the depot. + * @param south_dir In case of road transport, check reservation facing south if true. + * @return true iff depot tile/platform has no vehicle. + * @pre IsExtendedDepotTile + */ +static inline bool IsExtendedDepotEmpty(TileIndex t, bool south_dir = false) +{ + assert(IsExtendedDepotTile(t)); + return GetDepotReservation(t, south_dir) == DEPOT_RESERVATION_EMPTY; +} + +/** + * Mark whether this depot has a ship inside. + * @param tile of the depot. + * @param reservation type of reservation + * @param south_dir Whether to set south direction reservation. + * @pre tile is an extended ship depot. + */ +static inline void SetDepotReservation(Tile t, DepotReservation reservation, bool south_dir = false) +{ + assert(IsDepotTile(t)); + if (!IsExtendedDepot(t)) return; + switch (GetTileType(t)) { + default: NOT_REACHED(); + case MP_RAILWAY: + break; + case MP_ROAD: + if (south_dir) { + SB(t.m6(), 4, 2, reservation); + return; + } + break; + case MP_WATER: + assert(GetDepotReservation(t) == GetDepotReservation(GetOtherShipDepotTile(t))); + SB(Tile(GetOtherShipDepotTile(t)).m4(), 6, 2, reservation); + break; + case MP_STATION: return; + } + + SB(t.m4(), 6, 2, reservation); +} + #endif /* DEPOT_MAP_H */ diff --git a/src/depot_type.h b/src/depot_type.h index 2fdafc00ea..9a3812799e 100644 --- a/src/depot_type.h +++ b/src/depot_type.h @@ -18,4 +18,12 @@ static const DepotID NEW_DEPOT = INVALID_DEPOT - 1; static const uint MAX_LENGTH_DEPOT_NAME_CHARS = 32; ///< The maximum length of a depot name in characters including '\0' +/** Type of reservation of extended ship depots. */ +enum DepotReservation { + DEPOT_RESERVATION_EMPTY = 0, ///< No vehicle servicing/stopped on depot tile/platform. + DEPOT_RESERVATION_IN_USE = 1, ///< At least a vehicle is in the depot, but the depot tile is not full of stopped vehicles. + DEPOT_RESERVATION_FULL_STOPPED_VEH = 2, ///< The depot tile/platform is full with stopped vehicles. + DEPOT_RESERVATION_END +}; + #endif /* DEPOT_TYPE_H */ diff --git a/src/lang/english.txt b/src/lang/english.txt index a43c07b570..db85c9e349 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -910,6 +910,7 @@ STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} is lost STR_NEWS_VEHICLE_UNPROFITABLE_YEAR :{WHITE}{VEHICLE}'s profit last year was {CURRENCY_LONG} STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD :{WHITE}{VEHICLE}'s profit last period was {CURRENCY_LONG} +STR_NEWS_VEHICLE_CAN_T_FIND_FREE_DEPOT :{WHITE}{VEHICLE} can't find a free depot STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} can't get to the next destination because it is out of range STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} stopped because an ordered refit failed diff --git a/src/pathfinder/pathfinder_func.h b/src/pathfinder/pathfinder_func.h index 781d356458..410776511b 100644 --- a/src/pathfinder/pathfinder_func.h +++ b/src/pathfinder/pathfinder_func.h @@ -66,13 +66,22 @@ static inline TileIndex CalcClosestDepotTile(DepotID depot_id, TileIndex tile) } TileIndex best_tile = INVALID_TILE; + DepotReservation best_found_type = dep->veh_type == VEH_SHIP ? DEPOT_RESERVATION_END : DEPOT_RESERVATION_EMPTY; uint best_distance = UINT_MAX; for (auto const &depot_tile : dep->depot_tiles) { uint new_distance = DistanceManhattan(depot_tile, tile); - if (new_distance < best_distance) { + bool check_south_direction = dep->veh_type == VEH_ROAD; +again: + DepotReservation depot_reservation = GetDepotReservation(depot_tile, check_south_direction); + if (((best_found_type == depot_reservation) && new_distance < best_distance) || (depot_reservation < best_found_type)) { best_tile = depot_tile; best_distance = new_distance; + best_found_type = depot_reservation; + } + if (check_south_direction) { + check_south_direction = false; + goto again; } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index d10f8dcb0f..64876f780b 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -790,6 +790,22 @@ void Vehicle::ShiftDates(TimerGameEconomy::Date interval) */ void Vehicle::HandlePathfindingResult(bool path_found) { + if (this->dest_tile != INVALID_TILE && IsDepotTypeTile(this->dest_tile, (TransportType)this->type) && IsDepotFullWithStoppedVehicles(this->dest_tile)) { + /* Vehicle cannot find a free depot. */ + /* Were we already lost? */ + if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return; + + /* It is first time the problem occurred, set the "lost" flag. */ + SetBit(this->vehicle_flags, VF_PATHFINDER_LOST); + /* Notify user about the event. */ + AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index)); + if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) { + SetDParam(0, this->index); + AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_CAN_T_FIND_FREE_DEPOT, this->index); + } + return; + } + if (path_found) { /* Route found, is the vehicle marked with "lost" flag? */ if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;