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 "../Cheats.h"
11 #include "../Context.h"
12 #include "../Game.h"
13 #include "../Input.h"
14 #include "../actions/TrackPlaceAction.h"
15 #include "../audio/audio.h"
16 #include "../interface/Viewport.h"
17 #include "../network/network.h"
18 #include "../paint/VirtualFloor.h"
19 #include "../peep/Staff.h"
20 #include "../ride/RideData.h"
21 #include "../ride/Track.h"
22 #include "../ride/TrackData.h"
23 #include "../util/Math.hpp"
24 #include "../world/Banner.h"
25 #include "../world/Scenery.h"
26 #include "Intent.h"
27 
28 #include <iterator>
29 #include <tuple>
30 
31 using namespace OpenRCT2::TrackMetaData;
32 bool gDisableErrorWindowSound = false;
33 
34 uint64_t _enabledRidePieces;
35 RideConstructionState _rideConstructionState2;
36 
37 // This variable is updated separately from ride->num_stations because the latter
38 // is unreliable if currently in station construction mode
39 bool _stationConstructed;
40 bool _deferClose;
41 
42 /**
43  *
44  *  rct2: 0x006CA162
45  */
place_provisional_track_piece(ride_id_t rideIndex,int32_t trackType,int32_t trackDirection,int32_t liftHillAndAlternativeState,const CoordsXYZ & trackPos)46 money32 place_provisional_track_piece(
47     ride_id_t rideIndex, int32_t trackType, int32_t trackDirection, int32_t liftHillAndAlternativeState,
48     const CoordsXYZ& trackPos)
49 {
50     auto ride = get_ride(rideIndex);
51     if (ride == nullptr)
52         return MONEY32_UNDEFINED;
53 
54     ride_construction_remove_ghosts();
55     if (ride->type == RIDE_TYPE_MAZE)
56     {
57         int32_t flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND
58             | GAME_COMMAND_FLAG_GHOST; // 105
59         auto result = maze_set_track(trackPos.x, trackPos.y, trackPos.z, flags, true, 0, rideIndex, GC_SET_MAZE_TRACK_BUILD);
60         if (result == MONEY32_UNDEFINED)
61             return result;
62 
63         _unkF440C5 = { trackPos, static_cast<Direction>(trackDirection) };
64         _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_TRACK;
65         viewport_set_visibility(3);
66         if (_currentTrackSlopeEnd != 0)
67             viewport_set_visibility(2);
68 
69         // Invalidate previous track piece (we may not be changing height!)
70         virtual_floor_invalidate();
71 
72         if (!scenery_tool_is_active())
73         {
74             // Set new virtual floor height.
75             virtual_floor_set_height(trackPos.z);
76         }
77 
78         return result;
79     }
80 
81     auto trackPlaceAction = TrackPlaceAction(
82         rideIndex, trackType, { trackPos, static_cast<uint8_t>(trackDirection) }, 0, 0, 0, liftHillAndAlternativeState, false);
83     trackPlaceAction.SetFlags(GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
84     // This command must not be sent over the network
85     auto res = GameActions::Execute(&trackPlaceAction);
86     if (res->Error != GameActions::Status::Ok)
87         return MONEY32_UNDEFINED;
88 
89     int16_t z_begin, z_end;
90     const auto& ted = GetTrackElementDescriptor(trackType);
91     const rct_track_coordinates& coords = ted.Coordinates;
92     if (!ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_NO_TRACK))
93     {
94         z_begin = coords.z_begin;
95         z_end = coords.z_end;
96     }
97     else
98     {
99         z_end = z_begin = coords.z_begin;
100     }
101 
102     _unkF440C5 = { trackPos.x, trackPos.y, trackPos.z + z_begin, static_cast<Direction>(trackDirection) };
103     _currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_TRACK;
104 
105     const auto resultData = res->GetData<TrackPlaceActionResult>();
106     viewport_set_visibility((resultData.GroundFlags & ELEMENT_IS_UNDERGROUND) ? 1 : 3);
107     if (_currentTrackSlopeEnd != 0)
108         viewport_set_visibility(2);
109 
110     // Invalidate previous track piece (we may not be changing height!)
111     virtual_floor_invalidate();
112 
113     if (!scenery_tool_is_active())
114     {
115         // Set height to where the next track piece would begin
116         virtual_floor_set_height(trackPos.z - z_begin + z_end);
117     }
118 
119     return res->Cost;
120 }
121 
window_ride_construction_update_state_get_track_element()122 static std::tuple<bool, track_type_t> window_ride_construction_update_state_get_track_element()
123 {
124     auto intent = Intent(INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_PIECES);
125     context_broadcast_intent(&intent);
126 
127     uint8_t startSlope = _previousTrackSlopeEnd;
128     uint8_t endSlope = _currentTrackSlopeEnd;
129     uint8_t startBank = _previousTrackBankEnd;
130     uint8_t endBank = _currentTrackBankEnd;
131 
132     if (_rideConstructionState == RideConstructionState::Back)
133     {
134         startSlope = _currentTrackSlopeEnd;
135         endSlope = _previousTrackSlopeEnd;
136         startBank = _currentTrackBankEnd;
137         endBank = _previousTrackBankEnd;
138     }
139 
140     auto curve = _currentTrackCurve;
141     if (curve == TrackElemType::None)
142     {
143         return std::make_tuple(false, 0);
144     }
145 
146     bool startsDiagonal = (_currentTrackPieceDirection & (1 << 2)) != 0;
147     if (curve == TRACK_CURVE_LEFT_LARGE || curve == TRACK_CURVE_RIGHT_LARGE)
148     {
149         if (_rideConstructionState == RideConstructionState::Back)
150         {
151             startsDiagonal = !startsDiagonal;
152         }
153     }
154 
155     if (curve <= 8)
156     {
157         for (uint32_t i = 0; i < std::size(gTrackDescriptors); i++)
158         {
159             const track_descriptor* trackDescriptor = &gTrackDescriptors[i];
160 
161             if (trackDescriptor->track_curve != curve)
162                 continue;
163             if (trackDescriptor->starts_diagonal != startsDiagonal)
164                 continue;
165             if (trackDescriptor->slope_start != startSlope)
166                 continue;
167             if (trackDescriptor->slope_end != endSlope)
168                 continue;
169             if (trackDescriptor->bank_start != startBank)
170                 continue;
171             if (trackDescriptor->bank_end != endBank)
172                 continue;
173 
174             return std::make_tuple(true, trackDescriptor->track_element);
175         }
176 
177         return std::make_tuple(false, 0);
178     }
179 
180     switch (curve & 0xFFFF)
181     {
182         case TrackElemType::EndStation:
183         case TrackElemType::SBendLeft:
184         case TrackElemType::SBendRight:
185             if (startSlope != TRACK_SLOPE_NONE || endSlope != TRACK_SLOPE_NONE)
186             {
187                 return std::make_tuple(false, 0);
188             }
189 
190             if (startBank != TRACK_BANK_NONE || endBank != TRACK_BANK_NONE)
191             {
192                 return std::make_tuple(false, 0);
193             }
194 
195             return std::make_tuple(true, static_cast<track_type_t>(curve & 0xFFFF));
196 
197         case TrackElemType::LeftVerticalLoop:
198         case TrackElemType::RightVerticalLoop:
199             if (startBank != TRACK_BANK_NONE || endBank != TRACK_BANK_NONE)
200             {
201                 return std::make_tuple(false, 0);
202             }
203 
204             if (_rideConstructionState == RideConstructionState::Back)
205             {
206                 if (endSlope != TRACK_SLOPE_DOWN_25)
207                 {
208                     return std::make_tuple(false, 0);
209                 }
210             }
211             else
212             {
213                 if (startSlope != TRACK_SLOPE_UP_25)
214                 {
215                     return std::make_tuple(false, 0);
216                 }
217             }
218 
219             return std::make_tuple(true, static_cast<track_type_t>(curve & 0xFFFF));
220 
221         default:
222             return std::make_tuple(true, static_cast<track_type_t>(curve & 0xFFFF));
223     }
224 }
225 
226 /**
227  * rct2: 0x006CA2DF
228  *
229  * @param[out] _trackType (dh)
230  * @param[out] _trackDirection (bh)
231  * @param[out] _rideIndex (dl)
232  * @param[out] _liftHillAndInvertedState (liftHillAndInvertedState)
233  * @param[out] _x (ax)
234  * @param[out] _y (cx)
235  * @param[out] _z (di)
236  * @param[out] _properties (edirs16)
237  * @return (CF)
238  */
window_ride_construction_update_state(int32_t * _trackType,int32_t * _trackDirection,ride_id_t * _rideIndex,int32_t * _liftHillAndInvertedState,CoordsXYZ * _trackPos,int32_t * _properties)239 bool window_ride_construction_update_state(
240     int32_t* _trackType, int32_t* _trackDirection, ride_id_t* _rideIndex, int32_t* _liftHillAndInvertedState,
241     CoordsXYZ* _trackPos, int32_t* _properties)
242 {
243     ride_id_t rideIndex;
244     uint8_t trackDirection;
245     uint16_t x, y, liftHillAndInvertedState, properties;
246 
247     auto updated_element = window_ride_construction_update_state_get_track_element();
248     if (!std::get<0>(updated_element))
249     {
250         return true;
251     }
252 
253     track_type_t trackType = std::get<1>(updated_element);
254     liftHillAndInvertedState = 0;
255     rideIndex = _currentRideIndex;
256     if (_currentTrackLiftHill & CONSTRUCTION_LIFT_HILL_SELECTED)
257     {
258         liftHillAndInvertedState |= CONSTRUCTION_LIFT_HILL_SELECTED;
259     }
260 
261     if (_currentTrackAlternative & RIDE_TYPE_ALTERNATIVE_TRACK_TYPE)
262     {
263         liftHillAndInvertedState |= CONSTRUCTION_INVERTED_TRACK_SELECTED;
264     }
265 
266     auto ride = get_ride(rideIndex);
267     if (ride == nullptr)
268         return true;
269 
270     if (_enabledRidePieces & (1ULL << TRACK_SLOPE_STEEP_LONG))
271     {
272         switch (trackType)
273         {
274             case TrackElemType::FlatToUp60:
275                 trackType = TrackElemType::FlatToUp60LongBase;
276                 break;
277 
278             case TrackElemType::Up60ToFlat:
279                 trackType = TrackElemType::Up60ToFlatLongBase;
280                 break;
281 
282             case TrackElemType::FlatToDown60:
283                 trackType = TrackElemType::FlatToDown60LongBase;
284                 break;
285 
286             case TrackElemType::Down60ToFlat:
287                 trackType = TrackElemType::Down60ToFlatLongBase;
288                 break;
289 
290             case TrackElemType::DiagFlatToUp60:
291             case TrackElemType::DiagUp60ToFlat:
292             case TrackElemType::DiagFlatToDown60:
293             case TrackElemType::DiagDown60ToFlat:
294                 return true;
295         }
296     }
297 
298     const auto& rtd = ride->GetRideTypeDescriptor();
299     if (rtd.HasFlag(RIDE_TYPE_FLAG_TRACK_ELEMENTS_HAVE_TWO_VARIETIES)
300         && _currentTrackAlternative & RIDE_TYPE_ALTERNATIVE_TRACK_PIECES)
301     {
302         auto availablePieces = rtd.CoveredTrackPieces;
303         const auto& ted = GetTrackElementDescriptor(trackType);
304         auto alternativeType = ted.AlternativeType;
305         if (alternativeType != TrackElemType::None && (availablePieces & (1ULL << trackType)))
306         {
307             trackType = alternativeType;
308             if (!gCheatsEnableChainLiftOnAllTrack)
309                 liftHillAndInvertedState &= ~CONSTRUCTION_LIFT_HILL_SELECTED;
310         }
311     }
312 
313     const auto& ted = GetTrackElementDescriptor(trackType);
314     const rct_track_coordinates& trackCoordinates = ted.Coordinates;
315 
316     x = _currentTrackBegin.x;
317     y = _currentTrackBegin.y;
318     auto z = _currentTrackBegin.z;
319     if (_rideConstructionState == RideConstructionState::Back)
320     {
321         z -= trackCoordinates.z_end;
322         trackDirection = _currentTrackPieceDirection ^ 0x02;
323         trackDirection -= trackCoordinates.rotation_end;
324         trackDirection += trackCoordinates.rotation_begin;
325         trackDirection &= 0x03;
326 
327         if (trackCoordinates.rotation_begin & (1 << 2))
328         {
329             trackDirection |= 0x04;
330         }
331 
332         CoordsXY offsets = { trackCoordinates.x, trackCoordinates.y };
333         CoordsXY coords = { x, y };
334         coords += offsets.Rotate(direction_reverse(trackDirection));
335         x = static_cast<uint16_t>(coords.x);
336         y = static_cast<uint16_t>(coords.y);
337     }
338     else
339     {
340         z -= trackCoordinates.z_begin;
341         trackDirection = _currentTrackPieceDirection;
342     }
343 
344     bool turnOffLiftHill = false;
345     if (!(_enabledRidePieces & (1ULL << TRACK_LIFT_HILL_CURVE)))
346     {
347         if (ted.Flags & TRACK_ELEM_FLAG_CURVE_ALLOWS_LIFT)
348         {
349             turnOffLiftHill = true;
350         }
351     }
352 
353     if (!(ted.Flags & TRACK_ELEM_FLAG_ALLOW_LIFT_HILL))
354     {
355         turnOffLiftHill = true;
356     }
357 
358     if (turnOffLiftHill && !gCheatsEnableChainLiftOnAllTrack)
359     {
360         liftHillAndInvertedState &= ~CONSTRUCTION_LIFT_HILL_SELECTED;
361         _currentTrackLiftHill &= ~CONSTRUCTION_LIFT_HILL_SELECTED;
362 
363         if (trackType == TrackElemType::LeftCurvedLiftHill || trackType == TrackElemType::RightCurvedLiftHill)
364         {
365             liftHillAndInvertedState |= CONSTRUCTION_LIFT_HILL_SELECTED;
366         }
367     }
368 
369     if (TrackTypeHasSpeedSetting(trackType))
370     {
371         properties = _currentBrakeSpeed2;
372     }
373     else
374     {
375         properties = _currentSeatRotationAngle << 12;
376     }
377 
378     if (_trackType != nullptr)
379         *_trackType = trackType;
380     if (_trackDirection != nullptr)
381         *_trackDirection = trackDirection;
382     if (_rideIndex != nullptr)
383         *_rideIndex = rideIndex;
384     if (_liftHillAndInvertedState != nullptr)
385         *_liftHillAndInvertedState = liftHillAndInvertedState;
386     if (_trackPos != nullptr)
387         *_trackPos = { x, y, z };
388     if (_properties != nullptr)
389         *_properties = properties;
390 
391     return false;
392 }
393 
window_ride_construction_do_entrance_exit_check()394 void window_ride_construction_do_entrance_exit_check()
395 {
396     auto w = window_find_by_class(WC_RIDE_CONSTRUCTION);
397     auto ride = get_ride(_currentRideIndex);
398     if (w == nullptr || ride == nullptr)
399     {
400         return;
401     }
402 
403     if (_rideConstructionState == RideConstructionState::State0)
404     {
405         w = window_find_by_class(WC_RIDE_CONSTRUCTION);
406         if (w != nullptr)
407         {
408             if (!ride_are_all_possible_entrances_and_exits_built(ride))
409             {
410                 window_event_mouse_up_call(w, WC_RIDE_CONSTRUCTION__WIDX_ENTRANCE);
411             }
412             else
413             {
414                 _deferClose = true;
415             }
416         }
417     }
418 }
419 
window_ride_construction_do_station_check()420 void window_ride_construction_do_station_check()
421 {
422     auto ride = get_ride(_currentRideIndex);
423     if (ride != nullptr)
424     {
425         _stationConstructed = ride->num_stations != 0;
426     }
427 }
428 
window_ride_construction_mouseup_demolish_next_piece(const CoordsXYZD & piecePos,int32_t type)429 void window_ride_construction_mouseup_demolish_next_piece(const CoordsXYZD& piecePos, int32_t type)
430 {
431     if (gGotoStartPlacementMode)
432     {
433         _currentTrackBegin.z = floor2(piecePos.z, COORDS_Z_STEP);
434         _rideConstructionState = RideConstructionState::Front;
435         _currentTrackSelectionFlags = 0;
436         _currentTrackPieceDirection = piecePos.direction & 3;
437         auto savedCurrentTrackCurve = _currentTrackCurve;
438         int32_t savedPreviousTrackSlopeEnd = _previousTrackSlopeEnd;
439         int32_t savedCurrentTrackSlopeEnd = _currentTrackSlopeEnd;
440         int32_t savedPreviousTrackBankEnd = _previousTrackBankEnd;
441         int32_t savedCurrentTrackBankEnd = _currentTrackBankEnd;
442         int32_t savedCurrentTrackAlternative = _currentTrackAlternative;
443         int32_t savedCurrentTrackLiftHill = _currentTrackLiftHill;
444         ride_construction_set_default_next_piece();
445         window_ride_construction_update_active_elements();
446         auto ride = get_ride(_currentRideIndex);
447         if (!ride_try_get_origin_element(ride, nullptr))
448         {
449             ride_initialise_construction_window(ride);
450             _currentTrackPieceDirection = piecePos.direction & 3;
451             if (!(savedCurrentTrackCurve & RideConstructionSpecialPieceSelected))
452             {
453                 _currentTrackCurve = savedCurrentTrackCurve;
454                 _previousTrackSlopeEnd = savedPreviousTrackSlopeEnd;
455                 _currentTrackSlopeEnd = savedCurrentTrackSlopeEnd;
456                 _previousTrackBankEnd = savedPreviousTrackBankEnd;
457                 _currentTrackBankEnd = savedCurrentTrackBankEnd;
458                 _currentTrackAlternative = savedCurrentTrackAlternative;
459                 _currentTrackLiftHill = savedCurrentTrackLiftHill;
460                 window_ride_construction_update_active_elements();
461             }
462         }
463     }
464     else
465     {
466         if (_rideConstructionState2 == RideConstructionState::Selected
467             || _rideConstructionState2 == RideConstructionState::Front)
468         {
469             if (type == TrackElemType::MiddleStation || type == TrackElemType::BeginStation)
470             {
471                 type = TrackElemType::EndStation;
472             }
473         }
474         if (_rideConstructionState2 == RideConstructionState::Back)
475         {
476             if (type == TrackElemType::MiddleStation)
477             {
478                 type = TrackElemType::BeginStation;
479             }
480         }
481         if (network_get_mode() == NETWORK_MODE_CLIENT)
482         {
483             // rideConstructionState needs to be set again to the proper value, this only affects the client
484             _rideConstructionState = RideConstructionState::Selected;
485         }
486         _currentTrackBegin = piecePos;
487         _currentTrackPieceDirection = piecePos.direction;
488         _currentTrackPieceType = type;
489         _currentTrackSelectionFlags = 0;
490         if (_rideConstructionState2 == RideConstructionState::Front)
491         {
492             ride_select_next_section();
493         }
494         else if (_rideConstructionState2 == RideConstructionState::Back)
495         {
496             ride_select_previous_section();
497         }
498         window_ride_construction_update_active_elements();
499     }
500 }
501 
502 /**
503  *
504  *  rct2: 0x006C84CE
505  */
window_ride_construction_update_active_elements()506 void window_ride_construction_update_active_elements()
507 {
508     auto intent = Intent(INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_ACTIVE_ELEMENTS);
509     context_broadcast_intent(&intent);
510 }
511 
512 /**
513  *
514  *  rct2: 0x0066DB3D
515  */
scenery_tool_is_active()516 bool scenery_tool_is_active()
517 {
518     int32_t toolWindowClassification = gCurrentToolWidget.window_classification;
519     rct_widgetindex toolWidgetIndex = gCurrentToolWidget.widget_index;
520     if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
521         if (toolWindowClassification == WC_TOP_TOOLBAR && toolWidgetIndex == WC_TOP_TOOLBAR__WIDX_SCENERY)
522             return true;
523 
524     return false;
525 }
526 
init_scenery()527 void init_scenery()
528 {
529     auto intent = Intent(INTENT_ACTION_INIT_SCENERY);
530     context_broadcast_intent(&intent);
531 }
532 
scenery_set_default_placement_configuration()533 void scenery_set_default_placement_configuration()
534 {
535     auto intent = Intent(INTENT_ACTION_SET_DEFAULT_SCENERY_CONFIG);
536     context_broadcast_intent(&intent);
537 }
538