00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "station_map.h"
00015 #include "tunnelbridge_map.h"
00016 #include "vehicle_func.h"
00017 #include "viewport_func.h"
00018 #include "train.h"
00019 #include "company_base.h"
00020 #include "gui.h"
00021 #include "table/strings.h"
00022 #include "programmable_signals.h"
00023 #include "infrastructure_func.h"
00024
00026 typedef SmallVector<SignalReference, 4> SignalDependencyList;
00027
00032 typedef std::map<SignalReference, SignalDependencyList> SignalDependencyMap;
00033
00034 static SignalDependencyMap _signal_dependencies;
00035 static void MarkDependencidesForUpdate(SignalReference sig);
00036
00038 static const uint SIG_TBU_SIZE = 64;
00039 static const uint SIG_TBD_SIZE = 256;
00040 static const uint SIG_GLOB_SIZE = 128;
00041 static const uint SIG_GLOB_UPDATE = 64;
00042
00043 assert_compile(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE);
00044
00046 static const TrackBits _enterdir_to_trackbits[DIAGDIR_END] = {
00047 TRACK_BIT_3WAY_NE,
00048 TRACK_BIT_3WAY_SE,
00049 TRACK_BIT_3WAY_SW,
00050 TRACK_BIT_3WAY_NW
00051 };
00052
00054 static const TrackdirBits _enterdir_to_trackdirbits[DIAGDIR_END] = {
00055 TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S,
00056 TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N,
00057 TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N,
00058 TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S
00059 };
00060
00066 template <typename Tdir, uint items>
00067 struct SmallSet {
00068 private:
00069 uint n;
00070 bool overflowed;
00071 const char *name;
00072
00074 struct SSdata {
00075 TileIndex tile;
00076 Tdir dir;
00077 } data[items];
00078
00079 public:
00081 SmallSet(const char *name) : n(0), overflowed(false), name(name) { }
00082
00084 void Reset()
00085 {
00086 this->n = 0;
00087 this->overflowed = false;
00088 }
00089
00094 bool Overflowed()
00095 {
00096 return this->overflowed;
00097 }
00098
00103 bool IsEmpty()
00104 {
00105 return this->n == 0;
00106 }
00107
00112 bool IsFull()
00113 {
00114 return this->n == lengthof(data);
00115 }
00116
00121 uint Items()
00122 {
00123 return this->n;
00124 }
00125
00126
00133 bool Remove(TileIndex tile, Tdir dir)
00134 {
00135 for (uint i = 0; i < this->n; i++) {
00136 if (this->data[i].tile == tile && this->data[i].dir == dir) {
00137 this->data[i] = this->data[--this->n];
00138 return true;
00139 }
00140 }
00141
00142 return false;
00143 }
00144
00151 bool IsIn(TileIndex tile, Tdir dir)
00152 {
00153 for (uint i = 0; i < this->n; i++) {
00154 if (this->data[i].tile == tile && this->data[i].dir == dir) return true;
00155 }
00156
00157 return false;
00158 }
00159
00167 bool Add(TileIndex tile, Tdir dir)
00168 {
00169 if (this->IsFull()) {
00170 overflowed = true;
00171 DEBUG(misc, 0, "SignalSegment too complex. Set %s is full (maximum %d)", name, items);
00172 return false;
00173 }
00174
00175 this->data[this->n].tile = tile;
00176 this->data[this->n].dir = dir;
00177 this->n++;
00178
00179 return true;
00180 }
00181
00188 bool Get(TileIndex *tile, Tdir *dir)
00189 {
00190 if (this->n == 0) return false;
00191
00192 this->n--;
00193 *tile = this->data[this->n].tile;
00194 *dir = this->data[this->n].dir;
00195
00196 return true;
00197 }
00198 };
00199
00200 static SmallSet<Trackdir, SIG_TBU_SIZE> _tbuset("_tbuset");
00201 static SmallSet<DiagDirection, SIG_TBD_SIZE> _tbdset("_tbdset");
00202 static SmallSet<DiagDirection, SIG_GLOB_SIZE> _globset("_globset");
00203 static uint _num_signals_evaluated;
00204
00206 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
00207 {
00208 if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL;
00209
00210 return v;
00211 }
00212
00226 static inline bool CheckAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
00227 {
00228 _globset.Remove(t1, d1);
00229 _globset.Remove(t2, d2);
00230
00231 assert(!_tbdset.IsIn(t1, d1));
00232
00233 if (_tbdset.Remove(t2, d2)) return false;
00234
00235 return true;
00236 }
00237
00239 static Vehicle *TrainInWormholeTileEnum(Vehicle *v, void *data)
00240 {
00241
00242 if (v->type != VEH_TRAIN || (v->Previous() != NULL && v->Next() != NULL)) return NULL;
00243 if (*(TileIndex *)data != TileVirtXY(v->x_pos, v->y_pos)) return NULL;
00244 return v;
00245 }
00246
00260 static inline bool MaybeAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
00261 {
00262 if (!CheckAddToTodoSet(t1, d1, t2, d2)) return true;
00263
00264 return _tbdset.Add(t1, d1);
00265 }
00266
00267
00269 enum SigFlags {
00270 SF_NONE = 0,
00271 SF_TRAIN = 1 << 0,
00272 SF_FULL = 1 << 1,
00273 SF_PBS = 1 << 2,
00274 };
00275
00276 DECLARE_ENUM_AS_BIT_SET(SigFlags)
00277
00278 struct SigInfo {
00279 inline SigInfo()
00280 {
00281 flags = SF_NONE;
00282 num_exits = 0;
00283 num_green = 0;
00284 }
00285 SigFlags flags;
00286 uint num_exits;
00287 uint num_green;
00288 };
00289
00296 static SigInfo ExploreSegment(Owner owner)
00297 {
00298 SigInfo info;
00299 TileIndex tile;
00300 DiagDirection enterdir;
00301
00302 while (_tbdset.Get(&tile, &enterdir)) {
00303 TileIndex oldtile = tile;
00304 DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir);
00305
00306 switch (GetTileType(tile)) {
00307 case MP_RAILWAY: {
00308 if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
00309
00310 if (IsRailDepot(tile)) {
00311 if (enterdir == INVALID_DIAGDIR) {
00312 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00313 exitdir = GetRailDepotDirection(tile);
00314 tile += TileOffsByDiagDir(exitdir);
00315 enterdir = ReverseDiagDir(exitdir);
00316 break;
00317 } else if (enterdir == GetRailDepotDirection(tile)) {
00318 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00319 continue;
00320 } else {
00321 continue;
00322 }
00323 }
00324
00325 TrackBits tracks = GetTrackBits(tile);
00326 TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]);
00327
00328 if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) {
00329 tracks = tracks_masked;
00330
00331 if (!(info.flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) info.flags |= SF_TRAIN;
00332 } else {
00333 if (tracks_masked == TRACK_BIT_NONE) continue;
00334 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00335 }
00336
00337 if (HasSignals(tile)) {
00338 Track track = TrackBitsToTrack(tracks_masked);
00339 if (HasSignalOnTrack(tile, track) && !IsSpeedSignal(GetSignalType(tile, track))) {
00340 SignalType sig = GetSignalType(tile, track);
00341 Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101) & _enterdir_to_trackdirbits[enterdir]);
00342 Trackdir reversedir = ReverseTrackdir(trackdir);
00343
00344
00345
00346 if (HasSignalOnTrackdir(tile, reversedir)) {
00347 if (IsPbsSignal(sig)) {
00348 info.flags |= SF_PBS;
00349 } else if (!_tbuset.Add(tile, reversedir)) {
00350 info.flags |= SF_FULL;
00351 return info;
00352 }
00353 }
00354 if (HasSignalOnTrackdir(tile, trackdir) && !IsOnewaySignal(tile, track)) info.flags |= SF_PBS;
00355
00356
00357 if (IsPresignalExit(tile, track) && HasSignalOnTrackdir(tile, trackdir)) {
00358 info.num_exits++;
00359 if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) {
00360 info.num_green++;
00361 }
00362 }
00363
00364 continue;
00365 }
00366 }
00367
00368 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
00369 if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) {
00370 TileIndex newtile = tile + TileOffsByDiagDir(dir);
00371 DiagDirection newdir = ReverseDiagDir(dir);
00372 if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) {
00373 info.flags |= SF_FULL;
00374 return info;
00375 }
00376 }
00377 }
00378
00379 continue;
00380 }
00381
00382 case MP_STATION:
00383 if (!HasStationRail(tile)) continue;
00384 if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
00385 if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue;
00386 if (IsStationTileBlocked(tile)) continue;
00387
00388 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00389 tile += TileOffsByDiagDir(exitdir);
00390 break;
00391
00392 case MP_ROAD:
00393 if (!IsLevelCrossing(tile)) continue;
00394 if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
00395 if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue;
00396
00397 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00398 tile += TileOffsByDiagDir(exitdir);
00399 break;
00400
00401 case MP_TUNNELBRIDGE:
00402 {
00403 if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
00404 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
00405 DiagDirection dir;
00406 dir = GetTunnelBridgeDirection(tile);
00407
00408 if (HasWormholeSignals(tile)) {
00409 if (enterdir == INVALID_DIAGDIR) {
00410 if (!(info.flags & SF_TRAIN) && IsTunnelBridgeExit(tile)) {
00411 if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
00412 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
00413 }
00414 enterdir = dir;
00415 exitdir = ReverseDiagDir(dir);
00416 tile += TileOffsByDiagDir(exitdir);
00417 } else {
00418 if (ReverseDiagDir(enterdir) != dir) continue;
00419 if (!(info.flags & SF_TRAIN)) {
00420 if (HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
00421 if (!(info.flags & SF_TRAIN) && IsTunnelBridgeExit(tile)) {
00422 if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
00423 }
00424 }
00425 continue;
00426 }
00427 } else {
00428 if (enterdir == INVALID_DIAGDIR) {
00429 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00430 enterdir = dir;
00431 exitdir = ReverseDiagDir(dir);
00432 tile += TileOffsByDiagDir(exitdir);
00433 } else {
00434 if (ReverseDiagDir(enterdir) != dir) continue;
00435 if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
00436 tile = GetOtherTunnelBridgeEnd(tile);
00437 enterdir = INVALID_DIAGDIR;
00438 exitdir = INVALID_DIAGDIR;
00439 }
00440 }
00441 }
00442 break;
00443
00444 default:
00445 continue;
00446 }
00447
00448 if (!MaybeAddToTodoSet(tile, enterdir, oldtile, exitdir)) {
00449 info.flags |= SF_FULL;
00450 }
00451 }
00452
00453 return info;
00454 }
00455
00456
00462 static void UpdateSignalsAroundSegment(SigInfo info)
00463 {
00464 TileIndex tile;
00465 Trackdir trackdir;
00466 Track track;
00467
00468 while (_tbuset.Get(&tile, &trackdir)) {
00469 assert(HasSignalOnTrackdir(tile, trackdir));
00470
00471 track = TrackdirToTrack(trackdir);
00472 SignalType sig = GetSignalType(tile, track);
00473 SignalState newstate = SIGNAL_STATE_GREEN;
00474
00475
00476 if (sig == SIGTYPE_SPEED) {
00477 newstate = SIGNAL_STATE_GREEN;
00478 } else if (info.flags & SF_TRAIN) {
00479
00480 newstate = SIGNAL_STATE_RED;
00481 } else if (sig == SIGTYPE_PROG &&
00482 _num_signals_evaluated > _settings_game.construction.maximum_signal_evaluations) {
00483
00484 newstate = SIGNAL_STATE_RED;
00485 } else {
00486
00487 if (IsComboSignal(sig) && HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) {
00488
00489 uint exits = info.num_exits - 1;
00490 uint green = info.num_green;
00491 if (GetSignalStateByTrackdir(tile, ReverseTrackdir(trackdir)) == SIGNAL_STATE_GREEN)
00492 green--;
00493
00494 if (sig == SIGTYPE_PROG) {
00495 _num_signals_evaluated++;
00496
00497 if (!RunSignalProgram(SignalReference(tile, track), exits, green))
00498 newstate = SIGNAL_STATE_RED;
00499 } else {
00500 if (!green && exits)
00501 newstate = SIGNAL_STATE_RED;
00502 }
00503 } else {
00504 if (IsEntrySignal(sig)) {
00505 if (sig == SIGTYPE_PROG) {
00506 _num_signals_evaluated++;
00507 if (!RunSignalProgram(SignalReference(tile, track), info.num_exits, info.num_green))
00508 newstate = SIGNAL_STATE_RED;
00509 } else {
00510 if (!info.num_green && info.num_exits) newstate = SIGNAL_STATE_RED;
00511 }
00512 }
00513 }
00514 }
00515
00516
00517 if (newstate != GetSignalStateByTrackdir(tile, trackdir)) {
00518 if (IsExitSignal(sig)) {
00519
00520 DiagDirection exitdir = TrackdirToExitdir(ReverseTrackdir(trackdir));
00521 _globset.Add(tile, exitdir);
00522
00523
00524 MarkDependencidesForUpdate(SignalReference(tile, track));
00525 }
00526 SetSignalStateByTrackdir(tile, trackdir, newstate);
00527 MarkTileDirtyByTile(tile);
00528 }
00529 }
00530 }
00531
00532
00534 static inline void ResetSets()
00535 {
00536 _tbuset.Reset();
00537 _tbdset.Reset();
00538 _globset.Reset();
00539 }
00540
00541
00549 static SigSegState UpdateSignalsInBuffer(Owner owner)
00550 {
00551 assert(Company::IsValidID(owner));
00552
00553 bool first = true;
00554 SigSegState state = SIGSEG_FREE;
00555 _num_signals_evaluated = 0;
00556
00557 TileIndex tile;
00558 DiagDirection dir;
00559
00560 while (_globset.Get(&tile, &dir)) {
00561 assert(_tbuset.IsEmpty());
00562 assert(_tbdset.IsEmpty());
00563
00564
00565
00566
00567
00568
00569 switch (GetTileType(tile)) {
00570 case MP_TUNNELBRIDGE:
00571
00572 assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
00573 assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile)));
00574 _tbdset.Add(tile, INVALID_DIAGDIR);
00575 if (!HasWormholeSignals(tile)) {
00576 _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
00577 }
00578 break;
00579
00580 case MP_RAILWAY:
00581 if (IsRailDepot(tile)) {
00582
00583 assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
00584 _tbdset.Add(tile, INVALID_DIAGDIR);
00585 break;
00586 }
00587
00588 case MP_STATION:
00589 case MP_ROAD:
00590 if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
00591
00592 _tbdset.Add(tile, dir);
00593 _tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir));
00594 break;
00595 }
00596
00597 default:
00598
00599 tile = tile + TileOffsByDiagDir(dir);
00600 dir = ReverseDiagDir(dir);
00601 if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
00602 _tbdset.Add(tile, dir);
00603 break;
00604 }
00605
00606 continue;
00607 }
00608
00609 assert(!_tbdset.Overflowed());
00610 assert(!_tbdset.IsEmpty());
00611
00612 SigInfo info = ExploreSegment(owner);
00613
00614 if (first) {
00615 first = false;
00616
00617 if (info.flags & SF_PBS) {
00618 state = SIGSEG_PBS;
00619 } else if ((info.flags & SF_TRAIN) || ((info.num_exits) && !(info.num_green)) || (info.flags & SF_FULL)) {
00620 state = SIGSEG_FULL;
00621 }
00622 }
00623
00624
00625 if (info.flags & SF_FULL) {
00626 ResetSets();
00627 break;
00628 }
00629
00630 if (_num_signals_evaluated > _settings_game.construction.maximum_signal_evaluations) {
00631 ShowErrorMessage(STR_ERROR_SIGNAL_CHANGES, STR_EMPTY, WL_INFO);
00632 }
00633
00634 UpdateSignalsAroundSegment(info);
00635 }
00636
00637 return state;
00638 }
00639
00640
00641 static Owner _last_owner = INVALID_OWNER;
00642
00643
00648 void UpdateSignalsInBuffer()
00649 {
00650 if (!_globset.IsEmpty()) {
00651 UpdateSignalsInBuffer(_last_owner);
00652 _last_owner = INVALID_OWNER;
00653 }
00654 }
00655
00656
00664 void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
00665 {
00666 static const DiagDirection _search_dir_1[] = {
00667 DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE
00668 };
00669 static const DiagDirection _search_dir_2[] = {
00670 DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
00671 };
00672
00673
00674
00675 assert(_globset.IsEmpty() || IsOneSignalBlock(owner, _last_owner));
00676
00677 _last_owner = owner;
00678
00679 _globset.Add(tile, _search_dir_1[track]);
00680 _globset.Add(tile, _search_dir_2[track]);
00681
00682 if (_globset.Items() >= SIG_GLOB_UPDATE) {
00683
00684 UpdateSignalsInBuffer(_last_owner);
00685 _last_owner = INVALID_OWNER;
00686 }
00687 }
00688
00689
00697 void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
00698 {
00699
00700
00701 assert(_globset.IsEmpty() || IsOneSignalBlock(owner, _last_owner));
00702
00703 _last_owner = owner;
00704
00705 _globset.Add(tile, side);
00706
00707 if (_globset.Items() >= SIG_GLOB_UPDATE) {
00708
00709 UpdateSignalsInBuffer(_last_owner);
00710 _last_owner = INVALID_OWNER;
00711 }
00712 }
00713
00724 SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
00725 {
00726 assert(_globset.IsEmpty());
00727 _globset.Add(tile, side);
00728
00729 return UpdateSignalsInBuffer(owner);
00730 }
00731
00732
00742 void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner)
00743 {
00744 assert(_globset.IsEmpty());
00745
00746 AddTrackToSignalBuffer(tile, track, owner);
00747 UpdateSignalsInBuffer(owner);
00748 }
00749
00750 void AddSignalDependency(SignalReference on, SignalReference dep)
00751 {
00752 assert(GetTileOwner(on.tile) == GetTileOwner(dep.tile));
00753 SignalDependencyList &dependencies = _signal_dependencies[on];
00754 (*dependencies.Append()) = dep;
00755 }
00756
00757 void RemoveSignalDependency(SignalReference on, SignalReference dep)
00758 {
00759 SignalDependencyList &dependencies = _signal_dependencies[on];
00760 SignalReference *ob = dependencies.Find(dep);
00761
00762
00763 if(ob == dependencies.End())
00764 return;
00765
00766 dependencies.Erase(ob);
00767 if (dependencies.Length() == 0)
00768 _signal_dependencies.erase(on);
00769 }
00770
00771 void FreeSignalDependencies()
00772 {
00773 _signal_dependencies.clear();
00774 }
00775
00776 static void MarkDependencidesForUpdate(SignalReference on)
00777 {
00778 SignalDependencyMap::iterator f = _signal_dependencies.find(on);
00779 if (f == _signal_dependencies.end()) return;
00780
00781 SignalDependencyList &dependencies = f->second;
00782 for (SignalReference *i = dependencies.Begin(), *e = dependencies.End();
00783 i != e; ++i) {
00784 assert(GetTileOwner(i->tile) == GetTileOwner(on.tile));
00785
00786 Trackdir td = TrackToTrackdir(i->track);
00787 _globset.Add(i->tile, TrackdirToExitdir(td));
00788 _globset.Add(i->tile, TrackdirToExitdir(ReverseTrackdir(td)));
00789 }
00790 }
00791
00792 void CheckRemoveSignalsFromTile(TileIndex tile)
00793 {
00794 if (!HasSignals(tile)) return;
00795
00796 TrackBits tb = GetTrackBits(tile);
00797 Track tr;
00798 while ((tr = RemoveFirstTrack(&tb)) != INVALID_TRACK) {
00799 if (HasSignalOnTrack(tile, tr)) CheckRemoveSignal(tile, tr);
00800 }
00801 }
00802
00803 static void NotifyRemovingDependentSignal(SignalReference on, SignalReference by)
00804 {
00805 SignalType t = GetSignalType(by.tile, by.track);
00806 if (IsProgrammableSignal(t)) {
00807 RemoveProgramDependencies(by, on);
00808 } else DEBUG(misc, 0, "Removing dependency held by non-programmable signal (Unexpected)");
00809 }
00810
00811 void CheckRemoveSignal(TileIndex tile, Track track)
00812 {
00813 if (!HasSignalOnTrack(tile, track)) return;
00814 SignalReference thisRef(tile, track);
00815
00816 SignalType t = GetSignalType(tile, track);
00817 if (IsProgrammableSignal(t)) {
00818 FreeSignalProgram(thisRef);
00819 } else if (IsSpeedSignal(t)) {
00820 FreeSignalSpeed(thisRef);
00821 }
00822
00823 SignalDependencyMap::iterator i = _signal_dependencies.find(SignalReference(tile, track)), e = _signal_dependencies.end();
00824
00825 if (i != e) {
00826 SignalDependencyList &dependencies = i->second;
00827
00828 for (SignalReference *ir = dependencies.Begin(), *er = dependencies.End(); ir != er; ++ir) {
00829 assert(GetTileOwner(ir->tile) == GetTileOwner(tile));
00830 NotifyRemovingDependentSignal(thisRef, *ir);
00831 }
00832
00833 _signal_dependencies.erase(i);
00834 }
00835 }