mirror of
https://github.com/OpenRCT2/OpenRCT2.git
synced 2025-01-22 02:11:57 -05:00
Add new .park save format
Co-authored-by: Gymnasiast <Gymnasiast@users.noreply.github.com> Co-authored-by: duncanspumpkin <duncanspumpkin@users.noreply.github.com> Co-authored-by: ZehMatt <Zehmatt@users.noreply.github.com> Co-authored-by: Broxzier <Broxzier@users.noreply.github.com>
This commit is contained in:
parent
e9e8dceca7
commit
34128dc262
112 changed files with 7281 additions and 4243 deletions
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
7
distribution/openrct2.d.ts
vendored
7
distribution/openrct2.d.ts
vendored
|
@ -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 {
|
||||
|
|
255
docs/save-format.md
Normal file
255
docs/save-format.md
Normal file
|
@ -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
|
|
@ -46,8 +46,8 @@
|
|||
<GtestSha1>058b9df80244c03f1633cb06e9f70471a29ebb8e</GtestSha1>
|
||||
<TitleSequencesUrl>https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2c/title-sequences.zip</TitleSequencesUrl>
|
||||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>c38af45d51a6e440386180feacf76c64720b6ac5</ObjectsSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.2.2/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>a808fd47e9bc35d105dc371428a55888e6a86860</ObjectsSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.57/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>DF9C3B48755B19FDD4D0EC721007B98CD5B6F420</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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); });
|
||||
|
|
|
@ -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<uint32_t>(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<rct_object_filters> 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<rct_object_filters>();
|
||||
|
@ -316,7 +316,6 @@ static void visible_list_refresh(rct_window* w)
|
|||
|
||||
list_item currentListItem;
|
||||
currentListItem.repositoryItem = item;
|
||||
currentListItem.entry = const_cast<rct_object_entry*>(&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<uint32_t>(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<size_t>(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<int32_t>(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<ObjectType>(tab + 1);
|
||||
|
||||
return static_cast<ObjectType>(tab);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <openrct2/world/Surface.h>
|
||||
|
||||
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<uint32_t>(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<int32_t>(*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<size_t> 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<int32_t>(*defaultIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A8111 0x006A8135 0x006A815C 0x006A8183
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include <openrct2/core/Guard.hpp>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/localisation/StringIds.h>
|
||||
#include <openrct2/object/FootpathObject.h>
|
||||
#include <openrct2/object/FootpathRailingsObject.h>
|
||||
#include <openrct2/object/FootpathSurfaceObject.h>
|
||||
#include <openrct2/object/TerrainEdgeObject.h>
|
||||
#include <openrct2/object/TerrainSurfaceObject.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
|
@ -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<rct_string_id>(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<rct_string_id>(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<rct_string_id>(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<const rct_footpath_entry*>(footpathObj->GetLegacyData());
|
||||
auto ft = Formatter();
|
||||
ft.Add<rct_string_id>(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<rct_string_id>(STR_UNKNOWN_OBJECT_TYPE);
|
||||
ft = Formatter();
|
||||
auto ft = Formatter();
|
||||
ft.Add<rct_string_id>(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<int32_t>(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<int32_t>(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<rct_string_id>(STR_STRING);
|
||||
ft.Add<char*>(CheckBoxMarkString);
|
||||
if (invisible)
|
||||
{
|
||||
DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ InvisibleFlagColumnXY.x, 0 }, stringFormat, ft);
|
||||
}
|
||||
if (ghost)
|
||||
{
|
||||
DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ GhostFlagColumnXY.x, 0 }, stringFormat, ft);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<IParkImporter> 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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<int32_t>(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
|
||||
|
||||
|
|
|
@ -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<int32_t>(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);
|
||||
|
|
|
@ -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<uint32_t>();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ enum
|
|||
FILE_EXTENSION_SC6,
|
||||
FILE_EXTENSION_SV6,
|
||||
FILE_EXTENSION_TD6,
|
||||
FILE_EXTENSION_PARK,
|
||||
};
|
||||
|
||||
#include <string>
|
||||
|
@ -37,6 +38,7 @@ enum class FILE_TYPE
|
|||
SAVED_GAME,
|
||||
SCENARIO,
|
||||
TRACK_DESIGN,
|
||||
PARK,
|
||||
};
|
||||
|
||||
struct ClassifiedFileInfo
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -80,6 +80,9 @@ void GameState::InitAll(int32_t mapSize)
|
|||
context_broadcast_intent(&intent);
|
||||
|
||||
load_palette();
|
||||
|
||||
CheatsReset();
|
||||
ClearRestrictedScenery();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
4593
src/openrct2/ParkFile.cpp
Normal file
4593
src/openrct2/ParkFile.cpp
Normal file
File diff suppressed because it is too large
Load diff
22
src/openrct2/ParkFile.h
Normal file
22
src/openrct2/ParkFile.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
struct ObjectRepositoryItem;
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK
|
||||
|
||||
struct IStream;
|
||||
} // namespace OpenRCT2
|
||||
|
||||
class ParkFileExporter
|
||||
{
|
||||
public:
|
||||
std::vector<const ObjectRepositoryItem*> ExportObjectsList;
|
||||
|
||||
void Export(std::string_view path);
|
||||
void Export(OpenRCT2::IStream& stream);
|
||||
};
|
|
@ -62,6 +62,7 @@ namespace ParkImporter
|
|||
[[nodiscard]] std::unique_ptr<IParkImporter> Create(const std::string& hintPath);
|
||||
[[nodiscard]] std::unique_ptr<IParkImporter> CreateS4();
|
||||
[[nodiscard]] std::unique_ptr<IParkImporter> CreateS6(IObjectRepository& objectRepository);
|
||||
[[nodiscard]] std::unique_ptr<IParkImporter> CreateParkFile(IObjectRepository& objectRepository);
|
||||
|
||||
bool ExtensionIsRCT1(const std::string& extension);
|
||||
bool ExtensionIsScenario(const std::string& extension);
|
||||
|
|
|
@ -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>();
|
||||
s6exporter->ExportObjectsList = objects;
|
||||
s6exporter->Export();
|
||||
s6exporter->SaveGame(&replayData->parkData);
|
||||
auto exporter = std::make_unique<ParkFileExporter>();
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Staff>();
|
||||
if (newPeep == nullptr)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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 <memory>
|
||||
|
@ -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<S6Exporter>();
|
||||
auto exporter = std::make_unique<ParkFileExporter>();
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -809,7 +809,7 @@ template<> struct DataSerializerTraits_t<PeepThought>
|
|||
{
|
||||
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<int32_t>(val.type), val.item, val.freshness, val.fresh_timeout);
|
||||
stream->Write(msg, strlen(msg));
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace CODE_PAGE
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -288,6 +288,7 @@
|
|||
<ClInclude Include="paint\tile_element\Paint.Surface.h" />
|
||||
<ClInclude Include="paint\tile_element\Paint.TileElement.h" />
|
||||
<ClInclude Include="paint\VirtualFloor.h" />
|
||||
<ClInclude Include="ParkFile.h" />
|
||||
<ClInclude Include="ParkImporter.h" />
|
||||
<ClInclude Include="peep\Guest.h" />
|
||||
<ClInclude Include="peep\GuestPathfinding.h" />
|
||||
|
@ -306,7 +307,6 @@
|
|||
<ClInclude Include="rct1\RCT1.h" />
|
||||
<ClInclude Include="rct1\Tables.h" />
|
||||
<ClInclude Include="rct2\RCT2.h" />
|
||||
<ClInclude Include="rct2\S6Exporter.h" />
|
||||
<ClInclude Include="rct2\T6Exporter.h" />
|
||||
<ClInclude Include="ReplayManager.h" />
|
||||
<ClInclude Include="ride\CableLift.h" />
|
||||
|
@ -752,6 +752,7 @@
|
|||
<ClCompile Include="paint\tile_element\Paint.TileElement.cpp" />
|
||||
<ClCompile Include="paint\tile_element\Paint.Wall.cpp" />
|
||||
<ClCompile Include="paint\VirtualFloor.cpp" />
|
||||
<ClCompile Include="ParkFile.cpp" />
|
||||
<ClCompile Include="ParkImporter.cpp" />
|
||||
<ClCompile Include="peep\Guest.cpp" />
|
||||
<ClCompile Include="peep\GuestPathfinding.cpp" />
|
||||
|
@ -779,7 +780,6 @@
|
|||
<ClCompile Include="rct1\T4Importer.cpp" />
|
||||
<ClCompile Include="rct1\Tables.cpp" />
|
||||
<ClCompile Include="rct2\RCT2.cpp" />
|
||||
<ClCompile Include="rct2\S6Exporter.cpp" />
|
||||
<ClCompile Include="rct2\S6Importer.cpp" />
|
||||
<ClCompile Include="rct2\SeaDecrypt.cpp" />
|
||||
<ClCompile Include="rct2\T6Exporter.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<IPlatformEnvironment>& 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);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
struct ILanguagePack;
|
||||
struct IObjectManager;
|
||||
|
@ -36,6 +37,7 @@ namespace OpenRCT2::Localisation
|
|||
std::unique_ptr<ILanguagePack> _languageFallback;
|
||||
std::unique_ptr<ILanguagePack> _languageCurrent;
|
||||
std::stack<rct_string_id> _availableObjectStringIds;
|
||||
std::vector<std::string> _objectStrings;
|
||||
|
||||
public:
|
||||
int32_t GetCurrentLanguage() const
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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<ResearchItem>& 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(
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<std::string>& objects)
|
||||
void NetworkBase::Client_Send_MAPREQUEST(const std::vector<ObjectEntryDescriptor>& objects)
|
||||
{
|
||||
log_verbose("client requests %u objects", uint32_t(objects.size()));
|
||||
NetworkPacket packet(NetworkCommand::MapRequest);
|
||||
packet << static_cast<uint32_t>(objects.size());
|
||||
for (const auto& object : objects)
|
||||
{
|
||||
log_verbose("client requests object %s", object.c_str());
|
||||
packet.Write(reinterpret_cast<const uint8_t*>(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<uint8_t>(0);
|
||||
packet.Write(&object.Entry, sizeof(rct_object_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
packet << static_cast<uint8_t>(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<uint32_t>(i) << static_cast<uint32_t>(objects.size());
|
||||
|
||||
log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum);
|
||||
packet.Write(reinterpret_cast<const uint8_t*>(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<uint8_t>(0);
|
||||
packet.Write(&object->ObjectEntry, sizeof(rct_object_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
// JSON
|
||||
log_verbose("Object %s", object->Identifier.c_str());
|
||||
packet << static_cast<uint8_t>(1);
|
||||
packet.WriteString(object->Identifier);
|
||||
}
|
||||
|
||||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
@ -1401,37 +1423,18 @@ void NetworkBase::Server_Send_MAP(NetworkConnection* connection)
|
|||
|
||||
std::vector<uint8_t> NetworkBase::save_for_network(const std::vector<const ObjectRepositoryItem*>& objects) const
|
||||
{
|
||||
std::vector<uint8_t> header;
|
||||
bool RLEState = gUseRLE;
|
||||
gUseRLE = false;
|
||||
|
||||
std::vector<uint8_t> 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<const uint8_t*>(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<const rct_object_entry*>(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<uint8_t>(ObjectGeneration::DAT))
|
||||
{
|
||||
const auto* entry = reinterpret_cast<const rct_object_entry*>(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<const char*>(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<char*>(&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<uint32_t>();
|
||||
|
||||
// Read other data not in normal save files
|
||||
gGamePaused = stream->ReadValue<uint32_t>();
|
||||
_guestGenerationProbability = stream->ReadValue<uint32_t>();
|
||||
_suggestedGuestMaximum = stream->ReadValue<uint32_t>();
|
||||
gCheatsAllowTrackPlaceInvalidHeights = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsEnableAllDrawableTrackPieces = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsSandboxMode = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableClearanceChecks = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableSupportLimits = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableTrainLengthLimit = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsEnableChainLiftOnAllTrack = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsShowAllOperatingModes = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsUnlockOperatingLimits = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableBrakesFailure = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableAllBreakdowns = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsBuildInPauseMode = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsIgnoreRideIntensity = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableVandalism = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableLittering = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsNeverendingMarketing = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsFreezeWeather = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisablePlantAging = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsDisableRideValueAging = stream->ReadValue<uint8_t>() != 0;
|
||||
gConfigGeneral.show_real_names_of_guests = stream->ReadValue<uint8_t>() != 0;
|
||||
gCheatsIgnoreResearchStatus = stream->ReadValue<uint8_t>() != 0;
|
||||
gAllowEarlyCompletionInNetworkPlay = stream->ReadValue<uint8_t>() != 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<const ObjectReposit
|
|||
viewport_set_saved_view();
|
||||
try
|
||||
{
|
||||
auto s6exporter = std::make_unique<S6Exporter>();
|
||||
s6exporter->ExportObjectsList = objects;
|
||||
s6exporter->Export();
|
||||
s6exporter->SaveGame(stream);
|
||||
|
||||
// Write other data not in normal save files
|
||||
stream->WriteValue<uint32_t>(gGamePaused);
|
||||
stream->WriteValue<uint32_t>(_guestGenerationProbability);
|
||||
stream->WriteValue<uint32_t>(_suggestedGuestMaximum);
|
||||
stream->WriteValue<uint8_t>(gCheatsAllowTrackPlaceInvalidHeights);
|
||||
stream->WriteValue<uint8_t>(gCheatsEnableAllDrawableTrackPieces);
|
||||
stream->WriteValue<uint8_t>(gCheatsSandboxMode);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableClearanceChecks);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableSupportLimits);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableTrainLengthLimit);
|
||||
stream->WriteValue<uint8_t>(gCheatsEnableChainLiftOnAllTrack);
|
||||
stream->WriteValue<uint8_t>(gCheatsShowAllOperatingModes);
|
||||
stream->WriteValue<uint8_t>(gCheatsShowVehiclesFromOtherTrackTypes);
|
||||
stream->WriteValue<uint8_t>(gCheatsUnlockOperatingLimits);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableBrakesFailure);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableAllBreakdowns);
|
||||
stream->WriteValue<uint8_t>(gCheatsBuildInPauseMode);
|
||||
stream->WriteValue<uint8_t>(gCheatsIgnoreRideIntensity);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableVandalism);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableLittering);
|
||||
stream->WriteValue<uint8_t>(gCheatsNeverendingMarketing);
|
||||
stream->WriteValue<uint8_t>(gCheatsFreezeWeather);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisablePlantAging);
|
||||
stream->WriteValue<uint8_t>(gCheatsAllowArbitraryRideTypeChanges);
|
||||
stream->WriteValue<uint8_t>(gCheatsDisableRideValueAging);
|
||||
stream->WriteValue<uint8_t>(gConfigGeneral.show_real_names_of_guests);
|
||||
stream->WriteValue<uint8_t>(gCheatsIgnoreResearchStatus);
|
||||
stream->WriteValue<uint8_t>(gConfigGeneral.allow_early_completion);
|
||||
|
||||
auto exporter = std::make_unique<ParkFileExporter>();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<std::string>& objects);
|
||||
void Client_Send_MAPREQUEST(const std::vector<ObjectEntryDescriptor>& objects);
|
||||
void Client_Send_HEARTBEAT(NetworkConnection& connection) const;
|
||||
|
||||
// Handlers.
|
||||
|
@ -218,7 +219,7 @@ private: // Client Data
|
|||
std::map<uint32_t, PlayerListUpdate> _pendingPlayerLists;
|
||||
std::multimap<uint32_t, NetworkPlayer> _pendingPlayerInfo;
|
||||
std::map<uint32_t, ServerTickData_t> _serverTickData;
|
||||
std::vector<std::string> _missingObjects;
|
||||
std::vector<ObjectEntryDescriptor> _missingObjects;
|
||||
std::string _host;
|
||||
std::string _chatLogPath;
|
||||
std::string _chatLogFilenameFormat = "%Y%m%d-%H%M%S.txt";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -26,6 +26,11 @@ public:
|
|||
return &_legacyType;
|
||||
}
|
||||
|
||||
const void* GetLegacyData() const
|
||||
{
|
||||
return &_legacyType;
|
||||
}
|
||||
|
||||
const PathSurfaceDescriptor& GetPathSurfaceDescriptor() const
|
||||
{
|
||||
return _pathSurfaceDescriptor;
|
||||
|
|
|
@ -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 },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -11,18 +11,20 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -78,7 +78,10 @@ public:
|
|||
if (index >= static_cast<size_t>(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<ObjectEntryIndex>(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)
|
||||
|
|
|
@ -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<ObjectEntryDescriptor>& entries) abstract;
|
||||
virtual void UnloadAll() abstract;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<ShopItem>(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<uint8_t>& 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<S6Exporter>();
|
||||
auto exporter = std::make_unique<ParkFileExporter>();
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace RCT1
|
|||
class EntryList
|
||||
{
|
||||
private:
|
||||
std::vector<const char*> _entries;
|
||||
std::vector<std::string> _entries;
|
||||
|
||||
public:
|
||||
size_t GetCount() const
|
||||
|
@ -89,20 +89,22 @@ namespace RCT1
|
|||
return _entries.size();
|
||||
}
|
||||
|
||||
const std::vector<const char*>& GetEntries() const
|
||||
const std::vector<std::string>& 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<ObjectEntryIndex>(i);
|
||||
}
|
||||
}
|
||||
return static_cast<ObjectEntryIndex>(entryIndex);
|
||||
_entries.emplace_back(identifier);
|
||||
return static_cast<ObjectEntryIndex>(_entries.size() - 1);
|
||||
}
|
||||
|
||||
void AddRange(std::initializer_list<const char*> 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<MAX_RIDE_OBJECTS> _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<const char*> 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<const char*>({
|
||||
"BN1 ",
|
||||
"BN2 ",
|
||||
"BN3 ",
|
||||
"BN4 ",
|
||||
"BN5 ",
|
||||
"BN6 ",
|
||||
"BN7 ",
|
||||
"BN8 ",
|
||||
"BN9 ",
|
||||
}));
|
||||
LoadObjects(ObjectType::ParkEntrance, std::vector<const char*>({ "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<std::string>& objectNames)
|
||||
{
|
||||
LoadObjects(objectType, entries.GetEntries());
|
||||
}
|
||||
|
||||
void LoadObjects(ObjectType objectType, const std::vector<const char*>& 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<rct_object_entry>& entries, ObjectType objectType, const EntryList& entryList)
|
||||
{
|
||||
AppendRequiredObjects(entries, objectType, entryList.GetEntries());
|
||||
}
|
||||
|
||||
void AppendRequiredObjects(
|
||||
std::vector<rct_object_entry>& entries, ObjectType objectType, const std::vector<const char*>& objectNames)
|
||||
{
|
||||
for (const auto objectName : objectNames)
|
||||
{
|
||||
rct_object_entry entry{};
|
||||
entry.flags = ((static_cast<uint8_t>(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<rct_object_entry> 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<const char*>({
|
||||
"BN1 ",
|
||||
"BN2 ",
|
||||
"BN3 ",
|
||||
"BN4 ",
|
||||
"BN5 ",
|
||||
"BN6 ",
|
||||
"BN7 ",
|
||||
"BN8 ",
|
||||
"BN9 ",
|
||||
std::vector<std::string>({
|
||||
"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<const char*>({ "PKENT1 " }));
|
||||
AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector<std::string>({ "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<uint32_t>::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<uint8_t>::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;
|
||||
|
|
|
@ -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<size_t>(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<size_t>(8)));
|
||||
vehicleObject = RCT1::GetVehicleObject(td4Base.vehicle_type);
|
||||
}
|
||||
assert(!vehicleObject.empty());
|
||||
td->vehicle_object = ObjectEntryDescriptor(vehicleObject);
|
||||
td->vehicle_type = td4Base.vehicle_type;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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<const char*> GetSceneryObjects(uint8_t sceneryType);
|
||||
} // namespace RCT1
|
||||
|
|
|
@ -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<uint8_t> 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<ObjectEntryIndex>(i), _stationStyles[i]);
|
||||
}
|
||||
|
||||
// Music
|
||||
for (size_t i = 0; i < std::size(_musicStyles); i++)
|
||||
{
|
||||
if (!_musicStyles[i].empty())
|
||||
{
|
||||
objectList.SetObject(ObjectType::Music, static_cast<ObjectEntryIndex>(i), _musicStyles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
money64 RCT12CompletedCompanyValueToOpenRCT2(money32 origValue)
|
||||
{
|
||||
if (origValue == RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE)
|
||||
|
|
|
@ -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<uint8_t> GetStyleFromMusicIdentifier(std::string_view identifier);
|
||||
void SetDefaultRCT2TerrainObjects(ObjectList& objectList);
|
||||
void RCT12AddDefaultObjects(ObjectList& objectList);
|
||||
|
||||
static constexpr money32 RCT12_COMPANY_VALUE_ON_FAILED_OBJECTIVE = 0x80000001;
|
||||
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "../ride/VehicleColour.h"
|
||||
#include "../world/EntityList.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
constexpr const uint8_t RCT2_MAX_STAFF = 200;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
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<const ObjectRepositoryItem*> 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<typename RCT12_T, typename OpenRCT2_T> 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<std::string> _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<uint16_t> AllocateUserString(std::string_view value);
|
||||
void ExportUserStrings();
|
||||
void RebuildEntityLinks();
|
||||
void RebuildEntitySpatialLocation(const TileCoordsXY& loc);
|
||||
void ExportStaffPatrolAreas();
|
||||
};
|
|
@ -88,6 +88,9 @@ private:
|
|||
uint8_t _gameVersion = 0;
|
||||
bool _isSV7 = false;
|
||||
std::bitset<RCT12_MAX_RIDES_IN_PARK> _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<uint8_t>((sceneryEntryIndex >> 8) & 0xFF),
|
||||
static_cast<uint16_t>(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<RCT12TileElement>(RCT2_MAXIMUM_MAP_SIZE_TECHNICAL, _s6.tile_elements);
|
||||
|
||||
std::vector<TileElement> 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<RCT12TileElementType>(srcElement->GetType());
|
||||
if (tileElementType == RCT12TileElementType::Corrupt)
|
||||
{
|
||||
auto tileElementType = static_cast<RCT12TileElementType>(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<size_t TInternalLimit, typename T>
|
||||
static void AddRequiredObjects(std::vector<rct_object_entry>& 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<rct_object_entry> result;
|
||||
|
||||
AddRequiredObjects<MAX_RIDE_OBJECTS>(result, _s6.RideObjects);
|
||||
AddRequiredObjects<MAX_SMALL_SCENERY_OBJECTS>(result, _s6.SceneryObjects);
|
||||
AddRequiredObjects<MAX_LARGE_SCENERY_OBJECTS>(result, _s6.LargeSceneryObjects);
|
||||
AddRequiredObjects<MAX_WALL_SCENERY_OBJECTS>(result, _s6.WallSceneryObjects);
|
||||
AddRequiredObjects<MAX_BANNER_OBJECTS>(result, _s6.BannerObjects);
|
||||
AddRequiredObjects<MAX_PATH_OBJECTS>(result, _s6.PathObjects);
|
||||
AddRequiredObjects<MAX_PATH_ADDITION_OBJECTS>(result, _s6.PathAdditionObjects);
|
||||
AddRequiredObjects<MAX_SCENERY_GROUP_OBJECTS>(result, _s6.SceneryGroupObjects);
|
||||
AddRequiredObjects<MAX_PARK_ENTRANCE_OBJECTS>(result, _s6.ParkEntranceObjects);
|
||||
AddRequiredObjects<MAX_WATER_OBJECTS>(result, _s6.WaterObjects);
|
||||
AddRequiredObjects<MAX_SCENARIO_TEXT_OBJECTS>(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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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<uint32_t>(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<ride_id_t>(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<ride_id_t> GetTracklessRides()
|
||||
{
|
||||
// Iterate map and build list of seen ride IDs
|
||||
std::vector<bool> 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<size_t>(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<ride_id_t> result;
|
||||
for (const auto& ride : rideManager)
|
||||
{
|
||||
if (seen.size() <= static_cast<size_t>(ride.id) || !seen[static_cast<size_t>(ride.id)])
|
||||
{
|
||||
result.push_back(ride.id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -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<ride_id_t> GetTracklessRides();
|
||||
|
||||
void ride_remove_vehicles(Ride* ride);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<TrackSceneryEntry> TrackDesignPlaceSceneryElementGetEntry(const TrackDesignSceneryElement& scenery)
|
||||
{
|
||||
TrackSceneryEntry result;
|
||||
|
@ -742,14 +723,7 @@ static std::optional<TrackSceneryEntry> 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 {};
|
||||
|
|
|
@ -44,7 +44,6 @@ struct TrackDesignEntranceElement
|
|||
bool isExit;
|
||||
};
|
||||
|
||||
/* Track Scenery entry size: 0x16 */
|
||||
struct TrackDesignSceneryElement
|
||||
{
|
||||
ObjectEntryDescriptor scenery_object;
|
||||
|
|
|
@ -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 }),
|
||||
|
|
|
@ -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 }),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -126,7 +126,7 @@ class ScenarioFileIndex final : public FileIndex<scenario_index_entry>
|
|||
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
|
||||
|
|
|
@ -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<ObjectEntryIndex>::max())
|
||||
{
|
||||
return static_cast<ObjectEntryIndex>(value);
|
||||
}
|
||||
}
|
||||
return OBJECT_ENTRY_INDEX_NULL;
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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<ScScenarioObjective> objective_get() const
|
||||
|
|
|
@ -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<ObjectEntryIndex>(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<TileElement>(*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<ObjectEntryIndex>(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<ObjectEntryIndex>(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<ObjectEntryIndex>(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<ObjectEntryIndex>(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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -23,7 +23,6 @@ enum class TileInspectorPage : int16_t
|
|||
Wall,
|
||||
LargeScenery,
|
||||
Banner,
|
||||
Corrupt
|
||||
};
|
||||
|
||||
extern TileCoordsXY windowTileInspectorTile;
|
||||
|
|
|
@ -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<BannerIndex>(-1);
|
||||
|
||||
constexpr uint8_t SCROLLING_MODE_NONE = 255;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue