mirror of https://github.com/OpenRCT2/OpenRCT2.git
719 lines
26 KiB
C++
719 lines
26 KiB
C++
/*****************************************************************************
|
|
* 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 <limits>
|
|
#include <openrct2-ui/interface/Dropdown.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/StaffFireAction.h>
|
|
#include <openrct2/actions/StaffHireNewAction.h>
|
|
#include <openrct2/actions/StaffSetColourAction.h>
|
|
#include <openrct2/config/Config.h>
|
|
#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>
|
|
#include <openrct2/management/Finance.h>
|
|
#include <openrct2/sprites.h>
|
|
#include <openrct2/util/Util.h>
|
|
#include <openrct2/windows/Intent.h>
|
|
#include <openrct2/world/Footpath.h>
|
|
#include <openrct2/world/Park.h>
|
|
#include <vector>
|
|
|
|
enum
|
|
{
|
|
WINDOW_STAFF_LIST_TAB_HANDYMEN,
|
|
WINDOW_STAFF_LIST_TAB_MECHANICS,
|
|
WINDOW_STAFF_LIST_TAB_SECURITY,
|
|
WINDOW_STAFF_LIST_TAB_ENTERTAINERS
|
|
};
|
|
|
|
enum WindowStaffListWidgetIdx
|
|
{
|
|
WIDX_STAFF_LIST_BACKGROUND,
|
|
WIDX_STAFF_LIST_TITLE,
|
|
WIDX_STAFF_LIST_CLOSE,
|
|
WIDX_STAFF_LIST_TAB_CONTENT_PANEL,
|
|
WIDX_STAFF_LIST_HANDYMEN_TAB,
|
|
WIDX_STAFF_LIST_MECHANICS_TAB,
|
|
WIDX_STAFF_LIST_SECURITY_TAB,
|
|
WIDX_STAFF_LIST_ENTERTAINERS_TAB,
|
|
WIDX_STAFF_LIST_LIST,
|
|
WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER,
|
|
WIDX_STAFF_LIST_HIRE_BUTTON,
|
|
WIDX_STAFF_LIST_QUICK_FIRE,
|
|
WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON,
|
|
WIDX_STAFF_LIST_MAP,
|
|
};
|
|
|
|
static constexpr const rct_string_id WINDOW_TITLE = STR_STAFF;
|
|
static constexpr const int32_t WW = 320;
|
|
static constexpr const int32_t WH = 270;
|
|
constexpr int32_t MAX_WW = 500;
|
|
constexpr int32_t MAX_WH = 450;
|
|
|
|
// clang-format off
|
|
static rct_widget window_staff_list_widgets[] = {
|
|
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
|
|
MakeWidget({ 0, 43}, { WW, WH - 43}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel
|
|
MakeTab ({ 3, 17}, STR_STAFF_HANDYMEN_TAB_TIP ), // handymen tab
|
|
MakeTab ({ 34, 17}, STR_STAFF_MECHANICS_TAB_TIP ), // mechanics tab
|
|
MakeTab ({ 65, 17}, STR_STAFF_SECURITY_TAB_TIP ), // security guards tab
|
|
MakeTab ({ 96, 17}, STR_STAFF_ENTERTAINERS_TAB_TIP), // entertainers tab
|
|
MakeWidget({ 3, 72}, {WW - 6, 195}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // staff list
|
|
MakeWidget({130, 58}, { 12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, STR_NONE, STR_UNIFORM_COLOUR_TIP ), // uniform colour picker
|
|
MakeWidget({165, 17}, { 145, 13}, WindowWidgetType::Button, WindowColour::Primary , STR_NONE, STR_HIRE_STAFF_TIP ), // hire button
|
|
MakeWidget({243, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_DEMOLISH, STR_QUICK_FIRE_STAFF ), // quick fire staff
|
|
MakeWidget({267, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_PATROL_BTN, STR_SHOW_PATROL_AREA_TIP ), // show staff patrol area tool
|
|
MakeWidget({291, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_MAP, STR_SHOW_STAFF_ON_MAP_TIP ), // show staff on map button
|
|
WIDGETS_END,
|
|
};
|
|
// clang-format on
|
|
|
|
class StaffListWindow final : public Window
|
|
{
|
|
private:
|
|
struct StaffNamingConvention
|
|
{
|
|
rct_string_id Plural;
|
|
rct_string_id Singular;
|
|
rct_string_id ActionHire;
|
|
};
|
|
|
|
std::vector<EntityId> _staffList;
|
|
bool _quickFireMode{};
|
|
std::optional<size_t> _highlightedIndex{};
|
|
int32_t _selectedTab{};
|
|
uint32_t _tabAnimationIndex{};
|
|
|
|
public:
|
|
void OnOpen() override
|
|
{
|
|
widgets = window_staff_list_widgets;
|
|
WindowInitScrollWidgets(*this);
|
|
|
|
widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].type = WindowWidgetType::Empty;
|
|
min_width = WW;
|
|
min_height = WH;
|
|
max_width = MAX_WW;
|
|
max_height = MAX_WH;
|
|
|
|
RefreshList();
|
|
}
|
|
|
|
void OnClose() override
|
|
{
|
|
CancelTools();
|
|
}
|
|
|
|
void OnMouseUp(rct_widgetindex widgetIndex) override
|
|
{
|
|
switch (widgetIndex)
|
|
{
|
|
case WIDX_STAFF_LIST_CLOSE:
|
|
Close();
|
|
break;
|
|
case WIDX_STAFF_LIST_HIRE_BUTTON:
|
|
{
|
|
auto staffType = GetSelectedStaffType();
|
|
auto costume = EntertainerCostume::Count;
|
|
if (staffType == StaffType::Entertainer)
|
|
{
|
|
costume = GetRandomEntertainerCostume();
|
|
}
|
|
HireNewMember(staffType, costume);
|
|
break;
|
|
}
|
|
case WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON:
|
|
if (!tool_set(*this, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, Tool::Crosshair))
|
|
{
|
|
show_gridlines();
|
|
SetPatrolAreaToRender(GetSelectedStaffType());
|
|
gfx_invalidate_screen();
|
|
}
|
|
break;
|
|
case WIDX_STAFF_LIST_MAP:
|
|
context_open_window(WC_MAP);
|
|
break;
|
|
case WIDX_STAFF_LIST_QUICK_FIRE:
|
|
_quickFireMode = !_quickFireMode;
|
|
Invalidate();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnResize() override
|
|
{
|
|
min_width = WW;
|
|
min_height = WH;
|
|
if (width < min_width)
|
|
{
|
|
width = min_width;
|
|
Invalidate();
|
|
}
|
|
if (height < min_height)
|
|
{
|
|
height = min_height;
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void OnUpdate() override
|
|
{
|
|
_tabAnimationIndex++;
|
|
if (_tabAnimationIndex >= 24)
|
|
{
|
|
_tabAnimationIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
InvalidateWidget(WIDX_STAFF_LIST_HANDYMEN_TAB + _selectedTab);
|
|
|
|
// Enable highlighting of these staff members in map window
|
|
if (window_find_by_class(WC_MAP) != nullptr)
|
|
{
|
|
gWindowMapFlashingFlags |= MapFlashingFlags::StaffListOpen;
|
|
for (auto peep : EntityList<Staff>())
|
|
{
|
|
EntitySetFlashing(peep, false);
|
|
if (peep->AssignedStaffType == GetSelectedStaffType())
|
|
{
|
|
EntitySetFlashing(peep, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note this may be slow if number of staff increases a large amount.
|
|
// See GuestList for fix (more intents) if required.
|
|
RefreshList();
|
|
}
|
|
|
|
void OnMouseDown(rct_widgetindex widgetIndex) override
|
|
{
|
|
switch (widgetIndex)
|
|
{
|
|
case WIDX_STAFF_LIST_HANDYMEN_TAB:
|
|
case WIDX_STAFF_LIST_MECHANICS_TAB:
|
|
case WIDX_STAFF_LIST_SECURITY_TAB:
|
|
case WIDX_STAFF_LIST_ENTERTAINERS_TAB:
|
|
{
|
|
auto newSelectedTab = widgetIndex - WIDX_STAFF_LIST_HANDYMEN_TAB;
|
|
if (_selectedTab != newSelectedTab)
|
|
{
|
|
_selectedTab = static_cast<uint8_t>(newSelectedTab);
|
|
Invalidate();
|
|
scrolls[0].v_top = 0;
|
|
CancelTools();
|
|
}
|
|
break;
|
|
}
|
|
case WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER:
|
|
WindowDropdownShowColour(this, &widgets[widgetIndex], colours[1], staff_get_colour(GetSelectedStaffType()));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override
|
|
{
|
|
if (widgetIndex == WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER)
|
|
{
|
|
auto action = StaffSetColourAction(GetSelectedStaffType(), dropdownIndex);
|
|
GameActions::Execute(&action);
|
|
}
|
|
}
|
|
|
|
void OnPrepareDraw() override
|
|
{
|
|
// Set selected tab
|
|
SetWidgetPressed(WIDX_STAFF_LIST_HANDYMEN_TAB, false);
|
|
SetWidgetPressed(WIDX_STAFF_LIST_MECHANICS_TAB, false);
|
|
SetWidgetPressed(WIDX_STAFF_LIST_SECURITY_TAB, false);
|
|
SetWidgetPressed(WIDX_STAFF_LIST_ENTERTAINERS_TAB, false);
|
|
SetWidgetPressed(_selectedTab + WIDX_STAFF_LIST_HANDYMEN_TAB, true);
|
|
|
|
widgets[WIDX_STAFF_LIST_HIRE_BUTTON].text = GetStaffNamingConvention(GetSelectedStaffType()).ActionHire;
|
|
widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].type = WindowWidgetType::Empty;
|
|
|
|
if (GetSelectedStaffType() != StaffType::Entertainer)
|
|
{
|
|
widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].type = WindowWidgetType::ColourBtn;
|
|
auto spriteIdPalette = SPRITE_ID_PALETTE_COLOUR_1(static_cast<uint32_t>(staff_get_colour(GetSelectedStaffType())));
|
|
widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].image = spriteIdPalette | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN;
|
|
}
|
|
SetWidgetPressed(WIDX_STAFF_LIST_QUICK_FIRE, _quickFireMode);
|
|
|
|
widgets[WIDX_STAFF_LIST_BACKGROUND].right = width - 1;
|
|
widgets[WIDX_STAFF_LIST_BACKGROUND].bottom = height - 1;
|
|
widgets[WIDX_STAFF_LIST_TAB_CONTENT_PANEL].right = width - 1;
|
|
widgets[WIDX_STAFF_LIST_TAB_CONTENT_PANEL].bottom = height - 1;
|
|
widgets[WIDX_STAFF_LIST_TITLE].right = width - 2;
|
|
widgets[WIDX_STAFF_LIST_CLOSE].left = width - 2 - 11;
|
|
widgets[WIDX_STAFF_LIST_CLOSE].right = width - 2 - 11 + 10;
|
|
widgets[WIDX_STAFF_LIST_LIST].right = width - 4;
|
|
widgets[WIDX_STAFF_LIST_LIST].bottom = height - 15;
|
|
widgets[WIDX_STAFF_LIST_QUICK_FIRE].left = width - 77;
|
|
widgets[WIDX_STAFF_LIST_QUICK_FIRE].right = width - 54;
|
|
widgets[WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON].left = width - 53;
|
|
widgets[WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON].right = width - 30;
|
|
widgets[WIDX_STAFF_LIST_MAP].left = width - 29;
|
|
widgets[WIDX_STAFF_LIST_MAP].right = width - 6;
|
|
widgets[WIDX_STAFF_LIST_HIRE_BUTTON].left = width - 155;
|
|
widgets[WIDX_STAFF_LIST_HIRE_BUTTON].right = width - 11;
|
|
}
|
|
|
|
void OnDraw(rct_drawpixelinfo& dpi) override
|
|
{
|
|
DrawWidgets(dpi);
|
|
DrawTabImages(dpi);
|
|
|
|
if (!(gParkFlags & PARK_FLAGS_NO_MONEY))
|
|
{
|
|
auto ft = Formatter();
|
|
ft.Add<money64>(GetStaffWage(GetSelectedStaffType()));
|
|
DrawTextBasic(&dpi, windowPos + ScreenCoordsXY{ width - 155, 32 }, STR_COST_PER_MONTH, ft);
|
|
}
|
|
|
|
if (GetSelectedStaffType() != StaffType::Entertainer)
|
|
{
|
|
DrawTextBasic(
|
|
&dpi, windowPos + ScreenCoordsXY{ 6, widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].top + 1 },
|
|
STR_UNIFORM_COLOUR);
|
|
}
|
|
|
|
auto namingConvention = GetStaffNamingConvention(GetSelectedStaffType());
|
|
auto staffTypeStringId = _staffList.size() == 1 ? namingConvention.Singular : namingConvention.Plural;
|
|
|
|
auto ft = Formatter();
|
|
ft.Add<uint16_t>(_staffList.size());
|
|
ft.Add<rct_string_id>(staffTypeStringId);
|
|
|
|
DrawTextBasic(
|
|
&dpi, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_STAFF_LIST_LIST].bottom + 2 }, STR_STAFF_LIST_COUNTER, ft);
|
|
}
|
|
|
|
ScreenSize OnScrollGetSize(int32_t scrollIndex) override
|
|
{
|
|
if (_highlightedIndex)
|
|
{
|
|
_highlightedIndex = {};
|
|
Invalidate();
|
|
}
|
|
|
|
auto scrollHeight = static_cast<int16_t>(_staffList.size()) * SCROLLABLE_ROW_HEIGHT;
|
|
auto i = scrollHeight - widgets[WIDX_STAFF_LIST_LIST].bottom + widgets[WIDX_STAFF_LIST_LIST].top + 21;
|
|
if (i < 0)
|
|
i = 0;
|
|
if (i < scrolls[0].v_top)
|
|
{
|
|
scrolls[0].v_top = i;
|
|
Invalidate();
|
|
}
|
|
|
|
auto scrollWidth = widgets[WIDX_STAFF_LIST_LIST].width() - 15;
|
|
return { scrollWidth, scrollHeight };
|
|
}
|
|
|
|
void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
|
|
{
|
|
auto i = static_cast<size_t>(screenCoords.y / SCROLLABLE_ROW_HEIGHT);
|
|
if (i != _highlightedIndex)
|
|
{
|
|
_highlightedIndex = static_cast<size_t>(i);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
|
|
{
|
|
int32_t i = screenCoords.y / SCROLLABLE_ROW_HEIGHT;
|
|
for (auto spriteIndex : _staffList)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
if (_quickFireMode)
|
|
{
|
|
auto staffFireAction = StaffFireAction(spriteIndex);
|
|
GameActions::Execute(&staffFireAction);
|
|
}
|
|
else
|
|
{
|
|
auto peep = GetEntity<Staff>(spriteIndex);
|
|
if (peep != nullptr)
|
|
{
|
|
auto intent = Intent(WC_PEEP);
|
|
intent.putExtra(INTENT_EXTRA_PEEP, peep);
|
|
context_open_intent(&intent);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
}
|
|
|
|
void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override
|
|
{
|
|
auto dpiCoords = ScreenCoordsXY{ dpi.x, dpi.y };
|
|
gfx_fill_rect(
|
|
&dpi, { dpiCoords, dpiCoords + ScreenCoordsXY{ dpi.width - 1, dpi.height - 1 } }, ColourMapA[colours[1]].mid_light);
|
|
|
|
// How much space do we have for the name and action columns? (Discount scroll area and icons.)
|
|
const int32_t nonIconSpace = widgets[WIDX_STAFF_LIST_LIST].width() - 15 - 68;
|
|
const int32_t nameColumnSize = nonIconSpace * 0.42;
|
|
const int32_t actionColumnSize = nonIconSpace * 0.58;
|
|
const int32_t actionOffset = widgets[WIDX_STAFF_LIST_LIST].right - actionColumnSize - 15;
|
|
|
|
auto y = 0;
|
|
size_t i = 0;
|
|
for (auto spriteIndex : _staffList)
|
|
{
|
|
if (y > dpi.y + dpi.height)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (y + 11 >= dpi.y)
|
|
{
|
|
auto peep = GetEntity<Staff>(spriteIndex);
|
|
if (peep == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
int32_t format = (_quickFireMode ? STR_RED_STRINGID : STR_BLACK_STRING);
|
|
|
|
if (i == _highlightedIndex)
|
|
{
|
|
gfx_filter_rect(&dpi, { 0, y, 800, y + (SCROLLABLE_ROW_HEIGHT - 1) }, FilterPaletteID::PaletteDarken1);
|
|
format = (_quickFireMode ? STR_LIGHTPINK_STRINGID : STR_WINDOW_COLOUR_2_STRINGID);
|
|
}
|
|
|
|
auto ft = Formatter();
|
|
peep->FormatNameTo(ft);
|
|
DrawTextEllipsised(&dpi, { 0, y }, nameColumnSize, format, ft);
|
|
|
|
ft = Formatter();
|
|
peep->FormatActionTo(ft);
|
|
DrawTextEllipsised(&dpi, { actionOffset, y }, actionColumnSize, format, ft);
|
|
|
|
// True if a patrol path is set for the worker
|
|
if (peep->HasPatrolArea())
|
|
{
|
|
gfx_draw_sprite(&dpi, ImageId(SPR_STAFF_PATROL_PATH), { nameColumnSize + 5, y });
|
|
}
|
|
|
|
auto staffOrderIcon_x = nameColumnSize + 20;
|
|
if (peep->AssignedStaffType != StaffType::Entertainer)
|
|
{
|
|
auto staffOrders = peep->StaffOrders;
|
|
auto staffOrderSprite = GetStaffOrderBaseSprite(GetSelectedStaffType());
|
|
|
|
while (staffOrders != 0)
|
|
{
|
|
if (staffOrders & 1)
|
|
{
|
|
gfx_draw_sprite(&dpi, ImageId(staffOrderSprite), { staffOrderIcon_x, y });
|
|
}
|
|
staffOrders = staffOrders >> 1;
|
|
staffOrderIcon_x += 9;
|
|
// TODO: Remove sprite ID addition
|
|
staffOrderSprite++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gfx_draw_sprite(&dpi, ImageId(GetEntertainerCostumeSprite(peep->SpriteType)), { staffOrderIcon_x, y });
|
|
}
|
|
}
|
|
|
|
y += SCROLLABLE_ROW_HEIGHT;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void OnToolDown(rct_widgetindex widgetIndex, const ScreenCoordsXY& screenCoords) override
|
|
{
|
|
if (widgetIndex == WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON)
|
|
{
|
|
auto closestStaffMember = GetClosestStaffMemberTo(screenCoords);
|
|
if (closestStaffMember != nullptr)
|
|
{
|
|
tool_cancel();
|
|
auto* staffWindow = WindowStaffOpen(closestStaffMember);
|
|
window_event_dropdown_call(staffWindow, WC_PEEP__WIDX_PATROL, 0);
|
|
}
|
|
else
|
|
{
|
|
auto ft = Formatter();
|
|
ft.Add<rct_string_id>(GetStaffNamingConvention(GetSelectedStaffType()).Plural);
|
|
context_show_error(STR_NO_THING_IN_PARK_YET, STR_NONE, ft);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnToolAbort(rct_widgetindex widgetIndex) override
|
|
{
|
|
if (widgetIndex == WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON)
|
|
{
|
|
hide_gridlines();
|
|
tool_cancel();
|
|
ClearPatrolAreaToRender();
|
|
gfx_invalidate_screen();
|
|
}
|
|
}
|
|
|
|
void RefreshList()
|
|
{
|
|
_staffList.clear();
|
|
|
|
for (auto peep : EntityList<Staff>())
|
|
{
|
|
EntitySetFlashing(peep, false);
|
|
if (peep->AssignedStaffType == GetSelectedStaffType())
|
|
{
|
|
EntitySetFlashing(peep, true);
|
|
_staffList.push_back(peep->sprite_index);
|
|
}
|
|
}
|
|
|
|
std::sort(_staffList.begin(), _staffList.end(), [](const auto a, const auto b) { return peep_compare(a, b) < 0; });
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* Hires a new staff member of the given type.
|
|
*/
|
|
void HireNewMember(StaffType staffType, EntertainerCostume entertainerType)
|
|
{
|
|
bool autoPosition = gConfigGeneral.auto_staff_placement;
|
|
if (gInputPlaceObjectModifier & PLACE_OBJECT_MODIFIER_SHIFT_Z)
|
|
{
|
|
autoPosition = autoPosition ^ 1;
|
|
}
|
|
|
|
uint32_t staffOrders = 0;
|
|
|
|
if (staffType == StaffType::Handyman)
|
|
{
|
|
staffOrders = STAFF_ORDERS_SWEEPING | STAFF_ORDERS_WATER_FLOWERS | STAFF_ORDERS_EMPTY_BINS;
|
|
if (gConfigGeneral.handymen_mow_default)
|
|
{
|
|
staffOrders |= STAFF_ORDERS_MOWING;
|
|
}
|
|
}
|
|
else if (staffType == StaffType::Mechanic)
|
|
{
|
|
staffOrders = STAFF_ORDERS_INSPECT_RIDES | STAFF_ORDERS_FIX_RIDES;
|
|
}
|
|
|
|
auto hireStaffAction = StaffHireNewAction(autoPosition, staffType, entertainerType, staffOrders);
|
|
hireStaffAction.SetCallback([=](const GameAction*, const GameActions::Result* res) -> void {
|
|
if (res->Error != GameActions::Status::Ok)
|
|
return;
|
|
|
|
auto actionResult = res->GetData<StaffHireNewActionResult>();
|
|
// Open window for new staff.
|
|
auto* staff = GetEntity<Staff>(actionResult.StaffEntityId);
|
|
auto intent = Intent(WC_PEEP);
|
|
intent.putExtra(INTENT_EXTRA_PEEP, staff);
|
|
context_open_intent(&intent);
|
|
});
|
|
|
|
GameActions::Execute(&hireStaffAction);
|
|
}
|
|
|
|
StaffType GetSelectedStaffType() const
|
|
{
|
|
return static_cast<StaffType>(_selectedTab);
|
|
}
|
|
|
|
void DrawTabImages(rct_drawpixelinfo& dpi) const
|
|
{
|
|
DrawTabImage(dpi, WINDOW_STAFF_LIST_TAB_HANDYMEN, PeepSpriteType::Handyman, gStaffHandymanColour);
|
|
DrawTabImage(dpi, WINDOW_STAFF_LIST_TAB_MECHANICS, PeepSpriteType::Mechanic, gStaffMechanicColour);
|
|
DrawTabImage(dpi, WINDOW_STAFF_LIST_TAB_SECURITY, PeepSpriteType::Security, gStaffSecurityColour);
|
|
DrawTabImage(dpi, WINDOW_STAFF_LIST_TAB_ENTERTAINERS, PeepSpriteType::EntertainerElephant);
|
|
}
|
|
|
|
void DrawTabImage(rct_drawpixelinfo& dpi, int32_t tabIndex, PeepSpriteType type, colour_t colour) const
|
|
{
|
|
auto widgetIndex = WIDX_STAFF_LIST_HANDYMEN_TAB + tabIndex;
|
|
const auto& widget = widgets[widgetIndex];
|
|
auto imageId = (_selectedTab == tabIndex ? (_tabAnimationIndex & ~3) : 0);
|
|
imageId += GetPeepAnimation(type).base_image + 1;
|
|
gfx_draw_sprite(
|
|
&dpi, ImageId(imageId, colour), windowPos + ScreenCoordsXY{ (widget.left + widget.right) / 2, widget.bottom - 6 });
|
|
}
|
|
|
|
void DrawTabImage(rct_drawpixelinfo& dpi, int32_t tabIndex, PeepSpriteType type) const
|
|
{
|
|
auto widgetIndex = WIDX_STAFF_LIST_HANDYMEN_TAB + tabIndex;
|
|
const auto& widget = widgets[widgetIndex];
|
|
rct_drawpixelinfo clippedDpi;
|
|
if (clip_drawpixelinfo(
|
|
&clippedDpi, &dpi, windowPos + ScreenCoordsXY{ widget.left + 1, widget.top + 1 },
|
|
widget.right - widget.left - 1, widget.bottom - widget.top - 1))
|
|
{
|
|
auto imageId = (_selectedTab == 3 ? (_tabAnimationIndex & ~3) : 0);
|
|
imageId += GetPeepAnimation(type).base_image + 1;
|
|
gfx_draw_sprite(&clippedDpi, ImageId(imageId), { 15, 23 });
|
|
}
|
|
}
|
|
|
|
void CancelTools()
|
|
{
|
|
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
|
|
{
|
|
if (classification == gCurrentToolWidget.window_classification && number == gCurrentToolWidget.window_number)
|
|
{
|
|
tool_cancel();
|
|
}
|
|
}
|
|
}
|
|
|
|
Peep* GetClosestStaffMemberTo(const ScreenCoordsXY& screenCoords)
|
|
{
|
|
int32_t direction{};
|
|
TileElement* tileElement{};
|
|
auto footpathCoords = footpath_get_coordinates_from_pos(screenCoords, &direction, &tileElement);
|
|
if (footpathCoords.IsNull())
|
|
return nullptr;
|
|
|
|
auto isPatrolAreaSet = IsPatrolAreaSetForStaffType(GetSelectedStaffType(), footpathCoords);
|
|
|
|
Peep* closestPeep = nullptr;
|
|
auto closestPeepDistance = std::numeric_limits<int32_t>::max();
|
|
for (auto peep : EntityList<Staff>())
|
|
{
|
|
if (peep->AssignedStaffType != GetSelectedStaffType())
|
|
continue;
|
|
|
|
if (isPatrolAreaSet)
|
|
{
|
|
if (!peep->HasPatrolArea())
|
|
{
|
|
continue;
|
|
}
|
|
if (!peep->IsLocationInPatrol(footpathCoords))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (peep->x == LOCATION_NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto distance = std::abs(footpathCoords.x - peep->x) + std::abs(footpathCoords.y - peep->y);
|
|
if (distance < closestPeepDistance)
|
|
{
|
|
closestPeepDistance = distance;
|
|
closestPeep = peep;
|
|
}
|
|
}
|
|
return closestPeep;
|
|
}
|
|
|
|
static EntertainerCostume GetRandomEntertainerCostume()
|
|
{
|
|
auto result = EntertainerCostume::Panda;
|
|
EntertainerCostume costumeList[static_cast<uint8_t>(EntertainerCostume::Count)];
|
|
int32_t numCostumes = staff_get_available_entertainer_costume_list(costumeList);
|
|
if (numCostumes > 0)
|
|
{
|
|
int32_t index = util_rand() % numCostumes;
|
|
result = costumeList[index];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static constexpr StaffNamingConvention GetStaffNamingConvention(StaffType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
default:
|
|
case StaffType::Handyman:
|
|
return { STR_HANDYMAN_PLURAL, STR_HANDYMAN_SINGULAR, STR_HIRE_HANDYMAN };
|
|
case StaffType::Mechanic:
|
|
return { STR_MECHANIC_PLURAL, STR_MECHANIC_SINGULAR, STR_HIRE_MECHANIC };
|
|
case StaffType::Security:
|
|
return { STR_SECURITY_GUARD_PLURAL, STR_SECURITY_GUARD_SINGULAR, STR_HIRE_SECURITY_GUARD };
|
|
case StaffType::Entertainer:
|
|
return { STR_ENTERTAINER_PLURAL, STR_ENTERTAINER_SINGULAR, STR_HIRE_ENTERTAINER };
|
|
}
|
|
}
|
|
|
|
static uint32_t GetStaffOrderBaseSprite(StaffType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case StaffType::Handyman:
|
|
return SPR_STAFF_ORDERS_SWEEPING;
|
|
case StaffType::Mechanic:
|
|
return SPR_STAFF_ORDERS_INSPECT_RIDES;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static uint32_t GetEntertainerCostumeSprite(PeepSpriteType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
default:
|
|
case PeepSpriteType::EntertainerPanda:
|
|
return SPR_STAFF_COSTUME_PANDA;
|
|
case PeepSpriteType::EntertainerTiger:
|
|
return SPR_STAFF_COSTUME_TIGER;
|
|
case PeepSpriteType::EntertainerElephant:
|
|
return SPR_STAFF_COSTUME_ELEPHANT;
|
|
case PeepSpriteType::EntertainerRoman:
|
|
return SPR_STAFF_COSTUME_ROMAN;
|
|
case PeepSpriteType::EntertainerGorilla:
|
|
return SPR_STAFF_COSTUME_GORILLA;
|
|
case PeepSpriteType::EntertainerSnowman:
|
|
return SPR_STAFF_COSTUME_SNOWMAN;
|
|
case PeepSpriteType::EntertainerKnight:
|
|
return SPR_STAFF_COSTUME_KNIGHT;
|
|
case PeepSpriteType::EntertainerAstronaut:
|
|
return SPR_STAFF_COSTUME_ASTRONAUT;
|
|
case PeepSpriteType::EntertainerBandit:
|
|
return SPR_STAFF_COSTUME_BANDIT;
|
|
case PeepSpriteType::EntertainerSheriff:
|
|
return SPR_STAFF_COSTUME_SHERIFF;
|
|
case PeepSpriteType::EntertainerPirate:
|
|
return SPR_STAFF_COSTUME_PIRATE;
|
|
}
|
|
}
|
|
};
|
|
|
|
rct_window* WindowStaffListOpen()
|
|
{
|
|
return WindowFocusOrCreate<StaffListWindow>(WC_STAFF_LIST, WW, WH, WF_10 | WF_RESIZABLE);
|
|
}
|
|
|
|
void WindowStaffListRefresh()
|
|
{
|
|
auto* window = window_find_by_class(WC_STAFF_LIST);
|
|
if (window != nullptr)
|
|
{
|
|
static_cast<StaffListWindow*>(window)->RefreshList();
|
|
}
|
|
}
|