From 34128dc262cefd38911b7833ecc2ec5ea40dee69 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Wed, 27 Oct 2021 14:21:14 +0200 Subject: [PATCH] Add new .park save format Co-authored-by: Gymnasiast Co-authored-by: duncanspumpkin Co-authored-by: ZehMatt Co-authored-by: Broxzier --- CMakeLists.txt | 4 +- data/language/en-GB.txt | 6 +- distribution/openrct2.d.ts | 7 +- docs/save-format.md | 255 + openrct2.proj | 4 +- openrct2.targets | 10 +- shell.nix | 4 +- src/openrct2-ui/input/ShortcutIds.h | 2 +- src/openrct2-ui/input/ShortcutManager.cpp | 2 +- src/openrct2-ui/input/Shortcuts.cpp | 8 +- .../windows/EditorObjectSelection.cpp | 74 +- src/openrct2-ui/windows/Finances.cpp | 2 +- src/openrct2-ui/windows/Footpath.cpp | 95 +- src/openrct2-ui/windows/LoadSave.cpp | 10 +- src/openrct2-ui/windows/Map.cpp | 4 +- src/openrct2-ui/windows/Research.cpp | 2 +- src/openrct2-ui/windows/TileInspector.cpp | 180 +- src/openrct2-ui/windows/TitleMenu.cpp | 2 +- src/openrct2-ui/windows/TopToolbar.cpp | 2 +- src/openrct2/Context.cpp | 22 +- src/openrct2/Context.h | 6 +- src/openrct2/Editor.cpp | 63 +- src/openrct2/EditorObjectSelectionSession.cpp | 88 +- src/openrct2/FileClassifier.cpp | 33 + src/openrct2/FileClassifier.h | 2 + src/openrct2/Game.cpp | 6 +- src/openrct2/GameState.cpp | 3 + src/openrct2/ParkFile.cpp | 4593 +++++++++++++++++ src/openrct2/ParkFile.h | 22 + src/openrct2/ParkImporter.h | 1 + src/openrct2/ReplayManager.cpp | 24 +- src/openrct2/actions/RideCreateAction.cpp | 8 +- src/openrct2/actions/StaffHireNewAction.cpp | 7 - src/openrct2/actions/TileModifyAction.cpp | 10 +- src/openrct2/actions/TileModifyAction.h | 3 +- src/openrct2/actions/TrackDesignAction.cpp | 8 +- src/openrct2/cmdline/ConvertCommand.cpp | 32 +- src/openrct2/core/DataSerialiserTraits.h | 2 +- src/openrct2/core/String.hpp | 1 + src/openrct2/interface/InteractiveConsole.cpp | 11 +- src/openrct2/interface/Window.h | 37 +- src/openrct2/interface/Window_internal.h | 1 - src/openrct2/libopenrct2.vcxproj | 4 +- .../localisation/LocalisationService.cpp | 35 +- .../localisation/LocalisationService.h | 2 + src/openrct2/localisation/StringIds.h | 18 +- src/openrct2/management/Research.cpp | 157 +- src/openrct2/management/Research.h | 4 +- src/openrct2/network/NetworkBase.cpp | 241 +- src/openrct2/network/NetworkBase.h | 7 +- src/openrct2/object/DefaultObjects.cpp | 214 +- src/openrct2/object/DefaultObjects.h | 5 +- src/openrct2/object/FootpathObject.h | 5 + .../object/FootpathRailingsObject.cpp | 1 + src/openrct2/object/Object.cpp | 10 +- src/openrct2/object/Object.h | 1 - src/openrct2/object/ObjectLimits.h | 22 +- src/openrct2/object/ObjectList.cpp | 33 - src/openrct2/object/ObjectManager.cpp | 123 +- src/openrct2/object/ObjectManager.h | 2 +- src/openrct2/object/ObjectRepository.cpp | 6 +- src/openrct2/object/SmallSceneryObject.cpp | 4 +- src/openrct2/object/StationObject.cpp | 1 + src/openrct2/object/StationObject.h | 1 + .../paint/tile_element/Paint.Path.cpp | 12 +- .../paint/tile_element/Paint.TileElement.cpp | 29 +- src/openrct2/peep/Guest.cpp | 14 +- src/openrct2/peep/Staff.h | 1 - src/openrct2/platform/Crash.cpp | 34 +- src/openrct2/rct1/S4Importer.cpp | 357 +- src/openrct2/rct1/T4Importer.cpp | 11 +- src/openrct2/rct1/Tables.cpp | 1294 ++--- src/openrct2/rct1/Tables.h | 23 +- src/openrct2/rct12/RCT12.cpp | 59 + src/openrct2/rct12/RCT12.h | 2 + src/openrct2/rct2/RCT2.cpp | 2 +- src/openrct2/rct2/RCT2.h | 1 + src/openrct2/rct2/S6Exporter.cpp | 2127 -------- src/openrct2/rct2/S6Exporter.h | 84 - src/openrct2/rct2/S6Importer.cpp | 249 +- src/openrct2/ride/Ride.cpp | 48 +- src/openrct2/ride/Ride.h | 18 +- src/openrct2/ride/RideRatings.cpp | 2 +- src/openrct2/ride/TrackDesign.cpp | 28 +- src/openrct2/ride/TrackDesign.h | 1 - src/openrct2/ride/shops/meta/DrinkStall.h | 2 +- src/openrct2/ride/shops/meta/FoodStall.h | 2 +- src/openrct2/scenario/Scenario.cpp | 18 +- src/openrct2/scenario/Scenario.h | 3 +- src/openrct2/scenario/ScenarioRepository.cpp | 24 +- src/openrct2/scripting/Duktape.hpp | 13 + .../scripting/bindings/world/ScScenario.hpp | 2 +- .../bindings/world/ScTileElement.cpp | 218 +- .../bindings/world/ScTileElement.hpp | 13 +- src/openrct2/windows/tile_inspector.h | 1 - src/openrct2/world/Banner.h | 2 +- src/openrct2/world/Entity.h | 2 +- src/openrct2/world/Entrance.cpp | 17 + src/openrct2/world/Entrance.h | 3 +- src/openrct2/world/Footpath.h | 3 +- src/openrct2/world/Litter.cpp | 1 - src/openrct2/world/Map.h | 8 +- src/openrct2/world/MapGen.cpp | 26 +- src/openrct2/world/Scenery.cpp | 38 + src/openrct2/world/Scenery.h | 3 + src/openrct2/world/Surface.h | 1 + src/openrct2/world/TileElement.h | 16 +- src/openrct2/world/TileElementBase.cpp | 13 + src/openrct2/world/TileInspector.cpp | 108 +- src/openrct2/world/TileInspector.h | 2 +- test/tests/ReplayTests.cpp | 2 +- test/tests/S6ImportExportTests.cpp | 35 +- 112 files changed, 7281 insertions(+), 4243 deletions(-) create mode 100644 docs/save-format.md create mode 100644 src/openrct2/ParkFile.cpp create mode 100644 src/openrct2/ParkFile.h delete mode 100644 src/openrct2/rct2/S6Exporter.cpp delete mode 100644 src/openrct2/rct2/S6Exporter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bc6cf198d4..f8ecfca0c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,9 +61,9 @@ set(TITLE_SEQUENCE_VERSION "0.1.2c") set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v${TITLE_SEQUENCE_VERSION}/title-sequences.zip") set(TITLE_SEQUENCE_SHA1 "304d13a126c15bf2c86ff13b81a2f2cc1856ac8d") -set(OBJECTS_VERSION "1.0.21") +set(OBJECTS_VERSION "1.2.2") set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip") -set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5") +set(OBJECTS_SHA1 "a808fd47e9bc35d105dc371428a55888e6a86860") set(REPLAYS_VERSION "0.0.57") set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip") diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index e6b6e08d16..920483ad31 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -2226,7 +2226,6 @@ STR_3174 :This object is required by another object STR_3175 :This object is always required STR_3176 :Unable to select this object STR_3177 :Unable to de-select this object -STR_3178 :At least one path object must be selected STR_3179 :At least one ride vehicle/attraction object must be selected STR_3180 :Invalid selection of objects STR_3181 :Object Selection - {STRINGID} @@ -2237,7 +2236,7 @@ STR_3185 :Small Scenery STR_3186 :Large Scenery STR_3187 :Walls/Fences STR_3188 :Path Signs -STR_3189 :Footpaths +STR_3189 :Legacy footpaths STR_3190 :Path Extras STR_3191 :Scenery Groups STR_3192 :Park Entrance @@ -2833,8 +2832,6 @@ STR_5560 :Sets the inspection time to ‘Every 10 minutes’ on all rides STR_5561 :Failed to load language STR_5562 :WARNING! STR_5563 :This feature is currently unstable, take extra caution. -STR_5564 :Insert Corrupt Element -STR_5565 :Inserts a corrupt map element at top of tile. This will hide any element above the corrupt element. STR_5566 :Password: STR_5567 :Advertise STR_5568 :Password Required @@ -3532,7 +3529,6 @@ STR_6331 :Create ducks STR_6332 :Remove ducks STR_6333 :Increase scale factor STR_6334 :Decrease scale factor -STR_6335 :Tile Inspector: Insert corrupt element STR_6336 :Tile Inspector: Copy element STR_6337 :Tile Inspector: Paste element STR_6338 :Tile Inspector: Delete element diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index da94ea7000..0989682d11 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -362,7 +362,9 @@ declare global { "terrain_surface" | "terrain_edge" | "station" | - "music"; + "music" | + "footpath_surface" | + "footpath_railings"; type HookType = "interval.tick" | "interval.day" | @@ -623,6 +625,8 @@ declare global { type: "footpath"; object: number; + surfaceObject: number; + railingsObject: number; edges: number; corners: number; @@ -693,6 +697,7 @@ declare global { station: number; sequence: number; footpathObject: number; + footpathSurfaceObject: number; } interface LargeSceneryElement extends BaseTileElement { diff --git a/docs/save-format.md b/docs/save-format.md new file mode 100644 index 0000000000..161cc1e944 --- /dev/null +++ b/docs/save-format.md @@ -0,0 +1,255 @@ +# File + +All strings are null terminated UTF-8. + +Array32: + length: uint32 + element-size: uint32 + data: blob + + An element-size of 0 indicates varying. E.g. for strings. + +string-table: [] + lcode: string (E.g. "en-GB") + value: string + +## File + +Header: + magic: uint32 + target-version: uint32 + min-version: uint32 + num-chunks: uint32 + uncompressed-size: uint64 + compression: uint32 + sha1: byte[20] + +Chunks: + id: uint32 + offset: uint64 + length: uint64 + +## Chunks + +Authoring: + engine: string E.g. "openrct2 v0.1.2 (Linux)" + authors: string[] + notes: string + date-started: timestamp + date-modified: timestamp + +Objects: object[] + type: uint16 + id: string + version: string + +Scenario: + category: uint32 + name: string-table + park-name: string-table + details: string-table + objective-type: uint32 + objective-year: uint16 + objective-guests: uint32 + objective-rating: uint16 + objective-ride-excitement: uint16 + objective-ride-length: uint16 + objective-park-value: money32 + objective-ride-profit: money32 + objective-shop-profit: money32 + completed-company-value: money32 + completed-name: string + +General: + ticks: uint32 + elapsed-months: uint32 + current-day: uint16 + rand: uint32[2] + initial-cash: money32 + guest-initial-cash: money16 + guest-initial-hunger: uint8 + guest-initial-thirst: uint8 + guest-spawns: xyzd32 + land-price: money32 + construction-rights-price: money32 + +Interface: + main-viewport: + x: uint16 + y: uint16 + zoom: uint8 + rotation: uint8 + last-entrance-style: uint32 + +Climate: + climate: uint8 + climate-update-timer: uint16 + current: + weather: uint8 + temperature: uint8 + effect: uint8 + gloom: uint8 + rain-level: uint8 + next: + (same as above) + +Park: + name: string-id + cash: money32 + loan: money32 + loan-max: money32 + interest: uint16 + flags: uint64 + entrance-fee: money32 + rating: uint16 + rating-casualty-penalty: uint16 + current-expenditure: money32 + current-profit: money32 + total-admissions: uint32 + income-from-admissions: money32 + handyman-colour: uint8 + mechanic-colour: uint8 + security-colour: uint8 + campaigns: + weeks-left: uint16 + ride-index: uint32 + research-funding: uint8 + research-enabled: uint32 + research-progress-stage: uint8 + research-progress: uint16 + research-last-item: uint32 + research-next-item: uint32 + + rating-warning-days: uint16 + peep-warning-throttle: uint8[16] + awards: + + +History: + rating-history: uint16[] + guests-history: uint32[] + cash-history: money32[] + weekly-profit-history: money32[] + park-value-history: money32[] + expenditure-history: money32[][] + +Inventions: + + +Tiles: + map-size: xy32 + tile-elements: tile-element[] + +Things: + +Rides: + +Banners: + +Animations: + +Staff: + +Strings: string[] + +Editor: + step: uint8 + +Derived: + park-size: uint32 + guests-in-park: uint32 + guests-heading-for-park: uint32 + company-value: money32 + park-value: money32 + + +## Tile Element + +tile-element-base: + type: uint8 + flags: uint8 + base-z: uint8 + clear-z: uint8 + +surface-element: + slope: uint8 + water-height: uint8 + ownership: uint8 + grass-length: uint8 + surface-object-id: uint8 + edge-object-id: uint8 + (spare: 6) + +footpath-element: + object-id: uint16 + edges: uint8 + flags2: uint8 + addition: uint16 + addition-status: uint8 + station-index: uint8 + ride-index: uint32 + (spare: -2) + +track-element: + type: uint16 (straight, 25 deg up, brakes etc.) + sequence: uint8 + style: uint8 (wooden, intamin, b&m etc.) + station-index: uint8 + colour: uint8 + flags: uint8 (station / on-ride) + (spare: 5) + +track-element (maze): + type: uint16 + maze-entry: uint16 + (spare: 8) + +entrance-element: + object-id: uint16 + footpath-object-id: uint16 + ride-index: uint32 + station-index: uint8 + type: uint8 + (spare: 2) + +scenery-element: + object-id: uint32 + age: uint8 + colours: uint8[2] + (spare: 5) + +scenery-large-element: + object-id: uint32 + colour: uint8[3] + +wall-element: + object-id: uint32 + colours: uint8[3] + animation: uint8 + banner-index: uint32 + (spare: 0) + +banner-element: + object-id: uint16 + index: uint32 + flags: uint8 + position: uint8 + (spare: 4) + + +## Limits + +Ride index: uint32 +Banner index: uint32 +Station index: uint8 + +Ride object index: uint16 +Terrain (surface) object index: uint8 +Terrain (edge) object index: uint8 +Entrance object index: uint16 (can be for each type if necessary) +Footpath object index: uint16 +Footpath addition object index: uint16 +Scenery object index: uint32 +Scenery (large) object index: uint32 +Wall object index: uint32 +Banner object index: uint16 diff --git a/openrct2.proj b/openrct2.proj index 31b05e6561..d4913c96b9 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -46,8 +46,8 @@ 058b9df80244c03f1633cb06e9f70471a29ebb8e https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2c/title-sequences.zip 304d13a126c15bf2c86ff13b81a2f2cc1856ac8d - https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip - c38af45d51a6e440386180feacf76c64720b6ac5 + https://github.com/OpenRCT2/objects/releases/download/v1.2.2/objects.zip + a808fd47e9bc35d105dc371428a55888e6a86860 https://github.com/OpenRCT2/replays/releases/download/v0.0.57/replays.zip DF9C3B48755B19FDD4D0EC721007B98CD5B6F420 diff --git a/openrct2.targets b/openrct2.targets index 9a82f91fc6..dc3271132c 100644 --- a/openrct2.targets +++ b/openrct2.targets @@ -314,13 +314,15 @@ foreach (ZipArchiveEntry file in archive.Entries) { string fileName = Path.Combine(destinationDirectory, file.FullName); - if (file.Name == String.Empty) + string directory = Path.GetDirectoryName(fileName); + if (!Directory.Exists(directory)) { - string directory = Path.GetDirectoryName(fileName); Directory.CreateDirectory(directory); - continue; } - file.ExtractToFile(fileName, true); + if (file.Name != String.Empty) + { + file.ExtractToFile(fileName, true); + } } } ]]> diff --git a/shell.nix b/shell.nix index e935cc355c..2e0b444f59 100644 --- a/shell.nix +++ b/shell.nix @@ -15,8 +15,8 @@ let objects-src = pkgs.fetchFromGitHub { owner = "OpenRCT2"; repo = "objects"; - rev = "v1.0.21"; - sha256 = "b081f885311f9afebc41d9dd4a68b7db4cf736eb815c04e307e1a426f08cfa35"; + rev = "v1.2.2"; + sha256 = "2c77023068831c68423eb51f96251d1a06f58253414e4563ca17407d654ed96b"; }; title-sequences-src = pkgs.fetchFromGitHub { diff --git a/src/openrct2-ui/input/ShortcutIds.h b/src/openrct2-ui/input/ShortcutIds.h index 16417a30f7..5cf208fab5 100644 --- a/src/openrct2-ui/input/ShortcutIds.h +++ b/src/openrct2-ui/input/ShortcutIds.h @@ -100,7 +100,7 @@ namespace OpenRCT2::Ui::ShortcutId constexpr std::string_view WindowRideConstructionDemolish = "window.rideconstruction.demolish"; // Window / tile inspector - constexpr std::string_view WindowTileInspectorInsertCorrupt = "window.tileinspector.insert_corrupt"; + constexpr std::string_view WindowTileInspectorToggleInvisibility = "window.tileinspector.toggle_invisibility"; constexpr std::string_view WindowTileInspectorCopy = "window.tileinspector.copy"; constexpr std::string_view WindowTileInspectorPaste = "window.tileinspector.paste"; constexpr std::string_view WindowTileInspectorRemove = "window.tileinspector.remove"; diff --git a/src/openrct2-ui/input/ShortcutManager.cpp b/src/openrct2-ui/input/ShortcutManager.cpp index f7f24002fa..b6d59fa0db 100644 --- a/src/openrct2-ui/input/ShortcutManager.cpp +++ b/src/openrct2-ui/input/ShortcutManager.cpp @@ -427,7 +427,7 @@ std::string_view ShortcutManager::GetLegacyShortcutId(size_t index) ShortcutId::InterfaceSceneryPicker, ShortcutId::InterfaceScaleIncrease, ShortcutId::InterfaceScaleDecrease, - ShortcutId::WindowTileInspectorInsertCorrupt, + ShortcutId::WindowTileInspectorToggleInvisibility, ShortcutId::WindowTileInspectorCopy, ShortcutId::WindowTileInspectorPaste, ShortcutId::WindowTileInspectorRemove, diff --git a/src/openrct2-ui/input/Shortcuts.cpp b/src/openrct2-ui/input/Shortcuts.cpp index 087009bdcc..eed96334d6 100644 --- a/src/openrct2-ui/input/Shortcuts.cpp +++ b/src/openrct2-ui/input/Shortcuts.cpp @@ -533,9 +533,6 @@ static void ShortcutIncreaseElementHeight() case WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_BANNER: action = WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE; break; - case WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_CORRUPT: - action = WC_TILE_INSPECTOR__WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE; - break; case TileInspectorPage::Default: break; } @@ -577,9 +574,6 @@ static void ShortcutDecreaseElementHeight() case WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_BANNER: action = WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE; break; - case WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_CORRUPT: - action = WC_TILE_INSPECTOR__WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE; - break; case TileInspectorPage::Default: break; } @@ -857,7 +851,7 @@ void ShortcutManager::RegisterDefaultShortcuts() RegisterShortcut(ShortcutId::WindowRideConstructionBuild, STR_SHORTCUT_CONSTRUCTION_BUILD_CURRENT, "NUMPAD 0", []() { ShortcutConstructionBuildCurrent(); }); RegisterShortcut(ShortcutId::WindowRideConstructionDemolish, STR_SHORTCUT_CONSTRUCTION_DEMOLISH_CURRENT, "NUMPAD -", []() { ShortcutConstructionDemolishCurrent(); }); - RegisterShortcut(ShortcutId::WindowTileInspectorInsertCorrupt, STR_SHORTCUT_INSERT_CORRPUT_ELEMENT, []() { TileInspectorMouseUp(WC_TILE_INSPECTOR__WIDX_BUTTON_CORRUPT); }); + RegisterShortcut(ShortcutId::WindowTileInspectorToggleInvisibility, STR_SHORTCUT_TOGGLE_INVISIBILITY, []() { TileInspectorMouseUp(WC_TILE_INSPECTOR__WIDX_BUTTON_TOGGLE_INVISIBILITY); }); RegisterShortcut(ShortcutId::WindowTileInspectorCopy, STR_SHORTCUT_COPY_ELEMENT, []() { TileInspectorMouseUp(WC_TILE_INSPECTOR__WIDX_BUTTON_COPY); }); RegisterShortcut(ShortcutId::WindowTileInspectorPaste, STR_SHORTCUT_PASTE_ELEMENT, []() { TileInspectorMouseUp(WC_TILE_INSPECTOR__WIDX_BUTTON_PASTE); }); RegisterShortcut(ShortcutId::WindowTileInspectorRemove, STR_SHORTCUT_REMOVE_ELEMENT, []() { TileInspectorMouseUp(WC_TILE_INSPECTOR__WIDX_BUTTON_REMOVE); }); diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 704c6af43c..1804a7bdcd 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -86,7 +86,7 @@ static char _filter_string[MAX_PATH]; static constexpr const rct_string_id WINDOW_TITLE = STR_OBJECT_SELECTION; static constexpr const int32_t WH = 400; -static constexpr const int32_t WW = 600; +static constexpr const int32_t WW = 755; struct ObjectPageDesc { @@ -101,19 +101,21 @@ static constexpr const ObjectPageDesc ObjectSelectionPages[] = { { STR_OBJECT_SELECTION_LARGE_SCENERY, SPR_TAB_SCENERY_URBAN, true }, { STR_OBJECT_SELECTION_WALLS_FENCES, SPR_TAB_SCENERY_WALLS, true }, { STR_OBJECT_SELECTION_PATH_SIGNS, SPR_TAB_SCENERY_SIGNAGE, true }, - { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, false }, + { STR_OBJECT_SELECTION_FOOTPATHS, SPR_TAB_SCENERY_PATHS, true }, { STR_OBJECT_SELECTION_PATH_EXTRAS, SPR_TAB_SCENERY_PATH_ITEMS, false }, { STR_OBJECT_SELECTION_SCENERY_GROUPS, SPR_TAB_SCENERY_STATUES, false }, { STR_OBJECT_SELECTION_PARK_ENTRANCE, SPR_TAB_PARK, false }, { STR_OBJECT_SELECTION_WATER, SPR_TAB_WATER, false }, - // Currently hidden until new save format arrives: - // { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, true }, - // { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, true }, - // { STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, true }, - // { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false }, - // { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, SPR_TAB_SCENERY_PATHS, false }, - // { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, SPR_G2_PATH_RAILINGS_TAB, false }, + // Dummy place holder for string objects + { STR_NONE, static_cast(SPR_NONE), false }, + + { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, true }, + { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, true }, + { STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, true }, + { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false }, + { STR_OBJECT_SELECTION_FOOTPATH_SURFACES, SPR_TAB_SCENERY_PATHS, false }, + { STR_OBJECT_SELECTION_FOOTPATH_RAILINGS, SPR_G2_PATH_RAILINGS_TAB, false }, }; #pragma region Widgets @@ -258,7 +260,6 @@ enum struct list_item { const ObjectRepositoryItem* repositoryItem; - rct_object_entry* entry; std::unique_ptr filter; uint8_t* flags; }; @@ -305,8 +306,7 @@ static void visible_list_refresh(rct_window* w) { uint8_t selectionFlags = _objectSelectionFlags[i]; const ObjectRepositoryItem* item = &items[i]; - ObjectType objectType = item->ObjectEntry.GetType(); - if (objectType == get_selected_object_type(w) && !(selectionFlags & OBJECT_SELECTION_FLAG_6) && filter_source(item) + if (item->Type == get_selected_object_type(w) && !(selectionFlags & OBJECT_SELECTION_FLAG_6) && filter_source(item) && filter_string(item) && filter_chunks(item) && filter_selected(selectionFlags)) { auto filter = std::make_unique(); @@ -316,7 +316,6 @@ static void visible_list_refresh(rct_window* w) list_item currentListItem; currentListItem.repositoryItem = item; - currentListItem.entry = const_cast(&item->ObjectEntry); currentListItem.filter = std::move(filter); currentListItem.flags = &_objectSelectionFlags[i]; _listItems.push_back(std::move(currentListItem)); @@ -403,7 +402,6 @@ rct_window* window_editor_object_selection_open() window->selected_tab = 0; window->selected_list_item = -1; - window->object_entry = nullptr; window->min_width = WW; window->min_height = WH; window->max_width = 1200; @@ -478,7 +476,6 @@ static void window_editor_object_selection_mouseup(rct_window* w, rct_widgetinde visible_list_refresh(w); w->selected_list_item = -1; - w->object_entry = nullptr; w->scrolls[0].v_top = 0; w->Invalidate(); break; @@ -497,7 +494,6 @@ static void window_editor_object_selection_mouseup(rct_window* w, rct_widgetinde visible_list_refresh(w); w->selected_list_item = -1; - w->object_entry = nullptr; w->scrolls[0].v_top = 0; w->frame_no = 0; w->Invalidate(); @@ -766,15 +762,15 @@ static void window_editor_object_selection_scroll_mouseover( _loadedObject = nullptr; } - if (selectedObject == -1) - { - w->object_entry = nullptr; - } - else + if (selectedObject != -1) { auto listItem = &_listItems[selectedObject]; - w->object_entry = listItem->entry; - _loadedObject = object_repository_load_object(listItem->entry); + auto& objRepository = OpenRCT2::GetContext()->GetObjectRepository(); + _loadedObject = objRepository.LoadObject(listItem->repositoryItem); + if (_loadedObject != nullptr) + { + _loadedObject->Load(); + } } w->Invalidate(); @@ -857,7 +853,8 @@ static void window_editor_object_selection_invalidate(rct_window* w) for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { auto& widget = w->widgets[WIDX_TAB_1 + i]; - if (!advancedMode && ObjectSelectionPages[i].IsAdvanced) + if ((!advancedMode && ObjectSelectionPages[i].IsAdvanced) + || ObjectSelectionPages[i].Image == static_cast(SPR_NONE)) { widget.type = WindowWidgetType::Empty; } @@ -1214,8 +1211,9 @@ static void window_editor_object_selection_scrollpaint(rct_window* w, rct_drawpi gfx_clear(dpi, paletteIndex); screenCoords.y = 0; - for (const auto& listItem : _listItems) + for (size_t i = 0; i < _listItems.size(); i++) { + const auto& listItem = _listItems[i]; if (screenCoords.y + SCROLLABLE_ROW_HEIGHT >= dpi->y && screenCoords.y <= dpi->y + dpi->height) { // Draw checkbox @@ -1224,7 +1222,7 @@ static void window_editor_object_selection_scrollpaint(rct_window* w, rct_drawpi dpi, { { 2, screenCoords.y }, { 11, screenCoords.y + 10 } }, w->colours[1], INSET_RECT_F_E0); // Highlight background - auto highlighted = listItem.entry == w->object_entry && !(*listItem.flags & OBJECT_SELECTION_FLAG_6); + auto highlighted = i == static_cast(w->selected_list_item) && !(*listItem.flags & OBJECT_SELECTION_FLAG_6); if (highlighted) { auto bottom = screenCoords.y + (SCROLLABLE_ROW_HEIGHT - 1); @@ -1296,7 +1294,6 @@ static void window_editor_object_set_page(rct_window* w, int32_t page) w->selected_tab = page; w->selected_list_item = -1; - w->object_entry = nullptr; w->scrolls[0].v_top = 0; w->frame_no = 0; @@ -1371,26 +1368,27 @@ static void window_editor_object_selection_manage_tracks() */ static void editor_load_selected_objects() { + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); int32_t numItems = static_cast(object_repository_get_items_count()); const ObjectRepositoryItem* items = object_repository_get_items(); for (int32_t i = 0; i < numItems; i++) { if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { - const ObjectRepositoryItem* item = &items[i]; - const rct_object_entry* entry = &item->ObjectEntry; - const auto* loadedObject = object_manager_get_loaded_object(ObjectEntryDescriptor(*item)); + const auto* item = &items[i]; + auto descriptor = ObjectEntryDescriptor(*item); + const auto* loadedObject = objManager.GetLoadedObject(descriptor); if (loadedObject == nullptr) { - loadedObject = object_manager_load_object(entry); + loadedObject = objManager.LoadObject(descriptor); if (loadedObject == nullptr) { - log_error("Failed to load entry %.8s", entry->name); + log_error("Failed to load entry %s", std::string(descriptor.GetName()).c_str()); } else if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) { // Defaults selected items to researched (if in-game) - ObjectType objectType = entry->GetType(); + auto objectType = loadedObject->GetObjectType(); auto entryIndex = object_manager_get_loaded_object_entry_index(loadedObject); if (objectType == ObjectType::Ride) { @@ -1493,7 +1491,7 @@ static bool filter_string(const ObjectRepositoryItem* item) // Check if the searched string exists in the name, ride type, or filename bool inName = nameUpper.find(filterUpper) != std::string::npos; - bool inRideType = (item->ObjectEntry.GetType() == ObjectType::Ride) && typeUpper.find(filterUpper) != std::string::npos; + bool inRideType = (item->Type == ObjectType::Ride) && typeUpper.find(filterUpper) != std::string::npos; bool inPath = pathUpper.find(filterUpper) != std::string::npos; return inName || inRideType || inPath; @@ -1536,7 +1534,7 @@ static bool filter_source(const ObjectRepositoryItem* item) static bool filter_chunks(const ObjectRepositoryItem* item) { - if (item->ObjectEntry.GetType() == ObjectType::Ride) + if (item->Type == ObjectType::Ride) { uint8_t rideType = 0; for (int32_t i = 0; i < MAX_RIDE_TYPES_PER_RIDE_ENTRY; i++) @@ -1566,8 +1564,7 @@ static void filter_update_counts() const ObjectRepositoryItem* item = &items[i]; if (filter_source(item) && filter_string(item) && filter_chunks(item) && filter_selected(selectionFlags[i])) { - ObjectType objectType = item->ObjectEntry.GetType(); - _filter_object_counts[EnumValue(objectType)]++; + _filter_object_counts[EnumValue(item->Type)]++; } } } @@ -1605,8 +1602,5 @@ static std::string object_get_description(const Object* object) static ObjectType get_selected_object_type(rct_window* w) { auto tab = w->selected_tab; - if (tab >= EnumValue(ObjectType::ScenarioText)) - return static_cast(tab + 1); - return static_cast(tab); } diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 385dade6c2..551b486ec1 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -387,7 +387,7 @@ rct_window* window_finances_open() w->number = 0; w->frame_no = 0; - research_update_uncompleted_types(); + ResearchUpdateUncompletedTypes(); } w->page = WINDOW_FINANCES_PAGE_SUMMARY; diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index fec970f248..2e6129738d 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -31,7 +31,7 @@ #include static constexpr const rct_string_id WINDOW_TITLE = STR_FOOTPATHS; -static constexpr const int32_t WH = 381; +static constexpr const int32_t WH = 421; static constexpr const int32_t WW = 106; static constexpr const uint16_t ARROW_PULSE_DURATION = 200; @@ -60,6 +60,7 @@ enum WINDOW_FOOTPATH_WIDGET_IDX WIDX_TYPE_GROUP, WIDX_FOOTPATH_TYPE, WIDX_QUEUELINE_TYPE, + WIDX_RAILINGS_TYPE, WIDX_DIRECTION_GROUP, WIDX_DIRECTION_NW, @@ -83,29 +84,30 @@ static rct_widget window_footpath_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), // Type group - MakeWidget({ 3, 17}, {100, 55}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_TYPE ), + MakeWidget({ 3, 17}, {100, 95}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_TYPE ), MakeWidget({ 6, 30}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_FOOTPATH_TIP ), MakeWidget({53, 30}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_QUEUE_LINE_PATH_TIP ), + MakeWidget({29, 69}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_FOOTPATH_TIP ), // Direction group - MakeWidget({ 3, 75}, {100, 77}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_DIRECTION ), - MakeWidget({53, 87}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NE, STR_DIRECTION_TIP ), - MakeWidget({53, 116}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SE, STR_DIRECTION_TIP ), - MakeWidget({ 8, 116}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SW, STR_DIRECTION_TIP ), - MakeWidget({ 8, 87}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NW, STR_DIRECTION_TIP ), + MakeWidget({ 3, 115}, {100, 77}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_DIRECTION ), + MakeWidget({53, 127}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NE, STR_DIRECTION_TIP ), + MakeWidget({53, 156}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SE, STR_DIRECTION_TIP ), + MakeWidget({ 8, 156}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_SW, STR_DIRECTION_TIP ), + MakeWidget({ 8, 127}, { 45, 29}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_DIRECTION_NW, STR_DIRECTION_TIP ), // Slope group - MakeWidget({ 3, 155}, {100, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_SLOPE ), - MakeWidget({17, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_DOWN, STR_SLOPE_DOWN_TIP ), - MakeWidget({41, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_LEVEL, STR_LEVEL_TIP ), - MakeWidget({65, 167}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_UP, STR_SLOPE_UP_TIP ), - MakeWidget({ 8, 202}, { 90, 90}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP), - MakeWidget({30, 295}, { 46, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH_CURRENT_SECTION, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP ), + MakeWidget({ 3, 195}, {100, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_SLOPE ), + MakeWidget({17, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_DOWN, STR_SLOPE_DOWN_TIP ), + MakeWidget({41, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_LEVEL, STR_LEVEL_TIP ), + MakeWidget({65, 207}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_RIDE_CONSTRUCTION_SLOPE_UP, STR_SLOPE_UP_TIP ), + MakeWidget({ 8, 242}, { 90, 90}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP), + MakeWidget({30, 335}, { 46, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH_CURRENT_SECTION, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP ), // Mode group - MakeWidget({ 3, 321}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ), - MakeWidget({13, 332}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_LAND, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ), - MakeWidget({57, 332}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_BRIDGE, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ), + MakeWidget({ 3, 361}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ), + MakeWidget({13, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_LAND, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ), + MakeWidget({57, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_CONSTRUCTION_FOOTPATH_BRIDGE, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ), WIDGETS_END, }; @@ -172,6 +174,7 @@ static constexpr const uint8_t ConstructionPreviewImages[][4] = { static void window_footpath_mousedown_direction(int32_t direction); static void window_footpath_mousedown_slope(int32_t slope); static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget* widget, bool showQueues); +static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget* widget); static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY& screenCoords); static void window_footpath_set_selection_start_bridge_at_point(const ScreenCoordsXY& screenCoords); static void window_footpath_place_path_at_point(const ScreenCoordsXY& screenCoords); @@ -204,9 +207,10 @@ rct_window* window_footpath_open() window = WindowCreate(ScreenCoordsXY(0, 29), WW, WH, &window_footpath_events, WC_FOOTPATH, 0); window->widgets = window_footpath_widgets; window->enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_FOOTPATH_TYPE) | (1ULL << WIDX_QUEUELINE_TYPE) - | (1ULL << WIDX_DIRECTION_NW) | (1ULL << WIDX_DIRECTION_NE) | (1ULL << WIDX_DIRECTION_SW) | (1ULL << WIDX_DIRECTION_SE) - | (1ULL << WIDX_SLOPEDOWN) | (1ULL << WIDX_LEVEL) | (1ULL << WIDX_SLOPEUP) | (1ULL << WIDX_CONSTRUCT) - | (1ULL << WIDX_REMOVE) | (1ULL << WIDX_CONSTRUCT_ON_LAND) | (1ULL << WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL); + | (1ULL << WIDX_RAILINGS_TYPE) | (1ULL << WIDX_DIRECTION_NW) | (1ULL << WIDX_DIRECTION_NE) | (1ULL << WIDX_DIRECTION_SW) + | (1ULL << WIDX_DIRECTION_SE) | (1ULL << WIDX_SLOPEDOWN) | (1ULL << WIDX_LEVEL) | (1ULL << WIDX_SLOPEUP) + | (1ULL << WIDX_CONSTRUCT) | (1ULL << WIDX_REMOVE) | (1ULL << WIDX_CONSTRUCT_ON_LAND) + | (1ULL << WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL); WindowInitScrollWidgets(window); window_push_others_right(window); @@ -304,6 +308,9 @@ static void window_footpath_mousedown(rct_window* w, rct_widgetindex widgetIndex case WIDX_QUEUELINE_TYPE: window_footpath_show_footpath_types_dialog(w, widget, true); break; + case WIDX_RAILINGS_TYPE: + window_footpath_show_railings_types_dialog(w, widget); + break; case WIDX_DIRECTION_NW: window_footpath_mousedown_direction(0); break; @@ -364,6 +371,10 @@ static void window_footpath_dropdown(rct_window* w, rct_widgetindex widgetIndex, gFootpathSelection.QueueSurface = entryIndex.second; } } + else if (widgetIndex == WIDX_RAILINGS_TYPE) + { + gFootpathSelection.Railings = entryIndex.second; + } else { return; @@ -573,6 +584,16 @@ static void window_footpath_invalidate(rct_window* w) window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage; window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage; + + // Set railing + auto railingsImage = static_cast(SPR_NONE); + auto railingsEntry = GetPathRailingsEntry(gFootpathSelection.Railings); + if (railingsEntry != nullptr) + { + railingsImage = railingsEntry->PreviewImageId; + } + window_footpath_widgets[WIDX_RAILINGS_TYPE].image = railingsImage; + window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::FlatBtn; } else { @@ -592,6 +613,9 @@ static void window_footpath_invalidate(rct_window* w) window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage; window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = queueImage; + + // Hide railing button + window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::Empty; } } @@ -749,6 +773,39 @@ static void window_footpath_show_footpath_types_dialog(rct_window* w, rct_widget gDropdownDefaultIndex = static_cast(*defaultIndex); } +static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget* widget) +{ + uint32_t numRailingsTypes = 0; + // If the game is in sandbox mode, also show paths that are normally restricted to the scenario editor + + _dropdownEntries.clear(); + std::optional defaultIndex; + for (int32_t i = 0; i < MAX_FOOTPATH_RAILINGS_OBJECTS; i++) + { + const auto* railingsEntry = GetPathRailingsEntry(i); + if (railingsEntry == nullptr) + { + continue; + } + if (i == gFootpathSelection.Railings) + { + defaultIndex = numRailingsTypes; + } + + gDropdownItemsFormat[numRailingsTypes] = STR_NONE; + gDropdownItemsArgs[numRailingsTypes] = railingsEntry->PreviewImageId; + _dropdownEntries.push_back({ ObjectType::FootpathRailings, i }); + numRailingsTypes++; + } + + auto itemsPerRow = DropdownGetAppropriateImageDropdownItemsPerRow(numRailingsTypes); + WindowDropdownShowImage( + w->windowPos.x + widget->left, w->windowPos.y + widget->top, widget->height() + 1, w->colours[1], 0, numRailingsTypes, + 47, 36, itemsPerRow); + if (defaultIndex) + gDropdownDefaultIndex = static_cast(*defaultIndex); +} + /** * * rct2: 0x006A8111 0x006A8135 0x006A815C 0x006A8183 diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index 88a50c50d3..0037b3d7e2 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -201,13 +201,13 @@ static const char* getFilterPatternByType(const int32_t type, const bool isSave) switch (type & 0x0E) { case LOADSAVETYPE_GAME: - return isSave ? "*.sv6" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7;*.sea;"; + return isSave ? "*.park" : "*.park;*.sv6;*.sc6;*.sc4;*.sv4;*.sv7;*.sea"; case LOADSAVETYPE_LANDSCAPE: - return isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7;*.sea;"; + return isSave ? "*.park" : "*.park;*.sc6;*.sv6;*.sc4;*.sv4;*.sv7;*.sea"; case LOADSAVETYPE_SCENARIO: - return "*.sc6"; + return isSave ? "*.park" : "*.park;*.sc6;*.sc4"; case LOADSAVETYPE_TRACK: return isSave ? "*.td6" : "*.td6;*.td4"; @@ -1041,7 +1041,7 @@ static void window_loadsave_select(rct_window* w, const char* path) case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE): save_path(&gConfigGeneral.last_save_landscape_directory, pathBuffer); - safe_strcpy(gScenarioFileName, pathBuffer, sizeof(gScenarioFileName)); + gScenarioFileName = std::string(String::ToStringView(pathBuffer, std::size(pathBuffer))); if (scenario_save(pathBuffer, gConfigGeneral.save_plugin_data ? 3 : 2)) { gCurrentLoadedPath = pathBuffer; @@ -1062,7 +1062,7 @@ static void window_loadsave_select(rct_window* w, const char* path) int32_t parkFlagsBackup = gParkFlags; gParkFlags &= ~PARK_FLAGS_SPRITES_INITIALISED; gEditorStep = EditorStep::Invalid; - safe_strcpy(gScenarioFileName, pathBuffer, sizeof(gScenarioFileName)); + gScenarioFileName = std::string(String::ToStringView(pathBuffer, std::size(pathBuffer))); int32_t success = scenario_save(pathBuffer, gConfigGeneral.save_plugin_data ? 3 : 2); gParkFlags = parkFlagsBackup; diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index 07036740e2..530bdc8fa6 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -1405,7 +1405,6 @@ static constexpr const uint16_t ElementTypeMaskColour[] = { 0xFFFF, // TILE_ELEMENT_TYPE_WALL 0x0000, // TILE_ELEMENT_TYPE_LARGE_SCENERY 0xFFFF, // TILE_ELEMENT_TYPE_BANNER - 0x0000, // TILE_ELEMENT_TYPE_CORRUPT }; static constexpr const uint16_t ElementTypeAddColour[] = { @@ -1417,7 +1416,6 @@ static constexpr const uint16_t ElementTypeAddColour[] = { MapColour(PALETTE_INDEX_0), // TILE_ELEMENT_TYPE_WALL MapColour(PALETTE_INDEX_99), // TILE_ELEMENT_TYPE_LARGE_SCENERY MapColour(PALETTE_INDEX_0), // TILE_ELEMENT_TYPE_BANNER - MapColour(PALETTE_INDEX_68), // TILE_ELEMENT_TYPE_CORRUPT }; static uint16_t map_window_get_pixel_colour_peep(const CoordsXY& c) @@ -1445,7 +1443,7 @@ static uint16_t map_window_get_pixel_colour_peep(const CoordsXY& c) int32_t tileElementType = tileElement->GetType() >> 2; if (tileElementType >= maxSupportedTileElementType) { - tileElementType = TILE_ELEMENT_TYPE_CORRUPT >> 2; + tileElementType = TILE_ELEMENT_TYPE_SURFACE >> 2; } colour &= ElementTypeMaskColour[tileElementType]; colour |= ElementTypeAddColour[tileElementType]; diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index 7c7aec69ce..df7b6a9f3c 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -193,7 +193,7 @@ rct_window* window_research_open() w->page = 0; w->frame_no = 0; w->disabled_widgets = 0; - research_update_uncompleted_types(); + ResearchUpdateUncompletedTypes(); } w->page = 0; diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index cf5c607086..54f259cc1b 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -65,7 +68,7 @@ enum WINDOW_TILE_INSPECTOR_WIDGET_IDX WIDX_SPINNER_Y, WIDX_SPINNER_Y_INCREASE, WIDX_SPINNER_Y_DECREASE, - WIDX_BUTTON_CORRUPT, + WIDX_BUTTON_INVISIBLE, WIDX_BUTTON_REMOVE, WIDX_BUTTON_MOVE_UP, WIDX_BUTTON_MOVE_DOWN, @@ -77,6 +80,7 @@ enum WINDOW_TILE_INSPECTOR_WIDGET_IDX WIDX_COLUMN_BASEHEIGHT, WIDX_COLUMN_CLEARANCEHEIGHT, WIDX_COLUMN_DIRECTION, + WIDX_COLUMN_INVISIBLE, WIDX_COLUMN_GHOSTFLAG, WIDX_COLUMN_LASTFLAG, WIDX_GROUPBOX_DETAILS, @@ -162,12 +166,6 @@ enum WINDOW_TILE_INSPECTOR_WIDGET_IDX WIDX_BANNER_CHECK_BLOCK_SE, WIDX_BANNER_CHECK_BLOCK_SW, WIDX_BANNER_CHECK_BLOCK_NW, - - // Corrupt - WIDX_CORRUPT_SPINNER_HEIGHT = PAGE_WIDGETS, - WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE, - WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE, - WIDX_CORRUPT_BUTTON_CLAMP, }; static constexpr const rct_string_id WINDOW_TITLE = STR_TILE_INSPECTOR_TITLE; @@ -188,14 +186,16 @@ constexpr auto ToolbarButtonOffsetX = ScreenSize{ -24, 0 }; // List's column offsets constexpr auto TypeColumnXY = ScreenCoordsXY{ 3, 42 }; -constexpr auto TypeColumnSize = ScreenSize{ 272, 14 }; +constexpr auto TypeColumnSize = ScreenSize{ 257, 14 }; constexpr auto BaseHeightColumnXY = TypeColumnXY + ScreenSize{ TypeColumnSize.width, 0 }; constexpr auto BaseHeightColumnSize = ScreenSize{ 30, 14 }; constexpr auto ClearanceHeightColumnXY = BaseHeightColumnXY + ScreenCoordsXY{ BaseHeightColumnSize.width, 0 }; constexpr auto ClearanceHeightColumnSize = ScreenSize{ 30, 14 }; constexpr auto DirectionColumnXY = ClearanceHeightColumnXY + ScreenCoordsXY{ ClearanceHeightColumnSize.width, 0 }; constexpr auto DirectionColumnSize = ScreenSize{ 15, 14 }; -constexpr auto GhostFlagColumnXY = DirectionColumnXY + ScreenCoordsXY{ DirectionColumnSize.width, 0 }; +constexpr auto InvisibleFlagColumnXY = DirectionColumnXY + ScreenCoordsXY{ DirectionColumnSize.width, 0 }; +constexpr auto InvisibleFlagColumnSize = ScreenSize{ 15, 14 }; +constexpr auto GhostFlagColumnXY = InvisibleFlagColumnXY + ScreenCoordsXY{ InvisibleFlagColumnSize.width, 0 }; constexpr auto GhostFlagColumnSize = ScreenSize{ 15, 14 }; constexpr auto LastFlagColumnXY = GhostFlagColumnXY + ScreenCoordsXY{ GhostFlagColumnSize.width, 0 }; constexpr auto LastFlagColumnSize = ScreenSize{ 32, 14 }; @@ -232,7 +232,7 @@ constexpr ScreenCoordsXY CheckboxGroupOffset( MakeSpinnerWidgets({20, 23}, {51, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), /* Spinner X (3 widgets) */ \ MakeSpinnerWidgets({90, 23}, {51, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), /* Spinner Y (3 widgets) */ \ /* Top buttons */ \ - MakeWidget(ToolbarButtonAnchor, ToolbarButtonSize, WindowWidgetType::FlatBtn , WindowColour::Secondary, SPR_MAP, STR_INSERT_CORRUPT_TIP), /* Insert corrupt button */ \ + MakeWidget(ToolbarButtonAnchor, ToolbarButtonSize, WindowWidgetType::FlatBtn , WindowColour::Secondary, SPR_MAP, STR_TILE_INSPECTOR_TOGGLE_INVISIBILITY_TIP), /* Toggle invisibility button */ \ MakeWidget(ToolbarButtonAnchor + ToolbarButtonOffsetX * 1, ToolbarButtonSize, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH, STR_REMOVE_SELECTED_ELEMENT_TIP ), /* Remove button */ \ MakeWidget(ToolbarButtonAnchor + ToolbarButtonOffsetX * 2, ToolbarButtonHalfSize, WindowWidgetType::Button, WindowColour::Secondary, STR_UP, STR_MOVE_SELECTED_ELEMENT_UP_TIP), /* Move up */ \ MakeWidget(ToolbarButtonAnchor + ToolbarButtonOffsetX * 2 + ScreenSize{0, 12}, ToolbarButtonHalfSize, WindowWidgetType::Button, WindowColour::Secondary, STR_DOWN, STR_MOVE_SELECTED_ELEMENT_DOWN_TIP), /* Move down */ \ @@ -245,6 +245,7 @@ constexpr ScreenCoordsXY CheckboxGroupOffset( MakeWidget(BaseHeightColumnXY, BaseHeightColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_BASE_HEIGHT_SHORT, STR_TILE_INSPECTOR_BASE_HEIGHT), /* Base height */ \ MakeWidget(ClearanceHeightColumnXY, ClearanceHeightColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_CLEARANGE_HEIGHT_SHORT, STR_TILE_INSPECTOR_CLEARANCE_HEIGHT), /* Clearance height */ \ MakeWidget(DirectionColumnXY, DirectionColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_DIRECTION_SHORT, STR_TILE_INSPECTOR_DIRECTION), /* Direction */ \ + MakeWidget(InvisibleFlagColumnXY, InvisibleFlagColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_INVISIBLE_SHORT, STR_TILE_INSPECTOR_FLAG_INVISIBLE), /* Invisible flag */ \ MakeWidget(GhostFlagColumnXY, GhostFlagColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_FLAG_GHOST_SHORT, STR_TILE_INSPECTOR_FLAG_GHOST), /* Ghost flag */ \ MakeWidget(LastFlagColumnXY, LastFlagColumnSize, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_TILE_INSPECTOR_FLAG_LAST_SHORT, STR_TILE_INSPECTOR_FLAG_LAST), /* Last of tile flag */ \ /* Group boxes */ \ @@ -274,7 +275,7 @@ static rct_widget SurfaceWidgets[] = { }; constexpr int32_t NumPathProperties = 5; -constexpr int32_t NumPathDetails = 2; +constexpr int32_t NumPathDetails = 3; constexpr int32_t PathPropertiesHeight = 16 + NumPathProperties * 21; constexpr int32_t PathDetailsHeight = 20 + NumPathDetails * 11; static rct_widget PathWidgets[] = { @@ -374,17 +375,6 @@ static rct_widget BannerWidgets[] = { WIDGETS_END, }; -constexpr int32_t NumCorruptProperties = 2; -constexpr int32_t NumCorruptDetails = 0; -constexpr int32_t CorruptPropertiesHeight = 16 + NumCorruptProperties * 21; -constexpr int32_t CorruptDetailsHeight = 20 + NumCorruptDetails * 11; -static rct_widget CorruptWidgets[] = { - MAIN_TILE_INSPECTOR_WIDGETS, - MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_CORRUPT_SPINNER_HEIGHT - MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyButtonSize, WindowWidgetType::Button, WindowColour::Secondary,STR_TILE_INSPECTOR_CLAMP_TO_NEXT, STR_TILE_INSPECTOR_CLAMP_TO_NEXT_TIP ), // WIDX_CORRUPT_BUTTON_CLAMP - WIDGETS_END, -}; - static rct_widget *PageWidgets[] = { DefaultWidgets, SurfaceWidgets, @@ -395,7 +385,6 @@ static rct_widget *PageWidgets[] = { WallWidgets, LargeSceneryWidgets, BannerWidgets, - CorruptWidgets, }; // clang-format on @@ -430,7 +419,6 @@ static constexpr TileInspectorGroupboxSettings PageGroupBoxSettings[] = { MakeGroupboxSettings(WallDetailsHeight, WallPropertiesHeight, STR_TILE_INSPECTOR_GROUPBOX_WALL_INFO), MakeGroupboxSettings(LargeSceneryDetailsHeight, LargeSceneryPropertiesHeight, STR_TILE_INSPECTOR_GROUPBOX_BANNER_INFO), MakeGroupboxSettings(BannerDetailsHeight, BannerPropertiesHeight, STR_TILE_INSPECTOR_GROUPBOX_BANNER_INFO), - MakeGroupboxSettings(CorruptDetailsHeight, CorruptPropertiesHeight, STR_TILE_INSPECTOR_GROUPBOX_CORRUPT_INFO), }; static constexpr int32_t ViewportInteractionFlags = EnumsToFlags( @@ -487,16 +475,15 @@ static rct_window_event_list TileInspectorWindowEvents([](auto& events) { // clang-format off static uint64_t PageEnabledWidgets[] = { - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_SURFACE_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_SURFACE_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_SURFACE_BUTTON_REMOVE_FENCES) | (1ULL << WIDX_SURFACE_BUTTON_RESTORE_FENCES) | (1ULL << WIDX_SURFACE_CHECK_CORNER_N) | (1ULL << WIDX_SURFACE_CHECK_CORNER_E) | (1ULL << WIDX_SURFACE_CHECK_CORNER_S) | (1ULL << WIDX_SURFACE_CHECK_CORNER_W) | (1ULL << WIDX_SURFACE_CHECK_DIAGONAL), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_PATH_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_PATH_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_PATH_CHECK_SLOPED) | (1ULL << WIDX_PATH_CHECK_BROKEN) | (1ULL << WIDX_PATH_CHECK_EDGE_N) | (1ULL << WIDX_PATH_CHECK_EDGE_NE) | (1ULL << WIDX_PATH_CHECK_EDGE_E) | (1ULL << WIDX_PATH_CHECK_EDGE_SE) | (1ULL << WIDX_PATH_CHECK_EDGE_S) | (1ULL << WIDX_PATH_CHECK_EDGE_SW) | (1ULL << WIDX_PATH_CHECK_EDGE_W) | (1ULL << WIDX_PATH_CHECK_EDGE_NW), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_TRACK_CHECK_APPLY_TO_ALL) | (1ULL << WIDX_TRACK_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_TRACK_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_TRACK_CHECK_CHAIN_LIFT) | (1ULL << WIDX_TRACK_CHECK_BLOCK_BRAKE_CLOSED) | (1ULL << WIDX_TRACK_CHECK_IS_INDESTRUCTIBLE), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_SCENERY_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_SCENERY_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_N) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_E) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_S) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_W) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_N) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_E) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_S) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_W), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_ENTRANCE_BUTTON_MAKE_USABLE), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_WALL_DROPDOWN_SLOPE) | (1ULL << WIDX_WALL_DROPDOWN_SLOPE_BUTTON) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_INCREASE) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_DECREASE), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_NE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_SE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_SW) | (1ULL << WIDX_BANNER_CHECK_BLOCK_NW), - (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_CORRUPT_BUTTON_CLAMP), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_SURFACE_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_SURFACE_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_SURFACE_BUTTON_REMOVE_FENCES) | (1ULL << WIDX_SURFACE_BUTTON_RESTORE_FENCES) | (1ULL << WIDX_SURFACE_CHECK_CORNER_N) | (1ULL << WIDX_SURFACE_CHECK_CORNER_E) | (1ULL << WIDX_SURFACE_CHECK_CORNER_S) | (1ULL << WIDX_SURFACE_CHECK_CORNER_W) | (1ULL << WIDX_SURFACE_CHECK_DIAGONAL), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_PATH_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_PATH_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_PATH_CHECK_SLOPED) | (1ULL << WIDX_PATH_CHECK_BROKEN) | (1ULL << WIDX_PATH_CHECK_EDGE_N) | (1ULL << WIDX_PATH_CHECK_EDGE_NE) | (1ULL << WIDX_PATH_CHECK_EDGE_E) | (1ULL << WIDX_PATH_CHECK_EDGE_SE) | (1ULL << WIDX_PATH_CHECK_EDGE_S) | (1ULL << WIDX_PATH_CHECK_EDGE_SW) | (1ULL << WIDX_PATH_CHECK_EDGE_W) | (1ULL << WIDX_PATH_CHECK_EDGE_NW), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_TRACK_CHECK_APPLY_TO_ALL) | (1ULL << WIDX_TRACK_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_TRACK_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_TRACK_CHECK_CHAIN_LIFT) | (1ULL << WIDX_TRACK_CHECK_BLOCK_BRAKE_CLOSED) | (1ULL << WIDX_TRACK_CHECK_IS_INDESTRUCTIBLE), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_SCENERY_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_SCENERY_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_N) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_E) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_S) | (1ULL << WIDX_SCENERY_CHECK_QUARTER_W) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_N) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_E) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_S) | (1ULL << WIDX_SCENERY_CHECK_COLLISION_W), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_ENTRANCE_BUTTON_MAKE_USABLE), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_WALL_DROPDOWN_SLOPE) | (1ULL << WIDX_WALL_DROPDOWN_SLOPE_BUTTON) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_INCREASE) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_DECREASE), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_NE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_SE) | (1ULL << WIDX_BANNER_CHECK_BLOCK_SW) | (1ULL << WIDX_BANNER_CHECK_BLOCK_NW), }; static uint64_t PageHoldDownWidgets[] = { @@ -509,11 +496,10 @@ static uint64_t PageHoldDownWidgets[] = { (1ULL << WIDX_SPINNER_X_INCREASE) | (1ULL << WIDX_SPINNER_X_DECREASE) | (1ULL << WIDX_SPINNER_Y_INCREASE) | (1ULL << WIDX_SPINNER_Y_DECREASE) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_WALL_SPINNER_HEIGHT_DECREASE) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_INCREASE) | (1ULL << WIDX_WALL_SPINNER_ANIMATION_FRAME_DECREASE), (1ULL << WIDX_SPINNER_X_INCREASE) | (1ULL << WIDX_SPINNER_X_DECREASE) | (1ULL << WIDX_SPINNER_Y_INCREASE) | (1ULL << WIDX_SPINNER_Y_DECREASE) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE), (1ULL << WIDX_SPINNER_X_INCREASE) | (1ULL << WIDX_SPINNER_X_DECREASE) | (1ULL << WIDX_SPINNER_Y_INCREASE) | (1ULL << WIDX_SPINNER_Y_DECREASE) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_BANNER_SPINNER_HEIGHT_DECREASE), - (1ULL << WIDX_SPINNER_X_INCREASE) | (1ULL << WIDX_SPINNER_X_DECREASE) | (1ULL << WIDX_SPINNER_Y_INCREASE) | (1ULL << WIDX_SPINNER_Y_DECREASE) | (1ULL << WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE) | (1ULL << WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE), }; static uint64_t PageDisabledWidgets[] = { - (1ULL << WIDX_BUTTON_CORRUPT) | (1ULL << WIDX_BUTTON_MOVE_UP) | (1ULL << WIDX_BUTTON_MOVE_DOWN) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY), + (1ULL << WIDX_BUTTON_INVISIBLE) | (1ULL << WIDX_BUTTON_MOVE_UP) | (1ULL << WIDX_BUTTON_MOVE_DOWN) | (1ULL << WIDX_BUTTON_REMOVE) | (1ULL << WIDX_BUTTON_ROTATE) | (1ULL << WIDX_BUTTON_COPY), 0, 0, 0, @@ -522,7 +508,6 @@ static uint64_t PageDisabledWidgets[] = { 0, (1ULL << WIDX_BUTTON_ROTATE), 0, - (1ULL << WIDX_BUTTON_ROTATE), }; // clang-format on @@ -607,13 +592,6 @@ static void window_tile_inspector_load_tile(rct_window* w, TileElement* elementT w->Invalidate(); } -static void window_tile_inspector_insert_corrupt_element(int32_t elementIndex) -{ - openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); - auto modifyTile = TileModifyAction(windowTileInspectorToolMap, TileModifyType::AnyInsertCorrupt, elementIndex); - GameActions::Execute(&modifyTile); -} - static void window_tile_inspector_remove_element(int32_t elementIndex) { openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); @@ -787,9 +765,10 @@ static void window_tile_inspector_banner_toggle_block(int32_t elementIndex, int3 GameActions::Execute(&modifyTile); } -static void window_tile_inspector_clamp_corrupt(int32_t elementIndex) +static void WindowTileInspectorToggleInvisibility(int32_t elementIndex) { - auto modifyTile = TileModifyAction(windowTileInspectorToolMap, TileModifyType::CorruptClamp, elementIndex); + openrct2_assert(elementIndex >= 0 && elementIndex < windowTileInspectorElementCount, "elementIndex out of range"); + auto modifyTile = TileModifyAction(windowTileInspectorToolMap, TileModifyType::AnyToggleInvisilibity, elementIndex); GameActions::Execute(&modifyTile); } @@ -806,8 +785,8 @@ static void window_tile_inspector_mouseup(rct_window* w, rct_widgetindex widgetI tool_cancel(); window_close(w); return; - case WIDX_BUTTON_CORRUPT: - window_tile_inspector_insert_corrupt_element(windowTileInspectorSelectedIndex); + case WIDX_BUTTON_INVISIBLE: + WindowTileInspectorToggleInvisibility(windowTileInspectorSelectedIndex); break; case WIDX_BUTTON_REMOVE: { @@ -980,14 +959,6 @@ static void window_tile_inspector_mouseup(rct_window* w, rct_widgetindex widgetI } // switch widget index break; - case TILE_ELEMENT_TYPE_CORRUPT: - switch (widgetIndex) - { - case WIDX_CORRUPT_BUTTON_CLAMP: - window_tile_inspector_clamp_corrupt(windowTileInspectorSelectedIndex); - break; - } // switch widget index - break; case TILE_ELEMENT_TYPE_LARGE_SCENERY: case TILE_ELEMENT_TYPE_WALL: default: @@ -1186,16 +1157,6 @@ static void window_tile_inspector_mousedown(rct_window* w, rct_widgetindex widge } // switch widget index break; - case TILE_ELEMENT_TYPE_CORRUPT: - switch (widgetIndex) - { - case WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE: - window_tile_inspector_base_height_offset(windowTileInspectorSelectedIndex, 1); - break; - case WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE: - window_tile_inspector_base_height_offset(windowTileInspectorSelectedIndex, -1); - break; - } // switch widget index default: break; } @@ -1402,6 +1363,7 @@ static void window_tile_inspector_invalidate(rct_window* w) auto type = element->GetType(); switch (type) { + default: case TILE_ELEMENT_TYPE_SURFACE: page = TileInspectorPage::Surface; break; @@ -1426,10 +1388,6 @@ static void window_tile_inspector_invalidate(rct_window* w) case TILE_ELEMENT_TYPE_BANNER: page = TileInspectorPage::Banner; break; - case TILE_ELEMENT_TYPE_CORRUPT: - default: - page = TileInspectorPage::Corrupt; - break; } } @@ -1748,16 +1706,6 @@ static void window_tile_inspector_invalidate(rct_window* w) w, WIDX_BANNER_CHECK_BLOCK_NW, !(tileElement->AsBanner()->GetAllowedEdges() & (1 << ((3 - get_current_rotation()) & 3)))); break; - case TILE_ELEMENT_TYPE_CORRUPT: - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT].top = GBBT(propertiesAnchor, 0) + 3; - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT].bottom = GBBB(propertiesAnchor, 0) - 3; - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE].top = GBBT(propertiesAnchor, 0) + 4; - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE].bottom = GBBB(propertiesAnchor, 0) - 4; - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE].top = GBBT(propertiesAnchor, 0) + 4; - w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE].bottom = GBBB(propertiesAnchor, 0) - 4; - w->widgets[WIDX_CORRUPT_BUTTON_CLAMP].top = GBBT(propertiesAnchor, 1); - w->widgets[WIDX_CORRUPT_BUTTON_CLAMP].bottom = GBBB(propertiesAnchor, 1); - break; default: break; // Nothing. } @@ -1874,10 +1822,38 @@ static void window_tile_inspector_paint(rct_window* w, rct_drawpixelinfo* dpi) case TILE_ELEMENT_TYPE_PATH: { // Details - // Path name - auto ft = Formatter(); - ft.Add(tileElement->AsPath()->GetSurfaceDescriptor()->Name); - DrawTextBasic(dpi, screenCoords, STR_TILE_INSPECTOR_PATH_NAME, ft, { w->colours[1] }); + auto pathEl = tileElement->AsPath(); + auto footpathObj = pathEl->GetLegacyPathEntry(); + if (footpathObj == nullptr) + { + // Surface name + auto surfaceObj = pathEl->GetSurfaceEntry(); + if (surfaceObj != nullptr) + { + auto ft = Formatter(); + ft.Add(surfaceObj->NameStringId); + DrawTextBasic(dpi, screenCoords, STR_TILE_INSPECTOR_FOOTPATH_SURFACE_NAME, ft, { COLOUR_WHITE }); + } + + // Railings name + auto railingsObj = pathEl->GetRailingsEntry(); + if (railingsObj != nullptr) + { + auto ft = Formatter(); + ft.Add(railingsObj->NameStringId); + DrawTextBasic( + dpi, screenCoords + ScreenCoordsXY{ 0, 11 }, STR_TILE_INSPECTOR_FOOTPATH_RAILINGS_NAME, ft, + { COLOUR_WHITE }); + } + } + else + { + // Legacy path name + auto footpathEntry = reinterpret_cast(footpathObj->GetLegacyData()); + auto ft = Formatter(); + ft.Add(footpathEntry->string_idx); + DrawTextBasic(dpi, screenCoords, STR_TILE_INSPECTOR_PATH_NAME, ft, { COLOUR_WHITE }); + } // Path addition if (tileElement->AsPath()->HasAddition()) @@ -1887,15 +1863,18 @@ static void window_tile_inspector_paint(rct_window* w, rct_drawpixelinfo* dpi) rct_string_id additionNameId = pathBitEntry != nullptr ? pathBitEntry->name : static_cast(STR_UNKNOWN_OBJECT_TYPE); - ft = Formatter(); + auto ft = Formatter(); ft.Add(additionNameId); DrawTextBasic( - dpi, screenCoords + ScreenCoordsXY{ 0, 11 }, STR_TILE_INSPECTOR_PATH_ADDITIONS, ft, { w->colours[1] }); + dpi, screenCoords + ScreenCoordsXY{ 0, 2 * 11 }, STR_TILE_INSPECTOR_PATH_ADDITIONS, ft, + { COLOUR_WHITE }); } else + { DrawTextBasic( - dpi, screenCoords + ScreenCoordsXY{ 0, 11 }, STR_TILE_INSPECTOR_PATH_ADDITIONS_NONE, {}, - { w->colours[1] }); + dpi, screenCoords + ScreenCoordsXY{ 0, 2 * 11 }, STR_TILE_INSPECTOR_PATH_ADDITIONS_NONE, {}, + { COLOUR_WHITE }); + } // Properties // Raise / lower label @@ -1905,7 +1884,7 @@ static void window_tile_inspector_paint(rct_window* w, rct_drawpixelinfo* dpi) // Current base height screenCoords.x = w->windowPos.x + w->widgets[WIDX_PATH_SPINNER_HEIGHT].left + 3; - ft = Formatter(); + auto ft = Formatter(); ft.Add(tileElement->base_height); DrawTextBasic(dpi, screenCoords, STR_FORMAT_INTEGER, ft, { w->colours[1] }); @@ -2258,22 +2237,6 @@ static void window_tile_inspector_paint(rct_window* w, rct_drawpixelinfo* dpi) DrawTextBasic(dpi, screenCoords, STR_TILE_INSPECTOR_BANNER_BLOCKED_PATHS, {}, { w->colours[1] }); break; } - - case TILE_ELEMENT_TYPE_CORRUPT: - { - // Properties - // Raise / lower label - screenCoords.y = w->windowPos.y + w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT].top; - DrawTextBasic(dpi, screenCoords, STR_TILE_INSPECTOR_BASE_HEIGHT_FULL, {}, { w->colours[1] }); - - // Current base height - screenCoords.x = w->windowPos.x + w->widgets[WIDX_CORRUPT_SPINNER_HEIGHT].left + 3; - auto ft = Formatter(); - ft.Add(tileElement->base_height); - DrawTextBasic(dpi, screenCoords, STR_FORMAT_INTEGER, ft, { w->colours[1] }); - break; - } - default: { break; @@ -2365,14 +2328,13 @@ static void window_tile_inspector_scrollpaint(rct_window* w, rct_drawpixelinfo* tileElement->AsBanner()->GetIndex()); typeName = buffer; break; - case TILE_ELEMENT_TYPE_CORRUPT: - // fall-through default: snprintf(buffer, sizeof(buffer), "%s (%d)", language_get_string(STR_UNKNOWN_OBJECT_TYPE), type); typeName = buffer; } const int32_t clearanceHeight = tileElement->clearance_height; + const bool invisible = tileElement->IsInvisible(); const bool ghost = tileElement->IsGhost(); const bool last = tileElement->IsLastForTile(); @@ -2406,6 +2368,10 @@ static void window_tile_inspector_scrollpaint(rct_window* w, rct_drawpixelinfo* ft = Formatter(); ft.Add(STR_STRING); ft.Add(CheckBoxMarkString); + if (invisible) + { + DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ InvisibleFlagColumnXY.x, 0 }, stringFormat, ft); + } if (ghost) { DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ GhostFlagColumnXY.x, 0 }, stringFormat, ft); diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index a9e98a8107..61012436a4 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -112,7 +112,7 @@ rct_window* window_title_menu_open() static void window_title_menu_scenarioselect_callback(const utf8* path) { - context_load_park_from_file(path); + OpenRCT2::GetContext()->LoadParkFromFile(path, false, true); game_load_scripts(); } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index e9c3ac91d2..dfe31b718a 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -530,7 +530,7 @@ static void window_top_toolbar_mousedown(rct_window* w, rct_widgetindex widgetIn static void window_top_toolbar_scenarioselect_callback(const utf8* path) { window_close_by_class(WC_EDITOR_OBJECT_SELECTION); - context_load_park_from_file(path); + GetContext()->LoadParkFromFile(path, false, true); } /** diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 6f8cbfb6df..8c9a49d1c6 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -495,7 +495,6 @@ namespace OpenRCT2 #endif } - gCurrentTicks = 0; input_reset_place_obj_modifier(); viewport_init_all(); @@ -573,7 +572,8 @@ namespace OpenRCT2 _drawingEngine = nullptr; } - bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail) final override + bool LoadParkFromFile( + const std::string& path, bool loadTitleScreenOnFail = false, bool asScenario = false) final override { log_verbose("Context::LoadParkFromFile(%s)", path.c_str()); try @@ -582,7 +582,7 @@ namespace OpenRCT2 { auto data = DecryptSea(fs::u8path(path)); auto ms = MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ); - if (!LoadParkFromStream(&ms, path, loadTitleScreenOnFail)) + if (!LoadParkFromStream(&ms, path, loadTitleScreenOnFail, asScenario)) { throw std::runtime_error(".sea file may have been renamed."); } @@ -590,7 +590,7 @@ namespace OpenRCT2 } auto fs = FileStream(path, FILE_MODE_OPEN); - if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail)) + if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail, asScenario)) { return false; } @@ -609,7 +609,9 @@ namespace OpenRCT2 return false; } - bool LoadParkFromStream(IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail) final override + bool LoadParkFromStream( + IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false, + bool asScenario = false) final override { try { @@ -619,13 +621,17 @@ namespace OpenRCT2 throw std::runtime_error("Unable to detect file type"); } - if (info.Type != FILE_TYPE::SAVED_GAME && info.Type != FILE_TYPE::SCENARIO) + if (info.Type != FILE_TYPE::PARK && info.Type != FILE_TYPE::SAVED_GAME && info.Type != FILE_TYPE::SCENARIO) { throw std::runtime_error("Invalid file type."); } std::unique_ptr parkImporter; - if (info.Version <= FILE_TYPE_S4_CUTOFF) + if (info.Type == FILE_TYPE::PARK) + { + parkImporter = ParkImporter::CreateParkFile(*_objectRepository); + } + else if (info.Version <= FILE_TYPE_S4_CUTOFF) { // Save is an S4 (RCT1 format) parkImporter = ParkImporter::CreateS4(); @@ -656,7 +662,7 @@ namespace OpenRCT2 #ifndef DISABLE_NETWORK bool sendMap = false; #endif - if (info.Type == FILE_TYPE::SAVED_GAME) + if (!asScenario && (info.Type == FILE_TYPE::PARK || info.Type == FILE_TYPE::SAVED_GAME)) { #ifndef DISABLE_NETWORK if (_network.GetMode() == NETWORK_MODE_CLIENT) diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index c8fafaf058..cbb4529068 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -141,9 +141,11 @@ namespace OpenRCT2 virtual bool Initialise() abstract; virtual void InitialiseDrawingEngine() abstract; virtual void DisposeDrawingEngine() abstract; - virtual bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail = false) abstract; + virtual bool LoadParkFromFile( + const std::string& path, bool loadTitleScreenOnFail = false, bool asScenario = false) abstract; virtual bool LoadParkFromStream( - IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false) abstract; + IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false, + bool asScenario = false) abstract; virtual void WriteLine(const std::string& s) abstract; virtual void WriteErrorLine(const std::string& s) abstract; virtual void Finish() abstract; diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 529e95b0ff..87e10485dc 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -24,6 +24,7 @@ #include "localisation/Localisation.h" #include "localisation/LocalisationService.h" #include "management/NewsItem.h" +#include "object/DefaultObjects.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" #include "peep/Guest.h" @@ -60,6 +61,7 @@ namespace Editor static bool LoadLandscapeFromSC4(const char* path); static void FinaliseMainView(); static bool ReadS6(const char* path); + static bool ReadPark(const char* path); static void ClearMapForEditing(bool fromSave); static void object_list_load() @@ -76,7 +78,11 @@ namespace Editor objectRepository.LoadOrConstruct(localisationService.GetCurrentLanguage()); // Reset loaded objects to just defaults - objectManager.LoadDefaultObjects(); + // Load minimum required objects (like surface and edge) + for (const auto& entry : MinimumRequiredObjects) + { + objectManager.LoadObject(entry); + } } /** @@ -86,7 +92,6 @@ namespace Editor void Load() { OpenRCT2::Audio::StopAll(); - object_manager_unload_all_objects(); object_list_load(); OpenRCT2::GetContext()->GetGameState()->InitAll(150); gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; @@ -232,6 +237,8 @@ namespace Editor return LoadLandscapeFromSC4(path); case FILE_EXTENSION_SV4: return LoadLandscapeFromSV4(path); + case FILE_EXTENSION_PARK: + return ReadPark(path); default: return false; } @@ -298,6 +305,32 @@ namespace Editor return true; } + static bool ReadPark(const char* path) + { + try + { + auto context = GetContext(); + auto& objManager = context->GetObjectManager(); + auto importer = ParkImporter::CreateParkFile(context->GetObjectRepository()); + auto loadResult = importer->Load(path); + objManager.LoadObjects(loadResult.RequiredObjects); + importer->Import(); + + ClearMapForEditing(true); + gEditorStep = EditorStep::LandscapeEditor; + gScreenAge = 0; + gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; + viewport_init_all(); + context_open_window_view(WV_EDITOR_MAIN); + FinaliseMainView(); + return true; + } + catch (const std::exception&) + { + return false; + } + } + static void ClearMapForEditing(bool fromSave) { map_remove_all_rides(); @@ -323,8 +356,6 @@ namespace Editor gGuestChangeModifier = 0; if (fromSave) { - research_populate_list_random(); - if (gParkFlags & PARK_FLAGS_NO_MONEY) { gParkFlags |= PARK_FLAGS_NO_MONEY_SCENARIO; @@ -454,9 +485,17 @@ namespace Editor if (!isTrackDesignerManager) { - if (!editor_check_object_group_at_least_one_selected(ObjectType::Paths)) + if (!editor_check_object_group_at_least_one_surface_selected(false)) { - return { ObjectType::Paths, STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED }; + return { ObjectType::FootpathSurface, STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED }; + } + if (!editor_check_object_group_at_least_one_surface_selected(true)) + { + return { ObjectType::FootpathSurface, STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED }; + } + if (!editor_check_object_group_at_least_one_selected(ObjectType::FootpathRailings)) + { + return { ObjectType::FootpathRailings, STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED }; } } @@ -547,12 +586,16 @@ namespace Editor void SetSelectedObject(ObjectType objectType, size_t index, uint32_t flags) { - auto& list = _editorSelectedObjectFlags[EnumValue(objectType)]; - if (list.size() <= index) + if (index != OBJECT_ENTRY_INDEX_NULL) { - list.resize(index + 1); + assert(static_cast(objectType) < object_entry_group_counts[EnumValue(ObjectType::Paths)]); + auto& list = _editorSelectedObjectFlags[EnumValue(objectType)]; + if (list.size() <= index) + { + list.resize(index + 1); + } + list[index] |= flags; } - list[index] |= flags; } } // namespace Editor diff --git a/src/openrct2/EditorObjectSelectionSession.cpp b/src/openrct2/EditorObjectSelectionSession.cpp index 5b071e49b2..36d967310e 100644 --- a/src/openrct2/EditorObjectSelectionSession.cpp +++ b/src/openrct2/EditorObjectSelectionSession.cpp @@ -135,45 +135,73 @@ void setup_in_use_selection_flags() { default: case TILE_ELEMENT_TYPE_SURFACE: + { + auto surfaceEl = iter.element->AsSurface(); + auto surfaceIndex = surfaceEl->GetSurfaceStyle(); + auto edgeIndex = surfaceEl->GetEdgeStyle(); + + Editor::SetSelectedObject(ObjectType::TerrainSurface, surfaceIndex, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::TerrainEdge, edgeIndex, OBJECT_SELECTION_FLAG_SELECTED); + break; + } case TILE_ELEMENT_TYPE_TRACK: break; case TILE_ELEMENT_TYPE_PATH: - type = iter.element->AsPath()->GetLegacyPathEntryIndex(); - assert(type < object_entry_group_counts[EnumValue(ObjectType::Paths)]); - Editor::SetSelectedObject(ObjectType::Paths, type, OBJECT_SELECTION_FLAG_SELECTED); - - if (iter.element->AsPath()->HasAddition()) + { + auto footpathEl = iter.element->AsPath(); + auto legacyPathEntryIndex = footpathEl->GetLegacyPathEntryIndex(); + if (legacyPathEntryIndex == OBJECT_ENTRY_INDEX_NULL) { - uint8_t path_additions = iter.element->AsPath()->GetAdditionEntryIndex(); - Editor::SetSelectedObject(ObjectType::PathBits, path_additions, OBJECT_SELECTION_FLAG_SELECTED); + auto surfaceEntryIndex = footpathEl->GetSurfaceEntryIndex(); + auto railingEntryIndex = footpathEl->GetRailingsEntryIndex(); + Editor::SetSelectedObject(ObjectType::FootpathSurface, surfaceEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::FootpathRailings, railingEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); + } + else + { + Editor::SetSelectedObject(ObjectType::Paths, legacyPathEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); + } + if (footpathEl->HasAddition()) + { + auto pathAdditionEntryIndex = footpathEl->GetAdditionEntryIndex(); + Editor::SetSelectedObject(ObjectType::PathBits, pathAdditionEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); } break; + } case TILE_ELEMENT_TYPE_SMALL_SCENERY: type = iter.element->AsSmallScenery()->GetEntryIndex(); - assert(type < object_entry_group_counts[EnumValue(ObjectType::SmallScenery)]); Editor::SetSelectedObject(ObjectType::SmallScenery, type, OBJECT_SELECTION_FLAG_SELECTED); break; case TILE_ELEMENT_TYPE_ENTRANCE: - if (iter.element->AsEntrance()->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) - break; - // Skip if not the middle part - if (iter.element->AsEntrance()->GetSequenceIndex() != 0) + { + auto parkEntranceEl = iter.element->AsEntrance(); + if (parkEntranceEl->GetEntranceType() != ENTRANCE_TYPE_PARK_ENTRANCE) break; Editor::SetSelectedObject(ObjectType::ParkEntrance, 0, OBJECT_SELECTION_FLAG_SELECTED); - type = iter.element->AsEntrance()->GetLegacyPathEntryIndex(); - assert(type < object_entry_group_counts[EnumValue(ObjectType::Paths)]); - Editor::SetSelectedObject(ObjectType::Paths, type, OBJECT_SELECTION_FLAG_SELECTED); + // Skip if not the middle part + if (parkEntranceEl->GetSequenceIndex() != 0) + break; + + auto legacyPathEntryIndex = parkEntranceEl->GetLegacyPathEntryIndex(); + if (legacyPathEntryIndex == OBJECT_ENTRY_INDEX_NULL) + { + auto surfaceEntryIndex = parkEntranceEl->GetSurfaceEntryIndex(); + Editor::SetSelectedObject(ObjectType::FootpathSurface, surfaceEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); + } + else + { + Editor::SetSelectedObject(ObjectType::Paths, legacyPathEntryIndex, OBJECT_SELECTION_FLAG_SELECTED); + } break; + } case TILE_ELEMENT_TYPE_WALL: type = iter.element->AsWall()->GetEntryIndex(); - assert(type < object_entry_group_counts[EnumValue(ObjectType::Walls)]); Editor::SetSelectedObject(ObjectType::Walls, type, OBJECT_SELECTION_FLAG_SELECTED); break; case TILE_ELEMENT_TYPE_LARGE_SCENERY: type = iter.element->AsLargeScenery()->GetEntryIndex(); - assert(type < object_entry_group_counts[EnumValue(ObjectType::LargeScenery)]); Editor::SetSelectedObject(ObjectType::LargeScenery, type, OBJECT_SELECTION_FLAG_SELECTED); break; case TILE_ELEMENT_TYPE_BANNER: @@ -182,7 +210,6 @@ void setup_in_use_selection_flags() if (banner != nullptr) { type = banner->type; - assert(type < object_entry_group_counts[EnumValue(ObjectType::Banners)]); Editor::SetSelectedObject(ObjectType::Banners, type, OBJECT_SELECTION_FLAG_SELECTED); } break; @@ -192,8 +219,9 @@ void setup_in_use_selection_flags() for (auto& ride : GetRideManager()) { - ObjectEntryIndex type = ride.subtype; - Editor::SetSelectedObject(ObjectType::Ride, type, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::Ride, ride.subtype, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::Station, ride.entrance_style, OBJECT_SELECTION_FLAG_SELECTED); + Editor::SetSelectedObject(ObjectType::Music, ride.music, OBJECT_SELECTION_FLAG_SELECTED); } // Apply selected object status for hacked vehicles that may not have an associated ride @@ -214,19 +242,19 @@ void setup_in_use_selection_flags() } } - int32_t numObjects = static_cast(object_repository_get_items_count()); - const ObjectRepositoryItem* items = object_repository_get_items(); - for (int32_t i = 0; i < numObjects; i++) + auto numObjects = object_repository_get_items_count(); + const auto* items = object_repository_get_items(); + for (size_t i = 0; i < numObjects; i++) { - uint8_t* selectionFlags = &_objectSelectionFlags[i]; - const ObjectRepositoryItem* item = &items[i]; + auto* selectionFlags = &_objectSelectionFlags[i]; + const auto* item = &items[i]; *selectionFlags &= ~OBJECT_SELECTION_FLAG_IN_USE; - ObjectType entryType; - ObjectEntryIndex entryIndex; - if (find_object_in_entry_group(&item->ObjectEntry, &entryType, &entryIndex)) + if (item->LoadedObject != nullptr) { - auto flags = Editor::GetSelectedObjectFlags(entryType, entryIndex); + auto objectType = item->LoadedObject->GetObjectType(); + auto entryIndex = objectMgr.GetLoadedObjectEntryIndex(item->LoadedObject.get()); + auto flags = Editor::GetSelectedObjectFlags(objectType, entryIndex); if (flags & OBJECT_SELECTION_FLAG_SELECTED) { *selectionFlags |= OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_SELECTED; @@ -300,7 +328,7 @@ void editor_object_flags_free() * * rct2: 0x00685791 */ -static void remove_selected_objects_from_research(ObjectEntryDescriptor& descriptor) +static void remove_selected_objects_from_research(const ObjectEntryDescriptor& descriptor) { auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); auto obj = objManager.GetLoadedObject(descriptor); diff --git a/src/openrct2/FileClassifier.cpp b/src/openrct2/FileClassifier.cpp index 49dc9dd019..8aee1095fc 100644 --- a/src/openrct2/FileClassifier.cpp +++ b/src/openrct2/FileClassifier.cpp @@ -9,6 +9,7 @@ #include "FileClassifier.h" +#include "ParkFile.h" #include "core/Console.hpp" #include "core/FileStream.h" #include "core/Path.hpp" @@ -17,6 +18,7 @@ #include "scenario/Scenario.h" #include "util/SawyerCoding.h" +static bool TryClassifyAsPark(OpenRCT2::IStream* stream, ClassifiedFileInfo* result); static bool TryClassifyAsS6(OpenRCT2::IStream* stream, ClassifiedFileInfo* result); static bool TryClassifyAsS4(OpenRCT2::IStream* stream, ClassifiedFileInfo* result); static bool TryClassifyAsTD4_TD6(OpenRCT2::IStream* stream, ClassifiedFileInfo* result); @@ -41,6 +43,12 @@ bool TryClassifyFile(OpenRCT2::IStream* stream, ClassifiedFileInfo* result) // between them is to decode it. Decoding however is currently not protected // against invalid compression data for that decoding algorithm and will crash. + // Park detection + if (TryClassifyAsPark(stream, result)) + { + return true; + } + // S6 detection if (TryClassifyAsS6(stream, result)) { @@ -62,6 +70,29 @@ bool TryClassifyFile(OpenRCT2::IStream* stream, ClassifiedFileInfo* result) return false; } +static bool TryClassifyAsPark(OpenRCT2::IStream* stream, ClassifiedFileInfo* result) +{ + bool success = false; + uint64_t originalPosition = stream->GetPosition(); + try + { + auto magic = stream->ReadValue(); + if (magic == OpenRCT2::PARK_FILE_MAGIC) + { + result->Type = FILE_TYPE::PARK; + result->Version = 0; + success = true; + } + } + catch (const std::exception& e) + { + success = false; + log_verbose(e.what()); + } + stream->SetPosition(originalPosition); + return success; +} + static bool TryClassifyAsS6(OpenRCT2::IStream* stream, ClassifiedFileInfo* result) { bool success = false; @@ -183,5 +214,7 @@ uint32_t get_file_extension_type(const utf8* path) return FILE_EXTENSION_SV6; if (String::Equals(extension, ".td6", true)) return FILE_EXTENSION_TD6; + if (String::Equals(extension, ".park", true)) + return FILE_EXTENSION_PARK; return FILE_EXTENSION_UNKNOWN; } diff --git a/src/openrct2/FileClassifier.h b/src/openrct2/FileClassifier.h index ecf9ced3b2..85b428519a 100644 --- a/src/openrct2/FileClassifier.h +++ b/src/openrct2/FileClassifier.h @@ -21,6 +21,7 @@ enum FILE_EXTENSION_SC6, FILE_EXTENSION_SV6, FILE_EXTENSION_TD6, + FILE_EXTENSION_PARK, }; #include @@ -37,6 +38,7 @@ enum class FILE_TYPE SAVED_GAME, SCENARIO, TRACK_DESIGN, + PARK, }; struct ClassifiedFileInfo diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 0f215b5515..9eac22f2fb 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -501,7 +501,7 @@ void game_fix_save_vars() } } - research_fix(); + ResearchFix(); // Fix banner list pointing to NULL map elements banner_reset_broken_index(); @@ -514,6 +514,8 @@ void game_fix_save_vars() // Fix gParkEntrance locations for which the tile_element no longer exists fix_park_entrance_locations(); + + staff_update_greyed_patrol_areas(); } void game_load_init() @@ -824,7 +826,7 @@ void game_load_or_quit_no_save_prompt() void start_silent_record() { std::string name = Path::Combine( - OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath(OpenRCT2::DIRBASE::USER), "debug_replay.sv6r"); + OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath(OpenRCT2::DIRBASE::USER), "debug_replay.parkrep"); auto* replayManager = OpenRCT2::GetContext()->GetReplayManager(); if (replayManager->StartRecording(name, OpenRCT2::k_MaxReplayTicks, OpenRCT2::IReplayManager::RecordType::SILENT)) { diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 043f46dd1e..f3ecffb6b0 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -80,6 +80,9 @@ void GameState::InitAll(int32_t mapSize) context_broadcast_intent(&intent); load_palette(); + + CheatsReset(); + ClearRestrictedScenery(); } /** diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp new file mode 100644 index 0000000000..66603931a2 --- /dev/null +++ b/src/openrct2/ParkFile.cpp @@ -0,0 +1,4593 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "ParkFile.h" + +#include "Cheats.h" +#include "Context.h" +#include "Editor.h" +#include "GameState.h" +#include "OpenRCT2.h" +#include "ParkImporter.h" +#include "Version.h" +#include "core/Console.hpp" +#include "core/Crypt.h" +#include "core/DataSerialiser.h" +#include "core/File.h" +#include "core/OrcaStream.hpp" +#include "core/Path.hpp" +#include "drawing/Drawing.h" +#include "interface/Viewport.h" +#include "interface/Window.h" +#include "localisation/Date.h" +#include "localisation/Localisation.h" +#include "management/Award.h" +#include "management/Finance.h" +#include "management/NewsItem.h" +#include "object/Object.h" +#include "object/ObjectManager.h" +#include "object/ObjectRepository.h" +#include "peep/RideUseSystem.h" +#include "peep/Staff.h" +#include "ride/ShopItem.h" +#include "ride/Vehicle.h" +#include "scenario/Scenario.h" +#include "scenario/ScenarioRepository.h" +#include "world/Balloon.h" +#include "world/Climate.h" +#include "world/Duck.h" +#include "world/EntityList.h" +#include "world/Entrance.h" +#include "world/Fountain.h" +#include "world/Litter.h" +#include "world/Map.h" +#include "world/MoneyEffect.h" +#include "world/Park.h" +#include "world/Particle.h" +#include "world/Sprite.h" + +#include +#include +#include +#include +#include +#include + +using namespace OpenRCT2; + +static std::string_view MapToNewObjectIdentifier(std::string_view s); +static std::optional GetDATPathName(std::string_view newPathName); +static const FootpathMapping* GetFootpathMapping(const ObjectEntryDescriptor& desc); +static void UpdateFootpathsFromMapping( + ObjectEntryIndex* pathToSurfaceMap, ObjectEntryIndex* pathToQueueSurfaceMap, ObjectEntryIndex* pathToRailingsMap, + ObjectList& requiredObjects, ObjectEntryIndex& surfaceCount, ObjectEntryIndex& railingCount, ObjectEntryIndex entryIndex, + const FootpathMapping* footpathMapping); + +namespace OpenRCT2 +{ + // Current version that is saved. + constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x5; + + // The minimum version that is forwards compatible with the current version. + constexpr uint32_t PARK_FILE_MIN_VERSION = 0x5; + + namespace ParkFileChunkType + { + // clang-format off +// constexpr uint32_t RESERVED_0 = 0x00; + + constexpr uint32_t AUTHORING = 0x01; + constexpr uint32_t OBJECTS = 0x02; + constexpr uint32_t SCENARIO = 0x03; + constexpr uint32_t GENERAL = 0x04; + constexpr uint32_t CLIMATE = 0x05; + constexpr uint32_t PARK = 0x06; +// constexpr uint32_t HISTORY = 0x07; + constexpr uint32_t RESEARCH = 0x08; + constexpr uint32_t NOTIFICATIONS = 0x09; + constexpr uint32_t INTERFACE = 0x20; + constexpr uint32_t TILES = 0x30; + constexpr uint32_t ENTITIES = 0x31; + constexpr uint32_t RIDES = 0x32; + constexpr uint32_t BANNERS = 0x33; +// constexpr uint32_t STAFF = 0x35; + constexpr uint32_t CHEATS = 0x36; + constexpr uint32_t RESTRICTED_OBJECTS = 0x37; + constexpr uint32_t PACKED_OBJECTS = 0x80; + // clang-format on + }; // namespace ParkFileChunkType + + class ParkFile + { + public: + ObjectList RequiredObjects; + std::vector ExportObjectsList; + bool OmitTracklessRides{}; + + private: + std::unique_ptr _os; + ObjectEntryIndex _pathToSurfaceMap[MAX_PATH_OBJECTS]; + ObjectEntryIndex _pathToQueueSurfaceMap[MAX_PATH_OBJECTS]; + ObjectEntryIndex _pathToRailingsMap[MAX_PATH_OBJECTS]; + + public: + void Load(const std::string_view& path) + { + FileStream fs(path, FILE_MODE_OPEN); + Load(fs); + } + + void Load(IStream& stream) + { + _os = std::make_unique(stream, OrcaStream::Mode::READING); + RequiredObjects = {}; + ReadWriteObjectsChunk(*_os); + ReadWritePackedObjectsChunk(*_os); + } + + void Import() + { + auto& os = *_os; + ReadWriteTilesChunk(os); + ReadWriteBannersChunk(os); + ReadWriteRidesChunk(os); + ReadWriteEntitiesChunk(os); + ReadWriteScenarioChunk(os); + ReadWriteGeneralChunk(os); + ReadWriteParkChunk(os); + ReadWriteClimateChunk(os); + ReadWriteResearchChunk(os); + ReadWriteNotificationsChunk(os); + ReadWriteInterfaceChunk(os); + ReadWriteCheatsChunk(os); + ReadWriteRestrictedObjectsChunk(os); + if (os.GetHeader().TargetVersion < 0x4) + { + UpdateTrackElementsRideType(); + } + + // Initial cash will eventually be removed + gInitialCash = gCash; + } + + void Save(IStream& stream) + { + OrcaStream os(stream, OrcaStream::Mode::WRITING); + + auto& header = os.GetHeader(); + header.Magic = PARK_FILE_MAGIC; + header.TargetVersion = PARK_FILE_CURRENT_VERSION; + header.MinVersion = PARK_FILE_MIN_VERSION; + + ReadWriteAuthoringChunk(os); + ReadWriteObjectsChunk(os); + ReadWriteTilesChunk(os); + ReadWriteBannersChunk(os); + ReadWriteRidesChunk(os); + ReadWriteEntitiesChunk(os); + ReadWriteScenarioChunk(os); + ReadWriteGeneralChunk(os); + ReadWriteParkChunk(os); + ReadWriteClimateChunk(os); + ReadWriteResearchChunk(os); + ReadWriteNotificationsChunk(os); + ReadWriteInterfaceChunk(os); + ReadWriteCheatsChunk(os); + ReadWriteRestrictedObjectsChunk(os); + ReadWritePackedObjectsChunk(os); + } + + void Save(const std::string_view& path) + { + FileStream fs(path, FILE_MODE_WRITE); + Save(fs); + } + + scenario_index_entry ReadScenarioChunk() + { + scenario_index_entry entry{}; + auto& os = *_os; + os.ReadWriteChunk(ParkFileChunkType::SCENARIO, [&entry](OrcaStream::ChunkStream& cs) { + entry.category = cs.Read(); + + std::string name; + ReadWriteStringTable(cs, name, "en-GB"); + String::Set(entry.name, sizeof(entry.name), name.c_str()); + String::Set(entry.internal_name, sizeof(entry.internal_name), name.c_str()); + + std::string parkName; + ReadWriteStringTable(cs, parkName, "en-GB"); + + std::string scenarioDetails; + ReadWriteStringTable(cs, scenarioDetails, "en-GB"); + String::Set(entry.details, sizeof(entry.details), scenarioDetails.c_str()); + + entry.objective_type = cs.Read(); + entry.objective_arg_1 = cs.Read(); + entry.objective_arg_3 = cs.Read(); + entry.objective_arg_2 = cs.Read(); + + entry.source_game = ScenarioSource::Other; + }); + return entry; + } + + private: + static uint8_t GetMinCarsPerTrain(uint8_t value) + { + return value >> 4; + } + + static uint8_t GetMaxCarsPerTrain(uint8_t value) + { + return value & 0xF; + } + + void ReadWriteAuthoringChunk(OrcaStream& os) + { + // Write-only for now + if (os.GetMode() == OrcaStream::Mode::WRITING) + { + os.ReadWriteChunk(ParkFileChunkType::AUTHORING, [](OrcaStream::ChunkStream& cs) { + cs.Write(std::string_view(gVersionInfoFull)); + std::vector authors; + cs.ReadWriteVector(authors, [](std::string& s) {}); + cs.Write(std::string_view()); // custom notes that can be attached to the save + cs.Write(static_cast(std::time(0))); // date started + cs.Write(static_cast(std::time(0))); // date modified + }); + } + } + + void ReadWriteObjectsChunk(OrcaStream& os) + { + static constexpr uint8_t DESCRIPTOR_NONE = 0; + static constexpr uint8_t DESCRIPTOR_DAT = 1; + static constexpr uint8_t DESCRIPTOR_JSON = 2; + + if (os.GetMode() == OrcaStream::Mode::READING) + { + std::fill(std::begin(_pathToSurfaceMap), std::end(_pathToSurfaceMap), OBJECT_ENTRY_INDEX_NULL); + std::fill(std::begin(_pathToQueueSurfaceMap), std::end(_pathToQueueSurfaceMap), OBJECT_ENTRY_INDEX_NULL); + std::fill(std::begin(_pathToRailingsMap), std::end(_pathToRailingsMap), OBJECT_ENTRY_INDEX_NULL); + auto* pathToSurfaceMap = _pathToSurfaceMap; + auto* pathToQueueSurfaceMap = _pathToQueueSurfaceMap; + auto* pathToRailingsMap = _pathToRailingsMap; + const auto version = os.GetHeader().TargetVersion; + + ObjectList requiredObjects; + os.ReadWriteChunk( + ParkFileChunkType::OBJECTS, + [&requiredObjects, pathToSurfaceMap, pathToQueueSurfaceMap, pathToRailingsMap, + version](OrcaStream::ChunkStream& cs) { + ObjectEntryIndex surfaceCount = 0; + ObjectEntryIndex railingsCount = 0; + auto numSubLists = cs.Read(); + for (size_t i = 0; i < numSubLists; i++) + { + auto objectType = static_cast(cs.Read()); + auto subListSize = static_cast(cs.Read()); + for (ObjectEntryIndex j = 0; j < subListSize; j++) + { + auto kind = cs.Read(); + + switch (kind) + { + case DESCRIPTOR_NONE: + break; + case DESCRIPTOR_DAT: + { + rct_object_entry datEntry; + cs.Read(&datEntry, sizeof(datEntry)); + ObjectEntryDescriptor desc(datEntry); + if (version <= 2 && datEntry.GetType() == ObjectType::Paths) + { + auto footpathMapping = GetFootpathMapping(desc); + if (footpathMapping != nullptr) + { + UpdateFootpathsFromMapping( + pathToSurfaceMap, pathToQueueSurfaceMap, pathToRailingsMap, requiredObjects, + surfaceCount, railingsCount, j, footpathMapping); + + continue; + } + } + + requiredObjects.SetObject(j, desc); + break; + } + case DESCRIPTOR_JSON: + { + ObjectEntryDescriptor desc; + desc.Type = objectType; + desc.Identifier = MapToNewObjectIdentifier(cs.Read()); + desc.Version = cs.Read(); + + if (version <= 2) + { + auto footpathMapping = GetFootpathMapping(desc); + if (footpathMapping != nullptr) + { + // We have surface objects for this footpath + UpdateFootpathsFromMapping( + pathToSurfaceMap, pathToQueueSurfaceMap, pathToRailingsMap, requiredObjects, + surfaceCount, railingsCount, j, footpathMapping); + + continue; + } + } + + requiredObjects.SetObject(j, desc); + break; + } + default: + throw std::runtime_error("Unknown object descriptor kind."); + } + } + } + }); + RequiredObjects = std::move(requiredObjects); + } + else + { + os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [](OrcaStream::ChunkStream& cs) { + auto& objManager = GetContext()->GetObjectManager(); + auto objectList = objManager.GetLoadedObjects(); + + // Write number of object sub lists + cs.Write(static_cast(ObjectType::Count)); + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) + { + // Write sub list + const auto& list = objectList.GetList(objectType); + cs.Write(static_cast(objectType)); + cs.Write(static_cast(list.size())); + for (const auto& entry : list) + { + if (entry.HasValue()) + { + if (entry.Generation == ObjectGeneration::JSON) + { + cs.Write(DESCRIPTOR_JSON); + cs.Write(entry.Identifier); + cs.Write(""); // reserved for version + } + else + { + cs.Write(DESCRIPTOR_DAT); + cs.Write(&entry.Entry, sizeof(rct_object_entry)); + } + } + else + { + cs.Write(DESCRIPTOR_NONE); + } + } + } + }); + } + } + + void ReadWriteScenarioChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::SCENARIO, [&os](OrcaStream::ChunkStream& cs) { + cs.ReadWrite(gScenarioCategory); + ReadWriteStringTable(cs, gScenarioName, "en-GB"); + + auto& park = GetContext()->GetGameState()->GetPark(); + ReadWriteStringTable(cs, park.Name, "en-GB"); + + ReadWriteStringTable(cs, gScenarioDetails, "en-GB"); + + cs.ReadWrite(gScenarioObjective.Type); + cs.ReadWrite(gScenarioObjective.Year); + cs.ReadWrite(gScenarioObjective.NumGuests); + cs.ReadWrite(gScenarioObjective.Currency); + + cs.ReadWrite(gScenarioParkRatingWarningDays); + + cs.ReadWrite(gScenarioCompletedCompanyValue); + if (gScenarioCompletedCompanyValue == MONEY64_UNDEFINED + || gScenarioCompletedCompanyValue == COMPANY_VALUE_ON_FAILED_OBJECTIVE) + { + cs.Write(""); + } + else + { + cs.ReadWrite(gScenarioCompletedBy); + } + + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto earlyCompletion = cs.Read(); + if (network_get_mode() == NETWORK_MODE_CLIENT) + { + gAllowEarlyCompletionInNetworkPlay = earlyCompletion; + } + } + else + { + cs.Write(AllowEarlyCompletion()); + } + + if (os.GetHeader().TargetVersion >= 1) + { + cs.ReadWrite(gScenarioFileName); + } + }); + } + + void ReadWriteGeneralChunk(OrcaStream& os) + { + auto found = os.ReadWriteChunk(ParkFileChunkType::GENERAL, [this](OrcaStream::ChunkStream& cs) { + cs.ReadWrite(gGamePaused); + cs.ReadWrite(gCurrentTicks); + cs.ReadWrite(gDateMonthTicks); + cs.ReadWrite(gDateMonthsElapsed); + + if (cs.GetMode() == OrcaStream::Mode::READING) + { + uint32_t s0{}, s1{}; + cs.ReadWrite(s0); + cs.ReadWrite(s1); + Random::Rct2::Seed s{ s0, s1 }; + gScenarioRand.seed(s); + } + else + { + auto randState = gScenarioRand.state(); + cs.Write(randState.s0); + cs.Write(randState.s1); + } + + cs.ReadWrite(gGuestInitialHappiness); + cs.ReadWrite(gGuestInitialCash); + cs.ReadWrite(gGuestInitialHunger); + cs.ReadWrite(gGuestInitialThirst); + + cs.ReadWrite(gNextGuestNumber); + cs.ReadWriteVector(gPeepSpawns, [&cs](PeepSpawn& spawn) { + cs.ReadWrite(spawn.x); + cs.ReadWrite(spawn.y); + cs.ReadWrite(spawn.z); + cs.ReadWrite(spawn.direction); + }); + + cs.ReadWrite(gLandPrice); + cs.ReadWrite(gConstructionRightsPrice); + cs.ReadWrite(gGrassSceneryTileLoopPosition); + cs.ReadWrite(gWidePathTileLoopPosition); + + ReadWriteRideRatingCalculationData(cs, gRideRatingUpdateState); + }); + if (!found) + { + throw std::runtime_error("No general chunk found."); + } + } + + void ReadWriteRideRatingCalculationData(OrcaStream::ChunkStream& cs, RideRatingUpdateState& calcData) + { + cs.ReadWrite(calcData.AmountOfBrakes); + cs.ReadWrite(calcData.Proximity); + cs.ReadWrite(calcData.ProximityStart); + cs.ReadWrite(calcData.CurrentRide); + cs.ReadWrite(calcData.State); + cs.ReadWrite(calcData.ProximityTrackType); + cs.ReadWrite(calcData.ProximityBaseHeight); + cs.ReadWrite(calcData.ProximityTotal); + cs.ReadWriteArray(calcData.ProximityScores, [&cs](uint16_t& value) { + cs.ReadWrite(value); + return true; + }); + cs.ReadWrite(calcData.AmountOfBrakes); + cs.ReadWrite(calcData.AmountOfReversers); + cs.ReadWrite(calcData.StationFlags); + } + + void ReadWriteInterfaceChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::INTERFACE, [](OrcaStream::ChunkStream& cs) { + cs.ReadWrite(gSavedView.x); + cs.ReadWrite(gSavedView.y); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + gSavedViewZoom = static_cast(cs.Read()); + } + else + { + cs.Write(static_cast(gSavedViewZoom)); + } + cs.ReadWrite(gSavedViewRotation); + cs.ReadWrite(gLastEntranceStyle); + cs.ReadWrite(gEditorStep); + }); + } + + void ReadWriteCheatsChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::CHEATS, [](OrcaStream::ChunkStream& cs) { + DataSerialiser ds(cs.GetMode() == OrcaStream::Mode::WRITING, cs.GetStream()); + CheatsSerialise(ds); + }); + } + + void ReadWriteRestrictedObjectsChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::RESTRICTED_OBJECTS, [](OrcaStream::ChunkStream& cs) { + auto& restrictedScenery = GetRestrictedScenery(); + + // We are want to support all object types in the future, so convert scenery type + // to object type when we write the list + cs.ReadWriteVector(restrictedScenery, [&cs](ScenerySelection& item) { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + item.SceneryType = GetSceneryTypeFromObjectType(static_cast(cs.Read())); + item.EntryIndex = cs.Read(); + } + else + { + cs.Write(static_cast(GetObjectTypeFromSceneryType(item.SceneryType))); + cs.Write(item.EntryIndex); + } + }); + }); + } + + void ReadWritePackedObjectsChunk(OrcaStream& os) + { + static constexpr uint8_t DESCRIPTOR_DAT = 0; + static constexpr uint8_t DESCRIPTOR_PARKOBJ = 1; + + if (os.GetMode() == OrcaStream::Mode::WRITING && ExportObjectsList.size() == 0) + { + // Do not emit chunk if there are no packed objects + return; + } + + os.ReadWriteChunk(ParkFileChunkType::PACKED_OBJECTS, [this](OrcaStream::ChunkStream& cs) { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto& objRepository = GetContext()->GetObjectRepository(); + auto numObjects = cs.Read(); + for (uint32_t i = 0; i < numObjects; i++) + { + auto type = cs.Read(); + if (type == DESCRIPTOR_DAT) + { + rct_object_entry entry; + cs.Read(&entry, sizeof(entry)); + auto size = cs.Read(); + std::vector data; + data.resize(size); + cs.Read(data.data(), data.size()); + + auto legacyIdentifier = entry.GetName(); + if (objRepository.FindObjectLegacy(legacyIdentifier) == nullptr) + { + objRepository.AddObjectFromFile( + ObjectGeneration::DAT, legacyIdentifier, data.data(), data.size()); + } + } + else if (type == DESCRIPTOR_PARKOBJ) + { + auto identifier = cs.Read(); + auto size = cs.Read(); + std::vector data; + data.resize(size); + cs.Read(data.data(), data.size()); + if (objRepository.FindObject(identifier) == nullptr) + { + objRepository.AddObjectFromFile(ObjectGeneration::JSON, identifier, data.data(), data.size()); + } + } + else + { + throw std::runtime_error("Unsupported packed object"); + } + } + } + else + { + auto& stream = cs.GetStream(); + auto countPosition = stream.GetPosition(); + + // Write placeholder count, update later + uint32_t count = 0; + cs.Write(count); + + // Write objects + for (const auto* ori : ExportObjectsList) + { + auto extension = Path::GetExtension(ori->Path); + if (String::Equals(extension, ".dat", true)) + { + cs.Write(DESCRIPTOR_DAT); + cs.Write(&ori->ObjectEntry, sizeof(rct_object_entry)); + } + else if (String::Equals(extension, ".parkobj", true)) + { + cs.Write(DESCRIPTOR_PARKOBJ); + cs.Write(ori->Identifier); + } + else + { + Console::WriteLine("%s not packed: unsupported extension.", ori->Identifier.c_str()); + continue; + } + + auto data = File::ReadAllBytes(ori->Path); + cs.Write(static_cast(data.size())); + cs.Write(data.data(), data.size()); + count++; + } + + auto backupPosition = stream.GetPosition(); + stream.SetPosition(countPosition); + cs.Write(count); + stream.SetPosition(backupPosition); + } + }); + } + + void ReadWriteClimateChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::CLIMATE, [](OrcaStream::ChunkStream& cs) { + cs.ReadWrite(gClimate); + cs.ReadWrite(gClimateUpdateTimer); + + for (auto* cl : { &gClimateCurrent, &gClimateNext }) + { + cs.ReadWrite(cl->Weather); + cs.ReadWrite(cl->Temperature); + cs.ReadWrite(cl->WeatherEffect); + cs.ReadWrite(cl->WeatherGloom); + cs.ReadWrite(cl->Level); + } + }); + } + + void ReadWriteParkChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::PARK, [](OrcaStream::ChunkStream& cs) { + auto& park = GetContext()->GetGameState()->GetPark(); + cs.ReadWrite(park.Name); + cs.ReadWrite(gCash); + cs.ReadWrite(gBankLoan); + cs.ReadWrite(gMaxBankLoan); + cs.ReadWrite(gBankLoanInterestRate); + cs.ReadWrite(gParkFlags); + cs.ReadWrite(gParkEntranceFee); + cs.ReadWrite(gStaffHandymanColour); + cs.ReadWrite(gStaffMechanicColour); + cs.ReadWrite(gStaffSecurityColour); + cs.ReadWrite(gSamePriceThroughoutPark); + + // Finances + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto numMonths = std::min(EXPENDITURE_TABLE_MONTH_COUNT, cs.Read()); + auto numTypes = std::min(static_cast(ExpenditureType::Count), cs.Read()); + for (uint32_t i = 0; i < numMonths; i++) + { + for (uint32_t j = 0; j < numTypes; j++) + { + gExpenditureTable[i][j] = cs.Read(); + } + } + } + else + { + auto numMonths = static_cast(EXPENDITURE_TABLE_MONTH_COUNT); + auto numTypes = static_cast(ExpenditureType::Count); + + cs.Write(numMonths); + cs.Write(numTypes); + for (uint32_t i = 0; i < numMonths; i++) + { + for (uint32_t j = 0; j < numTypes; j++) + { + cs.Write(gExpenditureTable[i][j]); + } + } + } + cs.ReadWrite(gHistoricalProfit); + + // Marketing + cs.ReadWriteVector(gMarketingCampaigns, [&cs](MarketingCampaign& campaign) { + cs.ReadWrite(campaign.Type); + cs.ReadWrite(campaign.WeeksLeft); + cs.ReadWrite(campaign.Flags); + cs.ReadWrite(campaign.RideId); + }); + + // Awards + cs.ReadWriteArray(gCurrentAwards, [&cs](Award& award) { + if (award.Time != 0) + { + cs.ReadWrite(award.Time); + cs.ReadWrite(award.Type); + return true; + } + + return false; + }); + + cs.ReadWrite(gParkValue); + cs.ReadWrite(gCompanyValue); + cs.ReadWrite(gParkSize); + cs.ReadWrite(gNumGuestsInPark); + cs.ReadWrite(gNumGuestsHeadingForPark); + cs.ReadWrite(gParkRating); + cs.ReadWrite(gParkRatingCasualtyPenalty); + cs.ReadWrite(gCurrentExpenditure); + cs.ReadWrite(gCurrentProfit); + cs.ReadWrite(gWeeklyProfitAverageDividend); + cs.ReadWrite(gWeeklyProfitAverageDivisor); + cs.ReadWrite(gTotalAdmissions); + cs.ReadWrite(gTotalIncomeFromAdmissions); + cs.ReadWrite(gTotalRideValueForMoney); + cs.ReadWrite(gNumGuestsInParkLastWeek); + cs.ReadWrite(gGuestChangeModifier); + cs.ReadWrite(_guestGenerationProbability); + cs.ReadWrite(_suggestedGuestMaximum); + + cs.ReadWriteArray(gPeepWarningThrottle, [&cs](uint8_t& value) { + cs.ReadWrite(value); + return true; + }); + + cs.ReadWriteArray(gParkRatingHistory, [&cs](uint8_t& value) { + cs.ReadWrite(value); + return true; + }); + + cs.ReadWriteArray(gGuestsInParkHistory, [&cs](uint32_t& value) { + cs.ReadWrite(value); + return true; + }); + + cs.ReadWriteArray(gCashHistory, [&cs](money64& value) { + cs.ReadWrite(value); + return true; + }); + cs.ReadWriteArray(gWeeklyProfitHistory, [&cs](money64& value) { + cs.ReadWrite(value); + return true; + }); + cs.ReadWriteArray(gParkValueHistory, [&cs](money64& value) { + cs.ReadWrite(value); + return true; + }); + }); + } + + void ReadWriteResearchChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::RESEARCH, [](OrcaStream::ChunkStream& cs) { + // Research status + cs.ReadWrite(gResearchFundingLevel); + cs.ReadWrite(gResearchPriorities); + cs.ReadWrite(gResearchProgressStage); + cs.ReadWrite(gResearchProgress); + cs.ReadWrite(gResearchExpectedMonth); + cs.ReadWrite(gResearchExpectedDay); + ReadWriteResearchItem(cs, gResearchLastItem); + ReadWriteResearchItem(cs, gResearchNextItem); + + // Invention list + cs.ReadWriteVector(gResearchItemsUninvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); + cs.ReadWriteVector(gResearchItemsInvented, [&cs](ResearchItem& item) { ReadWriteResearchItem(cs, item); }); + }); + } + + static void ReadWriteResearchItem(OrcaStream::ChunkStream& cs, std::optional& item) + { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto hasValue = cs.Read(); + if (hasValue) + { + ResearchItem placeholder; + ReadWriteResearchItem(cs, placeholder); + item = placeholder; + } + } + else + { + if (item) + { + cs.Write(true); + ReadWriteResearchItem(cs, *item); + } + else + { + cs.Write(false); + } + } + } + + static void ReadWriteResearchItem(OrcaStream::ChunkStream& cs, ResearchItem& item) + { + cs.ReadWrite(item.type); + cs.ReadWrite(item.baseRideType); + cs.ReadWrite(item.entryIndex); + cs.ReadWrite(item.flags); + cs.ReadWrite(item.category); + } + + void ReadWriteNotificationsChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::NOTIFICATIONS, [](OrcaStream::ChunkStream& cs) { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + gNewsItems.Clear(); + + std::vector recent; + cs.ReadWriteVector(recent, [&cs](News::Item& item) { ReadWriteNewsItem(cs, item); }); + for (size_t i = 0; i < std::min(recent.size(), News::ItemHistoryStart); i++) + { + gNewsItems[i] = recent[i]; + } + + std::vector archived; + cs.ReadWriteVector(archived, [&cs](News::Item& item) { ReadWriteNewsItem(cs, item); }); + size_t offset = News::ItemHistoryStart; + for (size_t i = 0; i < std::min(archived.size(), News::MaxItemsArchive); i++) + { + gNewsItems[offset + i] = archived[i]; + } + } + else + { + std::vector recent(std::begin(gNewsItems.GetRecent()), std::end(gNewsItems.GetRecent())); + cs.ReadWriteVector(recent, [&cs](News::Item& item) { ReadWriteNewsItem(cs, item); }); + + std::vector archived(std::begin(gNewsItems.GetArchived()), std::end(gNewsItems.GetArchived())); + cs.ReadWriteVector(archived, [&cs](News::Item& item) { ReadWriteNewsItem(cs, item); }); + } + }); + } + + static void ReadWriteNewsItem(OrcaStream::ChunkStream& cs, News::Item& item) + { + cs.ReadWrite(item.Type); + cs.ReadWrite(item.Flags); + cs.ReadWrite(item.Assoc); + cs.ReadWrite(item.Ticks); + cs.ReadWrite(item.MonthYear); + cs.ReadWrite(item.Day); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto s = cs.Read(); + item.Text = s; + } + else + { + cs.Write(std::string_view(item.Text)); + } + } + + void ReadWriteTilesChunk(OrcaStream& os) + { + auto* pathToSurfaceMap = _pathToSurfaceMap; + auto* pathToQueueSurfaceMap = _pathToQueueSurfaceMap; + auto* pathToRailingsMap = _pathToRailingsMap; + + auto found = os.ReadWriteChunk( + ParkFileChunkType::TILES, + [pathToSurfaceMap, pathToQueueSurfaceMap, pathToRailingsMap](OrcaStream::ChunkStream& cs) { + cs.ReadWrite(gMapSize); // x + cs.Write(gMapSize); // y + + if (cs.GetMode() == OrcaStream::Mode::READING) + { + OpenRCT2::GetContext()->GetGameState()->InitAll(gMapSize); + + auto numElements = cs.Read(); + + std::vector tileElements; + tileElements.resize(numElements); + cs.Read(tileElements.data(), tileElements.size() * sizeof(TileElement)); + SetTileElements(std::move(tileElements)); + { + tile_element_iterator it; + tile_element_iterator_begin(&it); + while (tile_element_iterator_next(&it)) + { + if (it.element->GetType() == TILE_ELEMENT_TYPE_PATH) + { + auto* pathElement = it.element->AsPath(); + if (pathElement->HasLegacyPathEntry()) + { + auto pathEntryIndex = pathElement->GetLegacyPathEntryIndex(); + if (pathToRailingsMap[pathEntryIndex] != OBJECT_ENTRY_INDEX_NULL) + { + if (pathElement->IsQueue()) + pathElement->SetSurfaceEntryIndex(pathToQueueSurfaceMap[pathEntryIndex]); + else + pathElement->SetSurfaceEntryIndex(pathToSurfaceMap[pathEntryIndex]); + + pathElement->SetRailingsEntryIndex(pathToRailingsMap[pathEntryIndex]); + } + } + } + } + } + UpdateParkEntranceLocations(); + } + else + { + auto tileElements = GetReorganisedTileElementsWithoutGhosts(); + cs.Write(static_cast(tileElements.size())); + cs.Write(tileElements.data(), tileElements.size() * sizeof(TileElement)); + } + }); + if (!found) + { + throw std::runtime_error("No tiles chunk found."); + } + } + + void UpdateTrackElementsRideType() + { + for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) + { + for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) + { + TileElement* tileElement = map_get_first_element_at(TileCoordsXY{ x, y }); + if (tileElement == nullptr) + continue; + do + { + if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) + continue; + + auto* trackElement = tileElement->AsTrack(); + const auto* ride = get_ride(trackElement->GetRideIndex()); + if (ride != nullptr) + { + trackElement->SetRideType(ride->type); + } + + } while (!(tileElement++)->IsLastForTile()); + } + } + } + + void ReadWriteBannersChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::BANNERS, [&os](OrcaStream::ChunkStream& cs) { + auto version = os.GetHeader().TargetVersion; + if (cs.GetMode() == OrcaStream::Mode::WRITING) + { + auto numBanners = GetNumBanners(); + cs.Write(static_cast(numBanners)); + + [[maybe_unused]] size_t numWritten = 0; + for (BannerIndex i = 0; i < MAX_BANNERS; i++) + { + auto banner = GetBanner(i); + if (banner != nullptr) + { + ReadWriteBanner(version, cs, *banner); + numWritten++; + } + } + + assert(numWritten == numBanners); + } + else if (cs.GetMode() == OrcaStream::Mode::READING) + { + if (version == 0) + { + std::vector banners; + cs.ReadWriteVector(banners, [version, &cs](Banner& banner) { ReadWriteBanner(version, cs, banner); }); + for (size_t i = 0; i < banners.size(); i++) + { + auto bannerIndex = static_cast(i); + auto banner = GetOrCreateBanner(bannerIndex); + if (banner != nullptr) + { + *banner = std::move(banners[i]); + banner->id = bannerIndex; + } + } + } + else + { + auto numBanners = cs.Read(); + for (size_t i = 0; i < numBanners; i++) + { + Banner readBanner; + ReadWriteBanner(version, cs, readBanner); + + auto banner = GetOrCreateBanner(readBanner.id); + if (banner == nullptr) + { + throw std::runtime_error("Invalid banner index"); + } + else + { + *banner = std::move(readBanner); + } + } + } + } + }); + } + + static void ReadWriteBanner(uint32_t version, OrcaStream::ChunkStream& cs, Banner& banner) + { + if (version >= 1) + { + cs.ReadWrite(banner.id); + } + cs.ReadWrite(banner.type); + cs.ReadWrite(banner.flags); + cs.ReadWrite(banner.text); + cs.ReadWrite(banner.colour); + cs.ReadWrite(banner.ride_index); + cs.ReadWrite(banner.text_colour); + cs.ReadWrite(banner.position.x); + cs.ReadWrite(banner.position.y); + } + + void ReadWriteRidesChunk(OrcaStream& os) + { + const auto version = os.GetHeader().TargetVersion; + os.ReadWriteChunk(ParkFileChunkType::RIDES, [this, &version](OrcaStream::ChunkStream& cs) { + std::vector rideIds; + if (cs.GetMode() == OrcaStream::Mode::READING) + { + ride_init_all(); + } + else + { + if (OmitTracklessRides) + { + auto tracklessRides = GetTracklessRides(); + for (const auto& ride : GetRideManager()) + { + auto it = std::find(tracklessRides.begin(), tracklessRides.end(), ride.id); + if (it == tracklessRides.end()) + { + rideIds.push_back(ride.id); + } + } + } + else + { + for (const auto& ride : GetRideManager()) + { + rideIds.push_back(ride.id); + } + } + } + cs.ReadWriteVector(rideIds, [&cs, &version](ride_id_t& rideId) { + // Ride ID + cs.ReadWrite(rideId); + + auto& ride = *GetOrAllocateRide(rideId); + + // Status + cs.ReadWrite(ride.type); + cs.ReadWrite(ride.subtype); + cs.ReadWrite(ride.mode); + cs.ReadWrite(ride.status); + cs.ReadWrite(ride.depart_flags); + cs.ReadWrite(ride.lifecycle_flags); + + // Meta + cs.ReadWrite(ride.custom_name); + cs.ReadWrite(ride.default_name_number); + + cs.ReadWriteArray(ride.price, [&cs](money16& price) { + cs.ReadWrite(price); + return true; + }); + + // Colours + cs.ReadWrite(ride.entrance_style); + cs.ReadWrite(ride.colour_scheme_type); + cs.ReadWriteArray(ride.track_colour, [&cs](TrackColour& tc) { + cs.ReadWrite(tc.main); + cs.ReadWrite(tc.additional); + cs.ReadWrite(tc.supports); + return true; + }); + + cs.ReadWriteArray(ride.vehicle_colours, [&cs](VehicleColour& vc) { + cs.ReadWrite(vc.Body); + cs.ReadWrite(vc.Trim); + cs.ReadWrite(vc.Ternary); + return true; + }); + + // Stations + cs.ReadWrite(ride.num_stations); + cs.ReadWriteArray(ride.stations, [&cs](RideStation& station) { + cs.ReadWrite(station.Start); + cs.ReadWrite(station.Height); + cs.ReadWrite(station.Length); + cs.ReadWrite(station.Depart); + cs.ReadWrite(station.TrainAtStation); + cs.ReadWrite(station.Entrance); + cs.ReadWrite(station.Exit); + cs.ReadWrite(station.SegmentLength); + cs.ReadWrite(station.SegmentTime); + cs.ReadWrite(station.QueueTime); + cs.ReadWrite(station.QueueLength); + cs.ReadWrite(station.LastPeepInQueue); + return true; + }); + + cs.ReadWrite(ride.overall_view.x); + cs.ReadWrite(ride.overall_view.y); + + // Vehicles + cs.ReadWrite(ride.num_vehicles); + cs.ReadWrite(ride.num_cars_per_train); + cs.ReadWrite(ride.proposed_num_vehicles); + cs.ReadWrite(ride.proposed_num_cars_per_train); + cs.ReadWrite(ride.max_trains); + if (version < 0x5) + { + uint8_t value; + cs.ReadWrite(value); + ride.MinCarsPerTrain = GetMinCarsPerTrain(value); + ride.MaxCarsPerTrain = GetMaxCarsPerTrain(value); + } + else + { + cs.ReadWrite(ride.MinCarsPerTrain); + cs.ReadWrite(ride.MaxCarsPerTrain); + } + + cs.ReadWrite(ride.min_waiting_time); + cs.ReadWrite(ride.max_waiting_time); + cs.ReadWriteArray(ride.vehicles, [&cs](uint16_t& v) { + cs.ReadWrite(v); + return true; + }); + + // Operation + cs.ReadWrite(ride.operation_option); + cs.ReadWrite(ride.lift_hill_speed); + cs.ReadWrite(ride.num_circuits); + + // Special + cs.ReadWrite(ride.boat_hire_return_direction); + cs.ReadWrite(ride.boat_hire_return_position); + cs.ReadWrite(ride.ChairliftBullwheelLocation[0]); + cs.ReadWrite(ride.ChairliftBullwheelLocation[1]); + cs.ReadWrite(ride.chairlift_bullwheel_rotation); + cs.ReadWrite(ride.slide_in_use); + cs.ReadWrite(ride.slide_peep); + cs.ReadWrite(ride.slide_peep_t_shirt_colour); + cs.ReadWrite(ride.spiral_slide_progress); + cs.ReadWrite(ride.race_winner); + cs.ReadWrite(ride.cable_lift); + cs.ReadWrite(ride.CableLiftLoc); + + // Stats + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto hasMeasurement = cs.Read(); + if (hasMeasurement != 0) + { + ride.measurement = std::make_unique(); + ReadWriteRideMeasurement(cs, *ride.measurement); + } + } + else + { + if (ride.measurement == nullptr) + { + cs.Write(0); + } + else + { + cs.Write(1); + ReadWriteRideMeasurement(cs, *ride.measurement); + } + } + + cs.ReadWrite(ride.special_track_elements); + cs.ReadWrite(ride.max_speed); + cs.ReadWrite(ride.average_speed); + cs.ReadWrite(ride.current_test_segment); + cs.ReadWrite(ride.average_speed_test_timeout); + + cs.ReadWrite(ride.max_positive_vertical_g); + cs.ReadWrite(ride.max_negative_vertical_g); + cs.ReadWrite(ride.max_lateral_g); + cs.ReadWrite(ride.previous_vertical_g); + cs.ReadWrite(ride.previous_lateral_g); + + cs.ReadWrite(ride.testing_flags); + cs.ReadWrite(ride.CurTestTrackLocation); + + cs.ReadWrite(ride.turn_count_default); + cs.ReadWrite(ride.turn_count_banked); + cs.ReadWrite(ride.turn_count_sloped); + + cs.ReadWrite(ride.inversions); + cs.ReadWrite(ride.drops); + cs.ReadWrite(ride.start_drop_height); + cs.ReadWrite(ride.highest_drop_height); + cs.ReadWrite(ride.sheltered_length); + cs.ReadWrite(ride.var_11C); + cs.ReadWrite(ride.num_sheltered_sections); + cs.ReadWrite(ride.current_test_station); + cs.ReadWrite(ride.num_block_brakes); + cs.ReadWrite(ride.total_air_time); + + cs.ReadWrite(ride.excitement); + cs.ReadWrite(ride.intensity); + cs.ReadWrite(ride.nausea); + + cs.ReadWrite(ride.value); + + cs.ReadWrite(ride.num_riders); + cs.ReadWrite(ride.build_date); + cs.ReadWrite(ride.upkeep_cost); + + cs.ReadWrite(ride.cur_num_customers); + cs.ReadWrite(ride.num_customers_timeout); + + cs.ReadWriteArray(ride.num_customers, [&cs](uint16_t& v) { + cs.ReadWrite(v); + return true; + }); + + cs.ReadWrite(ride.total_customers); + cs.ReadWrite(ride.total_profit); + cs.ReadWrite(ride.popularity); + cs.ReadWrite(ride.popularity_time_out); + cs.ReadWrite(ride.popularity_next); + cs.ReadWrite(ride.guests_favourite); + cs.ReadWrite(ride.no_primary_items_sold); + cs.ReadWrite(ride.no_secondary_items_sold); + cs.ReadWrite(ride.income_per_hour); + cs.ReadWrite(ride.profit); + cs.ReadWrite(ride.satisfaction); + cs.ReadWrite(ride.satisfaction_time_out); + cs.ReadWrite(ride.satisfaction_next); + + // Breakdown + cs.ReadWrite(ride.breakdown_reason_pending); + cs.ReadWrite(ride.mechanic_status); + cs.ReadWrite(ride.mechanic); + cs.ReadWrite(ride.inspection_station); + cs.ReadWrite(ride.broken_vehicle); + cs.ReadWrite(ride.broken_car); + cs.ReadWrite(ride.breakdown_reason); + cs.ReadWrite(ride.reliability_subvalue); + cs.ReadWrite(ride.reliability_percentage); + cs.ReadWrite(ride.unreliability_factor); + cs.ReadWrite(ride.downtime); + cs.ReadWrite(ride.inspection_interval); + cs.ReadWrite(ride.last_inspection); + + cs.ReadWriteArray(ride.downtime_history, [&cs](uint8_t& v) { + cs.ReadWrite(v); + return true; + }); + + cs.ReadWrite(ride.breakdown_sound_modifier); + cs.ReadWrite(ride.not_fixed_timeout); + cs.ReadWrite(ride.last_crash_type); + cs.ReadWrite(ride.connected_message_throttle); + + cs.ReadWrite(ride.vehicle_change_timeout); + + cs.ReadWrite(ride.current_issues); + cs.ReadWrite(ride.last_issue_time); + + // Music + cs.ReadWrite(ride.music); + cs.ReadWrite(ride.music_tune_id); + cs.ReadWrite(ride.music_position); + return true; + }); + }); + } + + static void ReadWriteRideMeasurement(OrcaStream::ChunkStream& cs, RideMeasurement& measurement) + { + cs.ReadWrite(measurement.flags); + cs.ReadWrite(measurement.last_use_tick); + cs.ReadWrite(measurement.num_items); + cs.ReadWrite(measurement.current_item); + cs.ReadWrite(measurement.vehicle_index); + cs.ReadWrite(measurement.current_station); + for (size_t i = 0; i < measurement.num_items; i++) + { + cs.ReadWrite(measurement.vertical[i]); + cs.ReadWrite(measurement.lateral[i]); + cs.ReadWrite(measurement.velocity[i]); + cs.ReadWrite(measurement.altitude[i]); + } + } + + template static void ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, T& entity); + + static void ReadWriteEntityCommon(OrcaStream::ChunkStream& cs, EntityBase& entity) + { + cs.ReadWrite(entity.sprite_index); + cs.ReadWrite(entity.sprite_height_negative); + cs.ReadWrite(entity.x); + cs.ReadWrite(entity.y); + cs.ReadWrite(entity.z); + cs.ReadWrite(entity.sprite_width); + cs.ReadWrite(entity.sprite_height_positive); + cs.ReadWrite(entity.sprite_direction); + } + + static std::vector LegacyGetRideTypesBeenOn(const std::array& srcArray) + { + std::vector ridesTypesBeenOn; + for (ObjectEntryIndex i = 0; i < RCT12_MAX_RIDE_OBJECTS; i++) + { + if (srcArray[i / 8] & (1 << (i % 8))) + { + ridesTypesBeenOn.push_back(i); + } + } + return ridesTypesBeenOn; + } + static std::vector LegacyGetRidesBeenOn(const std::array& srcArray) + { + std::vector ridesBeenOn; + for (uint16_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) + { + if (srcArray[i / 8] & (1 << (i % 8))) + { + ridesBeenOn.push_back(static_cast(i)); + } + } + return ridesBeenOn; + } + + static void ReadWritePeep(OrcaStream& os, OrcaStream::ChunkStream& cs, Peep& entity) + { + auto version = os.GetHeader().TargetVersion; + + ReadWriteEntityCommon(cs, entity); + + auto guest = entity.As(); + auto staff = entity.As(); + + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto name = cs.Read(); + entity.SetName(name); + } + else + { + cs.Write(static_cast(entity.Name)); + } + + cs.ReadWrite(entity.NextLoc); + cs.ReadWrite(entity.NextFlags); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->OutsideOfPark); + } + else + { + cs.Ignore(); + } + } + + cs.ReadWrite(entity.State); + cs.ReadWrite(entity.SubState); + cs.ReadWrite(entity.SpriteType); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestNumRides); + } + else + { + cs.ReadWrite(staff->AssignedStaffType); + } + } + + cs.ReadWrite(entity.TshirtColour); + cs.ReadWrite(entity.TrousersColour); + cs.ReadWrite(entity.DestinationX); + cs.ReadWrite(entity.DestinationY); + cs.ReadWrite(entity.DestinationTolerance); + cs.ReadWrite(entity.Var37); + cs.ReadWrite(entity.Energy); + cs.ReadWrite(entity.EnergyTarget); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->Happiness); + cs.ReadWrite(guest->HappinessTarget); + cs.ReadWrite(guest->Nausea); + cs.ReadWrite(guest->NauseaTarget); + cs.ReadWrite(guest->Hunger); + cs.ReadWrite(guest->Thirst); + cs.ReadWrite(guest->Toilet); + } + else + { + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } + } + + cs.ReadWrite(entity.Mass); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->TimeToConsume); + } + else + { + uint8_t temp{}; + cs.ReadWrite(temp); + } + } + + if (version <= 1) + { + if (guest != nullptr) + { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + guest->Intensity = IntensityRange(cs.Read()); + } + else + { + cs.Write(static_cast(guest->Intensity)); + } + cs.ReadWrite(guest->NauseaTolerance); + } + else + { + cs.Ignore(); + cs.Ignore(); + } + } + + cs.ReadWrite(entity.WindowInvalidateFlags); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->PaidOnDrink); + std::array rideTypeBeenOn; + cs.ReadWriteArray(rideTypeBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + OpenRCT2::RideUse::GetTypeHistory().Set(guest->sprite_index, LegacyGetRideTypesBeenOn(rideTypeBeenOn)); + cs.ReadWrite(guest->ItemFlags); + cs.ReadWrite(guest->Photo2RideRef); + cs.ReadWrite(guest->Photo3RideRef); + cs.ReadWrite(guest->Photo4RideRef); + } + else + { + cs.Ignore(); + + std::vector temp; + cs.ReadWriteVector(temp, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } + } + + cs.ReadWrite(entity.CurrentRide); + cs.ReadWrite(entity.CurrentRideStation); + cs.ReadWrite(entity.CurrentTrain); + cs.ReadWrite(entity.TimeToSitdown); + cs.ReadWrite(entity.SpecialSprite); + cs.ReadWrite(entity.ActionSpriteType); + cs.ReadWrite(entity.NextActionSpriteType); + cs.ReadWrite(entity.ActionSpriteImageOffset); + cs.ReadWrite(entity.Action); + cs.ReadWrite(entity.ActionFrame); + cs.ReadWrite(entity.StepProgress); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestNextInQueue); + } + else + { + cs.ReadWrite(staff->MechanicTimeSinceCall); + } + } + + cs.ReadWrite(entity.PeepDirection); + cs.ReadWrite(entity.InteractionRideIndex); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->TimeInQueue); + std::array ridesBeenOn; + cs.ReadWriteArray(ridesBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + OpenRCT2::RideUse::GetHistory().Set(guest->sprite_index, LegacyGetRidesBeenOn(ridesBeenOn)); + } + else + { + cs.Ignore(); + + std::vector ridesBeenOn; + cs.ReadWriteVector(ridesBeenOn, [&cs](uint8_t& rideId) { + cs.ReadWrite(rideId); + return true; + }); + } + } + + cs.ReadWrite(entity.Id); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->CashInPocket); + cs.ReadWrite(guest->CashSpent); + cs.ReadWrite(guest->ParkEntryTime); + cs.ReadWrite(guest->RejoinQueueTimeout); + cs.ReadWrite(guest->PreviousRide); + cs.ReadWrite(guest->PreviousRideTimeOut); + cs.ReadWriteArray(guest->Thoughts, [&cs](PeepThought& thought) { + cs.ReadWrite(thought.type); + + uint8_t item; + cs.ReadWrite(item); + if (item == 255) + { + thought.item = PeepThoughtItemNone; + } + else + { + thought.item = item; + } + + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + } + else + { + cs.Ignore(); + cs.Ignore(); + cs.ReadWrite(staff->HireDate); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + + std::vector temp; + cs.ReadWriteVector(temp, [&cs](PeepThought& thought) { + cs.ReadWrite(thought.type); + cs.ReadWrite(thought.item); + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + } + } + + cs.ReadWrite(entity.PathCheckOptimisation); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->GuestHeadingToRideId); + cs.ReadWrite(guest->GuestIsLostCountdown); + cs.ReadWrite(guest->Photo1RideRef); + } + else + { + cs.Ignore(); + cs.ReadWrite(staff->StaffOrders); + cs.Ignore(); + } + } + + cs.ReadWrite(entity.PeepFlags); + cs.ReadWrite(entity.PathfindGoal.x); + cs.ReadWrite(entity.PathfindGoal.y); + cs.ReadWrite(entity.PathfindGoal.z); + cs.ReadWrite(entity.PathfindGoal.direction); + for (size_t i = 0; i < std::size(entity.PathfindHistory); i++) + { + cs.ReadWrite(entity.PathfindHistory[i].x); + cs.ReadWrite(entity.PathfindHistory[i].y); + cs.ReadWrite(entity.PathfindHistory[i].z); + cs.ReadWrite(entity.PathfindHistory[i].direction); + } + cs.ReadWrite(entity.WalkingFrameNum); + + if (version <= 1) + { + if (guest != nullptr) + { + cs.ReadWrite(guest->LitterCount); + cs.ReadWrite(guest->GuestTimeOnRide); + cs.ReadWrite(guest->DisgustingCount); + cs.ReadWrite(guest->PaidToEnter); + cs.ReadWrite(guest->PaidOnRides); + cs.ReadWrite(guest->PaidOnFood); + cs.ReadWrite(guest->PaidOnSouvenirs); + cs.ReadWrite(guest->AmountOfFood); + cs.ReadWrite(guest->AmountOfDrinks); + cs.ReadWrite(guest->AmountOfSouvenirs); + cs.ReadWrite(guest->VandalismSeen); + cs.ReadWrite(guest->VoucherType); + cs.ReadWrite(guest->VoucherRideId); + cs.ReadWrite(guest->SurroundingsThoughtTimeout); + cs.ReadWrite(guest->Angriness); + cs.ReadWrite(guest->TimeLost); + cs.ReadWrite(guest->DaysInQueue); + cs.ReadWrite(guest->BalloonColour); + cs.ReadWrite(guest->UmbrellaColour); + cs.ReadWrite(guest->HatColour); + cs.ReadWrite(guest->FavouriteRide); + cs.ReadWrite(guest->FavouriteRideRating); + } + else + { + cs.Ignore(); + cs.ReadWrite(staff->StaffMowingTimeout); + cs.Ignore(); + cs.ReadWrite(staff->StaffLawnsMown); + cs.ReadWrite(staff->StaffGardensWatered); + cs.ReadWrite(staff->StaffLitterSwept); + cs.ReadWrite(staff->StaffBinsEmptied); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + cs.Ignore(); + } + } + } + + template void WriteEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs); + template void WriteEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs); + + template void ReadEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs); + + template void ReadEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs); + + void ReadWriteEntitiesChunk(OrcaStream& os); + + static void ReadWriteStringTable(OrcaStream::ChunkStream& cs, std::string& value, const std::string_view& lcode) + { + std::vector> table; + if (cs.GetMode() != OrcaStream::Mode::READING) + { + table.push_back(std::make_tuple(std::string(lcode), value)); + } + cs.ReadWriteVector(table, [&cs](std::tuple& v) { + cs.ReadWrite(std::get<0>(v)); + cs.ReadWrite(std::get<1>(v)); + }); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + auto fr = std::find_if(table.begin(), table.end(), [&lcode](const std::tuple& v) { + return std::get<0>(v) == lcode; + }); + if (fr != table.end()) + { + value = std::get<1>(*fr); + } + else if (table.size() > 0) + { + value = std::get<1>(table[0]); + } + else + { + value = ""; + } + } + } + }; + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Vehicle& entity) + { + ReadWriteEntityCommon(cs, entity); + cs.ReadWrite(entity.SubType); + cs.ReadWrite(entity.Pitch); + cs.ReadWrite(entity.bank_rotation); + cs.ReadWrite(entity.remaining_distance); + cs.ReadWrite(entity.velocity); + cs.ReadWrite(entity.acceleration); + cs.ReadWrite(entity.ride); + cs.ReadWrite(entity.vehicle_type); + cs.ReadWrite(entity.colours.body_colour); + cs.ReadWrite(entity.colours.trim_colour); + cs.ReadWrite(entity.track_progress); + cs.ReadWrite(entity.BoatLocation); + cs.ReadWrite(entity.TrackTypeAndDirection); + cs.ReadWrite(entity.TrackLocation.x); + cs.ReadWrite(entity.TrackLocation.y); + cs.ReadWrite(entity.TrackLocation.z); + cs.ReadWrite(entity.next_vehicle_on_train); + cs.ReadWrite(entity.prev_vehicle_on_ride); + cs.ReadWrite(entity.next_vehicle_on_ride); + cs.ReadWrite(entity.var_44); + cs.ReadWrite(entity.mass); + cs.ReadWrite(entity.update_flags); + cs.ReadWrite(entity.SwingSprite); + cs.ReadWrite(entity.current_station); + cs.ReadWrite(entity.current_time); + cs.ReadWrite(entity.crash_z); + cs.ReadWrite(entity.status); + cs.ReadWrite(entity.sub_state); + for (size_t i = 0; i < std::size(entity.peep); i++) + { + cs.ReadWrite(entity.peep[i]); + cs.ReadWrite(entity.peep_tshirt_colours[i]); + } + cs.ReadWrite(entity.num_seats); + cs.ReadWrite(entity.num_peeps); + cs.ReadWrite(entity.next_free_seat); + cs.ReadWrite(entity.restraints_position); + cs.ReadWrite(entity.crash_x); + cs.ReadWrite(entity.sound2_flags); + cs.ReadWrite(entity.spin_sprite); + cs.ReadWrite(entity.sound1_id); + cs.ReadWrite(entity.sound1_volume); + cs.ReadWrite(entity.sound2_id); + cs.ReadWrite(entity.sound2_volume); + cs.ReadWrite(entity.sound_vector_factor); + cs.ReadWrite(entity.time_waiting); + cs.ReadWrite(entity.speed); + cs.ReadWrite(entity.powered_acceleration); + cs.ReadWrite(entity.dodgems_collision_direction); + cs.ReadWrite(entity.animation_frame); + cs.ReadWrite(entity.animationState); + cs.ReadWrite(entity.scream_sound_id); + cs.ReadWrite(entity.TrackSubposition); + cs.ReadWrite(entity.var_CE); + cs.ReadWrite(entity.var_CF); + cs.ReadWrite(entity.lost_time_out); + cs.ReadWrite(entity.vertical_drop_countdown); + cs.ReadWrite(entity.var_D3); + cs.ReadWrite(entity.mini_golf_current_animation); + cs.ReadWrite(entity.mini_golf_flags); + cs.ReadWrite(entity.ride_subtype); + cs.ReadWrite(entity.colours_extended); + cs.ReadWrite(entity.seat_rotation); + cs.ReadWrite(entity.target_seat_rotation); + cs.ReadWrite(entity.IsCrashedVehicle); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Guest& guest) + { + ReadWritePeep(os, cs, guest); + + if (os.GetHeader().TargetVersion <= 1) + { + return; + } + + cs.ReadWrite(guest.GuestNumRides); + cs.ReadWrite(guest.GuestNextInQueue); + cs.ReadWrite(guest.ParkEntryTime); + cs.ReadWrite(guest.GuestHeadingToRideId); + cs.ReadWrite(guest.GuestIsLostCountdown); + cs.ReadWrite(guest.GuestTimeOnRide); + cs.ReadWrite(guest.PaidToEnter); + cs.ReadWrite(guest.PaidOnRides); + cs.ReadWrite(guest.PaidOnFood); + cs.ReadWrite(guest.PaidOnDrink); + cs.ReadWrite(guest.PaidOnSouvenirs); + cs.ReadWrite(guest.OutsideOfPark); + cs.ReadWrite(guest.Happiness); + cs.ReadWrite(guest.HappinessTarget); + cs.ReadWrite(guest.Nausea); + cs.ReadWrite(guest.NauseaTarget); + cs.ReadWrite(guest.Hunger); + cs.ReadWrite(guest.Thirst); + cs.ReadWrite(guest.Toilet); + cs.ReadWrite(guest.TimeToConsume); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + guest.Intensity = IntensityRange(cs.Read()); + } + else + { + cs.Write(static_cast(guest.Intensity)); + } + cs.ReadWrite(guest.NauseaTolerance); + + if (os.GetHeader().TargetVersion < 3) + { + std::array rideTypeBeenOn; + cs.ReadWriteArray(rideTypeBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + OpenRCT2::RideUse::GetTypeHistory().Set(guest.sprite_index, LegacyGetRideTypesBeenOn(rideTypeBeenOn)); + } + + cs.ReadWrite(guest.TimeInQueue); + if (os.GetHeader().TargetVersion < 3) + { + std::array ridesBeenOn; + cs.ReadWriteArray(ridesBeenOn, [&cs](uint8_t& rideType) { + cs.ReadWrite(rideType); + return true; + }); + OpenRCT2::RideUse::GetHistory().Set(guest.sprite_index, LegacyGetRidesBeenOn(ridesBeenOn)); + } + else + { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + std::vector rideUse; + cs.ReadWriteVector(rideUse, [&cs](ride_id_t& rideId) { cs.ReadWrite(rideId); }); + OpenRCT2::RideUse::GetHistory().Set(guest.sprite_index, std::move(rideUse)); + std::vector rideTypeUse; + cs.ReadWriteVector(rideTypeUse, [&cs](ObjectEntryIndex& rideType) { cs.ReadWrite(rideType); }); + OpenRCT2::RideUse::GetTypeHistory().Set(guest.sprite_index, std::move(rideTypeUse)); + } + else + { + auto* rideUse = OpenRCT2::RideUse::GetHistory().GetAll(guest.sprite_index); + if (rideUse == nullptr) + { + std::vector empty; + cs.ReadWriteVector(empty, [&cs](ride_id_t& rideId) { cs.ReadWrite(rideId); }); + } + else + { + cs.ReadWriteVector(*rideUse, [&cs](ride_id_t& rideId) { cs.ReadWrite(rideId); }); + } + auto* rideTypeUse = OpenRCT2::RideUse::GetTypeHistory().GetAll(guest.sprite_index); + if (rideTypeUse == nullptr) + { + std::vector empty; + cs.ReadWriteVector(empty, [&cs](ObjectEntryIndex& rideId) { cs.ReadWrite(rideId); }); + } + else + { + cs.ReadWriteVector(*rideTypeUse, [&cs](ObjectEntryIndex& rideId) { cs.ReadWrite(rideId); }); + } + } + } + cs.ReadWrite(guest.CashInPocket); + cs.ReadWrite(guest.CashSpent); + cs.ReadWrite(guest.Photo1RideRef); + cs.ReadWrite(guest.Photo2RideRef); + cs.ReadWrite(guest.Photo3RideRef); + cs.ReadWrite(guest.Photo4RideRef); + cs.ReadWrite(guest.RejoinQueueTimeout); + cs.ReadWrite(guest.PreviousRide); + cs.ReadWrite(guest.PreviousRideTimeOut); + cs.ReadWriteArray(guest.Thoughts, [&cs](PeepThought& thought) { + cs.ReadWrite(thought.type); + cs.ReadWrite(thought.item); + cs.ReadWrite(thought.freshness); + cs.ReadWrite(thought.fresh_timeout); + return true; + }); + cs.ReadWrite(guest.LitterCount); + cs.ReadWrite(guest.DisgustingCount); + cs.ReadWrite(guest.AmountOfFood); + cs.ReadWrite(guest.AmountOfDrinks); + cs.ReadWrite(guest.AmountOfSouvenirs); + cs.ReadWrite(guest.VandalismSeen); + cs.ReadWrite(guest.VoucherType); + cs.ReadWrite(guest.VoucherRideId); + cs.ReadWrite(guest.SurroundingsThoughtTimeout); + cs.ReadWrite(guest.Angriness); + cs.ReadWrite(guest.TimeLost); + cs.ReadWrite(guest.DaysInQueue); + cs.ReadWrite(guest.BalloonColour); + cs.ReadWrite(guest.UmbrellaColour); + cs.ReadWrite(guest.HatColour); + cs.ReadWrite(guest.FavouriteRide); + cs.ReadWrite(guest.FavouriteRideRating); + cs.ReadWrite(guest.ItemFlags); + } + + static std::vector GetPatrolArea(Staff& staff) + { + std::vector area; + if (staff.PatrolInfo != nullptr) + { + for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++) + { + // 32 blocks per array item (32 bits) + auto arrayItem = staff.PatrolInfo->Data[i]; + for (size_t j = 0; j < 32; j++) + { + auto blockIndex = (i * 32) + j; + if (arrayItem & (1 << j)) + { + auto sx = (blockIndex % STAFF_PATROL_AREA_BLOCKS_PER_LINE) * 4; + auto sy = (blockIndex / STAFF_PATROL_AREA_BLOCKS_PER_LINE) * 4; + for (size_t y = 0; y < 4; y++) + { + for (size_t x = 0; x < 4; x++) + { + area.push_back({ static_cast(sx + x), static_cast(sy + y) }); + } + } + } + } + } + } + return area; + } + + static void SetPatrolArea(Staff& staff, const std::vector& area) + { + if (area.empty()) + { + staff.ClearPatrolArea(); + } + else + { + for (const auto& coord : area) + { + staff.SetPatrolArea(coord.ToCoordsXY(), true); + } + } + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Staff& entity) + { + ReadWritePeep(os, cs, entity); + + std::vector patrolArea; + if (cs.GetMode() == OrcaStream::Mode::WRITING) + { + patrolArea = GetPatrolArea(entity); + } + cs.ReadWriteVector(patrolArea, [&cs](TileCoordsXY& value) { cs.ReadWrite(value); }); + if (cs.GetMode() == OrcaStream::Mode::READING) + { + SetPatrolArea(entity, patrolArea); + } + + if (os.GetHeader().TargetVersion <= 1) + { + return; + } + + cs.ReadWrite(entity.AssignedStaffType); + cs.ReadWrite(entity.MechanicTimeSinceCall); + cs.ReadWrite(entity.HireDate); + cs.ReadWrite(entity.StaffOrders); + cs.ReadWrite(entity.StaffMowingTimeout); + cs.ReadWrite(entity.StaffLawnsMown); + cs.ReadWrite(entity.StaffGardensWatered); + cs.ReadWrite(entity.StaffLitterSwept); + cs.ReadWrite(entity.StaffBinsEmptied); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, SteamParticle& steamParticle) + { + ReadWriteEntityCommon(cs, steamParticle); + cs.ReadWrite(steamParticle.time_to_move); + cs.ReadWrite(steamParticle.frame); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, MoneyEffect& moneyEffect) + { + ReadWriteEntityCommon(cs, moneyEffect); + cs.ReadWrite(moneyEffect.MoveDelay); + cs.ReadWrite(moneyEffect.NumMovements); + cs.ReadWrite(moneyEffect.Vertical); + cs.ReadWrite(moneyEffect.Value); + cs.ReadWrite(moneyEffect.OffsetX); + cs.ReadWrite(moneyEffect.Wiggle); + } + + template<> + void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, VehicleCrashParticle& vehicleCrashParticle) + { + ReadWriteEntityCommon(cs, vehicleCrashParticle); + cs.ReadWrite(vehicleCrashParticle.frame); + cs.ReadWrite(vehicleCrashParticle.time_to_live); + cs.ReadWrite(vehicleCrashParticle.frame); + cs.ReadWrite(vehicleCrashParticle.colour[0]); + cs.ReadWrite(vehicleCrashParticle.colour[1]); + cs.ReadWrite(vehicleCrashParticle.crashed_sprite_base); + cs.ReadWrite(vehicleCrashParticle.velocity_x); + cs.ReadWrite(vehicleCrashParticle.velocity_y); + cs.ReadWrite(vehicleCrashParticle.velocity_z); + cs.ReadWrite(vehicleCrashParticle.acceleration_x); + cs.ReadWrite(vehicleCrashParticle.acceleration_y); + cs.ReadWrite(vehicleCrashParticle.acceleration_z); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, ExplosionCloud& entity) + { + ReadWriteEntityCommon(cs, entity); + cs.ReadWrite(entity.frame); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, CrashSplashParticle& entity) + { + ReadWriteEntityCommon(cs, entity); + cs.ReadWrite(entity.frame); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, ExplosionFlare& entity) + { + ReadWriteEntityCommon(cs, entity); + cs.ReadWrite(entity.frame); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, JumpingFountain& fountain) + { + ReadWriteEntityCommon(cs, fountain); + cs.ReadWrite(fountain.NumTicksAlive); + cs.ReadWrite(fountain.frame); + cs.ReadWrite(fountain.FountainFlags); + cs.ReadWrite(fountain.TargetX); + cs.ReadWrite(fountain.TargetY); + cs.ReadWrite(fountain.TargetY); + cs.ReadWrite(fountain.Iteration); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Balloon& balloon) + { + ReadWriteEntityCommon(cs, balloon); + cs.ReadWrite(balloon.popped); + cs.ReadWrite(balloon.time_to_move); + cs.ReadWrite(balloon.frame); + cs.ReadWrite(balloon.colour); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Duck& duck) + { + ReadWriteEntityCommon(cs, duck); + cs.ReadWrite(duck.frame); + cs.ReadWrite(duck.target_x); + cs.ReadWrite(duck.target_y); + cs.ReadWrite(duck.state); + } + + template<> void ParkFile::ReadWriteEntity(OrcaStream& os, OrcaStream::ChunkStream& cs, Litter& entity) + { + ReadWriteEntityCommon(cs, entity); + cs.ReadWrite(entity.SubType); + cs.ReadWrite(entity.creationTick); + } + + template void ParkFile::WriteEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs) + { + uint16_t count = GetEntityListCount(T::cEntityType); + cs.Write(T::cEntityType); + cs.Write(count); + for (auto* ent : EntityList()) + { + cs.Write(ent->sprite_index); + ReadWriteEntity(os, cs, *ent); + } + } + + template void ParkFile::WriteEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs) + { + (WriteEntitiesOfType(os, cs), ...); + } + + template void ParkFile::ReadEntitiesOfType(OrcaStream& os, OrcaStream::ChunkStream& cs) + { + [[maybe_unused]] auto t = cs.Read(); + assert(t == T::cEntityType); + auto count = cs.Read(); + for (auto i = 0; i < count; ++i) + { + T placeholder{}; + + auto index = cs.Read(); + auto* ent = CreateEntityAt(index); + if (ent == nullptr) + { + // Unable to allocate entity + ent = &placeholder; + } + ReadWriteEntity(os, cs, *ent); + } + } + + template void ParkFile::ReadEntitiesOfTypes(OrcaStream& os, OrcaStream::ChunkStream& cs) + { + (ReadEntitiesOfType(os, cs), ...); + } + + void ParkFile::ReadWriteEntitiesChunk(OrcaStream& os) + { + os.ReadWriteChunk(ParkFileChunkType::ENTITIES, [this, &os](OrcaStream::ChunkStream& cs) { + if (cs.GetMode() == OrcaStream::Mode::READING) + { + reset_sprite_list(); + } + + std::vector entityIndices; + if (cs.GetMode() == OrcaStream::Mode::READING) + { + ReadEntitiesOfTypes< + Vehicle, Guest, Staff, Litter, SteamParticle, MoneyEffect, VehicleCrashParticle, ExplosionCloud, + CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(os, cs); + } + else + { + WriteEntitiesOfTypes< + Vehicle, Guest, Staff, Litter, SteamParticle, MoneyEffect, VehicleCrashParticle, ExplosionCloud, + CrashSplashParticle, ExplosionFlare, JumpingFountain, Balloon, Duck>(os, cs); + } + }); + } +} // namespace OpenRCT2 + +void ParkFileExporter::Export(std::string_view path) +{ + auto parkFile = std::make_unique(); + parkFile->Save(path); +} + +void ParkFileExporter::Export(IStream& stream) +{ + auto parkFile = std::make_unique(); + parkFile->ExportObjectsList = ExportObjectsList; + parkFile->Save(stream); +} + +enum : uint32_t +{ + S6_SAVE_FLAG_EXPORT = 1 << 0, + S6_SAVE_FLAG_SCENARIO = 1 << 1, + S6_SAVE_FLAG_AUTOMATIC = 1u << 31, +}; + +int32_t scenario_save(const utf8* path, int32_t flags) +{ + if (flags & S6_SAVE_FLAG_SCENARIO) + { + log_verbose("saving scenario"); + } + else + { + log_verbose("saving game"); + } + + if (!(flags & S6_SAVE_FLAG_AUTOMATIC)) + { + window_close_construction_windows(); + } + + viewport_set_saved_view(); + + bool result = false; + auto parkFile = std::make_unique(); + try + { + if (flags & S6_SAVE_FLAG_EXPORT) + { + auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); + parkFile->ExportObjectsList = objManager.GetPackableObjects(); + } + parkFile->OmitTracklessRides = true; + if (flags & S6_SAVE_FLAG_SCENARIO) + { + // s6exporter->SaveScenario(path); + } + else + { + // s6exporter->SaveGame(path); + } + parkFile->Save(path); + result = true; + } + catch (const std::exception&) + { + } + + gfx_invalidate_screen(); + + if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC)) + { + gScreenAge = 0; + } + return result; +} + +class ParkFileImporter final : public IParkImporter +{ +private: +#ifdef __clang__ + [[maybe_unused]] +#endif + const IObjectRepository& _objectRepository; + std::unique_ptr _parkFile; + +public: + ParkFileImporter(IObjectRepository& objectRepository) + : _objectRepository(objectRepository) + { + } + + ParkLoadResult Load(const utf8* path) override + { + _parkFile = std::make_unique(); + _parkFile->Load(path); + return ParkLoadResult(std::move(_parkFile->RequiredObjects)); + } + + ParkLoadResult LoadSavedGame(const utf8* path, bool skipObjectCheck = false) override + { + return Load(path); + } + + ParkLoadResult LoadScenario(const utf8* path, bool skipObjectCheck = false) override + { + return Load(path); + } + + ParkLoadResult LoadFromStream( + OpenRCT2::IStream* stream, bool isScenario, bool skipObjectCheck = false, const utf8* path = String::Empty) override + { + _parkFile = std::make_unique(); + _parkFile->Load(*stream); + return ParkLoadResult(std::move(_parkFile->RequiredObjects)); + } + + void Import() override + { + _parkFile->Import(); + game_fix_save_vars(); + } + + bool GetDetails(scenario_index_entry* dst) override + { + *dst = _parkFile->ReadScenarioChunk(); + return true; + } +}; + +std::unique_ptr ParkImporter::CreateParkFile(IObjectRepository& objectRepository) +{ + return std::make_unique(objectRepository); +} + +static std::map oldObjectIds = { + { "official.scgpanda", "rct2dlc.scenery_group.scgpanda" }, + { "official.wtrpink", "rct2dlc.water.wtrpink" }, + { "official.ttrftl07", "toontowner.scenery_small.ttrftl07" }, + { "official.pandagr", "rct2dlc.scenery_small.pandagr" }, + { "official.ttrftl04", "toontowner.scenery_small.ttrftl04" }, + { "official.bigpanda", "rct2dlc.scenery_small.bigpanda" }, + { "official.ttrftl02", "toontowner.scenery_small.ttrftl02" }, + { "official.ttrftl03", "toontowner.scenery_small.ttrftl03" }, + { "official.ttrftl08", "toontowner.scenery_small.ttrftl08" }, + { "official.xxbbbr01", "toontowner.scenery_small.xxbbbr01" }, + { "official.mg-prar", "mamabear.scenery_wall.mg-prar" }, + { "official.litterpa", "rct2dlc.footpath_item.litterpa" }, + { "openrct2.railings.invisible", "openrct2.footpath_railings.invisible" }, + { "official.zpanda", "rct2dlc.ride.zpanda" }, + { "openrct2.surface.void", "openrct2.terrain_surface.void" }, + { "openrct2.station.noentrance", "openrct2.station.noentrance" }, + { "openrct2.station.noplatformnoentrance", "openrct2.station.noplatformnoentrance" }, + { "rct2.sct", "rct2.scenery_large.sct" }, + { "rct2.soh3", "rct2.scenery_large.soh3" }, + { "rct2.scln", "rct2.scenery_large.scln" }, + { "rct2.smh2", "rct2.scenery_large.smh2" }, + { "rct2.sdn3", "rct2.scenery_large.sdn3" }, + { "rct2.stb1", "rct2.scenery_large.stb1" }, + { "rct2.nitroent", "rct2.scenery_large.nitroent" }, + { "rct2.smh1", "rct2.scenery_large.smh1" }, + { "rct2.badrack", "rct2.scenery_large.badrack" }, + { "rct2.glthent", "rct2.scenery_large.glthent" }, + { "rct2.sth", "rct2.scenery_large.sth" }, + { "rct2.svlc", "rct2.scenery_large.svlc" }, + { "rct2.ssr", "rct2.scenery_large.ssr" }, + { "rct2.spyr", "rct2.scenery_large.spyr" }, + { "rct2.prship", "rct2.scenery_large.prship" }, + { "rct2.saloon", "rct2.scenery_large.saloon" }, + { "rct2.smb", "rct2.scenery_large.smb" }, + { "rct2.soh1", "rct2.scenery_large.soh1" }, + { "rct2.stg2", "rct2.scenery_large.stg2" }, + { "rct2.sspx", "rct2.scenery_large.sspx" }, + { "rct2.sip", "rct2.scenery_large.sip" }, + { "rct2.ssig4", "rct2.scenery_large.ssig4" }, + { "rct2.ssig3", "rct2.scenery_large.ssig3" }, + { "rct2.ssig2", "rct2.scenery_large.ssig2" }, + { "rct2.smn1", "rct2.scenery_large.smn1" }, + { "rct2.scol", "rct2.scenery_large.scol" }, + { "rct2.ssh", "rct2.scenery_large.ssh" }, + { "rct2.spg", "rct2.scenery_large.spg" }, + { "rct2.sah3", "rct2.scenery_large.sah3" }, + { "rct2.stg1", "rct2.scenery_large.stg1" }, + { "rct2.ssk1", "rct2.scenery_large.ssk1" }, + { "rct2.sah", "rct2.scenery_large.sah" }, + { "rct2.sgp", "rct2.scenery_large.sgp" }, + { "rct2.mdsaent", "rct2.scenery_large.mdsaent" }, + { "rct2.sdn2", "rct2.scenery_large.sdn2" }, + { "rct2.sah2", "rct2.scenery_large.sah2" }, + { "rct2.shs1", "rct2.scenery_large.shs1" }, + { "rct2.sps", "rct2.scenery_large.sps" }, + { "rct2.sst", "rct2.scenery_large.sst" }, + { "rct2.stb2", "rct2.scenery_large.stb2" }, + { "rct2.ssig1", "rct2.scenery_large.ssig1" }, + { "rct2.sdn1", "rct2.scenery_large.sdn1" }, + { "rct2.tavern", "rct2.scenery_large.tavern" }, + { "rct2.shs2", "rct2.scenery_large.shs2" }, + { "rct2.wwbank", "rct2.scenery_large.wwbank" }, + { "rct2.sob", "rct2.scenery_large.sob" }, + { "rct2.soh2", "rct2.scenery_large.soh2" }, + { "rct2.genstore", "rct2.scenery_large.genstore" }, + { "rct2.scgpirat", "rct2.scenery_group.scgpirat" }, + { "rct2.scgsport", "rct2.scenery_group.scgsport" }, + { "rct2.scgspook", "rct2.scenery_group.scgspook" }, + { "rct2.scgclass", "rct2.scenery_group.scgclass" }, + { "rct2.scghallo", "rct2.scenery_group.scghallo" }, + { "rct2.scgegypt", "rct2.scenery_group.scgegypt" }, + { "rct2.scgwater", "rct2.scenery_group.scgwater" }, + { "rct2.scgurban", "rct2.scenery_group.scgurban" }, + { "rct2.scgwond", "rct2.scenery_group.scgwond" }, + { "rct2.scgmine", "rct2.scenery_group.scgmine" }, + { "rct2.scgorien", "rct2.scenery_group.scgorien" }, + { "rct2.scgshrub", "rct2.scenery_group.scgshrub" }, + { "rct2.scgfence", "rct2.scenery_group.scgfence" }, + { "rct2.scggiant", "rct2.scenery_group.scggiant" }, + { "rct2.scgspace", "rct2.scenery_group.scgspace" }, + { "rct2.scgsixfl", "rct2.scenery_group.scgsixfl" }, + { "rct2.scgjuras", "rct2.scenery_group.scgjuras" }, + { "rct2.scgcandy", "rct2.scenery_group.scgcandy" }, + { "rct2.scgmart", "rct2.scenery_group.scgmart" }, + { "rct2.scgpathx", "rct2.scenery_group.scgpathx" }, + { "rct2.scgtrees", "rct2.scenery_group.scgtrees" }, + { "rct2.scgabstr", "rct2.scenery_group.scgabstr" }, + { "rct2.scgsnow", "rct2.scenery_group.scgsnow" }, + { "rct2.scgwwest", "rct2.scenery_group.scgwwest" }, + { "rct2.scggardn", "rct2.scenery_group.scggardn" }, + { "rct2.scgwalls", "rct2.scenery_group.scgwalls" }, + { "rct2.scgindus", "rct2.scenery_group.scgindus" }, + { "rct2.scgjungl", "rct2.scenery_group.scgjungl" }, + { "rct2.scgmedie", "rct2.scenery_group.scgmedie" }, + { "rct2.music.rock1", "rct2.music.rock1" }, + { "rct2.music.toyland", "rct2.music.toyland" }, + { "rct2.music.fantasy", "rct2.music.fantasy" }, + { "rct2.music.custom2", "rct2.music.custom2" }, + { "rct2.music.candy", "rct2.music.candy" }, + { "rct2.music.egyptian", "rct2.music.egyptian" }, + { "rct2.music.pirate", "rct2.music.pirate" }, + { "rct2.music.ice", "rct2.music.ice" }, + { "rct2.music.techno", "rct2.music.techno" }, + { "rct2.music.jurassic", "rct2.music.jurassic" }, + { "rct2.music.medieval", "rct2.music.medieval" }, + { "rct2.music.rock2", "rct2.music.rock2" }, + { "rct2.music.modern", "rct2.music.modern" }, + { "rct2.music.ragtime", "rct2.music.ragtime" }, + { "rct2.music.fairground", "rct2.music.fairground" }, + { "rct2.music.jungle", "rct2.music.jungle" }, + { "rct2.music.dodgems", "rct2.music.dodgems" }, + { "rct2.music.gentle", "rct2.music.gentle" }, + { "rct2.music.summer", "rct2.music.summer" }, + { "rct2.music.oriental", "rct2.music.oriental" }, + { "rct2.music.wildwest", "rct2.music.wildwest" }, + { "rct2.music.space", "rct2.music.space" }, + { "rct2.music.horror", "rct2.music.horror" }, + { "rct2.music.custom1", "rct2.music.custom1" }, + { "rct2.music.snow", "rct2.music.snow" }, + { "rct2.music.rock3", "rct2.music.rock3" }, + { "rct2.music.organ", "rct2.music.organ" }, + { "rct2.music.mechanical", "rct2.music.mechanical" }, + { "rct2.music", "rct2.music.water" }, + { "rct2.music.urban", "rct2.music.urban" }, + { "rct2.music.martian", "rct2.music.martian" }, + { "rct2.music.roman", "rct2.music.roman" }, + { "rct2.bn1", "rct2.footpath_banner.bn1" }, + { "rct2.bn3", "rct2.footpath_banner.bn3" }, + { "rct2.bn7", "rct2.footpath_banner.bn7" }, + { "rct2.bn6", "rct2.footpath_banner.bn6" }, + { "rct2.bn5", "rct2.footpath_banner.bn5" }, + { "rct2.bn8", "rct2.footpath_banner.bn8" }, + { "rct2.bn9", "rct2.footpath_banner.bn9" }, + { "rct2.bn2", "rct2.footpath_banner.bn2" }, + { "rct2.bn4", "rct2.footpath_banner.bn4" }, + { "rct2.wtrorng", "rct2.water.wtrorng" }, + { "rct2.wtrgreen", "rct2.water.wtrgreen" }, + { "rct2.wtrgrn", "rct2.water.wtrgrn" }, + { "rct2.wtrcyan", "rct2.water.wtrcyan" }, + { "rct2.trf3", "rct2.scenery_small.trf3" }, + { "rct2.tl3", "rct2.scenery_small.tl3" }, + { "rct2.tl0", "rct2.scenery_small.tl0" }, + { "rct2.stldw", "rct2.scenery_small.stldw" }, + { "rct2.trms", "rct2.scenery_small.trms" }, + { "rct2.tsm", "rct2.scenery_small.tsm" }, + { "rct2.tef", "rct2.scenery_small.tef" }, + { "rct2.tes1", "rct2.scenery_small.tes1" }, + { "rct2.hang1", "rct2.scenery_small.hang1" }, + { "rct2.tsk", "rct2.scenery_small.tsk" }, + { "rct2.tmg", "rct2.scenery_small.tmg" }, + { "rct2.jeldrop1", "rct2.scenery_small.jeldrop1" }, + { "rct2.chest1", "rct2.scenery_small.chest1" }, + { "rct2.trf", "rct2.scenery_small.trf" }, + { "rct2.ttf", "rct2.scenery_small.ttf" }, + { "rct2.sktdw2", "rct2.scenery_small.sktdw2" }, + { "rct2.roof5", "rct2.scenery_small.roof5" }, + { "rct2.tww", "rct2.scenery_small.tww" }, + { "rct2.tbn", "rct2.scenery_small.tbn" }, + { "rct2.totem1", "rct2.scenery_small.totem1" }, + { "rct2.brbase2", "rct2.scenery_small.brbase2" }, + { "rct2.chest2", "rct2.scenery_small.chest2" }, + { "rct2.tct", "rct2.scenery_small.tct" }, + { "rct2.tge4", "rct2.scenery_small.tge4" }, + { "rct2.tsp2", "rct2.scenery_small.tsp2" }, + { "rct2.stlbaset", "rct2.scenery_small.stlbaset" }, + { "rct2.tgs3", "rct2.scenery_small.tgs3" }, + { "rct2.tep", "rct2.scenery_small.tep" }, + { "rct2.tq2", "rct2.scenery_small.tq2" }, + { "rct2.tf2", "rct2.scenery_small.tf2" }, + { "rct2.tgs1", "rct2.scenery_small.tgs1" }, + { "rct2.tic", "rct2.scenery_small.tic" }, + { "rct2.tgc1", "rct2.scenery_small.tgc1" }, + { "rct2.tsf1", "rct2.scenery_small.tsf1" }, + { "rct2.tjt4", "rct2.scenery_small.tjt4" }, + { "rct2.cog2r", "rct2.scenery_small.cog2r" }, + { "rct2.cog2", "rct2.scenery_small.cog2" }, + { "rct2.tsph", "rct2.scenery_small.tsph" }, + { "rct2.tm0", "rct2.scenery_small.tm0" }, + { "rct2.tg10", "rct2.scenery_small.tg10" }, + { "rct2.tlp", "rct2.scenery_small.tlp" }, + { "rct2.beanst1", "rct2.scenery_small.beanst1" }, + { "rct2.georoof1", "rct2.scenery_small.georoof1" }, + { "rct2.allsort2", "rct2.scenery_small.allsort2" }, + { "rct2.tge1", "rct2.scenery_small.tge1" }, + { "rct2.tsh", "rct2.scenery_small.tsh" }, + { "rct2.tgs2", "rct2.scenery_small.tgs2" }, + { "rct2.cnballs", "rct2.scenery_small.cnballs" }, + { "rct2.tos", "rct2.scenery_small.tos" }, + { "rct2.colagum", "rct2.scenery_small.colagum" }, + { "rct2.brbase", "rct2.scenery_small.brbase" }, + { "rct2.tsnb", "rct2.scenery_small.tsnb" }, + { "rct2.mment2", "rct2.scenery_small.mment2" }, + { "rct2.tg12", "rct2.scenery_small.tg12" }, + { "rct2.tsh4", "rct2.scenery_small.tsh4" }, + { "rct2.tjp2", "rct2.scenery_small.tjp2" }, + { "rct2.tg17", "rct2.scenery_small.tg17" }, + { "rct2.tmj", "rct2.scenery_small.tmj" }, + { "rct2.tgg", "rct2.scenery_small.tgg" }, + { "rct2.tg7", "rct2.scenery_small.tg7" }, + { "rct2.tmo3", "rct2.scenery_small.tmo3" }, + { "rct2.tmw", "rct2.scenery_small.tmw" }, + { "rct2.thl", "rct2.scenery_small.thl" }, + { "rct2.roof9", "rct2.scenery_small.roof9" }, + { "rct2.chocroof", "rct2.scenery_small.chocroof" }, + { "rct2.ten", "rct2.scenery_small.ten" }, + { "rct2.roof14", "rct2.scenery_small.roof14" }, + { "rct2.tg15", "rct2.scenery_small.tg15" }, + { "rct2.tdf", "rct2.scenery_small.tdf" }, + { "rct2.tot2", "rct2.scenery_small.tot2" }, + { "rct2.tbp", "rct2.scenery_small.tbp" }, + { "rct2.tg19", "rct2.scenery_small.tg19" }, + { "rct2.helmet1", "rct2.scenery_small.helmet1" }, + { "rct2.tg14", "rct2.scenery_small.tg14" }, + { "rct2.tsh1", "rct2.scenery_small.tsh1" }, + { "rct2.tb1", "rct2.scenery_small.tb1" }, + { "rct2.twf", "rct2.scenery_small.twf" }, + { "rct2.tr1", "rct2.scenery_small.tr1" }, + { "rct2.tropt1", "rct2.scenery_small.tropt1" }, + { "rct2.suppw3", "rct2.scenery_small.suppw3" }, + { "rct2.tg4", "rct2.scenery_small.tg4" }, + { "rct2.pirroof2", "rct2.scenery_small.pirroof2" }, + { "rct2.tg5", "rct2.scenery_small.tg5" }, + { "rct2.twp", "rct2.scenery_small.twp" }, + { "rct2.allsort1", "rct2.scenery_small.allsort1" }, + { "rct2.tjt1", "rct2.scenery_small.tjt1" }, + { "rct2.tml", "rct2.scenery_small.tml" }, + { "rct2.ball2", "rct2.scenery_small.ball2" }, + { "rct2.cwfcrv32", "rct2.scenery_small.cwfcrv32" }, + { "rct2.tbr2", "rct2.scenery_small.tbr2" }, + { "rct2.tot1", "rct2.scenery_small.tot1" }, + { "rct2.roof8", "rct2.scenery_small.roof8" }, + { "rct2.tghc", "rct2.scenery_small.tghc" }, + { "rct2.lolly1", "rct2.scenery_small.lolly1" }, + { "rct2.roof10", "rct2.scenery_small.roof10" }, + { "rct2.tas3", "rct2.scenery_small.tas3" }, + { "rct2.tmo1", "rct2.scenery_small.tmo1" }, + { "rct2.sktdw", "rct2.scenery_small.sktdw" }, + { "rct2.corroof2", "rct2.scenery_small.corroof2" }, + { "rct2.prcan", "rct2.scenery_small.prcan" }, + { "rct2.tjf", "rct2.scenery_small.tjf" }, + { "rct2.tscp", "rct2.scenery_small.tscp" }, + { "rct2.tdt2", "rct2.scenery_small.tdt2" }, + { "rct2.cwbcrv32", "rct2.scenery_small.cwbcrv32" }, + { "rct2.beanst2", "rct2.scenery_small.beanst2" }, + { "rct2.twh2", "rct2.scenery_small.twh2" }, + { "rct2.tst5", "rct2.scenery_small.tst5" }, + { "rct2.tcrp", "rct2.scenery_small.tcrp" }, + { "rct2.tpm", "rct2.scenery_small.tpm" }, + { "rct2.tst3", "rct2.scenery_small.tst3" }, + { "rct2.romroof2", "rct2.scenery_small.romroof2" }, + { "rct2.ggrs1", "rct2.scenery_small.ggrs1" }, + { "rct2.cwbcrv33", "rct2.scenery_small.cwbcrv33" }, + { "rct2.stbase", "rct2.scenery_small.stbase" }, + { "rct2.carrot", "rct2.scenery_small.carrot" }, + { "rct2.buttfly", "rct2.scenery_small.buttfly" }, + { "rct2.tal", "rct2.scenery_small.tal" }, + { "rct2.trws", "rct2.scenery_small.trws" }, + { "rct2.tbr3", "rct2.scenery_small.tbr3" }, + { "rct2.tsmp", "rct2.scenery_small.tsmp" }, + { "rct2.tel", "rct2.scenery_small.tel" }, + { "rct2.thrs", "rct2.scenery_small.thrs" }, + { "rct2.tl1", "rct2.scenery_small.tl1" }, + { "rct2.tstd", "rct2.scenery_small.tstd" }, + { "rct2.twn", "rct2.scenery_small.twn" }, + { "rct2.ts3", "rct2.scenery_small.ts3" }, + { "rct2.ts1", "rct2.scenery_small.ts1" }, + { "rct2.tmo5", "rct2.scenery_small.tmo5" }, + { "rct2.twh1", "rct2.scenery_small.twh1" }, + { "rct2.tdm", "rct2.scenery_small.tdm" }, + { "rct2.tg9", "rct2.scenery_small.tg9" }, + { "rct2.torn1", "rct2.scenery_small.torn1" }, + { "rct2.tqf", "rct2.scenery_small.tqf" }, + { "rct2.snail", "rct2.scenery_small.snail" }, + { "rct2.tcd", "rct2.scenery_small.tcd" }, + { "rct2.tas", "rct2.scenery_small.tas" }, + { "rct2.spider1", "rct2.scenery_small.spider1" }, + { "rct2.tst1", "rct2.scenery_small.tst1" }, + { "rct2.roof13", "rct2.scenery_small.roof13" }, + { "rct2.tjt5", "rct2.scenery_small.tjt5" }, + { "rct2.tct2", "rct2.scenery_small.tct2" }, + { "rct2.ts4", "rct2.scenery_small.ts4" }, + { "rct2.wspout", "rct2.scenery_small.wspout" }, + { "rct2.tst4", "rct2.scenery_small.tst4" }, + { "rct2.wdbase", "rct2.scenery_small.wdbase" }, + { "rct2.toh2", "rct2.scenery_small.toh2" }, + { "rct2.igroof", "rct2.scenery_small.igroof" }, + { "rct2.ball3", "rct2.scenery_small.ball3" }, + { "rct2.tsf3", "rct2.scenery_small.tsf3" }, + { "rct2.fern1", "rct2.scenery_small.fern1" }, + { "rct2.mment1", "rct2.scenery_small.mment1" }, + { "rct2.brcrrf1", "rct2.scenery_small.brcrrf1" }, + { "rct2.sktbase", "rct2.scenery_small.sktbase" }, + { "rct2.cog2ur", "rct2.scenery_small.cog2ur" }, + { "rct2.wag1", "rct2.scenery_small.wag1" }, + { "rct2.tk4", "rct2.scenery_small.tk4" }, + { "rct2.tdn4", "rct2.scenery_small.tdn4" }, + { "rct2.ball4", "rct2.scenery_small.ball4" }, + { "rct2.mallow1", "rct2.scenery_small.mallow1" }, + { "rct2.tjb2", "rct2.scenery_small.tjb2" }, + { "rct2.tmbj", "rct2.scenery_small.tmbj" }, + { "rct2.smskull", "rct2.scenery_small.smskull" }, + { "rct2.tg21", "rct2.scenery_small.tg21" }, + { "rct2.tgs4", "rct2.scenery_small.tgs4" }, + { "rct2.tct1", "rct2.scenery_small.tct1" }, + { "rct2.tk3", "rct2.scenery_small.tk3" }, + { "rct2.tbr1", "rct2.scenery_small.tbr1" }, + { "rct2.tsnc", "rct2.scenery_small.tsnc" }, + { "rct2.tbc", "rct2.scenery_small.tbc" }, + { "rct2.tg16", "rct2.scenery_small.tg16" }, + { "rct2.pirflag", "rct2.scenery_small.pirflag" }, + { "rct2.toh1", "rct2.scenery_small.toh1" }, + { "rct2.tcc", "rct2.scenery_small.tcc" }, + { "rct2.roof1", "rct2.scenery_small.roof1" }, + { "rct2.cog1r", "rct2.scenery_small.cog1r" }, + { "rct2.th1", "rct2.scenery_small.th1" }, + { "rct2.tg3", "rct2.scenery_small.tg3" }, + { "rct2.tsh0", "rct2.scenery_small.tsh0" }, + { "rct2.tcb", "rct2.scenery_small.tcb" }, + { "rct2.roof4", "rct2.scenery_small.roof4" }, + { "rct2.tht", "rct2.scenery_small.tht" }, + { "rct2.minroof1", "rct2.scenery_small.minroof1" }, + { "rct2.tp1", "rct2.scenery_small.tp1" }, + { "rct2.tsh5", "rct2.scenery_small.tsh5" }, + { "rct2.tgc2", "rct2.scenery_small.tgc2" }, + { "rct2.ttg", "rct2.scenery_small.ttg" }, + { "rct2.tjb3", "rct2.scenery_small.tjb3" }, + { "rct2.romroof1", "rct2.scenery_small.romroof1" }, + { "rct2.tco", "rct2.scenery_small.tco" }, + { "rct2.pipe32", "rct2.scenery_small.pipe32" }, + { "rct2.sktbaset", "rct2.scenery_small.sktbaset" }, + { "rct2.tcf", "rct2.scenery_small.tcf" }, + { "rct2.tnss", "rct2.scenery_small.tnss" }, + { "rct2.tot4", "rct2.scenery_small.tot4" }, + { "rct2.tus", "rct2.scenery_small.tus" }, + { "rct2.tsg", "rct2.scenery_small.tsg" }, + { "rct2.roof2", "rct2.scenery_small.roof2" }, + { "rct2.suppleg2", "rct2.scenery_small.suppleg2" }, + { "rct2.georoof2", "rct2.scenery_small.georoof2" }, + { "rct2.tac", "rct2.scenery_small.tac" }, + { "rct2.tce", "rct2.scenery_small.tce" }, + { "rct2.tbw", "rct2.scenery_small.tbw" }, + { "rct2.stldw2", "rct2.scenery_small.stldw2" }, + { "rct2.cog2u", "rct2.scenery_small.cog2u" }, + { "rct2.tdt1", "rct2.scenery_small.tdt1" }, + { "rct2.th2", "rct2.scenery_small.th2" }, + { "rct2.ts5", "rct2.scenery_small.ts5" }, + { "rct2.tgh1", "rct2.scenery_small.tgh1" }, + { "rct2.cog1u", "rct2.scenery_small.cog1u" }, + { "rct2.tsp1", "rct2.scenery_small.tsp1" }, + { "rct2.tcfs", "rct2.scenery_small.tcfs" }, + { "rct2.tjb1", "rct2.scenery_small.tjb1" }, + { "rct2.suppw1", "rct2.scenery_small.suppw1" }, + { "rct2.tk1", "rct2.scenery_small.tk1" }, + { "rct2.tvl", "rct2.scenery_small.tvl" }, + { "rct2.tghc2", "rct2.scenery_small.tghc2" }, + { "rct2.trfs", "rct2.scenery_small.trfs" }, + { "rct2.tly", "rct2.scenery_small.tly" }, + { "rct2.wag2", "rct2.scenery_small.wag2" }, + { "rct2.tg13", "rct2.scenery_small.tg13" }, + { "rct2.tgh2", "rct2.scenery_small.tgh2" }, + { "rct2.tas1", "rct2.scenery_small.tas1" }, + { "rct2.tge2", "rct2.scenery_small.tge2" }, + { "rct2.tmc", "rct2.scenery_small.tmc" }, + { "rct2.tap", "rct2.scenery_small.tap" }, + { "rct2.tbr", "rct2.scenery_small.tbr" }, + { "rct2.tg6", "rct2.scenery_small.tg6" }, + { "rct2.tsc", "rct2.scenery_small.tsc" }, + { "rct2.jelbab1", "rct2.scenery_small.jelbab1" }, + { "rct2.tmo4", "rct2.scenery_small.tmo4" }, + { "rct2.tns", "rct2.scenery_small.tns" }, + { "rct2.tcl", "rct2.scenery_small.tcl" }, + { "rct2.tas2", "rct2.scenery_small.tas2" }, + { "rct2.tl2", "rct2.scenery_small.tl2" }, + { "rct2.roof12", "rct2.scenery_small.roof12" }, + { "rct2.trf2", "rct2.scenery_small.trf2" }, + { "rct2.tmo2", "rct2.scenery_small.tmo2" }, + { "rct2.tg20", "rct2.scenery_small.tg20" }, + { "rct2.tjt3", "rct2.scenery_small.tjt3" }, + { "rct2.tm3", "rct2.scenery_small.tm3" }, + { "rct2.tb2", "rct2.scenery_small.tb2" }, + { "rct2.teepee1", "rct2.scenery_small.teepee1" }, + { "rct2.tot3", "rct2.scenery_small.tot3" }, + { "rct2.pirroof1", "rct2.scenery_small.pirroof1" }, + { "rct2.jeldrop2", "rct2.scenery_small.jeldrop2" }, + { "rct2.tntroof1", "rct2.scenery_small.tntroof1" }, + { "rct2.toh3", "rct2.scenery_small.toh3" }, + { "rct2.pipe8", "rct2.scenery_small.pipe8" }, + { "rct2.tsh2", "rct2.scenery_small.tsh2" }, + { "rct2.tbn1", "rct2.scenery_small.tbn1" }, + { "rct2.tcy", "rct2.scenery_small.tcy" }, + { "rct2.wasp", "rct2.scenery_small.wasp" }, + { "rct2.tmm3", "rct2.scenery_small.tmm3" }, + { "rct2.ters", "rct2.scenery_small.ters" }, + { "rct2.tsp", "rct2.scenery_small.tsp" }, + { "rct2.ts6", "rct2.scenery_small.ts6" }, + { "rct2.tp2", "rct2.scenery_small.tp2" }, + { "rct2.torn2", "rct2.scenery_small.torn2" }, + { "rct2.tst2", "rct2.scenery_small.tst2" }, + { "rct2.tm2", "rct2.scenery_small.tm2" }, + { "rct2.tf1", "rct2.scenery_small.tf1" }, + { "rct2.tsb", "rct2.scenery_small.tsb" }, + { "rct2.mment3", "rct2.scenery_small.mment3" }, + { "rct2.tg11", "rct2.scenery_small.tg11" }, + { "rct2.ts2", "rct2.scenery_small.ts2" }, + { "rct2.tms1", "rct2.scenery_small.tms1" }, + { "rct2.spcroof1", "rct2.scenery_small.spcroof1" }, + { "rct2.tk2", "rct2.scenery_small.tk2" }, + { "rct2.whoriz", "rct2.scenery_small.whoriz" }, + { "rct2.tjt6", "rct2.scenery_small.tjt6" }, + { "rct2.brcrrf2", "rct2.scenery_small.brcrrf2" }, + { "rct2.suppleg1", "rct2.scenery_small.suppleg1" }, + { "rct2.roof11", "rct2.scenery_small.roof11" }, + { "rct2.tas4", "rct2.scenery_small.tas4" }, + { "rct2.tjt2", "rct2.scenery_small.tjt2" }, + { "rct2.tsd", "rct2.scenery_small.tsd" }, + { "rct2.mint1", "rct2.scenery_small.mint1" }, + { "rct2.corroof", "rct2.scenery_small.corroof" }, + { "rct2.brbase3", "rct2.scenery_small.brbase3" }, + { "rct2.pipe32j", "rct2.scenery_small.pipe32j" }, + { "rct2.tsf2", "rct2.scenery_small.tsf2" }, + { "rct2.tg18", "rct2.scenery_small.tg18" }, + { "rct2.tdt3", "rct2.scenery_small.tdt3" }, + { "rct2.tq1", "rct2.scenery_small.tq1" }, + { "rct2.tge5", "rct2.scenery_small.tge5" }, + { "rct2.cndyrk1", "rct2.scenery_small.cndyrk1" }, + { "rct2.tsc2", "rct2.scenery_small.tsc2" }, + { "rct2.tg2", "rct2.scenery_small.tg2" }, + { "rct2.roof3", "rct2.scenery_small.roof3" }, + { "rct2.cog1ur", "rct2.scenery_small.cog1ur" }, + { "rct2.jbean1", "rct2.scenery_small.jbean1" }, + { "rct2.icecube", "rct2.scenery_small.icecube" }, + { "rct2.suppw2", "rct2.scenery_small.suppw2" }, + { "rct2.tsq", "rct2.scenery_small.tsq" }, + { "rct2.sumrf", "rct2.scenery_small.sumrf" }, + { "rct2.roof7", "rct2.scenery_small.roof7" }, + { "rct2.tcn", "rct2.scenery_small.tcn" }, + { "rct2.ts0", "rct2.scenery_small.ts0" }, + { "rct2.tsh3", "rct2.scenery_small.tsh3" }, + { "rct2.tcj", "rct2.scenery_small.tcj" }, + { "rct2.badshut2", "rct2.scenery_small.badshut2" }, + { "rct2.tt1", "rct2.scenery_small.tt1" }, + { "rct2.wdiag", "rct2.scenery_small.wdiag" }, + { "rct2.tg8", "rct2.scenery_small.tg8" }, + { "rct2.jngroof1", "rct2.scenery_small.jngroof1" }, + { "rct2.tg1", "rct2.scenery_small.tg1" }, + { "rct2.tck", "rct2.scenery_small.tck" }, + { "rct2.badshut", "rct2.scenery_small.badshut" }, + { "rct2.cog1", "rct2.scenery_small.cog1" }, + { "rct2.ball1", "rct2.scenery_small.ball1" }, + { "rct2.pagroof1", "rct2.scenery_small.pagroof1" }, + { "rct2.chbbase", "rct2.scenery_small.chbbase" }, + { "rct2.tjb4", "rct2.scenery_small.tjb4" }, + { "rct2.tjp1", "rct2.scenery_small.tjp1" }, + { "rct2.cwfcrv33", "rct2.scenery_small.cwfcrv33" }, + { "rct2.mallow2", "rct2.scenery_small.mallow2" }, + { "rct2.roof6", "rct2.scenery_small.roof6" }, + { "rct2.tmzp", "rct2.scenery_small.tmzp" }, + { "rct2.tlc", "rct2.scenery_small.tlc" }, + { "rct2.tmm1", "rct2.scenery_small.tmm1" }, + { "rct2.tig", "rct2.scenery_small.tig" }, + { "rct2.tge3", "rct2.scenery_small.tge3" }, + { "rct2.tgs", "rct2.scenery_small.tgs" }, + { "rct2.titc", "rct2.scenery_small.titc" }, + { "rct2.terb", "rct2.scenery_small.terb" }, + { "rct2.tmm2", "rct2.scenery_small.tmm2" }, + { "rct2.tbr4", "rct2.scenery_small.tbr4" }, + { "rct2.tdn5", "rct2.scenery_small.tdn5" }, + { "rct2.tmp", "rct2.scenery_small.tmp" }, + { "rct2.trc", "rct2.scenery_small.trc" }, + { "rct2.tm1", "rct2.scenery_small.tm1" }, + { "rct2.tr2", "rct2.scenery_small.tr2" }, + { "rct2.fire1", "rct2.scenery_small.fire1" }, + { "rct2.wc7", "rct2.scenery_wall.wc7" }, + { "rct2.wc4", "rct2.scenery_wall.wc4" }, + { "rct2.wmf", "rct2.scenery_wall.wmf" }, + { "rct2.wc2", "rct2.scenery_wall.wc2" }, + { "rct2.wfwg", "rct2.scenery_wall.wfwg" }, + { "rct2.wallcfar", "rct2.scenery_wall.wallcfar" }, + { "rct2.wallcfwn", "rct2.scenery_wall.wallcfwn" }, + { "rct2.wallco16", "rct2.scenery_wall.wallco16" }, + { "rct2.wallpr34", "rct2.scenery_wall.wallpr34" }, + { "rct2.wallbb16", "rct2.scenery_wall.wallbb16" }, + { "rct2.wallmm17", "rct2.scenery_wall.wallmm17" }, + { "rct2.wallrs32", "rct2.scenery_wall.wallrs32" }, + { "rct2.wpw3", "rct2.scenery_wall.wpw3" }, + { "rct2.wew", "rct2.scenery_wall.wew" }, + { "rct2.wallsp32", "rct2.scenery_wall.wallsp32" }, + { "rct2.wallbb34", "rct2.scenery_wall.wallbb34" }, + { "rct2.wallsign", "rct2.scenery_wall.wallsign" }, + { "rct2.wallwd16", "rct2.scenery_wall.wallwd16" }, + { "rct2.wwtw", "rct2.scenery_wall.wwtw" }, + { "rct2.wallgl32", "rct2.scenery_wall.wallgl32" }, + { "rct2.wallcf16", "rct2.scenery_wall.wallcf16" }, + { "rct2.wwtwa", "rct2.scenery_wall.wwtwa" }, + { "rct2.walljn32", "rct2.scenery_wall.walljn32" }, + { "rct2.whg", "rct2.scenery_wall.whg" }, + { "rct2.wallmn32", "rct2.scenery_wall.wallmn32" }, + { "rct2.wpw2", "rct2.scenery_wall.wpw2" }, + { "rct2.wbr2a", "rct2.scenery_wall.wbr2a" }, + { "rct2.wsw", "rct2.scenery_wall.wsw" }, + { "rct2.wmw", "rct2.scenery_wall.wmw" }, + { "rct2.wallnt32", "rct2.scenery_wall.wallnt32" }, + { "rct2.wallpr33", "rct2.scenery_wall.wallpr33" }, + { "rct2.wallcf32", "rct2.scenery_wall.wallcf32" }, + { "rct2.wc8", "rct2.scenery_wall.wc8" }, + { "rct2.wc5", "rct2.scenery_wall.wc5" }, + { "rct2.wallu132", "rct2.scenery_wall.wallu132" }, + { "rct2.wallbadm", "rct2.scenery_wall.wallbadm" }, + { "rct2.wsw2", "rct2.scenery_wall.wsw2" }, + { "rct2.wc1", "rct2.scenery_wall.wc1" }, + { "rct2.wallsk16", "rct2.scenery_wall.wallsk16" }, + { "rct2.wsw1", "rct2.scenery_wall.wsw1" }, + { "rct2.wallcfpc", "rct2.scenery_wall.wallcfpc" }, + { "rct2.wc12", "rct2.scenery_wall.wc12" }, + { "rct2.wallpost", "rct2.scenery_wall.wallpost" }, + { "rct2.whgg", "rct2.scenery_wall.whgg" }, + { "rct2.wc10", "rct2.scenery_wall.wc10" }, + { "rct2.wc14", "rct2.scenery_wall.wc14" }, + { "rct2.wrw", "rct2.scenery_wall.wrw" }, + { "rct2.wallcb8", "rct2.scenery_wall.wallcb8" }, + { "rct2.wcw2", "rct2.scenery_wall.wcw2" }, + { "rct2.wchg", "rct2.scenery_wall.wchg" }, + { "rct2.wbr1a", "rct2.scenery_wall.wbr1a" }, + { "rct2.wallpg32", "rct2.scenery_wall.wallpg32" }, + { "rct2.wpf", "rct2.scenery_wall.wpf" }, + { "rct2.wallnt33", "rct2.scenery_wall.wallnt33" }, + { "rct2.wallcx32", "rct2.scenery_wall.wallcx32" }, + { "rct2.wallst16", "rct2.scenery_wall.wallst16" }, + { "rct2.wc9", "rct2.scenery_wall.wc9" }, + { "rct2.wpfg", "rct2.scenery_wall.wpfg" }, + { "rct2.wc13", "rct2.scenery_wall.wc13" }, + { "rct2.wjf", "rct2.scenery_wall.wjf" }, + { "rct2.wallbr16", "rct2.scenery_wall.wallbr16" }, + { "rct2.wbrg", "rct2.scenery_wall.wbrg" }, + { "rct2.wc11", "rct2.scenery_wall.wc11" }, + { "rct2.wallbb33", "rct2.scenery_wall.wallbb33" }, + { "rct2.wallwf32", "rct2.scenery_wall.wallwf32" }, + { "rct2.wfw1", "rct2.scenery_wall.wfw1" }, + { "rct2.wallgl8", "rct2.scenery_wall.wallgl8" }, + { "rct2.wallrs8", "rct2.scenery_wall.wallrs8" }, + { "rct2.wallsc16", "rct2.scenery_wall.wallsc16" }, + { "rct2.wallcy32", "rct2.scenery_wall.wallcy32" }, + { "rct2.wallpr32", "rct2.scenery_wall.wallpr32" }, + { "rct2.wallu232", "rct2.scenery_wall.wallu232" }, + { "rct2.wallbb32", "rct2.scenery_wall.wallbb32" }, + { "rct2.wallgl16", "rct2.scenery_wall.wallgl16" }, + { "rct2.wallst32", "rct2.scenery_wall.wallst32" }, + { "rct2.wallrh32", "rct2.scenery_wall.wallrh32" }, + { "rct2.wallst8", "rct2.scenery_wall.wallst8" }, + { "rct2.wswg", "rct2.scenery_wall.wswg" }, + { "rct2.wallrs16", "rct2.scenery_wall.wallrs16" }, + { "rct2.wallcf8", "rct2.scenery_wall.wallcf8" }, + { "rct2.wallwd33", "rct2.scenery_wall.wallwd33" }, + { "rct2.wbr3", "rct2.scenery_wall.wbr3" }, + { "rct2.wallcbdr", "rct2.scenery_wall.wallcbdr" }, + { "rct2.wallbr8", "rct2.scenery_wall.wallbr8" }, + { "rct2.wallcbpc", "rct2.scenery_wall.wallcbpc" }, + { "rct2.wallbb8", "rct2.scenery_wall.wallbb8" }, + { "rct2.wallmm16", "rct2.scenery_wall.wallmm16" }, + { "rct2.wallcb16", "rct2.scenery_wall.wallcb16" }, + { "rct2.wallcz32", "rct2.scenery_wall.wallcz32" }, + { "rct2.walltn32", "rct2.scenery_wall.walltn32" }, + { "rct2.wallstfn", "rct2.scenery_wall.wallstfn" }, + { "rct2.wallwd8", "rct2.scenery_wall.wallwd8" }, + { "rct2.wallig24", "rct2.scenery_wall.wallig24" }, + { "rct2.wallbr32", "rct2.scenery_wall.wallbr32" }, + { "rct2.wmfg", "rct2.scenery_wall.wmfg" }, + { "rct2.wallstwn", "rct2.scenery_wall.wallstwn" }, + { "rct2.walljb16", "rct2.scenery_wall.walljb16" }, + { "rct2.wallcbwn", "rct2.scenery_wall.wallcbwn" }, + { "rct2.wc18", "rct2.scenery_wall.wc18" }, + { "rct2.wbr2", "rct2.scenery_wall.wbr2" }, + { "rct2.wallrk32", "rct2.scenery_wall.wallrk32" }, + { "rct2.wcw1", "rct2.scenery_wall.wcw1" }, + { "rct2.walllt32", "rct2.scenery_wall.walllt32" }, + { "rct2.wpw1", "rct2.scenery_wall.wpw1" }, + { "rct2.wgw2", "rct2.scenery_wall.wgw2" }, + { "rct2.walltxgt", "rct2.scenery_wall.walltxgt" }, + { "rct2.wc6", "rct2.scenery_wall.wc6" }, + { "rct2.wallbrdr", "rct2.scenery_wall.wallbrdr" }, + { "rct2.wallcw32", "rct2.scenery_wall.wallcw32" }, + { "rct2.wc17", "rct2.scenery_wall.wc17" }, + { "rct2.wallcfdr", "rct2.scenery_wall.wallcfdr" }, + { "rct2.wallbrwn", "rct2.scenery_wall.wallbrwn" }, + { "rct2.wc3", "rct2.scenery_wall.wc3" }, + { "rct2.wallwd32", "rct2.scenery_wall.wallwd32" }, + { "rct2.wallwdps", "rct2.scenery_wall.wallwdps" }, + { "rct2.wrwa", "rct2.scenery_wall.wrwa" }, + { "rct2.wch", "rct2.scenery_wall.wch" }, + { "rct2.wbw", "rct2.scenery_wall.wbw" }, + { "rct2.wc15", "rct2.scenery_wall.wc15" }, + { "rct2.wallpr35", "rct2.scenery_wall.wallpr35" }, + { "rct2.wmww", "rct2.scenery_wall.wmww" }, + { "rct2.wallsk32", "rct2.scenery_wall.wallsk32" }, + { "rct2.wc16", "rct2.scenery_wall.wc16" }, + { "rct2.wallcb32", "rct2.scenery_wall.wallcb32" }, + { "rct2.wallig16", "rct2.scenery_wall.wallig16" }, + { "rct2.wbr1", "rct2.scenery_wall.wbr1" }, + { "rct2.littersp", "rct2.footpath_item.littersp" }, + { "rct2.litterww", "rct2.footpath_item.litterww" }, + { "rct2.jumpsnw1", "rct2.footpath_item.jumpsnw1" }, + { "rct2.benchspc", "rct2.footpath_item.benchspc" }, + { "rct2.lamppir", "rct2.footpath_item.lamppir" }, + { "rct2.benchpl", "rct2.footpath_item.benchpl" }, + { "rct2.bench1", "rct2.footpath_item.bench1" }, + { "rct2.lampdsy", "rct2.footpath_item.lampdsy" }, + { "rct2.qtv1", "rct2.footpath_item.qtv1" }, + { "rct2.benchlog", "rct2.footpath_item.benchlog" }, + { "rct2.lamp3", "rct2.footpath_item.lamp3" }, + { "rct2.jumpfnt1", "rct2.footpath_item.jumpfnt1" }, + { "rct2.lamp1", "rct2.footpath_item.lamp1" }, + { "rct2.litter1", "rct2.footpath_item.litter1" }, + { "rct2.benchstn", "rct2.footpath_item.benchstn" }, + { "rct2.littermn", "rct2.footpath_item.littermn" }, + { "rct2.lamp4", "rct2.footpath_item.lamp4" }, + { "rct2.lamp2", "rct2.footpath_item.lamp2" }, + { "rct2.railings.bamboobrown", "rct2.footpath_railings.bamboo_brown" }, + { "rct2.railings.space", "rct2.footpath_railings.space" }, + { "rct2.railings.bambooblack", "rct2.footpath_railings.bamboo_black" }, + { "rct2.railings.wood", "rct2.footpath_railings.wood" }, + { "rct2.railings.concretegreen", "rct2.footpath_railings.concrete_green" }, + { "rct2.railings.concrete", "rct2.footpath_railings.concrete" }, + { "rct2.rckc", "rct2.ride.rckc" }, + { "rct2.hchoc", "rct2.ride.hchoc" }, + { "rct2.vekst", "rct2.ride.vekst" }, + { "rct2.c3d", "rct2.ride.c3d" }, + { "rct2.obs1", "rct2.ride.obs1" }, + { "rct2.truck1", "rct2.ride.truck1" }, + { "rct2.arrsw1", "rct2.ride.arrsw1" }, + { "rct2.dough", "rct2.ride.dough" }, + { "rct2.faid1", "rct2.ride.faid1" }, + { "rct2.infok", "rct2.ride.infok" }, + { "rct2.vekdv", "rct2.ride.vekdv" }, + { "rct2.revcar", "rct2.ride.revcar" }, + { "rct2.smono", "rct2.ride.smono" }, + { "rct2.gdrop1", "rct2.ride.gdrop1" }, + { "rct2.tram1", "rct2.ride.tram1" }, + { "rct2.coffs", "rct2.ride.coffs" }, + { "rct2.bmsu", "rct2.ride.bmsu" }, + { "rct2.substl", "rct2.ride.substl" }, + { "rct2.steep2", "rct2.ride.steep2" }, + { "rct2.icetst", "rct2.ride.icetst" }, + { "rct2.intst", "rct2.ride.intst" }, + { "rct2.fsauc", "rct2.ride.fsauc" }, + { "rct2.aml1", "rct2.ride.aml1" }, + { "rct2.souvs", "rct2.ride.souvs" }, + { "rct2.rapboat", "rct2.ride.rapboat" }, + { "rct2.nrl2", "rct2.ride.nrl2" }, + { "rct2.bmsd", "rct2.ride.bmsd" }, + { "rct2.icecr2", "rct2.ride.icecr2" }, + { "rct2.wonton", "rct2.ride.wonton" }, + { "rct2.bnoodles", "rct2.ride.bnoodles" }, + { "rct2.obs2", "rct2.ride.obs2" }, + { "rct2.atm1", "rct2.ride.atm1" }, + { "rct2.ctcar", "rct2.ride.ctcar" }, + { "rct2.topsp1", "rct2.ride.topsp1" }, + { "rct2.tlt1", "rct2.ride.tlt1" }, + { "rct2.sungst", "rct2.ride.sungst" }, + { "rct2.4x4", "rct2.ride.4x4" }, + { "rct2.pmt1", "rct2.ride.pmt1" }, + { "rct2.toffs", "rct2.ride.toffs" }, + { "rct2.steep1", "rct2.ride.steep1" }, + { "rct2.soybean", "rct2.ride.soybean" }, + { "rct2.zldb", "rct2.ride.zldb" }, + { "rct2.ding1", "rct2.ride.ding1" }, + { "rct2.smc1", "rct2.ride.smc1" }, + { "rct2.funcake", "rct2.ride.funcake" }, + { "rct2.skytr", "rct2.ride.skytr" }, + { "rct2.cndyf", "rct2.ride.cndyf" }, + { "rct2.bmrb", "rct2.ride.bmrb" }, + { "rct2.goltr", "rct2.ride.goltr" }, + { "rct2.simpod", "rct2.ride.simpod" }, + { "rct2.amt1", "rct2.ride.amt1" }, + { "rct2.bmfl", "rct2.ride.bmfl" }, + { "rct2.premt1", "rct2.ride.premt1" }, + { "rct2.togst", "rct2.ride.togst" }, + { "rct2.chcks", "rct2.ride.chcks" }, + { "rct2.hhbuild", "rct2.ride.hhbuild" }, + { "rct2.icecr1", "rct2.ride.icecr1" }, + { "rct2.utcar", "rct2.ride.utcar" }, + { "rct2.submar", "rct2.ride.submar" }, + { "rct2.fwh1", "rct2.ride.fwh1" }, + { "rct2.swans", "rct2.ride.swans" }, + { "rct2.bboat", "rct2.ride.bboat" }, + { "rct2.golf1", "rct2.ride.golf1" }, + { "rct2.ptct2r", "rct2.ride.ptct2r" }, + { "rct2.arrx", "rct2.ride.arrx" }, + { "rct2.slcfo", "rct2.ride.slcfo" }, + { "rct2.burgb", "rct2.ride.burgb" }, + { "rct2.hotds", "rct2.ride.hotds" }, + { "rct2.gtc", "rct2.ride.gtc" }, + { "rct2.tshrt", "rct2.ride.tshrt" }, + { "rct2.tlt2", "rct2.ride.tlt2" }, + { "rct2.scht1", "rct2.ride.scht1" }, + { "rct2.mgr1", "rct2.ride.mgr1" }, + { "rct2.swsh2", "rct2.ride.swsh2" }, + { "rct2.wmspin", "rct2.ride.wmspin" }, + { "rct2.chpsh2", "rct2.ride.chpsh2" }, + { "rct2.cstboat", "rct2.ride.cstboat" }, + { "rct2.mono1", "rct2.ride.mono1" }, + { "rct2.balln", "rct2.ride.balln" }, + { "rct2.vekvamp", "rct2.ride.vekvamp" }, + { "rct2.mft", "rct2.ride.mft" }, + { "rct2.hmaze", "rct2.ride.hmaze" }, + { "rct2.sqdst", "rct2.ride.sqdst" }, + { "rct2.intinv", "rct2.ride.intinv" }, + { "rct2.jstar1", "rct2.ride.jstar1" }, + { "rct2.mono3", "rct2.ride.mono3" }, + { "rct2.ssc1", "rct2.ride.ssc1" }, + { "rct2.kart1", "rct2.ride.kart1" }, + { "rct2.cboat", "rct2.ride.cboat" }, + { "rct2.cookst", "rct2.ride.cookst" }, + { "rct2.monbk", "rct2.ride.monbk" }, + { "rct2.swsh1", "rct2.ride.swsh1" }, + { "rct2.trike", "rct2.ride.trike" }, + { "rct2.rftboat", "rct2.ride.rftboat" }, + { "rct2.bmvd", "rct2.ride.bmvd" }, + { "rct2.sbox", "rct2.ride.sbox" }, + { "rct2.sfric1", "rct2.ride.sfric1" }, + { "rct2.arrt1", "rct2.ride.arrt1" }, + { "rct2.thcar", "rct2.ride.thcar" }, + { "rct2.wmouse", "rct2.ride.wmouse" }, + { "rct2.spboat", "rct2.ride.spboat" }, + { "rct2.clift2", "rct2.ride.clift2" }, + { "rct2.jski", "rct2.ride.jski" }, + { "rct2.mcarpet1", "rct2.ride.mcarpet1" }, + { "rct2.lfb1", "rct2.ride.lfb1" }, + { "rct2.ivmc1", "rct2.ride.ivmc1" }, + { "rct2.popcs", "rct2.ride.popcs" }, + { "rct2.vreel", "rct2.ride.vreel" }, + { "rct2.mono2", "rct2.ride.mono2" }, + { "rct2.twist1", "rct2.ride.twist1" }, + { "rct2.pretst", "rct2.ride.pretst" }, + { "rct2.lemst", "rct2.ride.lemst" }, + { "rct2.ptct2", "rct2.ride.ptct2" }, + { "rct2.arrt2", "rct2.ride.arrt2" }, + { "rct2.srings", "rct2.ride.srings" }, + { "rct2.nemt", "rct2.ride.nemt" }, + { "rct2.chknug", "rct2.ride.chknug" }, + { "rct2.nrl", "rct2.ride.nrl" }, + { "rct2.cindr", "rct2.ride.cindr" }, + { "rct2.rcr", "rct2.ride.rcr" }, + { "rct2.rsaus", "rct2.ride.rsaus" }, + { "rct2.frnood", "rct2.ride.frnood" }, + { "rct2.mbsoup", "rct2.ride.mbsoup" }, + { "rct2.chbuild", "rct2.ride.chbuild" }, + { "rct2.zlog", "rct2.ride.zlog" }, + { "rct2.chpsh", "rct2.ride.chpsh" }, + { "rct2.slct", "rct2.ride.slct" }, + { "rct2.lift1", "rct2.ride.lift1" }, + { "rct2.spcar", "rct2.ride.spcar" }, + { "rct2.twist2", "rct2.ride.twist2" }, + { "rct2.hatst", "rct2.ride.hatst" }, + { "rct2.ptct1", "rct2.ride.ptct1" }, + { "rct2.dodg1", "rct2.ride.dodg1" }, + { "rct2.starfrdr", "rct2.ride.starfrdr" }, + { "rct2.clift1", "rct2.ride.clift1" }, + { "rct2.wmmine", "rct2.ride.wmmine" }, + { "rct2.pizzs", "rct2.ride.pizzs" }, + { "rct2.rboat", "rct2.ride.rboat" }, + { "rct2.batfl", "rct2.ride.batfl" }, + { "rct2.hskelt", "rct2.ride.hskelt" }, + { "rct2.utcarr", "rct2.ride.utcarr" }, + { "rct2.vcr", "rct2.ride.vcr" }, + { "rct2.hmcar", "rct2.ride.hmcar" }, + { "rct2.arrsw2", "rct2.ride.arrsw2" }, + { "rct2.helicar", "rct2.ride.helicar" }, + { "rct2.wcatc", "rct2.ride.wcatc" }, + { "rct2.bmair", "rct2.ride.bmair" }, + { "rct2.circus1", "rct2.ride.circus1" }, + { "rct2.bob1", "rct2.ride.bob1" }, + { "rct2.spdrcr", "rct2.ride.spdrcr" }, + { "rct2.enterp", "rct2.ride.enterp" }, + { "rct2.revf1", "rct2.ride.revf1" }, + { "rct2.intbob", "rct2.ride.intbob" }, + { "rct2.smc2", "rct2.ride.smc2" }, + { "rct2.drnks", "rct2.ride.drnks" }, + { "rct2.pkesfh", "rct2.park_entrance.pkesfh" }, + { "rct2.pkent1", "rct2.park_entrance.pkent1" }, + { "rct2.pkemm", "rct2.park_entrance.pkemm" }, + { "rct2.pathsurface.queue_red", "rct2.footpath_surface.queue_red" }, + { "rct2.pathsurface.queue_yellow", "rct2.footpath_surface.queue_yellow" }, + { "rct2.pathsurface.tarmac", "rct2.footpath_surface.tarmac" }, + { "rct2.pathsurface.crazypaving", "rct2.footpath_surface.crazy_paving" }, + { "rct2.pathsurface.ash", "rct2.footpath_surface.ash" }, + { "rct2.pathsurface.queue_green", "rct2.footpath_surface.queue_green" }, + { "rct2.pathsurface.tarmac.green", "rct2.footpath_surface.tarmac_green" }, + { "rct2.pathsurface.queue_blue", "rct2.footpath_surface.queue_blue" }, + { "rct2.pathsurface.space", "rct2.footpath_surface.tarmac_red" }, + { "rct2.pathsurface.tarmac.brown", "rct2.footpath_surface.tarmac_brown" }, + { "rct2.pathsurface.dirt", "rct2.footpath_surface.dirt" }, + { "rct2.pathsurface.road", "rct2.footpath_surface.road" }, + { "rct2.surface.sandred", "rct2.terrain_surface.sand_red" }, + { "rct2.surface.grassclumps", "rct2.terrain_surface.grass_clumps" }, + { "rct2.surface.gridgreen", "rct2.terrain_surface.grid_green" }, + { "rct2.surface.sandbrown", "rct2.terrain_surface.sand_brown" }, + { "rct2.surface.gridyellow", "rct2.terrain_surface.grid_yellow" }, + { "rct2.surface.martian", "rct2.terrain_surface.martian" }, + { "rct2.surface.dirt", "rct2.terrain_surface.dirt" }, + { "rct2.surface.gridred", "rct2.terrain_surface.grid_red" }, + { "rct2.surface.ice", "rct2.terrain_surface.ice" }, + { "rct2.surface.grass", "rct2.terrain_surface.grass" }, + { "rct2.surface.sand", "rct2.terrain_surface.sand" }, + { "rct2.surface.rock", "rct2.terrain_surface.rock" }, + { "rct2.surface.chequerboard", "rct2.terrain_surface.chequerboard" }, + { "rct2.surface.gridpurple", "rct2.terrain_surface.grid_purple" }, + { "rct2.station.castlegrey", "rct2.station.castle_grey" }, + { "rct2.station.space", "rct2.station.space" }, + { "rct2.station.plain", "rct2.station.plain" }, + { "rct2.station.log", "rct2.station.log" }, + { "rct2.station.jungle", "rct2.station.jungle" }, + { "rct2.station.snow", "rct2.station.snow" }, + { "rct2.station.castlebrown", "rct2.station.castle_brown" }, + { "rct2.station.abstract", "rct2.station.abstract" }, + { "rct2.station.pagoda", "rct2.station.pagoda" }, + { "rct2.station.classical", "rct2.station.classical" }, + { "rct2.station.canvastent", "rct2.station.canvas_tent" }, + { "rct2.station.wooden", "rct2.station.wooden" }, + { "rct2.edge.rock", "rct2.terrain_edge.rock" }, + { "rct2.edge.woodred", "rct2.terrain_edge.wood_red" }, + { "rct2.edge.ice", "rct2.terrain_edge.ice" }, + { "rct2.edge.woodblack", "rct2.terrain_edge.wood_black" }, + { "rct2.tt.rdmet2x2", "rct2tt.scenery_large.rdmet2x2" }, + { "rct2.tt.travlr02", "rct2tt.scenery_large.travlr02" }, + { "rct2.tt.romne2x1", "rct2tt.scenery_large.romne2x1" }, + { "rct2.tt.jailxx17", "rct2tt.scenery_large.jailxx17" }, + { "rct2.tt.perdtk02", "rct2tt.scenery_large.perdtk02" }, + { "rct2.tt.schntent", "rct2tt.scenery_large.schntent" }, + { "rct2.tt.hrbwal07", "rct2tt.scenery_large.hrbwal07" }, + { "rct2.tt.alnstr08", "rct2tt.scenery_large.alnstr08" }, + { "rct2.tt.4x4volca", "rct2tt.scenery_large.4x4volca" }, + { "rct2.tt.futsky25", "rct2tt.scenery_large.futsky25" }, + { "rct2.tt.bigdrums", "rct2tt.scenery_large.bigdrums" }, + { "rct2.tt.ploughxx", "rct2tt.scenery_large.ploughxx" }, + { "rct2.tt.oldnyk20", "rct2tt.scenery_large.oldnyk20" }, + { "rct2.tt.hrbwal08", "rct2tt.scenery_large.hrbwal08" }, + { "rct2.tt.psntwl26", "rct2tt.scenery_large.psntwl26" }, + { "rct2.tt.romns2x2", "rct2tt.scenery_large.romns2x2" }, + { "rct2.tt.oldnyk27", "rct2tt.scenery_large.oldnyk27" }, + { "rct2.tt.ghotrod2", "rct2tt.scenery_large.ghotrod2" }, + { "rct2.tt.futsky20", "rct2tt.scenery_large.futsky20" }, + { "rct2.tt.majoroak", "rct2tt.scenery_large.majoroak" }, + { "rct2.tt.artdec25", "rct2tt.scenery_large.artdec25" }, + { "rct2.tt.jailxx18", "rct2tt.scenery_large.jailxx18" }, + { "rct2.tt.futsky26", "rct2tt.scenery_large.futsky26" }, + { "rct2.tt.futsky22", "rct2tt.scenery_large.futsky22" }, + { "rct2.tt.oldnyk32", "rct2tt.scenery_large.oldnyk32" }, + { "rct2.tt.peasthut", "rct2tt.scenery_large.peasthut" }, + { "rct2.tt.histfix2", "rct2tt.scenery_large.histfix2" }, + { "rct2.tt.artdec27", "rct2tt.scenery_large.artdec27" }, + { "rct2.tt.strgs2x2", "rct2tt.scenery_large.strgs2x2" }, + { "rct2.tt.forbidft", "rct2tt.scenery_large.forbidft" }, + { "rct2.tt.histfix1", "rct2tt.scenery_large.histfix1" }, + { "rct2.tt.mcastl13", "rct2tt.scenery_large.mcastl13" }, + { "rct2.tt.futsky31", "rct2tt.scenery_large.futsky31" }, + { "rct2.tt.footprnt", "rct2tt.scenery_large.footprnt" }, + { "rct2.tt.hrbwal09", "rct2tt.scenery_large.hrbwal09" }, + { "rct2.tt.mcastl11", "rct2tt.scenery_large.mcastl11" }, + { "rct2.tt.oldnyk30", "rct2tt.scenery_large.oldnyk30" }, + { "rct2.tt.caventra", "rct2tt.scenery_large.caventra" }, + { "rct2.tt.4x4diner", "rct2tt.scenery_large.4x4diner" }, + { "rct2.tt.futsky24", "rct2tt.scenery_large.futsky24" }, + { "rct2.tt.metoan01", "rct2tt.scenery_large.metoan01" }, + { "rct2.tt.perdtk01", "rct2tt.scenery_large.perdtk01" }, + { "rct2.tt.artdec26", "rct2tt.scenery_large.artdec26" }, + { "rct2.tt.romvc2x2", "rct2tt.scenery_large.romvc2x2" }, + { "rct2.tt.alnstr09", "rct2tt.scenery_large.alnstr09" }, + { "rct2.tt.mcastl17", "rct2tt.scenery_large.mcastl17" }, + { "rct2.tt.strvs2x2", "rct2tt.scenery_large.strvs2x2" }, + { "rct2.tt.romnm2x2", "rct2tt.scenery_large.romnm2x2" }, + { "rct2.tt.gbeetlex", "rct2tt.scenery_large.gbeetlex" }, + { "rct2.tt.gschlbus", "rct2tt.scenery_large.gschlbus" }, + { "rct2.tt.schnpits", "rct2tt.scenery_large.schnpits" }, + { "rct2.tt.shipm4x4", "rct2tt.scenery_large.shipm4x4" }, + { "rct2.tt.romve2x1", "rct2tt.scenery_large.romve2x1" }, + { "rct2.tt.rdmet4x4", "rct2tt.scenery_large.rdmet4x4" }, + { "rct2.tt.psntwl28", "rct2tt.scenery_large.psntwl28" }, + { "rct2.tt.futsky30", "rct2tt.scenery_large.futsky30" }, + { "rct2.tt.rdmeto02", "rct2tt.scenery_large.rdmeto02" }, + { "rct2.tt.jetplan1", "rct2tt.scenery_large.jetplan1" }, + { "rct2.tt.oldnyk24", "rct2tt.scenery_large.oldnyk24" }, + { "rct2.tt.futsky32", "rct2tt.scenery_large.futsky32" }, + { "rct2.tt.peramob2", "rct2tt.scenery_large.peramob2" }, + { "rct2.tt.metoan02", "rct2tt.scenery_large.metoan02" }, + { "rct2.tt.prdyacht", "rct2tt.scenery_large.prdyacht" }, + { "rct2.tt.mcastl14", "rct2tt.scenery_large.mcastl14" }, + { "rct2.tt.mcastl12", "rct2tt.scenery_large.mcastl12" }, + { "rct2.tt.corns2x2", "rct2tt.scenery_large.corns2x2" }, + { "rct2.tt.psntwl27", "rct2tt.scenery_large.psntwl27" }, + { "rct2.tt.hadesxxx", "rct2tt.scenery_large.hadesxxx" }, + { "rct2.tt.corvs2x2", "rct2tt.scenery_large.corvs2x2" }, + { "rct2.tt.mcastl16", "rct2tt.scenery_large.mcastl16" }, + { "rct2.tt.alnstr10", "rct2tt.scenery_large.alnstr10" }, + { "rct2.tt.ashnymph", "rct2tt.scenery_large.ashnymph" }, + { "rct2.tt.schnpit2", "rct2tt.scenery_large.schnpit2" }, + { "rct2.tt.futsky28", "rct2tt.scenery_large.futsky28" }, + { "rct2.tt.cyclopss", "rct2tt.scenery_large.cyclopss" }, + { "rct2.tt.4x4stnhn", "rct2tt.scenery_large.4x4stnhn" }, + { "rct2.tt.feastabl", "rct2tt.scenery_large.feastabl" }, + { "rct2.tt.oldnyk26", "rct2tt.scenery_large.oldnyk26" }, + { "rct2.tt.oldnyk22", "rct2tt.scenery_large.oldnyk22" }, + { "rct2.tt.tavernxx", "rct2tt.scenery_large.tavernxx" }, + { "rct2.tt.mcastl15", "rct2tt.scenery_large.mcastl15" }, + { "rct2.tt.mcastl18", "rct2tt.scenery_large.mcastl18" }, + { "rct2.tt.crsss2x2", "rct2tt.scenery_large.crsss2x2" }, + { "rct2.tt.oldnyk28", "rct2tt.scenery_large.oldnyk28" }, + { "rct2.tt.hodshut2", "rct2tt.scenery_large.hodshut2" }, + { "rct2.tt.romvm2x2", "rct2tt.scenery_large.romvm2x2" }, + { "rct2.tt.travlr01", "rct2tt.scenery_large.travlr01" }, + { "rct2.tt.hrbwal11", "rct2tt.scenery_large.hrbwal11" }, + { "rct2.tt.rdmeto01", "rct2tt.scenery_large.rdmeto01" }, + { "rct2.tt.oldnyk25", "rct2tt.scenery_large.oldnyk25" }, + { "rct2.tt.jetplan2", "rct2tt.scenery_large.jetplan2" }, + { "rct2.tt.alencrsh", "rct2tt.scenery_large.alencrsh" }, + { "rct2.tt.cratr2x2", "rct2tt.scenery_large.cratr2x2" }, + { "rct2.tt.romnc2x2", "rct2tt.scenery_large.romnc2x2" }, + { "rct2.tt.hodshut1", "rct2tt.scenery_large.hodshut1" }, + { "rct2.tt.romvs2x2", "rct2tt.scenery_large.romvs2x2" }, + { "rct2.tt.jetplan3", "rct2tt.scenery_large.jetplan3" }, + { "rct2.tt.1950scar", "rct2tt.scenery_large.1950scar" }, + { "rct2.tt.oldnyk29", "rct2tt.scenery_large.oldnyk29" }, + { "rct2.tt.ghotrod1", "rct2tt.scenery_large.ghotrod1" }, + { "rct2.tt.peramob1", "rct2tt.scenery_large.peramob1" }, + { "rct2.tt.mcastl01", "rct2tt.scenery_large.mcastl01" }, + { "rct2.tt.robncamp", "rct2tt.scenery_large.robncamp" }, + { "rct2.tt.shipb4x4", "rct2tt.scenery_large.shipb4x4" }, + { "rct2.tt.oldnyk23", "rct2tt.scenery_large.oldnyk23" }, + { "rct2.tt.4x4gmant", "rct2tt.scenery_large.4x4gmant" }, + { "rct2.tt.bandbusx", "rct2tt.scenery_large.bandbusx" }, + { "rct2.tt.alnstr11", "rct2tt.scenery_large.alnstr11" }, + { "rct2.tt.ships4x4", "rct2tt.scenery_large.ships4x4" }, + { "rct2.tt.oldnyk21", "rct2tt.scenery_large.oldnyk21" }, + { "rct2.tt.4x4trpit", "rct2tt.scenery_large.4x4trpit" }, + { "rct2.tt.cratr4x4", "rct2tt.scenery_large.cratr4x4" }, + { "rct2.tt.melmtree", "rct2tt.scenery_large.melmtree" }, + { "rct2.tt.crsvs2x2", "rct2tt.scenery_large.crsvs2x2" }, + { "rct2.tt.scg1960s", "rct2tt.scenery_group.scg1960s" }, + { "rct2.tt.scgfutur", "rct2tt.scenery_group.scgfutur" }, + { "rct2.tt.scgmytho", "rct2tt.scenery_group.scgmytho" }, + { "rct2.tt.scg1920s", "rct2tt.scenery_group.scg1920s" }, + { "rct2.tt.scg1920w", "rct2tt.scenery_group.scg1920w" }, + { "rct2.tt.scgmediv", "rct2tt.scenery_group.scgmediv" }, + { "rct2.tt.scgjurra", "rct2tt.scenery_group.scgjurra" }, + { "rct2.tt.waveking", "rct2tt.scenery_small.waveking" }, + { "rct2.tt.shwdfrst", "rct2tt.scenery_small.shwdfrst" }, + { "rct2.tt.psntwl13", "rct2tt.scenery_small.psntwl13" }, + { "rct2.tt.hevbth09", "rct2tt.scenery_small.hevbth09" }, + { "rct2.tt.medtools", "rct2tt.scenery_small.medtools" }, + { "rct2.tt.compeyex", "rct2tt.scenery_small.compeyex" }, + { "rct2.tt.evalien3", "rct2tt.scenery_small.evalien3" }, + { "rct2.tt.psntwl10", "rct2tt.scenery_small.psntwl10" }, + { "rct2.tt.hrbwal04", "rct2tt.scenery_small.hrbwal04" }, + { "rct2.tt.runway06", "rct2tt.scenery_small.runway06" }, + { "rct2.tt.elecfen4", "rct2tt.scenery_small.elecfen4" }, + { "rct2.tt.primst01", "rct2tt.scenery_small.primst01" }, + { "rct2.tt.hevrof02", "rct2tt.scenery_small.hevrof02" }, + { "rct2.tt.dkfight1", "rct2tt.scenery_small.dkfight1" }, + { "rct2.tt.oldnyk07", "rct2tt.scenery_small.oldnyk07" }, + { "rct2.tt.swamplt4", "rct2tt.scenery_small.swamplt4" }, + { "rct2.tt.hovrcar4", "rct2tt.scenery_small.hovrcar4" }, + { "rct2.tt.spiktail", "rct2tt.scenery_small.spiktail" }, + { "rct2.tt.laserx01", "rct2tt.scenery_small.laserx01" }, + { "rct2.tt.stgband1", "rct2tt.scenery_small.stgband1" }, + { "rct2.tt.pdflag03", "rct2tt.scenery_small.pdflag03" }, + { "rct2.tt.futsky21", "rct2tt.scenery_small.futsky21" }, + { "rct2.tt.artdec01", "rct2tt.scenery_small.artdec01" }, + { "rct2.tt.horsecrt", "rct2tt.scenery_small.horsecrt" }, + { "rct2.tt.spcshp01", "rct2tt.scenery_small.spcshp01" }, + { "rct2.tt.gldchest", "rct2tt.scenery_small.gldchest" }, + { "rct2.tt.cavemenx", "rct2tt.scenery_small.cavemenx" }, + { "rct2.tt.dkfight2", "rct2tt.scenery_small.dkfight2" }, + { "rct2.tt.stnesta4", "rct2tt.scenery_small.stnesta4" }, + { "rct2.tt.dinsign2", "rct2tt.scenery_small.dinsign2" }, + { "rct2.tt.oldnyk19", "rct2tt.scenery_small.oldnyk19" }, + { "rct2.tt.argonau2", "rct2tt.scenery_small.argonau2" }, + { "rct2.tt.bigbassx", "rct2tt.scenery_small.bigbassx" }, + { "rct2.tt.artdec10", "rct2tt.scenery_small.artdec10" }, + { "rct2.tt.runway04", "rct2tt.scenery_small.runway04" }, + { "rct2.tt.valkri01", "rct2tt.scenery_small.valkri01" }, + { "rct2.tt.futsky39", "rct2tt.scenery_small.futsky39" }, + { "rct2.tt.artdec14", "rct2tt.scenery_small.artdec14" }, + { "rct2.tt.fwrprdc1", "rct2tt.scenery_small.fwrprdc1" }, + { "rct2.tt.skeleto3", "rct2tt.scenery_small.skeleto3" }, + { "rct2.tt.artdec12", "rct2tt.scenery_small.artdec12" }, + { "rct2.tt.alnstr06", "rct2tt.scenery_small.alnstr06" }, + { "rct2.tt.jailxx20", "rct2tt.scenery_small.jailxx20" }, + { "rct2.tt.indwal12", "rct2tt.scenery_small.indwal12" }, + { "rct2.tt.speakr01", "rct2tt.scenery_small.speakr01" }, + { "rct2.tt.futsky42", "rct2tt.scenery_small.futsky42" }, + { "rct2.tt.mcastl04", "rct2tt.scenery_small.mcastl04" }, + { "rct2.tt.jailxx21", "rct2tt.scenery_small.jailxx21" }, + { "rct2.tt.futsky33", "rct2tt.scenery_small.futsky33" }, + { "rct2.tt.spcshp06", "rct2tt.scenery_small.spcshp06" }, + { "rct2.tt.artdec09", "rct2tt.scenery_small.artdec09" }, + { "rct2.tt.indwal18", "rct2tt.scenery_small.indwal18" }, + { "rct2.tt.artdec22", "rct2tt.scenery_small.artdec22" }, + { "rct2.tt.psntwl05", "rct2tt.scenery_small.psntwl05" }, + { "rct2.tt.hevbth03", "rct2tt.scenery_small.hevbth03" }, + { "rct2.tt.elecfen5", "rct2tt.scenery_small.elecfen5" }, + { "rct2.tt.indwal10", "rct2tt.scenery_small.indwal10" }, + { "rct2.tt.schnpl01", "rct2tt.scenery_small.schnpl01" }, + { "rct2.tt.hevbth15", "rct2tt.scenery_small.hevbth15" }, + { "rct2.tt.alenplt2", "rct2tt.scenery_small.alenplt2" }, + { "rct2.tt.artdec28", "rct2tt.scenery_small.artdec28" }, + { "rct2.tt.robnhood", "rct2tt.scenery_small.robnhood" }, + { "rct2.tt.alentre2", "rct2tt.scenery_small.alentre2" }, + { "rct2.tt.schnpl05", "rct2tt.scenery_small.schnpl05" }, + { "rct2.tt.futsky36", "rct2tt.scenery_small.futsky36" }, + { "rct2.tt.smoksk01", "rct2tt.scenery_small.smoksk01" }, + { "rct2.tt.primhear", "rct2tt.scenery_small.primhear" }, + { "rct2.tt.skeleto2", "rct2tt.scenery_small.skeleto2" }, + { "rct2.tt.futsky11", "rct2tt.scenery_small.futsky11" }, + { "rct2.tt.swrdstne", "rct2tt.scenery_small.swrdstne" }, + { "rct2.tt.hrbwal01", "rct2tt.scenery_small.hrbwal01" }, + { "rct2.tt.evalien2", "rct2tt.scenery_small.evalien2" }, + { "rct2.tt.indwal21", "rct2tt.scenery_small.indwal21" }, + { "rct2.tt.smallcpu", "rct2tt.scenery_small.smallcpu" }, + { "rct2.tt.rswatres", "rct2tt.scenery_small.rswatres" }, + { "rct2.tt.psntwl06", "rct2tt.scenery_small.psntwl06" }, + { "rct2.tt.primroot", "rct2tt.scenery_small.primroot" }, + { "rct2.tt.spcshp03", "rct2tt.scenery_small.spcshp03" }, + { "rct2.tt.stoolset", "rct2tt.scenery_small.stoolset" }, + { "rct2.tt.ggntocto", "rct2tt.scenery_small.ggntocto" }, + { "rct2.tt.tarpit02", "rct2tt.scenery_small.tarpit02" }, + { "rct2.tt.drgnattk", "rct2tt.scenery_small.drgnattk" }, + { "rct2.tt.futsky01", "rct2tt.scenery_small.futsky01" }, + { "rct2.tt.tarpit05", "rct2tt.scenery_small.tarpit05" }, + { "rct2.tt.jailxx13", "rct2tt.scenery_small.jailxx13" }, + { "rct2.tt.tarpit10", "rct2tt.scenery_small.tarpit10" }, + { "rct2.tt.hvrbike1", "rct2tt.scenery_small.hvrbike1" }, + { "rct2.tt.oldnyk33", "rct2tt.scenery_small.oldnyk33" }, + { "rct2.tt.metrcrs2", "rct2tt.scenery_small.metrcrs2" }, + { "rct2.tt.hevbth12", "rct2tt.scenery_small.hevbth12" }, + { "rct2.tt.swamplt5", "rct2tt.scenery_small.swamplt5" }, + { "rct2.tt.spcshp08", "rct2tt.scenery_small.spcshp08" }, + { "rct2.tt.indwal22", "rct2tt.scenery_small.indwal22" }, + { "rct2.tt.spcshp09", "rct2tt.scenery_small.spcshp09" }, + { "rct2.tt.hevbth05", "rct2tt.scenery_small.hevbth05" }, + { "rct2.tt.oldnyk09", "rct2tt.scenery_small.oldnyk09" }, + { "rct2.tt.elecfen3", "rct2tt.scenery_small.elecfen3" }, + { "rct2.tt.frbeacon", "rct2tt.scenery_small.frbeacon" }, + { "rct2.tt.strictop", "rct2tt.scenery_small.strictop" }, + { "rct2.tt.futsky40", "rct2tt.scenery_small.futsky40" }, + { "rct2.tt.swamplt6", "rct2tt.scenery_small.swamplt6" }, + { "rct2.tt.mamthw02", "rct2tt.scenery_small.mamthw02" }, + { "rct2.tt.psntwl30", "rct2tt.scenery_small.psntwl30" }, + { "rct2.tt.primroor", "rct2tt.scenery_small.primroor" }, + { "rct2.tt.spcshp07", "rct2tt.scenery_small.spcshp07" }, + { "rct2.tt.futsky44", "rct2tt.scenery_small.futsky44" }, + { "rct2.tt.jazzmbr1", "rct2tt.scenery_small.jazzmbr1" }, + { "rct2.tt.pdflag05", "rct2tt.scenery_small.pdflag05" }, + { "rct2.tt.tarpit01", "rct2tt.scenery_small.tarpit01" }, + { "rct2.tt.futsky17", "rct2tt.scenery_small.futsky17" }, + { "rct2.tt.futsky04", "rct2tt.scenery_small.futsky04" }, + { "rct2.tt.pdflag04", "rct2tt.scenery_small.pdflag04" }, + { "rct2.tt.artdec05", "rct2tt.scenery_small.artdec05" }, + { "rct2.tt.psntwl02", "rct2tt.scenery_small.psntwl02" }, + { "rct2.tt.indwal30", "rct2tt.scenery_small.indwal30" }, + { "rct2.tt.mcastl06", "rct2tt.scenery_small.mcastl06" }, + { "rct2.tt.jazzmbr2", "rct2tt.scenery_small.jazzmbr2" }, + { "rct2.tt.futsky48", "rct2tt.scenery_small.futsky48" }, + { "rct2.tt.futsky05", "rct2tt.scenery_small.futsky05" }, + { "rct2.tt.oldnyk13", "rct2tt.scenery_small.oldnyk13" }, + { "rct2.tt.psntwl31", "rct2tt.scenery_small.psntwl31" }, + { "rct2.tt.argonau3", "rct2tt.scenery_small.argonau3" }, + { "rct2.tt.psntwl07", "rct2tt.scenery_small.psntwl07" }, + { "rct2.tt.oldnyk16", "rct2tt.scenery_small.oldnyk16" }, + { "rct2.tt.haybails", "rct2tt.scenery_small.haybails" }, + { "rct2.tt.indwal29", "rct2tt.scenery_small.indwal29" }, + { "rct2.tt.clnsmen1", "rct2tt.scenery_small.clnsmen1" }, + { "rct2.tt.smoksk02", "rct2tt.scenery_small.smoksk02" }, + { "rct2.tt.oldnyk05", "rct2tt.scenery_small.oldnyk05" }, + { "rct2.tt.tarpit13", "rct2tt.scenery_small.tarpit13" }, + { "rct2.tt.mcastl05", "rct2tt.scenery_small.mcastl05" }, + { "rct2.tt.hevbth10", "rct2tt.scenery_small.hevbth10" }, + { "rct2.tt.indwal04", "rct2tt.scenery_small.indwal04" }, + { "rct2.tt.futsky08", "rct2tt.scenery_small.futsky08" }, + { "rct2.tt.futsky12", "rct2tt.scenery_small.futsky12" }, + { "rct2.tt.stnesta1", "rct2tt.scenery_small.stnesta1" }, + { "rct2.tt.mcastl19", "rct2tt.scenery_small.mcastl19" }, + { "rct2.tt.futsky46", "rct2tt.scenery_small.futsky46" }, + { "rct2.tt.chprbke2", "rct2tt.scenery_small.chprbke2" }, + { "rct2.tt.spcshp11", "rct2tt.scenery_small.spcshp11" }, + { "rct2.tt.indwal11", "rct2tt.scenery_small.indwal11" }, + { "rct2.tt.artdec21", "rct2tt.scenery_small.artdec21" }, + { "rct2.tt.alenplt1", "rct2tt.scenery_small.alenplt1" }, + { "rct2.tt.hevbth08", "rct2tt.scenery_small.hevbth08" }, + { "rct2.tt.spcshp02", "rct2tt.scenery_small.spcshp02" }, + { "rct2.tt.tarpit08", "rct2tt.scenery_small.tarpit08" }, + { "rct2.tt.jailxx11", "rct2tt.scenery_small.jailxx11" }, + { "rct2.tt.artdec15", "rct2tt.scenery_small.artdec15" }, + { "rct2.tt.psntwl08", "rct2tt.scenery_small.psntwl08" }, + { "rct2.tt.dinsign4", "rct2tt.scenery_small.dinsign4" }, + { "rct2.tt.armrswrd", "rct2tt.scenery_small.armrswrd" }, + { "rct2.tt.oldnyk08", "rct2tt.scenery_small.oldnyk08" }, + { "rct2.tt.psntwl24", "rct2tt.scenery_small.psntwl24" }, + { "rct2.tt.gdalien2", "rct2tt.scenery_small.gdalien2" }, + { "rct2.tt.hevbth13", "rct2tt.scenery_small.hevbth13" }, + { "rct2.tt.psntwl21", "rct2tt.scenery_small.psntwl21" }, + { "rct2.tt.metrcrs1", "rct2tt.scenery_small.metrcrs1" }, + { "rct2.tt.swamplt2", "rct2tt.scenery_small.swamplt2" }, + { "rct2.tt.futsky19", "rct2tt.scenery_small.futsky19" }, + { "rct2.tt.hevbth14", "rct2tt.scenery_small.hevbth14" }, + { "rct2.tt.jailxx06", "rct2tt.scenery_small.jailxx06" }, + { "rct2.tt.gdalien3", "rct2tt.scenery_small.gdalien3" }, + { "rct2.tt.artdec19", "rct2tt.scenery_small.artdec19" }, + { "rct2.tt.hurcluls", "rct2tt.scenery_small.hurcluls" }, + { "rct2.tt.pdflag06", "rct2tt.scenery_small.pdflag06" }, + { "rct2.tt.yewtreex", "rct2tt.scenery_small.yewtreex" }, + { "rct2.tt.furobot1", "rct2tt.scenery_small.furobot1" }, + { "rct2.tt.furobot2", "rct2tt.scenery_small.furobot2" }, + { "rct2.tt.mcastl09", "rct2tt.scenery_small.mcastl09" }, + { "rct2.tt.futsky35", "rct2tt.scenery_small.futsky35" }, + { "rct2.tt.psntwl17", "rct2tt.scenery_small.psntwl17" }, + { "rct2.tt.killrvin", "rct2tt.scenery_small.killrvin" }, + { "rct2.tt.alentre1", "rct2tt.scenery_small.alentre1" }, + { "rct2.tt.swamplt7", "rct2tt.scenery_small.swamplt7" }, + { "rct2.tt.hevbth04", "rct2tt.scenery_small.hevbth04" }, + { "rct2.tt.primst03", "rct2tt.scenery_small.primst03" }, + { "rct2.tt.jailxx02", "rct2tt.scenery_small.jailxx02" }, + { "rct2.tt.wepnrack", "rct2tt.scenery_small.wepnrack" }, + { "rct2.tt.oldnyk35", "rct2tt.scenery_small.oldnyk35" }, + { "rct2.tt.laserx02", "rct2tt.scenery_small.laserx02" }, + { "rct2.tt.psntwl11", "rct2tt.scenery_small.psntwl11" }, + { "rct2.tt.souptl01", "rct2tt.scenery_small.souptl01" }, + { "rct2.tt.futsky41", "rct2tt.scenery_small.futsky41" }, + { "rct2.tt.tarpit12", "rct2tt.scenery_small.tarpit12" }, + { "rct2.tt.artdec13", "rct2tt.scenery_small.artdec13" }, + { "rct2.tt.mdusasta", "rct2tt.scenery_small.mdusasta" }, + { "rct2.tt.psntwl23", "rct2tt.scenery_small.psntwl23" }, + { "rct2.tt.wiskybl2", "rct2tt.scenery_small.wiskybl2" }, + { "rct2.tt.indwal14", "rct2tt.scenery_small.indwal14" }, + { "rct2.tt.pdflag15", "rct2tt.scenery_small.pdflag15" }, + { "rct2.tt.primscrn", "rct2tt.scenery_small.primscrn" }, + { "rct2.tt.tyranrex", "rct2tt.scenery_small.tyranrex" }, + { "rct2.tt.gscorpo2", "rct2tt.scenery_small.gscorpo2" }, + { "rct2.tt.mamthw05", "rct2tt.scenery_small.mamthw05" }, + { "rct2.tt.spcshp12", "rct2tt.scenery_small.spcshp12" }, + { "rct2.tt.valkri02", "rct2tt.scenery_small.valkri02" }, + { "rct2.tt.tarpit06", "rct2tt.scenery_small.tarpit06" }, + { "rct2.tt.hrbwal02", "rct2tt.scenery_small.hrbwal02" }, + { "rct2.tt.psntwl04", "rct2tt.scenery_small.psntwl04" }, + { "rct2.tt.alnstr01", "rct2tt.scenery_small.alnstr01" }, + { "rct2.tt.indwal09", "rct2tt.scenery_small.indwal09" }, + { "rct2.tt.artdec17", "rct2tt.scenery_small.artdec17" }, + { "rct2.tt.indwal06", "rct2tt.scenery_small.indwal06" }, + { "rct2.tt.fltsign1", "rct2tt.scenery_small.fltsign1" }, + { "rct2.tt.hrbwal05", "rct2tt.scenery_small.hrbwal05" }, + { "rct2.tt.futsky03", "rct2tt.scenery_small.futsky03" }, + { "rct2.tt.stnesta2", "rct2tt.scenery_small.stnesta2" }, + { "rct2.tt.futsky18", "rct2tt.scenery_small.futsky18" }, + { "rct2.tt.indwal28", "rct2tt.scenery_small.indwal28" }, + { "rct2.tt.tarpit14", "rct2tt.scenery_small.tarpit14" }, + { "rct2.tt.swamplt8", "rct2tt.scenery_small.swamplt8" }, + { "rct2.tt.indwal17", "rct2tt.scenery_small.indwal17" }, + { "rct2.tt.indwal23", "rct2tt.scenery_small.indwal23" }, + { "rct2.tt.mcastl03", "rct2tt.scenery_small.mcastl03" }, + { "rct2.tt.armrhelm", "rct2tt.scenery_small.armrhelm" }, + { "rct2.tt.gangster", "rct2tt.scenery_small.gangster" }, + { "rct2.tt.tarpit03", "rct2tt.scenery_small.tarpit03" }, + { "rct2.tt.stgband4", "rct2tt.scenery_small.stgband4" }, + { "rct2.tt.schnpl03", "rct2tt.scenery_small.schnpl03" }, + { "rct2.tt.hrbwal06", "rct2tt.scenery_small.hrbwal06" }, + { "rct2.tt.whccolds", "rct2tt.scenery_small.whccolds" }, + { "rct2.tt.futsky52", "rct2tt.scenery_small.futsky52" }, + { "rct2.tt.futsky13", "rct2tt.scenery_small.futsky13" }, + { "rct2.tt.armrshld", "rct2tt.scenery_small.armrshld" }, + { "rct2.tt.artdec02", "rct2tt.scenery_small.artdec02" }, + { "rct2.tt.indwal08", "rct2tt.scenery_small.indwal08" }, + { "rct2.tt.mamthw03", "rct2tt.scenery_small.mamthw03" }, + { "rct2.tt.gscorpon", "rct2tt.scenery_small.gscorpon" }, + { "rct2.tt.futsky38", "rct2tt.scenery_small.futsky38" }, + { "rct2.tt.wiskybl1", "rct2tt.scenery_small.wiskybl1" }, + { "rct2.tt.largecpu", "rct2tt.scenery_small.largecpu" }, + { "rct2.tt.schnbouy", "rct2tt.scenery_small.schnbouy" }, + { "rct2.tt.indwal16", "rct2tt.scenery_small.indwal16" }, + { "rct2.tt.hevrof03", "rct2tt.scenery_small.hevrof03" }, + { "rct2.tt.psntwl25", "rct2tt.scenery_small.psntwl25" }, + { "rct2.tt.meteorst", "rct2tt.scenery_small.meteorst" }, + { "rct2.tt.futsky14", "rct2tt.scenery_small.futsky14" }, + { "rct2.tt.indwal31", "rct2tt.scenery_small.indwal31" }, + { "rct2.tt.spcshp05", "rct2tt.scenery_small.spcshp05" }, + { "rct2.tt.jailxx01", "rct2tt.scenery_small.jailxx01" }, + { "rct2.tt.indwal25", "rct2tt.scenery_small.indwal25" }, + { "rct2.tt.futsky09", "rct2tt.scenery_small.futsky09" }, + { "rct2.tt.primwal1", "rct2tt.scenery_small.primwal1" }, + { "rct2.tt.artdec11", "rct2tt.scenery_small.artdec11" }, + { "rct2.tt.jailxx15", "rct2tt.scenery_small.jailxx15" }, + { "rct2.tt.souped01", "rct2tt.scenery_small.souped01" }, + { "rct2.tt.indwal13", "rct2tt.scenery_small.indwal13" }, + { "rct2.tt.artdec18", "rct2tt.scenery_small.artdec18" }, + { "rct2.tt.minotaur", "rct2tt.scenery_small.minotaur" }, + { "rct2.tt.indwal32", "rct2tt.scenery_small.indwal32" }, + { "rct2.tt.stnesta3", "rct2tt.scenery_small.stnesta3" }, + { "rct2.tt.zeusstat", "rct2tt.scenery_small.zeusstat" }, + { "rct2.tt.indwal27", "rct2tt.scenery_small.indwal27" }, + { "rct2.tt.knfight2", "rct2tt.scenery_small.knfight2" }, + { "rct2.tt.schncrsh", "rct2tt.scenery_small.schncrsh" }, + { "rct2.tt.polwtbtn", "rct2tt.scenery_small.polwtbtn" }, + { "rct2.tt.ggntspid", "rct2tt.scenery_small.ggntspid" }, + { "rct2.tt.oldnyk14", "rct2tt.scenery_small.oldnyk14" }, + { "rct2.tt.indwal02", "rct2tt.scenery_small.indwal02" }, + { "rct2.tt.futsky47", "rct2tt.scenery_small.futsky47" }, + { "rct2.tt.soupcrn2", "rct2tt.scenery_small.soupcrn2" }, + { "rct2.tt.indwal20", "rct2tt.scenery_small.indwal20" }, + { "rct2.tt.hevbth06", "rct2tt.scenery_small.hevbth06" }, + { "rct2.tt.futsky02", "rct2tt.scenery_small.futsky02" }, + { "rct2.tt.schnbost", "rct2tt.scenery_small.schnbost" }, + { "rct2.tt.alnstr02", "rct2tt.scenery_small.alnstr02" }, + { "rct2.tt.tarpit07", "rct2tt.scenery_small.tarpit07" }, + { "rct2.tt.pdflag14", "rct2tt.scenery_small.pdflag14" }, + { "rct2.tt.1920slmp", "rct2tt.scenery_small.1920slmp" }, + { "rct2.tt.tarpit09", "rct2tt.scenery_small.tarpit09" }, + { "rct2.tt.mcastl07", "rct2tt.scenery_small.mcastl07" }, + { "rct2.tt.artdec06", "rct2tt.scenery_small.artdec06" }, + { "rct2.tt.futsky29", "rct2tt.scenery_small.futsky29" }, + { "rct2.tt.indwal05", "rct2tt.scenery_small.indwal05" }, + { "rct2.tt.pdflag08", "rct2tt.scenery_small.pdflag08" }, + { "rct2.tt.rdmeto04", "rct2tt.scenery_small.rdmeto04" }, + { "rct2.tt.wdncart2", "rct2tt.scenery_small.wdncart2" }, + { "rct2.tt.gdalien1", "rct2tt.scenery_small.gdalien1" }, + { "rct2.tt.mamthw01", "rct2tt.scenery_small.mamthw01" }, + { "rct2.tt.jailxx10", "rct2tt.scenery_small.jailxx10" }, + { "rct2.tt.jailxx16", "rct2tt.scenery_small.jailxx16" }, + { "rct2.tt.smoksk03", "rct2tt.scenery_small.smoksk03" }, + { "rct2.tt.pdflag13", "rct2tt.scenery_small.pdflag13" }, + { "rct2.tt.oldnyk01", "rct2tt.scenery_small.oldnyk01" }, + { "rct2.tt.artdec29", "rct2tt.scenery_small.artdec29" }, + { "rct2.tt.firemanx", "rct2tt.scenery_small.firemanx" }, + { "rct2.tt.cagdstat", "rct2tt.scenery_small.cagdstat" }, + { "rct2.tt.oldnyk04", "rct2tt.scenery_small.oldnyk04" }, + { "rct2.tt.jailxx05", "rct2tt.scenery_small.jailxx05" }, + { "rct2.tt.chanmaid", "rct2tt.scenery_small.chanmaid" }, + { "rct2.tt.runway02", "rct2tt.scenery_small.runway02" }, + { "rct2.tt.hevrof04", "rct2tt.scenery_small.hevrof04" }, + { "rct2.tt.indwal19", "rct2tt.scenery_small.indwal19" }, + { "rct2.tt.mamthw04", "rct2tt.scenery_small.mamthw04" }, + { "rct2.tt.stmdran1", "rct2tt.scenery_small.stmdran1" }, + { "rct2.tt.futsky37", "rct2tt.scenery_small.futsky37" }, + { "rct2.tt.psntwl01", "rct2tt.scenery_small.psntwl01" }, + { "rct2.tt.indwal01", "rct2tt.scenery_small.indwal01" }, + { "rct2.tt.oldnyk18", "rct2tt.scenery_small.oldnyk18" }, + { "rct2.tt.alnstr04", "rct2tt.scenery_small.alnstr04" }, + { "rct2.tt.schnpl04", "rct2tt.scenery_small.schnpl04" }, + { "rct2.tt.oldnyk17", "rct2tt.scenery_small.oldnyk17" }, + { "rct2.tt.hovrcar1", "rct2tt.scenery_small.hovrcar1" }, + { "rct2.tt.goldflec", "rct2tt.scenery_small.goldflec" }, + { "rct2.tt.rcknrolr", "rct2tt.scenery_small.rcknrolr" }, + { "rct2.tt.jailxx08", "rct2tt.scenery_small.jailxx08" }, + { "rct2.tt.alnstr07", "rct2tt.scenery_small.alnstr07" }, + { "rct2.tt.schnpl06", "rct2tt.scenery_small.schnpl06" }, + { "rct2.tt.artdec03", "rct2tt.scenery_small.artdec03" }, + { "rct2.tt.swamplt3", "rct2tt.scenery_small.swamplt3" }, + { "rct2.tt.jailxx14", "rct2tt.scenery_small.jailxx14" }, + { "rct2.tt.futsky53", "rct2tt.scenery_small.futsky53" }, + { "rct2.tt.hevrof01", "rct2tt.scenery_small.hevrof01" }, + { "rct2.tt.sdragfly", "rct2tt.scenery_small.sdragfly" }, + { "rct2.tt.elecfen1", "rct2tt.scenery_small.elecfen1" }, + { "rct2.tt.knfight1", "rct2tt.scenery_small.knfight1" }, + { "rct2.tt.guyqwifx", "rct2tt.scenery_small.guyqwifx" }, + { "rct2.tt.psntwl20", "rct2tt.scenery_small.psntwl20" }, + { "rct2.tt.schntnny", "rct2tt.scenery_small.schntnny" }, + { "rct2.tt.oldnyk02", "rct2tt.scenery_small.oldnyk02" }, + { "rct2.tt.futsky10", "rct2tt.scenery_small.futsky10" }, + { "rct2.tt.rdmeto03", "rct2tt.scenery_small.rdmeto03" }, + { "rct2.tt.indwal26", "rct2tt.scenery_small.indwal26" }, + { "rct2.tt.psntwl12", "rct2tt.scenery_small.psntwl12" }, + { "rct2.tt.bolpot01", "rct2tt.scenery_small.bolpot01" }, + { "rct2.tt.biggutar", "rct2tt.scenery_small.biggutar" }, + { "rct2.tt.fltsign2", "rct2tt.scenery_small.fltsign2" }, + { "rct2.tt.artdec04", "rct2tt.scenery_small.artdec04" }, + { "rct2.tt.armrbody", "rct2tt.scenery_small.armrbody" }, + { "rct2.tt.souptl02", "rct2tt.scenery_small.souptl02" }, + { "rct2.tt.spcshp10", "rct2tt.scenery_small.spcshp10" }, + { "rct2.tt.futsky15", "rct2tt.scenery_small.futsky15" }, + { "rct2.tt.futsky54", "rct2tt.scenery_small.futsky54" }, + { "rct2.tt.soupcrnr", "rct2tt.scenery_small.soupcrnr" }, + { "rct2.tt.dinsign1", "rct2tt.scenery_small.dinsign1" }, + { "rct2.tt.volcvent", "rct2tt.scenery_small.volcvent" }, + { "rct2.tt.schnpl02", "rct2tt.scenery_small.schnpl02" }, + { "rct2.tt.futsky23", "rct2tt.scenery_small.futsky23" }, + { "rct2.tt.psntwl14", "rct2tt.scenery_small.psntwl14" }, + { "rct2.tt.astrongt", "rct2tt.scenery_small.astrongt" }, + { "rct2.tt.spterdac", "rct2tt.scenery_small.spterdac" }, + { "rct2.tt.futsky34", "rct2tt.scenery_small.futsky34" }, + { "rct2.tt.hovrcar2", "rct2tt.scenery_small.hovrcar2" }, + { "rct2.tt.alnstr03", "rct2tt.scenery_small.alnstr03" }, + { "rct2.tt.primhead", "rct2tt.scenery_small.primhead" }, + { "rct2.tt.futsky16", "rct2tt.scenery_small.futsky16" }, + { "rct2.tt.spcshp04", "rct2tt.scenery_small.spcshp04" }, + { "rct2.tt.jazzmbr3", "rct2tt.scenery_small.jazzmbr3" }, + { "rct2.tt.psntwl16", "rct2tt.scenery_small.psntwl16" }, + { "rct2.tt.mamthw06", "rct2tt.scenery_small.mamthw06" }, + { "rct2.tt.oldnyk15", "rct2tt.scenery_small.oldnyk15" }, + { "rct2.tt.tarpit04", "rct2tt.scenery_small.tarpit04" }, + { "rct2.tt.chprbke1", "rct2tt.scenery_small.chprbke1" }, + { "rct2.tt.indwal07", "rct2tt.scenery_small.indwal07" }, + { "rct2.tt.allseeye", "rct2tt.scenery_small.allseeye" }, + { "rct2.tt.artdec20", "rct2tt.scenery_small.artdec20" }, + { "rct2.tt.oldnyk34", "rct2tt.scenery_small.oldnyk34" }, + { "rct2.tt.argonau1", "rct2tt.scenery_small.argonau1" }, + { "rct2.tt.oldnyk11", "rct2tt.scenery_small.oldnyk11" }, + { "rct2.tt.indwal15", "rct2tt.scenery_small.indwal15" }, + { "rct2.tt.evalien1", "rct2tt.scenery_small.evalien1" }, + { "rct2.tt.tarpit11", "rct2tt.scenery_small.tarpit11" }, + { "rct2.tt.speakr02", "rct2tt.scenery_small.speakr02" }, + { "rct2.tt.runway05", "rct2tt.scenery_small.runway05" }, + { "rct2.tt.skeleto1", "rct2tt.scenery_small.skeleto1" }, + { "rct2.tt.pdflag16", "rct2tt.scenery_small.pdflag16" }, + { "rct2.tt.mcastl10", "rct2tt.scenery_small.mcastl10" }, + { "rct2.tt.cookspit", "rct2tt.scenery_small.cookspit" }, + { "rct2.tt.primst02", "rct2tt.scenery_small.primst02" }, + { "rct2.tt.jailxx03", "rct2tt.scenery_small.jailxx03" }, + { "rct2.tt.artdec07", "rct2tt.scenery_small.artdec07" }, + { "rct2.tt.geyserxx", "rct2tt.scenery_small.geyserxx" }, + { "rct2.tt.spacrang", "rct2tt.scenery_small.spacrang" }, + { "rct2.tt.hevbth11", "rct2tt.scenery_small.hevbth11" }, + { "rct2.tt.runway01", "rct2tt.scenery_small.runway01" }, + { "rct2.tt.jailxx12", "rct2tt.scenery_small.jailxx12" }, + { "rct2.tt.runway03", "rct2tt.scenery_small.runway03" }, + { "rct2.tt.hevbth16", "rct2tt.scenery_small.hevbth16" }, + { "rct2.tt.jazzmbr4", "rct2tt.scenery_small.jazzmbr4" }, + { "rct2.tt.stgband2", "rct2tt.scenery_small.stgband2" }, + { "rct2.tt.oldnyk03", "rct2tt.scenery_small.oldnyk03" }, + { "rct2.tt.oldnyk12", "rct2tt.scenery_small.oldnyk12" }, + { "rct2.tt.meteorcr", "rct2tt.scenery_small.meteorcr" }, + { "rct2.tt.indwal24", "rct2tt.scenery_small.indwal24" }, + { "rct2.tt.dinsign3", "rct2tt.scenery_small.dinsign3" }, + { "rct2.tt.futsky07", "rct2tt.scenery_small.futsky07" }, + { "rct2.tt.swamplt1", "rct2tt.scenery_small.swamplt1" }, + { "rct2.tt.psntwl29", "rct2tt.scenery_small.psntwl29" }, + { "rct2.tt.hrbwal03", "rct2tt.scenery_small.hrbwal03" }, + { "rct2.tt.swamplt9", "rct2tt.scenery_small.swamplt9" }, + { "rct2.tt.artdec24", "rct2tt.scenery_small.artdec24" }, + { "rct2.tt.schndrum", "rct2tt.scenery_small.schndrum" }, + { "rct2.tt.indwal03", "rct2tt.scenery_small.indwal03" }, + { "rct2.tt.mdbucket", "rct2tt.scenery_small.mdbucket" }, + { "rct2.tt.jailxx04", "rct2tt.scenery_small.jailxx04" }, + { "rct2.tt.souped02", "rct2tt.scenery_small.souped02" }, + { "rct2.tt.psntwl15", "rct2tt.scenery_small.psntwl15" }, + { "rct2.tt.hvrbike3", "rct2tt.scenery_small.hvrbike3" }, + { "rct2.tt.hevbth17", "rct2tt.scenery_small.hevbth17" }, + { "rct2.tt.artdec16", "rct2tt.scenery_small.artdec16" }, + { "rct2.tt.futsky06", "rct2tt.scenery_small.futsky06" }, + { "rct2.tt.artdec23", "rct2tt.scenery_small.artdec23" }, + { "rct2.tt.titansta", "rct2tt.scenery_small.titansta" }, + { "rct2.tt.oldnyk31", "rct2tt.scenery_small.oldnyk31" }, + { "rct2.tt.hvrbike4", "rct2tt.scenery_small.hvrbike4" }, + { "rct2.tt.medtrget", "rct2tt.scenery_small.medtrget" }, + { "rct2.tt.stgband3", "rct2tt.scenery_small.stgband3" }, + { "rct2.tt.primtall", "rct2tt.scenery_small.primtall" }, + { "rct2.tt.jailxx09", "rct2tt.scenery_small.jailxx09" }, + { "rct2.tt.hovrcar3", "rct2tt.scenery_small.hovrcar3" }, + { "rct2.tt.fircanon", "rct2tt.scenery_small.fircanon" }, + { "rct2.tt.psntwl03", "rct2tt.scenery_small.psntwl03" }, + { "rct2.tt.mcastl02", "rct2tt.scenery_small.mcastl02" }, + { "rct2.tt.oldnyk10", "rct2tt.scenery_small.oldnyk10" }, + { "rct2.tt.hevbth02", "rct2tt.scenery_small.hevbth02" }, + { "rct2.tt.elecfen2", "rct2tt.scenery_small.elecfen2" }, + { "rct2.tt.jailxx07", "rct2tt.scenery_small.jailxx07" }, + { "rct2.tt.alnstr05", "rct2tt.scenery_small.alnstr05" }, + { "rct2.tt.bkrgang1", "rct2tt.scenery_small.bkrgang1" }, + { "rct2.tt.medstool", "rct2tt.scenery_small.medstool" }, + { "rct2.tt.artdec08", "rct2tt.scenery_small.artdec08" }, + { "rct2.tt.psntwl09", "rct2tt.scenery_small.psntwl09" }, + { "rct2.tt.mcastl08", "rct2tt.scenery_small.mcastl08" }, + { "rct2.tt.hvrbike2", "rct2tt.scenery_small.hvrbike2" }, + { "rct2.tt.primwal3", "rct2tt.scenery_small.primwal3" }, + { "rct2.tt.pdflag02", "rct2tt.scenery_small.pdflag02" }, + { "rct2.tt.hevbth01", "rct2tt.scenery_small.hevbth01" }, + { "rct2.tt.hevbth07", "rct2tt.scenery_small.hevbth07" }, + { "rct2.tt.oldnyk06", "rct2tt.scenery_small.oldnyk06" }, + { "rct2.tt.primwal2", "rct2tt.scenery_small.primwal2" }, + { "rct2.tt.mspkwa01", "rct2tt.scenery_wall.mspkwa01" }, + { "rct2.tt.jailxx19", "rct2tt.scenery_wall.jailxx19" }, + { "rct2.tt.firhydrt", "rct2tt.footpath_item.firhydrt" }, + { "rct2.tt.medbench", "rct2tt.footpath_item.medbench" }, + { "rct2.tt.railings.balustrade", "rct2tt.footpath_railings.balustrade" }, + { "rct2.tt.railings.medieval", "rct2tt.footpath_railings.medieval" }, + { "rct2.tt.railings.rainbow", "rct2tt.footpath_railings.rainbow" }, + { "rct2.tt.railings.circuitboard", "rct2tt.footpath_railings.circuitboard" }, + { "rct2.tt.railings.rocky", "rct2tt.footpath_railings.rocky" }, + { "rct2.tt.railings.pavement", "rct2tt.footpath_railings.pavement" }, + { "rct2.tt.pathrailings.balustrade", "rct2tt.footpath_railings.balustrade" }, + { "rct2.tt.pathrailings.medieval", "rct2tt.footpath_railings.medieval" }, + { "rct2.tt.pathrailings.rainbow", "rct2tt.footpath_railings.rainbow" }, + { "rct2.tt.pathrailings.circuitboard", "rct2tt.footpath_railings.circuitboard" }, + { "rct2.tt.pathrailings.rocky", "rct2tt.footpath_railings.rocky" }, + { "rct2.tt.pathrailings.pavement", "rct2tt.footpath_railings.pavement" }, + { "rct2.tt.timemach", "rct2tt.ride.timemach" }, + { "rct2.tt.flygboat", "rct2tt.ride.flygboat" }, + { "rct2.tt.hoverbke", "rct2tt.ride.hoverbke" }, + { "rct2.tt.mgr2", "rct2tt.ride.mgr2" }, + { "rct2.tt.halofmrs", "rct2tt.ride.halofmrs" }, + { "rct2.tt.dragnfly", "rct2tt.ride.dragnfly" }, + { "rct2.tt.moonjuce", "rct2tt.ride.moonjuce" }, + { "rct2.tt.harpiesx", "rct2tt.ride.harpiesx" }, + { "rct2.tt.polchase", "rct2tt.ride.polchase" }, + { "rct2.tt.rivrstyx", "rct2tt.ride.rivrstyx" }, + { "rct2.tt.zeplelin", "rct2tt.ride.zeplelin" }, + { "rct2.tt.schoolbs", "rct2tt.ride.schoolbs" }, + { "rct2.tt.stamphrd", "rct2tt.ride.stamphrd" }, + { "rct2.tt.valkyrie", "rct2tt.ride.valkyrie" }, + { "rct2.tt.mktstal2", "rct2tt.ride.mktstal2" }, + { "rct2.tt.dinoeggs", "rct2tt.ride.dinoeggs" }, + { "rct2.tt.jetpackx", "rct2tt.ride.jetpackx" }, + { "rct2.tt.trebucht", "rct2tt.ride.trebucht" }, + { "rct2.tt.trilobte", "rct2tt.ride.trilobte" }, + { "rct2.tt.mktstal1", "rct2tt.ride.mktstal1" }, + { "rct2.tt.microbus", "rct2tt.ride.microbus" }, + { "rct2.tt.cyclopsx", "rct2tt.ride.cyclopsx" }, + { "rct2.tt.softoyst", "rct2tt.ride.softoyst" }, + { "rct2.tt.tricatop", "rct2tt.ride.tricatop" }, + { "rct2.tt.hovercar", "rct2tt.ride.hovercar" }, + { "rct2.tt.hovrbord", "rct2tt.ride.hovrbord" }, + { "rct2.tt.tommygun", "rct2tt.ride.tommygun" }, + { "rct2.tt.neptunex", "rct2tt.ride.neptunex" }, + { "rct2.tt.ganstrcr", "rct2tt.ride.ganstrcr" }, + { "rct2.tt.hotrodxx", "rct2tt.ride.hotrodxx" }, + { "rct2.tt.raptorxx", "rct2tt.ride.raptorxx" }, + { "rct2.tt.spokprsn", "rct2tt.ride.spokprsn" }, + { "rct2.tt.1960tsrt", "rct2tt.ride.1960tsrt" }, + { "rct2.tt.blckdeth", "rct2tt.ride.blckdeth" }, + { "rct2.tt.flwrpowr", "rct2tt.ride.flwrpowr" }, + { "rct2.tt.bmvoctps", "rct2tt.ride.bmvoctps" }, + { "rct2.tt.flalmace", "rct2tt.ride.flalmace" }, + { "rct2.tt.cavmncar", "rct2tt.ride.cavmncar" }, + { "rct2.tt.policecr", "rct2tt.ride.policecr" }, + { "rct2.tt.seaplane", "rct2tt.ride.seaplane" }, + { "rct2.tt.mythosea", "rct2tt.ride.mythosea" }, + { "rct2.tt.cerberus", "rct2tt.ride.cerberus" }, + { "rct2.tt.1920sand", "rct2tt.ride.1920sand" }, + { "rct2.tt.telepter", "rct2tt.ride.telepter" }, + { "rct2.tt.jetplane", "rct2tt.ride.jetplane" }, + { "rct2.tt.gintspdr", "rct2tt.ride.gintspdr" }, + { "rct2.tt.figtknit", "rct2tt.ride.figtknit" }, + { "rct2.tt.barnstrm", "rct2tt.ride.barnstrm" }, + { "rct2.tt.oakbarel", "rct2tt.ride.oakbarel" }, + { "rct2.tt.1920racr", "rct2tt.ride.1920racr" }, + { "rct2.tt.pegasusx", "rct2tt.ride.pegasusx" }, + { "rct2.tt.funhouse", "rct2tt.ride.funhouse" }, + { "rct2.tt.medisoup", "rct2tt.ride.medisoup" }, + { "rct2.tt.pterodac", "rct2tt.ride.pterodac" }, + { "rct2.tt.battrram", "rct2tt.ride.battrram" }, + { "rct2.tt.jousting", "rct2tt.ride.jousting" }, + { "rct2.tt.mythentr", "rct2tt.park_entrance.mythentr" }, + { "rct2.tt.futurent", "rct2tt.park_entrance.futurent" }, + { "rct2.tt.jurasent", "rct2tt.park_entrance.jurasent" }, + { "rct2.tt.gldyrent", "rct2tt.park_entrance.gldyrent" }, + { "rct2.tt.1920sent", "rct2tt.park_entrance.1920sent" }, + { "rct2.tt.medientr", "rct2tt.park_entrance.medientr" }, + { "rct2.tt.pathsurface.rocky", "rct2tt.footpath_surface.rocky" }, + { "rct2.tt.pathsurface.queue.pavement", "rct2tt.footpath_surface.queue_pavement" }, + { "rct2.tt.pathsurface.queue.rainbow", "rct2tt.footpath_surface.queue_rainbow" }, + { "rct2.tt.pathsurface.rainbow", "rct2tt.footpath_surface.rainbow" }, + { "rct2.tt.pathsurface.circuitboard", "rct2tt.footpath_surface.circuitboard" }, + { "rct2.tt.pathsurface.mosaic", "rct2tt.footpath_surface.mosaic" }, + { "rct2.tt.pathsurface.pavement", "rct2tt.footpath_surface.pavement" }, + { "rct2.tt.pathsurface.medieval", "rct2tt.footpath_surface.medieval" }, + { "rct2.tt.pathsurface.queue.circuitboard", "rct2tt.footpath_surface.queue_circuitboard" }, + { "rct2.ww.hippo01", "rct2ww.scenery_large.hippo01" }, + { "rct2.ww.geisha", "rct2ww.scenery_large.geisha" }, + { "rct2.ww.atractor", "rct2ww.scenery_large.atractor" }, + { "rct2.ww.easerlnd", "rct2ww.scenery_large.easerlnd" }, + { "rct2.ww.1x4brg01", "rct2ww.scenery_large.1x4brg01" }, + { "rct2.ww.gwoctur1", "rct2ww.scenery_large.gwoctur1" }, + { "rct2.ww.rtudor06", "rct2ww.scenery_large.rtudor06" }, + { "rct2.ww.3x3altre", "rct2ww.scenery_large.3x3altre" }, + { "rct2.ww.bigben", "rct2ww.scenery_large.bigben" }, + { "rct2.ww.pogodal", "rct2ww.scenery_large.pogodal" }, + { "rct2.ww.bigdish", "rct2ww.scenery_large.bigdish" }, + { "rct2.ww.rdrab01", "rct2ww.scenery_large.rdrab01" }, + { "rct2.ww.goodsam", "rct2ww.scenery_large.goodsam" }, + { "rct2.ww.mbskyr02", "rct2ww.scenery_large.mbskyr02" }, + { "rct2.ww.icefor02", "rct2ww.scenery_large.icefor02" }, + { "rct2.ww.tajmcolm", "rct2ww.scenery_large.tajmcolm" }, + { "rct2.ww.giraffe2", "rct2ww.scenery_large.giraffe2" }, + { "rct2.ww.rkreml10", "rct2ww.scenery_large.rkreml10" }, + { "rct2.ww.sputnik", "rct2ww.scenery_large.sputnik" }, + { "rct2.ww.pagodam", "rct2ww.scenery_large.pagodam" }, + { "rct2.ww.ovrgrwnt", "rct2ww.scenery_large.ovrgrwnt" }, + { "rct2.ww.sunken", "rct2ww.scenery_large.sunken" }, + { "rct2.ww.bamborf1", "rct2ww.scenery_large.bamborf1" }, + { "rct2.ww.1x2abr03", "rct2ww.scenery_large.1x2abr03" }, + { "rct2.ww.1x2abr01", "rct2ww.scenery_large.1x2abr01" }, + { "rct2.ww.3x3eucal", "rct2ww.scenery_large.3x3eucal" }, + { "rct2.ww.goldbuda", "rct2ww.scenery_large.goldbuda" }, + { "rct2.ww.lincolns", "rct2ww.scenery_large.lincolns" }, + { "rct2.ww.windmill", "rct2ww.scenery_large.windmill" }, + { "rct2.ww.helipad", "rct2ww.scenery_large.helipad" }, + { "rct2.ww.gdstaue2", "rct2ww.scenery_large.gdstaue2" }, + { "rct2.ww.3x3atre3", "rct2ww.scenery_large.3x3atre3" }, + { "rct2.ww.damtower", "rct2ww.scenery_large.damtower" }, + { "rct2.ww.spaceorb", "rct2ww.scenery_large.spaceorb" }, + { "rct2.ww.hippo02", "rct2ww.scenery_large.hippo02" }, + { "rct2.ww.eiffel", "rct2ww.scenery_large.eiffel" }, + { "rct2.ww.rkreml09", "rct2ww.scenery_large.rkreml09" }, + { "rct2.ww.1x4brg02", "rct2ww.scenery_large.1x4brg02" }, + { "rct2.ww.afrrhino", "rct2ww.scenery_large.afrrhino" }, + { "rct2.ww.giraffe1", "rct2ww.scenery_large.giraffe1" }, + { "rct2.ww.3x3mantr", "rct2ww.scenery_large.3x3mantr" }, + { "rct2.ww.indianst", "rct2ww.scenery_large.indianst" }, + { "rct2.ww.atomium", "rct2ww.scenery_large.atomium" }, + { "rct2.ww.tajmcbse", "rct2ww.scenery_large.tajmcbse" }, + { "rct2.ww.icefor01", "rct2ww.scenery_large.icefor01" }, + { "rct2.ww.bamborf3", "rct2ww.scenery_large.bamborf3" }, + { "rct2.ww.1x2lgchm", "rct2ww.scenery_large.1x2lgchm" }, + { "rct2.ww.circus", "rct2ww.scenery_large.circus" }, + { "rct2.ww.gdstaue1", "rct2ww.scenery_large.gdstaue1" }, + { "rct2.ww.cdragon", "rct2ww.scenery_large.cdragon" }, + { "rct2.ww.cowboy02", "rct2ww.scenery_large.cowboy02" }, + { "rct2.ww.3x3atre1", "rct2ww.scenery_large.3x3atre1" }, + { "rct2.ww.gwoctur2", "rct2ww.scenery_large.gwoctur2" }, + { "rct2.ww.1x2glama", "rct2ww.scenery_large.1x2glama" }, + { "rct2.ww.pagodas", "rct2ww.scenery_large.pagodas" }, + { "rct2.ww.1x2abr02", "rct2ww.scenery_large.1x2abr02" }, + { "rct2.ww.biggeosp", "rct2ww.scenery_large.biggeosp" }, + { "rct2.ww.evilsam", "rct2ww.scenery_large.evilsam" }, + { "rct2.ww.pagodatw", "rct2ww.scenery_large.pagodatw" }, + { "rct2.ww.mbskyr01", "rct2ww.scenery_large.mbskyr01" }, + { "rct2.ww.redwood", "rct2ww.scenery_large.redwood" }, + { "rct2.ww.soflibrt", "rct2ww.scenery_large.soflibrt" }, + { "rct2.ww.1x2azt01", "rct2ww.scenery_large.1x2azt01" }, + { "rct2.ww.rdrab03", "rct2ww.scenery_large.rdrab03" }, + { "rct2.ww.rdrab02", "rct2ww.scenery_large.rdrab02" }, + { "rct2.ww.1x4brg05", "rct2ww.scenery_large.1x4brg05" }, + { "rct2.ww.1x4brg04", "rct2ww.scenery_large.1x4brg04" }, + { "rct2.ww.radar", "rct2ww.scenery_large.radar" }, + { "rct2.ww.afrclion", "rct2ww.scenery_large.afrclion" }, + { "rct2.ww.afrzebra", "rct2ww.scenery_large.afrzebra" }, + { "rct2.ww.largeju1", "rct2ww.scenery_large.largeju1" }, + { "rct2.ww.cowboy01", "rct2ww.scenery_large.cowboy01" }, + { "rct2.ww.rdrab04", "rct2ww.scenery_large.rdrab04" }, + { "rct2.ww.50rocket", "rct2ww.scenery_large.50rocket" }, + { "rct2.ww.tajmdome", "rct2ww.scenery_large.tajmdome" }, + { "rct2.ww.fatbudda", "rct2ww.scenery_large.fatbudda" }, + { "rct2.ww.1x4brg03", "rct2ww.scenery_large.1x4brg03" }, + { "rct2.ww.shiva", "rct2ww.scenery_large.shiva" }, + { "rct2.ww.3x3hmsen", "rct2ww.scenery_large.3x3hmsen" }, + { "rct2.ww.rkreml08", "rct2ww.scenery_large.rkreml08" }, + { "rct2.ww.adultele", "rct2ww.scenery_large.adultele" }, + { "rct2.ww.3x3atre2", "rct2ww.scenery_large.3x3atre2" }, + { "rct2.ww.rtudor05", "rct2ww.scenery_large.rtudor05" }, + { "rct2.ww.tajmctop", "rct2ww.scenery_large.tajmctop" }, + { "rct2.ww.1x2azt02", "rct2ww.scenery_large.1x2azt02" }, + { "rct2.ww.bamborf2", "rct2ww.scenery_large.bamborf2" }, + { "rct2.ww.scgeurop", "rct2ww.scenery_group.scgeurop" }, + { "rct2.ww.scgaustr", "rct2ww.scenery_group.scgaustr" }, + { "rct2.ww.scgsamer", "rct2ww.scenery_group.scgsamer" }, + { "rct2.ww.scgartic", "rct2ww.scenery_group.scgartic" }, + { "rct2.ww.scgnamrc", "rct2ww.scenery_group.scgnamrc" }, + { "rct2.ww.scgafric", "rct2ww.scenery_group.scgafric" }, + { "rct2.ww.scgasia", "rct2ww.scenery_group.scgasia" }, + { "rct2.ww.1x1atree", "rct2ww.scenery_small.1x1atree" }, + { "rct2.ww.sbh1wgwh", "rct2ww.scenery_small.sbh1wgwh" }, + { "rct2.ww.1x1brang", "rct2ww.scenery_small.1x1brang" }, + { "rct2.ww.oriegong", "rct2ww.scenery_small.oriegong" }, + { "rct2.ww.sbwind07", "rct2ww.scenery_small.sbwind07" }, + { "rct2.ww.rdrab07", "rct2ww.scenery_small.rdrab07" }, + { "rct2.ww.rmud01", "rct2ww.scenery_small.rmud01" }, + { "rct2.ww.sbwind12", "rct2ww.scenery_small.sbwind12" }, + { "rct2.ww.rdrab09", "rct2ww.scenery_small.rdrab09" }, + { "rct2.ww.icebarl3", "rct2ww.scenery_small.icebarl3" }, + { "rct2.ww.sbskys17", "rct2ww.scenery_small.sbskys17" }, + { "rct2.ww.rcorr01", "rct2ww.scenery_small.rcorr01" }, + { "rct2.ww.sbh3cac2", "rct2ww.scenery_small.sbh3cac2" }, + { "rct2.ww.wtudor16", "rct2ww.scenery_small.wtudor16" }, + { "rct2.ww.waztec21", "rct2ww.scenery_small.waztec21" }, + { "rct2.ww.fountarc", "rct2ww.scenery_small.fountarc" }, + { "rct2.ww.fountrow", "rct2ww.scenery_small.fountrow" }, + { "rct2.ww.trckprt6", "rct2ww.scenery_small.trckprt6" }, + { "rct2.ww.wdrab09", "rct2ww.scenery_small.wdrab09" }, + { "rct2.ww.sbwind02", "rct2ww.scenery_small.sbwind02" }, + { "rct2.ww.sbskys03", "rct2ww.scenery_small.sbskys03" }, + { "rct2.ww.rdrab13", "rct2ww.scenery_small.rdrab13" }, + { "rct2.ww.sbwplm01", "rct2ww.scenery_small.sbwplm01" }, + { "rct2.ww.sbskys07", "rct2ww.scenery_small.sbskys07" }, + { "rct2.ww.rcorr11", "rct2ww.scenery_small.rcorr11" }, + { "rct2.ww.sbwind01", "rct2ww.scenery_small.sbwind01" }, + { "rct2.ww.wmayan08", "rct2ww.scenery_small.wmayan08" }, + { "rct2.ww.sbwplm04", "rct2ww.scenery_small.sbwplm04" }, + { "rct2.ww.icebarl1", "rct2ww.scenery_small.icebarl1" }, + { "rct2.ww.sbwind16", "rct2ww.scenery_small.sbwind16" }, + { "rct2.ww.wnauti01", "rct2ww.scenery_small.wnauti01" }, + { "rct2.ww.rkreml06", "rct2ww.scenery_small.rkreml06" }, + { "rct2.ww.sbskys15", "rct2ww.scenery_small.sbskys15" }, + { "rct2.ww.wcuzco24", "rct2ww.scenery_small.wcuzco24" }, + { "rct2.ww.inflag04", "rct2ww.scenery_small.inflag04" }, + { "rct2.ww.rlog04", "rct2ww.scenery_small.rlog04" }, + { "rct2.ww.conveyr1", "rct2ww.scenery_small.conveyr1" }, + { "rct2.ww.rcorr03", "rct2ww.scenery_small.rcorr03" }, + { "rct2.ww.waztec03", "rct2ww.scenery_small.waztec03" }, + { "rct2.ww.trckprt9", "rct2ww.scenery_small.trckprt9" }, + { "rct2.ww.wgeorg09", "rct2ww.scenery_small.wgeorg09" }, + { "rct2.ww.rcorr05", "rct2ww.scenery_small.rcorr05" }, + { "rct2.ww.rgeorg04", "rct2ww.scenery_small.rgeorg04" }, + { "rct2.ww.rcorr07", "rct2ww.scenery_small.rcorr07" }, + { "rct2.ww.bamboopl", "rct2ww.scenery_small.bamboopl" }, + { "rct2.ww.sbskys18", "rct2ww.scenery_small.sbskys18" }, + { "rct2.ww.sbskys06", "rct2ww.scenery_small.sbskys06" }, + { "rct2.ww.wkreml02", "rct2ww.scenery_small.wkreml02" }, + { "rct2.ww.trckprt1", "rct2ww.scenery_small.trckprt1" }, + { "rct2.ww.wtudor13", "rct2ww.scenery_small.wtudor13" }, + { "rct2.ww.rlog03", "rct2ww.scenery_small.rlog03" }, + { "rct2.ww.rdrab11", "rct2ww.scenery_small.rdrab11" }, + { "rct2.ww.sbh3oscr", "rct2ww.scenery_small.sbh3oscr" }, + { "rct2.ww.japsnotr", "rct2ww.scenery_small.japsnotr" }, + { "rct2.ww.trckprt5", "rct2ww.scenery_small.trckprt5" }, + { "rct2.ww.roofig06", "rct2ww.scenery_small.roofig06" }, + { "rct2.ww.wtudor18", "rct2ww.scenery_small.wtudor18" }, + { "rct2.ww.waztec18", "rct2ww.scenery_small.waztec18" }, + { "rct2.ww.wmayan20", "rct2ww.scenery_small.wmayan20" }, + { "rct2.ww.sbh3cac3", "rct2ww.scenery_small.sbh3cac3" }, + { "rct2.ww.sb2palm1", "rct2ww.scenery_small.sb2palm1" }, + { "rct2.ww.rgeorg01", "rct2ww.scenery_small.rgeorg01" }, + { "rct2.ww.1x1termm", "rct2ww.scenery_small.1x1termm" }, + { "rct2.ww.wmayan17", "rct2ww.scenery_small.wmayan17" }, + { "rct2.ww.sbh3rt66", "rct2ww.scenery_small.sbh3rt66" }, + { "rct2.ww.wcuzco09", "rct2ww.scenery_small.wcuzco09" }, + { "rct2.ww.bstatue1", "rct2ww.scenery_small.bstatue1" }, + { "rct2.ww.wcuzfoun", "rct2ww.scenery_small.wcuzfoun" }, + { "rct2.ww.wropeswa", "rct2ww.scenery_small.wropeswa" }, + { "rct2.ww.sbwplm07", "rct2ww.scenery_small.sbwplm07" }, + { "rct2.ww.roofice3", "rct2ww.scenery_small.roofice3" }, + { "rct2.ww.flamngo1", "rct2ww.scenery_small.flamngo1" }, + { "rct2.ww.wdrab13", "rct2ww.scenery_small.wdrab13" }, + { "rct2.ww.sbwplm02", "rct2ww.scenery_small.sbwplm02" }, + { "rct2.ww.rtudor03", "rct2ww.scenery_small.rtudor03" }, + { "rct2.ww.pipebase", "rct2ww.scenery_small.pipebase" }, + { "rct2.ww.wgeorg08", "rct2ww.scenery_small.wgeorg08" }, + { "rct2.ww.fishhole", "rct2ww.scenery_small.fishhole" }, + { "rct2.ww.wmayan12", "rct2ww.scenery_small.wmayan12" }, + { "rct2.ww.wcuzco18", "rct2ww.scenery_small.wcuzco18" }, + { "rct2.ww.rbrick02", "rct2ww.scenery_small.rbrick02" }, + { "rct2.ww.waborg08", "rct2ww.scenery_small.waborg08" }, + { "rct2.ww.rgeorg07", "rct2ww.scenery_small.rgeorg07" }, + { "rct2.ww.rdrab14", "rct2ww.scenery_small.rdrab14" }, + { "rct2.ww.wtudor17", "rct2ww.scenery_small.wtudor17" }, + { "rct2.ww.wmayan01", "rct2ww.scenery_small.wmayan01" }, + { "rct2.ww.g1dancer", "rct2ww.scenery_small.g1dancer" }, + { "rct2.ww.japchblo", "rct2ww.scenery_small.japchblo" }, + { "rct2.ww.wnauti05", "rct2ww.scenery_small.wnauti05" }, + { "rct2.ww.waborg02", "rct2ww.scenery_small.waborg02" }, + { "rct2.ww.pcg", "rct2ww.scenery_small.pcg" }, + { "rct2.ww.antilopf", "rct2ww.scenery_small.antilopf" }, + { "rct2.ww.waztec25", "rct2ww.scenery_small.waztec25" }, + { "rct2.ww.wcuzco23", "rct2ww.scenery_small.wcuzco23" }, + { "rct2.ww.sbh1tepe", "rct2ww.scenery_small.sbh1tepe" }, + { "rct2.ww.pst", "rct2ww.scenery_small.pst" }, + { "rct2.ww.trckprt4", "rct2ww.scenery_small.trckprt4" }, + { "rct2.ww.rgeorg10", "rct2ww.scenery_small.rgeorg10" }, + { "rct2.ww.wropecor", "rct2ww.scenery_small.wropecor" }, + { "rct2.ww.tjblock2", "rct2ww.scenery_small.tjblock2" }, + { "rct2.ww.wtudor15", "rct2ww.scenery_small.wtudor15" }, + { "rct2.ww.wmayan11", "rct2ww.scenery_small.wmayan11" }, + { "rct2.ww.inuit", "rct2ww.scenery_small.inuit" }, + { "rct2.ww.wmayan26", "rct2ww.scenery_small.wmayan26" }, + { "rct2.ww.wcuzco06", "rct2ww.scenery_small.wcuzco06" }, + { "rct2.ww.tjblock3", "rct2ww.scenery_small.tjblock3" }, + { "rct2.ww.waztec27", "rct2ww.scenery_small.waztec27" }, + { "rct2.ww.sbh3plm2", "rct2ww.scenery_small.sbh3plm2" }, + { "rct2.ww.wmayan09", "rct2ww.scenery_small.wmayan09" }, + { "rct2.ww.sbh3plm1", "rct2ww.scenery_small.sbh3plm1" }, + { "rct2.ww.sbwind21", "rct2ww.scenery_small.sbwind21" }, + { "rct2.ww.waztec10", "rct2ww.scenery_small.waztec10" }, + { "rct2.ww.sbh3cac1", "rct2ww.scenery_small.sbh3cac1" }, + { "rct2.ww.1x1kanga", "rct2ww.scenery_small.1x1kanga" }, + { "rct2.ww.rbrick08", "rct2ww.scenery_small.rbrick08" }, + { "rct2.ww.rgeorg03", "rct2ww.scenery_small.rgeorg03" }, + { "rct2.ww.rdrab10", "rct2ww.scenery_small.rdrab10" }, + { "rct2.ww.jachtree", "rct2ww.scenery_small.jachtree" }, + { "rct2.ww.tnt1", "rct2ww.scenery_small.tnt1" }, + { "rct2.ww.wmayan24", "rct2ww.scenery_small.wmayan24" }, + { "rct2.ww.wmayan10", "rct2ww.scenery_small.wmayan10" }, + { "rct2.ww.roofig03", "rct2ww.scenery_small.roofig03" }, + { "rct2.ww.rkreml07", "rct2ww.scenery_small.rkreml07" }, + { "rct2.ww.oilpump", "rct2ww.scenery_small.oilpump" }, + { "rct2.ww.inflag02", "rct2ww.scenery_small.inflag02" }, + { "rct2.ww.roofig04", "rct2ww.scenery_small.roofig04" }, + { "rct2.ww.waztec22", "rct2ww.scenery_small.waztec22" }, + { "rct2.ww.wmayan05", "rct2ww.scenery_small.wmayan05" }, + { "rct2.ww.jpflag06", "rct2ww.scenery_small.jpflag06" }, + { "rct2.ww.rgeorg05", "rct2ww.scenery_small.rgeorg05" }, + { "rct2.ww.rgeorg02", "rct2ww.scenery_small.rgeorg02" }, + { "rct2.ww.ptj", "rct2ww.scenery_small.ptj" }, + { "rct2.ww.sbskys10", "rct2ww.scenery_small.sbskys10" }, + { "rct2.ww.wcuzco21", "rct2ww.scenery_small.wcuzco21" }, + { "rct2.ww.trckprt2", "rct2ww.scenery_small.trckprt2" }, + { "rct2.ww.tnt3", "rct2ww.scenery_small.tnt3" }, + { "rct2.ww.rcorr09", "rct2ww.scenery_small.rcorr09" }, + { "rct2.ww.sbh3plm3", "rct2ww.scenery_small.sbh3plm3" }, + { "rct2.ww.rdrab12", "rct2ww.scenery_small.rdrab12" }, + { "rct2.ww.sbwplm06", "rct2ww.scenery_small.sbwplm06" }, + { "rct2.ww.inuit2", "rct2ww.scenery_small.inuit2" }, + { "rct2.ww.rcorr04", "rct2ww.scenery_small.rcorr04" }, + { "rct2.ww.1x1emuxx", "rct2ww.scenery_small.1x1emuxx" }, + { "rct2.ww.sbskys08", "rct2ww.scenery_small.sbskys08" }, + { "rct2.ww.waztec14", "rct2ww.scenery_small.waztec14" }, + { "rct2.ww.sbskys16", "rct2ww.scenery_small.sbskys16" }, + { "rct2.ww.ukphone", "rct2ww.scenery_small.ukphone" }, + { "rct2.ww.rdrab06", "rct2ww.scenery_small.rdrab06" }, + { "rct2.ww.waztec09", "rct2ww.scenery_small.waztec09" }, + { "rct2.ww.wcuzco17", "rct2ww.scenery_small.wcuzco17" }, + { "rct2.ww.jpflag05", "rct2ww.scenery_small.jpflag05" }, + { "rct2.ww.wmayan13", "rct2ww.scenery_small.wmayan13" }, + { "rct2.ww.sbwind10", "rct2ww.scenery_small.sbwind10" }, + { "rct2.ww.wkreml01", "rct2ww.scenery_small.wkreml01" }, + { "rct2.ww.waztec24", "rct2ww.scenery_small.waztec24" }, + { "rct2.ww.roofice5", "rct2ww.scenery_small.roofice5" }, + { "rct2.ww.sbwplm08", "rct2ww.scenery_small.sbwplm08" }, + { "rct2.ww.wmayan25", "rct2ww.scenery_small.wmayan25" }, + { "rct2.ww.sbwind18", "rct2ww.scenery_small.sbwind18" }, + { "rct2.ww.jpflag02", "rct2ww.scenery_small.jpflag02" }, + { "rct2.ww.wmayan22", "rct2ww.scenery_small.wmayan22" }, + { "rct2.ww.wnauti02", "rct2ww.scenery_small.wnauti02" }, + { "rct2.ww.rgeorg11", "rct2ww.scenery_small.rgeorg11" }, + { "rct2.ww.sbwind15", "rct2ww.scenery_small.sbwind15" }, + { "rct2.ww.wcuzco25", "rct2ww.scenery_small.wcuzco25" }, + { "rct2.ww.waztec12", "rct2ww.scenery_small.waztec12" }, + { "rct2.ww.wmayan18", "rct2ww.scenery_small.wmayan18" }, + { "rct2.ww.jappintr", "rct2ww.scenery_small.jappintr" }, + { "rct2.ww.sbwind06", "rct2ww.scenery_small.sbwind06" }, + { "rct2.ww.rmud05", "rct2ww.scenery_small.rmud05" }, + { "rct2.ww.waztec16", "rct2ww.scenery_small.waztec16" }, + { "rct2.ww.sbwind08", "rct2ww.scenery_small.sbwind08" }, + { "rct2.ww.sbwplm05", "rct2ww.scenery_small.sbwplm05" }, + { "rct2.ww.wmayan23", "rct2ww.scenery_small.wmayan23" }, + { "rct2.ww.bamboobs", "rct2ww.scenery_small.bamboobs" }, + { "rct2.ww.wcuzco11", "rct2ww.scenery_small.wcuzco11" }, + { "rct2.ww.waborg07", "rct2ww.scenery_small.waborg07" }, + { "rct2.ww.rshogi2", "rct2ww.scenery_small.rshogi2" }, + { "rct2.ww.rkreml02", "rct2ww.scenery_small.rkreml02" }, + { "rct2.ww.talllan2", "rct2ww.scenery_small.talllan2" }, + { "rct2.ww.wdrab10", "rct2ww.scenery_small.wdrab10" }, + { "rct2.ww.wcuzco07", "rct2ww.scenery_small.wcuzco07" }, + { "rct2.ww.sbwind17", "rct2ww.scenery_small.sbwind17" }, + { "rct2.ww.wmayan06", "rct2ww.scenery_small.wmayan06" }, + { "rct2.ww.roofice4", "rct2ww.scenery_small.roofice4" }, + { "rct2.ww.rkreml11", "rct2ww.scenery_small.rkreml11" }, + { "rct2.ww.wcuzco04", "rct2ww.scenery_small.wcuzco04" }, + { "rct2.ww.1x1atre2", "rct2ww.scenery_small.1x1atre2" }, + { "rct2.ww.sb1hspb1", "rct2ww.scenery_small.sb1hspb1" }, + { "rct2.ww.waborg03", "rct2ww.scenery_small.waborg03" }, + { "rct2.ww.sbwind09", "rct2ww.scenery_small.sbwind09" }, + { "rct2.ww.waztec01", "rct2ww.scenery_small.waztec01" }, + { "rct2.ww.waztec15", "rct2ww.scenery_small.waztec15" }, + { "rct2.ww.wgeorg12", "rct2ww.scenery_small.wgeorg12" }, + { "rct2.ww.rtudor01", "rct2ww.scenery_small.rtudor01" }, + { "rct2.ww.wmayan21", "rct2ww.scenery_small.wmayan21" }, + { "rct2.ww.wmayan03", "rct2ww.scenery_small.wmayan03" }, + { "rct2.ww.wcuzco03", "rct2ww.scenery_small.wcuzco03" }, + { "rct2.ww.sb1hspb3", "rct2ww.scenery_small.sb1hspb3" }, + { "rct2.ww.sbwind04", "rct2ww.scenery_small.sbwind04" }, + { "rct2.ww.waztec17", "rct2ww.scenery_small.waztec17" }, + { "rct2.ww.rdrab05", "rct2ww.scenery_small.rdrab05" }, + { "rct2.ww.sbskys09", "rct2ww.scenery_small.sbskys09" }, + { "rct2.ww.sbskys14", "rct2ww.scenery_small.sbskys14" }, + { "rct2.ww.babyele", "rct2ww.scenery_small.babyele" }, + { "rct2.ww.rshogi1", "rct2ww.scenery_small.rshogi1" }, + { "rct2.ww.sbh2shlt", "rct2ww.scenery_small.sbh2shlt" }, + { "rct2.ww.wnauti04", "rct2ww.scenery_small.wnauti04" }, + { "rct2.ww.wtudor14", "rct2ww.scenery_small.wtudor14" }, + { "rct2.ww.sbskys04", "rct2ww.scenery_small.sbskys04" }, + { "rct2.ww.antilopm", "rct2ww.scenery_small.antilopm" }, + { "rct2.ww.wmayan04", "rct2ww.scenery_small.wmayan04" }, + { "rct2.ww.campfani", "rct2ww.scenery_small.campfani" }, + { "rct2.ww.jpflag01", "rct2ww.scenery_small.jpflag01" }, + { "rct2.ww.conveyr4", "rct2ww.scenery_small.conveyr4" }, + { "rct2.ww.wcuzco19", "rct2ww.scenery_small.wcuzco19" }, + { "rct2.ww.sbwind13", "rct2ww.scenery_small.sbwind13" }, + { "rct2.ww.smallgeo", "rct2ww.scenery_small.smallgeo" }, + { "rct2.ww.antilopp", "rct2ww.scenery_small.antilopp" }, + { "rct2.ww.wdrab12", "rct2ww.scenery_small.wdrab12" }, + { "rct2.ww.rcorr02", "rct2ww.scenery_small.rcorr02" }, + { "rct2.ww.inflag03", "rct2ww.scenery_small.inflag03" }, + { "rct2.ww.sbwind11", "rct2ww.scenery_small.sbwind11" }, + { "rct2.ww.waztec13", "rct2ww.scenery_small.waztec13" }, + { "rct2.ww.1x1jugt3", "rct2ww.scenery_small.1x1jugt3" }, + { "rct2.ww.wcuzco16", "rct2ww.scenery_small.wcuzco16" }, + { "rct2.ww.rkreml05", "rct2ww.scenery_small.rkreml05" }, + { "rct2.ww.roofice2", "rct2ww.scenery_small.roofice2" }, + { "rct2.ww.rgeorg06", "rct2ww.scenery_small.rgeorg06" }, + { "rct2.ww.sbwind20", "rct2ww.scenery_small.sbwind20" }, + { "rct2.ww.waborg04", "rct2ww.scenery_small.waborg04" }, + { "rct2.ww.wcuzco10", "rct2ww.scenery_small.wcuzco10" }, + { "rct2.ww.wmayan14", "rct2ww.scenery_small.wmayan14" }, + { "rct2.ww.adpanda", "rct2ww.scenery_small.adpanda" }, + { "rct2.ww.rwdaub01", "rct2ww.scenery_small.rwdaub01" }, + { "rct2.ww.ptk", "rct2ww.scenery_small.ptk" }, + { "rct2.ww.roofice6", "rct2ww.scenery_small.roofice6" }, + { "rct2.ww.sb2sky01", "rct2ww.scenery_small.sb2sky01" }, + { "rct2.ww.sb1hspb2", "rct2ww.scenery_small.sb1hspb2" }, + { "rct2.ww.rlog01", "rct2ww.scenery_small.rlog01" }, + { "rct2.ww.roofig02", "rct2ww.scenery_small.roofig02" }, + { "rct2.ww.rkreml03", "rct2ww.scenery_small.rkreml03" }, + { "rct2.ww.wcuzco01", "rct2ww.scenery_small.wcuzco01" }, + { "rct2.ww.sbskys05", "rct2ww.scenery_small.sbskys05" }, + { "rct2.ww.rwdaub02", "rct2ww.scenery_small.rwdaub02" }, + { "rct2.ww.wgeorg07", "rct2ww.scenery_small.wgeorg07" }, + { "rct2.ww.rbrick03", "rct2ww.scenery_small.rbrick03" }, + { "rct2.ww.conveyr5", "rct2ww.scenery_small.conveyr5" }, + { "rct2.ww.rlog02", "rct2ww.scenery_small.rlog02" }, + { "rct2.ww.sbskys02", "rct2ww.scenery_small.sbskys02" }, + { "rct2.ww.rmud03", "rct2ww.scenery_small.rmud03" }, + { "rct2.ww.waztec20", "rct2ww.scenery_small.waztec20" }, + { "rct2.ww.rlog05", "rct2ww.scenery_small.rlog05" }, + { "rct2.ww.rbrick04", "rct2ww.scenery_small.rbrick04" }, + { "rct2.ww.sbskys01", "rct2ww.scenery_small.sbskys01" }, + { "rct2.ww.waztec11", "rct2ww.scenery_small.waztec11" }, + { "rct2.ww.waztec08", "rct2ww.scenery_small.waztec08" }, + { "rct2.ww.wcuzco12", "rct2ww.scenery_small.wcuzco12" }, + { "rct2.ww.rbrick07", "rct2ww.scenery_small.rbrick07" }, + { "rct2.ww.waborg06", "rct2ww.scenery_small.waborg06" }, + { "rct2.ww.wkreml04", "rct2ww.scenery_small.wkreml04" }, + { "rct2.ww.postbox", "rct2ww.scenery_small.postbox" }, + { "rct2.ww.waztec19", "rct2ww.scenery_small.waztec19" }, + { "rct2.ww.conveyr2", "rct2ww.scenery_small.conveyr2" }, + { "rct2.ww.talllan1", "rct2ww.scenery_small.talllan1" }, + { "rct2.ww.rbrick05", "rct2ww.scenery_small.rbrick05" }, + { "rct2.ww.vertpipe", "rct2ww.scenery_small.vertpipe" }, + { "rct2.ww.waborg01", "rct2ww.scenery_small.waborg01" }, + { "rct2.ww.trckprt7", "rct2ww.scenery_small.trckprt7" }, + { "rct2.ww.wgeorg11", "rct2ww.scenery_small.wgeorg11" }, + { "rct2.ww.flamngo2", "rct2ww.scenery_small.flamngo2" }, + { "rct2.ww.tjblock1", "rct2ww.scenery_small.tjblock1" }, + { "rct2.ww.sbskys13", "rct2ww.scenery_small.sbskys13" }, + { "rct2.ww.wmayan15", "rct2ww.scenery_small.wmayan15" }, + { "rct2.ww.sbskys11", "rct2ww.scenery_small.sbskys11" }, + { "rct2.ww.pipevent", "rct2ww.scenery_small.pipevent" }, + { "rct2.ww.balllant", "rct2ww.scenery_small.balllant" }, + { "rct2.ww.waztec04", "rct2ww.scenery_small.waztec04" }, + { "rct2.ww.rshogi3", "rct2ww.scenery_small.rshogi3" }, + { "rct2.ww.waztec06", "rct2ww.scenery_small.waztec06" }, + { "rct2.ww.wcuzco05", "rct2ww.scenery_small.wcuzco05" }, + { "rct2.ww.inflag01", "rct2ww.scenery_small.inflag01" }, + { "rct2.ww.roofice1", "rct2ww.scenery_small.roofice1" }, + { "rct2.ww.rmarble1", "rct2ww.scenery_small.rmarble1" }, + { "rct2.ww.rdrab08", "rct2ww.scenery_small.rdrab08" }, + { "rct2.ww.rkreml01", "rct2ww.scenery_small.rkreml01" }, + { "rct2.ww.conveyr3", "rct2ww.scenery_small.conveyr3" }, + { "rct2.ww.wcuzco28", "rct2ww.scenery_small.wcuzco28" }, + { "rct2.ww.wmayan16", "rct2ww.scenery_small.wmayan16" }, + { "rct2.ww.rmarble4", "rct2ww.scenery_small.rmarble4" }, + { "rct2.ww.wnauti03", "rct2ww.scenery_small.wnauti03" }, + { "rct2.ww.waztec07", "rct2ww.scenery_small.waztec07" }, + { "rct2.ww.rcorr10", "rct2ww.scenery_small.rcorr10" }, + { "rct2.ww.sbskys12", "rct2ww.scenery_small.sbskys12" }, + { "rct2.ww.rmud02", "rct2ww.scenery_small.rmud02" }, + { "rct2.ww.sbwind05", "rct2ww.scenery_small.sbwind05" }, + { "rct2.ww.rwdaub03", "rct2ww.scenery_small.rwdaub03" }, + { "rct2.ww.jpflag04", "rct2ww.scenery_small.jpflag04" }, + { "rct2.ww.wkreml06", "rct2ww.scenery_small.wkreml06" }, + { "rct2.ww.rkreml04", "rct2ww.scenery_small.rkreml04" }, + { "rct2.ww.rgeorg09", "rct2ww.scenery_small.rgeorg09" }, + { "rct2.ww.wkreml05", "rct2ww.scenery_small.wkreml05" }, + { "rct2.ww.pco", "rct2ww.scenery_small.pco" }, + { "rct2.ww.sbwind03", "rct2ww.scenery_small.sbwind03" }, + { "rct2.ww.rmarble2", "rct2ww.scenery_small.rmarble2" }, + { "rct2.ww.wcuzco22", "rct2ww.scenery_small.wcuzco22" }, + { "rct2.ww.wcuzco27", "rct2ww.scenery_small.wcuzco27" }, + { "rct2.ww.trckprt8", "rct2ww.scenery_small.trckprt8" }, + { "rct2.ww.waztec02", "rct2ww.scenery_small.waztec02" }, + { "rct2.ww.terrarmy", "rct2ww.scenery_small.terrarmy" }, + { "rct2.ww.sbwind19", "rct2ww.scenery_small.sbwind19" }, + { "rct2.ww.roofig01", "rct2ww.scenery_small.roofig01" }, + { "rct2.ww.icebarl2", "rct2ww.scenery_small.icebarl2" }, + { "rct2.ww.wcuzco26", "rct2ww.scenery_small.wcuzco26" }, + { "rct2.ww.balllan2", "rct2ww.scenery_small.balllan2" }, + { "rct2.ww.tnt4", "rct2ww.scenery_small.tnt4" }, + { "rct2.ww.sballoon", "rct2ww.scenery_small.sballoon" }, + { "rct2.ww.babpanda", "rct2ww.scenery_small.babpanda" }, + { "rct2.ww.trckprt3", "rct2ww.scenery_small.trckprt3" }, + { "rct2.ww.wcuzco08", "rct2ww.scenery_small.wcuzco08" }, + { "rct2.ww.waztec26", "rct2ww.scenery_small.waztec26" }, + { "rct2.ww.rtudor02", "rct2ww.scenery_small.rtudor02" }, + { "rct2.ww.rcorr08", "rct2ww.scenery_small.rcorr08" }, + { "rct2.ww.wgeorg10", "rct2ww.scenery_small.wgeorg10" }, + { "rct2.ww.1x1didge", "rct2ww.scenery_small.1x1didge" }, + { "rct2.ww.sbwplm03", "rct2ww.scenery_small.sbwplm03" }, + { "rct2.ww.1x1jugt2", "rct2ww.scenery_small.1x1jugt2" }, + { "rct2.ww.g2dancer", "rct2ww.scenery_small.g2dancer" }, + { "rct2.ww.wcuzco15", "rct2ww.scenery_small.wcuzco15" }, + { "rct2.ww.wcuzco14", "rct2ww.scenery_small.wcuzco14" }, + { "rct2.ww.rbrick01", "rct2ww.scenery_small.rbrick01" }, + { "rct2.ww.flamngo3", "rct2ww.scenery_small.flamngo3" }, + { "rct2.ww.sbh4totm", "rct2ww.scenery_small.sbh4totm" }, + { "rct2.ww.rgeorg12", "rct2ww.scenery_small.rgeorg12" }, + { "rct2.ww.sbh3cskl", "rct2ww.scenery_small.sbh3cskl" }, + { "rct2.ww.waztec05", "rct2ww.scenery_small.waztec05" }, + { "rct2.ww.wcuzco20", "rct2ww.scenery_small.wcuzco20" }, + { "rct2.ww.wcuzco13", "rct2ww.scenery_small.wcuzco13" }, + { "rct2.ww.inflag05", "rct2ww.scenery_small.inflag05" }, + { "rct2.ww.rmarble3", "rct2ww.scenery_small.rmarble3" }, + { "rct2.ww.waborg05", "rct2ww.scenery_small.waborg05" }, + { "rct2.ww.wmayan07", "rct2ww.scenery_small.wmayan07" }, + { "rct2.ww.tnt2", "rct2ww.scenery_small.tnt2" }, + { "rct2.ww.wmayan02", "rct2ww.scenery_small.wmayan02" }, + { "rct2.ww.wdrab11", "rct2ww.scenery_small.wdrab11" }, + { "rct2.ww.rgeorg08", "rct2ww.scenery_small.rgeorg08" }, + { "rct2.ww.pva", "rct2ww.scenery_small.pva" }, + { "rct2.ww.wtudor12", "rct2ww.scenery_small.wtudor12" }, + { "rct2.ww.wkreml03", "rct2ww.scenery_small.wkreml03" }, + { "rct2.ww.jpflag03", "rct2ww.scenery_small.jpflag03" }, + { "rct2.ww.fstatue1", "rct2ww.scenery_small.fstatue1" }, + { "rct2.ww.wcuzco02", "rct2ww.scenery_small.wcuzco02" }, + { "rct2.ww.waztec23", "rct2ww.scenery_small.waztec23" }, + { "rct2.ww.sbwind14", "rct2ww.scenery_small.sbwind14" }, + { "rct2.ww.wmarble1", "rct2ww.scenery_wall.wmarble1" }, + { "rct2.ww.wbambopc", "rct2ww.scenery_wall.wbambopc" }, + { "rct2.ww.wshogi07", "rct2ww.scenery_wall.wshogi07" }, + { "rct2.ww.wskysc08", "rct2ww.scenery_wall.wskysc08" }, + { "rct2.ww.wmud05", "rct2ww.scenery_wall.wmud05" }, + { "rct2.ww.wtudor03", "rct2ww.scenery_wall.wtudor03" }, + { "rct2.ww.wdrab07", "rct2ww.scenery_wall.wdrab07" }, + { "rct2.ww.wshogi10", "rct2ww.scenery_wall.wshogi10" }, + { "rct2.ww.wkreml07", "rct2ww.scenery_wall.wkreml07" }, + { "rct2.ww.wallna07", "rct2ww.scenery_wall.wallna07" }, + { "rct2.ww.wshogi11", "rct2ww.scenery_wall.wshogi11" }, + { "rct2.ww.w2corr06", "rct2ww.scenery_wall.w2corr06" }, + { "rct2.ww.w3corr08", "rct2ww.scenery_wall.w3corr08" }, + { "rct2.ww.wskysc04", "rct2ww.scenery_wall.wskysc04" }, + { "rct2.ww.wallice5", "rct2ww.scenery_wall.wallice5" }, + { "rct2.ww.wtudor11", "rct2ww.scenery_wall.wtudor11" }, + { "rct2.ww.wmud08", "rct2ww.scenery_wall.wmud08" }, + { "rct2.ww.wtudor09", "rct2ww.scenery_wall.wtudor09" }, + { "rct2.ww.wbambo01", "rct2ww.scenery_wall.wbambo01" }, + { "rct2.ww.wallna13", "rct2ww.scenery_wall.wallna13" }, + { "rct2.ww.wmarble3", "rct2ww.scenery_wall.wmarble3" }, + { "rct2.ww.wmud01", "rct2ww.scenery_wall.wmud01" }, + { "rct2.ww.wmud03", "rct2ww.scenery_wall.wmud03" }, + { "rct2.ww.wgwoc2", "rct2ww.scenery_wall.wgwoc2" }, + { "rct2.ww.wkreml10", "rct2ww.scenery_wall.wkreml10" }, + { "rct2.ww.wcorr09", "rct2ww.scenery_wall.wcorr09" }, + { "rct2.ww.w3corr05", "rct2ww.scenery_wall.w3corr05" }, + { "rct2.ww.wallna05", "rct2ww.scenery_wall.wallna05" }, + { "rct2.ww.wskysc05", "rct2ww.scenery_wall.wskysc05" }, + { "rct2.ww.wmarbpl7", "rct2ww.scenery_wall.wmarbpl7" }, + { "rct2.ww.wallna04", "rct2ww.scenery_wall.wallna04" }, + { "rct2.ww.wgeorg03", "rct2ww.scenery_wall.wgeorg03" }, + { "rct2.ww.w2corr03", "rct2ww.scenery_wall.w2corr03" }, + { "rct2.ww.wbrick01", "rct2ww.scenery_wall.wbrick01" }, + { "rct2.ww.wshogi02", "rct2ww.scenery_wall.wshogi02" }, + { "rct2.ww.w2corr05", "rct2ww.scenery_wall.w2corr05" }, + { "rct2.ww.tmarch1", "rct2ww.scenery_wall.tmarch1" }, + { "rct2.ww.wdrab02", "rct2ww.scenery_wall.wdrab02" }, + { "rct2.ww.wgeorg01", "rct2ww.scenery_wall.wgeorg01" }, + { "rct2.ww.wskysc09", "rct2ww.scenery_wall.wskysc09" }, + { "rct2.ww.wbambo15", "rct2ww.scenery_wall.wbambo15" }, + { "rct2.ww.wcorr08", "rct2ww.scenery_wall.wcorr08" }, + { "rct2.ww.wallna03", "rct2ww.scenery_wall.wallna03" }, + { "rct2.ww.wshogi06", "rct2ww.scenery_wall.wshogi06" }, + { "rct2.ww.wmud06", "rct2ww.scenery_wall.wmud06" }, + { "rct2.ww.wwdaub05", "rct2ww.scenery_wall.wwdaub05" }, + { "rct2.ww.wtudor04", "rct2ww.scenery_wall.wtudor04" }, + { "rct2.ww.wcorr12", "rct2ww.scenery_wall.wcorr12" }, + { "rct2.ww.wskysc03", "rct2ww.scenery_wall.wskysc03" }, + { "rct2.ww.w2corr07", "rct2ww.scenery_wall.w2corr07" }, + { "rct2.ww.wwdaub02", "rct2ww.scenery_wall.wwdaub02" }, + { "rct2.ww.wcorr03", "rct2ww.scenery_wall.wcorr03" }, + { "rct2.ww.wwdaub04", "rct2ww.scenery_wall.wwdaub04" }, + { "rct2.ww.wcorr10", "rct2ww.scenery_wall.wcorr10" }, + { "rct2.ww.wallice7", "rct2ww.scenery_wall.wallice7" }, + { "rct2.ww.wwdaub03", "rct2ww.scenery_wall.wwdaub03" }, + { "rct2.ww.wdrab03", "rct2ww.scenery_wall.wdrab03" }, + { "rct2.ww.wlog01", "rct2ww.scenery_wall.wlog01" }, + { "rct2.ww.wbrick05", "rct2ww.scenery_wall.wbrick05" }, + { "rct2.ww.wwind06", "rct2ww.scenery_wall.wwind06" }, + { "rct2.ww.wshogi14", "rct2ww.scenery_wall.wshogi14" }, + { "rct2.ww.wbrick04", "rct2ww.scenery_wall.wbrick04" }, + { "rct2.ww.wgeorg02", "rct2ww.scenery_wall.wgeorg02" }, + { "rct2.ww.wbambo21", "rct2ww.scenery_wall.wbambo21" }, + { "rct2.ww.wtudor06", "rct2ww.scenery_wall.wtudor06" }, + { "rct2.ww.wgeorg04", "rct2ww.scenery_wall.wgeorg04" }, + { "rct2.ww.wshogi04", "rct2ww.scenery_wall.wshogi04" }, + { "rct2.ww.w3corr04", "rct2ww.scenery_wall.w3corr04" }, + { "rct2.ww.wtudor02", "rct2ww.scenery_wall.wtudor02" }, + { "rct2.ww.wbrick03", "rct2ww.scenery_wall.wbrick03" }, + { "rct2.ww.wallna08", "rct2ww.scenery_wall.wallna08" }, + { "rct2.ww.wmarble2", "rct2ww.scenery_wall.wmarble2" }, + { "rct2.ww.wkreml09", "rct2ww.scenery_wall.wkreml09" }, + { "rct2.ww.wgeorg06", "rct2ww.scenery_wall.wgeorg06" }, + { "rct2.ww.wallice3", "rct2ww.scenery_wall.wallice3" }, + { "rct2.ww.wigloo2", "rct2ww.scenery_wall.wigloo2" }, + { "rct2.ww.wskysc10", "rct2ww.scenery_wall.wskysc10" }, + { "rct2.ww.wallice9", "rct2ww.scenery_wall.wallice9" }, + { "rct2.ww.w3corr02", "rct2ww.scenery_wall.w3corr02" }, + { "rct2.ww.wmarbpl3", "rct2ww.scenery_wall.wmarbpl3" }, + { "rct2.ww.w3corr07", "rct2ww.scenery_wall.w3corr07" }, + { "rct2.ww.wlog05", "rct2ww.scenery_wall.wlog05" }, + { "rct2.ww.wgwoc3", "rct2ww.scenery_wall.wgwoc3" }, + { "rct2.ww.wskysc06", "rct2ww.scenery_wall.wskysc06" }, + { "rct2.ww.wcorr14", "rct2ww.scenery_wall.wcorr14" }, + { "rct2.ww.wbrick13", "rct2ww.scenery_wall.wbrick13" }, + { "rct2.ww.wmarble5", "rct2ww.scenery_wall.wmarble5" }, + { "rct2.ww.wkreml08", "rct2ww.scenery_wall.wkreml08" }, + { "rct2.ww.wmarbpl4", "rct2ww.scenery_wall.wmarbpl4" }, + { "rct2.ww.wlog06", "rct2ww.scenery_wall.wlog06" }, + { "rct2.ww.wdrab06", "rct2ww.scenery_wall.wdrab06" }, + { "rct2.ww.wbrick12", "rct2ww.scenery_wall.wbrick12" }, + { "rct2.ww.wshogi17", "rct2ww.scenery_wall.wshogi17" }, + { "rct2.ww.wtudor05", "rct2ww.scenery_wall.wtudor05" }, + { "rct2.ww.wallna01", "rct2ww.scenery_wall.wallna01" }, + { "rct2.ww.wmarbpl6", "rct2ww.scenery_wall.wmarbpl6" }, + { "rct2.ww.wcorr07", "rct2ww.scenery_wall.wcorr07" }, + { "rct2.ww.wbambo05", "rct2ww.scenery_wall.wbambo05" }, + { "rct2.ww.wmud04", "rct2ww.scenery_wall.wmud04" }, + { "rct2.ww.wmarbpl5", "rct2ww.scenery_wall.wmarbpl5" }, + { "rct2.ww.wallice4", "rct2ww.scenery_wall.wallice4" }, + { "rct2.ww.wallice2", "rct2ww.scenery_wall.wallice2" }, + { "rct2.ww.wbambo13", "rct2ww.scenery_wall.wbambo13" }, + { "rct2.ww.wbambo04", "rct2ww.scenery_wall.wbambo04" }, + { "rct2.ww.wcorr01", "rct2ww.scenery_wall.wcorr01" }, + { "rct2.ww.wpalm01", "rct2ww.scenery_wall.wpalm01" }, + { "rct2.ww.wshogi16", "rct2ww.scenery_wall.wshogi16" }, + { "rct2.ww.wallice8", "rct2ww.scenery_wall.wallice8" }, + { "rct2.ww.wlog02", "rct2ww.scenery_wall.wlog02" }, + { "rct2.ww.wtudor01", "rct2ww.scenery_wall.wtudor01" }, + { "rct2.ww.wshogi08", "rct2ww.scenery_wall.wshogi08" }, + { "rct2.ww.wcorr04", "rct2ww.scenery_wall.wcorr04" }, + { "rct2.ww.wgwoc1", "rct2ww.scenery_wall.wgwoc1" }, + { "rct2.ww.w2corr02", "rct2ww.scenery_wall.w2corr02" }, + { "rct2.ww.wallice6", "rct2ww.scenery_wall.wallice6" }, + { "rct2.ww.wallna10", "rct2ww.scenery_wall.wallna10" }, + { "rct2.ww.wbrick11", "rct2ww.scenery_wall.wbrick11" }, + { "rct2.ww.wshogi13", "rct2ww.scenery_wall.wshogi13" }, + { "rct2.ww.wskysc01", "rct2ww.scenery_wall.wskysc01" }, + { "rct2.ww.wcorr05", "rct2ww.scenery_wall.wcorr05" }, + { "rct2.ww.w2corr01", "rct2ww.scenery_wall.w2corr01" }, + { "rct2.ww.wshogi15", "rct2ww.scenery_wall.wshogi15" }, + { "rct2.ww.wdrab01", "rct2ww.scenery_wall.wdrab01" }, + { "rct2.ww.wallna09", "rct2ww.scenery_wall.wallna09" }, + { "rct2.ww.wshogi12", "rct2ww.scenery_wall.wshogi12" }, + { "rct2.ww.wmud07", "rct2ww.scenery_wall.wmud07" }, + { "rct2.ww.wpalm02", "rct2ww.scenery_wall.wpalm02" }, + { "rct2.ww.wmarbpl2", "rct2ww.scenery_wall.wmarbpl2" }, + { "rct2.ww.wwind04", "rct2ww.scenery_wall.wwind04" }, + { "rct2.ww.wbambo14", "rct2ww.scenery_wall.wbambo14" }, + { "rct2.ww.wshogi09", "rct2ww.scenery_wall.wshogi09" }, + { "rct2.ww.wwdaub07", "rct2ww.scenery_wall.wwdaub07" }, + { "rct2.ww.wallna12", "rct2ww.scenery_wall.wallna12" }, + { "rct2.ww.wmarble6", "rct2ww.scenery_wall.wmarble6" }, + { "rct2.ww.wbrick08", "rct2ww.scenery_wall.wbrick08" }, + { "rct2.ww.wpalm04", "rct2ww.scenery_wall.wpalm04" }, + { "rct2.ww.tmarch2", "rct2ww.scenery_wall.tmarch2" }, + { "rct2.ww.wallna14", "rct2ww.scenery_wall.wallna14" }, + { "rct2.ww.wmarbpl1", "rct2ww.scenery_wall.wmarbpl1" }, + { "rct2.ww.wwind05", "rct2ww.scenery_wall.wwind05" }, + { "rct2.ww.wpalm05", "rct2ww.scenery_wall.wpalm05" }, + { "rct2.ww.wallice1", "rct2ww.scenery_wall.wallice1" }, + { "rct2.ww.wbambo02", "rct2ww.scenery_wall.wbambo02" }, + { "rct2.ww.wskysc11", "rct2ww.scenery_wall.wskysc11" }, + { "rct2.ww.wtudor08", "rct2ww.scenery_wall.wtudor08" }, + { "rct2.ww.w3corr03", "rct2ww.scenery_wall.w3corr03" }, + { "rct2.ww.w2corr08", "rct2ww.scenery_wall.w2corr08" }, + { "rct2.ww.wwind03", "rct2ww.scenery_wall.wwind03" }, + { "rct2.ww.wmarble4", "rct2ww.scenery_wall.wmarble4" }, + { "rct2.ww.wwdaub06", "rct2ww.scenery_wall.wwdaub06" }, + { "rct2.ww.wmud02", "rct2ww.scenery_wall.wmud02" }, + { "rct2.ww.wtudor10", "rct2ww.scenery_wall.wtudor10" }, + { "rct2.ww.wbambo03", "rct2ww.scenery_wall.wbambo03" }, + { "rct2.ww.wskysc02", "rct2ww.scenery_wall.wskysc02" }, + { "rct2.ww.wdrab04", "rct2ww.scenery_wall.wdrab04" }, + { "rct2.ww.wcorr02", "rct2ww.scenery_wall.wcorr02" }, + { "rct2.ww.wallna02", "rct2ww.scenery_wall.wallna02" }, + { "rct2.ww.wdrab05", "rct2ww.scenery_wall.wdrab05" }, + { "rct2.ww.wbrick02", "rct2ww.scenery_wall.wbrick02" }, + { "rct2.ww.wigloo1", "rct2ww.scenery_wall.wigloo1" }, + { "rct2.ww.wcorr13", "rct2ww.scenery_wall.wcorr13" }, + { "rct2.ww.wskysc07", "rct2ww.scenery_wall.wskysc07" }, + { "rct2.ww.wcorr15", "rct2ww.scenery_wall.wcorr15" }, + { "rct2.ww.wcorr16", "rct2ww.scenery_wall.wcorr16" }, + { "rct2.ww.w2corr04", "rct2ww.scenery_wall.w2corr04" }, + { "rct2.ww.wdrab08", "rct2ww.scenery_wall.wdrab08" }, + { "rct2.ww.wlog04", "rct2ww.scenery_wall.wlog04" }, + { "rct2.ww.wskysc12", "rct2ww.scenery_wall.wskysc12" }, + { "rct2.ww.wbambo12", "rct2ww.scenery_wall.wbambo12" }, + { "rct2.ww.wbambo11", "rct2ww.scenery_wall.wbambo11" }, + { "rct2.ww.w3corr01", "rct2ww.scenery_wall.w3corr01" }, + { "rct2.ww.wshogi03", "rct2ww.scenery_wall.wshogi03" }, + { "rct2.ww.wwdaub01", "rct2ww.scenery_wall.wwdaub01" }, + { "rct2.ww.wcorr06", "rct2ww.scenery_wall.wcorr06" }, + { "rct2.ww.wtudor07", "rct2ww.scenery_wall.wtudor07" }, + { "rct2.ww.wgeorg05", "rct2ww.scenery_wall.wgeorg05" }, + { "rct2.ww.wallna11", "rct2ww.scenery_wall.wallna11" }, + { "rct2.ww.wshogi05", "rct2ww.scenery_wall.wshogi05" }, + { "rct2.ww.wlog03", "rct2ww.scenery_wall.wlog03" }, + { "rct2.ww.w3corr06", "rct2ww.scenery_wall.w3corr06" }, + { "rct2.ww.wshogi01", "rct2ww.scenery_wall.wshogi01" }, + { "rct2.ww.wallic10", "rct2ww.scenery_wall.wallic10" }, + { "rct2.ww.wcorr11", "rct2ww.scenery_wall.wcorr11" }, + { "rct2.ww.wpalm03", "rct2ww.scenery_wall.wpalm03" }, + { "rct2.ww.wallna06", "rct2ww.scenery_wall.wallna06" }, + { "rct2.ww.lionride", "rct2ww.ride.lionride" }, + { "rct2.ww.tigrtwst", "rct2ww.ride.tigrtwst" }, + { "rct2.ww.tgvtrain", "rct2ww.ride.tgvtrain" }, + { "rct2.ww.caddilac", "rct2ww.ride.caddilac" }, + { "rct2.ww.bomerang", "rct2ww.ride.bomerang" }, + { "rct2.ww.coffeecu", "rct2ww.ride.coffeecu" }, + { "rct2.ww.football", "rct2ww.ride.football" }, + { "rct2.ww.dolphinr", "rct2ww.ride.dolphinr" }, + { "rct2.ww.mandarin", "rct2ww.ride.mandarin" }, + { "rct2.ww.crnvbfly", "rct2ww.ride.crnvbfly" }, + { "rct2.ww.mantaray", "rct2ww.ride.mantaray" }, + { "rct2.ww.blackcab", "rct2ww.ride.blackcab" }, + { "rct2.ww.skidoo", "rct2ww.ride.skidoo" }, + { "rct2.ww.dhowwatr", "rct2ww.ride.dhowwatr" }, + { "rct2.ww.minelift", "rct2ww.ride.minelift" }, + { "rct2.ww.sloth", "rct2ww.ride.sloth" }, + { "rct2.ww.huskie", "rct2ww.ride.huskie" }, + { "rct2.ww.condorrd", "rct2ww.ride.condorrd" }, + { "rct2.ww.junkswng", "rct2ww.ride.junkswng" }, + { "rct2.ww.congaeel", "rct2ww.ride.congaeel" }, + { "rct2.ww.dragdodg", "rct2ww.ride.dragdodg" }, + { "rct2.ww.diamondr", "rct2ww.ride.diamondr" }, + { "rct2.ww.fightkit", "rct2ww.ride.fightkit" }, + { "rct2.ww.faberge", "rct2ww.ride.faberge" }, + { "rct2.ww.penguinb", "rct2ww.ride.penguinb" }, + { "rct2.ww.crnvlzrd", "rct2ww.ride.crnvlzrd" }, + { "rct2.ww.killwhal", "rct2ww.ride.killwhal" }, + { "rct2.ww.rocket", "rct2ww.ride.rocket" }, + { "rct2.ww.tutlboat", "rct2ww.ride.tutlboat" }, + { "rct2.ww.gratwhte", "rct2ww.ride.gratwhte" }, + { "rct2.ww.steamtrn", "rct2ww.ride.steamtrn" }, + { "rct2.ww.londonbs", "rct2ww.ride.londonbs" }, + { "rct2.ww.rhinorid", "rct2ww.ride.rhinorid" }, + { "rct2.ww.anaconda", "rct2ww.ride.anaconda" }, + { "rct2.ww.italypor", "rct2ww.ride.italypor" }, + { "rct2.ww.gorilla", "rct2ww.ride.gorilla" }, + { "rct2.ww.ostrich", "rct2ww.ride.ostrich" }, + { "rct2.ww.crnvfrog", "rct2ww.ride.crnvfrog" }, + { "rct2.ww.dragon", "rct2ww.ride.dragon" }, + { "rct2.ww.minecart", "rct2ww.ride.minecart" }, + { "rct2.ww.firecrak", "rct2ww.ride.firecrak" }, + { "rct2.ww.hipporid", "rct2ww.ride.hipporid" }, + { "rct2.ww.rssncrrd", "rct2ww.ride.rssncrrd" }, + { "rct2.ww.kolaride", "rct2ww.ride.kolaride" }, + { "rct2.ww.seals", "rct2ww.ride.seals" }, + { "rct2.ww.polarber", "rct2ww.ride.polarber" }, + { "rct2.ww.taxicstr", "rct2ww.ride.taxicstr" }, + { "rct2.ww.whicgrub", "rct2ww.ride.whicgrub" }, + { "rct2.ww.jaguarrd", "rct2ww.ride.jaguarrd" }, + { "rct2.ww.sputnikr", "rct2ww.ride.sputnikr" }, + { "rct2.ww.outriggr", "rct2ww.ride.outriggr" }, + { "rct2.ww.stgccstr", "rct2ww.ride.stgccstr" }, + { "rct2.ww.surfbrdc", "rct2ww.ride.surfbrdc" }, + { "rct2.ww.bullet", "rct2ww.ride.bullet" }, + { "rct2.ww.crocflum", "rct2ww.ride.crocflum" }, + { "rct2.ww.sanftram", "rct2ww.ride.sanftram" }, + { "rct2.ww.ozentran", "rct2ww.park_entrance.ozentran" }, + { "rct2.ww.euroent", "rct2ww.park_entrance.euroent" }, + { "rct2.ww.iceent", "rct2ww.park_entrance.iceent" }, + { "rct2.ww.japent", "rct2ww.park_entrance.japent" }, + { "rct2.ww.africent", "rct2ww.park_entrance.africent" }, + { "rct2.ww.naent", "rct2ww.park_entrance.naent" }, + { "rct2.ww.samerent", "rct2ww.park_entrance.samerent" }, + { "rct1.wooden_fence_red", "rct1.scenery_wall.wooden_fence_red" }, + { "rct1.ll.railings.bamboo", "rct1ll.footpath_railings.bamboo" }, + { "rct1.ll.railings.space", "rct1ll.footpath_railings.space" }, + { "rct1.toilets", "rct1.ride.toilets" }, + { "rct1.pathsurface.crazy", "rct1.footpath_surface.crazy_paving" }, + { "rct1.ll.pathsurface.tile.red", "rct1ll.footpath_surface.tiles_red" }, + { "rct1.pathsurface.tarmac", "rct1.footpath_surface.tarmac" }, + { "rct1.aa.pathsurface.tile.grey", "rct1aa.footpath_surface.tiles_grey" }, + { "rct1.pathsurface.dirt", "rct1.footpath_surface.dirt" }, + { "rct1.aa.pathsurface.space", "rct1aa.footpath_surface.tarmac_red" }, + { "rct1.ll.pathsurface.tile.green", "rct1ll.footpath_surface.tiles_green" }, + { "rct1.pathsurface.queue.blue", "rct1.footpath_surface.queue_blue" }, + { "rct1.aa.pathsurface.queue.yellow", "rct1aa.footpath_surface.queue_yellow" }, + { "rct1.aa.pathsurface.ash", "rct1aa.footpath_surface.ash" }, + { "rct1.aa.pathsurface.tarmac.green", "rct1aa.footpath_surface.tarmac_green" }, + { "rct1.pathsurface.tile.pink", "rct1.footpath_surface.tiles_brown" }, + { "rct1.aa.pathsurface.tarmac.brown", "rct1aa.footpath_surface.tarmac_brown" }, + { "rct1.aa.pathsurface.queue.red", "rct1aa.footpath_surface.queue_red" }, + { "rct1.aa.pathsurface.queue.green", "rct1aa.footpath_surface.queue_green" }, + { "rct1.ll.surface.roofgrey", "rct1ll.terrain_surface.roof_grey" }, + { "rct1.ll.surface.wood", "rct1ll.terrain_surface.wood" }, + { "rct1.aa.surface.roofred", "rct1aa.terrain_surface.roof_red" }, + { "rct1.ll.surface.rust", "rct1ll.terrain_surface.rust" }, + { "rct1.ll.edge.green", "rct1ll.terrain_edge.green" }, + { "rct1.aa.edge.yellow", "rct1aa.terrain_edge.yellow" }, + { "rct1.ll.edge.stonegrey", "rct1ll.terrain_edge.stone_grey" }, + { "rct1.aa.edge.red", "rct1aa.terrain_edge.red" }, + { "rct1.ll.edge.skyscraperb", "rct1ll.terrain_edge.skyscraper_b" }, + { "rct1.ll.edge.stonebrown", "rct1ll.terrain_edge.stone_brown" }, + { "rct1.edge.iron", "rct1.terrain_edge.iron" }, + { "rct1.ll.edge.skyscrapera", "rct1ll.terrain_edge.skyscraper_a" }, + { "rct1.aa.edge.grey", "rct1aa.terrain_edge.grey" }, + { "rct1.ll.edge.purple", "rct1ll.terrain_edge.purple" }, + { "rct1.edge.brick", "rct1.terrain_edge.brick" }, + { "rct2.pathsurface.queue.red", "rct2.footpath_surface.queue_red" }, + { "rct2.pathsurface.queue.yellow", "rct2.footpath_surface.queue_yellow" }, + { "rct2.pathsurface.crazy", "rct2.footpath_surface.crazy_paving" }, + { "rct2.pathsurface.queue.green", "rct2.footpath_surface.queue_green" }, + { "rct2.pathsurface.queue.blue", "rct2.footpath_surface.queue_blue" }, + { "rct1.pathsurface.tile.brown", "rct1.footpath_surface.tiles_brown" }, +}; + +static std::string_view MapToNewObjectIdentifier(std::string_view s) +{ + auto it = oldObjectIds.find(s); + if (it != oldObjectIds.end()) + { + return it->second; + } + return s; +} + +static std::map DATPathNames = { + { "rct2.pathash", "PATHASH " }, { "rct2.pathcrzy", "PATHCRZY" }, { "rct2.pathdirt", "PATHDIRT" }, + { "rct2.pathspce", "PATHSPCE" }, { "rct2.road", "ROAD " }, { "rct2.tarmacb", "TARMACB " }, + { "rct2.tarmacg", "TARMACG " }, { "rct2.tarmac", "TARMAC " }, { "rct2.1920path", "1920PATH" }, + { "rct2.futrpath", "FUTRPATH" }, { "rct2.futrpat2", "FUTRPAT2" }, { "rct2.jurrpath", "JURRPATH" }, + { "rct2.medipath", "MEDIPATH" }, { "rct2.mythpath", "MYTHPATH" }, { "rct2.ranbpath", "RANBPATH" }, +}; + +static std::optional GetDATPathName(std::string_view newPathName) +{ + auto it = DATPathNames.find(newPathName); + if (it != DATPathNames.end()) + { + return it->second; + } + return std::nullopt; +} + +static FootpathMapping _extendedFootpathMappings[] = { + { "rct1.path.tarmac", "rct1.footpath_surface.tarmac", "rct1.footpath_surface.queue_blue", "rct2.footpath_railings.wood" }, +}; + +static const FootpathMapping* GetFootpathMapping(const ObjectEntryDescriptor& desc) +{ + for (const auto& mapping : _extendedFootpathMappings) + { + if (mapping.Original == desc.GetName()) + { + return &mapping; + } + } + + // GetFootpathSurfaceId expects an old-style DAT identifier. In early versions of the NSF, + // we used JSON ids for legacy paths, so we have to map those to old DAT identifiers first. + if (desc.Generation == ObjectGeneration::JSON) + { + auto datPathName = GetDATPathName(desc.Identifier); + if (datPathName.has_value()) + { + rct_object_entry objectEntry = {}; + objectEntry.SetName(datPathName.value()); + return GetFootpathSurfaceId(ObjectEntryDescriptor(objectEntry)); + } + + return nullptr; + } + + // Even old .park saves with DAT identifiers somehow exist. + return GetFootpathSurfaceId(desc); +} + +static void UpdateFootpathsFromMapping( + ObjectEntryIndex* pathToSurfaceMap, ObjectEntryIndex* pathToQueueSurfaceMap, ObjectEntryIndex* pathToRailingsMap, + ObjectList& requiredObjects, ObjectEntryIndex& surfaceCount, ObjectEntryIndex& railingCount, ObjectEntryIndex entryIndex, + const FootpathMapping* footpathMapping) +{ + auto surfaceIndex = requiredObjects.Find(ObjectType::FootpathSurface, footpathMapping->NormalSurface); + if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL) + { + requiredObjects.SetObject(ObjectType::FootpathSurface, surfaceCount, footpathMapping->NormalSurface); + surfaceIndex = surfaceCount++; + } + pathToSurfaceMap[entryIndex] = surfaceIndex; + + surfaceIndex = requiredObjects.Find(ObjectType::FootpathSurface, footpathMapping->QueueSurface); + if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL) + { + requiredObjects.SetObject(ObjectType::FootpathSurface, surfaceCount, footpathMapping->QueueSurface); + surfaceIndex = surfaceCount++; + } + pathToQueueSurfaceMap[entryIndex] = surfaceIndex; + + auto railingIndex = requiredObjects.Find(ObjectType::FootpathRailings, footpathMapping->Railing); + if (railingIndex == OBJECT_ENTRY_INDEX_NULL) + { + requiredObjects.SetObject(ObjectType::FootpathRailings, railingCount, footpathMapping->Railing); + railingIndex = railingCount++; + } + pathToRailingsMap[entryIndex] = railingIndex; +} diff --git a/src/openrct2/ParkFile.h b/src/openrct2/ParkFile.h new file mode 100644 index 0000000000..4ce953abf0 --- /dev/null +++ b/src/openrct2/ParkFile.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +struct ObjectRepositoryItem; + +namespace OpenRCT2 +{ + constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK + + struct IStream; +} // namespace OpenRCT2 + +class ParkFileExporter +{ +public: + std::vector ExportObjectsList; + + void Export(std::string_view path); + void Export(OpenRCT2::IStream& stream); +}; diff --git a/src/openrct2/ParkImporter.h b/src/openrct2/ParkImporter.h index eded50014c..db99c7576a 100644 --- a/src/openrct2/ParkImporter.h +++ b/src/openrct2/ParkImporter.h @@ -62,6 +62,7 @@ namespace ParkImporter [[nodiscard]] std::unique_ptr Create(const std::string& hintPath); [[nodiscard]] std::unique_ptr CreateS4(); [[nodiscard]] std::unique_ptr CreateS6(IObjectRepository& objectRepository); + [[nodiscard]] std::unique_ptr CreateParkFile(IObjectRepository& objectRepository); bool ExtensionIsRCT1(const std::string& extension); bool ExtensionIsScenario(const std::string& extension); diff --git a/src/openrct2/ReplayManager.cpp b/src/openrct2/ReplayManager.cpp index d2090aa077..11ce4acfa5 100644 --- a/src/openrct2/ReplayManager.cpp +++ b/src/openrct2/ReplayManager.cpp @@ -13,6 +13,7 @@ #include "Game.h" #include "GameStateSnapshots.h" #include "OpenRCT2.h" +#include "ParkFile.h" #include "ParkImporter.h" #include "PlatformEnvironment.h" #include "actions/FootpathPlaceAction.h" @@ -28,7 +29,7 @@ #include "management/NewsItem.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" -#include "rct2/S6Exporter.h" +#include "scenario/Scenario.h" #include "world/EntityTweener.h" #include "world/Park.h" #include "world/Sprite.h" @@ -98,7 +99,7 @@ namespace OpenRCT2 class ReplayManager final : public IReplayManager { - static constexpr uint16_t ReplayVersion = 4; + static constexpr uint16_t ReplayVersion = 10; static constexpr uint32_t ReplayMagic = 0x5243524F; // ORCR. static constexpr int ReplayCompressionLevel = 9; static constexpr int NormalRecordingChecksumTicks = 1; @@ -246,10 +247,9 @@ namespace OpenRCT2 auto& objManager = context->GetObjectManager(); auto objects = objManager.GetPackableObjects(); - auto s6exporter = std::make_unique(); - s6exporter->ExportObjectsList = objects; - s6exporter->Export(); - s6exporter->SaveGame(&replayData->parkData); + auto exporter = std::make_unique(); + exporter->ExportObjectsList = objects; + exporter->Export(replayData->parkData); replayData->timeRecorded = std::chrono::seconds(std::time(nullptr)).count(); @@ -521,7 +521,7 @@ namespace OpenRCT2 auto context = GetContext(); auto& objManager = context->GetObjectManager(); - auto importer = ParkImporter::CreateS6(context->GetObjectRepository()); + auto importer = ParkImporter::CreateParkFile(context->GetObjectRepository()); auto loadResult = importer->LoadFromStream(&data.parkData, false); objManager.LoadObjects(loadResult.RequiredObjects); @@ -534,12 +534,6 @@ namespace OpenRCT2 DataSerialiser parkParamsDs(false, data.parkParams); SerialiseParkParameters(parkParamsDs); - // New cheats might not be serialised, make sure they are using their defaults. - CheatsReset(); - - DataSerialiser cheatDataDs(false, data.cheatData); - SerialiseCheats(cheatDataDs); - game_load_init(); fix_invalid_vehicle_sprite_sizes(); } @@ -609,9 +603,9 @@ namespace OpenRCT2 MemoryStream stream; std::string fileName = file; - if (fileName.size() < 5 || fileName.substr(fileName.size() - 5) != ".sv6r") + if (fileName.size() < 5 || fileName.substr(fileName.size() - 5) != ".parkrep") { - fileName += ".sv6r"; + fileName += ".parkrep"; } std::string outPath = GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::USER, DIRID::REPLAY); diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp index 98f5705fe4..2e6ed2f446 100644 --- a/src/openrct2/actions/RideCreateAction.cpp +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -286,7 +286,13 @@ GameActions::Result::Ptr RideCreateAction::Execute() const ride->income_per_hour = MONEY64_UNDEFINED; ride->profit = MONEY64_UNDEFINED; ride->connected_message_throttle = 0; - ride->entrance_style = 0; + + ride->entrance_style = OBJECT_ENTRY_INDEX_NULL; + if (rtd.HasFlag(RIDE_TYPE_FLAG_HAS_ENTRANCE_EXIT)) + { + ride->entrance_style = gLastEntranceStyle; + } + ride->num_block_brakes = 0; ride->guests_favourite = 0; diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp index b3a63a128d..a6957bb12a 100644 --- a/src/openrct2/actions/StaffHireNewAction.cpp +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -111,13 +111,6 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const } } - auto numStaff = GetEntityListCount(EntityType::Staff); - if (numStaff == STAFF_MAX_COUNT) - { - // Too many staff members exist already. - return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_HIRE_NEW_STAFF, STR_TOO_MANY_STAFF_IN_GAME); - } - Staff* newPeep = CreateEntity(); if (newPeep == nullptr) { diff --git a/src/openrct2/actions/TileModifyAction.cpp b/src/openrct2/actions/TileModifyAction.cpp index 9ce357d659..636c6aa10b 100644 --- a/src/openrct2/actions/TileModifyAction.cpp +++ b/src/openrct2/actions/TileModifyAction.cpp @@ -67,10 +67,10 @@ GameActions::Result::Ptr TileModifyAction::QueryExecute(bool isExecuting) const res = TileInspector::SwapElementsAt(_loc, firstIndex, secondIndex, isExecuting); break; } - case TileModifyType::AnyInsertCorrupt: + case TileModifyType::AnyToggleInvisilibity: { const auto elementIndex = _value1; - res = TileInspector::InsertCorruptElementAt(_loc, elementIndex, isExecuting); + res = TileInspector::ToggleInvisibilityOfElementAt(_loc, elementIndex, isExecuting); break; } case TileModifyType::AnyRotate: @@ -210,12 +210,6 @@ GameActions::Result::Ptr TileModifyAction::QueryExecute(bool isExecuting) const res = TileInspector::BannerToggleBlockingEdge(_loc, elementIndex, edgeIndex, isExecuting); break; } - case TileModifyType::CorruptClamp: - { - const auto elementIndex = _value1; - res = TileInspector::CorruptClamp(_loc, elementIndex, isExecuting); - break; - } default: log_error("invalid instruction"); return MakeResult(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); diff --git a/src/openrct2/actions/TileModifyAction.h b/src/openrct2/actions/TileModifyAction.h index 7066a94057..73d81e78b0 100644 --- a/src/openrct2/actions/TileModifyAction.h +++ b/src/openrct2/actions/TileModifyAction.h @@ -15,7 +15,7 @@ enum class TileModifyType : uint8_t { AnyRemove, AnySwap, - AnyInsertCorrupt, + AnyToggleInvisilibity, AnyRotate, AnyPaste, AnySort, @@ -37,7 +37,6 @@ enum class TileModifyType : uint8_t ScenerySetQuarterLocation, ScenerySetQuarterCollision, BannerToggleBlockingEdge, - CorruptClamp, Count, }; diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index 822cc8a0df..bd28442648 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -14,6 +14,7 @@ #include "../management/Research.h" #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" +#include "../rct12/RCT12.h" #include "../ride/TrackDesign.h" #include "RideCreateAction.h" #include "RideDemolishAction.h" @@ -240,7 +241,12 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const ride->lifecycle_flags |= RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN; ride->colour_scheme_type = _td.colour_scheme; - ride->entrance_style = _td.entrance_style; + auto stationIdentifier = GetStationIdentifierFromStyle(_td.entrance_style); + ride->entrance_style = objManager.GetLoadedObjectEntryIndex(stationIdentifier); + if (ride->entrance_style == OBJECT_ENTRY_INDEX_NULL) + { + ride->entrance_style = gLastEntranceStyle; + } for (int32_t i = 0; i < RCT12_NUM_COLOUR_SCHEMES; i++) { diff --git a/src/openrct2/cmdline/ConvertCommand.cpp b/src/openrct2/cmdline/ConvertCommand.cpp index 4142903ffd..d69b781bd4 100644 --- a/src/openrct2/cmdline/ConvertCommand.cpp +++ b/src/openrct2/cmdline/ConvertCommand.cpp @@ -7,14 +7,17 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../Context.h" #include "../FileClassifier.h" #include "../OpenRCT2.h" +#include "../ParkFile.h" #include "../ParkImporter.h" #include "../common.h" #include "../core/Console.hpp" #include "../core/Path.hpp" #include "../interface/Window.h" -#include "../rct2/S6Exporter.h" +#include "../object/ObjectManager.h" +#include "../scenario/Scenario.h" #include "CommandLine.hpp" #include @@ -55,9 +58,9 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator* enumerato uint32_t destinationFileType = get_file_extension_type(destinationPath); // Validate target type - if (destinationFileType != FILE_EXTENSION_SC6 && destinationFileType != FILE_EXTENSION_SV6) + if (destinationFileType != FILE_EXTENSION_PARK) { - Console::Error::WriteLine("Only conversion to .SC6 or .SV4 is supported."); + Console::Error::WriteLine("Only conversion to .PARK is supported."); return EXITCODE_FAIL; } @@ -90,11 +93,18 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator* enumerato WriteConvertFromAndToMessage(sourceFileType, destinationFileType); gOpenRCT2Headless = true; + auto context = OpenRCT2::CreateContext(); + context->Initialise(); + + auto& objManager = context->GetObjectManager(); try { auto importer = ParkImporter::Create(sourcePath); - importer->Load(sourcePath); + auto loadResult = importer->Load(sourcePath); + + objManager.LoadObjects(loadResult.RequiredObjects); + importer->Import(); } catch (const std::exception& ex) @@ -111,21 +121,13 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator* enumerato try { - auto exporter = std::make_unique(); + auto exporter = std::make_unique(); // HACK remove the main window so it saves the park with the // correct initial view window_close_by_class(WC_MAIN_WINDOW); - exporter->Export(); - if (destinationFileType == FILE_EXTENSION_SC6) - { - exporter->SaveScenario(destinationPath); - } - else - { - exporter->SaveGame(destinationPath); - } + exporter->Export(destinationPath); } catch (const std::exception& ex) { @@ -157,6 +159,8 @@ static const utf8* GetFileTypeFriendlyName(uint32_t fileType) return "RollerCoaster Tycoon 2 scenario"; case FILE_EXTENSION_SV6: return "RollerCoaster Tycoon 2 saved game"; + case FILE_EXTENSION_PARK: + return "OpenRCT2 park"; } assert(false); diff --git a/src/openrct2/core/DataSerialiserTraits.h b/src/openrct2/core/DataSerialiserTraits.h index c48f33501b..f7cb6988d5 100644 --- a/src/openrct2/core/DataSerialiserTraits.h +++ b/src/openrct2/core/DataSerialiserTraits.h @@ -809,7 +809,7 @@ template<> struct DataSerializerTraits_t { char msg[128] = {}; snprintf( - msg, sizeof(msg), "PeepThought(type = %d, item = %d, freshness = %d, freshtimeout = %d)", + msg, sizeof(msg), "PeepThought(type = %d, item = %u, freshness = %d, freshtimeout = %d)", static_cast(val.type), val.item, val.freshness, val.fresh_timeout); stream->Write(msg, strlen(msg)); } diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index a09e84c0ce..0f4a42d250 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace CODE_PAGE diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 5c17d1dec0..035fa04e07 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -1278,15 +1278,12 @@ static int32_t cc_show_limits(InteractiveConsole& console, [[maybe_unused]] cons spriteCount += GetEntityListCount(EntityType(i)); } - int32_t staffCount = GetEntityListCount(EntityType::Staff); - auto bannerCount = GetNumBanners(); console.WriteFormatLine("Sprites: %d/%d", spriteCount, MAX_ENTITIES); console.WriteFormatLine("Map Elements: %zu/%d", tileElementCount, MAX_TILE_ELEMENTS); console.WriteFormatLine("Banners: %d/%zu", bannerCount, MAX_BANNERS); console.WriteFormatLine("Rides: %d/%d", rideCount, MAX_RIDES); - console.WriteFormatLine("Staff: %d/%d", staffCount, STAFF_MAX_COUNT); console.WriteFormatLine("Images: %zu/%zu", ImageListGetUsedCount(), ImageListGetMaximum()); return 0; } @@ -1430,9 +1427,9 @@ static int32_t cc_replay_startrecord(InteractiveConsole& console, const argument std::string name = argv[0]; - if (!String::EndsWith(name, ".sv6r", true)) + if (!String::EndsWith(name, ".parkrep", true)) { - name += ".sv6r"; + name += ".parkrep"; } std::string outPath = OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath( OpenRCT2::DIRBASE::USER, OpenRCT2::DIRID::REPLAY); @@ -1573,9 +1570,9 @@ static int32_t cc_replay_normalise(InteractiveConsole& console, const arguments_ std::string inputFile = argv[0]; std::string outputFile = argv[1]; - if (!String::EndsWith(outputFile, ".sv6r", true)) + if (!String::EndsWith(outputFile, ".parkrep", true)) { - outputFile += ".sv6r"; + outputFile += ".parkrep"; } std::string outPath = OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath( OpenRCT2::DIRBASE::USER, OpenRCT2::DIRID::REPLAY); diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 7bdbc22a4a..be37922de5 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -531,7 +531,7 @@ enum #define WC_EDITOR_OBJECT_SELECTION__WIDX_TAB_1 21 #define WC_STAFF__WIDX_PICKUP 9 #define WC_TILE_INSPECTOR__WIDX_BUTTON_ROTATE 14 -#define WC_TILE_INSPECTOR__WIDX_BUTTON_CORRUPT 10 +#define WC_TILE_INSPECTOR__WIDX_BUTTON_TOGGLE_INVISIBILITY 10 #define WC_TILE_INSPECTOR__WIDX_BUTTON_COPY 17 #define WC_TILE_INSPECTOR__WIDX_BUTTON_PASTE 16 #define WC_TILE_INSPECTOR__WIDX_BUTTON_REMOVE 11 @@ -542,32 +542,29 @@ enum #define WC_TILE_INSPECTOR__WIDX_SPINNER_Y_INCREASE 8 #define WC_TILE_INSPECTOR__WIDX_SPINNER_Y_DECREASE 9 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SURFACE TileInspectorPage::Surface -#define WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_PATH TileInspectorPage::Path -#define WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_TRACK TileInspectorPage::Track -#define WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE 28 -#define WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE 29 +#define WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE 29 +#define WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE 30 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SCENERY TileInspectorPage::Scenery -#define WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_ENTRANCE TileInspectorPage::Entrance -#define WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_WALL TileInspectorPage::Wall -#define WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_LARGE_SCENERY TileInspectorPage::LargeScenery -#define WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE 29 #define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_BANNER TileInspectorPage::Banner -#define WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE 28 -#define WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_CORRUPT TileInspectorPage::Corrupt -#define WC_TILE_INSPECTOR__WIDX_CORRUPT_SPINNER_HEIGHT_INCREASE 27 -#define WC_TILE_INSPECTOR__WIDX_CORRUPT_SPINNER_HEIGHT_DECREASE 28 +#define WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE 28 +#define WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE 29 enum class PromptMode : uint8_t { diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index 42649726cd..7ed0b20d60 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -92,7 +92,6 @@ struct rct_window uint32_t highlighted_item; uint16_t ride_colour; ResearchItem* research_item; - rct_object_entry* object_entry; const scenario_index_entry* highlighted_scenario; uint16_t var_496; }; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 50ff663968..ba645f2a93 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -288,6 +288,7 @@ + @@ -306,7 +307,6 @@ - @@ -752,6 +752,7 @@ + @@ -779,7 +780,6 @@ - diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index 965e177233..4b3949b55a 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -23,13 +23,13 @@ using namespace OpenRCT2; using namespace OpenRCT2::Localisation; -static constexpr rct_string_id NONSTEX_BASE_STRING_ID = 3463; -static constexpr uint16_t MAX_OBJECT_CACHED_STRINGS = 2048; +static constexpr uint16_t BASE_OBJECT_STRING_ID = 0x2000; +static constexpr uint16_t MAX_OBJECT_CACHED_STRINGS = 0x5000 - BASE_OBJECT_STRING_ID; LocalisationService::LocalisationService(const std::shared_ptr& env) : _env(env) { - for (rct_string_id stringId = NONSTEX_BASE_STRING_ID + MAX_OBJECT_CACHED_STRINGS; stringId >= NONSTEX_BASE_STRING_ID; + for (rct_string_id stringId = BASE_OBJECT_STRING_ID + MAX_OBJECT_CACHED_STRINGS; stringId >= BASE_OBJECT_STRING_ID; stringId--) { _availableObjectStringIds.push(stringId); @@ -48,6 +48,16 @@ const char* LocalisationService::GetString(rct_string_id id) const { result = ""; } + else if (id >= BASE_OBJECT_STRING_ID && id < BASE_OBJECT_STRING_ID + MAX_OBJECT_CACHED_STRINGS) + { + size_t index = id - BASE_OBJECT_STRING_ID; + if (index < _objectStrings.size()) + { + return _objectStrings[index].c_str(); + } + + result = "(unallocated string)"; + } else if (id != STR_NONE) { if (_languageCurrent != nullptr) @@ -129,9 +139,21 @@ rct_string_id LocalisationService::GetObjectOverrideStringId(std::string_view le rct_string_id LocalisationService::AllocateObjectString(const std::string& target) { + if (_availableObjectStringIds.empty()) + { + return STR_EMPTY; + } + auto stringId = _availableObjectStringIds.top(); _availableObjectStringIds.pop(); - _languageCurrent->SetString(stringId, target); + + size_t index = stringId - BASE_OBJECT_STRING_ID; + if (index >= _objectStrings.size()) + { + _objectStrings.resize(index + 1); + } + _objectStrings[index] = target; + return stringId; } @@ -139,9 +161,10 @@ void LocalisationService::FreeObjectString(rct_string_id stringId) { if (stringId != STR_EMPTY) { - if (_languageCurrent != nullptr) + size_t index = stringId - BASE_OBJECT_STRING_ID; + if (index < _objectStrings.size()) { - _languageCurrent->RemoveString(stringId); + _objectStrings[index] = {}; } _availableObjectStringIds.push(stringId); } diff --git a/src/openrct2/localisation/LocalisationService.h b/src/openrct2/localisation/LocalisationService.h index c0fdef973c..565a7e2fb2 100644 --- a/src/openrct2/localisation/LocalisationService.h +++ b/src/openrct2/localisation/LocalisationService.h @@ -16,6 +16,7 @@ #include #include #include +#include struct ILanguagePack; struct IObjectManager; @@ -36,6 +37,7 @@ namespace OpenRCT2::Localisation std::unique_ptr _languageFallback; std::unique_ptr _languageCurrent; std::stack _availableObjectStringIds; + std::vector _objectStrings; public: int32_t GetCurrentLanguage() const diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 4586f2d767..1142f6e4f2 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -2347,7 +2347,6 @@ enum : uint16_t STR_OBJECT_SELECTION_ERR_ALWAYS_REQUIRED = 3175, STR_UNABLE_TO_SELECT_THIS_OBJECT = 3176, STR_UNABLE_TO_DE_SELECT_THIS_OBJECT = 3177, - STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED = 3178, STR_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED = 3179, STR_INVALID_SELECTION_OF_OBJECTS = 3180, STR_OBJECT_SELECTION = 3181, @@ -2964,8 +2963,7 @@ enum : uint16_t STR_LANGUAGE_LOAD_FAILED = 5561, STR_WARNING_IN_CAPS = 5562, STR_THIS_FEATURE_IS_CURRENTLY_UNSTABLE = 5563, - STR_INSERT_CORRUPT = 5564, // Unused - STR_INSERT_CORRUPT_TIP = 5565, + STR_PASSWORD = 5566, STR_ADVERTISE = 5567, STR_PASSWORD_REQUIRED = 5568, @@ -3288,7 +3286,6 @@ enum : uint16_t STR_TILE_INSPECTOR_GROUPBOX_WALL_INFO = 5929, STR_TILE_INSPECTOR_GROUPBOX_LARGE_SCENERY_INFO = 5930, STR_TILE_INSPECTOR_GROUPBOX_BANNER_INFO = 5931, - STR_TILE_INSPECTOR_GROUPBOX_CORRUPT_INFO = 5932, STR_TILE_INSPECTOR_GROUPBOX_PROPERTIES = 5933, STR_TILE_INSPECTOR_SURFACE_TERAIN = 5934, STR_TILE_INSPECTOR_SURFACE_EDGE = 5935, @@ -3753,7 +3750,6 @@ enum : uint16_t STR_SHORTCUT_SCALE_UP = 6333, STR_SHORTCUT_SCALE_DOWN = 6334, - STR_SHORTCUT_INSERT_CORRPUT_ELEMENT = 6335, STR_SHORTCUT_COPY_ELEMENT = 6336, STR_SHORTCUT_PASTE_ELEMENT = 6337, STR_SHORTCUT_REMOVE_ELEMENT = 6338, @@ -3896,6 +3892,16 @@ enum : uint16_t STR_VIEWPORT_TRANSPARENT_WATER = 6440, + STR_AT_LEAST_ONE_FOOTPATH_NON_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED = 6441, + STR_AT_LEAST_ONE_FOOTPATH_QUEUE_SURFACE_OBJECT_MUST_BE_SELECTED = 6442, + STR_AT_LEAST_ONE_FOOTPATH_RAILING_OBJECT_MUST_BE_SELECTED = 6443, + STR_OBJECT_SELECTION_FOOTPATH_SURFACES = 6444, + STR_OBJECT_SELECTION_FOOTPATH_RAILINGS = 6445, + STR_TILE_INSPECTOR_FOOTPATH_SURFACE_NAME = 6446, + STR_TILE_INSPECTOR_FOOTPATH_RAILINGS_NAME = 6447, + + STR_UNSUPPORTED_OBJECT_FORMAT = 6448, + STR_MUSIC_OBJECT_TRACK_HEADER = 6449, STR_MUSIC_OBJECT_TRACK_LIST_ITEM = 6450, STR_MUSIC_OBJECT_TRACK_LIST_ITEM_WITH_COMPOSER = 6451, @@ -3913,8 +3919,6 @@ enum : uint16_t STR_FOLLOW_SUBJECT_TIP = 6458, - STR_UNSUPPORTED_OBJECT_FORMAT = 6459, - STR_TILE_INSPECTOR_DIRECTION_SHORT = 6460, STR_TILE_INSPECTOR_DIRECTION = 6461, diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index 1b35dc798e..896224eb15 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -76,7 +76,7 @@ void research_reset_items() * * rct2: 0x00684BAE */ -void research_update_uncompleted_types() +void ResearchUpdateUncompletedTypes() { int32_t uncompletedResearchTypes = 0; @@ -354,7 +354,7 @@ void research_update() gResearchProgress = 0; gResearchProgressStage = RESEARCH_STAGE_INITIAL_RESEARCH; research_calculate_expected_date(); - research_update_uncompleted_types(); + ResearchUpdateUncompletedTypes(); research_invalidate_related_windows(); break; case RESEARCH_STAGE_FINISHED_ALL: @@ -393,6 +393,12 @@ void research_reset_current_item() */ static void research_insert_unresearched(ResearchItem&& item) { + // First check to make sure that entry is not already accounted for + if (item.Exists()) + { + return; + } + gResearchItemsUninvented.push_back(std::move(item)); } @@ -724,18 +730,17 @@ void research_remove_flags() } } -void research_fix() +static void ResearchRemoveNullItems(std::vector& items) { - // Fix invalid research items - for (auto it = gResearchItemsInvented.begin(); it != gResearchItemsInvented.end();) + for (auto it = items.begin(); it != items.end();) { auto& researchItem = *it; if (researchItem.type == Research::EntryType::Ride) { - rct_ride_entry* rideEntry = get_ride_entry(researchItem.entryIndex); + const auto* rideEntry = get_ride_entry(researchItem.entryIndex); if (rideEntry == nullptr) { - it = gResearchItemsInvented.erase(it); + it = items.erase(it); } else { @@ -744,10 +749,10 @@ void research_fix() } else { - rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem.entryIndex); + const auto* sceneryGroupEntry = get_scenery_group_entry(researchItem.entryIndex); if (sceneryGroupEntry == nullptr) { - it = gResearchItemsInvented.erase(it); + it = items.erase(it); } else { @@ -755,74 +760,96 @@ void research_fix() } } } - for (auto it = gResearchItemsUninvented.begin(); it != gResearchItemsUninvented.end();) +} + +static void research_mark_item_as_researched(const ResearchItem& item) +{ + if (item.type == Research::EntryType::Ride) { - auto& researchItem = *it; - if (researchItem.type == Research::EntryType::Ride) + const auto* rideEntry = get_ride_entry(item.entryIndex); + if (rideEntry != nullptr) { - rct_ride_entry* rideEntry = get_ride_entry(researchItem.entryIndex); - if (rideEntry == nullptr) + ride_entry_set_invented(item.entryIndex); + for (auto rideType : rideEntry->ride_type) { - it = gResearchItemsUninvented.erase(it); - } - else - { - it++; - } - } - else - { - rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem.entryIndex); - if (sceneryGroupEntry == nullptr) - { - it = gResearchItemsUninvented.erase(it); - } - else - { - it++; - } - } - } - - research_update_uncompleted_types(); - if (gResearchUncompletedCategories == 0) - gResearchProgressStage = RESEARCH_STAGE_FINISHED_ALL; - - // Sometimes ride entries are not in the research table. - // If all research is done, simply insert all of them as researched. - // For good measure, also include scenery groups. - if (gResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL) - { - for (ObjectEntryIndex i = 0; i < MAX_RIDE_OBJECTS; i++) - { - const rct_ride_entry* rideEntry = get_ride_entry(i); - - if (rideEntry != nullptr) - { - research_insert_ride_entry(i, true); - ride_entry_set_invented(i); - - for (uint8_t j = 0; j < MAX_RIDE_TYPES_PER_RIDE_ENTRY; j++) + if (rideType != RIDE_TYPE_NULL) { - uint32_t rideType = rideEntry->ride_type[j]; - if (rideType != RIDE_TYPE_NULL) - { - ride_type_set_invented(rideEntry->ride_type[j]); - } + ride_type_set_invented(rideType); } } } - - for (uint8_t i = 0; i < MAX_SCENERY_GROUP_OBJECTS; i++) + } + else if (item.type == Research::EntryType::Scenery) + { + const auto sgEntry = get_scenery_group_entry(item.entryIndex); + if (sgEntry != nullptr) { - const rct_scenery_group_entry* groupEntry = get_scenery_group_entry(i); - - if (groupEntry != nullptr) - research_insert_scenery_group_entry(i, true); + for (auto i = 0; i < sgEntry->entry_count; i++) + { + auto sceneryEntryIndex = sgEntry->scenery_entries[i]; + scenery_set_invented(sceneryEntryIndex); + } } } } +static void ResearchRebuildInventedTables() +{ + set_every_ride_type_not_invented(); + set_every_ride_entry_invented(); + set_every_ride_entry_not_invented(); + set_all_scenery_items_not_invented(); + for (const auto& item : gResearchItemsInvented) + { + // Ignore item, if the research of it is in progress + if (gResearchProgressStage == RESEARCH_STAGE_DESIGNING || gResearchProgressStage == RESEARCH_STAGE_COMPLETING_DESIGN) + { + if (item == gResearchNextItem) + { + continue; + } + } + + research_mark_item_as_researched(item); + } +} + +static void ResearchAddAllMissingItems(bool isResearched) +{ + for (ObjectEntryIndex i = 0; i < MAX_RIDE_OBJECTS; i++) + { + const auto* rideEntry = get_ride_entry(i); + if (rideEntry != nullptr) + { + research_insert_ride_entry(i, isResearched); + } + } + + for (ObjectEntryIndex i = 0; i < MAX_SCENERY_GROUP_OBJECTS; i++) + { + const auto* groupEntry = get_scenery_group_entry(i); + if (groupEntry != nullptr) + { + research_insert_scenery_group_entry(i, isResearched); + } + } +} + +void ResearchFix() +{ + // Remove null entries from the research list + ResearchRemoveNullItems(gResearchItemsInvented); + ResearchRemoveNullItems(gResearchItemsUninvented); + + // Add missing entries to the research list + // If research is complete, mark all the missing items as available + ResearchAddAllMissingItems(gResearchProgressStage == RESEARCH_STAGE_FINISHED_ALL); + + // Now rebuild all the tables that say whether a ride or scenery item is invented + ResearchRebuildInventedTables(); + ResearchUpdateUncompletedTypes(); +} + void research_items_make_all_unresearched() { gResearchItemsUninvented.insert( diff --git a/src/openrct2/management/Research.h b/src/openrct2/management/Research.h index 3271eef7fc..91aab67307 100644 --- a/src/openrct2/management/Research.h +++ b/src/openrct2/management/Research.h @@ -169,7 +169,7 @@ extern uint8_t gResearchUncompletedCategories; extern bool gSilentResearch; void research_reset_items(); -void research_update_uncompleted_types(); +void ResearchUpdateUncompletedTypes(); void research_update(); void research_reset_current_item(); void research_populate_list_random(); @@ -199,7 +199,7 @@ void set_every_ride_type_not_invented(); void set_every_ride_entry_invented(); void set_every_ride_entry_not_invented(); void research_remove_flags(); -void research_fix(); +void ResearchFix(); void research_items_make_all_unresearched(); void research_items_make_all_researched(); diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index 24fc479689..9054e89999 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -13,6 +13,7 @@ #include "../Game.h" #include "../GameStateSnapshots.h" #include "../OpenRCT2.h" +#include "../ParkFile.h" #include "../PlatformEnvironment.h" #include "../actions/LoadOrQuitAction.h" #include "../actions/NetworkModifyGroupAction.h" @@ -21,6 +22,7 @@ #include "../core/Json.hpp" #include "../localisation/Formatting.h" #include "../platform/Platform2.h" +#include "../scenario/Scenario.h" #include "../scripting/ScriptEngine.h" #include "../ui/UiContext.h" #include "../ui/WindowManager.h" @@ -70,7 +72,6 @@ static constexpr uint32_t MaxPacketsPerUpdate = 100; # include "../localisation/Localisation.h" # include "../object/ObjectManager.h" # include "../object/ObjectRepository.h" -# include "../rct2/S6Exporter.h" # include "../scenario/Scenario.h" # include "../util/Util.h" # include "../world/Park.h" @@ -1219,15 +1220,25 @@ void NetworkBase::Client_Send_AUTH( _serverConnection->QueuePacket(std::move(packet)); } -void NetworkBase::Client_Send_MAPREQUEST(const std::vector& objects) +void NetworkBase::Client_Send_MAPREQUEST(const std::vector& objects) { log_verbose("client requests %u objects", uint32_t(objects.size())); NetworkPacket packet(NetworkCommand::MapRequest); packet << static_cast(objects.size()); for (const auto& object : objects) { - log_verbose("client requests object %s", object.c_str()); - packet.Write(reinterpret_cast(object.c_str()), 8); + std::string name(object.GetName()); + log_verbose("client requests object %s", name.c_str()); + if (object.Generation == ObjectGeneration::DAT) + { + packet << static_cast(0); + packet.Write(&object.Entry, sizeof(rct_object_entry)); + } + else + { + packet << static_cast(1); + packet.WriteString(name); + } } _serverConnection->QueuePacket(std::move(packet)); } @@ -1261,9 +1272,20 @@ void NetworkBase::Server_Send_OBJECTS_LIST( NetworkPacket packet(NetworkCommand::ObjectsList); packet << static_cast(i) << static_cast(objects.size()); - log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); - packet.Write(reinterpret_cast(object->ObjectEntry.name), 8); - packet << object->ObjectEntry.checksum << object->ObjectEntry.flags; + if (object->Identifier.empty()) + { + // DAT + log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); + packet << static_cast(0); + packet.Write(&object->ObjectEntry, sizeof(rct_object_entry)); + } + else + { + // JSON + log_verbose("Object %s", object->Identifier.c_str()); + packet << static_cast(1); + packet.WriteString(object->Identifier); + } connection.QueuePacket(std::move(packet)); } @@ -1401,37 +1423,18 @@ void NetworkBase::Server_Send_MAP(NetworkConnection* connection) std::vector NetworkBase::save_for_network(const std::vector& objects) const { - std::vector header; - bool RLEState = gUseRLE; - gUseRLE = false; - + std::vector result; auto ms = OpenRCT2::MemoryStream(); - if (!SaveMap(&ms, objects)) + if (SaveMap(&ms, objects)) { - log_warning("Failed to export map."); - return header; - } - gUseRLE = RLEState; - - const void* data = ms.GetData(); - int32_t size = ms.GetLength(); - - auto compressed = util_zlib_deflate(static_cast(data), size); - if (compressed.has_value()) - { - std::string headerString = "open2_sv6_zlib"; - header.resize(headerString.size() + 1 + compressed->size()); - std::memcpy(&header[0], headerString.c_str(), headerString.size() + 1); - std::memcpy(&header[headerString.size() + 1], compressed->data(), compressed->size()); - log_verbose("Sending map of size %u bytes, compressed to %u bytes", size, headerString.size() + 1 + compressed->size()); + result.resize(ms.GetLength()); + std::memcpy(result.data(), ms.GetData(), result.size()); } else { - log_warning("Failed to compress the data, falling back to non-compressed sv6."); - header.resize(size); - std::memcpy(header.data(), data, size); + log_warning("Failed to export map."); } - return header; + return result; } void NetworkBase::Client_Send_CHAT(const char* text) @@ -2339,26 +2342,45 @@ void NetworkBase::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, Netw intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { ::GetContext()->GetNetwork().Close(); }); context_open_intent(&intent); - char objectName[12]{}; - std::memcpy(objectName, packet.Read(8), 8); + uint8_t objectType{}; + packet >> objectType; - uint32_t checksum = 0; - uint32_t flags = 0; - packet >> checksum >> flags; - - const auto* object = repo.FindObjectLegacy(objectName); - // This could potentially request the object if checksums don't match, but since client - // won't replace its version with server-provided one, we don't do that. - if (object == nullptr) + if (objectType == 0) { - log_verbose("Requesting object %s with checksum %x from server", objectName, checksum); - _missingObjects.emplace_back(objectName); + // DAT + auto entry = reinterpret_cast(packet.Read(sizeof(rct_object_entry))); + if (entry != nullptr) + { + const auto* object = repo.FindObject(entry); + if (object == nullptr) + { + auto objectName = std::string(entry->GetName()); + log_verbose("Requesting object %s with checksum %x from server", objectName.c_str(), entry->checksum); + _missingObjects.push_back(ObjectEntryDescriptor(*entry)); + } + else if (object->ObjectEntry.checksum != entry->checksum || object->ObjectEntry.flags != entry->flags) + { + auto objectName = std::string(entry->GetName()); + log_warning( + "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", objectName.c_str(), + object->ObjectEntry.checksum, object->ObjectEntry.flags, entry->checksum, entry->flags); + } + } } - else if (object->ObjectEntry.checksum != checksum || object->ObjectEntry.flags != flags) + else { - log_warning( - "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", objectName, object->ObjectEntry.checksum, - object->ObjectEntry.flags, checksum, flags); + // JSON + auto identifier = packet.ReadString(); + if (!identifier.empty()) + { + const auto* object = repo.FindObject(identifier); + if (object == nullptr) + { + auto objectName = std::string(identifier); + log_verbose("Requesting object %s from server", objectName.c_str()); + _missingObjects.push_back(ObjectEntryDescriptor(objectName)); + } + } } } @@ -2490,13 +2512,28 @@ void NetworkBase::Server_Handle_MAPREQUEST(NetworkConnection& connection, Networ return; } - // This is required, as packet does not have null terminator - std::string s(name, name + 8); - log_verbose("Client requested object %s", s.c_str()); - const ObjectRepositoryItem* item = repo.FindObjectLegacy(s.c_str()); + uint8_t generation{}; + packet >> generation; + + std::string objectName; + const ObjectRepositoryItem* item{}; + if (generation == static_cast(ObjectGeneration::DAT)) + { + const auto* entry = reinterpret_cast(packet.Read(sizeof(rct_object_entry))); + objectName = std::string(entry->GetName()); + log_verbose("Client requested object %s", objectName.c_str()); + item = repo.FindObject(entry); + } + else + { + objectName = std::string(packet.ReadString()); + log_verbose("Client requested object %s", objectName.c_str()); + item = repo.FindObject(objectName); + } + if (item == nullptr) { - log_warning("Client tried getting non-existent object %s from us.", s.c_str()); + log_warning("Client tried getting non-existent object %s from us.", objectName.c_str()); } else { @@ -2504,7 +2541,7 @@ void NetworkBase::Server_Handle_MAPREQUEST(NetworkConnection& connection, Networ } } - const char* player_name = static_cast(connection.Player->Name.c_str()); + auto player_name = connection.Player->Name.c_str(); Server_Send_MAP(&connection); Server_Send_EVENT_PLAYER_JOINED(player_name); Server_Send_GROUPLIST(connection); @@ -2673,25 +2710,6 @@ void NetworkBase::Client_Handle_MAP([[maybe_unused]] NetworkConnection& connecti bool has_to_free = false; uint8_t* data = &chunk_buffer[0]; size_t data_size = size; - // zlib-compressed - if (strcmp("open2_sv6_zlib", reinterpret_cast(&chunk_buffer[0])) == 0) - { - log_verbose("Received zlib-compressed sv6 map"); - has_to_free = true; - size_t header_len = strlen("open2_sv6_zlib") + 1; - data = util_zlib_inflate(&chunk_buffer[header_len], size - header_len, &data_size); - if (data == nullptr) - { - log_warning("Failed to decompress data sent from server."); - Close(); - return; - } - } - else - { - log_verbose("Assuming received map is in plain sv6 format"); - } - auto ms = MemoryStream(data, data_size); if (LoadMap(&ms)) { @@ -2734,7 +2752,7 @@ bool NetworkBase::LoadMap(IStream* stream) { auto& context = GetContext(); auto& objManager = context.GetObjectManager(); - auto importer = ParkImporter::CreateS6(context.GetObjectRepository()); + auto importer = ParkImporter::CreateParkFile(context.GetObjectRepository()); auto loadResult = importer->LoadFromStream(stream, false); objManager.LoadObjects(loadResult.RequiredObjects); importer->Import(); @@ -2742,43 +2760,12 @@ bool NetworkBase::LoadMap(IStream* stream) EntityTweener::Get().Reset(); AutoCreateMapAnimations(); - // Read checksum - [[maybe_unused]] uint32_t checksum = stream->ReadValue(); - - // Read other data not in normal save files - gGamePaused = stream->ReadValue(); - _guestGenerationProbability = stream->ReadValue(); - _suggestedGuestMaximum = stream->ReadValue(); - gCheatsAllowTrackPlaceInvalidHeights = stream->ReadValue() != 0; - gCheatsEnableAllDrawableTrackPieces = stream->ReadValue() != 0; - gCheatsSandboxMode = stream->ReadValue() != 0; - gCheatsDisableClearanceChecks = stream->ReadValue() != 0; - gCheatsDisableSupportLimits = stream->ReadValue() != 0; - gCheatsDisableTrainLengthLimit = stream->ReadValue() != 0; - gCheatsEnableChainLiftOnAllTrack = stream->ReadValue() != 0; - gCheatsShowAllOperatingModes = stream->ReadValue() != 0; - gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue() != 0; - gCheatsUnlockOperatingLimits = stream->ReadValue() != 0; - gCheatsDisableBrakesFailure = stream->ReadValue() != 0; - gCheatsDisableAllBreakdowns = stream->ReadValue() != 0; - gCheatsBuildInPauseMode = stream->ReadValue() != 0; - gCheatsIgnoreRideIntensity = stream->ReadValue() != 0; - gCheatsDisableVandalism = stream->ReadValue() != 0; - gCheatsDisableLittering = stream->ReadValue() != 0; - gCheatsNeverendingMarketing = stream->ReadValue() != 0; - gCheatsFreezeWeather = stream->ReadValue() != 0; - gCheatsDisablePlantAging = stream->ReadValue() != 0; - gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue() != 0; - gCheatsDisableRideValueAging = stream->ReadValue() != 0; - gConfigGeneral.show_real_names_of_guests = stream->ReadValue() != 0; - gCheatsIgnoreResearchStatus = stream->ReadValue() != 0; - gAllowEarlyCompletionInNetworkPlay = stream->ReadValue() != 0; - gLastAutoSaveUpdate = AUTOSAVE_PAUSE; result = true; } - catch (const std::exception&) + catch (const std::exception& e) { + Console::Error::WriteLine("Unable to read map from server: %s", e.what()); } return result; } @@ -2789,44 +2776,14 @@ bool NetworkBase::SaveMap(IStream* stream, const std::vector(); - s6exporter->ExportObjectsList = objects; - s6exporter->Export(); - s6exporter->SaveGame(stream); - - // Write other data not in normal save files - stream->WriteValue(gGamePaused); - stream->WriteValue(_guestGenerationProbability); - stream->WriteValue(_suggestedGuestMaximum); - stream->WriteValue(gCheatsAllowTrackPlaceInvalidHeights); - stream->WriteValue(gCheatsEnableAllDrawableTrackPieces); - stream->WriteValue(gCheatsSandboxMode); - stream->WriteValue(gCheatsDisableClearanceChecks); - stream->WriteValue(gCheatsDisableSupportLimits); - stream->WriteValue(gCheatsDisableTrainLengthLimit); - stream->WriteValue(gCheatsEnableChainLiftOnAllTrack); - stream->WriteValue(gCheatsShowAllOperatingModes); - stream->WriteValue(gCheatsShowVehiclesFromOtherTrackTypes); - stream->WriteValue(gCheatsUnlockOperatingLimits); - stream->WriteValue(gCheatsDisableBrakesFailure); - stream->WriteValue(gCheatsDisableAllBreakdowns); - stream->WriteValue(gCheatsBuildInPauseMode); - stream->WriteValue(gCheatsIgnoreRideIntensity); - stream->WriteValue(gCheatsDisableVandalism); - stream->WriteValue(gCheatsDisableLittering); - stream->WriteValue(gCheatsNeverendingMarketing); - stream->WriteValue(gCheatsFreezeWeather); - stream->WriteValue(gCheatsDisablePlantAging); - stream->WriteValue(gCheatsAllowArbitraryRideTypeChanges); - stream->WriteValue(gCheatsDisableRideValueAging); - stream->WriteValue(gConfigGeneral.show_real_names_of_guests); - stream->WriteValue(gCheatsIgnoreResearchStatus); - stream->WriteValue(gConfigGeneral.allow_early_completion); - + auto exporter = std::make_unique(); + exporter->ExportObjectsList = objects; + exporter->Export(*stream); result = true; } - catch (const std::exception&) + catch (const std::exception& e) { + Console::Error::WriteLine("Unable to serialise map: %s", e.what()); } return result; } diff --git a/src/openrct2/network/NetworkBase.h b/src/openrct2/network/NetworkBase.h index 95d6dc8db2..79f49f8615 100644 --- a/src/openrct2/network/NetworkBase.h +++ b/src/openrct2/network/NetworkBase.h @@ -2,6 +2,7 @@ #include "../System.hpp" #include "../actions/GameAction.h" +#include "../object/Object.h" #include "NetworkConnection.h" #include "NetworkGroup.h" #include "NetworkPlayer.h" @@ -45,7 +46,7 @@ public: // Common std::string BeginLog(const std::string& directory, const std::string& midName, const std::string& filenameFormat); void AppendLog(std::ostream& fs, std::string_view s); void BeginChatLog(); - void AppendChatLog(std::string_view text); + void AppendChatLog(std::string_view s); void CloseChatLog(); NetworkStats_t GetStats() const; json_t GetServerInfoAsJson() const; @@ -138,7 +139,7 @@ public: // Client void Client_Send_GAME_ACTION(const GameAction* action); void Client_Send_PING(); void Client_Send_GAMEINFO(); - void Client_Send_MAPREQUEST(const std::vector& objects); + void Client_Send_MAPREQUEST(const std::vector& objects); void Client_Send_HEARTBEAT(NetworkConnection& connection) const; // Handlers. @@ -218,7 +219,7 @@ private: // Client Data std::map _pendingPlayerLists; std::multimap _pendingPlayerInfo; std::map _serverTickData; - std::vector _missingObjects; + std::vector _missingObjects; std::string _host; std::string _chatLogPath; std::string _chatLogFilenameFormat = "%Y%m%d-%H%M%S.txt"; diff --git a/src/openrct2/object/DefaultObjects.cpp b/src/openrct2/object/DefaultObjects.cpp index 6f112ff6ed..bc7f0016e1 100644 --- a/src/openrct2/object/DefaultObjects.cpp +++ b/src/openrct2/object/DefaultObjects.cpp @@ -11,60 +11,176 @@ #include "Object.h" +// clang-format off +const std::string_view MinimumRequiredObjects[] = { "rct2.terrain_surface.grass", "rct2.terrain_edge.rock" }; + const std::string_view DefaultSelectedObjects[] = { // An initial default selection - "rct2.scgtrees", // Scenery: Trees - "rct2.scgshrub", // Scenery: Shrubs and Ornaments - "rct2.scggardn", // Scenery: Gardens - "rct2.scgfence", // Scenery: Fences and Walls - "rct2.scgwalls", // Scenery: Walls and Roofs - "rct2.scgpathx", // Scenery: Signs and Items for Footpaths - "rct2.tarmac", // Footpath: Tarmac - "rct2.twist1", // Ride: Twist - "rct2.ptct1", // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) - "rct2.zldb", // Ride: Junior Roller Coaster (Ladybird Trains) - "rct2.lfb1", // Ride: Log Flume - "rct2.vcr", // Ride: Vintage Cars - "rct2.mgr1", // Ride: Merry-Go-Round - "rct2.tlt1", // Ride: Restroom - "rct2.atm1", // Ride: Cash Machine - "rct2.faid1", // Ride: First Aid Room - "rct2.infok", // Ride: Information Kiosk - "rct2.drnks", // Ride: Drinks Stall - "rct2.cndyf", // Ride: Candyfloss Stall - "rct2.burgb", // Ride: Burger Bar - "rct2.balln", // Ride: Balloon Stall - "rct2.arrt1", // Ride: Corkscrew Roller Coaster - "rct2.rboat", // Ride: Rowing Boats - "rct2.pkent1", // Park Entrance: Traditional Park Entrance - "rct2.wtrcyan", // Water: Natural Water - "rct2.tarmacb", // Footpath: Brown Tarmac Footpath - "rct2.pathspce", // Footpath: Space Style Footpath - "rct2.pathdirt", // Footpath: Dirt Footpath - "rct2.pathcrzy", // Footpath: Crazy Paving Footpath - "rct2.pathash", // Footpath: Ash Footpath + "rct2.scenery_group.scgtrees", // Scenery: Trees + "rct2.scenery_group.scgshrub", // Scenery: Shrubs and Ornaments + "rct2.scenery_group.scggardn", // Scenery: Gardens + "rct2.scenery_group.scgfence", // Scenery: Fences and Walls + "rct2.scenery_group.scgwalls", // Scenery: Walls and Roofs + "rct2.scenery_group.scgpathx", // Scenery: Signs and Items for Footpaths + "rct2.ride.twist1", // Ride: Twist + "rct2.ride.ptct1", // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) + "rct2.ride.zldb", // Ride: Junior Roller Coaster (Ladybird Trains) + "rct2.ride.lfb1", // Ride: Log Flume + "rct2.ride.vcr", // Ride: Vintage Cars + "rct2.ride.mgr1", // Ride: Merry-Go-Round + "rct2.ride.tlt1", // Ride: Restroom + "rct2.ride.atm1", // Ride: Cash Machine + "rct2.ride.faid1", // Ride: First Aid Room + "rct2.ride.infok", // Ride: Information Kiosk + "rct2.ride.drnks", // Ride: Drinks Stall + "rct2.ride.cndyf", // Ride: Candyfloss Stall + "rct2.ride.burgb", // Ride: Burger Bar + "rct2.ride.balln", // Ride: Balloon Stall + "rct2.ride.arrt1", // Ride: Corkscrew Roller Coaster + "rct2.ride.rboat", // Ride: Rowing Boats + "rct2.park_entrance.pkent1", // Park Entrance: Traditional Park Entrance + "rct2.water.wtrcyan", // Water: Natural Water // The following are for all random map generation features to work out the box - "rct2.scgjungl", // Jungle Theming - "rct2.scgsnow", // Snow and Ice Theming - "rct2.scgwater", // Water Feature Theming + "rct2.scenery_group.scgjungl", // Jungle Theming + "rct2.scenery_group.scgsnow", // Snow and Ice Theming + "rct2.scenery_group.scgwater", // Water Feature Theming + + // Surfaces + "rct2.terrain_surface.grass", + "rct2.terrain_surface.sand", + "rct2.terrain_surface.dirt", + "rct2.terrain_surface.rock", + "rct2.terrain_surface.martian", + "rct2.terrain_surface.chequerboard", + "rct2.terrain_surface.grass_clumps", + "rct2.terrain_surface.ice", + "rct2.terrain_surface.grid_red", + "rct2.terrain_surface.grid_yellow", + "rct2.terrain_surface.grid_purple", + "rct2.terrain_surface.grid_green", + "rct2.terrain_surface.sand_red", + "rct2.terrain_surface.sand_brown", + + // Edges + "rct2.terrain_edge.rock", + "rct2.terrain_edge.wood_red", + "rct2.terrain_edge.wood_black", + "rct2.terrain_edge.ice", + + // Stations + "rct2.station.plain", + "rct2.station.wooden", + "rct2.station.canvas_tent", + "rct2.station.castle_grey", + "rct2.station.castle_brown", + "rct2.station.jungle", + "rct2.station.log", + "rct2.station.classical", + "rct2.station.abstract", + "rct2.station.snow", + "rct2.station.pagoda", + "rct2.station.space", + + // Music + "rct2.music.dodgems", + "rct2.music.fairground", + "rct2.music.roman", + "rct2.music.oriental", + "rct2.music.martian", + "rct2.music.jungle", + "rct2.music.egyptian", + "rct2.music.toyland", + "rct2.music.space", + "rct2.music.horror", + "rct2.music.techno", + "rct2.music.gentle", + "rct2.music.summer", + "rct2.music.water", + "rct2.music.wildwest", + "rct2.music.jurassic", + "rct2.music.rock1", + "rct2.music.ragtime", + "rct2.music.fantasy", + "rct2.music.rock2", + "rct2.music.ice", + "rct2.music.snow", + "rct2.music.medieval", + "rct2.music.urban", + "rct2.music.organ", + "rct2.music.mechanical", + "rct2.music.modern", + "rct2.music.pirate", + "rct2.music.rock3", + "rct2.music.candy", + + // Footpath surfaces + "rct2.footpath_surface.tarmac", + "rct2.footpath_surface.tarmac_brown", + "rct2.footpath_surface.tarmac_red", + "rct2.footpath_surface.dirt", + "rct2.footpath_surface.crazy_paving", + "rct2.footpath_surface.ash", + "rct2.footpath_surface.queue_blue", + "rct2.footpath_surface.queue_green", + "rct2.footpath_surface.queue_red", + "rct2.footpath_surface.queue_yellow", + + // Footpath railings + "rct2.footpath_railings.bamboo_black", + "rct2.footpath_railings.bamboo_brown", + "rct2.footpath_railings.concrete", + "rct2.footpath_railings.concrete_green", + "rct2.footpath_railings.space", + "rct2.footpath_railings.wood", }; const std::string_view DesignerSelectedObjects[] = { - // An initial default selection + all standard footpaths - "rct2.scgtrees", // Scenery: Trees - "rct2.scgshrub", // Scenery: Shrubs and Ornaments - "rct2.scggardn", // Scenery: Gardens - "rct2.scgfence", // Scenery: Fences and Walls - "rct2.scgwalls", // Scenery: Walls and Roofs - "rct2.scgpathx", // Scenery: Signs and Items for Footpaths - "rct2.wtrcyan", // Water: Natural Water - "rct2.pkent1", // Park Entrance: Traditional Park Entrance - "rct2.tarmac", // Footpath: Tarmac - "rct2.tarmacg", // Footpath: Green Tarmac Footpath - "rct2.tarmacb", // Footpath: Brown Tarmac Footpath - "rct2.pathspce", // Footpath: Space Style Footpath - "rct2.pathcrzy", // Footpath: Crazy Paving Footpath - "rct2.pathdirt", // Footpath: Dirt Footpath - "rct2.pathash", // Footpath: Ash Footpath + // An initial default selection + all standard footpaths + all standard stations + "rct2.scenery_group.scgtrees", // Scenery: Trees + "rct2.scenery_group.scgshrub", // Scenery: Shrubs and Ornaments + "rct2.scenery_group.scggardn", // Scenery: Gardens + "rct2.scenery_group.scgfence", // Scenery: Fences and Walls + "rct2.scenery_group.scgwalls", // Scenery: Walls and Roofs + "rct2.scenery_group.scgpathx", // Scenery: Signs and Items for Footpaths + "rct2.water.wtrcyan", // Water: Natural Water + "rct2.park_entrance.pkent1", // Park Entrance: Traditional Park Entrance + "rct2.terrain_surface.grass", + "rct2.terrain_edge.rock", + + // Footpath surfaces + "rct2.footpath_surface.tarmac", + "rct2.footpath_surface.tarmac_brown", + "rct2.footpath_surface.tarmac_red", + "rct2.footpath_surface.dirt", + "rct2.footpath_surface.crazy_paving", + "rct2.footpath_surface.ash", + "rct2.footpath_surface.queue_blue", + "rct2.footpath_surface.queue_green", + "rct2.footpath_surface.queue_red", + "rct2.footpath_surface.queue_yellow", + + // Footpath railings + "rct2.footpath_railings.bamboo_black", + "rct2.footpath_railings.bamboo_brown", + "rct2.footpath_railings.concrete", + "rct2.footpath_railings.concrete_green", + "rct2.footpath_railings.space", + "rct2.footpath_railings.wood", + + // Stations + "rct2.station.plain", + "rct2.station.wooden", + "rct2.station.canvas_tent", + "rct2.station.castle_grey", + "rct2.station.castle_brown", + "rct2.station.jungle", + "rct2.station.log", + "rct2.station.classical", + "rct2.station.abstract", + "rct2.station.snow", + "rct2.station.pagoda", + "rct2.station.space", }; + +// clang-format on diff --git a/src/openrct2/object/DefaultObjects.h b/src/openrct2/object/DefaultObjects.h index 6453ecd008..38fc914e6b 100644 --- a/src/openrct2/object/DefaultObjects.h +++ b/src/openrct2/object/DefaultObjects.h @@ -11,5 +11,6 @@ #include "Object.h" -extern const std::string_view DefaultSelectedObjects[33]; -extern const std::string_view DesignerSelectedObjects[15]; +extern const std::string_view MinimumRequiredObjects[2]; +extern const std::string_view DefaultSelectedObjects[103]; +extern const std::string_view DesignerSelectedObjects[38]; diff --git a/src/openrct2/object/FootpathObject.h b/src/openrct2/object/FootpathObject.h index ebe409ae58..dee0e7c0e1 100644 --- a/src/openrct2/object/FootpathObject.h +++ b/src/openrct2/object/FootpathObject.h @@ -26,6 +26,11 @@ public: return &_legacyType; } + const void* GetLegacyData() const + { + return &_legacyType; + } + const PathSurfaceDescriptor& GetPathSurfaceDescriptor() const { return _pathSurfaceDescriptor; diff --git a/src/openrct2/object/FootpathRailingsObject.cpp b/src/openrct2/object/FootpathRailingsObject.cpp index b1045726f1..739f59489b 100644 --- a/src/openrct2/object/FootpathRailingsObject.cpp +++ b/src/openrct2/object/FootpathRailingsObject.cpp @@ -88,6 +88,7 @@ void FootpathRailingsObject::ReadJson(IReadObjectContext* context, json_t& root) { { "hasSupportImages", RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE }, { "hasElevatedPathImages", RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS }, + { "noQueueBanner", RAILING_ENTRY_FLAG_NO_QUEUE_BANNER }, }); } diff --git a/src/openrct2/object/Object.cpp b/src/openrct2/object/Object.cpp index fcf5477b67..1c419bc1a9 100644 --- a/src/openrct2/object/Object.cpp +++ b/src/openrct2/object/Object.cpp @@ -92,10 +92,8 @@ bool ObjectEntryDescriptor::operator==(const ObjectEntryDescriptor& rhs) const { return Entry == rhs.Entry; } - else - { - return Type == rhs.Type && Identifier == rhs.Identifier; - } + + return Type == rhs.Type && Identifier == rhs.Identifier; } bool ObjectEntryDescriptor::operator!=(const ObjectEntryDescriptor& rhs) const @@ -159,12 +157,12 @@ std::string Object::GetString(int32_t language, ObjectStringID index) const ObjectEntryDescriptor Object::GetScgWallsHeader() const { - return ObjectEntryDescriptor("rct2.scgwalls"); + return ObjectEntryDescriptor("rct2.scenery_group.scgwalls"); } ObjectEntryDescriptor Object::GetScgPathXHeader() const { - return ObjectEntryDescriptor("rct2.scgpathx"); + return ObjectEntryDescriptor("rct2.scenery_group.scgpathx"); } rct_object_entry Object::CreateHeader(const char name[DAT_NAME_LENGTH + 1], uint32_t flags, uint32_t checksum) diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index 666ae1555d..be1374529c 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -385,7 +385,6 @@ extern int32_t object_entry_group_counts[]; extern int32_t object_entry_group_encoding[]; int32_t object_calculate_checksum(const rct_object_entry* entry, const void* data, size_t dataLength); -bool find_object_in_entry_group(const rct_object_entry* entry, ObjectType* entry_type, ObjectEntryIndex* entryIndex); void object_create_identifier_name(char* string_buffer, size_t size, const rct_object_entry* object); const rct_object_entry* object_list_find(rct_object_entry* entry); diff --git a/src/openrct2/object/ObjectLimits.h b/src/openrct2/object/ObjectLimits.h index f9ebf6ffd7..9f8094c6d0 100644 --- a/src/openrct2/object/ObjectLimits.h +++ b/src/openrct2/object/ObjectLimits.h @@ -11,18 +11,20 @@ #include -constexpr const uint16_t MAX_RIDE_OBJECTS = 128; -constexpr const uint16_t MAX_SMALL_SCENERY_OBJECTS = 252; -constexpr const uint16_t MAX_LARGE_SCENERY_OBJECTS = 128; -constexpr const uint16_t MAX_WALL_SCENERY_OBJECTS = 128; -constexpr const uint16_t MAX_BANNER_OBJECTS = 32; -constexpr const uint16_t MAX_PATH_OBJECTS = 16; -constexpr const uint16_t MAX_PATH_ADDITION_OBJECTS = 15; -constexpr const uint16_t MAX_SCENERY_GROUP_OBJECTS = 19; +// Maximums based on number of values that can be represented in bit group. +// Subtract 1 to reserve the NULL entry identifier. +constexpr const uint16_t MAX_RIDE_OBJECTS = 2047; +constexpr const uint16_t MAX_SMALL_SCENERY_OBJECTS = 2047; +constexpr const uint16_t MAX_LARGE_SCENERY_OBJECTS = 2047; +constexpr const uint16_t MAX_WALL_SCENERY_OBJECTS = 2047; +constexpr const uint16_t MAX_BANNER_OBJECTS = 255; +constexpr const uint16_t MAX_PATH_OBJECTS = 255; +constexpr const uint16_t MAX_PATH_ADDITION_OBJECTS = 255; +constexpr const uint16_t MAX_SCENERY_GROUP_OBJECTS = 255; constexpr const uint16_t MAX_PARK_ENTRANCE_OBJECTS = 1; constexpr const uint16_t MAX_WATER_OBJECTS = 1; -constexpr const uint16_t MAX_SCENARIO_TEXT_OBJECTS = 1; -constexpr const uint16_t MAX_TERRAIN_SURFACE_OBJECTS = 18; +constexpr const uint16_t MAX_SCENARIO_TEXT_OBJECTS = 0; +constexpr const uint16_t MAX_TERRAIN_SURFACE_OBJECTS = 255; constexpr const uint16_t MAX_TERRAIN_EDGE_OBJECTS = 255; constexpr const uint16_t MAX_STATION_OBJECTS = 255; constexpr const uint16_t MAX_MUSIC_OBJECTS = 255; diff --git a/src/openrct2/object/ObjectList.cpp b/src/openrct2/object/ObjectList.cpp index 9057a36c69..75b1ae5dc4 100644 --- a/src/openrct2/object/ObjectList.cpp +++ b/src/openrct2/object/ObjectList.cpp @@ -199,39 +199,6 @@ void object_create_identifier_name(char* string_buffer, size_t size, const rct_o snprintf(string_buffer, size, "%.8s/%4X%4X", object->name, object->flags, object->checksum); } -/** - * - * rct2: 0x006A9DA2 - * bl = entry_index - * ecx = entry_type - */ -bool find_object_in_entry_group(const rct_object_entry* entry, ObjectType* entry_type, ObjectEntryIndex* entryIndex) -{ - ObjectType objectType = entry->GetType(); - if (objectType >= ObjectType::Count) - { - return false; - } - - auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager(); - auto maxObjects = object_entry_group_counts[EnumValue(objectType)]; - for (int32_t i = 0; i < maxObjects; i++) - { - auto loadedObj = objectMgr.GetLoadedObject(objectType, i); - if (loadedObj != nullptr) - { - auto thisEntry = object_entry_get_object(objectType, i)->GetObjectEntry(); - if (thisEntry == *entry) - { - *entry_type = objectType; - *entryIndex = i; - return true; - } - } - } - return false; -} - void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIndex* outEntryIndex) { uint8_t objectType = EnumValue(ObjectType::Ride); diff --git a/src/openrct2/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index 123b0ceeb6..a72a7cc60d 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -78,7 +78,10 @@ public: if (index >= static_cast(object_entry_group_counts[EnumValue(objectType)])) { #ifdef DEBUG - log_warning("Object index %u exceeds maximum for type %d.", index, objectType); + if (index != OBJECT_ENTRY_INDEX_NULL) + { + log_warning("Object index %u exceeds maximum for type %d.", index, objectType); + } #endif return nullptr; } @@ -127,6 +130,24 @@ public: return result; } + ObjectList GetLoadedObjects() override + { + ObjectList objectList; + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) + { + auto maxObjectsOfType = static_cast(object_entry_group_counts[EnumValue(objectType)]); + for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++) + { + auto obj = GetLoadedObject(objectType, i); + if (obj != nullptr) + { + objectList.SetObject(i, obj->GetDescriptor()); + } + } + } + return objectList; + } + Object* LoadObject(std::string_view identifier) override { const ObjectRepositoryItem* ori = _objectRepository.FindObject(identifier); @@ -153,9 +174,6 @@ public: // Load the required objects LoadObjects(requiredObjects); - // Load defaults. - LoadDefaultObjects(); - // Update indices. UpdateSceneryGroupIndexes(); ResetTypeToRideEntryIndexMap(); @@ -219,10 +237,8 @@ public: size_t numObjects = _objectRepository.GetNumObjects(); for (size_t i = 0; i < numObjects; i++) { - // TODO: remove ObjectGeneration::DAT check when the NSF is here const ObjectRepositoryItem* item = &_objectRepository.GetObjects()[i]; - if (item->LoadedObject != nullptr && IsObjectCustom(item) && item->LoadedObject->GetLegacyData() != nullptr - && item->LoadedObject->GetGeneration() == ObjectGeneration::DAT) + if (item->LoadedObject != nullptr && IsObjectCustom(item) && item->LoadedObject->GetLegacyData() != nullptr) { objects.push_back(item); } @@ -230,99 +246,6 @@ public: return objects; } - void LoadDefaultObjects() override - { - // We currently will load new object types here that apply to all - // loaded RCT1 and RCT2 save files. - - // Surfaces - LoadObject("rct2.surface.grass"); - LoadObject("rct2.surface.sand"); - LoadObject("rct2.surface.dirt"); - LoadObject("rct2.surface.rock"); - LoadObject("rct2.surface.martian"); - LoadObject("rct2.surface.chequerboard"); - LoadObject("rct2.surface.grassclumps"); - LoadObject("rct2.surface.ice"); - LoadObject("rct2.surface.gridred"); - LoadObject("rct2.surface.gridyellow"); - LoadObject("rct2.surface.gridpurple"); - LoadObject("rct2.surface.gridgreen"); - LoadObject("rct2.surface.sandred"); - LoadObject("rct2.surface.sandbrown"); - LoadObject("rct1.aa.surface.roofred"); - LoadObject("rct1.ll.surface.roofgrey"); - LoadObject("rct1.ll.surface.rust"); - LoadObject("rct1.ll.surface.wood"); - - // Edges - LoadObject("rct2.edge.rock"); - LoadObject("rct2.edge.woodred"); - LoadObject("rct2.edge.woodblack"); - LoadObject("rct2.edge.ice"); - LoadObject("rct1.edge.brick"); - LoadObject("rct1.edge.iron"); - LoadObject("rct1.aa.edge.grey"); - LoadObject("rct1.aa.edge.yellow"); - LoadObject("rct1.aa.edge.red"); - LoadObject("rct1.ll.edge.purple"); - LoadObject("rct1.ll.edge.green"); - LoadObject("rct1.ll.edge.stonebrown"); - LoadObject("rct1.ll.edge.stonegrey"); - LoadObject("rct1.ll.edge.skyscrapera"); - LoadObject("rct1.ll.edge.skyscraperb"); - - // Stations - LoadObject("rct2.station.plain"); - LoadObject("rct2.station.wooden"); - LoadObject("rct2.station.canvastent"); - LoadObject("rct2.station.castlegrey"); - LoadObject("rct2.station.castlebrown"); - LoadObject("rct2.station.jungle"); - LoadObject("rct2.station.log"); - LoadObject("rct2.station.classical"); - LoadObject("rct2.station.abstract"); - LoadObject("rct2.station.snow"); - LoadObject("rct2.station.pagoda"); - LoadObject("rct2.station.space"); - LoadObject("openrct2.station.noentrance"); - - // Music - auto baseIndex = GetIndexFromTypeEntry(ObjectType::Music, 0); - LoadObject(baseIndex + MUSIC_STYLE_DODGEMS_BEAT, "rct2.music.dodgems"); - LoadObject(baseIndex + MUSIC_STYLE_FAIRGROUND_ORGAN, "rct2.music.fairground"); - LoadObject(baseIndex + MUSIC_STYLE_ROMAN_FANFARE, "rct2.music.roman"); - LoadObject(baseIndex + MUSIC_STYLE_ORIENTAL, "rct2.music.oriental"); - LoadObject(baseIndex + MUSIC_STYLE_MARTIAN, "rct2.music.martian"); - LoadObject(baseIndex + MUSIC_STYLE_JUNGLE_DRUMS, "rct2.music.jungle"); - LoadObject(baseIndex + MUSIC_STYLE_EGYPTIAN, "rct2.music.egyptian"); - LoadObject(baseIndex + MUSIC_STYLE_TOYLAND, "rct2.music.toyland"); - LoadObject(baseIndex + MUSIC_STYLE_SPACE, "rct2.music.space"); - LoadObject(baseIndex + MUSIC_STYLE_HORROR, "rct2.music.horror"); - LoadObject(baseIndex + MUSIC_STYLE_TECHNO, "rct2.music.techno"); - LoadObject(baseIndex + MUSIC_STYLE_GENTLE, "rct2.music.gentle"); - LoadObject(baseIndex + MUSIC_STYLE_SUMMER, "rct2.music.summer"); - LoadObject(baseIndex + MUSIC_STYLE_WATER, "rct2.music.water"); - LoadObject(baseIndex + MUSIC_STYLE_WILD_WEST, "rct2.music.wildwest"); - LoadObject(baseIndex + MUSIC_STYLE_JURASSIC, "rct2.music.jurassic"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK, "rct2.music.rock1"); - LoadObject(baseIndex + MUSIC_STYLE_RAGTIME, "rct2.music.ragtime"); - LoadObject(baseIndex + MUSIC_STYLE_FANTASY, "rct2.music.fantasy"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_2, "rct2.music.rock2"); - LoadObject(baseIndex + MUSIC_STYLE_ICE, "rct2.music.ice"); - LoadObject(baseIndex + MUSIC_STYLE_SNOW, "rct2.music.snow"); - LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_1, "rct2.music.custom1"); - LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_2, "rct2.music.custom2"); - LoadObject(baseIndex + MUSIC_STYLE_MEDIEVAL, "rct2.music.medieval"); - LoadObject(baseIndex + MUSIC_STYLE_URBAN, "rct2.music.urban"); - LoadObject(baseIndex + MUSIC_STYLE_ORGAN, "rct2.music.organ"); - LoadObject(baseIndex + MUSIC_STYLE_MECHANICAL, "rct2.music.mechanical"); - LoadObject(baseIndex + MUSIC_STYLE_MODERN, "rct2.music.modern"); - LoadObject(baseIndex + MUSIC_STYLE_PIRATES, "rct2.music.pirate"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_3, "rct2.music.rock3"); - LoadObject(baseIndex + MUSIC_STYLE_CANDY_STYLE, "rct2.music.candy"); - } - static rct_string_id GetObjectSourceGameString(const ObjectSourceGame sourceGame) { switch (sourceGame) diff --git a/src/openrct2/object/ObjectManager.h b/src/openrct2/object/ObjectManager.h index e5083bfabc..7fe2d69a89 100644 --- a/src/openrct2/object/ObjectManager.h +++ b/src/openrct2/object/ObjectManager.h @@ -31,12 +31,12 @@ struct IObjectManager virtual ObjectEntryIndex GetLoadedObjectEntryIndex(std::string_view identifier) abstract; virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const ObjectEntryDescriptor& descriptor) abstract; virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const Object* object) abstract; + virtual ObjectList GetLoadedObjects() abstract; virtual Object* LoadObject(std::string_view identifier) abstract; virtual Object* LoadObject(const rct_object_entry* entry) abstract; virtual Object* LoadObject(const ObjectEntryDescriptor& descriptor) abstract; virtual void LoadObjects(const ObjectList& entries) abstract; - virtual void LoadDefaultObjects() abstract; virtual void UnloadObjects(const std::vector& entries) abstract; virtual void UnloadAll() abstract; diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index 4663730a63..f2e218b6fe 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -612,10 +612,8 @@ private: // Convert to UTF-8 filename return String::Convert(normalisedName, CODE_PAGE::CP_1252, CODE_PAGE::CP_UTF8); } - else - { - return std::string(name); - } + + return std::string(name); } void WritePackedObject(OpenRCT2::IStream* stream, const rct_object_entry* entry) diff --git a/src/openrct2/object/SmallSceneryObject.cpp b/src/openrct2/object/SmallSceneryObject.cpp index a52b14a9e0..6ec5727347 100644 --- a/src/openrct2/object/SmallSceneryObject.cpp +++ b/src/openrct2/object/SmallSceneryObject.cpp @@ -207,7 +207,7 @@ void SmallSceneryObject::PerformFixes() ObjectEntryDescriptor SmallSceneryObject::GetScgPiratHeader() const { - return ObjectEntryDescriptor("rct2.scgpirat"); + return ObjectEntryDescriptor("rct2.scenery_group.scgpirat"); } ObjectEntryDescriptor SmallSceneryObject::GetScgMineHeader() const @@ -217,7 +217,7 @@ ObjectEntryDescriptor SmallSceneryObject::GetScgMineHeader() const ObjectEntryDescriptor SmallSceneryObject::GetScgAbstrHeader() const { - return ObjectEntryDescriptor("rct2.scgabstr"); + return ObjectEntryDescriptor("rct2.scenery_group.scgabstr"); } void SmallSceneryObject::ReadJson(IReadObjectContext* context, json_t& root) diff --git a/src/openrct2/object/StationObject.cpp b/src/openrct2/object/StationObject.cpp index 4b88153142..ea1de3bf5f 100644 --- a/src/openrct2/object/StationObject.cpp +++ b/src/openrct2/object/StationObject.cpp @@ -95,6 +95,7 @@ void StationObject::ReadJson(IReadObjectContext* context, json_t& root) { "hasSecondaryColour", STATION_OBJECT_FLAGS::HAS_SECONDARY_COLOUR }, { "isTransparent", STATION_OBJECT_FLAGS::IS_TRANSPARENT }, { "noPlatforms", STATION_OBJECT_FLAGS::NO_PLATFORMS }, + { "hasShelter", STATION_OBJECT_FLAGS::HAS_SHELTER }, }); } diff --git a/src/openrct2/object/StationObject.h b/src/openrct2/object/StationObject.h index 6965a81592..45f4e8350b 100644 --- a/src/openrct2/object/StationObject.h +++ b/src/openrct2/object/StationObject.h @@ -17,6 +17,7 @@ namespace STATION_OBJECT_FLAGS const uint32_t HAS_SECONDARY_COLOUR = 1 << 1; const uint32_t IS_TRANSPARENT = 1 << 2; const uint32_t NO_PLATFORMS = 1 << 3; + const uint32_t HAS_SHELTER = (1 << 4); } // namespace STATION_OBJECT_FLAGS class StationObject final : public Object diff --git a/src/openrct2/paint/tile_element/Paint.Path.cpp b/src/openrct2/paint/tile_element/Paint.Path.cpp index 53a492ddd0..307996a6e9 100644 --- a/src/openrct2/paint/tile_element/Paint.Path.cpp +++ b/src/openrct2/paint/tile_element/Paint.Path.cpp @@ -410,7 +410,7 @@ static void sub_6A4101( } } - if (!pathElement.HasQueueBanner()) + if (!pathElement.HasQueueBanner() || (pathPaintInfo.RailingFlags & RAILING_ENTRY_FLAG_NO_QUEUE_BANNER)) { return; } @@ -487,7 +487,7 @@ static void sub_6A4101( uint32_t drawnCorners = 0; // If the path is not drawn over the supports, then no corner sprites will be drawn (making double-width paths // look like connected series of intersections). - if (pathElement.ShouldDrawPathOverSupports()) + if (pathPaintInfo.RailingFlags & RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS) { drawnCorners = (connectedEdges & FOOTPATH_PROPERTIES_EDGES_CORNERS_MASK) >> 4; } @@ -661,7 +661,7 @@ static void sub_6A4101( * @param pathElement (esp[0]) * @param connectedEdges (bp) (relative to the camera's rotation) * @param height (dx) - * @param railingsDescriptor (0x00F3EF6C) + * @param pathPaintInfo (0x00F3EF6C) * @param imageFlags (0x00F3EF70) * @param sceneryImageFlags (0x00F3EF74) */ @@ -1083,7 +1083,8 @@ void path_paint_box_support( session, image_id | imageFlags, { 0, 0, height }, { boundBoxSize, 0 }, { boundBoxOffset, height + boundingBoxZOffset }); - if (!pathElement.IsQueue() && !pathElement.ShouldDrawPathOverSupports()) + // TODO: Revert this when path import works correctly. + if (!pathElement.IsQueue() && !(pathPaintInfo.RailingFlags & RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS)) { // don't draw } @@ -1223,7 +1224,8 @@ void path_paint_pole_support( session, bridgeImage | imageFlags, { 0, 0, height }, { boundBoxSize, 0 }, { boundBoxOffset, height + boundingBoxZOffset }); - if (pathElement.IsQueue() || pathElement.ShouldDrawPathOverSupports()) + // TODO: Revert this when path import works correctly. + if (pathElement.IsQueue() || (pathPaintInfo.RailingFlags & RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS)) { PaintAddImageAsChild( session, imageId | imageFlags, 0, 0, boundBoxSize.x, boundBoxSize.y, 0, height, boundBoxOffset.x, diff --git a/src/openrct2/paint/tile_element/Paint.TileElement.cpp b/src/openrct2/paint/tile_element/Paint.TileElement.cpp index 8591e590b6..6da3c716c1 100644 --- a/src/openrct2/paint/tile_element/Paint.TileElement.cpp +++ b/src/openrct2/paint/tile_element/Paint.TileElement.cpp @@ -216,6 +216,11 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y) int32_t previousBaseZ = 0; do { + if (tile_element->IsInvisible()) + { + continue; + } + // Only paint tile_elements below the clip height. if ((session->ViewFlags & VIEWPORT_FLAG_CLIP_VIEW) && (tile_element->GetBaseZ() > gClipHeight * COORDS_Z_STEP)) continue; @@ -233,6 +238,11 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y) const TileElement* tile_element_sub_iterator = tile_element; while (!(tile_element_sub_iterator++)->IsLastForTile()) { + if (tile_element->IsInvisible()) + { + continue; + } + if (tile_element_sub_iterator->GetBaseZ() != tile_element->GetBaseZ()) { break; @@ -245,15 +255,6 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y) case TILE_ELEMENT_TYPE_TRACK: session->TrackElementOnSameHeight = tile_element_sub_iterator; break; - case TILE_ELEMENT_TYPE_CORRUPT: - // To preserve regular behaviour, make an element hidden by - // corruption also invisible to this method. - if (tile_element->IsLastForTile()) - { - break; - } - tile_element_sub_iterator++; - break; } } } @@ -287,16 +288,6 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y) case TILE_ELEMENT_TYPE_BANNER: PaintBanner(session, direction, baseZ, *(tile_element->AsBanner())); break; - // A corrupt element inserted by OpenRCT2 itself, which skips the drawing of the next element only. - case TILE_ELEMENT_TYPE_CORRUPT: - if (tile_element->IsLastForTile()) - return; - tile_element++; - break; - default: - // An undefined map element is most likely a corrupt element inserted by 8 cars' MOM feature to skip drawing of - // all elements after it. - return; } session->MapPosition = mapPosition; } while (!(tile_element++)->IsLastForTile()); diff --git a/src/openrct2/peep/Guest.cpp b/src/openrct2/peep/Guest.cpp index 8147b8bb8b..5970e06fb4 100644 --- a/src/openrct2/peep/Guest.cpp +++ b/src/openrct2/peep/Guest.cpp @@ -1475,7 +1475,7 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) if (HasItem(shopItem)) { - InsertNewThought(PeepThoughtType::AlreadyGot, EnumValue(shopItem)); + InsertNewThought(PeepThoughtType::AlreadyGot, shopItem); return false; } @@ -1484,7 +1484,7 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) int32_t food = bitscanforward(GetFoodOrDrinkFlags()); if (food != -1) { - InsertNewThought(PeepThoughtType::HaventFinished, food); + InsertNewThought(PeepThoughtType::HaventFinished, static_cast(food)); return false; } @@ -1533,7 +1533,7 @@ bool Guest::DecideAndBuyItem(Ride* ride, ShopItem shopItem, money32 price) } if (price > CashInPocket) { - InsertNewThought(PeepThoughtType::CantAffordItem, EnumValue(shopItem)); + InsertNewThought(PeepThoughtType::CantAffordItem, shopItem); return false; } } @@ -2326,17 +2326,11 @@ bool Guest::HasRidden(const Ride* ride) const void Guest::SetHasRiddenRideType(int32_t rideType) { - // This is needed to avoid desyncs. TODO: remove once the new save format is introduced. - rideType = OpenRCT2RideTypeToRCT2RideType(rideType); - OpenRCT2::RideUse::GetTypeHistory().Add(sprite_index, rideType); } bool Guest::HasRiddenRideType(int32_t rideType) const { - // This is needed to avoid desyncs. TODO: remove once the new save format is introduced. - rideType = OpenRCT2RideTypeToRCT2RideType(rideType); - return OpenRCT2::RideUse::GetTypeHistory().Contains(sprite_index, rideType); } @@ -2543,7 +2537,7 @@ bool Guest::FindVehicleToEnter(Ride* ride, std::vector& car_array) { chosen_train = ride->stations[CurrentRideStation].TrainAtStation; } - if (chosen_train == RideStation::NO_TRAIN || chosen_train >= MAX_VEHICLES_PER_RIDE) + if (chosen_train >= MAX_VEHICLES_PER_RIDE) { return false; } diff --git a/src/openrct2/peep/Staff.h b/src/openrct2/peep/Staff.h index 8b72ea2a15..9d29fa720c 100644 --- a/src/openrct2/peep/Staff.h +++ b/src/openrct2/peep/Staff.h @@ -15,7 +15,6 @@ class DataSerialiser; -#define STAFF_MAX_COUNT 200 // The number of elements in the gStaffPatrolAreas array per staff member. Every bit in the array represents a 4x4 square. // Right now, it's a 32-bit array like in RCT2. 32 * 128 = 4096 bits, which is also the number of 4x4 squares on a 256x256 map. constexpr size_t STAFF_PATROL_AREA_BLOCKS_PER_LINE = MAXIMUM_MAP_SIZE_TECHNICAL / 4; diff --git a/src/openrct2/platform/Crash.cpp b/src/openrct2/platform/Crash.cpp index 7576ef3719..1ff0fb17b9 100644 --- a/src/openrct2/platform/Crash.cpp +++ b/src/openrct2/platform/Crash.cpp @@ -27,6 +27,7 @@ # include "../Context.h" # include "../Game.h" # include "../OpenRCT2.h" +# include "../ParkFile.h" # include "../PlatformEnvironment.h" # include "../Version.h" # include "../config/Config.h" @@ -37,7 +38,6 @@ # include "../interface/Screenshot.h" # include "../localisation/Language.h" # include "../object/ObjectManager.h" -# include "../rct2/S6Exporter.h" # include "../scenario/Scenario.h" # include "../util/SawyerCoding.h" # include "../util/Util.h" @@ -119,13 +119,11 @@ static bool OnCrash( wchar_t dumpFilePath[MAX_PATH]; wchar_t saveFilePath[MAX_PATH]; wchar_t configFilePath[MAX_PATH]; - wchar_t saveFilePathGZIP[MAX_PATH]; wchar_t recordFilePathNew[MAX_PATH]; swprintf_s(dumpFilePath, std::size(dumpFilePath), L"%s\\%s.dmp", dumpPath, miniDumpId); - swprintf_s(saveFilePath, std::size(saveFilePath), L"%s\\%s.sv6", dumpPath, miniDumpId); + swprintf_s(saveFilePath, std::size(saveFilePath), L"%s\\%s.park", dumpPath, miniDumpId); swprintf_s(configFilePath, std::size(configFilePath), L"%s\\%s.ini", dumpPath, miniDumpId); - swprintf_s(saveFilePathGZIP, std::size(saveFilePathGZIP), L"%s\\%s.sv6.gz", dumpPath, miniDumpId); - swprintf_s(recordFilePathNew, std::size(recordFilePathNew), L"%s\\%s.sv6r", dumpPath, miniDumpId); + swprintf_s(recordFilePathNew, std::size(recordFilePathNew), L"%s\\%s.parkrep", dumpPath, miniDumpId); wchar_t dumpFilePathNew[MAX_PATH]; swprintf_s( @@ -177,7 +175,7 @@ static bool OnCrash( auto saveFilePathUTF8 = String::ToUtf8(saveFilePath); try { - auto exporter = std::make_unique(); + auto exporter = std::make_unique(); // Make sure the save is using the current viewport settings. viewport_set_saved_view(); @@ -190,8 +188,7 @@ static bool OnCrash( auto& objManager = ctx->GetObjectManager(); exporter->ExportObjectsList = objManager.GetPackableObjects(); - exporter->Export(); - exporter->SaveGame(saveFilePathUTF8.c_str()); + exporter->Export(saveFilePathUTF8.c_str()); savedGameDumped = true; } catch (const std::exception&) @@ -201,19 +198,7 @@ static bool OnCrash( // Compress the save if (savedGameDumped) { - FILE* input = _wfopen(saveFilePath, L"rb"); - FILE* dest = _wfopen(saveFilePathGZIP, L"wb"); - - if (util_gzip_compress(input, dest)) - { - uploadFiles[L"attachment_park.sv6.gz"] = saveFilePathGZIP; - } - else - { - uploadFiles[L"attachment_park.sv6"] = saveFilePath; - } - fclose(input); - fclose(dest); + uploadFiles[L"attachment_park.park"] = saveFilePath; } auto configFilePathUTF8 = String::ToUtf8(configFilePath); @@ -231,11 +216,11 @@ static bool OnCrash( if (with_record) { - auto sv6rPathW = String::ToWideChar(gSilentRecordingName); - bool record_copied = CopyFileW(sv6rPathW.c_str(), recordFilePathNew, true); + auto parkReplayPathW = String::ToWideChar(gSilentRecordingName); + bool record_copied = CopyFileW(parkReplayPathW.c_str(), recordFilePathNew, true); if (record_copied) { - uploadFiles[L"attachment_replay.sv6r"] = recordFilePathNew; + uploadFiles[L"attachment_replay.parkrep"] = recordFilePathNew; } else { @@ -299,7 +284,6 @@ static bool OnCrash( if (savedGameDumped) { files[numFiles++] = ILCreateFromPathW(saveFilePath); - files[numFiles++] = ILCreateFromPathW(saveFilePathGZIP); } if (with_record) { diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 9b98292fe7..6f6bc9d4b1 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -81,7 +81,7 @@ namespace RCT1 class EntryList { private: - std::vector _entries; + std::vector _entries; public: size_t GetCount() const @@ -89,20 +89,22 @@ namespace RCT1 return _entries.size(); } - const std::vector& GetEntries() const + const std::vector& GetEntries() const { return _entries; } - ObjectEntryIndex GetOrAddEntry(const char* entryName) + ObjectEntryIndex GetOrAddEntry(std::string_view identifier) { - auto entryIndex = Collections::IndexOf(_entries, entryName, true); - if (entryIndex == SIZE_MAX) + for (size_t i = 0; i < _entries.size(); i++) { - entryIndex = _entries.size(); - _entries.push_back(entryName); + if (_entries[i] == identifier) + { + return static_cast(i); + } } - return static_cast(entryIndex); + _entries.emplace_back(identifier); + return static_cast(_entries.size() - 1); } void AddRange(std::initializer_list initializerList) @@ -132,6 +134,10 @@ namespace RCT1 EntryList _pathAdditionEntries; EntryList _sceneryGroupEntries; EntryList _waterEntry; + EntryList _terrainSurfaceEntries; + EntryList _terrainEdgeEntries; + EntryList _footpathSurfaceEntries; + EntryList _footpathRailingsEntries; // Lookup tables for converting from RCT1 hard coded types to the new dynamic object entries ObjectEntryIndex _rideTypeToRideEntryMap[EnumValue(RideType::Count)]{}; @@ -142,6 +148,10 @@ namespace RCT1 ObjectEntryIndex _pathTypeToEntryMap[24]{}; ObjectEntryIndex _pathAdditionTypeToEntryMap[16]{}; ObjectEntryIndex _sceneryThemeTypeToEntryMap[24]{}; + ObjectEntryIndex _terrainSurfaceTypeToEntryMap[16]{}; + ObjectEntryIndex _terrainEdgeTypeToEntryMap[16]{}; + ObjectEntryIndex _footpathSurfaceTypeToEntryMap[32]{}; + ObjectEntryIndex _footpathRailingsTypeToEntryMap[4]{}; // Research std::bitset _researchRideEntryUsed{}; @@ -199,7 +209,6 @@ namespace RCT1 Initialise(); CreateAvailableObjectMappings(); - LoadObjects(); ImportRides(); ImportRideMeasurements(); @@ -222,6 +231,10 @@ namespace RCT1 map_count_remaining_land_rights(); research_determine_first_of_type(); + + CheatsReset(); + ClearRestrictedScenery(); + RestrictAllMiscScenery(); } bool GetDetails(scenario_index_entry* dst) override @@ -343,11 +356,10 @@ namespace RCT1 uint16_t mapSize = _s4.map_size == 0 ? RCT1_MAX_MAP_SIZE : _s4.map_size; - String::Set(gScenarioFileName, sizeof(gScenarioFileName), GetRCT1ScenarioName().c_str()); + gScenarioFileName = GetRCT1ScenarioName(); // Do map initialisation, same kind of stuff done when loading scenario editor auto context = OpenRCT2::GetContext(); - context->GetObjectManager().UnloadAll(); context->GetGameState()->InitAll(mapSize); gEditorStep = EditorStep::ObjectSelection; gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; @@ -375,6 +387,14 @@ namespace RCT1 std::fill(std::begin(_pathTypeToEntryMap), std::end(_pathTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); std::fill(std::begin(_pathAdditionTypeToEntryMap), std::end(_pathAdditionTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); std::fill(std::begin(_sceneryThemeTypeToEntryMap), std::end(_sceneryThemeTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); + std::fill( + std::begin(_terrainSurfaceTypeToEntryMap), std::end(_terrainSurfaceTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); + std::fill(std::begin(_terrainEdgeTypeToEntryMap), std::end(_terrainEdgeTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); + std::fill( + std::begin(_footpathSurfaceTypeToEntryMap), std::end(_footpathSurfaceTypeToEntryMap), OBJECT_ENTRY_INDEX_NULL); + std::fill( + std::begin(_footpathRailingsTypeToEntryMap), std::end(_footpathRailingsTypeToEntryMap), + OBJECT_ENTRY_INDEX_NULL); } /** @@ -395,25 +415,42 @@ namespace RCT1 { // Add default scenery groups _sceneryGroupEntries.AddRange({ - "SCGTREES", - "SCGSHRUB", - "SCGGARDN", - "SCGFENCE", - "SCGWALLS", - "SCGPATHX", + "rct2.scenery_group.scgtrees", + "rct2.scenery_group.scgshrub", + "rct2.scenery_group.scggardn", + "rct2.scenery_group.scgfence", + "rct2.scenery_group.scgwalls", + "rct2.scenery_group.scgpathx", }); // Add default footpaths - _pathEntries.AddRange({ - "TARMAC ", - "TARMACG ", - "TARMACB ", - "PATHCRZY", - "PATHSPCE", - "PATHDIRT", - "PATHASH ", - "ROAD ", - }); + _footpathSurfaceEntries.AddRange( + { "rct1.footpath_surface.tarmac", "rct1.footpath_surface.dirt", "rct1.footpath_surface.crazy_paving", + "rct1.footpath_surface.tiles_brown", "rct1aa.footpath_surface.ash", "rct1aa.footpath_surface.tarmac_green", + "rct1aa.footpath_surface.tarmac_brown", "rct1aa.footpath_surface.tiles_grey", + "rct1aa.footpath_surface.tarmac_red", "rct1ll.footpath_surface.tiles_green", + "rct1ll.footpath_surface.tiles_red", "rct1.footpath_surface.queue_blue", "rct1aa.footpath_surface.queue_red", + "rct1aa.footpath_surface.queue_yellow", "rct1aa.footpath_surface.queue_green" }); + + _footpathRailingsEntries.AddRange({ "rct2.footpath_railings.wood", "rct1ll.footpath_railings.space", + "rct1ll.footpath_railings.bamboo", "rct2.footpath_railings.concrete" }); + + // Add default surfaces + _terrainSurfaceEntries.AddRange( + { "rct2.terrain_surface.grass", "rct2.terrain_surface.sand", "rct2.terrain_surface.dirt", + "rct2.terrain_surface.rock", "rct2.terrain_surface.martian", "rct2.terrain_surface.chequerboard", + "rct2.terrain_surface.grass_clumps", "rct2.terrain_surface.ice", "rct2.terrain_surface.grid_red", + "rct2.terrain_surface.grid_yellow", "rct2.terrain_surface.grid_purple", "rct2.terrain_surface.grid_green", + "rct2.terrain_surface.sand_red", "rct2.terrain_surface.sand_brown", "rct1aa.terrain_surface.roof_red", + "rct1ll.terrain_surface.roof_grey", "rct1ll.terrain_surface.rust", "rct1ll.terrain_surface.wood" }); + + // Add default edges + _terrainEdgeEntries.AddRange({ "rct2.terrain_edge.rock", "rct2.terrain_edge.wood_red", + "rct2.terrain_edge.wood_black", "rct2.terrain_edge.ice", "rct1.terrain_edge.brick", + "rct1.terrain_edge.iron", "rct1aa.terrain_edge.grey", "rct1aa.terrain_edge.yellow", + "rct1aa.terrain_edge.red", "rct1ll.terrain_edge.purple", "rct1ll.terrain_edge.green", + "rct1ll.terrain_edge.stone_brown", "rct1ll.terrain_edge.stone_grey", + "rct1ll.terrain_edge.skyscraper_a", "rct1ll.terrain_edge.skyscraper_b" }); } void AddAvailableEntriesFromResearchList() @@ -469,13 +506,28 @@ namespace RCT1 { switch (tileElement->GetType()) { + case TILE_ELEMENT_TYPE_SURFACE: + { + auto surfaceEl = tileElement->AsSurface(); + auto surfaceStyle = surfaceEl->GetSurfaceStyle(); + auto edgeStyle = surfaceEl->GetEdgeStyle(); + AddEntryForTerrainSurface(surfaceStyle); + AddEntryForTerrainEdge(edgeStyle); + break; + } case TILE_ELEMENT_TYPE_PATH: { uint8_t pathType = tileElement->AsPath()->GetRCT1PathType(); uint8_t pathAdditionsType = tileElement->AsPath()->GetAddition(); + uint8_t footpathRailingsType = RCT1_PATH_SUPPORT_TYPE_TRUSS; + if (_gameVersion == FILE_VERSION_RCT1_LL) + { + footpathRailingsType = tileElement->AsPath()->GetRCT1SupportType(); + } - AddEntryForPath(pathType); AddEntryForPathAddition(pathAdditionsType); + AddEntryForPathSurface(pathType); + AddEntryForFootpathRailings(footpathRailingsType); break; } case TILE_ELEMENT_TYPE_SMALL_SCENERY: @@ -528,14 +580,14 @@ namespace RCT1 if (sceneryTheme != 0 && _sceneryThemeTypeToEntryMap[sceneryTheme] == OBJECT_ENTRY_INDEX_NULL) continue; - std::vector objects = RCT1::GetSceneryObjects(sceneryTheme); - for (const char* objectName : objects) + auto objects = RCT1::GetSceneryObjects(sceneryTheme); + for (auto objectName : objects) { auto& objectRepository = OpenRCT2::GetContext()->GetObjectRepository(); - auto foundObject = objectRepository.FindObjectLegacy(objectName); + auto foundObject = objectRepository.FindObject(objectName); if (foundObject != nullptr) { - ObjectType objectType = foundObject->ObjectEntry.GetType(); + auto objectType = foundObject->Type; switch (objectType) { case ObjectType::SmallScenery: @@ -559,14 +611,17 @@ namespace RCT1 break; } } + else + { + log_error("Cannot find object %s", objectName); + } } } } void AddEntryForWater() { - const char* entryName; - + std::string_view entryName; if (_gameVersion < FILE_VERSION_RCT1_LL) { entryName = RCT1::GetWaterObject(RCT1_WATER_CYAN); @@ -575,7 +630,6 @@ namespace RCT1 { entryName = RCT1::GetWaterObject(_s4.water_colour); } - _waterEntry.GetOrAddEntry(entryName); } @@ -585,8 +639,8 @@ namespace RCT1 if (_rideTypeToRideEntryMap[EnumValue(rideType)] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetRideTypeObject(rideType); - if (!String::Equals(entryName, " ")) + auto entryName = RCT1::GetRideTypeObject(rideType); + if (!entryName.empty()) { auto entryIndex = _rideEntries.GetOrAddEntry(entryName); _rideTypeToRideEntryMap[EnumValue(rideType)] = entryIndex; @@ -600,8 +654,8 @@ namespace RCT1 if (_vehicleTypeToRideEntryMap[vehicleType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetVehicleObject(vehicleType); - if (!String::Equals(entryName, " ")) + auto entryName = RCT1::GetVehicleObject(vehicleType); + if (!entryName.empty()) { auto entryIndex = _rideEntries.GetOrAddEntry(entryName); _vehicleTypeToRideEntryMap[vehicleType] = entryIndex; @@ -617,7 +671,7 @@ namespace RCT1 assert(smallSceneryType < std::size(_smallSceneryTypeToEntryMap)); if (_smallSceneryTypeToEntryMap[smallSceneryType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetSmallSceneryObject(smallSceneryType); + auto entryName = RCT1::GetSmallSceneryObject(smallSceneryType); auto entryIndex = _smallSceneryEntries.GetOrAddEntry(entryName); _smallSceneryTypeToEntryMap[smallSceneryType] = entryIndex; @@ -629,7 +683,7 @@ namespace RCT1 assert(largeSceneryType < std::size(_largeSceneryTypeToEntryMap)); if (_largeSceneryTypeToEntryMap[largeSceneryType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetLargeSceneryObject(largeSceneryType); + auto entryName = RCT1::GetLargeSceneryObject(largeSceneryType); auto entryIndex = _largeSceneryEntries.GetOrAddEntry(entryName); _largeSceneryTypeToEntryMap[largeSceneryType] = entryIndex; @@ -641,23 +695,23 @@ namespace RCT1 assert(wallType < std::size(_wallTypeToEntryMap)); if (_wallTypeToEntryMap[wallType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetWallObject(wallType); + auto entryName = RCT1::GetWallObject(wallType); auto entryIndex = _wallEntries.GetOrAddEntry(entryName); _wallTypeToEntryMap[wallType] = entryIndex; } } - void AddEntryForPath(ObjectEntryIndex pathType) + void AddEntryForPathSurface(ObjectEntryIndex pathType) { - assert(pathType < std::size(_pathTypeToEntryMap)); - if (_pathTypeToEntryMap[pathType] == OBJECT_ENTRY_INDEX_NULL) + assert(pathType < std::size(_footpathSurfaceTypeToEntryMap)); + if (_footpathSurfaceTypeToEntryMap[pathType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetPathObject(pathType); - if (!String::Equals(entryName, " ")) + auto identifier = RCT1::GetPathSurfaceObject(pathType); + if (!identifier.empty()) { - auto entryIndex = _pathEntries.GetOrAddEntry(entryName); - _pathTypeToEntryMap[pathType] = entryIndex; + auto entryIndex = _footpathSurfaceEntries.GetOrAddEntry(identifier); + _footpathSurfaceTypeToEntryMap[pathType] = entryIndex; } } } @@ -672,7 +726,7 @@ namespace RCT1 uint8_t normalisedPathAdditionType = RCT1::NormalisePathAddition(pathAdditionType); if (_pathAdditionTypeToEntryMap[normalisedPathAdditionType] == OBJECT_ENTRY_INDEX_NULL) { - const char* entryName = RCT1::GetPathAddtionObject(normalisedPathAdditionType); + auto entryName = RCT1::GetPathAddtionObject(normalisedPathAdditionType); auto entryIndex = _pathAdditionEntries.GetOrAddEntry(entryName); _pathAdditionTypeToEntryMap[normalisedPathAdditionType] = entryIndex; @@ -691,7 +745,7 @@ namespace RCT1 } else { - const char* entryName = RCT1::GetSceneryGroupObject(sceneryThemeType); + auto entryName = RCT1::GetSceneryGroupObject(sceneryThemeType); if (_sceneryGroupEntries.GetCount() >= MAX_SCENERY_GROUP_OBJECTS) { Console::WriteLine("Warning: More than %d (max scenery groups) in RCT1 park.", MAX_SCENERY_GROUP_OBJECTS); @@ -705,6 +759,48 @@ namespace RCT1 } } + void AddEntryForTerrainSurface(ObjectEntryIndex terrainSurfaceType) + { + assert(terrainSurfaceType < std::size(_terrainSurfaceTypeToEntryMap)); + if (_terrainSurfaceTypeToEntryMap[terrainSurfaceType] == OBJECT_ENTRY_INDEX_NULL) + { + auto identifier = RCT1::GetTerrainSurfaceObject(terrainSurfaceType); + if (!identifier.empty()) + { + auto entryIndex = _terrainSurfaceEntries.GetOrAddEntry(identifier); + _terrainSurfaceTypeToEntryMap[terrainSurfaceType] = entryIndex; + } + } + } + + void AddEntryForTerrainEdge(ObjectEntryIndex terrainEdgeType) + { + assert(terrainEdgeType < std::size(_terrainEdgeTypeToEntryMap)); + if (_terrainEdgeTypeToEntryMap[terrainEdgeType] == OBJECT_ENTRY_INDEX_NULL) + { + auto identifier = RCT1::GetTerrainEdgeObject(terrainEdgeType); + if (!identifier.empty()) + { + auto entryIndex = _terrainEdgeEntries.GetOrAddEntry(identifier); + _terrainEdgeTypeToEntryMap[terrainEdgeType] = entryIndex; + } + } + } + + void AddEntryForFootpathRailings(ObjectEntryIndex railingsType) + { + assert(railingsType < std::size(_footpathRailingsTypeToEntryMap)); + if (_footpathRailingsTypeToEntryMap[railingsType] == OBJECT_ENTRY_INDEX_NULL) + { + auto identifier = RCT1::GetFootpathRailingsObject(railingsType); + if (!identifier.empty()) + { + auto entryIndex = _footpathRailingsEntries.GetOrAddEntry(identifier); + _footpathRailingsTypeToEntryMap[railingsType] = entryIndex; + } + } + } + void ImportRides() { for (int32_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) @@ -1020,8 +1116,20 @@ namespace RCT1 dst->track_colour[i].additional = RCT1::GetColour(src->track_colour_additional[i]); dst->track_colour[i].supports = RCT1::GetColour(src->track_colour_supports[i]); } + } + + dst->entrance_style = OBJECT_ENTRY_INDEX_NULL; + if (dst->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_ENTRANCE_EXIT)) + { // Entrance styles were introduced with AA. They correspond directly with those in RCT2. - dst->entrance_style = src->entrance_style; + if (_gameVersion == FILE_VERSION_RCT1) + { + dst->entrance_style = 0; // plain entrance + } + else + { + dst->entrance_style = src->entrance_style; + } } if (_gameVersion < FILE_VERSION_RCT1_LL && dst->type == RIDE_TYPE_MERRY_GO_ROUND) @@ -1130,7 +1238,6 @@ namespace RCT1 { ImportEntity(_s4.sprites[i].unknown); } - FixImportStaff(); } void SetVehicleColours(::Vehicle* dst, const RCT1::Vehicle* src) @@ -1375,83 +1482,24 @@ namespace RCT1 } } - void LoadObjects() + void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const EntryList& entryList) { - auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); - objectManager.LoadDefaultObjects(); - - LoadObjects(ObjectType::Ride, _rideEntries); - LoadObjects(ObjectType::SmallScenery, _smallSceneryEntries); - LoadObjects(ObjectType::LargeScenery, _largeSceneryEntries); - LoadObjects(ObjectType::Walls, _wallEntries); - LoadObjects(ObjectType::Paths, _pathEntries); - LoadObjects(ObjectType::PathBits, _pathAdditionEntries); - LoadObjects(ObjectType::SceneryGroup, _sceneryGroupEntries); - LoadObjects( - ObjectType::Banners, - std::vector({ - "BN1 ", - "BN2 ", - "BN3 ", - "BN4 ", - "BN5 ", - "BN6 ", - "BN7 ", - "BN8 ", - "BN9 ", - })); - LoadObjects(ObjectType::ParkEntrance, std::vector({ "PKENT1 " })); - LoadObjects(ObjectType::Water, _waterEntry); + AppendRequiredObjects(objectList, objectType, entryList.GetEntries()); } - void LoadObjects(ObjectType objectType, const EntryList& entries) + void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const std::vector& objectNames) { - LoadObjects(objectType, entries.GetEntries()); - } - - void LoadObjects(ObjectType objectType, const std::vector& entries) - { - auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); - - uint32_t entryIndex = 0; - for (const char* objectName : entries) + for (const auto& objectName : objectNames) { - rct_object_entry entry; - entry.flags = 0x00008000 + EnumValue(objectType); - std::copy_n(objectName, 8, entry.name); - entry.checksum = 0; - - Object* object = objectManager.LoadObject(&entry); - if (object == nullptr && objectType != ObjectType::SceneryGroup) - { - log_error("Failed to load %s.", objectName); - throw std::runtime_error("Failed to load object."); - } - - entryIndex++; - } - } - - void AppendRequiredObjects(std::vector& entries, ObjectType objectType, const EntryList& entryList) - { - AppendRequiredObjects(entries, objectType, entryList.GetEntries()); - } - - void AppendRequiredObjects( - std::vector& entries, ObjectType objectType, const std::vector& objectNames) - { - for (const auto objectName : objectNames) - { - rct_object_entry entry{}; - entry.flags = ((static_cast(ObjectSourceGame::RCT2) << 4) & 0xF0) | (EnumValue(objectType) & 0x0F); - entry.SetName(objectName); - entries.push_back(entry); + auto descriptor = ObjectEntryDescriptor(objectName); + descriptor.Type = objectType; + objectList.Add(descriptor); } } ObjectList GetRequiredObjects() { - std::vector result; + ObjectList result; AppendRequiredObjects(result, ObjectType::Ride, _rideEntries); AppendRequiredObjects(result, ObjectType::SmallScenery, _smallSceneryEntries); AppendRequiredObjects(result, ObjectType::LargeScenery, _largeSceneryEntries); @@ -1461,27 +1509,25 @@ namespace RCT1 AppendRequiredObjects(result, ObjectType::SceneryGroup, _sceneryGroupEntries); AppendRequiredObjects( result, ObjectType::Banners, - std::vector({ - "BN1 ", - "BN2 ", - "BN3 ", - "BN4 ", - "BN5 ", - "BN6 ", - "BN7 ", - "BN8 ", - "BN9 ", + std::vector({ + "rct2.footpath_banner.bn1", + "rct2.footpath_banner.bn2", + "rct2.footpath_banner.bn3", + "rct2.footpath_banner.bn4", + "rct2.footpath_banner.bn5", + "rct2.footpath_banner.bn6", + "rct2.footpath_banner.bn7", + "rct2.footpath_banner.bn8", + "rct2.footpath_banner.bn9", })); - AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector({ "PKENT1 " })); + AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector({ "rct2.park_entrance.pkent1" })); AppendRequiredObjects(result, ObjectType::Water, _waterEntry); - - ObjectList objectList; - for (rct_object_entry entry : result) - { - objectList.Add(ObjectEntryDescriptor(entry)); - } - - return objectList; + AppendRequiredObjects(result, ObjectType::TerrainSurface, _terrainSurfaceEntries); + AppendRequiredObjects(result, ObjectType::TerrainEdge, _terrainEdgeEntries); + AppendRequiredObjects(result, ObjectType::FootpathSurface, _footpathSurfaceEntries); + AppendRequiredObjects(result, ObjectType::FootpathRailings, _footpathRailingsEntries); + RCT12AddDefaultObjects(result); + return result; } void ImportTileElements() @@ -1555,9 +1601,12 @@ namespace RCT1 auto dst2 = dst->AsSurface(); auto src2 = src->AsSurface(); + auto surfaceStyle = _terrainSurfaceTypeToEntryMap[src2->GetSurfaceStyle()]; + auto edgeStyle = _terrainEdgeTypeToEntryMap[src2->GetEdgeStyle()]; + dst2->SetSlope(src2->GetSlope()); - dst2->SetSurfaceStyle(RCT1::GetTerrain(src2->GetSurfaceStyle())); - dst2->SetEdgeStyle(RCT1::GetTerrainEdge(src2->GetEdgeStyle())); + dst2->SetSurfaceStyle(surfaceStyle); + dst2->SetEdgeStyle(edgeStyle); dst2->SetGrassLength(src2->GetGrassLength()); dst2->SetOwnership(src2->GetOwnership()); dst2->SetParkFences(src2->GetParkFences()); @@ -1586,7 +1635,7 @@ namespace RCT1 // Type uint8_t pathType = src2->GetRCT1PathType(); - auto entryIndex = _pathTypeToEntryMap[pathType]; + auto entryIndex = _footpathSurfaceTypeToEntryMap[pathType]; dst2->SetDirection(0); dst2->SetIsBroken(false); @@ -1598,7 +1647,14 @@ namespace RCT1 { dst2->SetIsQueue(true); } - // TODO: Set railings type + + uint8_t railingsType = RCT1_PATH_SUPPORT_TYPE_TRUSS; + if (_gameVersion == FILE_VERSION_RCT1_LL) + { + railingsType = src2->GetRCT1SupportType(); + } + auto railingsEntryIndex = _footpathRailingsTypeToEntryMap[railingsType]; + dst2->SetRailingsEntryIndex(railingsEntryIndex); // Additions ObjectEntryIndex additionType = dst2->GetAddition(); @@ -1713,8 +1769,8 @@ namespace RCT1 { pathType = RCT1_FOOTPATH_TYPE_TARMAC_GREY; } - auto entryIndex = _pathTypeToEntryMap[pathType]; - dst2->SetLegacyPathEntryIndex(entryIndex & 0x7F); + auto entryIndex = _footpathSurfaceTypeToEntryMap[pathType]; + dst2->SetSurfaceEntryIndex(entryIndex); } return 1; @@ -2112,9 +2168,13 @@ namespace RCT1 } // Number of guests history - for (size_t i = 0; i < 32; i++) + std::fill(std::begin(gGuestsInParkHistory), std::end(gGuestsInParkHistory), std::numeric_limits::max()); + for (size_t i = 0; i < std::size(_s4.guests_in_park_history); i++) { - gGuestsInParkHistory[i] = _s4.guests_in_park_history[i]; + if (_s4.guests_in_park_history[i] != std::numeric_limits::max()) + { + gGuestsInParkHistory[i] = _s4.guests_in_park_history[i] * 20; + } } // News items @@ -2343,7 +2403,10 @@ namespace RCT1 void ImportBanner(Banner* dst, const RCT12Banner* src) { + auto id = dst->id; + *dst = {}; + dst->id = id; dst->type = RCTEntryIndexToOpenRCT2EntryIndex(src->type); dst->flags = 0; diff --git a/src/openrct2/rct1/T4Importer.cpp b/src/openrct2/rct1/T4Importer.cpp index ba7b2fba32..0863558b2d 100644 --- a/src/openrct2/rct1/T4Importer.cpp +++ b/src/openrct2/rct1/T4Importer.cpp @@ -144,19 +144,16 @@ namespace RCT1 } // Convert RCT1 vehicle type to RCT2 vehicle type. Initialise with a string consisting of 8 spaces. - rct_object_entry vehicleObject = { 0x80, " " }; + std::string_view vehicleObject; if (td4Base.type == RideType::HedgeMaze) { - const char* vehObjName = RCT1::GetRideTypeObject(td4Base.type); - assert(vehObjName != nullptr); - std::memcpy(vehicleObject.name, vehObjName, std::min(String::SizeOf(vehObjName), static_cast(8))); + vehicleObject = RCT1::GetRideTypeObject(td4Base.type); } else { - const char* vehObjName = RCT1::GetVehicleObject(td4Base.vehicle_type); - assert(vehObjName != nullptr); - std::memcpy(vehicleObject.name, vehObjName, std::min(String::SizeOf(vehObjName), static_cast(8))); + vehicleObject = RCT1::GetVehicleObject(td4Base.vehicle_type); } + assert(!vehicleObject.empty()); td->vehicle_object = ObjectEntryDescriptor(vehicleObject); td->vehicle_type = td4Base.vehicle_type; diff --git a/src/openrct2/rct1/Tables.cpp b/src/openrct2/rct1/Tables.cpp index 2db463a495..7bdf9b1936 100644 --- a/src/openrct2/rct1/Tables.cpp +++ b/src/openrct2/rct1/Tables.cpp @@ -116,63 +116,51 @@ namespace RCT1 return map[rct1SpriteType]; } - ObjectEntryIndex GetTerrain(uint8_t terrainSurface) + std::string_view GetTerrainSurfaceObject(uint8_t terrainSurface) { static constexpr std::string_view map[RCT1_NUM_TERRAIN_SURFACES] = { - "rct2.surface.grass", - "rct2.surface.sand", - "rct2.surface.dirt", - "rct2.surface.rock", - "rct2.surface.martian", - "rct2.surface.chequerboard", - "rct2.surface.grassclumps", - "rct1.aa.surface.roofred", - "rct2.surface.ice", - "rct1.ll.surface.wood", - "rct1.ll.surface.rust", - "rct1.ll.surface.roofgrey", - "rct2.surface.gridred", - "rct2.surface.gridyellow", - "rct2.surface.gridpurple", - "rct2.surface.gridgreen", + "rct2.terrain_surface.grass", + "rct2.terrain_surface.sand", + "rct2.terrain_surface.dirt", + "rct2.terrain_surface.rock", + "rct2.terrain_surface.martian", + "rct2.terrain_surface.chequerboard", + "rct2.terrain_surface.grass_clumps", + "rct1aa.terrain_surface.roof_red", + "rct2.terrain_surface.ice", + "rct1ll.terrain_surface.wood", + "rct1ll.terrain_surface.rust", + "rct1ll.terrain_surface.roof_grey", + "rct2.terrain_surface.grid_red", + "rct2.terrain_surface.grid_yellow", + "rct2.terrain_surface.grid_purple", + "rct2.terrain_surface.grid_green", }; - std::string selectedSurface = "rct2.surface.grass"; - if (terrainSurface < std::size(map)) - { - selectedSurface = map[terrainSurface]; - } - - return object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(selectedSurface)); + return terrainSurface < std::size(map) ? map[terrainSurface] : map[0]; } - ObjectEntryIndex GetTerrainEdge(uint8_t terrainEdge) + std::string_view GetTerrainEdgeObject(uint8_t terrainEdge) { static constexpr std::string_view map[RCT1_NUM_TERRAIN_EDGES] = { - "rct2.edge.rock", - "rct1.edge.brick", - "rct1.edge.iron", - "rct2.edge.woodred", - "rct1.aa.edge.grey", - "rct1.aa.edge.yellow", - "rct2.edge.woodblack", - "rct1.aa.edge.red", - "rct2.edge.ice", - "rct1.ll.edge.purple", - "rct1.ll.edge.green", - "rct1.ll.edge.stonebrown", - "rct1.ll.edge.stonegrey", - "rct1.ll.edge.skyscrapera", - "rct1.ll.edge.skyscraperb", + "rct2.terrain_edge.rock", + "rct1.terrain_edge.brick", + "rct1.terrain_edge.iron", + "rct2.terrain_edge.wood_red", + "rct1aa.terrain_edge.grey", + "rct1aa.terrain_edge.yellow", + "rct2.terrain_edge.wood_black", + "rct1aa.terrain_edge.red", + "rct2.terrain_edge.ice", + "rct1ll.terrain_edge.purple", + "rct1ll.terrain_edge.green", + "rct1ll.terrain_edge.stone_brown", + "rct1ll.terrain_edge.stone_grey", + "rct1ll.terrain_edge.skyscraper_a", + "rct1ll.terrain_edge.skyscraper_b", }; - std::string selectedEdge = "rct2.edge.rock"; - if (terrainEdge < std::size(map)) - { - selectedEdge = map[terrainEdge]; - } - - return object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(selectedEdge)); + return terrainEdge < std::size(map) ? map[terrainEdge] : map[0]; } uint8_t GetRideType(RideType rideType, uint8_t vehicleType) @@ -698,95 +686,95 @@ namespace RCT1 return map[vehicleSubEntry]; } - const char * GetRideTypeObject(RideType rideType) + std::string_view GetRideTypeObject(RideType rideType) { static constexpr const char * map[] = { - "PTCT1 ", // RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER - "TOGST ", // RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER - "ARRSW1 ", // RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER - "NEMT ", // RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER - "ZLDB ", // RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER - "NRL ", // RCT1_RIDE_TYPE_MINIATURE_RAILWAY - "MONO2 ", // RCT1_RIDE_TYPE_MONORAIL - "BATFL ", // RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER - "RBOAT ", // RCT1_RIDE_TYPE_BOAT_HIRE - "WMOUSE ", // RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER - "STEEP1 ", // RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER - "SPCAR ", // RCT1_RIDE_TYPE_CAR_RIDE - "SSC1 ", // RCT1_RIDE_TYPE_LAUNCHED_FREEFALL - "BOB1 ", // RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER - "OBS1 ", // RCT1_RIDE_TYPE_OBSERVATION_TOWER - "SCHT1 ", // RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER - "DING1 ", // RCT1_RIDE_TYPE_WATER_SLIDE - "AMT1 ", // RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER - "CLIFT1 ", // RCT1_RIDE_TYPE_CHAIRLIFT - "ARRT1 ", // RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER - "HMAZE ", // RCT1_RIDE_TYPE_HEDGE_MAZE - "HSKELT ", // RCT1_RIDE_TYPE_SPIRAL_SLIDE - "KART1 ", // RCT1_RIDE_TYPE_GO_KARTS - "LFB1 ", // RCT1_RIDE_TYPE_LOG_FLUME - "RAPBOAT ", // RCT1_RIDE_TYPE_RIVER_RAPIDS - "DODG1 ", // RCT1_RIDE_TYPE_DODGEMS - "SWSH1 ", // RCT1_RIDE_TYPE_SWINGING_SHIP - "SWSH2 ", // RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP - "ICECR1 ", // RCT1_RIDE_TYPE_ICE_CREAM_STALL - "CHPSH ", // RCT1_RIDE_TYPE_CHIPS_STALL - "DRNKS ", // RCT1_RIDE_TYPE_DRINK_STALL - "CNDYF ", // RCT1_RIDE_TYPE_CANDYFLOSS_STALL - "BURGB ", // RCT1_RIDE_TYPE_BURGER_BAR - "MGR1 ", // RCT1_RIDE_TYPE_MERRY_GO_ROUND - "BALLN ", // RCT1_RIDE_TYPE_BALLOON_STALL - "INFOK ", // RCT1_RIDE_TYPE_INFORMATION_KIOSK - "TLT1 ", // RCT1_RIDE_TYPE_TOILETS - "FWH1 ", // RCT1_RIDE_TYPE_FERRIS_WHEEL - "SIMPOD ", // RCT1_RIDE_TYPE_MOTION_SIMULATOR - "C3D ", // RCT1_RIDE_TYPE_3D_CINEMA - "TOPSP1 ", // RCT1_RIDE_TYPE_TOP_SPIN - "SRINGS ", // RCT1_RIDE_TYPE_SPACE_RINGS - "REVF1 ", // RCT1_RIDE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER - "SOUVS ", // RCT1_RIDE_TYPE_SOUVENIR_STALL - "BMVD ", // RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER - "PIZZS ", // RCT1_RIDE_TYPE_PIZZA_STALL - "TWIST1 ", // RCT1_RIDE_TYPE_TWIST - "HHBUILD ", // RCT1_RIDE_TYPE_HAUNTED_HOUSE - "POPCS ", // RCT1_RIDE_TYPE_POPCORN_STALL - "CIRCUS1 ", // RCT1_RIDE_TYPE_CIRCUS - "GTC ", // RCT1_RIDE_TYPE_GHOST_TRAIN - "BMSD ", // RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER - "MFT ", // RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER - "SFRIC1 ", // RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER - "SMC1 ", // RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER - "HOTDS ", // RCT1_RIDE_TYPE_HOT_DOG_STALL - "SQDST ", // RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL - "HATST ", // RCT1_RIDE_TYPE_HAT_STALL - "TOFFS ", // RCT1_RIDE_TYPE_TOFFEE_APPLE_STALL - "VREEL ", // RCT1_RIDE_TYPE_VIRGINIA_REEL - "SPBOAT ", // RCT1_RIDE_TYPE_RIVER_RIDE - "MONBK ", // RCT1_RIDE_TYPE_CYCLE_MONORAIL - "VEKST ", // RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER - "SMONO ", // RCT1_RIDE_TYPE_SUSPENDED_MONORAIL - " ", // RCT1_RIDE_TYPE_40 - "REVCAR ", // RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER - "UTCAR ", // RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER - "GOLF1 ", // RCT1_RIDE_TYPE_MINIATURE_GOLF - " ", // RCT1_RIDE_TYPE_44 - "GDROP1 ", // RCT1_RIDE_TYPE_ROTO_DROP - "FSAUC ", // RCT1_RIDE_TYPE_FLYING_SAUCERS - "CHBUILD ", // RCT1_RIDE_TYPE_CROOKED_HOUSE - "HELICAR ", // RCT1_RIDE_TYPE_CYCLE_RAILWAY - "SLCT ", // RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER - "CSTBOAT ", // RCT1_RIDE_TYPE_WATER_COASTER - "THCAR ", // RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER - "IVMC1 ", // RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER - "JSKI ", // RCT1_RIDE_TYPE_JET_SKIS - "TSHRT ", // RCT1_RIDE_TYPE_T_SHIRT_STALL - "RFTBOAT ", // RCT1_RIDE_TYPE_RAFT_RIDE - "DOUGH ", // RCT1_RIDE_TYPE_DOUGHNUT_SHOP - "ENTERP ", // RCT1_RIDE_TYPE_ENTERPRISE - "COFFS ", // RCT1_RIDE_TYPE_COFFEE_SHOP - "CHCKS ", // RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL - "LEMST ", // RCT1_RIDE_TYPE_LEMONADE_STALL + "rct2.ride.ptct1", // RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER + "rct2.ride.togst", // RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER + "rct2.ride.arrsw1", // RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER + "rct2.ride.nemt", // RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER + "rct2.ride.zldb", // RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER + "rct2.ride.nrl", // RCT1_RIDE_TYPE_MINIATURE_RAILWAY + "rct2.ride.mono2", // RCT1_RIDE_TYPE_MONORAIL + "rct2.ride.batfl", // RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER + "rct2.ride.rboat", // RCT1_RIDE_TYPE_BOAT_HIRE + "rct2.ride.wmouse", // RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER + "rct2.ride.steep1", // RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER + "rct2.ride.spcar", // RCT1_RIDE_TYPE_CAR_RIDE + "rct2.ride.ssc1", // RCT1_RIDE_TYPE_LAUNCHED_FREEFALL + "rct2.ride.bob1", // RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER + "rct2.ride.obs1", // RCT1_RIDE_TYPE_OBSERVATION_TOWER + "rct2.ride.scht1", // RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER + "rct2.ride.ding1", // RCT1_RIDE_TYPE_WATER_SLIDE + "rct2.ride.amt1", // RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER + "rct2.ride.clift1", // RCT1_RIDE_TYPE_CHAIRLIFT + "rct2.ride.arrt1", // RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER + "rct2.ride.hmaze", // RCT1_RIDE_TYPE_HEDGE_MAZE + "rct2.ride.hskelt", // RCT1_RIDE_TYPE_SPIRAL_SLIDE + "rct2.ride.kart1", // RCT1_RIDE_TYPE_GO_KARTS + "rct2.ride.lfb1", // RCT1_RIDE_TYPE_LOG_FLUME + "rct2.ride.rapboat", // RCT1_RIDE_TYPE_RIVER_RAPIDS + "rct2.ride.dodg1", // RCT1_RIDE_TYPE_DODGEMS + "rct2.ride.swsh1", // RCT1_RIDE_TYPE_SWINGING_SHIP + "rct2.ride.swsh2", // RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP + "rct2.ride.icecr1", // RCT1_RIDE_TYPE_ICE_CREAM_STALL + "rct2.ride.chpsh", // RCT1_RIDE_TYPE_CHIPS_STALL + "rct2.ride.drnks", // RCT1_RIDE_TYPE_DRINK_STALL + "rct2.ride.cndyf", // RCT1_RIDE_TYPE_CANDYFLOSS_STALL + "rct2.ride.burgb", // RCT1_RIDE_TYPE_BURGER_BAR + "rct2.ride.mgr1", // RCT1_RIDE_TYPE_MERRY_GO_ROUND + "rct2.ride.balln", // RCT1_RIDE_TYPE_BALLOON_STALL + "rct2.ride.infok", // RCT1_RIDE_TYPE_INFORMATION_KIOSK + "rct1.ride.toilets", // RCT1_RIDE_TYPE_TOILETS + "rct2.ride.fwh1", // RCT1_RIDE_TYPE_FERRIS_WHEEL + "rct2.ride.simpod", // RCT1_RIDE_TYPE_MOTION_SIMULATOR + "rct2.ride.c3d", // RCT1_RIDE_TYPE_3D_CINEMA + "rct2.ride.topsp1", // RCT1_RIDE_TYPE_TOP_SPIN + "rct2.ride.srings", // RCT1_RIDE_TYPE_SPACE_RINGS + "rct2.ride.revf1", // RCT1_RIDE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER + "rct2.ride.souvs", // RCT1_RIDE_TYPE_SOUVENIR_STALL + "rct2.ride.bmvd", // RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER + "rct2.ride.pizzs", // RCT1_RIDE_TYPE_PIZZA_STALL + "rct2.ride.twist1", // RCT1_RIDE_TYPE_TWIST + "rct2.ride.hhbuild", // RCT1_RIDE_TYPE_HAUNTED_HOUSE + "rct2.ride.popcs", // RCT1_RIDE_TYPE_POPCORN_STALL + "rct2.ride.circus1", // RCT1_RIDE_TYPE_CIRCUS + "rct2.ride.gtc", // RCT1_RIDE_TYPE_GHOST_TRAIN + "rct2.ride.bmsd", // RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER + "rct2.ride.mft", // RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER + "rct2.ride.sfric1", // RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER + "rct2.ride.smc1", // RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER + "rct2.ride.hotds", // RCT1_RIDE_TYPE_HOT_DOG_STALL + "rct2.ride.sqdst", // RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL + "rct2.ride.hatst", // RCT1_RIDE_TYPE_HAT_STALL + "rct2.ride.toffs", // RCT1_RIDE_TYPE_TOFFEE_APPLE_STALL + "rct2.ride.vreel", // RCT1_RIDE_TYPE_VIRGINIA_REEL + "rct2.ride.spboat", // RCT1_RIDE_TYPE_RIVER_RIDE + "rct2.ride.monbk", // RCT1_RIDE_TYPE_CYCLE_MONORAIL + "rct2.ride.vekst", // RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER + "rct2.ride.smono", // RCT1_RIDE_TYPE_SUSPENDED_MONORAIL + "", // RCT1_RIDE_TYPE_40 + "rct2.ride.revcar", // RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER + "rct2.ride.utcar", // RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER + "rct2.ride.golf1", // RCT1_RIDE_TYPE_MINIATURE_GOLF + "", // RCT1_RIDE_TYPE_44 + "rct2.ride.gdrop1", // RCT1_RIDE_TYPE_ROTO_DROP + "rct2.ride.fsauc", // RCT1_RIDE_TYPE_FLYING_SAUCERS + "rct2.ride.chbuild", // RCT1_RIDE_TYPE_CROOKED_HOUSE + "rct2.ride.helicar", // RCT1_RIDE_TYPE_CYCLE_RAILWAY + "rct2.ride.slct", // RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER + "rct2.ride.cstboat", // RCT1_RIDE_TYPE_WATER_COASTER + "rct2.ride.thcar", // RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + "rct2.ride.ivmc1", // RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER + "rct2.ride.jski", // RCT1_RIDE_TYPE_JET_SKIS + "rct2.ride.tshrt", // RCT1_RIDE_TYPE_T_SHIRT_STALL + "rct2.ride.rftboat", // RCT1_RIDE_TYPE_RAFT_RIDE + "rct2.ride.dough", // RCT1_RIDE_TYPE_DOUGHNUT_SHOP + "rct2.ride.enterp", // RCT1_RIDE_TYPE_ENTERPRISE + "rct2.ride.coffs", // RCT1_RIDE_TYPE_COFFEE_SHOP + "rct2.ride.chcks", // RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL + "rct2.ride.lemst", // RCT1_RIDE_TYPE_LEMONADE_STALL }; const auto index = EnumValue(rideType); @@ -795,460 +783,460 @@ namespace RCT1 return map[index]; } - const char * GetVehicleObject(uint8_t vehicleType) + std::string_view GetVehicleObject(uint8_t vehicleType) { static constexpr const char * map[] = { - "SCHT1 ", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN - "SCHT1 ", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN_BACKWARDS - "PTCT1 ", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN - "SLCT ", // RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN (Not in RCT2) - "ARRSW1 ", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_CARS - "ZLDB ", // RCT1_VEHICLE_TYPE_LADYBIRD_CARS - "TOGST ", // RCT1_VEHICLE_TYPE_STANDUP_ROLLER_COASTER_CARS - "WMSPIN ", // RCT1_VEHICLE_TYPE_SPINNING_CARS - "BATFL ", // RCT1_VEHICLE_TYPE_SINGLE_PERSON_SWINGING_CHAIRS - "SWANS ", // RCT1_VEHICLE_TYPE_SWANS_PEDAL_BOATS - "MONO1 ", // RCT1_VEHICLE_TYPE_LARGE_MONORAIL_TRAIN - "CBOAT ", // RCT1_VEHICLE_TYPE_CANOES - "RBOAT ", // RCT1_VEHICLE_TYPE_ROWING_BOATS - "NRL ", // RCT1_VEHICLE_TYPE_STEAM_TRAIN - "WMOUSE ", // RCT1_VEHICLE_TYPE_WOODEN_MOUSE_CARS - "BBOAT ", // RCT1_VEHICLE_TYPE_BUMPER_BOATS - "PTCT1 ", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN_BACKWARDS - "RCKC ", // RCT1_VEHICLE_TYPE_ROCKET_CARS - "STEEP1 ", // RCT1_VEHICLE_TYPE_HORSES // Steeplechase - "SPCAR ", // RCT1_VEHICLE_TYPE_SPORTSCARS - "SKYTR ", // RCT1_VEHICLE_TYPE_LYING_DOWN_SWINGING_CARS (Inverted single-rail) - "WMMINE ", // RCT1_VEHICLE_TYPE_WOODEN_MINE_CARS - "ARRSW2 ", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_AIRPLANE_CARS - "MONO2 ", // RCT1_VEHICLE_TYPE_SMALL_MONORAIL_CARS - "TRIKE ", // RCT1_VEHICLE_TYPE_WATER_TRICYCLES - "SSC1 ", // RCT1_VEHICLE_TYPE_LAUNCHED_FREEFALL_CAR - "BOB1 ", // RCT1_VEHICLE_TYPE_BOBSLEIGH_CARS - "DING1 ", // RCT1_VEHICLE_TYPE_DINGHIES - "OBS1 ", // RCT1_VEHICLE_TYPE_ROTATING_CABIN - "AMT1 ", // RCT1_VEHICLE_TYPE_MINE_TRAIN - "CLIFT1 ", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS - "ARRT1 ", // RCT1_VEHICLE_TYPE_CORKSCREW_ROLLER_COASTER_TRAIN - "STEEP2 ", // RCT1_VEHICLE_TYPE_MOTORBIKES - "RCR ", // RCT1_VEHICLE_TYPE_RACING_CARS - "TRUCK1 ", // RCT1_VEHICLE_TYPE_TRUCKS - "KART1 ", // RCT1_VEHICLE_TYPE_GO_KARTS - "RAPBOAT ", // RCT1_VEHICLE_TYPE_RAPIDS_BOATS - "LFB1 ", // RCT1_VEHICLE_TYPE_LOG_FLUME_BOATS - "DODG1 ", // RCT1_VEHICLE_TYPE_DODGEMS - "SWSH1 ", // RCT1_VEHICLE_TYPE_SWINGING_SHIP - "SWSH2 ", // RCT1_VEHICLE_TYPE_SWINGING_INVERTER_SHIP - "MGR1 ", // RCT1_VEHICLE_TYPE_MERRY_GO_ROUND - "FWH1 ", // RCT1_VEHICLE_TYPE_FERRIS_WHEEL - "SIMPOD ", // RCT1_VEHICLE_TYPE_SIMULATOR_POD - "C3D ", // RCT1_VEHICLE_TYPE_CINEMA_BUILDING - "TOPSP1 ", // RCT1_VEHICLE_TYPE_TOPSPIN_CAR - "SRINGS ", // RCT1_VEHICLE_TYPE_SPACE_RINGS - "REVF1 ", // RCT1_VEHICLE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER_CAR - "BMVD ", // RCT1_VEHICLE_TYPE_VERTICAL_ROLLER_COASTER_CARS - "CTCAR ", // RCT1_VEHICLE_TYPE_CAT_CARS - "TWIST1 ", // RCT1_VEHICLE_TYPE_TWIST_ARMS_AND_CARS - "HHBUILD ", // RCT1_VEHICLE_TYPE_HAUNTED_HOUSE_BUILDING - "ZLOG ", // RCT1_VEHICLE_TYPE_LOG_CARS - "CIRCUS1 ", // RCT1_VEHICLE_TYPE_CIRCUS_TENT - "GTC ", // RCT1_VEHICLE_TYPE_GHOST_TRAIN_CARS - "BMSD ", // RCT1_VEHICLE_TYPE_STEEL_TWISTER_ROLLER_COASTER_TRAIN - "MFT ", // RCT1_VEHICLE_TYPE_WOODEN_TWISTER_ROLLER_COASTER_TRAIN - "SFRIC1 ", // RCT1_VEHICLE_TYPE_WOODEN_SIDE_FRICTION_CARS - "VCR ", // RCT1_VEHICLE_TYPE_VINTAGE_CARS - "NRL2 ", // RCT1_VEHICLE_TYPE_STEAM_TRAIN_COVERED_CARS - "BMSU ", // RCT1_VEHICLE_TYPE_STAND_UP_STEEL_TWISTER_ROLLER_COASTER_TRAIN - "BMFL ", // RCT1_VEHICLE_TYPE_FLOORLESS_STEEL_TWISTER_ROLLER_COASTER_TRAIN - "SMC1 ", // RCT1_VEHICLE_TYPE_STEEL_MOUSE_CARS - "CLIFT2 ", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS_ALTERNATIVE - "SMONO ", // RCT1_VEHICLE_TYPE_SUSPENDED_MONORAIL_TRAIN - "HELICAR ", // RCT1_VEHICLE_TYPE_HELICOPTER_CARS - "VREEL ", // RCT1_VEHICLE_TYPE_VIRGINIA_REEL_TUBS - "REVCAR ", // RCT1_VEHICLE_TYPE_REVERSER_CARS - "GOLF1 ", // RCT1_VEHICLE_TYPE_GOLFERS - "SPBOAT ", // RCT1_VEHICLE_TYPE_RIVER_RIDE_BOATS - "VEKST ", // RCT1_VEHICLE_TYPE_FLYING_ROLLER_COASTER_TRAIN - "BMRB ", // RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN - "UTCAR ", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS - "UTCARR ", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS_REVERSED - " ", // RCT1_VEHICLE_TYPE_RESERVED - "GDROP1 ", // RCT1_VEHICLE_TYPE_ROTODROP_CAR - "FSAUC ", // RCT1_VEHICLE_TYPE_FLYING_SAUCERS - "CHBUILD ", // RCT1_VEHICLE_TYPE_CROOKED_HOUSE_BUILDING - "MONBK ", // RCT1_VEHICLE_TYPE_BICYCLES - "ARRT2 ", // RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN - "NEMT ", // RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN - "CSTBOAT ", // RCT1_VEHICLE_TYPE_WATER_COASTER_BOATS - "SLCFO ", // RCT1_VEHICLE_TYPE_FACEOFF_CARS - "JSKI ", // RCT1_VEHICLE_TYPE_JET_SKIS - "RFTBOAT ", // RCT1_VEHICLE_TYPE_RAFT_BOATS - "AML1 ", // RCT1_VEHICLE_TYPE_AMERICAN_STYLE_STEAM_TRAIN - "THCAR ", // RCT1_VEHICLE_TYPE_AIR_POWERED_COASTER_TRAIN - "IVMC1 ", // RCT1_VEHICLE_TYPE_SUSPENDED_WILD_MOUSE_CARS (Inverted Hairpin in RCT2) - "ENTERP ", // RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL + "rct2.ride.scht1", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN + "rct2.ride.scht1", // RCT1_VEHICLE_TYPE_STEEL_ROLLER_COASTER_TRAIN_BACKWARDS + "rct2.ride.ptct1", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN + "rct2.ride.slct", // RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN (Not in RCT2) + "rct2.ride.arrsw1", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_CARS + "rct2.ride.zldb", // RCT1_VEHICLE_TYPE_LADYBIRD_CARS + "rct2.ride.togst", // RCT1_VEHICLE_TYPE_STANDUP_ROLLER_COASTER_CARS + "rct2.ride.wmspin", // RCT1_VEHICLE_TYPE_SPINNING_CARS + "rct2.ride.batfl", // RCT1_VEHICLE_TYPE_SINGLE_PERSON_SWINGING_CHAIRS + "rct2.ride.swans", // RCT1_VEHICLE_TYPE_SWANS_PEDAL_BOATS + "rct2.ride.mono1", // RCT1_VEHICLE_TYPE_LARGE_MONORAIL_TRAIN + "rct2.ride.cboat", // RCT1_VEHICLE_TYPE_CANOES + "rct2.ride.rboat", // RCT1_VEHICLE_TYPE_ROWING_BOATS + "rct2.ride.nrl", // RCT1_VEHICLE_TYPE_STEAM_TRAIN + "rct2.ride.wmouse", // RCT1_VEHICLE_TYPE_WOODEN_MOUSE_CARS + "rct2.ride.bboat", // RCT1_VEHICLE_TYPE_BUMPER_BOATS + "rct2.ride.ptct1", // RCT1_VEHICLE_TYPE_WOODEN_ROLLER_COASTER_TRAIN_BACKWARDS + "rct2.ride.rckc", // RCT1_VEHICLE_TYPE_ROCKET_CARS + "rct2.ride.steep1", // RCT1_VEHICLE_TYPE_HORSES // Steeplechase + "rct2.ride.spcar", // RCT1_VEHICLE_TYPE_SPORTSCARS + "rct2.ride.skytr", // RCT1_VEHICLE_TYPE_LYING_DOWN_SWINGING_CARS (Inverted single-rail) + "rct2.ride.wmmine", // RCT1_VEHICLE_TYPE_WOODEN_MINE_CARS + "rct2.ride.arrsw2", // RCT1_VEHICLE_TYPE_SUSPENDED_SWINGING_AIRPLANE_CARS + "rct2.ride.mono2", // RCT1_VEHICLE_TYPE_SMALL_MONORAIL_CARS + "rct2.ride.trike", // RCT1_VEHICLE_TYPE_WATER_TRICYCLES + "rct2.ride.ssc1", // RCT1_VEHICLE_TYPE_LAUNCHED_FREEFALL_CAR + "rct2.ride.bob1", // RCT1_VEHICLE_TYPE_BOBSLEIGH_CARS + "rct2.ride.ding1", // RCT1_VEHICLE_TYPE_DINGHIES + "rct2.ride.obs1", // RCT1_VEHICLE_TYPE_ROTATING_CABIN + "rct2.ride.amt1", // RCT1_VEHICLE_TYPE_MINE_TRAIN + "rct2.ride.clift1", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS + "rct2.ride.arrt1", // RCT1_VEHICLE_TYPE_CORKSCREW_ROLLER_COASTER_TRAIN + "rct2.ride.steep2", // RCT1_VEHICLE_TYPE_MOTORBIKES + "rct2.ride.rcr", // RCT1_VEHICLE_TYPE_RACING_CARS + "rct2.ride.truck1", // RCT1_VEHICLE_TYPE_TRUCKS + "rct2.ride.kart1", // RCT1_VEHICLE_TYPE_GO_KARTS + "rct2.ride.rapboat", // RCT1_VEHICLE_TYPE_RAPIDS_BOATS + "rct2.ride.lfb1", // RCT1_VEHICLE_TYPE_LOG_FLUME_BOATS + "rct2.ride.dodg1", // RCT1_VEHICLE_TYPE_DODGEMS + "rct2.ride.swsh1", // RCT1_VEHICLE_TYPE_SWINGING_SHIP + "rct2.ride.swsh2", // RCT1_VEHICLE_TYPE_SWINGING_INVERTER_SHIP + "rct2.ride.mgr1", // RCT1_VEHICLE_TYPE_MERRY_GO_ROUND + "rct2.ride.fwh1", // RCT1_VEHICLE_TYPE_FERRIS_WHEEL + "rct2.ride.simpod", // RCT1_VEHICLE_TYPE_SIMULATOR_POD + "rct2.ride.c3d", // RCT1_VEHICLE_TYPE_CINEMA_BUILDING + "rct2.ride.topsp1", // RCT1_VEHICLE_TYPE_TOPSPIN_CAR + "rct2.ride.srings", // RCT1_VEHICLE_TYPE_SPACE_RINGS + "rct2.ride.revf1", // RCT1_VEHICLE_TYPE_REVERSE_FREEFALL_ROLLER_COASTER_CAR + "rct2.ride.bmvd", // RCT1_VEHICLE_TYPE_VERTICAL_ROLLER_COASTER_CARS + "rct2.ride.ctcar", // RCT1_VEHICLE_TYPE_CAT_CARS + "rct2.ride.twist1", // RCT1_VEHICLE_TYPE_TWIST_ARMS_AND_CARS + "rct2.ride.hhbuild", // RCT1_VEHICLE_TYPE_HAUNTED_HOUSE_BUILDING + "rct2.ride.zlog", // RCT1_VEHICLE_TYPE_LOG_CARS + "rct2.ride.circus1", // RCT1_VEHICLE_TYPE_CIRCUS_TENT + "rct2.ride.gtc", // RCT1_VEHICLE_TYPE_GHOST_TRAIN_CARS + "rct2.ride.bmsd", // RCT1_VEHICLE_TYPE_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "rct2.ride.mft", // RCT1_VEHICLE_TYPE_WOODEN_TWISTER_ROLLER_COASTER_TRAIN + "rct2.ride.sfric1", // RCT1_VEHICLE_TYPE_WOODEN_SIDE_FRICTION_CARS + "rct2.ride.vcr", // RCT1_VEHICLE_TYPE_VINTAGE_CARS + "rct2.ride.nrl2", // RCT1_VEHICLE_TYPE_STEAM_TRAIN_COVERED_CARS + "rct2.ride.bmsu", // RCT1_VEHICLE_TYPE_STAND_UP_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "rct2.ride.bmfl", // RCT1_VEHICLE_TYPE_FLOORLESS_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "rct2.ride.smc1", // RCT1_VEHICLE_TYPE_STEEL_MOUSE_CARS + "rct2.ride.clift2", // RCT1_VEHICLE_TYPE_CHAIRLIFT_CARS_ALTERNATIVE + "rct2.ride.smono", // RCT1_VEHICLE_TYPE_SUSPENDED_MONORAIL_TRAIN + "rct2.ride.helicar", // RCT1_VEHICLE_TYPE_HELICOPTER_CARS + "rct2.ride.vreel", // RCT1_VEHICLE_TYPE_VIRGINIA_REEL_TUBS + "rct2.ride.revcar", // RCT1_VEHICLE_TYPE_REVERSER_CARS + "rct2.ride.golf1", // RCT1_VEHICLE_TYPE_GOLFERS + "rct2.ride.spboat", // RCT1_VEHICLE_TYPE_RIVER_RIDE_BOATS + "rct2.ride.vekst", // RCT1_VEHICLE_TYPE_FLYING_ROLLER_COASTER_TRAIN + "rct2.ride.bmrb", // RCT1_VEHICLE_TYPE_NON_LOOPING_STEEL_TWISTER_ROLLER_COASTER_TRAIN + "rct2.ride.utcar", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS + "rct2.ride.utcarr", // RCT1_VEHICLE_TYPE_HEARTLINE_TWISTER_CARS_REVERSED + "", // RCT1_VEHICLE_TYPE_RESERVED + "rct2.ride.gdrop1", // RCT1_VEHICLE_TYPE_ROTODROP_CAR + "rct2.ride.fsauc", // RCT1_VEHICLE_TYPE_FLYING_SAUCERS + "rct2.ride.chbuild", // RCT1_VEHICLE_TYPE_CROOKED_HOUSE_BUILDING + "rct2.ride.monbk", // RCT1_VEHICLE_TYPE_BICYCLES + "rct2.ride.arrt2", // RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN + "rct2.ride.nemt", // RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN + "rct2.ride.cstboat", // RCT1_VEHICLE_TYPE_WATER_COASTER_BOATS + "rct2.ride.slcfo", // RCT1_VEHICLE_TYPE_FACEOFF_CARS + "rct2.ride.jski", // RCT1_VEHICLE_TYPE_JET_SKIS + "rct2.ride.rftboat", // RCT1_VEHICLE_TYPE_RAFT_BOATS + "rct2.ride.aml1", // RCT1_VEHICLE_TYPE_AMERICAN_STYLE_STEAM_TRAIN + "rct2.ride.thcar", // RCT1_VEHICLE_TYPE_AIR_POWERED_COASTER_TRAIN + "rct2.ride.ivmc1", // RCT1_VEHICLE_TYPE_SUSPENDED_WILD_MOUSE_CARS (Inverted Hairpin in RCT2) + "rct2.ride.enterp", // RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL }; Guard::ArgumentInRange(vehicleType, 0, std::size(map), "Unsupported RCT1 vehicle type."); return map[vehicleType]; } - const char * GetSmallSceneryObject(uint8_t smallSceneryType) + std::string_view GetSmallSceneryObject(uint8_t smallSceneryType) { static constexpr const char * map[] = { - "TL0 ", - "TL1 ", - "TL2 ", - "TL3 ", - "TM0 ", - "TM1 ", - "TM2 ", - "TM3 ", - "TS0 ", - "TS1 ", - "TS2 ", - "TS3 ", - "TS4 ", - "TS5 ", - "TS6 ", - "TIC ", - "TLC ", - "TMC ", - "TMP ", - "TITC ", - "TGHC ", - "TAC ", - "TGHC2 ", - "TCJ ", - "TMBJ ", - "TCF ", - "TCL ", - "TRF ", - "TRF2 ", - "TEL ", - "TAP ", - "TSP ", - "TMZP ", - "TCRP ", - "TBP ", - "TLP ", - "TWP ", - "TAS ", - "TMG ", - "TWW ", - "TSB ", - "TVL ", - "TCT ", - "TEF ", - "TAL ", - "TSQ ", - "THT ", - "TCB ", - "TDM ", - "TSD ", - "TGS ", - "TUS ", - "TH1 ", - "TBC ", - "TH2 ", - "TPM ", - "TSC ", - "TG1 ", - "TWF ", - "TSH0 ", - "TSH1 ", - "TSH2 ", - "TSH3 ", - "TSH4 ", - "TSH5 ", - "TG2 ", - "TG3 ", - "TG4 ", - "TG5 ", - "TG6 ", - "TG7 ", - "TG8 ", - "TG9 ", - "TG10 ", - "TG11 ", - "TG12 ", - "TG13 ", - "TG14 ", - "TT1 ", - "TDF ", - "TSH ", - "THRS ", - "TSTD ", - "TRMS ", - "TRWS ", - "TRC ", - "TQF ", - "TES1 ", - "TEN ", - "TERS ", - "TERB ", - "TEP ", - "TST1 ", - "TST2 ", - "TMS1 ", - "TAS1 ", - "TAS2 ", - "TAS3 ", - "TST3 ", - "TST4 ", - "TST5 ", - "TAS4 ", - "TCY ", - "TBW ", - "TBR1 ", - "TBR2 ", - "TML ", - "TMW ", - "TBR3 ", - "TBR4 ", - "TMJ ", - "TBR ", - "TMO1 ", - "TMO2 ", - "TMO3 ", - "TMO4 ", - "TMO5 ", - "TWH1 ", - "TWH2 ", - "TNS ", - "TP1 ", - "TP2 ", - "TK1 ", - "TK2 ", - "TR1 ", - "TR2 ", - "TQ1 ", - "TQ2 ", - "TWN ", - "TCE ", - "TCO ", - "THL ", - "TCC ", - "TB1 ", - "TB2 ", - "TK3 ", - "TK4 ", - "TBN ", - "TBN1 ", - "TDT1 ", - "TDT2 ", - "TDT3 ", - "TMM1 ", - "TMM2 ", - "TMM3 ", - "TGS1 ", - "TGS2 ", - "TGS3 ", - "TGS4 ", - "TDN4 ", - "TDN5 ", - "TJT1 ", - "TJT2 ", - "TJB1 ", - "TTF ", - "TF1 ", - "TF2 ", - "TGE1 ", - "TJT3 ", - "TJT4 ", - "TJP1 ", - "TJB2 ", - "TGE2 ", - "TJT5 ", - "TJB3 ", - "TJB4 ", - "TJT6 ", - "TJP2 ", - "TGE3 ", - "TCK ", - "TGE4 ", - "TGE5 ", - "TG15 ", - "TG16 ", - "TG17 ", - "TG18 ", - "TG19 ", - "TG20 ", - "TG21 ", - "TSM ", - "TIG ", - "TCFS ", - "TRFS ", - "TRF3 ", - "TNSS ", - "TCT1 ", - "TCT2 ", - "TSF1 ", - "TSF2 ", - "TSF3 ", - "TCN ", - "TTG ", - "TSNC ", - "TSNB ", - "TSCP ", - "TCD ", - "TSG ", - "TSK ", - "TGH1 ", - "TGH2 ", - "TSMP ", - "TJF ", - "TLY ", - "TGC1 ", - "TGC2 ", - "TGG ", - "TSPH ", - "TOH1 ", - "TOH2 ", - "TOT1 ", - "TOT2 ", - "TOS ", - "TOT3 ", - "TOT4 ", - "TSC2 ", - "TSP1 ", - "TOH3 ", - "TSP2 ", - "ROMROOF1", - "GEOROOF1", - "TNTROOF1", - "JNGROOF1", - "MINROOF1", - "ROMROOF2", - "GEOROOF2", - "PAGROOF1", - "SPCROOF1", - "ROOF1 ", - "ROOF2 ", - "ROOF3 ", - "ROOF4 ", - "ROOF5 ", - "ROOF6 ", - "ROOF7 ", - "ROOF8 ", - "ROOF9 ", - "ROOF10 ", - "ROOF11 ", - "ROOF12 ", - "ROOF13 ", - "ROOF14 ", - "IGROOF ", - "CORROOF ", - "CORROOF2", + "rct2.scenery_small.tl0", + "rct2.scenery_small.tl1", + "rct2.scenery_small.tl2", + "rct2.scenery_small.tl3", + "rct2.scenery_small.tm0", + "rct2.scenery_small.tm1", + "rct2.scenery_small.tm2", + "rct2.scenery_small.tm3", + "rct2.scenery_small.ts0", + "rct2.scenery_small.ts1", + "rct2.scenery_small.ts2", + "rct2.scenery_small.ts3", + "rct2.scenery_small.ts4", + "rct2.scenery_small.ts5", + "rct2.scenery_small.ts6", + "rct2.scenery_small.tic", + "rct2.scenery_small.tlc", + "rct2.scenery_small.tmc", + "rct2.scenery_small.tmp", + "rct2.scenery_small.titc", + "rct2.scenery_small.tghc", + "rct2.scenery_small.tac", + "rct2.scenery_small.tghc2", + "rct2.scenery_small.tcj", + "rct2.scenery_small.tmbj", + "rct2.scenery_small.tcf", + "rct2.scenery_small.tcl", + "rct2.scenery_small.trf", + "rct2.scenery_small.trf2", + "rct2.scenery_small.tel", + "rct2.scenery_small.tap", + "rct2.scenery_small.tsp", + "rct2.scenery_small.tmzp", + "rct2.scenery_small.tcrp", + "rct2.scenery_small.tbp", + "rct2.scenery_small.tlp", + "rct2.scenery_small.twp", + "rct2.scenery_small.tas", + "rct2.scenery_small.tmg", + "rct2.scenery_small.tww", + "rct2.scenery_small.tsb", + "rct2.scenery_small.tvl", + "rct2.scenery_small.tct", + "rct2.scenery_small.tef", + "rct2.scenery_small.tal", + "rct2.scenery_small.tsq", + "rct2.scenery_small.tht", + "rct2.scenery_small.tcb", + "rct2.scenery_small.tdm", + "rct2.scenery_small.tsd", + "rct2.scenery_small.tgs", + "rct2.scenery_small.tus", + "rct2.scenery_small.th1", + "rct2.scenery_small.tbc", + "rct2.scenery_small.th2", + "rct2.scenery_small.tpm", + "rct2.scenery_small.tsc", + "rct2.scenery_small.tg1", + "rct2.scenery_small.twf", + "rct2.scenery_small.tsh0", + "rct2.scenery_small.tsh1", + "rct2.scenery_small.tsh2", + "rct2.scenery_small.tsh3", + "rct2.scenery_small.tsh4", + "rct2.scenery_small.tsh5", + "rct2.scenery_small.tg2", + "rct2.scenery_small.tg3", + "rct2.scenery_small.tg4", + "rct2.scenery_small.tg5", + "rct2.scenery_small.tg6", + "rct2.scenery_small.tg7", + "rct2.scenery_small.tg8", + "rct2.scenery_small.tg9", + "rct2.scenery_small.tg10", + "rct2.scenery_small.tg11", + "rct2.scenery_small.tg12", + "rct2.scenery_small.tg13", + "rct2.scenery_small.tg14", + "rct2.scenery_small.tt1", + "rct2.scenery_small.tdf", + "rct2.scenery_small.tsh", + "rct2.scenery_small.thrs", + "rct2.scenery_small.tstd", + "rct2.scenery_small.trms", + "rct2.scenery_small.trws", + "rct2.scenery_small.trc", + "rct2.scenery_small.tqf", + "rct2.scenery_small.tes1", + "rct2.scenery_small.ten", + "rct2.scenery_small.ters", + "rct2.scenery_small.terb", + "rct2.scenery_small.tep", + "rct2.scenery_small.tst1", + "rct2.scenery_small.tst2", + "rct2.scenery_small.tms1", + "rct2.scenery_small.tas1", + "rct2.scenery_small.tas2", + "rct2.scenery_small.tas3", + "rct2.scenery_small.tst3", + "rct2.scenery_small.tst4", + "rct2.scenery_small.tst5", + "rct2.scenery_small.tas4", + "rct2.scenery_small.tcy", + "rct2.scenery_small.tbw", + "rct2.scenery_small.tbr1", + "rct2.scenery_small.tbr2", + "rct2.scenery_small.tml", + "rct2.scenery_small.tmw", + "rct2.scenery_small.tbr3", + "rct2.scenery_small.tbr4", + "rct2.scenery_small.tmj", + "rct2.scenery_small.tbr", + "rct2.scenery_small.tmo1", + "rct2.scenery_small.tmo2", + "rct2.scenery_small.tmo3", + "rct2.scenery_small.tmo4", + "rct2.scenery_small.tmo5", + "rct2.scenery_small.twh1", + "rct2.scenery_small.twh2", + "rct2.scenery_small.tns", + "rct2.scenery_small.tp1", + "rct2.scenery_small.tp2", + "rct2.scenery_small.tk1", + "rct2.scenery_small.tk2", + "rct2.scenery_small.tr1", + "rct2.scenery_small.tr2", + "rct2.scenery_small.tq1", + "rct2.scenery_small.tq2", + "rct2.scenery_small.twn", + "rct2.scenery_small.tce", + "rct2.scenery_small.tco", + "rct2.scenery_small.thl", + "rct2.scenery_small.tcc", + "rct2.scenery_small.tb1", + "rct2.scenery_small.tb2", + "rct2.scenery_small.tk3", + "rct2.scenery_small.tk4", + "rct2.scenery_small.tbn", + "rct2.scenery_small.tbn1", + "rct2.scenery_small.tdt1", + "rct2.scenery_small.tdt2", + "rct2.scenery_small.tdt3", + "rct2.scenery_small.tmm1", + "rct2.scenery_small.tmm2", + "rct2.scenery_small.tmm3", + "rct2.scenery_small.tgs1", + "rct2.scenery_small.tgs2", + "rct2.scenery_small.tgs3", + "rct2.scenery_small.tgs4", + "rct2.scenery_small.tdn4", + "rct2.scenery_small.tdn5", + "rct2.scenery_small.tjt1", + "rct2.scenery_small.tjt2", + "rct2.scenery_small.tjb1", + "rct2.scenery_small.ttf", + "rct2.scenery_small.tf1", + "rct2.scenery_small.tf2", + "rct2.scenery_small.tge1", + "rct2.scenery_small.tjt3", + "rct2.scenery_small.tjt4", + "rct2.scenery_small.tjp1", + "rct2.scenery_small.tjb2", + "rct2.scenery_small.tge2", + "rct2.scenery_small.tjt5", + "rct2.scenery_small.tjb3", + "rct2.scenery_small.tjb4", + "rct2.scenery_small.tjt6", + "rct2.scenery_small.tjp2", + "rct2.scenery_small.tge3", + "rct2.scenery_small.tck", + "rct2.scenery_small.tge4", + "rct2.scenery_small.tge5", + "rct2.scenery_small.tg15", + "rct2.scenery_small.tg16", + "rct2.scenery_small.tg17", + "rct2.scenery_small.tg18", + "rct2.scenery_small.tg19", + "rct2.scenery_small.tg20", + "rct2.scenery_small.tg21", + "rct2.scenery_small.tsm", + "rct2.scenery_small.tig", + "rct2.scenery_small.tcfs", + "rct2.scenery_small.trfs", + "rct2.scenery_small.trf3", + "rct2.scenery_small.tnss", + "rct2.scenery_small.tct1", + "rct2.scenery_small.tct2", + "rct2.scenery_small.tsf1", + "rct2.scenery_small.tsf2", + "rct2.scenery_small.tsf3", + "rct2.scenery_small.tcn", + "rct2.scenery_small.ttg", + "rct2.scenery_small.tsnc", + "rct2.scenery_small.tsnb", + "rct2.scenery_small.tscp", + "rct2.scenery_small.tcd", + "rct2.scenery_small.tsg", + "rct2.scenery_small.tsk", + "rct2.scenery_small.tgh1", + "rct2.scenery_small.tgh2", + "rct2.scenery_small.tsmp", + "rct2.scenery_small.tjf", + "rct2.scenery_small.tly", + "rct2.scenery_small.tgc1", + "rct2.scenery_small.tgc2", + "rct2.scenery_small.tgg", + "rct2.scenery_small.tsph", + "rct2.scenery_small.toh1", + "rct2.scenery_small.toh2", + "rct2.scenery_small.tot1", + "rct2.scenery_small.tot2", + "rct2.scenery_small.tos", + "rct2.scenery_small.tot3", + "rct2.scenery_small.tot4", + "rct2.scenery_small.tsc2", + "rct2.scenery_small.tsp1", + "rct2.scenery_small.toh3", + "rct2.scenery_small.tsp2", + "rct2.scenery_small.romroof1", + "rct2.scenery_small.georoof1", + "rct2.scenery_small.tntroof1", + "rct2.scenery_small.jngroof1", + "rct2.scenery_small.minroof1", + "rct2.scenery_small.romroof2", + "rct2.scenery_small.georoof2", + "rct2.scenery_small.pagroof1", + "rct2.scenery_small.spcroof1", + "rct2.scenery_small.roof1", + "rct2.scenery_small.roof2", + "rct2.scenery_small.roof3", + "rct2.scenery_small.roof4", + "rct2.scenery_small.roof5", + "rct2.scenery_small.roof6", + "rct2.scenery_small.roof7", + "rct2.scenery_small.roof8", + "rct2.scenery_small.roof9", + "rct2.scenery_small.roof10", + "rct2.scenery_small.roof11", + "rct2.scenery_small.roof12", + "rct2.scenery_small.roof13", + "rct2.scenery_small.roof14", + "rct2.scenery_small.igroof", + "rct2.scenery_small.corroof", + "rct2.scenery_small.corroof2", }; return map[smallSceneryType]; } - const char * GetLargeSceneryObject(uint8_t largeSceneryType) + std::string_view GetLargeSceneryObject(uint8_t largeSceneryType) { static constexpr const char * map[] = { - "SCOL ", - "SHS1 ", - "SSPX ", - "SHS2 ", - "SCLN ", - "SMH1 ", - "SMH2 ", - "SVLC ", - "SPYR ", - "SMN1 ", - "SMB ", - "SSK1 ", - "SDN1 ", - "SDN2 ", - "SDN3 ", - "SIP ", - "STB1 ", - "STB2 ", - "STG1 ", - "STG2 ", - "SCT ", - "SOH1 ", - "SOH2 ", - "SOH3 ", - "SGP ", - "SSR ", - "STH ", - "SAH ", - "SPS ", - "SPG ", - "SOB ", - "SAH2 ", - "SST ", - "SSH ", - "SAH3 ", - "SSIG1 ", - "SSIG2 ", - "SSIG3 ", - "SSIG4 ", + "rct2.scenery_large.scol", + "rct2.scenery_large.shs1", + "rct2.scenery_large.sspx", + "rct2.scenery_large.shs2", + "rct2.scenery_large.scln", + "rct2.scenery_large.smh1", + "rct2.scenery_large.smh2", + "rct2.scenery_large.svlc", + "rct2.scenery_large.spyr", + "rct2.scenery_large.smn1", + "rct2.scenery_large.smb", + "rct2.scenery_large.ssk1", + "rct2.scenery_large.sdn1", + "rct2.scenery_large.sdn2", + "rct2.scenery_large.sdn3", + "rct2.scenery_large.sip", + "rct2.scenery_large.stb1", + "rct2.scenery_large.stb2", + "rct2.scenery_large.stg1", + "rct2.scenery_large.stg2", + "rct2.scenery_large.sct", + "rct2.scenery_large.soh1", + "rct2.scenery_large.soh2", + "rct2.scenery_large.soh3", + "rct2.scenery_large.sgp", + "rct2.scenery_large.ssr", + "rct2.scenery_large.sth", + "rct2.scenery_large.sah", + "rct2.scenery_large.sps", + "rct2.scenery_large.spg", + "rct2.scenery_large.sob", + "rct2.scenery_large.sah2", + "rct2.scenery_large.sst", + "rct2.scenery_large.ssh", + "rct2.scenery_large.sah3", + "rct2.scenery_large.ssig1", + "rct2.scenery_large.ssig2", + "rct2.scenery_large.ssig3", + "rct2.scenery_large.ssig4", }; return map[largeSceneryType]; } - const char * GetWallObject(uint8_t wallType) + std::string_view GetWallObject(uint8_t wallType) { static constexpr const char * map[] = { - "WMF ", // RCT1_WALL_TYPE_MESH_FENCE - "WMFG ", // RCT1_WALL_TYPE_MESH_FENCE_WITH_GATE - "WRW ", // RCT1_WALL_TYPE_ROMAN - "WEW ", // RCT1_WALL_TYPE_EGYPTIAN - "WHG ", // RCT1_WALL_TYPE_HEDGE - "WHGG ", // RCT1_WALL_TYPE_HEDGE_WITH_GATE - "WCW1 ", // RCT1_WALL_TYPE_BLUE_PLAYING_CARDS - "WCW2 ", // RCT1_WALL_TYPE_RED_PLAYING_CARDS - "WSW ", // RCT1_WALL_TYPE_WHITE_RAILING - "WSWG ", // RCT1_WALL_TYPE_WHITE_RAILING_WITH_GATE - "WMW ", // RCT1_WALL_TYPE_MARTIAN - "WALLGL16", // RCT1_WALL_TYPE_GLASS_SMOOTH - "WFW1 ", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE - "WFWG ", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE_WITH_GATE - "WPW1 ", // RCT1_WALL_TYPE_WOODEN_POST_FENCE - "WPW2 ", // RCT1_WALL_TYPE_RED_WOODEN_POST_FENCE - "WPF ", // RCT1_WALL_TYPE_BARBED_WIRE - "WPFG ", // RCT1_WALL_TYPE_BARBED_WIRE_WITH_GATE - "WWTW ", // RCT1_WALL_TYPE_PRIMITIVE_TALL_WOOD_FENCE - "WMWW ", // RCT1_WALL_TYPE_PRIMITIVE_SHORT_WOOD_FENCE - "WSW1 ", // RCT1_WALL_TYPE_IRON_RAILING - "WSW2 ", // RCT1_WALL_TYPE_IRON_RAILING_WITH_GATE - "WGW2 ", // RCT1_WALL_TYPE_GLASS_PANELS - "WBW ", // RCT1_WALL_TYPE_BONE_FENCE - "WBR1 ", // RCT1_WALL_TYPE_BRICK - "WBRG ", // RCT1_WALL_TYPE_BRICK_WITH_GATE - "WFW1 ", // RCT1_WALL_TYPE_WHITE_WOODEN_PANEL_FENCE - "WFW1 ", // RCT1_WALL_TYPE_RED_WOODEN_PANEL_FENCE - "WBR2 ", // RCT1_WALL_TYPE_STONE - "WBR3 ", // RCT1_WALL_TYPE_STONE_WITH_GATE - "WPW3 ", // RCT1_WALL_TYPE_WOODEN_FENCE - "WJF ", // RCT1_WALL_TYPE_JUNGLE - "WCH ", // RCT1_WALL_TYPE_CONIFER_HEDGE - "WCHG ", // RCT1_WALL_TYPE_CONIFER_HEDGE_WITH_GATE - "WC1 ", // RCT1_WALL_TYPE_SMALL_BROWN_CASTLE - "WC2 ", // RCT1_WALL_TYPE_SMALL_GREY_CASTLE - "WC3 ", // RCT1_WALL_TYPE_ROMAN_COLUMN - "WC4 ", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE - "WC5 ", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_CROSS - "WC6 ", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_GATE - "WC7 ", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_WINDOW - "WC8 ", // RCT1_WALL_TYPE_MEDIUM_BROWN_CASTLE - "WC9 ", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE - "WC10 ", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_CROSS - "WC11 ", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_GATE - "WC12 ", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_WINDOW - "WC13 ", // RCT1_WALL_TYPE_MEDIUM_GREY_CASTLE - "WC14 ", // RCT1_WALL_TYPE_CREEPY - "WC15 ", // RCT1_WALL_TYPE_CREEPY_GATE - "WC16 ", // RCT1_WALL_TYPE_BARBED_WIRE_WITH_SNOW - "WC17 ", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE_WITH_SNOW - "WC18 ", // RCT1_WALL_TYPE_WOODEN_POST_FENCE_WITH_SNOW + "rct2.scenery_wall.wmf", // RCT1_WALL_TYPE_MESH_FENCE + "rct2.scenery_wall.wmfg", // RCT1_WALL_TYPE_MESH_FENCE_WITH_GATE + "rct2.scenery_wall.wrw", // RCT1_WALL_TYPE_ROMAN + "rct2.scenery_wall.wew", // RCT1_WALL_TYPE_EGYPTIAN + "rct2.scenery_wall.whg", // RCT1_WALL_TYPE_HEDGE + "rct2.scenery_wall.whgg", // RCT1_WALL_TYPE_HEDGE_WITH_GATE + "rct2.scenery_wall.wcw1", // RCT1_WALL_TYPE_BLUE_PLAYING_CARDS + "rct2.scenery_wall.wcw2", // RCT1_WALL_TYPE_RED_PLAYING_CARDS + "rct2.scenery_wall.wsw", // RCT1_WALL_TYPE_WHITE_RAILING + "rct2.scenery_wall.wswg", // RCT1_WALL_TYPE_WHITE_RAILING_WITH_GATE + "rct2.scenery_wall.wmw", // RCT1_WALL_TYPE_MARTIAN + "rct2.scenery_wall.wallgl16", // RCT1_WALL_TYPE_GLASS_SMOOTH + "rct2.scenery_wall.wfw1", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE + "rct2.scenery_wall.wfwg", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE_WITH_GATE + "rct2.scenery_wall.wpw1", // RCT1_WALL_TYPE_WOODEN_POST_FENCE + "rct2.scenery_wall.wpw2", // RCT1_WALL_TYPE_RED_WOODEN_POST_FENCE + "rct2.scenery_wall.wpf", // RCT1_WALL_TYPE_BARBED_WIRE + "rct2.scenery_wall.wpfg", // RCT1_WALL_TYPE_BARBED_WIRE_WITH_GATE + "rct2.scenery_wall.wwtw", // RCT1_WALL_TYPE_PRIMITIVE_TALL_WOOD_FENCE + "rct2.scenery_wall.wmww", // RCT1_WALL_TYPE_PRIMITIVE_SHORT_WOOD_FENCE + "rct2.scenery_wall.wsw1", // RCT1_WALL_TYPE_IRON_RAILING + "rct2.scenery_wall.wsw2", // RCT1_WALL_TYPE_IRON_RAILING_WITH_GATE + "rct2.scenery_wall.wgw2", // RCT1_WALL_TYPE_GLASS_PANELS + "rct2.scenery_wall.wbw", // RCT1_WALL_TYPE_BONE_FENCE + "rct2.scenery_wall.wbr1", // RCT1_WALL_TYPE_BRICK + "rct2.scenery_wall.wbrg", // RCT1_WALL_TYPE_BRICK_WITH_GATE + "rct2.scenery_wall.wfw1", // RCT1_WALL_TYPE_WHITE_WOODEN_PANEL_FENCE + "rct1.scenery_wall.wooden_fence_red", // RCT1_WALL_TYPE_RED_WOODEN_PANEL_FENCE + "rct2.scenery_wall.wbr2", // RCT1_WALL_TYPE_STONE + "rct2.scenery_wall.wbr3", // RCT1_WALL_TYPE_STONE_WITH_GATE + "rct2.scenery_wall.wpw3", // RCT1_WALL_TYPE_WOODEN_FENCE + "rct2.scenery_wall.wjf", // RCT1_WALL_TYPE_JUNGLE + "rct2.scenery_wall.wch", // RCT1_WALL_TYPE_CONIFER_HEDGE + "rct2.scenery_wall.wchg", // RCT1_WALL_TYPE_CONIFER_HEDGE_WITH_GATE + "rct2.scenery_wall.wc1", // RCT1_WALL_TYPE_SMALL_BROWN_CASTLE + "rct2.scenery_wall.wc2", // RCT1_WALL_TYPE_SMALL_GREY_CASTLE + "rct2.scenery_wall.wc3", // RCT1_WALL_TYPE_ROMAN_COLUMN + "rct2.scenery_wall.wc4", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE + "rct2.scenery_wall.wc5", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_CROSS + "rct2.scenery_wall.wc6", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_GATE + "rct2.scenery_wall.wc7", // RCT1_WALL_TYPE_LARGE_BROWN_CASTLE_WINDOW + "rct2.scenery_wall.wc8", // RCT1_WALL_TYPE_MEDIUM_BROWN_CASTLE + "rct2.scenery_wall.wc9", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE + "rct2.scenery_wall.wc10", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_CROSS + "rct2.scenery_wall.wc11", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_GATE + "rct2.scenery_wall.wc12", // RCT1_WALL_TYPE_LARGE_GREY_CASTLE_WINDOW + "rct2.scenery_wall.wc13", // RCT1_WALL_TYPE_MEDIUM_GREY_CASTLE + "rct2.scenery_wall.wc14", // RCT1_WALL_TYPE_CREEPY + "rct2.scenery_wall.wc15", // RCT1_WALL_TYPE_CREEPY_GATE + "rct2.scenery_wall.wc16", // RCT1_WALL_TYPE_BARBED_WIRE_WITH_SNOW + "rct2.scenery_wall.wc17", // RCT1_WALL_TYPE_WOODEN_PANEL_FENCE_WITH_SNOW + "rct2.scenery_wall.wc18", // RCT1_WALL_TYPE_WOODEN_POST_FENCE_WITH_SNOW }; if (wallType < std::size(map)) return map[wallType]; @@ -1256,98 +1244,110 @@ namespace RCT1 return map[0]; } - const char * GetPathObject(uint8_t pathType) + std::string_view GetPathSurfaceObject(uint8_t pathType) { static constexpr const char * map[] = { - "TARMAC ", // RCT1_FOOTPATH_TYPE_QUEUE_BLUE - "PATHSPCE", // RCT1_FOOTPATH_TYPE_QUEUE_RED - "PATHDIRT", // RCT1_FOOTPATH_TYPE_QUEUE_YELLOW - "TARMACG ", // RCT1_FOOTPATH_TYPE_QUEUE_GREEN + "rct1.footpath_surface.queue_blue", // RCT1_FOOTPATH_TYPE_QUEUE_BLUE + "rct1aa.footpath_surface.queue_red", // RCT1_FOOTPATH_TYPE_QUEUE_RED + "rct1aa.footpath_surface.queue_yellow", // RCT1_FOOTPATH_TYPE_QUEUE_YELLOW + "rct1aa.footpath_surface.queue_green", // RCT1_FOOTPATH_TYPE_QUEUE_GREEN - "TARMAC ", // RCT1_FOOTPATH_TYPE_TARMAC_GREY - "PATHSPCE", // RCT1_FOOTPATH_TYPE_TARMAC_RED - "TARMACB ", // RCT1_FOOTPATH_TYPE_TARMAC_BROWN - "TARMACG ", // RCT1_FOOTPATH_TYPE_TARMAC_GREEN + "rct1.footpath_surface.tarmac", // RCT1_FOOTPATH_TYPE_TARMAC_GREY + "rct1aa.footpath_surface.tarmac_red", // RCT1_FOOTPATH_TYPE_TARMAC_RED + "rct1aa.footpath_surface.tarmac_brown", // RCT1_FOOTPATH_TYPE_TARMAC_BROWN + "rct1aa.footpath_surface.tarmac_green", // RCT1_FOOTPATH_TYPE_TARMAC_GREEN - "PATHDIRT", // RCT1_FOOTPATH_TYPE_DIRT_BROWN - "PATHASH ", // RCT1_FOOTPATH_TYPE_DIRT_BLACK - " ", - " ", + "rct1.footpath_surface.dirt", // RCT1_FOOTPATH_TYPE_DIRT_BROWN + "rct1aa.footpath_surface.ash", // RCT1_FOOTPATH_TYPE_DIRT_BLACK + "", + "", - "PATHCRZY", // RCT1_FOOTPATH_TYPE_CRAZY_PAVING - " ", - " ", - " ", + "rct1.footpath_surface.crazy_paving", // RCT1_FOOTPATH_TYPE_CRAZY_PAVING + "", + "", + "", - "ROAD ", // RCT1_FOOTPATH_TYPE_ROAD - " ", - " ", - " ", + "rct2.footpath_surface.road", // RCT1_FOOTPATH_TYPE_ROAD + "", + "", + "", - "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_BROWN - "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_GREY - "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_RED - "PATHCRZY", // RCT1_FOOTPATH_TYPE_TILE_GREEN + "rct1.footpath_surface.tiles_brown", // RCT1_FOOTPATH_TYPE_TILE_BROWN + "rct1aa.footpath_surface.tiles_grey", // RCT1_FOOTPATH_TYPE_TILE_GREY + "rct1ll.footpath_surface.tiles_red", // RCT1_FOOTPATH_TYPE_TILE_RED + "rct1ll.footpath_surface.tiles_green", // RCT1_FOOTPATH_TYPE_TILE_GREEN }; return map[pathType]; } - const char * GetPathAddtionObject(uint8_t pathAdditionType) + std::string_view GetPathAddtionObject(uint8_t pathAdditionType) { static constexpr const char * map[] = { - " ", // RCT1_PATH_ADDITION_NONE - "LAMP1 ", // RCT1_PATH_ADDITION_LAMP_1 - "LAMP2 ", // RCT1_PATH_ADDITION_LAMP_2 - "LITTER1 ", // RCT1_PATH_ADDITION_BIN - "BENCH1 ", // RCT1_PATH_ADDITION_BENCH - "JUMPFNT1", // RCT1_PATH_ADDITION_JUMPING_FOUNTAIN - "LAMP3 ", // RCT1_PATH_ADDITION_LAMP_3 - "LAMP4 ", // RCT1_PATH_ADDITION_LAMP_4 - "LAMP1 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_1 - "LAMP2 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_2 - "LITTER1 ", // RCT1_PATH_ADDITION_BROKEN_BIN - "BENCH1 ", // RCT1_PATH_ADDITION_BROKEN_BENCH - "LAMP3 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_3 - "LAMP4 ", // RCT1_PATH_ADDITION_BROKEN_LAMP_4 - "JUMPSNW1", // RCT1_PATH_ADDITION_JUMPING_SNOW + "", // RCT1_PATH_ADDITION_NONE + "rct2.footpath_item.lamp1", // RCT1_PATH_ADDITION_LAMP_1 + "rct2.footpath_item.lamp2", // RCT1_PATH_ADDITION_LAMP_2 + "rct2.footpath_item.litter1", // RCT1_PATH_ADDITION_BIN + "rct2.footpath_item.bench1", // RCT1_PATH_ADDITION_BENCH + "rct2.footpath_item.jumpfnt1", // RCT1_PATH_ADDITION_JUMPING_FOUNTAIN + "rct2.footpath_item.lamp3", // RCT1_PATH_ADDITION_LAMP_3 + "rct2.footpath_item.lamp4", // RCT1_PATH_ADDITION_LAMP_4 + "rct2.footpath_item.lamp1", // RCT1_PATH_ADDITION_BROKEN_LAMP_1 + "rct2.footpath_item.lamp2", // RCT1_PATH_ADDITION_BROKEN_LAMP_2 + "rct2.footpath_item.litter1", // RCT1_PATH_ADDITION_BROKEN_BIN + "rct2.footpath_item.bench1", // RCT1_PATH_ADDITION_BROKEN_BENCH + "rct2.footpath_item.lamp3", // RCT1_PATH_ADDITION_BROKEN_LAMP_3 + "rct2.footpath_item.lamp4", // RCT1_PATH_ADDITION_BROKEN_LAMP_4 + "rct2.footpath_item.jumpsnw1", // RCT1_PATH_ADDITION_JUMPING_SNOW }; return map[pathAdditionType]; } - const char * GetSceneryGroupObject(uint8_t sceneryGroupType) + std::string_view GetFootpathRailingsObject(uint8_t footpathRailingsType) { static constexpr const char * map[] = { - " ", // RCT1_SCENERY_THEME_GENERAL - "SCGMINE ", // RCT1_SCENERY_THEME_MINE - "SCGCLASS", // RCT1_SCENERY_THEME_CLASSICAL_ROMAN - "SCGEGYPT", // RCT1_SCENERY_THEME_EGYPTIAN - "SCGMART ", // RCT1_SCENERY_THEME_MARTIAN - " ", // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS - "SCGWOND ", // RCT1_SCENERY_THEME_WONDERLAND - "SCGJURAS", // RCT1_SCENERY_THEME_JURASSIC - "SCGSPOOK", // RCT1_SCENERY_THEME_SPOOKY - "SCGJUNGL", // RCT1_SCENERY_THEME_JUNGLE - "SCGABSTR", // RCT1_SCENERY_THEME_ABSTRACT - " ", // RCT1_SCENERY_THEME_GARDEN_CLOCK - "SCGSNOW ", // RCT1_SCENERY_THEME_SNOW_ICE - "SCGMEDIE", // RCT1_SCENERY_THEME_MEDIEVAL - "SCGSPACE", // RCT1_SCENERY_THEME_SPACE - "SCGHALLO", // RCT1_SCENERY_THEME_CREEPY - "SCGURBAN", // RCT1_SCENERY_THEME_URBAN - "SCGORIEN", // RCT1_SCENERY_THEME_PAGODA + "rct2.footpath_railings.wood", // RCT1_PATH_SUPPORT_TYPE_TRUSS + "rct2.footpath_railings.concrete", // RCT1_PATH_SUPPORT_TYPE_COATED_WOOD + "rct1ll.footpath_railings.space", // RCT1_PATH_SUPPORT_TYPE_SPACE + "rct1ll.footpath_railings.bamboo", // RCT1_PATH_SUPPORT_TYPE_BAMBOO + }; + return map[footpathRailingsType]; + } + + std::string_view GetSceneryGroupObject(uint8_t sceneryGroupType) + { + static constexpr const char * map[] = + { + "", // RCT1_SCENERY_THEME_GENERAL + "rct2.scenery_group.scgmine", // RCT1_SCENERY_THEME_MINE + "rct2.scenery_group.scgclass", // RCT1_SCENERY_THEME_CLASSICAL_ROMAN + "rct2.scenery_group.scgegypt", // RCT1_SCENERY_THEME_EGYPTIAN + "rct2.scenery_group.scgmart", // RCT1_SCENERY_THEME_MARTIAN + "", // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS + "rct2.scenery_group.scgwond", // RCT1_SCENERY_THEME_WONDERLAND + "rct2.scenery_group.scgjuras", // RCT1_SCENERY_THEME_JURASSIC + "rct2.scenery_group.scgspook", // RCT1_SCENERY_THEME_SPOOKY + "rct2.scenery_group.scgjungl", // RCT1_SCENERY_THEME_JUNGLE + "rct2.scenery_group.scgabstr", // RCT1_SCENERY_THEME_ABSTRACT + "", // RCT1_SCENERY_THEME_GARDEN_CLOCK + "rct2.scenery_group.scgsnow", // RCT1_SCENERY_THEME_SNOW_ICE + "rct2.scenery_group.scgmedie", // RCT1_SCENERY_THEME_MEDIEVAL + "rct2.scenery_group.scgspace", // RCT1_SCENERY_THEME_SPACE + "rct2.scenery_group.scghallo", // RCT1_SCENERY_THEME_CREEPY + "rct2.scenery_group.scgurban", // RCT1_SCENERY_THEME_URBAN + "rct2.scenery_group.scgorien", // RCT1_SCENERY_THEME_PAGODA }; return map[sceneryGroupType]; } - const char * GetWaterObject(uint8_t waterType) + std::string_view GetWaterObject(uint8_t waterType) { static constexpr const char * map[] = { - "WTRCYAN ", - "WTRORNG ", + "rct2.water.wtrcyan", + "rct2.water.wtrorng", }; return map[waterType]; } @@ -1357,46 +1357,46 @@ namespace RCT1 static const std::vector map[] = { // RCT1_SCENERY_THEME_GENERAL (trees, shrubs, garden, walls, fence, path accessories) - { "TIC ", "TLC ", "TMC ", "TMP ", "TITC ", "TGHC ", "TAC ", "TGHC2 ", "TCJ ", "TMBJ ", "TCF ", "TCL ", "TRF ", "TRF2 ", "TEL ", "TAP ", "TSP ", "TMZP ", "TCRP ", "TBP ", "TLP ", "TWP ", "TAS ", "TMG ", "TWW ", "TSB ", "TVL ", "TCY ", "TNS ", "TWN ", "TCE ", "TCO ", "THL ", "TCC ", "TF1 ", "TF2 ", "TCT ", "TH1 ", "TH2 ", "TPM ", "TROPT1 ", - "TS0 ", "TS1 ", "TS2 ", "TS3 ", "TS4 ", "TS5 ", "TS6 ", "TEF ", "TAL ", "TSQ ", "THT ", "TCB ", "TDM ", "TSD ", "TORN1 ", "TORN2 ", "TGS ", "TUS ", "TBC ", "TSC ", "TWF ", "TSH0 ", "TSH1 ", "TSH2 ", "TSH3 ", "TSH4 ", "TSH5 ", "TDF ", "TSH ", "THRS ", "TSTD ", "TBR ", "TTF ", "WHG ", "WHGG ", "WCH ", "WCHG ", - "TG1 ", "TG2 ", "TG3 ", "TG4 ", "TG5 ", "TG6 ", "TG7 ", "TG8 ", "TG9 ", "TG10 ", "TG11 ", "TG12 ", "TG13 ", "TG14 ", "TG15 ", "TG16 ", "TG17 ", "TG18 ", "TG19 ", "TG20 ", "TG21 ", - "WBR1A ", "WBR2A ", "WALLBB34", "WALLTN32", "TNTROOF1", "WALLBB33", "WALLBB32", "WALLBB16", "WALLBB8 ", "ROOF5 ", "ROOF7 ", "WALLRS32", "WALLRS16", "WALLRS8 ", "WALLBR32", "WALLBR16", "WALLBR8 ", "WALLBRDR", "WALLBRWN", "BRBASE ", "ROOF1 ", "ROOF2 ", "ROOF3 ", "ROOF4 ", "WALLCB32", "WALLCB16", "WALLCB8 ", "WALLCBDR", "WALLCBWN", "BRBASE2 ", "CWBCRV33", "CWBCRV32", "BRCRRF1 ", "ROOF6 ", "ROOF8 ", "WALLCF32", "WALLCF16", "WALLCF8 ", "WALLCFDR", "WALLCFWN", "WALLCFAR", "BRBASE3 ", "CWFCRV33", "CWFCRV32", "BRCRRF2 ", "ROOF9 ", "ROOF11 ", "ROOF10 ", "ROOF12 ", "CORROOF2", "WALLCO16", "CORROOF ", "WALLLT32", "WALLSK16", "WALLSK32", "SKTDW2 ", "SKTDW ", "SKTBASE ", "SKTBASET", "SUPPW2 ", "SUPPW1 ", "SUPPW3 ", "SUPPLEG1", "SUPPLEG2", "SUMRF ", "WALLRH32", - "WMF ", "WMFG ", "WSW ", "WSWG ", "WFW1 ", "WFWG ", "WPF ", "WPFG ", "WSW1 ", "WSW2 ", "WBR1 ", "WBRG ", "WBR2 ", "WBR3 ", "WALLMM16", "WALLMM17", - "LAMP1 ", "LAMP2 ", "LITTER1 ", "BENCH1 ", "QTV1 ", "BN1 ", "WALLPOST", "WALLSIGN", "SSIG1 ", "SSIG2 ", "SSIG3 ", "SSIG4 " }, + { "rct2.scenery_small.tic", "rct2.scenery_small.tlc", "rct2.scenery_small.tmc", "rct2.scenery_small.tmp", "rct2.scenery_small.titc", "rct2.scenery_small.tghc", "rct2.scenery_small.tac", "rct2.scenery_small.tghc2", "rct2.scenery_small.tcj", "rct2.scenery_small.tmbj", "rct2.scenery_small.tcf", "rct2.scenery_small.tcl", "rct2.scenery_small.trf", "rct2.scenery_small.trf2", "rct2.scenery_small.tel", "rct2.scenery_small.tap", "rct2.scenery_small.tsp", "rct2.scenery_small.tmzp", "rct2.scenery_small.tcrp", "rct2.scenery_small.tbp", "rct2.scenery_small.tlp", "rct2.scenery_small.twp", "rct2.scenery_small.tas", "rct2.scenery_small.tmg", "rct2.scenery_small.tww", "rct2.scenery_small.tsb", "rct2.scenery_small.tvl", "rct2.scenery_small.tcy", "rct2.scenery_small.tns", "rct2.scenery_small.twn", "rct2.scenery_small.tce", "rct2.scenery_small.tco", "rct2.scenery_small.thl", "rct2.scenery_small.tcc", "rct2.scenery_small.tf1", "rct2.scenery_small.tf2", "rct2.scenery_small.tct", "rct2.scenery_small.th1", "rct2.scenery_small.th2", "rct2.scenery_small.tpm", "rct2.scenery_small.tropt1", + "rct2.scenery_small.ts0", "rct2.scenery_small.ts1", "rct2.scenery_small.ts2", "rct2.scenery_small.ts3", "rct2.scenery_small.ts4", "rct2.scenery_small.ts5", "rct2.scenery_small.ts6", "rct2.scenery_small.tef", "rct2.scenery_small.tal", "rct2.scenery_small.tsq", "rct2.scenery_small.tht", "rct2.scenery_small.tcb", "rct2.scenery_small.tdm", "rct2.scenery_small.tsd", "rct2.scenery_small.torn1", "rct2.scenery_small.torn2", "rct2.scenery_small.tgs", "rct2.scenery_small.tus", "rct2.scenery_small.tbc", "rct2.scenery_small.tsc", "rct2.scenery_small.twf", "rct2.scenery_small.tsh0", "rct2.scenery_small.tsh1", "rct2.scenery_small.tsh2", "rct2.scenery_small.tsh3", "rct2.scenery_small.tsh4", "rct2.scenery_small.tsh5", "rct2.scenery_small.tdf", "rct2.scenery_small.tsh", "rct2.scenery_small.thrs", "rct2.scenery_small.tstd", "rct2.scenery_small.tbr", "rct2.scenery_small.ttf", "rct2.scenery_wall.whg", "rct2.scenery_wall.whgg", "rct2.scenery_wall.wch", "rct2.scenery_wall.wchg", + "rct2.scenery_small.tg1", "rct2.scenery_small.tg2", "rct2.scenery_small.tg3", "rct2.scenery_small.tg4", "rct2.scenery_small.tg5", "rct2.scenery_small.tg6", "rct2.scenery_small.tg7", "rct2.scenery_small.tg8", "rct2.scenery_small.tg9", "rct2.scenery_small.tg10", "rct2.scenery_small.tg11", "rct2.scenery_small.tg12", "rct2.scenery_small.tg13", "rct2.scenery_small.tg14", "rct2.scenery_small.tg15", "rct2.scenery_small.tg16", "rct2.scenery_small.tg17", "rct2.scenery_small.tg18", "rct2.scenery_small.tg19", "rct2.scenery_small.tg20", "rct2.scenery_small.tg21", + "rct2.scenery_wall.wbr1a", "rct2.scenery_wall.wbr2a", "rct2.scenery_wall.wallbb34", "rct2.scenery_wall.walltn32", "rct2.scenery_small.tntroof1", "rct2.scenery_wall.wallbb33", "rct2.scenery_wall.wallbb32", "rct2.scenery_wall.wallbb16", "rct2.scenery_wall.wallbb8", "rct2.scenery_small.roof5", "rct2.scenery_small.roof7", "rct2.scenery_wall.wallrs32", "rct2.scenery_wall.wallrs16", "rct2.scenery_wall.wallrs8", "rct2.scenery_wall.wallbr32", "rct2.scenery_wall.wallbr16", "rct2.scenery_wall.wallbr8", "rct2.scenery_wall.wallbrdr", "rct2.scenery_wall.wallbrwn", "rct2.scenery_small.brbase", "rct2.scenery_small.roof1", "rct2.scenery_small.roof2", "rct2.scenery_small.roof3", "rct2.scenery_small.roof4", "rct2.scenery_wall.wallcb32", "rct2.scenery_wall.wallcb16", "rct2.scenery_wall.wallcb8", "rct2.scenery_wall.wallcbdr", "rct2.scenery_wall.wallcbwn", "rct2.scenery_small.brbase2", "rct2.scenery_small.cwbcrv33", "rct2.scenery_small.cwbcrv32", "rct2.scenery_small.brcrrf1", "rct2.scenery_small.roof6", "rct2.scenery_small.roof8", "rct2.scenery_wall.wallcf32", "rct2.scenery_wall.wallcf16", "rct2.scenery_wall.wallcf8", "rct2.scenery_wall.wallcfdr", "rct2.scenery_wall.wallcfwn", "rct2.scenery_wall.wallcfar", "rct2.scenery_small.brbase3", "rct2.scenery_small.cwfcrv33", "rct2.scenery_small.cwfcrv32", "rct2.scenery_small.brcrrf2", "rct2.scenery_small.roof9", "rct2.scenery_small.roof11", "rct2.scenery_small.roof10", "rct2.scenery_small.roof12", "rct2.scenery_small.corroof2", "rct2.scenery_wall.wallco16", "rct2.scenery_small.corroof", "rct2.scenery_wall.walllt32", "rct2.scenery_wall.wallsk16", "rct2.scenery_wall.wallsk32", "rct2.scenery_small.sktdw2", "rct2.scenery_small.sktdw", "rct2.scenery_small.sktbase", "rct2.scenery_small.sktbaset", "rct2.scenery_small.suppw2", "rct2.scenery_small.suppw1", "rct2.scenery_small.suppw3", "rct2.scenery_small.suppleg1", "rct2.scenery_small.suppleg2", "rct2.scenery_small.sumrf", "rct2.scenery_wall.wallrh32", + "rct2.scenery_wall.wmf", "rct2.scenery_wall.wmfg", "rct2.scenery_wall.wsw", "rct2.scenery_wall.wswg", "rct2.scenery_wall.wfw1", "rct1.scenery_wall.wooden_fence_red", "rct2.scenery_wall.wfwg", "rct2.scenery_wall.wpf", "rct2.scenery_wall.wpfg", "rct2.scenery_wall.wsw1", "rct2.scenery_wall.wsw2", "rct2.scenery_wall.wbr1", "rct2.scenery_wall.wbrg", "rct2.scenery_wall.wbr2", "rct2.scenery_wall.wbr3", "rct2.scenery_wall.wallmm16", "rct2.scenery_wall.wallmm17", + "rct2.footpath_item.lamp1", "rct2.footpath_item.lamp2", "rct2.footpath_item.litter1", "rct2.footpath_item.bench1", "rct2.footpath_item.qtv1", "rct2.footpath_banner.bn1", "rct2.scenery_wall.wallpost", "rct2.scenery_wall.wallsign", "rct2.scenery_large.ssig1", "rct2.scenery_large.ssig2", "rct2.scenery_large.ssig3", "rct2.scenery_large.ssig4" }, // RCT1_SCENERY_THEME_MINE - { "SMH1 ", "SMH2 ", "SMN1 ", "TBW ", "TBR1 ", "TBR2 ", "TML ", "TMW ", "TBR3 ", "TBR4 ", "TMJ ", "BN5 ", "WALLWD8 ", "WALLWD16", "WALLWD32", "WALLWD33", "WALLMN32", "WDBASE ", "MINROOF1", "ROOF13 ", "LITTERMN" }, + { "rct2.scenery_large.smh1", "rct2.scenery_large.smh2", "rct2.scenery_large.smn1", "rct2.scenery_small.tbw", "rct2.scenery_small.tbr1", "rct2.scenery_small.tbr2", "rct2.scenery_small.tml", "rct2.scenery_small.tmw", "rct2.scenery_small.tbr3", "rct2.scenery_small.tbr4", "rct2.scenery_small.tmj", "rct2.footpath_banner.bn5", "rct2.scenery_wall.wallwd8", "rct2.scenery_wall.wallwd16", "rct2.scenery_wall.wallwd32", "rct2.scenery_wall.wallwd33", "rct2.scenery_wall.wallmn32", "rct2.scenery_small.wdbase", "rct2.scenery_small.minroof1", "rct2.scenery_small.roof13", "rct2.footpath_item.littermn" }, // RCT1_SCENERY_THEME_CLASSICAL_ROMAN - { "SCOL ", "TT1 ", "TRMS ", "TRWS ", "TRC ", "TQF ", "WRW ", "WRWA ", "ROMROOF2", "WC3 ", "ROMROOF1", "BN3 " }, + { "rct2.scenery_large.scol", "rct2.scenery_small.tt1", "rct2.scenery_small.trms", "rct2.scenery_small.trws", "rct2.scenery_small.trc", "rct2.scenery_small.tqf", "rct2.scenery_wall.wrw", "rct2.scenery_wall.wrwa", "rct2.scenery_small.romroof2", "rct2.scenery_wall.wc3", "rct2.scenery_small.romroof1", "rct2.footpath_banner.bn3" }, // RCT1_SCENERY_THEME_EGYPTIAN - { "SSPX ", "SCLN ", "SPYR ", "TES1 ", "TEN ", "TERS ", "TERB ", "TEP ", "WEW ", "LAMP3 ", "BN4 ", "BENCHSTN" }, + { "rct2.scenery_large.sspx", "rct2.scenery_large.scln", "rct2.scenery_large.spyr", "rct2.scenery_small.tes1", "rct2.scenery_small.ten", "rct2.scenery_small.ters", "rct2.scenery_small.terb", "rct2.scenery_small.tep", "rct2.scenery_wall.wew", "rct2.footpath_item.lamp3", "rct2.footpath_banner.bn4", "rct2.footpath_item.benchstn" }, // RCT1_SCENERY_THEME_MARTIAN - { "SMB ", "TMO1 ", "TMO2 ", "TMO3 ", "TMO4 ", "TMO5 ", "SVLC ", "WMW ", "LAMP4 " }, + { "rct2.scenery_large.smb", "rct2.scenery_small.tmo1", "rct2.scenery_small.tmo2", "rct2.scenery_small.tmo3", "rct2.scenery_small.tmo4", "rct2.scenery_small.tmo5", "rct2.scenery_large.svlc", "rct2.scenery_wall.wmw", "rct2.footpath_item.lamp4" }, // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS (Single researchable scenery item) - { "JUMPFNT1" }, + { "rct2.footpath_item.jumpfnt1" }, // RCT1_SCENERY_THEME_WONDERLAND - { "TWH1 ", "TWH2 ", "TST1 ", "TST2 ", "TMS1 ", "TST3 ", "TST4 ", "TST5 ", "TAS1 ", "TAS2 ", "TAS3 ", "TAS4 ", "CHBBASE ", "TP1 ", "TP2 ", "TK1 ", "TK2 ", "TR1 ", "TR2 ", "TQ1 ", "TQ2 ", "TB1 ", "TB2 ", "TK3 ", "TK4 ", "WCW1 ", "WCW2 " }, + { "rct2.scenery_small.twh1", "rct2.scenery_small.twh2", "rct2.scenery_small.tst1", "rct2.scenery_small.tst2", "rct2.scenery_small.tms1", "rct2.scenery_small.tst3", "rct2.scenery_small.tst4", "rct2.scenery_small.tst5", "rct2.scenery_small.tas1", "rct2.scenery_small.tas2", "rct2.scenery_small.tas3", "rct2.scenery_small.tas4", "rct2.scenery_small.chbbase", "rct2.scenery_small.tp1", "rct2.scenery_small.tp2", "rct2.scenery_small.tk1", "rct2.scenery_small.tk2", "rct2.scenery_small.tr1", "rct2.scenery_small.tr2", "rct2.scenery_small.tq1", "rct2.scenery_small.tq2", "rct2.scenery_small.tb1", "rct2.scenery_small.tb2", "rct2.scenery_small.tk3", "rct2.scenery_small.tk4", "rct2.scenery_wall.wcw1", "rct2.scenery_wall.wcw2" }, // RCT1_SCENERY_THEME_JURASSIC - { "TBN ", "TBN1 ", "TDN4 ", "TDN5 ", "SDN1 ", "SDN2 ", "SDN3 ", "WWTW ", "WMWW ", "WWTWA ", "WBW ", "BN6 " }, + { "rct2.scenery_small.tbn", "rct2.scenery_small.tbn1", "rct2.scenery_small.tdn4", "rct2.scenery_small.tdn5", "rct2.scenery_large.sdn1", "rct2.scenery_large.sdn2", "rct2.scenery_large.sdn3", "rct2.scenery_wall.wwtw", "rct2.scenery_wall.wmww", "rct2.scenery_wall.wwtwa", "rct2.scenery_wall.wbw", "rct2.footpath_banner.bn6" }, // RCT1_SCENERY_THEME_SPOOKY, - { "SSK1 ", "TDT1 ", "TDT2 ", "TDT3 ", "TMM1 ", "TMM2 ", "TMM3 ", "TGS1 ", "TGS2 ", "TGS3 ", "TGS4 ", "SMSKULL ", "WALLRK32" }, + { "rct2.scenery_large.ssk1", "rct2.scenery_small.tdt1", "rct2.scenery_small.tdt2", "rct2.scenery_small.tdt3", "rct2.scenery_small.tmm1", "rct2.scenery_small.tmm2", "rct2.scenery_small.tmm3", "rct2.scenery_small.tgs1", "rct2.scenery_small.tgs2", "rct2.scenery_small.tgs3", "rct2.scenery_small.tgs4", "rct2.scenery_small.smskull", "rct2.scenery_wall.wallrk32" }, // RCT1_SCENERY_THEME_JUNGLE - { "TJT1 ", "TJT2 ", "TJB1 ", "TJT3 ", "TJT4 ", "TJP1 ", "TJB2 ", "TJT5 ", "TJB3 ", "TJB4 ", "TJT6 ", "TJP2 ", "TJF ", "WPW1 ", "WPW2 ", "WJF ", "BN2 ", "WALLJN32", "JNGROOF1", "ROOF14 ", "BENCHLOG" }, + { "rct2.scenery_small.tjt1", "rct2.scenery_small.tjt2", "rct2.scenery_small.tjb1", "rct2.scenery_small.tjt3", "rct2.scenery_small.tjt4", "rct2.scenery_small.tjp1", "rct2.scenery_small.tjb2", "rct2.scenery_small.tjt5", "rct2.scenery_small.tjb3", "rct2.scenery_small.tjb4", "rct2.scenery_small.tjt6", "rct2.scenery_small.tjp2", "rct2.scenery_small.tjf", "rct2.scenery_wall.wpw1", "rct2.scenery_wall.wpw2", "rct2.scenery_wall.wjf", "rct2.footpath_banner.bn2", "rct2.scenery_wall.walljn32", "rct2.scenery_small.jngroof1", "rct2.scenery_small.roof14", "rct2.footpath_item.benchlog" }, // RCT1_SCENERY_THEME_ABSTRACT - { "TGE1 ", "TGE2 ", "TGE3 ", "TGE4 ", "TGE5 ", "TGC1 ", "TGC2 ", "WALLGL8 ", "WALLGL16", "WALLGL32", "GEOROOF1", "WGW2 ", "GEOROOF2" }, + { "rct2.scenery_small.tge1", "rct2.scenery_small.tge2", "rct2.scenery_small.tge3", "rct2.scenery_small.tge4", "rct2.scenery_small.tge5", "rct2.scenery_small.tgc1", "rct2.scenery_small.tgc2", "rct2.scenery_wall.wallgl8", "rct2.scenery_wall.wallgl16", "rct2.scenery_wall.wallgl32", "rct2.scenery_small.georoof1", "rct2.scenery_wall.wgw2", "rct2.scenery_small.georoof2" }, // RCT1_SCENERY_THEME_GARDEN_CLOCK (Single researchable scenery item) - { "TCK " }, + { "rct2.scenery_small.tck" }, // RCT1_SCENERY_THEME_SNOW_ICE - { "SIP ", "TSM ", "TIG ", "TSF1 ", "TSF2 ", "TSF3 ", "TSNC ", "TSNB ", "WC16 ", "WC17 ", "WC18 ", "JUMPSNW1", "TCFS ", "TRFS ", "TRF3 ", "TNSS ", "BN8 ", "WALLIG16", "WALLIG24", "IGROOF " }, + { "rct2.scenery_large.sip", "rct2.scenery_small.tsm", "rct2.scenery_small.tig", "rct2.scenery_small.tsf1", "rct2.scenery_small.tsf2", "rct2.scenery_small.tsf3", "rct2.scenery_small.tsnc", "rct2.scenery_small.tsnb", "rct2.scenery_wall.wc16", "rct2.scenery_wall.wc17", "rct2.scenery_wall.wc18", "rct2.footpath_item.jumpsnw1", "rct2.scenery_small.tcfs", "rct2.scenery_small.trfs", "rct2.scenery_small.trf3", "rct2.scenery_small.tnss", "rct2.footpath_banner.bn8", "rct2.scenery_wall.wallig16", "rct2.scenery_wall.wallig24", "rct2.scenery_small.igroof" }, // RCT1_SCENERY_THEME_MEDIEVAL - { "TCT1 ", "STB1 ", "STB2 ", "WC1 ", "WC4 ", "WC5 ", "WC6 ", "WC7 ", "WC8 ", "WALLCZ32", "WALLCY32", "TCT2 ", "STG1 ", "STG2 ", "WC2 ", "WC9 ", "WC10 ", "WC11 ", "WC12 ", "WC13 ", "WALLCW32", "WALLCX32", "TCN ", "TTG ", "SCT ", "SOH1 ", "SOH2 ", "SOH3 ", "WPW3 ", "WALLCFPC", "WALLCBPC" }, + { "rct2.scenery_small.tct1", "rct2.scenery_large.stb1", "rct2.scenery_large.stb2", "rct2.scenery_wall.wc1", "rct2.scenery_wall.wc4", "rct2.scenery_wall.wc5", "rct2.scenery_wall.wc6", "rct2.scenery_wall.wc7", "rct2.scenery_wall.wc8", "rct2.scenery_wall.wallcz32", "rct2.scenery_wall.wallcy32", "rct2.scenery_small.tct2", "rct2.scenery_large.stg1", "rct2.scenery_large.stg2", "rct2.scenery_wall.wc2", "rct2.scenery_wall.wc9", "rct2.scenery_wall.wc10", "rct2.scenery_wall.wc11", "rct2.scenery_wall.wc12", "rct2.scenery_wall.wc13", "rct2.scenery_wall.wallcw32", "rct2.scenery_wall.wallcx32", "rct2.scenery_small.tcn", "rct2.scenery_small.ttg", "rct2.scenery_large.sct", "rct2.scenery_large.soh1", "rct2.scenery_large.soh2", "rct2.scenery_large.soh3", "rct2.scenery_wall.wpw3", "rct2.scenery_wall.wallcfpc", "rct2.scenery_wall.wallcbpc" }, // RCT1_SCENERY_THEME_SPACE - { "SSR ", "SST ", "SSH ", "TSCP ", "TSPH ", "TSC2 ", "TSP1 ", "TSP2 ", "WALLSP32", "SPCROOF1", "BN9 ", "BENCHSPC", "LITTERSP" }, + { "rct2.scenery_large.ssr", "rct2.scenery_large.sst", "rct2.scenery_large.ssh", "rct2.scenery_small.tscp", "rct2.scenery_small.tsph", "rct2.scenery_small.tsc2", "rct2.scenery_small.tsp1", "rct2.scenery_small.tsp2", "rct2.scenery_wall.wallsp32", "rct2.scenery_small.spcroof1", "rct2.footpath_banner.bn9", "rct2.footpath_item.benchspc", "rct2.footpath_item.littersp" }, // RCT1_SCENERY_THEME_CREEPY - { "TCD ", "TSG ", "TSK ", "TGH1 ", "TGH2 ", "TSMP ", "SGP ", "WC14 ", "WC15 ", "TL0 ", "TL1 ", "TL2 ", "TL3 ", "TM0 ", "TM1 ", "TM2 ", "TM3 " }, + { "rct2.scenery_small.tcd", "rct2.scenery_small.tsg", "rct2.scenery_small.tsk", "rct2.scenery_small.tgh1", "rct2.scenery_small.tgh2", "rct2.scenery_small.tsmp", "rct2.scenery_large.sgp", "rct2.scenery_wall.wc14", "rct2.scenery_wall.wc15", "rct2.scenery_small.tl0", "rct2.scenery_small.tl1", "rct2.scenery_small.tl2", "rct2.scenery_small.tl3", "rct2.scenery_small.tm0", "rct2.scenery_small.tm1", "rct2.scenery_small.tm2", "rct2.scenery_small.tm3" }, // RCT1_SCENERY_THEME_URBAN - { "SHS1 ", "SHS2 ", "STH ", "SAH ", "SPS ", "SAH2 ", "SAH3 ", "SOB ", "WALLU132", "WALLU232" }, + { "rct2.scenery_large.shs1", "rct2.scenery_large.shs2", "rct2.scenery_large.sth", "rct2.scenery_large.sah", "rct2.scenery_large.sps", "rct2.scenery_large.sah2", "rct2.scenery_large.sah3", "rct2.scenery_large.sob", "rct2.scenery_wall.wallu132", "rct2.scenery_wall.wallu232" }, // RCT1_SCENERY_THEME_PAGODA - { "SPG ", "TLY ", "TGG ", "TOH1 ", "TOH2 ", "TOT1 ", "TOT2 ", "TOS ", "TOT3 ", "TOT4 ", "TOH3 ", "WALLPG32", "PAGROOF1", "BN7 " } + { "rct2.scenery_large.spg", "rct2.scenery_small.tly", "rct2.scenery_small.tgg", "rct2.scenery_small.toh1", "rct2.scenery_small.toh2", "rct2.scenery_small.tot1", "rct2.scenery_small.tot2", "rct2.scenery_small.tos", "rct2.scenery_small.tot3", "rct2.scenery_small.tot4", "rct2.scenery_small.toh3", "rct2.scenery_wall.wallpg32", "rct2.scenery_small.pagroof1", "rct2.footpath_banner.bn7" } }; return map[sceneryType]; } diff --git a/src/openrct2/rct1/Tables.h b/src/openrct2/rct1/Tables.h index 6667e61eac..b9cdeac19a 100644 --- a/src/openrct2/rct1/Tables.h +++ b/src/openrct2/rct1/Tables.h @@ -25,8 +25,6 @@ namespace RCT1 colour_t GetColour(colour_t colour); PeepSpriteType GetPeepSpriteType(uint8_t rct1SpriteType); - ObjectEntryIndex GetTerrain(uint8_t terrain); - ObjectEntryIndex GetTerrainEdge(uint8_t terrainEdge); uint8_t GetRideType(RideType rideType, uint8_t vehicleType); VehicleColourSchemeCopyDescriptor GetColourSchemeCopyDescriptor(uint8_t vehicleType); @@ -35,15 +33,18 @@ namespace RCT1 uint8_t NormalisePathAddition(uint8_t pathAdditionType); uint8_t GetVehicleSubEntryIndex(uint8_t vehicleSubEntry); - const char* GetRideTypeObject(RideType rideType); - const char* GetVehicleObject(uint8_t vehicleType); - const char* GetSmallSceneryObject(uint8_t smallSceneryType); - const char* GetLargeSceneryObject(uint8_t largeSceneryType); - const char* GetWallObject(uint8_t wallType); - const char* GetPathObject(uint8_t pathType); - const char* GetPathAddtionObject(uint8_t pathAdditionType); - const char* GetSceneryGroupObject(uint8_t sceneryGroupType); - const char* GetWaterObject(uint8_t waterType); + std::string_view GetRideTypeObject(RideType rideType); + std::string_view GetVehicleObject(uint8_t vehicleType); + std::string_view GetSmallSceneryObject(uint8_t smallSceneryType); + std::string_view GetLargeSceneryObject(uint8_t largeSceneryType); + std::string_view GetWallObject(uint8_t wallType); + std::string_view GetPathSurfaceObject(uint8_t pathType); + std::string_view GetPathAddtionObject(uint8_t pathAdditionType); + std::string_view GetFootpathRailingsObject(uint8_t footpathRailingsType); + std::string_view GetSceneryGroupObject(uint8_t sceneryGroupType); + std::string_view GetWaterObject(uint8_t waterType); + std::string_view GetTerrainSurfaceObject(uint8_t terrain); + std::string_view GetTerrainEdgeObject(uint8_t terrainEdge); const std::vector GetSceneryObjects(uint8_t sceneryType); } // namespace RCT1 diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index 65d85ebc93..78e6dd509d 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -12,6 +12,7 @@ #include "../core/String.hpp" #include "../localisation/Formatting.h" #include "../localisation/Localisation.h" +#include "../object/ObjectList.h" #include "../ride/Track.h" #include "../scenario/Scenario.h" #include "../world/Banner.h" @@ -1409,6 +1410,64 @@ std::optional GetStyleFromMusicIdentifier(std::string_view identifier) return std::nullopt; } +void SetDefaultRCT2TerrainObjects(ObjectList& objectList) +{ + // Surfaces + objectList.SetObject(ObjectType::TerrainSurface, 0, "rct2.terrain_surface.grass"); + objectList.SetObject(ObjectType::TerrainSurface, 1, "rct2.terrain_surface.sand"); + objectList.SetObject(ObjectType::TerrainSurface, 2, "rct2.terrain_surface.dirt"); + objectList.SetObject(ObjectType::TerrainSurface, 3, "rct2.terrain_surface.rock"); + objectList.SetObject(ObjectType::TerrainSurface, 4, "rct2.terrain_surface.martian"); + objectList.SetObject(ObjectType::TerrainSurface, 5, "rct2.terrain_surface.chequerboard"); + objectList.SetObject(ObjectType::TerrainSurface, 6, "rct2.terrain_surface.grass_clumps"); + objectList.SetObject(ObjectType::TerrainSurface, 7, "rct2.terrain_surface.ice"); + objectList.SetObject(ObjectType::TerrainSurface, 8, "rct2.terrain_surface.grid_red"); + objectList.SetObject(ObjectType::TerrainSurface, 9, "rct2.terrain_surface.grid_yellow"); + objectList.SetObject(ObjectType::TerrainSurface, 10, "rct2.terrain_surface.grid_purple"); + objectList.SetObject(ObjectType::TerrainSurface, 11, "rct2.terrain_surface.grid_green"); + objectList.SetObject(ObjectType::TerrainSurface, 12, "rct2.terrain_surface.sand_red"); + objectList.SetObject(ObjectType::TerrainSurface, 13, "rct2.terrain_surface.sand_brown"); + objectList.SetObject(ObjectType::TerrainSurface, 14, "rct1aa.terrain_surface.roof_red"); + objectList.SetObject(ObjectType::TerrainSurface, 15, "rct1ll.terrain_surface.roof_grey"); + objectList.SetObject(ObjectType::TerrainSurface, 16, "rct1ll.terrain_surface.rust"); + objectList.SetObject(ObjectType::TerrainSurface, 17, "rct1ll.terrain_surface.wood"); + + // Edges + objectList.SetObject(ObjectType::TerrainEdge, 0, "rct2.terrain_edge.rock"); + objectList.SetObject(ObjectType::TerrainEdge, 1, "rct2.terrain_edge.wood_red"); + objectList.SetObject(ObjectType::TerrainEdge, 2, "rct2.terrain_edge.wood_black"); + objectList.SetObject(ObjectType::TerrainEdge, 3, "rct2.terrain_edge.ice"); + objectList.SetObject(ObjectType::TerrainEdge, 4, "rct1.terrain_edge.brick"); + objectList.SetObject(ObjectType::TerrainEdge, 5, "rct1.terrain_edge.iron"); + objectList.SetObject(ObjectType::TerrainEdge, 6, "rct1aa.terrain_edge.grey"); + objectList.SetObject(ObjectType::TerrainEdge, 7, "rct1aa.terrain_edge.yellow"); + objectList.SetObject(ObjectType::TerrainEdge, 8, "rct1aa.terrain_edge.red"); + objectList.SetObject(ObjectType::TerrainEdge, 9, "rct1ll.terrain_edge.purple"); + objectList.SetObject(ObjectType::TerrainEdge, 10, "rct1ll.terrain_edge.green"); + objectList.SetObject(ObjectType::TerrainEdge, 11, "rct1ll.terrain_edge.stone_brown"); + objectList.SetObject(ObjectType::TerrainEdge, 12, "rct1ll.terrain_edge.stone_grey"); + objectList.SetObject(ObjectType::TerrainEdge, 13, "rct1ll.terrain_edge.skyscraper_a"); + objectList.SetObject(ObjectType::TerrainEdge, 14, "rct1ll.terrain_edge.skyscraper_b"); +} + +void RCT12AddDefaultObjects(ObjectList& objectList) +{ + // Stations + for (size_t i = 0; i < std::size(_stationStyles); i++) + { + objectList.SetObject(ObjectType::Station, static_cast(i), _stationStyles[i]); + } + + // Music + for (size_t i = 0; i < std::size(_musicStyles); i++) + { + if (!_musicStyles[i].empty()) + { + objectList.SetObject(ObjectType::Music, static_cast(i), _musicStyles[i]); + } + } +} + money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue) { if (origValue == RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE) diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 3e23bc95c7..c377e03556 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -944,6 +944,8 @@ track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType); RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType); std::string_view GetStationIdentifierFromStyle(uint8_t style); std::optional GetStyleFromMusicIdentifier(std::string_view identifier); +void SetDefaultRCT2TerrainObjects(ObjectList& objectList); +void RCT12AddDefaultObjects(ObjectList& objectList); static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001; diff --git a/src/openrct2/rct2/RCT2.cpp b/src/openrct2/rct2/RCT2.cpp index 80048c8a10..d2b43cfc74 100644 --- a/src/openrct2/rct2/RCT2.cpp +++ b/src/openrct2/rct2/RCT2.cpp @@ -178,7 +178,7 @@ static FootpathMapping _footpathMappings[] = { { "FUTRPATH", "rct2tt.footpath_surface.circuitboard", "rct2tt.footpath_surface.queue_circuitboard", "rct2tt.footpath_railings.circuitboard" }, { "FUTRPAT2", "rct2tt.footpath_surface.circuitboard", "rct2tt.footpath_surface.queue_circuitboard", - "openrct2.footpath_railings.invisible" }, + "rct2tt.footpath_railings.circuitboard_invisible" }, { "JURRPATH", "rct2tt.footpath_surface.rocky", "rct2.footpath_surface.queue_yellow", "rct2tt.footpath_railings.rocky" }, { "MEDIPATH", "rct2tt.footpath_surface.medieval", "rct2.footpath_surface.queue_yellow", "rct2tt.footpath_railings.medieval" }, diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index f091c5d557..245398b047 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -17,6 +17,7 @@ #include "../ride/VehicleColour.h" #include "../world/EntityList.h" +#include #include constexpr const uint8_t RCT2_MAX_STAFF = 200; diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp deleted file mode 100644 index b283e7356a..0000000000 --- a/src/openrct2/rct2/S6Exporter.cpp +++ /dev/null @@ -1,2127 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#include "S6Exporter.h" - -#include "../Context.h" -#include "../Editor.h" -#include "../Game.h" -#include "../GameState.h" -#include "../OpenRCT2.h" -#include "../common.h" -#include "../config/Config.h" -#include "../core/FileStream.h" -#include "../core/IStream.hpp" -#include "../core/Numerics.hpp" -#include "../core/String.hpp" -#include "../interface/Viewport.h" -#include "../interface/Window.h" -#include "../localisation/Date.h" -#include "../localisation/Localisation.h" -#include "../management/Award.h" -#include "../management/Finance.h" -#include "../management/Marketing.h" -#include "../management/NewsItem.h" -#include "../management/Research.h" -#include "../object/Object.h" -#include "../object/ObjectLimits.h" -#include "../object/ObjectManager.h" -#include "../object/ObjectRepository.h" -#include "../peep/Guest.h" -#include "../peep/RideUseSystem.h" -#include "../peep/Staff.h" -#include "../rct12/SawyerChunkWriter.h" -#include "../ride/Ride.h" -#include "../ride/RideData.h" -#include "../ride/RideRatings.h" -#include "../ride/ShopItem.h" -#include "../ride/Station.h" -#include "../ride/TrackData.h" -#include "../ride/Vehicle.h" -#include "../scenario/Scenario.h" -#include "../util/SawyerCoding.h" -#include "../util/Util.h" -#include "../world/Balloon.h" -#include "../world/Climate.h" -#include "../world/Duck.h" -#include "../world/EntityList.h" -#include "../world/Fountain.h" -#include "../world/Litter.h" -#include "../world/MapAnimation.h" -#include "../world/MoneyEffect.h" -#include "../world/Park.h" -#include "../world/Particle.h" -#include "../world/Sprite.h" - -#include -#include -#include -#include -#include - -#define ENCRYPT_MONEY(money) (static_cast(Numerics::ror32((money), 13) ^ 0xF4EC9621)) - -S6Exporter::S6Exporter() -{ - RemoveTracklessRides = false; - std::memset(&_s6, 0x00, sizeof(_s6)); -} - -void S6Exporter::SaveGame(const utf8* path) -{ - auto fs = OpenRCT2::FileStream(path, OpenRCT2::FILE_MODE_WRITE); - SaveGame(&fs); -} - -void S6Exporter::SaveGame(OpenRCT2::IStream* stream) -{ - Save(stream, false); -} - -void S6Exporter::SaveScenario(const utf8* path) -{ - auto fs = OpenRCT2::FileStream(path, OpenRCT2::FILE_MODE_WRITE); - SaveScenario(&fs); -} - -void S6Exporter::SaveScenario(OpenRCT2::IStream* stream) -{ - Save(stream, true); -} - -void S6Exporter::Save(OpenRCT2::IStream* stream, bool isScenario) -{ - _s6.header.type = isScenario ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME; - _s6.header.classic_flag = 0; - _s6.header.num_packed_objects = uint16_t(ExportObjectsList.size()); - _s6.header.version = S6_RCT2_VERSION; - _s6.header.magic_number = S6_MAGIC_NUMBER; - _s6.game_version_number = 201028; - - auto chunkWriter = SawyerChunkWriter(stream); - - // 0: Write header chunk - chunkWriter.WriteChunk(&_s6.header, SAWYER_ENCODING::ROTATE); - - // 1: Write scenario info chunk - if (_s6.header.type == S6_TYPE_SCENARIO) - { - chunkWriter.WriteChunk(&_s6.info, SAWYER_ENCODING::ROTATE); - } - - // 2: Write packed objects - if (_s6.header.num_packed_objects > 0) - { - auto& objRepo = OpenRCT2::GetContext()->GetObjectRepository(); - objRepo.WritePackedObjects(stream, ExportObjectsList); - } - - // 3: Write available objects chunk - chunkWriter.WriteChunk(_s6.Objects, sizeof(_s6.Objects), SAWYER_ENCODING::ROTATE); - - // 4: Misc fields (data, rand...) chunk - chunkWriter.WriteChunk(&_s6.elapsed_months, 16, SAWYER_ENCODING::RLECOMPRESSED); - - // 5: Map elements + sprites and other fields chunk - chunkWriter.WriteChunk(&_s6.tile_elements, 0x180000, SAWYER_ENCODING::RLECOMPRESSED); - - if (_s6.header.type == S6_TYPE_SCENARIO) - { - // 6 to 13: - chunkWriter.WriteChunk(&_s6.next_free_tile_element_pointer_index, 0x27104C, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.guests_in_park, 4, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.last_guests_in_park, 8, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.park_rating, 2, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.active_research_types, 1082, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.current_expenditure, 16, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.park_value, 4, SAWYER_ENCODING::RLECOMPRESSED); - chunkWriter.WriteChunk(&_s6.completed_company_value, 0x761E8, SAWYER_ENCODING::RLECOMPRESSED); - } - else - { - // 6: Everything else... - chunkWriter.WriteChunk(&_s6.next_free_tile_element_pointer_index, 0x2E8570, SAWYER_ENCODING::RLECOMPRESSED); - } - - // Determine number of bytes written - size_t fileSize = stream->GetLength(); - - // Read all written bytes back into a single buffer - stream->SetPosition(0); - auto data = stream->ReadArray(fileSize); - uint32_t checksum = sawyercoding_calculate_checksum(data.get(), fileSize); - - // Write the checksum on the end - stream->SetPosition(fileSize); - stream->WriteValue(checksum); -} - -static void ride_all_has_any_track_elements(std::array& rideIndexArray) -{ - tile_element_iterator it; - tile_element_iterator_begin(&it); - while (tile_element_iterator_next(&it)) - { - if (it.element->GetType() != TILE_ELEMENT_TYPE_TRACK) - continue; - if (it.element->IsGhost()) - continue; - - rideIndexArray[EnumValue(it.element->AsTrack()->GetRideIndex())] = true; - } -} - -static void scenario_remove_trackless_rides(rct_s6_data* s6) -{ - std::array rideHasTrack{}; - ride_all_has_any_track_elements(rideHasTrack); - for (int32_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) - { - auto ride = &s6->rides[i]; - if (rideHasTrack[i] || ride->type == RIDE_TYPE_NULL) - { - continue; - } - - ride->type = RIDE_TYPE_NULL; - if (is_user_string_id(ride->name)) - { - s6->custom_strings[(ride->name % RCT12_MAX_USER_STRINGS)][0] = 0; - } - } -} - -/** - * Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved. - */ -static void scenario_fix_ghosts(rct_s6_data* s6) -{ - // Build tile pointer cache (needed to get the first element at a certain location) - RCT12TileElement* tilePointers[MAX_TILE_TILE_ELEMENT_POINTERS]; - for (size_t i = 0; i < MAX_TILE_TILE_ELEMENT_POINTERS; i++) - { - tilePointers[i] = TILE_UNDEFINED_TILE_ELEMENT; - } - - RCT12TileElement* tileElement = s6->tile_elements; - RCT12TileElement** tile = tilePointers; - for (size_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (size_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - *tile++ = tileElement; - while (!(tileElement++)->IsLastForTile()) - ; - } - } - - // Remove all ghost elements - RCT12TileElement* destinationElement = s6->tile_elements; - - for (int32_t y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) - { - for (int32_t x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) - { - // This is the equivalent of map_get_first_element_at(x, y), but on S6 data. - RCT12TileElement* originalElement = tilePointers[x + y * MAXIMUM_MAP_SIZE_TECHNICAL]; - do - { - if (originalElement->IsGhost()) - { - uint8_t bannerIndex = originalElement->GetBannerIndex(); - if (bannerIndex != RCT12_BANNER_INDEX_NULL) - { - auto banner = &s6->banners[bannerIndex]; - if (banner->type != RCT12_OBJECT_ENTRY_INDEX_NULL) - { - banner->type = RCT12_OBJECT_ENTRY_INDEX_NULL; - if (is_user_string_id(banner->string_idx)) - s6->custom_strings[(banner->string_idx % RCT12_MAX_USER_STRINGS)][0] = 0; - } - } - } - else - { - *destinationElement++ = *originalElement; - } - } while (!(originalElement++)->IsLastForTile()); - - // Set last element flag in case the original last element was never added - (destinationElement - 1)->flags |= TILE_ELEMENT_FLAG_LAST_TILE; - } - } -} - -template -static void ExportObjectList(IObjectManager& objMgr, T& objects) -{ - for (size_t i = 0; i < TMaxEntries; i++) - { - auto& dst = objects[i]; - - const auto* object = objMgr.GetLoadedObject(TObjectType, i); - if (object == nullptr) - { - // The sv6 format expects null/invalid entries to be filled with 0xFF. - std::memset(&dst, 0xFF, sizeof(dst)); - } - else - { - dst = object->GetObjectEntry(); - } - } -} - -void S6Exporter::Export() -{ - _s6.info = {}; - _s6.info.editor_step = gEditorStep; - _s6.info.category = gScenarioCategory; - _s6.info.objective_type = gScenarioObjective.Type; - _s6.info.objective_arg_1 = gScenarioObjective.Year; - _s6.info.objective_arg_2 = gScenarioObjective.Currency; - _s6.info.objective_arg_3 = gScenarioObjective.NumGuests; - _s6.info.entry.flags = 0xFFFFFFFF; - - { - auto temp = utf8_to_rct2(gScenarioName.c_str()); - safe_strcpy(_s6.info.name, temp.data(), sizeof(_s6.info.name)); - } - { - auto temp = utf8_to_rct2(gScenarioDetails.c_str()); - safe_strcpy(_s6.info.details, temp.data(), sizeof(_s6.info.details)); - } - - uint32_t researchedTrackPiecesA[128] = {}; - uint32_t researchedTrackPiecesB[128] = {}; - - auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager(); - ExportObjectList(objectMgr, _s6.RideObjects); - ExportObjectList(objectMgr, _s6.SceneryObjects); - ExportObjectList(objectMgr, _s6.LargeSceneryObjects); - ExportObjectList(objectMgr, _s6.WallSceneryObjects); - ExportObjectList(objectMgr, _s6.BannerObjects); - ExportObjectList(objectMgr, _s6.PathObjects); - ExportObjectList(objectMgr, _s6.PathAdditionObjects); - ExportObjectList(objectMgr, _s6.SceneryGroupObjects); - ExportObjectList(objectMgr, _s6.ParkEntranceObjects); - ExportObjectList(objectMgr, _s6.WaterObjects); - ExportObjectList(objectMgr, _s6.ScenarioTextObjects); - - _s6.elapsed_months = static_cast(gDateMonthsElapsed); - _s6.current_day = gDateMonthTicks; - _s6.scenario_ticks = gCurrentTicks; - - auto state = scenario_rand_state(); - _s6.scenario_srand_0 = state.s0; - _s6.scenario_srand_1 = state.s1; - - // Map elements must be reorganised prior to saving otherwise save may be invalid - ReorganiseTileElements(); - ExportTileElements(); - ExportEntities(); - ExportParkName(); - - _s6.initial_cash = ToMoney32(gInitialCash); - _s6.current_loan = ToMoney32(gBankLoan); - _s6.park_flags = gParkFlags; - _s6.park_entrance_fee = gParkEntranceFee; - // rct1_park_entrance_x - // rct1_park_entrance_y - // pad_013573EE - // rct1_park_entrance_z - ExportPeepSpawns(); - _s6.guest_count_change_modifier = gGuestChangeModifier; - _s6.current_research_level = gResearchFundingLevel; - // pad_01357400 - ExportResearchedRideTypes(); - ExportResearchedRideEntries(); - // Not used by OpenRCT2 any more, but left in to keep RCT2 export working. - for (uint8_t i = 0; i < std::size(RideTypeDescriptors); i++) - { - researchedTrackPiecesA[i] = (GetRideTypeDescriptor(i).EnabledTrackPieces) & 0xFFFFFFFFULL; - researchedTrackPiecesB[i] = (GetRideTypeDescriptor(i).EnabledTrackPieces >> 32ULL) & 0xFFFFFFFFULL; - } - std::memcpy(_s6.researched_track_types_a, researchedTrackPiecesA, sizeof(_s6.researched_track_types_a)); - std::memcpy(_s6.researched_track_types_b, researchedTrackPiecesB, sizeof(_s6.researched_track_types_b)); - - _s6.guests_in_park = gNumGuestsInPark; - _s6.guests_heading_for_park = gNumGuestsHeadingForPark; - - for (size_t i = 0; i < RCT12_EXPENDITURE_TABLE_MONTH_COUNT; i++) - { - for (size_t j = 0; j < RCT12_EXPENDITURE_TYPE_COUNT; j++) - { - _s6.expenditure_table[i][j] = ToMoney32(gExpenditureTable[i][j]); - } - } - - _s6.last_guests_in_park = gNumGuestsInParkLastWeek; - // pad_01357BCA - _s6.handyman_colour = gStaffHandymanColour; - _s6.mechanic_colour = gStaffMechanicColour; - _s6.security_colour = gStaffSecurityColour; - - ExportResearchedSceneryItems(); - - _s6.park_rating = gParkRating; - - std::copy(std::begin(gParkRatingHistory), std::end(gParkRatingHistory), _s6.park_rating_history); - std::fill(std::begin(_s6.guests_in_park_history), std::end(_s6.guests_in_park_history), RCT12ParkHistoryUndefined); - for (size_t i = 0; i < std::size(gGuestsInParkHistory); i++) - { - if (gGuestsInParkHistory[i] != GuestsInParkHistoryUndefined) - { - _s6.guests_in_park_history[i] = std::min(gGuestsInParkHistory[i], 5000) / RCT12GuestsInParkHistoryFactor; - } - } - - std::memcpy(_s6.guests_in_park_history, gGuestsInParkHistory, sizeof(_s6.guests_in_park_history)); - - _s6.active_research_types = gResearchPriorities; - _s6.research_progress_stage = gResearchProgressStage; - if (gResearchLastItem.has_value()) - _s6.last_researched_item_subject = gResearchLastItem->ToRCT12ResearchItem().rawValue; - else - _s6.last_researched_item_subject = RCT12_RESEARCHED_ITEMS_SEPARATOR; - // pad_01357CF8 - _s6.research_progress = gResearchProgress; - - if (gResearchNextItem.has_value()) - { - auto RCT2ResearchItem = gResearchNextItem->ToRCT12ResearchItem(); - _s6.next_research_item = RCT2ResearchItem.rawValue; - _s6.next_research_category = RCT2ResearchItem.category; - } - else - { - _s6.next_research_item = RCT12_RESEARCHED_ITEMS_SEPARATOR; - _s6.next_research_category = 0; - } - - _s6.next_research_expected_day = gResearchExpectedDay; - _s6.next_research_expected_month = gResearchExpectedMonth; - _s6.guest_initial_happiness = gGuestInitialHappiness; - _s6.park_size = gParkSize; - _s6.guest_generation_probability = _guestGenerationProbability; - _s6.total_ride_value_for_money = gTotalRideValueForMoney; - _s6.maximum_loan = ToMoney32(gMaxBankLoan); - _s6.guest_initial_cash = gGuestInitialCash; - _s6.guest_initial_hunger = gGuestInitialHunger; - _s6.guest_initial_thirst = gGuestInitialThirst; - _s6.objective_type = gScenarioObjective.Type; - _s6.objective_year = gScenarioObjective.Year; - // pad_013580FA - _s6.objective_currency = gScenarioObjective.Currency; - // In RCT2, the ride string IDs start at index STR_0002 and are directly mappable. - // This is not always the case in OpenRCT2, so we use the actual ride ID. - if (gScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST) - _s6.objective_guests = gScenarioObjective.RideId + RCT2_RIDE_STRING_START; - else - _s6.objective_guests = gScenarioObjective.NumGuests; - - ExportMarketingCampaigns(); - - _s6.current_expenditure = ToMoney32(gCurrentExpenditure); - _s6.current_profit = ToMoney32(gCurrentProfit); - _s6.weekly_profit_average_dividend = ToMoney32(gWeeklyProfitAverageDividend); - _s6.weekly_profit_average_divisor = gWeeklyProfitAverageDivisor; - // pad_0135833A - - _s6.park_value = ToMoney32(gParkValue); - - for (size_t i = 0; i < RCT12_FINANCE_GRAPH_SIZE; i++) - { - _s6.balance_history[i] = ToMoney32(gCashHistory[i]); - _s6.weekly_profit_history[i] = ToMoney32(gWeeklyProfitHistory[i]); - _s6.park_value_history[i] = ToMoney32(gParkValueHistory[i]); - } - - _s6.completed_company_value = OpenRCT2CompletedCompanyValueToRCT12(gScenarioCompletedCompanyValue); - _s6.total_admissions = gTotalAdmissions; - _s6.income_from_admissions = ToMoney32(gTotalIncomeFromAdmissions); - _s6.company_value = ToMoney32(gCompanyValue); - std::memcpy(_s6.peep_warning_throttle, gPeepWarningThrottle, sizeof(_s6.peep_warning_throttle)); - - // Awards - for (int32_t i = 0; i < RCT12_MAX_AWARDS; i++) - { - Award* src = &gCurrentAwards[i]; - rct12_award* dst = &_s6.awards[i]; - dst->time = src->Time; - dst->type = src->Type; - } - - _s6.land_price = gLandPrice; - _s6.construction_rights_price = gConstructionRightsPrice; - // unk_01358774 - // pad_01358776 - // _s6.cd_key - // _s6.game_version_number - _s6.completed_company_value_record = gScenarioCompanyValueRecord; - _s6.loan_hash = GetLoanHash(gInitialCash, gBankLoan, gMaxBankLoan); - _s6.ride_count = ride_get_count(); - // pad_013587CA - _s6.historical_profit = ToMoney32(gHistoricalProfit); - // pad_013587D4 - String::Set(_s6.scenario_completed_name, sizeof(_s6.scenario_completed_name), gScenarioCompletedBy.c_str()); - _s6.cash = ENCRYPT_MONEY(ToMoney32(gCash)); - // pad_013587FC - _s6.park_rating_casualty_penalty = gParkRatingCasualtyPenalty; - _s6.map_size_units = GetMapSizeUnits(); - _s6.map_size_minus_2 = GetMapSizeMinus2(); - _s6.map_size = gMapSize; - _s6.map_max_xy = GetMapSizeMaxXY(); - _s6.same_price_throughout = gSamePriceThroughoutPark & 0xFFFFFFFF; - _s6.suggested_max_guests = _suggestedGuestMaximum; - _s6.park_rating_warning_days = gScenarioParkRatingWarningDays; - _s6.last_entrance_style = gLastEntranceStyle; - // rct1_water_colour - // pad_01358842 - ExportResearchList(); - _s6.map_base_z = gMapBaseZ; - String::Set(_s6.scenario_name, sizeof(_s6.scenario_name), gScenarioName.c_str()); - String::Set(_s6.scenario_description, sizeof(_s6.scenario_description), gScenarioDetails.c_str()); - _s6.current_interest_rate = gBankLoanInterestRate; - // pad_0135934B - _s6.same_price_throughout_extended = gSamePriceThroughoutPark >> 32; - // Preserve compatibility with vanilla RCT2's save format. - for (uint8_t i = 0; i < RCT12_MAX_PARK_ENTRANCES; i++) - { - CoordsXYZD entrance = { LOCATION_NULL, LOCATION_NULL, 0, 0 }; - if (gParkEntrances.size() > i) - { - entrance = gParkEntrances[i]; - } - _s6.park_entrance_x[i] = entrance.x; - _s6.park_entrance_y[i] = entrance.y; - _s6.park_entrance_z[i] = entrance.z; - _s6.park_entrance_direction[i] = entrance.direction; - } - safe_strcpy(_s6.scenario_filename, gScenarioFileName, sizeof(_s6.scenario_filename)); - std::memcpy(_s6.saved_expansion_pack_names, gScenarioExpansionPacks, sizeof(_s6.saved_expansion_pack_names)); - ExportBanners(); - _s6.game_ticks_1 = gCurrentTicks; - - this->ExportRides(); - - _s6.saved_age = gSavedAge; - _s6.saved_view_x = gSavedView.x; - _s6.saved_view_y = gSavedView.y; - _s6.saved_view_zoom = static_cast(std::clamp(gSavedViewZoom, 0, 3)); - _s6.saved_view_rotation = gSavedViewRotation; - - ExportMapAnimations(); - - ExportRideRatingsCalcData(); - ExportRideMeasurements(); - _s6.next_guest_index = gNextGuestNumber; - _s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition; - ExportStaffPatrolAreas(); - // unk_13CA73E - // pad_13CA73F - // unk_13CA740 - _s6.climate = static_cast(gClimate); - // pad_13CA741; - // byte_13CA742 - // pad_013CA747 - _s6.climate_update_timer = gClimateUpdateTimer; - _s6.current_weather = EnumValue(gClimateCurrent.Weather); - _s6.next_weather = EnumValue(gClimateNext.Weather); - _s6.temperature = gClimateCurrent.Temperature; - _s6.next_temperature = gClimateNext.Temperature; - _s6.current_weather_effect = static_cast(gClimateCurrent.WeatherEffect); - _s6.next_weather_effect = static_cast(gClimateNext.WeatherEffect); - _s6.current_weather_gloom = gClimateCurrent.WeatherGloom; - _s6.next_weather_gloom = gClimateNext.WeatherGloom; - _s6.current_weather_level = static_cast(gClimateCurrent.Level); - _s6.next_weather_level = static_cast(gClimateNext.Level); - - // News items - for (size_t i = 0; i < RCT12_MAX_NEWS_ITEMS; i++) - { - const News::Item* src = &gNewsItems[i]; - rct12_news_item* dst = &_s6.news_items[i]; - - dst->Type = static_cast(src->Type); - dst->Flags = src->Flags; - dst->Assoc = src->Assoc; - dst->Ticks = src->Ticks; - dst->MonthYear = src->MonthYear; - dst->Day = src->Day; - - auto rct2text = ConvertFormattedStringToRCT2(src->Text, sizeof(dst->Text)); - std::memcpy(dst->Text, rct2text.c_str(), std::min(sizeof(dst->Text), rct2text.size())); - } - - // pad_13CE730 - // rct1_scenario_flags - _s6.wide_path_tile_loop_x = gWidePathTileLoopPosition.x; - _s6.wide_path_tile_loop_y = gWidePathTileLoopPosition.y; - // pad_13CE778 - - String::Set(_s6.scenario_filename, sizeof(_s6.scenario_filename), gScenarioFileName); - - if (RemoveTracklessRides) - { - scenario_remove_trackless_rides(&_s6); - } - - scenario_fix_ghosts(&_s6); - game_convert_strings_to_rct2(&_s6); - - ExportUserStrings(); -} - -void S6Exporter::ExportPeepSpawns() -{ - for (size_t i = 0; i < RCT12_MAX_PEEP_SPAWNS; i++) - { - if (gPeepSpawns.size() > i) - { - _s6.peep_spawns[i] = { static_cast(gPeepSpawns[i].x), static_cast(gPeepSpawns[i].y), - static_cast(gPeepSpawns[i].z / 16), gPeepSpawns[i].direction }; - } - else - { - _s6.peep_spawns[i] = { RCT12_PEEP_SPAWN_UNDEFINED, RCT12_PEEP_SPAWN_UNDEFINED, 0, 0 }; - } - } -} - -uint32_t S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32_t maxBankLoan) -{ - int32_t value = 0x70093A; - value -= initialCash; - value = Numerics::ror32(value, 5); - value -= bankLoan; - value = Numerics::ror32(value, 7); - value += maxBankLoan; - value = Numerics::ror32(value, 3); - return value; -} - -void S6Exporter::ExportParkName() -{ - auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); - auto stringId = AllocateUserString(park.Name); - if (stringId.has_value()) - { - _s6.park_name = stringId.value(); - _s6.park_name_args = 0; - } - else - { - log_warning("Unable to allocate user string for park name during S6 export."); - _s6.park_name = STR_UNNAMED_PARK; - _s6.park_name_args = 0; - } -} - -void S6Exporter::ExportRides() -{ - const Ride nullRide{}; - for (int32_t index = 0; index < RCT12_MAX_RIDES_IN_PARK; index++) - { - const auto* src = get_ride(static_cast(index)); - if (src == nullptr) - { - src = &nullRide; - } - auto dst = &_s6.rides[index]; - *dst = {}; - if (src->type == RIDE_TYPE_NULL) - { - dst->type = RIDE_TYPE_NULL; - } - else - { - ExportRide(dst, src); - } - } -} - -void S6Exporter::ExportRide(rct2_ride* dst, const Ride* src) -{ - std::memset(dst, 0, sizeof(rct2_ride)); - - dst->type = OpenRCT2RideTypeToRCT2RideType(src->type); - dst->subtype = OpenRCT2EntryIndexToRCTEntryIndex(src->subtype); - // pad_002; - dst->mode = static_cast(src->mode); - dst->colour_scheme_type = src->colour_scheme_type; - - for (uint8_t i = 0; i < RCT2_MAX_CARS_PER_TRAIN; i++) - { - dst->vehicle_colours[i].body_colour = src->vehicle_colours[i].Body; - dst->vehicle_colours[i].trim_colour = src->vehicle_colours[i].Trim; - } - - // pad_046; - dst->status = EnumValue(src->status); - - bool useDefaultName = true; - if (!src->custom_name.empty()) - { - // Custom name, allocate user string for ride - auto stringId = AllocateUserString(src->custom_name); - if (stringId.has_value()) - { - dst->name = stringId.value(); - dst->name_arguments = 0; - useDefaultName = false; - } - else - { - log_warning( - "Unable to allocate user string for ride #%d (%s).", static_cast(src->id), src->custom_name.c_str()); - } - } - if (useDefaultName) - { - // Default name with number - dst->name = GetRideTypeDescriptor(src->type).Naming.Name; - dst->name_arguments_number = src->default_name_number; - } - - if (src->overall_view.IsNull()) - { - dst->overall_view.SetNull(); - } - else - { - auto tileLoc = TileCoordsXY(src->overall_view); - dst->overall_view = { static_cast(tileLoc.x), static_cast(tileLoc.y) }; - } - - for (int32_t i = 0; i < RCT12_MAX_STATIONS_PER_RIDE; i++) - { - if (src->stations[i].Start.IsNull()) - { - dst->station_starts[i].SetNull(); - } - else - { - auto tileStartLoc = TileCoordsXY(src->stations[i].Start); - dst->station_starts[i] = { static_cast(tileStartLoc.x), static_cast(tileStartLoc.y) }; - } - dst->station_heights[i] = src->stations[i].Height; - dst->station_length[i] = src->stations[i].Length; - dst->station_depart[i] = src->stations[i].Depart; - dst->train_at_station[i] = src->stations[i].TrainAtStation; - - TileCoordsXYZD entrance = ride_get_entrance_location(src, i); - if (entrance.IsNull()) - dst->entrances[i].SetNull(); - else - dst->entrances[i] = { static_cast(entrance.x), static_cast(entrance.y) }; - - TileCoordsXYZD exit = ride_get_exit_location(src, i); - if (exit.IsNull()) - dst->exits[i].SetNull(); - else - dst->exits[i] = { static_cast(exit.x), static_cast(exit.y) }; - - dst->last_peep_in_queue[i] = src->stations[i].LastPeepInQueue; - - dst->length[i] = src->stations[i].SegmentLength; - dst->time[i] = src->stations[i].SegmentTime; - - dst->queue_time[i] = src->stations[i].QueueTime; - - dst->queue_length[i] = src->stations[i].QueueLength; - } - - for (uint8_t i = 0; i <= RCT2_MAX_VEHICLES_PER_RIDE; i++) - { - dst->vehicles[i] = src->vehicles[i]; - } - - dst->depart_flags = src->depart_flags; - - dst->num_stations = src->num_stations; - dst->num_vehicles = src->num_vehicles; - dst->num_cars_per_train = src->num_cars_per_train; - dst->proposed_num_vehicles = src->proposed_num_vehicles; - dst->proposed_num_cars_per_train = src->proposed_num_cars_per_train; - dst->max_trains = src->max_trains; - dst->SetMinCarsPerTrain(src->MinCarsPerTrain); - dst->SetMaxCarsPerTrain(src->MaxCarsPerTrain); - dst->min_waiting_time = src->min_waiting_time; - dst->max_waiting_time = src->max_waiting_time; - - // Includes time_limit, num_laps, launch_speed, speed, rotations - dst->operation_option = src->operation_option; - - dst->boat_hire_return_direction = src->boat_hire_return_direction; - dst->boat_hire_return_position = { static_cast(src->boat_hire_return_position.x), - static_cast(src->boat_hire_return_position.y) }; - - dst->special_track_elements = src->special_track_elements; - // pad_0D6[2]; - - dst->max_speed = src->max_speed; - dst->average_speed = src->average_speed; - dst->current_test_segment = src->current_test_segment; - dst->average_speed_test_timeout = src->average_speed_test_timeout; - // pad_0E2[0x2]; - - dst->max_positive_vertical_g = src->max_positive_vertical_g; - dst->max_negative_vertical_g = src->max_negative_vertical_g; - dst->max_lateral_g = src->max_lateral_g; - dst->previous_vertical_g = src->previous_vertical_g; - dst->previous_lateral_g = src->previous_lateral_g; - // pad_106[0x2]; - dst->testing_flags = src->testing_flags; - - if (src->CurTestTrackLocation.IsNull()) - { - dst->cur_test_track_location.SetNull(); - } - else - { - dst->cur_test_track_location = { static_cast(src->CurTestTrackLocation.x), - static_cast(src->CurTestTrackLocation.y) }; - dst->cur_test_track_z = static_cast(src->CurTestTrackLocation.z); - } - - dst->turn_count_default = src->turn_count_default; - dst->turn_count_banked = src->turn_count_banked; - dst->turn_count_sloped = src->turn_count_sloped; - if (dst->type == RIDE_TYPE_MINI_GOLF) - dst->inversions = static_cast(std::min(src->holes, RCT12_MAX_GOLF_HOLES)); - else - dst->inversions = static_cast(std::min(src->inversions, RCT12_MAX_INVERSIONS)); - dst->inversions |= (src->sheltered_eighths << 5); - dst->drops = src->drops; - dst->start_drop_height = src->start_drop_height; - dst->highest_drop_height = src->highest_drop_height; - dst->sheltered_length = src->sheltered_length; - dst->var_11C = src->var_11C; - dst->num_sheltered_sections = src->num_sheltered_sections; - - dst->cur_num_customers = src->cur_num_customers; - dst->num_customers_timeout = src->num_customers_timeout; - - for (uint8_t i = 0; i < RCT2_CUSTOMER_HISTORY_SIZE; i++) - { - dst->num_customers[i] = src->num_customers[i]; - } - - dst->price = src->price[0]; - - for (uint8_t i = 0; i < 2; i++) - { - dst->chairlift_bullwheel_location[i] = { static_cast(src->ChairliftBullwheelLocation[i].x), - static_cast(src->ChairliftBullwheelLocation[i].y) }; - dst->chairlift_bullwheel_z[i] = static_cast(src->ChairliftBullwheelLocation[i].z); - } - - dst->ratings = src->ratings; - dst->value = src->value; - - dst->chairlift_bullwheel_rotation = src->chairlift_bullwheel_rotation; - - dst->satisfaction = src->satisfaction; - dst->satisfaction_time_out = src->satisfaction_time_out; - dst->satisfaction_next = src->satisfaction_next; - - dst->window_invalidate_flags = src->window_invalidate_flags; - // pad_14E[0x02]; - - dst->total_customers = src->total_customers; - dst->total_profit = ToMoney32(src->total_profit); - dst->popularity = src->popularity; - dst->popularity_time_out = src->popularity_time_out; - dst->popularity_next = src->popularity_next; - dst->num_riders = src->num_riders; - dst->music_tune_id = src->music_tune_id; - dst->slide_in_use = src->slide_in_use; - // Includes maze_tiles - dst->slide_peep = src->slide_peep; - // pad_160[0xE]; - dst->slide_peep_t_shirt_colour = src->slide_peep_t_shirt_colour; - // pad_16F[0x7]; - dst->spiral_slide_progress = src->spiral_slide_progress; - // pad_177[0x9]; - dst->build_date = static_cast(src->build_date); - dst->upkeep_cost = src->upkeep_cost; - dst->race_winner = src->race_winner; - // pad_186[0x02]; - dst->music_position = src->music_position; - - dst->breakdown_reason_pending = src->breakdown_reason_pending; - dst->mechanic_status = src->mechanic_status; - dst->mechanic = src->mechanic; - dst->inspection_station = src->inspection_station; - dst->broken_vehicle = src->broken_vehicle; - dst->broken_car = src->broken_car; - dst->breakdown_reason = src->breakdown_reason; - - dst->price_secondary = src->price[1]; - - dst->reliability = src->reliability; - dst->unreliability_factor = src->unreliability_factor; - dst->downtime = src->downtime; - dst->inspection_interval = src->inspection_interval; - dst->last_inspection = src->last_inspection; - - for (uint8_t i = 0; i < RCT2_DOWNTIME_HISTORY_SIZE; i++) - { - dst->downtime_history[i] = src->downtime_history[i]; - } - - dst->no_primary_items_sold = src->no_primary_items_sold; - dst->no_secondary_items_sold = src->no_secondary_items_sold; - - dst->breakdown_sound_modifier = src->breakdown_sound_modifier; - dst->not_fixed_timeout = src->not_fixed_timeout; - dst->last_crash_type = src->last_crash_type; - dst->connected_message_throttle = src->connected_message_throttle; - - dst->income_per_hour = src->income_per_hour; - dst->profit = ToMoney32(src->profit); - - for (uint8_t i = 0; i < RCT12_NUM_COLOUR_SCHEMES; i++) - { - dst->track_colour_main[i] = src->track_colour[i].main; - dst->track_colour_additional[i] = src->track_colour[i].additional; - dst->track_colour_supports[i] = src->track_colour[i].supports; - } - - dst->music = src->music; - dst->entrance_style = src->entrance_style; - dst->vehicle_change_timeout = src->vehicle_change_timeout; - dst->num_block_brakes = src->num_block_brakes; - dst->lift_hill_speed = src->lift_hill_speed; - dst->guests_favourite = src->guests_favourite; - dst->lifecycle_flags = src->lifecycle_flags; - - for (uint8_t i = 0; i < RCT2_MAX_CARS_PER_TRAIN; i++) - { - dst->vehicle_colours_extended[i] = src->vehicle_colours[i].Ternary; - } - - dst->total_air_time = src->total_air_time; - dst->current_test_station = src->current_test_station; - dst->num_circuits = src->num_circuits; - dst->cable_lift_x = static_cast(src->CableLiftLoc.x); - dst->cable_lift_y = static_cast(src->CableLiftLoc.y); - dst->cable_lift_z = static_cast(src->CableLiftLoc.z / COORDS_Z_STEP); - // pad_1FD; - dst->cable_lift = src->cable_lift; - - // pad_208[0x58]; -} - -void S6Exporter::ExportRideRatingsCalcData() -{ - const auto& src = gRideRatingUpdateState; - auto& dst = _s6.ride_ratings_calc_data; - dst.proximity_x = src.Proximity.x; - dst.proximity_y = src.Proximity.y; - dst.proximity_z = src.Proximity.z; - dst.proximity_start_x = src.ProximityStart.x; - dst.proximity_start_y = src.ProximityStart.y; - dst.proximity_start_z = src.ProximityStart.z; - dst.current_ride = OpenRCT2RideIdToRCT12RideId(src.CurrentRide); - dst.state = src.State; - if (src.ProximityTrackType == TrackElemType::None) - dst.proximity_track_type = 0xFF; - else - dst.proximity_track_type = OpenRCT2TrackTypeToRCT2(src.ProximityTrackType); - dst.proximity_base_height = src.ProximityBaseHeight; - dst.proximity_total = src.ProximityTotal; - for (size_t i = 0; i < std::size(dst.proximity_scores); i++) - { - dst.proximity_scores[i] = src.ProximityScores[i]; - } - dst.num_brakes = src.AmountOfBrakes; - dst.num_reversers = src.AmountOfReversers; - dst.station_flags = src.StationFlags; -} - -void S6Exporter::ExportRideMeasurements() -{ - // Get all the ride measurements - std::vector ridesWithMeasurements; - for (size_t i = 0; i < RCT12_MAX_RIDES_IN_PARK; i++) - { - auto ride = get_ride(static_cast(i)); - if (ride != nullptr && ride->measurement != nullptr) - { - ridesWithMeasurements.push_back(ride); - } - } - - // If there are more than S6 can hold, trim it by LRU - if (ridesWithMeasurements.size() > RCT12_RIDE_MEASUREMENT_MAX_ITEMS) - { - // Sort in order of last recently used - std::sort(ridesWithMeasurements.begin(), ridesWithMeasurements.end(), [](const Ride* a, const Ride* b) { - return a->measurement->last_use_tick > b->measurement->last_use_tick; - }); - ridesWithMeasurements.resize(RCT12_RIDE_MEASUREMENT_MAX_ITEMS); - } - - // Convert ride measurements to S6 format - uint8_t i{}; - for (auto src : ridesWithMeasurements) - { - auto& dst = _s6.ride_measurements[i]; - ExportRideMeasurement(_s6.ride_measurements[i], *src->measurement.get()); - - auto rideId = src->id; - dst.ride_index = static_cast(rideId); - _s6.rides[dst.ride_index].measurement_index = i; - i++; - } -} - -void S6Exporter::ExportRideMeasurement(RCT12RideMeasurement& dst, const RideMeasurement& src) -{ - dst.flags = src.flags; - dst.last_use_tick = src.last_use_tick; - dst.num_items = src.num_items; - dst.current_item = src.current_item; - dst.vehicle_index = src.vehicle_index; - dst.current_station = src.current_station; - for (size_t i = 0; i < std::size(src.velocity); i++) - { - dst.velocity[i] = src.velocity[i]; - dst.altitude[i] = src.altitude[i]; - dst.vertical[i] = src.vertical[i]; - dst.lateral[i] = src.lateral[i]; - } -} - -void S6Exporter::ExportResearchedRideTypes() -{ - std::fill(std::begin(_s6.researched_ride_types), std::end(_s6.researched_ride_types), false); - - for (int32_t rideType = 0; rideType < RCT2_RIDE_TYPE_COUNT; rideType++) - { - if (ride_type_is_invented(rideType)) - { - int32_t quadIndex = rideType >> 5; - int32_t bitIndex = rideType & 0x1F; - _s6.researched_ride_types[quadIndex] |= 1UL << bitIndex; - } - } -} - -void S6Exporter::ExportResearchedRideEntries() -{ - std::fill(std::begin(_s6.researched_ride_entries), std::end(_s6.researched_ride_entries), false); - - for (int32_t rideEntryIndex = 0; rideEntryIndex < MAX_RIDE_OBJECTS; rideEntryIndex++) - { - if (ride_entry_is_invented(rideEntryIndex)) - { - int32_t quadIndex = rideEntryIndex >> 5; - int32_t bitIndex = rideEntryIndex & 0x1F; - _s6.researched_ride_entries[quadIndex] |= 1UL << bitIndex; - } - } -} - -void S6Exporter::ExportResearchedSceneryItems() -{ - std::fill(std::begin(_s6.researched_scenery_items), std::end(_s6.researched_scenery_items), false); - - for (uint16_t sceneryEntryIndex = 0; sceneryEntryIndex < RCT2_MAX_RESEARCHED_SCENERY_ITEMS; sceneryEntryIndex++) - { - ScenerySelection scenerySelection = { static_cast((sceneryEntryIndex >> 8) & 0xFF), - static_cast(sceneryEntryIndex & 0xFF) }; - - // SV6 allows for more scenery types than there are. Avoid triggering an assertion in scenery_is_invented(). - if (scenerySelection.SceneryType >= SCENERY_TYPE_COUNT) - break; - - if (scenery_is_invented(scenerySelection)) - { - int32_t quadIndex = sceneryEntryIndex >> 5; - int32_t bitIndex = sceneryEntryIndex & 0x1F; - _s6.researched_scenery_items[quadIndex] |= 1UL << bitIndex; - } - } -} - -void S6Exporter::ExportResearchList() -{ - size_t i = 0; - for (const auto& researchItem : gResearchItemsInvented) - { - _s6.research_items[i++] = researchItem.ToRCT12ResearchItem(); - } - _s6.research_items[i++] = { RCT12_RESEARCHED_ITEMS_SEPARATOR, 0 }; - for (const auto& researchItem : gResearchItemsUninvented) - { - _s6.research_items[i++] = researchItem.ToRCT12ResearchItem(); - } - _s6.research_items[i++] = { RCT12_RESEARCHED_ITEMS_END, 0 }; - _s6.research_items[i] = { RCT12_RESEARCHED_ITEMS_END_2, 0 }; -} - -void S6Exporter::ExportMarketingCampaigns() -{ - std::memset(_s6.campaign_weeks_left, 0, sizeof(_s6.campaign_weeks_left)); - std::memset(_s6.campaign_ride_index, 0, sizeof(_s6.campaign_ride_index)); - for (const auto& campaign : gMarketingCampaigns) - { - _s6.campaign_weeks_left[campaign.Type] = campaign.WeeksLeft | CAMPAIGN_ACTIVE_FLAG; - if ((campaign.Flags & MarketingCampaignFlags::FIRST_WEEK)) - _s6.campaign_weeks_left[campaign.Type] |= CAMPAIGN_FIRST_WEEK_FLAG; - if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE) - { - _s6.campaign_ride_index[campaign.Type] = OpenRCT2RideIdToRCT12RideId(campaign.RideId); - } - else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) - { - _s6.campaign_ride_index[campaign.Type] = EnumValue(campaign.ShopItemType); - } - } -} - -void S6Exporter::RebuildEntitySpatialLocation(const TileCoordsXY& loc) -{ - uint16_t previous = SPRITE_INDEX_NULL; - for (auto* entity : EntityTileList(loc.ToCoordsXY())) - { - if (previous != SPRITE_INDEX_NULL) - { - _s6.sprites[previous].unknown.next_in_quadrant = entity->sprite_index; - } - previous = entity->sprite_index; - } - if (previous != SPRITE_INDEX_NULL) - { - _s6.sprites[previous].unknown.next_in_quadrant = SPRITE_INDEX_NULL; - } -} - -void S6Exporter::ExportStaffPatrolAreas() -{ - std::fill(std::begin(_s6.staff_modes), std::end(_s6.staff_modes), RCT2StaffMode::None); - std::fill(std::begin(_s6.patrol_areas), std::end(_s6.patrol_areas), 0); - - auto staffId = 0; - for (auto* staff : EntityList()) - { - if (staff->HasPatrolArea()) - { - const size_t staffPatrolOffset = staffId * STAFF_PATROL_AREA_SIZE; - std::copy( - std::begin(staff->PatrolInfo->Data), std::end(staff->PatrolInfo->Data), &_s6.patrol_areas[staffPatrolOffset]); - _s6.staff_modes[staffId] = RCT2StaffMode::Patrol; - } - else - { - _s6.staff_modes[staffId] = RCT2StaffMode::Walk; - } - - _s6.sprites[staff->sprite_index].peep.staff_id = staffId; - - staffId++; - } - - constexpr auto hasData = [](const auto& datapoint) { return datapoint != 0; }; - for (const auto type : { StaffType::Handyman, StaffType::Mechanic, StaffType::Security, StaffType::Entertainer }) - { - const size_t staffPatrolOffset = (EnumValue(type) + STAFF_MAX_COUNT) * STAFF_PATROL_AREA_SIZE; - const auto& area = GetMergedPatrolArea(type); - std::copy(std::begin(area.Data), std::end(area.Data), &_s6.patrol_areas[staffPatrolOffset]); - if (std::any_of(std::begin(area.Data), std::end(area.Data), hasData)) - { - _s6.staff_modes[EnumValue(type) + STAFF_MAX_COUNT] = RCT2StaffMode::Patrol; - } - else - { - _s6.staff_modes[EnumValue(type) + STAFF_MAX_COUNT] = RCT2StaffMode::Walk; - } - } -} - -void S6Exporter::RebuildEntityLinks() -{ - // Rebuild next/previous linked list entity indexs - for (auto list : - { RCT12EntityLinkListOffset::Free, RCT12EntityLinkListOffset::Litter, RCT12EntityLinkListOffset::Misc, - RCT12EntityLinkListOffset::Peep, RCT12EntityLinkListOffset::TrainHead, RCT12EntityLinkListOffset::Vehicle }) - { - uint16_t previous = SPRITE_INDEX_NULL; - // Intialise Head to NULL for situations where there are no entities of this type. - _s6.sprite_lists_head[EnumValue(list) >> 1] = SPRITE_INDEX_NULL; - - for (auto& entity : _s6.sprites) - { - if (entity.unknown.linked_list_type_offset == list) - { - _s6.sprite_lists_count[EnumValue(list) >> 1]++; - _s6.sprites[entity.unknown.sprite_index].unknown.previous = previous; - if (previous != SPRITE_INDEX_NULL) - { - _s6.sprites[previous].unknown.next = entity.unknown.sprite_index; - } - else - { - _s6.sprite_lists_head[EnumValue(list) >> 1] = entity.unknown.sprite_index; - } - _s6.sprites[entity.unknown.sprite_index].unknown.next = SPRITE_INDEX_NULL; - previous = entity.unknown.sprite_index; - } - } - } - - // Rebuild next_in_quadrant linked list entity indexs - // This in theory is not required but to be on the safe side we are rebuilding it. - for (auto x = 0; x < 255; ++x) - { - for (auto y = 0; y < 255; ++y) - { - RebuildEntitySpatialLocation(TileCoordsXY{ x, y }); - } - } - // Rebuild next_in_quadrant linked list for LOCATION_NULL - TileCoordsXY invalid; - invalid.SetNull(); - RebuildEntitySpatialLocation(invalid); -} - -constexpr RCT12EntityLinkListOffset GetRCT2LinkListOffset(const EntityBase* src) -{ - RCT12EntityLinkListOffset output = RCT12EntityLinkListOffset::Free; - switch (src->Type) - { - case EntityType::Vehicle: - { - auto veh = src->As(); - if (veh != nullptr && veh->IsHead()) - { - output = RCT12EntityLinkListOffset::TrainHead; - } - else - { - output = RCT12EntityLinkListOffset::Vehicle; - } - } - break; - case EntityType::Guest: - case EntityType::Staff: - output = RCT12EntityLinkListOffset::Peep; - break; - case EntityType::SteamParticle: - case EntityType::MoneyEffect: - case EntityType::CrashedVehicleParticle: - case EntityType::ExplosionCloud: - case EntityType::CrashSplash: - case EntityType::ExplosionFlare: - case EntityType::JumpingFountain: - case EntityType::Balloon: - case EntityType::Duck: - output = RCT12EntityLinkListOffset::Misc; - break; - case EntityType::Litter: - output = RCT12EntityLinkListOffset::Litter; - break; - default: - break; - } - return output; -} - -constexpr RCT12SpriteIdentifier GetRCT2SpriteIdentifier(const EntityBase* src) -{ - RCT12SpriteIdentifier output = RCT12SpriteIdentifier::Null; - switch (src->Type) - { - case EntityType::Vehicle: - output = RCT12SpriteIdentifier::Vehicle; - break; - case EntityType::Guest: - case EntityType::Staff: - output = RCT12SpriteIdentifier::Peep; - break; - case EntityType::SteamParticle: - case EntityType::MoneyEffect: - case EntityType::CrashedVehicleParticle: - case EntityType::ExplosionCloud: - case EntityType::CrashSplash: - case EntityType::ExplosionFlare: - case EntityType::JumpingFountain: - case EntityType::Balloon: - case EntityType::Duck: - output = RCT12SpriteIdentifier::Misc; - break; - case EntityType::Litter: - output = RCT12SpriteIdentifier::Litter; - break; - default: - break; - } - return output; -} - -void S6Exporter::ExportEntityCommonProperties(RCT12SpriteBase* dst, const EntityBase* src) -{ - dst->sprite_identifier = GetRCT2SpriteIdentifier(src); - dst->linked_list_type_offset = GetRCT2LinkListOffset(src); - dst->next_in_quadrant = SPRITE_INDEX_NULL; - dst->sprite_height_negative = src->sprite_height_negative; - dst->sprite_index = src->sprite_index; - dst->flags = 0; - dst->x = static_cast(src->x); - dst->y = static_cast(src->y); - dst->z = static_cast(src->z); - dst->sprite_width = src->sprite_width; - dst->sprite_height_positive = src->sprite_height_positive; - dst->sprite_left = src->SpriteRect.GetLeft(); - dst->sprite_top = src->SpriteRect.GetTop(); - dst->sprite_right = src->SpriteRect.GetRight(); - dst->sprite_bottom = src->SpriteRect.GetBottom(); - dst->sprite_direction = src->sprite_direction; -} - -template<> void S6Exporter::ExportEntity(RCT2SpriteVehicle* dst, const Vehicle* src) -{ - const auto* ride = src->GetRide(); - - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(src->SubType); - dst->Pitch = src->Pitch; - dst->bank_rotation = src->bank_rotation; - dst->remaining_distance = src->remaining_distance; - dst->velocity = src->velocity; - dst->acceleration = src->acceleration; - dst->ride = static_cast(src->ride); - dst->vehicle_type = src->vehicle_type; - dst->colours = src->colours; - dst->track_progress = src->track_progress; - if (ride != nullptr && ride->mode == RideMode::BoatHire && src->status == Vehicle::Status::TravellingBoat) - { - if (src->BoatLocation.IsNull()) - { - dst->boat_location.SetNull(); - } - else - { - dst->boat_location = { static_cast(src->BoatLocation.x / COORDS_XY_STEP), - static_cast(src->BoatLocation.y / COORDS_XY_STEP) }; - } - } - else - { - auto trackType = OpenRCT2TrackTypeToRCT2(src->GetTrackType()); - // Track direction and type are in the same field - dst->SetTrackType(trackType); - dst->SetTrackDirection(src->GetTrackDirection()); - } - dst->track_x = src->TrackLocation.x; - dst->track_y = src->TrackLocation.y; - dst->track_z = src->TrackLocation.z; - dst->next_vehicle_on_train = src->next_vehicle_on_train; - dst->prev_vehicle_on_ride = src->prev_vehicle_on_ride; - dst->next_vehicle_on_ride = src->next_vehicle_on_ride; - dst->var_44 = src->var_44; - dst->mass = src->mass; - dst->update_flags = src->update_flags; - dst->SwingSprite = src->SwingSprite; - dst->current_station = src->current_station; - dst->current_time = src->current_time; - dst->crash_z = src->crash_z; - dst->status = static_cast(src->status); - dst->sub_state = src->sub_state; - for (size_t i = 0; i < std::size(src->peep); i++) - { - dst->peep[i] = src->peep[i]; - dst->peep_tshirt_colours[i] = src->peep_tshirt_colours[i]; - } - dst->num_seats = src->num_seats; - dst->num_peeps = src->num_peeps; - dst->next_free_seat = src->next_free_seat; - dst->restraints_position = src->restraints_position; - dst->crash_x = src->crash_x; - dst->sound2_flags = src->sound2_flags; - dst->spin_sprite = src->spin_sprite; - dst->sound1_id = static_cast(src->sound1_id); - dst->sound1_volume = src->sound1_volume; - dst->sound2_id = static_cast(src->sound2_id); - dst->sound2_volume = src->sound2_volume; - dst->sound_vector_factor = src->sound_vector_factor; - dst->time_waiting = src->time_waiting; - dst->speed = src->speed; - dst->powered_acceleration = src->powered_acceleration; - dst->dodgems_collision_direction = src->dodgems_collision_direction; - dst->animation_frame = src->animation_frame; - dst->animationState = src->animationState; - dst->scream_sound_id = static_cast(src->scream_sound_id); - dst->TrackSubposition = static_cast(src->TrackSubposition); - dst->var_CE = src->var_CE; - dst->var_CF = src->var_CF; - dst->lost_time_out = src->lost_time_out; - dst->vertical_drop_countdown = src->vertical_drop_countdown; - dst->var_D3 = src->var_D3; - dst->mini_golf_current_animation = EnumValue(src->mini_golf_current_animation); - dst->mini_golf_flags = src->mini_golf_flags; - dst->ride_subtype = OpenRCT2EntryIndexToRCTEntryIndex(src->ride_subtype); - dst->colours_extended = src->colours_extended; - dst->seat_rotation = src->seat_rotation; - dst->target_seat_rotation = src->target_seat_rotation; - dst->flags = src->IsCrashedVehicle ? RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE : 0; -} - -template<> void S6Exporter::ExportEntity(RCT2SpritePeep* dst, const Guest* src) -{ - ExportEntityPeep(dst, src); - dst->outside_of_park = static_cast(src->OutsideOfPark); - dst->no_of_rides = src->GuestNumRides; - dst->happiness = src->Happiness; - dst->happiness_target = src->HappinessTarget; - dst->nausea = src->Nausea; - dst->nausea_target = src->NauseaTarget; - dst->hunger = src->Hunger; - dst->thirst = src->Thirst; - dst->toilet = src->Toilet; - dst->time_to_consume = src->TimeToConsume; - dst->intensity = static_cast(src->Intensity); - dst->nausea_tolerance = EnumValue(src->NauseaTolerance); - dst->paid_on_drink = src->PaidOnDrink; - auto* typeHistory = OpenRCT2::RideUse::GetTypeHistory().GetAll(src->sprite_index); - if (typeHistory != nullptr) - { - for (auto typeId : *typeHistory) - { - dst->ride_types_been_on[typeId / 8] |= (1 << (typeId % 8)); - } - } - auto* rideHistory = OpenRCT2::RideUse::GetHistory().GetAll(src->sprite_index); - if (rideHistory != nullptr) - { - for (auto rideId : *rideHistory) - { - const auto rideIndex = EnumValue(rideId); - dst->rides_been_on[rideIndex / 8] |= (1 << (rideIndex % 8)); - } - } - dst->item_extra_flags = static_cast(src->GetItemFlags() >> 32); - dst->photo1_ride_ref = OpenRCT2RideIdToRCT12RideId(src->Photo1RideRef); - dst->photo2_ride_ref = OpenRCT2RideIdToRCT12RideId(src->Photo2RideRef); - dst->photo3_ride_ref = OpenRCT2RideIdToRCT12RideId(src->Photo3RideRef); - dst->photo4_ride_ref = OpenRCT2RideIdToRCT12RideId(src->Photo4RideRef); - dst->next_in_queue = src->GuestNextInQueue; - dst->time_in_queue = src->TimeInQueue; - dst->cash_in_pocket = src->CashInPocket; - dst->cash_spent = src->CashSpent; - dst->park_entry_time = src->ParkEntryTime; - dst->rejoin_queue_timeout = src->RejoinQueueTimeout; - dst->previous_ride = OpenRCT2RideIdToRCT12RideId(src->PreviousRide); - dst->previous_ride_time_out = src->PreviousRideTimeOut; - for (size_t i = 0; i < std::size(src->Thoughts); i++) - { - auto srcThought = &src->Thoughts[i]; - auto dstThought = &dst->thoughts[i]; - dstThought->type = static_cast(srcThought->type); - dstThought->item = static_cast(srcThought->item); - dstThought->freshness = srcThought->freshness; - dstThought->fresh_timeout = srcThought->fresh_timeout; - } - dst->guest_heading_to_ride_id = OpenRCT2RideIdToRCT12RideId(src->GuestHeadingToRideId); - dst->peep_is_lost_countdown = src->GuestIsLostCountdown; - dst->litter_count = src->LitterCount; - dst->time_on_ride = src->GuestTimeOnRide; - dst->disgusting_count = src->DisgustingCount; - dst->paid_to_enter = src->PaidToEnter; - dst->paid_on_rides = src->PaidOnRides; - dst->paid_on_food = src->PaidOnFood; - dst->paid_on_souvenirs = src->PaidOnSouvenirs; - dst->no_of_food = src->AmountOfFood; - dst->no_of_drinks = src->AmountOfDrinks; - dst->no_of_souvenirs = src->AmountOfSouvenirs; - dst->vandalism_seen = src->VandalismSeen; - dst->voucher_type = src->VoucherType; - dst->voucher_arguments = OpenRCT2RideIdToRCT12RideId(src->VoucherRideId); - dst->surroundings_thought_timeout = src->SurroundingsThoughtTimeout; - dst->angriness = src->Angriness; - dst->time_lost = src->TimeLost; - dst->days_in_queue = src->DaysInQueue; - dst->balloon_colour = src->BalloonColour; - dst->umbrella_colour = src->UmbrellaColour; - dst->hat_colour = src->HatColour; - dst->favourite_ride = OpenRCT2RideIdToRCT12RideId(src->FavouriteRide); - dst->favourite_ride_rating = src->FavouriteRideRating; - dst->item_standard_flags = static_cast(src->GetItemFlags()); -} -template<> void S6Exporter::ExportEntity(RCT2SpritePeep* dst, const Staff* src) -{ - ExportEntityPeep(dst, src); - dst->staff_type = static_cast(src->AssignedStaffType); - dst->mechanic_time_since_call = src->MechanicTimeSinceCall; - dst->park_entry_time = src->HireDate; - dst->staff_orders = src->StaffOrders; - dst->staff_mowing_timeout = src->StaffMowingTimeout; - dst->paid_to_enter = src->StaffLawnsMown; - dst->paid_on_rides = src->StaffGardensWatered; - dst->paid_on_food = src->StaffLitterSwept; - dst->paid_on_souvenirs = src->StaffBinsEmptied; -} - -void S6Exporter::ExportEntityPeep(RCT2SpritePeep* dst, const Peep* src) -{ - ExportEntityCommonProperties(dst, src); - - auto generateName = true; - if (src->Name != nullptr) - { - auto stringId = AllocateUserString(src->Name); - if (stringId.has_value()) - { - dst->name_string_idx = stringId.value(); - generateName = false; - } - else - { - log_warning( - "Unable to allocate user string for peep #%d (%s) during S6 export.", static_cast(src->sprite_index), - src->Name); - } - } - if (generateName) - { - auto* staff = src->As(); - if (staff != nullptr) - { - static constexpr const rct_string_id staffNames[] = { - STR_HANDYMAN_X, - STR_MECHANIC_X, - STR_SECURITY_GUARD_X, - STR_ENTERTAINER_X, - }; - dst->name_string_idx = staffNames[static_cast(staff->AssignedStaffType) % sizeof(staffNames)]; - } - else if (gParkFlags & PARK_FLAGS_SHOW_REAL_GUEST_NAMES) - { - dst->name_string_idx = get_real_name_string_id_from_id(src->Id); - } - else - { - dst->name_string_idx = STR_GUEST_X; - } - } - - dst->next_x = src->NextLoc.x; - dst->next_y = src->NextLoc.y; - dst->next_z = src->NextLoc.z / COORDS_Z_STEP; - dst->next_flags = src->NextFlags; - dst->state = static_cast(src->State); - dst->sub_state = src->SubState; - dst->sprite_type = static_cast(src->SpriteType); - dst->peep_type = static_cast(src->Type == EntityType::Staff ? RCT12PeepType::Staff : RCT12PeepType::Guest); - dst->tshirt_colour = src->TshirtColour; - dst->trousers_colour = src->TrousersColour; - dst->destination_x = src->DestinationX; - dst->destination_y = src->DestinationY; - dst->destination_tolerance = src->DestinationTolerance; - dst->var_37 = src->Var37; - dst->energy = src->Energy; - dst->energy_target = src->EnergyTarget; - dst->mass = src->Mass; - dst->window_invalidate_flags = src->WindowInvalidateFlags; - dst->current_ride = OpenRCT2RideIdToRCT12RideId(src->CurrentRide); - dst->current_ride_station = src->CurrentRideStation; - dst->current_train = src->CurrentTrain; - dst->time_to_sitdown = src->TimeToSitdown; - dst->special_sprite = src->SpecialSprite; - dst->action_sprite_type = static_cast(src->ActionSpriteType); - dst->next_action_sprite_type = static_cast(src->NextActionSpriteType); - dst->action_sprite_image_offset = src->ActionSpriteImageOffset; - dst->action = static_cast(src->Action); - dst->action_frame = src->ActionFrame; - dst->step_progress = src->StepProgress; - dst->direction = src->PeepDirection; - dst->interaction_ride_index = OpenRCT2RideIdToRCT12RideId(src->InteractionRideIndex); - dst->id = src->Id; - dst->path_check_optimisation = src->PathCheckOptimisation; - dst->peep_flags = src->PeepFlags; - if (src->PathfindGoal.IsNull()) - { - dst->pathfind_goal = { 0xFF, 0xFF, 0xFF, INVALID_DIRECTION }; - } - else - { - dst->pathfind_goal = { static_cast(src->PathfindGoal.x), static_cast(src->PathfindGoal.y), - static_cast(src->PathfindGoal.z), src->PathfindGoal.direction }; - } - for (size_t i = 0; i < std::size(src->PathfindHistory); i++) - { - if (src->PathfindHistory[i].IsNull()) - { - dst->pathfind_history[i] = { 0xFF, 0xFF, 0xFF, INVALID_DIRECTION }; - } - else - { - dst->pathfind_history[i] = { static_cast(src->PathfindHistory[i].x), - static_cast(src->PathfindHistory[i].y), - static_cast(src->PathfindHistory[i].z), src->PathfindHistory[i].direction }; - } - } - dst->no_action_frame_num = src->WalkingFrameNum; -} - -template<> void S6Exporter::ExportEntity(RCT12SpriteSteamParticle* dst, const SteamParticle* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::SteamParticle); - dst->time_to_move = src->time_to_move; - dst->frame = src->frame; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteMoneyEffect* dst, const MoneyEffect* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::MoneyEffect); - dst->move_delay = src->MoveDelay; - dst->num_movements = src->NumMovements; - dst->vertical = src->Vertical; - dst->value = src->Value; - dst->offset_x = src->OffsetX; - dst->wiggle = src->Wiggle; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteCrashedVehicleParticle* dst, const VehicleCrashParticle* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::CrashedVehicleParticle); - dst->frame = src->frame; - dst->time_to_live = src->time_to_live; - dst->frame = src->frame; - dst->colour[0] = src->colour[0]; - dst->colour[1] = src->colour[1]; - dst->crashed_sprite_base = src->crashed_sprite_base; - dst->velocity_x = src->velocity_x; - dst->velocity_y = src->velocity_y; - dst->velocity_z = src->velocity_z; - dst->acceleration_x = src->acceleration_x; - dst->acceleration_y = src->acceleration_y; - dst->acceleration_z = src->acceleration_z; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteJumpingFountain* dst, const JumpingFountain* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue( - src->FountainType == JumpingFountainType::Snow ? RCT12MiscEntityType::JumpingFountainSnow - : RCT12MiscEntityType::JumpingFountainWater); - dst->num_ticks_alive = src->NumTicksAlive; - dst->frame = src->frame; - dst->fountain_flags = src->FountainFlags; - dst->target_x = src->TargetX; - dst->target_y = src->TargetY; - dst->target_y = src->TargetY; - dst->iteration = src->Iteration; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteBalloon* dst, const Balloon* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::Balloon); - dst->popped = src->popped; - dst->time_to_move = src->time_to_move; - dst->frame = src->frame; - dst->colour = src->colour; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteDuck* dst, const Duck* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::Duck); - dst->frame = src->frame; - dst->target_x = src->target_x; - dst->target_y = src->target_y; - dst->state = EnumValue(src->state); -} -template<> void S6Exporter::ExportEntity(RCT12SpriteParticle* dst, const ExplosionCloud* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::ExplosionCloud); - dst->frame = src->frame; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteParticle* dst, const ExplosionFlare* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::ExplosionFlare); - dst->frame = src->frame; -} -template<> void S6Exporter::ExportEntity(RCT12SpriteParticle* dst, const CrashSplashParticle* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(RCT12MiscEntityType::CrashSplash); - dst->frame = src->frame; -} - -template<> void S6Exporter::ExportEntity(RCT12SpriteLitter* dst, const Litter* src) -{ - ExportEntityCommonProperties(dst, src); - dst->type = EnumValue(src->SubType); - dst->creationTick = src->creationTick; -} - -void S6Exporter::ExportEntities() -{ - // Clear everything to free - for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++) - { - auto& entity = _s6.sprites[i]; - std::memset(&entity, 0, sizeof(entity)); - entity.unknown.sprite_identifier = RCT12SpriteIdentifier::Null; - entity.unknown.sprite_index = i; - entity.unknown.linked_list_type_offset = RCT12EntityLinkListOffset::Free; - } - - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].peep, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].peep, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].vehicle, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].litter, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].duck, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].steam_particle, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].money_effect, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].crashed_vehicle_particle, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].jumping_fountain, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].balloon, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].misc_particle, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].misc_particle, entity); - } - for (auto* entity : EntityList()) - { - ExportEntity(&_s6.sprites[entity->sprite_index].misc_particle, entity); - } - - RebuildEntityLinks(); -} - -void S6Exporter::ExportBanners() -{ - for (BannerIndex i = 0; i < RCT2_MAX_BANNERS_IN_PARK; i++) - { - auto src = GetBanner(i); - auto dst = &_s6.banners[i]; - if (src != nullptr) - { - ExportBanner(*dst, *src); - } - else - { - ExportBanner(*dst, {}); - } - } -} - -void S6Exporter::ExportBanner(RCT12Banner& dst, const Banner& src) -{ - dst = {}; - dst.type = OpenRCT2EntryIndexToRCTEntryIndex(src.type); - - if (!src.IsNull()) - { - dst.flags = src.flags; - - dst.string_idx = STR_DEFAULT_SIGN; - - std::string bannerText; - if (!(src.flags & BANNER_FLAG_IS_WALL) && !(src.flags & BANNER_FLAG_IS_LARGE_SCENERY)) - { - auto formatCode = static_cast(RCT2_STRING_FORMAT_COLOUR_START + src.text_colour); - String::AppendCodepoint(bannerText, formatCode); - } - bannerText.append(src.text); - - auto stringId = AllocateUserString(bannerText); - if (stringId.has_value()) - { - dst.string_idx = stringId.value(); - } - - if (src.flags & BANNER_FLAG_LINKED_TO_RIDE) - { - dst.ride_index = OpenRCT2RideIdToRCT12RideId(src.ride_index); - } - else - { - dst.colour = src.colour; - } - dst.text_colour = src.text_colour; - dst.x = src.position.x; - dst.y = src.position.y; - } -} - -void S6Exporter::ExportMapAnimations() -{ - const auto& mapAnimations = GetMapAnimations(); - auto numAnimations = std::min(mapAnimations.size(), std::size(_s6.map_animations)); - _s6.num_map_animations = static_cast(numAnimations); - for (size_t i = 0; i < numAnimations; i++) - { - const auto& src = mapAnimations[i]; - auto& dst = _s6.map_animations[i]; - - dst.type = src.type; - // In RCT12MapAnimation, the x and y coordinates use big coords, while the z coordinate uses small coords. - dst.x = src.location.x; - dst.y = src.location.y; - dst.baseZ = src.location.z / COORDS_Z_STEP; - } -} - -void S6Exporter::ExportTileElements() -{ - const auto& tileElements = GetTileElements(); - for (uint32_t index = 0; index < RCT2_MAX_TILE_ELEMENTS; index++) - { - auto dst = &_s6.tile_elements[index]; - if (index >= tileElements.size()) - { - dst = {}; - continue; - } - auto src = &tileElements[index]; - if (src->base_height == MAX_ELEMENT_HEIGHT) - { - std::memcpy(dst, src, sizeof(*dst)); - } - else - { - auto tileElementType = static_cast(src->GetType()); - if (tileElementType == RCT12TileElementType::Corrupt || tileElementType == RCT12TileElementType::EightCarsCorrupt14 - || tileElementType == RCT12TileElementType::EightCarsCorrupt15) - std::memcpy(dst, src, sizeof(*dst)); - else - ExportTileElement(dst, src); - } - } - _s6.next_free_tile_element_pointer_index = static_cast(tileElements.size()); -} - -void S6Exporter::ExportTileElement(RCT12TileElement* dst, const TileElement* src) -{ - // Todo: allow for changing definition of OpenRCT2 tile element types - replace with a map - uint8_t tileElementType = src->GetType(); - dst->ClearAs(tileElementType); - dst->SetDirection(src->GetDirection()); - dst->base_height = src->base_height; - dst->clearance_height = src->clearance_height; - - // All saved in "flags" - dst->SetOccupiedQuadrants(src->GetOccupiedQuadrants()); - dst->SetGhost(src->IsGhost()); - dst->SetLastForTile(src->IsLastForTile()); - - switch (tileElementType) - { - case TILE_ELEMENT_TYPE_SURFACE: - { - auto dst2 = dst->AsSurface(); - auto src2 = src->AsSurface(); - - dst2->SetSlope(src2->GetSlope()); - dst2->SetSurfaceStyle(src2->GetSurfaceStyle()); - dst2->SetEdgeStyle(src2->GetEdgeStyle()); - dst2->SetGrassLength(src2->GetGrassLength()); - dst2->SetOwnership(src2->GetOwnership()); - dst2->SetParkFences(src2->GetParkFences()); - dst2->SetWaterHeight(src2->GetWaterHeight()); - dst2->SetHasTrackThatNeedsWater(src2->HasTrackThatNeedsWater()); - - break; - } - case TILE_ELEMENT_TYPE_PATH: - { - auto dst2 = dst->AsPath(); - auto src2 = src->AsPath(); - - dst2->SetPathEntryIndex(src2->GetLegacyPathEntryIndex()); - dst2->SetQueueBannerDirection(src2->GetQueueBannerDirection()); - dst2->SetSloped(src2->IsSloped()); - dst2->SetSlopeDirection(src2->GetSlopeDirection()); - dst2->SetRideIndex(OpenRCT2RideIdToRCT12RideId(src2->GetRideIndex())); - dst2->SetStationIndex(src2->GetStationIndex()); - dst2->SetWide(src2->IsWide()); - dst2->SetIsQueue(src2->IsQueue()); - dst2->SetHasQueueBanner(src2->HasQueueBanner()); - dst2->SetEdges(src2->GetEdges()); - dst2->SetCorners(src2->GetCorners()); - dst2->SetAddition(src2->GetAddition()); - dst2->SetAdditionIsGhost(src2->AdditionIsGhost()); - dst2->SetAdditionStatus(src2->GetAdditionStatus()); - dst2->SetIsBroken(src2->IsBroken()); - dst2->SetIsBlockedByVehicle(src2->IsBlockedByVehicle()); - - break; - } - case TILE_ELEMENT_TYPE_TRACK: - { - auto dst2 = dst->AsTrack(); - auto src2 = src->AsTrack(); - - auto trackType = OpenRCT2TrackTypeToRCT2(src2->GetTrackType()); - dst2->SetTrackType(static_cast(trackType)); - dst2->SetSequenceIndex(src2->GetSequenceIndex()); - dst2->SetRideIndex(OpenRCT2RideIdToRCT12RideId(src2->GetRideIndex())); - dst2->SetColourScheme(src2->GetColourScheme()); - dst2->SetStationIndex(src2->GetStationIndex()); - dst2->SetHasGreenLight(src2->HasGreenLight()); - dst2->SetHasChain(src2->HasChain()); - dst2->SetHasCableLift(src2->HasCableLift()); - dst2->SetInverted(src2->IsInverted()); - dst2->SetBrakeBoosterSpeed(src2->GetBrakeBoosterSpeed()); - dst2->SetPhotoTimeout(src2->GetPhotoTimeout()); - dst2->SetBlockBrakeClosed(src2->BlockBrakeClosed()); - dst2->SetIsIndestructible(src2->IsIndestructible()); - - // Skipping IsHighlighted() - - // This has to be done last, since the maze entry shares fields with the colour and sequence fields. - auto ride = get_ride(static_cast(dst2->GetRideIndex())); - if (ride != nullptr) - { - if (ride->type == RIDE_TYPE_MAZE) - { - dst2->SetMazeEntry(src2->GetMazeEntry()); - } - else if (ride->type == RIDE_TYPE_GHOST_TRAIN) - { - dst2->SetDoorAState(src2->GetDoorAState()); - dst2->SetDoorBState(src2->GetDoorBState()); - } - else - { - dst2->SetSeatRotation(src2->GetSeatRotation()); - } - } - // _Should_ not happen, but if it does, pick the most likely option. - else - { - dst2->SetSeatRotation(src2->GetSeatRotation()); - } - - break; - } - case TILE_ELEMENT_TYPE_SMALL_SCENERY: - { - auto dst2 = dst->AsSmallScenery(); - auto src2 = src->AsSmallScenery(); - - dst2->SetEntryIndex(src2->GetEntryIndex()); - dst2->SetAge(src2->GetAge()); - dst2->SetSceneryQuadrant(src2->GetSceneryQuadrant()); - dst2->SetPrimaryColour(src2->GetPrimaryColour()); - dst2->SetSecondaryColour(src2->GetSecondaryColour()); - if (src2->NeedsSupports()) - dst2->SetNeedsSupports(); - - break; - } - case TILE_ELEMENT_TYPE_ENTRANCE: - { - auto dst2 = dst->AsEntrance(); - auto src2 = src->AsEntrance(); - - dst2->SetEntranceType(src2->GetEntranceType()); - dst2->SetRideIndex(OpenRCT2RideIdToRCT12RideId(src2->GetRideIndex())); - dst2->SetStationIndex(src2->GetStationIndex()); - dst2->SetSequenceIndex(src2->GetSequenceIndex()); - dst2->SetPathType(src2->GetLegacyPathEntryIndex()); - - break; - } - case TILE_ELEMENT_TYPE_WALL: - { - auto dst2 = dst->AsWall(); - auto src2 = src->AsWall(); - - dst2->SetEntryIndex(src2->GetEntryIndex()); - dst2->SetSlope(src2->GetSlope()); - dst2->SetPrimaryColour(src2->GetPrimaryColour()); - dst2->SetSecondaryColour(src2->GetSecondaryColour()); - dst2->SetTertiaryColour(src2->GetTertiaryColour()); - dst2->SetAnimationFrame(src2->GetAnimationFrame()); - dst2->SetAcrossTrack(src2->IsAcrossTrack()); - dst2->SetAnimationIsBackwards(src2->AnimationIsBackwards()); - - auto entry = src2->GetEntry(); - if (entry != nullptr && entry->scrolling_mode != SCROLLING_MODE_NONE) - { - auto bannerIndex = src2->GetBannerIndex(); - if (bannerIndex != BANNER_INDEX_NULL) - dst2->SetBannerIndex(bannerIndex); - else - dst2->SetBannerIndex(RCT12_BANNER_INDEX_NULL); - } - - break; - } - case TILE_ELEMENT_TYPE_LARGE_SCENERY: - { - auto dst2 = dst->AsLargeScenery(); - auto src2 = src->AsLargeScenery(); - - dst2->SetEntryIndex(src2->GetEntryIndex()); - dst2->SetSequenceIndex(src2->GetSequenceIndex()); - dst2->SetPrimaryColour(src2->GetPrimaryColour()); - dst2->SetSecondaryColour(src2->GetSecondaryColour()); - - auto entry = src2->GetEntry(); - if (entry != nullptr && entry->scrolling_mode != SCROLLING_MODE_NONE) - { - auto bannerIndex = src2->GetBannerIndex(); - if (bannerIndex != BANNER_INDEX_NULL) - dst2->SetBannerIndex(bannerIndex); - else - dst2->SetBannerIndex(RCT12_BANNER_INDEX_NULL); - } - - break; - } - case TILE_ELEMENT_TYPE_BANNER: - { - auto dst2 = dst->AsBanner(); - auto src2 = src->AsBanner(); - - dst2->SetPosition(src2->GetPosition()); - dst2->SetAllowedEdges(src2->GetAllowedEdges()); - auto bannerIndex = src2->GetIndex(); - if (bannerIndex != BANNER_INDEX_NULL) - dst2->SetIndex(bannerIndex); - else - dst2->SetIndex(RCT12_BANNER_INDEX_NULL); - break; - } - default: - assert(false); - } -} - -std::optional S6Exporter::AllocateUserString(std::string_view value) -{ - auto nextId = _userStrings.size(); - if (nextId < RCT12_MAX_USER_STRINGS) - { - _userStrings.emplace_back(value); - return static_cast(USER_STRING_START + nextId); - } - return std::nullopt; -} - -void S6Exporter::ExportUserStrings() -{ - auto numUserStrings = std::min(_userStrings.size(), RCT12_MAX_USER_STRINGS); - for (size_t i = 0; i < numUserStrings; i++) - { - auto dst = _s6.custom_strings[i]; - const auto& src = _userStrings[i]; - auto encodedSrc = GetTruncatedRCT2String(src, RCT12_USER_STRING_MAX_LENGTH); - auto stringLen = std::min(encodedSrc.size(), RCT12_USER_STRING_MAX_LENGTH - 1); - std::memcpy(dst, encodedSrc.data(), stringLen); - } -} - -enum : uint32_t -{ - S6_SAVE_FLAG_EXPORT = 1 << 0, - S6_SAVE_FLAG_SCENARIO = 1 << 1, - S6_SAVE_FLAG_AUTOMATIC = 1u << 31, -}; - -/** - * - * rct2: 0x006754F5 - * @param flags bit 0: pack objects, 1: save as scenario - */ -int32_t scenario_save(const utf8* path, int32_t flags) -{ - if (flags & S6_SAVE_FLAG_SCENARIO) - { - log_verbose("scenario_save(%s, SCENARIO)", path); - } - else - { - log_verbose("scenario_save(%s, SAVED GAME)", path); - } - - if (!(flags & S6_SAVE_FLAG_AUTOMATIC)) - { - window_close_construction_windows(); - } - - viewport_set_saved_view(); - - bool result = false; - auto s6exporter = new S6Exporter(); - try - { - if (flags & S6_SAVE_FLAG_EXPORT) - { - auto& objManager = OpenRCT2::GetContext()->GetObjectManager(); - s6exporter->ExportObjectsList = objManager.GetPackableObjects(); - } - s6exporter->RemoveTracklessRides = true; - s6exporter->Export(); - if (flags & S6_SAVE_FLAG_SCENARIO) - { - s6exporter->SaveScenario(path); - } - else - { - s6exporter->SaveGame(path); - } - result = true; - } - catch (const std::exception& e) - { - log_error("Unable to save park: '%s'", e.what()); - } - delete s6exporter; - - gfx_invalidate_screen(); - - if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC)) - { - gScreenAge = 0; - } - return result; -} diff --git a/src/openrct2/rct2/S6Exporter.h b/src/openrct2/rct2/S6Exporter.h deleted file mode 100644 index 12e28128ff..0000000000 --- a/src/openrct2/rct2/S6Exporter.h +++ /dev/null @@ -1,84 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014-2020 OpenRCT2 developers - * - * For a complete list of all authors, please refer to contributors.md - * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is licensed under the GNU General Public License version 3. - *****************************************************************************/ - -#pragma once - -#include "../common.h" -#include "../object/ObjectList.h" -#include "../scenario/Scenario.h" - -#include -#include -#include -#include - -namespace OpenRCT2 -{ - struct IStream; -} - -struct Litter; -struct ObjectRepositoryItem; -struct RCT12SpriteBase; -struct EntityBase; -struct Peep; -union rct_sprite; - -/** - * Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). - */ -class S6Exporter final -{ -public: - bool RemoveTracklessRides; - std::vector ExportObjectsList; - - S6Exporter(); - - void SaveGame(const utf8* path); - void SaveGame(OpenRCT2::IStream* stream); - void SaveScenario(const utf8* path); - void SaveScenario(OpenRCT2::IStream* stream); - void Export(); - void ExportParkName(); - void ExportRides(); - void ExportRide(rct2_ride* dst, const Ride* src); - void ExportEntities(); - template void ExportEntity(RCT12_T* dst, const OpenRCT2_T* src); - void ExportEntityCommonProperties(RCT12SpriteBase* dst, const EntityBase* src); - void ExportEntityPeep(RCT2SpritePeep* dst, const Peep* src); - -private: - rct_s6_data _s6{}; - std::vector _userStrings; - - void Save(OpenRCT2::IStream* stream, bool isScenario); - static uint32_t GetLoanHash(money32 initialCash, money32 bankLoan, uint32_t maxBankLoan); - void ExportResearchedRideTypes(); - void ExportResearchedRideEntries(); - void ExportResearchedSceneryItems(); - void ExportResearchList(); - void ExportMarketingCampaigns(); - void ExportPeepSpawns(); - void ExportRideRatingsCalcData(); - void ExportRideMeasurements(); - void ExportRideMeasurement(RCT12RideMeasurement& dst, const RideMeasurement& src); - void ExportBanners(); - void ExportBanner(RCT12Banner& dst, const Banner& src); - void ExportMapAnimations(); - - void ExportTileElements(); - void ExportTileElement(RCT12TileElement* dst, const TileElement* src); - - std::optional AllocateUserString(std::string_view value); - void ExportUserStrings(); - void RebuildEntityLinks(); - void RebuildEntitySpatialLocation(const TileCoordsXY& loc); - void ExportStaffPatrolAreas(); -}; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index b9323d52fc..91a6e0e136 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -88,6 +88,9 @@ private: uint8_t _gameVersion = 0; bool _isSV7 = false; std::bitset _isFlatRide{}; + ObjectEntryIndex _pathToSurfaceMap[16]; + ObjectEntryIndex _pathToQueueSurfaceMap[16]; + ObjectEntryIndex _pathToRailingMap[16]; public: S6Importer(IObjectRepository& objectRepository) @@ -254,8 +257,6 @@ public: gGuestChangeModifier = _s6.guest_count_change_modifier; gResearchFundingLevel = _s6.current_research_level; // pad_01357400 - ImportResearchedRideTypes(); - ImportResearchedRideEntries(); // _s6.researched_track_types_a // _s6.researched_track_types_b @@ -276,8 +277,6 @@ public: gStaffMechanicColour = _s6.mechanic_colour; gStaffSecurityColour = _s6.security_colour; - ImportResearchedSceneryItems(); - gParkRating = _s6.park_rating; auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); @@ -401,14 +400,13 @@ public: if (_s6.header.type == S6_TYPE_SCENARIO) { // _s6.scenario_filename is wrong for some RCT2 expansion scenarios, so we use the real filename - String::Set(gScenarioFileName, sizeof(gScenarioFileName), Path::GetFileName(_s6Path)); + gScenarioFileName = String::ToStd(Path::GetFileName(_s6Path)); } else { // For savegames the filename can be arbitrary, so we have no choice but to rely on the name provided - String::Set(gScenarioFileName, sizeof(gScenarioFileName), _s6.scenario_filename); + gScenarioFileName = std::string(String::ToStringView(_s6.scenario_filename, std::size(_s6.scenario_filename))); } - std::memcpy(gScenarioExpansionPacks, _s6.saved_expansion_pack_names, sizeof(_s6.saved_expansion_pack_names)); gCurrentRealTimeTicks = 0; ImportRides(); @@ -485,6 +483,9 @@ public: research_determine_first_of_type(); staff_update_greyed_patrol_areas(); + + CheatsReset(); + ClearRestrictedScenery(); } void FixLandOwnership() const @@ -871,13 +872,14 @@ public: } dst->music = musicStyle; - auto entranceStyle = src->entrance_style; // In SV7, "plain" entrances are invisible. - if (_isSV7 && entranceStyle == RCT12_STATION_STYLE_PLAIN) + auto entranceStyle = OBJECT_ENTRY_INDEX_NULL; + if (!_isSV7 && GetRideTypeDescriptor(dst->type).HasFlag(RIDE_TYPE_FLAG_HAS_ENTRANCE_EXIT)) { - entranceStyle = RCT12_STATION_STYLE_INVISIBLE; + entranceStyle = src->entrance_style; } dst->entrance_style = entranceStyle; + dst->vehicle_change_timeout = src->vehicle_change_timeout; dst->num_block_brakes = src->num_block_brakes; dst->lift_hill_speed = src->lift_hill_speed; @@ -958,61 +960,6 @@ public: } } - void ImportResearchedRideTypes() - { - set_every_ride_type_not_invented(); - - for (int32_t rideType = 0; rideType < RCT2_RIDE_TYPE_COUNT; rideType++) - { - int32_t quadIndex = rideType >> 5; - int32_t bitIndex = rideType & 0x1F; - bool invented = (_s6.researched_ride_types[quadIndex] & (1UL << bitIndex)); - - if (invented) - ride_type_set_invented(rideType); - } - } - - void ImportResearchedRideEntries() - { - set_every_ride_entry_not_invented(); - - for (int32_t rideEntryIndex = 0; rideEntryIndex < MAX_RIDE_OBJECTS; rideEntryIndex++) - { - int32_t quadIndex = rideEntryIndex >> 5; - int32_t bitIndex = rideEntryIndex & 0x1F; - bool invented = (_s6.researched_ride_entries[quadIndex] & (1UL << bitIndex)); - - if (invented) - ride_entry_set_invented(rideEntryIndex); - } - } - - void ImportResearchedSceneryItems() - { - set_all_scenery_items_not_invented(); - - for (uint16_t sceneryEntryIndex = 0; sceneryEntryIndex < RCT2_MAX_RESEARCHED_SCENERY_ITEMS; sceneryEntryIndex++) - { - int32_t quadIndex = sceneryEntryIndex >> 5; - int32_t bitIndex = sceneryEntryIndex & 0x1F; - bool invented = (_s6.researched_scenery_items[quadIndex] & (1UL << bitIndex)); - - if (invented) - { - ScenerySelection scenerySelection = { static_cast((sceneryEntryIndex >> 8) & 0xFF), - static_cast(sceneryEntryIndex & 0xFF) }; - - // SV6 has room for 8 types of scenery, and sometimes scenery of non-existing types 5 and 6 is marked as - // "invented". - if (scenerySelection.SceneryType < SCENERY_TYPE_COUNT) - { - scenery_set_invented(scenerySelection); - } - } - } - } - void ImportResearchList() { bool invented = true; @@ -1037,7 +984,10 @@ public: void ImportBanner(Banner* dst, const RCT12Banner* src) { + auto id = dst->id; + *dst = {}; + dst->id = id; dst->type = RCTEntryIndexToOpenRCT2EntryIndex(src->type); dst->flags = src->flags; @@ -1137,10 +1087,15 @@ public: auto tilePointerIndex = TilePointerIndex(RCT2_MAXIMUM_MAP_SIZE_TECHNICAL, _s6.tile_elements); std::vector tileElements; + bool nextElementInvisible = false; + bool restOfTileInvisible = false; for (TileCoordsXY coords = { 0, 0 }; coords.y < MAXIMUM_MAP_SIZE_TECHNICAL; coords.y++) { for (coords.x = 0; coords.x < MAXIMUM_MAP_SIZE_TECHNICAL; coords.x++) { + nextElementInvisible = false; + restOfTileInvisible = false; + if (coords.x >= RCT2_MAXIMUM_MAP_SIZE_TECHNICAL || coords.y >= RCT2_MAXIMUM_MAP_SIZE_TECHNICAL) { auto& dstElement = tileElements.emplace_back(); @@ -1161,22 +1116,30 @@ public: do { - auto& dstElement = tileElements.emplace_back(); if (srcElement->base_height == RCT12_MAX_ELEMENT_HEIGHT) { - std::memcpy(&dstElement, srcElement, sizeof(*srcElement)); + continue; } - else + + auto tileElementType = static_cast(srcElement->GetType()); + if (tileElementType == RCT12TileElementType::Corrupt) { - auto tileElementType = static_cast(srcElement->GetType()); - // Todo: replace with setting invisibility bit - if (tileElementType == RCT12TileElementType::Corrupt - || tileElementType == RCT12TileElementType::EightCarsCorrupt14 - || tileElementType == RCT12TileElementType::EightCarsCorrupt15) - std::memcpy(&dstElement, srcElement, sizeof(*srcElement)); - else - ImportTileElement(&dstElement, srcElement); + // One property of corrupt elements was to hide tops of tower tracks, and to avoid the next element from + // being hidden, multiple consecutive corrupt elements were sometimes used. This would essentially + // toggle the flag, so we inverse nextElementInvisible here instead of always setting it to true. + nextElementInvisible = !nextElementInvisible; + continue; } + if (tileElementType == RCT12TileElementType::EightCarsCorrupt14 + || tileElementType == RCT12TileElementType::EightCarsCorrupt15) + { + restOfTileInvisible = true; + continue; + } + + auto& dstElement = tileElements.emplace_back(); + ImportTileElement(&dstElement, srcElement, nextElementInvisible || restOfTileInvisible); + nextElementInvisible = false; } while (!(srcElement++)->IsLastForTile()); // Set last element flag in case the original last element was never added @@ -1189,7 +1152,7 @@ public: SetTileElements(std::move(tileElements)); } - void ImportTileElement(TileElement* dst, const RCT12TileElement* src) + void ImportTileElement(TileElement* dst, const RCT12TileElement* src, bool invisible) { // Todo: allow for changing definition of OpenRCT2 tile element types - replace with a map uint8_t tileElementType = src->GetType(); @@ -1202,6 +1165,7 @@ public: dst->SetOccupiedQuadrants(src->GetOccupiedQuadrants()); dst->SetGhost(src->IsGhost()); dst->SetLastForTile(src->IsLastForTile()); + dst->SetInvisible(invisible); switch (tileElementType) { @@ -1226,7 +1190,21 @@ public: auto dst2 = dst->AsPath(); auto src2 = src->AsPath(); - dst2->SetLegacyPathEntryIndex(src2->GetEntryIndex()); + auto pathEntryIndex = src2->GetEntryIndex(); + auto surfaceEntry = src2->IsQueue() ? _pathToQueueSurfaceMap[pathEntryIndex] + : _pathToSurfaceMap[pathEntryIndex]; + if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL) + { + // Legacy footpath object + dst2->SetLegacyPathEntryIndex(pathEntryIndex); + } + else + { + // Surface / railing + dst2->SetSurfaceEntryIndex(surfaceEntry); + dst2->SetRailingsEntryIndex(_pathToRailingMap[pathEntryIndex]); + } + dst2->SetQueueBannerDirection(src2->GetQueueBannerDirection()); dst2->SetSloped(src2->IsSloped()); dst2->SetSlopeDirection(src2->GetSlopeDirection()); @@ -1317,8 +1295,26 @@ public: dst2->SetRideIndex(RCT12RideIdToOpenRCT2RideId(src2->GetRideIndex())); dst2->SetStationIndex(src2->GetStationIndex()); dst2->SetSequenceIndex(src2->GetSequenceIndex()); - dst2->SetLegacyPathEntryIndex(src2->GetPathType()); + if (src2->GetSequenceIndex() == 0) + { + auto pathEntryIndex = src2->GetPathType(); + auto surfaceEntry = _pathToSurfaceMap[pathEntryIndex]; + if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL) + { + // Legacy footpath object + dst2->SetLegacyPathEntryIndex(pathEntryIndex); + } + else + { + // Surface + dst2->SetSurfaceEntryIndex(surfaceEntry); + } + } + else + { + dst2->SetSurfaceEntryIndex(OBJECT_ENTRY_INDEX_NULL); + } break; } case TILE_ELEMENT_TYPE_WALL: @@ -1655,56 +1651,69 @@ public: return justText.data(); } - template - static void AddRequiredObjects(std::vector& required, const T& list) - { - rct_object_entry nullEntry = {}; - std::memset(&nullEntry, 0xFF, sizeof(nullEntry)); - - for (const auto& entry : list) - { - required.push_back(entry); - } - - // NOTE: The segment of this object type needs to be filled to the internal limit - // the object manager currently expects this. - for (size_t i = std::size(list); i < TInternalLimit; i++) - { - required.push_back(nullEntry); - } - } - ObjectList GetRequiredObjects() { - std::vector result; - - AddRequiredObjects(result, _s6.RideObjects); - AddRequiredObjects(result, _s6.SceneryObjects); - AddRequiredObjects(result, _s6.LargeSceneryObjects); - AddRequiredObjects(result, _s6.WallSceneryObjects); - AddRequiredObjects(result, _s6.BannerObjects); - AddRequiredObjects(result, _s6.PathObjects); - AddRequiredObjects(result, _s6.PathAdditionObjects); - AddRequiredObjects(result, _s6.SceneryGroupObjects); - AddRequiredObjects(result, _s6.ParkEntranceObjects); - AddRequiredObjects(result, _s6.WaterObjects); - AddRequiredObjects(result, _s6.ScenarioTextObjects); + std::fill(std::begin(_pathToSurfaceMap), std::end(_pathToSurfaceMap), OBJECT_ENTRY_INDEX_NULL); + std::fill(std::begin(_pathToQueueSurfaceMap), std::end(_pathToQueueSurfaceMap), OBJECT_ENTRY_INDEX_NULL); + std::fill(std::begin(_pathToRailingMap), std::end(_pathToRailingMap), OBJECT_ENTRY_INDEX_NULL); ObjectList objectList; - for (size_t i = 0; i < result.size(); i++) + int objectIt = 0; + ObjectEntryIndex surfaceCount = 0; + ObjectEntryIndex railingCount = 0; + for (int16_t objectType = EnumValue(ObjectType::Ride); objectType <= EnumValue(ObjectType::Water); objectType++) { - ObjectType objectType; - ObjectEntryIndex entryIndex; - get_type_entry_index(i, &objectType, &entryIndex); - - auto desc = ObjectEntryDescriptor(result[i]); - if (desc.HasValue()) + for (int16_t i = 0; i < rct2_object_entry_group_counts[objectType]; i++, objectIt++) { - assert(desc.GetType() == objectType); - objectList.SetObject(entryIndex, desc); + auto entry = ObjectEntryDescriptor(_s6.Objects[objectIt]); + if (entry.HasValue()) + { + if (objectType == EnumValue(ObjectType::Paths)) + { + auto footpathMapping = GetFootpathSurfaceId(entry); + if (footpathMapping == nullptr) + { + // Unsupported footpath + objectList.SetObject(i, entry); + } + else + { + // We have surface objects for this footpath + auto surfaceIndex = objectList.Find(ObjectType::FootpathSurface, footpathMapping->NormalSurface); + if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL) + { + objectList.SetObject(ObjectType::FootpathSurface, surfaceCount, footpathMapping->NormalSurface); + surfaceIndex = surfaceCount++; + } + _pathToSurfaceMap[i] = surfaceIndex; + + surfaceIndex = objectList.Find(ObjectType::FootpathSurface, footpathMapping->QueueSurface); + if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL) + { + objectList.SetObject(ObjectType::FootpathSurface, surfaceCount, footpathMapping->QueueSurface); + surfaceIndex = surfaceCount++; + } + _pathToQueueSurfaceMap[i] = surfaceIndex; + + auto railingIndex = objectList.Find(ObjectType::FootpathRailings, footpathMapping->Railing); + if (railingIndex == OBJECT_ENTRY_INDEX_NULL) + { + objectList.SetObject(ObjectType::FootpathRailings, railingCount, footpathMapping->Railing); + railingIndex = railingCount++; + } + _pathToRailingMap[i] = railingIndex; + } + } + else + { + objectList.SetObject(i, entry); + } + } } } + SetDefaultRCT2TerrainObjects(objectList); + RCT12AddDefaultObjects(objectList); return objectList; } }; diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 4c1b5770ba..b9e4088957 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -1026,8 +1026,12 @@ void Ride::Update() // Various things include news messages if (lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_DUE_INSPECTION)) - if (((gCurrentTicks >> 1) & 255) == static_cast(id)) + { + // Breakdown updates are distributed, only one ride can update the breakdown status per tick. + const auto updatingRideId = (gCurrentTicks / 2) % MAX_RIDES; + if (static_cast(updatingRideId) == id) ride_breakdown_status_update(this); + } ride_inspection_update(this); @@ -1274,6 +1278,7 @@ static void ride_breakdown_update(Ride* ride) { if (gCurrentTicks & 255) return; + if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) return; @@ -5413,12 +5418,7 @@ bool ride_has_adjacent_station(Ride* ride) bool ride_has_station_shelter(Ride* ride) { auto stationObj = ride_get_station_object(ride); - if (network_get_mode() != NETWORK_MODE_NONE) - { - // The server might run in headless mode so no images will be loaded, only check for stations. - return stationObj != nullptr; - } - return stationObj != nullptr && stationObj->BaseImageId != 0; + return stationObj != nullptr && (stationObj->Flags & STATION_OBJECT_FLAGS::HAS_SHELTER); } bool ride_has_ratings(const Ride* ride) @@ -5789,3 +5789,37 @@ void Ride::UpdateRideTypeForAllPieces() } } } + +std::vector GetTracklessRides() +{ + // Iterate map and build list of seen ride IDs + std::vector seen; + seen.resize(256); + tile_element_iterator it; + tile_element_iterator_begin(&it); + while (tile_element_iterator_next(&it)) + { + auto trackEl = it.element->AsTrack(); + if (trackEl != nullptr && !trackEl->IsGhost()) + { + auto rideId = static_cast(trackEl->GetRideIndex()); + if (rideId >= seen.size()) + { + seen.resize(rideId + 1); + } + seen[rideId] = true; + } + } + + // Get all rides that did not get seen during map iteration + const auto& rideManager = GetRideManager(); + std::vector result; + for (const auto& ride : rideManager) + { + if (seen.size() <= static_cast(ride.id) || !seen[static_cast(ride.id)]) + { + result.push_back(ride.id); + } + } + return result; +} diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index b732838186..bfc82c26ca 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -35,7 +35,7 @@ struct Vehicle; // The max number of different types of vehicle. // Examples of vehicles here are the locomotive, tender and carriage of the Miniature Railway. #define MAX_VEHICLES_PER_RIDE_ENTRY 4 -constexpr const uint8_t MAX_VEHICLES_PER_RIDE = 31; +constexpr const uint8_t MAX_VEHICLES_PER_RIDE = 255; // Note: that 255 represents No Train (null) hence why this is not 256 constexpr const uint8_t MAX_CIRCUITS_PER_RIDE = 20; constexpr const uint8_t MAX_CARS_PER_TRAIN = 255; constexpr const uint8_t MAX_VEHICLE_COLOURS = std::max(MAX_CARS_PER_TRAIN, MAX_VEHICLES_PER_RIDE); @@ -43,8 +43,9 @@ constexpr const uint8_t MAX_VEHICLE_COLOURS = std::max(MAX_CARS_PER_TRAIN, MAX_V #define MAX_CATEGORIES_PER_RIDE 2 #define DOWNTIME_HISTORY_SIZE 8 #define CUSTOMER_HISTORY_SIZE 10 -#define MAX_STATIONS 4 -#define MAX_RIDES 255 +#define MAX_CARS_PER_TRAIN 255 +#define MAX_STATIONS 255 +constexpr const uint16_t MAX_RIDES = 1000; #define RIDE_TYPE_NULL 255 #define RIDE_ADJACENCY_CHECK_DISTANCE 5 @@ -217,7 +218,7 @@ struct Ride ObjectEntryIndex subtype; RideMode mode; uint8_t colour_scheme_type; - VehicleColour vehicle_colours[MAX_VEHICLE_COLOURS]; + VehicleColour vehicle_colours[MAX_VEHICLES_PER_RIDE + 1]; // 0 = closed, 1 = open, 2 = test RideStatus status; std::string custom_name; @@ -515,8 +516,9 @@ enum RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK = 1 << 15, RIDE_LIFECYCLE_CABLE_LIFT_HILL_COMPONENT_USED = 1 << 16, RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17, - RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN = 1 << 18, // Used for the Award for Best Custom-designed Rides - RIDE_LIFECYCLE_SIX_FLAGS_DEPRECATED = 1 << 19 // Not used anymore + RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN = 1 << 18, // Used for the Award for Best Custom-designed Rides + RIDE_LIFECYCLE_SIX_FLAGS_DEPRECATED = 1 << 19, // Not used anymore + RIDE_LIFECYCLE_FIXED_RATINGS = 1 << 20, // When set, the ratings will not be updated (useful for hacked rides). }; // Constants used by the ride_type->flags property at 0x008 @@ -1249,3 +1251,7 @@ void ride_action_modify(Ride* ride, int32_t modifyType, int32_t flags); void determine_ride_entrance_and_exit_locations(); void ride_clear_leftover_entrances(Ride* ride); + +std::vector GetTracklessRides(); + +void ride_remove_vehicles(Ride* ride); diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp index 5249cc4483..5a84f61dd9 100644 --- a/src/openrct2/ride/RideRatings.cpp +++ b/src/openrct2/ride/RideRatings.cpp @@ -166,7 +166,7 @@ static void ride_ratings_update_state_0(RideRatingUpdateState& state) } auto ride = get_ride(currentRide); - if (ride != nullptr && ride->status != RideStatus::Closed) + if (ride != nullptr && ride->status != RideStatus::Closed && !(ride->lifecycle_flags & RIDE_LIFECYCLE_FIXED_RATINGS)) { state.State = RIDE_RATINGS_STATE_INITIALISE; } diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index f2237b2607..155bd70950 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -688,25 +688,6 @@ static ObjectEntryIndex TrackDesignGetDefaultRailingIndex() return OBJECT_ENTRY_INDEX_NULL; } -static ObjectEntryIndex TrackDesignGetDefaultPathIndex(bool isQueue) -{ - for (ObjectEntryIndex i = 0; i < MAX_PATH_OBJECTS; i++) - { - auto legacyPathEntry = GetLegacyFootpathEntry(i); - if (legacyPathEntry != nullptr) - { - const auto& surfaceDescriptor = isQueue ? legacyPathEntry->GetQueueSurfaceDescriptor() - : legacyPathEntry->GetPathSurfaceDescriptor(); - if (surfaceDescriptor.IsEditorOnly()) - { - continue; - } - return i; - } - } - return OBJECT_ENTRY_INDEX_NULL; -} - static std::optional TrackDesignPlaceSceneryElementGetEntry(const TrackDesignSceneryElement& scenery) { TrackSceneryEntry result; @@ -742,14 +723,7 @@ static std::optional TrackDesignPlaceSceneryElementGetEntry(c if (result.SecondaryIndex == OBJECT_ENTRY_INDEX_NULL) result.SecondaryIndex = TrackDesignGetDefaultRailingIndex(); - // NOTE: This block can be deleted in the NSF branch. - if (result.Index == OBJECT_ENTRY_INDEX_NULL) - { - result.Type = ObjectType::Paths; - result.Index = TrackDesignGetDefaultPathIndex(scenery.IsQueue()); - } - - if (result.Index == OBJECT_ENTRY_INDEX_NULL) + if (result.Index == OBJECT_ENTRY_INDEX_NULL || result.SecondaryIndex == OBJECT_ENTRY_INDEX_NULL) { _trackDesignPlaceStateSceneryUnavailable = true; return {}; diff --git a/src/openrct2/ride/TrackDesign.h b/src/openrct2/ride/TrackDesign.h index 3d1640bb5a..d63dcb8c7e 100644 --- a/src/openrct2/ride/TrackDesign.h +++ b/src/openrct2/ride/TrackDesign.h @@ -44,7 +44,6 @@ struct TrackDesignEntranceElement bool isExit; }; -/* Track Scenery entry size: 0x16 */ struct TrackDesignSceneryElement { ObjectEntryDescriptor scenery_object; diff --git a/src/openrct2/ride/shops/meta/DrinkStall.h b/src/openrct2/ride/shops/meta/DrinkStall.h index 0a2276b901..46ac397bec 100644 --- a/src/openrct2/ride/shops/meta/DrinkStall.h +++ b/src/openrct2/ride/shops/meta/DrinkStall.h @@ -25,7 +25,7 @@ constexpr const RideTypeDescriptor DrinkStallRTD = SET_FIELD(TrackPaintFunction, get_track_paint_function_shop), SET_FIELD(Flags, RIDE_TYPE_FLAG_HAS_SINGLE_PIECE_STATION | RIDE_TYPE_FLAG_CANNOT_HAVE_GAPS | RIDE_TYPE_FLAG_NO_TEST_MODE | RIDE_TYPE_FLAG_NO_VEHICLES | RIDE_TYPE_FLAG_HAS_NO_TRACK | RIDE_TYPE_FLAG_IS_SHOP | RIDE_TYPE_FLAG_TRACK_NO_WALLS | RIDE_TYPE_FLAG_FLAT_RIDE | - RIDE_TYPE_FLAG_SELLS_DRINKS | RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY), + RIDE_TYPE_FLAG_SELLS_DRINKS | RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY | RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_MAIN), SET_FIELD(RideModes, EnumsToFlags(RideMode::ShopStall)), SET_FIELD(DefaultMode, RideMode::ShopStall), SET_FIELD(OperatingSettings, { 0, 0, 0, 0, 0, 0 }), diff --git a/src/openrct2/ride/shops/meta/FoodStall.h b/src/openrct2/ride/shops/meta/FoodStall.h index 4dfbb3d1c3..4a69faae2e 100644 --- a/src/openrct2/ride/shops/meta/FoodStall.h +++ b/src/openrct2/ride/shops/meta/FoodStall.h @@ -25,7 +25,7 @@ constexpr const RideTypeDescriptor FoodStallRTD = SET_FIELD(TrackPaintFunction, get_track_paint_function_shop), SET_FIELD(Flags, RIDE_TYPE_FLAG_HAS_SINGLE_PIECE_STATION | RIDE_TYPE_FLAG_CANNOT_HAVE_GAPS | RIDE_TYPE_FLAG_NO_TEST_MODE | RIDE_TYPE_FLAG_NO_VEHICLES | RIDE_TYPE_FLAG_HAS_NO_TRACK | RIDE_TYPE_FLAG_IS_SHOP | RIDE_TYPE_FLAG_TRACK_NO_WALLS | RIDE_TYPE_FLAG_FLAT_RIDE | - RIDE_TYPE_FLAG_SELLS_FOOD | RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY), + RIDE_TYPE_FLAG_SELLS_FOOD | RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY | RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_MAIN), SET_FIELD(RideModes, EnumsToFlags(RideMode::ShopStall)), SET_FIELD(DefaultMode, RideMode::ShopStall), SET_FIELD(OperatingSettings, { 0, 0, 0, 0, 0, 0 }), diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index b47d15d3e2..53f973fe3e 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -31,6 +31,7 @@ #include "../network/network.h" #include "../object/Object.h" #include "../object/ObjectList.h" +#include "../object/ObjectManager.h" #include "../peep/Guest.h" #include "../peep/Staff.h" #include "../platform/platform.h" @@ -64,7 +65,6 @@ std::string gScenarioName; std::string gScenarioDetails; std::string gScenarioCompletedBy; std::string gScenarioSavePath; -char gScenarioExpansionPacks[3256]; bool gFirstTimeSaving = true; uint16_t gSavedAge; uint32_t gLastAutoSaveUpdate = 0; @@ -78,7 +78,7 @@ uint16_t gScenarioParkRatingWarningDays; money64 gScenarioCompletedCompanyValue; money64 gScenarioCompanyValueRecord; -char gScenarioFileName[MAX_PATH]; +std::string gScenarioFileName; static void scenario_objective_check(); @@ -154,7 +154,15 @@ void scenario_begin() park_calculate_size(); map_count_remaining_land_rights(); Staff::ResetStats(); - gLastEntranceStyle = 0; + + auto& objManager = GetContext()->GetObjectManager(); + gLastEntranceStyle = objManager.GetLoadedObjectEntryIndex("rct2.station.plain"); + if (gLastEntranceStyle == OBJECT_ENTRY_INDEX_NULL) + { + // Fall back to first entrance object + gLastEntranceStyle = 0; + } + gMarketingCampaigns.clear(); gParkRatingCasualtyPenalty = 0; @@ -199,7 +207,7 @@ void scenario_success() gScenarioCompletedCompanyValue = companyValue; peep_applause(); - if (scenario_repository_try_record_highscore(gScenarioFileName, companyValue, nullptr)) + if (scenario_repository_try_record_highscore(gScenarioFileName.c_str(), companyValue, nullptr)) { // Allow name entry gParkFlags |= PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; @@ -214,7 +222,7 @@ void scenario_success() */ void scenario_success_submit_name(const char* name) { - if (scenario_repository_try_record_highscore(gScenarioFileName, gScenarioCompanyValueRecord, name)) + if (scenario_repository_try_record_highscore(gScenarioFileName.c_str(), gScenarioCompanyValueRecord, name)) { gScenarioCompletedBy = name; } diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 50f3b43af2..b7de2b2c80 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -162,12 +162,11 @@ extern std::string gScenarioName; extern std::string gScenarioDetails; extern std::string gScenarioCompletedBy; extern std::string gScenarioSavePath; -extern char gScenarioExpansionPacks[3256]; extern bool gFirstTimeSaving; extern uint16_t gSavedAge; extern uint32_t gLastAutoSaveUpdate; -extern char gScenarioFileName[260]; +extern std::string gScenarioFileName; void load_from_sc6(const char* path); void scenario_begin(); diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index a2aa515876..35286f14f9 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -126,7 +126,7 @@ class ScenarioFileIndex final : public FileIndex private: static constexpr uint32_t MAGIC_NUMBER = 0x58444953; // SIDX static constexpr uint16_t VERSION = 5; - static constexpr auto PATTERN = "*.sc4;*.sc6;*.sea"; + static constexpr auto PATTERN = "*.sc4;*.sc6;*.sea;*.park"; public: explicit ScenarioFileIndex(const IPlatformEnvironment& env) @@ -197,6 +197,28 @@ private: try { std::string extension = Path::GetExtension(path); + if (String::Equals(extension, ".park", true)) + { + // OpenRCT2 park + bool result = false; + try + { + auto& objRepository = OpenRCT2::GetContext()->GetObjectRepository(); + auto importer = ParkImporter::CreateParkFile(objRepository); + importer->LoadScenario(path.c_str(), true); + if (importer->GetDetails(entry)) + { + String::Set(entry->path, sizeof(entry->path), path.c_str()); + entry->timestamp = timestamp; + result = true; + } + } + catch (const std::exception&) + { + } + return result; + } + if (String::Equals(extension, ".sc4", true)) { // RCT1 scenario diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index 4f3881dc75..5cb475353e 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -415,6 +415,19 @@ namespace OpenRCT2::Scripting return dukCoords.Take(); } + template<> ObjectEntryIndex inline FromDuk(const DukValue& d) + { + if (d.type() == DukValue::Type::NUMBER) + { + auto value = d.as_int(); + if (value >= 0 && value <= std::numeric_limits::max()) + { + return static_cast(value); + } + } + return OBJECT_ENTRY_INDEX_NULL; + } + } // namespace OpenRCT2::Scripting #endif diff --git a/src/openrct2/scripting/bindings/world/ScScenario.hpp b/src/openrct2/scripting/bindings/world/ScScenario.hpp index d912be2d0f..0992b2ac25 100644 --- a/src/openrct2/scripting/bindings/world/ScScenario.hpp +++ b/src/openrct2/scripting/bindings/world/ScScenario.hpp @@ -224,7 +224,7 @@ namespace OpenRCT2::Scripting void filename_set(const std::string& value) { ThrowIfGameStateNotMutable(); - String::Set(gScenarioFileName, std::size(gScenarioFileName), value.c_str()); + gScenarioFileName = value; } std::shared_ptr objective_get() const diff --git a/src/openrct2/scripting/bindings/world/ScTileElement.cpp b/src/openrct2/scripting/bindings/world/ScTileElement.cpp index c582c6dd81..6605812e97 100644 --- a/src/openrct2/scripting/bindings/world/ScTileElement.cpp +++ b/src/openrct2/scripting/bindings/world/ScTileElement.cpp @@ -54,8 +54,6 @@ namespace OpenRCT2::Scripting return "large_scenery"; case TILE_ELEMENT_TYPE_BANNER: return "banner"; - case TILE_ELEMENT_TYPE_CORRUPT: - return "openrct2_corrupt_deprecated"; default: return "unknown"; } @@ -81,9 +79,7 @@ namespace OpenRCT2::Scripting _element->type = TILE_ELEMENT_TYPE_BANNER; else { - if (value == "openrct2_corrupt_deprecated") - std::puts( - "Creation of new corrupt elements is deprecated. To hide elements, use the 'hidden' property instead."); + std::puts("Element type not recognised!"); return; } @@ -746,43 +742,46 @@ namespace OpenRCT2::Scripting } return DukValue::take_from_stack(ctx); } - void ScTileElement::object_set(uint32_t value) + + void ScTileElement::object_set(const DukValue& value) { ThrowIfGameStateNotMutable(); + + auto index = FromDuk(value); switch (_element->GetType()) { case TILE_ELEMENT_TYPE_PATH: { auto el = _element->AsPath(); - el->SetLegacyPathEntryIndex(value & 0xFF); + el->SetLegacyPathEntryIndex(index); Invalidate(); break; } case TILE_ELEMENT_TYPE_SMALL_SCENERY: { auto el = _element->AsSmallScenery(); - el->SetEntryIndex(value & 0xFF); + el->SetEntryIndex(index); Invalidate(); break; } case TILE_ELEMENT_TYPE_LARGE_SCENERY: { auto el = _element->AsLargeScenery(); - el->SetEntryIndex(value); + el->SetEntryIndex(index); Invalidate(); break; } case TILE_ELEMENT_TYPE_WALL: { auto el = _element->AsWall(); - el->SetEntryIndex(value & 0xFFFF); + el->SetEntryIndex(index); Invalidate(); break; } case TILE_ELEMENT_TYPE_ENTRANCE: { auto el = _element->AsEntrance(); - el->SetEntranceType(value & 0xFF); + el->SetEntranceType(index); Invalidate(); break; } @@ -791,77 +790,13 @@ namespace OpenRCT2::Scripting bool ScTileElement::isHidden_get() const { - // TODO: Simply return the 'hidden' field once corrupt elements are superseded. - const TileElement* element = map_get_first_element_at(_coords); - bool previousElementWasUsefulCorrupt = false; - do - { - if (element == _element) - return previousElementWasUsefulCorrupt; - - if (element->GetType() == TILE_ELEMENT_TYPE_CORRUPT) - previousElementWasUsefulCorrupt = !previousElementWasUsefulCorrupt; - else - previousElementWasUsefulCorrupt = false; - } while (!(element++)->IsLastForTile()); - - Guard::Assert(false); - return false; + return _element->IsInvisible(); } + void ScTileElement::isHidden_set(bool hide) { - // TODO: Simply update the 'hidden' field once corrupt elements are superseded. ThrowIfGameStateNotMutable(); - const bool isHidden = isHidden_get(); - if (hide == isHidden) - return; - - if (hide) - { - // Get index of our current element (has to be done now before inserting the corrupt element) - const auto elementIndex = _element - map_get_first_element_at(_coords); - - // Insert corrupt element at the end of the list for this tile - // Note: Z = MAX_ELEMENT_HEIGHT to guarantee this - TileElement* insertedElement = tile_element_insert( - { _coords, MAX_ELEMENT_HEIGHT * COORDS_Z_STEP }, 0, TileElementType::Corrupt); - if (insertedElement == nullptr) - { - // TODO: Show error - return; - } - - // Since inserting a new element may move the tile elements in memory, we have to update the local pointer - _element = map_get_first_element_at(_coords) + elementIndex; - - // Move the corrupt element down in the list until it's right under our element - while (insertedElement > _element) - { - std::swap(*insertedElement, *(insertedElement - 1)); - insertedElement--; - - // Un-swap the last-for-tile flag - if (insertedElement->IsLastForTile()) - { - insertedElement->SetLastForTile(false); - (insertedElement + 1)->SetLastForTile(true); - } - } - - // Now the corrupt element took the hidden element's place, increment it by one - _element++; - - // Update base and clearance heights of inserted corrupt element to match the element to hide - insertedElement->base_height = insertedElement->clearance_height = _element->base_height; - } - else - { - TileElement* const elementToRemove = _element - 1; - Guard::Assert(elementToRemove->GetType() == TILE_ELEMENT_TYPE_CORRUPT); - tile_element_remove(elementToRemove); - _element--; - } - + _element->SetInvisible(hide); Invalidate(); } @@ -1294,6 +1229,74 @@ namespace OpenRCT2::Scripting } } + DukValue ScTileElement::surfaceObject_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + if (_element->GetType() == TILE_ELEMENT_TYPE_PATH) + { + auto el = _element->AsPath(); + auto index = el->GetSurfaceEntryIndex(); + if (index != OBJECT_ENTRY_INDEX_NULL) + { + duk_push_int(ctx, index); + } + else + { + duk_push_null(ctx); + } + } + else + { + duk_push_null(ctx); + } + return DukValue::take_from_stack(ctx); + } + + void ScTileElement::surfaceObject_set(const DukValue& value) + { + ThrowIfGameStateNotMutable(); + if (_element->GetType() == TILE_ELEMENT_TYPE_PATH) + { + auto el = _element->AsPath(); + el->SetSurfaceEntryIndex(FromDuk(value)); + Invalidate(); + } + } + + DukValue ScTileElement::railingsObject_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + if (_element->GetType() == TILE_ELEMENT_TYPE_PATH) + { + auto el = _element->AsPath(); + auto index = el->GetRailingsEntryIndex(); + if (index != OBJECT_ENTRY_INDEX_NULL) + { + duk_push_int(ctx, index); + } + else + { + duk_push_null(ctx); + } + } + else + { + duk_push_null(ctx); + } + return DukValue::take_from_stack(ctx); + } + + void ScTileElement::railingsObject_set(const DukValue& value) + { + ThrowIfGameStateNotMutable(); + if (_element->GetType() == TILE_ELEMENT_TYPE_PATH) + { + auto el = _element->AsPath(); + el->SetRailingsEntryIndex(FromDuk(value)); + Invalidate(); + } + } + DukValue ScTileElement::addition_get() const { auto ctx = GetContext()->GetScriptEngine().GetContext(); @@ -1395,18 +1398,64 @@ namespace OpenRCT2::Scripting auto ctx = GetContext()->GetScriptEngine().GetContext(); auto el = _element->AsEntrance(); if (el != nullptr) - duk_push_int(ctx, el->GetLegacyPathEntryIndex()); + { + auto index = el->GetLegacyPathEntryIndex(); + if (index != OBJECT_ENTRY_INDEX_NULL) + { + duk_push_int(ctx, index); + } + else + { + duk_push_null(ctx); + } + } else + { duk_push_null(ctx); + } return DukValue::take_from_stack(ctx); } - void ScTileElement::footpathObject_set(uint8_t value) + void ScTileElement::footpathObject_set(const DukValue& value) { ThrowIfGameStateNotMutable(); auto el = _element->AsEntrance(); if (el != nullptr) { - el->SetLegacyPathEntryIndex(value); + el->SetLegacyPathEntryIndex(FromDuk(value)); + Invalidate(); + } + } + + DukValue ScTileElement::footpathSurfaceObject_get() const + { + auto ctx = GetContext()->GetScriptEngine().GetContext(); + auto el = _element->AsEntrance(); + if (el != nullptr) + { + auto index = el->GetSurfaceEntryIndex(); + if (index != OBJECT_ENTRY_INDEX_NULL) + { + duk_push_int(ctx, index); + } + else + { + duk_push_null(ctx); + } + } + else + { + duk_push_null(ctx); + } + return DukValue::take_from_stack(ctx); + } + + void ScTileElement::footpathSurfaceObject_set(const DukValue& value) + { + ThrowIfGameStateNotMutable(); + auto el = _element->AsEntrance(); + if (el != nullptr) + { + el->SetSurfaceEntryIndex(FromDuk(value)); Invalidate(); } } @@ -1524,12 +1573,15 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &ScTileElement::isQueue_get, &ScTileElement::isQueue_set, "isQueue"); dukglue_register_property( ctx, &ScTileElement::queueBannerDirection_get, &ScTileElement::queueBannerDirection_set, "queueBannerDirection"); - dukglue_register_property(ctx, &ScTileElement::queueBannerDirection_get, &ScTileElement::edges_set, "test"); dukglue_register_property( ctx, &ScTileElement::isBlockedByVehicle_get, &ScTileElement::isBlockedByVehicle_set, "isBlockedByVehicle"); dukglue_register_property(ctx, &ScTileElement::isWide_get, &ScTileElement::isWide_set, "isWide"); + dukglue_register_property(ctx, &ScTileElement::surfaceObject_get, &ScTileElement::surfaceObject_set, "surfaceObject"); + dukglue_register_property( + ctx, &ScTileElement::railingsObject_get, &ScTileElement::railingsObject_set, "railingsObject"); + dukglue_register_property(ctx, &ScTileElement::addition_get, &ScTileElement::addition_set, "addition"); dukglue_register_property( ctx, &ScTileElement::additionStatus_get, &ScTileElement::additionStatus_set, "additionStatus"); @@ -1560,6 +1612,8 @@ namespace OpenRCT2::Scripting // Entrance only dukglue_register_property( ctx, &ScTileElement::footpathObject_get, &ScTileElement::footpathObject_set, "footpathObject"); + dukglue_register_property( + ctx, &ScTileElement::footpathSurfaceObject_get, &ScTileElement::footpathSurfaceObject_set, "footpathSurfaceObject"); } } // namespace OpenRCT2::Scripting diff --git a/src/openrct2/scripting/bindings/world/ScTileElement.hpp b/src/openrct2/scripting/bindings/world/ScTileElement.hpp index 7fa36099ea..feca670d5c 100644 --- a/src/openrct2/scripting/bindings/world/ScTileElement.hpp +++ b/src/openrct2/scripting/bindings/world/ScTileElement.hpp @@ -112,7 +112,7 @@ namespace OpenRCT2::Scripting void hasCableLift_set(bool value); DukValue object_get() const; - void object_set(uint32_t value); + void object_set(const DukValue& value); bool isHidden_get() const; void isHidden_set(bool hide); @@ -172,6 +172,12 @@ namespace OpenRCT2::Scripting DukValue addition_get() const; void addition_set(const DukValue& value); + DukValue surfaceObject_get() const; + void surfaceObject_set(const DukValue& value); + + DukValue railingsObject_get() const; + void railingsObject_set(const DukValue& value); + DukValue additionStatus_get() const; void additionStatus_set(uint8_t value); @@ -182,7 +188,10 @@ namespace OpenRCT2::Scripting void isAdditionGhost_set(bool value); DukValue footpathObject_get() const; - void footpathObject_set(uint8_t value); + void footpathObject_set(const DukValue& value); + + DukValue footpathSurfaceObject_get() const; + void footpathSurfaceObject_set(const DukValue& value); DukValue direction_get() const; void direction_set(uint8_t value); diff --git a/src/openrct2/windows/tile_inspector.h b/src/openrct2/windows/tile_inspector.h index cd7357c280..42d00f645a 100644 --- a/src/openrct2/windows/tile_inspector.h +++ b/src/openrct2/windows/tile_inspector.h @@ -23,7 +23,6 @@ enum class TileInspectorPage : int16_t Wall, LargeScenery, Banner, - Corrupt }; extern TileCoordsXY windowTileInspectorTile; diff --git a/src/openrct2/world/Banner.h b/src/openrct2/world/Banner.h index 1ec15ec3c2..e4ad35c2ec 100644 --- a/src/openrct2/world/Banner.h +++ b/src/openrct2/world/Banner.h @@ -22,7 +22,7 @@ struct WallElement; using BannerIndex = uint16_t; constexpr ObjectEntryIndex BANNER_NULL = OBJECT_ENTRY_INDEX_NULL; -constexpr size_t MAX_BANNERS = 250; +constexpr size_t MAX_BANNERS = 8192; constexpr BannerIndex BANNER_INDEX_NULL = static_cast(-1); constexpr uint8_t SCROLLING_MODE_NONE = 255; diff --git a/src/openrct2/world/Entity.h b/src/openrct2/world/Entity.h index 407f474afe..ca438cbf8f 100644 --- a/src/openrct2/world/Entity.h +++ b/src/openrct2/world/Entity.h @@ -11,7 +11,7 @@ #include "EntityBase.h" -constexpr uint16_t MAX_ENTITIES = 10000; +constexpr uint16_t MAX_ENTITIES = 65535; EntityBase* try_get_sprite(size_t spriteIndex); EntityBase* get_sprite(size_t sprite_idx); diff --git a/src/openrct2/world/Entrance.cpp b/src/openrct2/world/Entrance.cpp index 49685c3508..03fa13ae2e 100644 --- a/src/openrct2/world/Entrance.cpp +++ b/src/openrct2/world/Entrance.cpp @@ -217,6 +217,23 @@ void fix_park_entrance_locations(void) gParkEntrances.end()); } +void UpdateParkEntranceLocations() +{ + gParkEntrances.clear(); + tile_element_iterator it; + tile_element_iterator_begin(&it); + while (tile_element_iterator_next(&it)) + { + auto entranceElement = it.element->AsEntrance(); + if (entranceElement != nullptr && entranceElement->GetEntranceType() == ENTRANCE_TYPE_PARK_ENTRANCE + && entranceElement->GetSequenceIndex() == 0 && !entranceElement->IsGhost()) + { + auto entrance = TileCoordsXYZD(it.x, it.y, it.element->base_height, it.element->GetDirection()).ToCoordsXYZD(); + gParkEntrances.push_back(entrance); + } + } +} + uint8_t EntranceElement::GetStationIndex() const { return StationIndex; diff --git a/src/openrct2/world/Entrance.h b/src/openrct2/world/Entrance.h index cd89adbe4b..2874541a71 100644 --- a/src/openrct2/world/Entrance.h +++ b/src/openrct2/world/Entrance.h @@ -40,7 +40,7 @@ constexpr const uint8_t RideExitHeight = 5 * COORDS_Z_STEP; extern bool gParkEntranceGhostExists; extern CoordsXYZD gParkEntranceGhostPosition; -#define MAX_PARK_ENTRANCES 4 +#define MAX_PARK_ENTRANCES 256 constexpr int32_t MaxRideEntranceOrExitHeight = 244 * COORDS_Z_STEP; @@ -60,3 +60,4 @@ void maze_entrance_hedge_replacement(const CoordsXYE& entrance); void maze_entrance_hedge_removal(const CoordsXYE& entrance); void fix_park_entrance_locations(); +void UpdateParkEntranceLocations(); diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 82c198df7a..ce058ec45b 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -29,8 +29,6 @@ constexpr auto FootpathMinHeight = 2 * COORDS_Z_STEP; constexpr auto PATH_HEIGHT_STEP = 2 * COORDS_Z_STEP; constexpr auto PATH_CLEARANCE = 4 * COORDS_Z_STEP; -class FootpathObject; - enum class RailingEntrySupportType : uint8_t { Box = 0, @@ -176,6 +174,7 @@ enum { RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE = (1 << 0), RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS = (1 << 1), // When elevated + RAILING_ENTRY_FLAG_NO_QUEUE_BANNER = (1 << 2), }; enum diff --git a/src/openrct2/world/Litter.cpp b/src/openrct2/world/Litter.cpp index a5310d9f42..236f0150af 100644 --- a/src/openrct2/world/Litter.cpp +++ b/src/openrct2/world/Litter.cpp @@ -3,7 +3,6 @@ #include "../Cheats.h" #include "../Game.h" #include "../localisation/StringIds.h" -#include "../scenario/Scenario.h" #include "EntityList.h" #include "Map.h" #include "Sprite.h" diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index c204a474f3..8c63223d01 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -19,10 +19,10 @@ #define MINIMUM_LAND_HEIGHT 2 #define MAXIMUM_LAND_HEIGHT 142 #define MINIMUM_WATER_HEIGHT 2 -#define MAXIMUM_WATER_HEIGHT 58 +#define MAXIMUM_WATER_HEIGHT 142 #define MINIMUM_MAP_SIZE_TECHNICAL 15 -#define MAXIMUM_MAP_SIZE_TECHNICAL 256 +#define MAXIMUM_MAP_SIZE_TECHNICAL 1001 #define MINIMUM_MAP_SIZE_PRACTICAL (MINIMUM_MAP_SIZE_TECHNICAL - 2) #define MAXIMUM_MAP_SIZE_PRACTICAL (MAXIMUM_MAP_SIZE_TECHNICAL - 2) constexpr const int32_t MAXIMUM_MAP_SIZE_BIG = COORDS_XY_STEP * MAXIMUM_MAP_SIZE_TECHNICAL; @@ -32,10 +32,10 @@ constexpr const int32_t MINIMUM_LAND_HEIGHT_BIG = MINIMUM_LAND_HEIGHT * COORDS_Z #define MAP_MINIMUM_X_Y (-MAXIMUM_MAP_SIZE_TECHNICAL) -constexpr const uint32_t MAX_TILE_ELEMENTS_WITH_SPARE_ROOM = 0x30000; +constexpr const uint32_t MAX_TILE_ELEMENTS_WITH_SPARE_ROOM = 0x1000000; constexpr const uint32_t MAX_TILE_ELEMENTS = MAX_TILE_ELEMENTS_WITH_SPARE_ROOM - 512; #define MAX_TILE_TILE_ELEMENT_POINTERS (MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL) -#define MAX_PEEP_SPAWNS 2 +#define MAX_PEEP_SPAWNS 256 #define TILE_UNDEFINED_TILE_ELEMENT NULL diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index ee1e37a6ad..4e94d522c6 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -86,7 +86,8 @@ static constexpr const char* SnowTrees[] = { // Randomly chosen base terrains. We rarely want a whole map made out of chequerboard or rock. static constexpr const std::string_view BaseTerrain[] = { - "rct2.surface.grass", "rct2.surface.sand", "rct2.surface.sandbrown", "rct2.surface.dirt", "rct2.surface.ice", + "rct2.terrain_surface.grass", "rct2.terrain_surface.sand", "rct2.terrain_surface.sand_brown", + "rct2.terrain_surface.dirt", "rct2.terrain_surface.ice", }; static void mapgen_place_trees(); @@ -152,12 +153,12 @@ void mapgen_generate(mapgen_settings* settings) if (edgeTexture.empty()) { // Base edge type on surface type - if (floorTexture == "rct2.surface.dirt") - edgeTexture = "rct2.edge.woodred"; - else if (floorTexture == "rct2.surface.ice") - edgeTexture = "rct2.edge.ice"; + if (floorTexture == "rct2.terrain_surface.dirt") + edgeTexture = "rct2.terrain_edge.wood_red"; + else if (floorTexture == "rct2.terrain_surface.ice") + edgeTexture = "rct2.terrain_edge.ice"; else - edgeTexture = "rct2.edge.rock"; + edgeTexture = "rct2.terrain_edge.rock"; } auto floorTextureId = object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(floorTexture)); @@ -204,15 +205,15 @@ void mapgen_generate(mapgen_settings* settings) // Add sandy beaches std::string beachTexture = std::string(floorTexture); - if (settings->floor == -1 && floorTexture == "rct2.surface.grass") + if (settings->floor == -1 && floorTexture == "rct2.terrain_surface.grass") { switch (util_rand() % 4) { case 0: - beachTexture = "rct2.surface.sand"; + beachTexture = "rct2.terrain_surface.sand"; break; case 1: - beachTexture = "rct2.surface.sandbrown"; + beachTexture = "rct2.terrain_surface.sand_brown"; break; } } @@ -257,19 +258,20 @@ static void mapgen_place_tree(int32_t type, const CoordsXY& loc) static bool MapGenSurfaceTakesGrassTrees(const TerrainSurfaceObject& surface) { const auto& id = surface.GetIdentifier(); - return id == "rct2.surface.grass" || id == "rct2.surface.grassclumps" || id == "rct2.surface.dirt"; + return id == "rct2.terrain_surface.grass" || id == "rct2.terrain_surface.grass_clumps" || id == "rct2.terrain_surface.dirt"; } static bool MapGenSurfaceTakesSandTrees(const TerrainSurfaceObject& surface) { const auto& id = surface.GetIdentifier(); - return id == "rct2.surface.sand" || id == "rct2.surface.sandbrown" || id == "rct2.surface.sandred"; + return id == "rct2.terrain_surface.sand" || id == "rct2.terrain_surface.sand_brown" + || id == "rct2.terrain_surface.sand_red"; } static bool MapGenSurfaceTakesSnowTrees(const TerrainSurfaceObject& surface) { const auto& id = surface.GetIdentifier(); - return id == "rct2.surface.ice"; + return id == "rct2.terrain_surface.ice"; } /** diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index f36a1978cf..5b4b21fd99 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -401,3 +401,41 @@ void RestrictAllMiscScenery() } } } + +ObjectType GetObjectTypeFromSceneryType(uint8_t type) +{ + switch (type) + { + case SCENERY_TYPE_SMALL: + return ObjectType::SmallScenery; + case SCENERY_TYPE_PATH_ITEM: + return ObjectType::PathBits; + case SCENERY_TYPE_WALL: + return ObjectType::Walls; + case SCENERY_TYPE_LARGE: + return ObjectType::LargeScenery; + case SCENERY_TYPE_BANNER: + return ObjectType::Banners; + default: + throw std::runtime_error("Invalid scenery type"); + } +} + +uint8_t GetSceneryTypeFromObjectType(ObjectType type) +{ + switch (type) + { + case ObjectType::SmallScenery: + return SCENERY_TYPE_SMALL; + case ObjectType::PathBits: + return SCENERY_TYPE_PATH_ITEM; + case ObjectType::Walls: + return SCENERY_TYPE_WALL; + case ObjectType::LargeScenery: + return SCENERY_TYPE_LARGE; + case ObjectType::Banners: + return SCENERY_TYPE_BANNER; + default: + throw std::runtime_error("Invalid object type"); + } +} diff --git a/src/openrct2/world/Scenery.h b/src/openrct2/world/Scenery.h index 6b678e6ad1..395ec8416d 100644 --- a/src/openrct2/world/Scenery.h +++ b/src/openrct2/world/Scenery.h @@ -301,3 +301,6 @@ bool IsSceneryItemRestricted(const ScenerySelection& item); void ClearRestrictedScenery(); void RestrictAllMiscScenery(); std::vector& GetRestrictedScenery(); + +ObjectType GetObjectTypeFromSceneryType(uint8_t type); +uint8_t GetSceneryTypeFromObjectType(ObjectType type); diff --git a/src/openrct2/world/Surface.h b/src/openrct2/world/Surface.h index a63ee5e1c8..7e01ce922e 100644 --- a/src/openrct2/world/Surface.h +++ b/src/openrct2/world/Surface.h @@ -36,6 +36,7 @@ enum TERRAIN_ROOF_IRON, TERRAIN_ROOF_LOG, TERRAIN_COUNT_REGULAR, // The amount of surface types the user can actually select - what follows are technical types + // Technical types (not selectable) TERRAIN_CHECKERBOARD_INVERTED = TERRAIN_COUNT_REGULAR, TERRAIN_UNDERGROUND_VIEW, }; diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index 893b3f06b5..e71522fd23 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -46,9 +46,6 @@ enum TILE_ELEMENT_TYPE_WALL = (5 << 2), TILE_ELEMENT_TYPE_LARGE_SCENERY = (6 << 2), TILE_ELEMENT_TYPE_BANNER = (7 << 2), - // The corrupt element type is used for skipping drawing other following - // elements on a given tile. - TILE_ELEMENT_TYPE_CORRUPT = (8 << 2), }; enum class TileElementType : uint8_t @@ -61,7 +58,6 @@ enum class TileElementType : uint8_t Wall = (5 << 2), LargeScenery = (6 << 2), Banner = (7 << 2), - Corrupt = (8 << 2), }; struct TileElement; @@ -73,7 +69,6 @@ struct LargeSceneryElement; struct WallElement; struct EntranceElement; struct BannerElement; -struct CorruptElement; struct TileElementBase { @@ -96,6 +91,8 @@ struct TileElementBase void SetLastForTile(bool on); bool IsGhost() const; void SetGhost(bool isGhost); + bool IsInvisible() const; + void SetInvisible(bool on); uint8_t GetOccupiedQuadrants() const; void SetOccupiedQuadrants(uint8_t quadrants); @@ -638,14 +635,6 @@ public: }; assert_struct_size(BannerElement, 16); -struct CorruptElement : TileElementBase -{ - static constexpr TileElementType ElementType = TileElementType::Corrupt; - - uint8_t pad[3]; - uint8_t pad_08[8]; -}; -assert_struct_size(CorruptElement, 16); #pragma pack(pop) class QuarterTile @@ -702,6 +691,7 @@ enum enum { TILE_ELEMENT_FLAG_GHOST = (1 << 4), + TILE_ELEMENT_FLAG_INVISIBLE = (1 << 5), TILE_ELEMENT_FLAG_LAST_TILE = (1 << 7) }; diff --git a/src/openrct2/world/TileElementBase.cpp b/src/openrct2/world/TileElementBase.cpp index 17c08b6e27..88d4f9f73c 100644 --- a/src/openrct2/world/TileElementBase.cpp +++ b/src/openrct2/world/TileElementBase.cpp @@ -50,6 +50,19 @@ void TileElementBase::SetLastForTile(bool on) Flags &= ~TILE_ELEMENT_FLAG_LAST_TILE; } +bool TileElementBase::IsInvisible() const +{ + return (this->Flags & TILE_ELEMENT_FLAG_INVISIBLE) != 0; +} + +void TileElementBase::SetInvisible(bool on) +{ + if (on) + Flags |= TILE_ELEMENT_FLAG_INVISIBLE; + else + Flags &= ~TILE_ELEMENT_FLAG_INVISIBLE; +} + bool TileElementBase::IsGhost() const { return (this->Flags & TILE_ELEMENT_FLAG_GHOST) != 0; diff --git a/src/openrct2/world/TileInspector.cpp b/src/openrct2/world/TileInspector.cpp index 01698c85bd..bdd2221a32 100644 --- a/src/openrct2/world/TileInspector.cpp +++ b/src/openrct2/world/TileInspector.cpp @@ -85,69 +85,6 @@ namespace OpenRCT2::TileInspector return nullptr; } - /** - * Inserts a corrupt element under a given element on a given tile - * @param x The x coordinate of the tile - * @param y The y coordinate of the tile - * @param elementIndex The nth element on this tile - * Returns 0 on success, MONEY_UNDEFINED otherwise. - */ - GameActionResultPtr InsertCorruptElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting) - { - // Make sure there is enough space for the new element - if (!MapCheckCapacityAndReorganise(loc)) - return std::make_unique(GameActions::Status::NoFreeElements, STR_NONE, STR_NONE); - - if (isExecuting) - { - // Create new corrupt element - TileElement* corruptElement = tile_element_insert( - { loc, (-1 * COORDS_Z_STEP) }, 0b0000, - TileElementType::Corrupt); // Ugly hack: -1 guarantees this to be placed first - if (corruptElement == nullptr) - { - log_warning("Failed to insert corrupt element."); - return std::make_unique(GameActions::Status::Unknown, STR_NONE, STR_NONE); - } - - // Set the base height to be the same as the selected element - TileElement* const selectedElement = map_get_nth_element_at(loc, elementIndex + 1); - if (selectedElement == nullptr) - { - return std::make_unique(GameActions::Status::Unknown, STR_NONE, STR_NONE); - } - corruptElement->base_height = corruptElement->clearance_height = selectedElement->base_height; - - // Move the corrupt element up until the selected list item is reached - // this way it's placed under the selected element, even when there are multiple elements with the same base height - for (int16_t i = 0; i < elementIndex; i++) - { - if (!SwapTileElements(loc, i, i + 1)) - { - // don't return error here, we've already inserted an element - // and moved it as far as we could, the only sensible thing left - // to do is to invalidate the window. - break; - } - } - - map_invalidate_tile_full(loc); - - if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) - { - windowTileInspectorElementCount++; - if (windowTileInspectorSelectedIndex > elementIndex) - { - windowTileInspectorSelectedIndex++; - } - inspector->Invalidate(); - } - } - - // Nothing went wrong - return std::make_unique(); - } - static int32_t numLargeScenerySequences(const CoordsXY& loc, const LargeSceneryElement* const largeScenery) { const auto* const largeEntry = largeScenery->GetEntry(); @@ -357,6 +294,26 @@ namespace OpenRCT2::TileInspector return std::make_unique(); } + GameActionResultPtr ToggleInvisibilityOfElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) + { + if (!isExecuting) + { + return std::make_unique(); + } + + TileElement* tileElement = map_get_nth_element_at(loc, elementIndex); + bool currentlyInvisible = tileElement->IsInvisible(); + tileElement->SetInvisible(!currentlyInvisible); + + map_invalidate_tile_full(loc); + if (loc == windowTileInspectorTile.ToCoordsXY()) + { + window_invalidate_by_class(WC_TILE_INSPECTOR); + } + + return std::make_unique(); + } + GameActionResultPtr PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting) { // Make sure there is enough space for the new element @@ -1087,30 +1044,6 @@ namespace OpenRCT2::TileInspector return std::make_unique(); } - GameActionResultPtr CorruptClamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting) - { - TileElement* const corruptElement = map_get_nth_element_at(loc, elementIndex); - - if (corruptElement == nullptr || corruptElement->GetType() != TILE_ELEMENT_TYPE_CORRUPT) - return std::make_unique(GameActions::Status::Unknown, STR_NONE, STR_NONE); - - if (corruptElement->IsLastForTile()) - return std::make_unique(GameActions::Status::Unknown, STR_NONE, STR_NONE); - - if (isExecuting) - { - TileElement* const nextElement = corruptElement + 1; - corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height; - - if (auto* inspector = GetTileInspectorWithPos(loc); inspector != nullptr) - { - inspector->Invalidate(); - } - } - - return std::make_unique(); - } - // NOTE: The pointer is exclusively used to determine the current selection, // do not access the data, points to potentially invalid memory. static const TileElement* _highlightedElement = nullptr; @@ -1124,5 +1057,4 @@ namespace OpenRCT2::TileInspector { return _highlightedElement == elem; } - } // namespace OpenRCT2::TileInspector diff --git a/src/openrct2/world/TileInspector.h b/src/openrct2/world/TileInspector.h index 0f204f8bf5..f8a03ac000 100644 --- a/src/openrct2/world/TileInspector.h +++ b/src/openrct2/world/TileInspector.h @@ -28,6 +28,7 @@ namespace OpenRCT2::TileInspector GameActionResultPtr RemoveElementAt(const CoordsXY& loc, int16_t elementIndex, bool isExecuting); GameActionResultPtr SwapElementsAt(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting); GameActionResultPtr RotateElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); + GameActionResultPtr ToggleInvisibilityOfElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); GameActionResultPtr PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting); GameActionResultPtr SortElementsAt(const CoordsXY& loc, bool isExecuting); GameActionResultPtr AnyBaseHeightOffset(const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting); @@ -53,6 +54,5 @@ namespace OpenRCT2::TileInspector const CoordsXY& loc, int32_t elementIndex, int32_t quarterIndex, bool isExecuting); GameActionResultPtr BannerToggleBlockingEdge( const CoordsXY& loc, int32_t elementIndex, int32_t edgeIndex, bool isExecuting); - GameActionResultPtr CorruptClamp(const CoordsXY& loc, int32_t elementIndex, bool isExecuting); } // namespace OpenRCT2::TileInspector diff --git a/test/tests/ReplayTests.cpp b/test/tests/ReplayTests.cpp index fee8e6e56b..88c5a6a581 100644 --- a/test/tests/ReplayTests.cpp +++ b/test/tests/ReplayTests.cpp @@ -50,7 +50,7 @@ static std::vector GetReplayFiles() std::vector res; std::string basePath = TestData::GetBasePath(); std::string replayPath = Path::Combine(basePath, "replays"); - std::string replayPathPattern = Path::Combine(replayPath, "*.sv6r"); + std::string replayPathPattern = Path::Combine(replayPath, "*.parkrep"); std::vector files; auto scanner = Path::ScanDirectory(replayPathPattern, true); diff --git a/test/tests/S6ImportExportTests.cpp b/test/tests/S6ImportExportTests.cpp index 5741842e01..dcd5093325 100644 --- a/test/tests/S6ImportExportTests.cpp +++ b/test/tests/S6ImportExportTests.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,10 @@ #include #include #include -#include #include +#include #include +#include #include #include #include @@ -70,7 +72,7 @@ static void GameInit(bool retainSpatialIndices) gGameSpeed = 1; } -static bool ImportSave(MemoryStream& stream, std::unique_ptr& context, bool retainSpatialIndices) +static bool ImportS6(MemoryStream& stream, std::unique_ptr& context, bool retainSpatialIndices) { stream.SetPosition(0); @@ -86,14 +88,29 @@ static bool ImportSave(MemoryStream& stream, std::unique_ptr& context, return true; } +static bool ImportPark(MemoryStream& stream, std::unique_ptr& context, bool retainSpatialIndices) +{ + stream.SetPosition(0); + + auto& objManager = context->GetObjectManager(); + + auto importer = ParkImporter::CreateParkFile(context->GetObjectRepository()); + auto loadResult = importer->LoadFromStream(&stream, false); + objManager.LoadObjects(loadResult.RequiredObjects); + importer->Import(); + + GameInit(retainSpatialIndices); + + return true; +} + static bool ExportSave(MemoryStream& stream, std::unique_ptr& context) { auto& objManager = context->GetObjectManager(); - auto exporter = std::make_unique(); + auto exporter = std::make_unique(); exporter->ExportObjectsList = objManager.GetPackableObjects(); - exporter->Export(); - exporter->SaveGame(&stream); + exporter->Export(stream); return true; } @@ -185,7 +202,7 @@ TEST(S6ImportExportBasic, all) std::string testParkPath = TestData::GetParkPath("BigMapTest.sv6"); ASSERT_TRUE(LoadFileToBuffer(importBuffer, testParkPath)); - ASSERT_TRUE(ImportSave(importBuffer, context, false)); + ASSERT_TRUE(ImportS6(importBuffer, context, false)); RecordGameStateSnapshot(context, snapshotStream); ASSERT_TRUE(ExportSave(exportBuffer, context)); @@ -199,7 +216,7 @@ TEST(S6ImportExportBasic, all) bool initialised = context->Initialise(); ASSERT_TRUE(initialised); - ASSERT_TRUE(ImportSave(exportBuffer, context, true)); + ASSERT_TRUE(ImportPark(exportBuffer, context, true)); RecordGameStateSnapshot(context, snapshotStream); } @@ -231,7 +248,7 @@ TEST(S6ImportExportAdvanceTicks, all) std::string testParkPath = TestData::GetParkPath("BigMapTest.sv6"); ASSERT_TRUE(LoadFileToBuffer(importBuffer, testParkPath)); - ASSERT_TRUE(ImportSave(importBuffer, context, false)); + ASSERT_TRUE(ImportS6(importBuffer, context, false)); AdvanceGameTicks(1000, context); ASSERT_TRUE(ExportSave(exportBuffer, context)); @@ -246,7 +263,7 @@ TEST(S6ImportExportAdvanceTicks, all) bool initialised = context->Initialise(); ASSERT_TRUE(initialised); - ASSERT_TRUE(ImportSave(exportBuffer, context, true)); + ASSERT_TRUE(ImportPark(exportBuffer, context, true)); RecordGameStateSnapshot(context, snapshotStream); }