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 "Editor.h"
11 
12 #include "Context.h"
13 #include "EditorObjectSelectionSession.h"
14 #include "FileClassifier.h"
15 #include "Game.h"
16 #include "GameState.h"
17 #include "OpenRCT2.h"
18 #include "ParkImporter.h"
19 #include "actions/LandBuyRightsAction.h"
20 #include "actions/LandSetRightsAction.h"
21 #include "audio/audio.h"
22 #include "interface/Viewport.h"
23 #include "interface/Window_internal.h"
24 #include "localisation/Localisation.h"
25 #include "localisation/LocalisationService.h"
26 #include "management/NewsItem.h"
27 #include "object/ObjectManager.h"
28 #include "object/ObjectRepository.h"
29 #include "peep/Guest.h"
30 #include "peep/Staff.h"
31 #include "rct1/RCT1.h"
32 #include "scenario/Scenario.h"
33 #include "ui/UiContext.h"
34 #include "ui/WindowManager.h"
35 #include "util/Util.h"
36 #include "windows/Intent.h"
37 #include "world/Climate.h"
38 #include "world/EntityList.h"
39 #include "world/Entrance.h"
40 #include "world/Footpath.h"
41 #include "world/Park.h"
42 #include "world/Scenery.h"
43 #include "world/Sprite.h"
44 
45 #include <algorithm>
46 #include <array>
47 #include <vector>
48 
49 using namespace OpenRCT2;
50 
51 EditorStep gEditorStep;
52 
53 namespace Editor
54 {
55     static std::array<std::vector<uint8_t>, EnumValue(ObjectType::Count)> _editorSelectedObjectFlags;
56 
57     static void ConvertSaveToScenarioCallback(int32_t result, const utf8* path);
58     static void SetAllLandOwned();
59     static bool LoadLandscapeFromSV4(const char* path);
60     static bool LoadLandscapeFromSC4(const char* path);
61     static void FinaliseMainView();
62     static bool ReadS6(const char* path);
63     static void ClearMapForEditing(bool fromSave);
64 
object_list_load()65     static void object_list_load()
66     {
67         auto* context = GetContext();
68 
69         // Unload objects first, the repository is re-populated which owns the objects.
70         auto& objectManager = context->GetObjectManager();
71         objectManager.UnloadAll();
72 
73         // Scan objects if necessary
74         const auto& localisationService = context->GetLocalisationService();
75         auto& objectRepository = context->GetObjectRepository();
76         objectRepository.LoadOrConstruct(localisationService.GetCurrentLanguage());
77 
78         // Reset loaded objects to just defaults
79         objectManager.LoadDefaultObjects();
80     }
81 
82     /**
83      *
84      *  rct2: 0x0066FFE1
85      */
Load()86     void Load()
87     {
88         OpenRCT2::Audio::StopAll();
89         object_manager_unload_all_objects();
90         object_list_load();
91         OpenRCT2::GetContext()->GetGameState()->InitAll(150);
92         gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
93         gEditorStep = EditorStep::ObjectSelection;
94         gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES;
95         gScenarioCategory = SCENARIO_CATEGORY_OTHER;
96         viewport_init_all();
97         rct_window* mainWindow = context_open_window_view(WV_EDITOR_MAIN);
98         mainWindow->SetLocation(TileCoordsXYZ{ 75, 75, 14 }.ToCoordsXYZ());
99         load_palette();
100         gScreenAge = 0;
101         gScenarioName = language_get_string(STR_MY_NEW_SCENARIO);
102     }
103 
104     /**
105      *
106      *  rct2: 0x00672781
107      */
ConvertSaveToScenario()108     void ConvertSaveToScenario()
109     {
110         tool_cancel();
111         auto intent = Intent(WC_LOADSAVE);
112         intent.putExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME);
113         intent.putExtra(INTENT_EXTRA_CALLBACK, reinterpret_cast<void*>(ConvertSaveToScenarioCallback));
114         context_open_intent(&intent);
115     }
116 
ConvertSaveToScenarioCallback(int32_t result,const utf8 * path)117     static void ConvertSaveToScenarioCallback(int32_t result, const utf8* path)
118     {
119         if (result != MODAL_RESULT_OK)
120         {
121             return;
122         }
123 
124         if (!context_load_park_from_file(path))
125         {
126             return;
127         }
128 
129         if (gParkFlags & PARK_FLAGS_NO_MONEY)
130         {
131             gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO;
132         }
133         else
134         {
135             gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO;
136         }
137         gParkFlags |= PARK_FLAGS_NO_MONEY;
138 
139         climate_reset(gClimate);
140 
141         // Clear the scenario completion status
142         gParkFlags &= ~PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT;
143         gScenarioCompletedCompanyValue = MONEY64_UNDEFINED;
144 
145         gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
146         gEditorStep = EditorStep::ObjectiveSelection;
147         gScenarioCategory = SCENARIO_CATEGORY_OTHER;
148         viewport_init_all();
149         News::InitQueue();
150         context_open_window_view(WV_EDITOR_MAIN);
151         FinaliseMainView();
152         gScreenAge = 0;
153     }
154 
155     /**
156      *
157      *  rct2: 0x00672957
158      */
LoadTrackDesigner()159     void LoadTrackDesigner()
160     {
161         OpenRCT2::Audio::StopAll();
162         gScreenFlags = SCREEN_FLAGS_TRACK_DESIGNER;
163         gScreenAge = 0;
164 
165         object_manager_unload_all_objects();
166         object_list_load();
167         OpenRCT2::GetContext()->GetGameState()->InitAll(150);
168         SetAllLandOwned();
169         gEditorStep = EditorStep::ObjectSelection;
170         viewport_init_all();
171         rct_window* mainWindow = context_open_window_view(WV_EDITOR_MAIN);
172         mainWindow->SetLocation(TileCoordsXYZ{ 75, 75, 14 }.ToCoordsXYZ());
173         load_palette();
174     }
175 
176     /**
177      *
178      *  rct2: 0x006729FD
179      */
LoadTrackManager()180     void LoadTrackManager()
181     {
182         OpenRCT2::Audio::StopAll();
183         gScreenFlags = SCREEN_FLAGS_TRACK_MANAGER;
184         gScreenAge = 0;
185 
186         object_manager_unload_all_objects();
187         object_list_load();
188         OpenRCT2::GetContext()->GetGameState()->InitAll(150);
189         SetAllLandOwned();
190         gEditorStep = EditorStep::ObjectSelection;
191         viewport_init_all();
192         rct_window* mainWindow = context_open_window_view(WV_EDITOR_MAIN);
193         mainWindow->SetLocation(TileCoordsXYZ{ 75, 75, 14 }.ToCoordsXYZ());
194         load_palette();
195     }
196 
197     /**
198      *
199      *  rct2: 0x0068ABEC
200      */
SetAllLandOwned()201     static void SetAllLandOwned()
202     {
203         int32_t mapSize = gMapSize;
204 
205         MapRange range = { 64, 64, (mapSize - 3) * 32, (mapSize - 3) * 32 };
206         auto landSetRightsAction = LandSetRightsAction(range, LandSetRightSetting::SetForSale);
207         landSetRightsAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND);
208         GameActions::Execute(&landSetRightsAction);
209 
210         auto landBuyRightsAction = LandBuyRightsAction(range, LandBuyRightSetting::BuyLand);
211         landBuyRightsAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND);
212         GameActions::Execute(&landBuyRightsAction);
213     }
214 
215     /**
216      *
217      *  rct2: 0x006758C0
218      */
LoadLandscape(const utf8 * path)219     bool LoadLandscape(const utf8* path)
220     {
221         // #4996: Make sure the object selection window closes here to prevent unload objects
222         //        after we have loaded a new park.
223         window_close_all();
224 
225         uint32_t extension = get_file_extension_type(path);
226         switch (extension)
227         {
228             case FILE_EXTENSION_SC6:
229             case FILE_EXTENSION_SV6:
230                 return ReadS6(path);
231             case FILE_EXTENSION_SC4:
232                 return LoadLandscapeFromSC4(path);
233             case FILE_EXTENSION_SV4:
234                 return LoadLandscapeFromSV4(path);
235             default:
236                 return false;
237         }
238     }
239 
240     /**
241      *
242      *  rct2: 0x006A2B02
243      */
LoadLandscapeFromSV4(const char * path)244     static bool LoadLandscapeFromSV4(const char* path)
245     {
246         load_from_sv4(path);
247         ClearMapForEditing(true);
248 
249         gEditorStep = EditorStep::LandscapeEditor;
250         gScreenAge = 0;
251         gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
252         viewport_init_all();
253         context_open_window_view(WV_EDITOR_MAIN);
254         FinaliseMainView();
255         return true;
256     }
257 
LoadLandscapeFromSC4(const char * path)258     static bool LoadLandscapeFromSC4(const char* path)
259     {
260         load_from_sc4(path);
261         ClearMapForEditing(false);
262 
263         gEditorStep = EditorStep::LandscapeEditor;
264         gScreenAge = 0;
265         gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
266         viewport_init_all();
267         context_open_window_view(WV_EDITOR_MAIN);
268         FinaliseMainView();
269         return true;
270     }
271 
272     /**
273      *
274      *  rct2: 0x006758FE
275      */
ReadS6(const char * path)276     static bool ReadS6(const char* path)
277     {
278         auto extension = path_get_extension(path);
279         auto loadedFromSave = false;
280         if (_stricmp(extension, ".sc6") == 0)
281         {
282             load_from_sc6(path);
283         }
284         else if (_stricmp(extension, ".sv6") == 0 || _stricmp(extension, ".sv7") == 0)
285         {
286             load_from_sv6(path);
287             loadedFromSave = true;
288         }
289 
290         ClearMapForEditing(loadedFromSave);
291 
292         gEditorStep = EditorStep::LandscapeEditor;
293         gScreenAge = 0;
294         gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
295         viewport_init_all();
296         context_open_window_view(WV_EDITOR_MAIN);
297         FinaliseMainView();
298         return true;
299     }
300 
ClearMapForEditing(bool fromSave)301     static void ClearMapForEditing(bool fromSave)
302     {
303         map_remove_all_rides();
304         UnlinkAllRideBanners();
305 
306         ride_init_all();
307 
308         //
309         for (auto* guest : EntityList<Guest>())
310         {
311             guest->SetName({});
312         }
313         for (auto* staff : EntityList<Staff>())
314         {
315             staff->SetName({});
316         }
317 
318         reset_sprite_list();
319         staff_reset_modes();
320         gNumGuestsInPark = 0;
321         gNumGuestsHeadingForPark = 0;
322         gNumGuestsInParkLastWeek = 0;
323         gGuestChangeModifier = 0;
324         if (fromSave)
325         {
326             research_populate_list_random();
327 
328             if (gParkFlags & PARK_FLAGS_NO_MONEY)
329             {
330                 gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO;
331             }
332             else
333             {
334                 gParkFlags &= ~PARK_FLAGS_NO_MONEY_SCENARIO;
335             }
336             gParkFlags |= PARK_FLAGS_NO_MONEY;
337 
338             if (gParkEntranceFee == 0)
339             {
340                 gParkFlags |= PARK_FLAGS_PARK_FREE_ENTRY;
341             }
342             else
343             {
344                 gParkFlags &= ~PARK_FLAGS_PARK_FREE_ENTRY;
345             }
346 
347             gParkFlags &= ~PARK_FLAGS_SPRITES_INITIALISED;
348 
349             gGuestInitialCash = std::clamp(
350                 gGuestInitialCash, static_cast<money16>(MONEY(10, 00)), static_cast<money16>(MAX_ENTRANCE_FEE));
351 
352             gInitialCash = std::min<money64>(gInitialCash, 100000);
353             finance_reset_cash_to_initial();
354 
355             gBankLoan = std::clamp<money64>(gBankLoan, MONEY(0, 00), MONEY(5000000, 00));
356 
357             gMaxBankLoan = std::clamp<money64>(gMaxBankLoan, MONEY(0, 00), MONEY(5000000, 00));
358 
359             gBankLoanInterestRate = std::clamp<uint8_t>(gBankLoanInterestRate, 5, 80);
360         }
361 
362         climate_reset(gClimate);
363 
364         News::InitQueue();
365     }
366 
367     /**
368      *
369      *  rct2: 0x0067009A
370      */
OpenWindowsForCurrentStep()371     void OpenWindowsForCurrentStep()
372     {
373         if (!(gScreenFlags & SCREEN_FLAGS_EDITOR))
374         {
375             return;
376         }
377 
378         switch (gEditorStep)
379         {
380             case EditorStep::ObjectSelection:
381                 if (window_find_by_class(WC_EDITOR_OBJECT_SELECTION) != nullptr)
382                 {
383                     return;
384                 }
385 
386                 if (window_find_by_class(WC_INSTALL_TRACK) != nullptr)
387                 {
388                     return;
389                 }
390 
391                 if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)
392                 {
393                     object_manager_unload_all_objects();
394                 }
395 
396                 context_open_window(WC_EDITOR_OBJECT_SELECTION);
397                 break;
398             case EditorStep::InventionsListSetUp:
399                 if (window_find_by_class(WC_EDITOR_INVENTION_LIST) != nullptr)
400                 {
401                     return;
402                 }
403 
404                 context_open_window(WC_EDITOR_INVENTION_LIST);
405                 break;
406             case EditorStep::OptionsSelection:
407                 if (window_find_by_class(WC_EDITOR_SCENARIO_OPTIONS) != nullptr)
408                 {
409                     return;
410                 }
411 
412                 context_open_window(WC_EDITOR_SCENARIO_OPTIONS);
413                 break;
414             case EditorStep::ObjectiveSelection:
415                 if (window_find_by_class(WC_EDITOR_OBJECTIVE_OPTIONS) != nullptr)
416                 {
417                     return;
418                 }
419 
420                 context_open_window(WC_EDITOR_OBJECTIVE_OPTIONS);
421                 break;
422             case EditorStep::LandscapeEditor:
423             case EditorStep::SaveScenario:
424             case EditorStep::RollercoasterDesigner:
425             case EditorStep::DesignsManager:
426             case EditorStep::Invalid:
427                 break;
428         }
429     }
430 
FinaliseMainView()431     static void FinaliseMainView()
432     {
433         auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
434         windowManager->SetMainView(gSavedView, gSavedViewZoom, gSavedViewRotation);
435 
436         reset_all_sprite_quadrant_placements();
437         scenery_set_default_placement_configuration();
438 
439         windowManager->BroadcastIntent(Intent(INTENT_ACTION_REFRESH_NEW_RIDES));
440 
441         gWindowUpdateTicks = 0;
442         load_palette();
443 
444         windowManager->BroadcastIntent(Intent(INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD));
445     }
446 
447     /**
448      *
449      *  rct2: 0x006AB9B8
450      */
CheckObjectSelection()451     std::pair<ObjectType, rct_string_id> CheckObjectSelection()
452     {
453         bool isTrackDesignerManager = gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER);
454 
455         if (!isTrackDesignerManager)
456         {
457             if (!editor_check_object_group_at_least_one_selected(ObjectType::Paths))
458             {
459                 return { ObjectType::Paths, STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED };
460             }
461         }
462 
463         if (!editor_check_object_group_at_least_one_selected(ObjectType::Ride))
464         {
465             return { ObjectType::Ride, STR_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED };
466         }
467 
468         if (!isTrackDesignerManager)
469         {
470             if (!editor_check_object_group_at_least_one_selected(ObjectType::ParkEntrance))
471             {
472                 return { ObjectType::ParkEntrance, STR_PARK_ENTRANCE_TYPE_MUST_BE_SELECTED };
473             }
474 
475             if (!editor_check_object_group_at_least_one_selected(ObjectType::Water))
476             {
477                 return { ObjectType::Water, STR_WATER_TYPE_MUST_BE_SELECTED };
478             }
479         }
480 
481         return { ObjectType::None, STR_NONE };
482     }
483 
484     /**
485      *
486      *  rct2: 0x0066FEAC
487      */
CheckPark()488     std::pair<bool, rct_string_id> CheckPark()
489     {
490         int32_t parkSize = park_calculate_size();
491         if (parkSize == 0)
492         {
493             return { false, STR_PARK_MUST_OWN_SOME_LAND };
494         }
495 
496         if (gParkEntrances.empty())
497         {
498             return { false, STR_NO_PARK_ENTRANCES };
499         }
500 
501         for (const auto& parkEntrance : gParkEntrances)
502         {
503             int32_t direction = direction_reverse(parkEntrance.direction);
504 
505             switch (footpath_is_connected_to_map_edge(parkEntrance, direction, 0))
506             {
507                 case FOOTPATH_SEARCH_NOT_FOUND:
508                     return { false, STR_PARK_ENTRANCE_WRONG_DIRECTION_OR_NO_PATH };
509                 case FOOTPATH_SEARCH_INCOMPLETE:
510                 case FOOTPATH_SEARCH_TOO_COMPLEX:
511                     return { false, STR_PARK_ENTRANCE_PATH_INCOMPLETE_OR_COMPLEX };
512                 case FOOTPATH_SEARCH_SUCCESS:
513                     // Run the search again and unown the path
514                     footpath_is_connected_to_map_edge(parkEntrance, direction, (1 << 5));
515                     break;
516             }
517         }
518 
519         if (gPeepSpawns.empty())
520         {
521             return { false, STR_PEEP_SPAWNS_NOT_SET };
522         }
523 
524         return { true, STR_NONE };
525     }
526 
GetSelectedObjectFlags(ObjectType objectType,size_t index)527     uint8_t GetSelectedObjectFlags(ObjectType objectType, size_t index)
528     {
529         uint8_t result = 0;
530         auto& list = _editorSelectedObjectFlags[EnumValue(objectType)];
531         if (list.size() > index)
532         {
533             result = list[index];
534         }
535         return result;
536     }
537 
ClearSelectedObject(ObjectType objectType,size_t index,uint32_t flags)538     void ClearSelectedObject(ObjectType objectType, size_t index, uint32_t flags)
539     {
540         auto& list = _editorSelectedObjectFlags[EnumValue(objectType)];
541         if (list.size() <= index)
542         {
543             list.resize(index + 1);
544         }
545         list[index] &= ~flags;
546     }
547 
SetSelectedObject(ObjectType objectType,size_t index,uint32_t flags)548     void SetSelectedObject(ObjectType objectType, size_t index, uint32_t flags)
549     {
550         auto& list = _editorSelectedObjectFlags[EnumValue(objectType)];
551         if (list.size() <= index)
552         {
553             list.resize(index + 1);
554         }
555         list[index] |= flags;
556     }
557 } // namespace Editor
558 
editor_open_windows_for_current_step()559 void editor_open_windows_for_current_step()
560 {
561     Editor::OpenWindowsForCurrentStep();
562 }
563