diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index d969fcb494..f6d945f719 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -206,13 +206,17 @@ static void window_staff_list_mouseup(rct_window* w, rct_widgetindex widgetIndex break; case WIDX_STAFF_LIST_HIRE_BUTTON: { - int32_t staffType = _windowStaffListSelectedTab; + STAFF_TYPE staffType = static_cast(_windowStaffListSelectedTab); if (staffType == STAFF_TYPE_ENTERTAINER) { - uint8_t costume = window_staff_list_get_random_entertainer_costume(); - staffType += costume; + ENTERTAINER_COSTUME costume = static_cast( + window_staff_list_get_random_entertainer_costume()); + staff_hire_new_member(staffType, costume); + } + else + { + staff_hire_new_member(staffType, ENTERTAINER_COSTUME::ENTERTAINER_COSTUME_COUNT); } - hire_new_staff_member(staffType); break; } case WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON: diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 7a46e8b733..8606a50b59 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -94,7 +94,7 @@ static GAME_COMMAND_CALLBACK_POINTER * const game_command_callback_table[] = { nullptr, game_command_callback_place_banner, nullptr, - game_command_callback_hire_new_staff_member, + nullptr, game_command_callback_pickup_guest, game_command_callback_pickup_staff }; @@ -1290,7 +1290,7 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_raise_water, game_command_lower_water, game_command_set_brakes_speed, - game_command_hire_new_staff_member, + nullptr, game_command_set_staff_patrol, game_command_fire_staff_member, nullptr, diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 99961ed78e..bd4e54c6fc 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -48,7 +48,7 @@ enum GAME_COMMAND GAME_COMMAND_RAISE_WATER, GAME_COMMAND_LOWER_WATER, GAME_COMMAND_SET_BRAKES_SPEED, - GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, + GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, // GA GAME_COMMAND_SET_STAFF_PATROL, GAME_COMMAND_FIRE_STAFF_MEMBER, GAME_COMMAND_SET_STAFF_ORDERS, // GA diff --git a/src/openrct2/actions/GameActionRegistration.cpp b/src/openrct2/actions/GameActionRegistration.cpp index c24a8e0a7f..d78da9e082 100644 --- a/src/openrct2/actions/GameActionRegistration.cpp +++ b/src/openrct2/actions/GameActionRegistration.cpp @@ -43,6 +43,7 @@ #include "SignSetStyleAction.hpp" #include "SmallSceneryPlaceAction.hpp" #include "SmallSceneryRemoveAction.hpp" +#include "StaffHireNewAction.hpp" #include "StaffSetColourAction.hpp" #include "StaffSetCostumeAction.hpp" #include "StaffSetNameAction.hpp" @@ -99,5 +100,6 @@ namespace GameActions Register(); Register(); Register(); + Register(); } } // namespace GameActions diff --git a/src/openrct2/actions/StaffHireNewAction.hpp b/src/openrct2/actions/StaffHireNewAction.hpp new file mode 100644 index 0000000000..7941f86285 --- /dev/null +++ b/src/openrct2/actions/StaffHireNewAction.hpp @@ -0,0 +1,345 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 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 "../Cheats.h" +#include "../Context.h" +#include "../core/MemoryStream.h" +#include "../drawing/Drawing.h" +#include "../interface/Window.h" +#include "../localisation/Localisation.h" +#include "../localisation/StringIds.h" +#include "../management/Finance.h" +#include "../ride/Ride.h" +#include "../scenario/Scenario.h" +#include "../ui/UiContext.h" +#include "../ui/WindowManager.h" +#include "../world/Entrance.h" +#include "../world/Park.h" +#include "../world/Sprite.h" +#include "GameAction.h" + +static constexpr const rct_string_id staffNames[] = { + STR_HANDYMAN_X, + STR_MECHANIC_X, + STR_SECURITY_GUARD_X, + STR_ENTERTAINER_X, +}; + +/* rct2: 0x009929FC */ +static constexpr const PeepSpriteType spriteTypes[] = { + PEEP_SPRITE_TYPE_HANDYMAN, + PEEP_SPRITE_TYPE_MECHANIC, + PEEP_SPRITE_TYPE_SECURITY, + PEEP_SPRITE_TYPE_ENTERTAINER_PANDA, +}; + +class StaffHireNewActionResult final : public GameActionResult +{ +public: + StaffHireNewActionResult() + : GameActionResult(GA_ERROR::OK, 0) + { + } + StaffHireNewActionResult(GA_ERROR error, rct_string_id message) + : GameActionResult(error, STR_CANT_HIRE_NEW_STAFF, message) + { + } + + uint32_t peepSriteIndex = SPRITE_INDEX_NULL; +}; + +DEFINE_GAME_ACTION(StaffHireNewAction, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, StaffHireNewActionResult) +{ +private: + bool _autoPosition = false; + uint8_t _staffType = STAFF_TYPE::STAFF_TYPE_COUNT; + uint8_t _entertainerType = ENTERTAINER_COSTUME::ENTERTAINER_COSTUME_COUNT; + +public: + StaffHireNewAction() = default; + StaffHireNewAction(bool autoPosition, STAFF_TYPE staffType, ENTERTAINER_COSTUME entertainerType) + : _autoPosition(autoPosition) + , _staffType(staffType) + , _entertainerType(entertainerType) + { + } + + uint16_t GetActionFlags() const override + { + return GameAction::GetActionFlags(); + } + + void Serialise(DataSerialiser & stream) override + { + GameAction::Serialise(stream); + + stream << DS_TAG(_autoPosition) << DS_TAG(_staffType) << DS_TAG(_entertainerType); + } + + GameActionResult::Ptr Query() const override + { + return QueryExecute(false); + } + + GameActionResult::Ptr Execute() const override + { + return QueryExecute(true); + } + +private: + GameActionResult::Ptr QueryExecute(bool execute) const + { + auto res = std::make_unique(); + + res->ExpenditureType = RCT_EXPENDITURE_TYPE_WAGES; + + if (_staffType >= STAFF_TYPE_COUNT) + { + // Invalid staff type. + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + if (gSpriteListCount[SPRITE_LIST_NULL] < 400) + { + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (_staffType == STAFF_TYPE_ENTERTAINER) + { + if (_entertainerType >= ENTERTAINER_COSTUME_COUNT) + { + // Invalid entertainer costume + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS); + } + + uint32_t availableCostumes = staff_get_available_entertainer_costumes(); + if (!(availableCostumes & (1 << _entertainerType))) + { + // Entertainer costume unavailable + return MakeResult(GA_ERROR::INVALID_PARAMETERS, STR_INVALID_SELECTION_OF_OBJECTS); + } + } + + // Look for a free slot in the staff modes. + int32_t staffIndex; + for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex) + { + if (!(gStaffModes[staffIndex] & 1)) + break; + } + + if (staffIndex == STAFF_MAX_COUNT) + { + // Too many staff members exist already. + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_TOO_MANY_STAFF_IN_GAME); + } + + Peep* newPeep = &(create_sprite(GetFlags())->peep); + if (newPeep == nullptr) + { + // Too many staff members exist already. + return MakeResult(GA_ERROR::NO_FREE_ELEMENTS, STR_TOO_MANY_PEOPLE_IN_GAME); + } + + if (execute == false) + { + // In query we just want to see if we can obtain a sprite slot. + sprite_remove((rct_sprite*)newPeep); + } + else + { + move_sprite_to_list((rct_sprite*)newPeep, SPRITE_LIST_PEEP * 2); + + newPeep->sprite_identifier = 1; + newPeep->window_invalidate_flags = 0; + newPeep->action = PEEP_ACTION_NONE_2; + newPeep->special_sprite = 0; + newPeep->action_sprite_image_offset = 0; + newPeep->no_action_frame_num = 0; + newPeep->action_sprite_type = PEEP_ACTION_SPRITE_TYPE_NONE; + newPeep->path_check_optimisation = 0; + newPeep->type = PEEP_TYPE_STAFF; + newPeep->outside_of_park = 0; + newPeep->peep_flags = 0; + newPeep->paid_to_enter = 0; + newPeep->paid_on_rides = 0; + newPeep->paid_on_food = 0; + newPeep->paid_on_souvenirs = 0; + + if (_staffType == STAFF_TYPE_HANDYMAN) + newPeep->staff_orders = STAFF_ORDERS_SWEEPING | STAFF_ORDERS_WATER_FLOWERS | STAFF_ORDERS_EMPTY_BINS; + else if (_staffType == STAFF_TYPE_MECHANIC) + newPeep->staff_orders = STAFF_ORDERS_INSPECT_RIDES | STAFF_ORDERS_FIX_RIDES; + else + newPeep->staff_orders = 0; + + uint16_t idSearchSpriteIndex; + Peep* idSearchPeep; + + // We search for the first available id for a given staff type + uint32_t newStaffId = 0; + for (;;) + { + bool found = false; + ++newStaffId; + + FOR_ALL_STAFF (idSearchSpriteIndex, idSearchPeep) + { + if (idSearchPeep->staff_type != _staffType) + continue; + + if (idSearchPeep->id == newStaffId) + { + found = true; + break; + } + } + + if (!found) + break; + } + + newPeep->id = newStaffId; + newPeep->staff_type = _staffType; + + PeepSpriteType spriteType = spriteTypes[_staffType]; + if (_staffType == STAFF_TYPE_ENTERTAINER) + { + spriteType = static_cast(PEEP_SPRITE_TYPE_ENTERTAINER_PANDA + _entertainerType); + } + newPeep->name_string_idx = staffNames[_staffType]; + newPeep->sprite_type = spriteType; + + const rct_sprite_bounds* spriteBounds = g_peep_animation_entries[spriteType].sprite_bounds; + newPeep->sprite_width = spriteBounds->sprite_width; + newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; + newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; + + if (_autoPosition == true) + { + AutoPositionNewStaff(newPeep); + } + else + { + // NOTE: This state is required for the window to act. + newPeep->state = PEEP_STATE_PICKED; + + sprite_move(newPeep->x, newPeep->y, newPeep->z, (rct_sprite*)newPeep); + invalidate_sprite_2((rct_sprite*)newPeep); + } + + // Staff uses this + newPeep->time_in_park = gDateMonthsElapsed; + newPeep->pathfind_goal.x = 0xFF; + newPeep->pathfind_goal.y = 0xFF; + newPeep->pathfind_goal.z = 0xFF; + newPeep->pathfind_goal.direction = 0xFF; + + uint8_t colour = staff_get_colour(_staffType); + newPeep->tshirt_colour = colour; + newPeep->trousers_colour = colour; + + // Staff energy determines their walking speed + newPeep->energy = 0x60; + newPeep->energy_target = 0x60; + newPeep->staff_mowing_timeout = 0; + + peep_update_name_sort(newPeep); + + newPeep->staff_id = newStaffId; + + gStaffModes[staffIndex] = STAFF_MODE_WALK; + + for (int32_t newStaffIndex = 0; newStaffIndex < STAFF_PATROL_AREA_SIZE; newStaffIndex++) + { + gStaffPatrolAreas[newStaffIndex * STAFF_PATROL_AREA_SIZE + newStaffId] = 0; + } + + res->peepSriteIndex = newPeep->sprite_index; + } + + return res; + } + + void AutoPositionNewStaff(Peep * newPeep) const + { + // Find a location to place new staff member + + newPeep->state = PEEP_STATE_FALLING; + + int16_t x, y, z; + uint32_t count = 0; + uint16_t sprite_index; + Peep* guest = nullptr; + TileElement* guest_tile = nullptr; + + // Count number of walking guests + FOR_ALL_GUESTS (sprite_index, guest) + { + if (guest->state == PEEP_STATE_WALKING) + { + // Check the walking guest's tile. Only count them if they're on a path tile. + guest_tile = map_get_path_element_at(guest->next_x / 32, guest->next_y / 32, guest->next_z); + if (guest_tile != nullptr) + ++count; + } + } + + if (count > 0) + { + // Place staff at a random guest + uint32_t rand = scenario_rand_max(count); + FOR_ALL_GUESTS (sprite_index, guest) + { + if (guest->state == PEEP_STATE_WALKING) + { + guest_tile = map_get_path_element_at(guest->next_x / 32, guest->next_y / 32, guest->next_z); + if (guest_tile != nullptr) + { + if (rand == 0) + break; + --rand; + } + } + } + + x = guest->x; + y = guest->y; + z = guest->z; + } + else + { + // No walking guests; pick random park entrance + if (gParkEntrances.size() > 0) + { + auto rand = scenario_rand_max((uint32_t)gParkEntrances.size()); + const auto& entrance = gParkEntrances[rand]; + auto dir = entrance.direction; + x = entrance.x; + y = entrance.y; + z = entrance.z; + x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); + y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); + } + else + { + // User must pick a location + newPeep->state = PEEP_STATE_PICKED; + x = newPeep->x; + y = newPeep->y; + z = newPeep->z; + } + } + + sprite_move(x, y, z + 16, (rct_sprite*)newPeep); + invalidate_sprite_2((rct_sprite*)newPeep); + } +}; diff --git a/src/openrct2/peep/Staff.cpp b/src/openrct2/peep/Staff.cpp index 89e9e0351b..1cf3704928 100644 --- a/src/openrct2/peep/Staff.cpp +++ b/src/openrct2/peep/Staff.cpp @@ -12,6 +12,7 @@ #include "../Context.h" #include "../Game.h" #include "../Input.h" +#include "../actions/StaffHireNewAction.hpp" #include "../actions/StaffSetOrdersAction.hpp" #include "../audio/audio.h" #include "../config/Config.h" @@ -81,286 +82,6 @@ void staff_reset_modes() staff_update_greyed_patrol_areas(); } -static inline void staff_autoposition_new_staff_member(Peep* newPeep) -{ - // Find a location to place new staff member - - newPeep->state = PEEP_STATE_FALLING; - - int16_t x, y, z; - uint32_t count = 0; - uint16_t sprite_index; - Peep* guest = nullptr; - TileElement* guest_tile = nullptr; - - // Count number of walking guests - FOR_ALL_GUESTS (sprite_index, guest) - { - if (guest->state == PEEP_STATE_WALKING) - { - // Check the walking guest's tile. Only count them if they're on a path tile. - guest_tile = map_get_path_element_at(guest->next_x / 32, guest->next_y / 32, guest->next_z); - if (guest_tile != nullptr) - ++count; - } - } - - if (count > 0) - { - // Place staff at a random guest - uint32_t rand = scenario_rand_max(count); - FOR_ALL_GUESTS (sprite_index, guest) - { - if (guest->state == PEEP_STATE_WALKING) - { - guest_tile = map_get_path_element_at(guest->next_x / 32, guest->next_y / 32, guest->next_z); - if (guest_tile != nullptr) - { - if (rand == 0) - break; - --rand; - } - } - } - - x = guest->x; - y = guest->y; - z = guest->z; - } - else - { - // No walking guests; pick random park entrance - if (gParkEntrances.size() > 0) - { - auto rand = scenario_rand_max((uint32_t)gParkEntrances.size()); - const auto& entrance = gParkEntrances[rand]; - auto dir = entrance.direction; - x = entrance.x; - y = entrance.y; - z = entrance.z; - x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); - y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); - } - else - { - // User must pick a location - newPeep->state = PEEP_STATE_PICKED; - x = newPeep->x; - y = newPeep->y; - z = newPeep->z; - } - } - - sprite_move(x, y, z + 16, (rct_sprite*)newPeep); - invalidate_sprite_2((rct_sprite*)newPeep); -} - -static money32 staff_hire_new_staff_member( - uint8_t staff_type, uint8_t flags, int16_t command_x, int16_t command_y, int16_t command_z, int32_t autoposition, - int32_t* newPeep_sprite_index) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_WAGES; - gCommandPosition.x = command_x; - gCommandPosition.y = command_y; - gCommandPosition.z = command_z; - - if (gSpriteListCount[SPRITE_LIST_NULL] < 400) - { - gGameCommandErrorText = STR_TOO_MANY_PEOPLE_IN_GAME; - return MONEY32_UNDEFINED; - } - - // Staff type matches STAFF_TYPE enum, but ENTERTAINER onwards will match - // the ENTERTAINER_COSTUME enum - uint8_t entertainerType = ENTERTAINER_COSTUME_PANDA; - if (staff_type >= STAFF_TYPE_ENTERTAINER) - { - entertainerType = staff_type - STAFF_TYPE_ENTERTAINER; - if (entertainerType >= ENTERTAINER_COSTUME_COUNT) - { - // Invalid entertainer costume - return MONEY32_UNDEFINED; - } - - uint32_t availableCostumes = staff_get_available_entertainer_costumes(); - if (!(availableCostumes & (1 << entertainerType))) - { - // Entertainer costume unavailable - return MONEY32_UNDEFINED; - } - - staff_type = STAFF_TYPE_ENTERTAINER; - } - - int32_t i; - for (i = 0; i < STAFF_MAX_COUNT; ++i) - { - if (!(gStaffModes[i] & 1)) - break; - } - - if (i == STAFF_MAX_COUNT) - { - gGameCommandErrorText = STR_TOO_MANY_STAFF_IN_GAME; - return MONEY32_UNDEFINED; - } - - if (flags & GAME_COMMAND_FLAG_APPLY) - { - int32_t newStaffId = i; - const rct_sprite_bounds* spriteBounds; - Peep* newPeep = &(create_sprite(flags)->peep); - - if (newPeep == nullptr) - { - gGameCommandErrorText = STR_TOO_MANY_PEOPLE_IN_GAME; - return MONEY32_UNDEFINED; - } - - if (flags == 0) - { - sprite_remove((rct_sprite*)newPeep); - } - else - { - move_sprite_to_list((rct_sprite*)newPeep, SPRITE_LIST_PEEP * 2); - - newPeep->sprite_identifier = 1; - newPeep->window_invalidate_flags = 0; - newPeep->action = PEEP_ACTION_NONE_2; - newPeep->special_sprite = 0; - newPeep->action_sprite_image_offset = 0; - newPeep->no_action_frame_num = 0; - newPeep->action_sprite_type = PEEP_ACTION_SPRITE_TYPE_NONE; - newPeep->path_check_optimisation = 0; - newPeep->type = PEEP_TYPE_STAFF; - newPeep->outside_of_park = 0; - newPeep->peep_flags = 0; - newPeep->paid_to_enter = 0; - newPeep->paid_on_rides = 0; - newPeep->paid_on_food = 0; - newPeep->paid_on_souvenirs = 0; - - if (staff_type == STAFF_TYPE_HANDYMAN) - newPeep->staff_orders = STAFF_ORDERS_SWEEPING | STAFF_ORDERS_WATER_FLOWERS | STAFF_ORDERS_EMPTY_BINS; - else if (staff_type == STAFF_TYPE_MECHANIC) - newPeep->staff_orders = STAFF_ORDERS_INSPECT_RIDES | STAFF_ORDERS_FIX_RIDES; - else - newPeep->staff_orders = 0; - - uint16_t idSearchSpriteIndex; - Peep* idSearchPeep; - - // We search for the first available id for a given staff type - uint32_t newStaffIndex = 0; - for (;;) - { - bool found = false; - ++newStaffIndex; - - FOR_ALL_STAFF (idSearchSpriteIndex, idSearchPeep) - { - if (idSearchPeep->staff_type != staff_type) - continue; - - if (idSearchPeep->id == newStaffIndex) - { - found = true; - break; - } - } - - if (!found) - break; - } - - newPeep->id = newStaffIndex; - newPeep->staff_type = staff_type; - - static constexpr const rct_string_id staffNames[] = { - STR_HANDYMAN_X, - STR_MECHANIC_X, - STR_SECURITY_GUARD_X, - STR_ENTERTAINER_X, - }; - - /* rct2: 0x009929FC */ - static constexpr const PeepSpriteType spriteTypes[] = { - PEEP_SPRITE_TYPE_HANDYMAN, - PEEP_SPRITE_TYPE_MECHANIC, - PEEP_SPRITE_TYPE_SECURITY, - PEEP_SPRITE_TYPE_ENTERTAINER_PANDA, - }; - - PeepSpriteType sprite_type = spriteTypes[staff_type]; - if (staff_type == STAFF_TYPE_ENTERTAINER) - { - sprite_type = static_cast(PEEP_SPRITE_TYPE_ENTERTAINER_PANDA + entertainerType); - } - newPeep->name_string_idx = staffNames[staff_type]; - newPeep->sprite_type = sprite_type; - - spriteBounds = g_peep_animation_entries[sprite_type].sprite_bounds; - newPeep->sprite_width = spriteBounds->sprite_width; - newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; - newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; - - if (autoposition) - { - staff_autoposition_new_staff_member(newPeep); - } - else - { - newPeep->state = PEEP_STATE_PICKED; - - sprite_move(newPeep->x, newPeep->y, newPeep->z, (rct_sprite*)newPeep); - invalidate_sprite_2((rct_sprite*)newPeep); - } - - newPeep->time_in_park = gDateMonthsElapsed; - newPeep->pathfind_goal.x = 0xFF; - newPeep->pathfind_goal.y = 0xFF; - newPeep->pathfind_goal.z = 0xFF; - newPeep->pathfind_goal.direction = 0xFF; - - uint8_t colour = staff_get_colour(staff_type); - newPeep->tshirt_colour = colour; - newPeep->trousers_colour = colour; - - // Staff energy determines their walking speed - newPeep->energy = 0x60; - newPeep->energy_target = 0x60; - newPeep->staff_mowing_timeout = 0; - - peep_update_name_sort(newPeep); - - newPeep->staff_id = newStaffId; - - gStaffModes[newStaffId] = STAFF_MODE_WALK; - - for (i = 0; i < STAFF_PATROL_AREA_SIZE; i++) - { - gStaffPatrolAreas[newStaffId * STAFF_PATROL_AREA_SIZE + i] = 0; - } - } - - *newPeep_sprite_index = newPeep->sprite_index; - } - return 0; -} - -/** - * - * rct2: 0x006BEFA1 - */ -void game_command_hire_new_staff_member( - int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, - [[maybe_unused]] int32_t* ebp) -{ - *ebx = staff_hire_new_staff_member( - (*ebx & 0xFF00) >> 8, *ebx & 0xFF, *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFFFF, (*ebx & 0xFF0000) >> 16, edi); -} - /** * * rct2: 0x006C09D1 @@ -449,42 +170,39 @@ void game_command_fire_staff_member( } /** - * Hires a new staff member of the given type. If the hire cannot be completed (eg. the maximum number of staff is reached or - * there are too many peeps) it returns SPRITE_INDEX_NULL. + * Hires a new staff member of the given type. */ -uint16_t hire_new_staff_member(uint8_t staffType) +bool staff_hire_new_member(STAFF_TYPE staffType, ENTERTAINER_COSTUME entertainerType) { - gGameCommandErrorTitle = STR_CANT_HIRE_NEW_STAFF; - - int32_t command_x, ebx, command_y, command_z, esi, new_sprite_index, ebp; - command_y = command_z = esi = new_sprite_index = ebp = 0; - command_x = 0x8000; - - int32_t autoposition = gConfigGeneral.auto_staff_placement; + bool autoPosition = gConfigGeneral.auto_staff_placement; if (gInputPlaceObjectModifier & PLACE_OBJECT_MODIFIER_SHIFT_Z) { - autoposition = autoposition ^ 1; + autoPosition = autoPosition ^ 1; } - ebx = autoposition << 16 | staffType << 8 | GAME_COMMAND_FLAG_APPLY; + auto hireStaffAction = StaffHireNewAction(autoPosition, staffType, entertainerType); + hireStaffAction.SetCallback([=](const GameAction*, const StaffHireNewActionResult* res) -> void { + if (res->Error != GA_ERROR::OK) + return; - game_command_callback = game_command_callback_hire_new_staff_member; - int32_t result = game_do_command_p( - GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, &command_x, &ebx, &command_y, &command_z, &esi, &new_sprite_index, &ebp); + if ((staffType == STAFF_TYPE_HANDYMAN) && gConfigGeneral.handymen_mow_default) + { + Peep* newPeep = GET_PEEP(res->peepSriteIndex); + uint8_t newOrders = newPeep->staff_orders | STAFF_ORDERS_MOWING; - if (result == MONEY32_UNDEFINED) - return SPRITE_INDEX_NULL; + auto staffSetOrdersAction = StaffSetOrdersAction(res->peepSriteIndex, newOrders); + GameActions::Execute(&staffSetOrdersAction); + } - if ((staffType == STAFF_TYPE_HANDYMAN) && gConfigGeneral.handymen_mow_default) - { - Peep* newPeep = GET_PEEP(new_sprite_index); - uint8_t newOrders = newPeep->staff_orders | STAFF_ORDERS_MOWING; + // Open window for new staff. + Peep* peep = &get_sprite(res->peepSriteIndex)->peep; + auto intent = Intent(WC_PEEP); + intent.putExtra(INTENT_EXTRA_PEEP, peep); + context_open_intent(&intent); + }); - auto staffSetOrdersAction = StaffSetOrdersAction(new_sprite_index, newOrders); - GameActions::Execute(&staffSetOrdersAction); - } - - return new_sprite_index; + auto res = GameActions::Execute(&hireStaffAction); + return res->Error == GA_ERROR::OK; } /** diff --git a/src/openrct2/peep/Staff.h b/src/openrct2/peep/Staff.h index 61c15896a3..30ef68ef5f 100644 --- a/src/openrct2/peep/Staff.h +++ b/src/openrct2/peep/Staff.h @@ -25,7 +25,7 @@ enum STAFF_MODE STAFF_MODE_PATROL = 3 }; -enum STAFF_TYPE +enum STAFF_TYPE : uint8_t { STAFF_TYPE_HANDYMAN, STAFF_TYPE_MECHANIC, @@ -45,7 +45,7 @@ enum STAFF_ORDERS STAFF_ORDERS_FIX_RIDES = (1 << 1) }; -enum ENTERTAINER_COSTUME +enum ENTERTAINER_COSTUME : uint8_t { ENTERTAINER_COSTUME_PANDA, ENTERTAINER_COSTUME_TIGER, @@ -86,7 +86,7 @@ void game_command_pickup_staff( void staff_reset_modes(); void staff_set_name(uint16_t spriteIndex, const char* name); -uint16_t hire_new_staff_member(uint8_t staffType); +bool staff_hire_new_member(STAFF_TYPE staffType, ENTERTAINER_COSTUME entertainerType); void staff_update_greyed_patrol_areas(); bool staff_is_location_in_patrol(Peep* mechanic, int32_t x, int32_t y); bool staff_is_location_on_patrol_edge(Peep* mechanic, int32_t x, int32_t y); diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index 207255dd2b..f051444ab0 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -55,25 +55,6 @@ void game_command_callback_pickup_guest( } } -void game_command_callback_hire_new_staff_member( - [[maybe_unused]] int32_t eax, [[maybe_unused]] int32_t ebx, [[maybe_unused]] int32_t ecx, [[maybe_unused]] int32_t edx, - [[maybe_unused]] int32_t esi, int32_t edi, [[maybe_unused]] int32_t ebp) -{ - int32_t sprite_index = edi; - if (sprite_index == SPRITE_INDEX_NULL) - { - rct_window* window = window_find_by_class(WC_STAFF_LIST); - window_invalidate(window); - } - else - { - Peep* peep = &get_sprite(sprite_index)->peep; - auto intent = Intent(WC_PEEP); - intent.putExtra(INTENT_EXTRA_PEEP, peep); - context_open_intent(&intent); - } -} - void game_command_callback_pickup_staff( int32_t eax, int32_t ebx, int32_t ecx, [[maybe_unused]] int32_t edx, [[maybe_unused]] int32_t esi, [[maybe_unused]] int32_t edi, [[maybe_unused]] int32_t ebp)