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