Changeset - r26113:052b5113bfa8
[Not reviewed]
master
0 7 0
Michael Lutz - 3 years ago 2021-11-14 19:07:23
michi@icosahedron.de
Codechange: Un-bitstuff rail commands.
7 files changed with 154 insertions and 259 deletions:
0 comments (0 inline, 0 general)
src/rail_cmd.cpp
Show inline comments
 
@@ -426,24 +426,19 @@ static inline bool ValParamTrackOrientat
 
}
 

	
 
/**
 
 * Build a single piece of rail
 
 * @param flags operation to perform
 
 * @param tile tile  to build on
 
 * @param p1 railtype of being built piece (normal, mono, maglev)
 
 * @param p2 various bitstuffed elements
 
 *           - (bit  0- 2) - track-orientation, valid values: 0-5 (@see Track)
 
 *           - (bit  3)    - 0 = error on signal in the way, 1 = auto remove signals when in the way
 
 * @param text unused
 
 * @param railtype railtype of being built piece (normal, mono, maglev)
 
 * @param track track-orientation
 
 * @param auto_remove_signals false = error on signal in the way, true = auto remove signals when in the way
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals)
 
{
 
	RailType railtype = Extract<RailType, 0, 6>(p1);
 
	Track track = Extract<Track, 0, 3>(p2);
 
	bool auto_remove_signals = HasBit(p2, 3);
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 

	
 
	if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 

	
 
	Slope tileh = GetTileSlope(tile);
 
	TrackBits trackbit = TrackToTrackBits(track);
 
@@ -468,25 +463,25 @@ CommandCost CmdBuildSingleRail(DoCommand
 
			if (HasSignals(tile) && TracksOverlap(GetTrackBits(tile) | TrackToTrackBits(track))) {
 
				/* If adding the new track causes any overlap, all signals must be removed first */
 
				if (!auto_remove_signals) return_cmd_error(STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
 

	
 
				for (Track track_it = TRACK_BEGIN; track_it < TRACK_END; track_it++) {
 
					if (HasTrack(tile, track_it) && HasSignalOnTrack(tile, track_it)) {
 
						CommandCost ret_remove_signals = Command<CMD_REMOVE_SIGNALS>::Do(flags, tile, track_it, 0, {});
 
						CommandCost ret_remove_signals = Command<CMD_REMOVE_SIGNALS>::Do(flags, tile, track_it);
 
						if (ret_remove_signals.Failed()) return ret_remove_signals;
 
						cost.AddCost(ret_remove_signals);
 
					}
 
				}
 
			}
 

	
 
			/* If the rail types don't match, try to convert only if engines of
 
			 * the new rail type are not powered on the present rail type and engines of
 
			 * the present rail type are powered on the new rail type. */
 
			if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
 
				if (HasPowerOnRail(GetRailType(tile), railtype)) {
 
					ret = Command<CMD_CONVERT_RAIL>::Do(flags, tile, tile, railtype, {});
 
					ret = Command<CMD_CONVERT_RAIL>::Do(flags, tile, tile, railtype, false);
 
					if (ret.Failed()) return ret;
 
					cost.AddCost(ret);
 
				} else {
 
					return CMD_ERROR;
 
				}
 
			}
 
@@ -616,20 +611,17 @@ CommandCost CmdBuildSingleRail(DoCommand
 
}
 

	
 
/**
 
 * Remove a single piece of track
 
 * @param flags operation to perform
 
 * @param tile tile to remove track from
 
 * @param p1 unused
 
 * @param p2 rail orientation
 
 * @param text unused
 
 * @param track rail orientation
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track)
 
{
 
	Track track = Extract<Track, 0, 3>(p2);
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	bool crossing = false;
 

	
 
	if (!ValParamTrackOrientation(track)) return CMD_ERROR;
 
	TrackBits trackbit = TrackToTrackBits(track);
 

	
 
@@ -690,13 +682,13 @@ CommandCost CmdRemoveSingleRail(DoComman
 
			if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
 

	
 
			cost.AddCost(RailClearCost(GetRailType(tile)));
 

	
 
			/* Charge extra to remove signals on the track, if they are there */
 
			if (HasSignalOnTrack(tile, track)) {
 
				cost.AddCost(Command<CMD_REMOVE_SIGNALS>::Do(flags, tile, track, 0, {}));
 
				cost.AddCost(Command<CMD_REMOVE_SIGNALS>::Do(flags, tile, track));
 
			}
 

	
 
			if (flags & DC_EXEC) {
 
				if (HasReservedTracks(tile, trackbit)) {
 
					v = GetTrainForReservation(tile, track);
 
					if (v != nullptr) FreeTrainTrackReservation(v);
 
@@ -783,13 +775,13 @@ bool FloodHalftile(TileIndex t)
 
	if (IsSlopeWithOneCornerRaised(tileh)) {
 
		TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
 

	
 
		TrackBits to_remove = lower_track & rail_bits;
 
		if (to_remove != 0) {
 
			Backup<CompanyID> cur_company(_current_company, OWNER_WATER, FILE_LINE);
 
			flooded = Command<CMD_REMOVE_SINGLE_RAIL>::Do(DC_EXEC, t, 0, FIND_FIRST_BIT(to_remove), {}).Succeeded();
 
			flooded = Command<CMD_REMOVE_SINGLE_RAIL>::Do(DC_EXEC, t, FindFirstTrack(to_remove)).Succeeded();
 
			cur_company.Restore();
 
			if (!flooded) return flooded; // not yet floodable
 
			rail_bits = rail_bits & ~to_remove;
 
			if (rail_bits == 0) {
 
				MakeShore(t);
 
				MarkTileDirtyByTile(t);
 
@@ -873,48 +865,41 @@ static CommandCost ValidateAutoDrag(Trac
 
}
 

	
 
/**
 
 * Build or remove a stretch of railroad tracks.
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1 end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-5) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building
 
 * - p2 = (bit 6-8) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit 9)   - 0 = build, 1 = remove tracks
 
 * - p2 = (bit 10)  - 0 = build up to an obstacle, 1 = fail if an obstacle is found (used for AIs).
 
 * - p2 = (bit 11)  - 0 = error on signal in the way, 1 = auto remove signals when in the way
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param railtype railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building
 
 * @param track track-orientation
 
 * @param remove remove tracks?
 
 * @param auto_remove_signals false = build up to an obstacle, true = fail if an obstacle is found (used for AIs), only used for building
 
 * @param fail_on_obstacle false = error on signal in the way, true = auto remove signals when in the way, only used for building
 
 * @return the cost of this operation or an error
 
 */
 
static CommandCost CmdRailTrackHelper(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
static CommandCost CmdRailTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool remove, bool auto_remove_signals, bool fail_on_obstacle)
 
{
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	Track track = Extract<Track, 6, 3>(p2);
 
	bool remove = HasBit(p2, 9);
 
	bool auto_remove_signals = HasBit(p2, 11);
 
	RailType railtype = Extract<RailType, 0, 6>(p2);
 

	
 
	if ((!remove && !ValParamRailtype(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
	if (p1 >= MapSize()) return CMD_ERROR;
 
	TileIndex end_tile = p1;
 
	if (end_tile >= MapSize()) return CMD_ERROR;
 

	
 
	Trackdir trackdir = TrackToTrackdir(track);
 

	
 
	CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
 
	if (ret.Failed()) return ret;
 

	
 
	bool had_success = false;
 
	CommandCost last_error = CMD_ERROR;
 
	for (;;) {
 
		uint32 p2 = TrackdirToTrack(trackdir) | (auto_remove_signals << 3);
 
		CommandCost ret = remove ? Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, 0, p2, {}) : Command<CMD_BUILD_SINGLE_RAIL>::Do(flags, tile, railtype, p2, {});
 
		CommandCost ret = remove ? Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, TrackdirToTrack(trackdir)) : Command<CMD_BUILD_SINGLE_RAIL>::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals);
 

	
 
		if (ret.Failed()) {
 
			last_error = ret;
 
			if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
 
				if (HasBit(p2, 10)) return last_error;
 
				if (fail_on_obstacle) return last_error;
 
				break;
 
			}
 

	
 
			/* Ownership errors are more important. */
 
			if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
 
		} else {
 
@@ -936,43 +921,38 @@ static CommandCost CmdRailTrackHelper(Do
 

	
 
/**
 
 * Build rail on a stretch of track.
 
 * Stub for the unified rail builder/remover
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1 end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-5) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev)
 
 * - p2 = (bit 6-8) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit 9)   - 0 = build, 1 = remove tracks
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 * @param end_tile end tile of drag
 
 * @param railtype railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building
 
 * @param track track-orientation
 
 * @param auto_remove_signals false = build up to an obstacle, true = fail if an obstacle is found (used for AIs).
 
 * @param fail_on_obstacle false = error on signal in the way, true = auto remove signals when in the way
 

	
 
 * @see CmdRailTrackHelper
 
 */
 
CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool auto_remove_signals, bool fail_on_obstacle)
 
{
 
	return CmdRailTrackHelper(flags, tile, p1, ClrBit(p2, 9), text);
 
	return CmdRailTrackHelper(flags, tile, end_tile, railtype, track, false, auto_remove_signals, fail_on_obstacle);
 
}
 

	
 
/**
 
 * Build rail on a stretch of track.
 
 * Stub for the unified rail builder/remover
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1 end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-5) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building
 
 * - p2 = (bit 6-8) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit 9)   - 0 = build, 1 = remove tracks
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param track track-orientation
 
 * @return the cost of this operation or an error
 
 * @see CmdRailTrackHelper
 
 */
 
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track)
 
{
 
	return CmdRailTrackHelper(flags, tile, p1, SetBit(p2, 9), text);
 
	return CmdRailTrackHelper(flags, tile, end_tile, INVALID_RAILTYPE, track, true, false, false);
 
}
 

	
 
/**
 
 * Build a train depot
 
 * @param flags operation to perform
 
 * @param tile position of the train depot
 
@@ -1034,70 +1014,61 @@ CommandCost CmdBuildTrainDepot(DoCommand
 
	return cost;
 
}
 

	
 
/**
 
 * 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, bit 4 (cycle signal-type) is ignored
 
 * have any signals, signal cycling is ignored
 
 * @param flags operation to perform
 
 * @param tile tile where to build the signals
 
 * @param p1 various bitstuffed elements
 
 * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p1 = (bit 3)   - 1 = override signal/semaphore, or pre/exit/combo signal or (for bit 7) toggle variant (CTRL-toggle)
 
 * - p1 = (bit 4)   - 0 = signals, 1 = semaphores
 
 * - p1 = (bit 5-7) - type of the signal, for valid values see enum SignalType in rail_map.h
 
 * - p1 = (bit 8)   - convert the present signal type and variant
 
 * - p1 = (bit 9-11)- start cycle from this signal type
 
 * - p1 = (bit 12-14)-wrap around after this signal type
 
 * - p1 = (bit 15-16)-cycle the signal direction this many times
 
 * - p1 = (bit 17)  - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type
 
 * @param p2 used for CmdBuildManySignals() to copy direction of first signal
 
 * @param text unused
 
 * @param track track-orientation
 
 * @param sigtype type of the signal
 
 * @param sigvar variant of signal type (normal/semaphore)
 
 * @param ctrl_pressed true = override signal/semaphore, or pre/exit/combo signal or toggle variant (CTRL-toggle)
 
 * @param convert_signal convert the present signal type and variant
 
 * @param cycle_start start cycle from this signal type
 
 * @param cycle_stop wrap around after this signal type
 
 * @param num_dir_cycle cycle the signal direction this many times
 
 * @param skip_existing_signals true = don't modify an existing signal but don't fail either, false = always set new signal type
 
 * @param signals_copy used for CmdBuildManySignals() to copy direction of first signal
 
 * @return the cost of this operation or an error
 
 * @todo p2 should be replaced by two bits for "along" and "against" the track.
 
 */
 
CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildSingleSignal(DoCommandFlag 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 num_dir_cycle, byte signals_copy)
 
{
 
	Track track = Extract<Track, 0, 3>(p1);
 
	bool ctrl_pressed = HasBit(p1, 3); // was the CTRL button pressed
 
	SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; // the signal variant of the new signal
 
	SignalType sigtype = Extract<SignalType, 5, 3>(p1); // the signal type of the new signal
 
	bool convert_signal = HasBit(p1, 8); // convert button pressed
 
	SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
 
	SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
 
	uint num_dir_cycle = GB(p1, 15, 2);
 

	
 
	if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
 
	if (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE) return CMD_ERROR;
 
	if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
 

	
 
	if (ctrl_pressed) sigvar = (SignalVariant)(sigvar ^ SIG_SEMAPHORE);
 

	
 
	/* You can only build signals on plain rail tiles, and the selected track must exist */
 
	if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
 
			!HasTrack(tile, track)) {
 
		return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
 
	}
 
	/* Protect against invalid signal copying */
 
	if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
 
	if (signals_copy != 0 && (signals_copy & SignalOnTrack(track)) == 0) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckTileOwnership(tile);
 
	if (ret.Failed()) return ret;
 

	
 
	/* See if this is a valid track combination for signals (no overlap) */
 
	if (TracksOverlap(GetTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
 

	
 
	/* In case we don't want to change an existing signal, return without error. */
 
	if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
 
	if (skip_existing_signals && HasSignalOnTrack(tile, track)) return CommandCost();
 

	
 
	/* you can not convert a signal if no signal is on track */
 
	if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
 

	
 
	CommandCost cost;
 
	if (!HasSignalOnTrack(tile, track)) {
 
		/* build new signals */
 
		cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
 
	} else {
 
		if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
 
		if (signals_copy != 0 && sigvar != GetSignalVariant(tile, track)) {
 
			/* convert signals <-> semaphores */
 
			cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
 

	
 
		} else if (convert_signal) {
 
			/* convert button pressed */
 
			if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
 
@@ -1133,13 +1104,13 @@ CommandCost CmdBuildSingleSignal(DoComma
 
			SetSignalVariant(tile, track, sigvar);
 
		}
 

	
 
		/* Subtract old signal infrastructure count. */
 
		Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
 

	
 
		if (p2 == 0) {
 
		if (signals_copy == 0) {
 
			if (!HasSignalOnTrack(tile, track)) {
 
				/* build new signals */
 
				SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
 
				SetSignalType(tile, track, sigtype);
 
				SetSignalVariant(tile, track, sigvar);
 
				while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
 
@@ -1177,13 +1148,13 @@ CommandCost CmdBuildSingleSignal(DoComma
 
					sigtype = GetSignalType(tile, track);
 
				}
 
			}
 
		} else {
 
			/* If CmdBuildManySignals is called with copying signals, just copy the
 
			 * direction of the first signal given as parameter by CmdBuildManySignals */
 
			SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
 
			SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (signals_copy & SignalOnTrack(track)));
 
			SetSignalVariant(tile, track, sigvar);
 
			SetSignalType(tile, track, sigtype);
 
		}
 

	
 
		/* Add new signal infrastructure count. */
 
		Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
 
@@ -1254,43 +1225,33 @@ static bool AdvanceSignalAutoFill(TileIn
 
}
 

	
 
/**
 
 * Build many signals by dragging; AutoSignals
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1  end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit  0- 2) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit  3)    - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * - p2 = (bit  4)    - 0 = signals, 1 = semaphores
 
 * - p2 = (bit  5)    - 0 = build, 1 = remove signals
 
 * - p2 = (bit  6)    - 0 = selected stretch, 1 = auto fill
 
 * - p2 = (bit  7- 9) - default signal type
 
 * - p2 = (bit 10)    - 0 = keep fixed distance, 1 = minimise gaps between signals
 
 * - p2 = (bit 24-31) - user defined signals_density
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param track track-orientation
 
 * @param sigtype default signal type
 
 * @param sigvar signal variant to build
 
 * @param mode true = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * @param remove remove signals?
 
 * @param autofill fill beyond selected stretch?
 
 * @param minimise_gaps false = keep fixed distance, true = minimise gaps between signals
 
 * @param signal_density user defined signals_density
 
 * @return the cost of this operation or an error
 
 */
 
static CommandCost CmdSignalTrackHelper(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
static CommandCost CmdSignalTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool remove, bool autofill, bool minimise_gaps, int signal_density)
 
{
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	TileIndex start_tile = tile;
 

	
 
	Track track = Extract<Track, 0, 3>(p2);
 
	bool mode = HasBit(p2, 3);
 
	bool semaphores = HasBit(p2, 4);
 
	bool remove = HasBit(p2, 5);
 
	bool autofill = HasBit(p2, 6);
 
	bool minimise_gaps = HasBit(p2, 10);
 
	int signal_density = GB(p2, 24, 8);
 

	
 
	if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
	TileIndex end_tile = p1;
 

	
 
	if (end_tile >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
	if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
 
	if (!remove && (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE)) return CMD_ERROR;
 

	
 
	if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
 
	TileIndex start_tile = tile;
 

	
 
	/* Interpret signal_density as the logical length of said amount of tiles in X/Y direction. */
 
	signal_density *= TILE_AXIAL_DISTANCE;
 

	
 
	Trackdir trackdir = TrackToTrackdir(track);
 
	CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
 
@@ -1299,23 +1260,20 @@ static CommandCost CmdSignalTrackHelper(
 
	track = TrackdirToTrack(trackdir); // trackdir might have changed, keep track in sync
 
	Trackdir start_trackdir = trackdir;
 

	
 
	/* Must start on a valid track to be able to avoid loops */
 
	if (!HasTrack(tile, track)) return CMD_ERROR;
 

	
 
	SignalType sigtype = (SignalType)GB(p2, 7, 3);
 
	if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
 

	
 
	byte signals;
 
	/* copy the signal-style of the first rail-piece if existing */
 
	if (HasSignalOnTrack(tile, track)) {
 
		signals = GetPresentSignals(tile) & SignalOnTrack(track);
 
		assert(signals != 0);
 

	
 
		/* copy signal/semaphores style (independent of CTRL) */
 
		semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
 
		sigvar = GetSignalVariant(tile, track);
 

	
 
		sigtype = GetSignalType(tile, track);
 
		/* Don't but copy entry or exit-signal type */
 
		if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
 
	} else { // no signals exist, drag a two-way signal stretch
 
		signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
 
@@ -1341,28 +1299,20 @@ static CommandCost CmdSignalTrackHelper(
 
	int last_used_ctr = -signal_density; // to force signal at first tile
 
	int last_suitable_ctr = 0;
 
	TileIndex last_suitable_tile = INVALID_TILE;
 
	Trackdir last_suitable_trackdir = INVALID_TRACKDIR;
 
	CommandCost last_error = CMD_ERROR;
 
	bool had_success = false;
 
	uint32 param1 = 0;
 
	SB(param1, 3, 1, mode);
 
	SB(param1, 4, 1, semaphores);
 
	SB(param1, 5, 3, sigtype);
 

	
 
	auto build_signal = [&](TileIndex tile, Trackdir trackdir, bool test_only) {
 
		SB(param1, 0, 3, TrackdirToTrack(trackdir));
 
		SB(param1, 17, 1, (!remove && signal_ctr == 0 ? 1 : 0));
 

	
 
		/* Pick the correct orientation for the track direction */
 
		byte signals = 0;
 
		if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
 
		if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
 

	
 
		DoCommandFlag do_flags = test_only ? flags & ~DC_EXEC : flags;
 
		CommandCost ret = remove ? Command<CMD_REMOVE_SIGNALS>::Do(do_flags, tile, param1, signals, {}) : Command<CMD_BUILD_SIGNALS>::Do(do_flags, tile, param1, signals, {});
 
		CommandCost ret = remove ? Command<CMD_REMOVE_SIGNALS>::Do(do_flags, tile, TrackdirToTrack(trackdir)) : Command<CMD_BUILD_SIGNALS>::Do(do_flags, tile, TrackdirToTrack(trackdir), sigtype, sigvar, false, signal_ctr == 0, mode, SIGTYPE_NORMAL, SIGTYPE_NORMAL, 0, signals);
 

	
 
		if (test_only) return ret.Succeeded();
 

	
 
		if (ret.Succeeded()) {
 
			had_success = true;
 
			total_cost.AddCost(ret);
 
@@ -1466,46 +1416,37 @@ static CommandCost CmdSignalTrackHelper(
 

	
 
/**
 
 * Build signals on a stretch of track.
 
 * Stub for the unified signal builder/remover
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1  end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit  0- 2) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit  3)    - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * - p2 = (bit  4)    - 0 = signals, 1 = semaphores
 
 * - p2 = (bit  5)    - 0 = build, 1 = remove signals
 
 * - p2 = (bit  6)    - 0 = selected stretch, 1 = auto fill
 
 * - p2 = (bit  7- 9) - default signal type
 
 * - p2 = (bit 24-31) - user defined signals_density
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param track track-orientation
 
 * @param sigtype default signal type
 
 * @param sigvar signal variant to build
 
 * @param mode true = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * @param autofill fill beyond selected stretch?
 
 * @param minimise_gaps false = keep fixed distance, true = minimise gaps between signals
 
 * @param signal_density user defined signals_density
 
 * @return the cost of this operation or an error
 
 * @see CmdSignalTrackHelper
 
 */
 
CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool autofill, bool minimise_gaps, byte signal_density)
 
{
 
	return CmdSignalTrackHelper(flags, tile, p1, p2, text);
 
	return CmdSignalTrackHelper(flags, tile, end_tile, track, sigtype, sigvar, mode, false, autofill, minimise_gaps, signal_density);
 
}
 

	
 
/**
 
 * Remove signals
 
 * @param flags operation to perform
 
 * @param tile coordinates where signal is being deleted from
 
 * @param p1 various bitstuffed elements, only track information is used
 
 *           - (bit  0- 2) - track-orientation, valid values: 0-5 (Track enum)
 
 *           - (bit  3)    - override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 *           - (bit  4)    - 0 = signals, 1 = semaphores
 
 * @param p2 unused
 
 * @param text unused
 
 * @param track track-orientation
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track)
 
{
 
	Track track = Extract<Track, 0, 3>(p1);
 

	
 
	if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
 
		return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
 
	}
 
	if (!HasSignalOnTrack(tile, track)) {
 
		return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
 
	}
 
@@ -1558,28 +1499,21 @@ CommandCost CmdRemoveSingleSignal(DoComm
 

	
 
/**
 
 * Remove signals on a stretch of track.
 
 * Stub for the unified signal builder/remover
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param p1  end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit  0- 2) - track-orientation, valid values: 0-5 (Track enum)
 
 * - p2 = (bit  3)    - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * - p2 = (bit  4)    - 0 = signals, 1 = semaphores
 
 * - p2 = (bit  5)    - 0 = build, 1 = remove signals
 
 * - p2 = (bit  6)    - 0 = selected stretch, 1 = auto fill
 
 * - p2 = (bit  7- 9) - default signal type
 
 * - p2 = (bit 24-31) - user defined signals_density
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param track track-orientation
 
 * @param autofill fill beyond selected stretch?
 
 * @return the cost of this operation or an error
 
 * @see CmdSignalTrackHelper
 
 */
 
CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, bool autofill)
 
{
 
	return CmdSignalTrackHelper(flags, tile, p1, SetBit(p2, 5), text); // bit 5 is remove bit
 
	return CmdSignalTrackHelper(flags, tile, end_tile, track, SIGTYPE_NORMAL, SIG_ELECTRIC, false, true, autofill, false, 1); // bit 5 is remove bit
 
}
 

	
 
/** Update power of train under which is the railtype being converted */
 
static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
 
{
 
	if (v->type != VEH_TRAIN) return nullptr;
 
@@ -1592,25 +1526,20 @@ static Vehicle *UpdateTrainPowerProc(Veh
 

	
 
/**
 
 * Convert one rail type to the other. You can convert normal rail to
 
 * monorail/maglev easily or vice-versa.
 
 * @param flags operation to perform
 
 * @param tile end tile of rail conversion drag
 
 * @param p1 start tile of drag
 
 * @param p2 various bitstuffed elements:
 
 * - p2 = (bit  0- 5) new railtype to convert to.
 
 * - p2 = (bit  6)    build diagonally or not.
 
 * @param text unused
 
 * @param area_start start tile of drag
 
 * @param totype new railtype to convert to.
 
 * @param diagonal build diagonally or not.
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal)
 
{
 
	RailType totype = Extract<RailType, 0, 6>(p2);
 
	TileIndex area_start = p1;
 
	TileIndex area_end = tile;
 
	bool diagonal = HasBit(p2, 6);
 

	
 
	if (!ValParamRailtype(totype)) return CMD_ERROR;
 
	if (area_start >= MapSize()) return CMD_ERROR;
 

	
 
	TrainList affected_trains;
 

	
 
@@ -1876,13 +1805,13 @@ static CommandCost ClearTile_Track(TileI
 
			/* Is there flat water on the lower halftile that gets cleared expensively? */
 
			bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
 

	
 
			TrackBits tracks = GetTrackBits(tile);
 
			while (tracks != TRACK_BIT_NONE) {
 
				Track track = RemoveFirstTrack(&tracks);
 
				CommandCost ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, 0, track, {});
 
				CommandCost ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, track);
 
				if (ret.Failed()) return ret;
 
				cost.AddCost(ret);
 
			}
 

	
 
			/* When bankrupting, don't make water dirty, there could be a ship on lower halftile.
 
			 * Same holds for non-companies clearing the tile, e.g. disasters. */
src/rail_cmd.h
Show inline comments
 
@@ -8,23 +8,26 @@
 
/** @file rail_cmd.h Command definitions for rail. */
 

	
 
#ifndef RAIL_CMD_H
 
#define RAIL_CMD_H
 

	
 
#include "command_type.h"
 
#include "track_type.h"
 
#include "rail_type.h"
 
#include "signal_type.h"
 

	
 
CommandProc CmdBuildRailroadTrack;
 
CommandProc CmdRemoveRailroadTrack;
 
CommandProc CmdBuildSingleRail;
 
CommandProc CmdRemoveSingleRail;
 
CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool auto_remove_signals, bool fail_on_obstacle);
 
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track);
 
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals);
 
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track);
 
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir);
 
CommandProc CmdBuildSingleSignal;
 
CommandProc CmdRemoveSingleSignal;
 
CommandProc CmdConvertRail;
 
CommandProc CmdBuildSignalTrack;
 
CommandProc CmdRemoveSignalTrack;
 
CommandCost CmdBuildSingleSignal(DoCommandFlag 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 num_dir_cycle, byte signals_copy);
 
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track);
 
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal);
 
CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool autofill, bool minimise_gaps, byte signal_density);
 
CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, bool autofill);
 

	
 
DEF_CMD_TRAIT(CMD_BUILD_RAILROAD_TRACK,  CmdBuildRailroadTrack,  CMD_AUTO | CMD_NO_WATER, CMDT_LANDSCAPE_CONSTRUCTION)
 
DEF_CMD_TRAIT(CMD_REMOVE_RAILROAD_TRACK, CmdRemoveRailroadTrack, CMD_AUTO,                CMDT_LANDSCAPE_CONSTRUCTION)
 
DEF_CMD_TRAIT(CMD_BUILD_SINGLE_RAIL,     CmdBuildSingleRail,     CMD_AUTO | CMD_NO_WATER, CMDT_LANDSCAPE_CONSTRUCTION)
 
DEF_CMD_TRAIT(CMD_REMOVE_SINGLE_RAIL,    CmdRemoveSingleRail,    CMD_AUTO,                CMDT_LANDSCAPE_CONSTRUCTION)
 
DEF_CMD_TRAIT(CMD_BUILD_TRAIN_DEPOT,     CmdBuildTrainDepot,     CMD_AUTO | CMD_NO_WATER, CMDT_LANDSCAPE_CONSTRUCTION)
src/rail_gui.cpp
Show inline comments
 
@@ -91,20 +91,20 @@ static bool IsStationAvailable(const Sta
 

	
 
void CcPlaySound_CONSTRUCTION_RAIL(Commands cmd, const CommandCost &result,TileIndex tile, const CommandDataBuffer &)
 
{
 
	if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, tile);
 
}
 

	
 
static void GenericPlaceRail(TileIndex tile, int cmd)
 
static void GenericPlaceRail(TileIndex tile, Track track)
 
{
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3), {});
 
				tile, track);
 
	} else {
 
		Command<CMD_BUILD_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3), {});
 
				tile, _cur_railtype, track, _settings_client.gui.auto_remove_signals);
 
	}
 
}
 

	
 
/**
 
 * Try to add an additional rail-track at the entrance of a depot
 
 * @param tile  Tile to use for adding the rail-track
 
@@ -115,13 +115,13 @@ static void GenericPlaceRail(TileIndex t
 
static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track)
 
{
 
	if (GetRailTileType(tile) == RAIL_TILE_DEPOT) return;
 
	if (GetRailTileType(tile) == RAIL_TILE_SIGNALS && !_settings_client.gui.auto_remove_signals) return;
 
	if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
 

	
 
	Command<CMD_BUILD_SINGLE_RAIL>::Post(tile, _cur_railtype, track | (_settings_client.gui.auto_remove_signals << 3), {});
 
	Command<CMD_BUILD_SINGLE_RAIL>::Post(tile, _cur_railtype, track, _settings_client.gui.auto_remove_signals);
 
}
 

	
 
/** Additional pieces of track to add at the entrance of a depot. */
 
static const Track _place_depot_extra_track[12] = {
 
	TRACK_LEFT,  TRACK_UPPER, TRACK_UPPER, TRACK_RIGHT, // First additional track for directions 0..3
 
	TRACK_X,     TRACK_Y,     TRACK_X,     TRACK_Y,     // Second additional track
 
@@ -237,45 +237,27 @@ static void GenericPlaceSignals(TileInde
 
		trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
 
	}
 

	
 
	Track track = FindFirstTrack(trackbits);
 

	
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_SIGNALS>::Post(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL, tile, track, 0, {});
 
		Command<CMD_REMOVE_SIGNALS>::Post(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL, tile, track);
 
	} else {
 
		const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
 

	
 
		/* various bitstuffed elements for CmdBuildSingleSignal() */
 
		uint32 p1 = track;
 

	
 
		/* Which signals should we cycle through? */
 
		uint8 cycle_types;
 

	
 
		if (_settings_client.gui.cycle_signal_types == SIGNAL_CYCLE_ALL && _settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL) {
 
			cycle_types = SIGTYPE_NORMAL | (SIGTYPE_LAST << 3);
 
		} else {
 
			cycle_types = SIGTYPE_PBS | (SIGTYPE_LAST << 3);
 
		}
 
		SignalType cycle_start = _settings_client.gui.cycle_signal_types == SIGNAL_CYCLE_ALL && _settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL ? SIGTYPE_NORMAL : SIGTYPE_PBS;
 

	
 
		if (w != nullptr) {
 
		if (FindWindowById(WC_BUILD_SIGNAL, 0) != nullptr) {
 
			/* signal GUI is used */
 
			SB(p1, 3, 1, _ctrl_pressed);
 
			SB(p1, 4, 1, _cur_signal_variant);
 
			SB(p1, 5, 3, _cur_signal_type);
 
			SB(p1, 8, 1, _convert_signal_button);
 
			SB(p1, 9, 6, cycle_types);
 
			Command<CMD_BUILD_SIGNALS>::Post(_convert_signal_button ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, track, _cur_signal_type, _cur_signal_variant, _convert_signal_button, false, _ctrl_pressed, cycle_start, SIGTYPE_LAST, 0, 0);
 
		} else {
 
			SB(p1, 3, 1, _ctrl_pressed);
 
			SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
			SB(p1, 5, 3, SIGTYPE_PBS_ONEWAY);
 
			SB(p1, 8, 1, 0);
 
			SB(p1, 9, 6, cycle_types);
 
			SignalVariant sigvar = _cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC;
 
			Command<CMD_BUILD_SIGNALS>::Post(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, track, SIGTYPE_PBS_ONEWAY, sigvar, false, false, _ctrl_pressed, cycle_start, SIGTYPE_LAST, 0, 0);
 

	
 
		}
 

	
 
		Command<CMD_BUILD_SIGNALS>::Post((w != nullptr && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE,
 
				CcPlaySound_CONSTRUCTION_RAIL, tile, p1, 0, {});
 
	}
 
}
 

	
 
/**
 
 * Start placing a rail bridge.
 
 * @param tile Position of the first tile of the bridge.
 
@@ -368,27 +350,26 @@ static void BuildRailClick_Remove(Window
 
				VpSetPlaceSizingLimit(_settings_game.station.station_spread);
 
			}
 
		}
 
	}
 
}
 

	
 
static void DoRailroadTrack(int mode)
 
static void DoRailroadTrack(Track track)
 
{
 
	uint32 p2 = _cur_railtype | (mode << 6) | (_settings_client.gui.auto_remove_signals << 11);
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), track);
 
	} else {
 
		Command<CMD_BUILD_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype, track, _settings_client.gui.auto_remove_signals, false);
 
	}
 
}
 

	
 
static void HandleAutodirPlacement()
 
{
 
	int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5
 
	Track trackstat = static_cast<Track>( _thd.drawstyle & HT_DIR_MASK); // 0..5
 

	
 
	if (_thd.drawstyle & HT_RAIL) { // one tile case
 
		GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat);
 
		return;
 
	}
 

	
 
@@ -400,46 +381,30 @@ static void HandleAutodirPlacement()
 
 *
 
 * If one tile marked abort and use GenericPlaceSignals()
 
 * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals
 
 */
 
static void HandleAutoSignalPlacement()
 
{
 
	uint32 p2 = GB(_thd.drawstyle, 0, 3); // 0..5
 
	Track track = (Track)GB(_thd.drawstyle, 0, 3); // 0..5
 

	
 
	if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT) { // one tile case
 
		GenericPlaceSignals(TileVirtXY(_thd.selend.x, _thd.selend.y));
 
		return;
 
	}
 

	
 
	const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
 

	
 
	if (w != nullptr) {
 
		/* signal GUI is used */
 
		SB(p2,  3, 1, 0);
 
		SB(p2,  4, 1, _cur_signal_variant);
 
		SB(p2,  6, 1, _ctrl_pressed);
 
		SB(p2,  7, 3, _cur_signal_type);
 
		SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
 
		SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance);
 
	} else {
 
		SB(p2,  3, 1, 0);
 
		SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
		SB(p2,  6, 1, _ctrl_pressed);
 
		SB(p2,  7, 3, SIGTYPE_PBS_ONEWAY);
 
		SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
 
		SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance);
 
	}
 

	
 
	/* _settings_client.gui.drag_signals_density is given as a parameter such that each user
 
	 * in a network game can specify their own signal density */
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_SIGNAL_TRACK>::Post(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), track, _ctrl_pressed);
 
	} else {
 
		bool sig_gui = FindWindowById(WC_BUILD_SIGNAL, 0) != nullptr;
 
		SignalType sigtype = sig_gui ? _cur_signal_type : SIGTYPE_PBS_ONEWAY;
 
		SignalVariant sigvar = sig_gui ? _cur_signal_variant : (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
		Command<CMD_BUILD_SIGNAL_TRACK>::Post(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), track, sigtype, sigvar, false, _ctrl_pressed, !_settings_client.gui.drag_signals_fixed_distance, _settings_client.gui.drag_signals_density);
 
	}
 
}
 

	
 

	
 
/** Rail toolbar management class. */
 
struct BuildRailToolbarWindow : Window {
 
@@ -722,13 +687,13 @@ struct BuildRailToolbarWindow : Window {
 

	
 
				case DDSP_DEMOLISH_AREA:
 
					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 
					break;
 

	
 
				case DDSP_CONVERT_RAIL:
 
					Command<CMD_CONVERT_RAIL>::Post(STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 1 << 6 : 0), {});
 
					Command<CMD_CONVERT_RAIL>::Post(STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype, _ctrl_pressed);
 
					break;
 

	
 
				case DDSP_REMOVE_STATION:
 
				case DDSP_BUILD_STATION:
 
					if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) {
 
						/* Station */
src/road_cmd.cpp
Show inline comments
 
@@ -2226,13 +2226,13 @@ static void ChangeTileOwner_Road(TileInd
 
		}
 
	}
 

	
 
	if (IsLevelCrossing(tile)) {
 
		if (GetTileOwner(tile) == old_owner) {
 
			if (new_owner == INVALID_OWNER) {
 
				Command<CMD_REMOVE_SINGLE_RAIL>::Do(DC_EXEC | DC_BANKRUPT, tile, 0, GetCrossingRailTrack(tile), {});
 
				Command<CMD_REMOVE_SINGLE_RAIL>::Do(DC_EXEC | DC_BANKRUPT, tile, GetCrossingRailTrack(tile));
 
			} else {
 
				/* Update infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
 
				Company::Get(old_owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
 
				Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR;
 

	
 
				SetTileOwner(tile, new_owner);
src/script/api/script_rail.cpp
Show inline comments
 
@@ -113,13 +113,13 @@
 
{
 
	EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
 
	EnforcePrecondition(false, ::IsValidTile(start_tile));
 
	EnforcePrecondition(false, ::IsValidTile(end_tile));
 
	EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
 

	
 
	return ScriptObject::Command<CMD_CONVERT_RAIL>::Do(start_tile, end_tile, convert_to, {});
 
	return ScriptObject::Command<CMD_CONVERT_RAIL>::Do(start_tile, end_tile, (::RailType)convert_to, false);
 
}
 

	
 
/* static */ TileIndex ScriptRail::GetRailDepotFrontTile(TileIndex depot)
 
{
 
	if (!IsRailDepotTile(depot)) return INVALID_TILE;
 

	
 
@@ -250,24 +250,24 @@
 
	EnforcePrecondition(false, ::IsValidTile(tile));
 
	EnforcePrecondition(false, rail_track != 0);
 
	EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0);
 
	EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
 
	EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
 

	
 
	return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 6), {});
 
	return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(tile, tile, (::RailType)GetCurrentRailType(), FindFirstTrack((::TrackBits)rail_track), false, false);
 
}
 

	
 
/* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
 
{
 
	EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
 
	EnforcePrecondition(false, ::IsValidTile(tile));
 
	EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile));
 
	EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
 
	EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
 

	
 
	return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(tile, tile, FindFirstTrack((::TrackBits)rail_track) << 6, {});
 
	return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(tile, tile, FindFirstTrack((::TrackBits)rail_track));
 
}
 

	
 
/* static */ bool ScriptRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to)
 
{
 
	if (!IsRailTile(tile)) return false;
 
	if (from == to || ScriptMap::DistanceManhattan(from, tile) != 1 || ScriptMap::DistanceManhattan(tile, to) != 1) return false;
 
@@ -289,68 +289,68 @@
 
}
 

	
 
/**
 
 * Prepare the second parameter for CmdBuildRailroadTrack and CmdRemoveRailroadTrack. The direction
 
 * depends on all three tiles. Sometimes the third tile needs to be adjusted.
 
 */
 
static uint32 SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
 
static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
 
{
 
	int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile)));
 
	uint32 p2 = 0;
 
	Track track = TRACK_BEGIN;
 
	if (::TileY(from) == ::TileY(*to)) {
 
		p2 |= (TRACK_X << 6);
 
		track = TRACK_X;
 
		*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
 
	} else if (::TileX(from) == ::TileX(*to)) {
 
		p2 |= (TRACK_Y << 6);
 
		track = TRACK_Y;
 
		*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
 
	} else if (::TileY(from) < ::TileY(tile)) {
 
		if (::TileX(*to) < ::TileX(tile)) {
 
			p2 |= (TRACK_UPPER << 6);
 
			track = TRACK_UPPER;
 
		} else {
 
			p2 |= (TRACK_LEFT << 6);
 
			track = TRACK_LEFT;
 
		}
 
		if (diag_offset != 0) {
 
			*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
 
		} else {
 
			*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
 
		}
 
	} else if (::TileY(from) > ::TileY(tile)) {
 
		if (::TileX(*to) < ::TileX(tile)) {
 
			p2 |= (TRACK_RIGHT << 6);
 
			track = TRACK_RIGHT;
 
		} else {
 
			p2 |= (TRACK_LOWER << 6);
 
			track = TRACK_LOWER;
 
		}
 
		if (diag_offset != 0) {
 
			*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
 
		} else {
 
			*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
 
		}
 
	} else if (::TileX(from) < ::TileX(tile)) {
 
		if (::TileY(*to) < ::TileY(tile)) {
 
			p2 |= (TRACK_UPPER << 6);
 
			track = TRACK_UPPER;
 
		} else {
 
			p2 |= (TRACK_RIGHT << 6);
 
			track = TRACK_RIGHT;
 
		}
 
		if (diag_offset == 0) {
 
			*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
 
		} else {
 
			*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
 
		}
 
	} else if (::TileX(from) > ::TileX(tile)) {
 
		if (::TileY(*to) < ::TileY(tile)) {
 
			p2 |= (TRACK_LEFT << 6);
 
			track = TRACK_LEFT;
 
		} else {
 
			p2 |= (TRACK_LOWER << 6);
 
			track = TRACK_LOWER;
 
		}
 
		if (diag_offset == 0) {
 
			*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
 
		} else {
 
			*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
 
		}
 
	}
 
	return p2;
 
	return track;
 
}
 

	
 
/* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
 
{
 
	EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
 
	EnforcePrecondition(false, ::IsValidTile(from));
 
@@ -361,14 +361,14 @@ static uint32 SimulateDrag(TileIndex fro
 
	EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
 
	int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
 
	EnforcePrecondition(false, diag_offset <= 1 ||
 
			(::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
 
			(::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
 

	
 
	uint32 p2 = SimulateDrag(from, tile, &to) | 1 << 10 | ScriptRail::GetCurrentRailType();;
 
	return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(tile, to, p2, {});
 
	Track track = SimulateDrag(from, tile, &to);
 
	return ScriptObject::Command<CMD_BUILD_RAILROAD_TRACK>::Do(tile, to, (::RailType)ScriptRail::GetCurrentRailType(), track, false, true);
 
}
 

	
 
/* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
 
{
 
	EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
 
	EnforcePrecondition(false, ::IsValidTile(from));
 
@@ -378,14 +378,14 @@ static uint32 SimulateDrag(TileIndex fro
 
	EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1);
 
	int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile)));
 
	EnforcePrecondition(false, diag_offset <= 1 ||
 
			(::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) ||
 
			(::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to)));
 

	
 
	uint32 p2 = SimulateDrag(from, tile, &to);
 
	return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(tile, to, p2, {});
 
	Track track = SimulateDrag(from, tile, &to);
 
	return ScriptObject::Command<CMD_REMOVE_RAILROAD_TRACK>::Do(tile, to, track);
 
}
 

	
 
/**
 
 * Contains information about the trackdir that belongs to a track when entering
 
 *   from a specific direction.
 
 */
 
@@ -458,20 +458,18 @@ static bool IsValidSignalType(int signal
 
		track = t;
 
		signal_cycles = _possible_trackdirs[data_index][i].signal_cycles;
 
		break;
 
	}
 
	EnforcePrecondition(false, track != INVALID_TRACK);
 

	
 
	uint p1 = track;
 
	if (signal < SIGNALTYPE_TWOWAY) {
 
		if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++;
 
		p1 |= (signal_cycles << 15);
 
	}
 
	p1 |= ((signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal) << 5);
 
	::SignalType sig_type = (::SignalType)(signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal);
 

	
 
	return ScriptObject::Command<CMD_BUILD_SIGNALS>::Do(tile, p1, 0, {});
 
	return ScriptObject::Command<CMD_BUILD_SIGNALS>::Do(tile, track, sig_type, ::SIG_ELECTRIC, false, false, false, ::SIGTYPE_NORMAL, ::SIGTYPE_NORMAL, signal_cycles, 0);
 
}
 

	
 
/* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front)
 
{
 
	EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
 
	EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
 
@@ -484,13 +482,13 @@ static bool IsValidSignalType(int signal
 
		if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue;
 
		track = t;
 
		break;
 
	}
 
	EnforcePrecondition(false, track != INVALID_TRACK);
 

	
 
	return ScriptObject::Command<CMD_REMOVE_SIGNALS>::Do(tile, track, 0, {});
 
	return ScriptObject::Command<CMD_REMOVE_SIGNALS>::Do(tile, track);
 
}
 

	
 
/* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type)
 
{
 
	if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
 

	
src/signal_type.h
Show inline comments
 
@@ -10,20 +10,20 @@
 
#ifndef SIGNAL_TYPE_H
 
#define SIGNAL_TYPE_H
 

	
 
#include "core/enum_type.hpp"
 

	
 
/** Variant of the signal, i.e. how does the signal look? */
 
enum SignalVariant {
 
enum SignalVariant : byte {
 
	SIG_ELECTRIC  = 0, ///< Light signal
 
	SIG_SEMAPHORE = 1, ///< Old-fashioned semaphore signal
 
};
 

	
 

	
 
/** Type of signal, i.e. how does the signal behave? */
 
enum SignalType {
 
enum SignalType : byte {
 
	SIGTYPE_NORMAL     = 0, ///< normal signal
 
	SIGTYPE_ENTRY      = 1, ///< presignal block entry
 
	SIGTYPE_EXIT       = 2, ///< presignal block exit
 
	SIGTYPE_COMBO      = 3, ///< presignal inter-block
 
	SIGTYPE_PBS        = 4, ///< normal pbs signal
 
	SIGTYPE_PBS_ONEWAY = 5, ///< no-entry signal
src/station_cmd.cpp
Show inline comments
 
@@ -922,13 +922,13 @@ static CommandCost CheckFlatLandRailStat
 
					if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
 
						Train *v = GetTrainForReservation(tile_cur, track);
 
						if (v != nullptr) {
 
							affected_vehicles.push_back(v);
 
						}
 
					}
 
					CommandCost ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile_cur, 0, track, {});
 
					CommandCost ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile_cur, track);
 
					if (ret.Failed()) return ret;
 
					cost.AddCost(ret);
 
					/* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
 
					continue;
 
				}
 
			}
0 comments (0 inline, 0 general)