Merge branch 'development' into feature/no_multiplayer_grf_limit
[openttd-joker.git] / src / logic_signals.cpp
blobbad902fada8d2fa7cf57580a7a203fb29b149e6a
1 /*
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/>.
6 */
8 /** @file logic_signals.cpp Utility functions of the Logic Signals patch. */
10 #include "logic_signals.h"
11 #include "rail_map.h"
12 #include "viewport_func.h"
13 #include "tile_cmd.h"
14 #include "window_func.h"
15 #include "overlay_cmd.h"
17 /**
18 * List of all signal programs.
20 SignalProgramList _signal_program_list;
21 /**
22 * List of all links between signals.
24 SignalLinkList _signal_link_list;
26 /**
27 * Remove any nasty foul-smelling signal programs taking up precious RAM.
29 void FreeAllSignalPrograms()
31 for (SignalProgramList::iterator it = _signal_program_list.begin(); it != _signal_program_list.end(); it++) {
32 SignalProgram *program = it->second;
33 delete program;
36 _signal_program_list.clear();
37 _signal_link_list.clear();
40 /**
41 * Determine the color of signals at the given tile/track.
42 * @param tile The tile where the tested signal is located.
43 * @param track The track where the tested signal is located.
44 * @return Red if either of the two possible signals is red.
46 SignalState DetermineSignalState(TileIndex tile, Track track)
48 assert(HasSignalOnTrack(tile, track));
50 uint signal_states = GetSignalStates(tile);
51 byte signal_mask_for_track = SignalOnTrack(track);
52 byte present_signals_on_tile = GetPresentSignals(tile);
54 byte present_signals_on_track = signal_mask_for_track & present_signals_on_tile;
55 byte signal_states_on_track = present_signals_on_track & signal_states;
57 // We return red if one of the two possibly present signals is red. Both need to be green for us to accept the tile as green.
58 return (signal_states_on_track == present_signals_on_track) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED;
61 /**
62 * Set the signal state for the given tile and track to the specified state.
63 * Both possible signals for the given tile/track are set to the given state.
64 * @param tile Tile where the changed signal is located.
65 * @param track Track where the changed signal is located.
66 * @param state The new state to set to the signals.
68 void SetSignalStateForTrack(TileIndex tile, Track track, SignalState state)
70 byte signal_mask_for_track = SignalOnTrack(track);
71 byte present_signals_on_tile = GetPresentSignals(tile);
73 if (state == SIGNAL_STATE_GREEN) {
74 SetSignalStates(tile, GetSignalStates(tile) | present_signals_on_tile);
76 else {
77 SetSignalStates(tile, GetSignalStates(tile) & ~present_signals_on_tile);
81 /**
82 * Read a Track from a TileIndex.
84 * The author of this patch has no idea how this works or what it does. The code
85 * is copied directly from GenericPlaceSignals function in rail_gui.cpp.
87 * @param tile The tile where to read the Track from.
88 * @return The read Track
90 Track SignalTrackFromTile(TileIndex tile)
92 TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
94 if (trackbits & TRACK_BIT_VERT) { // N-S direction
95 trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
98 if (trackbits & TRACK_BIT_HORZ) { // E-W direction
99 trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
102 return FindFirstTrack(trackbits);
106 * Combine TileIndex and Track to a SignalReference.
107 * @param tile The tile to get a signal reference from
108 * @param track The track to get a signal reference from
109 * @return The signal reference made up of the given tile and track
111 SignalReference GetSignalReference(TileIndex tile, Track track)
113 return tile | (((uint32) track) << 29);
117 * Extract a TileIndex from a SignalReference.
118 * @param key The signal reference to extract a TileIndex from
119 * @return The TileIndex component of the given signal reference
121 TileIndex GetTileFromSignalReference(SignalReference key)
123 return GB(key, 0, 29);
127 * Extract a Track from a SignalReference.
128 * @param key The signal reference to extract a Track from
129 * @return The Track component of the given signal reference
131 Track GetTrackFromSignalReference(SignalReference key)
133 return (Track) (key >> 29);
137 * An internal helper function used in searching for a signal program.
138 * @param tile The tile to search for
139 * @param track The track to search for
140 * @return The corresponding signal program, or NULL if not found.
142 static inline SignalProgram * DoFindSignalProgram(TileIndex tile, Track track)
144 SignalProgramList::iterator it = _signal_program_list.find(GetSignalReference(tile, track));
146 if (it != _signal_program_list.end()) {
147 return it->second;
148 } else {
149 return NULL;
154 * Find a link from a signal at the given tile/track.
155 * @param tile The tile to search for.
156 * @param track The track to search for.
157 * @return The corresponding target where the link points to, if found, otherwise NULL.
158 * @bug This code returns NULL (0) as a not-found value, but that is also valid for the first Tile/Track
160 static inline SignalReference FindSignalLink(TileIndex tile, Track track)
162 SignalLinkList::iterator it = _signal_link_list.find(GetSignalReference(tile, track));
164 if (it != _signal_link_list.end()) {
165 return it->second;
166 } else {
167 return NULL;
172 * Used to find a signal program at the given tile and track.
173 * @param tile The tile to search for.
174 * @param track The track to search for.
175 * @return The signal program if found, or NULL.
177 SignalProgram * FindSignalProgram(TileIndex tile, Track track)
179 SignalProgram *program = DoFindSignalProgram(tile, track);
180 assert(program != NULL);
181 return program;
185 * Remove a signal link at the given tile and track, if it is found.
186 * It is perfectly valid to call this function even if the said tile/track has no outgoing link.
188 * @param tile The tile to search for
189 * @param track The track to search for
191 void RemoveSignalLink(TileIndex tile, Track track)
193 SignalReference existing = FindSignalLink(tile, track);
195 if (existing != NULL) {
196 /* Remove from signal program */
197 SignalProgram *old_prog = FindSignalProgram(GetTileFromSignalReference(existing), GetTrackFromSignalReference(existing));
198 old_prog->RemoveLink(tile, track);
200 /* Remove from global list */
201 _signal_link_list.erase(GetSignalReference(tile, track));
203 /* Invalidate any windows which have this program open */
204 InvalidateWindowData(WC_SIGNAL_PROGRAM, existing);
209 * Create a new signal program at the given tile and track.
210 * Used when a new logic signal is created.
211 * @param tile The tile of the logic signal
212 * @param track The track of the logic signal
213 * @return The newly created signal program
215 SignalProgram * CreateSignalProgram(TileIndex tile, Track track)
217 /* Existing program for same tile/track would be a bug */
218 assert(DoFindSignalProgram(tile, track) == NULL);
220 SignalProgram *program = new SignalProgram(tile, track);
221 _signal_program_list[GetSignalReference(tile, track)] = program;
222 return program;
226 * Delete a signal program at the given tile and track.
227 * @param tile The tile of the logic signal
228 * @param track The track of the logic signal
230 void DeleteSignalProgram(TileIndex tile, Track track)
232 SignalReference key = GetSignalReference(tile, track);
234 /* Delete any windows which have this program open */
235 DeleteWindowById(WC_SIGNAL_PROGRAM, key, false);
237 /* Remove the actual program and all links attached to it */
238 SignalProgram *program = FindSignalProgram(tile, track);
240 Overlays::Instance()->HandleSignalProgramDeletion(program);
242 _signal_program_list.erase(key);
243 program->ClearAllLinks();
245 delete program;
249 * Used to create or delete signal programs at the given tile when the signal type changes.
250 * @param tile The tile where the change occurred.
251 * @param track The track where the change occurred.
252 * @param old_type The old type of the changed signal
253 * @param new_type The new type of the changed signal
255 void SignalTypeChanged(TileIndex tile, Track track, SignalType old_type, SignalType new_type)
257 if (old_type == SIGTYPE_LOGIC) DeleteSignalProgram(tile, track);
258 if (new_type == SIGTYPE_LOGIC) CreateSignalProgram(tile, track);
262 * Executed whenever signal state has changed by the main program.
263 * @param tile Tile where the change occurred
264 * @param track Track where the change occurred
265 * @param depth Recursion depth, starts at 1.
267 void SignalStateChanged(TileIndex tile, Track track, int depth)
269 SignalReference link = FindSignalLink(tile, track);
270 if (link != NULL) {
271 SignalProgram *program = FindSignalProgram(GetTileFromSignalReference(link), GetTrackFromSignalReference(link));
272 program->InputChanged(depth);