You've already forked OpenRCT2-Unity
mirror of
https://github.com/izzy2lost/OpenRCT2-Unity.git
synced 2026-03-10 12:38:22 -07:00
Merge pull request #16740 from IntelOrca/precise-patrol-areas
Allow patrol areas to be single tiles.
This commit is contained in:
@@ -68,9 +68,9 @@ set(OBJECTS_VERSION "1.2.6")
|
||||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
|
||||
set(OBJECTS_SHA1 "cd86dd2e42edb513b18293ef7ae52a93a7cdfc57")
|
||||
|
||||
set(REPLAYS_VERSION "0.0.64")
|
||||
set(REPLAYS_VERSION "0.0.65")
|
||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
|
||||
set(REPLAYS_SHA1 "E8DA520B3462090D894F0E7B844C5AB646BFB12E")
|
||||
set(REPLAYS_SHA1 "CE3796062BF3FDDC3FA3C8FC2F0DDD8EE9314174")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
|
||||
@@ -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 #
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- Improved: [#16251] openrct2.d.ts: removed unused LabelWidget.onChange property.
|
||||
- Improved: [#16258] Increased image limit in the engine.
|
||||
- Improved: [#16408] Improve --version cli option to report more compatibility information.
|
||||
- Improved: [#16740] Allow staff patrol areas to be defined with individual tiles rather than groups of 4x4.
|
||||
- Improved: [#16764] [Plugin] Add hook 'map.save', called before the map is about is saved.
|
||||
- Change: [#14484] Make the Heartline Twister coaster ratings a little bit less hateful.
|
||||
- Change: [#16077] When importing SV6 files, the RCT1 land types are only added when they were actually used.
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.2.6/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>cd86dd2e42edb513b18293ef7ae52a93a7cdfc57</ObjectsSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.64/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>E8DA520B3462090D894F0E7B844C5AB646BFB12E</ReplaysSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.65/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>CE3796062BF3FDDC3FA3C8FC2F0DDD8EE9314174</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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 ) },
|
||||
|
||||
@@ -156,6 +156,7 @@
|
||||
<ClCompile Include="windows\ObjectLoadError.cpp" />
|
||||
<ClCompile Include="windows\Options.cpp" />
|
||||
<ClCompile Include="windows\Park.cpp" />
|
||||
<ClCompile Include="windows\PatrolArea.cpp" />
|
||||
<ClCompile Include="windows\Player.cpp" />
|
||||
<ClCompile Include="windows\RefurbishRidePrompt.cpp" />
|
||||
<ClCompile Include="windows\Research.cpp" />
|
||||
|
||||
303
src/openrct2-ui/windows/PatrolArea.cpp
Normal file
303
src/openrct2-ui/windows/PatrolArea.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/*****************************************************************************
|
||||
* 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 <algorithm>
|
||||
#include <openrct2-ui/interface/LandTool.h>
|
||||
#include <openrct2-ui/interface/Viewport.h>
|
||||
#include <openrct2-ui/interface/Widget.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Game.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/actions/StaffSetPatrolAreaAction.h>
|
||||
#include <openrct2/core/String.hpp>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/entity/EntityRegistry.h>
|
||||
#include <openrct2/entity/PatrolArea.h>
|
||||
#include <openrct2/entity/Staff.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/world/Park.h>
|
||||
|
||||
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<int32_t>(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<uint16_t>(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<uint16_t>(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<Staff>(_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<Staff>(_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()
|
||||
{
|
||||
if (PatrolAreaToolIsActive())
|
||||
{
|
||||
SetPatrolAreaToRender(_staffId);
|
||||
gfx_invalidate_screen();
|
||||
}
|
||||
else
|
||||
{
|
||||
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<int16_t>(MINIMUM_TOOL_SIZE);
|
||||
ft.Add<int16_t>(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<CoordsXY> 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 w = WindowFocusOrCreate<PatrolAreaWindow>(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<PatrolAreaWindow*>(window_find_by_class(WC_PATROL_AREA));
|
||||
return current != nullptr ? current->GetStaffId() : EntityId();
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <openrct2/actions/StaffSetPatrolAreaAction.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/entity/EntityRegistry.h>
|
||||
#include <openrct2/entity/PatrolArea.h>
|
||||
#include <openrct2/entity/Staff.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
@@ -134,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);
|
||||
@@ -169,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;
|
||||
@@ -208,15 +205,6 @@ static rct_window_event_list* window_staff_page_events[] = {
|
||||
|
||||
static EntertainerCostume _availableCostumes[static_cast<uint8_t>(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<Staff>(EntityId::FromUnderlying(w->number));
|
||||
@@ -541,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();
|
||||
gStaffDrawPatrolAreas = w->number;
|
||||
gfx_invalidate_screen();
|
||||
window_close_by_class(WC_PATROL_AREA);
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowPatrolAreaOpen(staffId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -894,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;
|
||||
|
||||
@@ -1173,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<Staff>(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<Staff>(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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1271,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();
|
||||
gStaffDrawPatrolAreas = 0xFFFF;
|
||||
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 */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/entity/EntityList.h>
|
||||
#include <openrct2/entity/EntityRegistry.h>
|
||||
#include <openrct2/entity/PatrolArea.h>
|
||||
#include <openrct2/entity/Staff.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
@@ -141,7 +142,7 @@ public:
|
||||
if (!tool_set(this, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, Tool::Crosshair))
|
||||
{
|
||||
show_gridlines();
|
||||
gStaffDrawPatrolAreas = _selectedTab | 0x8000;
|
||||
SetPatrolAreaToRender(GetSelectedStaffType());
|
||||
gfx_invalidate_screen();
|
||||
}
|
||||
break;
|
||||
@@ -471,7 +472,7 @@ public:
|
||||
{
|
||||
hide_gridlines();
|
||||
tool_cancel();
|
||||
gStaffDrawPatrolAreas = 0xFFFF;
|
||||
ClearPatrolAreaToRender();
|
||||
gfx_invalidate_screen();
|
||||
}
|
||||
}
|
||||
@@ -593,7 +594,7 @@ private:
|
||||
if (footpathCoords.IsNull())
|
||||
return nullptr;
|
||||
|
||||
auto isPatrolAreaSet = staff_is_patrol_area_set_for_type(GetSelectedStaffType(), footpathCoords);
|
||||
auto isPatrolAreaSet = IsPatrolAreaSetForStaffType(GetSelectedStaffType(), footpathCoords);
|
||||
|
||||
Peep* closestPeep = nullptr;
|
||||
auto closestPeepDistance = std::numeric_limits<int32_t>::max();
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <openrct2-ui/interface/Window.h>
|
||||
#include <openrct2/Identifiers.h>
|
||||
#include <openrct2/common.h>
|
||||
#include <openrct2/ride/Ride.h>
|
||||
#include <openrct2/windows/tile_inspector.h>
|
||||
@@ -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) \
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "entity/EntityList.h"
|
||||
#include "entity/EntityRegistry.h"
|
||||
#include "entity/Guest.h"
|
||||
#include "entity/PatrolArea.h"
|
||||
#include "entity/Staff.h"
|
||||
#include "interface/Viewport.h"
|
||||
#include "interface/Window_internal.h"
|
||||
@@ -350,7 +351,7 @@ namespace Editor
|
||||
}
|
||||
|
||||
ResetAllEntities();
|
||||
staff_reset_modes();
|
||||
UpdateConsolidatedPatrolAreas();
|
||||
gNumGuestsInPark = 0;
|
||||
gNumGuestsHeadingForPark = 0;
|
||||
gNumGuestsInParkLastWeek = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "core/FileScanner.h"
|
||||
#include "core/Path.hpp"
|
||||
#include "entity/EntityRegistry.h"
|
||||
#include "entity/PatrolArea.h"
|
||||
#include "entity/Peep.h"
|
||||
#include "entity/Staff.h"
|
||||
#include "interface/Colour.h"
|
||||
@@ -448,7 +449,7 @@ 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();
|
||||
UpdateConsolidatedPatrolAreas();
|
||||
}
|
||||
|
||||
void game_load_init()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "actions/GameAction.h"
|
||||
#include "config/Config.h"
|
||||
#include "entity/EntityRegistry.h"
|
||||
#include "entity/PatrolArea.h"
|
||||
#include "entity/Staff.h"
|
||||
#include "interface/Screenshot.h"
|
||||
#include "localisation/Date.h"
|
||||
@@ -67,7 +68,7 @@ void GameState::InitAll(const TileCoordsXY& mapSize)
|
||||
banner_init();
|
||||
ride_init_all();
|
||||
ResetAllEntities();
|
||||
staff_reset_modes();
|
||||
UpdateConsolidatedPatrolAreas();
|
||||
date_reset();
|
||||
climate_reset(ClimateType::CoolAndWet);
|
||||
News::InitQueue();
|
||||
|
||||
@@ -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<typename T> void Visit(std::string_view name, T& param)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T> || std::is_enum_v<T>, "Not an arithmetic type");
|
||||
|
||||
@@ -10,17 +10,25 @@
|
||||
#include "StaffSetPatrolAreaAction.h"
|
||||
|
||||
#include "../entity/EntityRegistry.h"
|
||||
#include "../entity/PatrolArea.h"
|
||||
#include "../entity/Peep.h"
|
||||
#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;
|
||||
@@ -29,75 +37,67 @@ 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
|
||||
{
|
||||
if (_spriteId.ToUnderlying() >= MAX_ENTITIES || _spriteId.IsNull())
|
||||
{
|
||||
log_error("Invalid spriteId. spriteId = %u", _spriteId);
|
||||
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<Staff>(_spriteId);
|
||||
if (staff == nullptr)
|
||||
{
|
||||
log_error("Invalid spriteId. spriteId = %u", _spriteId);
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE);
|
||||
}
|
||||
|
||||
return GameActions::Result();
|
||||
}
|
||||
|
||||
static void InvalidatePatrolTile(const CoordsXY& loc)
|
||||
{
|
||||
// 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 });
|
||||
}
|
||||
}
|
||||
return QueryExecute(false);
|
||||
}
|
||||
|
||||
GameActions::Result StaffSetPatrolAreaAction::Execute() const
|
||||
{
|
||||
return QueryExecute(true);
|
||||
}
|
||||
|
||||
static void InvalidatePatrolTiles(const MapRange& range)
|
||||
{
|
||||
map_invalidate_region(range.Point1, range.Point2);
|
||||
}
|
||||
|
||||
GameActions::Result StaffSetPatrolAreaAction::QueryExecute(bool executing) const
|
||||
{
|
||||
auto staff = TryGetEntity<Staff>(_spriteId);
|
||||
if (staff == nullptr)
|
||||
{
|
||||
log_error("Invalid spriteId. spriteId = %u", _spriteId);
|
||||
log_error("Invalid entity ID: %u", _spriteId.ToUnderlying());
|
||||
return GameActions::Result(GameActions::Status::InvalidParameters, STR_NONE, STR_NONE);
|
||||
}
|
||||
|
||||
switch (_mode)
|
||||
auto validRange = ClampRangeWithinMap(_range);
|
||||
for (int32_t y = validRange.GetTop(); y <= validRange.GetBottom(); y += COORDS_XY_STEP)
|
||||
{
|
||||
case StaffSetPatrolAreaMode::Set:
|
||||
staff->SetPatrolArea(_loc, true);
|
||||
InvalidatePatrolTile(_loc);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::Unset:
|
||||
staff->SetPatrolArea(_loc, false);
|
||||
if (!staff->HasPatrolArea())
|
||||
for (int32_t x = validRange.GetLeft(); x <= validRange.GetRight(); x += COORDS_XY_STEP)
|
||||
{
|
||||
if (!LocationValid({ x, y }))
|
||||
{
|
||||
staff->ClearPatrolArea();
|
||||
return GameActions::Result(GameActions::Status::NotOwned, STR_SET_PATROL_AREA, STR_LAND_NOT_OWNED_BY_PARK);
|
||||
}
|
||||
InvalidatePatrolTile(_loc);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::ClearAll:
|
||||
staff->ClearPatrolArea();
|
||||
gfx_invalidate_screen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
staff_update_greyed_patrol_areas();
|
||||
|
||||
if (executing)
|
||||
{
|
||||
switch (_mode)
|
||||
{
|
||||
case StaffSetPatrolAreaMode::Set:
|
||||
staff->SetPatrolArea(_range, true);
|
||||
InvalidatePatrolTiles(_range);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::Unset:
|
||||
staff->SetPatrolArea(_range, false);
|
||||
if (!staff->HasPatrolArea())
|
||||
{
|
||||
staff->ClearPatrolArea();
|
||||
}
|
||||
InvalidatePatrolTiles(_range);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::ClearAll:
|
||||
staff->ClearPatrolArea();
|
||||
gfx_invalidate_screen();
|
||||
break;
|
||||
}
|
||||
UpdateConsolidatedPatrolAreas();
|
||||
}
|
||||
return GameActions::Result();
|
||||
}
|
||||
|
||||
@@ -22,15 +22,18 @@ class StaffSetPatrolAreaAction final : public GameActionBase<GameCommand::SetSta
|
||||
{
|
||||
private:
|
||||
EntityId _spriteId{ EntityId::GetNull() };
|
||||
CoordsXY _loc;
|
||||
MapRange _range;
|
||||
StaffSetPatrolAreaMode _mode;
|
||||
|
||||
GameActions::Result QueryExecute(bool executing) const;
|
||||
|
||||
public:
|
||||
StaffSetPatrolAreaAction() = default;
|
||||
StaffSetPatrolAreaAction(EntityId spriteId, const CoordsXY& loc, const StaffSetPatrolAreaMode mode);
|
||||
StaffSetPatrolAreaAction(EntityId spriteId, const MapRange& range, const StaffSetPatrolAreaMode mode);
|
||||
|
||||
uint16_t GetActionFlags() const override;
|
||||
|
||||
void AcceptParameters(GameActionParameterVisitor& visitor) override;
|
||||
void Serialise(DataSerialiser& stream) override;
|
||||
GameActions::Result Query() const override;
|
||||
GameActions::Result Execute() const override;
|
||||
|
||||
20
src/openrct2/core/Algorithm.hpp
Normal file
20
src/openrct2/core/Algorithm.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2022 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 <algorithm>
|
||||
#include <functional>
|
||||
|
||||
template<class ForwardIt, class T, class Compare = std::less<>>
|
||||
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp = {})
|
||||
{
|
||||
first = std::lower_bound(first, last, value, comp);
|
||||
return first != last && !comp(value, *first) ? first : last;
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "EntityRegistry.h"
|
||||
|
||||
#include "../Game.h"
|
||||
#include "../core/Algorithm.hpp"
|
||||
#include "../core/ChecksumStream.h"
|
||||
#include "../core/Crypt.h"
|
||||
#include "../core/DataSerialiser.h"
|
||||
@@ -291,8 +292,8 @@ static void AddToFreeList(EntityId index)
|
||||
static void RemoveFromEntityList(EntityBase* entity)
|
||||
{
|
||||
auto& list = gEntityLists[EnumValue(entity->Type)];
|
||||
auto ptr = std::lower_bound(std::begin(list), std::end(list), entity->sprite_index);
|
||||
if (ptr != std::end(list) && *ptr == entity->sprite_index)
|
||||
auto ptr = binary_find(std::begin(list), std::end(list), entity->sprite_index);
|
||||
if (ptr != std::end(list))
|
||||
{
|
||||
list.erase(ptr);
|
||||
}
|
||||
@@ -364,8 +365,8 @@ EntityBase* CreateEntity(EntityType type)
|
||||
|
||||
EntityBase* CreateEntityAt(const EntityId index, const EntityType type)
|
||||
{
|
||||
auto id = std::lower_bound(std::rbegin(_freeIdList), std::rend(_freeIdList), index);
|
||||
if (id == std::rend(_freeIdList) || *id != index)
|
||||
auto id = binary_find(std::rbegin(_freeIdList), std::rend(_freeIdList), index);
|
||||
if (id == std::rend(_freeIdList))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -421,8 +422,8 @@ static void EntitySpatialRemove(EntityBase* entity)
|
||||
{
|
||||
size_t currentIndex = GetSpatialIndexOffset({ entity->x, entity->y });
|
||||
auto& spatialVector = gEntitySpatialIndex[currentIndex];
|
||||
auto index = std::lower_bound(std::begin(spatialVector), std::end(spatialVector), entity->sprite_index);
|
||||
if (index != std::end(spatialVector) && *index == entity->sprite_index)
|
||||
auto index = binary_find(std::begin(spatialVector), std::end(spatialVector), entity->sprite_index);
|
||||
if (index != std::end(spatialVector))
|
||||
{
|
||||
spatialVector.erase(index, index + 1);
|
||||
}
|
||||
|
||||
178
src/openrct2/entity/PatrolArea.cpp
Normal file
178
src/openrct2/entity/PatrolArea.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2022 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 "PatrolArea.h"
|
||||
|
||||
#include "../core/Algorithm.hpp"
|
||||
#include "EntityList.h"
|
||||
#include "Staff.h"
|
||||
|
||||
static PatrolArea _consolidatedPatrolArea[EnumValue(StaffType::Count)];
|
||||
static std::variant<StaffType, EntityId> _patrolAreaToRender;
|
||||
|
||||
static bool CompareTileCoordsXY(const TileCoordsXY& lhs, const TileCoordsXY& rhs)
|
||||
{
|
||||
if (lhs.y == rhs.y)
|
||||
return lhs.x < rhs.x;
|
||||
return lhs.y < rhs.y;
|
||||
}
|
||||
|
||||
const PatrolArea::Cell* PatrolArea::GetCell(const TileCoordsXY& pos) const
|
||||
{
|
||||
return const_cast<PatrolArea*>(this)->GetCell(pos);
|
||||
}
|
||||
|
||||
PatrolArea::Cell* PatrolArea::GetCell(const TileCoordsXY& pos)
|
||||
{
|
||||
auto areaPos = TileCoordsXY(pos.x / Cell::Width, pos.y / Cell::Height);
|
||||
if (areaPos.x < 0 || areaPos.x >= CellColumns || areaPos.y < 0 || areaPos.y >= CellRows)
|
||||
return nullptr;
|
||||
|
||||
auto& area = Areas[(areaPos.y * CellColumns) + areaPos.x];
|
||||
return &area;
|
||||
}
|
||||
|
||||
bool PatrolArea::IsEmpty() const
|
||||
{
|
||||
return TileCount == 0;
|
||||
}
|
||||
|
||||
void PatrolArea::Clear()
|
||||
{
|
||||
for (auto& area : Areas)
|
||||
{
|
||||
area.SortedTiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool PatrolArea::Get(const TileCoordsXY& pos) const
|
||||
{
|
||||
auto* area = GetCell(pos);
|
||||
if (area == nullptr)
|
||||
return false;
|
||||
|
||||
auto it = binary_find(area->SortedTiles.begin(), area->SortedTiles.end(), pos, CompareTileCoordsXY);
|
||||
auto found = it != area->SortedTiles.end();
|
||||
return found;
|
||||
}
|
||||
|
||||
bool PatrolArea::Get(const CoordsXY& pos) const
|
||||
{
|
||||
return Get(TileCoordsXY(pos));
|
||||
}
|
||||
|
||||
void PatrolArea::Set(const TileCoordsXY& pos, bool value)
|
||||
{
|
||||
auto* area = GetCell(pos);
|
||||
if (area == nullptr)
|
||||
return;
|
||||
|
||||
auto it = std::lower_bound(area->SortedTiles.begin(), area->SortedTiles.end(), pos, CompareTileCoordsXY);
|
||||
auto found = it != area->SortedTiles.end() && *it == pos;
|
||||
|
||||
if (!found && value)
|
||||
{
|
||||
area->SortedTiles.insert(it, pos);
|
||||
TileCount++;
|
||||
}
|
||||
else if (found && !value)
|
||||
{
|
||||
area->SortedTiles.erase(it);
|
||||
assert(TileCount != 0);
|
||||
TileCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void PatrolArea::Set(const CoordsXY& pos, bool value)
|
||||
{
|
||||
Set(TileCoordsXY(pos), value);
|
||||
}
|
||||
|
||||
void PatrolArea::Union(const PatrolArea& other)
|
||||
{
|
||||
for (size_t i = 0; i < Areas.size(); i++)
|
||||
{
|
||||
for (const auto& pos : other.Areas[i].SortedTiles)
|
||||
{
|
||||
Set(pos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PatrolArea::Union(const std::vector<TileCoordsXY>& other)
|
||||
{
|
||||
for (const auto& pos : other)
|
||||
{
|
||||
Set(pos, true);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TileCoordsXY> PatrolArea::ToVector() const
|
||||
{
|
||||
std::vector<TileCoordsXY> result;
|
||||
for (const auto& area : Areas)
|
||||
{
|
||||
for (const auto& pos : area.SortedTiles)
|
||||
{
|
||||
result.push_back(pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const PatrolArea& GetMergedPatrolArea(const StaffType type)
|
||||
{
|
||||
return _consolidatedPatrolArea[EnumValue(type)];
|
||||
}
|
||||
|
||||
void UpdateConsolidatedPatrolAreas()
|
||||
{
|
||||
for (int32_t staffType = 0; staffType < EnumValue(StaffType::Count); ++staffType)
|
||||
{
|
||||
// Reset all of the merged data for the type.
|
||||
auto& mergedArea = _consolidatedPatrolArea[staffType];
|
||||
mergedArea.Clear();
|
||||
|
||||
for (auto staff : EntityList<Staff>())
|
||||
{
|
||||
if (EnumValue(staff->AssignedStaffType) != staffType)
|
||||
continue;
|
||||
|
||||
if (staff->PatrolInfo == nullptr)
|
||||
continue;
|
||||
|
||||
mergedArea.Union(*staff->PatrolInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPatrolAreaSetForStaffType(StaffType type, const CoordsXY& coords)
|
||||
{
|
||||
return _consolidatedPatrolArea[EnumValue(type)].Get(coords);
|
||||
}
|
||||
|
||||
std::variant<StaffType, EntityId> GetPatrolAreaToRender()
|
||||
{
|
||||
return _patrolAreaToRender;
|
||||
}
|
||||
|
||||
void ClearPatrolAreaToRender()
|
||||
{
|
||||
SetPatrolAreaToRender(EntityId::GetNull());
|
||||
}
|
||||
|
||||
void SetPatrolAreaToRender(EntityId staffId)
|
||||
{
|
||||
_patrolAreaToRender = staffId;
|
||||
}
|
||||
|
||||
void SetPatrolAreaToRender(StaffType staffType)
|
||||
{
|
||||
_patrolAreaToRender = staffType;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user