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