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 #pragma once
11 
12 #include "../common.h"
13 #include "../interface/Viewport.h"
14 #include "../object/Object.h"
15 
16 class FootpathObject;
17 class FootpathSurfaceObject;
18 class FootpathRailingsObject;
19 
20 enum
21 {
22     PROVISIONAL_PATH_FLAG_SHOW_ARROW = (1 << 0),
23     PROVISIONAL_PATH_FLAG_1 = (1 << 1),
24     PROVISIONAL_PATH_FLAG_2 = (1 << 2),
25 };
26 
27 constexpr auto FootpathMaxHeight = 248 * COORDS_Z_STEP;
28 constexpr auto FootpathMinHeight = 2 * COORDS_Z_STEP;
29 constexpr auto PATH_HEIGHT_STEP = 2 * COORDS_Z_STEP;
30 constexpr auto PATH_CLEARANCE = 4 * COORDS_Z_STEP;
31 
32 class FootpathObject;
33 
34 enum class RailingEntrySupportType : uint8_t
35 {
36     Box = 0,
37     Pole = 1,
38     Count
39 };
40 
41 enum
42 {
43     FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR = (1 << 2),
44     FOOTPATH_ENTRY_FLAG_IS_QUEUE = (1 << 3),
45     FOOTPATH_ENTRY_FLAG_NO_SLOPE_RAILINGS = (1 << 4),
46 };
47 
48 #pragma pack(push, 1)
49 struct rct_footpath_entry
50 {
51     rct_string_id string_idx;             // 0x00
52     uint32_t image;                       // 0x02
53     uint32_t bridge_image;                // 0x06
54     RailingEntrySupportType support_type; // 0x0A
55     uint8_t flags;                        // 0x0B
56     uint8_t scrolling_mode;               // 0x0C
57 
GetQueueImagerct_footpath_entry58     constexpr uint32_t GetQueueImage() const
59     {
60         return image + 51;
61     }
GetPreviewImagerct_footpath_entry62     constexpr uint32_t GetPreviewImage() const
63     {
64         return image + 71;
65     }
GetQueuePreviewImagerct_footpath_entry66     constexpr uint32_t GetQueuePreviewImage() const
67     {
68         // Editor-only paths usually lack queue images. In this case, use the main path image.
69         if (flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR)
70         {
71             return GetPreviewImage();
72         }
73 
74         return image + 72;
75     }
GetRailingsImagerct_footpath_entry76     constexpr uint32_t GetRailingsImage() const
77     {
78         return image + 73;
79     }
80 };
81 assert_struct_size(rct_footpath_entry, 13);
82 #pragma pack(pop)
83 
84 struct PathSurfaceDescriptor
85 {
86     rct_string_id Name;
87     uint32_t Image;
88     uint32_t PreviewImage;
89     uint8_t Flags;
90 
IsEditorOnlyPathSurfaceDescriptor91     inline constexpr bool IsEditorOnly() const
92     {
93         return Flags & FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR;
94     }
95 };
96 
97 struct PathRailingsDescriptor
98 {
99     rct_string_id Name;
100     uint32_t PreviewImage;
101     uint32_t BridgeImage;
102     uint32_t RailingsImage;
103     RailingEntrySupportType SupportType;
104     colour_t SupportColour;
105     uint8_t Flags;
106     uint8_t ScrollingMode;
107 };
108 
109 using PathConstructFlags = uint8_t;
110 namespace PathConstructFlag
111 {
112     constexpr PathConstructFlags IsQueue = 1 << 0;
113     constexpr PathConstructFlags IsLegacyPathObject = 1 << 1;
114 } // namespace PathConstructFlag
115 
116 struct FootpathSelection
117 {
118     ObjectEntryIndex LegacyPath = OBJECT_ENTRY_INDEX_NULL;
119     ObjectEntryIndex NormalSurface = OBJECT_ENTRY_INDEX_NULL;
120     ObjectEntryIndex QueueSurface = OBJECT_ENTRY_INDEX_NULL;
121     ObjectEntryIndex Railings = OBJECT_ENTRY_INDEX_NULL;
122     bool IsQueueSelected{};
123 
GetSelectedSurfaceFootpathSelection124     ObjectEntryIndex GetSelectedSurface() const
125     {
126         return IsQueueSelected ? QueueSurface : NormalSurface;
127     }
128 };
129 
130 struct ProvisionalFootpath
131 {
132     ObjectEntryIndex Type;
133     CoordsXYZ Position;
134     uint8_t Slope;
135     uint8_t Flags;
136     ObjectEntryIndex SurfaceIndex;
137     ObjectEntryIndex RailingsIndex;
138     PathConstructFlags ConstructFlags;
139 };
140 
141 // Masks for values stored in TileElement.type
142 enum
143 {
144     FOOTPATH_ELEMENT_TYPE_FLAG_IS_QUEUE = (1 << 0),
145     FOOTPATH_ELEMENT_TYPE_FLAG_IS_WIDE = (1 << 1),
146     FOOTPATH_ELEMENT_TYPE_DIRECTION_MASK = (1 << 6) | (1 << 7),
147 };
148 
149 // Masks and flags for values stored in TileElement.properties.path.type
150 enum
151 {
152     FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK = (1 << 0) | (1 << 1),
153     FOOTPATH_PROPERTIES_FLAG_IS_SLOPED = (1 << 2),
154     FOOTPATH_PROPERTIES_FLAG_HAS_QUEUE_BANNER = (1 << 3),
155     FOOTPATH_PROPERTIES_TYPE_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
156 };
157 
158 // Masks and flags for values stored in TileElement.properties.path.edges
159 enum
160 {
161     FOOTPATH_PROPERTIES_EDGES_EDGES_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
162     FOOTPATH_PROPERTIES_EDGES_CORNERS_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
163 };
164 
165 enum
166 {
167     FOOTPATH_ELEMENT_FLAGS2_IS_SLOPED = 1 << 0,
168     FOOTPATH_ELEMENT_FLAGS2_HAS_QUEUE_BANNER = (1 << 1),
169     FOOTPATH_ELEMENT_FLAGS2_ADDITION_IS_GHOST = (1 << 2),
170     FOOTPATH_ELEMENT_FLAGS2_BLOCKED_BY_VEHICLE = (1 << 3),
171     FOOTPATH_ELEMENT_FLAGS2_ADDITION_IS_BROKEN = (1 << 4),
172     FOOTPATH_ELEMENT_FLAGS2_LEGACY_PATH_ENTRY = (1 << 5),
173 };
174 
175 enum
176 {
177     RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE = (1 << 0),
178     RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS = (1 << 1), // When elevated
179 };
180 
181 enum
182 {
183     FOOTPATH_SEARCH_SUCCESS,
184     FOOTPATH_SEARCH_NOT_FOUND,
185     FOOTPATH_SEARCH_INCOMPLETE,
186     FOOTPATH_SEARCH_TOO_COMPLEX
187 };
188 
189 enum
190 {
191     SLOPE_IS_IRREGULAR_FLAG = (1 << 3), // Flag set in `DefaultPathSlope[]` and checked in `footpath_place_real`
192     RAISE_FOOTPATH_FLAG = (1 << 4)
193 };
194 
195 enum
196 {
197     FOOTPATH_CORNER_0 = (1 << 0),
198     FOOTPATH_CORNER_1 = (1 << 1),
199     FOOTPATH_CORNER_2 = (1 << 2),
200     FOOTPATH_CORNER_3 = (1 << 3),
201 };
202 
203 enum
204 {
205     FOOTPATH_CONNECTION_S = (1 << 0),
206     FOOTPATH_CONNECTION_NE = (1 << 1),
207     FOOTPATH_CONNECTION_W = (1 << 2),
208     FOOTPATH_CONNECTION_SE = (1 << 3),
209     FOOTPATH_CONNECTION_N = (1 << 4),
210     FOOTPATH_CONNECTION_SW = (1 << 5),
211     FOOTPATH_CONNECTION_E = (1 << 6),
212     FOOTPATH_CONNECTION_NW = (1 << 7),
213 };
214 
215 enum
216 {
217     FOOTPATH_CONNECTED_MAP_EDGE_IGNORE_QUEUES = (1 << 0),
218     FOOTPATH_CONNECTED_MAP_EDGE_UNOWN = (1 << 5),
219     FOOTPATH_CONNECTED_MAP_EDGE_IGNORE_NO_ENTRY = (1 << 7)
220 };
221 
222 extern FootpathSelection gFootpathSelection;
223 extern ProvisionalFootpath gProvisionalFootpath;
224 extern uint16_t gFootpathSelectedId;
225 extern CoordsXYZ gFootpathConstructFromPosition;
226 extern uint8_t gFootpathConstructSlope;
227 extern uint8_t gFootpathGroundFlags;
228 
229 // Given a direction, this will return how to increase/decrease the x and y coordinates.
230 extern const CoordsXY DirectionOffsets[NumOrthogonalDirections];
231 extern const CoordsXY BinUseOffsets[NumOrthogonalDirections];
232 extern const CoordsXY BenchUseOffsets[NumOrthogonalDirections * 2];
233 
234 TileElement* map_get_footpath_element(const CoordsXYZ& coords);
235 void footpath_interrupt_peeps(const CoordsXYZ& footpathPos);
236 money32 footpath_remove(const CoordsXYZ& footpathLoc, int32_t flags);
237 money32 footpath_provisional_set(
238     ObjectEntryIndex type, ObjectEntryIndex railingsType, const CoordsXYZ& footpathLoc, int32_t slope,
239     PathConstructFlags constructFlags);
240 void footpath_provisional_remove();
241 void footpath_provisional_update();
242 CoordsXY footpath_get_coordinates_from_pos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement);
243 CoordsXY footpath_bridge_get_info_from_pos(const ScreenCoordsXY& screenCoords, int32_t* direction, TileElement** tileElement);
244 void footpath_remove_litter(const CoordsXYZ& footpathPos);
245 void footpath_connect_edges(const CoordsXY& footpathPos, TileElement* tileElement, int32_t flags);
246 void footpath_update_queue_chains();
247 bool fence_in_the_way(const CoordsXYRangedZ& fencePos, int32_t direction);
248 void footpath_chain_ride_queue(
249     ride_id_t rideIndex, int32_t entranceIndex, const CoordsXY& footpathPos, TileElement* tileElement, int32_t direction);
250 void footpath_update_path_wide_flags(const CoordsXY& footpathPos);
251 bool footpath_is_blocked_by_vehicle(const TileCoordsXYZ& position);
252 
253 int32_t footpath_is_connected_to_map_edge(const CoordsXYZ& footpathPos, int32_t direction, int32_t flags);
254 void footpath_remove_edges_at(const CoordsXY& footpathPos, TileElement* tileElement);
255 
256 const FootpathObject* GetLegacyFootpathEntry(ObjectEntryIndex entryIndex);
257 const FootpathSurfaceObject* GetPathSurfaceEntry(ObjectEntryIndex entryIndex);
258 const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex);
259 
260 void footpath_queue_chain_reset();
261 void footpath_queue_chain_push(ride_id_t rideIndex);
262