diff options
Diffstat (limited to 'train_cmd.c')
-rw-r--r-- | train_cmd.c | 218 |
1 files changed, 211 insertions, 7 deletions
diff --git a/train_cmd.c b/train_cmd.c index d62e8251b..d8ac7a051 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -15,6 +15,7 @@ #include "player.h" #include "sound.h" #include "depot.h" +#include "debug.h" #include "waypoint.h" #include "vehicle_gui.h" @@ -1296,14 +1297,86 @@ static void AdvanceWagons(Vehicle *v, bool before) } } +TileIndex GetVehicleTileOutOfTunnel(const Vehicle *v, bool reverse) +{ + TileIndex tile; + byte direction = (!reverse) ? DirToDiagdir(v->direction) : ReverseDiagdir(v->direction >> 1); + TileIndexDiff delta = TileOffsByDir(direction); + + if (v->u.rail.track != 0x40) + return v->tile; + + for (tile = v->tile;; tile += delta) { + if (IsTileType(tile, MP_TUNNELBRIDGE) && + (_map5[tile] & 0xF3) != (direction) && + GetTileZ(tile) == v->z_pos) + break; + } + return tile; + +}; + static void ReverseTrainDirection(Vehicle *v) { int l = 0, r = -1; Vehicle *u; + TileIndex tile; + byte trackdir; + + u = GetLastVehicleInChain(v); + tile = GetVehicleTileOutOfTunnel(u, false); + trackdir = ReverseTrackdir(GetVehicleTrackdir(u)); + + if (PBSTileReserved(tile) & (1 << (trackdir&7))) { + NPFFindStationOrTileData fstd; + NPFFoundTargetData ftd; + + NPFFillWithOrderData(&fstd, v); + + tile = GetVehicleTileOutOfTunnel(u, true); + + DEBUG(pbs, 2) ("pbs: (%i) choose reverse (RV), tile:%x, trackdir:%i",v->unitnumber, u->tile, trackdir); + ftd = NPFRouteToStationOrTile(tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_ANY); + + if (ftd.best_trackdir == 0xFF) { + DEBUG(pbs, 0) ("pbs: (%i) no nodes encountered (RV)", v->unitnumber); + CLRBIT(v->u.rail.flags, VRF_REVERSING); + return; + } + + // we found a way out of the pbs block + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) { + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED)) { + CLRBIT(v->u.rail.flags, VRF_REVERSING); + return; + } + } + } + + tile = GetVehicleTileOutOfTunnel(v, false); + trackdir = GetVehicleTrackdir(v); + + if (v->u.rail.pbs_status == PBS_STAT_HAS_PATH) { + byte trackdir = GetVehicleTrackdir(v); + TileIndex tile = AddTileIndexDiffCWrap(v->tile, TileIndexDiffCByDir(TrackdirToExitdir(trackdir))); + uint32 ts; + assert(tile != INVALID_TILE); + ts = GetTileTrackStatus(tile, TRANSPORT_RAIL); + ts &= TrackdirReachesTrackdirs(trackdir); + assert(ts != 0 && KillFirstBit2x64(ts) == 0); + trackdir = FindFirstBit2x64(ts); + PBSClearPath(tile, trackdir); + v->u.rail.pbs_status = PBS_STAT_NONE; + } else if (PBSTileReserved(tile) & (1 << (trackdir&7))) { + PBSClearPath(tile, trackdir); + if (v->u.rail.track != 0x40) + PBSReserveTrack(tile, trackdir & 7); + }; if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); + /* Check if we were approaching a rail/road-crossing */ { TileIndex tile = v->tile; @@ -1748,12 +1821,35 @@ static bool CheckTrainStayInDepot(Vehicle *v) v->load_unload_time_rem = 0; + if (PBSIsPbsDepot(v->tile)) { + byte trackdir = GetVehicleTrackdir(v); + NPFFindStationOrTileData fstd; + NPFFoundTargetData ftd; + + if (PBSTileUnavail(v->tile) & (1 << trackdir)) + return true; + + NPFFillWithOrderData(&fstd, v); + + DEBUG(pbs, 2) ("pbs: (%i) choose depot (DP), tile:%x, trackdir:%i",v->unitnumber, v->tile, trackdir); + ftd = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_GREEN); + + // we found a way out of the pbs block + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) { + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED)) + return true; + else + goto green; + } + } + + if (UpdateSignalsOnSegment(v->tile, v->direction)) { InvalidateWindowClasses(WC_TRAINS_LIST); return true; } } - +green: VehicleServiceInDepot(v); InvalidateWindowClasses(WC_TRAINS_LIST); TrainPlayLeaveStationSound(v); @@ -1904,13 +2000,26 @@ static byte ChooseTrainTrack(Vehicle *v, TileIndex tile, int enterdir, TrackdirB NPFFindStationOrTileData fstd; NPFFoundTargetData ftd; Trackdir trackdir; + uint16 pbs_tracks; NPFFillWithOrderData(&fstd, v); /* The enterdir for the new tile, is the exitdir for the old tile */ trackdir = GetVehicleTrackdir(v); assert(trackdir != 0xff); - ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype); + pbs_tracks = PBSTileReserved(tile); + pbs_tracks |= pbs_tracks << 8; + pbs_tracks &= TrackdirReachesTrackdirs(trackdir); + if (pbs_tracks || (v->u.rail.pbs_status == PBS_STAT_NEED_PATH)) { + DEBUG(pbs, 2) ("pbs: (%i) choosefromblock, tile_org:%x tile_dst:%x trackdir:%i pbs_tracks:%i",v->unitnumber, tile,tile - TileOffsByDir(enterdir), trackdir, pbs_tracks); + // clear the currently planned path + if (v->u.rail.pbs_status != PBS_STAT_NEED_PATH) PBSClearPath(tile, FindFirstBit2x64(pbs_tracks)); + + // try to find a route to a green exit signal + ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_ANY); + + } else + ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_NONE); if (ftd.best_trackdir == 0xff) { /* We are already at our target. Just do something */ @@ -1923,7 +2032,7 @@ static byte ChooseTrainTrack(Vehicle *v, TileIndex tile, int enterdir, TrackdirB we did not find our target, but ftd.best_trackdir contains the direction leading to the tile closest to our target. */ /* Discard enterdir information, making it a normal track */ - best_track = ftd.best_trackdir & 7; /* TODO: Wrapper function? */ + best_track = TrackdirToTrack(ftd.best_trackdir); } } else { @@ -2048,7 +2157,8 @@ 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.railtype, PBS_MODE_NONE); + if (ftd.best_bird_dist != 0) { /* We didn't find anything, just keep on going straight ahead */ reverse_best = false; @@ -2644,7 +2754,7 @@ static void TrainController(Vehicle *v) } else { /* is not inside depot */ - if (!TrainCheckIfLineEnds(v)) + if ((prev == NULL) && (!TrainCheckIfLineEnds(v))) return; r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); @@ -2699,11 +2809,54 @@ static void TrainController(Vehicle *v) } if (prev == NULL) { + byte trackdir; /* Currently the locomotive is active. Determine which one of the * available tracks to choose */ chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits); assert(chosen_track & tracks); + trackdir = TrackEnterdirToTrackdir(FIND_FIRST_BIT(chosen_track), enterdir); + assert(trackdir != 0xff); + + if (PBSIsPbsSignal(gp.new_tile,trackdir)) { + // encountered a pbs signal, and possible a pbs block + DEBUG(pbs, 3) ("pbs: (%i) arrive AT signal, tile:%x pbs_stat:%i",v->unitnumber, gp.new_tile, v->u.rail.pbs_status); + + if (v->u.rail.pbs_status == PBS_STAT_NONE) { + // we havent planned a path already, so try to find one now + NPFFindStationOrTileData fstd; + NPFFoundTargetData ftd; + + NPFFillWithOrderData(&fstd, v); + + DEBUG(pbs, 2) ("pbs: (%i) choose signal (TC), tile:%x, trackdir:%i",v->unitnumber, gp.new_tile, trackdir); + ftd = NPFRouteToStationOrTile(gp.new_tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_GREEN); + + if (v->u.rail.force_proceed != 0) + goto green_light; + + if (ftd.best_trackdir == 0xFF) + goto red_light; + + // we found a way out of the pbs block + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) { + if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED)) + goto red_light; + else { + goto green_light; + } + + }; + + } else { + // we have already planned a path through this pbs block + // on entering the block, we reset our status + v->u.rail.pbs_status = PBS_STAT_NONE; + goto green_light; + }; + DEBUG(pbs, 3) ("pbs: (%i) no green light found, or was no pbs-block",v->unitnumber); + }; + /* Check if it's a red signal and that force proceed is not clicked. */ if ( (tracks>>16)&chosen_track && v->u.rail.force_proceed == 0) goto red_light; } else { @@ -2712,6 +2865,9 @@ static void TrainController(Vehicle *v) /* The wagon is active, simply follow the prev vehicle. */ chosen_track = (byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits); } +green_light: + if (v->next == NULL) + PBSClearTrack(gp.old_tile, FIND_FIRST_BIT(v->u.rail.track)); /* make sure chosen track is a valid track */ assert(chosen_track==1 || chosen_track==2 || chosen_track==4 || chosen_track==8 || chosen_track==16 || chosen_track==32); @@ -2740,12 +2896,12 @@ static void TrainController(Vehicle *v) } if (v->subtype == TS_Front_Engine) - TrainMovedChangeSignals(gp.new_tile, enterdir); + TrainMovedChangeSignals(gp.new_tile, enterdir); /* Signals can only change when the first * (above) or the last vehicle moves. */ if (v->next == NULL) - TrainMovedChangeSignals(gp.old_tile, (enterdir) ^ 2); + TrainMovedChangeSignals(gp.old_tile, (enterdir) ^ 2); if (prev == NULL) { AffectSpeedByDirChange(v, chosen_dir); @@ -2860,6 +3016,17 @@ static void DeleteLastWagon(Vehicle *v) EndVehicleMove(v); DeleteVehicle(v); + // clear up reserved pbs tracks + if (PBSTileReserved(v->tile) & v->u.rail.track) { + if (v == u) { + PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track)); + PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track) + 8); + }; + if (v->tile != u->tile) { + PBSClearTrack(v->tile, FIND_FIRST_BIT(v->u.rail.track)); + }; + } + if (!(v->u.rail.track & 0xC0)) SetSignalsOnBothDir(v->tile, FIND_FIRST_BIT(v->u.rail.track)); @@ -2987,6 +3154,7 @@ static bool TrainCheckIfLineEnds(Vehicle *v) uint x,y; int t; uint32 ts; + byte trackdir; if ((uint)(t=v->breakdown_ctr) > 1) { v->vehstatus |= VS_TRAIN_SLOWING; @@ -3002,6 +3170,10 @@ static bool TrainCheckIfLineEnds(Vehicle *v) if (v->u.rail.track & 0x40) return true; + // exit if inside a depot + if (v->u.rail.track & 0x80) + return true; + tile = v->tile; // tunnel entrance? @@ -3025,6 +3197,12 @@ static bool TrainCheckIfLineEnds(Vehicle *v) // determine the track status on the next tile. ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[t]; + // if there are tracks on the new tile, pick one (trackdir will only be used when its a signal tile, in which case only 1 trackdir is accessible for us) + if (ts & TRACKDIR_BIT_MASK) + trackdir = FindFirstBit2x64(ts & TRACKDIR_BIT_MASK); + else + trackdir = INVALID_TRACKDIR; + /* Calc position within the current tile ?? */ x = v->x_pos & 0xF; y = v->y_pos & 0xF; @@ -3077,6 +3255,26 @@ static bool TrainCheckIfLineEnds(Vehicle *v) return false; } + if (v->u.rail.pbs_status == PBS_STAT_HAS_PATH) + return true; + + if ((trackdir != INVALID_TRACKDIR) && (PBSIsPbsSignal(tile,trackdir)) && !(IsTileType(v->tile, MP_STATION) && (v->current_order.station == _map2[v->tile]))) { + NPFFindStationOrTileData fstd; + NPFFoundTargetData ftd; + + NPFFillWithOrderData(&fstd, v); + + DEBUG(pbs, 2) ("pbs: (%i) choose signal (CEOL), tile:%x trackdir:%i", v->unitnumber, tile, trackdir); + ftd = NPFRouteToStationOrTile(tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_GREEN); + + if (ftd.best_trackdir != 0xFF && NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) { + if (!(NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED))) { + v->u.rail.pbs_status = PBS_STAT_HAS_PATH; + return true; + } + }; + }; + // slow down v->vehstatus |= VS_TRAIN_SLOWING; t = _breakdown_speeds[x & 0xF]; @@ -3237,6 +3435,12 @@ static void CheckIfTrainNeedsService(Vehicle *v) Depot *depot; TrainFindDepotData tfdd; + if (PBSTileReserved(v->tile) & v->u.rail.track) + return; + + if (v->u.rail.pbs_status == PBS_STAT_HAS_PATH) + return; + if (_patches.servint_trains == 0) return; |