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