* Build signals, alternate between double/single, signal/semaphore, * pre/exit/combo-signals, and what-else not. If the rail piece does not * have any signals, signal cycling is ignored * @param flags operation to perform * @param tile tile where to build the signals * @param track track-orientation * @param sigtype type of the signal * @param sigvar variant of signal type (normal/semaphore
| 1047 | * @todo p2 should be replaced by two bits for "along" and "against" the track. |
| 1048 | */ |
| 1049 | CommandCost CmdBuildSingleSignal(DoCommandFlags flags, TileIndex tile, Track track, SignalType sigtype, SignalVariant sigvar, bool convert_signal, bool skip_existing_signals, bool ctrl_pressed, SignalType cycle_start, SignalType cycle_stop, uint8_t num_dir_cycle, uint8_t signals_copy) |
| 1050 | { |
| 1051 | if (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE) return CMD_ERROR; |
| 1052 | if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR; |
| 1053 | |
| 1054 | if (ctrl_pressed) sigvar = (SignalVariant)(sigvar ^ SIG_SEMAPHORE); |
| 1055 | |
| 1056 | /* You can only build signals on plain rail tiles, and the selected track must exist */ |
| 1057 | if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || |
| 1058 | !HasTrack(tile, track)) { |
| 1059 | return CommandCost(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); |
| 1060 | } |
| 1061 | /* Protect against invalid signal copying */ |
| 1062 | if (signals_copy != 0 && (signals_copy & SignalOnTrack(track)) == 0) return CMD_ERROR; |
| 1063 | |
| 1064 | CommandCost ret = CheckTileOwnership(tile); |
| 1065 | if (ret.Failed()) return ret; |
| 1066 | |
| 1067 | /* See if this is a valid track combination for signals (no overlap) */ |
| 1068 | if (TracksOverlap(GetTrackBits(tile))) return CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); |
| 1069 | |
| 1070 | /* In case we don't want to change an existing signal, return without error. */ |
| 1071 | if (skip_existing_signals && HasSignalOnTrack(tile, track)) return CommandCost(); |
| 1072 | |
| 1073 | /* you can not convert a signal if no signal is on track */ |
| 1074 | if (convert_signal && !HasSignalOnTrack(tile, track)) return CommandCost(STR_ERROR_THERE_ARE_NO_SIGNALS); |
| 1075 | |
| 1076 | CommandCost cost; |
| 1077 | if (!HasSignalOnTrack(tile, track)) { |
| 1078 | /* build new signals */ |
| 1079 | cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]); |
| 1080 | } else { |
| 1081 | if (signals_copy != 0 && sigvar != GetSignalVariant(tile, track)) { |
| 1082 | /* convert signals <-> semaphores */ |
| 1083 | cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]); |
| 1084 | |
| 1085 | } else if (convert_signal) { |
| 1086 | /* convert button pressed */ |
| 1087 | if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) { |
| 1088 | /* it costs money to change signal variant (light or semaphore) */ |
| 1089 | cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]); |
| 1090 | } else { |
| 1091 | /* it is free to change signal type (block, exit, entry, combo, path, etc) */ |
| 1092 | cost = CommandCost(); |
| 1093 | } |
| 1094 | |
| 1095 | } else { |
| 1096 | /* it is free to change orientation or number of signals on the tile (for block/presignals which allow signals in both directions) */ |
| 1097 | cost = CommandCost(); |
| 1098 | } |
| 1099 | } |
| 1100 | |
| 1101 | if (flags.Test(DoCommandFlag::Execute)) { |
| 1102 | Train *v = nullptr; |
| 1103 | /* The new/changed signal could block our path. As this can lead to |
| 1104 | * stale reservations, we clear the path reservation here and try |
| 1105 | * to redo it later on. */ |
| 1106 | if (HasReservedTracks(tile, TrackToTrackBits(track))) { |
nothing calls this directly
no test coverage detected