mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement StaffHireNewAction game action.
This commit is contained in:
parent
25eb403c78
commit
f96a1a1b5f
|
@ -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<STAFF_TYPE>(_windowStaffListSelectedTab);
|
||||
if (staffType == STAFF_TYPE_ENTERTAINER)
|
||||
{
|
||||
uint8_t costume = window_staff_list_get_random_entertainer_costume();
|
||||
staffType += costume;
|
||||
ENTERTAINER_COSTUME costume = static_cast<ENTERTAINER_COSTUME>(
|
||||
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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<PauseToggleAction>();
|
||||
Register<LoadOrQuitAction>();
|
||||
Register<WaterSetHeightAction>();
|
||||
Register<StaffHireNewAction>();
|
||||
}
|
||||
} // namespace GameActions
|
||||
|
|
|
@ -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<StaffHireNewActionResult>();
|
||||
|
||||
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<PeepSpriteType>(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);
|
||||
}
|
||||
};
|
|
@ -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<PeepSpriteType>(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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue