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 "T6Exporter.h"
11 
12 #include "../Context.h"
13 #include "../core/FileStream.h"
14 #include "../core/MemoryStream.h"
15 #include "../localisation/Localisation.h"
16 #include "../localisation/StringIds.h"
17 #include "../object/ObjectList.h"
18 #include "../rct12/SawyerChunkWriter.h"
19 #include "../ride/Ride.h"
20 #include "../ride/Station.h"
21 #include "../ride/Track.h"
22 #include "../ride/TrackData.h"
23 #include "../ride/TrackDesign.h"
24 #include "../ride/TrackDesignRepository.h"
25 #include "../windows/Intent.h"
26 
27 #include <functional>
28 
T6Exporter(TrackDesign * trackDesign)29 T6Exporter::T6Exporter(TrackDesign* trackDesign)
30     : _trackDesign(trackDesign)
31 {
32 }
33 
SaveTrack(const utf8 * path)34 bool T6Exporter::SaveTrack(const utf8* path)
35 {
36     try
37     {
38         auto fs = OpenRCT2::FileStream(path, OpenRCT2::FILE_MODE_WRITE);
39         return SaveTrack(&fs);
40     }
41     catch (const std::exception& e)
42     {
43         log_error("Unable to save track design: %s", e.what());
44         return false;
45     }
46 }
47 
SaveTrack(OpenRCT2::IStream * stream)48 bool T6Exporter::SaveTrack(OpenRCT2::IStream* stream)
49 {
50     OpenRCT2::MemoryStream tempStream;
51     tempStream.WriteValue<uint8_t>(OpenRCT2RideTypeToRCT2RideType(_trackDesign->type));
52     tempStream.WriteValue<uint8_t>(_trackDesign->vehicle_type);
53     tempStream.WriteValue<uint32_t>(_trackDesign->flags);
54     tempStream.WriteValue<uint8_t>(static_cast<uint8_t>(_trackDesign->ride_mode));
55     tempStream.WriteValue<uint8_t>((_trackDesign->colour_scheme & 0x3) | (2 << 2));
56     tempStream.WriteArray(_trackDesign->vehicle_colours.data(), RCT12_MAX_VEHICLE_COLOURS);
57     tempStream.WriteValue<uint8_t>(0);
58     tempStream.WriteValue<uint8_t>(_trackDesign->entrance_style);
59     tempStream.WriteValue<uint8_t>(_trackDesign->total_air_time);
60     tempStream.WriteValue<uint8_t>(_trackDesign->depart_flags);
61     tempStream.WriteValue<uint8_t>(_trackDesign->number_of_trains);
62     tempStream.WriteValue<uint8_t>(_trackDesign->number_of_cars_per_train);
63     tempStream.WriteValue<uint8_t>(_trackDesign->min_waiting_time);
64     tempStream.WriteValue<uint8_t>(_trackDesign->max_waiting_time);
65     tempStream.WriteValue<uint8_t>(_trackDesign->operation_setting);
66     tempStream.WriteValue<int8_t>(_trackDesign->max_speed);
67     tempStream.WriteValue<int8_t>(_trackDesign->average_speed);
68     tempStream.WriteValue<uint16_t>(_trackDesign->ride_length);
69     tempStream.WriteValue<uint8_t>(_trackDesign->max_positive_vertical_g);
70     tempStream.WriteValue<int8_t>(_trackDesign->max_negative_vertical_g);
71     tempStream.WriteValue<uint8_t>(_trackDesign->max_lateral_g);
72     tempStream.WriteValue<uint8_t>(_trackDesign->type == RIDE_TYPE_MINI_GOLF ? _trackDesign->holes : _trackDesign->inversions);
73     tempStream.WriteValue<uint8_t>(_trackDesign->drops);
74     tempStream.WriteValue<uint8_t>(_trackDesign->highest_drop_height);
75     tempStream.WriteValue<uint8_t>(_trackDesign->excitement);
76     tempStream.WriteValue<uint8_t>(_trackDesign->intensity);
77     tempStream.WriteValue<uint8_t>(_trackDesign->nausea);
78     tempStream.WriteValue<money16>(_trackDesign->upkeep_cost);
79     tempStream.WriteArray(_trackDesign->track_spine_colour, RCT12_NUM_COLOUR_SCHEMES);
80     tempStream.WriteArray(_trackDesign->track_rail_colour, RCT12_NUM_COLOUR_SCHEMES);
81     tempStream.WriteArray(_trackDesign->track_support_colour, RCT12_NUM_COLOUR_SCHEMES);
82     tempStream.WriteValue<uint32_t>(_trackDesign->flags2);
83     tempStream.Write(&_trackDesign->vehicle_object.Entry, sizeof(rct_object_entry));
84     tempStream.WriteValue<uint8_t>(_trackDesign->space_required_x);
85     tempStream.WriteValue<uint8_t>(_trackDesign->space_required_y);
86     tempStream.WriteArray(_trackDesign->vehicle_additional_colour, RCT2_MAX_CARS_PER_TRAIN);
87     tempStream.WriteValue<uint8_t>(_trackDesign->lift_hill_speed | (_trackDesign->num_circuits << 5));
88 
89     if (_trackDesign->type == RIDE_TYPE_MAZE)
90     {
91         for (const auto& mazeElement : _trackDesign->maze_elements)
92         {
93             tempStream.WriteValue<uint32_t>(mazeElement.all);
94         }
95 
96         tempStream.WriteValue<uint32_t>(0);
97     }
98     else
99     {
100         for (const auto& trackElement : _trackDesign->track_elements)
101         {
102             auto trackType = OpenRCT2TrackTypeToRCT2(trackElement.type);
103             if (trackType == TrackElemType::MultiDimInvertedUp90ToFlatQuarterLoop)
104             {
105                 trackType = TrackElemType::InvertedUp90ToFlatQuarterLoopAlias;
106             }
107             tempStream.WriteValue<uint8_t>(static_cast<uint8_t>(trackType));
108             tempStream.WriteValue<uint8_t>(trackElement.flags);
109         }
110 
111         tempStream.WriteValue<uint8_t>(0xFF);
112 
113         for (const auto& entranceElement : _trackDesign->entrance_elements)
114         {
115             tempStream.WriteValue<uint8_t>(entranceElement.z == -1 ? static_cast<uint8_t>(0x80) : entranceElement.z);
116             tempStream.WriteValue<uint8_t>(entranceElement.direction | (entranceElement.isExit << 7));
117             tempStream.WriteValue<int16_t>(entranceElement.x);
118             tempStream.WriteValue<int16_t>(entranceElement.y);
119         }
120 
121         tempStream.WriteValue<uint8_t>(0xFF);
122     }
123 
124     for (const auto& sceneryElement : _trackDesign->scenery_elements)
125     {
126         tempStream.Write(&sceneryElement.scenery_object.Entry, sizeof(rct_object_entry));
127         tempStream.WriteValue<int8_t>(sceneryElement.x);
128         tempStream.WriteValue<int8_t>(sceneryElement.y);
129         tempStream.WriteValue<int8_t>(sceneryElement.z);
130         tempStream.WriteValue<uint8_t>(sceneryElement.flags);
131         tempStream.WriteValue<uint8_t>(sceneryElement.primary_colour);
132         tempStream.WriteValue<uint8_t>(sceneryElement.secondary_colour);
133     }
134 
135     tempStream.WriteValue<uint8_t>(0xFF);
136 
137     SawyerChunkWriter sawyerCoding(stream);
138     sawyerCoding.WriteChunkTrack(tempStream.GetData(), tempStream.GetLength());
139     return true;
140 }
141