diff --git a/npf.c b/npf.c index 06e5d79f84..bbc992fede 100644 --- a/npf.c +++ b/npf.c @@ -234,9 +234,12 @@ static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* pare break; } /* Fall through if above if is false, it is a bridge - * then. We treat that as ordinary rail */ + * then. We treat that as ordinary road */ case MP_STREET: cost = NPF_TILE_LENGTH; + /* Increase the cost for level crossings */ + if ((_map5[tile] & 0xF0) == 0x10) + cost += _patches.npf_crossing_penalty; break; default: break; @@ -524,16 +527,11 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current) if (IsTileType(dst_tile, MP_TUNNELBRIDGE) && (_map5[dst_tile] & 0xF0) == 0 && GetTileZ(dst_tile) < GetTileZ(src_tile)) return; - /* check correct rail type (mono, maglev, etc) - * XXX: This now compares with the previous tile, which should not pose a - * problem, but it might be nicer to compare with the first tile, or even - * the type of the vehicle... Maybe an NPF_RAILTYPE userdata sometime? */ + /* check correct rail type (mono, maglev, etc) */ if (type == TRANSPORT_RAIL) { - RailType src_type = GetTileRailType(src_tile, src_trackdir); - RailType dst_type = GetTileRailType(dst_tile, TrackdirToExitdir(src_trackdir)); - if (src_type != dst_type) { + RailType dst_type = GetTileRailType(dst_tile, src_trackdir); + if (!IsCompatibleRail(aystar->user_data[NPF_RAILTYPE], dst_type)) return; - } } /* Check the owner of the tile */ @@ -604,7 +602,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, uint reverse_penalty) +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) { int r; NPFFoundTargetData result; @@ -646,6 +644,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; /* GO! */ r = AyStarMain_Main(&_npf_aystar); @@ -663,7 +662,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) +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype) { AyStarNode start1; AyStarNode start2; @@ -677,15 +676,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, 0); + return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, owner, railtype, 0); } -NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner) +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype) { - return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner); + return NPFRouteToStationOrTileTwoWay(tile, trackdir, INVALID_TILE, 0, target, type, owner, railtype); } -NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, uint reverse_penalty) +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailType railtype, uint reverse_penalty) { AyStarNode start1; AyStarNode start2; @@ -701,15 +700,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, reverse_penalty); + return NPFRouteInternal(&start1, (IsValidTile(tile2) ? &start2 : NULL), NULL, NPFFindDepot, NPFCalcZero, type, owner, railtype, reverse_penalty); } -NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner) +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype) { - return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, 0); + return NPFRouteToDepotBreadthFirstTwoWay(tile, trackdir, INVALID_TILE, 0, type, owner, railtype, 0); } -NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner) +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype) { /* 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 f0d021cc71..847a36b4ec 100644 --- a/npf.h +++ b/npf.h @@ -35,6 +35,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. */ }; enum { /* Indices into AyStarNode.userdata[] */ @@ -59,27 +60,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); +NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype); /* 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); +NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, NPFFindStationOrTileData* target, TransportType type, Owner owner, RailType railtype); /* 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); +NPFFoundTargetData NPFRouteToDepotBreadthFirst(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype); /* 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, uint reverse_penalty); +NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, TileIndex tile2, Trackdir trackdir2, TransportType type, Owner owner, RailType railtype, 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); +NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, TransportType type, Owner owner, RailType railtype); void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v); diff --git a/pathfind.c b/pathfind.c index 376c584fdf..fc8b543dbe 100644 --- a/pathfind.c +++ b/pathfind.c @@ -131,6 +131,7 @@ static void TPFMode2(TrackPathFinder *tpf, TileIndex tile, int direction) RememberData rd; int owner = -1; + /* XXX: Mode 2 is currently only used for ships, why is this code here? */ if (tpf->tracktype == TRANSPORT_RAIL) { if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE)) { owner = GetTileOwner(tile); @@ -340,6 +341,10 @@ static void TPFMode1(TrackPathFinder *tpf, TileIndex tile, int direction) /* if i can get rid of this, tail end recursion can be used to minimize * stack space dramatically. */ + + /* If we are doing signal setting, we must reverse at evere tile, so we + * iterate all the tracks in a signal block, even when a normal train would + * not reach it (for example, when two lines merge */ if (tpf->hasbit_13) return; diff --git a/rail.c b/rail.c index 89fb87c523..670b8345b5 100644 --- a/rail.c +++ b/rail.c @@ -97,7 +97,7 @@ const Trackdir _reverse_trackdir[] = { TRACKDIR_DIAG1_NE, TRACKDIR_DIAG2_SE, TRACKDIR_UPPER_E, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S, TRACKDIR_RIGHT_S }; -RailType GetTileRailType(TileIndex tile, byte trackdir) +RailType GetTileRailType(TileIndex tile, Trackdir trackdir) { RailType type = INVALID_RAILTYPE; switch (GetTileType(tile)) { @@ -123,7 +123,7 @@ RailType GetTileRailType(TileIndex tile, byte trackdir) if ((_map5[tile] & 0xC6) == 0xC0 && ((DiagDirection)(_map5[tile] & 0x1)) == (TrackdirToExitdir(trackdir) & 0x1)) type = (_map3_lo[tile] >> 4) & RAILTYPE_MASK; /* under bridge (any type) */ - if ((_map5[tile] & 0xC0) == 0xC0 && (_map5[tile] & 0x1) != (trackdir & 0x1)) + if ((_map5[tile] & 0xC0) == 0xC0 && ((uint)_map5[tile] & 0x1) != (trackdir & 0x1)) type = _map3_lo[tile] & RAILTYPE_MASK; break; default: diff --git a/rail.h b/rail.h index 4152a406fb..323e0f9832 100644 --- a/rail.h +++ b/rail.h @@ -441,7 +441,7 @@ static inline bool HasSemaphores(TileIndex tile, Track track) * The given trackdir is used when there are (could be) multiple rail types on * one tile. */ -RailType GetTileRailType(TileIndex tile, byte trackdir); +RailType GetTileRailType(TileIndex tile, Trackdir trackdir); /** * Returns whether the given tile is a level crossing. @@ -472,4 +472,17 @@ static inline TransportType GetCrossingTransportType(TileIndex tile, Track track return INVALID_TRANSPORT; } +/** + * Checks if an engine of the given RailType can drive on a tile with a given + * RailType. This would normally just be an equality check, but for electric + * rails (which also support non-electric engines). + * @return Whether the engine can drive on this tile. + * @param enginetype The RailType of the engine we are considering. + * @param tiletype The RailType of the tile we are considering. + */ +static inline bool IsCompatibleRail(RailType enginetype, RailType tiletype) +{ + return enginetype == tiletype; +} + #endif // RAIL_H diff --git a/roadveh_cmd.c b/roadveh_cmd.c index f28002cd2d..1796d1a32d 100644 --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -304,7 +304,7 @@ static Depot *FindClosestRoadDepot(Vehicle *v) /* See where we are now */ Trackdir trackdir = GetVehicleTrackdir(v); - ftd = NPFRouteToDepotBreadthFirst(v->tile, trackdir, TRANSPORT_ROAD, v->owner); + ftd = NPFRouteToDepotBreadthFirst(v->tile, trackdir, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE); if (ftd.best_bird_dist == 0) return GetDepotByTile(ftd.node.tile); /* Target found */ else @@ -1086,7 +1086,7 @@ static int RoadFindPathToDest(Vehicle *v, TileIndex tile, int enterdir) trackdir = DiagdirToDiagTrackdir(enterdir); //debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir); - ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->owner); + ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE); if (ftd.best_trackdir == 0xff) { /* We are already at our target. Just do something */ //TODO: maybe display error? @@ -1163,7 +1163,7 @@ static uint RoadFindPathToStation(const Vehicle *v, TileIndex tile) fstd.dest_coords = tile; fstd.station_index = -1; // indicates that the destination is a tile, not a station - return NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner).best_path_dist; + return NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE).best_path_dist; } typedef struct RoadDriveEntry { diff --git a/settings.c b/settings.c index d63662597e..03d0abbe47 100644 --- a/settings.c +++ b/settings.c @@ -977,6 +977,8 @@ const SettingDesc patch_settings[] = { {"npf_water_curve_penalty", SDT_UINT32, (void*)(NPF_TILE_LENGTH / 4), &_patches.npf_water_curve_penalty, NULL}, /* This is the penalty for road, same as for rail. */ {"npf_road_curve_penalty", SDT_UINT32, (void*)(1), &_patches.npf_road_curve_penalty, NULL}, + /* This is the penalty for level crossings, for both road and rail vehicles */ + {"npf_crossing_penalty", SDT_UINT32, (void*)(3 * NPF_TILE_LENGTH), &_patches.npf_crossing_penalty, NULL}, {NULL, 0, NULL, NULL, NULL} }; diff --git a/ship_cmd.c b/ship_cmd.c index fe53aa8a84..08c6528516 100644 --- a/ship_cmd.c +++ b/ship_cmd.c @@ -65,7 +65,7 @@ static Depot *FindClosestShipDepot(Vehicle *v) if (_patches.new_pathfinding_all) { NPFFoundTargetData ftd; byte trackdir = GetVehicleTrackdir(v); - ftd = NPFRouteToDepotTrialError(v->tile, trackdir, TRANSPORT_WATER, v->owner); + ftd = NPFRouteToDepotTrialError(v->tile, trackdir, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE); if (ftd.best_bird_dist == 0) best_depot = GetDepotByTile(ftd.node.tile); /* Found target */ else @@ -565,7 +565,7 @@ static int ChooseShipTrack(Vehicle *v, TileIndex tile, int enterdir, uint tracks NPFFillWithOrderData(&fstd, v); - ftd = NPFRouteToStationOrTile(src_tile, trackdir, &fstd, TRANSPORT_WATER, v->owner); + ftd = NPFRouteToStationOrTile(src_tile, trackdir, &fstd, TRANSPORT_WATER, v->owner, INVALID_RAILTYPE); if (ftd.best_trackdir != 0xff) /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains diff --git a/train_cmd.c b/train_cmd.c index 3806e0f165..d62e8251ba 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -1543,7 +1543,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, NPF_INFINITE_PENALTY); + ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, NPF_INFINITE_PENALTY); if (ftd.best_bird_dist == 0) { /* Found target */ tfdd.tile = ftd.node.tile; @@ -1910,7 +1910,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); + ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype); if (ftd.best_trackdir == 0xff) { /* We are already at our target. Just do something */ @@ -2048,7 +2048,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); + ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype); if (ftd.best_bird_dist != 0) { /* We didn't find anything, just keep on going straight ahead */ reverse_best = false; diff --git a/variables.h b/variables.h index 5d750aa50d..4b6d382456 100644 --- a/variables.h +++ b/variables.h @@ -216,6 +216,7 @@ typedef struct Patches { uint32 npf_buoy_penalty; /* The penalty for going over (through) a buoy */ uint32 npf_water_curve_penalty; /* The penalty for curves */ uint32 npf_road_curve_penalty; /* The penalty for curves */ + uint32 npf_crossing_penalty; /* The penalty for level crossings */ bool population_in_label; // Show the population of a town in his label? } Patches; diff --git a/vehicle.c b/vehicle.c index aadfb87a22..5e5d4de8c7 100644 --- a/vehicle.c +++ b/vehicle.c @@ -368,9 +368,9 @@ Vehicle *GetLastVehicleInChain(Vehicle *v) static Vehicle *GetPrevVehicleInChain_bruteforce(const Vehicle *v) { Vehicle *u; - + FOR_ALL_VEHICLES(u) if (u->type == VEH_Train && u->next == v) return u; - + return NULL; }