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 // Structures shared between both RCT1 and RCT2.
13
14 #include "../common.h"
15 #include "../object/Object.h"
16 #include "../ride/RideTypes.h"
17
18 #include <string>
19 #include <string_view>
20 #include <vector>
21
22 class ObjectList;
23
24 using track_type_t = uint16_t;
25 using RCT12TrackType = uint8_t;
26
27 constexpr uint8_t RCT2_STRING_FORMAT_ARG_START = 123;
28 constexpr uint8_t RCT2_STRING_FORMAT_ARG_END = 141;
29 constexpr uint8_t RCT2_STRING_FORMAT_COLOUR_START = 142;
30 constexpr uint8_t RCT2_STRING_FORMAT_COLOUR_END = 156;
31
32 constexpr const uint8_t RCT12_MAX_RIDE_OBJECTS = 128;
33
34 constexpr const uint8_t RCT12_MAX_RIDES_IN_PARK = 255;
35 constexpr const uint8_t RCT12_MAX_AWARDS = 4;
36 constexpr const uint8_t RCT12_MAX_NEWS_ITEMS = 61;
37 constexpr const uint8_t RCT12_MAX_STATIONS_PER_RIDE = 4;
38 constexpr const uint8_t RCT12_MAX_PEEP_SPAWNS = 2;
39 constexpr const uint8_t RCT12_MAX_PARK_ENTRANCES = 4;
40 // The number of elements in the patrol_areas array per staff member. Every bit in the array represents a 4x4 square.
41 // In RCT1, that's an 8-bit array. 8 * 128 = 1024 bits, which is also the number of 4x4 squares on a 128x128 map.
42 // For RCT2, it's a 32-bit array. 32 * 128 = 4096 bits, which is also the number of 4x4 squares on a 256x256 map.
43 constexpr const uint8_t RCT12_PATROL_AREA_SIZE = 128;
44 constexpr const uint8_t RCT12_STAFF_TYPE_COUNT = 4;
45 constexpr const uint8_t RCT12_NUM_COLOUR_SCHEMES = 4;
46 constexpr const uint8_t RCT12_MAX_VEHICLE_COLOURS = 32;
47 constexpr const uint8_t RCT12_SOUND_ID_NULL = 0xFF;
48
49 constexpr const uint8_t RCT12_EXPENDITURE_TABLE_MONTH_COUNT = 16;
50 constexpr const uint8_t RCT12_EXPENDITURE_TYPE_COUNT = 14;
51 constexpr const uint8_t RCT12_FINANCE_GRAPH_SIZE = 128;
52
53 constexpr const uint16_t RCT12_MAX_USER_STRINGS = 1024;
54 constexpr const uint8_t RCT12_USER_STRING_MAX_LENGTH = 32;
55
56 constexpr const uint8_t RCT12_PEEP_MAX_THOUGHTS = 5;
57
58 using RCT12RideId = uint8_t;
59 constexpr const RCT12RideId RCT12_RIDE_ID_NULL = 255;
60 constexpr const uint16_t RCT12_RIDE_MEASUREMENT_MAX_ITEMS = 4800;
61
62 constexpr uint16_t const RCT12_MAX_INVERSIONS = 31;
63 constexpr uint16_t const RCT12_MAX_GOLF_HOLES = 31;
64 constexpr uint16_t const RCT12_MAX_HELICES = 31;
65
66 constexpr uint8_t RCT12_BANNER_INDEX_NULL = std::numeric_limits<uint8_t>::max();
67
68 constexpr const uint8_t RCT12_TILE_ELEMENT_SURFACE_EDGE_STYLE_MASK = 0xE0; // in RCT12TileElement.properties.surface.slope
69 constexpr const uint8_t RCT12_TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK = 0x1F; // in RCT12TileElement.properties.surface.terrain
70 constexpr const uint8_t RCT12_TILE_ELEMENT_SURFACE_TERRAIN_MASK = 0xE0; // in RCT12TileElement.properties.surface.terrain
71
72 constexpr const uint16_t RCT12_TILE_ELEMENT_LARGE_TYPE_MASK = 0x3FF;
73
74 constexpr uint16_t const RCT12_XY8_UNDEFINED = 0xFFFF;
75
76 using RCT12ObjectEntryIndex = uint8_t;
77 constexpr const RCT12ObjectEntryIndex RCT12_OBJECT_ENTRY_INDEX_NULL = 255;
78
79 // Everything before this point has been researched
80 constexpr const uint32_t RCT12_RESEARCHED_ITEMS_SEPARATOR = 0xFFFFFFFF;
81 // Everything before this point and after separator still requires research
82 constexpr const uint32_t RCT12_RESEARCHED_ITEMS_END = 0xFFFFFFFE;
83 // Extra end of list entry. Leftover from RCT1.
84 constexpr const uint32_t RCT12_RESEARCHED_ITEMS_END_2 = 0xFFFFFFFD;
85
86 constexpr const uint8_t RCT12_MAX_ELEMENT_HEIGHT = 255;
87
88 constexpr const uint16_t RCT12_PEEP_SPAWN_UNDEFINED = 0xFFFF;
89
90 constexpr const uint16_t RCT12VehicleTrackDirectionMask = 0b0000000000000011;
91 constexpr const uint16_t RCT12VehicleTrackTypeMask = 0b1111111111111100;
92
93 constexpr const uint8_t RCT12PeepThoughtItemNone = std::numeric_limits<uint8_t>::max();
94
95 constexpr const uint8_t RCT12GuestsInParkHistoryFactor = 20;
96 constexpr const uint8_t RCT12ParkHistoryUndefined = std::numeric_limits<uint8_t>::max();
97
98 enum class RCT12TrackDesignVersion : uint8_t
99 {
100 TD4,
101 TD4_AA,
102 TD6,
103 unknown
104 };
105
106 enum
107 {
108 RCT12_SURFACE_ELEMENT_TYPE_SURFACE_MASK = 0b00000011,
109 RCT12_SURFACE_ELEMENT_TYPE_EDGE_MASK = 0b01000000,
110 };
111
112 enum
113 {
114 RCT12_TILE_ELEMENT_FLAG_GHOST = (1 << 4),
115 RCT12_TILE_ELEMENT_FLAG_BROKEN = (1 << 5),
116 RCT12_TILE_ELEMENT_FLAG_BLOCK_BRAKE_CLOSED = (1 << 5),
117 RCT12_TILE_ELEMENT_FLAG_INDESTRUCTIBLE_TRACK_PIECE = (1 << 6),
118 RCT12_TILE_ELEMENT_FLAG_BLOCKED_BY_VEHICLE = (1 << 6),
119 RCT12_TILE_ELEMENT_FLAG_LARGE_SCENERY_ACCOUNTED = (1 << 6),
120 RCT12_TILE_ELEMENT_FLAG_LAST_TILE = (1 << 7)
121 };
122
123 enum
124 {
125 RCT12_TRACK_ELEMENT_TYPE_FLAG_CHAIN_LIFT = 1 << 7,
126 };
127
128 enum
129 {
130 RCT12_TRACK_ELEMENT_SEQUENCE_STATION_INDEX_MASK = 0b01110000,
131 RCT12_TRACK_ELEMENT_SEQUENCE_SEQUENCE_MASK = 0b00001111,
132 RCT12_TRACK_ELEMENT_SEQUENCE_TAKING_PHOTO_MASK = 0b11110000,
133 };
134
135 enum
136 {
137 // Not anything to do with colour but uses
138 // that field in the tile element
139
140 // Used for multi-dimension coaster
141 RCT12_TRACK_ELEMENT_COLOUR_FLAG_INVERTED = (1 << 2),
142
143 // Used for giga coaster
144 RCT12_TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT = (1 << 3),
145
146 RCT12_TRACK_ELEMENT_DOOR_A_MASK = 0b00011100,
147 RCT12_TRACK_ELEMENT_DOOR_B_MASK = 0b11100000,
148 };
149
150 // Masks and flags for values stored in TileElement.properties.path.type
151 enum
152 {
153 RCT12_FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK = (1 << 0) | (1 << 1),
154 RCT12_FOOTPATH_PROPERTIES_FLAG_IS_SLOPED = (1 << 2),
155 RCT12_FOOTPATH_PROPERTIES_FLAG_HAS_QUEUE_BANNER = (1 << 3),
156 RCT12_FOOTPATH_PROPERTIES_TYPE_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
157 };
158
159 // Masks and flags for values stored in RCT12TileElement.properties.path.additions
160 enum
161 {
162 RCT12_FOOTPATH_PROPERTIES_ADDITIONS_TYPE_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
163 // The most significant bit in this mask will always be zero, since rides can only have 4 stations
164 RCT12_FOOTPATH_PROPERTIES_ADDITIONS_STATION_INDEX_MASK = (1 << 4) | (1 << 5) | (1 << 6),
165 RCT12_FOOTPATH_PROPERTIES_ADDITIONS_FLAG_GHOST = (1 << 7),
166 };
167
168 enum
169 {
170 RCT12_STATION_STYLE_PLAIN,
171 RCT12_STATION_STYLE_WOODEN,
172 RCT12_STATION_STYLE_CANVAS_TENT,
173 RCT12_STATION_STYLE_CASTLE_GREY,
174 RCT12_STATION_STYLE_CASTLE_BROWN,
175 RCT12_STATION_STYLE_JUNGLE,
176 RCT12_STATION_STYLE_LOG_CABIN,
177 RCT12_STATION_STYLE_CLASSICAL,
178 RCT12_STATION_STYLE_ABSTRACT,
179 RCT12_STATION_STYLE_SNOW,
180 RCT12_STATION_STYLE_PAGODA,
181 RCT12_STATION_STYLE_SPACE,
182
183 RCT12_STATION_STYLE_INVISIBLE, // Added by OpenRCT2
184 };
185
186 enum
187 {
188 RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE = 1 << 7,
189 };
190
191 #pragma pack(push, 1)
192
193 struct RCT12xy8
194 {
195 union
196 {
197 struct
198 {
199 uint8_t x, y;
200 };
201 uint16_t xy;
202 };
203
IsNullRCT12xy8204 bool IsNull() const
205 {
206 return xy == RCT12_XY8_UNDEFINED;
207 }
208
SetNullRCT12xy8209 void SetNull()
210 {
211 xy = RCT12_XY8_UNDEFINED;
212 }
213 };
214 assert_struct_size(RCT12xy8, 2);
215
216 /* Maze Element entry size: 0x04 */
217 struct rct_td46_maze_element
218 {
219 union
220 {
221 uint32_t all;
222 struct
223 {
224 int8_t x;
225 int8_t y;
226 union
227 {
228 uint16_t maze_entry;
229 struct
230 {
231 uint8_t direction;
232 uint8_t type;
233 };
234 };
235 };
236 };
237 };
238 assert_struct_size(rct_td46_maze_element, 0x04);
239
240 /* Track Element entry size: 0x02 */
241 struct rct_td46_track_element
242 {
243 uint8_t type; // 0x00
244 uint8_t flags; // 0x01
245 };
246 assert_struct_size(rct_td46_track_element, 0x02);
247
248 struct rct12_award
249 {
250 uint16_t time;
251 uint16_t type;
252 };
253 assert_struct_size(rct12_award, 4);
254
255 /**
256 * A single news item / message.
257 * size: 0x10C
258 */
259 struct rct12_news_item
260 {
261 uint8_t Type;
262 uint8_t Flags;
263 uint32_t Assoc;
264 uint16_t Ticks;
265 uint16_t MonthYear;
266 uint8_t Day;
267 uint8_t pad_0B;
268 char Text[256];
269 };
270 assert_struct_size(rct12_news_item, 0x10C);
271
272 struct rct12_xyzd8
273 {
274 uint8_t x, y, z, direction;
275 };
276 assert_struct_size(rct12_xyzd8, 4);
277
278 struct rct12_peep_spawn
279 {
280 uint16_t x;
281 uint16_t y;
282 uint8_t z;
283 uint8_t direction;
284 };
285 assert_struct_size(rct12_peep_spawn, 6);
286
287 enum class RCT12TileElementType : uint8_t
288 {
289 Surface = (0 << 2),
290 Path = (1 << 2),
291 Track = (2 << 2),
292 SmallScenery = (3 << 2),
293 Entrance = (4 << 2),
294 Wall = (5 << 2),
295 LargeScenery = (6 << 2),
296 Banner = (7 << 2),
297 Corrupt = (8 << 2),
298 EightCarsCorrupt14 = (14 << 2),
299 EightCarsCorrupt15 = (15 << 2),
300 };
301 struct RCT12SurfaceElement;
302 struct RCT12PathElement;
303 struct RCT12TrackElement;
304 struct RCT12SmallSceneryElement;
305 struct RCT12LargeSceneryElement;
306 struct RCT12WallElement;
307 struct RCT12EntranceElement;
308 struct RCT12BannerElement;
309 struct RCT12CorruptElement;
310 struct RCT12EightCarsCorruptElement14;
311 struct RCT12EightCarsCorruptElement15;
312
313 struct RCT12TileElementBase
314 {
315 uint8_t type; // 0
316 uint8_t flags; // 1. Upper nibble: flags. Lower nibble: occupied quadrants (one bit per quadrant).
317 uint8_t base_height; // 2
318 uint8_t clearance_height; // 3
319 uint8_t GetType() const;
320 uint8_t GetDirection() const;
321 void SetDirection(uint8_t direction);
322
323 uint8_t GetOccupiedQuadrants() const;
324 void SetOccupiedQuadrants(uint8_t quadrants);
325
326 bool IsLastForTile() const;
327 void SetLastForTile(bool on);
328 bool IsGhost() const;
329 void SetGhost(bool isGhost);
330 };
331 /**
332 * Map element structure
333 * size: 0x08
334 */
335 struct RCT12TileElement : public RCT12TileElementBase
336 {
337 uint8_t pad_04[4];
asRCT12TileElement338 template<typename TType, RCT12TileElementType TClass> const TType* as() const
339 {
340 return static_cast<RCT12TileElementType>(GetType()) == TClass ? reinterpret_cast<const TType*>(this) : nullptr;
341 }
asRCT12TileElement342 template<typename TType, RCT12TileElementType TClass> TType* as()
343 {
344 return static_cast<RCT12TileElementType>(GetType()) == TClass ? reinterpret_cast<TType*>(this) : nullptr;
345 }
346
AsSurfaceRCT12TileElement347 const RCT12SurfaceElement* AsSurface() const
348 {
349 return as<RCT12SurfaceElement, RCT12TileElementType::Surface>();
350 }
AsSurfaceRCT12TileElement351 RCT12SurfaceElement* AsSurface()
352 {
353 return as<RCT12SurfaceElement, RCT12TileElementType::Surface>();
354 }
AsPathRCT12TileElement355 const RCT12PathElement* AsPath() const
356 {
357 return as<RCT12PathElement, RCT12TileElementType::Path>();
358 }
AsPathRCT12TileElement359 RCT12PathElement* AsPath()
360 {
361 return as<RCT12PathElement, RCT12TileElementType::Path>();
362 }
AsTrackRCT12TileElement363 const RCT12TrackElement* AsTrack() const
364 {
365 return as<RCT12TrackElement, RCT12TileElementType::Track>();
366 }
AsTrackRCT12TileElement367 RCT12TrackElement* AsTrack()
368 {
369 return as<RCT12TrackElement, RCT12TileElementType::Track>();
370 }
AsSmallSceneryRCT12TileElement371 const RCT12SmallSceneryElement* AsSmallScenery() const
372 {
373 return as<RCT12SmallSceneryElement, RCT12TileElementType::SmallScenery>();
374 }
AsSmallSceneryRCT12TileElement375 RCT12SmallSceneryElement* AsSmallScenery()
376 {
377 return as<RCT12SmallSceneryElement, RCT12TileElementType::SmallScenery>();
378 }
AsLargeSceneryRCT12TileElement379 const RCT12LargeSceneryElement* AsLargeScenery() const
380 {
381 return as<RCT12LargeSceneryElement, RCT12TileElementType::LargeScenery>();
382 }
AsLargeSceneryRCT12TileElement383 RCT12LargeSceneryElement* AsLargeScenery()
384 {
385 return as<RCT12LargeSceneryElement, RCT12TileElementType::LargeScenery>();
386 }
AsWallRCT12TileElement387 const RCT12WallElement* AsWall() const
388 {
389 return as<RCT12WallElement, RCT12TileElementType::Wall>();
390 }
AsWallRCT12TileElement391 RCT12WallElement* AsWall()
392 {
393 return as<RCT12WallElement, RCT12TileElementType::Wall>();
394 }
AsEntranceRCT12TileElement395 const RCT12EntranceElement* AsEntrance() const
396 {
397 return as<RCT12EntranceElement, RCT12TileElementType::Entrance>();
398 }
AsEntranceRCT12TileElement399 RCT12EntranceElement* AsEntrance()
400 {
401 return as<RCT12EntranceElement, RCT12TileElementType::Entrance>();
402 }
AsBannerRCT12TileElement403 const RCT12BannerElement* AsBanner() const
404 {
405 return as<RCT12BannerElement, RCT12TileElementType::Banner>();
406 }
AsBannerRCT12TileElement407 RCT12BannerElement* AsBanner()
408 {
409 return as<RCT12BannerElement, RCT12TileElementType::Banner>();
410 }
411 void ClearAs(uint8_t newType);
412 uint8_t GetBannerIndex();
413 };
414 assert_struct_size(RCT12TileElement, 8);
415 struct RCT12SurfaceElement : RCT12TileElementBase
416 {
417 private:
418 uint8_t slope; // 4 0xE0 Edge Style, 0x1F Slope
419 uint8_t terrain; // 5 0xE0 Terrain Style, 0x1F Water height
420 uint8_t grass_length; // 6
421 uint8_t ownership; // 7
422 public:
423 uint8_t GetSlope() const;
424 uint32_t GetSurfaceStyle() const;
425 uint32_t GetEdgeStyle() const;
426 uint8_t GetGrassLength() const;
427 uint8_t GetOwnership() const;
428 uint32_t GetWaterHeight() const;
429 uint8_t GetParkFences() const;
430 bool HasTrackThatNeedsWater() const;
431
432 void SetSlope(uint8_t newSlope);
433 void SetSurfaceStyle(uint32_t newStyle);
434 void SetEdgeStyle(uint32_t newStyle);
435 void SetGrassLength(uint8_t newLength);
436 void SetOwnership(uint8_t newOwnership);
437 void SetWaterHeight(uint32_t newWaterHeight);
438 void SetParkFences(uint8_t newParkFences);
439 void SetHasTrackThatNeedsWater(bool on);
440 };
441 assert_struct_size(RCT12SurfaceElement, 8);
442 struct RCT12PathElement : RCT12TileElementBase
443 {
444 private:
445 uint8_t entryIndex; // 4, 0xF0 Path type, 0x08 Ride sign, 0x04 Set when path is sloped, 0x03 Rotation
446 uint8_t additions; // 5, 0bGSSSAAAA: G = Ghost, S = station index, A = addition (0 means no addition)
447 uint8_t edges; // 6
448 union
449 {
450 uint8_t additionStatus; // 7
451 uint8_t rideIndex;
452 };
453
454 public:
455 RCT12ObjectEntryIndex GetEntryIndex() const;
456 uint8_t GetQueueBannerDirection() const;
457 bool IsSloped() const;
458 uint8_t GetSlopeDirection() const;
459 uint8_t GetRideIndex() const;
460 uint8_t GetStationIndex() const;
461 bool IsWide() const;
462 bool IsQueue() const;
463 bool HasQueueBanner() const;
464 uint8_t GetEdges() const;
465 uint8_t GetCorners() const;
466 uint8_t GetAddition() const;
467 bool AdditionIsGhost() const;
468 uint8_t GetAdditionStatus() const;
469 uint8_t GetRCT1PathType() const;
470 uint8_t GetRCT1SupportType() const;
471
472 void SetPathEntryIndex(RCT12ObjectEntryIndex newIndex);
473 void SetQueueBannerDirection(uint8_t direction);
474 void SetSloped(bool isSloped);
475 void SetSlopeDirection(uint8_t newSlope);
476 void SetRideIndex(uint8_t newRideIndex);
477 void SetStationIndex(uint8_t newStationIndex);
478 void SetWide(bool isWide);
479 void SetIsQueue(bool isQueue);
480 void SetHasQueueBanner(bool hasQueueBanner);
481 void SetEdges(uint8_t newEdges);
482 void SetCorners(uint8_t newCorners);
483 void SetAddition(uint8_t newAddition);
484 void SetAdditionIsGhost(bool isGhost);
485 void SetAdditionStatus(uint8_t newStatus);
486
487 bool IsBroken() const;
488 void SetIsBroken(bool isBroken);
489
490 bool IsBlockedByVehicle() const;
491 void SetIsBlockedByVehicle(bool isBlocked);
492 };
493 assert_struct_size(RCT12PathElement, 8);
494 struct RCT12TrackElement : RCT12TileElementBase
495 {
496 private:
497 uint8_t trackType; // 4
498 union
499 {
500 struct
501 {
502 // The lower 4 bits are the track sequence.
503 // The upper 4 bits are either station bits or on-ride photo bits.
504 //
505 // Station bits:
506 // - Bit 8 marks green light
507 // - Bit 5-7 are station index.
508 //
509 // On-ride photo bits:
510 // - Bits 7 and 8 are never set
511 // - Bits 5 and 6 are set when a vehicle triggers the on-ride photo and act like a countdown from 3.
512 // - If any of the bits 5-8 are set, the game counts it as a photo being taken.
513 uint8_t sequence; // 5.
514 uint8_t colour; // 6
515 };
516 uint16_t mazeEntry; // 5
517 };
518 uint8_t rideIndex; // 7
519 public:
520 uint8_t GetTrackType() const;
521 uint8_t GetSequenceIndex() const;
522 uint8_t GetRideIndex() const;
523 uint8_t GetColourScheme() const;
524 uint8_t GetStationIndex() const;
525 bool HasChain() const;
526 bool HasCableLift() const;
527 bool IsInverted() const;
528 uint8_t GetBrakeBoosterSpeed() const;
529 bool HasGreenLight() const;
530 uint8_t GetSeatRotation() const;
531 uint16_t GetMazeEntry() const;
532 uint8_t GetPhotoTimeout() const;
533 // RCT1 feature, reintroduced by OpenRCT2. See https://github.com/OpenRCT2/OpenRCT2/issues/7059
534 uint8_t GetDoorAState() const;
535 uint8_t GetDoorBState() const;
536 void SetDoorAState(uint8_t newState);
537 void SetDoorBState(uint8_t newState);
538
539 void SetTrackType(uint8_t newEntryIndex);
540 void SetSequenceIndex(uint8_t newSequenceIndex);
541 void SetRideIndex(uint8_t newRideIndex);
542 void SetColourScheme(uint8_t newColourScheme);
543 void SetStationIndex(uint8_t newStationIndex);
544 void SetHasChain(bool on);
545 void SetHasCableLift(bool on);
546 void SetInverted(bool inverted);
547 bool BlockBrakeClosed() const;
548 void SetBlockBrakeClosed(bool isClosed);
549 void SetBrakeBoosterSpeed(uint8_t speed);
550 void SetHasGreenLight(uint8_t greenLight);
551 void SetSeatRotation(uint8_t newSeatRotation);
552 void SetMazeEntry(uint16_t newMazeEntry);
553 void SetPhotoTimeout(uint8_t newValue);
554
555 bool IsIndestructible() const;
556 void SetIsIndestructible(bool isIndestructible);
557 };
558 assert_struct_size(RCT12TrackElement, 8);
559 struct RCT12SmallSceneryElement : RCT12TileElementBase
560 {
561 private:
562 uint8_t entryIndex; // 4
563 uint8_t age; // 5
564 uint8_t colour_1; // 6
565 uint8_t colour_2; // 7
566 public:
567 RCT12ObjectEntryIndex GetEntryIndex() const;
568 uint8_t GetAge() const;
569 uint8_t GetSceneryQuadrant() const;
570 colour_t GetPrimaryColour() const;
571 colour_t GetSecondaryColour() const;
572 bool NeedsSupports() const;
573
574 void SetEntryIndex(RCT12ObjectEntryIndex newIndex);
575 void SetAge(uint8_t newAge);
576 void SetSceneryQuadrant(uint8_t newQuadrant);
577 void SetPrimaryColour(colour_t colour);
578 void SetSecondaryColour(colour_t colour);
579 void SetNeedsSupports();
580 };
581 assert_struct_size(RCT12SmallSceneryElement, 8);
582 struct RCT12LargeSceneryElement : RCT12TileElementBase
583 {
584 private:
585 uint16_t entryIndex; // 4
586 uint8_t colour[2]; // 6
587 public:
588 uint32_t GetEntryIndex() const;
589 uint16_t GetSequenceIndex() const;
590 colour_t GetPrimaryColour() const;
591 colour_t GetSecondaryColour() const;
592 uint8_t GetBannerIndex() const;
593
594 void SetEntryIndex(uint32_t newIndex);
595 void SetSequenceIndex(uint16_t sequence);
596 void SetPrimaryColour(colour_t colour);
597 void SetSecondaryColour(colour_t colour);
598 void SetBannerIndex(uint8_t newIndex);
599 };
600 assert_struct_size(RCT12LargeSceneryElement, 8);
601 struct RCT12WallElement : RCT12TileElementBase
602 {
603 private:
604 uint8_t entryIndex; // 4
605 union
606 {
607 uint8_t colour_3; // 5
608 uint8_t banner_index; // 5
609 };
610 uint8_t colour_1; // 6 0b_2221_1111 2 = colour_2 (uses flags for rest of colour2), 1 = colour_1
611 uint8_t animation; // 7 0b_dfff_ft00 d = direction, f = frame num, t = across track flag (not used)
612 public:
613 RCT12ObjectEntryIndex GetEntryIndex() const;
614 uint8_t GetSlope() const;
615 colour_t GetPrimaryColour() const;
616 colour_t GetSecondaryColour() const;
617 colour_t GetTertiaryColour() const;
618 uint8_t GetAnimationFrame() const;
619 uint8_t GetBannerIndex() const;
620 bool IsAcrossTrack() const;
621 bool AnimationIsBackwards() const;
622 int32_t GetRCT1WallType(int32_t edge) const;
623 colour_t GetRCT1WallColour() const;
624 uint8_t GetRCT1Slope() const;
625
626 void SetEntryIndex(RCT12ObjectEntryIndex newIndex);
627 void SetSlope(uint8_t newslope);
628 void SetPrimaryColour(colour_t newColour);
629 void SetSecondaryColour(colour_t newColour);
630 void SetTertiaryColour(colour_t newColour);
631 void SetAnimationFrame(uint8_t frameNum);
632 void SetBannerIndex(uint8_t newIndex);
633 void SetAcrossTrack(bool acrossTrack);
634 void SetAnimationIsBackwards(bool isBackwards);
635 };
636 assert_struct_size(RCT12WallElement, 8);
637 struct RCT12EntranceElement : RCT12TileElementBase
638 {
639 private:
640 uint8_t entranceType; // 4
641 uint8_t index; // 5. 0bUSSS????, S = station index.
642 uint8_t pathType; // 6
643 uint8_t rideIndex; // 7
644 public:
645 uint8_t GetEntranceType() const;
646 uint8_t GetRideIndex() const;
647 uint8_t GetStationIndex() const;
648 uint8_t GetSequenceIndex() const;
649 uint8_t GetPathType() const;
650
651 void SetEntranceType(uint8_t newType);
652 void SetRideIndex(uint8_t newRideIndex);
653 void SetStationIndex(uint8_t stationIndex);
654 void SetSequenceIndex(uint8_t newSequenceIndex);
655 void SetPathType(uint8_t newPathType);
656 };
657 assert_struct_size(RCT12EntranceElement, 8);
658 struct RCT12BannerElement : RCT12TileElementBase
659 {
660 private:
661 uint8_t index; // 4
662 uint8_t position; // 5
663 uint8_t AllowedEdges; // 6
664 #pragma clang diagnostic push
665 #pragma clang diagnostic ignored "-Wunused-private-field"
666 uint8_t unused; // 7
667 #pragma clang diagnostic pop
668 public:
669 uint8_t GetIndex() const;
670 uint8_t GetPosition() const;
671 uint8_t GetAllowedEdges() const;
672
673 void SetIndex(uint8_t newIndex);
674 void SetPosition(uint8_t newPosition);
675 void SetAllowedEdges(uint8_t newEdges);
676 };
677 assert_struct_size(RCT12BannerElement, 8);
678
679 struct RCT12CorruptElement : RCT12TileElementBase
680 {
681 uint8_t pad[4];
682 };
683 assert_struct_size(RCT12CorruptElement, 8);
684
685 struct RCT12EightCarsCorruptElement14 : RCT12TileElementBase
686 {
687 uint8_t pad[4];
688 };
689 assert_struct_size(RCT12EightCarsCorruptElement14, 8);
690
691 struct RCT12EightCarsCorruptElement15 : RCT12TileElementBase
692 {
693 uint8_t pad[4];
694 };
695 assert_struct_size(RCT12EightCarsCorruptElement15, 8);
696
697 // Offset into sprite_lists_head and sprite_lists_count
698 enum class RCT12EntityLinkListOffset : uint8_t
699 {
700 Free = 0,
701 TrainHead = 1 * sizeof(uint16_t),
702 Peep = 2 * sizeof(uint16_t),
703 Misc = 3 * sizeof(uint16_t),
704 Litter = 4 * sizeof(uint16_t),
705 Vehicle = 5 * sizeof(uint16_t),
706 };
707
708 enum class RCT12SpriteIdentifier : uint8_t
709 {
710 Vehicle = 0,
711 Peep = 1,
712 Misc = 2,
713 Litter = 3,
714 Null = 255
715 };
716
717 enum class RCT12MiscEntityType : uint8_t
718 {
719 SteamParticle,
720 MoneyEffect,
721 CrashedVehicleParticle,
722 ExplosionCloud,
723 CrashSplash,
724 ExplosionFlare,
725 JumpingFountainWater,
726 Balloon,
727 Duck,
728 JumpingFountainSnow
729 };
730
731 enum class RCT12PeepType : uint8_t
732 {
733 Guest,
734 Staff,
735
736 Invalid = 0xFF
737 };
738
739 struct RCT12SpriteBase
740 {
741 RCT12SpriteIdentifier sprite_identifier; // 0x00
742 uint8_t type; // 0x01
743 uint16_t next_in_quadrant; // 0x02
744 uint16_t next; // 0x04
745 uint16_t previous; // 0x06
746 RCT12EntityLinkListOffset linked_list_type_offset; // 0x08
747 uint8_t sprite_height_negative; // 0x09
748 uint16_t sprite_index; // 0x0A
749 uint16_t flags; // 0x0C
750 int16_t x; // 0x0E
751 int16_t y; // 0x10
752 int16_t z; // 0x12
753 uint8_t sprite_width; // 0x14
754 uint8_t sprite_height_positive; // 0x15
755 int16_t sprite_left; // 0x16
756 int16_t sprite_top; // 0x18
757 int16_t sprite_right; // 0x1A
758 int16_t sprite_bottom; // 0x1C
759 uint8_t sprite_direction; // 0x1E
760 };
761 assert_struct_size(RCT12SpriteBase, 0x1F);
762
763 struct RCT12SpriteBalloon : RCT12SpriteBase
764 {
765 uint8_t pad_1F[0x24 - 0x1F];
766 uint16_t popped; // 0x24
767 uint8_t time_to_move; // 0x26
768 uint8_t frame; // 0x27
769 uint8_t pad_28[4];
770 uint8_t colour; // 0x2C
771 };
772 assert_struct_size(RCT12SpriteBalloon, 0x2D);
773
774 struct RCT12SpriteDuck : RCT12SpriteBase
775 {
776 uint8_t pad_1F[0x26 - 0x1F];
777 uint16_t frame; // 0x26
778 uint8_t pad_28[0x30 - 0x28];
779 int16_t target_x; // 0x30
780 int16_t target_y; // 0x32
781 uint8_t pad_34[0x14];
782 uint8_t state; // 0x48
783 };
784 assert_struct_size(RCT12SpriteDuck, 0x49);
785
786 struct RCT12SpriteLitter : RCT12SpriteBase
787 {
788 uint8_t pad_1F[0x24 - 0x1F];
789 uint32_t creationTick; // 0x24
790 };
791 assert_struct_size(RCT12SpriteLitter, 0x28);
792
793 struct RCT12SpriteParticle : RCT12SpriteBase
794 {
795 uint8_t pad_1F[0x26 - 0x1F];
796 uint16_t frame; // 0x26
797 };
798 assert_struct_size(RCT12SpriteParticle, 0x28);
799
800 struct RCT12SpriteJumpingFountain : RCT12SpriteBase
801 {
802 uint8_t pad_1F[0x26 - 0x1F];
803 uint8_t num_ticks_alive; // 0x26
804 uint8_t frame; // 0x27
805 uint8_t pad_28[0x2F - 0x28];
806 uint8_t fountain_flags; // 0x2F
807 int16_t target_x; // 0x30
808 int16_t target_y; // 0x32
809 uint8_t pad_34[0x46 - 0x34];
810 uint16_t iteration; // 0x46
811 };
812 assert_struct_size(RCT12SpriteJumpingFountain, 0x48);
813
814 struct RCT12SpriteMoneyEffect : RCT12SpriteBase
815 {
816 uint8_t pad_1F[0x24 - 0x1F];
817 uint16_t move_delay; // 0x24
818 uint8_t num_movements; // 0x26
819 uint8_t vertical;
820 money32 value; // 0x28
821 uint8_t pad_2C[0x44 - 0x2C];
822 int16_t offset_x; // 0x44
823 uint16_t wiggle; // 0x46
824 };
825 assert_struct_size(RCT12SpriteMoneyEffect, 0x48);
826
827 struct RCT12SpriteCrashedVehicleParticle : RCT12SpriteBase
828 {
829 uint8_t pad_1F[0x24 - 0x1F];
830 uint16_t time_to_live; // 0x24
831 uint16_t frame; // 0x26
832 uint8_t pad_28[0x2C - 0x28];
833 uint8_t colour[2]; // 0x2C
834 uint16_t crashed_sprite_base; // 0x2E
835 int16_t velocity_x; // 0x30
836 int16_t velocity_y; // 0x32
837 int16_t velocity_z; // 0x34
838 uint8_t pad_36[0x38 - 0x36];
839 int32_t acceleration_x; // 0x38
840 int32_t acceleration_y; // 0x3C
841 int32_t acceleration_z; // 0x40
842 };
843 assert_struct_size(RCT12SpriteCrashedVehicleParticle, 0x44);
844
845 struct RCT12SpriteCrashSplash : RCT12SpriteBase
846 {
847 uint8_t pad_1F[0x26 - 0x1F];
848 uint16_t frame; // 0x26
849 };
850 assert_struct_size(RCT12SpriteCrashSplash, 0x28);
851
852 struct RCT12SpriteSteamParticle : RCT12SpriteBase
853 {
854 uint8_t pad_1F[0x24 - 0x1F];
855 uint16_t time_to_move; // 0x24
856 uint16_t frame; // 0x26
857 };
858 assert_struct_size(RCT12SpriteSteamParticle, 0x28);
859
860 struct RCT12PeepThought
861 {
862 uint8_t type;
863 uint8_t item;
864 uint8_t freshness;
865 uint8_t fresh_timeout;
866 };
867 assert_struct_size(RCT12PeepThought, 4);
868
869 struct RCT12RideMeasurement
870 {
871 uint8_t ride_index; // 0x0000
872 uint8_t flags; // 0x0001
873 uint32_t last_use_tick; // 0x0002
874 uint16_t num_items; // 0x0006
875 uint16_t current_item; // 0x0008
876 uint8_t vehicle_index; // 0x000A
877 uint8_t current_station; // 0x000B
878 int8_t vertical[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C
879 int8_t lateral[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC
880 uint8_t velocity[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C
881 uint8_t altitude[RCT12_RIDE_MEASUREMENT_MAX_ITEMS]; // 0x384C
882 };
883 assert_struct_size(RCT12RideMeasurement, 0x4B0C);
884
885 struct RCT12Banner
886 {
887 RCT12ObjectEntryIndex type;
888 uint8_t flags; // 0x01
889 rct_string_id string_idx; // 0x02
890 union
891 {
892 uint8_t colour; // 0x04
893 uint8_t ride_index; // 0x04
894 };
895 uint8_t text_colour; // 0x05
896 uint8_t x; // 0x06
897 uint8_t y; // 0x07
898 };
899 assert_struct_size(RCT12Banner, 8);
900
901 struct RCT12MapAnimation
902 {
903 uint8_t baseZ;
904 uint8_t type;
905 uint16_t x;
906 uint16_t y;
907 };
908 assert_struct_size(RCT12MapAnimation, 6);
909
910 struct RCT12ResearchItem
911 {
912 // Bit 16 (0: scenery entry, 1: ride entry)
913 union
914 {
915 uint32_t rawValue;
916 struct
917 {
918 RCT12ObjectEntryIndex entryIndex;
919 uint8_t baseRideType;
920 uint8_t type; // 0: scenery entry, 1: ride entry
921 uint8_t flags;
922 };
923 };
924 uint8_t category;
925
926 bool IsInventedEndMarker() const;
927 bool IsRandomEndMarker() const;
928 bool IsUninventedEndMarker() const;
929 };
930 assert_struct_size(RCT12ResearchItem, 5);
931
932 #pragma pack(pop)
933
934 ObjectEntryIndex RCTEntryIndexToOpenRCT2EntryIndex(const RCT12ObjectEntryIndex index);
935 RCT12ObjectEntryIndex OpenRCT2EntryIndexToRCTEntryIndex(const ObjectEntryIndex index);
936 ride_id_t RCT12RideIdToOpenRCT2RideId(const RCT12RideId rideId);
937 RCT12RideId OpenRCT2RideIdToRCT12RideId(const ride_id_t rideId);
938 bool IsLikelyUTF8(std::string_view s);
939 std::string RCT12RemoveFormattingUTF8(std::string_view s);
940 std::string ConvertFormattedStringToOpenRCT2(std::string_view buffer);
941 std::string ConvertFormattedStringToRCT2(std::string_view buffer, size_t maxLength);
942 std::string GetTruncatedRCT2String(std::string_view src, size_t maxLength);
943 track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType);
944 RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType);
945 std::string_view GetStationIdentifierFromStyle(uint8_t style);
946 std::optional<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier);
947
948 static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001;
949
950 money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue);
951 money32 OpenRCT2CompletedCompanyValueToRCT12(money64 origValue);
952
RCT12GetRideTypesBeenOn(T * srcPeep)953 template<typename T> std::vector<uint16_t> RCT12GetRideTypesBeenOn(T* srcPeep)
954 {
955 std::vector<uint16_t> ridesTypesBeenOn;
956 for (uint16_t i = 0; i < RCT12_MAX_RIDE_OBJECTS; i++)
957 {
958 if (srcPeep->ride_types_been_on[i / 8] & (1 << (i % 8)))
959 {
960 ridesTypesBeenOn.push_back(i);
961 }
962 }
963 return ridesTypesBeenOn;
964 }
RCT12GetRidesBeenOn(T * srcPeep)965 template<typename T> std::vector<ride_id_t> RCT12GetRidesBeenOn(T* srcPeep)
966 {
967 std::vector<ride_id_t> ridesBeenOn;
968 for (uint16_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++)
969 {
970 if (srcPeep->rides_been_on[i / 8] & (1 << (i % 8)))
971 {
972 ridesBeenOn.push_back(static_cast<ride_id_t>(i));
973 }
974 }
975 return ridesBeenOn;
976 }
977