Remove costly recalculation of a date format we already have.
[openttd-joker.git] / src / logic_signal_program.cpp
blob9eb45d2fb46052f4cfb81bf39bf16936d30d0952
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_signal_program.cpp Implementation of the SignalProgram class functions. */
10 #include "logic_signals.h"
11 #include "rail_map.h"
12 #include "viewport_func.h"
14 /**
15 * Return the opposite of the given signal state.
16 * @param state The original signal state to revert.
17 * @return Green if the given argument is Red and vice versa.
19 static inline SignalState OppositeSignalState(SignalState state)
21 return state == SIGNAL_STATE_RED ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED;
24 /**
25 * The maximum number of signal programs which are evaluated in succession.
27 static const int MAX_LOGIC_SIGNAL_RECURSIONS = 5;
29 /**
30 * Default constructor, used by the save/load handler.
32 SignalProgram::SignalProgram()
37 /**
38 * The constructor for creating a new signal program.
39 * @param t The tile where the logic signal for this program is located.
40 * @param tr The track where the logic signal for this program is located.
42 SignalProgram::SignalProgram(TileIndex t, Track tr)
44 this->tile = t;
45 this->track = tr;
47 /* Default to a priority signal: if any of the linked input
48 * signals are red, this one goes red. */
49 this->own_default_state = SIGNAL_STATE_GREEN;
50 this->trigger_state = SIGNAL_STATE_RED;
51 this->signal_op = SIGNAL_OP_OR;
53 this->blocked_by_train = false;
56 /**
57 * Add a new signal as input for this signal program.
58 * @param tile The tile of the signal to be linked.
59 * @param track The track of the signal to be linked.
61 void SignalProgram::AddLink(TileIndex tile, Track track, bool remove_first)
63 SignalReference source = GetSignalReference(tile, track);
65 if (!this->linked_signals.Contains(source)) {
66 /* Remove any existing link first, because we can only have one per signal (for now) */
67 if (remove_first) RemoveSignalLink(tile, track);
69 *(this->linked_signals.Append()) = source;
70 _signal_link_list[source] = GetSignalReference(this->tile, this->track);
74 /**
75 * Remove a linked signal from this program. The link must exist.
76 * @param tile The tile of the signal to be removed.
77 * @param track The track of the signal to be removed.
79 void SignalProgram::RemoveLink(TileIndex tile, Track track)
81 SignalReference key = GetSignalReference(tile, track);
82 SignalReference *value = this->linked_signals.Find(key);
83 assert(value != this->linked_signals.End());
84 this->linked_signals.Erase(value);
87 /**
88 * Remove all links that this signal program has.
90 void SignalProgram::ClearAllLinks()
92 /* Delete all links from the global list too */
93 for (SignalReference *sref = this->linked_signals.Begin(); sref != this->linked_signals.End(); sref++) {
94 _signal_link_list.erase(*sref);
97 this->linked_signals.Clear();
101 * The number of signals linked to this signal program.
103 uint SignalProgram::LinkCount()
105 return this->linked_signals.Length();
109 * This function is run when one of the signals linked to this program has changed.
110 * It will (possibly) change the state of the signal, and then recursively change
111 * the state of any signal linked to it.
112 * @param depth The recursion depth, which starts at 1.
114 void SignalProgram::InputChanged(int depth)
116 /* If this signal is blocked by a train, we can't do anything */
117 if (this->blocked_by_train) {
118 return;
121 SignalState new_state = this->Evaluate();
123 if (new_state != DetermineSignalState(this->tile, this->track)) {
124 SetSignalStateForTrack(this->tile, this->track, new_state);
125 MarkTileDirtyByTile(tile);
127 /* Recursively update any signals that have this one as input */
128 if (depth < MAX_LOGIC_SIGNAL_RECURSIONS) {
129 SignalStateChanged(this->tile, this->track, depth + 1);
135 * The main evaluation function which determines the state of the signal linked
136 * to this signal program. It should be short, simple and readable.
138 SignalState SignalProgram::Evaluate()
140 int trigger_states = 0, not_trigger_states = 0;
142 /* We need at least one linked signal to evaluate anything */
143 if (this->LinkCount() == 0) return this->own_default_state;
145 /* Loop through all linked signals and count the states */
146 for (SignalReference *sref = this->linked_signals.Begin(); sref != this->linked_signals.End(); sref++) {
147 TileIndex target_tile = GetTileFromSignalReference(*sref);
148 Track target_track = GetTrackFromSignalReference(*sref);
149 SignalState target_state = DetermineSignalState(target_tile, target_track);
151 if (target_state == trigger_state) {
152 trigger_states++;
153 } else {
154 not_trigger_states++;
158 switch (this->signal_op) {
159 case SIGNAL_OP_OR:
160 /* OR is triggered if we have at least one signal of trigger color */
161 if (trigger_states > 0) return OppositeSignalState(this->own_default_state);
162 break;
163 case SIGNAL_OP_AND:
164 /* AND is triggered if no signals were of the 'wrong' color */
165 if (not_trigger_states == 0) return OppositeSignalState(this->own_default_state);
166 break;
167 case SIGNAL_OP_NAND:
168 /* NAND is triggered if we have at least one signal of the 'wrong' color */
169 if (not_trigger_states > 0) return OppositeSignalState(this->own_default_state);
170 break;
171 case SIGNAL_OP_XOR:
172 /* XOR is triggered if the number of signals in trigger color is uneven */
173 if ((trigger_states % 2) > 0) return OppositeSignalState(this->own_default_state);
174 break;
177 /* Not triggered, return default color */
178 return this->own_default_state;