Fix crash when setting separation mode for vehicles with no orders list.
[openttd-joker.git] / src / logic_signals_cmd.cpp
blob1ff1857380bd7388adb4d06158d8d1ca86ed7b44
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_cmd.cpp Commands for modifying logic signal programs. */
10 #include "logic_signals.h"
11 #include "core/bitmath_func.hpp"
12 #include "window_func.h"
13 #include "command_func.h"
14 #include "rail_map.h"
15 #include "table/strings.h"
16 #include "company_func.h"
18 /**
19 * The main command for editing a signal program.
20 * @param tile The tile which contains the edited signal.
21 * @param flags Internal command handler stuff.
22 * @param p1 Bitstuffed items
23 * - p1 = (bit 0-2) - The Track part of the signal program tile.
24 * - p1 = (bit 3-5) - Subcommand to execute.
25 * - p1 = (bit 6-7) - The value to set to the signal program.
26 * @param p2 Target SignalReference for linking of two signals
27 * @param text Unused
28 * @return the cost of this operation (which is free), or an error
30 CommandCost CmdProgramLogicSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char* text)
32 const auto track = Extract<Track, 0, 3>(p1);
33 const uint32 sub_cmd = GB(p1, 3, 3);
34 const uint32 value = GB(p1, 6, 2);
36 // Start by checking tile ownership.
37 CommandCost ret = CheckTileOwnership(tile);
38 if (ret.Failed()) return ret;
40 SignalProgram* program = FindSignalProgram(tile, track);
42 if (sub_cmd == 1) {
43 if (flags & DC_EXEC) {
44 program->own_default_state = static_cast<SignalState>(value);
46 } else if (sub_cmd == 2) {
47 if (flags & DC_EXEC) {
48 program->trigger_state = static_cast<SignalState>(value);
50 } else if (sub_cmd == 3) {
51 if (flags & DC_EXEC) {
52 program->signal_op = static_cast<SignalOperator>(value);
54 } else if (sub_cmd == 4) {
55 const TileIndex target_tile = p2;
56 const Track target_track = SignalTrackFromTile(target_tile);
58 if (tile == target_tile && track == target_track) {
59 return CommandError(STR_ERROR_LINK_SIGNAL_TO_ITSELF);
62 if (!IsPlainRailTile(target_tile) || !HasSignalOnTrack(target_tile, target_track)) {
63 return CommandError(STR_ERROR_LINK_SIGNAL_NO_SIGNAL);
66 if (CheckTileOwnership(target_tile).Failed()) {
67 return CommandError(STR_ERROR_OWNED_BY);
70 if (flags & DC_EXEC) {
71 program->AddLink(target_tile, target_track);
73 } else if (sub_cmd == 5) {
74 if (flags & DC_EXEC) {
75 program->ClearAllLinks();
79 if (flags & DC_EXEC) {
80 // Invalidate any open windows if something was changed.
81 InvalidateWindowData(WC_SIGNAL_PROGRAM, GetSignalReference(tile, track));
83 // Re-evaluate the signal state too.
84 program->InputChanged(1);
87 // No cost, this fun is free :)
88 return CommandCost();