2009-08-21 20:21:05 +00:00
/*
* This file is part of OpenTTD .
* 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.
* 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 .
* 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/>.
*/
2008-05-06 15:11:33 +00:00
/** @file rail_cmd.cpp Handling of rail tiles. */
2007-03-28 20:41:35 +00:00
2004-08-09 17:04:08 +00:00
# include "stdafx.h"
2007-02-24 09:42:39 +00:00
# include "cmd_helper.h"
2008-01-09 09:45:45 +00:00
# include "viewport_func.h"
2007-12-21 21:50:46 +00:00
# include "command_func.h"
2008-04-17 19:10:30 +00:00
# include "depot_base.h"
2009-12-02 16:48:55 +00:00
# include "pathfinder/yapf/yapf_cache.h"
2010-04-24 13:39:11 +00:00
# include "newgrf_debug.h"
2010-02-07 22:22:54 +00:00
# include "newgrf_railtype.h"
2006-09-05 16:40:23 +00:00
# include "train.h"
2007-09-14 22:27:40 +00:00
# include "autoslope.h"
2007-11-24 08:45:04 +00:00
# include "water.h"
2007-12-16 15:38:51 +00:00
# include "tunnelbridge_map.h"
2016-09-18 18:48:52 +00:00
# include "bridge_signal_map.h"
2007-12-27 13:35:39 +00:00
# include "vehicle_func.h"
2007-12-29 09:24:26 +00:00
# include "sound_func.h"
2008-01-23 22:34:04 +00:00
# include "tunnelbridge.h"
2008-05-08 16:48:29 +00:00
# include "elrail_func.h"
2009-06-26 13:44:14 +00:00
# include "town.h"
2009-12-01 23:56:04 +00:00
# include "pbs.h"
2010-01-15 16:41:15 +00:00
# include "company_base.h"
2010-05-31 20:22:57 +00:00
# include "core/backup_type.hpp"
2010-06-20 19:13:02 +00:00
# include "date_func.h"
2011-11-07 19:35:02 +00:00
# include "strings_func.h"
2011-12-03 23:40:13 +00:00
# include "company_gui.h"
2013-05-29 17:13:53 +00:00
# include "object_map.h"
2015-07-21 23:28:53 +00:00
# include "tracerestrict.h"
2014-01-14 20:32:07 +00:00
# include "programmable_signals.h"
2015-11-24 19:59:40 +00:00
# include "spritecache.h"
2016-09-11 12:20:30 +00:00
# include "core/container_func.hpp"
2018-03-29 18:16:44 +00:00
# include "news_func.h"
2020-11-21 16:49:41 +00:00
# include "scope.h"
2007-12-16 15:38:51 +00:00
2008-01-13 01:21:35 +00:00
# include "table/strings.h"
# include "table/railtypes.h"
2008-02-15 17:38:18 +00:00
# include "table/track_land.h"
2004-08-09 17:04:08 +00:00
2016-09-18 12:43:25 +00:00
# include <vector>
2014-04-23 20:13:33 +00:00
# include "safeguards.h"
2010-08-15 15:47:07 +00:00
/** Helper type for lists/vectors of trains */
2019-03-03 17:30:09 +00:00
typedef std : : vector < Train * > TrainList ;
2010-08-15 15:47:07 +00:00
2008-08-24 23:00:11 +00:00
RailtypeInfo _railtypes [ RAILTYPE_END ] ;
2019-04-12 15:55:35 +00:00
std : : vector < RailType > _sorted_railtypes ;
2016-04-13 20:03:48 +00:00
TileIndex _rail_track_endtile ; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes.
2019-02-05 08:23:25 +00:00
RailTypes _railtypes_hidden_mask ;
2008-08-24 23:00:11 +00:00
/**
2011-01-18 23:09:43 +00:00
* Reset all rail type information to its default values .
2008-08-24 23:00:11 +00:00
*/
void ResetRailTypes ( )
{
2020-12-27 10:44:22 +00:00
static_assert ( lengthof ( _original_railtypes ) < = lengthof ( _railtypes ) ) ;
2016-12-10 13:26:29 +00:00
uint i = 0 ;
for ( ; i < lengthof ( _original_railtypes ) ; i + + ) _railtypes [ i ] = _original_railtypes [ i ] ;
2016-12-10 15:49:25 +00:00
static const RailtypeInfo empty_railtype = {
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , { } } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 } ,
2020-10-15 19:37:57 +00:00
0 , RAILTYPES_NONE , RAILTYPES_NONE , RAILTYPES_NONE , 0 , 0 , 0 , RTFB_NONE , 0 , 0 , 0 , 0 , 0 , 0 ,
2016-12-10 15:49:25 +00:00
RailTypeLabelList ( ) , 0 , 0 , RAILTYPES_NONE , RAILTYPES_NONE , 0 ,
{ } , { } } ;
for ( ; i < lengthof ( _railtypes ) ; i + + ) _railtypes [ i ] = empty_railtype ;
2019-02-05 08:23:25 +00:00
_railtypes_hidden_mask = RAILTYPES_NONE ;
2008-08-24 23:00:11 +00:00
}
2010-02-07 22:22:54 +00:00
void ResolveRailTypeGUISprites ( RailtypeInfo * rti )
{
SpriteID cursors_base = GetCustomRailSprite ( rti , INVALID_TILE , RTSG_CURSORS ) ;
if ( cursors_base ! = 0 ) {
rti - > gui_sprites . build_ns_rail = cursors_base + 0 ;
rti - > gui_sprites . build_x_rail = cursors_base + 1 ;
rti - > gui_sprites . build_ew_rail = cursors_base + 2 ;
rti - > gui_sprites . build_y_rail = cursors_base + 3 ;
rti - > gui_sprites . auto_rail = cursors_base + 4 ;
rti - > gui_sprites . build_depot = cursors_base + 5 ;
rti - > gui_sprites . build_tunnel = cursors_base + 6 ;
rti - > gui_sprites . convert_rail = cursors_base + 7 ;
rti - > cursor . rail_ns = cursors_base + 8 ;
rti - > cursor . rail_swne = cursors_base + 9 ;
rti - > cursor . rail_ew = cursors_base + 10 ;
rti - > cursor . rail_nwse = cursors_base + 11 ;
rti - > cursor . autorail = cursors_base + 12 ;
rti - > cursor . depot = cursors_base + 13 ;
rti - > cursor . tunnel = cursors_base + 14 ;
rti - > cursor . convert = cursors_base + 15 ;
}
2012-07-01 23:12:50 +00:00
/* Array of default GUI signal sprite numbers. */
const SpriteID _signal_lookup [ 2 ] [ SIGTYPE_END ] = {
{ SPR_IMG_SIGNAL_ELECTRIC_NORM , SPR_IMG_SIGNAL_ELECTRIC_ENTRY , SPR_IMG_SIGNAL_ELECTRIC_EXIT ,
2014-01-14 20:32:07 +00:00
SPR_IMG_SIGNAL_ELECTRIC_COMBO , SPR_IMG_SIGNAL_ELECTRIC_PBS , SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY ,
SPR_IMG_SIGNAL_ELECTRIC_PROG } ,
2012-07-01 23:12:50 +00:00
{ SPR_IMG_SIGNAL_SEMAPHORE_NORM , SPR_IMG_SIGNAL_SEMAPHORE_ENTRY , SPR_IMG_SIGNAL_SEMAPHORE_EXIT ,
2014-01-14 20:32:07 +00:00
SPR_IMG_SIGNAL_SEMAPHORE_COMBO , SPR_IMG_SIGNAL_SEMAPHORE_PBS , SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY ,
SPR_IMG_SIGNAL_SEMAPHORE_PROG } ,
2012-07-01 23:12:50 +00:00
} ;
for ( SignalType type = SIGTYPE_NORMAL ; type < SIGTYPE_END ; type = ( SignalType ) ( type + 1 ) ) {
for ( SignalVariant var = SIG_ELECTRIC ; var < = SIG_SEMAPHORE ; var = ( SignalVariant ) ( var + 1 ) ) {
SpriteID red = GetCustomSignalSprite ( rti , INVALID_TILE , type , var , SIGNAL_STATE_RED , true ) ;
SpriteID green = GetCustomSignalSprite ( rti , INVALID_TILE , type , var , SIGNAL_STATE_GREEN , true ) ;
rti - > gui_sprites . signals [ type ] [ var ] [ 0 ] = ( red ! = 0 ) ? red + SIGNAL_TO_SOUTH : _signal_lookup [ var ] [ type ] ;
rti - > gui_sprites . signals [ type ] [ var ] [ 1 ] = ( green ! = 0 ) ? green + SIGNAL_TO_SOUTH : _signal_lookup [ var ] [ type ] + 1 ;
}
}
2010-02-07 22:22:54 +00:00
}
2015-10-30 17:24:30 +00:00
/**
* Compare railtypes based on their sorting order .
* @ param first The railtype to compare to .
* @ param second The railtype to compare .
* @ return True iff the first should be sorted before the second .
*/
2019-04-12 15:55:35 +00:00
static bool CompareRailTypes ( const RailType & first , const RailType & second )
2015-10-30 17:24:30 +00:00
{
2019-04-12 15:55:35 +00:00
return GetRailTypeInfo ( first ) - > sorting_order < GetRailTypeInfo ( second ) - > sorting_order ;
2015-10-30 17:24:30 +00:00
}
2011-01-18 23:09:43 +00:00
/**
* Resolve sprites of custom rail types
*/
2010-02-07 22:22:54 +00:00
void InitRailTypes ( )
{
for ( RailType rt = RAILTYPE_BEGIN ; rt ! = RAILTYPE_END ; rt + + ) {
RailtypeInfo * rti = & _railtypes [ rt ] ;
ResolveRailTypeGUISprites ( rti ) ;
2019-02-05 08:23:25 +00:00
if ( HasBit ( rti - > flags , RTF_HIDDEN ) ) SetBit ( _railtypes_hidden_mask , rt ) ;
2010-02-07 22:22:54 +00:00
}
2015-10-30 17:24:30 +00:00
2019-04-12 15:55:35 +00:00
_sorted_railtypes . clear ( ) ;
2015-10-30 17:24:30 +00:00
for ( RailType rt = RAILTYPE_BEGIN ; rt ! = RAILTYPE_END ; rt + + ) {
2019-02-05 08:23:25 +00:00
if ( _railtypes [ rt ] . label ! = 0 & & ! HasBit ( _railtypes_hidden_mask , rt ) ) {
2019-04-12 15:55:35 +00:00
_sorted_railtypes . push_back ( rt ) ;
2015-10-30 17:24:30 +00:00
}
}
2019-04-12 15:55:35 +00:00
std : : sort ( _sorted_railtypes . begin ( ) , _sorted_railtypes . end ( ) , CompareRailTypes ) ;
2020-10-15 19:37:57 +00:00
for ( RailType rt = RAILTYPE_BEGIN ; rt ! = RAILTYPE_END ; rt + + ) {
_railtypes [ rt ] . all_compatible_railtypes = _railtypes [ rt ] . compatible_railtypes ;
}
for ( RailType rt = RAILTYPE_BEGIN ; rt ! = RAILTYPE_END ; rt + + ) {
RailTypes compatible = _railtypes [ rt ] . all_compatible_railtypes ;
RailTypes to_check = compatible ;
while ( to_check ) {
RailType i = ( RailType ) FindFirstBit64 ( to_check ) ;
to_check = KillFirstBit ( to_check ) ;
RailTypes new_types = _railtypes [ i ] . compatible_railtypes & ( ~ compatible ) ;
to_check | = new_types ;
compatible | = new_types ;
}
RailTypes to_update = compatible ;
while ( to_update ) {
RailType i = ( RailType ) FindFirstBit64 ( to_update ) ;
to_update = KillFirstBit ( to_update ) ;
_railtypes [ i ] . all_compatible_railtypes = compatible ;
}
}
2010-02-07 22:22:54 +00:00
}
2011-01-18 23:09:43 +00:00
/**
* Allocate a new rail type label
*/
2010-01-30 21:49:22 +00:00
RailType AllocateRailType ( RailTypeLabel label )
{
for ( RailType rt = RAILTYPE_BEGIN ; rt ! = RAILTYPE_END ; rt + + ) {
RailtypeInfo * rti = & _railtypes [ rt ] ;
if ( rti - > label = = 0 ) {
/* Set up new rail type */
2016-12-10 13:28:47 +00:00
* rti = _original_railtypes [ RAILTYPE_RAIL ] ;
2010-01-30 21:49:22 +00:00
rti - > label = label ;
2018-09-20 22:44:14 +00:00
rti - > alternate_labels . clear ( ) ;
2010-01-30 21:49:22 +00:00
/* Make us compatible with ourself. */
2018-07-22 23:05:23 +00:00
rti - > powered_railtypes = ( RailTypes ) ( 1LL < < rt ) ;
rti - > compatible_railtypes = ( RailTypes ) ( 1LL < < rt ) ;
2011-01-18 21:28:07 +00:00
/* We also introduce ourself. */
2018-07-22 23:05:23 +00:00
rti - > introduces_railtypes = ( RailTypes ) ( 1LL < < rt ) ;
2011-01-20 12:22:38 +00:00
/* Default sort order; order of allocation, but with some
* offsets so it ' s easier for NewGRF to pick a spot without
* changing the order of other ( original ) rail types .
* The < < is so you can place other railtypes in between the
* other railtypes , the 7 is to be able to place something
* before the first ( default ) rail type . */
rti - > sorting_order = rt < < 4 | 7 ;
2010-01-30 21:49:22 +00:00
return rt ;
}
}
return INVALID_RAILTYPE ;
}
2009-09-20 23:11:01 +00:00
static const byte _track_sloped_sprites [ 14 ] = {
2005-08-01 16:31:19 +00:00
14 , 15 , 22 , 13 ,
0 , 21 , 17 , 12 ,
23 , 0 , 18 , 20 ,
19 , 16
} ;
2004-08-09 17:04:08 +00:00
/* 4
* - - - - - - - - -
* | \ / |
* | \ 1 / |
* | \ / |
* | \ / |
* 16 | \ | 32
2004-09-11 09:55:19 +00:00
* | / \ 2 |
2004-08-09 17:04:08 +00:00
* | / \ |
* | / \ |
* | / \ |
* - - - - - - - - -
* 8
*/
2004-08-11 22:07:08 +00:00
/* MAP2 byte: abcd???? => Signal On? Same coding as map3lo
2004-09-11 09:55:19 +00:00
* MAP3LO byte : abcd ? ? ? ? = > Signal Exists ?
2006-08-28 18:53:03 +00:00
* a and b are for diagonals , upper and left ,
* one for each direction . ( ie a = = NE - > SW , b = =
* SW - > NE , or v . v . , I don ' t know . b and c are
* similar for lower and right .
2004-08-09 17:04:08 +00:00
* MAP2 byte : ? ? ? ? abcd = > Type of ground .
* MAP3LO byte : ? ? ? ? abcd = > Type of rail .
* MAP5 : 00 abcdef = > rail
* 01 abcdef = > rail w / signals
* 10uuuuuu = > unused
2004-09-11 09:55:19 +00:00
* 11uuuu dd = > rail depot
2004-08-09 17:04:08 +00:00
*/
2007-08-16 13:13:07 +00:00
/**
* Tests if a vehicle interacts with the specified track .
2010-03-07 15:54:58 +00:00
* All track bits interact except parallel # TRACK_BIT_HORZ or # TRACK_BIT_VERT .
2007-08-16 13:13:07 +00:00
*
* @ param tile The tile .
* @ param track The track .
2010-03-07 18:29:53 +00:00
* @ return Succeeded command ( no train found ) , or a failed command ( a train was found ) .
2007-08-16 13:13:07 +00:00
*/
2010-03-07 18:29:53 +00:00
static CommandCost EnsureNoTrainOnTrack ( TileIndex tile , Track track )
2007-08-16 13:13:07 +00:00
{
2007-12-15 23:11:18 +00:00
TrackBits rail_bits = TrackToTrackBits ( track ) ;
2010-03-07 18:29:53 +00:00
return EnsureNoTrainOnTrackBits ( tile , rail_bits ) ;
2007-08-16 13:13:07 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Check that the new track bits may be built .
2010-02-21 20:34:57 +00:00
* @ param tile % Tile to build on .
* @ param to_build New track bits .
2018-12-21 03:27:58 +00:00
* @ param railtype New rail type .
* @ param disable_dual_rail_type Whether dual rail types are disabled .
2010-02-21 20:34:57 +00:00
* @ param flags Flags of the operation .
* @ return Succeeded or failed command .
*/
2021-01-31 01:41:05 +00:00
static CommandCost CheckTrackCombination ( TileIndex tile , TrackBits to_build , RailType railtype , bool disable_dual_rail_type , DoCommandFlag flags , bool auto_remove_signals )
2004-08-09 17:04:08 +00:00
{
2010-02-21 20:34:57 +00:00
if ( ! IsPlainRail ( tile ) ) return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
2005-03-28 07:25:36 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
/* So, we have a tile with tracks on it (and possibly signals). Let's see
* what tracks first */
2010-02-15 19:52:40 +00:00
TrackBits current = GetTrackBits ( tile ) ; // The current track layout.
TrackBits future = current | to_build ; // The track layout we want to build.
2005-03-28 07:25:36 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
/* Are we really building something new? */
if ( current = = future ) {
/* Nothing new is being built */
2018-12-21 03:27:58 +00:00
if ( IsCompatibleRail ( GetTileRailTypeByTrackBit ( tile , to_build ) , railtype ) ) {
return_cmd_error ( STR_ERROR_ALREADY_BUILT ) ;
} else {
return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
}
}
/* These combinations are always allowed, unless disable_dual_rail_type is set */
if ( ( future = = TRACK_BIT_HORZ | | future = = TRACK_BIT_VERT ) & & ! disable_dual_rail_type ) {
if ( flags & DC_EXEC ) {
if ( to_build & TRACK_BIT_RT_1 ) {
RailType current_rt = GetRailType ( tile ) ;
SetRailType ( tile , railtype ) ;
SetSecondaryRailType ( tile , current_rt ) ;
} else {
SetSecondaryRailType ( tile , railtype ) ;
}
}
return CommandCost ( ) ;
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
}
2005-03-28 07:25:36 +00:00
2021-01-31 01:41:05 +00:00
/* Let's see if we may build this */
if ( HasSignals ( tile ) & & ! auto_remove_signals ) {
/* If we are not allowed to overlap (flag is on for ai companies or we have
* signals on the tile ) , check that */
if ( future ! = TRACK_BIT_HORZ & & future ! = TRACK_BIT_VERT ) {
return_cmd_error ( STR_ERROR_MUST_REMOVE_SIGNALS_FIRST ) ;
}
}
2018-12-21 03:27:58 +00:00
RailType rt = INVALID_RAILTYPE ;
if ( current = = TRACK_BIT_HORZ | | current = = TRACK_BIT_VERT ) {
RailType rt1 = GetRailType ( tile ) ;
if ( ! IsCompatibleRail ( rt1 , railtype ) ) return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
RailType rt2 = GetSecondaryRailType ( tile ) ;
if ( ! IsCompatibleRail ( rt2 , railtype ) ) return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
if ( rt1 ! = rt2 ) {
/* Two different railtypes present */
if ( ( railtype = = rt1 | | HasPowerOnRail ( rt1 , railtype ) ) & & ( railtype = = rt2 | | HasPowerOnRail ( rt2 , railtype ) ) ) {
rt = railtype ;
} else if ( ( railtype = = rt1 | | HasPowerOnRail ( railtype , rt1 ) ) & & HasPowerOnRail ( rt2 , rt1 ) ) {
rt = railtype = rt1 ;
} else if ( ( railtype = = rt2 | | HasPowerOnRail ( railtype , rt2 ) ) & & HasPowerOnRail ( rt1 , rt2 ) ) {
rt = railtype = rt2 ;
} else {
return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
}
} else if ( railtype = = rt1 ) {
/* Nothing to do */
rt = INVALID_RAILTYPE ;
} else if ( HasPowerOnRail ( railtype , rt1 ) ) {
/* Try to keep existing railtype */
railtype = rt1 ;
rt = INVALID_RAILTYPE ;
} else if ( HasPowerOnRail ( rt1 , railtype ) ) {
rt = railtype ;
} else {
return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
}
} else {
rt = GetRailType ( tile ) ;
if ( railtype = = rt ) {
/* Nothing to do */
rt = INVALID_RAILTYPE ;
} else if ( ! IsCompatibleRail ( rt , railtype ) ) {
return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
} else if ( HasPowerOnRail ( railtype , rt ) ) {
/* Try to keep existing railtype */
railtype = rt ;
rt = INVALID_RAILTYPE ;
} else if ( HasPowerOnRail ( rt , railtype ) ) {
rt = railtype ;
} else {
return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
}
}
CommandCost ret ;
if ( rt ! = INVALID_RAILTYPE ) {
ret = DoCommand ( tile , tile , rt , flags , CMD_CONVERT_RAIL ) ;
if ( ret . Failed ( ) ) return ret ;
}
if ( flags & DC_EXEC ) {
SetRailType ( tile , railtype ) ;
SetSecondaryRailType ( tile , railtype ) ;
}
return ret ;
2004-08-09 17:04:08 +00:00
}
2007-10-09 21:11:23 +00:00
/** Valid TrackBits on a specific (non-steep)-slope without foundation */
static const TrackBits _valid_tracks_without_foundation [ 15 ] = {
2006-03-18 13:20:50 +00:00
TRACK_BIT_ALL ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_RIGHT ,
TRACK_BIT_UPPER ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_X ,
2004-08-09 17:04:08 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_LEFT ,
2007-01-10 18:56:51 +00:00
TRACK_BIT_NONE ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_Y ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_LOWER ,
2004-09-11 09:55:19 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_LOWER ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_Y ,
2007-01-10 18:56:51 +00:00
TRACK_BIT_NONE ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_LEFT ,
2004-09-11 09:55:19 +00:00
2006-03-01 09:40:34 +00:00
TRACK_BIT_X ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_UPPER ,
TRACK_BIT_RIGHT ,
2007-10-09 21:11:23 +00:00
} ;
2004-08-09 17:04:08 +00:00
2007-10-09 21:11:23 +00:00
/** Valid TrackBits on a specific (non-steep)-slope with leveled foundation */
static const TrackBits _valid_tracks_on_leveled_foundation [ 15 ] = {
2007-01-10 18:56:51 +00:00
TRACK_BIT_NONE ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_LEFT ,
TRACK_BIT_LOWER ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_RIGHT ,
2006-03-18 13:20:50 +00:00
TRACK_BIT_ALL ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT ,
2006-03-18 13:20:50 +00:00
TRACK_BIT_ALL ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
TRACK_BIT_UPPER ,
2006-03-01 09:40:34 +00:00
TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT ,
2006-03-18 13:20:50 +00:00
TRACK_BIT_ALL ,
TRACK_BIT_ALL ,
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
2006-03-01 09:40:34 +00:00
TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT ,
2006-03-18 13:20:50 +00:00
TRACK_BIT_ALL ,
TRACK_BIT_ALL
2004-08-09 17:04:08 +00:00
} ;
2007-10-09 21:11:23 +00:00
/**
* Checks if a track combination is valid on a specific slope and returns the needed foundation .
*
* @ param tileh Tile slope .
* @ param bits Trackbits .
* @ return Needed foundation or FOUNDATION_INVALID if track / slope combination is not allowed .
*/
2007-07-26 16:51:10 +00:00
Foundation GetRailFoundation ( Slope tileh , TrackBits bits )
2004-08-09 17:04:08 +00:00
{
2007-10-09 21:11:23 +00:00
if ( bits = = TRACK_BIT_NONE ) return FOUNDATION_NONE ;
if ( IsSteepSlope ( tileh ) ) {
/* Test for inclined foundations */
if ( bits = = TRACK_BIT_X ) return FOUNDATION_INCLINED_X ;
if ( bits = = TRACK_BIT_Y ) return FOUNDATION_INCLINED_Y ;
/* Get higher track */
Corner highest_corner = GetHighestSlopeCorner ( tileh ) ;
TrackBits higher_track = CornerToTrackBits ( highest_corner ) ;
/* Only higher track? */
2007-10-20 21:04:14 +00:00
if ( bits = = higher_track ) return HalftileFoundation ( highest_corner ) ;
2007-10-09 21:11:23 +00:00
/* Overlap with higher track? */
if ( TracksOverlap ( bits | higher_track ) ) return FOUNDATION_INVALID ;
/* either lower track or both higher and lower track */
2007-10-20 21:04:14 +00:00
return ( ( bits & higher_track ) ! = 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER ) ;
2007-10-09 21:11:23 +00:00
} else {
if ( ( ~ _valid_tracks_without_foundation [ tileh ] & bits ) = = 0 ) return FOUNDATION_NONE ;
2006-05-20 18:03:22 +00:00
2007-10-09 21:11:23 +00:00
bool valid_on_leveled = ( ( ~ _valid_tracks_on_leveled_foundation [ tileh ] & bits ) = = 0 ) ;
2007-10-20 21:04:14 +00:00
Corner track_corner ;
2007-10-09 21:11:23 +00:00
switch ( bits ) {
2007-10-20 21:04:14 +00:00
case TRACK_BIT_LEFT : track_corner = CORNER_W ; break ;
case TRACK_BIT_LOWER : track_corner = CORNER_S ; break ;
case TRACK_BIT_RIGHT : track_corner = CORNER_E ; break ;
case TRACK_BIT_UPPER : track_corner = CORNER_N ; break ;
case TRACK_BIT_HORZ :
if ( tileh = = SLOPE_N ) return HalftileFoundation ( CORNER_N ) ;
if ( tileh = = SLOPE_S ) return HalftileFoundation ( CORNER_S ) ;
return ( valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID ) ;
case TRACK_BIT_VERT :
if ( tileh = = SLOPE_W ) return HalftileFoundation ( CORNER_W ) ;
if ( tileh = = SLOPE_E ) return HalftileFoundation ( CORNER_E ) ;
return ( valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID ) ;
2007-10-09 21:11:23 +00:00
case TRACK_BIT_X :
2008-01-25 15:47:58 +00:00
if ( IsSlopeWithOneCornerRaised ( tileh ) ) return FOUNDATION_INCLINED_X ;
2007-10-09 21:11:23 +00:00
return ( valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID ) ;
case TRACK_BIT_Y :
2008-01-25 15:47:58 +00:00
if ( IsSlopeWithOneCornerRaised ( tileh ) ) return FOUNDATION_INCLINED_Y ;
2007-10-09 21:11:23 +00:00
return ( valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID ) ;
default :
return ( valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID ) ;
}
2007-10-20 21:04:14 +00:00
/* Single diagonal track */
/* Track must be at least valid on leveled foundation */
if ( ! valid_on_leveled ) return FOUNDATION_INVALID ;
/* If slope has three raised corners, build leveled foundation */
2008-01-25 15:47:58 +00:00
if ( IsSlopeWithThreeCornersRaised ( tileh ) ) return FOUNDATION_LEVELED ;
2007-10-20 21:04:14 +00:00
/* If neighboured corners of track_corner are lowered, build halftile foundation */
if ( ( tileh & SlopeWithThreeCornersRaised ( OppositeCorner ( track_corner ) ) ) = = SlopeWithOneCornerRaised ( track_corner ) ) return HalftileFoundation ( track_corner ) ;
/* else special anti-zig-zag foundation */
return SpecialRailFoundation ( track_corner ) ;
2006-02-01 06:32:03 +00:00
}
2004-08-09 17:04:08 +00:00
}
2005-11-14 19:48:04 +00:00
2007-10-09 21:11:23 +00:00
/**
* Tests if a track can be build on a tile .
*
* @ param tileh Tile slope .
* @ param rail_bits Tracks to build .
* @ param existing Tracks already built .
* @ param tile Tile ( used for water test )
* @ return Error message or cost for foundation building .
*/
2007-06-18 10:48:15 +00:00
static CommandCost CheckRailSlope ( Slope tileh , TrackBits rail_bits , TrackBits existing , TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2007-10-09 21:11:23 +00:00
/* don't allow building on the lower side of a coast */
2010-07-10 13:04:31 +00:00
if ( GetFloodingBehaviour ( tile ) ! = FLOOD_NONE ) {
2009-04-21 23:40:56 +00:00
if ( ! IsSteepSlope ( tileh ) & & ( ( ~ _valid_tracks_on_leveled_foundation [ tileh ] & ( rail_bits | existing ) ) ! = 0 ) ) return_cmd_error ( STR_ERROR_CAN_T_BUILD_ON_WATER ) ;
2007-10-09 21:11:23 +00:00
}
2004-08-09 17:04:08 +00:00
2007-10-09 21:11:23 +00:00
Foundation f_new = GetRailFoundation ( tileh , rail_bits | existing ) ;
2004-08-09 17:04:08 +00:00
2007-10-09 21:11:23 +00:00
/* check track/slope combination */
if ( ( f_new = = FOUNDATION_INVALID ) | |
2009-01-12 17:11:45 +00:00
( ( f_new ! = FOUNDATION_NONE ) & & ( ! _settings_game . construction . build_on_slopes ) ) ) {
2009-04-21 23:40:56 +00:00
return_cmd_error ( STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION ) ;
2008-08-06 15:52:04 +00:00
}
2004-09-11 09:55:19 +00:00
2007-10-09 21:11:23 +00:00
Foundation f_old = GetRailFoundation ( tileh , existing ) ;
2009-11-24 22:15:42 +00:00
return CommandCost ( EXPENSES_CONSTRUCTION , f_new ! = f_old ? _price [ PR_BUILD_FOUNDATION ] : ( Money ) 0 ) ;
2004-08-09 17:04:08 +00:00
}
2018-07-03 18:09:10 +00:00
bool IsValidFlatRailBridgeHeadTrackBits ( Slope normalised_slope , DiagDirection bridge_direction , TrackBits tracks )
{
/* bridge_direction c1 c2
* 0 0 1
* 1 0 3
* 2 2 3
* 3 2 1
*/
const Corner c1 = ( Corner ) ( bridge_direction & 2 ) ;
const Corner c2 = ( Corner ) ( ( ( bridge_direction + 1 ) & 2 ) + 1 ) ;
auto test_corner = [ & ] ( Corner c ) - > bool {
if ( normalised_slope & SlopeWithOneCornerRaised ( c ) ) return true ;
Slope effective_slope = normalised_slope | SlopeWithOneCornerRaised ( OppositeCorner ( c ) ) ;
assert ( effective_slope < lengthof ( _valid_tracks_on_leveled_foundation ) ) ;
return ( _valid_tracks_on_leveled_foundation [ effective_slope ] & tracks ) = = tracks ;
} ;
return test_corner ( c1 ) & & test_corner ( c2 ) ;
}
2005-05-07 10:26:12 +00:00
/* Validate functions for rail building */
2010-03-14 14:30:51 +00:00
static inline bool ValParamTrackOrientation ( Track track )
{
return IsValidTrack ( track ) ;
}
2005-05-07 10:26:12 +00:00
2010-08-01 19:22:34 +00:00
/**
* Build a single piece of rail
2006-04-10 07:15:58 +00:00
* @ param tile tile to build on
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 railtype of being built piece ( normal , mono , maglev )
2021-01-07 09:17:05 +00:00
* @ 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
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-07 10:26:12 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuildSingleRail ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2018-07-22 23:05:23 +00:00
RailType railtype = Extract < RailType , 0 , 6 > ( p1 ) ;
2010-04-17 13:31:41 +00:00
Track track = Extract < Track , 0 , 3 > ( p2 ) ;
2021-01-07 09:17:05 +00:00
bool auto_remove_signals = HasBit ( p2 , 3 ) ;
2018-07-03 18:09:10 +00:00
bool disable_custom_bridge_heads = HasBit ( p2 , 4 ) ;
2018-12-21 03:27:58 +00:00
bool disable_dual_rail_type = HasBit ( p2 , 5 ) ;
2008-01-09 16:55:48 +00:00
CommandCost cost ( EXPENSES_CONSTRUCTION ) ;
2005-04-02 18:33:53 +00:00
2016-04-13 20:03:48 +00:00
_rail_track_endtile = INVALID_TILE ;
2008-01-09 21:05:03 +00:00
if ( ! ValParamRailtype ( railtype ) | | ! ValParamTrackOrientation ( track ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2011-11-04 10:22:27 +00:00
Slope tileh = GetTileSlope ( tile ) ;
2010-02-15 19:52:40 +00:00
TrackBits trackbit = TrackToTrackBits ( track ) ;
2004-08-09 17:04:08 +00:00
2005-04-02 18:33:53 +00:00
switch ( GetTileType ( tile ) ) {
2010-02-15 19:52:40 +00:00
case MP_RAILWAY : {
2010-03-07 20:44:05 +00:00
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
2009-03-14 15:34:30 +00:00
2017-01-08 11:45:08 +00:00
if ( ! IsPlainRail ( tile ) ) return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ; // just get appropriate error message
2009-05-15 16:07:36 +00:00
2020-11-21 16:49:41 +00:00
const RailType old_rt = GetRailType ( tile ) ;
const RailType old_secondary_rt = GetSecondaryRailType ( tile ) ;
auto rt_guard = scope_guard ( [ & ] ( ) {
if ( flags & DC_EXEC ) {
SetRailType ( tile , old_rt ) ;
SetSecondaryRailType ( tile , old_secondary_rt ) ;
}
} ) ;
2021-01-31 01:41:05 +00:00
ret = CheckTrackCombination ( tile , trackbit , railtype , disable_dual_rail_type , flags , auto_remove_signals ) ;
2018-12-21 03:27:58 +00:00
if ( ret . Succeeded ( ) ) {
cost . AddCost ( ret ) ;
ret = EnsureNoTrainOnTrack ( tile , track ) ;
}
2016-04-13 20:03:48 +00:00
if ( ret . Failed ( ) ) {
if ( ret . GetErrorMessage ( ) = = STR_ERROR_ALREADY_BUILT ) _rail_track_endtile = tile ;
return ret ;
}
2010-02-21 20:34:57 +00:00
2021-03-31 08:27:25 +00:00
ret = CheckRailSlope ( tileh , trackbit , GetTrackBits ( tile ) , tile ) ;
if ( ret . Failed ( ) ) return ret ;
cost . AddCost ( ret ) ;
2021-01-07 09:17:05 +00:00
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 = DoCommand ( tile , track_it , 0 , flags , CMD_REMOVE_SIGNALS ) ;
if ( ret_remove_signals . Failed ( ) ) return ret_remove_signals ;
cost . AddCost ( ret_remove_signals ) ;
}
}
}
2020-11-21 16:49:41 +00:00
rt_guard . cancel ( ) ;
2005-04-24 07:56:18 +00:00
if ( flags & DC_EXEC ) {
2006-04-12 11:58:07 +00:00
SetRailGroundType ( tile , RAIL_GROUND_BARREN ) ;
2011-12-03 23:40:13 +00:00
TrackBits bits = GetTrackBits ( tile ) ;
2018-12-21 03:27:58 +00:00
TrackBits newbits = bits | trackbit ;
SetTrackBits ( tile , newbits ) ;
if ( newbits = = TRACK_BIT_HORZ | | newbits = = TRACK_BIT_VERT ) {
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . rail [ GetPlainRailParallelTrackRailTypeByTrackBit ( tile , trackbit ) ] + + ;
} else {
/* Subtract old infrastructure count. */
uint pieces = CountBits ( bits ) ;
if ( TracksOverlap ( bits ) ) pieces * = pieces ;
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . rail [ GetRailType ( tile ) ] - = pieces ;
/* Add new infrastructure count. */
pieces = CountBits ( newbits ) ;
if ( TracksOverlap ( newbits ) ) pieces * = pieces ;
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . rail [ GetRailType ( tile ) ] + = pieces ;
}
2011-12-03 23:40:13 +00:00
DirtyCompanyInfrastructureWindows ( GetTileOwner ( tile ) ) ;
2005-04-24 07:56:18 +00:00
}
2005-04-02 18:33:53 +00:00
break ;
2010-02-15 19:52:40 +00:00
}
2004-08-09 17:04:08 +00:00
2018-07-03 18:09:10 +00:00
case MP_TUNNELBRIDGE : {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
if ( disable_custom_bridge_heads | | ! _settings_game . construction . rail_custom_bridge_heads | | ! IsFlatRailBridgeHeadTile ( tile ) ) return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ; // just get appropriate error message
const DiagDirection entrance_dir = GetTunnelBridgeDirection ( tile ) ;
const TrackBits axial_track = DiagDirToDiagTrackBits ( entrance_dir ) ;
const TrackBits existing = GetCustomBridgeHeadTrackBits ( tile ) ;
const TrackBits future = existing | trackbit ;
2018-12-21 03:27:58 +00:00
const bool secondary_piece = ( ( future = = TRACK_BIT_HORZ | | future = = TRACK_BIT_VERT ) & & ( future ! = existing ) ) ;
if ( ! secondary_piece & & ! disable_dual_rail_type ) {
if ( ! IsCompatibleRail ( GetRailType ( tile ) , railtype ) ) return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
if ( GetRailType ( tile ) ! = railtype & & ! HasPowerOnRail ( railtype , GetRailType ( tile ) ) ) return_cmd_error ( STR_ERROR_CAN_T_CONVERT_RAIL ) ;
if ( GetSecondaryTunnelBridgeTrackBits ( tile ) ! = TRACK_BIT_NONE ) {
if ( ! IsCompatibleRail ( GetSecondaryRailType ( tile ) , railtype ) ) return_cmd_error ( STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION ) ;
if ( GetRailType ( tile ) ! = railtype & & ! HasPowerOnRail ( railtype , GetSecondaryRailType ( tile ) ) ) return_cmd_error ( STR_ERROR_CAN_T_CONVERT_RAIL ) ;
}
}
2018-07-03 18:09:10 +00:00
if ( existing = = future ) return_cmd_error ( STR_ERROR_ALREADY_BUILT ) ;
2021-01-31 01:10:01 +00:00
if ( IsTunnelBridgeWithSignalSimulation ( tile ) ) {
2018-07-03 18:09:10 +00:00
if ( future ! = TRACK_BIT_HORZ & & future ! = TRACK_BIT_VERT ) {
2021-01-31 01:10:01 +00:00
return_cmd_error ( STR_ERROR_MUST_REMOVE_SIGNALS_FIRST ) ;
2018-07-03 18:09:10 +00:00
}
}
if ( ( trackbit & ~ axial_track ) & & ! _settings_game . construction . build_on_slopes ) {
return_cmd_error ( STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION ) ;
}
/* Steep slopes behave the same as slopes with one corner raised. */
const Slope normalised_tileh = IsSteepSlope ( tileh ) ? SlopeWithOneCornerRaised ( GetHighestSlopeCorner ( tileh ) ) : tileh ;
if ( ! IsValidFlatRailBridgeHeadTrackBits ( normalised_tileh , GetTunnelBridgeDirection ( tile ) , future ) ) {
return_cmd_error ( STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION ) ;
}
const TileIndex other_end = GetOtherTunnelBridgeEnd ( tile ) ;
2018-12-21 03:27:58 +00:00
if ( ! secondary_piece ) {
ret = TunnelBridgeIsFree ( tile , other_end ) ;
if ( ret . Failed ( ) ) return ret ;
}
2018-07-03 18:09:10 +00:00
if ( flags & DC_EXEC ) {
2018-12-21 03:27:58 +00:00
SubtractRailTunnelBridgeInfrastructure ( tile , other_end ) ;
2018-07-03 18:09:10 +00:00
SetCustomBridgeHeadTrackBits ( tile , future ) ;
2020-05-18 23:41:35 +00:00
SetTunnelBridgeGroundBits ( tile , IsRailCustomBridgeHead ( tile ) ? 2 : 0 ) ;
2018-12-21 03:27:58 +00:00
if ( secondary_piece ) {
SetSecondaryRailType ( tile , railtype ) ;
}
AddRailTunnelBridgeInfrastructure ( tile , other_end ) ;
2018-07-03 18:09:10 +00:00
DirtyCompanyInfrastructureWindows ( _current_company ) ;
}
break ;
}
2010-03-05 21:20:22 +00:00
case MP_ROAD : {
2006-03-04 13:52:52 +00:00
/* Level crossings may only be built on these slopes */
2010-07-09 12:14:02 +00:00
if ( ! HasBit ( VALID_LEVEL_CROSSING_SLOPES , tileh ) ) return_cmd_error ( STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION ) ;
2006-03-04 13:52:52 +00:00
2010-03-05 21:20:22 +00:00
CommandCost ret = EnsureNoVehicleOnGround ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
2005-04-02 18:33:53 +00:00
2008-02-14 15:59:16 +00:00
if ( IsNormalRoad ( tile ) ) {
2009-08-05 17:59:21 +00:00
if ( HasRoadWorks ( tile ) ) return_cmd_error ( STR_ERROR_ROAD_WORKS_IN_PROGRESS ) ;
2006-07-15 09:29:39 +00:00
2009-08-05 17:59:21 +00:00
if ( GetDisallowedRoadDirections ( tile ) ! = DRD_NONE ) return_cmd_error ( STR_ERROR_CROSSING_ON_ONEWAY_ROAD ) ;
2008-03-03 19:15:53 +00:00
2019-04-06 06:46:15 +00:00
if ( RailNoLevelCrossings ( railtype ) ) return_cmd_error ( STR_ERROR_CROSSING_DISALLOWED_RAIL ) ;
2010-07-02 16:34:11 +00:00
2019-04-06 06:46:15 +00:00
RoadType roadtype_road = GetRoadTypeRoad ( tile ) ;
RoadType roadtype_tram = GetRoadTypeTram ( tile ) ;
if ( roadtype_road ! = INVALID_ROADTYPE & & RoadNoLevelCrossing ( roadtype_road ) ) return_cmd_error ( STR_ERROR_CROSSING_DISALLOWED_ROAD ) ;
if ( roadtype_tram ! = INVALID_ROADTYPE & & RoadNoLevelCrossing ( roadtype_tram ) ) return_cmd_error ( STR_ERROR_CROSSING_DISALLOWED_ROAD ) ;
RoadBits road = GetRoadBits ( tile , RTT_ROAD ) ;
RoadBits tram = GetRoadBits ( tile , RTT_TRAM ) ;
2015-06-20 13:15:35 +00:00
if ( ( track = = TRACK_X & & ( ( road | tram ) & ROAD_X ) = = 0 ) | |
( track = = TRACK_Y & & ( ( road | tram ) & ROAD_Y ) = = 0 ) ) {
2019-04-06 06:46:15 +00:00
Owner road_owner = GetRoadOwner ( tile , RTT_ROAD ) ;
Owner tram_owner = GetRoadOwner ( tile , RTT_TRAM ) ;
2015-06-20 13:15:35 +00:00
/* Disallow breaking end-of-line of someone else
* so trams can still reverse on this tile . */
if ( Company : : IsValidID ( tram_owner ) & & HasExactlyOneBit ( tram ) ) {
CommandCost ret = CheckOwnership ( tram_owner ) ;
if ( ret . Failed ( ) ) return ret ;
2015-04-26 10:23:55 +00:00
}
2007-05-20 19:14:08 +00:00
2019-04-06 06:46:15 +00:00
uint num_new_road_pieces = ( road ! = ROAD_NONE ) ? 2 - CountBits ( road ) : 0 ;
if ( num_new_road_pieces > 0 ) {
cost . AddCost ( num_new_road_pieces * RoadBuildCost ( roadtype_road ) ) ;
}
uint num_new_tram_pieces = ( tram ! = ROAD_NONE ) ? 2 - CountBits ( tram ) : 0 ;
if ( num_new_tram_pieces > 0 ) {
cost . AddCost ( num_new_tram_pieces * RoadBuildCost ( roadtype_tram ) ) ;
}
2007-05-20 19:14:08 +00:00
2006-07-15 09:29:39 +00:00
if ( flags & DC_EXEC ) {
2019-04-06 06:46:15 +00:00
MakeRoadCrossing ( tile , road_owner , tram_owner , _current_company , ( track = = TRACK_X ? AXIS_Y : AXIS_X ) , railtype , roadtype_road , roadtype_tram , GetTownIndex ( tile ) ) ;
2008-01-17 20:41:33 +00:00
UpdateLevelCrossing ( tile , false ) ;
2011-12-03 23:40:13 +00:00
Company : : Get ( _current_company ) - > infrastructure . rail [ railtype ] + = LEVELCROSSING_TRACKBIT_FACTOR ;
DirtyCompanyInfrastructureWindows ( _current_company ) ;
2015-06-20 13:15:35 +00:00
if ( num_new_road_pieces > 0 & & Company : : IsValidID ( road_owner ) ) {
2019-04-06 06:46:15 +00:00
Company : : Get ( road_owner ) - > infrastructure . road [ roadtype_road ] + = num_new_road_pieces ;
2015-06-20 13:15:35 +00:00
DirtyCompanyInfrastructureWindows ( road_owner ) ;
}
if ( num_new_tram_pieces > 0 & & Company : : IsValidID ( tram_owner ) ) {
2019-04-06 06:46:15 +00:00
Company : : Get ( tram_owner ) - > infrastructure . road [ roadtype_tram ] + = num_new_tram_pieces ;
2015-06-20 13:15:35 +00:00
DirtyCompanyInfrastructureWindows ( tram_owner ) ;
}
2020-10-26 22:17:25 +00:00
UpdateRoadCachedOneWayStatesAroundTile ( tile ) ;
2006-07-15 09:29:39 +00:00
}
break ;
2005-04-02 18:33:53 +00:00
}
}
2004-08-09 17:04:08 +00:00
2006-03-19 12:06:12 +00:00
if ( IsLevelCrossing ( tile ) & & GetCrossingRailBits ( tile ) = = trackbit ) {
2016-04-13 20:03:48 +00:00
_rail_track_endtile = tile ;
2009-04-21 23:40:56 +00:00
return_cmd_error ( STR_ERROR_ALREADY_BUILT ) ;
2006-03-19 12:06:12 +00:00
}
2017-08-15 15:56:34 +00:00
FALLTHROUGH ;
2010-03-05 21:20:22 +00:00
}
2004-08-09 17:04:08 +00:00
2010-02-15 19:52:40 +00:00
default : {
2008-01-25 16:51:35 +00:00
/* Will there be flat water on the lower halftile? */
2008-01-25 15:47:58 +00:00
bool water_ground = IsTileType ( tile , MP_WATER ) & & IsSlopeWithOneCornerRaised ( tileh ) ;
2007-10-20 21:05:18 +00:00
2010-02-15 19:52:40 +00:00
CommandCost ret = CheckRailSlope ( tileh , trackbit , TRACK_BIT_NONE , tile ) ;
2010-01-18 22:57:21 +00:00
if ( ret . Failed ( ) ) return ret ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( ret ) ;
2004-08-09 17:04:08 +00:00
2017-07-30 13:27:42 +00:00
ret = DoCommand ( tile , 0 , 0 , flags | DC_ALLOW_REMOVE_WATER , CMD_LANDSCAPE_CLEAR ) ;
2010-01-18 22:57:21 +00:00
if ( ret . Failed ( ) ) return ret ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( ret ) ;
2004-08-09 17:04:08 +00:00
2007-10-20 21:05:18 +00:00
if ( water_ground ) {
2009-11-07 22:47:54 +00:00
cost . AddCost ( - _price [ PR_CLEAR_WATER ] ) ;
cost . AddCost ( _price [ PR_CLEAR_ROUGH ] ) ;
2007-10-20 21:05:18 +00:00
}
if ( flags & DC_EXEC ) {
2008-09-30 20:39:50 +00:00
MakeRailNormal ( tile , _current_company , trackbit , railtype ) ;
2019-03-11 10:37:47 +00:00
if ( water_ground ) {
SetRailGroundType ( tile , RAIL_GROUND_WATER ) ;
2020-05-09 20:27:06 +00:00
if ( IsPossibleDockingTile ( tile ) ) CheckForDockingTile ( tile ) ;
2019-03-11 10:37:47 +00:00
}
2011-12-03 23:40:13 +00:00
Company : : Get ( _current_company ) - > infrastructure . rail [ railtype ] + + ;
DirtyCompanyInfrastructureWindows ( _current_company ) ;
2007-10-20 21:05:18 +00:00
}
2005-04-02 18:33:53 +00:00
break ;
2010-02-15 19:52:40 +00:00
}
2005-04-02 18:33:53 +00:00
}
2004-08-09 17:04:08 +00:00
2005-04-02 18:33:53 +00:00
if ( flags & DC_EXEC ) {
2004-08-09 17:04:08 +00:00
MarkTileDirtyByTile ( tile ) ;
2008-09-30 20:39:50 +00:00
AddTrackToSignalBuffer ( tile , track , _current_company ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2004-08-09 17:04:08 +00:00
}
2010-02-14 15:30:08 +00:00
cost . AddCost ( RailBuildCost ( railtype ) ) ;
2016-04-13 20:03:48 +00:00
_rail_track_endtile = tile ;
2010-02-14 15:30:08 +00:00
return cost ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Remove a single piece of track
2006-04-10 07:15:58 +00:00
* @ param tile tile to remove track from
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 unused
* @ param p2 rail orientation
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2004-08-09 17:04:08 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdRemoveSingleRail ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-04-17 13:31:41 +00:00
Track track = Extract < Track , 0 , 3 > ( p2 ) ;
2010-03-16 06:30:31 +00:00
CommandCost cost ( EXPENSES_CONSTRUCTION ) ;
2006-03-21 21:11:41 +00:00
bool crossing = false ;
2005-05-07 10:26:12 +00:00
2016-04-13 20:03:48 +00:00
_rail_track_endtile = INVALID_TILE ;
2010-04-17 13:31:41 +00:00
if ( ! ValParamTrackOrientation ( track ) ) return CMD_ERROR ;
2010-02-15 19:52:40 +00:00
TrackBits trackbit = TrackToTrackBits ( track ) ;
2004-08-09 17:04:08 +00:00
2008-01-16 22:26:45 +00:00
/* Need to read tile owner now because it may change when the rail is removed
2008-09-30 20:39:50 +00:00
* Also , in case of floods , _current_company ! = owner
2008-01-16 22:26:45 +00:00
* There may be invalid tiletype even in exec run ( when removing long track ) ,
* so do not call GetTileOwner ( tile ) in any case here */
Owner owner = INVALID_OWNER ;
2008-01-15 15:00:01 +00:00
2019-04-10 21:07:06 +00:00
Train * v = nullptr ;
2008-08-02 22:55:08 +00:00
2006-03-19 17:52:02 +00:00
switch ( GetTileType ( tile ) ) {
2007-07-29 23:42:59 +00:00
case MP_ROAD : {
2010-07-10 20:15:35 +00:00
if ( ! IsLevelCrossing ( tile ) | | GetCrossingRailBits ( tile ) ! = trackbit ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2010-03-07 20:44:05 +00:00
if ( _current_company ! = OWNER_WATER ) {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
2006-03-19 17:52:02 +00:00
}
2010-03-07 20:44:05 +00:00
2010-03-05 21:20:22 +00:00
if ( ! ( flags & DC_BANKRUPT ) ) {
CommandCost ret = EnsureNoVehicleOnGround ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
}
2004-08-09 17:04:08 +00:00
2010-03-16 06:30:31 +00:00
cost . AddCost ( RailClearCost ( GetRailType ( tile ) ) ) ;
2021-01-25 02:33:14 +00:00
if ( HasReservedTracks ( tile , trackbit ) ) {
v = GetTrainForReservation ( tile , track ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
2008-08-02 22:55:08 +00:00
}
2021-01-25 02:33:14 +00:00
}
if ( flags & DC_EXEC ) {
if ( v ! = nullptr ) FreeTrainTrackReservation ( v ) ;
2019-04-06 06:46:15 +00:00
2008-01-16 22:26:45 +00:00
owner = GetTileOwner ( tile ) ;
2011-12-03 23:40:13 +00:00
Company : : Get ( owner ) - > infrastructure . rail [ GetRailType ( tile ) ] - = LEVELCROSSING_TRACKBIT_FACTOR ;
DirtyCompanyInfrastructureWindows ( owner ) ;
2019-04-06 06:46:15 +00:00
MakeRoadNormal ( tile , GetCrossingRoadBits ( tile ) , GetRoadTypeRoad ( tile ) , GetRoadTypeTram ( tile ) , GetTownIndex ( tile ) , GetRoadOwner ( tile , RTT_ROAD ) , GetRoadOwner ( tile , RTT_TRAM ) ) ;
2010-04-24 13:39:11 +00:00
DeleteNewGRFInspectWindow ( GSF_RAILTYPES , tile ) ;
2020-10-26 22:17:25 +00:00
UpdateRoadCachedOneWayStatesAroundTile ( tile ) ;
2006-03-19 17:52:02 +00:00
}
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
break ;
2006-02-23 12:24:19 +00:00
}
2004-08-09 17:04:08 +00:00
2006-03-19 17:52:02 +00:00
case MP_RAILWAY : {
TrackBits present ;
2010-07-10 20:15:35 +00:00
/* There are no rails present at depots. */
if ( ! IsPlainRail ( tile ) ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2010-03-07 20:44:05 +00:00
if ( _current_company ! = OWNER_WATER ) {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
}
2010-03-07 18:29:53 +00:00
CommandCost ret = EnsureNoTrainOnTrack ( tile , track ) ;
if ( ret . Failed ( ) ) return ret ;
2006-03-19 17:52:02 +00:00
present = GetTrackBits ( tile ) ;
2010-07-10 20:15:35 +00:00
if ( ( present & trackbit ) = = 0 ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2006-03-21 21:11:41 +00:00
if ( present = = ( TRACK_BIT_X | TRACK_BIT_Y ) ) crossing = true ;
2004-08-09 17:04:08 +00:00
2018-12-21 03:27:58 +00:00
cost . AddCost ( RailClearCost ( GetTileRailTypeByTrackBit ( tile , trackbit ) ) ) ;
2010-03-16 06:30:31 +00:00
2005-06-21 19:45:05 +00:00
/* Charge extra to remove signals on the track, if they are there */
2010-07-24 10:14:39 +00:00
if ( HasSignalOnTrack ( tile , track ) ) {
2015-10-03 13:28:47 +00:00
if ( flags & DC_EXEC ) CheckRemoveSignal ( tile , track ) ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( DoCommand ( tile , track , 0 , flags , CMD_REMOVE_SIGNALS ) ) ;
2010-07-24 10:14:39 +00:00
}
2004-08-09 17:04:08 +00:00
2021-01-25 02:33:14 +00:00
if ( HasReservedTracks ( tile , trackbit ) ) {
v = GetTrainForReservation ( tile , track ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
2008-08-02 22:55:08 +00:00
}
2021-01-25 02:33:14 +00:00
}
if ( flags & DC_EXEC ) {
if ( v ! = nullptr ) FreeTrainTrackReservation ( v ) ;
2011-12-03 23:40:13 +00:00
2008-01-16 22:26:45 +00:00
owner = GetTileOwner ( tile ) ;
2011-12-03 23:40:13 +00:00
2018-12-21 03:27:58 +00:00
if ( present = = TRACK_BIT_HORZ | | present = = TRACK_BIT_VERT ) {
Company : : Get ( owner ) - > infrastructure . rail [ GetTileRailTypeByTrackBit ( tile , trackbit ) ] - - ;
present ^ = trackbit ;
SetRailType ( tile , GetTileRailTypeByTrackBit ( tile , present ) ) ;
} else {
/* Subtract old infrastructure count. */
uint pieces = CountBits ( present ) ;
if ( TracksOverlap ( present ) ) pieces * = pieces ;
Company : : Get ( owner ) - > infrastructure . rail [ GetRailType ( tile ) ] - = pieces ;
/* Add new infrastructure count. */
present ^ = trackbit ;
pieces = CountBits ( present ) ;
if ( TracksOverlap ( present ) ) pieces * = pieces ;
Company : : Get ( owner ) - > infrastructure . rail [ GetRailType ( tile ) ] + = pieces ;
}
2011-12-03 23:40:13 +00:00
DirtyCompanyInfrastructureWindows ( owner ) ;
2006-03-19 17:52:02 +00:00
if ( present = = 0 ) {
2011-11-04 10:22:27 +00:00
Slope tileh = GetTileSlope ( tile ) ;
2008-01-25 16:51:35 +00:00
/* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
if ( GetRailGroundType ( tile ) = = RAIL_GROUND_WATER & & IsSlopeWithOneCornerRaised ( tileh ) ) {
2019-03-11 10:37:47 +00:00
bool docking = IsDockingTile ( tile ) ;
2007-10-20 21:05:18 +00:00
MakeShore ( tile ) ;
2019-03-11 10:37:47 +00:00
SetDockingTile ( tile , docking ) ;
2007-10-20 21:05:18 +00:00
} else {
DoClearSquare ( tile ) ;
}
2010-04-24 13:39:11 +00:00
DeleteNewGRFInspectWindow ( GSF_RAILTYPES , tile ) ;
2006-03-19 17:52:02 +00:00
} else {
SetTrackBits ( tile , present ) ;
2009-07-21 22:37:10 +00:00
SetTrackReservation ( tile , GetRailReservationTrackBits ( tile ) & present ) ;
2006-03-19 17:52:02 +00:00
}
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
}
break ;
2006-03-19 17:52:02 +00:00
}
2005-10-22 06:39:32 +00:00
2018-07-03 18:09:10 +00:00
case MP_TUNNELBRIDGE : {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
if ( ! IsFlatRailBridgeHeadTile ( tile ) | | GetCustomBridgeHeadTrackBits ( tile ) = = DiagDirToDiagTrackBits ( GetTunnelBridgeDirection ( tile ) ) ) {
return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ; // just get appropriate error message
}
const TrackBits present = GetCustomBridgeHeadTrackBits ( tile ) ;
if ( ( present & trackbit ) = = 0 ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
if ( present = = ( TRACK_BIT_X | TRACK_BIT_Y ) ) crossing = true ;
const TrackBits future = present ^ trackbit ;
if ( ( GetAcrossBridgePossibleTrackBits ( tile ) & future ) = = 0 ) return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ; // just get appropriate error message
const TileIndex other_end = GetOtherTunnelBridgeEnd ( tile ) ;
2018-12-21 03:27:58 +00:00
if ( present = = TRACK_BIT_HORZ | | present = = TRACK_BIT_VERT ) {
ret = EnsureNoTrainOnTrack ( tile , track ) ;
} else {
ret = TunnelBridgeIsFree ( tile , other_end ) ;
}
2018-07-03 18:09:10 +00:00
if ( ret . Failed ( ) ) return ret ;
2021-01-25 02:33:14 +00:00
if ( HasReservedTracks ( tile , trackbit ) ) {
v = GetTrainForReservation ( tile , track ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
}
}
2018-12-21 03:27:58 +00:00
cost . AddCost ( RailClearCost ( GetTileRailTypeByTrackBit ( tile , trackbit ) ) ) ;
2018-07-03 18:09:10 +00:00
if ( flags & DC_EXEC ) {
2018-12-21 03:27:58 +00:00
SubtractRailTunnelBridgeInfrastructure ( tile , other_end ) ;
2018-07-03 18:09:10 +00:00
owner = GetTileOwner ( tile ) ;
2021-01-25 02:33:14 +00:00
if ( v ! = nullptr ) FreeTrainTrackReservation ( v ) ;
2018-07-03 18:09:10 +00:00
2020-04-29 16:56:26 +00:00
if ( future = = TRACK_BIT_HORZ | | future = = TRACK_BIT_VERT ) {
// Changing to two separate tracks with separate rail types
SetSecondaryRailType ( tile , GetRailType ( tile ) ) ;
}
2018-07-03 18:09:10 +00:00
SetCustomBridgeHeadTrackBits ( tile , future ) ;
2020-05-18 23:41:35 +00:00
SetTunnelBridgeGroundBits ( tile , IsRailCustomBridgeHead ( tile ) ? 2 : 0 ) ;
2018-12-21 03:27:58 +00:00
AddRailTunnelBridgeInfrastructure ( tile , other_end ) ;
2018-07-03 18:09:10 +00:00
DirtyCompanyInfrastructureWindows ( _current_company ) ;
}
break ;
}
2010-07-10 20:15:35 +00:00
default : return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2004-08-09 17:04:08 +00:00
}
2006-03-19 17:52:02 +00:00
if ( flags & DC_EXEC ) {
2008-01-16 22:26:45 +00:00
/* if we got that far, 'owner' variable is set correctly */
2009-05-17 01:00:56 +00:00
assert ( Company : : IsValidID ( owner ) ) ;
2008-01-16 22:26:45 +00:00
2006-03-19 17:52:02 +00:00
MarkTileDirtyByTile ( tile ) ;
2006-03-21 21:11:41 +00:00
if ( crossing ) {
/* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we
* are removing one of these pieces , we ' ll need to update signals for
* both directions explicitly , as after the track is removed it won ' t
* ' connect ' with the other piece . */
2008-01-16 01:18:15 +00:00
AddTrackToSignalBuffer ( tile , TRACK_X , owner ) ;
AddTrackToSignalBuffer ( tile , TRACK_Y , owner ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , TRACK_X ) ;
YapfNotifyTrackLayoutChange ( tile , TRACK_Y ) ;
2006-03-21 21:11:41 +00:00
} else {
2008-01-16 01:18:15 +00:00
AddTrackToSignalBuffer ( tile , track , owner ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2006-03-21 21:11:41 +00:00
}
2008-08-02 22:55:08 +00:00
2019-04-10 21:07:06 +00:00
if ( v ! = nullptr ) TryPathReserve ( v , true ) ;
2006-03-19 17:52:02 +00:00
}
2004-09-11 09:55:19 +00:00
2016-04-13 20:03:48 +00:00
_rail_track_endtile = tile ;
2005-06-21 19:45:05 +00:00
return cost ;
2004-08-09 17:04:08 +00:00
}
2006-04-10 12:36:04 +00:00
2007-10-20 21:05:18 +00:00
/**
* Called from water_cmd if a non - flat rail - tile gets flooded and should be converted to shore .
* The function floods the lower halftile , if the tile has a halftile foundation .
*
* @ param t The tile to flood .
2008-01-17 17:13:47 +00:00
* @ return true if something was flooded .
2007-10-20 21:05:18 +00:00
*/
2008-01-17 17:13:47 +00:00
bool FloodHalftile ( TileIndex t )
2007-10-20 21:05:18 +00:00
{
2018-07-26 18:13:35 +00:00
assert_tile ( IsPlainRailTile ( t ) , t ) ;
2009-05-15 16:07:36 +00:00
2008-01-17 17:13:47 +00:00
bool flooded = false ;
if ( GetRailGroundType ( t ) = = RAIL_GROUND_WATER ) return flooded ;
2007-10-20 21:05:18 +00:00
2011-11-04 10:22:27 +00:00
Slope tileh = GetTileSlope ( t ) ;
2007-10-20 21:05:18 +00:00
TrackBits rail_bits = GetTrackBits ( t ) ;
2008-01-25 15:47:58 +00:00
if ( IsSlopeWithOneCornerRaised ( tileh ) ) {
2007-10-20 21:05:18 +00:00
TrackBits lower_track = CornerToTrackBits ( OppositeCorner ( GetHighestSlopeCorner ( tileh ) ) ) ;
TrackBits to_remove = lower_track & rail_bits ;
if ( to_remove ! = 0 ) {
2019-04-22 08:10:04 +00:00
Backup < CompanyID > cur_company ( _current_company , OWNER_WATER , FILE_LINE ) ;
2010-05-31 20:22:57 +00:00
flooded = DoCommand ( t , 0 , FIND_FIRST_BIT ( to_remove ) , DC_EXEC , CMD_REMOVE_SINGLE_RAIL ) . Succeeded ( ) ;
cur_company . Restore ( ) ;
if ( ! flooded ) return flooded ; // not yet floodable
2007-10-20 21:05:18 +00:00
rail_bits = rail_bits & ~ to_remove ;
if ( rail_bits = = 0 ) {
MakeShore ( t ) ;
MarkTileDirtyByTile ( t ) ;
2008-01-17 17:13:47 +00:00
return flooded ;
2007-10-20 21:05:18 +00:00
}
}
if ( IsNonContinuousFoundation ( GetRailFoundation ( tileh , rail_bits ) ) ) {
2008-01-17 17:13:47 +00:00
flooded = true ;
2007-10-20 21:05:18 +00:00
SetRailGroundType ( t , RAIL_GROUND_WATER ) ;
MarkTileDirtyByTile ( t ) ;
}
2008-01-25 16:51:35 +00:00
} else {
/* Make shore on steep slopes and 'three-corners-raised'-slopes. */
2011-11-04 10:31:46 +00:00
if ( ApplyFoundationToSlope ( GetRailFoundation ( tileh , rail_bits ) , & tileh ) = = 0 ) {
2008-01-25 16:51:35 +00:00
if ( IsSteepSlope ( tileh ) | | IsSlopeWithThreeCornersRaised ( tileh ) ) {
flooded = true ;
SetRailGroundType ( t , RAIL_GROUND_WATER ) ;
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( t , VMDF_NOT_MAP_MODE ) ;
2008-01-25 16:51:35 +00:00
}
}
2007-10-20 21:05:18 +00:00
}
2008-01-17 17:13:47 +00:00
return flooded ;
2007-10-20 21:05:18 +00:00
}
2006-04-10 12:36:04 +00:00
static const TileIndexDiffC _trackdelta [ ] = {
{ - 1 , 0 } , { 0 , 1 } , { - 1 , 0 } , { 0 , 1 } , { 1 , 0 } , { 0 , 1 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 1 , 0 } , { 0 , - 1 } , { 0 , - 1 } , { 1 , 0 } , { 0 , - 1 } , { - 1 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 }
} ;
2007-06-18 10:48:15 +00:00
static CommandCost ValidateAutoDrag ( Trackdir * trackdir , TileIndex start , TileIndex end )
2005-01-30 15:57:38 +00:00
{
2006-04-10 12:36:04 +00:00
int x = TileX ( start ) ;
int y = TileY ( start ) ;
int ex = TileX ( end ) ;
int ey = TileY ( end ) ;
2004-08-09 17:04:08 +00:00
2007-01-10 18:56:51 +00:00
if ( ! ValParamTrackOrientation ( TrackdirToTrack ( * trackdir ) ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* calculate delta x,y from start to end tile */
2010-02-15 19:52:40 +00:00
int dx = ex - x ;
int dy = ey - y ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* calculate delta x,y for the first direction */
2010-02-15 19:52:40 +00:00
int trdx = _trackdelta [ * trackdir ] . x ;
int trdy = _trackdelta [ * trackdir ] . y ;
2005-01-30 15:57:38 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
if ( ! IsDiagonalTrackdir ( * trackdir ) ) {
2006-04-10 12:36:04 +00:00
trdx + = _trackdelta [ * trackdir ^ 1 ] . x ;
trdy + = _trackdelta [ * trackdir ^ 1 ] . y ;
2005-01-30 15:57:38 +00:00
}
2007-04-04 01:35:16 +00:00
/* validate the direction */
2010-07-24 10:14:39 +00:00
while ( ( trdx < = 0 & & dx > 0 ) | |
( trdx > = 0 & & dx < 0 ) | |
( trdy < = 0 & & dy > 0 ) | |
( trdy > = 0 & & dy < 0 ) ) {
2007-11-19 21:02:30 +00:00
if ( ! HasBit ( * trackdir , 3 ) ) { // first direction is invalid, try the other
2007-11-20 13:35:54 +00:00
SetBit ( * trackdir , 3 ) ; // reverse the direction
2005-01-30 15:57:38 +00:00
trdx = - trdx ;
trdy = - trdy ;
2006-06-27 21:25:53 +00:00
} else { // other direction is invalid too, invalid drag
2005-01-30 15:57:38 +00:00
return CMD_ERROR ;
2006-06-27 21:25:53 +00:00
}
2005-01-30 15:57:38 +00:00
}
2007-04-04 01:35:16 +00:00
/* (for diagonal tracks, this is already made sure of by above test), but:
* for non - diagonal tracks , check if the start and end tile are on 1 line */
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
if ( ! IsDiagonalTrackdir ( * trackdir ) ) {
2006-04-10 12:36:04 +00:00
trdx = _trackdelta [ * trackdir ] . x ;
trdy = _trackdelta [ * trackdir ] . y ;
2010-03-20 15:30:57 +00:00
if ( abs ( dx ) ! = abs ( dy ) & & abs ( dx ) + abs ( trdy ) ! = abs ( dy ) + abs ( trdx ) ) return CMD_ERROR ;
2005-01-30 15:57:38 +00:00
}
2007-06-18 19:53:50 +00:00
return CommandCost ( ) ;
2005-01-30 15:57:38 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Build or remove a stretch of railroad tracks .
2006-04-10 07:15:58 +00:00
* @ param tile start tile of drag
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 end tile of drag
* @ param p2 various bitstuffed elements
2018-07-22 23:05:23 +00:00
* - 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 ) .
2021-01-31 01:10:01 +00:00
* - p2 = ( bit 13 ) - 0 = error on signal in the way , 1 = auto remove signals when in the way
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-01-30 15:57:38 +00:00
*/
2009-02-09 21:20:05 +00:00
static CommandCost CmdRailTrackHelper ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-03-14 12:58:51 +00:00
CommandCost total_cost ( EXPENSES_CONSTRUCTION ) ;
2018-07-26 19:54:13 +00:00
RailType railtype = Extract < RailType , 0 , 6 > ( p2 ) ;
2018-07-22 23:05:23 +00:00
Track track = Extract < Track , 6 , 3 > ( p2 ) ;
bool remove = HasBit ( p2 , 9 ) ;
2018-07-26 19:54:13 +00:00
bool fail_if_obstacle = HasBit ( p2 , 10 ) ;
2018-12-19 18:51:15 +00:00
bool no_custom_bridge_heads = HasBit ( p2 , 11 ) ;
2018-12-21 03:27:58 +00:00
bool no_dual_rail_type = HasBit ( p2 , 12 ) ;
2021-01-31 01:10:01 +00:00
bool auto_remove_signals = HasBit ( p2 , 13 ) ;
2005-01-30 15:57:38 +00:00
2016-04-13 20:03:48 +00:00
_rail_track_endtile = INVALID_TILE ;
2014-01-26 14:54:34 +00:00
if ( ( ! remove & & ! ValParamRailtype ( railtype ) ) | | ! ValParamTrackOrientation ( track ) ) return CMD_ERROR ;
2006-01-30 17:18:45 +00:00
if ( p1 > = MapSize ( ) ) return CMD_ERROR ;
2009-02-21 18:10:08 +00:00
TileIndex end_tile = p1 ;
Trackdir trackdir = TrackToTrackdir ( track ) ;
2005-05-07 10:26:12 +00:00
2010-03-14 12:58:51 +00:00
CommandCost ret = ValidateAutoDrag ( & trackdir , tile , end_tile ) ;
if ( ret . Failed ( ) ) return ret ;
2004-09-11 09:55:19 +00:00
2010-03-14 15:42:26 +00:00
bool had_success = false ;
CommandCost last_error = CMD_ERROR ;
2006-02-01 07:36:15 +00:00
for ( ; ; ) {
2016-04-13 20:03:48 +00:00
TileIndex last_endtile = _rail_track_endtile ;
2021-01-31 01:10:01 +00:00
CommandCost ret = DoCommand ( tile , remove ? 0 : railtype , TrackdirToTrack ( trackdir ) | ( auto_remove_signals < < 3 ) | ( no_custom_bridge_heads ? 1 < < 4 : 0 ) | ( no_dual_rail_type ? 1 < < 5 : 0 ) , flags , remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL ) ;
2004-08-09 17:04:08 +00:00
2010-01-18 22:57:21 +00:00
if ( ret . Failed ( ) ) {
2010-03-14 15:42:26 +00:00
last_error = ret ;
2016-04-13 20:03:48 +00:00
if ( _rail_track_endtile = = INVALID_TILE ) _rail_track_endtile = last_endtile ;
2010-03-14 15:42:26 +00:00
if ( last_error . GetErrorMessage ( ) ! = STR_ERROR_ALREADY_BUILT & & ! remove ) {
2016-04-01 19:27:19 +00:00
if ( fail_if_obstacle ) return last_error ;
2010-02-02 22:27:03 +00:00
break ;
}
2010-07-09 16:43:00 +00:00
/* Ownership errors are more important. */
if ( last_error . GetErrorMessage ( ) = = STR_ERROR_OWNED_BY & & remove ) break ;
2006-06-27 21:25:53 +00:00
} else {
2010-03-14 15:42:26 +00:00
had_success = true ;
2007-06-18 19:53:50 +00:00
total_cost . AddCost ( ret ) ;
2006-06-27 21:25:53 +00:00
}
2004-08-09 17:04:08 +00:00
2006-04-10 12:36:04 +00:00
if ( tile = = end_tile ) break ;
2004-08-09 17:04:08 +00:00
2006-04-10 12:36:04 +00:00
tile + = ToTileIndexDiff ( _trackdelta [ trackdir ] ) ;
2004-09-11 09:55:19 +00:00
2007-04-04 01:35:16 +00:00
/* toggle railbit for the non-diagonal tracks */
2007-11-20 14:11:19 +00:00
if ( ! IsDiagonalTrackdir ( trackdir ) ) ToggleBit ( trackdir , 0 ) ;
2004-09-11 09:55:19 +00:00
}
2004-08-09 17:04:08 +00:00
2010-03-14 15:42:26 +00:00
if ( had_success ) return total_cost ;
return last_error ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Build rail on a stretch of track .
2005-05-12 23:46:01 +00:00
* Stub for the unified rail builder / remover
2007-04-17 21:09:38 +00:00
* @ param tile start tile of drag
* @ param flags operation to perform
* @ param p1 end tile of drag
* @ param p2 various bitstuffed elements
2018-07-22 23:05:23 +00:00
* - 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
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 23:46:01 +00:00
* @ see CmdRailTrackHelper
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuildRailroadTrack ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2005-01-30 15:57:38 +00:00
{
2018-07-22 23:05:23 +00:00
return CmdRailTrackHelper ( tile , flags , p1 , ClrBit ( p2 , 9 ) , text ) ;
2005-01-30 15:57:38 +00:00
}
2004-08-09 17:04:08 +00:00
2010-08-01 19:22:34 +00:00
/**
* Build rail on a stretch of track .
2005-05-12 23:46:01 +00:00
* Stub for the unified rail builder / remover
2007-04-17 21:09:38 +00:00
* @ param tile start tile of drag
* @ param flags operation to perform
* @ param p1 end tile of drag
* @ param p2 various bitstuffed elements
2018-07-22 23:05:23 +00:00
* - 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
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 23:46:01 +00:00
* @ see CmdRailTrackHelper
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdRemoveRailroadTrack ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2018-07-22 23:05:23 +00:00
return CmdRailTrackHelper ( tile , flags , p1 , SetBit ( p2 , 9 ) , text ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Build a train depot
2006-04-10 07:15:58 +00:00
* @ param tile position of the train depot
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 rail type
2007-02-24 09:42:39 +00:00
* @ param p2 bit 0. .1 entrance direction ( DiagDirection )
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-07-16 23:47:37 +00:00
*
* @ todo When checking for the tile slope ,
2013-01-08 22:46:42 +00:00
* distinguish between " Flat land required " and " land sloped in wrong direction "
2004-08-09 17:04:08 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuildTrainDepot ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2005-05-07 10:26:12 +00:00
/* check railtype and valid direction for depot (0 through 3), 4 in total */
2018-07-22 23:05:23 +00:00
RailType railtype = Extract < RailType , 0 , 6 > ( p1 ) ;
2010-04-17 13:31:41 +00:00
if ( ! ValParamRailtype ( railtype ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2011-11-04 10:22:27 +00:00
Slope tileh = GetTileSlope ( tile ) ;
2005-07-16 23:47:37 +00:00
2010-04-13 17:29:19 +00:00
DiagDirection dir = Extract < DiagDirection , 0 , 2 > ( p2 ) ;
2007-02-24 09:42:39 +00:00
2018-08-11 00:32:32 +00:00
CommandCost cost ( EXPENSES_CONSTRUCTION ) ;
2005-07-16 23:47:37 +00:00
/* Prohibit construction if
2006-09-04 20:40:33 +00:00
* The tile is non - flat AND
2009-01-12 19:49:23 +00:00
* 1 ) build - on - slopes is disabled
* 2 ) the tile is steep i . e . spans two height levels
* 3 ) the exit points in the wrong direction
2006-09-04 20:40:33 +00:00
*/
2005-07-16 23:47:37 +00:00
2018-08-11 00:32:32 +00:00
if ( tileh ! = SLOPE_FLAT ) {
if ( ! _settings_game . construction . build_on_slopes | | ! CanBuildDepotByTileh ( dir , tileh ) ) {
return_cmd_error ( STR_ERROR_FLAT_LAND_REQUIRED ) ;
}
cost . AddCost ( _price [ PR_BUILD_FOUNDATION ] ) ;
2004-08-09 17:04:08 +00:00
}
2018-08-11 00:32:32 +00:00
cost . AddCost ( DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ) ;
2010-03-14 12:58:51 +00:00
if ( cost . Failed ( ) ) return cost ;
2004-08-09 17:04:08 +00:00
2014-09-21 11:24:51 +00:00
if ( IsBridgeAbove ( tile ) ) return_cmd_error ( STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST ) ;
2006-12-27 12:38:02 +00:00
2008-04-23 20:56:08 +00:00
if ( ! Depot : : CanAllocateItem ( ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2008-04-23 20:56:08 +00:00
Depot * d = new Depot ( tile ) ;
2010-06-20 19:13:02 +00:00
d - > build_date = _date ;
2004-08-09 17:04:08 +00:00
2010-04-17 13:31:41 +00:00
MakeRailDepot ( tile , _current_company , d - > index , dir , railtype ) ;
2009-09-10 14:33:07 +00:00
MarkTileDirtyByTile ( tile ) ;
2010-05-12 19:21:00 +00:00
MakeDefaultName ( d ) ;
2009-09-10 14:33:07 +00:00
2011-12-03 23:40:13 +00:00
Company : : Get ( _current_company ) - > infrastructure . rail [ railtype ] + + ;
DirtyCompanyInfrastructureWindows ( _current_company ) ;
2008-09-30 20:39:50 +00:00
AddSideToSignalBuffer ( tile , INVALID_DIAGDIR , _current_company ) ;
2008-05-14 18:31:21 +00:00
YapfNotifyTrackLayoutChange ( tile , DiagDirToDiagTrack ( dir ) ) ;
2004-08-09 17:04:08 +00:00
}
2010-02-14 15:30:08 +00:00
cost . AddCost ( _price [ PR_BUILD_DEPOT_TRAIN ] ) ;
2010-06-04 21:00:17 +00:00
cost . AddCost ( RailBuildCost ( railtype ) ) ;
2010-02-14 15:30:08 +00:00
return cost ;
2004-08-09 17:04:08 +00:00
}
2016-09-18 18:48:52 +00:00
static void ClearBridgeTunnelSignalSimulation ( TileIndex entrance , TileIndex exit )
{
if ( IsBridge ( entrance ) ) ClearBridgeEntranceSimulatedSignals ( entrance ) ;
ClrTunnelBridgeSignalSimulationEntrance ( entrance ) ;
ClrTunnelBridgeSignalSimulationExit ( exit ) ;
}
static void SetupBridgeTunnelSignalSimulation ( TileIndex entrance , TileIndex exit )
{
SetTunnelBridgeSignalSimulationEntrance ( entrance ) ;
2018-06-17 02:29:47 +00:00
SetTunnelBridgeEntranceSignalState ( entrance , SIGNAL_STATE_GREEN ) ;
2016-09-18 18:48:52 +00:00
SetTunnelBridgeSignalSimulationExit ( exit ) ;
}
2019-06-08 16:12:51 +00:00
static void ReReserveTrainPath ( Train * v )
{
/* Extend the train's path if it's not stopped or loading, or not at a safe position. */
if ( ! ( ( ( v - > vehstatus & VS_STOPPED ) & & v - > cur_speed = = 0 ) | | v - > current_order . IsType ( OT_LOADING ) ) | |
! IsSafeWaitingPosition ( v , v - > tile , v - > GetVehicleTrackdir ( ) , true , _settings_game . pf . forbid_90_deg ) ) {
TryPathReserve ( v , true ) ;
}
}
2010-08-01 19:22:34 +00:00
/**
* Build signals , alternate between double / single , signal / semaphore ,
2007-01-19 00:01:52 +00:00
* pre / exit / combo - signals , and what - else not . If the rail piece does not
* have any signals , bit 4 ( cycle signal - type ) is ignored
2006-04-10 07:15:58 +00:00
* @ param tile tile where to build the signals
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 various bitstuffed elements
2007-01-19 17:44:11 +00:00
* - p1 = ( bit 0 - 2 ) - track - orientation , valid values : 0 - 5 ( Track enum )
2007-12-01 21:40:18 +00:00
* - p1 = ( bit 3 ) - 1 = override signal / semaphore , or pre / exit / combo signal or ( for bit 7 ) toggle variant ( CTRL - toggle )
2007-01-19 17:44:11 +00:00
* - p1 = ( bit 4 ) - 0 = signals , 1 = semaphores
2008-08-02 22:49:23 +00:00
* - 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
2014-01-14 20:32:07 +00:00
* - p1 = ( bit 9 - 14 ) - cycle through which signal set ?
2008-09-20 17:43:06 +00:00
* - p1 = ( bit 15 - 16 ) - cycle the signal direction this many times
2009-02-24 19:15:23 +00:00
* - p1 = ( bit 17 ) - 1 = don ' t modify an existing signal but don ' t fail either , 0 = always set new signal type
2018-06-17 03:27:03 +00:00
* - p1 = ( bit 18 ) - permit creation of / conversion to bidirectionally signalled bridges / tunnels
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
* @ param p2 used for CmdBuildManySignals ( ) to copy direction of first signal
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
* @ todo p2 should be replaced by two bits for " along " and " against " the track .
2004-08-15 20:23:42 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuildSingleSignal ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-04-17 13:31:41 +00:00
Track track = Extract < Track , 0 , 3 > ( p1 ) ;
2007-12-01 21:40:18 +00:00
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
2010-04-17 13:31:41 +00:00
SignalType sigtype = Extract < SignalType , 5 , 3 > ( p1 ) ; // the signal type of the new signal
2008-08-02 22:49:23 +00:00
bool convert_signal = HasBit ( p1 , 8 ) ; // convert button pressed
2008-09-20 17:43:06 +00:00
uint num_dir_cycle = GB ( p1 , 15 , 2 ) ;
2004-09-11 09:55:19 +00:00
2014-01-14 20:32:07 +00:00
uint which_signals = GB ( p1 , 9 , 6 ) ;
2008-08-02 22:49:23 +00:00
2021-01-25 02:33:14 +00:00
if ( _settings_game . vehicle . train_braking_model = = TBM_REALISTIC & & IsSignalTypeUnsuitableForRealisticBraking ( sigtype ) ) return CMD_ERROR ;
2015-08-01 19:24:07 +00:00
/* You can only build signals on plain rail tiles or tunnel/bridges, and the selected track must exist */
if ( IsTileType ( tile , MP_TUNNELBRIDGE ) ) {
if ( GetTunnelBridgeTransportType ( tile ) ! = TRANSPORT_RAIL ) return CMD_ERROR ;
2018-07-08 22:04:30 +00:00
if ( ! ValParamTrackOrientation ( track ) | | ! IsTrackAcrossTunnelBridge ( tile , track ) ) {
return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
}
2015-08-01 19:24:07 +00:00
CommandCost ret = EnsureNoTrainOnTrack ( GetOtherTunnelBridgeEnd ( tile ) , track ) ;
2015-08-16 16:31:34 +00:00
if ( ret . Failed ( ) ) return ret ;
ret = EnsureNoTrainOnTrack ( tile , track ) ;
if ( ret . Failed ( ) ) return ret ;
2015-08-01 19:24:07 +00:00
} else if ( ! ValParamTrackOrientation ( track ) | | ! IsPlainRailTile ( tile ) | | ! HasTrack ( tile , track ) ) {
2010-07-10 20:15:35 +00:00
return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2009-05-18 01:26:23 +00:00
}
2005-05-07 10:26:12 +00:00
/* Protect against invalid signal copying */
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
if ( p2 ! = 0 & & ( p2 & SignalOnTrack ( track ) ) = = 0 ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2012-06-23 20:18:29 +00:00
CommandCost ret = CheckTileOwnership ( tile ) ;
2010-03-07 20:44:05 +00:00
if ( ret . Failed ( ) ) return ret ;
2004-08-09 17:04:08 +00:00
2015-08-01 19:24:07 +00:00
CommandCost cost ;
/* handle signals simulation on tunnel/bridge. */
if ( IsTileType ( tile , MP_TUNNELBRIDGE ) ) {
TileIndex tile_exit = GetOtherTunnelBridgeEnd ( tile ) ;
2018-08-04 16:40:11 +00:00
if ( TracksOverlap ( GetTunnelBridgeTrackBits ( tile ) ) | | TracksOverlap ( GetTunnelBridgeTrackBits ( tile_exit ) ) ) return_cmd_error ( STR_ERROR_NO_SUITABLE_RAILROAD_TRACK ) ;
bool bidirectional = HasBit ( p1 , 18 ) & & ( sigtype = = SIGTYPE_PBS ) ;
2015-08-01 19:24:07 +00:00
cost = CommandCost ( ) ;
2016-02-20 22:13:30 +00:00
bool flip_variant = false ;
2016-02-20 23:26:16 +00:00
bool is_pbs = ( sigtype = = SIGTYPE_PBS ) | | ( sigtype = = SIGTYPE_PBS_ONEWAY ) ;
2018-07-08 22:04:30 +00:00
Trackdir entrance_td = TrackExitdirToTrackdir ( track , GetTunnelBridgeDirection ( tile ) ) ;
bool p2_signal_in = p2 & SignalAlongTrackdir ( entrance_td ) ;
bool p2_signal_out = p2 & SignalAgainstTrackdir ( entrance_td ) ;
bool p2_active = p2_signal_in | | p2_signal_out ;
2016-09-18 13:23:02 +00:00
if ( ! IsTunnelBridgeWithSignalSimulation ( tile ) ) { // toggle signal zero costs.
2016-02-20 22:13:30 +00:00
if ( convert_signal ) return_cmd_error ( STR_ERROR_THERE_ARE_NO_SIGNALS ) ;
2018-07-08 22:04:30 +00:00
if ( ! ( p2_signal_in & & p2_signal_out ) ) cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_SIGNALS ] * ( ( GetTunnelBridgeLength ( tile , tile_exit ) + 4 ) > > 2 ) * ( bidirectional ? 2 : 1 ) ) ; // minimal 1
2016-02-20 22:13:30 +00:00
} else {
if ( HasBit ( p1 , 17 ) ) return CommandCost ( ) ;
2018-06-17 03:27:03 +00:00
bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional ( tile ) ;
bool will_be_bidi = is_bidi ;
2018-07-08 22:04:30 +00:00
if ( ! p2_active ) {
2018-06-17 03:27:03 +00:00
if ( convert_signal ) {
will_be_bidi = bidirectional & & ! ctrl_pressed ;
} else if ( ctrl_pressed ) {
will_be_bidi = false ;
}
} else if ( ! is_pbs ) {
will_be_bidi = false ;
}
2021-02-04 12:14:54 +00:00
if ( ( p2_active & & ( sigvar = = SIG_SEMAPHORE ) ! = IsTunnelBridgeSemaphore ( tile ) ) | |
2016-02-20 22:13:30 +00:00
( convert_signal & & ( ctrl_pressed | | ( sigvar = = SIG_SEMAPHORE ) ! = IsTunnelBridgeSemaphore ( tile ) ) ) ) {
flip_variant = true ;
2018-06-17 03:27:03 +00:00
cost = CommandCost ( EXPENSES_CONSTRUCTION , ( ( _price [ PR_BUILD_SIGNALS ] * ( will_be_bidi ? 2 : 1 ) ) + ( _price [ PR_CLEAR_SIGNALS ] * ( is_bidi ? 2 : 1 ) ) ) *
2016-02-20 22:13:30 +00:00
( ( GetTunnelBridgeLength ( tile , tile_exit ) + 4 ) > > 2 ) ) ; // minimal 1
2018-06-17 03:27:03 +00:00
} else if ( is_bidi ! = will_be_bidi ) {
cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ will_be_bidi ? PR_BUILD_SIGNALS : PR_CLEAR_SIGNALS ] * ( ( GetTunnelBridgeLength ( tile , tile_exit ) + 4 ) > > 2 ) ) ; // minimal 1
2016-02-20 22:13:30 +00:00
}
2015-08-01 19:24:07 +00:00
}
2018-06-17 03:27:03 +00:00
auto remove_pbs_bidi = [ & ] ( ) {
if ( IsTunnelBridgeSignalSimulationBidirectional ( tile ) ) {
ClrTunnelBridgeSignalSimulationExit ( tile ) ;
ClrTunnelBridgeSignalSimulationEntrance ( tile_exit ) ;
}
} ;
auto set_bidi = [ & ] ( TileIndex t ) {
SetTunnelBridgeSignalSimulationEntrance ( t ) ;
SetTunnelBridgeEntranceSignalState ( t , SIGNAL_STATE_GREEN ) ;
SetTunnelBridgeSignalSimulationExit ( t ) ;
} ;
2021-01-25 02:33:14 +00:00
if ( _settings_game . vehicle . train_braking_model = = TBM_REALISTIC ) {
for ( TileIndex t : { tile , tile_exit } ) {
if ( HasAcrossTunnelBridgeReservation ( t ) ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( t , FindFirstTrack ( GetAcrossTunnelBridgeReservationTrackBits ( t ) ) ) ;
if ( ret . Failed ( ) ) return ret ;
}
}
}
2015-08-01 19:24:07 +00:00
if ( flags & DC_EXEC ) {
2017-01-30 21:37:17 +00:00
Company * const c = Company : : Get ( GetTileOwner ( tile ) ) ;
2021-01-25 02:33:14 +00:00
std : : vector < Train * > re_reserve_trains ;
2019-06-08 16:12:51 +00:00
if ( IsTunnelBridgeWithSignalSimulation ( tile ) ) {
c - > infrastructure . signal - = GetTunnelBridgeSignalSimulationSignalCount ( tile , tile_exit ) ;
} else {
2021-01-25 02:33:14 +00:00
for ( TileIndex t : { tile , tile_exit } ) {
if ( HasAcrossTunnelBridgeReservation ( t ) ) {
Train * re_reserve_train = GetTrainForReservation ( t , FindFirstTrack ( GetAcrossTunnelBridgeReservationTrackBits ( t ) ) ) ;
if ( re_reserve_train ! = nullptr ) {
FreeTrainTrackReservation ( re_reserve_train ) ;
re_reserve_trains . push_back ( re_reserve_train ) ;
}
}
2019-06-08 16:12:51 +00:00
}
}
2018-07-08 22:04:30 +00:00
if ( ! p2_active & & IsTunnelBridgeWithSignalSimulation ( tile ) ) { // Toggle signal if already signals present.
2016-02-20 22:13:30 +00:00
if ( convert_signal ) {
if ( flip_variant ) {
SetTunnelBridgeSemaphore ( tile , ! IsTunnelBridgeSemaphore ( tile ) ) ;
2016-02-20 23:26:16 +00:00
SetTunnelBridgeSemaphore ( tile_exit , IsTunnelBridgeSemaphore ( tile ) ) ;
2016-02-20 22:13:30 +00:00
}
2016-02-20 23:26:16 +00:00
if ( ! ctrl_pressed ) {
SetTunnelBridgePBS ( tile , is_pbs ) ;
SetTunnelBridgePBS ( tile_exit , is_pbs ) ;
2018-06-17 03:27:03 +00:00
if ( bidirectional ) {
set_bidi ( tile ) ;
set_bidi ( tile_exit ) ;
} else {
remove_pbs_bidi ( ) ;
}
2016-02-20 23:26:16 +00:00
}
} else if ( ctrl_pressed ) {
SetTunnelBridgePBS ( tile , ! IsTunnelBridgePBS ( tile ) ) ;
SetTunnelBridgePBS ( tile_exit , IsTunnelBridgePBS ( tile ) ) ;
2018-06-17 03:27:03 +00:00
if ( ! IsTunnelBridgePBS ( tile ) ) remove_pbs_bidi ( ) ;
} else if ( ! IsTunnelBridgeSignalSimulationBidirectional ( tile ) ) {
2016-09-18 13:23:02 +00:00
if ( IsTunnelBridgeSignalSimulationEntrance ( tile ) ) {
2016-09-18 18:48:52 +00:00
ClearBridgeTunnelSignalSimulation ( tile , tile_exit ) ;
SetupBridgeTunnelSignalSimulation ( tile_exit , tile ) ;
2016-02-20 22:13:30 +00:00
} else {
2016-09-18 18:48:52 +00:00
ClearBridgeTunnelSignalSimulation ( tile_exit , tile ) ;
SetupBridgeTunnelSignalSimulation ( tile , tile_exit ) ;
2016-02-20 22:13:30 +00:00
}
2015-08-01 19:26:41 +00:00
}
2015-10-31 01:30:08 +00:00
} else {
2015-08-01 19:24:07 +00:00
/* Create one direction tunnel/bridge if required. */
2018-07-08 22:04:30 +00:00
if ( ! p2_active ) {
2018-06-17 03:27:03 +00:00
if ( bidirectional ) {
set_bidi ( tile ) ;
set_bidi ( tile_exit ) ;
} else {
SetupBridgeTunnelSignalSimulation ( tile , tile_exit ) ;
}
2018-07-08 22:04:30 +00:00
} else if ( p2_signal_in ! = p2_signal_out ) {
2015-08-01 19:24:07 +00:00
/* If signal only on one side build accoringly one-way tunnel/bridge. */
2018-07-08 22:04:30 +00:00
if ( p2_signal_in ) {
2016-09-18 18:48:52 +00:00
ClearBridgeTunnelSignalSimulation ( tile_exit , tile ) ;
SetupBridgeTunnelSignalSimulation ( tile , tile_exit ) ;
2015-08-01 19:24:07 +00:00
} else {
2016-09-18 18:48:52 +00:00
ClearBridgeTunnelSignalSimulation ( tile , tile_exit ) ;
SetupBridgeTunnelSignalSimulation ( tile_exit , tile ) ;
2015-08-01 19:24:07 +00:00
}
2015-08-01 19:26:41 +00:00
}
2018-07-08 22:04:30 +00:00
if ( ! ( p2_signal_in & & p2_signal_out ) ) {
2016-04-01 20:17:33 +00:00
SetTunnelBridgeSemaphore ( tile , sigvar = = SIG_SEMAPHORE ) ;
SetTunnelBridgeSemaphore ( tile_exit , sigvar = = SIG_SEMAPHORE ) ;
SetTunnelBridgePBS ( tile , is_pbs ) ;
SetTunnelBridgePBS ( tile_exit , is_pbs ) ;
2018-06-17 03:27:03 +00:00
if ( ! IsTunnelBridgePBS ( tile ) ) remove_pbs_bidi ( ) ;
2016-04-01 20:17:33 +00:00
}
2015-08-01 19:24:07 +00:00
}
2021-01-25 02:33:14 +00:00
if ( IsTunnelBridgeSignalSimulationExit ( tile ) & & IsTunnelBridgeEffectivelyPBS ( tile ) & & ! HasAcrossTunnelBridgeReservation ( tile ) ) SetTunnelBridgeExitSignalState ( tile , SIGNAL_STATE_RED ) ;
if ( IsTunnelBridgeSignalSimulationExit ( tile_exit ) & & IsTunnelBridgeEffectivelyPBS ( tile_exit ) & & ! HasAcrossTunnelBridgeReservation ( tile_exit ) ) SetTunnelBridgeExitSignalState ( tile_exit , SIGNAL_STATE_RED ) ;
2015-11-01 14:05:22 +00:00
MarkBridgeOrTunnelDirty ( tile ) ;
2015-10-31 01:30:08 +00:00
AddSideToSignalBuffer ( tile , INVALID_DIAGDIR , GetTileOwner ( tile ) ) ;
2015-11-01 14:05:50 +00:00
AddSideToSignalBuffer ( tile_exit , INVALID_DIAGDIR , GetTileOwner ( tile ) ) ;
2015-08-01 19:24:07 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2015-11-01 14:05:50 +00:00
YapfNotifyTrackLayoutChange ( tile_exit , track ) ;
2017-01-30 21:37:17 +00:00
if ( IsTunnelBridgeWithSignalSimulation ( tile ) ) c - > infrastructure . signal + = GetTunnelBridgeSignalSimulationSignalCount ( tile , tile_exit ) ;
DirtyCompanyInfrastructureWindows ( GetTileOwner ( tile ) ) ;
2021-01-25 02:33:14 +00:00
for ( Train * re_reserve_train : re_reserve_trains ) {
2019-06-08 16:12:51 +00:00
ReReserveTrainPath ( re_reserve_train ) ;
}
2015-08-01 19:24:07 +00:00
}
return cost ;
}
2013-03-11 18:01:23 +00:00
/* 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 ) ;
2004-08-09 17:04:08 +00:00
2009-02-24 19:15:23 +00:00
/* In case we don't want to change an existing signal, return without error. */
if ( HasBit ( p1 , 17 ) & & HasSignalOnTrack ( tile , track ) ) return CommandCost ( ) ;
2007-12-01 21:40:18 +00:00
/* you can not convert a signal if no signal is on track */
2010-07-10 20:18:59 +00:00
if ( convert_signal & & ! HasSignalOnTrack ( tile , track ) ) return_cmd_error ( STR_ERROR_THERE_ARE_NO_SIGNALS ) ;
2007-12-01 21:40:18 +00:00
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
if ( ! HasSignalOnTrack ( tile , track ) ) {
2007-04-04 01:35:16 +00:00
/* build new signals */
2009-11-07 22:47:54 +00:00
cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_SIGNALS ] ) ;
2005-01-19 13:31:46 +00:00
} else {
2007-05-31 21:21:04 +00:00
if ( p2 ! = 0 & & sigvar ! = GetSignalVariant ( tile , track ) ) {
2007-04-04 01:35:16 +00:00
/* convert signals <-> semaphores */
2009-11-07 22:47:54 +00:00
cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_SIGNALS ] + _price [ PR_CLEAR_SIGNALS ] ) ;
2007-12-01 21:40:18 +00:00
} else if ( convert_signal ) {
/* convert button pressed */
if ( ctrl_pressed | | GetSignalVariant ( tile , track ) ! = sigvar ) {
/* convert electric <-> semaphore */
2009-11-07 22:47:54 +00:00
cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_SIGNALS ] + _price [ PR_CLEAR_SIGNALS ] ) ;
2007-12-01 21:40:18 +00:00
} else {
/* it is free to change signal type: normal-pre-exit-combo */
cost = CommandCost ( ) ;
}
2005-01-22 14:52:20 +00:00
} else {
2007-04-06 04:10:19 +00:00
/* it is free to change orientation/pre-exit-combo signals */
2007-06-18 19:53:50 +00:00
cost = CommandCost ( ) ;
2005-01-22 14:52:20 +00:00
}
2004-08-09 17:04:08 +00:00
}
2021-01-25 02:33:14 +00:00
Train * v = nullptr ;
/* The new/changed signal could block our path. As this can lead to
* stale reservations , we clear the path reservation here and try
* to redo it later on . */
if ( HasReservedTracks ( tile , TrackToTrackBits ( track ) ) ) {
v = GetTrainForReservation ( tile , track ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
if ( flags & DC_EXEC ) FreeTrainTrackReservation ( v ) ;
2008-08-03 11:28:35 +00:00
}
2021-01-25 02:33:14 +00:00
}
2008-08-03 11:28:35 +00:00
2021-01-25 02:33:14 +00:00
if ( flags & DC_EXEC ) {
2006-07-27 05:30:53 +00:00
if ( ! HasSignals ( tile ) ) {
2007-04-04 01:35:16 +00:00
/* there are no signals at all on this tile yet */
2007-02-27 23:36:28 +00:00
SetHasSignals ( tile , true ) ;
2007-05-30 13:33:19 +00:00
SetSignalStates ( tile , 0xF ) ; // all signals are on
SetPresentSignals ( tile , 0 ) ; // no signals built by default
2007-12-01 21:40:18 +00:00
SetSignalType ( tile , track , sigtype ) ;
2007-05-31 21:21:04 +00:00
SetSignalVariant ( tile , track , sigvar ) ;
2004-08-09 17:04:08 +00:00
}
2011-12-03 23:40:13 +00:00
/* Subtract old signal infrastructure count. */
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . signal - = CountBits ( GetPresentSignals ( tile ) ) ;
2005-01-22 14:52:20 +00:00
if ( p2 = = 0 ) {
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
if ( ! HasSignalOnTrack ( tile , track ) ) {
2007-04-04 01:35:16 +00:00
/* build new signals */
2021-01-25 02:33:14 +00:00
SetPresentSignals ( tile , GetPresentSignals ( tile ) | ( ( IsPbsSignal ( sigtype ) | | _settings_game . vehicle . train_braking_model = = TBM_REALISTIC ) ? KillFirstBit ( SignalOnTrack ( track ) ) : SignalOnTrack ( track ) ) ) ;
2007-12-01 21:40:18 +00:00
SetSignalType ( tile , track , sigtype ) ;
2007-05-31 21:21:04 +00:00
SetSignalVariant ( tile , track , sigvar ) ;
2008-09-20 17:43:06 +00:00
while ( num_dir_cycle - - > 0 ) CycleSignalSide ( tile , track ) ;
2005-01-22 14:52:20 +00:00
} else {
2007-12-01 21:40:18 +00:00
if ( convert_signal ) {
/* convert signal button pressed */
if ( ctrl_pressed ) {
2013-01-08 22:46:42 +00:00
/* toggle the present signal variant: SIG_ELECTRIC <-> SIG_SEMAPHORE */
2007-12-01 21:40:18 +00:00
SetSignalVariant ( tile , track , ( GetSignalVariant ( tile , track ) = = SIG_ELECTRIC ) ? SIG_SEMAPHORE : SIG_ELECTRIC ) ;
2008-08-22 22:19:23 +00:00
/* Query current signal type so the check for PBS signals below works. */
sigtype = GetSignalType ( tile , track ) ;
2007-12-01 21:40:18 +00:00
} else {
/* convert the present signal to the chosen type and variant */
2021-01-25 02:33:14 +00:00
if ( IsPresignalProgrammable ( tile , track ) ) {
2014-01-14 20:32:07 +00:00
FreeSignalProgram ( SignalReference ( tile , track ) ) ;
2021-01-25 02:33:14 +00:00
}
2007-12-01 21:40:18 +00:00
SetSignalType ( tile , track , sigtype ) ;
SetSignalVariant ( tile , track , sigvar ) ;
2008-08-02 22:50:04 +00:00
if ( IsPbsSignal ( sigtype ) & & ( GetPresentSignals ( tile ) & SignalOnTrack ( track ) ) = = SignalOnTrack ( track ) ) {
SetPresentSignals ( tile , ( GetPresentSignals ( tile ) & ~ SignalOnTrack ( track ) ) | KillFirstBit ( SignalOnTrack ( track ) ) ) ;
}
2007-12-01 21:40:18 +00:00
}
} else if ( ctrl_pressed ) {
2014-01-14 20:32:07 +00:00
/* cycle through signal types */
sigtype = ( SignalType ) ( GetSignalType ( tile , track ) ) ;
if ( IsProgrammableSignal ( sigtype ) )
FreeSignalProgram ( SignalReference ( tile , track ) ) ;
2008-08-02 22:49:23 +00:00
2021-01-25 02:33:14 +00:00
do {
sigtype = NextSignalType ( sigtype , which_signals ) ;
} while ( _settings_game . vehicle . train_braking_model = = TBM_REALISTIC & & IsSignalTypeUnsuitableForRealisticBraking ( sigtype ) ) ;
2006-03-17 06:26:37 +00:00
2008-08-02 22:49:23 +00:00
SetSignalType ( tile , track , sigtype ) ;
2008-08-02 22:50:04 +00:00
if ( IsPbsSignal ( sigtype ) & & ( GetPresentSignals ( tile ) & SignalOnTrack ( track ) ) = = SignalOnTrack ( track ) ) {
SetPresentSignals ( tile , ( GetPresentSignals ( tile ) & ~ SignalOnTrack ( track ) ) | KillFirstBit ( SignalOnTrack ( track ) ) ) ;
}
2005-01-22 14:52:20 +00:00
} else {
2019-12-05 18:13:35 +00:00
/* programmable pre-signal dependencies are invalidated when the signal direction is changed */
2016-01-31 20:56:11 +00:00
CheckRemoveSignal ( tile , track ) ;
2007-12-01 21:40:18 +00:00
/* cycle the signal side: both -> left -> right -> both -> ... */
2006-04-12 09:36:27 +00:00
CycleSignalSide ( tile , track ) ;
2008-08-22 22:19:23 +00:00
/* Query current signal type so the check for PBS signals below works. */
sigtype = GetSignalType ( tile , track ) ;
2005-01-22 14:52:20 +00:00
}
2004-08-15 20:23:42 +00:00
}
2005-01-22 14:52:20 +00:00
} else {
/* If CmdBuildManySignals is called with copying signals, just copy the
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
* direction of the first signal given as parameter by CmdBuildManySignals */
2007-05-30 13:33:19 +00:00
SetPresentSignals ( tile , ( GetPresentSignals ( tile ) & ~ SignalOnTrack ( track ) ) | ( p2 & SignalOnTrack ( track ) ) ) ;
2007-05-31 21:21:04 +00:00
SetSignalVariant ( tile , track , sigvar ) ;
2014-01-14 20:32:07 +00:00
if ( IsPresignalProgrammable ( tile , track ) )
FreeSignalProgram ( SignalReference ( tile , track ) ) ;
2008-08-02 22:49:39 +00:00
SetSignalType ( tile , track , sigtype ) ;
2004-08-09 17:04:08 +00:00
}
2004-09-11 09:55:19 +00:00
2011-12-03 23:40:13 +00:00
/* Add new signal infrastructure count. */
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . signal + = CountBits ( GetPresentSignals ( tile ) ) ;
DirtyCompanyInfrastructureWindows ( GetTileOwner ( tile ) ) ;
2021-01-25 02:33:14 +00:00
if ( IsPbsSignalNonExtended ( sigtype ) | | ( _settings_game . vehicle . train_braking_model = = TBM_REALISTIC & & HasBit ( GetRailReservationTrackBits ( tile ) , track ) ) ) {
2013-02-23 18:15:54 +00:00
/* PBS signals should show red unless they are on reserved tiles without a train. */
2008-08-02 22:49:23 +00:00
uint mask = GetPresentSignals ( tile ) & SignalOnTrack ( track ) ;
2013-02-23 18:15:54 +00:00
SetSignalStates ( tile , ( GetSignalStates ( tile ) & ~ mask ) | ( ( HasBit ( GetRailReservationTrackBits ( tile ) , track ) & & EnsureNoVehicleOnGround ( tile ) . Succeeded ( ) ? UINT_MAX : 0 ) & mask ) ) ;
2008-08-02 22:49:23 +00:00
}
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
2008-09-30 20:39:50 +00:00
AddTrackToSignalBuffer ( tile , track , _current_company ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2019-04-10 21:07:06 +00:00
if ( v ! = nullptr ) {
2019-06-08 16:12:51 +00:00
ReReserveTrainPath ( v ) ;
2009-12-27 14:37:46 +00:00
}
2004-08-09 17:04:08 +00:00
}
return cost ;
}
2007-07-04 17:21:28 +00:00
static bool CheckSignalAutoFill ( TileIndex & tile , Trackdir & trackdir , int & signal_ctr , bool remove )
{
tile = AddTileIndexDiffCWrap ( tile , _trackdelta [ trackdir ] ) ;
if ( tile = = INVALID_TILE ) return false ;
/* Check for track bits on the new tile */
2008-02-20 17:49:50 +00:00
TrackdirBits trackdirbits = TrackStatusToTrackdirBits ( GetTileTrackStatus ( tile , TRANSPORT_RAIL , 0 ) ) ;
2007-07-04 17:21:28 +00:00
if ( TracksOverlap ( TrackdirBitsToTrackBits ( trackdirbits ) ) ) return false ;
trackdirbits & = TrackdirReachesTrackdirs ( trackdir ) ;
/* No track bits, must stop */
if ( trackdirbits = = TRACKDIR_BIT_NONE ) return false ;
/* Get the first track dir */
trackdir = RemoveFirstTrackdir ( & trackdirbits ) ;
/* Any left? It's a junction so we stop */
if ( trackdirbits ! = TRACKDIR_BIT_NONE ) return false ;
switch ( GetTileType ( tile ) ) {
case MP_RAILWAY :
if ( IsRailDepot ( tile ) ) return false ;
if ( ! remove & & HasSignalOnTrack ( tile , TrackdirToTrack ( trackdir ) ) ) return false ;
signal_ctr + + ;
if ( IsDiagonalTrackdir ( trackdir ) ) {
signal_ctr + + ;
/* Ensure signal_ctr even so X and Y pieces get signals */
2007-11-19 21:32:20 +00:00
ClrBit ( signal_ctr , 0 ) ;
2007-07-04 17:21:28 +00:00
}
return true ;
2007-07-29 23:42:59 +00:00
case MP_ROAD :
2007-07-04 17:21:28 +00:00
if ( ! IsLevelCrossing ( tile ) ) return false ;
signal_ctr + = 2 ;
return true ;
case MP_TUNNELBRIDGE : {
2016-09-18 13:23:02 +00:00
if ( ! remove & & IsTunnelBridgeWithSignalSimulation ( tile ) ) return false ;
2007-12-16 19:30:42 +00:00
TileIndex orig_tile = tile ; // backup old value
if ( GetTunnelBridgeTransportType ( tile ) ! = TRANSPORT_RAIL ) return false ;
2018-07-03 18:09:10 +00:00
signal_ctr + = IsDiagonalTrackdir ( trackdir ) ? 2 : 1 ;
if ( GetTunnelBridgeDirection ( tile ) = = TrackdirToExitdir ( trackdir ) ) {
/* Skip to end of tunnel or bridge
* note that tile is a parameter by reference , so it must be updated */
tile = GetOtherTunnelBridgeEnd ( tile ) ;
signal_ctr + = GetTunnelBridgeLength ( orig_tile , tile ) * 2 ;
2007-12-16 19:30:42 +00:00
2018-07-03 18:09:10 +00:00
/* Check for track bits on the new tile */
trackdirbits = TrackStatusToTrackdirBits ( GetTileTrackStatus ( tile , TRANSPORT_RAIL , 0 ) ) ;
2007-12-16 19:30:42 +00:00
2018-07-03 18:09:10 +00:00
if ( TracksOverlap ( TrackdirBitsToTrackBits ( trackdirbits ) ) ) return false ;
trackdirbits & = TrackdirReachesTrackdirs ( trackdir ) ;
2007-12-16 19:30:42 +00:00
2018-07-03 18:09:10 +00:00
/* Get the first track dir */
trackdir = RemoveFirstTrackdir ( & trackdirbits ) ;
2007-12-16 19:30:42 +00:00
2018-07-03 18:09:10 +00:00
/* Any left? It's a junction so we stop */
if ( trackdirbits ! = TRACKDIR_BIT_NONE ) return false ;
signal_ctr + = IsDiagonalTrackdir ( trackdir ) ? 2 : 1 ;
}
2007-07-04 17:21:28 +00:00
return true ;
}
default : return false ;
}
}
2010-08-01 19:22:34 +00:00
/**
* Build many signals by dragging ; AutoSignals
2006-04-10 07:15:58 +00:00
* @ param tile start tile of drag
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-12 23:46:01 +00:00
* @ param p1 end tile of drag
* @ param p2 various bitstuffed elements
2007-01-19 17:44:11 +00:00
* - 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
2007-01-19 00:01:52 +00:00
* - p2 = ( bit 5 ) - 0 = build , 1 = remove signals
2007-07-04 17:21:28 +00:00
* - p2 = ( bit 6 ) - 0 = selected stretch , 1 = auto fill
2008-08-02 22:49:39 +00:00
* - p2 = ( bit 7 - 9 ) - default signal type
2012-04-17 19:43:29 +00:00
* - p2 = ( bit 10 ) - 0 = keep fixed distance , 1 = minimise gaps between signals
2005-05-12 23:46:01 +00:00
* - p2 = ( bit 24 - 31 ) - user defined signals_density
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2004-08-15 20:23:42 +00:00
*/
2009-02-09 21:20:05 +00:00
static CommandCost CmdSignalTrackHelper ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-15 20:23:42 +00:00
{
2010-03-14 12:58:51 +00:00
CommandCost total_cost ( EXPENSES_CONSTRUCTION ) ;
2007-07-04 17:21:28 +00:00
TileIndex start_tile = tile ;
2005-05-12 23:46:01 +00:00
2010-04-17 13:31:41 +00:00
Track track = Extract < Track , 0 , 3 > ( p2 ) ;
2007-11-19 21:02:30 +00:00
bool mode = HasBit ( p2 , 3 ) ;
bool semaphores = HasBit ( p2 , 4 ) ;
bool remove = HasBit ( p2 , 5 ) ;
bool autofill = HasBit ( p2 , 6 ) ;
2012-04-17 19:43:29 +00:00
bool minimise_gaps = HasBit ( p2 , 10 ) ;
2007-01-19 00:01:52 +00:00
byte signal_density = GB ( p2 , 24 , 8 ) ;
2005-05-12 23:46:01 +00:00
2010-04-17 13:31:41 +00:00
if ( p1 > = MapSize ( ) | | ! ValParamTrackOrientation ( track ) ) return CMD_ERROR ;
2010-02-15 19:52:40 +00:00
TileIndex end_tile = p1 ;
2005-05-12 23:46:01 +00:00
if ( signal_density = = 0 | | signal_density > 20 ) return CMD_ERROR ;
2004-08-15 20:23:42 +00:00
2010-07-10 20:15:35 +00:00
if ( ! IsPlainRailTile ( tile ) ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2005-06-19 11:56:07 +00:00
2005-05-12 23:46:01 +00:00
/* for vertical/horizontal tracks, double the given signals density
2006-09-04 20:40:33 +00:00
* since the original amount will be too dense ( shorter tracks ) */
2007-07-04 17:21:28 +00:00
signal_density * = 2 ;
2005-05-12 23:46:01 +00:00
2010-04-17 13:31:41 +00:00
Trackdir trackdir = TrackToTrackdir ( track ) ;
2010-03-14 12:58:51 +00:00
CommandCost ret = ValidateAutoDrag ( & trackdir , tile , end_tile ) ;
if ( ret . Failed ( ) ) return ret ;
2004-08-15 20:23:42 +00:00
2009-03-15 00:32:18 +00:00
track = TrackdirToTrack ( trackdir ) ; // trackdir might have changed, keep track in sync
2007-07-04 17:21:28 +00:00
Trackdir start_trackdir = trackdir ;
2008-08-07 13:07:51 +00:00
/* Must start on a valid track to be able to avoid loops */
if ( ! HasTrack ( tile , track ) ) return CMD_ERROR ;
2004-08-15 20:23:42 +00:00
2014-01-14 20:32:07 +00:00
SignalType sigtype = Extract < SignalType , 7 , 3 > ( p2 ) ;
2008-08-02 22:49:39 +00:00
if ( sigtype > SIGTYPE_LAST ) return CMD_ERROR ;
2010-02-15 19:52:40 +00:00
byte signals ;
2007-04-06 04:10:19 +00:00
/* copy the signal-style of the first rail-piece if existing */
2008-12-14 19:52:55 +00:00
if ( HasSignalOnTrack ( tile , track ) ) {
2007-05-30 13:33:19 +00:00
signals = GetPresentSignals ( tile ) & SignalOnTrack ( track ) ;
2008-12-14 19:52:55 +00:00
assert ( signals ! = 0 ) ;
2004-08-15 20:23:42 +00:00
2007-04-04 01:35:16 +00:00
/* copy signal/semaphores style (independent of CTRL) */
2007-05-31 21:21:04 +00:00
semaphores = GetSignalVariant ( tile , track ) ! = SIG_ELECTRIC ;
2008-08-02 22:49:39 +00:00
sigtype = GetSignalType ( tile , track ) ;
2011-01-15 22:50:49 +00:00
/* Don't but copy entry or exit-signal type */
if ( sigtype = = SIGTYPE_ENTRY | | sigtype = = SIGTYPE_EXIT ) sigtype = SIGTYPE_NORMAL ;
2006-06-27 21:25:53 +00:00
} else { // no signals exist, drag a two-way signal stretch
2008-08-02 22:49:39 +00:00
signals = IsPbsSignal ( sigtype ) ? SignalAlongTrackdir ( trackdir ) : SignalOnTrack ( track ) ;
2006-06-27 21:25:53 +00:00
}
2004-08-15 20:23:42 +00:00
2007-07-04 17:21:28 +00:00
byte signal_dir = 0 ;
2007-11-20 13:35:54 +00:00
if ( signals & SignalAlongTrackdir ( trackdir ) ) SetBit ( signal_dir , 0 ) ;
if ( signals & SignalAgainstTrackdir ( trackdir ) ) SetBit ( signal_dir , 1 ) ;
2007-07-04 17:21:28 +00:00
2005-06-19 11:56:07 +00:00
/* signal_ctr - amount of tiles already processed
2012-04-17 19:43:29 +00:00
* last_used_ctr - amount of tiles before previously placed signal
2009-02-08 12:25:13 +00:00
* signals_density - setting to put signal on every Nth tile ( double space on | , - - tracks )
2012-04-17 19:43:29 +00:00
* last_suitable_ctr - amount of tiles before last possible signal place
* last_suitable_tile - last tile where it is possible to place a signal
* last_suitable_trackdir - trackdir of the last tile
2004-08-15 20:23:42 +00:00
* * * * * * * * * *
2005-06-19 11:56:07 +00:00
* trackdir - trackdir to build with autorail
* semaphores - semaphores or signals
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
* signals - is there a signal / semaphore on the first tile , copy its style ( two - way / single - way )
2006-09-04 20:40:33 +00:00
* and convert all others to semaphore / signal
2007-01-19 00:01:52 +00:00
* remove - 1 remove signals , 0 build signals */
2010-02-15 19:52:40 +00:00
int signal_ctr = 0 ;
2012-04-17 19:43:29 +00:00
int last_used_ctr = INT_MIN ; // initially INT_MIN to force building/removing at the first tile
int last_suitable_ctr = 0 ;
TileIndex last_suitable_tile = INVALID_TILE ;
Trackdir last_suitable_trackdir = INVALID_TRACKDIR ;
2010-03-14 15:42:26 +00:00
CommandCost last_error = CMD_ERROR ;
bool had_success = false ;
2016-09-11 12:20:30 +00:00
std : : vector < TileIndex > tunnel_bridge_blacklist ;
2005-05-12 23:46:01 +00:00
for ( ; ; ) {
2016-09-11 12:20:30 +00:00
bool tile_ok = true ;
if ( IsTileType ( tile , MP_TUNNELBRIDGE ) ) {
if ( container_unordered_remove ( tunnel_bridge_blacklist , tile ) > 0 ) {
/* This tile is blacklisted, skip tile and remove from blacklist.
* Mark last used counter as current tile .
*/
tile_ok = false ;
last_used_ctr = signal_ctr ;
last_suitable_tile = INVALID_TILE ;
}
}
2015-08-01 19:24:07 +00:00
2016-09-11 12:20:30 +00:00
/* only build/remove signals with the specified density */
if ( tile_ok & & ( remove | | minimise_gaps | | signal_ctr % signal_density = = 0 | | IsTileType ( tile , MP_TUNNELBRIDGE ) ) ) {
2007-01-19 17:44:11 +00:00
uint32 p1 = GB ( TrackdirToTrack ( trackdir ) , 0 , 3 ) ;
SB ( p1 , 3 , 1 , mode ) ;
SB ( p1 , 4 , 1 , semaphores ) ;
2008-08-02 22:49:39 +00:00
SB ( p1 , 5 , 3 , sigtype ) ;
2009-02-24 19:15:23 +00:00
if ( ! remove & & signal_ctr = = 0 ) SetBit ( p1 , 17 ) ;
2007-07-04 17:21:28 +00:00
/* Pick the correct orientation for the track direction */
signals = 0 ;
2007-11-19 21:02:30 +00:00
if ( HasBit ( signal_dir , 0 ) ) signals | = SignalAlongTrackdir ( trackdir ) ;
if ( HasBit ( signal_dir , 1 ) ) signals | = SignalAgainstTrackdir ( trackdir ) ;
2007-07-04 17:21:28 +00:00
2012-04-17 19:43:29 +00:00
/* Test tiles in between for suitability as well if minimising gaps. */
2013-02-23 18:29:55 +00:00
bool test_only = ! remove & & minimise_gaps & & signal_ctr < ( last_used_ctr + signal_density ) ;
2012-04-17 19:43:29 +00:00
CommandCost ret = DoCommand ( tile , p1 , signals , test_only ? flags & ~ DC_EXEC : flags , remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS ) ;
2016-09-11 12:20:30 +00:00
if ( ! test_only & & ret . Succeeded ( ) & & IsTileType ( tile , MP_TUNNELBRIDGE ) & & GetTunnelBridgeDirection ( tile ) = = TrackdirToExitdir ( trackdir ) ) {
/* Blacklist far end of tunnel if we just actioned the near end */
tunnel_bridge_blacklist . push_back ( GetOtherTunnelBridgeEnd ( tile ) ) ;
}
2004-08-15 20:23:42 +00:00
2010-01-18 22:57:21 +00:00
if ( ret . Succeeded ( ) ) {
2012-04-17 19:43:29 +00:00
/* Remember last track piece where we can place a signal. */
last_suitable_ctr = signal_ctr ;
last_suitable_tile = tile ;
last_suitable_trackdir = trackdir ;
2021-02-03 03:37:06 +00:00
} else if ( ! test_only & & last_suitable_tile ! = INVALID_TILE & & ret . GetErrorMessage ( ) ! = STR_ERROR_CANNOT_MODIFY_TRACK_TRAIN_APPROACHING ) {
2012-04-17 19:43:29 +00:00
/* If a signal can't be placed, place it at the last possible position. */
SB ( p1 , 0 , 3 , TrackdirToTrack ( last_suitable_trackdir ) ) ;
ClrBit ( p1 , 17 ) ;
/* Pick the correct orientation for the track direction. */
signals = 0 ;
if ( HasBit ( signal_dir , 0 ) ) signals | = SignalAlongTrackdir ( last_suitable_trackdir ) ;
if ( HasBit ( signal_dir , 1 ) ) signals | = SignalAgainstTrackdir ( last_suitable_trackdir ) ;
ret = DoCommand ( last_suitable_tile , p1 , signals , flags , remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS ) ;
2016-09-11 12:20:30 +00:00
if ( ret . Succeeded ( ) & & IsTileType ( last_suitable_tile , MP_TUNNELBRIDGE ) & & GetTunnelBridgeDirection ( last_suitable_tile ) = = TrackdirToExitdir ( last_suitable_trackdir ) ) {
/* Blacklist far end of tunnel if we just actioned the near end */
tunnel_bridge_blacklist . push_back ( GetOtherTunnelBridgeEnd ( last_suitable_tile ) ) ;
}
2012-04-17 19:43:29 +00:00
}
/* Collect cost. */
if ( ! test_only ) {
/* Be user-friendly and try placing signals as much as possible */
if ( ret . Succeeded ( ) ) {
had_success = true ;
2016-09-11 12:20:30 +00:00
total_cost . AddCost ( ret ) ;
2012-04-17 19:43:29 +00:00
last_used_ctr = last_suitable_ctr ;
last_suitable_tile = INVALID_TILE ;
} else {
/* The "No railway" error is the least important one. */
if ( ret . GetErrorMessage ( ) ! = STR_ERROR_THERE_IS_NO_RAILROAD_TRACK | |
last_error . GetErrorMessage ( ) = = INVALID_STRING_ID ) {
last_error = ret ;
}
2010-07-10 20:18:59 +00:00
}
2004-08-15 20:23:42 +00:00
}
}
2007-07-04 17:21:28 +00:00
if ( autofill ) {
if ( ! CheckSignalAutoFill ( tile , trackdir , signal_ctr , remove ) ) break ;
2004-08-15 20:23:42 +00:00
2007-07-04 17:21:28 +00:00
/* Prevent possible loops */
if ( tile = = start_tile & & trackdir = = start_trackdir ) break ;
} else {
if ( tile = = end_tile ) break ;
2004-09-11 09:55:19 +00:00
2007-07-04 17:21:28 +00:00
tile + = ToTileIndexDiff ( _trackdelta [ trackdir ] ) ;
signal_ctr + + ;
/* toggle railbit for the non-diagonal tracks (|, -- tracks) */
if ( IsDiagonalTrackdir ( trackdir ) ) {
signal_ctr + + ;
} else {
2007-11-20 14:11:19 +00:00
ToggleBit ( trackdir , 0 ) ;
2007-07-04 17:21:28 +00:00
}
}
2004-08-15 20:23:42 +00:00
}
2010-03-14 15:42:26 +00:00
return had_success ? total_cost : last_error ;
2004-08-15 20:23:42 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Build signals on a stretch of track .
2005-05-12 23:46:01 +00:00
* Stub for the unified signal builder / remover
2007-04-17 21:09:38 +00:00
* @ param tile start tile of drag
* @ param flags operation to perform
* @ 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
2007-07-04 17:21:28 +00:00
* - p2 = ( bit 6 ) - 0 = selected stretch , 1 = auto fill
2008-08-02 22:49:39 +00:00
* - p2 = ( bit 7 - 9 ) - default signal type
2007-04-17 21:09:38 +00:00
* - p2 = ( bit 24 - 31 ) - user defined signals_density
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 23:46:01 +00:00
* @ see CmdSignalTrackHelper
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuildSignalTrack ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2005-01-30 15:57:38 +00:00
{
2009-07-16 10:13:33 +00:00
return CmdSignalTrackHelper ( tile , flags , p1 , p2 , text ) ;
2005-01-30 15:57:38 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Remove signals
2006-04-10 07:15:58 +00:00
* @ param tile coordinates where signal is being deleted from
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2007-04-18 18:00:33 +00:00
* @ 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
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2004-08-09 17:04:08 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdRemoveSingleSignal ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-04-17 13:31:41 +00:00
Track track = Extract < Track , 0 , 3 > ( p1 ) ;
2015-08-01 19:24:07 +00:00
Money cost = _price [ PR_CLEAR_SIGNALS ] ;
2004-08-09 17:04:08 +00:00
2015-08-01 19:24:07 +00:00
if ( IsTileType ( tile , MP_TUNNELBRIDGE ) ) {
TileIndex end = GetOtherTunnelBridgeEnd ( tile ) ;
if ( GetTunnelBridgeTransportType ( tile ) ! = TRANSPORT_RAIL ) return_cmd_error ( STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ) ;
2016-09-18 13:23:02 +00:00
if ( ! IsTunnelBridgeWithSignalSimulation ( tile ) ) return_cmd_error ( STR_ERROR_THERE_ARE_NO_SIGNALS ) ;
2015-08-01 19:24:07 +00:00
cost * = ( ( GetTunnelBridgeLength ( tile , end ) + 4 ) > > 2 ) ;
2018-06-17 03:27:03 +00:00
if ( IsTunnelBridgeSignalSimulationBidirectional ( tile ) ) cost * = 2 ;
2015-08-01 19:24:07 +00:00
CommandCost ret = EnsureNoTrainOnTrack ( GetOtherTunnelBridgeEnd ( tile ) , track ) ;
2015-08-01 19:26:41 +00:00
if ( ret . Failed ( ) ) return ret ;
2015-08-16 16:31:34 +00:00
ret = EnsureNoTrainOnTrack ( tile , track ) ;
if ( ret . Failed ( ) ) return ret ;
2015-08-01 19:24:07 +00:00
} else {
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 ) ;
}
2006-06-27 21:25:53 +00:00
}
2004-08-09 17:04:08 +00:00
2005-05-07 10:26:12 +00:00
/* Only water can remove signals from anyone */
2010-03-07 20:44:05 +00:00
if ( _current_company ! = OWNER_WATER ) {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
}
2005-01-19 13:31:46 +00:00
2021-01-25 02:33:14 +00:00
if ( IsTunnelBridgeWithSignalSimulation ( tile ) ) { // handle tunnel/bridge signals.
TileIndex end = GetOtherTunnelBridgeEnd ( tile ) ;
std : : vector < Train * > re_reserve_trains ;
for ( TileIndex t : { tile , end } ) {
if ( HasAcrossTunnelBridgeReservation ( t ) ) {
Train * v = GetTrainForReservation ( t , FindFirstTrack ( GetAcrossTunnelBridgeReservationTrackBits ( t ) ) ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
if ( flags & DC_EXEC ) {
2019-07-29 21:49:24 +00:00
FreeTrainTrackReservation ( v ) ;
re_reserve_trains . push_back ( v ) ;
}
2019-06-08 16:12:51 +00:00
}
}
2015-08-01 19:24:07 +00:00
}
2021-02-04 12:02:54 +00:00
if ( flags & DC_EXEC ) {
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . signal - = GetTunnelBridgeSignalSimulationSignalCount ( tile , end ) ;
ClearBridgeTunnelSignalSimulation ( end , tile ) ;
ClearBridgeTunnelSignalSimulation ( tile , end ) ;
MarkBridgeOrTunnelDirty ( tile ) ;
AddSideToSignalBuffer ( tile , INVALID_DIAGDIR , GetTileOwner ( tile ) ) ;
AddSideToSignalBuffer ( end , INVALID_DIAGDIR , GetTileOwner ( tile ) ) ;
YapfNotifyTrackLayoutChange ( tile , track ) ;
YapfNotifyTrackLayoutChange ( end , track ) ;
DirtyCompanyInfrastructureWindows ( GetTileOwner ( tile ) ) ;
for ( Train * v : re_reserve_trains ) {
ReReserveTrainPath ( v ) ;
}
2021-01-25 02:33:14 +00:00
}
return CommandCost ( EXPENSES_CONSTRUCTION , cost ) ;
}
2015-08-01 19:24:07 +00:00
2021-01-25 02:33:14 +00:00
Train * v = nullptr ;
if ( HasReservedTracks ( tile , TrackToTrackBits ( track ) ) ) {
v = GetTrainForReservation ( tile , track ) ;
} else if ( IsPbsSignal ( GetSignalType ( tile , track ) ) ) {
/* PBS signal, might be the end of a path reservation. */
Trackdir td = TrackToTrackdir ( track ) ;
for ( int i = 0 ; v = = nullptr & & i < 2 ; i + + , td = ReverseTrackdir ( td ) ) {
/* Only test the active signal side. */
if ( ! HasSignalOnTrackdir ( tile , ReverseTrackdir ( td ) ) ) continue ;
TileIndex next = TileAddByDiagDir ( tile , TrackdirToExitdir ( td ) ) ;
TrackBits tracks = TrackdirBitsToTrackBits ( TrackdirReachesTrackdirs ( td ) ) ;
if ( HasReservedTracks ( next , tracks ) ) {
v = GetTrainForReservation ( next , TrackBitsToTrack ( GetReservedTrackbits ( next ) & tracks ) ) ;
2009-12-27 14:37:46 +00:00
}
2008-08-03 11:28:35 +00:00
}
2021-01-25 02:33:14 +00:00
}
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
}
/* Do it? */
if ( flags & DC_EXEC ) {
2011-12-03 23:40:13 +00:00
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . signal - = CountBits ( GetPresentSignals ( tile ) ) ;
2014-01-14 20:32:07 +00:00
CheckRemoveSignal ( tile , track ) ;
2007-05-30 13:33:19 +00:00
SetPresentSignals ( tile , GetPresentSignals ( tile ) & ~ SignalOnTrack ( track ) ) ;
2011-12-03 23:40:13 +00:00
Company : : Get ( GetTileOwner ( tile ) ) - > infrastructure . signal + = CountBits ( GetPresentSignals ( tile ) ) ;
DirtyCompanyInfrastructureWindows ( GetTileOwner ( tile ) ) ;
2015-07-21 23:28:53 +00:00
TraceRestrictNotifySignalRemoval ( tile , track ) ;
2004-09-11 09:55:19 +00:00
2005-01-19 13:31:46 +00:00
/* removed last signal from tile? */
2007-05-30 13:33:19 +00:00
if ( GetPresentSignals ( tile ) = = 0 ) {
SetSignalStates ( tile , 0 ) ;
2007-02-27 23:36:28 +00:00
SetHasSignals ( tile , false ) ;
2007-05-31 21:21:04 +00:00
SetSignalVariant ( tile , INVALID_TRACK , SIG_ELECTRIC ) ; // remove any possible semaphores
2005-01-19 13:31:46 +00:00
}
2005-01-23 13:09:35 +00:00
2008-01-16 01:18:15 +00:00
AddTrackToSignalBuffer ( tile , track , GetTileOwner ( tile ) ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2020-02-11 22:08:21 +00:00
if ( v ! = nullptr & & ! ( v - > track & TRACK_BIT_WORMHOLE & & IsTunnelBridgeWithSignalSimulation ( v - > tile ) ) ) {
TryPathReserve ( v , false ) ;
}
2004-08-09 17:04:08 +00:00
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
2004-08-09 17:04:08 +00:00
}
2004-09-11 09:55:19 +00:00
2015-08-01 19:24:07 +00:00
return CommandCost ( EXPENSES_CONSTRUCTION , cost ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Remove signals on a stretch of track .
2005-05-12 23:46:01 +00:00
* Stub for the unified signal builder / remover
2007-04-17 21:09:38 +00:00
* @ param tile start tile of drag
* @ param flags operation to perform
* @ 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
2007-07-04 17:21:28 +00:00
* - p2 = ( bit 6 ) - 0 = selected stretch , 1 = auto fill
2008-08-02 22:49:39 +00:00
* - p2 = ( bit 7 - 9 ) - default signal type
2007-04-17 21:09:38 +00:00
* - p2 = ( bit 24 - 31 ) - user defined signals_density
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 23:46:01 +00:00
* @ see CmdSignalTrackHelper
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdRemoveSignalTrack ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2005-01-30 15:57:38 +00:00
{
2008-12-28 14:37:19 +00:00
return CmdSignalTrackHelper ( tile , flags , p1 , SetBit ( p2 , 5 ) , text ) ; // bit 5 is remove bit
2005-01-30 15:57:38 +00:00
}
2007-12-17 22:29:27 +00:00
/** Update power of train under which is the railtype being converted */
2009-11-09 10:40:33 +00:00
static Vehicle * UpdateTrainPowerProc ( Vehicle * v , void * data )
2007-09-08 09:52:02 +00:00
{
2010-08-15 15:47:07 +00:00
TrainList * affected_trains = static_cast < TrainList * > ( data ) ;
2019-02-20 21:35:41 +00:00
include ( * affected_trains , Train : : From ( v ) - > First ( ) ) ;
2007-09-08 09:52:02 +00:00
2019-04-10 21:07:06 +00:00
return nullptr ;
2007-09-08 09:52:02 +00:00
}
2020-09-24 17:00:59 +00:00
struct EnsureNoIncompatibleRailtypeTrainOnGroundData {
int z ;
RailType type ;
} ;
static Vehicle * EnsureNoIncompatibleRailtypeTrainProc ( Vehicle * v , void * data )
{
const EnsureNoIncompatibleRailtypeTrainOnGroundData * procdata = ( EnsureNoIncompatibleRailtypeTrainOnGroundData * ) data ;
if ( v - > z_pos > procdata - > z ) return nullptr ;
if ( HasBit ( Train : : From ( v ) - > First ( ) - > compatible_railtypes , procdata - > type ) ) return nullptr ;
return v ;
}
CommandCost EnsureNoIncompatibleRailtypeTrainOnGround ( TileIndex tile , RailType type )
{
EnsureNoIncompatibleRailtypeTrainOnGroundData data = {
GetTileMaxPixelZ ( tile ) ,
type
} ;
if ( HasVehicleOnPos ( tile , VEH_TRAIN , & data , & EnsureNoIncompatibleRailtypeTrainProc ) ) {
return_cmd_error ( STR_ERROR_TRAIN_IN_THE_WAY ) ;
}
return CommandCost ( ) ;
}
struct EnsureNoIncompatibleRailtypeTrainOnTrackBitsData {
TrackBits track_bits ;
RailType type ;
} ;
static Vehicle * EnsureNoIncompatibleRailtypeTrainOnTrackProc ( Vehicle * v , void * data )
{
const EnsureNoIncompatibleRailtypeTrainOnTrackBitsData * procdata = ( EnsureNoIncompatibleRailtypeTrainOnTrackBitsData * ) data ;
TrackBits rail_bits = procdata - > track_bits ;
Train * t = Train : : From ( v ) ;
if ( HasBit ( t - > First ( ) - > compatible_railtypes , procdata - > type ) ) return nullptr ;
if ( rail_bits & TRACK_BIT_WORMHOLE ) {
if ( t - > track & TRACK_BIT_WORMHOLE ) return v ;
rail_bits & = ~ TRACK_BIT_WORMHOLE ;
} else if ( t - > track & TRACK_BIT_WORMHOLE ) {
return nullptr ;
}
if ( ( t - > track ! = rail_bits ) & & ! TracksOverlap ( t - > track | rail_bits ) ) return nullptr ;
return v ;
}
CommandCost EnsureNoIncompatibleRailtypeTrainOnTrackBits ( TileIndex tile , TrackBits track_bits , RailType type )
{
EnsureNoIncompatibleRailtypeTrainOnTrackBitsData data = {
track_bits ,
type
} ;
if ( HasVehicleOnPos ( tile , VEH_TRAIN , & data , & EnsureNoIncompatibleRailtypeTrainOnTrackProc ) ) {
return_cmd_error ( STR_ERROR_TRAIN_IN_THE_WAY ) ;
}
return CommandCost ( ) ;
}
2010-08-01 19:22:34 +00:00
/**
* Convert one rail type to the other . You can convert normal rail to
2005-05-09 16:37:40 +00:00
* monorail / maglev easily or vice - versa .
2006-04-10 07:15:58 +00:00
* @ param tile end tile of rail conversion drag
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-09 16:37:40 +00:00
* @ param p1 start tile of drag
2011-11-26 18:11:22 +00:00
* @ param p2 various bitstuffed elements :
2018-07-22 23:05:23 +00:00
* - p2 = ( bit 0 - 5 ) new railtype to convert to .
* - p2 = ( bit 6 ) build diagonally or not .
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-09 16:37:40 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdConvertRail ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2018-07-22 23:05:23 +00:00
RailType totype = Extract < RailType , 0 , 6 > ( p2 ) ;
2014-02-02 14:54:13 +00:00
TileIndex area_start = p1 ;
TileIndex area_end = tile ;
2018-07-22 23:05:23 +00:00
bool diagonal = HasBit ( p2 , 6 ) ;
2005-01-04 17:11:03 +00:00
2008-01-09 21:05:03 +00:00
if ( ! ValParamRailtype ( totype ) ) return CMD_ERROR ;
2014-02-02 14:54:13 +00:00
if ( area_start > = MapSize ( ) ) return CMD_ERROR ;
2005-05-09 16:37:40 +00:00
2010-08-15 15:47:07 +00:00
TrainList affected_trains ;
2010-03-14 16:42:55 +00:00
CommandCost cost ( EXPENSES_CONSTRUCTION ) ;
CommandCost error = CommandCost ( STR_ERROR_NO_SUITABLE_RAILROAD_TRACK ) ; // by default, there is no track to convert.
2019-07-01 08:37:59 +00:00
bool found_convertible_track = false ; // whether we actually did convert some track (see bug #7633)
2014-02-02 14:54:13 +00:00
2021-04-01 16:26:27 +00:00
std : : unique_ptr < TileIterator > iter ( diagonal ? ( TileIterator * ) new DiagonalTileIterator ( area_start , area_end ) : new OrthogonalTileIterator ( area_start , area_end ) ) ;
2011-11-26 18:11:22 +00:00
for ( ; ( tile = * iter ) ! = INVALID_TILE ; + + ( * iter ) ) {
2010-12-12 17:21:49 +00:00
TileType tt = GetTileType ( tile ) ;
/* Check if there is any track on tile */
switch ( tt ) {
case MP_RAILWAY :
break ;
case MP_STATION :
if ( ! HasStationRail ( tile ) ) continue ;
break ;
case MP_ROAD :
if ( ! IsLevelCrossing ( tile ) ) continue ;
if ( RailNoLevelCrossings ( totype ) ) {
2019-04-06 06:46:15 +00:00
error . MakeError ( STR_ERROR_CROSSING_DISALLOWED_RAIL ) ;
2010-12-12 17:21:49 +00:00
continue ;
}
break ;
case MP_TUNNELBRIDGE :
if ( GetTunnelBridgeTransportType ( tile ) ! = TRANSPORT_RAIL ) continue ;
break ;
default : continue ;
}
/* Original railtype we are converting from */
2018-12-21 03:27:58 +00:00
const RailType type = GetRailType ( tile ) ;
const RailType raw_secondary_type = GetTileSecondaryRailTypeIfValid ( tile ) ;
const RailType secondary_type = ( raw_secondary_type = = INVALID_RAILTYPE ) ? type : raw_secondary_type ;
2010-12-12 17:21:49 +00:00
/* Converting to the same type or converting 'hidden' elrail -> rail */
2018-12-21 03:27:58 +00:00
if ( ( type = = totype | | ( _settings_game . vehicle . disable_elrails & & totype = = RAILTYPE_RAIL & & type = = RAILTYPE_ELECTRIC ) )
& & ( secondary_type = = totype | | ( _settings_game . vehicle . disable_elrails & & totype = = RAILTYPE_RAIL & & secondary_type = = RAILTYPE_ELECTRIC ) ) ) continue ;
2010-12-12 17:21:49 +00:00
/* Trying to convert other's rail */
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) {
error = ret ;
continue ;
}
2019-03-03 17:30:09 +00:00
std : : vector < Train * > vehicles_affected ;
2010-12-12 17:21:49 +00:00
2021-01-25 02:33:14 +00:00
auto find_train_reservations = [ & vehicles_affected , & totype , & flags ] ( TileIndex tile , TrackBits reserved ) - > CommandCost {
if ( ! ( flags & DC_EXEC ) & & _settings_game . vehicle . train_braking_model ! = TBM_REALISTIC ) {
/* Nothing to do */
return CommandCost ( ) ;
}
2018-07-03 18:09:10 +00:00
Track track ;
while ( ( track = RemoveFirstTrack ( & reserved ) ) ! = INVALID_TRACK ) {
Train * v = GetTrainForReservation ( tile , track ) ;
2021-01-25 02:33:14 +00:00
bool check_train = false ;
2019-04-11 17:14:13 +00:00
if ( v ! = nullptr & & ! HasPowerOnRail ( v - > railtype , totype ) ) {
2021-01-25 02:33:14 +00:00
check_train = true ;
} else if ( v ! = nullptr & & _settings_game . vehicle . train_braking_model = = TBM_REALISTIC ) {
RailType original = GetRailTypeByTrack ( tile , track ) ;
if ( ( uint ) ( GetRailTypeInfo ( original ) - > max_speed - 1 ) > ( uint ) ( GetRailTypeInfo ( totype ) - > max_speed - 1 ) ) {
check_train = true ;
}
}
if ( check_train ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
2018-07-03 18:09:10 +00:00
/* No power on new rail type, reroute. */
2021-01-25 02:33:14 +00:00
if ( flags & DC_EXEC ) {
FreeTrainTrackReservation ( v ) ;
vehicles_affected . push_back ( v ) ;
}
2018-07-03 18:09:10 +00:00
}
}
2021-01-25 02:33:14 +00:00
return CommandCost ( ) ;
2018-07-03 18:09:10 +00:00
} ;
auto yapf_notify_track_change = [ ] ( TileIndex tile , TrackBits tracks ) {
while ( tracks ! = TRACK_BIT_NONE ) {
YapfNotifyTrackLayoutChange ( tile , RemoveFirstTrack ( & tracks ) ) ;
}
} ;
2010-12-12 17:21:49 +00:00
/* Vehicle on the tile when not converting Rail <-> ElRail
* Tunnels and bridges have special check later */
if ( tt ! = MP_TUNNELBRIDGE ) {
2018-12-21 03:27:58 +00:00
if ( ! IsCompatibleRail ( type , totype ) | | ! IsCompatibleRail ( secondary_type , totype ) ) {
2020-09-24 17:00:59 +00:00
CommandCost ret = IsPlainRailTile ( tile ) ? EnsureNoIncompatibleRailtypeTrainOnTrackBits ( tile , GetTrackBits ( tile ) , totype ) : EnsureNoIncompatibleRailtypeTrainOnGround ( tile , totype ) ;
2010-12-12 17:21:49 +00:00
if ( ret . Failed ( ) ) {
error = ret ;
continue ;
}
}
2021-01-25 02:33:14 +00:00
CommandCost ret = find_train_reservations ( tile , GetReservedTrackbits ( tile ) ) ;
if ( ret . Failed ( ) ) return ret ;
2010-12-12 17:21:49 +00:00
if ( flags & DC_EXEC ) { // we can safely convert, too
2011-12-03 23:40:13 +00:00
/* Update the company infrastructure counters. */
2011-12-19 14:24:12 +00:00
if ( ! IsRailStationTile ( tile ) | | ! IsStationTileBlocked ( tile ) ) {
2011-12-03 23:40:13 +00:00
Company * c = Company : : Get ( GetTileOwner ( tile ) ) ;
uint num_pieces = IsLevelCrossingTile ( tile ) ? LEVELCROSSING_TRACKBIT_FACTOR : 1 ;
if ( IsPlainRailTile ( tile ) ) {
TrackBits bits = GetTrackBits ( tile ) ;
2018-12-21 03:27:58 +00:00
if ( bits = = TRACK_BIT_HORZ | | bits = = TRACK_BIT_VERT ) {
c - > infrastructure . rail [ secondary_type ] - - ;
c - > infrastructure . rail [ totype ] + + ;
} else {
num_pieces = CountBits ( bits ) ;
if ( TracksOverlap ( bits ) ) num_pieces * = num_pieces ;
}
2011-12-03 23:40:13 +00:00
}
c - > infrastructure . rail [ type ] - = num_pieces ;
c - > infrastructure . rail [ totype ] + = num_pieces ;
DirtyCompanyInfrastructureWindows ( c - > index ) ;
}
2010-12-12 17:21:49 +00:00
SetRailType ( tile , totype ) ;
2018-12-21 03:27:58 +00:00
if ( IsPlainRailTile ( tile ) ) SetSecondaryRailType ( tile , totype ) ;
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
2010-12-12 17:21:49 +00:00
/* update power of train on this tile */
2020-02-28 22:21:10 +00:00
FindVehicleOnPos ( tile , VEH_TRAIN , & affected_trains , & UpdateTrainPowerProc ) ;
2005-10-23 13:04:44 +00:00
}
2010-12-12 17:21:49 +00:00
}
2004-09-11 09:55:19 +00:00
2010-12-12 17:21:49 +00:00
switch ( tt ) {
case MP_RAILWAY :
switch ( GetRailTileType ( tile ) ) {
case RAIL_TILE_DEPOT :
if ( flags & DC_EXEC ) {
/* notify YAPF about the track layout change */
YapfNotifyTrackLayoutChange ( tile , GetRailDepotTrack ( tile ) ) ;
/* Update build vehicle window related to this depot */
InvalidateWindowData ( WC_VEHICLE_DEPOT , tile ) ;
InvalidateWindowData ( WC_BUILD_VEHICLE , tile ) ;
}
2019-07-01 08:37:59 +00:00
found_convertible_track = true ;
2010-12-12 17:21:49 +00:00
cost . AddCost ( RailConvertCost ( type , totype ) ) ;
break ;
2007-09-08 09:52:02 +00:00
2010-12-12 17:21:49 +00:00
default : // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
if ( flags & DC_EXEC ) {
/* notify YAPF about the track layout change */
2018-07-03 18:09:10 +00:00
yapf_notify_track_change ( tile , GetTrackBits ( tile ) ) ;
2010-12-12 17:21:49 +00:00
}
2019-07-01 08:37:59 +00:00
found_convertible_track = true ;
2018-12-21 03:27:58 +00:00
if ( raw_secondary_type ! = INVALID_RAILTYPE ) {
cost . AddCost ( RailConvertCost ( type , totype ) ) ;
cost . AddCost ( RailConvertCost ( raw_secondary_type , totype ) ) ;
} else {
cost . AddCost ( RailConvertCost ( type , totype ) * CountBits ( GetTrackBits ( tile ) ) ) ;
}
2010-12-12 17:21:49 +00:00
break ;
}
break ;
2007-12-17 22:29:27 +00:00
2010-12-12 17:21:49 +00:00
case MP_TUNNELBRIDGE : {
TileIndex endtile = GetOtherTunnelBridgeEnd ( tile ) ;
2007-12-17 22:29:27 +00:00
2010-12-12 17:21:49 +00:00
/* If both ends of tunnel/bridge are in the range, do not try to convert twice -
* it would cause assert because of different test and exec runs */
2014-02-02 14:54:13 +00:00
if ( endtile < tile ) {
if ( diagonal ) {
if ( DiagonalTileArea ( area_start , area_end ) . Contains ( endtile ) ) continue ;
} else {
if ( OrthogonalTileArea ( area_start , area_end ) . Contains ( endtile ) ) continue ;
}
}
2008-08-02 22:55:08 +00:00
2013-01-08 22:46:42 +00:00
/* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
2018-12-21 03:27:58 +00:00
if ( ! IsCompatibleRail ( type , totype ) | | ! IsCompatibleRail ( secondary_type , totype ) ) {
2010-12-12 17:21:49 +00:00
CommandCost ret = TunnelBridgeIsFree ( tile , endtile ) ;
2010-03-05 21:20:22 +00:00
if ( ret . Failed ( ) ) {
2010-03-14 16:42:55 +00:00
error = ret ;
2010-03-05 21:20:22 +00:00
continue ;
}
}
2010-12-12 17:21:49 +00:00
2018-12-21 03:27:58 +00:00
uint num_primary_pieces = GetTunnelBridgeLength ( tile , endtile ) + CountBits ( GetPrimaryTunnelBridgeTrackBits ( tile ) ) + CountBits ( GetPrimaryTunnelBridgeTrackBits ( endtile ) ) ;
2019-07-13 19:34:52 +00:00
found_convertible_track = true ;
2018-12-21 03:27:58 +00:00
cost . AddCost ( num_primary_pieces * RailConvertCost ( type , totype ) ) ;
RailType end_secondary_type = GetTileSecondaryRailTypeIfValid ( endtile ) ;
if ( raw_secondary_type ! = INVALID_RAILTYPE ) cost . AddCost ( RailConvertCost ( raw_secondary_type , totype ) ) ;
if ( end_secondary_type ! = INVALID_RAILTYPE ) cost . AddCost ( RailConvertCost ( end_secondary_type , totype ) ) ;
2018-07-03 18:09:10 +00:00
2021-01-25 02:33:14 +00:00
CommandCost ret = find_train_reservations ( tile , GetTunnelBridgeReservationTrackBits ( tile ) ) ;
if ( ret . Failed ( ) ) return ret ;
ret = find_train_reservations ( endtile , GetTunnelBridgeReservationTrackBits ( endtile ) ) ;
if ( ret . Failed ( ) ) return ret ;
if ( ( uint ) ( GetRailTypeInfo ( type ) - > max_speed - 1 ) > ( uint ) ( GetRailTypeInfo ( totype ) - > max_speed - 1 ) ) {
ret = CheckTrainInTunnelBridgePreventsTrackModification ( tile , endtile ) ;
if ( ret . Failed ( ) ) return ret ;
}
2010-12-12 17:21:49 +00:00
if ( flags & DC_EXEC ) {
2018-12-21 03:27:58 +00:00
SubtractRailTunnelBridgeInfrastructure ( tile , endtile ) ;
2007-12-17 22:29:27 +00:00
SetRailType ( tile , totype ) ;
2010-12-12 17:21:49 +00:00
SetRailType ( endtile , totype ) ;
2018-12-21 03:27:58 +00:00
SetSecondaryRailType ( tile , totype ) ;
SetSecondaryRailType ( endtile , totype ) ;
2007-09-08 09:52:02 +00:00
2020-02-28 22:21:10 +00:00
FindVehicleOnPos ( tile , VEH_TRAIN , & affected_trains , & UpdateTrainPowerProc ) ;
FindVehicleOnPos ( endtile , VEH_TRAIN , & affected_trains , & UpdateTrainPowerProc ) ;
2007-12-17 22:29:27 +00:00
2018-07-03 18:09:10 +00:00
/* notify YAPF about the track layout change */
yapf_notify_track_change ( tile , GetTunnelBridgeTrackBits ( tile ) ) ;
yapf_notify_track_change ( endtile , GetTunnelBridgeTrackBits ( endtile ) ) ;
2007-12-17 22:29:27 +00:00
2010-12-12 17:21:49 +00:00
if ( IsBridge ( tile ) ) {
2020-10-01 17:50:31 +00:00
MarkBridgeDirty ( tile , VMDF_NOT_MAP_MODE ) ;
2015-02-22 14:01:24 +00:00
} else {
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
MarkTileDirtyByTile ( endtile , VMDF_NOT_MAP_MODE ) ;
2010-03-05 21:34:12 +00:00
}
2007-12-17 22:29:27 +00:00
2018-12-21 03:27:58 +00:00
AddRailTunnelBridgeInfrastructure ( tile , endtile ) ;
DirtyCompanyInfrastructureWindows ( Company : : Get ( GetTileOwner ( tile ) ) - > index ) ;
}
2010-12-12 17:21:49 +00:00
break ;
}
2007-12-17 22:29:27 +00:00
2010-12-12 17:21:49 +00:00
default : // MP_STATION, MP_ROAD
if ( flags & DC_EXEC ) {
Track track = ( ( tt = = MP_STATION ) ? GetRailStationTrack ( tile ) : GetCrossingRailTrack ( tile ) ) ;
YapfNotifyTrackLayoutChange ( tile , track ) ;
2010-08-01 18:53:30 +00:00
}
2007-12-17 22:29:27 +00:00
2019-07-01 08:37:59 +00:00
found_convertible_track = true ;
2010-12-12 17:21:49 +00:00
cost . AddCost ( RailConvertCost ( type , totype ) ) ;
break ;
}
2008-08-02 22:55:08 +00:00
2018-09-23 11:23:54 +00:00
for ( uint i = 0 ; i < vehicles_affected . size ( ) ; + + i ) {
2010-12-12 17:21:49 +00:00
TryPathReserve ( vehicles_affected [ i ] , true ) ;
2004-08-09 17:04:08 +00:00
}
}
2005-05-09 16:37:40 +00:00
2010-08-15 15:47:07 +00:00
if ( flags & DC_EXEC ) {
/* Railtype changed, update trains as when entering different track */
2019-02-17 11:20:52 +00:00
for ( Train * v : affected_trains ) {
v - > ConsistChanged ( CCF_TRACK ) ;
2010-08-15 15:47:07 +00:00
}
}
2019-07-01 08:37:59 +00:00
return found_convertible_track ? cost : error ;
2004-08-09 17:04:08 +00:00
}
2009-02-09 21:20:05 +00:00
static CommandCost RemoveTrainDepot ( TileIndex tile , DoCommandFlag flags )
2004-08-09 17:04:08 +00:00
{
2010-03-07 20:44:05 +00:00
if ( _current_company ! = OWNER_WATER ) {
CommandCost ret = CheckTileOwnership ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
}
2004-08-09 17:04:08 +00:00
2010-03-05 21:20:22 +00:00
CommandCost ret = EnsureNoVehicleOnGround ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
2004-08-09 17:04:08 +00:00
2021-01-25 02:33:14 +00:00
/* read variables before the depot is removed */
DiagDirection dir = GetRailDepotDirection ( tile ) ;
Train * v = nullptr ;
if ( HasDepotReservation ( tile ) ) {
v = GetTrainForReservation ( tile , DiagDirToDiagTrack ( dir ) ) ;
if ( v ! = nullptr ) {
CommandCost ret = CheckTrainReservationPreventsTrackModification ( v ) ;
if ( ret . Failed ( ) ) return ret ;
}
}
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2008-01-15 15:00:01 +00:00
/* read variables before the depot is removed */
Owner owner = GetTileOwner ( tile ) ;
2008-08-02 22:55:08 +00:00
2021-01-25 02:33:14 +00:00
if ( v ! = nullptr ) FreeTrainTrackReservation ( v ) ;
2004-08-09 17:04:08 +00:00
2011-12-03 23:40:13 +00:00
Company : : Get ( owner ) - > infrastructure . rail [ GetRailType ( tile ) ] - - ;
DirtyCompanyInfrastructureWindows ( owner ) ;
2009-06-24 19:26:41 +00:00
delete Depot : : GetByTile ( tile ) ;
2009-09-07 08:35:45 +00:00
DoClearSquare ( tile ) ;
2008-01-16 01:18:15 +00:00
AddSideToSignalBuffer ( tile , dir , owner ) ;
2008-05-14 18:31:21 +00:00
YapfNotifyTrackLayoutChange ( tile , DiagDirToDiagTrack ( dir ) ) ;
2019-04-10 21:07:06 +00:00
if ( v ! = nullptr ) TryPathReserve ( v , true ) ;
2021-01-05 17:44:19 +00:00
DeleteNewGRFInspectWindow ( GSF_RAILTYPES , tile ) ;
2004-08-09 17:04:08 +00:00
}
2009-11-07 22:47:54 +00:00
return CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_CLEAR_DEPOT_TRAIN ] ) ;
2004-08-09 17:04:08 +00:00
}
2009-02-09 21:20:05 +00:00
static CommandCost ClearTile_Track ( TileIndex tile , DoCommandFlag flags )
2005-03-23 20:02:28 +00:00
{
2008-01-09 16:55:48 +00:00
CommandCost cost ( EXPENSES_CONSTRUCTION ) ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_AUTO ) {
2009-05-18 01:26:23 +00:00
if ( ! IsTileOwner ( tile , _current_company ) ) {
2009-04-21 23:40:56 +00:00
return_cmd_error ( STR_ERROR_AREA_IS_OWNED_BY_ANOTHER ) ;
2009-05-18 01:26:23 +00:00
}
2004-08-09 17:04:08 +00:00
2009-05-18 01:26:23 +00:00
if ( IsPlainRail ( tile ) ) {
2009-04-21 23:40:56 +00:00
return_cmd_error ( STR_ERROR_MUST_REMOVE_RAILROAD_TRACK ) ;
2006-07-27 05:30:53 +00:00
} else {
2009-04-21 23:40:56 +00:00
return_cmd_error ( STR_ERROR_BUILDING_MUST_BE_DEMOLISHED ) ;
2006-07-27 05:30:53 +00:00
}
2004-08-09 17:04:08 +00:00
}
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
switch ( GetRailTileType ( tile ) ) {
2006-05-09 08:17:33 +00:00
case RAIL_TILE_SIGNALS :
2014-01-14 20:32:07 +00:00
if ( flags & DC_EXEC ) CheckRemoveSignalsFromTile ( tile ) ;
// FALL THROUGH
2006-05-09 08:17:33 +00:00
case RAIL_TILE_NORMAL : {
2011-11-04 10:22:27 +00:00
Slope tileh = GetTileSlope ( tile ) ;
2010-10-30 17:51:07 +00:00
/* Is there flat water on the lower halftile that gets cleared expensively? */
2008-01-25 16:51:35 +00:00
bool water_ground = ( GetRailGroundType ( tile ) = = RAIL_GROUND_WATER & & IsSlopeWithOneCornerRaised ( tileh ) ) ;
2007-10-20 21:05:18 +00:00
2006-12-29 16:40:22 +00:00
TrackBits tracks = GetTrackBits ( tile ) ;
2007-01-10 18:56:51 +00:00
while ( tracks ! = TRACK_BIT_NONE ) {
2007-01-11 10:34:42 +00:00
Track track = RemoveFirstTrack ( & tracks ) ;
2010-02-15 19:52:40 +00:00
CommandCost ret = DoCommand ( tile , 0 , track , flags , CMD_REMOVE_SINGLE_RAIL ) ;
2010-03-14 12:58:51 +00:00
if ( ret . Failed ( ) ) return ret ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( ret ) ;
2005-03-23 20:02:28 +00:00
}
2007-10-20 21:05:18 +00:00
2012-12-26 13:01:28 +00:00
/* 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 . */
if ( water_ground & & ! ( flags & DC_BANKRUPT ) & & Company : : IsValidID ( _current_company ) ) {
2010-03-05 21:20:22 +00:00
CommandCost ret = EnsureNoVehicleOnGround ( tile ) ;
if ( ret . Failed ( ) ) return ret ;
2008-06-12 11:15:43 +00:00
2017-07-30 13:27:42 +00:00
if ( _game_mode ! = GM_EDITOR & & ! _settings_game . construction . enable_remove_water & & ! ( flags & DC_ALLOW_REMOVE_WATER ) ) return_cmd_error ( STR_ERROR_CAN_T_BUILD_ON_WATER ) ;
2007-10-20 21:05:18 +00:00
/* The track was removed, and left a coast tile. Now also clear the water. */
2020-05-09 21:41:01 +00:00
if ( flags & DC_EXEC ) {
bool remove = IsDockingTile ( tile ) ;
DoClearSquare ( tile ) ;
if ( remove ) RemoveDockingTile ( tile ) ;
}
2009-11-07 22:47:54 +00:00
cost . AddCost ( _price [ PR_CLEAR_WATER ] ) ;
2007-10-20 21:05:18 +00:00
}
2005-03-23 20:02:28 +00:00
return cost ;
2004-08-09 17:04:08 +00:00
}
2007-02-27 23:36:28 +00:00
case RAIL_TILE_DEPOT :
return RemoveTrainDepot ( tile , flags ) ;
2005-03-23 20:02:28 +00:00
default :
return CMD_ERROR ;
}
2004-08-09 17:04:08 +00:00
}
2007-10-20 16:50:48 +00:00
/**
* Get surface height in point ( x , y )
2008-08-25 20:54:34 +00:00
* On tiles with halftile foundations move ( x , y ) to a safe point wrt . track
2007-10-20 16:50:48 +00:00
*/
static uint GetSaveSlopeZ ( uint x , uint y , Track track )
{
switch ( track ) {
case TRACK_UPPER : x & = ~ 0xF ; y & = ~ 0xF ; break ;
case TRACK_LOWER : x | = 0xF ; y | = 0xF ; break ;
case TRACK_LEFT : x | = 0xF ; y & = ~ 0xF ; break ;
case TRACK_RIGHT : x & = ~ 0xF ; y | = 0xF ; break ;
default : break ;
}
2011-11-04 10:18:13 +00:00
return GetSlopePixelZ ( x , y ) ;
2007-10-20 16:50:48 +00:00
}
2020-02-20 19:28:53 +00:00
static void GetSignalXY ( TileIndex tile , uint pos , uint & x , uint & y )
2004-08-09 17:04:08 +00:00
{
2012-05-01 15:53:51 +00:00
bool side ;
switch ( _settings_game . construction . train_signal_side ) {
case 0 : side = false ; break ; // left
case 2 : side = true ; break ; // right
default : side = _settings_game . vehicle . road_side ! = 0 ; break ; // driving side
}
2006-04-11 10:19:50 +00:00
static const Point SignalPositions [ 2 ] [ 12 ] = {
2009-03-15 00:32:18 +00:00
{ // Signals on the left side
2006-04-11 10:19:50 +00:00
/* LEFT LEFT RIGHT RIGHT UPPER UPPER */
{ 8 , 5 } , { 14 , 1 } , { 1 , 14 } , { 9 , 11 } , { 1 , 0 } , { 3 , 10 } ,
/* LOWER LOWER X X Y Y */
{ 11 , 4 } , { 14 , 14 } , { 11 , 3 } , { 4 , 13 } , { 3 , 4 } , { 11 , 13 }
2009-03-15 00:32:18 +00:00
} , { // Signals on the right side
2006-04-11 10:19:50 +00:00
/* LEFT LEFT RIGHT RIGHT UPPER UPPER */
{ 14 , 1 } , { 12 , 10 } , { 4 , 6 } , { 1 , 14 } , { 10 , 4 } , { 0 , 1 } ,
/* LOWER LOWER X X Y Y */
{ 14 , 14 } , { 5 , 12 } , { 11 , 13 } , { 4 , 3 } , { 13 , 4 } , { 3 , 11 }
}
} ;
2004-08-09 17:04:08 +00:00
2020-02-20 19:28:53 +00:00
x = TileX ( tile ) * TILE_SIZE + SignalPositions [ side ] [ pos ] . x ;
y = TileY ( tile ) * TILE_SIZE + SignalPositions [ side ] [ pos ] . y ;
}
static bool _signal_sprite_oversized = false ;
2020-02-28 23:10:23 +00:00
static const int SIGNAL_DIRTY_LEFT = 14 * ZOOM_LVL_BASE ;
static const int SIGNAL_DIRTY_RIGHT = 14 * ZOOM_LVL_BASE ;
2020-02-20 19:28:53 +00:00
static const int SIGNAL_DIRTY_TOP = 30 * ZOOM_LVL_BASE ;
static const int SIGNAL_DIRTY_BOTTOM = 5 * ZOOM_LVL_BASE ;
void DrawSingleSignal ( TileIndex tile , const RailtypeInfo * rti , Track track , SignalState condition , SignalOffsets image , uint pos , SignalType type , SignalVariant variant , bool show_restricted )
{
uint x , y ;
GetSignalXY ( tile , pos , x , y ) ;
2006-04-17 19:09:30 +00:00
2020-09-26 10:53:44 +00:00
SpriteID sprite = GetCustomSignalSprite ( rti , tile , type , variant , condition , false , show_restricted ) ;
2020-09-26 10:21:49 +00:00
bool is_custom_sprite = ( sprite ! = 0 ) ;
if ( sprite ! = 0 ) {
sprite + = image ;
} else if ( type = = SIGTYPE_PROG ) {
2019-04-02 17:19:28 +00:00
if ( variant = = SIG_SEMAPHORE ) {
sprite = SPR_PROGSIGNAL_BASE + image * 2 + condition ;
} else {
sprite = SPR_PROGSIGNAL_BASE + 16 + image * 2 + condition ;
}
2020-09-26 10:21:49 +00:00
2019-04-02 17:19:28 +00:00
extern int _progsig_grf_file_index ;
is_custom_sprite = ( int ) GetOriginFileSlot ( sprite ) ! = _progsig_grf_file_index ;
2006-04-23 15:57:34 +00:00
} else {
2020-09-26 10:21:49 +00:00
/* Normal electric signals are stored in a different sprite block than all other signals. */
sprite = ( type = = SIGTYPE_NORMAL & & variant = = SIG_ELECTRIC ) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16 ;
sprite + = type * 16 + variant * 64 + image * 2 + condition + ( IsSignalSpritePBS ( type ) ? 64 : 0 ) ;
int origin_slot = GetOriginFileSlot ( sprite ) ;
extern int _first_user_grf_file_index ;
extern int _opengfx_grf_file_index ;
is_custom_sprite = origin_slot ! = _opengfx_grf_file_index & & ( origin_slot > = _first_user_grf_file_index ) ;
2015-12-09 01:03:37 +00:00
}
2006-04-17 19:09:30 +00:00
2020-09-26 10:53:44 +00:00
if ( is_custom_sprite & & show_restricted & & _settings_client . gui . show_restricted_signal_default & & ! HasBit ( rti - > ctrl_flags , RTCF_RESTRICTEDSIG ) ) {
2015-12-09 01:01:37 +00:00
/* Use duplicate sprite block, instead of GRF-specified signals */
2019-04-02 17:19:28 +00:00
if ( type = = SIGTYPE_PROG ) {
2020-09-26 10:21:49 +00:00
if ( variant = = SIG_SEMAPHORE ) {
sprite = SPR_DUP_PROGSIGNAL_BASE + image * 2 + condition ;
} else {
sprite = SPR_DUP_PROGSIGNAL_BASE + 16 + image * 2 + condition ;
}
2019-04-02 17:19:28 +00:00
} else {
sprite = ( type = = SIGTYPE_NORMAL & & variant = = SIG_ELECTRIC ) ? SPR_DUP_ORIGINAL_SIGNALS_BASE : SPR_DUP_SIGNALS_BASE - 16 ;
sprite + = type * 16 + variant * 64 + image * 2 + condition + ( IsSignalSpritePBS ( type ) ? 64 : 0 ) ;
}
2015-12-09 01:01:37 +00:00
is_custom_sprite = false ;
2006-04-23 15:57:34 +00:00
}
2006-04-17 19:09:30 +00:00
2015-12-09 01:01:37 +00:00
if ( ! is_custom_sprite & & show_restricted ) {
2015-08-19 20:56:22 +00:00
if ( type = = SIGTYPE_PBS | | type = = SIGTYPE_PBS_ONEWAY ) {
2015-08-25 17:22:18 +00:00
static const SubSprite lower_part = { - 50 , - 10 , 50 , 50 } ;
static const SubSprite upper_part = { - 50 , - 50 , 50 , - 11 } ;
2015-08-19 20:56:22 +00:00
AddSortableSpriteToDraw ( sprite , SPR_TRACERESTRICT_BASE , x , y , 1 , 1 , BB_HEIGHT_UNDER_BRIDGE , GetSaveSlopeZ ( x , y , track ) , false , 0 , 0 , 0 , & lower_part ) ;
AddSortableSpriteToDraw ( sprite , PAL_NONE , x , y , 1 , 1 , BB_HEIGHT_UNDER_BRIDGE , GetSaveSlopeZ ( x , y , track ) , false , 0 , 0 , 0 , & upper_part ) ;
} else {
AddSortableSpriteToDraw ( sprite , SPR_TRACERESTRICT_BASE + 1 , x , y , 1 , 1 , BB_HEIGHT_UNDER_BRIDGE , GetSaveSlopeZ ( x , y , track ) ) ;
}
} else {
AddSortableSpriteToDraw ( sprite , PAL_NONE , x , y , 1 , 1 , BB_HEIGHT_UNDER_BRIDGE , GetSaveSlopeZ ( x , y , track ) ) ;
2014-01-14 20:32:07 +00:00
}
2020-02-20 19:28:53 +00:00
const Sprite * sp = GetSprite ( sprite , ST_NORMAL ) ;
if ( sp - > x_offs < - SIGNAL_DIRTY_LEFT | | sp - > x_offs + sp - > width > SIGNAL_DIRTY_RIGHT | | sp - > y_offs < - SIGNAL_DIRTY_TOP | | sp - > y_offs + sp - > height > SIGNAL_DIRTY_BOTTOM ) {
_signal_sprite_oversized = true ;
}
2004-08-09 17:04:08 +00:00
}
2018-07-08 22:04:30 +00:00
static void DrawSingleSignal ( TileIndex tile , const RailtypeInfo * rti , Track track , SignalState condition , SignalOffsets image , uint pos )
{
SignalType type = GetSignalType ( tile , track ) ;
SignalVariant variant = GetSignalVariant ( tile , track ) ;
2019-04-11 17:14:13 +00:00
bool show_restricted = ( variant = = SIG_ELECTRIC ) & & IsRestrictedSignal ( tile ) & & ( GetExistingTraceRestrictProgram ( tile , track ) ! = nullptr ) ;
2018-07-08 22:04:30 +00:00
DrawSingleSignal ( tile , rti , track , condition , image , pos , type , variant , show_restricted ) ;
2004-08-09 17:04:08 +00:00
}
2020-02-20 19:28:53 +00:00
void MarkSingleSignalDirty ( TileIndex tile , Trackdir td )
{
if ( _signal_sprite_oversized | | td > = TRACKDIR_END ) {
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
2020-02-20 19:28:53 +00:00
return ;
}
static const uint8 trackdir_to_pos [ TRACKDIR_END ] = {
8 , // TRACKDIR_X_NE
10 , // TRACKDIR_Y_SE
4 , // TRACKDIR_UPPER_E
6 , // TRACKDIR_LOWER_E
0 , // TRACKDIR_LEFT_S
2 , // TRACKDIR_RIGHT_S
0 , // TRACKDIR_RVREV_NE
0 , // TRACKDIR_RVREV_SE
9 , // TRACKDIR_X_SW
11 , // TRACKDIR_Y_NW
5 , // TRACKDIR_UPPER_W
7 , // TRACKDIR_LOWER_W
1 , // TRACKDIR_LEFT_N
3 , // TRACKDIR_RIGHT_N
0 , // TRACKDIR_RVREV_SW
0 , // TRACKDIR_RVREV_NW
} ;
uint x , y ;
GetSignalXY ( tile , trackdir_to_pos [ td ] , x , y ) ;
Point pt = RemapCoords ( x , y , GetSaveSlopeZ ( x , y , TrackdirToTrack ( td ) ) ) ;
MarkAllViewportsDirty (
pt . x - SIGNAL_DIRTY_LEFT ,
pt . y - SIGNAL_DIRTY_TOP ,
pt . x + SIGNAL_DIRTY_RIGHT ,
pt . y + SIGNAL_DIRTY_BOTTOM ,
2020-10-01 17:50:31 +00:00
VMDF_NOT_MAP_MODE
2020-02-20 19:28:53 +00:00
) ;
}
2004-08-09 17:04:08 +00:00
static uint32 _drawtile_track_palette ;
2015-07-26 12:28:34 +00:00
/** Offsets for drawing fences */
struct FenceOffset {
Corner height_ref ; //!< Corner to use height offset from.
int x_offs ; //!< Bounding box X offset.
int y_offs ; //!< Bounding box Y offset.
int x_size ; //!< Bounding box X size.
int y_size ; //!< Bounding box Y size.
} ;
2004-08-09 17:04:08 +00:00
2015-07-26 12:28:34 +00:00
/** Offsets for drawing fences */
static FenceOffset _fence_offsets [ ] = {
{ CORNER_INVALID , 0 , 1 , 16 , 1 } , // RFO_FLAT_X_NW
{ CORNER_INVALID , 1 , 0 , 1 , 16 } , // RFO_FLAT_Y_NE
{ CORNER_W , 8 , 8 , 1 , 1 } , // RFO_FLAT_LEFT
{ CORNER_N , 8 , 8 , 1 , 1 } , // RFO_FLAT_UPPER
{ CORNER_INVALID , 0 , 1 , 16 , 1 } , // RFO_SLOPE_SW_NW
{ CORNER_INVALID , 1 , 0 , 1 , 16 } , // RFO_SLOPE_SE_NE
{ CORNER_INVALID , 0 , 1 , 16 , 1 } , // RFO_SLOPE_NE_NW
{ CORNER_INVALID , 1 , 0 , 1 , 16 } , // RFO_SLOPE_NW_NE
{ CORNER_INVALID , 0 , 15 , 16 , 1 } , // RFO_FLAT_X_SE
{ CORNER_INVALID , 15 , 0 , 1 , 16 } , // RFO_FLAT_Y_SW
{ CORNER_E , 8 , 8 , 1 , 1 } , // RFO_FLAT_RIGHT
{ CORNER_S , 8 , 8 , 1 , 1 } , // RFO_FLAT_LOWER
{ CORNER_INVALID , 0 , 15 , 16 , 1 } , // RFO_SLOPE_SW_SE
{ CORNER_INVALID , 15 , 0 , 1 , 16 } , // RFO_SLOPE_SE_SW
{ CORNER_INVALID , 0 , 15 , 16 , 1 } , // RFO_SLOPE_NE_SE
{ CORNER_INVALID , 15 , 0 , 1 , 16 } , // RFO_SLOPE_NW_SW
} ;
2004-08-09 17:04:08 +00:00
2015-07-26 12:28:34 +00:00
/**
* Draw a track fence .
* @ param ti Tile drawing information .
* @ param base_image First fence sprite .
* @ param num_sprites Number of fence sprites .
* @ param rfo Fence to draw .
*/
static void DrawTrackFence ( const TileInfo * ti , SpriteID base_image , uint num_sprites , RailFenceOffset rfo )
2004-08-09 17:04:08 +00:00
{
2015-07-26 12:28:34 +00:00
int z = ti - > z ;
if ( _fence_offsets [ rfo ] . height_ref ! = CORNER_INVALID ) {
z + = GetSlopePixelZInCorner ( RemoveHalftileSlope ( ti - > tileh ) , _fence_offsets [ rfo ] . height_ref ) ;
}
AddSortableSpriteToDraw ( base_image + ( rfo % num_sprites ) , _drawtile_track_palette ,
ti - > x + _fence_offsets [ rfo ] . x_offs ,
ti - > y + _fence_offsets [ rfo ] . y_offs ,
_fence_offsets [ rfo ] . x_size ,
_fence_offsets [ rfo ] . y_size ,
4 , z ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-23 16:08:58 +00:00
/**
2015-07-26 12:28:34 +00:00
* Draw fence at NW border matching the tile slope .
2007-07-23 16:08:58 +00:00
*/
2015-07-26 12:28:34 +00:00
static void DrawTrackFence_NW ( const TileInfo * ti , SpriteID base_image , uint num_sprites )
2004-08-09 17:04:08 +00:00
{
2015-07-26 12:28:34 +00:00
RailFenceOffset rfo = RFO_FLAT_X_NW ;
if ( ti - > tileh & SLOPE_NW ) rfo = ( ti - > tileh & SLOPE_W ) ? RFO_SLOPE_SW_NW : RFO_SLOPE_NE_NW ;
DrawTrackFence ( ti , base_image , num_sprites , rfo ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-23 16:08:58 +00:00
/**
2015-07-26 12:28:34 +00:00
* Draw fence at SE border matching the tile slope .
2007-07-23 16:08:58 +00:00
*/
2015-07-26 12:28:34 +00:00
static void DrawTrackFence_SE ( const TileInfo * ti , SpriteID base_image , uint num_sprites )
2004-08-09 17:04:08 +00:00
{
2015-07-26 12:28:34 +00:00
RailFenceOffset rfo = RFO_FLAT_X_SE ;
if ( ti - > tileh & SLOPE_SE ) rfo = ( ti - > tileh & SLOPE_S ) ? RFO_SLOPE_SW_SE : RFO_SLOPE_NE_SE ;
DrawTrackFence ( ti , base_image , num_sprites , rfo ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-23 16:08:58 +00:00
/**
2015-07-26 12:28:34 +00:00
* Draw fence at NE border matching the tile slope .
2007-07-23 16:08:58 +00:00
*/
2015-07-26 12:28:34 +00:00
static void DrawTrackFence_NE ( const TileInfo * ti , SpriteID base_image , uint num_sprites )
2004-08-09 17:04:08 +00:00
{
2015-07-26 12:28:34 +00:00
RailFenceOffset rfo = RFO_FLAT_Y_NE ;
if ( ti - > tileh & SLOPE_NE ) rfo = ( ti - > tileh & SLOPE_E ) ? RFO_SLOPE_SE_NE : RFO_SLOPE_NW_NE ;
DrawTrackFence ( ti , base_image , num_sprites , rfo ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-23 16:08:58 +00:00
/**
2015-07-26 12:28:34 +00:00
* Draw fence at SW border matching the tile slope .
2007-07-23 16:08:58 +00:00
*/
2015-07-26 12:28:34 +00:00
static void DrawTrackFence_SW ( const TileInfo * ti , SpriteID base_image , uint num_sprites )
2004-08-09 17:04:08 +00:00
{
2015-07-26 12:28:34 +00:00
RailFenceOffset rfo = RFO_FLAT_Y_SW ;
if ( ti - > tileh & SLOPE_SW ) rfo = ( ti - > tileh & SLOPE_S ) ? RFO_SLOPE_SE_SW : RFO_SLOPE_NW_SW ;
DrawTrackFence ( ti , base_image , num_sprites , rfo ) ;
2004-08-09 17:04:08 +00:00
}
2015-07-26 12:28:34 +00:00
/**
* Draw track fences .
* @ param ti Tile drawing information .
* @ param rti Rail type information .
*/
2020-05-18 23:41:35 +00:00
void DrawTrackDetails ( const TileInfo * ti , const RailtypeInfo * rti , const RailGroundType rgt )
2004-08-09 17:04:08 +00:00
{
2010-07-11 17:28:19 +00:00
/* Base sprite for track fences.
* Note : Halftile slopes only have fences on the upper part . */
2015-07-26 12:28:34 +00:00
uint num_sprites = 0 ;
2015-07-31 21:43:40 +00:00
SpriteID base_image = GetCustomRailSprite ( rti , ti - > tile , RTSG_FENCES , IsHalftileSlope ( ti - > tileh ) ? TCX_UPPER_HALFTILE : TCX_NORMAL , & num_sprites ) ;
2015-07-26 12:28:34 +00:00
if ( base_image = = 0 ) {
base_image = SPR_TRACK_FENCE_FLAT_X ;
num_sprites = 8 ;
}
assert ( num_sprites > 0 ) ;
2009-01-13 08:39:25 +00:00
2020-05-18 23:41:35 +00:00
switch ( rgt ) {
2015-07-26 12:28:34 +00:00
case RAIL_GROUND_FENCE_NW : DrawTrackFence_NW ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_SE : DrawTrackFence_SE ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_SENW : DrawTrackFence_NW ( ti , base_image , num_sprites ) ;
DrawTrackFence_SE ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_NE : DrawTrackFence_NE ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_SW : DrawTrackFence_SW ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_NESW : DrawTrackFence_NE ( ti , base_image , num_sprites ) ;
DrawTrackFence_SW ( ti , base_image , num_sprites ) ; break ;
case RAIL_GROUND_FENCE_VERT1 : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_LEFT ) ; break ;
case RAIL_GROUND_FENCE_VERT2 : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_RIGHT ) ; break ;
case RAIL_GROUND_FENCE_HORIZ1 : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_UPPER ) ; break ;
case RAIL_GROUND_FENCE_HORIZ2 : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_LOWER ) ; break ;
2008-01-25 16:51:35 +00:00
case RAIL_GROUND_WATER : {
Corner track_corner ;
if ( IsHalftileSlope ( ti - > tileh ) ) {
/* Steep slope or one-corner-raised slope with halftile foundation */
track_corner = GetHalftileSlopeCorner ( ti - > tileh ) ;
} else {
/* Three-corner-raised slope */
track_corner = OppositeCorner ( GetHighestSlopeCorner ( ComplementSlope ( ti - > tileh ) ) ) ;
}
switch ( track_corner ) {
2015-07-26 12:28:34 +00:00
case CORNER_W : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_LEFT ) ; break ;
case CORNER_S : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_LOWER ) ; break ;
case CORNER_E : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_RIGHT ) ; break ;
case CORNER_N : DrawTrackFence ( ti , base_image , num_sprites , RFO_FLAT_UPPER ) ; break ;
2007-10-20 21:05:18 +00:00
default : NOT_REACHED ( ) ;
}
break ;
2008-01-25 16:51:35 +00:00
}
2006-06-18 09:37:08 +00:00
default : break ;
}
2004-08-09 17:04:08 +00:00
}
2010-02-07 22:22:54 +00:00
/* SubSprite for drawing the track halftile of 'three-corners-raised'-sloped rail sprites. */
static const int INF = 1000 ; // big number compared to tilesprite size
static const SubSprite _halftile_sub_sprite [ 4 ] = {
{ - INF , - INF , 32 - 33 , INF } , // CORNER_W, clip 33 pixels from right
{ - INF , 0 + 7 , INF , INF } , // CORNER_S, clip 7 pixels from top
{ - 31 + 33 , - INF , INF , INF } , // CORNER_E, clip 33 pixels from left
{ - INF , - INF , INF , 30 - 23 } // CORNER_N, clip 23 pixels from bottom
} ;
2019-01-04 11:51:16 +00:00
static const SubSprite _dual_track_halftile_sub_sprite [ 4 ] = {
{ - INF , - INF , 32 - 33 , INF } , // CORNER_W, clip 33 pixels from right
{ - INF , 0 + 15 , INF , INF } , // CORNER_S, clip 15 pixels from top
{ - 31 + 33 , - INF , INF , INF } , // CORNER_E, clip 33 pixels from left
{ - INF , - INF , INF , 30 - 15 } // CORNER_N, clip 15 pixels from bottom
} ;
2010-02-07 22:22:54 +00:00
static inline void DrawTrackSprite ( SpriteID sprite , PaletteID pal , const TileInfo * ti , Slope s )
{
2019-04-10 21:07:06 +00:00
DrawGroundSprite ( sprite , pal , nullptr , 0 , ( ti - > tileh & s ) ? - 8 : 0 ) ;
2010-02-07 22:22:54 +00:00
}
2018-07-03 18:09:10 +00:00
static RailGroundType GetRailOrBridgeGroundType ( TileInfo * ti ) {
if ( IsTileType ( ti - > tile , MP_TUNNELBRIDGE ) ) {
2020-05-18 23:41:35 +00:00
return GetTunnelBridgeGroundType ( ti - > tile ) ;
2018-07-03 18:09:10 +00:00
} else {
return GetRailGroundType ( ti - > tile ) ;
}
}
2018-12-21 03:27:58 +00:00
static void DrawTrackBitsOverlay ( TileInfo * ti , TrackBits track , const RailtypeInfo * rti , RailGroundType rgt , bool is_bridge , Corner halftile_corner , Corner draw_half_tile )
2010-02-07 22:22:54 +00:00
{
2018-12-21 03:27:58 +00:00
if ( halftile_corner ! = CORNER_INVALID ) track & = ~ CornerToTrackBits ( halftile_corner ) ;
2010-02-07 22:22:54 +00:00
2018-12-21 03:27:58 +00:00
if ( halftile_corner ! = CORNER_INVALID | | draw_half_tile = = CORNER_INVALID ) {
/* Draw ground */
if ( rgt = = RAIL_GROUND_WATER ) {
if ( track ! = TRACK_BIT_NONE | | IsSteepSlope ( ti - > tileh ) ) {
/* three-corner-raised slope or steep slope with track on upper part */
DrawShoreTile ( ti - > tileh ) ;
} else {
/* single-corner-raised slope with track on upper part */
DrawGroundSprite ( SPR_FLAT_WATER_TILE , PAL_NONE ) ;
}
2010-02-07 22:22:54 +00:00
} else {
2018-12-21 03:27:58 +00:00
SpriteID image ;
2010-02-07 22:22:54 +00:00
2018-12-21 03:27:58 +00:00
switch ( rgt ) {
case RAIL_GROUND_BARREN : image = SPR_FLAT_BARE_LAND ; break ;
case RAIL_GROUND_ICE_DESERT : image = SPR_FLAT_SNOW_DESERT_TILE ; break ;
default : image = SPR_FLAT_GRASS_TILE ; break ;
}
2010-02-07 22:22:54 +00:00
2018-12-21 03:27:58 +00:00
image + = SlopeToSpriteOffset ( ti - > tileh ) ;
2010-02-07 22:22:54 +00:00
2019-04-11 17:14:13 +00:00
const SubSprite * sub = nullptr ;
2019-01-04 11:51:16 +00:00
if ( draw_half_tile ! = CORNER_INVALID ) sub = & ( _halftile_sub_sprite [ draw_half_tile ] ) ;
2018-12-21 03:27:58 +00:00
DrawGroundSprite ( image , PAL_NONE , sub ) ;
}
2010-02-07 22:22:54 +00:00
}
2019-03-09 02:53:43 +00:00
bool no_combine = ti - > tileh = = SLOPE_FLAT & & HasBit ( rti - > flags , RTF_NO_SPRITE_COMBINE ) ;
2010-02-07 22:22:54 +00:00
SpriteID overlay = GetCustomRailSprite ( rti , ti - > tile , RTSG_OVERLAY ) ;
2019-03-09 02:53:43 +00:00
SpriteID ground = GetCustomRailSprite ( rti , ti - > tile , no_combine ? RTSG_GROUND_COMPLETE : RTSG_GROUND ) ;
2018-07-03 18:09:10 +00:00
TrackBits pbs = TRACK_BIT_NONE ;
if ( _settings_client . gui . show_track_reservation ) {
pbs = is_bridge ? GetTunnelBridgeReservationTrackBits ( ti - > tile ) : GetRailReservationTrackBits ( ti - > tile ) ;
}
2010-02-07 22:22:54 +00:00
if ( track = = TRACK_BIT_NONE ) {
/* Half-tile foundation, no track here? */
2019-03-09 02:53:43 +00:00
} else if ( no_combine ) {
/* Use trackbits as direct index from ground sprite, subtract 1
* because there is no sprite for no bits . */
DrawGroundSprite ( ground + track - 1 , PAL_NONE ) ;
/* Draw reserved track bits */
if ( pbs & TRACK_BIT_X ) DrawGroundSprite ( overlay + RTO_X , PALETTE_CRASH ) ;
if ( pbs & TRACK_BIT_Y ) DrawGroundSprite ( overlay + RTO_Y , PALETTE_CRASH ) ;
if ( pbs & TRACK_BIT_UPPER ) DrawTrackSprite ( overlay + RTO_N , PALETTE_CRASH , ti , SLOPE_N ) ;
if ( pbs & TRACK_BIT_LOWER ) DrawTrackSprite ( overlay + RTO_S , PALETTE_CRASH , ti , SLOPE_S ) ;
if ( pbs & TRACK_BIT_RIGHT ) DrawTrackSprite ( overlay + RTO_E , PALETTE_CRASH , ti , SLOPE_E ) ;
if ( pbs & TRACK_BIT_LEFT ) DrawTrackSprite ( overlay + RTO_W , PALETTE_CRASH , ti , SLOPE_W ) ;
2010-02-07 22:22:54 +00:00
} else if ( ti - > tileh = = SLOPE_NW & & track = = TRACK_BIT_Y ) {
DrawGroundSprite ( ground + RTO_SLOPE_NW , PAL_NONE ) ;
2015-03-28 14:00:39 +00:00
if ( pbs ! = TRACK_BIT_NONE ) DrawGroundSprite ( overlay + RTO_SLOPE_NW , PALETTE_CRASH ) ;
2010-02-07 22:22:54 +00:00
} else if ( ti - > tileh = = SLOPE_NE & & track = = TRACK_BIT_X ) {
DrawGroundSprite ( ground + RTO_SLOPE_NE , PAL_NONE ) ;
2015-03-28 14:00:39 +00:00
if ( pbs ! = TRACK_BIT_NONE ) DrawGroundSprite ( overlay + RTO_SLOPE_NE , PALETTE_CRASH ) ;
2010-02-07 22:22:54 +00:00
} else if ( ti - > tileh = = SLOPE_SE & & track = = TRACK_BIT_Y ) {
DrawGroundSprite ( ground + RTO_SLOPE_SE , PAL_NONE ) ;
2015-03-28 14:00:39 +00:00
if ( pbs ! = TRACK_BIT_NONE ) DrawGroundSprite ( overlay + RTO_SLOPE_SE , PALETTE_CRASH ) ;
2010-02-07 22:22:54 +00:00
} else if ( ti - > tileh = = SLOPE_SW & & track = = TRACK_BIT_X ) {
DrawGroundSprite ( ground + RTO_SLOPE_SW , PAL_NONE ) ;
2015-03-28 14:00:39 +00:00
if ( pbs ! = TRACK_BIT_NONE ) DrawGroundSprite ( overlay + RTO_SLOPE_SW , PALETTE_CRASH ) ;
2010-02-07 22:22:54 +00:00
} else {
switch ( track ) {
/* Draw single ground sprite when not overlapping. No track overlay
* is necessary for these sprites . */
case TRACK_BIT_X : DrawGroundSprite ( ground + RTO_X , PAL_NONE ) ; break ;
case TRACK_BIT_Y : DrawGroundSprite ( ground + RTO_Y , PAL_NONE ) ; break ;
case TRACK_BIT_UPPER : DrawTrackSprite ( ground + RTO_N , PAL_NONE , ti , SLOPE_N ) ; break ;
case TRACK_BIT_LOWER : DrawTrackSprite ( ground + RTO_S , PAL_NONE , ti , SLOPE_S ) ; break ;
case TRACK_BIT_RIGHT : DrawTrackSprite ( ground + RTO_E , PAL_NONE , ti , SLOPE_E ) ; break ;
case TRACK_BIT_LEFT : DrawTrackSprite ( ground + RTO_W , PAL_NONE , ti , SLOPE_W ) ; break ;
case TRACK_BIT_CROSS : DrawGroundSprite ( ground + RTO_CROSSING_XY , PAL_NONE ) ; break ;
case TRACK_BIT_HORZ : DrawTrackSprite ( ground + RTO_N , PAL_NONE , ti , SLOPE_N ) ;
DrawTrackSprite ( ground + RTO_S , PAL_NONE , ti , SLOPE_S ) ; break ;
case TRACK_BIT_VERT : DrawTrackSprite ( ground + RTO_E , PAL_NONE , ti , SLOPE_E ) ;
DrawTrackSprite ( ground + RTO_W , PAL_NONE , ti , SLOPE_W ) ; break ;
default :
/* We're drawing a junction tile */
if ( ( track & TRACK_BIT_3WAY_NE ) = = 0 ) {
DrawGroundSprite ( ground + RTO_JUNCTION_SW , PAL_NONE ) ;
} else if ( ( track & TRACK_BIT_3WAY_SW ) = = 0 ) {
DrawGroundSprite ( ground + RTO_JUNCTION_NE , PAL_NONE ) ;
} else if ( ( track & TRACK_BIT_3WAY_NW ) = = 0 ) {
DrawGroundSprite ( ground + RTO_JUNCTION_SE , PAL_NONE ) ;
} else if ( ( track & TRACK_BIT_3WAY_SE ) = = 0 ) {
DrawGroundSprite ( ground + RTO_JUNCTION_NW , PAL_NONE ) ;
} else {
DrawGroundSprite ( ground + RTO_JUNCTION_NSEW , PAL_NONE ) ;
}
/* Mask out PBS bits as we shall draw them afterwards anyway. */
track & = ~ pbs ;
/* Draw regular track bits */
if ( track & TRACK_BIT_X ) DrawGroundSprite ( overlay + RTO_X , PAL_NONE ) ;
if ( track & TRACK_BIT_Y ) DrawGroundSprite ( overlay + RTO_Y , PAL_NONE ) ;
if ( track & TRACK_BIT_UPPER ) DrawGroundSprite ( overlay + RTO_N , PAL_NONE ) ;
if ( track & TRACK_BIT_LOWER ) DrawGroundSprite ( overlay + RTO_S , PAL_NONE ) ;
if ( track & TRACK_BIT_RIGHT ) DrawGroundSprite ( overlay + RTO_E , PAL_NONE ) ;
if ( track & TRACK_BIT_LEFT ) DrawGroundSprite ( overlay + RTO_W , PAL_NONE ) ;
}
/* Draw reserved track bits */
if ( pbs & TRACK_BIT_X ) DrawGroundSprite ( overlay + RTO_X , PALETTE_CRASH ) ;
if ( pbs & TRACK_BIT_Y ) DrawGroundSprite ( overlay + RTO_Y , PALETTE_CRASH ) ;
if ( pbs & TRACK_BIT_UPPER ) DrawTrackSprite ( overlay + RTO_N , PALETTE_CRASH , ti , SLOPE_N ) ;
if ( pbs & TRACK_BIT_LOWER ) DrawTrackSprite ( overlay + RTO_S , PALETTE_CRASH , ti , SLOPE_S ) ;
if ( pbs & TRACK_BIT_RIGHT ) DrawTrackSprite ( overlay + RTO_E , PALETTE_CRASH , ti , SLOPE_E ) ;
if ( pbs & TRACK_BIT_LEFT ) DrawTrackSprite ( overlay + RTO_W , PALETTE_CRASH , ti , SLOPE_W ) ;
}
2018-12-21 03:27:58 +00:00
if ( IsValidCorner ( halftile_corner ) & & ( draw_half_tile = = halftile_corner | | draw_half_tile = = CORNER_INVALID ) ) {
2010-02-07 22:22:54 +00:00
DrawFoundation ( ti , HalftileFoundation ( halftile_corner ) ) ;
2010-08-09 10:59:30 +00:00
overlay = GetCustomRailSprite ( rti , ti - > tile , RTSG_OVERLAY , TCX_UPPER_HALFTILE ) ;
ground = GetCustomRailSprite ( rti , ti - > tile , RTSG_GROUND , TCX_UPPER_HALFTILE ) ;
2010-02-07 22:22:54 +00:00
/* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
Slope fake_slope = SlopeWithThreeCornersRaised ( OppositeCorner ( halftile_corner ) ) ;
SpriteID image ;
switch ( rgt ) {
case RAIL_GROUND_BARREN : image = SPR_FLAT_BARE_LAND ; break ;
case RAIL_GROUND_ICE_DESERT :
case RAIL_GROUND_HALF_SNOW : image = SPR_FLAT_SNOW_DESERT_TILE ; break ;
default : image = SPR_FLAT_GRASS_TILE ; break ;
}
2010-07-19 17:00:54 +00:00
image + = SlopeToSpriteOffset ( fake_slope ) ;
2010-02-07 22:22:54 +00:00
DrawGroundSprite ( image , PAL_NONE , & ( _halftile_sub_sprite [ halftile_corner ] ) ) ;
track = CornerToTrackBits ( halftile_corner ) ;
int offset ;
switch ( track ) {
default : NOT_REACHED ( ) ;
case TRACK_BIT_UPPER : offset = RTO_N ; break ;
case TRACK_BIT_LOWER : offset = RTO_S ; break ;
case TRACK_BIT_RIGHT : offset = RTO_E ; break ;
case TRACK_BIT_LEFT : offset = RTO_W ; break ;
}
DrawTrackSprite ( ground + offset , PAL_NONE , ti , fake_slope ) ;
2010-08-08 08:52:47 +00:00
if ( _settings_client . gui . show_track_reservation & & HasReservedTracks ( ti - > tile , track ) ) {
2010-02-07 22:22:54 +00:00
DrawTrackSprite ( overlay + offset , PALETTE_CRASH , ti , fake_slope ) ;
}
}
}
2004-08-09 17:04:08 +00:00
2005-09-29 20:20:34 +00:00
/**
* Draw ground sprite and track bits
* @ param ti TileInfo
* @ param track TrackBits to draw
2018-12-21 03:27:58 +00:00
* @ param rt Rail type
* @ param half_tile Half tile corner
2005-09-29 20:20:34 +00:00
*/
2018-12-21 03:27:58 +00:00
void DrawTrackBits ( TileInfo * ti , TrackBits track , RailType rt , RailGroundType rgt , bool is_bridge , Corner halftile_corner , Corner draw_half_tile )
2004-08-09 17:04:08 +00:00
{
2018-12-21 03:27:58 +00:00
const RailtypeInfo * rti = GetRailTypeInfo ( rt ) ;
2010-02-07 22:22:54 +00:00
if ( rti - > UsesOverlay ( ) ) {
2018-12-21 03:27:58 +00:00
DrawTrackBitsOverlay ( ti , track , rti , rgt , is_bridge , halftile_corner , draw_half_tile ) ;
2010-02-07 22:22:54 +00:00
return ;
}
2007-01-14 19:57:49 +00:00
SpriteID image ;
2010-01-21 01:38:13 +00:00
PaletteID pal = PAL_NONE ;
2019-04-10 21:07:06 +00:00
const SubSprite * sub = nullptr ;
2005-09-29 20:20:34 +00:00
bool junction = false ;
2019-01-04 11:51:16 +00:00
if ( halftile_corner ! = CORNER_INVALID ) {
track & = ~ CornerToTrackBits ( halftile_corner ) ;
if ( draw_half_tile ! = CORNER_INVALID ) {
sub = & ( _halftile_sub_sprite [ draw_half_tile ] ) ;
}
} else {
if ( draw_half_tile ! = CORNER_INVALID ) {
sub = & ( _dual_track_halftile_sub_sprite [ draw_half_tile ] ) ;
}
}
2018-12-21 03:27:58 +00:00
2007-04-04 01:35:16 +00:00
/* Select the sprite to use. */
2018-12-21 03:27:58 +00:00
if ( track = = 0 & & draw_half_tile ! = CORNER_INVALID ) {
image = 0 ;
} else if ( track = = 0 ) {
2007-10-20 21:04:14 +00:00
/* Clear ground (only track on halftile foundation) */
2007-10-20 21:05:18 +00:00
if ( rgt = = RAIL_GROUND_WATER ) {
2008-01-25 16:51:35 +00:00
if ( IsSteepSlope ( ti - > tileh ) ) {
DrawShoreTile ( ti - > tileh ) ;
image = 0 ;
} else {
image = SPR_FLAT_WATER_TILE ;
}
2007-10-20 21:05:18 +00:00
} else {
switch ( rgt ) {
case RAIL_GROUND_BARREN : image = SPR_FLAT_BARE_LAND ; break ;
2009-09-07 13:38:57 +00:00
case RAIL_GROUND_ICE_DESERT : image = SPR_FLAT_SNOW_DESERT_TILE ; break ;
2007-10-20 21:05:18 +00:00
default : image = SPR_FLAT_GRASS_TILE ; break ;
}
2010-07-19 17:00:54 +00:00
image + = SlopeToSpriteOffset ( ti - > tileh ) ;
2007-10-20 21:04:14 +00:00
}
} else {
if ( ti - > tileh ! = SLOPE_FLAT ) {
/* track on non-flat ground */
image = _track_sloped_sprites [ ti - > tileh - 1 ] + rti - > base_sprites . track_y ;
} else {
/* track on flat ground */
2019-03-12 19:41:37 +00:00
switch ( track ) {
/* single track, select combined track + ground sprite*/
case TRACK_BIT_Y : image = rti - > base_sprites . track_y ; break ;
case TRACK_BIT_X : image = rti - > base_sprites . track_y + 1 ; break ;
case TRACK_BIT_UPPER : image = rti - > base_sprites . track_y + 2 ; break ;
case TRACK_BIT_LOWER : image = rti - > base_sprites . track_y + 3 ; break ;
case TRACK_BIT_RIGHT : image = rti - > base_sprites . track_y + 4 ; break ;
case TRACK_BIT_LEFT : image = rti - > base_sprites . track_y + 5 ; break ;
case TRACK_BIT_CROSS : image = rti - > base_sprites . track_y + 6 ; break ;
/* double diagonal track, select combined track + ground sprite*/
case TRACK_BIT_HORZ : image = rti - > base_sprites . track_ns ; break ;
case TRACK_BIT_VERT : image = rti - > base_sprites . track_ns + 1 ; break ;
/* junction, select only ground sprite, handle track sprite later */
default :
junction = true ;
if ( ( track & TRACK_BIT_3WAY_NE ) = = 0 ) { image = rti - > base_sprites . ground ; break ; }
if ( ( track & TRACK_BIT_3WAY_SW ) = = 0 ) { image = rti - > base_sprites . ground + 1 ; break ; }
if ( ( track & TRACK_BIT_3WAY_NW ) = = 0 ) { image = rti - > base_sprites . ground + 2 ; break ; }
if ( ( track & TRACK_BIT_3WAY_SE ) = = 0 ) { image = rti - > base_sprites . ground + 3 ; break ; }
image = rti - > base_sprites . ground + 4 ;
break ;
}
2007-10-20 21:04:14 +00:00
}
2004-09-11 09:55:19 +00:00
2007-10-20 21:04:14 +00:00
switch ( rgt ) {
case RAIL_GROUND_BARREN : pal = PALETTE_TO_BARE_LAND ; break ;
case RAIL_GROUND_ICE_DESERT : image + = rti - > snow_offset ; break ;
2008-01-25 16:51:35 +00:00
case RAIL_GROUND_WATER : {
/* three-corner-raised slope */
DrawShoreTile ( ti - > tileh ) ;
Corner track_corner = OppositeCorner ( GetHighestSlopeCorner ( ComplementSlope ( ti - > tileh ) ) ) ;
sub = & ( _halftile_sub_sprite [ track_corner ] ) ;
break ;
}
2007-10-20 21:04:14 +00:00
default : break ;
}
2005-09-29 20:20:34 +00:00
}
2004-08-09 17:04:08 +00:00
2008-01-25 16:51:35 +00:00
if ( image ! = 0 ) DrawGroundSprite ( image , pal , sub ) ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* Draw track pieces individually for junction tiles */
2005-09-29 20:20:34 +00:00
if ( junction ) {
2009-12-15 13:59:20 +00:00
if ( track & TRACK_BIT_X ) DrawGroundSprite ( rti - > base_sprites . single_x , PAL_NONE ) ;
if ( track & TRACK_BIT_Y ) DrawGroundSprite ( rti - > base_sprites . single_y , PAL_NONE ) ;
2007-01-14 19:57:49 +00:00
if ( track & TRACK_BIT_UPPER ) DrawGroundSprite ( rti - > base_sprites . single_n , PAL_NONE ) ;
if ( track & TRACK_BIT_LOWER ) DrawGroundSprite ( rti - > base_sprites . single_s , PAL_NONE ) ;
if ( track & TRACK_BIT_LEFT ) DrawGroundSprite ( rti - > base_sprites . single_w , PAL_NONE ) ;
if ( track & TRACK_BIT_RIGHT ) DrawGroundSprite ( rti - > base_sprites . single_e , PAL_NONE ) ;
2005-09-29 20:20:34 +00:00
}
2007-10-20 21:04:14 +00:00
2008-08-02 22:47:34 +00:00
/* PBS debugging, draw reserved tracks darker */
2008-09-11 21:53:59 +00:00
if ( _game_mode ! = GM_MENU & & _settings_client . gui . show_track_reservation ) {
2009-06-07 13:25:21 +00:00
/* Get reservation, but mask track on halftile slope */
2018-07-03 18:09:10 +00:00
TrackBits pbs = ( is_bridge ? GetTunnelBridgeReservationTrackBits ( ti - > tile ) : GetRailReservationTrackBits ( ti - > tile ) ) & track ;
2008-08-02 22:47:34 +00:00
if ( pbs & TRACK_BIT_X ) {
if ( ti - > tileh = = SLOPE_FLAT | | ti - > tileh = = SLOPE_ELEVATED ) {
2009-12-15 13:59:20 +00:00
DrawGroundSprite ( rti - > base_sprites . single_x , PALETTE_CRASH ) ;
2008-08-02 22:47:34 +00:00
} else {
DrawGroundSprite ( _track_sloped_sprites [ ti - > tileh - 1 ] + rti - > base_sprites . single_sloped - 20 , PALETTE_CRASH ) ;
}
}
if ( pbs & TRACK_BIT_Y ) {
if ( ti - > tileh = = SLOPE_FLAT | | ti - > tileh = = SLOPE_ELEVATED ) {
2009-12-15 13:59:20 +00:00
DrawGroundSprite ( rti - > base_sprites . single_y , PALETTE_CRASH ) ;
2008-08-02 22:47:34 +00:00
} else {
DrawGroundSprite ( _track_sloped_sprites [ ti - > tileh - 1 ] + rti - > base_sprites . single_sloped - 20 , PALETTE_CRASH ) ;
}
}
2019-04-10 21:07:06 +00:00
if ( pbs & TRACK_BIT_UPPER ) DrawGroundSprite ( rti - > base_sprites . single_n , PALETTE_CRASH , nullptr , 0 , ti - > tileh & SLOPE_N ? - ( int ) TILE_HEIGHT : 0 ) ;
if ( pbs & TRACK_BIT_LOWER ) DrawGroundSprite ( rti - > base_sprites . single_s , PALETTE_CRASH , nullptr , 0 , ti - > tileh & SLOPE_S ? - ( int ) TILE_HEIGHT : 0 ) ;
if ( pbs & TRACK_BIT_LEFT ) DrawGroundSprite ( rti - > base_sprites . single_w , PALETTE_CRASH , nullptr , 0 , ti - > tileh & SLOPE_W ? - ( int ) TILE_HEIGHT : 0 ) ;
if ( pbs & TRACK_BIT_RIGHT ) DrawGroundSprite ( rti - > base_sprites . single_e , PALETTE_CRASH , nullptr , 0 , ti - > tileh & SLOPE_E ? - ( int ) TILE_HEIGHT : 0 ) ;
2008-08-02 22:47:34 +00:00
}
2018-12-21 03:27:58 +00:00
if ( IsValidCorner ( halftile_corner ) & & ( draw_half_tile = = halftile_corner | | draw_half_tile = = CORNER_INVALID ) ) {
2007-10-20 21:04:14 +00:00
DrawFoundation ( ti , HalftileFoundation ( halftile_corner ) ) ;
/* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
Slope fake_slope = SlopeWithThreeCornersRaised ( OppositeCorner ( halftile_corner ) ) ;
image = _track_sloped_sprites [ fake_slope - 1 ] + rti - > base_sprites . track_y ;
pal = PAL_NONE ;
switch ( rgt ) {
case RAIL_GROUND_BARREN : pal = PALETTE_TO_BARE_LAND ; break ;
2008-02-10 11:35:05 +00:00
case RAIL_GROUND_ICE_DESERT :
case RAIL_GROUND_HALF_SNOW : image + = rti - > snow_offset ; break ; // higher part has snow in this case too
2007-10-20 21:04:14 +00:00
default : break ;
}
DrawGroundSprite ( image , pal , & ( _halftile_sub_sprite [ halftile_corner ] ) ) ;
2008-08-02 22:47:34 +00:00
2009-06-07 13:25:21 +00:00
if ( _game_mode ! = GM_MENU & & _settings_client . gui . show_track_reservation & & HasReservedTracks ( ti - > tile , CornerToTrackBits ( halftile_corner ) ) ) {
2008-08-02 22:47:34 +00:00
static const byte _corner_to_track_sprite [ ] = { 3 , 1 , 2 , 0 } ;
2019-04-10 21:07:06 +00:00
DrawGroundSprite ( _corner_to_track_sprite [ halftile_corner ] + rti - > base_sprites . single_n , PALETTE_CRASH , nullptr , 0 , - ( int ) TILE_HEIGHT ) ;
2008-08-02 22:47:34 +00:00
}
2007-10-20 21:04:14 +00:00
}
2005-09-29 20:20:34 +00:00
}
2004-08-09 17:04:08 +00:00
2018-12-21 03:27:58 +00:00
void DrawTrackBits ( TileInfo * ti , TrackBits track )
{
const bool is_bridge = IsTileType ( ti - > tile , MP_TUNNELBRIDGE ) ;
RailGroundType rgt = GetRailOrBridgeGroundType ( ti ) ;
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation ( ti - > tileh , track ) ;
Corner halftile_corner = CORNER_INVALID ;
if ( IsNonContinuousFoundation ( f ) ) {
/* Save halftile corner */
halftile_corner = ( f = = FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner ( ti - > tileh ) : GetHalftileFoundationCorner ( f ) ) ;
/* Draw lower part first */
f = ( f = = FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE ) ;
}
DrawFoundation ( ti , f ) ;
/* DrawFoundation modifies ti */
RailType rt1 = GetRailType ( ti - > tile ) ;
RailType rt2 = GetTileSecondaryRailTypeIfValid ( ti - > tile ) ;
if ( rt2 = = INVALID_RAILTYPE | | rt1 = = rt2 ) {
DrawTrackBits ( ti , track , rt1 , rgt , is_bridge , halftile_corner , CORNER_INVALID ) ;
} else {
const bool is_bridge = IsTileType ( ti - > tile , MP_TUNNELBRIDGE ) ;
TrackBits primary_track = track & ( is_bridge ? GetAcrossBridgePossibleTrackBits ( ti - > tile ) : TRACK_BIT_RT_1 ) ;
TrackBits secondary_track = track ^ primary_track ;
assert ( ( primary_track & ( TRACK_BIT_HORZ | TRACK_BIT_VERT ) ) = = primary_track ) ;
assert ( ( primary_track & ( primary_track - 1 ) ) = = 0 ) ;
Track primary = FindFirstTrack ( primary_track ) ;
// TRACK_UPPER 2 -> CORNER_N 3
// TRACK_LOWER 3 -> CORNER_S 1
// TRACK_LEFT 4 -> CORNER_W 0
// TRACK_RIGHT 5 -> CORNER_E 2
Corner primary_corner = ( Corner ) ( ( 0x870 > > ( primary * 2 ) ) & 3 ) ;
if ( halftile_corner = = primary_corner ) {
std : : swap ( primary_track , secondary_track ) ;
std : : swap ( rt1 , rt2 ) ;
primary_corner = OppositeCorner ( primary_corner ) ;
}
if ( halftile_corner = = CORNER_INVALID ) {
// draw ground sprite
SpriteID image ;
switch ( rgt ) {
case RAIL_GROUND_BARREN : image = SPR_FLAT_BARE_LAND ; break ;
case RAIL_GROUND_ICE_DESERT : image = SPR_FLAT_SNOW_DESERT_TILE ; break ;
default : image = SPR_FLAT_GRASS_TILE ; break ;
}
image + = SlopeToSpriteOffset ( ti - > tileh ) ;
DrawGroundSprite ( image , PAL_NONE ) ;
}
DrawTrackBits ( ti , primary_track , rt1 , rgt , is_bridge , halftile_corner , primary_corner ) ;
DrawTrackBits ( ti , secondary_track , rt2 , rgt , is_bridge , halftile_corner , OppositeCorner ( primary_corner ) ) ;
}
}
2012-07-01 23:12:50 +00:00
static void DrawSignals ( TileIndex tile , TrackBits rails , const RailtypeInfo * rti )
2006-04-12 08:06:08 +00:00
{
2012-07-01 23:12:50 +00:00
# define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, rti, t, GetSingleSignalState(tile, x), y, z)
2006-04-12 08:06:08 +00:00
if ( ! ( rails & TRACK_BIT_Y ) ) {
if ( ! ( rails & TRACK_BIT_X ) ) {
if ( rails & TRACK_BIT_LEFT ) {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 2 , SIGNAL_TO_NORTH , 0 , TRACK_LEFT ) ;
MAYBE_DRAW_SIGNAL ( 3 , SIGNAL_TO_SOUTH , 1 , TRACK_LEFT ) ;
2006-04-12 08:06:08 +00:00
}
if ( rails & TRACK_BIT_RIGHT ) {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 0 , SIGNAL_TO_NORTH , 2 , TRACK_RIGHT ) ;
MAYBE_DRAW_SIGNAL ( 1 , SIGNAL_TO_SOUTH , 3 , TRACK_RIGHT ) ;
2006-04-12 08:06:08 +00:00
}
if ( rails & TRACK_BIT_UPPER ) {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 3 , SIGNAL_TO_WEST , 4 , TRACK_UPPER ) ;
MAYBE_DRAW_SIGNAL ( 2 , SIGNAL_TO_EAST , 5 , TRACK_UPPER ) ;
2006-04-12 08:06:08 +00:00
}
if ( rails & TRACK_BIT_LOWER ) {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 1 , SIGNAL_TO_WEST , 6 , TRACK_LOWER ) ;
MAYBE_DRAW_SIGNAL ( 0 , SIGNAL_TO_EAST , 7 , TRACK_LOWER ) ;
2006-04-12 08:06:08 +00:00
}
} else {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 3 , SIGNAL_TO_SOUTHWEST , 8 , TRACK_X ) ;
MAYBE_DRAW_SIGNAL ( 2 , SIGNAL_TO_NORTHEAST , 9 , TRACK_X ) ;
2006-04-12 08:06:08 +00:00
}
} else {
2008-03-05 11:41:26 +00:00
MAYBE_DRAW_SIGNAL ( 3 , SIGNAL_TO_SOUTHEAST , 10 , TRACK_Y ) ;
MAYBE_DRAW_SIGNAL ( 2 , SIGNAL_TO_NORTHWEST , 11 , TRACK_Y ) ;
2006-04-12 08:06:08 +00:00
}
}
2020-02-26 21:15:42 +00:00
static void DrawTile_Track ( TileInfo * ti , DrawTileProcParams params )
2005-09-29 20:20:34 +00:00
{
const RailtypeInfo * rti = GetRailTypeInfo ( GetRailType ( ti - > tile ) ) ;
2004-08-09 17:04:08 +00:00
2009-02-09 02:57:15 +00:00
_drawtile_track_palette = COMPANY_SPRITE_COLOUR ( GetTileOwner ( ti - > tile ) ) ;
2004-08-09 17:04:08 +00:00
2009-05-18 01:26:23 +00:00
if ( IsPlainRail ( ti - > tile ) ) {
2021-02-01 17:07:34 +00:00
if ( ! IsBridgeAbove ( ti - > tile ) & & params . min_visible_height > std : : max < int > ( SIGNAL_DIRTY_TOP , ( TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE ) * ZOOM_LVL_BASE ) & & ! _signal_sprite_oversized ) return ;
2020-02-26 21:15:42 +00:00
2006-03-19 12:06:12 +00:00
TrackBits rails = GetTrackBits ( ti - > tile ) ;
2004-08-09 17:04:08 +00:00
2006-06-28 06:10:20 +00:00
DrawTrackBits ( ti , rails ) ;
2005-07-04 14:58:55 +00:00
2020-05-18 23:41:35 +00:00
if ( HasBit ( _display_opt , DO_FULL_DETAIL ) ) DrawTrackDetails ( ti , rti , GetRailGroundType ( ti - > tile ) ) ;
2004-08-09 17:04:08 +00:00
2018-12-21 03:27:58 +00:00
if ( HasRailCatenaryDrawn ( GetRailType ( ti - > tile ) , GetTileSecondaryRailTypeIfValid ( ti - > tile ) ) ) DrawRailCatenary ( ti ) ;
2007-06-24 20:06:10 +00:00
2012-07-01 23:12:50 +00:00
if ( HasSignals ( ti - > tile ) ) DrawSignals ( ti - > tile , rails , rti ) ;
2004-08-09 17:04:08 +00:00
} else {
2009-07-22 08:59:57 +00:00
/* draw depot */
2009-01-10 00:31:47 +00:00
const DrawTileSprites * dts ;
2010-01-21 01:38:13 +00:00
PaletteID pal = PAL_NONE ;
2010-02-07 22:22:54 +00:00
SpriteID relocation ;
2004-08-09 17:04:08 +00:00
2007-07-26 16:51:10 +00:00
if ( ti - > tileh ! = SLOPE_FLAT ) DrawFoundation ( ti , FOUNDATION_LEVELED ) ;
2004-08-09 17:04:08 +00:00
2009-07-22 08:59:57 +00:00
if ( IsInvisibilitySet ( TO_BUILDINGS ) ) {
/* Draw rail instead of depot */
dts = & _depot_invisible_gfx_table [ GetRailDepotDirection ( ti - > tile ) ] ;
2006-08-05 16:54:55 +00:00
} else {
2009-07-22 08:59:57 +00:00
dts = & _depot_gfx_table [ GetRailDepotDirection ( ti - > tile ) ] ;
}
2006-05-06 09:40:12 +00:00
2010-02-15 19:52:40 +00:00
SpriteID image ;
2010-02-07 22:22:54 +00:00
if ( rti - > UsesOverlay ( ) ) {
image = SPR_FLAT_GRASS_TILE ;
} else {
image = dts - > ground . sprite ;
2011-05-08 15:58:59 +00:00
if ( image ! = SPR_FLAT_GRASS_TILE ) image + = rti - > GetRailtypeSpriteOffset ( ) ;
2010-02-07 22:22:54 +00:00
}
2006-08-05 16:54:55 +00:00
2019-10-08 10:51:15 +00:00
/* Adjust ground tile for desert and snow. */
if ( IsSnowRailGround ( ti - > tile ) ) {
2009-07-22 08:59:57 +00:00
if ( image ! = SPR_FLAT_GRASS_TILE ) {
image + = rti - > snow_offset ; // tile with tracks
2005-10-23 13:04:44 +00:00
} else {
2009-09-07 13:38:57 +00:00
image = SPR_FLAT_SNOW_DESERT_TILE ; // flat ground
2005-10-23 13:04:44 +00:00
}
2004-08-09 17:04:08 +00:00
}
2008-11-22 16:04:11 +00:00
DrawGroundSprite ( image , GroundSpritePaletteTransform ( image , pal , _drawtile_track_palette ) ) ;
2004-08-09 17:04:08 +00:00
2010-02-07 22:22:54 +00:00
if ( rti - > UsesOverlay ( ) ) {
SpriteID ground = GetCustomRailSprite ( rti , ti - > tile , RTSG_GROUND ) ;
2009-07-22 08:59:57 +00:00
switch ( GetRailDepotDirection ( ti - > tile ) ) {
2017-08-13 18:38:42 +00:00
case DIAGDIR_NE :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SW :
DrawGroundSprite ( ground + RTO_X , PAL_NONE ) ;
break ;
case DIAGDIR_NW :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SE :
DrawGroundSprite ( ground + RTO_Y , PAL_NONE ) ;
break ;
default :
break ;
2009-07-22 08:59:57 +00:00
}
2010-02-07 22:22:54 +00:00
if ( _settings_client . gui . show_track_reservation & & HasDepotReservation ( ti - > tile ) ) {
SpriteID overlay = GetCustomRailSprite ( rti , ti - > tile , RTSG_OVERLAY ) ;
switch ( GetRailDepotDirection ( ti - > tile ) ) {
2017-08-13 18:38:42 +00:00
case DIAGDIR_NE :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SW :
DrawGroundSprite ( overlay + RTO_X , PALETTE_CRASH ) ;
break ;
case DIAGDIR_NW :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SE :
DrawGroundSprite ( overlay + RTO_Y , PALETTE_CRASH ) ;
break ;
default :
break ;
2010-02-07 22:22:54 +00:00
}
}
} else {
/* PBS debugging, draw reserved tracks darker */
if ( _game_mode ! = GM_MENU & & _settings_client . gui . show_track_reservation & & HasDepotReservation ( ti - > tile ) ) {
switch ( GetRailDepotDirection ( ti - > tile ) ) {
2017-08-13 18:38:42 +00:00
case DIAGDIR_NE :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SW :
DrawGroundSprite ( rti - > base_sprites . single_x , PALETTE_CRASH ) ;
break ;
case DIAGDIR_NW :
if ( ! IsInvisibilitySet ( TO_BUILDINGS ) ) break ;
FALLTHROUGH ;
case DIAGDIR_SE :
DrawGroundSprite ( rti - > base_sprites . single_y , PALETTE_CRASH ) ;
break ;
default :
break ;
2010-02-07 22:22:54 +00:00
}
}
2008-08-02 22:47:34 +00:00
}
2011-08-28 20:33:40 +00:00
int depot_sprite = GetCustomRailSprite ( rti , ti - > tile , RTSG_DEPOT ) ;
relocation = depot_sprite ! = 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti - > GetRailtypeSpriteOffset ( ) ;
2008-08-02 22:47:34 +00:00
2016-11-05 11:53:03 +00:00
if ( HasRailCatenaryDrawn ( GetRailType ( ti - > tile ) ) ) DrawRailCatenary ( ti ) ;
2006-03-29 16:30:26 +00:00
2010-02-07 22:22:54 +00:00
DrawRailTileSeq ( ti , dts , TO_BUILDINGS , relocation , 0 , _drawtile_track_palette ) ;
2004-08-09 17:04:08 +00:00
}
2006-12-27 12:38:02 +00:00
DrawBridgeMiddle ( ti ) ;
2004-08-09 17:04:08 +00:00
}
2006-08-05 16:54:55 +00:00
void DrawTrainDepotSprite ( int x , int y , int dir , RailType railtype )
{
2009-01-10 00:31:47 +00:00
const DrawTileSprites * dts = & _depot_gfx_table [ dir ] ;
2010-02-08 16:07:46 +00:00
const RailtypeInfo * rti = GetRailTypeInfo ( railtype ) ;
SpriteID image = rti - > UsesOverlay ( ) ? SPR_FLAT_GRASS_TILE : dts - > ground . sprite ;
2011-05-08 15:58:59 +00:00
uint32 offset = rti - > GetRailtypeSpriteOffset ( ) ;
2004-08-09 17:04:08 +00:00
2006-08-05 16:54:55 +00:00
if ( image ! = SPR_FLAT_GRASS_TILE ) image + = offset ;
2010-01-21 01:38:13 +00:00
PaletteID palette = COMPANY_SPRITE_COLOUR ( _local_company ) ;
2010-01-16 22:44:03 +00:00
DrawSprite ( image , PAL_NONE , x , y ) ;
2010-02-08 16:07:46 +00:00
if ( rti - > UsesOverlay ( ) ) {
SpriteID ground = GetCustomRailSprite ( rti , INVALID_TILE , RTSG_GROUND ) ;
switch ( dir ) {
case DIAGDIR_SW : DrawSprite ( ground + RTO_X , PAL_NONE , x , y ) ; break ;
case DIAGDIR_SE : DrawSprite ( ground + RTO_Y , PAL_NONE , x , y ) ; break ;
default : break ;
}
}
2011-08-28 20:33:40 +00:00
int depot_sprite = GetCustomRailSprite ( rti , INVALID_TILE , RTSG_DEPOT ) ;
if ( depot_sprite ! = 0 ) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1 ;
2010-02-08 16:07:46 +00:00
2010-01-17 15:05:25 +00:00
DrawRailTileSeqInGUI ( x , y , dts , offset , 0 , palette ) ;
2004-08-09 17:04:08 +00:00
}
2011-11-04 11:36:10 +00:00
static int GetSlopePixelZ_Track ( TileIndex tile , uint x , uint y )
2004-08-09 17:04:08 +00:00
{
2009-05-18 01:26:23 +00:00
if ( IsPlainRail ( tile ) ) {
2011-11-04 11:30:37 +00:00
int z ;
2011-11-04 10:18:13 +00:00
Slope tileh = GetTilePixelSlope ( tile , & z ) ;
2011-09-25 13:35:17 +00:00
if ( tileh = = SLOPE_FLAT ) return z ;
2011-11-04 10:18:13 +00:00
z + = ApplyPixelFoundationToSlope ( GetRailFoundation ( tileh , GetTrackBits ( tile ) ) , & tileh ) ;
return z + GetPartialPixelZ ( x & 0xF , y & 0xF , tileh ) ;
2006-07-27 05:30:53 +00:00
} else {
2011-11-04 10:18:13 +00:00
return GetTileMaxPixelZ ( tile ) ;
2004-08-09 17:04:08 +00:00
}
}
2007-07-26 16:51:10 +00:00
static Foundation GetFoundation_Track ( TileIndex tile , Slope tileh )
2004-08-13 18:27:33 +00:00
{
2009-05-18 01:26:23 +00:00
return IsPlainRail ( tile ) ? GetRailFoundation ( tileh , GetTrackBits ( tile ) ) : FlatteningFoundation ( tileh ) ;
2004-08-13 18:27:33 +00:00
}
2020-05-18 23:41:35 +00:00
RailGroundType RailTrackToFence ( TileIndex tile , TrackBits rail )
{
Owner owner = GetTileOwner ( tile ) ;
byte fences = 0 ;
for ( DiagDirection d = DIAGDIR_BEGIN ; d < DIAGDIR_END ; d + + ) {
static const TrackBits dir_to_trackbits [ DIAGDIR_END ] = { TRACK_BIT_3WAY_NE , TRACK_BIT_3WAY_SE , TRACK_BIT_3WAY_SW , TRACK_BIT_3WAY_NW } ;
/* Track bit on this edge => no fence. */
if ( ( rail & dir_to_trackbits [ d ] ) ! = TRACK_BIT_NONE ) continue ;
TileIndex tile2 = tile + TileOffsByDiagDir ( d ) ;
/* Show fences if it's a house, industry, object, road, tunnelbridge or not owned by us. */
if ( ! IsValidTile ( tile2 ) | | IsTileType ( tile2 , MP_HOUSE ) | | IsTileType ( tile2 , MP_INDUSTRY ) | |
IsTileType ( tile2 , MP_ROAD ) | | ( IsTileType ( tile2 , MP_OBJECT ) & & ! IsObjectType ( tile2 , OBJECT_OWNED_LAND ) ) | | IsTileType ( tile2 , MP_TUNNELBRIDGE ) | | ! IsTileOwner ( tile2 , owner ) ) {
fences | = 1 < < d ;
}
}
RailGroundType new_ground ;
switch ( fences ) {
case 0 : new_ground = RAIL_GROUND_GRASS ; break ;
case ( 1 < < DIAGDIR_NE ) : new_ground = RAIL_GROUND_FENCE_NE ; break ;
case ( 1 < < DIAGDIR_SE ) : new_ground = RAIL_GROUND_FENCE_SE ; break ;
case ( 1 < < DIAGDIR_SW ) : new_ground = RAIL_GROUND_FENCE_SW ; break ;
case ( 1 < < DIAGDIR_NW ) : new_ground = RAIL_GROUND_FENCE_NW ; break ;
case ( 1 < < DIAGDIR_NE ) | ( 1 < < DIAGDIR_SW ) : new_ground = RAIL_GROUND_FENCE_NESW ; break ;
case ( 1 < < DIAGDIR_SE ) | ( 1 < < DIAGDIR_NW ) : new_ground = RAIL_GROUND_FENCE_SENW ; break ;
case ( 1 < < DIAGDIR_NE ) | ( 1 < < DIAGDIR_SE ) : new_ground = RAIL_GROUND_FENCE_VERT1 ; break ;
case ( 1 < < DIAGDIR_NE ) | ( 1 < < DIAGDIR_NW ) : new_ground = RAIL_GROUND_FENCE_HORIZ2 ; break ;
case ( 1 < < DIAGDIR_SE ) | ( 1 < < DIAGDIR_SW ) : new_ground = RAIL_GROUND_FENCE_HORIZ1 ; break ;
case ( 1 < < DIAGDIR_SW ) | ( 1 < < DIAGDIR_NW ) : new_ground = RAIL_GROUND_FENCE_VERT2 ; break ;
default : NOT_REACHED ( ) ;
}
return new_ground ;
}
2005-06-24 12:38:35 +00:00
static void TileLoop_Track ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2006-04-12 11:58:07 +00:00
RailGroundType old_ground = GetRailGroundType ( tile ) ;
2006-08-31 12:19:32 +00:00
RailGroundType new_ground ;
2004-08-09 17:04:08 +00:00
2007-10-20 21:05:18 +00:00
if ( old_ground = = RAIL_GROUND_WATER ) {
TileLoop_Water ( tile ) ;
return ;
}
2008-05-29 15:13:28 +00:00
switch ( _settings_game . game_creation . landscape ) {
2008-02-10 11:35:05 +00:00
case LT_ARCTIC : {
2011-11-04 11:30:37 +00:00
int z ;
2011-11-04 10:25:58 +00:00
Slope slope = GetTileSlope ( tile , & z ) ;
2008-02-10 11:35:05 +00:00
bool half = false ;
/* for non-flat track, use lower part of track
* in other cases , use the highest part with track */
2009-05-18 01:26:23 +00:00
if ( IsPlainRail ( tile ) ) {
2008-02-10 11:35:05 +00:00
TrackBits track = GetTrackBits ( tile ) ;
Foundation f = GetRailFoundation ( slope , track ) ;
switch ( f ) {
case FOUNDATION_NONE :
/* no foundation - is the track on the upper side of three corners raised tile? */
2011-11-04 10:25:58 +00:00
if ( IsSlopeWithThreeCornersRaised ( slope ) ) z + + ;
2008-02-10 11:35:05 +00:00
break ;
case FOUNDATION_INCLINED_X :
case FOUNDATION_INCLINED_Y :
/* sloped track - is it on a steep slope? */
2011-11-04 10:25:58 +00:00
if ( IsSteepSlope ( slope ) ) z + + ;
2008-02-10 11:35:05 +00:00
break ;
case FOUNDATION_STEEP_LOWER :
/* only lower part of steep slope */
2011-11-04 10:25:58 +00:00
z + + ;
2008-02-10 11:35:05 +00:00
break ;
default :
/* if it is a steep slope, then there is a track on higher part */
2011-11-04 10:25:58 +00:00
if ( IsSteepSlope ( slope ) ) z + + ;
z + + ;
2008-02-10 11:35:05 +00:00
break ;
}
half = IsInsideMM ( f , FOUNDATION_STEEP_BOTH , FOUNDATION_HALFTILE_N + 1 ) ;
} else {
/* is the depot on a non-flat tile? */
2011-11-04 10:25:58 +00:00
if ( slope ! = SLOPE_FLAT ) z + + ;
2008-02-10 11:35:05 +00:00
}
/* 'z' is now the lowest part of the highest track bit -
* for sloped track , it is ' z ' of lower part
* for two track bits , it is ' z ' of higher track bit
* For non - continuous foundations ( and STEEP_BOTH ) , ' half ' is set */
if ( z > GetSnowLine ( ) ) {
2011-11-04 10:25:58 +00:00
if ( half & & z - GetSnowLine ( ) = = 1 ) {
2008-02-10 11:35:05 +00:00
/* track on non-continuous foundation, lower part is not under snow */
new_ground = RAIL_GROUND_HALF_SNOW ;
} else {
new_ground = RAIL_GROUND_ICE_DESERT ;
}
2006-08-31 11:42:16 +00:00
goto set_ground ;
2006-04-15 22:16:47 +00:00
}
2005-11-13 14:54:09 +00:00
break ;
2008-02-10 11:35:05 +00:00
}
2004-08-09 17:04:08 +00:00
2007-03-22 03:42:43 +00:00
case LT_TROPIC :
2006-04-15 22:16:47 +00:00
if ( GetTropicZone ( tile ) = = TROPICZONE_DESERT ) {
new_ground = RAIL_GROUND_ICE_DESERT ;
2006-08-31 11:42:16 +00:00
goto set_ground ;
2006-04-15 22:16:47 +00:00
}
2005-11-13 14:54:09 +00:00
break ;
2004-08-09 17:04:08 +00:00
}
2006-04-12 11:58:07 +00:00
new_ground = RAIL_GROUND_GRASS ;
2004-08-09 17:04:08 +00:00
2010-07-26 17:37:50 +00:00
if ( IsPlainRail ( tile ) & & old_ground ! = RAIL_GROUND_BARREN ) { // wait until bottom is green
2004-08-09 17:04:08 +00:00
/* determine direction of fence */
2006-03-19 12:06:12 +00:00
TrackBits rail = GetTrackBits ( tile ) ;
2020-05-18 23:41:35 +00:00
new_ground = RailTrackToFence ( tile , rail ) ;
2004-08-09 17:04:08 +00:00
}
2006-08-31 11:42:16 +00:00
set_ground :
2005-11-16 14:30:24 +00:00
if ( old_ground ! = new_ground ) {
2006-04-12 11:58:07 +00:00
SetRailGroundType ( tile , new_ground ) ;
2020-10-01 17:50:31 +00:00
MarkTileDirtyByTile ( tile , VMDF_NOT_MAP_MODE ) ;
2004-08-09 17:04:08 +00:00
}
}
2008-02-20 17:49:50 +00:00
static TrackStatus GetTileTrackStatus_Track ( TileIndex tile , TransportType mode , uint sub_mode , DiagDirection side )
2005-06-24 12:38:35 +00:00
{
2008-06-12 11:15:43 +00:00
/* Case of half tile slope with water. */
2012-07-30 19:38:17 +00:00
if ( mode = = TRANSPORT_WATER & & IsPlainRail ( tile ) & & GetRailGroundType ( tile ) = = RAIL_GROUND_WATER & & IsSlopeWithOneCornerRaised ( GetTileSlope ( tile ) ) ) {
2008-06-12 11:15:43 +00:00
TrackBits tb = GetTrackBits ( tile ) ;
switch ( tb ) {
default : NOT_REACHED ( ) ;
case TRACK_BIT_UPPER : tb = TRACK_BIT_LOWER ; break ;
case TRACK_BIT_LOWER : tb = TRACK_BIT_UPPER ; break ;
case TRACK_BIT_LEFT : tb = TRACK_BIT_RIGHT ; break ;
case TRACK_BIT_RIGHT : tb = TRACK_BIT_LEFT ; break ;
}
return CombineTrackStatus ( TrackBitsToTrackdirBits ( tb ) , TRACKDIR_BIT_NONE ) ;
}
2005-11-14 19:48:04 +00:00
if ( mode ! = TRANSPORT_RAIL ) return 0 ;
2004-08-09 17:04:08 +00:00
2008-02-20 17:49:50 +00:00
TrackBits trackbits = TRACK_BIT_NONE ;
TrackdirBits red_signals = TRACKDIR_BIT_NONE ;
2007-03-02 00:17:35 +00:00
switch ( GetRailTileType ( tile ) ) {
default : NOT_REACHED ( ) ;
2008-02-18 16:11:31 +00:00
case RAIL_TILE_NORMAL :
2008-02-20 17:49:50 +00:00
trackbits = GetTrackBits ( tile ) ;
break ;
2007-03-02 00:17:35 +00:00
case RAIL_TILE_SIGNALS : {
2008-02-20 17:49:50 +00:00
trackbits = GetTrackBits ( tile ) ;
2007-05-30 13:33:19 +00:00
byte a = GetPresentSignals ( tile ) ;
uint b = GetSignalStates ( tile ) ;
2004-08-09 17:04:08 +00:00
b & = a ;
2008-08-02 22:48:57 +00:00
/* When signals are not present (in neither direction),
* we pretend them to be green . Otherwise , it depends on
* the signal type . For signals that are only active from
2013-01-08 22:46:42 +00:00
* one side , we set the missing signals explicitly to
* ` green ' . Otherwise , they implicitly become ` red ' . */
2008-08-02 22:48:57 +00:00
if ( ! IsOnewaySignal ( tile , TRACK_UPPER ) | | ( a & SignalOnTrack ( TRACK_UPPER ) ) = = 0 ) b | = ~ a & SignalOnTrack ( TRACK_UPPER ) ;
if ( ! IsOnewaySignal ( tile , TRACK_LOWER ) | | ( a & SignalOnTrack ( TRACK_LOWER ) ) = = 0 ) b | = ~ a & SignalOnTrack ( TRACK_LOWER ) ;
2004-08-09 17:04:08 +00:00
2008-02-20 17:49:50 +00:00
if ( ( b & 0x8 ) = = 0 ) red_signals | = ( TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E ) ;
if ( ( b & 0x4 ) = = 0 ) red_signals | = ( TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W ) ;
if ( ( b & 0x2 ) = = 0 ) red_signals | = ( TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E ) ;
if ( ( b & 0x1 ) = = 0 ) red_signals | = ( TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W ) ;
2007-03-02 00:17:35 +00:00
2008-02-20 17:49:50 +00:00
break ;
2006-03-19 12:06:12 +00:00
}
2007-03-02 00:17:35 +00:00
2008-02-18 16:11:31 +00:00
case RAIL_TILE_DEPOT : {
DiagDirection dir = GetRailDepotDirection ( tile ) ;
2008-02-20 17:49:50 +00:00
if ( side ! = INVALID_DIAGDIR & & side ! = dir ) break ;
2008-02-18 16:11:31 +00:00
2008-05-14 18:31:21 +00:00
trackbits = DiagDirToDiagTrackBits ( dir ) ;
2008-02-20 17:49:50 +00:00
break ;
2008-02-18 16:11:31 +00:00
}
2006-03-19 12:06:12 +00:00
}
2008-02-20 17:49:50 +00:00
return CombineTrackStatus ( TrackBitsToTrackdirBits ( trackbits ) , red_signals ) ;
2004-08-09 17:04:08 +00:00
}
2009-01-02 22:42:05 +00:00
static bool ClickTile_Track ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2017-04-12 16:42:09 +00:00
if ( _ctrl_pressed & & IsPlainRailTile ( tile ) ) {
TrackBits trackbits = TrackStatusToTrackBits ( GetTileTrackStatus ( tile , TRANSPORT_RAIL , 0 ) ) ;
if ( trackbits & TRACK_BIT_VERT ) { // N-S direction
trackbits = ( _tile_fract_coords . x < = _tile_fract_coords . y ) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT ;
}
if ( trackbits & TRACK_BIT_HORZ ) { // E-W direction
trackbits = ( _tile_fract_coords . x + _tile_fract_coords . y < = 15 ) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER ;
}
Track track = FindFirstTrack ( trackbits ) ;
if ( HasTrack ( tile , track ) & & HasSignalOnTrack ( tile , track ) ) {
bool result = false ;
if ( GetExistingTraceRestrictProgram ( tile , track ) ! = nullptr ) {
ShowTraceRestrictProgramWindow ( tile , track ) ;
result = true ;
}
if ( IsPresignalProgrammable ( tile , track ) ) {
ShowSignalProgramWindow ( SignalReference ( tile , track ) ) ;
result = true ;
}
return result ;
}
}
2009-07-22 08:59:57 +00:00
if ( ! IsRailDepot ( tile ) ) return false ;
ShowDepotWindow ( tile , VEH_TRAIN ) ;
return true ;
2004-08-09 17:04:08 +00:00
}
2005-03-28 07:02:51 +00:00
static void GetTileDesc_Track ( TileIndex tile , TileDesc * td )
2004-08-09 17:04:08 +00:00
{
2018-12-21 03:27:58 +00:00
RailType rt = GetRailType ( tile ) ;
const RailtypeInfo * rti = GetRailTypeInfo ( rt ) ;
2010-03-16 06:43:41 +00:00
td - > rail_speed = rti - > max_speed ;
2016-12-09 21:27:22 +00:00
td - > railtype = rti - > strings . name ;
2018-12-21 03:27:58 +00:00
RailType secondary_rt = GetTileSecondaryRailTypeIfValid ( tile ) ;
if ( secondary_rt ! = rt & & secondary_rt ! = INVALID_RAILTYPE ) {
const RailtypeInfo * secondary_rti = GetRailTypeInfo ( secondary_rt ) ;
td - > rail_speed2 = secondary_rti - > max_speed ;
td - > railtype2 = secondary_rti - > strings . name ;
}
2008-05-21 22:15:39 +00:00
td - > owner [ 0 ] = GetTileOwner ( tile ) ;
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
switch ( GetRailTileType ( tile ) ) {
2006-05-09 08:17:33 +00:00
case RAIL_TILE_NORMAL :
2009-08-05 17:59:21 +00:00
td - > str = STR_LAI_RAIL_DESCRIPTION_TRACK ;
2005-03-28 07:02:51 +00:00
break ;
2006-05-09 08:17:33 +00:00
case RAIL_TILE_SIGNALS : {
2014-01-14 20:32:07 +00:00
static const StringID signal_type [ 7 ] [ 7 ] = {
2007-05-31 21:21:04 +00:00
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PROGSIGNALS
2007-05-31 21:21:04 +00:00
} ,
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PROGSIGNALS
2007-05-31 21:21:04 +00:00
} ,
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PROGSIGNALS
2007-05-31 21:21:04 +00:00
} ,
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PROGSIGNALS
2008-08-02 22:48:43 +00:00
} ,
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_PROGSIGNALS
2008-08-02 22:48:43 +00:00
} ,
{
2009-08-05 17:59:21 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS ,
2014-01-14 20:32:07 +00:00
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_PROGSIGNALS
} ,
{
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY_PROGSIGNALS ,
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PROGSIGNALS
2007-05-31 21:21:04 +00:00
}
2005-03-28 07:02:51 +00:00
} ;
2008-10-02 22:48:52 +00:00
SignalType primary_signal ;
SignalType secondary_signal ;
2008-10-02 00:23:30 +00:00
if ( HasSignalOnTrack ( tile , TRACK_UPPER ) ) {
primary_signal = GetSignalType ( tile , TRACK_UPPER ) ;
secondary_signal = HasSignalOnTrack ( tile , TRACK_LOWER ) ? GetSignalType ( tile , TRACK_LOWER ) : primary_signal ;
} else {
secondary_signal = primary_signal = GetSignalType ( tile , TRACK_LOWER ) ;
}
td - > str = signal_type [ secondary_signal ] [ primary_signal ] ;
2015-07-28 20:43:23 +00:00
if ( IsRestrictedSignal ( tile ) ) {
SetDParamX ( td - > dparam , 0 , td - > str ) ;
td - > str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL ;
}
2005-03-28 07:02:51 +00:00
break ;
2004-08-09 17:04:08 +00:00
}
2005-03-28 07:02:51 +00:00
2007-02-27 23:36:28 +00:00
case RAIL_TILE_DEPOT :
2009-08-05 17:59:21 +00:00
td - > str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT ;
2010-04-03 20:25:23 +00:00
if ( _settings_game . vehicle . train_acceleration_model ! = AM_ORIGINAL ) {
if ( td - > rail_speed > 0 ) {
2021-01-08 10:16:18 +00:00
td - > rail_speed = std : : min < uint16 > ( td - > rail_speed , 61 ) ;
2010-04-03 20:25:23 +00:00
} else {
td - > rail_speed = 61 ;
}
2010-03-16 06:43:41 +00:00
}
2010-06-20 19:13:02 +00:00
td - > build_date = Depot : : GetByTile ( tile ) - > build_date ;
2007-02-27 23:36:28 +00:00
break ;
2005-03-28 07:02:51 +00:00
default :
2009-07-22 08:59:57 +00:00
NOT_REACHED ( ) ;
2004-08-09 17:04:08 +00:00
}
}
2008-09-30 20:39:50 +00:00
static void ChangeTileOwner_Track ( TileIndex tile , Owner old_owner , Owner new_owner )
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
if ( ! IsTileOwner ( tile , old_owner ) ) return ;
2004-09-11 09:55:19 +00:00
2008-09-30 20:39:50 +00:00
if ( new_owner ! = INVALID_OWNER ) {
2011-12-03 23:40:13 +00:00
/* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
uint num_pieces = 1 ;
if ( IsPlainRail ( tile ) ) {
TrackBits bits = GetTrackBits ( tile ) ;
2018-12-21 03:27:58 +00:00
if ( bits = = TRACK_BIT_HORZ | | bits = = TRACK_BIT_VERT ) {
RailType secondary_rt = GetSecondaryRailType ( tile ) ;
Company : : Get ( old_owner ) - > infrastructure . rail [ secondary_rt ] - - ;
Company : : Get ( new_owner ) - > infrastructure . rail [ secondary_rt ] + + ;
} else {
num_pieces = CountBits ( bits ) ;
if ( TracksOverlap ( bits ) ) num_pieces * = num_pieces ;
}
2011-12-03 23:40:13 +00:00
}
RailType rt = GetRailType ( tile ) ;
Company : : Get ( old_owner ) - > infrastructure . rail [ rt ] - = num_pieces ;
Company : : Get ( new_owner ) - > infrastructure . rail [ rt ] + = num_pieces ;
if ( HasSignals ( tile ) ) {
uint num_sigs = CountBits ( GetPresentSignals ( tile ) ) ;
Company : : Get ( old_owner ) - > infrastructure . signal - = num_sigs ;
Company : : Get ( new_owner ) - > infrastructure . signal + = num_sigs ;
}
2008-09-30 20:39:50 +00:00
SetTileOwner ( tile , new_owner ) ;
2006-08-28 18:53:03 +00:00
} else {
2008-02-09 15:07:31 +00:00
DoCommand ( tile , 0 , 0 , DC_EXEC | DC_BANKRUPT , CMD_LANDSCAPE_CLEAR ) ;
2004-08-09 17:04:08 +00:00
}
}
static const byte _fractcoords_behind [ 4 ] = { 0x8F , 0x8 , 0x80 , 0xF8 } ;
static const byte _fractcoords_enter [ 4 ] = { 0x8A , 0x48 , 0x84 , 0xA8 } ;
2009-09-20 23:11:01 +00:00
static const int8 _deltacoord_leaveoffset [ 8 ] = {
2005-06-06 22:44:11 +00:00
- 1 , 0 , 1 , 0 , /* x */
0 , 1 , 0 , - 1 /* y */
} ;
2004-08-09 17:04:08 +00:00
2008-03-19 20:50:19 +00:00
2010-08-01 19:22:34 +00:00
/**
* Compute number of ticks when next wagon will leave a depot .
2008-03-19 20:50:19 +00:00
* Negative means next wagon should have left depot n ticks before .
* @ param v vehicle outside ( leaving ) the depot
* @ return number of ticks when the next wagon will leave
*/
2009-05-22 22:55:41 +00:00
int TicksToLeaveDepot ( const Train * v )
2008-03-19 20:50:19 +00:00
{
DiagDirection dir = GetRailDepotDirection ( v - > tile ) ;
2011-11-21 20:51:43 +00:00
int length = v - > CalcNextVehicleOffset ( ) ;
2008-03-19 20:50:19 +00:00
switch ( dir ) {
case DIAGDIR_NE : return ( ( int ) ( v - > x_pos & 0x0F ) - ( ( _fractcoords_enter [ dir ] & 0x0F ) - ( length + 1 ) ) ) ;
case DIAGDIR_SE : return - ( ( int ) ( v - > y_pos & 0x0F ) - ( ( _fractcoords_enter [ dir ] > > 4 ) + ( length + 1 ) ) ) ;
case DIAGDIR_SW : return - ( ( int ) ( v - > x_pos & 0x0F ) - ( ( _fractcoords_enter [ dir ] & 0x0F ) + ( length + 1 ) ) ) ;
case DIAGDIR_NW : return ( ( int ) ( v - > y_pos & 0x0F ) - ( ( _fractcoords_enter [ dir ] > > 4 ) - ( length + 1 ) ) ) ;
2018-10-14 18:31:14 +00:00
default : NOT_REACHED ( ) ;
2008-03-19 20:50:19 +00:00
}
}
2010-08-01 19:22:34 +00:00
/**
* Tile callback routine when vehicle enters tile
2010-08-01 19:44:49 +00:00
* @ see vehicle_enter_tile_proc
*/
2009-05-22 22:22:46 +00:00
static VehicleEnterTileStatus VehicleEnter_Track ( Vehicle * u , TileIndex tile , int x , int y )
2004-08-09 17:04:08 +00:00
{
2019-02-16 20:52:49 +00:00
/* This routine applies only to trains in depot tiles. */
2009-05-22 22:22:46 +00:00
if ( u - > type ! = VEH_TRAIN | | ! IsRailDepotTile ( tile ) ) return VETSB_CONTINUE ;
2009-06-06 16:54:22 +00:00
Train * v = Train : : From ( u ) ;
2004-08-09 17:04:08 +00:00
2018-03-29 18:16:44 +00:00
auto abort_load_through = [ & ] ( bool leave_station ) {
if ( _local_company = = v - > owner ) {
SetDParam ( 0 , v - > index ) ;
SetDParam ( 1 , v - > current_order . GetDestination ( ) ) ;
AddNewsItem ( STR_VEHICLE_LOAD_THROUGH_ABORTED_DEPOT , NT_ADVICE , NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0 ,
NR_VEHICLE , v - > index ,
NR_STATION , v - > current_order . GetDestination ( ) ) ;
}
if ( leave_station ) {
v - > LeaveStation ( ) ;
/* Only advance to next order if we are loading at the current one */
const Order * order = v - > GetOrder ( v - > cur_implicit_order_index ) ;
2019-04-11 17:14:13 +00:00
if ( order ! = nullptr & & order - > IsType ( OT_GOTO_STATION ) & & order - > GetDestination ( ) = = v - > last_station_visited ) {
2018-03-29 18:16:44 +00:00
v - > IncrementImplicitOrderIndex ( ) ;
}
}
} ;
if ( v - > IsFrontEngine ( ) & & v - > current_order . IsType ( OT_LOADING_ADVANCE ) ) abort_load_through ( true ) ;
2019-02-16 20:52:49 +00:00
/* Depot direction. */
2010-02-15 19:52:40 +00:00
DiagDirection dir = GetRailDepotDirection ( tile ) ;
2004-09-11 09:55:19 +00:00
2011-11-21 20:51:43 +00:00
/* Calculate the point where the following wagon should be activated. */
int length = v - > CalcNextVehicleOffset ( ) ;
2005-06-06 22:44:11 +00:00
2010-02-15 19:52:40 +00:00
byte fract_coord_leave =
2006-08-28 18:53:03 +00:00
( ( _fractcoords_enter [ dir ] & 0x0F ) + // x
2005-06-06 22:44:11 +00:00
( length + 1 ) * _deltacoord_leaveoffset [ dir ] ) +
2006-08-28 18:53:03 +00:00
( ( ( _fractcoords_enter [ dir ] > > 4 ) + // y
2009-07-16 10:13:33 +00:00
( ( length + 1 ) * _deltacoord_leaveoffset [ dir + 4 ] ) ) < < 4 ) ;
2005-06-06 22:44:11 +00:00
2010-02-15 19:52:40 +00:00
byte fract_coord = ( x & 0xF ) + ( ( y & 0xF ) < < 4 ) ;
2005-06-06 22:44:11 +00:00
2004-08-09 17:04:08 +00:00
if ( _fractcoords_behind [ dir ] = = fract_coord ) {
/* make sure a train is not entering the tile from behind */
2007-02-13 10:26:53 +00:00
return VETSB_CANNOT_ENTER ;
2004-08-09 17:04:08 +00:00
} else if ( _fractcoords_enter [ dir ] = = fract_coord ) {
2006-03-08 06:55:33 +00:00
if ( DiagDirToDir ( ReverseDiagDir ( dir ) ) = = v - > direction ) {
2004-08-09 17:04:08 +00:00
/* enter the depot */
2018-03-29 18:16:44 +00:00
2019-01-19 21:22:32 +00:00
if ( v - > IsFrontEngine ( ) ) {
if ( v - > current_order . IsType ( OT_LOADING_ADVANCE ) ) {
abort_load_through ( true ) ;
} else if ( HasBit ( v - > flags , VRF_BEYOND_PLATFORM_END ) ) {
abort_load_through ( false ) ;
}
SetBit ( v - > flags , VRF_CONSIST_SPEED_REDUCTION ) ;
2018-03-29 18:16:44 +00:00
}
2009-05-22 22:33:05 +00:00
v - > track = TRACK_BIT_DEPOT ,
2009-03-15 00:32:18 +00:00
v - > vehstatus | = VS_HIDDEN ; // hide it
2020-02-02 22:59:18 +00:00
v - > UpdateIsDrawn ( ) ;
2006-03-08 06:55:33 +00:00
v - > direction = ReverseDir ( v - > direction ) ;
2019-04-11 17:14:13 +00:00
if ( v - > Next ( ) = = nullptr ) VehicleEnterDepot ( v - > First ( ) ) ;
2004-08-09 17:04:08 +00:00
v - > tile = tile ;
2006-12-01 00:09:13 +00:00
InvalidateWindowData ( WC_VEHICLE_DEPOT , v - > tile ) ;
2007-02-13 10:26:53 +00:00
return VETSB_ENTERED_WORMHOLE ;
2004-08-09 17:04:08 +00:00
}
2005-06-06 22:44:11 +00:00
} else if ( fract_coord_leave = = fract_coord ) {
2006-03-08 06:55:33 +00:00
if ( DiagDirToDir ( dir ) = = v - > direction ) {
2004-08-09 17:04:08 +00:00
/* leave the depot? */
2019-04-10 21:07:06 +00:00
if ( ( v = v - > Next ( ) ) ! = nullptr ) {
2004-08-09 17:04:08 +00:00
v - > vehstatus & = ~ VS_HIDDEN ;
2009-05-22 22:33:05 +00:00
v - > track = ( DiagDirToAxis ( dir ) = = AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y ) ;
2020-02-02 22:59:18 +00:00
v - > UpdateIsDrawn ( ) ;
2004-08-09 17:04:08 +00:00
}
}
}
2007-02-13 10:26:53 +00:00
return VETSB_CONTINUE ;
2004-08-09 17:04:08 +00:00
}
2007-09-14 22:27:40 +00:00
/**
* Tests if autoslope is allowed .
*
* @ param tile The tile .
* @ param flags Terraform command flags .
* @ param z_old Old TileZ .
* @ param tileh_old Old TileSlope .
* @ param z_new New TileZ .
* @ param tileh_new New TileSlope .
* @ param rail_bits Trackbits .
*/
2011-11-04 11:52:19 +00:00
static CommandCost TestAutoslopeOnRailTile ( TileIndex tile , uint flags , int z_old , Slope tileh_old , int z_new , Slope tileh_new , TrackBits rail_bits )
2007-09-14 22:27:40 +00:00
{
2010-03-07 14:00:53 +00:00
if ( ! _settings_game . construction . build_on_slopes | | ! AutoslopeEnabled ( ) ) return_cmd_error ( STR_ERROR_MUST_REMOVE_RAILROAD_TRACK ) ;
2007-09-14 22:27:40 +00:00
2008-08-25 20:54:34 +00:00
/* Is the slope-rail_bits combination valid in general? I.e. is it safe to call GetRailFoundation() ? */
2010-03-07 14:00:53 +00:00
if ( CheckRailSlope ( tileh_new , rail_bits , TRACK_BIT_NONE , tile ) . Failed ( ) ) return_cmd_error ( STR_ERROR_MUST_REMOVE_RAILROAD_TRACK ) ;
2007-09-14 22:27:40 +00:00
/* Get the slopes on top of the foundations */
2011-11-04 10:30:10 +00:00
z_old + = ApplyFoundationToSlope ( GetRailFoundation ( tileh_old , rail_bits ) , & tileh_old ) ;
z_new + = ApplyFoundationToSlope ( GetRailFoundation ( tileh_new , rail_bits ) , & tileh_new ) ;
2007-09-14 22:27:40 +00:00
2007-10-26 16:26:50 +00:00
Corner track_corner ;
2007-09-14 22:27:40 +00:00
switch ( rail_bits ) {
2007-10-26 16:26:50 +00:00
case TRACK_BIT_LEFT : track_corner = CORNER_W ; break ;
case TRACK_BIT_LOWER : track_corner = CORNER_S ; break ;
case TRACK_BIT_RIGHT : track_corner = CORNER_E ; break ;
case TRACK_BIT_UPPER : track_corner = CORNER_N ; break ;
2007-09-14 22:27:40 +00:00
/* Surface slope must not be changed */
2010-03-07 14:00:53 +00:00
default :
if ( z_old ! = z_new | | tileh_old ! = tileh_new ) return_cmd_error ( STR_ERROR_MUST_REMOVE_RAILROAD_TRACK ) ;
return CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_FOUNDATION ] ) ;
2007-09-14 22:27:40 +00:00
}
/* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
2011-11-04 10:30:10 +00:00
z_old + = GetSlopeZInCorner ( RemoveHalftileSlope ( tileh_old ) , track_corner ) ;
z_new + = GetSlopeZInCorner ( RemoveHalftileSlope ( tileh_new ) , track_corner ) ;
2010-03-07 14:00:53 +00:00
if ( z_old ! = z_new ) return_cmd_error ( STR_ERROR_MUST_REMOVE_RAILROAD_TRACK ) ;
2007-09-14 22:27:40 +00:00
2009-11-24 22:15:42 +00:00
CommandCost cost = CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_FOUNDATION ] ) ;
2007-10-26 16:26:50 +00:00
/* Make the ground dirty, if surface slope has changed */
if ( tileh_old ! = tileh_new ) {
2008-01-25 16:51:35 +00:00
/* If there is flat water on the lower halftile add the cost for clearing it */
2017-07-30 13:27:42 +00:00
if ( GetRailGroundType ( tile ) = = RAIL_GROUND_WATER & & IsSlopeWithOneCornerRaised ( tileh_old ) ) {
if ( _game_mode ! = GM_EDITOR & & ! _settings_game . construction . enable_remove_water & & ! ( flags & DC_ALLOW_REMOVE_WATER ) ) return_cmd_error ( STR_ERROR_CAN_T_BUILD_ON_WATER ) ;
cost . AddCost ( _price [ PR_CLEAR_WATER ] ) ;
}
2007-10-26 16:26:50 +00:00
if ( ( flags & DC_EXEC ) ! = 0 ) SetRailGroundType ( tile , RAIL_GROUND_BARREN ) ;
}
2007-10-20 21:05:18 +00:00
return cost ;
2007-09-14 22:27:40 +00:00
}
2012-07-27 19:55:27 +00:00
/**
* Test - procedure for HasVehicleOnPos to check for a ship .
*/
static Vehicle * EnsureNoShipProc ( Vehicle * v , void * data )
{
2020-02-28 22:21:10 +00:00
return v ;
2012-07-27 19:55:27 +00:00
}
2011-11-04 11:36:10 +00:00
static CommandCost TerraformTile_Track ( TileIndex tile , DoCommandFlag flags , int z_new , Slope tileh_new )
2007-08-30 17:17:04 +00:00
{
2011-11-04 11:30:37 +00:00
int z_old ;
2011-11-04 10:30:10 +00:00
Slope tileh_old = GetTileSlope ( tile , & z_old ) ;
2009-05-18 01:26:23 +00:00
if ( IsPlainRail ( tile ) ) {
2007-08-30 17:17:04 +00:00
TrackBits rail_bits = GetTrackBits ( tile ) ;
2010-10-30 17:51:07 +00:00
/* Is there flat water on the lower halftile that must be cleared expensively? */
2008-01-25 16:51:35 +00:00
bool was_water = ( GetRailGroundType ( tile ) = = RAIL_GROUND_WATER & & IsSlopeWithOneCornerRaised ( tileh_old ) ) ;
2007-08-30 17:17:04 +00:00
2012-07-27 19:55:27 +00:00
/* Allow clearing the water only if there is no ship */
2020-02-28 22:21:10 +00:00
if ( was_water & & HasVehicleOnPos ( tile , VEH_SHIP , nullptr , & EnsureNoShipProc ) ) return_cmd_error ( STR_ERROR_SHIP_IN_THE_WAY ) ;
2012-07-27 19:55:27 +00:00
2017-07-30 13:27:42 +00:00
if ( was_water & & _game_mode ! = GM_EDITOR & & ! _settings_game . construction . enable_remove_water & & ! ( flags & DC_ALLOW_REMOVE_WATER ) ) return_cmd_error ( STR_ERROR_CAN_T_BUILD_ON_WATER ) ;
2007-09-14 22:27:40 +00:00
/* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */
CommandCost autoslope_result = TestAutoslopeOnRailTile ( tile , flags , z_old , tileh_old , z_new , tileh_new , rail_bits ) ;
2007-08-30 17:17:04 +00:00
/* When there is only a single horizontal/vertical track, one corner can be terraformed. */
2007-10-20 21:04:14 +00:00
Corner allowed_corner ;
2007-08-30 17:17:04 +00:00
switch ( rail_bits ) {
2007-10-20 21:04:14 +00:00
case TRACK_BIT_RIGHT : allowed_corner = CORNER_W ; break ;
case TRACK_BIT_UPPER : allowed_corner = CORNER_S ; break ;
case TRACK_BIT_LEFT : allowed_corner = CORNER_E ; break ;
case TRACK_BIT_LOWER : allowed_corner = CORNER_N ; break ;
2007-09-14 22:27:40 +00:00
default : return autoslope_result ;
2007-08-30 17:17:04 +00:00
}
Foundation f_old = GetRailFoundation ( tileh_old , rail_bits ) ;
2007-10-20 21:04:14 +00:00
/* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */
if ( tileh_old ! = SLOPE_NS & & tileh_old ! = SLOPE_EW & & IsSpecialRailFoundation ( f_old ) ) return autoslope_result ;
2007-08-30 17:17:04 +00:00
2007-10-20 21:04:14 +00:00
/* Everything is valid, which only changes allowed_corner */
for ( Corner corner = ( Corner ) 0 ; corner < CORNER_END ; corner = ( Corner ) ( corner + 1 ) ) {
if ( allowed_corner = = corner ) continue ;
2011-11-04 10:30:10 +00:00
if ( z_old + GetSlopeZInCorner ( tileh_old , corner ) ! = z_new + GetSlopeZInCorner ( tileh_new , corner ) ) return autoslope_result ;
2007-08-30 17:17:04 +00:00
}
/* Make the ground dirty */
if ( ( flags & DC_EXEC ) ! = 0 ) SetRailGroundType ( tile , RAIL_GROUND_BARREN ) ;
2007-10-20 21:05:18 +00:00
/* allow terraforming */
2009-11-07 22:47:54 +00:00
return CommandCost ( EXPENSES_CONSTRUCTION , was_water ? _price [ PR_CLEAR_WATER ] : ( Money ) 0 ) ;
2009-07-22 08:59:57 +00:00
} else if ( _settings_game . construction . build_on_slopes & & AutoslopeEnabled ( ) & &
AutoslopeCheckForEntranceEdge ( tile , z_new , tileh_new , GetRailDepotDirection ( tile ) ) ) {
2009-11-24 22:15:42 +00:00
return CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_FOUNDATION ] ) ;
2007-08-30 17:17:04 +00:00
}
return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ;
}
2004-08-09 17:04:08 +00:00
2007-01-10 18:56:51 +00:00
extern const TileTypeProcs _tile_type_rail_procs = {
2009-03-15 00:32:18 +00:00
DrawTile_Track , // draw_tile_proc
2011-11-04 10:18:13 +00:00
GetSlopePixelZ_Track , // get_slope_z_proc
2009-03-15 00:32:18 +00:00
ClearTile_Track , // clear_tile_proc
2019-04-10 21:07:06 +00:00
nullptr , // add_accepted_cargo_proc
2009-03-15 00:32:18 +00:00
GetTileDesc_Track , // get_tile_desc_proc
GetTileTrackStatus_Track , // get_tile_track_status_proc
ClickTile_Track , // click_tile_proc
2019-04-10 21:07:06 +00:00
nullptr , // animate_tile_proc
2011-11-08 17:37:32 +00:00
TileLoop_Track , // tile_loop_proc
ChangeTileOwner_Track , // change_tile_owner_proc
2019-04-10 21:07:06 +00:00
nullptr , // add_produced_cargo_proc
2009-03-15 00:32:18 +00:00
VehicleEnter_Track , // vehicle_enter_tile_proc
GetFoundation_Track , // get_foundation_proc
TerraformTile_Track , // terraform_tile_proc
2004-08-09 17:04:08 +00:00
} ;