Merge remote-tracking branch 'upstream/develop' into new-save-format

This commit is contained in:
ζeh Matt 2021-10-21 19:05:17 +03:00
commit 5199325209
No known key found for this signature in database
GPG Key ID: 18CE582C71A225B0
40 changed files with 496 additions and 451 deletions

View File

@ -2899,7 +2899,7 @@ STR_5626 :Overige parken
STR_5627 :Scenariolijst groeperen op:
STR_5628 :Oorsprong
STR_5629 :Moeilijkheidsgraad
STR_5630 :Moeilijke scenarios ontgrendelden met gemakkelijke
STR_5630 :Moeilijke scenarios ontgrendelden met makkelijke
STR_5631 :Originele DLC
STR_5632 :Bouw je eigen…
STR_5633 :CMD +

View File

@ -387,22 +387,21 @@ void window_editor_bottom_toolbar_paint(rct_window* w, rct_drawpixelinfo* dpi)
if (!(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER))
{
auto previousWidget = window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_IMAGE];
auto nextWidget = window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE];
if (drawPreviousButton)
{
gfx_filter_rect(
dpi, window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_IMAGE].left + w->windowPos.x,
window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_IMAGE].top + w->windowPos.y,
window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_IMAGE].right + w->windowPos.x,
window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_IMAGE].bottom + w->windowPos.y, FilterPaletteID::Palette51);
auto leftTop = w->windowPos + ScreenCoordsXY{ previousWidget.left, previousWidget.top };
auto rightBottom = w->windowPos + ScreenCoordsXY{ previousWidget.right, previousWidget.bottom };
gfx_filter_rect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51);
}
if ((drawPreviousButton || drawNextButton) && gEditorStep != EditorStep::RollercoasterDesigner)
{
gfx_filter_rect(
dpi, window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].left + w->windowPos.x,
window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].top + w->windowPos.y,
window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].right + w->windowPos.x,
window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].bottom + w->windowPos.y, FilterPaletteID::Palette51);
auto leftTop = w->windowPos + ScreenCoordsXY{ nextWidget.left, nextWidget.top };
auto rightBottom = w->windowPos + ScreenCoordsXY{ nextWidget.right, nextWidget.bottom };
gfx_filter_rect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51);
}
}

View File

@ -607,7 +607,7 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
bottom = itemY;
}
gfx_filter_rect(dpi, 0, top, boxWidth, bottom, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, top, boxWidth, bottom }, FilterPaletteID::PaletteDarken1);
}
if (researchItem == _editorInventionsListDraggedItem)

View File

@ -1226,7 +1226,7 @@ static void window_editor_object_selection_scrollpaint(rct_window* w, rct_drawpi
if (highlighted)
{
auto bottom = screenCoords.y + (SCROLLABLE_ROW_HEIGHT - 1);
gfx_filter_rect(dpi, 0, screenCoords.y, w->width, bottom, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, screenCoords.y, w->width, bottom }, FilterPaletteID::PaletteDarken1);
}
// Draw checkmark

View File

@ -1095,7 +1095,7 @@ static void window_editor_objective_options_rides_scrollpaint(rct_window* w, rct
if (i == w->selected_list_item)
{
stringId = STR_WINDOW_COLOUR_2_STRINGID;
gfx_filter_rect(dpi, 0, y, w->width, y + 11, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, y, w->width, y + 11 }, FilterPaletteID::PaletteDarken1);
}
// Checkbox mark

View File

@ -350,26 +350,25 @@ void window_game_bottom_toolbar_invalidate_news_item()
*/
static void window_game_bottom_toolbar_paint(rct_window* w, rct_drawpixelinfo* dpi)
{
auto leftWidget = window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET];
auto rightWidget = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET];
auto middleWidget = window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET];
// Draw panel grey backgrounds
gfx_filter_rect(
dpi, w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].left,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].top,
w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].right,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].bottom, FilterPaletteID::Palette51);
gfx_filter_rect(
dpi, w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top,
w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].bottom, FilterPaletteID::Palette51);
auto leftTop = w->windowPos + ScreenCoordsXY{ leftWidget.left, leftWidget.top };
auto rightBottom = w->windowPos + ScreenCoordsXY{ leftWidget.right, leftWidget.bottom };
gfx_filter_rect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51);
leftTop = w->windowPos + ScreenCoordsXY{ rightWidget.left, rightWidget.top };
rightBottom = w->windowPos + ScreenCoordsXY{ rightWidget.right, rightWidget.bottom };
gfx_filter_rect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51);
if (ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR)
{
// Draw grey background
gfx_filter_rect(
dpi, w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].left,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].top,
w->windowPos.x + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right,
w->windowPos.y + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].bottom, FilterPaletteID::Palette51);
leftTop = w->windowPos + ScreenCoordsXY{ middleWidget.left, middleWidget.top };
rightBottom = w->windowPos + ScreenCoordsXY{ middleWidget.right, middleWidget.bottom };
gfx_filter_rect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51);
}
WindowDrawWidgets(w, dpi);

View File

@ -1636,7 +1636,7 @@ void window_guest_rides_scroll_paint(rct_window* w, rct_drawpixelinfo* dpi, int3
rct_string_id stringId = STR_BLACK_STRING;
if (list_index == w->selected_list_item)
{
gfx_filter_rect(dpi, 0, y, 800, y + 9, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, y, 800, y + 9 }, FilterPaletteID::PaletteDarken1);
stringId = STR_WINDOW_COLOUR_2_STRINGID;
}

View File

@ -675,7 +675,7 @@ private:
rct_string_id format = STR_BLACK_STRING;
if (index == _highlightedIndex)
{
gfx_filter_rect(&dpi, 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(&dpi, { 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1 }, FilterPaletteID::PaletteDarken1);
format = STR_WINDOW_COLOUR_2_STRINGID;
}
@ -745,7 +745,7 @@ private:
rct_string_id format = STR_BLACK_STRING;
if (index == _highlightedIndex)
{
gfx_filter_rect(&dpi, 0, y, 800, y + SUMMARISED_GUEST_ROW_HEIGHT, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(&dpi, { 0, y, 800, y + SUMMARISED_GUEST_ROW_HEIGHT }, FilterPaletteID::PaletteDarken1);
format = STR_WINDOW_COLOUR_2_STRINGID;
}

View File

@ -759,7 +759,7 @@ static void window_loadsave_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, i
if (i == w->selected_list_item)
{
stringId = STR_WINDOW_COLOUR_2_STRINGID;
gfx_filter_rect(dpi, 0, y, listWidth, y + SCROLLABLE_ROW_HEIGHT, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, y, listWidth, y + SCROLLABLE_ROW_HEIGHT }, FilterPaletteID::PaletteDarken1);
}
// display a marker next to the currently loaded game file
if (_listItems[i].loaded)

View File

@ -603,7 +603,8 @@ static void window_multiplayer_players_scrollpaint(rct_window* w, rct_drawpixeli
if (i == w->selected_list_item)
{
gfx_filter_rect(
dpi, 0, screenCoords.y, 800, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1);
dpi, { 0, screenCoords.y, 800, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1 },
FilterPaletteID::PaletteDarken1);
buffer += network_get_player_name(i);
colour = w->colours[2];
}
@ -905,7 +906,7 @@ static void window_multiplayer_groups_scrollpaint(rct_window* w, rct_drawpixelin
if (i == w->selected_list_item)
{
gfx_filter_rect(
dpi, 0, screenCoords.y, 800, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1);
dpi, { 0, screenCoords.y, 800, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1 }, FilterPaletteID::PaletteDarken1);
}
if (screenCoords.y > dpi->y + dpi->height)
{

View File

@ -578,7 +578,7 @@ static void window_ride_list_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi,
if (i == static_cast<size_t>(w->selected_list_item))
{
// Background highlight
gfx_filter_rect(dpi, 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1 }, FilterPaletteID::PaletteDarken1);
format = (_quickDemolishMode ? STR_LIGHTPINK_STRINGID : STR_WINDOW_COLOUR_2_STRINGID);
}

View File

@ -596,7 +596,7 @@ static void window_scenarioselect_scrollpaint(rct_window* w, rct_drawpixelinfo*
bool isHighlighted = w->highlighted_scenario == scenario;
if (isHighlighted)
{
gfx_filter_rect(dpi, 0, y, w->width, y + scenarioItemHeight - 1, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, y, w->width, y + scenarioItemHeight - 1 }, FilterPaletteID::PaletteDarken1);
}
bool isCompleted = scenario->highscore != nullptr;

View File

@ -40,8 +40,8 @@ static std::future<std::tuple<std::vector<ServerListEntry>, rct_string_id>> _fet
static uint32_t _numPlayersOnline = 0;
static rct_string_id _statusText = STR_SERVER_LIST_CONNECTING;
// clang-format off
enum {
enum
{
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
@ -52,39 +52,42 @@ enum {
WIDX_START_SERVER
};
enum {
enum
{
WIDX_LIST_REMOVE,
WIDX_LIST_SPECTATE
};
// clang-format off
static rct_widget window_server_list_widgets[] = {
MakeWidget({ 0, 0}, {341, 91}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background
MakeWidget({ 1, 1}, {338, 14}, WindowWidgetType::Caption, WindowColour::Primary , STR_SERVER_LIST, STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({327, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary , STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button
MakeWidget({100, 20}, {245, 12}, WindowWidgetType::TextBox, WindowColour::Secondary ), // player name text box
MakeWidget({ 1, 1}, {338, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_SERVER_LIST, STR_WINDOW_TITLE_TIP), // title bar
MakeWidget({327, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button
MakeWidget({100, 20}, {245, 12}, WindowWidgetType::TextBox, WindowColour::Secondary ), // player name text box
MakeWidget({ 6, 37}, {332, 14}, WindowWidgetType::Scroll, WindowColour::Secondary ), // server list
MakeWidget({ 6, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_FETCH_SERVERS ), // fetch servers button
MakeWidget({112, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_ADD_SERVER ), // add server button
MakeWidget({218, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_START_SERVER ), // start server button
WIDGETS_END,
};
// clang-format on
static void window_server_list_close(rct_window *w);
static void window_server_list_mouseup(rct_window *w, rct_widgetindex widgetIndex);
static void window_server_list_resize(rct_window *w);
static void window_server_list_dropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex);
static void window_server_list_update(rct_window *w);
static void window_server_list_scroll_getsize(rct_window *w, int32_t scrollIndex, int32_t *width, int32_t *height);
static void window_server_list_scroll_mousedown(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
static void window_server_list_scroll_mouseover(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
static void window_server_list_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text);
static OpenRCT2String window_server_list_tooltip(rct_window* const w, const rct_widgetindex widgetIndex, rct_string_id fallback);
static void window_server_list_invalidate(rct_window *w);
static void window_server_list_paint(rct_window *w, rct_drawpixelinfo *dpi);
static void window_server_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex);
static void window_server_list_close(rct_window* w);
static void window_server_list_mouseup(rct_window* w, rct_widgetindex widgetIndex);
static void window_server_list_resize(rct_window* w);
static void window_server_list_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex);
static void window_server_list_update(rct_window* w);
static void window_server_list_scroll_getsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height);
static void window_server_list_scroll_mousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
static void window_server_list_scroll_mouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
static void window_server_list_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text);
static OpenRCT2String window_server_list_tooltip(
rct_window* const w, const rct_widgetindex widgetIndex, rct_string_id fallback);
static void window_server_list_invalidate(rct_window* w);
static void window_server_list_paint(rct_window* w, rct_drawpixelinfo* dpi);
static void window_server_list_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex);
static rct_window_event_list window_server_list_events([](auto& events)
{
static rct_window_event_list window_server_list_events([](auto& events) {
events.close = &window_server_list_close;
events.mouse_up = &window_server_list_mouseup;
events.resize = &window_server_list_resize;
@ -99,7 +102,6 @@ static rct_window_event_list window_server_list_events([](auto& events)
events.paint = &window_server_list_paint;
events.scroll_paint = &window_server_list_scrollpaint;
});
// clang-format on
enum
{
@ -439,7 +441,7 @@ static void window_server_list_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi
// Draw hover highlight
if (highlighted)
{
gfx_filter_rect(dpi, 0, screenCoords.y, width, screenCoords.y + ITEM_HEIGHT, FilterPaletteID::PaletteDarken1);
gfx_filter_rect(dpi, { 0, screenCoords.y, width, screenCoords.y + ITEM_HEIGHT }, FilterPaletteID::PaletteDarken1);
_version = serverDetails.Version;
listWidget.tooltip = STR_NETWORK_VERSION_TIP;
}

View File

@ -509,7 +509,7 @@ private:
if (isHighlighted)
{
format = STR_WINDOW_COLOUR_2_STRINGID;
gfx_filter_rect(&dpi, 0, y - 1, scrollWidth, y + (SCROLLABLE_ROW_HEIGHT - 2), FilterPaletteID::PaletteDarken1);
gfx_filter_rect(&dpi, { 0, y - 1, scrollWidth, y + (SCROLLABLE_ROW_HEIGHT - 2) }, FilterPaletteID::PaletteDarken1);
}
auto bindingOffset = (scrollWidth * 2) / 3;

View File

@ -401,7 +401,7 @@ public:
if (i == _highlightedIndex)
{
gfx_filter_rect(&dpi, 0, y, 800, y + (SCROLLABLE_ROW_HEIGHT - 1), FilterPaletteID::PaletteDarken1);
gfx_filter_rect(&dpi, { 0, y, 800, y + (SCROLLABLE_ROW_HEIGHT - 1) }, FilterPaletteID::PaletteDarken1);
format = (_quickFireMode ? STR_LIGHTPINK_STRINGID : STR_WINDOW_COLOUR_2_STRINGID);
}

View File

@ -867,31 +867,26 @@ void window_themes_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t sc
if (i + 1 < get_colour_scheme_tab_count())
{
int32_t colour = w->colours[1];
auto leftTop = ScreenCoordsXY{ 0, screenCoords.y + _row_height - 2 };
auto rightBottom = ScreenCoordsXY{ window_themes_widgets[WIDX_THEMES_LIST].right,
screenCoords.y + _row_height - 2 };
auto yPixelOffset = ScreenCoordsXY{ 0, 1 };
if (colour & COLOUR_FLAG_TRANSLUCENT)
{
translucent_window_palette windowPalette = TranslucentWindowPalettes[BASE_COLOUR(colour)];
gfx_filter_rect(
dpi, 0, screenCoords.y + _row_height - 2, window_themes_widgets[WIDX_THEMES_LIST].right,
screenCoords.y + _row_height - 2, windowPalette.highlight);
gfx_filter_rect(
dpi, 0, screenCoords.y + _row_height - 1, window_themes_widgets[WIDX_THEMES_LIST].right,
screenCoords.y + _row_height - 1, windowPalette.shadow);
gfx_filter_rect(dpi, { leftTop, rightBottom }, windowPalette.highlight);
gfx_filter_rect(dpi, { leftTop + yPixelOffset, rightBottom + yPixelOffset }, windowPalette.shadow);
}
else
{
colour = ColourMapA[w->colours[1]].mid_dark;
gfx_fill_rect(
dpi,
{ { 0, screenCoords.y + _row_height - 2 },
{ window_themes_widgets[WIDX_THEMES_LIST].right, screenCoords.y + _row_height - 2 } },
colour);
gfx_fill_rect(dpi, { leftTop, rightBottom }, colour);
colour = ColourMapA[w->colours[1]].lightest;
gfx_fill_rect(
dpi,
{ { 0, screenCoords.y + _row_height - 1 },
{ window_themes_widgets[WIDX_THEMES_LIST].right, screenCoords.y + _row_height - 1 } },
colour);
gfx_fill_rect(dpi, { leftTop + yPixelOffset, rightBottom + yPixelOffset }, colour);
}
}

View File

@ -690,7 +690,7 @@ public:
{
// Highlight
gfx_filter_rect(
&dpi, screenCoords.x, screenCoords.y, width, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1,
&dpi, { screenCoords, { width, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1 } },
FilterPaletteID::PaletteDarken1);
stringId = STR_WINDOW_COLOUR_2_STRINGID;
}
@ -715,7 +715,7 @@ public:
{
// Highlight
gfx_filter_rect(
&dpi, screenCoords.x, screenCoords.y, width, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1,
&dpi, { screenCoords, { width, screenCoords.y + SCROLLABLE_ROW_HEIGHT - 1 } },
FilterPaletteID::PaletteDarken1);
stringId = STR_WINDOW_COLOUR_2_STRINGID;
}

View File

@ -15,6 +15,7 @@
#include "../interface/Window.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../world/ConstructionClearance.h"
#include "../world/Footpath.h"
#include "../world/Location.hpp"
#include "../world/Park.h"

View File

@ -15,6 +15,7 @@
#include "../interface/Window.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../world/ConstructionClearance.h"
#include "../world/Footpath.h"
#include "../world/Location.hpp"
#include "../world/Park.h"

View File

@ -17,6 +17,7 @@
#include "../management/Finance.h"
#include "../ride/RideData.h"
#include "../windows/Intent.h"
#include "../world/ConstructionClearance.h"
#include "../world/Park.h"
#include "../world/Scenery.h"
#include "../world/SmallScenery.h"

View File

@ -14,6 +14,7 @@
#include "../object/ObjectLimits.h"
#include "../ride/Ride.h"
#include "../world/Banner.h"
#include "../world/ConstructionClearance.h"
#include "../world/MapAnimation.h"
#include "../world/Surface.h"

View File

@ -11,6 +11,7 @@
#include "../management/Finance.h"
#include "../ride/RideData.h"
#include "../ride/TrackData.h"
#include "../world/ConstructionClearance.h"
using namespace OpenRCT2::TrackMetaData;

View File

@ -18,6 +18,7 @@
#include "../ride/RideData.h"
#include "../ride/Track.h"
#include "../ride/TrackData.h"
#include "../world/ConstructionClearance.h"
#include "../world/Footpath.h"
#include "../world/Park.h"

View File

@ -14,6 +14,7 @@
#include "../core/MemoryStream.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../world/ConstructionClearance.h"
#include "../world/Entrance.h"
#include "../world/Footpath.h"
#include "../world/MapAnimation.h"

View File

@ -13,6 +13,7 @@
#include "../management/Finance.h"
#include "../ride/Ride.h"
#include "../ride/Station.h"
#include "../world/ConstructionClearance.h"
#include "../world/MapAnimation.h"
RideEntranceExitPlaceAction::RideEntranceExitPlaceAction(

View File

@ -19,6 +19,7 @@
#include "../management/Finance.h"
#include "../ride/Ride.h"
#include "../ride/TrackDesign.h"
#include "../world/ConstructionClearance.h"
#include "../world/MapAnimation.h"
#include "../world/Park.h"
#include "../world/SmallScenery.h"

View File

@ -16,6 +16,7 @@
#include "../ride/TrackData.h"
#include "../ride/TrackDesign.h"
#include "../util/Math.hpp"
#include "../world/ConstructionClearance.h"
#include "../world/MapAnimation.h"
#include "../world/Surface.h"
#include "RideSetSettingAction.h"

View File

@ -14,6 +14,7 @@
#include "../ride/Track.h"
#include "../ride/TrackDesign.h"
#include "../world/Banner.h"
#include "../world/ConstructionClearance.h"
#include "../world/LargeScenery.h"
#include "../world/MapAnimation.h"
#include "../world/SmallScenery.h"

View File

@ -11,6 +11,7 @@
#include "../OpenRCT2.h"
#include "../management/Finance.h"
#include "../world/ConstructionClearance.h"
#include "../world/Park.h"
#include "../world/Surface.h"

View File

@ -692,7 +692,6 @@ void gfx_draw_dashed_line(
// rect
void gfx_fill_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colour);
void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colour, uint8_t flags);
void gfx_filter_rect(rct_drawpixelinfo* dpi, int32_t left, int32_t top, int32_t right, int32_t bottom, FilterPaletteID palette);
void gfx_filter_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, FilterPaletteID palette);
// sprite

View File

@ -180,11 +180,6 @@ void gfx_fill_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, int32_t colou
}
}
void gfx_filter_rect(rct_drawpixelinfo* dpi, int32_t left, int32_t top, int32_t right, int32_t bottom, FilterPaletteID palette)
{
gfx_filter_rect(dpi, { left, top, right, bottom }, palette);
}
void gfx_filter_rect(rct_drawpixelinfo* dpi, const ScreenRect& rect, FilterPaletteID palette)
{
auto drawingEngine = dpi->DrawingEngine;

View File

@ -466,6 +466,7 @@
<ClInclude Include="world\Balloon.h" />
<ClInclude Include="world\Banner.h" />
<ClInclude Include="world\Climate.h" />
<ClInclude Include="world\ConstructionClearance.h" />
<ClInclude Include="world\Duck.h" />
<ClInclude Include="world\Entity.h" />
<ClInclude Include="world\EntityList.h" />
@ -911,6 +912,7 @@
<ClCompile Include="world\Balloon.cpp" />
<ClCompile Include="world\Banner.cpp" />
<ClCompile Include="world\Climate.cpp" />
<ClCompile Include="world\ConstructionClearance.cpp" />
<ClCompile Include="world\Duck.cpp" />
<ClCompile Include="world\Entity.cpp" />
<ClCompile Include="world\EntityTweener.cpp" />

View File

@ -23,6 +23,7 @@
#include "../../world/Banner.h"
#include "../../world/Entrance.h"
#include "../../world/Footpath.h"
#include "../../world/Map.h"
#include "../../world/Scenery.h"
#include "../../world/Surface.h"
#include "../Paint.h"
@ -146,27 +147,24 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y)
}
#endif // __TESTPAINT__
int32_t dx = 0;
switch (rotation)
{
case 0:
dx = x + y;
break;
case 1:
x += 32;
dx = y - x;
break;
case 2:
x += 32;
y += 32;
dx = -(x + y);
break;
case 3:
y += 32;
dx = x - y;
break;
}
dx >>= 1;
int32_t screenMinY = translate_3d_to_2d_with_z(rotation, { x, y, 0 }).y;
// Display little yellow arrow when building footpaths?
if ((gMapSelectFlags & MAP_SELECT_FLAG_ENABLE_ARROW) && session->MapPosition.x == gMapSelectArrowPosition.x
&& session->MapPosition.y == gMapSelectArrowPosition.y)
@ -182,9 +180,8 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y)
PaintAddImageAsParent(session, imageId, { 0, 0, arrowZ }, { 32, 32, -1 }, { 0, 0, arrowZ + 18 });
}
int32_t bx = dx + 52;
if (bx <= dpi->y)
if (screenMinY + 52 <= dpi->y)
return;
const TileElement* element = tile_element; // push tile_element
@ -210,9 +207,7 @@ static void sub_68B3FB(paint_session* session, int32_t x, int32_t y)
}
#endif // __TESTPAINT__
dx -= max_height + 32;
dx -= dpi->height;
if (dx >= dpi->y)
if (screenMinY - (max_height + 32) >= dpi->y + dpi->height)
return;
session->SpritePosition.x = x;

View File

@ -36,6 +36,7 @@
#include "../windows/Intent.h"
#include "../world/Balloon.h"
#include "../world/Climate.h"
#include "../world/ConstructionClearance.h"
#include "../world/EntityTweener.h"
#include "../world/Entrance.h"
#include "../world/Footpath.h"

View File

@ -0,0 +1,358 @@
/*****************************************************************************
* Copyright (c) 2014-2021 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "ConstructionClearance.h"
#include "../Game.h"
#include "../openrct2/Cheats.h"
#include "../ride/Ride.h"
#include "../ride/RideData.h"
#include "Park.h"
#include "Scenery.h"
#include "SmallScenery.h"
#include "Surface.h"
static int32_t map_place_clear_func(
TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price, bool is_scenery)
{
if ((*tile_element)->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
return 1;
if (is_scenery && !(flags & GAME_COMMAND_FLAG_PATH_SCENERY))
return 1;
auto* scenery = (*tile_element)->AsSmallScenery()->GetEntry();
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
{
if (scenery != nullptr && scenery->HasFlag(SMALL_SCENERY_FLAG_IS_TREE))
return 1;
}
if (!(gParkFlags & PARK_FLAGS_NO_MONEY) && scenery != nullptr)
*price += scenery->removal_price * 10;
if (flags & GAME_COMMAND_FLAG_GHOST)
return 0;
if (!(flags & GAME_COMMAND_FLAG_APPLY))
return 0;
map_invalidate_tile({ coords, (*tile_element)->GetBaseZ(), (*tile_element)->GetClearanceZ() });
tile_element_remove(*tile_element);
(*tile_element)--;
return 0;
}
/**
*
* rct2: 0x006E0D6E, 0x006B8D88
*/
int32_t map_place_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price)
{
return map_place_clear_func(tile_element, coords, flags, price, /*is_scenery=*/true);
}
/**
*
* rct2: 0x006C5A4F, 0x006CDE57, 0x006A6733, 0x0066637E
*/
int32_t map_place_non_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price)
{
return map_place_clear_func(tile_element, coords, flags, price, /*is_scenery=*/false);
}
static bool MapLoc68BABCShouldContinue(
TileElement* tileElement, const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, uint8_t flags, money32& price,
uint8_t crossingMode, bool canBuildCrossing)
{
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &price))
{
return true;
}
}
// Crossing mode 1: building track over path
if (crossingMode == 1 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_PATH
&& tileElement->GetBaseZ() == pos.baseZ && !tileElement->AsPath()->IsQueue() && !tileElement->AsPath()->IsSloped())
{
return true;
}
// Crossing mode 2: building path over track
else if (
crossingMode == 2 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK
&& tileElement->GetBaseZ() == pos.baseZ && tileElement->AsTrack()->GetTrackType() == TrackElemType::Flat)
{
auto ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr && ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS))
{
return true;
}
}
return false;
}
/**
*
* rct2: 0x0068B932
* ax = x
* cx = y
* dl = zLow
* dh = zHigh
* ebp = clearFunc
* bl = bl
*/
std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode, bool isTree)
{
int32_t northZ, eastZ, baseHeight, southZ, westZ, water_height;
northZ = eastZ = baseHeight = southZ = westZ = water_height = 0;
auto res = std::make_unique<GameActions::ConstructClearResult>();
uint8_t slope = 0;
res->GroundFlags = ELEMENT_IS_ABOVE_GROUND;
bool canBuildCrossing = false;
if (map_is_edge(pos))
{
res->Error = GameActions::Status::InvalidParameters;
res->ErrorMessage = STR_OFF_EDGE_OF_MAP;
return res;
}
if (gCheatsDisableClearanceChecks)
{
return res;
}
TileElement* tileElement = map_get_first_element_at(pos);
if (tileElement == nullptr)
{
res->Error = GameActions::Status::Unknown;
res->ErrorMessage = STR_NONE;
return res;
}
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SURFACE)
{
if (pos.baseZ < tileElement->GetClearanceZ() && pos.clearanceZ > tileElement->GetBaseZ()
&& !(tileElement->IsGhost()))
{
if (tileElement->GetOccupiedQuadrants() & (quarterTile.GetBaseQuarterOccupied()))
{
if (MapLoc68BABCShouldContinue(
tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
if (tileElement != nullptr)
{
map_obstruction_set_error_text(tileElement, *res);
res->Error = GameActions::Status::NoClearance;
}
return res;
}
}
continue;
}
water_height = tileElement->AsSurface()->GetWaterHeight();
if (water_height && water_height > pos.baseZ && tileElement->GetBaseZ() < pos.clearanceZ)
{
res->GroundFlags |= ELEMENT_IS_UNDERWATER;
if (water_height < pos.clearanceZ)
{
bool returnError = true;
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &res->Cost))
{
returnError = false;
}
}
if (returnError)
{
if (tileElement != nullptr)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER;
}
return res;
}
}
}
if (gParkFlags & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION && !isTree)
{
auto heightFromGround = pos.clearanceZ - tileElement->GetBaseZ();
if (heightFromGround > (18 * COORDS_Z_STEP))
{
res->Error = GameActions::Status::Disallowed;
res->ErrorMessage = STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT;
return res;
}
}
// Only allow building crossings directly on a flat surface tile.
if (tileElement->GetType() == TILE_ELEMENT_TYPE_SURFACE
&& (tileElement->AsSurface()->GetSlope()) == TILE_ELEMENT_SLOPE_FLAT && tileElement->GetBaseZ() == pos.baseZ)
{
canBuildCrossing = true;
}
if (quarterTile.GetZQuarterOccupied() != 0b1111)
{
if (tileElement->GetBaseZ() >= pos.clearanceZ)
{
// loc_68BA81
res->GroundFlags |= ELEMENT_IS_UNDERGROUND;
res->GroundFlags &= ~ELEMENT_IS_ABOVE_GROUND;
}
else
{
northZ = tileElement->GetBaseZ();
eastZ = northZ;
southZ = northZ;
westZ = northZ;
slope = tileElement->AsSurface()->GetSlope();
if (slope & TILE_ELEMENT_SLOPE_N_CORNER_UP)
{
northZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_S_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
northZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_E_CORNER_UP)
{
eastZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_W_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
eastZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_S_CORNER_UP)
{
southZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_N_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
southZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_W_CORNER_UP)
{
westZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_E_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
westZ += LAND_HEIGHT_STEP;
}
baseHeight = pos.baseZ + (4 * COORDS_Z_STEP);
{
auto baseQuarter = quarterTile.GetBaseQuarterOccupied();
auto zQuarter = quarterTile.GetZQuarterOccupied();
if ((!(baseQuarter & 0b0001) || ((zQuarter & 0b0001 || pos.baseZ >= northZ) && baseHeight >= northZ))
&& (!(baseQuarter & 0b0010) || ((zQuarter & 0b0010 || pos.baseZ >= eastZ) && baseHeight >= eastZ))
&& (!(baseQuarter & 0b0100) || ((zQuarter & 0b0100 || pos.baseZ >= southZ) && baseHeight >= southZ))
&& (!(baseQuarter & 0b1000) || ((zQuarter & 0b1000 || pos.baseZ >= westZ) && baseHeight >= westZ)))
{
continue;
}
}
if (MapLoc68BABCShouldContinue(tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
if (tileElement != nullptr)
{
map_obstruction_set_error_text(tileElement, *res);
res->Error = GameActions::Status::NoClearance;
}
return res;
}
}
} while (!(tileElement++)->IsLastForTile());
return res;
}
std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructAt(const CoordsXYRangedZ& pos, QuarterTile bl)
{
return MapCanConstructWithClearAt(pos, nullptr, bl, 0);
}
/**
*
* rct2: 0x0068BB18
*/
void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Result& res)
{
Ride* ride;
res.ErrorMessage = STR_OBJECT_IN_THE_WAY;
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_SURFACE:
res.ErrorMessage = STR_RAISE_OR_LOWER_LAND_FIRST;
break;
case TILE_ELEMENT_TYPE_PATH:
res.ErrorMessage = STR_FOOTPATH_IN_THE_WAY;
break;
case TILE_ELEMENT_TYPE_TRACK:
ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr)
{
res.ErrorMessage = STR_X_IN_THE_WAY;
Formatter ft(res.ErrorMessageArgs.data());
ride->FormatNameTo(ft);
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
{
auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = sceneryEntry != nullptr ? sceneryEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
case TILE_ELEMENT_TYPE_ENTRANCE:
switch (tileElement->AsEntrance()->GetEntranceType())
{
case ENTRANCE_TYPE_RIDE_ENTRANCE:
res.ErrorMessage = STR_RIDE_ENTRANCE_IN_THE_WAY;
break;
case ENTRANCE_TYPE_RIDE_EXIT:
res.ErrorMessage = STR_RIDE_EXIT_IN_THE_WAY;
break;
case ENTRANCE_TYPE_PARK_ENTRANCE:
res.ErrorMessage = STR_PARK_ENTRANCE_IN_THE_WAY;
break;
}
break;
case TILE_ELEMENT_TYPE_WALL:
{
auto* wallEntry = tileElement->AsWall()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = wallEntry != nullptr ? wallEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
{
auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = sceneryEntry != nullptr ? sceneryEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
}
}

View File

@ -0,0 +1,34 @@
/*****************************************************************************
* Copyright (c) 2014-2021 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 "../actions/GameActionResult.h"
#include "../common.h"
#include "Map.h"
#include <cstdint>
struct TileElement;
struct CoordsXY;
struct CoordsXYRangedZ;
class QuarterTile;
using CLEAR_FUNC = int32_t (*)(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
int32_t map_place_non_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
int32_t map_place_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
[[nodiscard]] std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags,
uint8_t crossingMode = CREATE_CROSSING_MODE_NONE, bool isTree = false);
[[nodiscard]] std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructAt(const CoordsXYRangedZ& pos, QuarterTile bl);
void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Result& res);

View File

@ -1308,292 +1308,6 @@ TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants
return insertedElement;
}
/**
*
* rct2: 0x0068BB18
*/
void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Result& res)
{
Ride* ride;
res.ErrorMessage = STR_OBJECT_IN_THE_WAY;
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_SURFACE:
res.ErrorMessage = STR_RAISE_OR_LOWER_LAND_FIRST;
break;
case TILE_ELEMENT_TYPE_PATH:
res.ErrorMessage = STR_FOOTPATH_IN_THE_WAY;
break;
case TILE_ELEMENT_TYPE_TRACK:
ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr)
{
res.ErrorMessage = STR_X_IN_THE_WAY;
Formatter ft(res.ErrorMessageArgs.data());
ride->FormatNameTo(ft);
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
{
auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = sceneryEntry != nullptr ? sceneryEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
case TILE_ELEMENT_TYPE_ENTRANCE:
switch (tileElement->AsEntrance()->GetEntranceType())
{
case ENTRANCE_TYPE_RIDE_ENTRANCE:
res.ErrorMessage = STR_RIDE_ENTRANCE_IN_THE_WAY;
break;
case ENTRANCE_TYPE_RIDE_EXIT:
res.ErrorMessage = STR_RIDE_EXIT_IN_THE_WAY;
break;
case ENTRANCE_TYPE_PARK_ENTRANCE:
res.ErrorMessage = STR_PARK_ENTRANCE_IN_THE_WAY;
break;
}
break;
case TILE_ELEMENT_TYPE_WALL:
{
auto* wallEntry = tileElement->AsWall()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = wallEntry != nullptr ? wallEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
{
auto* sceneryEntry = tileElement->AsLargeScenery()->GetEntry();
res.ErrorMessage = STR_X_IN_THE_WAY;
auto ft = Formatter(res.ErrorMessageArgs.data());
rct_string_id stringId = sceneryEntry != nullptr ? sceneryEntry->name : static_cast<rct_string_id>(STR_EMPTY);
ft.Add<rct_string_id>(stringId);
break;
}
}
}
static bool MapLoc68BABCShouldContinue(
TileElement* tileElement, const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, uint8_t flags, money32& price,
uint8_t crossingMode, bool canBuildCrossing)
{
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &price))
{
return true;
}
}
// Crossing mode 1: building track over path
if (crossingMode == 1 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_PATH
&& tileElement->GetBaseZ() == pos.baseZ && !tileElement->AsPath()->IsQueue() && !tileElement->AsPath()->IsSloped())
{
return true;
}
// Crossing mode 2: building path over track
else if (
crossingMode == 2 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK
&& tileElement->GetBaseZ() == pos.baseZ && tileElement->AsTrack()->GetTrackType() == TrackElemType::Flat)
{
auto ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr && ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS))
{
return true;
}
}
return false;
}
/**
*
* rct2: 0x0068B932
* ax = x
* cx = y
* dl = zLow
* dh = zHigh
* ebp = clearFunc
* bl = bl
*/
std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags, uint8_t crossingMode, bool isTree)
{
int32_t northZ, eastZ, baseHeight, southZ, westZ, water_height;
northZ = eastZ = baseHeight = southZ = westZ = water_height = 0;
auto res = std::make_unique<GameActions::ConstructClearResult>();
uint8_t slope = 0;
res->GroundFlags = ELEMENT_IS_ABOVE_GROUND;
bool canBuildCrossing = false;
if (map_is_edge(pos))
{
res->Error = GameActions::Status::InvalidParameters;
res->ErrorMessage = STR_OFF_EDGE_OF_MAP;
return res;
}
if (gCheatsDisableClearanceChecks)
{
return res;
}
TileElement* tileElement = map_get_first_element_at(pos);
if (tileElement == nullptr)
{
res->Error = GameActions::Status::Unknown;
res->ErrorMessage = STR_NONE;
return res;
}
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SURFACE)
{
if (pos.baseZ < tileElement->GetClearanceZ() && pos.clearanceZ > tileElement->GetBaseZ()
&& !(tileElement->IsGhost()))
{
if (tileElement->GetOccupiedQuadrants() & (quarterTile.GetBaseQuarterOccupied()))
{
if (MapLoc68BABCShouldContinue(
tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
if (tileElement != nullptr)
{
map_obstruction_set_error_text(tileElement, *res);
res->Error = GameActions::Status::NoClearance;
}
return res;
}
}
continue;
}
water_height = tileElement->AsSurface()->GetWaterHeight();
if (water_height && water_height > pos.baseZ && tileElement->GetBaseZ() < pos.clearanceZ)
{
res->GroundFlags |= ELEMENT_IS_UNDERWATER;
if (water_height < pos.clearanceZ)
{
bool returnError = true;
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &res->Cost))
{
returnError = false;
}
}
if (returnError)
{
if (tileElement != nullptr)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER;
}
return res;
}
}
}
if (gParkFlags & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION && !isTree)
{
auto heightFromGround = pos.clearanceZ - tileElement->GetBaseZ();
if (heightFromGround > (18 * COORDS_Z_STEP))
{
res->Error = GameActions::Status::Disallowed;
res->ErrorMessage = STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT;
return res;
}
}
// Only allow building crossings directly on a flat surface tile.
if (tileElement->GetType() == TILE_ELEMENT_TYPE_SURFACE
&& (tileElement->AsSurface()->GetSlope()) == TILE_ELEMENT_SLOPE_FLAT && tileElement->GetBaseZ() == pos.baseZ)
{
canBuildCrossing = true;
}
if (quarterTile.GetZQuarterOccupied() != 0b1111)
{
if (tileElement->GetBaseZ() >= pos.clearanceZ)
{
// loc_68BA81
res->GroundFlags |= ELEMENT_IS_UNDERGROUND;
res->GroundFlags &= ~ELEMENT_IS_ABOVE_GROUND;
}
else
{
northZ = tileElement->GetBaseZ();
eastZ = northZ;
southZ = northZ;
westZ = northZ;
slope = tileElement->AsSurface()->GetSlope();
if (slope & TILE_ELEMENT_SLOPE_N_CORNER_UP)
{
northZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_S_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
northZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_E_CORNER_UP)
{
eastZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_W_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
eastZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_S_CORNER_UP)
{
southZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_N_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
southZ += LAND_HEIGHT_STEP;
}
if (slope & TILE_ELEMENT_SLOPE_W_CORNER_UP)
{
westZ += LAND_HEIGHT_STEP;
if (slope == (TILE_ELEMENT_SLOPE_E_CORNER_DN | TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT))
westZ += LAND_HEIGHT_STEP;
}
baseHeight = pos.baseZ + (4 * COORDS_Z_STEP);
{
auto baseQuarter = quarterTile.GetBaseQuarterOccupied();
auto zQuarter = quarterTile.GetZQuarterOccupied();
if ((!(baseQuarter & 0b0001) || ((zQuarter & 0b0001 || pos.baseZ >= northZ) && baseHeight >= northZ))
&& (!(baseQuarter & 0b0010) || ((zQuarter & 0b0010 || pos.baseZ >= eastZ) && baseHeight >= eastZ))
&& (!(baseQuarter & 0b0100) || ((zQuarter & 0b0100 || pos.baseZ >= southZ) && baseHeight >= southZ))
&& (!(baseQuarter & 0b1000) || ((zQuarter & 0b1000 || pos.baseZ >= westZ) && baseHeight >= westZ)))
{
continue;
}
}
if (MapLoc68BABCShouldContinue(tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
if (tileElement != nullptr)
{
map_obstruction_set_error_text(tileElement, *res);
res->Error = GameActions::Status::NoClearance;
}
return res;
}
}
} while (!(tileElement++)->IsLastForTile());
return res;
}
std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructAt(const CoordsXYRangedZ& pos, QuarterTile bl)
{
return MapCanConstructWithClearAt(pos, nullptr, bl, 0);
}
/**
* Updates grass length, scenery age and jumping fountains.
*

View File

@ -234,21 +234,6 @@ template<typename T> T* TileElementInsert(const CoordsXYZ& loc, int32_t occupied
return (element != nullptr) ? element->template as<T>() : nullptr;
}
namespace GameActions
{
class Result;
class ConstructClearResult;
} // namespace GameActions
using CLEAR_FUNC = int32_t (*)(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
int32_t map_place_non_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
int32_t map_place_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price);
[[nodiscard]] std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, QuarterTile quarterTile, uint8_t flags,
uint8_t crossingMode = CREATE_CROSSING_MODE_NONE, bool isTree = false);
[[nodiscard]] std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructAt(const CoordsXYRangedZ& pos, QuarterTile bl);
struct tile_element_iterator
{
int32_t x;
@ -306,7 +291,6 @@ TileElement* map_get_track_element_at_from_ride(const CoordsXYZ& trackPos, ride_
TileElement* map_get_track_element_at_with_direction_from_ride(const CoordsXYZD& trackPos, ride_id_t rideIndex);
bool map_is_location_at_edge(const CoordsXY& loc);
void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Result& res);
uint16_t check_max_allowable_land_rights_for_tile(const CoordsXYZ& tileMapPos);

View File

@ -24,58 +24,6 @@
#include "Scenery.h"
#include "Surface.h"
static int32_t map_place_clear_func(
TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price, bool is_scenery)
{
if ((*tile_element)->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
return 1;
if (is_scenery && !(flags & GAME_COMMAND_FLAG_PATH_SCENERY))
return 1;
auto* scenery = (*tile_element)->AsSmallScenery()->GetEntry();
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
{
if (scenery != nullptr && scenery->HasFlag(SMALL_SCENERY_FLAG_IS_TREE))
return 1;
}
if (!(gParkFlags & PARK_FLAGS_NO_MONEY) && scenery != nullptr)
*price += scenery->removal_price * 10;
if (flags & GAME_COMMAND_FLAG_GHOST)
return 0;
if (!(flags & GAME_COMMAND_FLAG_APPLY))
return 0;
map_invalidate_tile({ coords, (*tile_element)->GetBaseZ(), (*tile_element)->GetClearanceZ() });
tile_element_remove(*tile_element);
(*tile_element)--;
return 0;
}
/**
*
* rct2: 0x006E0D6E, 0x006B8D88
*/
int32_t map_place_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price)
{
return map_place_clear_func(tile_element, coords, flags, price, /*is_scenery=*/true);
}
/**
*
* rct2: 0x006C5A4F, 0x006CDE57, 0x006A6733, 0x0066637E
*/
int32_t map_place_non_scenery_clear_func(TileElement** tile_element, const CoordsXY& coords, uint8_t flags, money32* price)
{
return map_place_clear_func(tile_element, coords, flags, price, /*is_scenery=*/false);
}
uint8_t SmallSceneryElement::GetSceneryQuadrant() const
{
return (this->type & TILE_ELEMENT_QUADRANT_MASK) >> 6;

View File

@ -894,3 +894,10 @@ namespace OpenRCT2
return nullptr;
}
} // namespace OpenRCT2
ScreenCoordsXY translate_3d_to_2d_with_z(int32_t rotation, const CoordsXYZ& pos)
{
auto rotated = pos.Rotate(rotation);
// Use right shift to avoid issues like #9301
return ScreenCoordsXY{ rotated.y - rotated.x, ((rotated.x + rotated.y) >> 1) - pos.z };
}