Make it possible to stop road vehicles from slowing down in curves so "diagonal"...
[openttd-joker.git] / src / logic_signals.cpp
blob0a8aee78df8dac7ce70d897b733be90da57b7f91
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 "overlay_cmd.h"
12 #include "rail_map.h"
13 #include "tile_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.
20 /**
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;
27 delete program;
30 _signal_program_list.clear();
31 _signal_link_list.clear();
34 /**
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;
57 /**
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);
71 } else {
72 SetSignalStates(tile, GetSignalStates(tile) & ~present_signals_on_tile);
76 /**
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) {
87 // N-S direction
88 trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
91 if (trackbits & TRACK_BIT_HORZ) {
92 // E-W direction
93 trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
96 return FindFirstTrack(trackbits);
99 /**
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);
161 return targets;
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);
176 return program;
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;
216 return 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();
240 delete program;
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);