2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file logic_signals.cpp Utility functions of the Logic Signals patch. */
10 #include "logic_signals.h"
11 #include "overlay_cmd.h"
14 #include "viewport_func.h"
15 #include "window_func.h"
17 SignalProgramList _signal_program_list
; //!< List of all signal programs.
18 SignalLinkList _signal_link_list
; //!< List of all links between signals.
21 * Remove all signal programs.
23 void FreeAllSignalPrograms()
25 for (auto it
= _signal_program_list
.begin(); it
!= _signal_program_list
.end(); ++it
) {
26 SignalProgram
* program
= it
->second
;
30 _signal_program_list
.clear();
31 _signal_link_list
.clear();
35 * Determine the color of signals at the given tile/track.
37 * @param tile The tile where the tested signal is located.
38 * @param track The track where the tested signal is located.
39 * @return Red if either of the two possible signals is red.
41 SignalState
DetermineSignalState(TileIndex tile
, Track track
)
43 assert(HasSignalOnTrack(tile
, track
));
45 const uint signal_states
= GetSignalStates(tile
);
46 const byte signal_mask_for_track
= SignalOnTrack(track
);
47 const byte present_signals_on_tile
= GetPresentSignals(tile
);
49 const byte present_signals_on_track
= signal_mask_for_track
& present_signals_on_tile
;
50 const byte signal_states_on_track
= present_signals_on_track
& signal_states
;
52 // We return red if one of the two possibly present signals is red.
53 // Both need to be green for us to accept the tile as green.
54 return (signal_states_on_track
== present_signals_on_track
) ? SIGNAL_STATE_GREEN
: SIGNAL_STATE_RED
;
58 * Set the signal state for the given tile and track to the specified state.
59 * Both possible signals for the given tile/track are set to the given state.
61 * @param tile Tile where the changed signal is located.
62 * @param track Track where the changed signal is located.
63 * @param state The new state to set to the signals.
65 void SetSignalStateForTrack(TileIndex tile
, Track track
, SignalState state
)
67 const byte present_signals_on_tile
= GetPresentSignals(tile
);
69 if (state
== SIGNAL_STATE_GREEN
) {
70 SetSignalStates(tile
, GetSignalStates(tile
) | present_signals_on_tile
);
72 SetSignalStates(tile
, GetSignalStates(tile
) & ~present_signals_on_tile
);
77 * Read a Track from a TileIndex.
79 * @param tile The tile where to read the Track from.
80 * @return The read Track
82 Track
SignalTrackFromTile(TileIndex tile
)
84 TrackBits trackbits
= TrackStatusToTrackBits(GetTileTrackStatus(tile
, TRANSPORT_RAIL
, 0));
86 if (trackbits
& TRACK_BIT_VERT
) {
88 trackbits
= (_tile_fract_coords
.x
<= _tile_fract_coords
.y
) ? TRACK_BIT_RIGHT
: TRACK_BIT_LEFT
;
91 if (trackbits
& TRACK_BIT_HORZ
) {
93 trackbits
= (_tile_fract_coords
.x
+ _tile_fract_coords
.y
<= 15) ? TRACK_BIT_UPPER
: TRACK_BIT_LOWER
;
96 return FindFirstTrack(trackbits
);
100 * Combine TileIndex and Track to a SignalReference.
101 * @param tile The tile to get a signal reference from
102 * @param track The track to get a signal reference from
103 * @return The signal reference made up of the given tile and track
105 SignalReference
GetSignalReference(TileIndex tile
, Track track
)
107 return uint64(tile
) | (uint64(track
) << 32);
111 * Extract a TileIndex from a SignalReference.
112 * @param key The signal reference to extract a TileIndex from
113 * @return The TileIndex component of the given signal reference
115 TileIndex
GetTileFromSignalReference(SignalReference key
)
117 return GB(key
, 0, 32);
121 * Extract a Track from a SignalReference.
122 * @param key The signal reference to extract a Track from
123 * @return The Track component of the given signal reference
125 Track
GetTrackFromSignalReference(SignalReference key
)
127 return static_cast<Track
>(key
>> 32);
131 * An internal helper function used in searching for a signal program.
132 * @param tile The tile to search for
133 * @param track The track to search for
134 * @return The corresponding signal program, or nullptr if not found.
136 static SignalProgram
* DoFindSignalProgram(TileIndex tile
, Track track
)
138 const auto found
= _signal_program_list
.find(GetSignalReference(tile
, track
));
140 return (found
!= _signal_program_list
.end()) ? found
->second
: nullptr;
144 * Finds all links from a signal at the given tile/track.
145 * @param tile The tile to search for.
146 * @param track The track to search for.
147 * @return The corresponding targets where the link points to.
149 static std::list
<SignalReference
> FindSignalLinks(TileIndex tile
, Track track
)
151 const auto source
= GetSignalReference(tile
, track
);
153 std::list
<SignalReference
> targets
;
155 for (const auto link
: _signal_link_list
) {
156 if (link
.first
== source
) {
157 targets
.push_back(link
.second
);
165 * Used to find a signal program at the given tile and track.
166 * @param tile The tile to search for.
167 * @param track The track to search for.
168 * @return The signal program if found, or nullptr.
170 SignalProgram
* FindSignalProgram(TileIndex tile
, Track track
)
172 SignalProgram
* program
= DoFindSignalProgram(tile
, track
);
174 assert(program
!= nullptr);
180 * Remove a signal link at the given tile and track, if it is found.
181 * It is perfectly valid to call this function even if the said tile/track has no outgoing link.
183 * @param tile The tile to search for
184 * @param track The track to search for
186 void RemoveSignalLink(TileIndex tile
, Track track
)
188 auto targets
= FindSignalLinks(tile
, track
);
190 for (auto target
: targets
) {
191 SignalProgram
* program
= FindSignalProgram(GetTileFromSignalReference(target
),
192 GetTrackFromSignalReference(target
));
193 program
->RemoveLink(tile
, track
);
195 // Invalidate any windows which have this program open.
196 InvalidateWindowData(WC_SIGNAL_PROGRAM
, target
);
201 * Create a new signal program at the given tile and track.
202 * Used when a new logic signal is created.
204 * @param tile The tile of the logic signal
205 * @param track The track of the logic signal
206 * @return The newly created signal program
208 SignalProgram
* CreateSignalProgram(TileIndex tile
, Track track
)
210 // Existing program for same tile/track should not exist.
211 assert(DoFindSignalProgram(tile
, track
) == nullptr);
213 const auto program
= new SignalProgram(tile
, track
);
214 _signal_program_list
[GetSignalReference(tile
, track
)] = program
;
220 * Delete a signal program at the given tile and track.
222 * @param tile The tile of the logic signal
223 * @param track The track of the logic signal
225 void DeleteSignalProgram(TileIndex tile
, Track track
)
227 const SignalReference signal_reference
= GetSignalReference(tile
, track
);
229 // Delete any windows which have this program open.
230 DeleteWindowById(WC_SIGNAL_PROGRAM
, signal_reference
, false);
232 // Remove the actual program and all links attached to it.
233 SignalProgram
* program
= FindSignalProgram(tile
, track
);
235 Overlays::Instance()->HandleSignalProgramDeletion(program
);
237 _signal_program_list
.erase(signal_reference
);
238 program
->ClearAllLinks();
244 * Used to create or delete signal programs at the given tile when the signal type changes.
246 * @param tile The tile where the change occurred.
247 * @param track The track where the change occurred.
248 * @param old_type The old type of the changed signal
249 * @param new_type The new type of the changed signal
251 void SignalTypeChanged(TileIndex tile
, Track track
, SignalType old_type
, SignalType new_type
)
253 if (old_type
== SIGTYPE_LOGIC
) DeleteSignalProgram(tile
, track
);
254 if (new_type
== SIGTYPE_LOGIC
) CreateSignalProgram(tile
, track
);
258 * Executed whenever signal state has changed by the main program.
260 * @param tile Tile where the change occurred
261 * @param track Track where the change occurred
262 * @param depth Recursion depth, starts at 1.
264 void SignalStateChanged(TileIndex tile
, Track track
, int depth
)
266 auto targets
= FindSignalLinks(tile
, track
);
268 for (auto target
: targets
) {
269 SignalProgram
* program
= FindSignalProgram(GetTileFromSignalReference(target
),
270 GetTrackFromSignalReference(target
));
271 program
->InputChanged(depth
);