1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include "../../interface/Viewport.h"
11 #include "../../paint/Paint.h"
12 #include "../../paint/Supports.h"
13 #include "../../world/Map.h"
14 #include "../RideData.h"
15 #include "../Track.h"
16 #include "../TrackPaint.h"
17 #include "../VehiclePaint.h"
18 
19 enum
20 {
21     SPR_GHOST_TRAIN_TRACK_FLAT_SW_NE = 28821,
22     SPR_GHOST_TRAIN_TRACK_FLAT_NW_SE = 28822,
23     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_SW_NE = 28823,
24     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_NW_SE = 28824,
25     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_NE_SW = 28825,
26     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_SE_NW = 28826,
27     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_SW_NE = 28827,
28     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_NW_SE = 28828,
29     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_NE_SW = 28829,
30     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_SE_NW = 28830,
31     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_SW_NE = 28831,
32     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_NW_SE = 28832,
33     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_NE_SW = 28833,
34     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_SE_NW = 28834,
35     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_SW_NE = 28835,
36     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_NW_SE = 28836,
37     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_NE_SW = 28837,
38     SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_SE_NW = 28838,
39     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_SW_NE = 28839,
40     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_NW_SE = 28840,
41     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_NE_SW = 28841,
42     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_SE_NW = 28842,
43     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_SW_NE = 28843,
44     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_NW_SE = 28844,
45     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_NE_SW = 28845,
46     SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_SE_NW = 28846,
47     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_SW_NW = 28847,
48     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_NW_NE = 28848,
49     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_NE_SE = 28849,
50     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_SE_SW = 28850,
51     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_0 = 28851,
52     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_1 = 28852,
53     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_2 = 28853,
54     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_0 = 28854,
55     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_1 = 28855,
56     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_2 = 28856,
57     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_0 = 28857,
58     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_1 = 28858,
59     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_2 = 28859,
60     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_0 = 28860,
61     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_1 = 28861,
62     SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_2 = 28862,
63     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_SW_NE = 28863,
64     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_NW_SE = 28864,
65 
66     SPR_GHOST_TRAIN_TRACK_BRAKES_SW_NE = 28881,
67     SPR_GHOST_TRAIN_TRACK_BRAKES_NW_SE = 28882
68 };
69 
70 static constexpr const uint32_t ghost_train_track_pieces_flat[4] = {
71     SPR_GHOST_TRAIN_TRACK_FLAT_SW_NE,
72     SPR_GHOST_TRAIN_TRACK_FLAT_NW_SE,
73     SPR_GHOST_TRAIN_TRACK_FLAT_SW_NE,
74     SPR_GHOST_TRAIN_TRACK_FLAT_NW_SE,
75 };
76 
77 static constexpr const uint32_t ghost_train_track_pieces_flat_to_25_deg_up[4][2] = {
78     { SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_SW_NE, SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_SW_NE },
79     { SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_NW_SE, SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_NW_SE },
80     { SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_NE_SW, SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_NE_SW },
81     { SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_SE_NW, SPR_GHOST_TRAIN_TRACK_FLAT_TO_25_DEG_UP_FRONT_SE_NW },
82 };
83 
84 static constexpr const uint32_t ghost_train_track_pieces_25_deg_up_to_flat[4][2] = {
85     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_SW_NE, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_SW_NE },
86     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_NW_SE, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_NW_SE },
87     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_NE_SW, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_NE_SW },
88     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_SE_NW, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_TO_FLAT_FRONT_SE_NW },
89 };
90 
91 static constexpr const uint32_t ghost_train_track_pieces_25_deg_up[4][2] = {
92     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_SW_NE, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_SW_NE },
93     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_NW_SE, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_NW_SE },
94     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_NE_SW, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_NE_SW },
95     { SPR_GHOST_TRAIN_TRACK_25_DEG_UP_SE_NW, SPR_GHOST_TRAIN_TRACK_25_DEG_UP_FRONT_SE_NW },
96 };
97 
98 static constexpr const uint32_t ghost_train_track_pieces_quarter_turn_1_tile[4] = {
99     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_SW_NW,
100     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_NW_NE,
101     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_NE_SE,
102     SPR_GHOST_TRAIN_QUARTER_TURN_1_TILE_SE_SW,
103 };
104 
105 static constexpr const uint32_t ghost_train_track_pieces_quarter_turn_3_tiles[4][3] = {
106     {
107         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_0,
108         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_1,
109         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SW_SE_PART_2,
110     },
111     {
112         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_0,
113         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_1,
114         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NW_SW_PART_2,
115     },
116     {
117         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_0,
118         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_1,
119         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_NE_NW_PART_2,
120     },
121     {
122         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_0,
123         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_1,
124         SPR_GHOST_TRAIN_QUARTER_TURN_3_TILES_SE_NE_PART_2,
125     },
126 };
127 
128 static constexpr const uint32_t ghost_train_track_pieces_spinning_tunnel_track[4] = {
129     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_SW_NE,
130     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_NW_SE,
131     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_SW_NE,
132     SPR_GHOST_TRAIN_SPINNING_TUNNEL_TRACK_NW_SE,
133 };
134 
135 static constexpr const uint32_t ghost_train_track_pieces_brakes[4] = {
136     SPR_GHOST_TRAIN_TRACK_BRAKES_SW_NE,
137     SPR_GHOST_TRAIN_TRACK_BRAKES_NW_SE,
138     SPR_GHOST_TRAIN_TRACK_BRAKES_SW_NE,
139     SPR_GHOST_TRAIN_TRACK_BRAKES_NW_SE,
140 };
141 
142 static constexpr const uint8_t doorOpeningOutwardsToImage[] = {
143     TUNNEL_DOORS_2, // Closed
144     TUNNEL_DOORS_2, // Unused?
145     TUNNEL_DOORS_3, // Half open
146     TUNNEL_DOORS_4, // Fully open
147     TUNNEL_DOORS_2, // Unused?
148     TUNNEL_DOORS_2, // Unused?
149     TUNNEL_DOORS_2, // Unused?
150 };
151 
152 static constexpr const uint8_t doorOpeningInwardsToImage[] = {
153     TUNNEL_DOORS_2, // Closed
154     TUNNEL_DOORS_2, // Unused?
155     TUNNEL_DOORS_5, // Half open
156     TUNNEL_DOORS_6, // Fully open
157     TUNNEL_DOORS_2, // Unused?
158     TUNNEL_DOORS_2, // Unused?
159     TUNNEL_DOORS_2, // Unused?
160 };
161 
get_tunnel_doors_image_straight_flat(const TrackElement & trackElement,uint8_t direction)162 static uint8_t get_tunnel_doors_image_straight_flat(const TrackElement& trackElement, uint8_t direction)
163 {
164     switch (direction)
165     {
166         case 0:
167             return doorOpeningInwardsToImage[trackElement.GetDoorAState()];
168         case 1:
169             return doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
170         case 2:
171             return doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
172         case 3:
173             return doorOpeningInwardsToImage[trackElement.GetDoorAState()];
174     }
175     return TUNNEL_DOORS_2;
176 }
177 
178 /** rct2: 0x00770BEC */
paint_ghost_train_track_flat(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)179 static void paint_ghost_train_track_flat(
180     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
181     const TrackElement& trackElement)
182 {
183     uint32_t imageId = ghost_train_track_pieces_flat[direction] | session->TrackColours[SCHEME_TRACK];
184 
185     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 6, height);
186 
187     auto tunnelImage = get_tunnel_doors_image_straight_flat(trackElement, direction);
188     paint_util_push_tunnel_rotated(session, direction, height, tunnelImage);
189 
190     if (track_paint_util_should_paint_supports(session->MapPosition))
191     {
192         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
193     }
194 
195     paint_util_set_segment_support_height(
196         session, paint_util_rotate_segments(SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC, direction), 0xFFFF, 0);
197     paint_util_set_general_support_height(session, height + 32, 0x20);
198 }
199 
200 /** rct2: 0x00770BFC */
paint_ghost_train_track_25_deg_up(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)201 static void paint_ghost_train_track_25_deg_up(
202     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
203     const TrackElement& trackElement)
204 {
205     uint32_t imageId = ghost_train_track_pieces_25_deg_up[direction][0] | session->TrackColours[SCHEME_TRACK];
206     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 6, height);
207 
208     imageId = ghost_train_track_pieces_25_deg_up[direction][1] | session->TrackColours[SCHEME_TRACK];
209     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 1, 23, height, 0, 27, height);
210 
211     if (track_paint_util_should_paint_supports(session->MapPosition))
212     {
213         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 8, height, session->TrackColours[SCHEME_SUPPORTS]);
214     }
215 
216     switch (direction)
217     {
218         case 0:
219             paint_util_push_tunnel_left(session, height - 8, TUNNEL_1);
220             break;
221         case 1:
222             paint_util_push_tunnel_right(session, height + 8, TUNNEL_2);
223             break;
224         case 2:
225             paint_util_push_tunnel_left(session, height + 8, TUNNEL_2);
226             break;
227         case 3:
228             paint_util_push_tunnel_right(session, height - 8, TUNNEL_1);
229             break;
230     }
231 
232     paint_util_set_segment_support_height(
233         session, paint_util_rotate_segments(SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC, direction), 0xFFFF, 0);
234     paint_util_set_general_support_height(session, height + 56, 0x20);
235 }
236 
237 /** rct2: 0x00770C0C */
paint_ghost_train_track_flat_to_25_deg_up(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)238 static void paint_ghost_train_track_flat_to_25_deg_up(
239     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
240     const TrackElement& trackElement)
241 {
242     bool isBackwards = trackElement.GetTrackType() == TrackElemType::Down25ToFlat;
243     uint8_t doorImage;
244     if (!isBackwards)
245     {
246         doorImage = doorOpeningInwardsToImage[trackElement.GetDoorAState()];
247     }
248     else
249     {
250         doorImage = doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
251     }
252 
253     uint32_t imageId = ghost_train_track_pieces_flat_to_25_deg_up[direction][0] | session->TrackColours[SCHEME_TRACK];
254     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 6, height);
255 
256     imageId = ghost_train_track_pieces_flat_to_25_deg_up[direction][1] | session->TrackColours[SCHEME_TRACK];
257     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 1, 15, height, 0, 27, height);
258 
259     if (track_paint_util_should_paint_supports(session->MapPosition))
260     {
261         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 3, height, session->TrackColours[SCHEME_SUPPORTS]);
262     }
263 
264     switch (direction)
265     {
266         case 0:
267             paint_util_push_tunnel_left(session, height, doorImage);
268             break;
269         case 1:
270             paint_util_push_tunnel_right(session, height, TUNNEL_2);
271             break;
272         case 2:
273             paint_util_push_tunnel_left(session, height, TUNNEL_2);
274             break;
275         case 3:
276             paint_util_push_tunnel_right(session, height, doorImage);
277             break;
278     }
279 
280     paint_util_set_segment_support_height(
281         session, paint_util_rotate_segments(SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC, direction), 0xFFFF, 0);
282     paint_util_set_general_support_height(session, height + 48, 0x20);
283 }
284 
paint_ghost_train_track_25_deg_up_to_flat_shared(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)285 static void paint_ghost_train_track_25_deg_up_to_flat_shared(
286     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
287     const TrackElement& trackElement)
288 {
289     uint32_t imageId = ghost_train_track_pieces_25_deg_up_to_flat[direction][0] | session->TrackColours[SCHEME_TRACK];
290     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 6, height);
291 
292     imageId = ghost_train_track_pieces_25_deg_up_to_flat[direction][1] | session->TrackColours[SCHEME_TRACK];
293     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 1, 15, height, 0, 27, height);
294 
295     if (track_paint_util_should_paint_supports(session->MapPosition))
296     {
297         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 6, height, session->TrackColours[SCHEME_SUPPORTS]);
298     }
299 
300     paint_util_set_segment_support_height(
301         session, paint_util_rotate_segments(SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC, direction), 0xFFFF, 0);
302     paint_util_set_general_support_height(session, height + 40, 0x20);
303 }
304 
305 /** rct2: 0x00770C1C */
paint_ghost_train_track_25_deg_up_to_flat(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)306 static void paint_ghost_train_track_25_deg_up_to_flat(
307     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
308     const TrackElement& trackElement)
309 {
310     paint_ghost_train_track_25_deg_up_to_flat_shared(session, ride, trackSequence, direction, height, trackElement);
311 
312     switch (direction)
313     {
314         case 0:
315             paint_util_push_tunnel_left(session, height - 8, TUNNEL_0);
316             break;
317         case 1:
318             paint_util_push_tunnel_right(session, height + 8, doorOpeningOutwardsToImage[trackElement.GetDoorBState()]);
319             break;
320         case 2:
321             paint_util_push_tunnel_left(session, height + 8, doorOpeningOutwardsToImage[trackElement.GetDoorBState()]);
322             break;
323         case 3:
324             paint_util_push_tunnel_right(session, height - 8, TUNNEL_0);
325             break;
326     }
327 }
328 
329 /** rct2: 0x00770C2C */
paint_ghost_train_track_25_deg_down(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)330 static void paint_ghost_train_track_25_deg_down(
331     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
332     const TrackElement& trackElement)
333 {
334     paint_ghost_train_track_25_deg_up(session, ride, trackSequence, (direction + 2) % 4, height, trackElement);
335 }
336 
337 /** rct2: 0x00770C3C */
paint_ghost_train_track_flat_to_25_deg_down(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)338 static void paint_ghost_train_track_flat_to_25_deg_down(
339     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
340     const TrackElement& trackElement)
341 {
342     paint_ghost_train_track_25_deg_up_to_flat_shared(session, ride, trackSequence, (direction + 2) % 4, height, trackElement);
343 
344     switch ((direction + 2) % 4)
345     {
346         case 0:
347             paint_util_push_tunnel_left(session, height - 8, TUNNEL_0);
348             break;
349         case 1:
350             paint_util_push_tunnel_right(session, height + 8, doorOpeningInwardsToImage[trackElement.GetDoorAState()]);
351             break;
352         case 2:
353             paint_util_push_tunnel_left(session, height + 8, doorOpeningInwardsToImage[trackElement.GetDoorAState()]);
354             break;
355         case 3:
356             paint_util_push_tunnel_right(session, height - 8, TUNNEL_0);
357             break;
358     }
359 }
360 
361 /** rct2: 0x00770C4C */
paint_ghost_train_track_25_deg_down_to_flat(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)362 static void paint_ghost_train_track_25_deg_down_to_flat(
363     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
364     const TrackElement& trackElement)
365 {
366     paint_ghost_train_track_flat_to_25_deg_up(session, ride, trackSequence, (direction + 2) % 4, height, trackElement);
367 }
368 
369 /** rct2: 0x00770C5C, 0x00770C6C, 0x00770C7C */
paint_ghost_train_station(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)370 static void paint_ghost_train_station(
371     paint_session* session, const Ride* ride, [[maybe_unused]] uint8_t trackSequence, uint8_t direction, int32_t height,
372     const TrackElement& trackElement)
373 {
374     uint32_t imageId;
375 
376     static constexpr const std::array imageIds = {
377         SPR_STATION_BASE_B_SW_NE,
378         SPR_STATION_BASE_B_NW_SE,
379         SPR_STATION_BASE_B_SW_NE,
380         SPR_STATION_BASE_B_NW_SE,
381     };
382 
383     imageId = imageIds[direction] | session->TrackColours[SCHEME_MISC];
384     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 28, 3, height - 2, 0, 2, height);
385 
386     imageId = ghost_train_track_pieces_flat[direction] | session->TrackColours[SCHEME_TRACK];
387     PaintAddImageAsChildRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 0, height);
388 
389     paint_util_push_tunnel_rotated(session, direction, height, TUNNEL_SQUARE_FLAT);
390 
391     if (direction == 0 || direction == 2)
392     {
393         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 5, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
394         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 8, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
395     }
396     else
397     {
398         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 6, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
399         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 7, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
400     }
401 
402     track_paint_util_draw_station(session, ride, direction, height, trackElement);
403 
404     paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
405     paint_util_set_general_support_height(session, height + 32, 0x20);
406 }
407 
408 /** rct2: 0x00770C9C */
paint_ghost_train_track_right_quarter_turn_3_tiles(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)409 static void paint_ghost_train_track_right_quarter_turn_3_tiles(
410     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
411     const TrackElement& trackElement)
412 {
413     track_paint_util_right_quarter_turn_3_tiles_paint(
414         session, 3, height, direction, trackSequence, session->TrackColours[SCHEME_TRACK],
415         ghost_train_track_pieces_quarter_turn_3_tiles, nullptr, defaultRightQuarterTurn3TilesBoundLengths,
416         defaultRightQuarterTurn3TilesBoundOffsets);
417     bool isBackwards = trackElement.GetTrackType() == TrackElemType::LeftQuarterTurn3Tiles;
418     bool isDoorA = (!isBackwards && trackSequence == 0) || (isBackwards && trackSequence == 3);
419     auto tunnelType = isDoorA ? doorOpeningInwardsToImage[trackElement.GetDoorAState()]
420                               : doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
421     track_paint_util_right_quarter_turn_3_tiles_tunnel(session, height, direction, trackSequence, tunnelType);
422 
423     switch (trackSequence)
424     {
425         case 0:
426         case 3:
427             metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
428             break;
429     }
430 
431     int32_t blockedSegments = 0;
432     switch (trackSequence)
433     {
434         case 0:
435             blockedSegments = SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC | SEGMENT_BC;
436             break;
437         case 2:
438             blockedSegments = SEGMENT_D0 | SEGMENT_C4 | SEGMENT_D4 | SEGMENT_C0;
439             break;
440         case 3:
441             blockedSegments = SEGMENT_D4 | SEGMENT_C4 | SEGMENT_C8 | SEGMENT_B8;
442             break;
443     }
444     paint_util_set_segment_support_height(session, paint_util_rotate_segments(blockedSegments, direction), 0xFFFF, 0);
445 
446     paint_util_set_general_support_height(session, height + 32, 0x20);
447 }
448 
449 /** rct2: 0x00770CAC */
paint_ghost_train_track_left_quarter_turn_3_tiles(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)450 static void paint_ghost_train_track_left_quarter_turn_3_tiles(
451     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
452     const TrackElement& trackElement)
453 {
454     trackSequence = mapLeftQuarterTurn3TilesToRightQuarterTurn3Tiles[trackSequence];
455     paint_ghost_train_track_right_quarter_turn_3_tiles(session, ride, trackSequence, (direction + 1) % 4, height, trackElement);
456 }
457 
458 /** rct2: 0x00770CAC */
paint_ghost_train_track_left_quarter_turn_1_tile(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)459 static void paint_ghost_train_track_left_quarter_turn_1_tile(
460     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
461     const TrackElement& trackElement)
462 {
463     bool isBackwards = trackElement.GetTrackType() == TrackElemType::RightQuarterTurn1Tile;
464     uint8_t tunnelStartImage, tunnelEndImage;
465     if (!isBackwards)
466     {
467         tunnelStartImage = doorOpeningInwardsToImage[trackElement.GetDoorAState()];
468         tunnelEndImage = doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
469     }
470     else
471     {
472         tunnelStartImage = doorOpeningOutwardsToImage[trackElement.GetDoorBState()];
473         tunnelEndImage = doorOpeningInwardsToImage[trackElement.GetDoorAState()];
474     }
475 
476     track_paint_util_left_quarter_turn_1_tile_paint(
477         session, 3, height, 0, direction, session->TrackColours[SCHEME_TRACK], ghost_train_track_pieces_quarter_turn_1_tile);
478     track_paint_util_left_quarter_turn_1_tile_tunnel(session, direction, height, 0, tunnelStartImage, 0, tunnelEndImage);
479 
480     metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
481     paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
482     paint_util_set_general_support_height(session, height + 32, 0x20);
483 }
484 
485 /** rct2: 0x00770CBC */
paint_ghost_train_track_right_quarter_turn_1_tile(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)486 static void paint_ghost_train_track_right_quarter_turn_1_tile(
487     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
488     const TrackElement& trackElement)
489 {
490     paint_ghost_train_track_left_quarter_turn_1_tile(session, ride, trackSequence, (direction + 3) % 4, height, trackElement);
491 }
492 
493 /** rct2: 0x00770CCC */
paint_ghost_train_track_spinning_tunnel(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)494 static void paint_ghost_train_track_spinning_tunnel(
495     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
496     const TrackElement& trackElement)
497 {
498     uint32_t imageId = ghost_train_track_pieces_spinning_tunnel_track[direction] | session->TrackColours[SCHEME_TRACK];
499 
500     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 28, 20, 3, height, 2, 6, height);
501 
502     track_paint_util_spinning_tunnel_paint(session, 3, height, direction);
503 
504     auto tunnelImage = get_tunnel_doors_image_straight_flat(trackElement, direction);
505     paint_util_push_tunnel_rotated(session, direction, height, tunnelImage);
506 
507     wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]);
508 
509     paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
510     paint_util_set_general_support_height(session, height + 32, 0x20);
511 }
512 
513 /** rct2: 0x00770CDC */
paint_ghost_train_track_brakes(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)514 static void paint_ghost_train_track_brakes(
515     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
516     const TrackElement& trackElement)
517 {
518     uint32_t imageId = ghost_train_track_pieces_brakes[direction] | session->TrackColours[SCHEME_TRACK];
519 
520     PaintAddImageAsParentRotated(session, direction, imageId, 0, 0, 32, 20, 3, height, 0, 6, height);
521 
522     auto tunnelImage = get_tunnel_doors_image_straight_flat(trackElement, direction);
523     paint_util_push_tunnel_rotated(session, direction, height, tunnelImage);
524 
525     if (track_paint_util_should_paint_supports(session->MapPosition))
526     {
527         metal_a_supports_paint_setup(session, METAL_SUPPORTS_BOXED, 4, 0, height, session->TrackColours[SCHEME_SUPPORTS]);
528     }
529 
530     paint_util_set_segment_support_height(
531         session, paint_util_rotate_segments(SEGMENT_D0 | SEGMENT_C4 | SEGMENT_CC, direction), 0xFFFF, 0);
532     paint_util_set_general_support_height(session, height + 32, 0x20);
533 }
534 
535 /**
536  * rct2: 0x00770924
537  */
get_track_paint_function_ghost_train(int32_t trackType)538 TRACK_PAINT_FUNCTION get_track_paint_function_ghost_train(int32_t trackType)
539 {
540     switch (trackType)
541     {
542         case TrackElemType::Flat:
543             return paint_ghost_train_track_flat;
544 
545         case TrackElemType::EndStation:
546         case TrackElemType::BeginStation:
547         case TrackElemType::MiddleStation:
548             return paint_ghost_train_station;
549 
550         case TrackElemType::Up25:
551             return paint_ghost_train_track_25_deg_up;
552         case TrackElemType::FlatToUp25:
553             return paint_ghost_train_track_flat_to_25_deg_up;
554         case TrackElemType::Up25ToFlat:
555             return paint_ghost_train_track_25_deg_up_to_flat;
556 
557         case TrackElemType::Down25:
558             return paint_ghost_train_track_25_deg_down;
559         case TrackElemType::FlatToDown25:
560             return paint_ghost_train_track_flat_to_25_deg_down;
561         case TrackElemType::Down25ToFlat:
562             return paint_ghost_train_track_25_deg_down_to_flat;
563 
564         case TrackElemType::LeftQuarterTurn3Tiles:
565             return paint_ghost_train_track_left_quarter_turn_3_tiles;
566         case TrackElemType::RightQuarterTurn3Tiles:
567             return paint_ghost_train_track_right_quarter_turn_3_tiles;
568 
569         case TrackElemType::LeftQuarterTurn1Tile:
570             return paint_ghost_train_track_left_quarter_turn_1_tile;
571         case TrackElemType::RightQuarterTurn1Tile:
572             return paint_ghost_train_track_right_quarter_turn_1_tile;
573 
574         case TrackElemType::Brakes:
575             return paint_ghost_train_track_brakes;
576 
577         case TrackElemType::SpinningTunnel:
578             return paint_ghost_train_track_spinning_tunnel;
579     }
580 
581     return nullptr;
582 }
583