Add templated versions of CeilDiv and Ceil maths functions
[openttd-joker.git] / src / logic_signals.cpp
blobd6b20e95f3e62cbae0740e1e5bbff440778db8d9
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"
16 /**
17 * List of all signal programs.
19 SignalProgramList _signal_program_list;
20 /**
21 * List of all links between signals.
23 SignalLinkList _signal_link_list;
25 /**
26 * Remove any nasty foul-smelling signal programs taking up precious RAM.
28 void FreeAllSignalPrograms()
30 for (SignalProgramList::iterator it = _signal_program_list.begin(); it != _signal_program_list.end(); it++) {
31 SignalProgram *program = it->second;
32 delete program;
35 _signal_program_list.clear();
36 _signal_link_list.clear();
39 /**
40 * Determine the color of signals at the given tile/track.
41 * @param tile The tile where the tested signal is located.
42 * @param track The track where the tested signal is located.
43 * @return Red if either of the two possible signals is red.
45 SignalState DetermineSignalState(TileIndex tile, Track track)
47 assert(HasSignalOnTrack(tile, track));
49 uint signal_states = GetSignalStates(tile);
50 byte signal_mask_for_track = SignalOnTrack(track);
51 byte present_signals_on_tile = GetPresentSignals(tile);
53 byte present_signals_on_track = signal_mask_for_track & present_signals_on_tile;
54 byte signal_states_on_track = present_signals_on_track & signal_states;
56 // 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.
57 return (signal_states_on_track == present_signals_on_track) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED;
60 /**
61 * Set the signal state for the given tile and track to the specified state.
62 * Both possible signals for the given tile/track are set to the given state.
63 * @param tile Tile where the changed signal is located.
64 * @param track Track where the changed signal is located.
65 * @param state The new state to set to the signals.
67 void SetSignalStateForTrack(TileIndex tile, Track track, SignalState state)
69 byte signal_mask_for_track = SignalOnTrack(track);
70 byte present_signals_on_tile = GetPresentSignals(tile);
72 if (state == SIGNAL_STATE_GREEN) {
73 SetSignalStates(tile, GetSignalStates(tile) | present_signals_on_tile);
75 else {
76 SetSignalStates(tile, GetSignalStates(tile) & ~present_signals_on_tile);
80 /**
81 * Read a Track from a TileIndex.
83 * The author of this patch has no idea how this works or what it does. The code
84 * is copied directly from GenericPlaceSignals function in rail_gui.cpp.
86 * @param tile The tile where to read the Track from.
87 * @return The read Track
89 Track SignalTrackFromTile(TileIndex tile)
91 TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
93 if (trackbits & TRACK_BIT_VERT) { // N-S direction
94 trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
97 if (trackbits & TRACK_BIT_HORZ) { // E-W direction
98 trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
101 return FindFirstTrack(trackbits);
105 * Combine TileIndex and Track to a SignalReference.
106 * @param tile The tile to get a signal reference from
107 * @param track The track to get a signal reference from
108 * @return The signal reference made up of the given tile and track
110 SignalReference GetSignalReference(TileIndex tile, Track track)
112 return tile | (((uint32) track) << 29);
116 * Extract a TileIndex from a SignalReference.
117 * @param key The signal reference to extract a TileIndex from
118 * @return The TileIndex component of the given signal reference
120 TileIndex GetTileFromSignalReference(SignalReference key)
122 return GB(key, 0, 29);
126 * Extract a Track from a SignalReference.
127 * @param key The signal reference to extract a Track from
128 * @return The Track component of the given signal reference
130 Track GetTrackFromSignalReference(SignalReference key)
132 return (Track) (key >> 29);
136 * An internal helper function used in searching for a signal program.
137 * @param tile The tile to search for
138 * @param track The track to search for
139 * @return The corresponding signal program, or NULL if not found.
141 static inline SignalProgram * DoFindSignalProgram(TileIndex tile, Track track)
143 SignalProgramList::iterator it = _signal_program_list.find(GetSignalReference(tile, track));
145 if (it != _signal_program_list.end()) {
146 return it->second;
147 } else {
148 return NULL;
153 * Find a link from a signal at the given tile/track.
154 * @param tile The tile to search for.
155 * @param track The track to search for.
156 * @return The corresponding target where the link points to, if found, otherwise NULL.
157 * @bug This code returns NULL (0) as a not-found value, but that is also valid for the first Tile/Track
159 static inline SignalReference FindSignalLink(TileIndex tile, Track track)
161 SignalLinkList::iterator it = _signal_link_list.find(GetSignalReference(tile, track));
163 if (it != _signal_link_list.end()) {
164 return it->second;
165 } else {
166 return NULL;
171 * Used to find a signal program at the given tile and track.
172 * @param tile The tile to search for.
173 * @param track The track to search for.
174 * @return The signal program if found, or NULL.
176 SignalProgram * FindSignalProgram(TileIndex tile, Track track)
178 SignalProgram *program = DoFindSignalProgram(tile, track);
179 assert(program != NULL);
180 return program;
184 * Remove a signal link at the given tile and track, if it is found.
185 * It is perfectly valid to call this function even if the said tile/track has no outgoing link.
187 * @param tile The tile to search for
188 * @param track The track to search for
190 void RemoveSignalLink(TileIndex tile, Track track)
192 SignalReference existing = FindSignalLink(tile, track);
194 if (existing != NULL) {
195 /* Remove from signal program */
196 SignalProgram *old_prog = FindSignalProgram(GetTileFromSignalReference(existing), GetTrackFromSignalReference(existing));
197 old_prog->RemoveLink(tile, track);
199 /* Remove from global list */
200 _signal_link_list.erase(GetSignalReference(tile, track));
202 /* Invalidate any windows which have this program open */
203 InvalidateWindowData(WC_SIGNAL_PROGRAM, existing);
208 * Create a new signal program at the given tile and track.
209 * Used when a new logic signal is created.
210 * @param tile The tile of the logic signal
211 * @param track The track of the logic signal
212 * @return The newly created signal program
214 SignalProgram * CreateSignalProgram(TileIndex tile, Track track)
216 /* Existing program for same tile/track would be a bug */
217 assert(DoFindSignalProgram(tile, track) == NULL);
219 SignalProgram *program = new SignalProgram(tile, track);
220 _signal_program_list[GetSignalReference(tile, track)] = program;
221 return program;
225 * Delete a signal program at the given tile and track.
226 * @param tile The tile of the logic signal
227 * @param track The track of the logic signal
229 void DeleteSignalProgram(TileIndex tile, Track track)
231 SignalReference key = GetSignalReference(tile, track);
233 /* Delete any windows which have this program open */
234 DeleteWindowById(WC_SIGNAL_PROGRAM, key, false);
236 /* Remove the actual program and all links attached to it */
237 SignalProgram *program = FindSignalProgram(tile, track);
238 _signal_program_list.erase(key);
239 program->ClearAllLinks();
240 delete program;
244 * Used to create or delete signal programs at the given tile when the signal type changes.
245 * @param tile The tile where the change occurred.
246 * @param track The track where the change occurred.
247 * @param old_type The old type of the changed signal
248 * @param new_type The new type of the changed signal
250 void SignalTypeChanged(TileIndex tile, Track track, SignalType old_type, SignalType new_type)
252 if (old_type == SIGTYPE_LOGIC) DeleteSignalProgram(tile, track);
253 if (new_type == SIGTYPE_LOGIC) CreateSignalProgram(tile, track);
257 * Executed whenever signal state has changed by the main program.
258 * @param tile Tile where the change occurred
259 * @param track Track where the change occurred
260 * @param depth Recursion depth, starts at 1.
262 void SignalStateChanged(TileIndex tile, Track track, int depth)
264 SignalReference link = FindSignalLink(tile, track);
265 if (link != NULL) {
266 SignalProgram *program = FindSignalProgram(GetTileFromSignalReference(link), GetTrackFromSignalReference(link));
267 program->InputChanged(depth);