diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index ed9b41a46a..ca7d4cbfa5 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3657,6 +3657,8 @@ STR_6465 :Intensity: {COMMA2DP32} STR_6466 :Nausea STR_6467 :Nausea: {COMMA2DP32} STR_6468 :Not Yet Known +STR_6469 :Adjust smaller area of patrol area +STR_6470 :Adjust larger area of patrol area ############# # Scenarios # diff --git a/src/openrct2-ui/interface/Theme.cpp b/src/openrct2-ui/interface/Theme.cpp index f0a9905b86..65ef37be3b 100644 --- a/src/openrct2-ui/interface/Theme.cpp +++ b/src/openrct2-ui/interface/Theme.cpp @@ -174,6 +174,7 @@ static constexpr const WindowThemeDesc WindowThemeDescriptors[] = { THEME_WC(WC_TITLE_EDITOR), STR_TITLE_EDITOR_TITLE, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) }, { THEME_WC(WC_TILE_INSPECTOR), STR_TILE_INSPECTOR_TITLE, COLOURS_2(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, { THEME_WC(WC_VIEW_CLIPPING), STR_VIEW_CLIPPING_TITLE, COLOURS_1(COLOUR_DARK_GREEN ) }, + { THEME_WC(WC_PATROL_AREA), STR_SET_PATROL_AREA, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE ) }, { THEME_WC(WC_ABOUT), STR_ABOUT, COLOURS_2(COLOUR_GREY, COLOUR_LIGHT_BLUE ) }, { THEME_WC(WC_CHANGELOG), STR_CHANGELOG_TITLE, COLOURS_2(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, { THEME_WC(WC_MULTIPLAYER), STR_MULTIPLAYER, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, diff --git a/src/openrct2-ui/libopenrct2ui.vcxproj b/src/openrct2-ui/libopenrct2ui.vcxproj index b8a3649b3c..1103d25e87 100644 --- a/src/openrct2-ui/libopenrct2ui.vcxproj +++ b/src/openrct2-ui/libopenrct2ui.vcxproj @@ -156,6 +156,7 @@ + diff --git a/src/openrct2-ui/windows/PatrolArea.cpp b/src/openrct2-ui/windows/PatrolArea.cpp new file mode 100644 index 0000000000..fe89e273ad --- /dev/null +++ b/src/openrct2-ui/windows/PatrolArea.cpp @@ -0,0 +1,305 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static constexpr const rct_string_id WINDOW_TITLE = STR_SET_PATROL_AREA; +static constexpr const int32_t WH = 54; +static constexpr const int32_t WW = 104; + +enum WindowPatrolAreaWidgetIdx +{ + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PREVIEW, + WIDX_DECREMENT, + WIDX_INCREMENT, +}; + +// clang-format off +static rct_widget PatrolAreaWidgets[] = { + WINDOW_SHIM(WINDOW_TITLE, WW, WH), + MakeWidget ({27, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , SPR_LAND_TOOL_SIZE_0 ), // preview box + MakeRemapWidget({28, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_PATROL_AREA_TIP), // decrement size + MakeRemapWidget({54, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_PATROL_AREA_TIP ), // increment size + WIDGETS_END, +}; +// clang-format on + +class PatrolAreaWindow final : public Window +{ +public: + void OnOpen() override + { + widgets = PatrolAreaWidgets; + hold_down_widgets = (1ULL << WIDX_INCREMENT) | (1ULL << WIDX_DECREMENT); + WindowInitScrollWidgets(this); + window_push_others_below(this); + gLandToolSize = 4; + } + + void OnClose() override + { + // If the tool wasn't changed, turn tool off + if (PatrolAreaToolIsActive()) + tool_cancel(); + } + + void OnMouseUp(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + break; + case WIDX_PREVIEW: + InputSize(); + break; + } + } + + void OnMouseDown(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_DECREMENT: + gLandToolSize = std::max(MINIMUM_TOOL_SIZE, gLandToolSize - 1); + Invalidate(); + break; + case WIDX_INCREMENT: + gLandToolSize = std::min(MAXIMUM_TOOL_SIZE, gLandToolSize + 1); + Invalidate(); + break; + } + } + + void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) override + { + if (text.empty()) + return; + + if (widgetIndex != WIDX_PREVIEW) + return; + + const auto res = String::Parse(text); + if (res.has_value()) + { + int32_t size; + size = res.value(); + size = std::max(MINIMUM_TOOL_SIZE, size); + size = std::min(MAXIMUM_TOOL_SIZE, size); + gLandToolSize = size; + Invalidate(); + } + } + + void OnUpdate() override + { + // Close window if another tool is open or staff window gets closed + if (!PatrolAreaToolIsActive() || !IsStaffWindowOpen()) + { + Close(); + } + } + + void OnPrepareDraw() override + { + SetWidgetPressed(WIDX_PREVIEW, true); + PatrolAreaWidgets[WIDX_PREVIEW].image = LandTool::SizeToSpriteIndex(gLandToolSize); + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + DrawWidgets(dpi); + + // Draw number for tool sizes bigger than 7 + if (gLandToolSize > MAX_TOOL_SIZE_WITH_SPRITE) + { + auto screenCoords = ScreenCoordsXY{ windowPos.x + PatrolAreaWidgets[WIDX_PREVIEW].midX(), + windowPos.y + PatrolAreaWidgets[WIDX_PREVIEW].midY() }; + auto ft = Formatter(); + ft.Add(gLandToolSize); + DrawTextBasic(&dpi, screenCoords - ScreenCoordsXY{ 0, 2 }, STR_LAND_TOOL_SIZE_VALUE, ft, { TextAlignment::CENTRE }); + } + } + + void OnToolUpdate(rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) override + { + auto mapTile = GetBestCoordsFromPos(screenCoords); + if (!mapTile) + return; + + auto stateChanged = false; + if (!(gMapSelectFlags & MAP_SELECT_FLAG_ENABLE)) + stateChanged = true; + + if (gMapSelectType != MAP_SELECT_TYPE_FULL) + stateChanged = true; + + auto toolSize = std::max(1, gLandToolSize); + auto toolLength = (toolSize - 1) * 32; + + // Move to tool bottom left + mapTile->x -= (toolSize - 1) * 16; + mapTile->y -= (toolSize - 1) * 16; + mapTile = mapTile->ToTileStart(); + auto posA = *mapTile; + mapTile->x += toolLength; + mapTile->y += toolLength; + auto posB = *mapTile; + if (gMapSelectPositionA != posA || gMapSelectPositionB != posB) + stateChanged = true; + + if (stateChanged) + { + // Invalidate previous area + map_invalidate_selection_rect(); + + // Update and invalidate new area + gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; + gMapSelectType = MAP_SELECT_TYPE_FULL; + gMapSelectPositionA = posA; + gMapSelectPositionB = posB; + map_invalidate_selection_rect(); + } + } + + void OnToolAbort(rct_widgetindex widgetIndex) override + { + hide_gridlines(); + ClearPatrolAreaToRender(); + gfx_invalidate_screen(); + } + + void OnToolDown(rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) override + { + auto mapTile = GetBestCoordsFromPos(screenCoords); + if (mapTile) + { + auto staff = GetEntity(_staffId); + if (staff != nullptr) + { + _mode = staff->IsPatrolAreaSet(*mapTile) ? StaffSetPatrolAreaMode::Unset : StaffSetPatrolAreaMode::Set; + } + } + + OnToolDrag(widgetIndex, screenCoords); + } + + void OnToolDrag(rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) override + { + auto staff = GetEntity(_staffId); + if (staff != nullptr) + { + MapRange range(gMapSelectPositionA, gMapSelectPositionB); + auto staffSetPatrolAreaAction = StaffSetPatrolAreaAction(_staffId, range, _mode); + GameActions::Execute(&staffSetPatrolAreaAction); + } + } + + EntityId GetStaffId() const + { + return _staffId; + } + + void SetStaffId(EntityId staffId) + { + _staffId = staffId; + EnableTool(); + } + +private: + EntityId _staffId; + StaffSetPatrolAreaMode _mode; + + void EnableTool() + { + show_gridlines(); + if (!tool_set(this, 0, Tool::WalkDown)) + { + input_set_flag(INPUT_FLAG_6, true); + show_gridlines(); + SetPatrolAreaToRender(_staffId); + gfx_invalidate_screen(); + } + } + + void InputSize() + { + Formatter ft; + ft.Add(MINIMUM_TOOL_SIZE); + ft.Add(MAXIMUM_TOOL_SIZE); + WindowTextInputOpen(this, WIDX_PREVIEW, STR_SELECTION_SIZE, STR_ENTER_SELECTION_SIZE, ft, STR_NONE, STR_NONE, 3); + } + + bool PatrolAreaToolIsActive() + { + if (!(input_test_flag(INPUT_FLAG_TOOL_ACTIVE))) + return false; + if (gCurrentToolWidget.window_classification != WC_PATROL_AREA) + return false; + return true; + } + + bool IsStaffWindowOpen() + { + // If staff window for this patrol area was closed, tool is no longer active + auto staffWindow = window_find_by_number(WC_PEEP, _staffId); + return staffWindow != nullptr; + } + + std::optional GetBestCoordsFromPos(const ScreenCoordsXY& pos) + { + auto coords = footpath_get_coordinates_from_pos(pos, nullptr, nullptr); + return coords.IsNull() ? std::nullopt : std::make_optional(coords); + } +}; + +rct_window* WindowPatrolAreaOpen(EntityId staffId) +{ + auto current = reinterpret_cast(window_find_by_class(WC_PATROL_AREA)); + if (current != nullptr) + { + if (current->GetStaffId() == staffId) + { + return window_bring_to_front(current); + } + current->Close(); + } + + auto w = WindowFocusOrCreate(WC_PATROL_AREA, ScreenCoordsXY(context_get_width() - WW, 29), WW, WH, 0); + if (w != nullptr) + { + w->SetStaffId(staffId); + } + return w; +} + +EntityId WindowPatrolAreaGetCurrentStaffId() +{ + auto current = reinterpret_cast(window_find_by_class(WC_PATROL_AREA)); + return current != nullptr ? current->GetStaffId() : EntityId(); +} diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index ecf681b5e9..5172d72cc9 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -135,8 +135,6 @@ static void WindowStaffOverviewPaint(rct_window* w, rct_drawpixelinfo* dpi); static void WindowStaffOverviewTabPaint(rct_window* w, rct_drawpixelinfo* dpi); static void WindowStaffOverviewToolUpdate(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); static void WindowStaffOverviewToolDown(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); -static void WindowStaffOverviewToolDrag(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); -static void WindowStaffOverviewToolUp(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords); static void WindowStaffOverviewToolAbort(rct_window* w, rct_widgetindex widgetIndex); static void WindowStaffOverviewTextInput(rct_window* w, rct_widgetindex widgetIndex, char* text); static void WindowStaffOverviewViewportRotate(rct_window* w); @@ -170,8 +168,6 @@ static rct_window_event_list window_staff_overview_events([](auto& events) { events.update = &WindowStaffOverviewUpdate; events.tool_update = &WindowStaffOverviewToolUpdate; events.tool_down = &WindowStaffOverviewToolDown; - events.tool_drag = &WindowStaffOverviewToolDrag; - events.tool_up = &WindowStaffOverviewToolUp; events.tool_abort = &WindowStaffOverviewToolAbort; events.text_input = &WindowStaffOverviewTextInput; events.viewport_rotate = &WindowStaffOverviewViewportRotate; @@ -209,15 +205,6 @@ static rct_window_event_list* window_staff_page_events[] = { static EntertainerCostume _availableCostumes[static_cast(EntertainerCostume::Count)]; -enum class PatrolAreaValue -{ - UNSET = 0, - SET = 1, - NONE = -1, -}; - -static PatrolAreaValue _staffPatrolAreaPaintValue = PatrolAreaValue::NONE; - static Staff* GetStaff(rct_window* w) { auto staff = GetEntity(EntityId::FromUnderlying(w->number)); @@ -542,17 +529,22 @@ void WindowStaffOverviewDropdown(rct_window* w, rct_widgetindex widgetIndex, int return; } + window_close_by_class(WC_PATROL_AREA); + auto staffSetPatrolAreaAction = StaffSetPatrolAreaAction( peep->sprite_index, {}, StaffSetPatrolAreaMode::ClearAll); GameActions::Execute(&staffSetPatrolAreaAction); } else { - if (!tool_set(w, widgetIndex, Tool::WalkDown)) + auto staffId = EntityId::FromUnderlying(w->number); + if (WindowPatrolAreaGetCurrentStaffId() == staffId) { - show_gridlines(); - SetPatrolAreaToRender(EntityId::FromUnderlying(w->number)); - gfx_invalidate_screen(); + window_close_by_class(WC_PATROL_AREA); + } + else + { + WindowPatrolAreaOpen(staffId); } } break; @@ -895,6 +887,7 @@ void WindowStaffOverviewInvalidate(rct_window* w) window_staff_overview_widgets[WIDX_PICKUP].left = w->width - 25; window_staff_overview_widgets[WIDX_PICKUP].right = w->width - 2; + WidgetSetPressed(w, WIDX_PATROL, WindowPatrolAreaGetCurrentStaffId() == peep->sprite_index); window_staff_overview_widgets[WIDX_PATROL].left = w->width - 25; window_staff_overview_widgets[WIDX_PATROL].right = w->width - 2; @@ -1174,96 +1167,26 @@ void WindowStaffOverviewToolUpdate(rct_window* w, rct_widgetindex widgetIndex, c */ void WindowStaffOverviewToolDown(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) { + if (widgetIndex != WIDX_PICKUP) + return; + const auto staffEntityId = EntityId::FromUnderlying(w->number); - - if (widgetIndex == WIDX_PICKUP) - { - TileElement* tileElement; - auto destCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, &tileElement); - - if (destCoords.IsNull()) - return; - - PeepPickupAction pickupAction{ - PeepPickupType::Place, staffEntityId, { destCoords, tileElement->GetBaseZ() }, network_get_current_player_id() - }; - pickupAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) { - if (result->Error != GameActions::Status::Ok) - return; - tool_cancel(); - gPickupPeepImage = ImageId(); - }); - GameActions::Execute(&pickupAction); - } - else if (widgetIndex == WIDX_PATROL) - { - auto destCoords = footpath_get_coordinates_from_pos(screenCoords, nullptr, nullptr); - - if (destCoords.IsNull()) - return; - - auto staff = TryGetEntity(staffEntityId); - if (staff == nullptr) - return; - - if (staff->IsPatrolAreaSet(destCoords)) - { - _staffPatrolAreaPaintValue = PatrolAreaValue::UNSET; - } - else - { - _staffPatrolAreaPaintValue = PatrolAreaValue::SET; - } - auto staffSetPatrolAreaAction = StaffSetPatrolAreaAction( - staffEntityId, destCoords, - _staffPatrolAreaPaintValue == PatrolAreaValue::SET ? StaffSetPatrolAreaMode::Set : StaffSetPatrolAreaMode::Unset); - GameActions::Execute(&staffSetPatrolAreaAction); - } -} - -void WindowStaffOverviewToolDrag(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - if (widgetIndex != WIDX_PATROL) - return; - - if (network_get_mode() != NETWORK_MODE_NONE) - return; - - // This works only for singleplayer if the game_do_command can not be prevented - // to send packets more often than patrol area is updated. - - if (_staffPatrolAreaPaintValue == PatrolAreaValue::NONE) - return; // Do nothing if we do not have a paintvalue(this should never happen) - - auto destCoords = footpath_get_coordinates_from_pos(screenCoords, nullptr, nullptr); + TileElement* tileElement; + auto destCoords = footpath_get_coordinates_from_pos({ screenCoords.x, screenCoords.y + 16 }, nullptr, &tileElement); if (destCoords.IsNull()) return; - const auto staffEntityId = EntityId::FromUnderlying(w->number); - - auto* staff = TryGetEntity(staffEntityId); - if (staff == nullptr) - return; - - bool patrolAreaValue = staff->IsPatrolAreaSet(destCoords); - if (_staffPatrolAreaPaintValue == PatrolAreaValue::SET && patrolAreaValue) - return; // Since area is already the value we want, skip... - if (_staffPatrolAreaPaintValue == PatrolAreaValue::UNSET && !patrolAreaValue) - return; // Since area is already the value we want, skip... - - auto staffSetPatrolAreaAction = StaffSetPatrolAreaAction( - staffEntityId, destCoords, - _staffPatrolAreaPaintValue == PatrolAreaValue::SET ? StaffSetPatrolAreaMode::Set : StaffSetPatrolAreaMode::Unset); - GameActions::Execute(&staffSetPatrolAreaAction); -} - -void WindowStaffOverviewToolUp(rct_window* w, rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - if (widgetIndex != WIDX_PATROL) - return; - - _staffPatrolAreaPaintValue = PatrolAreaValue::NONE; + PeepPickupAction pickupAction{ + PeepPickupType::Place, staffEntityId, { destCoords, tileElement->GetBaseZ() }, network_get_current_player_id() + }; + pickupAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) { + if (result->Error != GameActions::Status::Ok) + return; + tool_cancel(); + gPickupPeepImage = ImageId(); + }); + GameActions::Execute(&pickupAction); } /** @@ -1272,20 +1195,14 @@ void WindowStaffOverviewToolUp(rct_window* w, rct_widgetindex widgetIndex, const */ void WindowStaffOverviewToolAbort(rct_window* w, rct_widgetindex widgetIndex) { - if (widgetIndex == WIDX_PICKUP) - { - PeepPickupAction pickupAction{ PeepPickupType::Cancel, - EntityId::FromUnderlying(w->number), - { w->picked_peep_old_x, 0, 0 }, - network_get_current_player_id() }; - GameActions::Execute(&pickupAction); - } - else if (widgetIndex == WIDX_PATROL) - { - hide_gridlines(); - ClearPatrolAreaToRender(); - gfx_invalidate_screen(); - } + if (widgetIndex != WIDX_PICKUP) + return; + + PeepPickupAction pickupAction{ PeepPickupType::Cancel, + EntityId::FromUnderlying(w->number), + { w->picked_peep_old_x, 0, 0 }, + network_get_current_player_id() }; + GameActions::Execute(&pickupAction); } /* rct2: 0x6BDFED */ diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp index 6ef1cb0069..5af77f7cbd 100644 --- a/src/openrct2-ui/windows/Themes.cpp +++ b/src/openrct2-ui/windows/Themes.cpp @@ -195,6 +195,7 @@ static rct_windowclass window_themes_tab_3_classes[] = { WC_TRACK_DESIGN_PLACE, WC_CONSTRUCT_RIDE, WC_TRACK_DESIGN_LIST, + WC_PATROL_AREA, }; static rct_windowclass window_themes_tab_4_classes[] = { diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 362e914a10..ae814db5d4 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include #include @@ -200,6 +201,8 @@ void WindowTooltipOpen(rct_window* widgetWindow, rct_widgetindex widgetIndex, co void WindowTooltipClose(); rct_window* WindowSceneryScatterOpen(); +rct_window* WindowPatrolAreaOpen(EntityId staffId); +EntityId WindowPatrolAreaGetCurrentStaffId(); // clang-format off #define WINDOW_SHIM_RAW(TITLE, WIDTH, HEIGHT, CLOSE_STR) \ diff --git a/src/openrct2/actions/GameAction.h b/src/openrct2/actions/GameAction.h index 7e5e89eb0a..c0a6fe2d12 100644 --- a/src/openrct2/actions/GameAction.h +++ b/src/openrct2/actions/GameAction.h @@ -79,6 +79,14 @@ public: Visit("direction", param.direction); } + void Visit(MapRange& param) + { + Visit("x1", param.Point1.x); + Visit("y1", param.Point1.y); + Visit("x2", param.Point2.x); + Visit("y2", param.Point2.y); + } + template void Visit(std::string_view name, T& param) { static_assert(std::is_arithmetic_v || std::is_enum_v, "Not an arithmetic type"); diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.cpp b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp index 2c528ed40e..601292adb2 100644 --- a/src/openrct2/actions/StaffSetPatrolAreaAction.cpp +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.cpp @@ -15,13 +15,20 @@ #include "../entity/Staff.h" #include "../interface/Window.h" -StaffSetPatrolAreaAction::StaffSetPatrolAreaAction(EntityId spriteId, const CoordsXY& loc, const StaffSetPatrolAreaMode mode) +StaffSetPatrolAreaAction::StaffSetPatrolAreaAction(EntityId spriteId, const MapRange& range, const StaffSetPatrolAreaMode mode) : _spriteId(spriteId) - , _loc(loc) + , _range(range) , _mode(mode) { } +void StaffSetPatrolAreaAction::AcceptParameters(GameActionParameterVisitor& visitor) +{ + visitor.Visit("id", _spriteId); + visitor.Visit(_range); + visitor.Visit("mode", _mode); +} + uint16_t StaffSetPatrolAreaAction::GetActionFlags() const { return GameAction::GetActionFlags() | GameActions::Flags::AllowWhilePaused; @@ -30,7 +37,7 @@ uint16_t StaffSetPatrolAreaAction::GetActionFlags() const void StaffSetPatrolAreaAction::Serialise(DataSerialiser& stream) { GameAction::Serialise(stream); - stream << DS_TAG(_spriteId) << DS_TAG(_loc) << DS_TAG(_mode); + stream << DS_TAG(_spriteId) << DS_TAG(_range) << DS_TAG(_mode); } GameActions::Result StaffSetPatrolAreaAction::Query() const @@ -41,11 +48,6 @@ GameActions::Result StaffSetPatrolAreaAction::Query() const return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); } - if (!LocationValid(_loc)) - { - return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE); - } - auto staff = TryGetEntity(_spriteId); if (staff == nullptr) { @@ -56,17 +58,9 @@ GameActions::Result StaffSetPatrolAreaAction::Query() const return GameActions::Result(); } -static void InvalidatePatrolTile(const CoordsXY& loc) +static void InvalidatePatrolTiles(const MapRange& range) { - // Align the location to the top left of the patrol square - const auto alignedLoc = CoordsXY{ loc.x & 0x1F80, loc.y & 0x1F80 }; - for (int32_t y = 0; y < 4 * COORDS_XY_STEP; y += COORDS_XY_STEP) - { - for (int32_t x = 0; x < 4 * COORDS_XY_STEP; x += COORDS_XY_STEP) - { - map_invalidate_tile_full(alignedLoc + CoordsXY{ x, y }); - } - } + map_invalidate_region(range.Point1, range.Point2); } GameActions::Result StaffSetPatrolAreaAction::Execute() const @@ -81,16 +75,16 @@ GameActions::Result StaffSetPatrolAreaAction::Execute() const switch (_mode) { case StaffSetPatrolAreaMode::Set: - staff->SetPatrolArea(_loc, true); - InvalidatePatrolTile(_loc); + staff->SetPatrolArea(_range, true); + InvalidatePatrolTiles(_range); break; case StaffSetPatrolAreaMode::Unset: - staff->SetPatrolArea(_loc, false); + staff->SetPatrolArea(_range, false); if (!staff->HasPatrolArea()) { staff->ClearPatrolArea(); } - InvalidatePatrolTile(_loc); + InvalidatePatrolTiles(_range); break; case StaffSetPatrolAreaMode::ClearAll: staff->ClearPatrolArea(); diff --git a/src/openrct2/actions/StaffSetPatrolAreaAction.h b/src/openrct2/actions/StaffSetPatrolAreaAction.h index 939f608a73..cdfc10b533 100644 --- a/src/openrct2/actions/StaffSetPatrolAreaAction.h +++ b/src/openrct2/actions/StaffSetPatrolAreaAction.h @@ -22,15 +22,16 @@ class StaffSetPatrolAreaAction final : public GameActionBase