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 "../../world/Map.h"
15 #include "../Track.h"
16 #include "../TrackPaint.h"
17 #include "../Vehicle.h"
18 #include "../VehiclePaint.h"
19 
20 enum
21 {
22     SPR_OBSERVATION_TOWER_SEGMENT_BASE = 14986,
23     SPR_OBSERVATION_TOWER_SEGMENT = 14987,
24     SPR_OBSERVATION_TOWER_SEGMENT_TOP = 14988,
25 };
26 
27 /**
28  *
29  *  rct2: 0x006D6258
30  */
vehicle_visual_observation_tower(paint_session * session,int32_t x,int32_t imageDirection,int32_t y,int32_t z,const Vehicle * vehicle,const rct_ride_entry_vehicle * vehicleEntry)31 void vehicle_visual_observation_tower(
32     paint_session* session, int32_t x, int32_t imageDirection, int32_t y, int32_t z, const Vehicle* vehicle,
33     const rct_ride_entry_vehicle* vehicleEntry)
34 {
35     int32_t image_id;
36     int32_t baseImage_id = (vehicle->restraints_position / 64);
37     if (vehicle->restraints_position >= 64)
38     {
39         auto directionOffset = imageDirection / 8;
40         if ((directionOffset == 0) || (directionOffset == 3))
41         {
42             baseImage_id = vehicleEntry->base_image_id + 8;
43         }
44         else
45         {
46             baseImage_id *= 2;
47             baseImage_id += vehicleEntry->base_image_id;
48             if (directionOffset == 1)
49             {
50                 baseImage_id += 28;
51             }
52             else
53             {
54                 baseImage_id += 22;
55             }
56         }
57     }
58     else
59     {
60         baseImage_id = (vehicle->animation_frame * 2) + vehicleEntry->base_image_id + 8;
61     }
62 
63     image_id = baseImage_id | SPRITE_ID_PALETTE_COLOUR_3(vehicle->colours.body_colour, vehicle->colours.trim_colour);
64     if (vehicle->IsGhost())
65     {
66         image_id = (image_id & 0x7FFFF) | CONSTRUCTION_MARKER;
67     }
68     paint_struct* ps = PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 2, 2, 41 }, { -11, -11, z + 1 });
69     if (ps != nullptr)
70     {
71         ps->tertiary_colour = vehicle->colours_extended;
72     }
73 
74     image_id++;
75 
76     ps = PaintAddImageAsParent(session, image_id, { 0, 0, z }, { 16, 16, 41 }, { -5, -5, z + 1 });
77     if (ps != nullptr)
78     {
79         ps->tertiary_colour = vehicle->colours_extended;
80     }
81 
82     assert(vehicleEntry->effect_visual == 1);
83 }
84 
85 /** rct2: 0x0070DD6C */
paint_observation_tower_base(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)86 static void paint_observation_tower_base(
87     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
88     const TrackElement& trackElement)
89 {
90     trackSequence = track_map_3x3[direction][trackSequence];
91 
92     int32_t edges = edges_3x3[trackSequence];
93     CoordsXY position = session->MapPosition;
94 
95     wooden_a_supports_paint_setup(session, (direction & 1), 0, height, session->TrackColours[SCHEME_MISC]);
96 
97     StationObject* stationObject = nullptr;
98     if (ride != nullptr)
99         stationObject = ride_get_station_object(ride);
100 
101     track_paint_util_paint_floor(
102         session, edges, session->TrackColours[SCHEME_SUPPORTS], height, floorSpritesMetalB, stationObject);
103 
104     if (ride != nullptr)
105     {
106         track_paint_util_paint_fences(
107             session, edges, position, trackElement, ride, session->TrackColours[SCHEME_TRACK], height, fenceSpritesMetalB,
108             session->CurrentRotation);
109     }
110 
111     if (trackSequence == 0)
112     {
113         uint32_t imageId = SPR_OBSERVATION_TOWER_SEGMENT_BASE | session->TrackColours[SCHEME_TRACK];
114         PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 27 }, { 8, 8, height + 3 });
115 
116         imageId = SPR_OBSERVATION_TOWER_SEGMENT | session->TrackColours[SCHEME_TRACK];
117         PaintAddImageAsParent(session, imageId, { 0, 0, height + 32 }, { 2, 2, 30 }, { 8, 8, height + 32 });
118 
119         imageId = SPR_OBSERVATION_TOWER_SEGMENT | session->TrackColours[SCHEME_TRACK];
120         PaintAddImageAsParent(session, imageId, { 0, 0, height + 64 }, { 2, 2, 30 }, { 8, 8, height + 64 });
121 
122         paint_util_set_vertical_tunnel(session, height + 96);
123         paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
124 
125 #ifdef __TESTPAINT__
126         paint_util_set_general_support_height(session, height + 32, 0x20);
127 #else
128         paint_util_set_general_support_height(session, height + 96, 0x20);
129 #endif
130         return;
131     }
132 
133     int32_t blockedSegments = 0;
134     switch (trackSequence)
135     {
136         case 1:
137             blockedSegments = SEGMENT_B8 | SEGMENT_C8 | SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC;
138             break;
139         case 2:
140             blockedSegments = SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC;
141             break;
142         case 3:
143             blockedSegments = SEGMENT_B4 | SEGMENT_CC | SEGMENT_BC | SEGMENT_D4 | SEGMENT_C0;
144             break;
145         case 4:
146             blockedSegments = SEGMENT_B4 | SEGMENT_C8 | SEGMENT_B8;
147             break;
148         case 5:
149             blockedSegments = SEGMENT_BC | SEGMENT_D4 | SEGMENT_C0;
150             break;
151         case 6:
152             blockedSegments = SEGMENT_B4 | SEGMENT_C8 | SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0;
153             break;
154         case 7:
155             blockedSegments = SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0 | SEGMENT_D4 | SEGMENT_BC;
156             break;
157         case 8:
158             blockedSegments = SEGMENT_B8 | SEGMENT_D0 | SEGMENT_C0;
159             break;
160     }
161     paint_util_set_segment_support_height(session, blockedSegments, 0xFFFF, 0);
162     paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~blockedSegments, height + 2, 0x20);
163     paint_util_set_general_support_height(session, height + 32, 0x20);
164 }
165 
166 /** rct2: 0x0070DD7C */
paint_observation_tower_section(paint_session * session,const Ride * ride,uint8_t trackSequence,uint8_t direction,int32_t height,const TrackElement & trackElement)167 static void paint_observation_tower_section(
168     paint_session* session, const Ride* ride, uint8_t trackSequence, uint8_t direction, int32_t height,
169     const TrackElement& trackElement)
170 {
171     if (trackSequence == 1)
172     {
173         return;
174     }
175 
176     uint32_t imageId = SPR_OBSERVATION_TOWER_SEGMENT | session->TrackColours[SCHEME_TRACK];
177     PaintAddImageAsParent(session, imageId, { 0, 0, height }, { 2, 2, 30 }, { 8, 8, height });
178 
179     const TileElement* nextTileElement = reinterpret_cast<const TileElement*>(&trackElement) + 1;
180     if (trackElement.IsLastForTile() || trackElement.GetClearanceZ() != nextTileElement->GetBaseZ())
181     {
182         imageId = SPR_OBSERVATION_TOWER_SEGMENT_TOP | session->TrackColours[SCHEME_TRACK];
183         PaintAddImageAsChild(session, imageId, 0, 0, 2, 2, 30, height, 8, 8, height);
184     }
185 
186     paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
187 
188     paint_util_set_vertical_tunnel(session, height + 32);
189     paint_util_set_general_support_height(session, height + 32, 0x20);
190 }
191 
192 /**
193  * rct2: 0x0070DC5C
194  */
get_track_paint_function_observation_tower(int32_t trackType)195 TRACK_PAINT_FUNCTION get_track_paint_function_observation_tower(int32_t trackType)
196 {
197     switch (trackType)
198     {
199         case TrackElemType::TowerBase:
200             return paint_observation_tower_base;
201 
202         case TrackElemType::TowerSection:
203             return paint_observation_tower_section;
204     }
205 
206     return nullptr;
207 }
208