diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -440,7 +440,7 @@ void ChangeOwnershipOfPlayerItems(Player TrackBits tracks = GetTrackBits(tile); do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT Track track = RemoveFirstTrack(&tracks); - if (HasSignalOnTrack(tile, track)) SetSignalsOnBothDir(tile, track); + if (HasSignalOnTrack(tile, track)) SetSignalsOnBothDir(tile, track, new_player); } while (tracks != TRACK_BIT_NONE); } } while (++tile != MapSize()); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -418,7 +418,7 @@ CommandCost CmdBuildSingleRail(TileIndex if (flags & DC_EXEC) { MarkTileDirtyByTile(tile); - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, _current_player); YapfNotifyTrackLayoutChange(tile, track); } @@ -441,6 +441,10 @@ CommandCost CmdRemoveSingleRail(TileInde if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR; trackbit = TrackToTrackBits(track); + /* Need to read tile owner now because it may change when the rail is removed. + * Also, in case of floods, _current_player != owner */ + Owner owner = GetTileOwner(tile); + switch (GetTileType(tile)) { case MP_ROAD: { if (!IsLevelCrossing(tile) || @@ -498,12 +502,12 @@ CommandCost CmdRemoveSingleRail(TileInde * are removing one of these pieces, we'll need to update signals for * both directions explicitly, as after the track is removed it won't * 'connect' with the other piece. */ - SetSignalsOnBothDir(tile, TRACK_X); - SetSignalsOnBothDir(tile, TRACK_Y); + SetSignalsOnBothDir(tile, TRACK_X, owner); + SetSignalsOnBothDir(tile, TRACK_Y, owner); YapfNotifyTrackLayoutChange(tile, TRACK_X); YapfNotifyTrackLayoutChange(tile, TRACK_Y); } else { - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, owner); YapfNotifyTrackLayoutChange(tile, track); } } @@ -741,7 +745,7 @@ CommandCost CmdBuildTrainDepot(TileIndex d->town_index = ClosestTownFromTile(tile, (uint)-1)->index; - UpdateSignalsOnSegment(tile, INVALID_DIAGDIR); + UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, _current_player); YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir))); d_auto_delete.Detach(); } @@ -867,7 +871,7 @@ CommandCost CmdBuildSingleSignal(TileInd } MarkTileDirtyByTile(tile); - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, _current_player); YapfNotifyTrackLayoutChange(tile, track); } @@ -1098,7 +1102,7 @@ CommandCost CmdRemoveSingleSignal(TileIn SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores } - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, GetTileOwner(tile)); YapfNotifyTrackLayoutChange(tile, track); MarkTileDirtyByTile(tile); @@ -1304,11 +1308,13 @@ static CommandCost RemoveTrainDepot(Tile return CMD_ERROR; if (flags & DC_EXEC) { + /* read variables before the depot is removed */ DiagDirection dir = GetRailDepotDirection(tile); + Owner owner = GetTileOwner(tile); DoClearSquare(tile); delete GetDepotByTile(tile); - UpdateSignalsOnSegment(tile, dir); + UpdateSignalsOnSegment(tile, dir, owner); YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir))); } diff --git a/src/signal.cpp b/src/signal.cpp --- a/src/signal.cpp +++ b/src/signal.cpp @@ -257,12 +257,10 @@ static SigFlags ExploreSegment(Owner own { SigFlags flags = SF_NONE; - while (!_tbdset.IsEmpty()) { - TileIndex tile; - DiagDirection enterdir; + TileIndex tile; + DiagDirection enterdir; - _tbdset.Get(&tile, &enterdir); - + while (_tbdset.Get(&tile, &enterdir)) { TileIndex oldtile = tile; // tile we are leaving DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir); // expected new exit direction (for straight line) @@ -396,11 +394,10 @@ static SigFlags ExploreSegment(Owner own */ static void UpdateSignalsAroundSegment(SigFlags flags) { - while (!_tbuset.IsEmpty()) { - TileIndex tile; - Trackdir trackdir; - _tbuset.Get(&tile, &trackdir); + TileIndex tile; + Trackdir trackdir; + while (_tbuset.Get(&tile, &trackdir)) { assert(HasSignalOnTrackdir(tile, trackdir)); SignalType sig = GetSignalType(tile, TrackdirToTrack(trackdir)); @@ -453,15 +450,17 @@ static inline void ResetSets() /** * Updates blocks in _globset buffer * + * @param owner player whose signals we are updating * @return false iff presignal entry would be green (needed for trains leaving depot) + * @pre IsValidPlayer(owner) */ -static bool UpdateSignalsInBuffer() +static bool UpdateSignalsInBuffer(Owner owner) { + assert(IsValidPlayer(owner)); + bool first = true; // first block? bool state = false; // value to return - Owner owner = OWNER_NONE; // owner whose signals we are updating - TileIndex tile; DiagDirection dir; @@ -479,7 +478,6 @@ static bool UpdateSignalsInBuffer() /* 'optimization assert' - do not try to update signals when it is not needed */ assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL); assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile))); - if (first) owner = GetTileOwner(tile); _tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR); break; @@ -488,7 +486,6 @@ static bool UpdateSignalsInBuffer() if (IsRailDepot(tile)) { /* 'optimization assert' do not try to update signals in other cases */ assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile)); - if (first) owner = GetTileOwner(tile); _tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside break; } @@ -497,7 +494,6 @@ static bool UpdateSignalsInBuffer() case MP_ROAD: if ((TrackBits)(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { /* only add to set when there is some 'interesting' track */ - if (first) owner = GetTileOwner(tile); _tbdset.Add(tile, dir); _tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir)); break; @@ -508,7 +504,6 @@ static bool UpdateSignalsInBuffer() tile = tile + TileOffsByDiagDir(dir); dir = ReverseDiagDir(dir); if ((TrackBits)(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { - if (first) owner = GetTileOwner(tile); _tbdset.Add(tile, dir); break; } @@ -516,7 +511,6 @@ static bool UpdateSignalsInBuffer() continue; // continue the while() loop } - assert(IsValidPlayer(owner)); assert(!_tbdset.Overflowed()); // it really shouldn't overflow by these one or two items assert(!_tbdset.IsEmpty()); // it wouldn't hurt anyone, but shouldn't happen too @@ -547,14 +541,15 @@ static bool UpdateSignalsInBuffer() * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param side side of tile + * @param owner owner whose signals we will update * @return false iff train can leave depot */ -bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side) +bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner) { assert(_globset.IsEmpty()); _globset.Add(tile, side); - return UpdateSignalsInBuffer(); + return UpdateSignalsInBuffer(owner); } @@ -565,8 +560,9 @@ bool UpdateSignalsOnSegment(TileIndex ti * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param track track at which ends we will update signals + * @param owner owner whose signals we will update */ -void SetSignalsOnBothDir(TileIndex tile, Track track) +void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner) { static const DiagDirection _search_dir_1[] = { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE @@ -579,5 +575,5 @@ void SetSignalsOnBothDir(TileIndex tile, _globset.Add(tile, _search_dir_1[track]); _globset.Add(tile, _search_dir_2[track]); - UpdateSignalsInBuffer(); + UpdateSignalsInBuffer(owner); } diff --git a/src/signal_func.h b/src/signal_func.h --- a/src/signal_func.h +++ b/src/signal_func.h @@ -9,6 +9,7 @@ #include "tile_type.h" #include "direction_type.h" #include "track_type.h" +#include "player_type.h" /** * Maps a trackdir to the bit that stores its status in the map arrays, in the @@ -40,7 +41,7 @@ static inline byte SignalOnTrack(Track t return _signal_on_track[track]; } -bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side); -void SetSignalsOnBothDir(TileIndex tile, Track track); +bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner); +void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner); #endif /* SIGNAL_FUNC_H */ diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1073,7 +1073,7 @@ CommandCost CmdBuildRailroadStation(Tile tile += tile_delta; } while (--w); - SetSignalsOnBothDir(tile_org, track); + SetSignalsOnBothDir(tile_org, track, _current_player); YapfNotifyTrackLayoutChange(tile_org, track); tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta } while (--numtracks); @@ -1202,11 +1202,14 @@ CommandCost CmdRemoveFromRailroadStation quantity++; if (flags & DC_EXEC) { + /* read variables before the station tile is removed */ uint specindex = GetCustomStationSpecIndex(tile2); Track track = GetRailStationTrack(tile2); + Owner owner = GetTileOwner(tile2); + DoClearSquare(tile2); st->rect.AfterRemoveTile(st, tile2); - SetSignalsOnBothDir(tile2, track); + SetSignalsOnBothDir(tile2, track, owner); YapfNotifyTrackLayoutChange(tile2, track); DeallocateSpecFromStation(st, specindex); @@ -1257,15 +1260,17 @@ static CommandCost RemoveRailroadStation do { int w_bak = w; do { - // for nonuniform stations, only remove tiles that are actually train station tiles + /* for nonuniform stations, only remove tiles that are actually train station tiles */ if (st->TileBelongsToRailStation(tile)) { if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; cost.AddCost(_price.remove_rail_station); if (flags & DC_EXEC) { + /* read variables before the station tile is removed */ Track track = GetRailStationTrack(tile); + Owner owner = GetTileOwner(tile); // _current_player can be OWNER_WATER DoClearSquare(tile); - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, owner); YapfNotifyTrackLayoutChange(tile, track); } } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2168,7 +2168,7 @@ static bool CheckTrainStayInDepot(Vehicl v->load_unload_time_rem = 0; - if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR)) { + if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner)) { InvalidateWindowClasses(WC_TRAINS_LIST); return true; } @@ -2187,7 +2187,7 @@ static bool CheckTrainStayInDepot(Vehicl v->UpdateDeltaXY(v->direction); v->cur_image = v->GetImage(v->direction); VehiclePositionChanged(v); - UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR); + UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); UpdateTrainAcceleration(v); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); @@ -2768,7 +2768,7 @@ static void TrainMovedChangeSignals(Tile if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_SIGNALS) { uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]); - UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); + UpdateSignalsOnSegment(tile, _otherside_signal_directions[i], GetTileOwner(tile)); } } @@ -3141,8 +3141,10 @@ static void DeleteLastWagon(Vehicle *v) /* 'v' shouldn't be accessed after it has been deleted */ TrackBits track = v->u.rail.track; TileIndex tile = v->tile; + Owner owner = v->owner; delete v; + v = NULL; // make sure nobody will won't try to read 'v' anymore /* Check if the wagon was on a road/rail-crossing and disable it if no * others are on it */ @@ -3150,9 +3152,9 @@ static void DeleteLastWagon(Vehicle *v) /* Update signals */ if (IsTileType(tile, MP_TUNNELBRIDGE) || IsTileDepotType(tile, TRANSPORT_RAIL)) { - UpdateSignalsOnSegment(tile, INVALID_DIAGDIR); + UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); } else { - SetSignalsOnBothDir(tile, (Track)(FIND_FIRST_BIT(track))); + SetSignalsOnBothDir(tile, (Track)(FIND_FIRST_BIT(track)), owner); } } diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -419,7 +419,7 @@ not_valid_below:; if (flags & DC_EXEC && railtype != INVALID_RAILTYPE) { Track track = AxisToTrack(direction); - UpdateSignalsOnSegment(tile_start, INVALID_DIAGDIR); + UpdateSignalsOnSegment(tile_start, INVALID_DIAGDIR, _current_player); YapfNotifyTrackLayoutChange(tile_start, track); } @@ -549,7 +549,7 @@ CommandCost CmdBuildTunnel(TileIndex sta if (GB(p1, 9, 1) == TRANSPORT_RAIL) { MakeRailTunnel(start_tile, _current_player, direction, (RailType)GB(p1, 0, 4)); MakeRailTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4)); - UpdateSignalsOnSegment(start_tile, INVALID_DIAGDIR); + UpdateSignalsOnSegment(start_tile, INVALID_DIAGDIR, _current_player); YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction))); } else { MakeRoadTunnel(start_tile, _current_player, direction, (RoadTypes)GB(p1, 0, 3)); @@ -603,21 +603,24 @@ static CommandCost DoClearTunnel(TileInd } if (flags & DC_EXEC) { - /* We first need to request the direction before calling DoClearSquare - * else the direction is always 0.. dah!! ;) */ - DiagDirection dir = GetTunnelBridgeDirection(tile); - bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL; + if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + /* We first need to request values before calling DoClearSquare */ + DiagDirection dir = GetTunnelBridgeDirection(tile); + Owner owner = GetTileOwner(tile); - DoClearSquare(tile); - DoClearSquare(endtile); + DoClearSquare(tile); + DoClearSquare(endtile); - if (rail) { - UpdateSignalsOnSegment(tile, ReverseDiagDir(dir)); - UpdateSignalsOnSegment(endtile, dir); + /* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */ + UpdateSignalsOnSegment(tile, ReverseDiagDir(dir), owner); + UpdateSignalsOnSegment(endtile, dir, owner); Track track = AxisToTrack(DiagDirToAxis(dir)); YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); + } else { + DoClearSquare(tile); + DoClearSquare(endtile); } } return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_tunnel * (DistanceManhattan(tile, endtile) + 1)); @@ -660,6 +663,7 @@ static CommandCost DoClearBridge(TileInd if (flags & DC_EXEC) { /* read this value before actual removal of bridge */ bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL; + Owner owner = GetTileOwner(tile); DoClearSquare(tile); DoClearSquare(endtile); @@ -669,8 +673,9 @@ static CommandCost DoClearBridge(TileInd } if (rail) { - UpdateSignalsOnSegment(tile, ReverseDiagDir(direction)); - UpdateSignalsOnSegment(endtile, direction); + /* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */ + UpdateSignalsOnSegment(tile, ReverseDiagDir(direction), owner); + UpdateSignalsOnSegment(endtile, direction, owner); Track track = AxisToTrack(DiagDirToAxis(direction)); YapfNotifyTrackLayoutChange(tile, track); diff --git a/src/vehicle.cpp b/src/vehicle.cpp --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2178,7 +2178,7 @@ void VehicleEnterDepot(Vehicle *v) case VEH_TRAIN: InvalidateWindowClasses(WC_TRAINS_LIST); if (!IsFrontEngine(v)) v = v->First(); - UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR); + UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); v->load_unload_time_rem = 0; break; diff --git a/src/waypoint.cpp b/src/waypoint.cpp --- a/src/waypoint.cpp +++ b/src/waypoint.cpp @@ -286,6 +286,7 @@ CommandCost RemoveTrainWaypoint(TileInde if (flags & DC_EXEC) { Track track = GetRailWaypointTrack(tile); + Owner owner = GetTileOwner(tile); // cannot use _current_player because of possible floods wp = GetWaypointByTile(tile); wp->deleted = 30; // let it live for this many days before we do the actual deletion. @@ -296,7 +297,7 @@ CommandCost RemoveTrainWaypoint(TileInde MarkTileDirtyByTile(tile); } else { DoClearSquare(tile); - SetSignalsOnBothDir(tile, track); + SetSignalsOnBothDir(tile, track, owner); } YapfNotifyTrackLayoutChange(tile, track); }