diff --git a/npf.c b/npf.c index 01494349ab..87386cbe78 100644 --- a/npf.c +++ b/npf.c @@ -576,7 +576,7 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current) /* check correct rail type (mono, maglev, etc) */ if (type == TRANSPORT_RAIL) { RailType dst_type = GetTileRailType(dst_tile, src_trackdir); - if (!IsCompatibleRail(aystar->user_data[NPF_RAILTYPE], dst_type)) + if (!HASBIT(aystar->user_data[NPF_RAILTYPES], dst_type)) return; } @@ -649,7 +649,7 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current) * multiple targets that are spread around, we should perform a breadth first * search by specifiying CalcZero as our heuristic. */ -static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start2, NPFFindStationOrTileData* target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, Owner owner, RailType railtype, uint reverse_penalty) +static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start2, NPFFindStationOrTileData* target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, Owner owner, byte railtypes, uint reverse_penalty) { int r; NPFFoundTargetData result; @@ -691,7 +691,7 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start /* Initialize user_data */ _npf_aystar.user_data[NPF_TYPE] = type; _npf_aystar.user_data[NPF_OWNER] = owner; - _npf_aystar.user_data[NPF_RAILTYPE] = railtype; + _npf_aystar.user_data[NPF_RAILTYPES] = railtypes; /* GO! */ r = AyStarMain_Main(&_npf_aystar); @@ -709,7 +709,7 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, AyStarNode* start return result; } -NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype) +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, byte railtypes) { AyStarNode start1; AyStarNode start2; @@ -723,15 +723,15 @@ NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir track start2.direction = trackdir2; start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; - return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, railtype, 0); + return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, railtypes, 0); } -NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype) +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, byte railtypes) { - return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner, railtype); + return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner, railtypes); } -NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailType railtype, uint reverse_penalty) +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, byte railtypes, uint reverse_penalty) { AyStarNode start1; AyStarNode start2; @@ -747,15 +747,15 @@ NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir t /* perform a breadth first search. Target is NULL, * since we are just looking for any depot...*/ - return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, railtype, reverse_penalty); + return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, railtypes, reverse_penalty); } -NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype) +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, byte railtypes) { - return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, railtype, 0); + return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, railtypes, 0); } -NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype) +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, byte railtypes) { /* Okay, what we're gonna do. First, we look at all depots, calculate * the manhatten distance to get to each depot. We then sort them by diff --git a/npf.h b/npf.h index 743a439e9a..6e63a65baa 100644 --- a/npf.h +++ b/npf.h @@ -37,7 +37,7 @@ typedef struct NPFFindStationOrTileData { /* Meant to be stored in AyStar.target enum { /* Indices into AyStar.userdata[] */ NPF_TYPE = 0, /* Contains a TransportTypes value */ NPF_OWNER, /* Contains an Owner value */ - NPF_RAILTYPE, /* Contains the RailType value of the engine when NPF_TYPE == TRANSPORT_RAIL. Unused otherwise. */ + NPF_RAILTYPES, /* Contains a bitmask the compatible RailTypes of the engine when NPF_TYPE == TRANSPORT_RAIL. Unused otherwise. */ }; enum { /* Indices into AyStarNode.userdata[] */ @@ -63,27 +63,27 @@ typedef struct NPFFoundTargetData { /* Meant to be stored in AyStar.userpath */ /* Will search from the given tile and direction, for a route to the given * station for the given transport type. See the declaration of * NPFFoundTargetData above for the meaning of the result. */ -NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype); +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, byte railtypes); /* Will search as above, but with two start nodes, the second being the * reverse. Look at the NPF_FLAG_REVERSE flag in the result node to see which * direction was taken (NPFGetBit(result.node, NPF_FLAG_REVERSE)) */ -NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype); +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, byte railtypes); /* Will search a route to the closest depot. */ /* Search using breadth first. Good for little track choice and inaccurate * heuristic, such as railway/road.*/ -NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype); +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, byte railtypes); /* Same as above but with two start nodes, the second being the reverse. Call * NPFGetBit(result.node, NPF_FLAG_REVERSE) to see from which node the path * orginated. All pathfs from the second node will have the given * reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full * tile). */ -NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailType railtype, uint reverse_penalty); +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, byte railtypes, uint reverse_penalty); /* Search by trying each depot in order of Manhattan Distance. Good for lots * of choices and accurate heuristics, such as water. */ -NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype); +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, byte railtypes); void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v); diff --git a/pathfind.c b/pathfind.c index 17cb9185d9..abf79d2c16 100644 --- a/pathfind.c +++ b/pathfind.c @@ -5,8 +5,8 @@ #include "functions.h" #include "map.h" #include "tile.h" -#include "pathfind.h" #include "rail.h" +#include "pathfind.h" #include "debug.h" #include "variables.h" #include "depot.h" @@ -442,7 +442,8 @@ typedef struct { void *userdata; TileIndex dest; - byte tracktype; + TransportType tracktype; + byte railtypes; uint maxlength; HashLink *new_link; @@ -728,6 +729,11 @@ start_at: /* We are not driving into the tunnel, or it * is an invalid tunnel */ continue; + + if (!HASBIT(tpf->railtypes, GetRailType(tile))) { + bits = 0; + break; + } flotr = FindLengthOfTunnel(tile, direction); si.cur_length += flotr.length * DIAG_FACTOR; tile = flotr.tile; @@ -760,6 +766,12 @@ start_at: // Check that the tile contains exactly one track if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break; + if ((IsTileType(tile, MP_STREET) && !HASBIT(tpf->railtypes, GB(_m[tile].m4, 0, 4))) || + !HASBIT(tpf->railtypes, GetRailType(tile))) { + bits = 0; + break; + } + /////////////////// // If we reach here, the tile has exactly one track. // tile - index to a tile that is not rail tile, but still straight (with optional signals) @@ -781,6 +793,11 @@ start_at: * bits, not just reachable ones, to prevent infinite loops. */ if (bits == 0 || TracksOverlap(allbits)) break; + if (!HASBIT(tpf->railtypes, GetRailType(tile))) { + bits = 0; + break; + } + /* If we reach here, the tile has exactly one track, and this track is reachable => Rail segment continues */ @@ -916,14 +933,15 @@ start_at: // new pathfinder for trains. better and faster. -void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data) +void NewTrainPathfind(TileIndex tile, TileIndex dest, byte railtypes, byte direction, NTPEnumProc *enum_proc, void *data) { NewTrackPathFinder tpf; tpf.dest = dest; tpf.userdata = data; tpf.enum_proc = enum_proc; - tpf.tracktype = 0; + tpf.tracktype = TRANSPORT_RAIL; + tpf.railtypes = railtypes; tpf.maxlength = min(_patches.pf_maxlength * 3, 10000); tpf.nstack = 0; tpf.new_link = tpf.links; diff --git a/pathfind.h b/pathfind.h index e2ee50d181..a76eb20f98 100644 --- a/pathfind.h +++ b/pathfind.h @@ -66,6 +66,6 @@ typedef struct { } FindLengthOfTunnelResult; FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, uint direction); -void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data); +void NewTrainPathfind(TileIndex tile, TileIndex dest, byte railtypes, byte direction, NTPEnumProc *enum_proc, void *data); #endif /* PATHFIND_H */ diff --git a/train_cmd.c b/train_cmd.c index 15da398eb0..cc432ab53e 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -88,6 +88,7 @@ void TrainConsistChanged(Vehicle* v) rvi_v = RailVehInfo(v->engine_type); first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_VEHICLE; v->u.rail.cached_total_length = 0; + v->u.rail.compatible_railtypes = 0; for (u = v; u != NULL; u = u->next) { const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); @@ -98,6 +99,7 @@ void TrainConsistChanged(Vehicle* v) // update the 'first engine' u->u.rail.first_engine = (v == u) ? INVALID_VEHICLE : first_engine; + u->u.rail.railtype = GetEngine(u->engine_type)->railtype; if (rvi_u->visual_effect != 0) { u->u.rail.cached_vis_effect = rvi_u->visual_effect; @@ -135,6 +137,11 @@ void TrainConsistChanged(Vehicle* v) } } + /* Do not count powered wagons for the compatible railtypes, as + * wagons always have railtype normal */ + if (rvi_u->power > 0) + v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->compatible_railtypes; + // max speed is the minimum of the speed limits of all vehicles in the consist if (!(rvi_u->flags & RVI_WAGON) || _patches.wagon_speed_limits) if (rvi_u->max_speed != 0 && !UsesWagonOverride(u)) @@ -1793,7 +1800,7 @@ static TrainFindDepotData FindClosestTrainDepot(Vehicle *v) Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); assert (trackdir != INVALID_TRACKDIR); - ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, NPF_INFINITE_PENALTY); + ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY); if (ftd.best_bird_dist == 0) { /* Found target */ tfdd.tile = ftd.node.tile; @@ -1809,13 +1816,13 @@ static TrainFindDepotData FindClosestTrainDepot(Vehicle *v) // search in the forward direction first. i = v->direction >> 1; if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) i = (i - 1) & 3; - NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); + NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); if (tfdd.best_length == (uint)-1){ tfdd.reverse = true; // search in backwards direction i = (v->direction^4) >> 1; if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) i = (i - 1) & 3; - NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); + NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); } } @@ -2137,7 +2144,7 @@ static byte ChooseTrainTrack(Vehicle *v, TileIndex tile, int enterdir, TrackdirB trackdir = GetVehicleTrackdir(v); assert(trackdir != 0xff); - ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype); + ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); if (ftd.best_trackdir == 0xff) { /* We are already at our target. Just do something */ @@ -2161,7 +2168,7 @@ static byte ChooseTrainTrack(Vehicle *v, TileIndex tile, int enterdir, TrackdirB fd.best_track = 0xFF; NewTrainPathfind(tile - TileOffsByDir(enterdir), v->dest_tile, - enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd); + v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd); if (fd.best_track == 0xff) { // blaha @@ -2217,7 +2224,7 @@ static bool CheckReverseTrain(Vehicle *v) assert(trackdir != 0xff); assert(trackdir_rev != 0xff); - ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype); + ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); if (ftd.best_bird_dist != 0) { /* We didn't find anything, just keep on going straight ahead */ reverse_best = false; @@ -2232,7 +2239,7 @@ static bool CheckReverseTrain(Vehicle *v) fd.best_bird_dist = (uint)-1; fd.best_track_dist = (uint)-1; - NewTrainPathfind(v->tile, v->dest_tile, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd); + NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd); if (best_track != -1) { if (best_bird_dist != 0) { @@ -2601,7 +2608,7 @@ static bool CheckCompatibleRail(const Vehicle *v, TileIndex tile) return IsTileOwner(tile, v->owner) && ( !IsFrontEngine(v) || - IsCompatibleRail(v->u.rail.railtype, GetRailType(tile)) + HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile)) ); } diff --git a/vehicle.h b/vehicle.h index ef66b63dc9..a64363aa0e 100644 --- a/vehicle.h +++ b/vehicle.h @@ -71,6 +71,7 @@ typedef struct VehicleRail { byte track; byte force_proceed; byte railtype; + byte compatible_railtypes; byte flags;