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 "../../common.h"
11 #include "../../interface/Viewport.h"
12 #include "../../paint/Paint.h"
13 #include "../../paint/Supports.h"
14 #include "../Track.h"
15 #include "../TrackPaint.h"
16 #include "../Vehicle.h"
17 #include "../VehiclePaint.h"
18
19 #include <cstring>
20
21 enum
22 {
23 SPR_ROTO_DROP_TOWER_SEGMENT = 14558,
24 SPR_ROTO_DROP_TOWER_SEGMENT_TOP = 14559,
25 SPR_ROTO_DROP_TOWER_BASE = 14560,
26 SPR_ROTO_DROP_TOWER_BASE_SEGMENT = 14561,
27 SPR_ROTO_DROP_TOWER_BASE_90_DEG = 14562,
28 SPR_ROTO_DROP_TOWER_BASE_SEGMENT_90_DEG = 14563,
29 };
30
31 /**
32 *
33 * rct2: 0x006D5DA9
34 */
vehicle_visual_roto_drop(paint_session * session,int32_t x,int32_t imageDirection,int32_t y,int32_t z,const Vehicle * vehicle,const rct_ride_entry_vehicle * vehicleEntry)35 void vehicle_visual_roto_drop(
36 paint_session* session, int32_t x, int32_t imageDirection, int32_t y, int32_t z, const Vehicle* vehicle,
37 const rct_ride_entry_vehicle* vehicleEntry)
38 {
39 auto imageFlags = SPRITE_ID_PALETTE_COLOUR_2(vehicle->colours.body_colour, vehicle->colours.trim_colour);
40 if (vehicle->IsGhost())
41 {
42 imageFlags = CONSTRUCTION_MARKER;
43 }
44
45 int32_t image_id;
46 int32_t baseImage_id = (vehicleEntry->base_image_id + 4) + ((vehicle->animation_frame / 4) & 0x3);
47 if (vehicle->restraints_position >= 64)
48 {
49 baseImage_id += 7;
50 baseImage_id += (vehicle->restraints_position / 64);
51 }
52
53 // Draw back:
54 image_id = baseImage_id | imageFlags;
55 PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 2, 2, 41 }, { -11, -11, z + 1 });
56
57 // Draw front:
58 image_id = (baseImage_id + 4) | imageFlags;
59 PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 16, 16, 41 }, { -5, -5, z + 1 });
60
61 if (vehicle->num_peeps > 0 && !vehicle->IsGhost())
62 {
63 uint8_t riding_peep_sprites[64];
64 std::fill_n(riding_peep_sprites, sizeof(riding_peep_sprites), 0xFF);
65 for (int32_t i = 0; i < vehicle->num_peeps; i++)
66 {
67 uint8_t cl = (i & 3) * 16;
68 cl += (i & 0xFC);
69 cl += vehicle->animation_frame / 4;
70 cl += (imageDirection / 8) * 16;
71 cl &= 0x3F;
72 riding_peep_sprites[cl] = vehicle->peep_tshirt_colours[i];
73 }
74
75 // Draw riding peep sprites in back to front order:
76 for (int32_t j = 0; j <= 48; j++)
77 {
78 int32_t i = (j % 2) ? (48 - (j / 2)) : (j / 2);
79 if (riding_peep_sprites[i] != 0xFF)
80 {
81 baseImage_id = vehicleEntry->base_image_id + 20 + i;
82 if (vehicle->restraints_position >= 64)
83 {
84 baseImage_id += 64;
85 baseImage_id += vehicle->restraints_position / 64;
86 }
87 image_id = baseImage_id | SPRITE_ID_PALETTE_COLOUR_1(riding_peep_sprites[i]);
88 PaintAddImageAsChild(session, image_id, 0, 0, 16, 16, 41, z, -5, -5, z + 1);
89 }
90 }
91 }
92
93 assert(vehicleEntry->effect_visual == 1);
94 // Although called in original code, effect_visual (splash effects) are not used for many rides and does not make sense so
95 // it was taken out
96 }
97
98 /** rct2: 0x00886194 */
paint_roto_drop_base(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)99 static void paint_roto_drop_base(
100 paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
101 const TrackElement& trackElement)
102 {
103 trackSequence = track_map_3x3[direction][trackSequence];
104
105 int32_t edges = edges_3x3[trackSequence];
106
107 wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]);
108
109 StationObject* stationObject = nullptr;
110 if (ride != nullptr)
111 stationObject = ride_get_station_object(ride);
112
113 track_paint_util_paint_floor(
114 session, edges, session->TrackColours[SCHEME_SUPPORTS], height, floorSpritesMetalB, stationObject);
115
116 if (ride != nullptr)
117 {
118 track_paint_util_paint_fences(
119 session, edges, session->MapPosition, trackElement, ride, session->TrackColours[SCHEME_TRACK], height,
120 fenceSpritesMetalB, session->CurrentRotation);
121 }
122
123 if (trackSequence == 0)
124 {
125 uint32_t imageId = (direction & 1 ? SPR_ROTO_DROP_TOWER_BASE_90_DEG : SPR_ROTO_DROP_TOWER_BASE)
126 | session->TrackColours[SCHEME_TRACK];
127 PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 27 }, { 8, 8, height + 3 });
128
129 imageId = (direction & 1 ? SPR_ROTO_DROP_TOWER_BASE_SEGMENT_90_DEG : SPR_ROTO_DROP_TOWER_BASE_SEGMENT)
130 | session->TrackColours[SCHEME_TRACK];
131 PaintAddImageAsParent(session, imageId, { 0, 0, height + 32 }, { 2, 2, 30 }, { 8, 8, height + 32 });
132
133 imageId = (direction & 1 ? SPR_ROTO_DROP_TOWER_BASE_SEGMENT_90_DEG : SPR_ROTO_DROP_TOWER_BASE_SEGMENT)
134 | session->TrackColours[SCHEME_TRACK];
135 PaintAddImageAsParent(session, imageId, { 0, 0, height + 64 }, { 2, 2, 30 }, { 8, 8, height + 64 });
136
137 paint_util_set_vertical_tunnel(session, height + 96);
138 paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
139
140 #ifdef __TESTPAINT__
141 paint_util_set_general_support_height(session, height + 32, 0x20);
142 #else
143 paint_util_set_general_support_height(session, height + 96, 0x20);
144 #endif
145
146 return;
147 }
148
149 int32_t blockedSegments = 0;
150 switch (trackSequence)
151 {
152 case 1:
153 blockedSegments = SEGMENT_B8 | SEGMENT_C8 | SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC;
154 break;
155 case 2:
156 blockedSegments = SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC;
157 break;
158 case 3:
159 blockedSegments = SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC | SEGMENT_D4 | SEGMENT_C0;
160 break;
161 case 4:
162 blockedSegments = SEGMENT_B4 | SEGMENT_C8 | SEGMENT_B8;
163 break;
164 case 5:
165 blockedSegments = SEGMENT_BC | SEGMENT_D4 | SEGMENT_C0;
166 break;
167 case 6:
168 blockedSegments = SEGMENT_B4 | SEGMENT_C8 | SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0;
169 break;
170 case 7:
171 blockedSegments = SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0 | SEGMENT_D4 | SEGMENT_BC;
172 break;
173 case 8:
174 blockedSegments = SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0;
175 break;
176 }
177 paint_util_set_segment_support_height(session, blockedSegments, 0xFFFF, 0);
178 paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~blockedSegments, height + 2, 0x20);
179 paint_util_set_general_support_height(session, height + 32, 0x20);
180 }
181
182 /** rct2: 0x008861A4 */
paint_roto_drop_tower_section(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)183 static void paint_roto_drop_tower_section(
184 paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
185 const TrackElement& trackElement)
186 {
187 if (trackSequence == 1)
188 {
189 return;
190 }
191
192 uint32_t imageId = SPR_ROTO_DROP_TOWER_SEGMENT | session->TrackColours[SCHEME_TRACK];
193 PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 30 }, { 8, 8, height });
194
195 const TileElement* nextTileElement = reinterpret_cast<const TileElement*>(&trackElement) + 1;
196 if (trackElement.IsLastForTile() || trackElement.GetClearanceZ() != nextTileElement->GetBaseZ())
197 {
198 imageId = SPR_ROTO_DROP_TOWER_SEGMENT_TOP | session->TrackColours[SCHEME_TRACK];
199 PaintAddImageAsChild(session, imageId, 0, 0, 2, 2, 30, height, 8, 8, height);
200 }
201
202 paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
203
204 paint_util_set_vertical_tunnel(session, height + 32);
205 paint_util_set_general_support_height(session, height + 32, 0x20);
206 }
207
208 /**
209 * rct2: 0x00886074
210 */
get_track_paint_function_roto_drop(int32_t trackType)211 TRACK_PAINT_FUNCTION get_track_paint_function_roto_drop(int32_t trackType)
212 {
213 switch (trackType)
214 {
215 case TrackElemType::TowerBase:
216 return paint_roto_drop_base;
217
218 case TrackElemType::TowerSection:
219 return paint_roto_drop_tower_section;
220 }
221
222 return nullptr;
223 }
224