4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
12 * This file deals with displaying wires and pylons for electric railways.
17 * We have two different types of tiles in the drawing code:
18 * Normal Railway Tiles (NRTs) which can have more than one track on it, and
19 * Special Railways tiles (SRTs) which have only one track (like crossings, depots
22 * <h3>Location Categories</h3>
24 * All tiles are categorized into three location groups (TLG):
25 * Group 0: Tiles with both an even X coordinate and an even Y coordinate
26 * Group 1: Tiles with an even X and an odd Y coordinate
27 * Group 2: Tiles with an odd X and an even Y coordinate
28 * Group 3: Tiles with both an odd X and Y coordinate.
30 * <h3>Pylon Points</h3>
31 * <h4>Control Points</h4>
32 * A Pylon Control Point (PCP) is a position where a wire (or rather two)
33 * is mounted onto a pylon.
34 * Each NRT does contain 4 PCPs which are bitmapped to a byte
35 * variable and are represented by the DiagDirection enum
37 * Each track ends on two PCPs and thus requires one pylon on each end. However,
38 * there is one exception: Straight-and-level tracks only have one pylon every
41 * Now on each edge there are two PCPs: One from each adjacent tile. Both PCPs
42 * are merged using an OR operation (i. e. if one tile needs a PCP at the position
43 * in question, both tiles get it).
45 * <h4>Position Points</h4>
46 * A Pylon Position Point (PPP) is a position where a pylon is located on the
47 * ground. Each PCP owns 8 in (45 degree steps) PPPs that are located around
48 * it. PPPs are represented using the Direction enum. Each track bit has PPPs
49 * that are impossible (because the pylon would be situated on the track) and
50 * some that are preferred (because the pylon would be rectangular to the track).
52 * @image html elrail_tile.png
53 * @image html elrail_track.png
63 #include "map/slope.h"
64 #include "map/bridge.h"
65 #include "map/tunnelbridge.h"
66 #include "viewport_func.h"
70 #include "elrail_func.h"
71 #include "company_base.h"
72 #include "newgrf_railtype.h"
73 #include "station_func.h"
74 #include "newgrf_station.h"
77 /** Which PPPs are possible at all on a given PCP */
78 static const byte AllowedPPPonPCP
[DIAGDIR_END
] = {
79 1 << DIR_N
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_W
| 1 << DIR_NW
,
80 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_W
,
81 1 << DIR_N
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_W
| 1 << DIR_NW
,
82 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_W
,
86 /* Geometric placement of the PCP relative to the tile origin */
87 static const int8 x_pcp_offsets
[DIAGDIR_END
] = {0, 8, 16, 8};
88 static const int8 y_pcp_offsets
[DIAGDIR_END
] = {8, 16, 8, 0};
89 /* Geometric placement of the PPP relative to the PCP*/
90 static const int8 x_ppp_offsets
[DIR_END
] = {-2, -4, -2, 0, 2, 4, 2, 0};
91 static const int8 y_ppp_offsets
[DIR_END
] = {-2, 0, 2, 4, 2, 0, -2, -4};
93 /* The type of pylon to draw at each PPP */
94 static const uint8 pylon_sprites
[DIR_END
] = { 4, 0, 7, 3, 5, 1, 6, 2, };
97 * Offset for wire sprites from the base wire sprite.
99 enum WireSpriteOffset
{
133 struct SortableSpriteStructM
{
139 uint8 image_offset
[3];
142 /** Distance between wire and rail */
143 static const uint ELRAIL_ELEVATION
= 10;
144 /** Wires that a draw one level higher than the north corner. */
145 static const uint ELRAIL_ELEVRAISE
= ELRAIL_ELEVATION
+ TILE_HEIGHT
;
147 static const SortableSpriteStructM CatenarySpriteData
[TRACK_END
] = {
148 { 0, 7, 15, 1, ELRAIL_ELEVATION
, { WSO_X_NE
, WSO_X_SW
, WSO_X_SHORT
} }, // X flat
149 { 7, 0, 1, 15, ELRAIL_ELEVATION
, { WSO_Y_SE
, WSO_Y_NW
, WSO_Y_SHORT
} }, // Y flat
150 { 7, 0, 1, 1, ELRAIL_ELEVATION
, { WSO_EW_W
, WSO_EW_E
, WSO_EW_SHORT
} }, // UPPER
151 { 15, 8, 3, 3, ELRAIL_ELEVATION
, { WSO_EW_E
, WSO_EW_W
, WSO_EW_SHORT
} }, // LOWER
152 { 8, 0, 8, 8, ELRAIL_ELEVATION
, { WSO_NS_S
, WSO_NS_N
, WSO_NS_SHORT
} }, // LEFT
153 { 0, 8, 8, 8, ELRAIL_ELEVATION
, { WSO_NS_N
, WSO_NS_S
, WSO_NS_SHORT
} }, // RIGHT
156 static const SortableSpriteStructM CatenarySpriteDataSW
=
157 { 0, 7, 15, 8, ELRAIL_ELEVRAISE
, { WSO_X_NE_UP
, WSO_X_SW_UP
, WSO_X_SHORT_UP
} }; // X up
159 static const SortableSpriteStructM CatenarySpriteDataSE
=
160 { 7, 0, 8, 15, ELRAIL_ELEVRAISE
, { WSO_Y_SE_UP
, WSO_Y_NW_UP
, WSO_Y_SHORT_UP
} }; // Y up
162 static const SortableSpriteStructM CatenarySpriteDataNW
=
163 { 7, 0, 8, 15, ELRAIL_ELEVATION
, { WSO_Y_SE_DOWN
, WSO_Y_NW_DOWN
, WSO_Y_SHORT_DOWN
} }; // Y down
165 static const SortableSpriteStructM CatenarySpriteDataNE
=
166 { 0, 7, 15, 8, ELRAIL_ELEVATION
, { WSO_X_NE_DOWN
, WSO_X_SW_DOWN
, WSO_X_SHORT_DOWN
} }; // X down
170 * Check if a tile is on an odd X coordinate.
171 * @param t The tile to check
172 * @return Whether the tile is on an odd X coordinate
174 static inline bool IsOddX (TileIndex t
)
176 return HasBit (TileX(t
), 0);
180 * Check if a tile is on an odd Y coordinate.
181 * @param t The tile to check
182 * @return Whether the tile is on an odd Y coordinate
184 static inline bool IsOddY (TileIndex t
)
186 return HasBit (TileY(t
), 0);
190 * Test if a rail type has catenary
191 * @param rt Rail type to test
193 static inline bool HasRailCatenary (RailType rt
)
195 return HasRailCatenary (GetRailTypeInfo (rt
));
198 /** Get the electrified track bits on a railway tile. */
199 static TrackBits
GetElectrifiedTrackBits (TileIndex t
)
201 TrackBits present
= GetTrackBits(t
);
202 TrackBits result
= TRACK_BIT_NONE
;
203 if (HasRailCatenary (GetRailType (t
, TRACK_UPPER
))) result
|= present
& (TRACK_BIT_CROSS
| TRACK_BIT_UPPER
| TRACK_BIT_LEFT
);
204 if (HasRailCatenary (GetRailType (t
, TRACK_LOWER
))) result
|= present
& (TRACK_BIT_LOWER
| TRACK_BIT_RIGHT
);
209 * Masks out track bits when neighbouring tiles are unelectrified.
211 static TrackBits
MaskWireBits(TileIndex t
, TrackBits tracks
)
213 if (!IsNormalRailTile(t
)) return tracks
;
215 TrackdirBits neighbour_tdb
= TRACKDIR_BIT_NONE
;
216 for (DiagDirection d
= DIAGDIR_BEGIN
; d
< DIAGDIR_END
; d
++) {
217 /* If the neighbour tile is either not electrified or has no tracks that can be reached
218 * from this tile, mark all trackdirs that can be reached from the neighbour tile
219 * as needing no catenary. We make an exception for blocked station tiles with a matching
220 * axis that still display wires to preserve visual continuity. */
221 TileIndex next_tile
= TileAddByDiagDir(t
, d
);
222 TrackBits reachable
= TrackStatusToTrackBits(GetTileRailwayStatus(next_tile
)) & DiagdirReachesTracks(d
);
224 if (reachable
!= TRACK_BIT_NONE
) {
225 RailType rt
= GetRailType (next_tile
, FindFirstTrack (reachable
));
226 add
= (rt
== INVALID_RAILTYPE
|| !HasRailCatenary(rt
));
227 } else if (!HasStationTileRail(next_tile
) || GetRailStationAxis(next_tile
) != DiagDirToAxis(d
)) {
230 const StationSpec
*statspec
= GetStationSpec (next_tile
);
231 add
= (statspec
!= NULL
) && HasBit(statspec
->wires
, GetStationGfx (next_tile
));
234 neighbour_tdb
|= DiagdirReachesTrackdirs(ReverseDiagDir(d
));
238 /* If the tracks from either a diagonal crossing or don't overlap, both
239 * trackdirs have to be marked to mask the corresponding track bit. Else
240 * one marked trackdir is enough the mask the track bit. */
242 if (tracks
== TRACK_BIT_CROSS
|| !TracksOverlap(tracks
)) {
243 /* If the tracks form either a diagonal crossing or don't overlap, both
244 * trackdirs have to be marked to mask the corresponding track bit. */
245 mask
= ~(TrackBits
)((neighbour_tdb
& (neighbour_tdb
>> 8)) & TRACK_BIT_MASK
);
246 /* If that results in no masked tracks and it is not a diagonal crossing,
247 * require only one marked trackdir to mask. */
248 if (tracks
!= TRACK_BIT_CROSS
&& (mask
& TRACK_BIT_MASK
) == TRACK_BIT_MASK
) mask
= ~TrackdirBitsToTrackBits(neighbour_tdb
);
250 /* Require only one marked trackdir to mask the track. */
251 mask
= ~TrackdirBitsToTrackBits(neighbour_tdb
);
252 /* If that results in an empty set, require both trackdirs for diagonal track. */
253 if ((tracks
& mask
) == TRACK_BIT_NONE
) {
254 if ((neighbour_tdb
& TRACKDIR_BIT_X_NE
) == 0 || (neighbour_tdb
& TRACKDIR_BIT_X_SW
) == 0) mask
|= TRACK_BIT_X
;
255 if ((neighbour_tdb
& TRACKDIR_BIT_Y_NW
) == 0 || (neighbour_tdb
& TRACKDIR_BIT_Y_SE
) == 0) mask
|= TRACK_BIT_Y
;
256 /* If that still is not enough, require both trackdirs for any track. */
257 if ((tracks
& mask
) == TRACK_BIT_NONE
) mask
= ~(TrackBits
)((neighbour_tdb
& (neighbour_tdb
>> 8)) & TRACK_BIT_MASK
);
261 /* Mask the tracks only if at least one track bit would remain. */
262 return (tracks
& mask
) != TRACK_BIT_NONE
? tracks
& mask
: tracks
;
265 /** Get the base wire sprite to use. */
266 static inline SpriteID
GetWireBase (const RailtypeInfo
*rti
, TileIndex tile
,
267 TileContext context
= TCX_NORMAL
)
269 SpriteID wires
= GetCustomRailSprite (rti
, tile
, RTSG_WIRES
, context
);
270 return wires
== 0 ? SPR_WIRE_BASE
: wires
;
273 /** Get the base pylon sprite to use. */
274 static inline SpriteID
GetPylonBase (const RailtypeInfo
*rti
, TileIndex tile
,
275 TileContext context
= TCX_NORMAL
)
277 SpriteID pylons
= GetCustomRailSprite (rti
, tile
, RTSG_PYLONS
, context
);
278 return pylons
== 0 ? SPR_PYLON_BASE
: pylons
;
282 * Draws wires on a rail tunnel or depot tile.
283 * @param ti The TileInfo to draw the tile for.
284 * @param rti The rail type information of the rail.
285 * @param depot The tile is a depot, else a tunnel.
286 * @param dir The direction of the tunnel or depot.
288 void DrawRailTunnelDepotCatenary (const TileInfo
*ti
, const RailtypeInfo
*rti
,
289 bool depot
, DiagDirection dir
)
291 struct SortableSpriteStruct
{
292 struct { int8 x
, y
, w
, h
; } bb
[2];
297 static const SortableSpriteStruct data
[2] = {
298 { { { 0, -6, 16, 8 }, { 0, 0, 15, 1 } }, 0, 7 }, //! Wire along X axis
299 { { { -6, 0, 8, 16 }, { 0, 0, 1, 15 } }, 7, 0 }, //! Wire along Y axis
302 assert_compile (WSO_ENTRANCE_NE
== WSO_ENTRANCE_NE
+ DIAGDIR_NE
);
303 assert_compile (WSO_ENTRANCE_SE
== WSO_ENTRANCE_NE
+ DIAGDIR_SE
);
304 assert_compile (WSO_ENTRANCE_SW
== WSO_ENTRANCE_NE
+ DIAGDIR_SW
);
305 assert_compile (WSO_ENTRANCE_NW
== WSO_ENTRANCE_NE
+ DIAGDIR_NW
);
307 const SortableSpriteStruct
*sss
= &data
[DiagDirToAxis(dir
)];
308 int dz
= depot
? 0 : BB_Z_SEPARATOR
- ELRAIL_ELEVATION
;
309 int z
= depot
? GetTileMaxPixelZ (ti
->tile
) : GetTilePixelZ (ti
->tile
);
310 /* This wire is not visible with the default depot sprites. */
311 AddSortableSpriteToDraw (ti
->vd
,
312 GetWireBase (rti
, ti
->tile
) + WSO_ENTRANCE_NE
+ dir
, PAL_NONE
,
313 ti
->x
+ sss
->x_offset
, ti
->y
+ sss
->y_offset
,
314 sss
->bb
[depot
].w
, sss
->bb
[depot
].h
, dz
+ 1,
315 z
+ ELRAIL_ELEVATION
, IsTransparencySet (TO_CATENARY
),
316 sss
->bb
[depot
].x
, sss
->bb
[depot
].y
, dz
);
320 struct SideTrackData
{
321 byte track
; ///< a track that incides at this side
322 byte preferred
; ///< preferred pylon position points for it
325 static const uint NUM_TRACKS_PER_SIDE
= 3;
327 /* Side track data, 3 tracks per side. */
328 static const SideTrackData side_tracks
[DIAGDIR_END
][NUM_TRACKS_PER_SIDE
] = {
330 { TRACK_X
, 1 << DIR_NE
| 1 << DIR_SE
| 1 << DIR_NW
},
331 { TRACK_UPPER
, 1 << DIR_E
| 1 << DIR_N
| 1 << DIR_S
},
332 { TRACK_RIGHT
, 1 << DIR_N
| 1 << DIR_E
| 1 << DIR_W
},
334 { TRACK_Y
, 1 << DIR_NE
| 1 << DIR_SE
| 1 << DIR_SW
},
335 { TRACK_LOWER
, 1 << DIR_E
| 1 << DIR_N
| 1 << DIR_S
},
336 { TRACK_RIGHT
, 1 << DIR_S
| 1 << DIR_E
| 1 << DIR_W
},
338 { TRACK_X
, 1 << DIR_SE
| 1 << DIR_SW
| 1 << DIR_NW
},
339 { TRACK_LOWER
, 1 << DIR_W
| 1 << DIR_N
| 1 << DIR_S
},
340 { TRACK_LEFT
, 1 << DIR_S
| 1 << DIR_E
| 1 << DIR_W
},
342 { TRACK_Y
, 1 << DIR_SW
| 1 << DIR_NW
| 1 << DIR_NE
},
343 { TRACK_UPPER
, 1 << DIR_W
| 1 << DIR_N
| 1 << DIR_S
},
344 { TRACK_LEFT
, 1 << DIR_N
| 1 << DIR_E
| 1 << DIR_W
},
348 /* Mask of positions at which pylons can be built per track. */
349 static const byte allowed_ppp
[TRACK_END
] = {
350 1 << DIR_N
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_W
| 1 << DIR_NW
, // X
351 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_W
, // Y
352 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_NW
, // UPPER
353 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_NW
, // LOWER
354 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_SW
| 1 << DIR_W
| 1 << DIR_NW
, // LEFT
355 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_SW
| 1 << DIR_W
| 1 << DIR_NW
, // RIGHT
359 * Mask preferred and allowed pylon position points on a tile side.
360 * @param tracks Tracks present on the tile.
361 * @param wires Electrified tracks present on the tile.
362 * @param side Tile side to check.
363 * @param preferred Pointer to preferred positions to mask.
364 * @param allowed Pointer to allowed positions to mask.
365 * @return The number of wires inciding on the given side.
367 static uint
CheckCatenarySide (TrackBits tracks
, TrackBits wires
,
368 DiagDirection side
, byte
*preferred
, byte
*allowed
)
374 for (uint k
= 0; k
< NUM_TRACKS_PER_SIDE
; k
++) {
375 /* We check whether the track in question is present. */
376 const SideTrackData
*data
= &side_tracks
[side
][k
];
377 byte track
= data
->track
;
378 if (HasBit(wires
, track
)) {
381 pmask
&= data
->preferred
;
383 if (HasBit(tracks
, track
)) {
384 amask
&= allowed_ppp
[track
];
388 /* At least the PPPs along the tile side must be in the allowed set. */
389 byte test
= (DiagDirToAxis(side
) == AXIS_X
) ?
390 (1 << DIR_SE
) | (1 << DIR_NW
) :
391 (1 << DIR_NE
) | (1 << DIR_SW
);
392 assert ((amask
& test
) == test
);
400 * Check if the pylon on a tile side should be elided on long track runs.
401 * @param side Tile side to check.
402 * @param preferred Preferred pylon positions.
403 * @param odd Array of tile coordinate parity per axis.
404 * @param level Whether the land is level (for tracks running along an axis).
405 * @return Whether the pylon should be elided.
407 static bool CheckPylonElision (DiagDirection side
, byte preferred
,
408 const bool *odd
, bool level
)
410 Axis axis
= DiagDirToAxis (side
);
413 case 1 << DIR_NW
| 1 << DIR_SE
:
414 if (!level
) return false;
415 ignore
= false; // must be X axis
418 case 1 << DIR_NE
| 1 << DIR_SW
:
419 if (!level
) return false;
420 ignore
= true; // must be Y axis
423 case 1 << DIR_E
| 1 << DIR_W
:
424 /* Non-orthogonal tracks must always be level. */
425 ignore
= (axis
== AXIS_X
) ? !odd
[AXIS_Y
] : odd
[AXIS_X
];
428 case 1 << DIR_N
| 1 << DIR_S
:
429 /* Non-orthogonal tracks must always be level. */
430 ignore
= !odd
[OtherAxis(axis
)];
437 /* This configuration may be subject to pylon elision. */
438 /* Toggle ignore if we are in an odd row, or heading the other way. */
439 return (ignore
^ odd
[axis
] ^ HasBit(side
, 1));
442 /** Possible return values for CheckNeighbourPCP below. */
444 PCP_NB_NONE
, ///< PCP not in use from the neighbour tile
445 PCP_NB_TUNNEL
, ///< PCP in use by a tunnel from the neighbour tile
446 PCP_NB_IN_USE
, ///< PCP is in use and may not be elided
447 PCP_NB_TRY_ELIDE
, ///< PCP is in use and may be subject to elision
451 * Check whether a pylon is also in use from a railway tile at the other side.
452 * @param tile The neighbour railway tile to check.
453 * @param side The tile side to check from this tile.
454 * @param preferred Pointer to preferred positions to mask.
455 * @param allowed Pointer to allowed positions to mask.
456 * @param slope Pointer to store the tile slope if pylon elision is possible.
457 * @return A value representing the PCP state at the given side.
459 static uint
CheckRailNeighbourPCP (TileIndex tile
, DiagDirection side
,
460 byte
*preferred
, byte
*allowed
, Slope
*slope
)
462 assert (IsRailwayTile (tile
));
464 bool is_bridge
= IsTileSubtype (tile
, TT_BRIDGE
);
465 if (is_bridge
&& GetTunnelBridgeDirection (tile
) == side
) {
469 TrackBits nb_tracks
= GetElectrifiedTrackBits (tile
);
470 if (nb_tracks
== TRACK_BIT_NONE
) return PCP_NB_NONE
;
471 TrackBits nb_wires
= MaskWireBits (tile
, nb_tracks
);
473 /* Tracks inciding from the neighbour tile */
474 switch (CheckCatenarySide (nb_tracks
, nb_wires
, side
,
475 preferred
, allowed
)) {
476 case 0: return PCP_NB_NONE
;
478 default: /* more than one wire, so we need the pylon */
479 return PCP_NB_IN_USE
;
482 /* Read the foundations if they are present, and adjust the tileh */
483 assert_compile (TRACK_BIT_X
== 1);
484 assert_compile (TRACK_BIT_Y
== 2);
488 /* Anything having more than a single X or Y track must be
489 * flat (or a half tile slope, but we treat those as flat). */
490 nb_slope
= SLOPE_FLAT
;
491 } else if (!is_bridge
) {
492 nb_slope
= GetTileSlope (tile
);
493 Foundation f
= GetRailFoundation (nb_slope
, nb_tracks
);
494 ApplyFoundationToSlope (f
, &nb_slope
);
496 nb_slope
= GetTileSlope (tile
);
497 /* With a single X or Y track, bridge must
498 * head away from our side. */
499 nb_slope
= HasBridgeFlatRamp (nb_slope
, DiagDirToAxis (side
)) ?
501 InclinedSlope (ReverseDiagDir (side
));
505 return PCP_NB_TRY_ELIDE
;
509 * Check whether a pylon is also in use from the other side.
510 * @param tile The neighbour tile to check.
511 * @param side The tile side to check from this tile.
512 * @param preferred Pointer to preferred positions to mask.
513 * @param allowed Pointer to allowed positions to mask.
514 * @param slope Pointer to store the tile slope if pylon elision is possible.
515 * @return A value representing the PCP state at the given side.
517 static uint
CheckNeighbourPCP (TileIndex tile
, DiagDirection side
,
518 byte
*preferred
, byte
*allowed
, Slope
*slope
)
521 switch (GetTileType (tile
)) {
523 return CheckRailNeighbourPCP (tile
, side
,
524 preferred
, allowed
, slope
);
527 switch (GetTileSubtype (tile
)) {
528 default: return PCP_NB_NONE
;
530 case TT_MISC_CROSSING
:
531 if (!HasRailCatenary (GetRailType (tile
))) return PCP_NB_NONE
;
532 axis
= GetCrossingRailAxis (tile
);
536 if (GetTunnelTransportType (tile
) != TRANSPORT_RAIL
) return PCP_NB_NONE
;
537 if (!HasRailCatenary (GetRailType (tile
))) return PCP_NB_NONE
;
538 /* ignore tunnels facing the wrong way for neighbouring tiles */
539 if (GetTunnelBridgeDirection (tile
) != ReverseDiagDir (side
)) return PCP_NB_NONE
;
540 return PCP_NB_TUNNEL
;
545 if (!HasStationRail (tile
)) return PCP_NB_NONE
;
546 if (!HasRailCatenary (GetRailType (tile
))) return PCP_NB_NONE
;
547 /* Ignore neighbouring station tiles that allow neither wires nor pylons. */
548 const StationSpec
*statspec
= GetStationSpec (tile
);
549 if (statspec
!= NULL
) {
550 byte mask
= statspec
->wires
& ~statspec
->pylons
;
551 uint gfx
= GetStationGfx (tile
);
552 if (HasBit(mask
, gfx
)) return PCP_NB_NONE
;
554 axis
= GetRailStationAxis (tile
);
562 /* Crossing or station tile, so just one flat track along an axis. */
564 /* We check whether the track in question is present. */
565 if (DiagDirToAxis (side
) != axis
) return PCP_NB_NONE
;
568 *preferred
&= side_tracks
[side
][0].preferred
;
570 return PCP_NB_TRY_ELIDE
;
573 /** Possible return values for CheckSidePCP below. */
575 PCP_NONE
, ///< PCP is not in use
576 PCP_IN_USE
, ///< PCP is in use from this tile
577 PCP_IN_USE_BOTH
, ///< PCP is in use also from the neighbour tile
581 * Check whether there should be a pylon at a tile side.
582 * @param tile The tile to check.
583 * @param home_tracks Tracks present on the home tile.
584 * @param home_wires Electrified tracks present on the home tile.
585 * @param home_slope Slope of the home tile, adjusted for foundations.
586 * @param side The side to check.
587 * @param odd Array of tile coordinate parity per axis.
588 * @return A value representing the PCP state at the given side, plus
589 * a bitmask of allowed directions for the pylon, if any.
591 static std::pair
<uint
, byte
> CheckSidePCP (TileIndex tile
,
592 TrackBits home_tracks
, TrackBits home_wires
, Slope home_slope
,
593 DiagDirection side
, const bool *odd
)
595 /* We cycle through all the existing tracks at a PCP and see what
596 * PPPs we want to have, or may not have at all */
597 byte PPPpreferred
= 0xFF; // We start with preferring everything (end-of-line in any direction)
598 byte PPPallowed
= AllowedPPPonPCP
[side
];
600 /* Tracks inciding from the home tile */
601 if (CheckCatenarySide (home_tracks
, home_wires
, side
, &PPPpreferred
,
603 /* PCP not used at all from this tile. */
604 return std::make_pair (PCP_NONE
, 0);
609 switch (CheckNeighbourPCP (tile
+ TileOffsByDiagDir (side
),
610 ReverseDiagDir (side
),
611 &PPPpreferred
, &PPPallowed
, &nb_slope
)) {
612 default: // PCP_NB_TRY_ELIDE
613 if (CheckPylonElision (side
, PPPpreferred
, odd
, home_slope
== nb_slope
)) {
614 return std::make_pair (PCP_NONE
, 0);
618 pcp_neighbour
= true;
622 /* force tunnels to always have a pylon (no elision) */
623 return std::make_pair (PCP_IN_USE_BOTH
, PPPallowed
);
626 pcp_neighbour
= false;
630 /* At least the PPPs along the tile side must be in the allowed set. */
631 byte test
= (DiagDirToAxis(side
) == AXIS_X
) ?
632 (1 << DIR_SE
) | (1 << DIR_NW
) :
633 (1 << DIR_NE
) | (1 << DIR_SW
);
634 assert ((PPPallowed
& test
) == test
);
636 /* Now decide where we draw our pylons. First try the preferred PPPs,
637 * but they may not exist. In that case, we try the any of the allowed
638 * ones. Note that the preferred PPPs still contain the end-of-line
639 * markers. Remove those (simply by ANDing with allowed, since these
640 * markers are never allowed). */
641 PPPpreferred
&= PPPallowed
;
642 return std::make_pair (pcp_neighbour
? PCP_IN_USE_BOTH
: PCP_IN_USE
,
643 PPPpreferred
!= 0 ? PPPpreferred
: PPPallowed
);
647 * Choose the pylon position point to use for a pylon.
648 * @param side Tile side where the pylon will be drawn.
649 * @param allowed Mask of allowed pylon position points.
650 * @param order Possible pylon positions arranged by preference.
651 * @param nb Whether there is a neighbour tile that could draw this pylon.
652 * @return The pylon position point to use, or -1 for none.
653 * @note Use the overloaded variant below.
655 static int ChoosePylonPosition (DiagDirection side
, byte allowed
,
656 const Direction
*order
, bool nb
)
658 /* Which of the PPPs are inside the tile. For the two PPPs on the tile
659 * border the following system is used: if you rotate the PCP so that
660 * it is in the north, the eastern PPP belongs to the tile. */
661 static const byte owned
[DIAGDIR_END
] = {
662 1 << DIR_SE
| 1 << DIR_S
| 1 << DIR_SW
| 1 << DIR_W
,
663 1 << DIR_N
| 1 << DIR_SW
| 1 << DIR_W
| 1 << DIR_NW
,
664 1 << DIR_N
| 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_NW
,
665 1 << DIR_NE
| 1 << DIR_E
| 1 << DIR_SE
| 1 << DIR_S
,
668 assert (allowed
!= 0);
670 byte own
= owned
[side
] & allowed
;
671 byte mask
= nb
? allowed
: own
;
673 for (Direction k
= DIR_BEGIN
; k
< DIR_END
; k
++) {
676 /* Don't build the pylon if it would be outside the tile */
677 if (HasBit(mask
, pos
)) {
678 /* We have a neighbour that will draw it, bail out */
679 return HasBit(own
, pos
) ? pos
: -1;
687 * Choose the pylon position point to use for a pylon.
688 * @param side Tile side where the pylon will be drawn.
689 * @param allowed Mask of allowed pylon position points.
690 * @param odd_x Whether the tile is on an odd X coordinate.
691 * @param odd_y Whether the tile is on an odd Y coordinate.
692 * @param nb Whether there is a neighbour tile that could draw this pylon.
693 * @return The pylon position point to use.
695 static inline int ChoosePylonPosition (DiagDirection side
, byte allowed
,
696 bool odd_x
, bool odd_y
, bool nb
)
698 /* Several PPPs maybe exist, here they are sorted in order of preference. */
699 static const Direction order
[2][2][DIAGDIR_END
][DIR_END
] = {
702 {DIR_NE
, DIR_NW
, DIR_SE
, DIR_SW
, DIR_N
, DIR_E
, DIR_S
, DIR_W
}, // NE
703 {DIR_NE
, DIR_NW
, DIR_SE
, DIR_SW
, DIR_S
, DIR_E
, DIR_N
, DIR_W
}, // SE
704 {DIR_NE
, DIR_NW
, DIR_SE
, DIR_SW
, DIR_S
, DIR_W
, DIR_N
, DIR_E
}, // SW
705 {DIR_NE
, DIR_NW
, DIR_SE
, DIR_SW
, DIR_N
, DIR_W
, DIR_S
, DIR_E
}, // NW
707 {DIR_NE
, DIR_SE
, DIR_SW
, DIR_NW
, DIR_S
, DIR_W
, DIR_N
, DIR_E
}, // NE
708 {DIR_NE
, DIR_SE
, DIR_SW
, DIR_NW
, DIR_N
, DIR_W
, DIR_S
, DIR_E
}, // SE
709 {DIR_NE
, DIR_SE
, DIR_SW
, DIR_NW
, DIR_N
, DIR_E
, DIR_S
, DIR_W
}, // SW
710 {DIR_NE
, DIR_SE
, DIR_SW
, DIR_NW
, DIR_S
, DIR_E
, DIR_N
, DIR_W
}, // NW
714 {DIR_SW
, DIR_NW
, DIR_NE
, DIR_SE
, DIR_S
, DIR_W
, DIR_N
, DIR_E
}, // NE
715 {DIR_SW
, DIR_NW
, DIR_NE
, DIR_SE
, DIR_N
, DIR_W
, DIR_S
, DIR_E
}, // SE
716 {DIR_SW
, DIR_NW
, DIR_NE
, DIR_SE
, DIR_N
, DIR_E
, DIR_S
, DIR_W
}, // SW
717 {DIR_SW
, DIR_NW
, DIR_NE
, DIR_SE
, DIR_S
, DIR_E
, DIR_N
, DIR_W
}, // NW
719 {DIR_SW
, DIR_SE
, DIR_NE
, DIR_NW
, DIR_N
, DIR_E
, DIR_S
, DIR_W
}, // NE
720 {DIR_SW
, DIR_SE
, DIR_NE
, DIR_NW
, DIR_S
, DIR_E
, DIR_N
, DIR_W
}, // SE
721 {DIR_SW
, DIR_SE
, DIR_NE
, DIR_NW
, DIR_S
, DIR_W
, DIR_N
, DIR_E
}, // SW
722 {DIR_SW
, DIR_SE
, DIR_NE
, DIR_NW
, DIR_N
, DIR_W
, DIR_S
, DIR_E
}, // NW
727 return ChoosePylonPosition (side
, allowed
, order
[odd_x
][odd_y
][side
], nb
);
731 * Add a pylon sprite for a tile.
732 * @param ti The TileInfo struct of the tile being drawn.
733 * @param pylon The sprite to draw.
734 * @param x X position of the sprite.
735 * @param y Y position of the sprite.
736 * @param z Z position of the sprite.
738 static void AddPylonSprite (const TileInfo
*ti
, SpriteID pylon
,
741 AddSortableSpriteToDraw (ti
->vd
, pylon
, PAL_NONE
, x
, y
, 1, 1,
742 BB_HEIGHT_UNDER_BRIDGE
, z
,
743 IsTransparencySet (TO_CATENARY
), -1, -1);
747 * Draw a pylon at a tile side.
748 * @param ti The TileInfo struct of the tile being drawn.
749 * @param side Side where to draw the pylon.
750 * @param dir Pylon position point.
751 * @param pylon_base Pylon sprite base.
753 static void DrawPylon (const TileInfo
*ti
, DiagDirection side
, Direction dir
,
756 uint x
= ti
->x
+ x_pcp_offsets
[side
] + x_ppp_offsets
[dir
];
757 uint y
= ti
->y
+ y_pcp_offsets
[side
] + y_ppp_offsets
[dir
];
759 /* The elevation of the "pylon"-sprite should be the elevation
760 * at the PCP. PCPs are always on a tile edge.
762 * This position can be outside of the tile, i.e.
763 * ?_pcp_offset == TILE_SIZE > TILE_SIZE - 1.
764 * So we have to move it inside the tile, because if the neighboured
765 * tile has a foundation, that does not smoothly connect to the
766 * current tile, we will get a wrong elevation from GetSlopePixelZ().
768 * When we move the position inside the tile, we will get a wrong
769 * elevation if we have a slope. To catch all cases we round the Z
770 * position to the next (TILE_HEIGHT / 2). This will return the
771 * correct elevation for slopes and will also detect non-continuous
772 * elevation on edges.
774 * Also note that the result of GetSlopePixelZ() is very special on
778 TileIndex tile
= ti
->tile
;
779 int z
= GetSlopePixelZ (TileX(tile
) * TILE_SIZE
+ min(x_pcp_offsets
[side
], TILE_SIZE
- 1), TileY(tile
) * TILE_SIZE
+ min(y_pcp_offsets
[side
], TILE_SIZE
- 1));
780 int elevation
= (z
+ 2) & ~3; // this means z = (z + TILE_HEIGHT / 4) / (TILE_HEIGHT / 2) * (TILE_HEIGHT / 2);
782 AddPylonSprite (ti
, pylon_base
+ pylon_sprites
[dir
], x
, y
, elevation
);
786 * Add a wire sprite for a tile.
787 * @param ti The TileInfo struct of the tile being drawn.
788 * @param wire_base The base of the wire sprite to draw.
789 * @param sss The sprite data for the wire.
790 * @param config The configuration to use for the wire.
791 * @param z Base Z position of the sprite.
793 static inline void AddWireSprite (const TileInfo
*ti
, SpriteID wire_base
,
794 const SortableSpriteStructM
*sss
, uint config
, int z
)
796 AddSortableSpriteToDraw (ti
->vd
,
797 wire_base
+ sss
->image_offset
[config
- 1], PAL_NONE
,
798 ti
->x
+ sss
->x_offset
, ti
->y
+ sss
->y_offset
,
799 sss
->x_size
, sss
->y_size
, 1,
800 z
+ sss
->z_offset
, IsTransparencySet (TO_CATENARY
));
804 * Draws overhead wires and pylons for electric railways.
805 * @param ti The TileInfo struct of the tile being drawn.
806 * @param rti The rail type information of the rail.
807 * @param tracks Tracks on which to draw.
808 * @param wires Wires to draw.
809 * @param slope Slope of the track surface for pylon elision.
810 * @param draw_pylons Whether to draw pylons (some stations disable this).
811 * @param draw_wires Whether to draw wires (some stations disable this).
812 * @param context Tile context for GetWireBase and GetPylonBase.
813 * @param bridge Bridge direction, if any.
815 static void DrawRailCatenary (const TileInfo
*ti
, const RailtypeInfo
*rti
,
816 TrackBits tracks
, TrackBits wires
, Slope slope
,
817 bool draw_pylons
, bool draw_wires
, TileContext context
= TCX_NORMAL
,
818 DiagDirection bridge
= INVALID_DIAGDIR
)
821 odd
[AXIS_X
] = IsOddX(ti
->tile
);
822 odd
[AXIS_Y
] = IsOddY(ti
->tile
);
826 SpriteID pylon_base
= draw_pylons
? GetPylonBase (rti
, ti
->tile
, context
) : 0;
828 for (DiagDirection side
= DIAGDIR_BEGIN
; side
< DIAGDIR_END
; side
++) {
831 if (side
!= bridge
) {
832 std::pair
<uint
, byte
> pcp_state
= CheckSidePCP (ti
->tile
,
833 tracks
, wires
, slope
, side
, odd
);
834 if (pcp_state
.first
== PCP_NONE
) continue;
835 pcp_neighbour
= (pcp_state
.first
== PCP_IN_USE_BOTH
);
836 ppp_allowed
= pcp_state
.second
;
837 SetBit(pcp_status
, side
);
840 TrackBits bridge_tracks
= DiagdirReachesTracks (ReverseDiagDir (side
));
841 if ((tracks
& bridge_tracks
) == TRACK_BIT_NONE
) continue;
842 SetBit(pcp_status
, side
);
843 /* Pylon is drawn by the middle part if there is any. */
844 if (GetTunnelBridgeLength (ti
->tile
, GetOtherBridgeEnd (ti
->tile
)) > 0) continue;
845 pcp_neighbour
= true;
846 ppp_allowed
= AllowedPPPonPCP
[side
];
849 if (pylon_base
== 0) continue;
851 if (HasBridgeAbove(ti
->tile
)) {
852 if (GetBridgeAxis (ti
->tile
) == DiagDirToAxis (side
)) {
853 int height
= GetBridgeHeight (GetNorthernBridgeEnd (ti
->tile
));
854 if (height
<= GetTileMaxZ (ti
->tile
) + 1) {
860 int pos
= ChoosePylonPosition (side
, ppp_allowed
,
861 odd
[AXIS_X
], odd
[AXIS_Y
], pcp_neighbour
);
863 DrawPylon (ti
, side
, (Direction
)pos
, pylon_base
);
867 /* Don't draw a wire if the station tile does not want any */
868 if (!draw_wires
) return;
870 /* Don't draw a wire under a low bridge */
871 if (HasBridgeAbove(ti
->tile
) && !IsTransparencySet(TO_BRIDGES
)) {
872 int height
= GetBridgeHeight(GetNorthernBridgeEnd(ti
->tile
));
874 if (height
<= GetTileMaxZ(ti
->tile
) + 1) return;
877 /* Drawing of pylons is finished, now draw the wires */
878 SpriteID wire_base
= GetWireBase (rti
, ti
->tile
, context
);
881 FOR_EACH_SET_TRACK(t
, wires
) {
882 /* Map a track bit onto its two tile sides. */
883 static const byte track_sides
[TRACK_END
][2] = {
884 {DIAGDIR_NE
, DIAGDIR_SW
}, // X
885 {DIAGDIR_SE
, DIAGDIR_NW
}, // Y
886 {DIAGDIR_NW
, DIAGDIR_NE
}, // UPPER
887 {DIAGDIR_SE
, DIAGDIR_SW
}, // LOWER
888 {DIAGDIR_SW
, DIAGDIR_NW
}, // LEFT
889 {DIAGDIR_NE
, DIAGDIR_SE
}, // RIGHT
892 byte pcp_config
= HasBit(pcp_status
, track_sides
[t
][0]) +
893 (HasBit(pcp_status
, track_sides
[t
][1]) << 1);
895 assert(pcp_config
!= 0); // We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that)
896 assert(!IsSteepSlope(slope
));
898 const SortableSpriteStructM
*sss
;
900 case SLOPE_SW
: sss
= &CatenarySpriteDataSW
; break;
901 case SLOPE_SE
: sss
= &CatenarySpriteDataSE
; break;
902 case SLOPE_NW
: sss
= &CatenarySpriteDataNW
; break;
903 case SLOPE_NE
: sss
= &CatenarySpriteDataNE
; break;
904 default: sss
= &CatenarySpriteData
[t
]; break;
908 * The "wire"-sprite position is inside the tile, i.e. 0 <= sss->?_offset < TILE_SIZE.
909 * Therefore it is safe to use GetSlopePixelZ() for the elevation.
910 * Also note that the result of GetSlopePixelZ() is very special for bridge-ramps.
912 AddWireSprite (ti
, wire_base
, sss
, pcp_config
,
913 GetSlopePixelZ (ti
->x
+ sss
->x_offset
, ti
->y
+ sss
->y_offset
));
918 * Draws overhead wires and pylons for electric railways.
919 * @param ti The TileInfo struct of the tile being drawn
921 void DrawRailwayCatenary (const TileInfo
*ti
)
923 assert (IsRailwayTile (ti
->tile
));
925 /* Find which rail bits are present, and select the override points. */
926 DiagDirection overridePCP
= IsTileSubtype (ti
->tile
, TT_BRIDGE
) ? GetTunnelBridgeDirection (ti
->tile
) : INVALID_DIAGDIR
;
927 TrackBits tracks
= GetElectrifiedTrackBits (ti
->tile
);
928 TrackBits wires
= MaskWireBits (ti
->tile
, tracks
);
930 /* Note that ti->tileh has already been adjusted for Foundations */
931 Slope slope
= ti
->tileh
;
933 const RailtypeInfo
*rti
, *halftile_rti
;
934 Track halftile_track
;
935 TileContext halftile_context
;
936 if (IsHalftileSlope (slope
)) {
937 switch (GetHalftileSlopeCorner (slope
)) {
938 default: NOT_REACHED();
939 case CORNER_W
: halftile_track
= TRACK_LEFT
; break;
940 case CORNER_S
: halftile_track
= TRACK_LOWER
; break;
941 case CORNER_E
: halftile_track
= TRACK_RIGHT
; break;
942 case CORNER_N
: halftile_track
= TRACK_UPPER
; break;
944 halftile_rti
= GetRailTypeInfo (GetRailType (ti
->tile
, halftile_track
));
945 halftile_context
= TCX_UPPER_HALFTILE
;
946 Track opposite
= TrackToOppositeTrack (halftile_track
);
947 rti
= !HasBit(tracks
, opposite
) ? NULL
:
948 GetRailTypeInfo (GetRailType (ti
->tile
, opposite
));
951 RailType rt1
= GetRailType (ti
->tile
, TRACK_UPPER
);
952 RailType rt2
= GetRailType (ti
->tile
, TRACK_LOWER
);
953 rti
= GetRailTypeInfo (rt1
);
955 halftile_track
= INVALID_TRACK
;
957 const RailtypeInfo
*rti2
= GetRailTypeInfo (rt2
);
961 halftile_track
= TRACK_LOWER
;
965 halftile_track
= TRACK_RIGHT
;
967 case TRACK_BIT_LOWER
:
968 case TRACK_BIT_RIGHT
:
971 default: // TRACK_BIT_UPPER or TRACK_BIT_LEFT
972 halftile_track
= INVALID_TRACK
;
976 halftile_context
= TCX_NORMAL
;
979 if (halftile_track
!= INVALID_TRACK
) {
980 TrackBits tracks
= TrackToTrackBits (halftile_track
);
981 if (HasRailCatenary (halftile_rti
)) {
982 DrawRailCatenary (ti
, halftile_rti
, tracks
, tracks
,
983 SLOPE_FLAT
, true, true,
986 if (rti
== NULL
) return;
991 if (HasRailCatenary (rti
)) {
992 DrawRailCatenary (ti
, rti
, tracks
, wires
, slope
, true, true,
993 TCX_NORMAL
, overridePCP
);
998 * Draws overhead wires and pylons on a normal (non-custom) bridge head.
999 * @param ti The TileInfo struct of the tile being drawn.
1000 * @param rti The rail type information of the rail.
1001 * @param dir The direction of the bridge.
1003 void DrawRailBridgeHeadCatenary (const TileInfo
*ti
, const RailtypeInfo
*rti
,
1006 TrackBits tracks
= DiagDirToDiagTrackBits (dir
);
1008 DrawRailCatenary (ti
, rti
, tracks
, tracks
, (ti
->tileh
!= SLOPE_FLAT
) ?
1009 SLOPE_FLAT
: InclinedSlope (dir
),
1010 true, true, TCX_NORMAL
, dir
);
1014 * Draws overhead wires and pylons for electric railways along an axis
1015 * (for crossings and station tiles).
1016 * @param ti The TileInfo struct of the tile being drawn.
1017 * @param rti The rail type information of the rail.
1018 * @param axis The axis along which to draw the wire.
1019 * @param draw_pylons Whether to draw pylons (some stations disable this).
1020 * @param draw_wire Whether to draw the wire (some stations disable this).
1022 void DrawRailAxisCatenary (const TileInfo
*ti
, const RailtypeInfo
*rti
,
1023 Axis axis
, bool draw_pylons
, bool draw_wire
)
1025 /* Note that ti->tileh has already been adjusted for Foundations */
1026 assert (ti
->tileh
== SLOPE_FLAT
);
1028 TrackBits tracks
= AxisToTrackBits (axis
);
1029 DrawRailCatenary (ti
, rti
, tracks
, tracks
, SLOPE_FLAT
, draw_pylons
, draw_wire
);
1033 * Draws overhead wires and pylons at a tunnel entrance.
1034 * @param ti The TileInfo struct of the tile being drawn.
1035 * @param dir The direction of the tunnel.
1037 void DrawRailTunnelCatenary (const TileInfo
*ti
, DiagDirection dir
)
1040 TileIndex tile
= ti
->tile
;
1041 DiagDirection rev
= ReverseDiagDir (dir
);
1043 byte dummy_preferred
, dummy_allowed
;
1045 bool pcp_neighbour
= CheckNeighbourPCP (tile
+ TileOffsByDiagDir (rev
),
1046 dir
, &dummy_preferred
, &dummy_allowed
, &dummy_slope
)
1049 int pos
= ChoosePylonPosition (rev
, AllowedPPPonPCP
[rev
],
1050 IsOddX(tile
), IsOddY(tile
), pcp_neighbour
);
1052 const RailtypeInfo
*rti
= GetRailTypeInfo (GetRailType (tile
));
1054 DrawPylon (ti
, rev
, (Direction
)pos
,
1055 GetPylonBase (rti
, tile
, TCX_NORMAL
));
1059 StartSpriteCombine (ti
->vd
);
1060 DrawRailTunnelDepotCatenary (ti
, rti
, false, dir
);
1064 * Draws wires on a tunnel tile
1066 * DrawTile_TunnelBridge() calls this function to draw the wires on the bridge.
1068 * @param ti The Tileinfo to draw the tile for
1070 void DrawRailCatenaryOnBridge(const TileInfo
*ti
)
1072 TileIndex start
= GetNorthernBridgeEnd(ti
->tile
);
1073 bool odd
= ((GetTunnelBridgeLength (ti
->tile
, start
) + 1) % 2) != 0;
1075 TileIndex end
= GetSouthernBridgeEnd(ti
->tile
);
1076 bool last
= (GetTunnelBridgeLength (ti
->tile
, end
) == 0);
1078 const RailtypeInfo
*rti
= GetRailTypeInfo (GetBridgeRailType (end
));
1080 Axis axis
= GetBridgeAxis(ti
->tile
);
1084 /* Draw the "short" wire on the southern end of the bridge
1085 * only needed if the length of the bridge is odd */
1088 /* Draw "long" wires on all other tiles of the bridge (one pylon every two tiles) */
1092 uint height
= GetBridgePixelHeight(end
);
1094 AddWireSprite (ti
, GetWireBase (rti
, end
, TCX_ON_BRIDGE
),
1095 &CatenarySpriteData
[AxisToTrack(axis
)], config
, height
);
1097 /* Finished with wires, draw pylons */
1098 if (!odd
&& !last
) return; /* no pylons to draw */
1100 DiagDirection PCPpos
;
1102 if (axis
== AXIS_X
) {
1103 PCPpos
= DIAGDIR_NE
;
1104 PPPpos
= IsOddY(ti
->tile
) ? DIR_SE
: DIR_NW
;
1106 PCPpos
= DIAGDIR_NW
;
1107 PPPpos
= IsOddX(ti
->tile
) ? DIR_SW
: DIR_NE
;
1110 SpriteID pylon
= GetPylonBase (rti
, end
, TCX_ON_BRIDGE
) + pylon_sprites
[PPPpos
];
1111 uint x
= ti
->x
+ x_ppp_offsets
[PPPpos
];
1112 uint y
= ti
->y
+ y_ppp_offsets
[PPPpos
];
1114 /* every other tile needs a pylon on the northern end */
1116 AddPylonSprite (ti
, pylon
, x
+ x_pcp_offsets
[PCPpos
],
1117 y
+ y_pcp_offsets
[PCPpos
], height
);
1120 /* need a pylon on the southern end of the bridge */
1122 PCPpos
= ReverseDiagDir(PCPpos
);
1123 AddPylonSprite (ti
, pylon
, x
+ x_pcp_offsets
[PCPpos
],
1124 y
+ y_pcp_offsets
[PCPpos
], height
);
1128 bool SettingsDisableElrail(int32 p1
)
1132 bool disable
= (p1
!= 0);
1134 /* we will now walk through all electric train engines and change their railtypes if it is the wrong one*/
1135 const RailType old_railtype
= disable
? RAILTYPE_ELECTRIC
: RAILTYPE_RAIL
;
1136 const RailType new_railtype
= disable
? RAILTYPE_RAIL
: RAILTYPE_ELECTRIC
;
1138 /* walk through all train engines */
1140 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_TRAIN
) {
1141 RailVehicleInfo
*rv_info
= &e
->u
.rail
;
1142 /* if it is an electric rail engine and its railtype is the wrong one */
1143 if (rv_info
->engclass
== 2 && rv_info
->railtype
== old_railtype
) {
1144 /* change it to the proper one */
1145 rv_info
->railtype
= new_railtype
;
1149 /* when disabling elrails, make sure that all existing trains can run on
1150 * normal rail too */
1153 if (t
->railtype
== RAILTYPE_ELECTRIC
) {
1154 /* this railroad vehicle is now compatible only with elrail,
1155 * so add there also normal rail compatibility */
1156 t
->compatible_railtypes
|= RAILTYPES_RAIL
;
1157 t
->railtype
= RAILTYPE_RAIL
;
1158 SetBit(t
->flags
, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL
);
1163 /* Fix the total power and acceleration for trains */
1165 /* power and acceleration is cached only for front engines */
1166 if (t
->IsFrontEngine()) {
1167 t
->ConsistChanged(CCF_TRACK
);
1171 FOR_ALL_COMPANIES(c
) c
->avail_railtypes
= GetCompanyRailtypes(c
->index
);
1173 /* This resets the _last_built_railtype, which will be invalid for electric
1174 * rails. It may have unintended consequences if that function is ever
1175 * extended, though. */
1176 ReinitGuiAfterToggleElrail(disable
);