Rework ChoosePylonPosition to simplify the loop
[openttd/fttd.git] / src / elrail.cpp
blob8c6d7af142a9c6061840395bb4b8d3a9b99b8477
1 /* $Id$ */
3 /*
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/>.
8 */
10 /**
11 * @file elrail.cpp
12 * This file deals with displaying wires and pylons for electric railways.
13 * <h2>Basics</h2>
15 * <h3>Tile Types</h3>
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
20 * stations, etc).
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
39 * other tile.
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
57 #include "stdafx.h"
59 #include <utility>
61 #include "map/rail.h"
62 #include "map/road.h"
63 #include "map/slope.h"
64 #include "map/bridge.h"
65 #include "map/tunnelbridge.h"
66 #include "viewport_func.h"
67 #include "train.h"
68 #include "rail_gui.h"
69 #include "bridge.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, };
96 /**
97 * Offset for wire sprites from the base wire sprite.
99 enum WireSpriteOffset {
100 WSO_X_SHORT,
101 WSO_Y_SHORT,
102 WSO_EW_SHORT,
103 WSO_NS_SHORT,
104 WSO_X_SHORT_DOWN,
105 WSO_Y_SHORT_UP,
106 WSO_X_SHORT_UP,
107 WSO_Y_SHORT_DOWN,
109 WSO_X_SW,
110 WSO_Y_SE,
111 WSO_EW_E,
112 WSO_NS_S,
113 WSO_X_SW_DOWN,
114 WSO_Y_SE_UP,
115 WSO_X_SW_UP,
116 WSO_Y_SE_DOWN,
118 WSO_X_NE,
119 WSO_Y_NW,
120 WSO_EW_W,
121 WSO_NS_N,
122 WSO_X_NE_DOWN,
123 WSO_Y_NW_UP,
124 WSO_X_NE_UP,
125 WSO_Y_NW_DOWN,
127 WSO_ENTRANCE_NE,
128 WSO_ENTRANCE_SE,
129 WSO_ENTRANCE_SW,
130 WSO_ENTRANCE_NW,
133 struct SortableSpriteStructM {
134 int8 x_offset;
135 int8 y_offset;
136 int8 x_size;
137 int8 y_size;
138 int8 z_offset;
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);
205 return result;
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);
223 bool add;
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)) {
228 add = true;
229 } else {
230 const StationSpec *statspec = GetStationSpec (next_tile);
231 add = (statspec != NULL) && HasBit(statspec->wires, GetStationGfx (next_tile));
233 if (add) {
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. */
241 TrackBits mask;
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);
249 } else {
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];
293 int8 x_offset;
294 int8 y_offset;
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] = {
329 { // NE
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 },
333 }, { // SE
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 },
337 }, { // SW
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 },
341 }, { // NW
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)
370 uint pcp_in_use = 0;
371 byte pmask = 0xFF;
372 byte amask = 0xFF;
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)) {
379 /* track found */
380 pcp_in_use++;
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);
394 *preferred &= pmask;
395 *allowed &= amask;
396 return pcp_in_use;
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);
411 bool ignore;
412 switch (preferred) {
413 case 1 << DIR_NW | 1 << DIR_SE:
414 if (!level) return false;
415 ignore = false; // must be X axis
416 break;
418 case 1 << DIR_NE | 1 << DIR_SW:
419 if (!level) return false;
420 ignore = true; // must be Y axis
421 break;
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];
426 break;
428 case 1 << DIR_N | 1 << DIR_S:
429 /* Non-orthogonal tracks must always be level. */
430 ignore = !odd[OtherAxis(axis)];
431 break;
433 default:
434 return false;
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. */
443 enum {
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) {
466 return PCP_NB_NONE;
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;
477 case 1: break;
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);
486 Slope nb_slope;
487 if (nb_tracks > 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);
495 } else {
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)) ?
500 SLOPE_FLAT :
501 InclinedSlope (ReverseDiagDir (side));
504 *slope = nb_slope;
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)
520 Axis axis;
521 switch (GetTileType (tile)) {
522 case TT_RAILWAY:
523 return CheckRailNeighbourPCP (tile, side,
524 preferred, allowed, slope);
526 case TT_MISC:
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);
533 break;
535 case TT_MISC_TUNNEL:
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;
542 break;
544 case TT_STATION: {
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);
555 break;
558 default:
559 return PCP_NB_NONE;
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;
567 /* Track found. */
568 *preferred &= side_tracks[side][0].preferred;
569 *slope = SLOPE_FLAT;
570 return PCP_NB_TRY_ELIDE;
573 /** Possible return values for CheckSidePCP below. */
574 enum {
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,
602 &PPPallowed) == 0) {
603 /* PCP not used at all from this tile. */
604 return std::make_pair (PCP_NONE, 0);
607 bool pcp_neighbour;
608 Slope nb_slope;
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);
616 FALLTHROUGH;
617 case PCP_NB_IN_USE:
618 pcp_neighbour = true;
619 break;
621 case PCP_NB_TUNNEL:
622 /* force tunnels to always have a pylon (no elision) */
623 return std::make_pair (PCP_IN_USE_BOTH, PPPallowed);
625 case PCP_NB_NONE:
626 pcp_neighbour = false;
627 break;
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++) {
674 byte pos = order[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;
683 NOT_REACHED();
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] = {
700 { // X even
701 { // Y even
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
706 }, { // Y odd
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
712 }, { // X odd
713 { // Y even
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
718 }, { // Y odd
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,
739 int x, int y, int z)
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,
754 SpriteID pylon_base)
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
775 * bridge-ramps.
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)
820 bool odd[AXIS_END];
821 odd[AXIS_X] = IsOddX(ti->tile);
822 odd[AXIS_Y] = IsOddY(ti->tile);
824 byte pcp_status = 0;
826 SpriteID pylon_base = draw_pylons ? GetPylonBase (rti, ti->tile, context) : 0;
828 for (DiagDirection side = DIAGDIR_BEGIN; side < DIAGDIR_END; side++) {
829 bool pcp_neighbour;
830 byte ppp_allowed;
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);
838 } else {
839 /* Bridge tile. */
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) {
855 continue;
860 int pos = ChoosePylonPosition (side, ppp_allowed,
861 odd[AXIS_X], odd[AXIS_Y], pcp_neighbour);
862 if (pos >= 0) {
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);
880 Track t;
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;
899 switch (slope) {
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));
949 slope = SLOPE_FLAT;
950 } else {
951 RailType rt1 = GetRailType (ti->tile, TRACK_UPPER);
952 RailType rt2 = GetRailType (ti->tile, TRACK_LOWER);
953 rti = GetRailTypeInfo (rt1);
954 if (rt1 == rt2) {
955 halftile_track = INVALID_TRACK;
956 } else {
957 const RailtypeInfo *rti2 = GetRailTypeInfo (rt2);
958 switch (tracks) {
959 case TRACK_BIT_HORZ:
960 halftile_rti = rti2;
961 halftile_track = TRACK_LOWER;
962 break;
963 case TRACK_BIT_VERT:
964 halftile_rti = rti2;
965 halftile_track = TRACK_RIGHT;
966 break;
967 case TRACK_BIT_LOWER:
968 case TRACK_BIT_RIGHT:
969 rti = rti2;
970 /* fall through */
971 default: // TRACK_BIT_UPPER or TRACK_BIT_LEFT
972 halftile_track = INVALID_TRACK;
973 break;
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,
984 halftile_context);
986 if (rti == NULL) return;
987 tracks &= ~tracks;
988 wires = tracks;
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,
1004 DiagDirection dir)
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)
1039 /* Draw pylon. */
1040 TileIndex tile = ti->tile;
1041 DiagDirection rev = ReverseDiagDir (dir);
1043 byte dummy_preferred, dummy_allowed;
1044 Slope dummy_slope;
1045 bool pcp_neighbour = CheckNeighbourPCP (tile + TileOffsByDiagDir (rev),
1046 dir, &dummy_preferred, &dummy_allowed, &dummy_slope)
1047 != PCP_NB_NONE;
1049 int pos = ChoosePylonPosition (rev, AllowedPPPonPCP[rev],
1050 IsOddX(tile), IsOddY(tile), pcp_neighbour);
1052 const RailtypeInfo *rti = GetRailTypeInfo (GetRailType (tile));
1053 if (pos >= 0) {
1054 DrawPylon (ti, rev, (Direction)pos,
1055 GetPylonBase (rti, tile, TCX_NORMAL));
1058 /* Draw wire. */
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);
1082 uint config;
1083 if (odd && last) {
1084 /* Draw the "short" wire on the southern end of the bridge
1085 * only needed if the length of the bridge is odd */
1086 config = 3;
1087 } else {
1088 /* Draw "long" wires on all other tiles of the bridge (one pylon every two tiles) */
1089 config = 2 - odd;
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;
1101 Direction PPPpos;
1102 if (axis == AXIS_X) {
1103 PCPpos = DIAGDIR_NE;
1104 PPPpos = IsOddY(ti->tile) ? DIR_SE : DIR_NW;
1105 } else {
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 */
1115 if (odd) {
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 */
1121 if (last) {
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)
1130 Company *c;
1131 Train *t;
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 */
1139 Engine *e;
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 */
1151 if (disable) {
1152 FOR_ALL_TRAINS(t) {
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 */
1164 FOR_ALL_TRAINS(t) {
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);
1177 return true;