diff --git a/src/depot.cpp b/src/depot.cpp index 3451bdcf80..b0e750e87b 100644 --- a/src/depot.cpp +++ b/src/depot.cpp @@ -65,6 +65,20 @@ Depot::~Depot() InvalidateWindowData(WC_SELECT_DEPOT, this->veh_type); } +/** + * Cancel deletion of this depot (reuse it). + * @param xy New location of the depot. + * @see Depot::IsInUse + * @see Depot::Disuse + */ +void Depot::Reuse(TileIndex xy) +{ + this->delete_ctr = 0; + this->xy = xy; + this->ta.tile = xy; + this->ta.h = this->ta.w = 1; +} + /** * Schedule deletion of this depot. * @@ -73,6 +87,7 @@ Depot::~Depot() * placed again later without messing vehicle orders. * * @see Depot::IsInUse + * @see Depot::Reuse */ void Depot::Disuse() { @@ -112,13 +127,19 @@ CommandCost Depot::BeforeAddTiles(TileArea ta) { assert(ta.tile != INVALID_TILE); - if (this->ta.tile != INVALID_TILE) { + if (this->ta.tile != INVALID_TILE && this->IsInUse()) { /* Important when the old rect is completely inside the new rect, resp. the old one was empty. */ ta.Add(this->ta.tile); ta.Add(TileAddXY(this->ta.tile, this->ta.w - 1, this->ta.h - 1)); } - if ((ta.w > _settings_game.depot.depot_spread) || (ta.h > _settings_game.depot.depot_spread)) { + /* A max depot spread of 1 for VEH_SHIP is a special case, + * as ship depots consist of two tiles. */ + if (this->veh_type == VEH_SHIP && _settings_game.depot.depot_spread == 1) { + /* (ta.w, ta.h) must be equal to (1, 2) or (2, 1). + * This means that ta.w * ta.h must be equal to 2. */ + if (ta.w * ta.h != 2) return_cmd_error(STR_ERROR_DEPOT_TOO_SPREAD_OUT); + } else if (std::max(ta.w, ta.h) > _settings_game.depot.depot_spread) { return_cmd_error(STR_ERROR_DEPOT_TOO_SPREAD_OUT); } return CommandCost(); @@ -158,8 +179,13 @@ void Depot::AfterAddRemove(TileArea ta, bool adding) } else { assert(this->IsInUse()); this->Disuse(); + TileIndex old_tile = this->xy; + this->RescanDepotTiles(); + assert(this->depot_tiles.empty()); + this->xy = old_tile; } + InvalidateWindowData(WC_VEHICLE_DEPOT, this->index); InvalidateWindowData(WC_SELECT_DEPOT, veh_type); } diff --git a/src/depot_base.h b/src/depot_base.h index 6f22f2428c..f6fcd04027 100644 --- a/src/depot_base.h +++ b/src/depot_base.h @@ -78,12 +78,14 @@ struct Depot : DepotPool::PoolItem<&_depot_pool> { * and the depot awaits to be deleted. * @return true iff still in use * @see Depot::Disuse + * @see Depot::Reuse */ inline bool IsInUse() const { return this->delete_ctr == 0; } + void Reuse(TileIndex xy); void Disuse(); /* Check we can add some tiles to this depot. */ diff --git a/src/depot_cmd.cpp b/src/depot_cmd.cpp index 1bbdfffe73..88959bf98e 100644 --- a/src/depot_cmd.cpp +++ b/src/depot_cmd.cpp @@ -77,6 +77,23 @@ CommandCost CmdRenameDepot(DoCommandFlag flags, DepotID depot_id, const std::str return CommandCost(); } +/** + * Find a demolished depot close to a tile. + * @param ta Tile area to search for. + * @param type Depot type. + * @param cid Previous owner of the depot. + * @return The index of a demolished nearby depot, or INVALID_DEPOT if none. + */ +DepotID FindDeletedDepotCloseTo(TileArea ta, VehicleType type, CompanyID cid) +{ + for (Depot *depot : Depot::Iterate()) { + if (depot->IsInUse() || depot->veh_type != type || depot->owner != cid) continue; + if (ta.Contains(depot->xy)) return depot->index; + } + + return INVALID_DEPOT; +} + void OnTick_Depot() { if (_game_mode == GM_EDITOR) return; @@ -128,6 +145,12 @@ CommandCost FindJoiningDepot(TileArea ta, VehicleType veh_type, DepotID &join_to } } + if (closest_depot == INVALID_DEPOT) { + /* Check for close unused depots. */ + check_area.Expand(7); // total distance of 8 + closest_depot = FindDeletedDepotCloseTo(check_area, veh_type, _current_company); + } + if (closest_depot != INVALID_DEPOT) { assert(Depot::IsValidID(closest_depot)); depot = Depot::Get(closest_depot); @@ -151,6 +174,7 @@ CommandCost FindJoiningDepot(TileArea ta, VehicleType veh_type, DepotID &join_to depot = Depot::Get(join_to); assert(depot->owner == _current_company); assert(depot->veh_type == veh_type); + if (!depot->IsInUse() && (flags & DC_EXEC)) depot->Reuse(ta.tile); return depot->BeforeAddTiles(ta); } diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 36b7846620..81c0109f9d 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -1249,6 +1249,15 @@ static const Depot *FindDepotsNearby(TileArea ta, VehicleType veh_type, bool dis TileIndex tile = TileAddByDir(andd.search_area.tile, DIR_N); CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyDepot, &andd); + /* Add reusable depots. */ + ta.Expand(8); + for (Depot *d : Depot::Iterate()) { + if (d->IsInUse()) continue; + if (d->veh_type != veh_type || d->owner != _current_company) continue; + if (!ta.Contains(d->xy)) continue; + _depots_nearby_list.push_back(d->index); + } + return nullptr; }