2016-05-04 19:24:41 +02:00
/*****************************************************************************
2024-01-01 12:52:28 +01:00
* Copyright ( c ) 2014 - 2024 OpenRCT2 developers
2016-05-04 19:24:41 +02:00
*
2018-06-15 14:07:34 +02:00
* For a complete list of all authors , please refer to contributors . md
* Interested in contributing ? Visit https : //github.com/OpenRCT2/OpenRCT2
2016-05-04 19:24:41 +02:00
*
2018-06-15 14:07:34 +02:00
* OpenRCT2 is licensed under the GNU General Public License version 3.
2016-05-04 19:24:41 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-07 20:39:52 +02:00
2017-10-16 00:13:22 +02:00
# include <limits>
2018-06-22 23:21:44 +02:00
# include <openrct2-ui/interface/Dropdown.h>
# include <openrct2-ui/interface/Viewport.h>
# include <openrct2-ui/interface/Widget.h>
2017-08-12 23:06:12 +02:00
# include <openrct2-ui/windows/Window.h>
2017-09-06 16:09:35 +02:00
# include <openrct2/Context.h>
2017-11-30 18:17:06 +01:00
# include <openrct2/Game.h>
2024-01-22 16:03:39 +01:00
# include <openrct2/GameState.h>
2017-12-12 14:52:57 +01:00
# include <openrct2/Input.h>
2023-01-27 09:20:59 +01:00
# include <openrct2/actions/PeepPickupAction.h>
Split actions hpp files into separate h and cpp files (#13548)
* Split up SmallSceneryPlace/Remove
Added undo function for Remove Scenery
* Refactor: Balloon and Banner actions hpp=>h/cpp
* Refactor: rename all action *.hpp files to *.cpp
This is preparation for separation in later commits. Note that without
the complete set of commits in this branch, the code will not build.
* Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp
* VSCode: add src subdirectories to includePath
* Refactor Guest actions hpp=>h/cpp
* Refactor Land actions hpp=>h/cpp
* Refactor LargeScenery actions hpp=>h/cpp
* Refactor Load, Maze, Network actions hpp=>h/cpp
* Refactor Park actions hpp=>h/cpp
* Refactor/style: move private function declarations in actions *.h
Previous action .h files included private function declarations with
private member variables, before public function declarations. This
commit re-orders the header files to the following order:
- public member variables
- private member variables
- public functions
- private functions
* Refactor Pause action hpp=>h/cpp
* Refactor Peep, Place, Player actions hpp=>h/cpp
* Refactor Ride actions hpp=>h/cpp
* Refactor Scenario, Set*, Sign* actions hpp=>h/cpp
* Refactor SmallScenerySetColourAction hpp=>h/cpp
* Refactor Staff actions hpp=>h/cpp
* Refactor Surface, Tile, Track* actions hpp=>h/cpp
* Refactor Wall and Water actions hpp=>h/cpp
* Fix various includes and other compile errors
Update includes for tests.
Move static function declarations to .h files
Add explicit includes to various files that were previously implicit
(the required header was a nested include in an action hpp file, and the
action .h file does not include that header)
Move RideSetStatus string enum to the cpp file to avoid unused imports
* Xcode: modify project file for actions refactor
* Cleanup whitespace and end-of-file newlines
Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-12-10 07:39:10 +01:00
# include <openrct2/actions/StaffFireAction.h>
2021-12-03 16:37:39 +01:00
# include <openrct2/actions/StaffHireNewAction.h>
Split actions hpp files into separate h and cpp files (#13548)
* Split up SmallSceneryPlace/Remove
Added undo function for Remove Scenery
* Refactor: Balloon and Banner actions hpp=>h/cpp
* Refactor: rename all action *.hpp files to *.cpp
This is preparation for separation in later commits. Note that without
the complete set of commits in this branch, the code will not build.
* Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp
* VSCode: add src subdirectories to includePath
* Refactor Guest actions hpp=>h/cpp
* Refactor Land actions hpp=>h/cpp
* Refactor LargeScenery actions hpp=>h/cpp
* Refactor Load, Maze, Network actions hpp=>h/cpp
* Refactor Park actions hpp=>h/cpp
* Refactor/style: move private function declarations in actions *.h
Previous action .h files included private function declarations with
private member variables, before public function declarations. This
commit re-orders the header files to the following order:
- public member variables
- private member variables
- public functions
- private functions
* Refactor Pause action hpp=>h/cpp
* Refactor Peep, Place, Player actions hpp=>h/cpp
* Refactor Ride actions hpp=>h/cpp
* Refactor Scenario, Set*, Sign* actions hpp=>h/cpp
* Refactor SmallScenerySetColourAction hpp=>h/cpp
* Refactor Staff actions hpp=>h/cpp
* Refactor Surface, Tile, Track* actions hpp=>h/cpp
* Refactor Wall and Water actions hpp=>h/cpp
* Fix various includes and other compile errors
Update includes for tests.
Move static function declarations to .h files
Add explicit includes to various files that were previously implicit
(the required header was a nested include in an action hpp file, and the
action .h file does not include that header)
Move RideSetStatus string enum to the cpp file to avoid unused imports
* Xcode: modify project file for actions refactor
* Cleanup whitespace and end-of-file newlines
Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-12-10 07:39:10 +01:00
# include <openrct2/actions/StaffSetColourAction.h>
2018-06-22 23:21:44 +02:00
# include <openrct2/config/Config.h>
# include <openrct2/drawing/Drawing.h>
2021-11-24 15:48:33 +01:00
# include <openrct2/entity/EntityList.h>
2021-11-24 15:58:01 +01:00
# include <openrct2/entity/EntityRegistry.h>
2022-03-08 01:14:52 +01:00
# include <openrct2/entity/PatrolArea.h>
2021-11-25 22:47:24 +01:00
# include <openrct2/entity/Staff.h>
2021-12-12 00:06:06 +01:00
# include <openrct2/localisation/Formatter.h>
2018-01-06 18:32:25 +01:00
# include <openrct2/localisation/Localisation.h>
2018-06-22 23:21:44 +02:00
# include <openrct2/management/Finance.h>
2024-04-14 16:51:54 +02:00
# include <openrct2/peep/PeepAnimationData.h>
2017-09-18 17:05:28 +02:00
# include <openrct2/sprites.h>
2017-12-13 13:02:24 +01:00
# include <openrct2/util/Util.h>
2018-06-22 23:21:44 +02:00
# include <openrct2/windows/Intent.h>
2018-01-11 10:59:26 +01:00
# include <openrct2/world/Footpath.h>
2018-03-19 23:28:40 +01:00
# include <openrct2/world/Park.h>
2020-03-28 13:12:53 +01:00
# include <vector>
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
namespace OpenRCT2 : : Ui : : Windows
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
enum
{
WINDOW_STAFF_LIST_TAB_HANDYMEN ,
WINDOW_STAFF_LIST_TAB_MECHANICS ,
WINDOW_STAFF_LIST_TAB_SECURITY ,
WINDOW_STAFF_LIST_TAB_ENTERTAINERS
} ;
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
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 ,
} ;
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
static constexpr StringId WINDOW_TITLE = STR_STAFF ;
static constexpr int32_t WW = 320 ;
static constexpr int32_t WH = 270 ;
constexpr int32_t MAX_WW = 500 ;
constexpr int32_t MAX_WH = 450 ;
2016-01-09 11:32:28 +01:00
2024-03-10 14:52:35 +01:00
// clang-format off
2023-07-05 22:49:09 +02:00
static Widget _staffListWidgets [ ] = {
2020-05-09 16:44:21 +02:00
WINDOW_SHIM ( WINDOW_TITLE , WW , WH ) ,
2020-11-27 04:14:20 +01:00
MakeWidget ( { 0 , 43 } , { WW , WH - 43 } , WindowWidgetType : : Resize , WindowColour : : Secondary ) , // tab content panel
2020-08-29 04:31:31 +02:00
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
2020-11-27 04:14:20 +01:00
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
2022-12-24 17:47:22 +01:00
MakeWidget ( { 243 , 46 } , { 24 , 24 } , WindowWidgetType : : FlatBtn , WindowColour : : Secondary , ImageId ( SPR_DEMOLISH ) , STR_QUICK_FIRE_STAFF ) , // quick fire staff
MakeWidget ( { 267 , 46 } , { 24 , 24 } , WindowWidgetType : : FlatBtn , WindowColour : : Secondary , ImageId ( SPR_PATROL_BTN ) , STR_SHOW_PATROL_AREA_TIP ) , // show staff patrol area tool
MakeWidget ( { 291 , 46 } , { 24 , 24 } , WindowWidgetType : : FlatBtn , WindowColour : : Secondary , ImageId ( SPR_MAP ) , STR_SHOW_STAFF_ON_MAP_TIP ) , // show staff on map button
2024-03-09 15:15:45 +01:00
kWidgetsEnd ,
2014-10-07 20:39:52 +02:00
} ;
2024-03-10 14:52:35 +01:00
// clang-format on
2016-07-14 14:07:49 +02:00
2024-03-10 14:52:35 +01:00
class StaffListWindow final : public Window
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
private :
struct StaffNamingConvention
{
StringId Plural ;
StringId Singular ;
StringId ActionHire ;
} ;
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
struct StaffEntry
{
EntityId Id ;
u8string Name ;
} ;
std : : vector < StaffEntry > _staffList ;
bool _quickFireMode { } ;
std : : optional < size_t > _highlightedIndex { } ;
int32_t _selectedTab { } ;
uint32_t _tabAnimationIndex { } ;
public :
void OnOpen ( ) override
{
widgets = _staffListWidgets ;
WindowInitScrollWidgets ( * this ) ;
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
widgets [ WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER ] . type = WindowWidgetType : : Empty ;
min_width = WW ;
min_height = WH ;
max_width = MAX_WW ;
max_height = MAX_WH ;
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
RefreshList ( ) ;
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
void OnClose ( ) override
{
CancelTools ( ) ;
}
2020-06-10 18:54:34 +02:00
2024-03-10 14:52:35 +01:00
void OnMouseUp ( WidgetIndex widgetIndex ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
switch ( widgetIndex )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
case WIDX_STAFF_LIST_CLOSE :
Close ( ) ;
break ;
case WIDX_STAFF_LIST_HIRE_BUTTON :
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto staffType = GetSelectedStaffType ( ) ;
auto costume = EntertainerCostume : : Count ;
if ( staffType = = StaffType : : Entertainer )
{
costume = GetRandomEntertainerCostume ( ) ;
}
HireNewMember ( staffType , costume ) ;
break ;
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
case WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON :
if ( ! ToolSet ( * this , WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON , Tool : : Crosshair ) )
{
ShowGridlines ( ) ;
SetPatrolAreaToRender ( GetSelectedStaffType ( ) ) ;
GfxInvalidateScreen ( ) ;
}
break ;
case WIDX_STAFF_LIST_MAP :
ContextOpenWindow ( WindowClass : : Map ) ;
break ;
case WIDX_STAFF_LIST_QUICK_FIRE :
_quickFireMode = ! _quickFireMode ;
Invalidate ( ) ;
break ;
2021-01-25 22:57:06 +01:00
}
}
2020-03-28 13:12:53 +01:00
2024-03-10 14:52:35 +01:00
void OnResize ( ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
min_width = WW ;
min_height = WH ;
if ( width < min_width )
{
width = min_width ;
Invalidate ( ) ;
}
if ( height < min_height )
{
height = min_height ;
Invalidate ( ) ;
}
ResizeFrameWithPage ( ) ;
2021-01-25 22:57:06 +01:00
}
2020-03-28 13:12:53 +01:00
2024-03-10 14:52:35 +01:00
void OnUpdate ( ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
_tabAnimationIndex + + ;
if ( _tabAnimationIndex > = 24 )
{
_tabAnimationIndex = 0 ;
}
else
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
InvalidateWidget ( WIDX_STAFF_LIST_HANDYMEN_TAB + _selectedTab ) ;
// Enable highlighting of these staff members in map window
if ( WindowFindByClass ( WindowClass : : Map ) ! = nullptr )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
gWindowMapFlashingFlags | = MapFlashingFlags : : StaffListOpen ;
for ( auto peep : EntityList < Staff > ( ) )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
EntitySetFlashing ( peep , false ) ;
if ( peep - > AssignedStaffType = = GetSelectedStaffType ( ) )
{
EntitySetFlashing ( peep , true ) ;
}
2021-01-25 22:57:06 +01:00
}
}
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
// Note this may be slow if number of staff increases a large amount.
// See GuestList for fix (more intents) if required.
RefreshList ( ) ;
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
void OnMouseDown ( WidgetIndex widgetIndex ) override
2017-06-06 23:24:18 +02:00
{
2024-03-10 14:52:35 +01:00
switch ( widgetIndex )
2018-06-22 23:21:44 +02:00
{
2024-03-10 14:52:35 +01:00
case WIDX_STAFF_LIST_HANDYMEN_TAB :
case WIDX_STAFF_LIST_MECHANICS_TAB :
case WIDX_STAFF_LIST_SECURITY_TAB :
case WIDX_STAFF_LIST_ENTERTAINERS_TAB :
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
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 ;
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
case WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER :
WindowDropdownShowColour ( this , & widgets [ widgetIndex ] , colours [ 1 ] , StaffGetColour ( GetSelectedStaffType ( ) ) ) ;
break ;
2018-06-22 23:21:44 +02:00
}
2017-06-06 23:24:18 +02:00
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
void OnDropdown ( WidgetIndex widgetIndex , int32_t dropdownIndex ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( dropdownIndex = = - 1 )
{
return ;
}
if ( widgetIndex = = WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER )
{
auto action = StaffSetColourAction ( GetSelectedStaffType ( ) , ColourDropDownIndexToColour ( dropdownIndex ) ) ;
GameActions : : Execute ( & action ) ;
}
2021-01-25 22:57:06 +01:00
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
void OnPrepareDraw ( ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
// 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 ) ;
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
widgets [ WIDX_STAFF_LIST_HIRE_BUTTON ] . text = GetStaffNamingConvention ( GetSelectedStaffType ( ) ) . ActionHire ;
widgets [ WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER ] . type = WindowWidgetType : : Empty ;
2018-08-13 14:05:52 +02:00
2024-03-10 14:52:35 +01:00
if ( GetSelectedStaffType ( ) ! = StaffType : : Entertainer )
{
widgets [ WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER ] . type = WindowWidgetType : : ColourBtn ;
widgets [ WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER ] . image = GetColourButtonImage (
StaffGetColour ( GetSelectedStaffType ( ) ) ) ;
}
SetWidgetPressed ( WIDX_STAFF_LIST_QUICK_FIRE , _quickFireMode ) ;
ResizeFrameWithPage ( ) ;
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 ;
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
void OnDraw ( DrawPixelInfo & dpi ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
DrawWidgets ( dpi ) ;
DrawTabImages ( dpi ) ;
2021-01-25 22:57:06 +01:00
2024-03-26 21:35:55 +01:00
if ( ! ( GetGameState ( ) . Park . Flags & PARK_FLAGS_NO_MONEY ) )
2024-03-10 14:52:35 +01:00
{
auto ft = Formatter ( ) ;
ft . Add < money64 > ( GetStaffWage ( GetSelectedStaffType ( ) ) ) ;
DrawTextBasic ( dpi , windowPos + ScreenCoordsXY { width - 155 , 32 } , STR_COST_PER_MONTH , ft ) ;
}
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
if ( GetSelectedStaffType ( ) ! = StaffType : : Entertainer )
{
DrawTextBasic (
dpi , windowPos + ScreenCoordsXY { 6 , widgets [ WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER ] . top + 1 } ,
STR_UNIFORM_COLOUR ) ;
}
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
auto namingConvention = GetStaffNamingConvention ( GetSelectedStaffType ( ) ) ;
auto staffTypeStringId = _staffList . size ( ) = = 1 ? namingConvention . Singular : namingConvention . Plural ;
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
auto ft = Formatter ( ) ;
ft . Add < uint32_t > ( _staffList . size ( ) ) ;
ft . Add < StringId > ( staffTypeStringId ) ;
DrawTextBasic (
dpi , windowPos + ScreenCoordsXY { 4 , widgets [ WIDX_STAFF_LIST_LIST ] . bottom + 2 } , STR_STAFF_LIST_COUNTER , ft ) ;
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
ScreenSize OnScrollGetSize ( int32_t scrollIndex ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( _highlightedIndex )
{
_highlightedIndex = { } ;
Invalidate ( ) ;
}
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
auto scrollHeight = static_cast < int32_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 ( ) ;
}
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
auto scrollWidth = widgets [ WIDX_STAFF_LIST_LIST ] . width ( ) - 15 ;
return { scrollWidth , scrollHeight } ;
}
void OnScrollMouseOver ( int32_t scrollIndex , const ScreenCoordsXY & screenCoords ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto i = static_cast < size_t > ( screenCoords . y / SCROLLABLE_ROW_HEIGHT ) ;
if ( i ! = _highlightedIndex )
{
_highlightedIndex = static_cast < size_t > ( i ) ;
Invalidate ( ) ;
}
2021-01-25 22:57:06 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
void OnScrollMouseDown ( int32_t scrollIndex , const ScreenCoordsXY & screenCoords ) override
2018-06-22 23:21:44 +02:00
{
2024-03-10 14:52:35 +01:00
int32_t i = screenCoords . y / SCROLLABLE_ROW_HEIGHT ;
for ( const auto & entry : _staffList )
2018-06-22 23:21:44 +02:00
{
2024-03-10 14:52:35 +01:00
if ( i = = 0 )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( _quickFireMode )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto staffFireAction = StaffFireAction ( entry . Id ) ;
GameActions : : Execute ( & staffFireAction ) ;
}
else
{
auto peep = GetEntity < Staff > ( entry . Id ) ;
if ( peep ! = nullptr )
{
auto intent = Intent ( WindowClass : : Peep ) ;
intent . PutExtra ( INTENT_EXTRA_PEEP , peep ) ;
ContextOpenIntent ( & intent ) ;
}
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
break ;
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
i - - ;
}
2017-06-06 23:24:18 +02:00
}
2020-03-28 13:12:53 +01:00
2024-03-10 14:52:35 +01:00
void OnScrollDraw ( int32_t scrollIndex , DrawPixelInfo & dpi ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto dpiCoords = ScreenCoordsXY { dpi . x , dpi . y } ;
GfxFillRect (
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 ( const auto & entry : _staffList )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( y > dpi . y + dpi . height )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
break ;
2021-01-25 22:57:06 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
if ( y + 11 > = dpi . y )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
const auto * peep = GetEntity < Staff > ( entry . Id ) ;
if ( peep = = nullptr )
{
continue ;
}
int32_t format = ( _quickFireMode ? STR_RED_STRINGID : STR_BLACK_STRING ) ;
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
if ( i = = _highlightedIndex )
{
GfxFilterRect ( dpi , { 0 , y , 800 , y + ( SCROLLABLE_ROW_HEIGHT - 1 ) } , FilterPaletteID : : PaletteDarken1 ) ;
format = ( _quickFireMode ? STR_LIGHTPINK_STRINGID : STR_WINDOW_COLOUR_2_STRINGID ) ;
}
2020-06-10 18:54:34 +02:00
2024-03-10 14:52:35 +01:00
auto ft = Formatter ( ) ;
peep - > FormatNameTo ( ft ) ;
DrawTextEllipsised ( dpi , { 0 , y } , nameColumnSize , format , ft ) ;
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
ft = Formatter ( ) ;
peep - > FormatActionTo ( ft ) ;
DrawTextEllipsised ( dpi , { actionOffset , y } , actionColumnSize , format , ft ) ;
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
// True if a patrol path is set for the worker
if ( peep - > HasPatrolArea ( ) )
{
GfxDrawSprite ( dpi , ImageId ( SPR_STAFF_PATROL_PATH ) , { nameColumnSize + 5 , y } ) ;
}
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
auto staffOrderIcon_x = nameColumnSize + 20 ;
if ( peep - > AssignedStaffType ! = StaffType : : Entertainer )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto staffOrders = peep - > StaffOrders ;
auto staffOrderSprite = GetStaffOrderBaseSprite ( GetSelectedStaffType ( ) ) ;
while ( staffOrders ! = 0 )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( staffOrders & 1 )
{
GfxDrawSprite ( dpi , ImageId ( staffOrderSprite ) , { staffOrderIcon_x , y } ) ;
}
staffOrders = staffOrders > > 1 ;
staffOrderIcon_x + = 9 ;
// TODO: Remove sprite ID addition
staffOrderSprite + + ;
2021-01-25 22:57:06 +01:00
}
}
2024-03-10 14:52:35 +01:00
else
{
GfxDrawSprite ( dpi , ImageId ( GetEntertainerCostumeSprite ( peep - > SpriteType ) ) , { staffOrderIcon_x , y } ) ;
}
}
y + = SCROLLABLE_ROW_HEIGHT ;
i + + ;
}
}
void OnToolDown ( WidgetIndex widgetIndex , const ScreenCoordsXY & screenCoords ) override
{
if ( widgetIndex = = WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON )
{
auto closestStaffMember = GetClosestStaffMemberTo ( screenCoords ) ;
if ( closestStaffMember ! = nullptr )
{
ToolCancel ( ) ;
2024-03-17 07:37:46 +01:00
auto * staffWindow = StaffOpen ( closestStaffMember ) ;
2024-03-10 14:52:35 +01:00
staffWindow - > OnDropdown ( WC_PEEP__WIDX_PATROL , 0 ) ;
2021-01-25 22:57:06 +01:00
}
else
{
2024-03-10 14:52:35 +01:00
auto ft = Formatter ( ) ;
ft . Add < StringId > ( GetStaffNamingConvention ( GetSelectedStaffType ( ) ) . Plural ) ;
ContextShowError ( STR_NO_THING_IN_PARK_YET , STR_NONE , ft ) ;
2017-06-06 23:24:18 +02:00
}
}
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
void OnToolAbort ( WidgetIndex widgetIndex ) override
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
if ( widgetIndex = = WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON )
2018-06-22 23:21:44 +02:00
{
2024-03-10 14:52:35 +01:00
HideGridlines ( ) ;
2023-01-16 21:13:42 +01:00
ToolCancel ( ) ;
2024-03-10 14:52:35 +01:00
ClearPatrolAreaToRender ( ) ;
GfxInvalidateScreen ( ) ;
2017-06-06 23:24:18 +02:00
}
}
2024-03-10 14:52:35 +01:00
void RefreshList ( )
2018-06-22 23:21:44 +02:00
{
2024-03-10 14:52:35 +01:00
_staffList . clear ( ) ;
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
for ( auto * peep : EntityList < Staff > ( ) )
2019-03-16 21:45:52 +01:00
{
2024-03-10 14:52:35 +01:00
EntitySetFlashing ( peep , false ) ;
if ( peep - > AssignedStaffType = = GetSelectedStaffType ( ) )
{
EntitySetFlashing ( peep , true ) ;
2023-02-28 05:11:45 +01:00
2024-03-10 14:52:35 +01:00
StaffEntry entry ;
entry . Id = peep - > Id ;
entry . Name = peep - > GetName ( ) ;
2023-02-28 05:11:45 +01:00
2024-03-10 14:52:35 +01:00
_staffList . push_back ( std : : move ( entry ) ) ;
}
2019-03-16 21:45:52 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
std : : sort ( _staffList . begin ( ) , _staffList . end ( ) , [ ] ( const auto & a , const auto & b ) {
return StrLogicalCmp ( a . Name . c_str ( ) , b . Name . c_str ( ) ) < 0 ;
} ) ;
2021-12-03 16:37:39 +01:00
}
2024-03-10 14:52:35 +01:00
private :
/**
* Hires a new staff member of the given type .
*/
void HireNewMember ( StaffType staffType , EntertainerCostume entertainerType )
2021-12-03 16:37:39 +01:00
{
2024-03-10 14:52:35 +01:00
bool autoPosition = gConfigGeneral . AutoStaffPlacement ;
if ( gInputPlaceObjectModifier & PLACE_OBJECT_MODIFIER_SHIFT_Z )
2021-12-03 16:37:39 +01:00
{
2024-03-10 14:52:35 +01:00
autoPosition = autoPosition ^ 1 ;
2021-12-03 16:37:39 +01:00
}
2024-03-10 14:52:35 +01:00
uint32_t staffOrders = 0 ;
2023-01-27 09:20:59 +01:00
2024-03-10 14:52:35 +01:00
if ( staffType = = StaffType : : Handyman )
2023-01-27 09:20:59 +01:00
{
2024-03-10 14:52:35 +01:00
staffOrders = STAFF_ORDERS_SWEEPING | STAFF_ORDERS_WATER_FLOWERS | STAFF_ORDERS_EMPTY_BINS ;
if ( gConfigGeneral . HandymenMowByDefault )
{
staffOrders | = STAFF_ORDERS_MOWING ;
}
2023-01-27 09:20:59 +01:00
}
2024-03-10 14:52:35 +01:00
else if ( staffType = = StaffType : : Mechanic )
2023-01-27 09:20:59 +01:00
{
2024-03-10 14:52:35 +01:00
staffOrders = STAFF_ORDERS_INSPECT_RIDES | STAFF_ORDERS_FIX_RIDES ;
2023-01-27 09:20:59 +01:00
}
2021-12-03 16:37:39 +01:00
2024-03-10 14:52:35 +01:00
auto hireStaffAction = StaffHireNewAction ( autoPosition , staffType , entertainerType , staffOrders ) ;
hireStaffAction . SetCallback ( [ = ] ( const GameAction * , const GameActions : : Result * res ) - > void {
if ( res - > Error ! = GameActions : : Status : : Ok )
return ;
2021-12-03 16:37:39 +01:00
2024-03-10 14:52:35 +01:00
auto actionResult = res - > GetData < StaffHireNewActionResult > ( ) ;
auto * staff = GetEntity < Staff > ( actionResult . StaffEntityId ) ;
if ( staff = = nullptr )
return ;
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
// If autoposition of staff is disabled, pickup peep and then open the staff window
if ( staff - > State = = PeepState : : Picked )
{
CoordsXYZ nullLoc { } ;
nullLoc . SetNull ( ) ;
2014-10-07 20:39:52 +02:00
2024-03-10 14:52:35 +01:00
PeepPickupAction pickupAction { PeepPickupType : : Pickup , staff - > Id , nullLoc , NetworkGetCurrentPlayerId ( ) } ;
pickupAction . SetCallback ( [ staffId = staff - > Id ] ( const GameAction * ga , const GameActions : : Result * result ) {
if ( result - > Error ! = GameActions : : Status : : Ok )
return ;
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
auto * staff2 = GetEntity < Staff > ( staffId ) ;
auto intent = Intent ( WindowClass : : Peep ) ;
intent . PutExtra ( INTENT_EXTRA_PEEP , staff2 ) ;
auto * wind = ContextOpenIntent ( & intent ) ;
if ( wind ! = nullptr )
{
ToolSet ( * wind , WC_STAFF__WIDX_PICKUP , Tool : : Picker ) ;
}
} ) ;
GameActions : : Execute ( & pickupAction ) ;
}
else
{
// Open window for new staff.
auto intent = Intent ( WindowClass : : Peep ) ;
intent . PutExtra ( INTENT_EXTRA_PEEP , staff ) ;
ContextOpenIntent ( & intent ) ;
}
} ) ;
GameActions : : Execute ( & hireStaffAction ) ;
}
StaffType GetSelectedStaffType ( ) const
{
return static_cast < StaffType > ( _selectedTab ) ;
}
void DrawTabImages ( DrawPixelInfo & dpi ) const
{
const auto & gameState = GetGameState ( ) ;
DrawTabImage ( dpi , WINDOW_STAFF_LIST_TAB_HANDYMEN , PeepSpriteType : : Handyman , gameState . StaffHandymanColour ) ;
DrawTabImage ( dpi , WINDOW_STAFF_LIST_TAB_MECHANICS , PeepSpriteType : : Mechanic , gameState . StaffMechanicColour ) ;
DrawTabImage ( dpi , WINDOW_STAFF_LIST_TAB_SECURITY , PeepSpriteType : : Security , gameState . StaffSecurityColour ) ;
DrawTabImage ( dpi , WINDOW_STAFF_LIST_TAB_ENTERTAINERS , PeepSpriteType : : EntertainerElephant ) ;
}
void DrawTabImage ( DrawPixelInfo & dpi , int32_t tabIndex , PeepSpriteType type , colour_t colour ) const
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto widgetIndex = WIDX_STAFF_LIST_HANDYMEN_TAB + tabIndex ;
const auto & widget = widgets [ widgetIndex ] ;
auto imageId = ( _selectedTab = = tabIndex ? ( _tabAnimationIndex & ~ 3 ) : 0 ) ;
2021-01-25 22:57:06 +01:00
imageId + = GetPeepAnimation ( type ) . base_image + 1 ;
2024-03-10 14:52:35 +01:00
GfxDrawSprite (
dpi , ImageId ( imageId , colour ) ,
windowPos + ScreenCoordsXY { ( widget . left + widget . right ) / 2 , widget . bottom - 6 } ) ;
2021-01-25 22:57:06 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
void DrawTabImage ( DrawPixelInfo & dpi , int32_t tabIndex , PeepSpriteType type ) const
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto widgetIndex = WIDX_STAFF_LIST_HANDYMEN_TAB + tabIndex ;
const auto & widget = widgets [ widgetIndex ] ;
DrawPixelInfo clippedDpi ;
if ( ClipDrawPixelInfo (
clippedDpi , dpi , windowPos + ScreenCoordsXY { widget . left + 1 , widget . top + 1 } ,
widget . right - widget . left - 1 , widget . bottom - widget . top - 1 ) )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto imageId = ( _selectedTab = = 3 ? ( _tabAnimationIndex & ~ 3 ) : 0 ) ;
imageId + = GetPeepAnimation ( type ) . base_image + 1 ;
GfxDrawSprite ( clippedDpi , ImageId ( imageId ) , { 15 , 23 } ) ;
2021-01-25 22:57:06 +01:00
}
}
2016-07-28 23:21:01 +02:00
2024-03-10 14:52:35 +01:00
void CancelTools ( )
{
if ( InputTestFlag ( INPUT_FLAG_TOOL_ACTIVE ) )
{
if ( classification = = gCurrentToolWidget . window_classification & & number = = gCurrentToolWidget . window_number )
{
ToolCancel ( ) ;
}
}
}
2016-07-28 23:21:01 +02:00
2024-03-10 14:52:35 +01:00
Peep * GetClosestStaffMemberTo ( const ScreenCoordsXY & screenCoords )
2018-06-02 13:06:38 +02:00
{
2024-03-10 14:52:35 +01:00
int32_t direction { } ;
TileElement * tileElement { } ;
auto footpathCoords = FootpathGetCoordinatesFromPos ( screenCoords , & direction , & tileElement ) ;
if ( footpathCoords . IsNull ( ) )
return nullptr ;
auto isPatrolAreaSet = IsPatrolAreaSetForStaffType ( GetSelectedStaffType ( ) , footpathCoords ) ;
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
Peep * closestPeep = nullptr ;
auto closestPeepDistance = std : : numeric_limits < int32_t > : : max ( ) ;
for ( auto peep : EntityList < Staff > ( ) )
2020-07-26 18:42:02 +02:00
{
2024-03-10 14:52:35 +01:00
if ( peep - > AssignedStaffType ! = GetSelectedStaffType ( ) )
2021-01-25 22:57:06 +01:00
continue ;
2024-03-10 14:52:35 +01:00
if ( isPatrolAreaSet )
{
if ( ! peep - > HasPatrolArea ( ) )
{
continue ;
}
if ( ! peep - > IsLocationInPatrol ( footpathCoords ) )
{
continue ;
}
2021-01-25 22:57:06 +01:00
}
2024-03-10 14:52:35 +01:00
if ( peep - > x = = LOCATION_NULL )
2021-01-25 22:57:06 +01:00
{
continue ;
}
2024-03-10 14:52:35 +01:00
auto distance = std : : abs ( footpathCoords . x - peep - > x ) + std : : abs ( footpathCoords . y - peep - > y ) ;
if ( distance < closestPeepDistance )
{
closestPeepDistance = distance ;
closestPeep = peep ;
}
2020-07-26 18:42:02 +02:00
}
2024-03-10 14:52:35 +01:00
return closestPeep ;
}
2020-03-29 23:00:28 +02:00
2024-03-10 14:52:35 +01:00
static EntertainerCostume GetRandomEntertainerCostume ( )
{
auto result = EntertainerCostume : : Panda ;
EntertainerCostume costumeList [ EnumValue ( EntertainerCostume : : Count ) ] ;
int32_t numCostumes = StaffGetAvailableEntertainerCostumeList ( costumeList ) ;
if ( numCostumes > 0 )
2018-06-02 13:06:38 +02:00
{
2024-03-10 14:52:35 +01:00
int32_t index = UtilRand ( ) % numCostumes ;
result = costumeList [ index ] ;
2020-03-29 23:00:28 +02:00
}
2024-03-10 14:52:35 +01:00
return result ;
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
static constexpr StaffNamingConvention GetStaffNamingConvention ( StaffType type )
{
switch ( type )
2020-03-29 23:00:28 +02:00
{
2024-03-10 14:52:35 +01:00
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 } ;
2020-03-29 23:00:28 +02:00
}
2021-01-25 22:57:06 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
static uint32_t GetStaffOrderBaseSprite ( StaffType type )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
switch ( type )
{
case StaffType : : Handyman :
return SPR_STAFF_ORDERS_SWEEPING ;
case StaffType : : Mechanic :
return SPR_STAFF_ORDERS_INSPECT_RIDES ;
default :
return 0 ;
}
2021-01-25 22:57:06 +01:00
}
2017-06-06 23:24:18 +02:00
2024-03-10 14:52:35 +01:00
static uint32_t GetEntertainerCostumeSprite ( PeepSpriteType type )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
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 ;
}
2017-06-06 23:24:18 +02:00
}
2024-03-10 14:52:35 +01:00
} ;
2020-03-29 23:00:28 +02:00
2024-03-17 07:37:46 +01:00
WindowBase * StaffListOpen ( )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
return WindowFocusOrCreate < StaffListWindow > ( WindowClass : : StaffList , WW , WH , WF_10 | WF_RESIZABLE ) ;
2017-06-06 23:24:18 +02:00
}
2021-01-25 22:57:06 +01:00
2024-03-10 14:52:35 +01:00
void WindowStaffListRefresh ( )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
auto * window = WindowFindByClass ( WindowClass : : StaffList ) ;
if ( window ! = nullptr )
2021-01-25 22:57:06 +01:00
{
2024-03-10 14:52:35 +01:00
static_cast < StaffListWindow * > ( window ) - > RefreshList ( ) ;
2021-01-25 22:57:06 +01:00
}
}
2024-03-10 14:52:35 +01:00
} // namespace OpenRCT2::Ui::Windows