From ef7c8884b89bd9cdee139f8c386da391a5e9b6d2 Mon Sep 17 00:00:00 2001 From: J0anJosep Date: Thu, 1 Apr 2021 21:19:02 +0200 Subject: [PATCH] Codechange: Add additional rules for placing trains in depots according to railtypes. --- src/lang/english.txt | 1 + src/train_cmd.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 2b251064e4..36f555620a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5138,6 +5138,7 @@ STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... must STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Trains can only be altered when stopped inside a depot STR_ERROR_TRAIN_TOO_LONG :{WHITE}Train too long +STR_ERROR_INCOMPATIBLE_RAILTYPES_WITH_DEPOT :{WHITE}Train chain is incompatible with any tile of this depot STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Can't reverse direction of vehicle... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... consists of multiple units STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Incompatible rail types diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index d6c65140ca..52afef664f 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1051,6 +1051,82 @@ static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *origina 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::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. * @param t the train to check @@ -1061,6 +1137,8 @@ static CommandCost CheckTrainAttachment(Train *t) /* No multi-part train, no need to check. */ if (t == nullptr || t->Next() == nullptr) return CommandCost(); + if (LookForTileInDepot(t) == INVALID_TILE) return_cmd_error(STR_ERROR_INCOMPATIBLE_RAILTYPES_WITH_DEPOT); + /* 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. */ int allowed_len = _settings_game.vehicle.max_train_length * TILE_SIZE - t->gcache.cached_veh_length; @@ -1426,8 +1504,15 @@ CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID CheckCargoCapacity(dst_head); } - if (src_head != nullptr) src_head->First()->MarkDirty(); - if (dst_head != nullptr) dst_head->First()->MarkDirty(); + if (src_head != nullptr) { + PlaceOnRailDepot(src_head->First()); + src_head->First()->MarkDirty(); + } + + if (dst_head != nullptr) { + PlaceOnRailDepot(dst_head->First()); + dst_head->First()->MarkDirty(); + } /* We are undoubtedly changing something in the depot and train list. */ InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(src->tile));