mirror of https://github.com/OpenRCT2/OpenRCT2.git
Staff patrol area 2 from NSF (#15600)
* Port over changes from NSF for staff * Fix import and export * Fix crash on export * Fix import issue * Fix patrol import issue * Remove staff id field * Increment network version * Actually remove all instances of staff id * Update replays
This commit is contained in:
parent
1cfa4f8a9e
commit
a8d2d5fd44
|
@ -65,9 +65,9 @@ set(OBJECTS_VERSION "1.0.21")
|
||||||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
|
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip")
|
||||||
set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5")
|
set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5")
|
||||||
|
|
||||||
set(REPLAYS_VERSION "0.0.56")
|
set(REPLAYS_VERSION "0.0.57")
|
||||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
|
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
|
||||||
set(REPLAYS_SHA1 "C47048B71A95A95428A08035C94AD10E7A020D4D")
|
set(REPLAYS_SHA1 "DF9C3B48755B19FDD4D0EC721007B98CD5B6F420")
|
||||||
|
|
||||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||||
option(WITH_TESTS "Build tests")
|
option(WITH_TESTS "Build tests")
|
||||||
|
|
|
@ -48,8 +48,8 @@
|
||||||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip</ObjectsUrl>
|
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip</ObjectsUrl>
|
||||||
<ObjectsSha1>c38af45d51a6e440386180feacf76c64720b6ac5</ObjectsSha1>
|
<ObjectsSha1>c38af45d51a6e440386180feacf76c64720b6ac5</ObjectsSha1>
|
||||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.56/replays.zip</ReplaysUrl>
|
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.57/replays.zip</ReplaysUrl>
|
||||||
<ReplaysSha1>C47048B71A95A95428A08035C94AD10E7A020D4D</ReplaysSha1>
|
<ReplaysSha1>DF9C3B48755B19FDD4D0EC721007B98CD5B6F420</ReplaysSha1>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <openrct2/actions/SmallSceneryRemoveAction.h>
|
#include <openrct2/actions/SmallSceneryRemoveAction.h>
|
||||||
#include <openrct2/actions/WallRemoveAction.h>
|
#include <openrct2/actions/WallRemoveAction.h>
|
||||||
#include <openrct2/localisation/Localisation.h>
|
#include <openrct2/localisation/Localisation.h>
|
||||||
|
#include <openrct2/peep/Staff.h>
|
||||||
#include <openrct2/ride/Ride.h>
|
#include <openrct2/ride/Ride.h>
|
||||||
#include <openrct2/ride/RideData.h>
|
#include <openrct2/ride/RideData.h>
|
||||||
#include <openrct2/ride/Track.h>
|
#include <openrct2/ride/Track.h>
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <openrct2/actions/SurfaceSetStyleAction.h>
|
#include <openrct2/actions/SurfaceSetStyleAction.h>
|
||||||
#include <openrct2/audio/audio.h>
|
#include <openrct2/audio/audio.h>
|
||||||
#include <openrct2/localisation/Localisation.h>
|
#include <openrct2/localisation/Localisation.h>
|
||||||
|
#include <openrct2/peep/Staff.h>
|
||||||
#include <openrct2/ride/RideData.h>
|
#include <openrct2/ride/RideData.h>
|
||||||
#include <openrct2/ride/Track.h>
|
#include <openrct2/ride/Track.h>
|
||||||
#include <openrct2/ride/TrainManager.h>
|
#include <openrct2/ride/TrainManager.h>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <openrct2/drawing/Drawing.h>
|
#include <openrct2/drawing/Drawing.h>
|
||||||
#include <openrct2/interface/Colour.h>
|
#include <openrct2/interface/Colour.h>
|
||||||
#include <openrct2/localisation/Localisation.h>
|
#include <openrct2/localisation/Localisation.h>
|
||||||
|
#include <openrct2/peep/Staff.h>
|
||||||
#include <openrct2/world/Entity.h>
|
#include <openrct2/world/Entity.h>
|
||||||
|
|
||||||
static constexpr const rct_string_id WINDOW_TITLE = STR_SACK_STAFF;
|
static constexpr const rct_string_id WINDOW_TITLE = STR_SACK_STAFF;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "core/CircularBuffer.h"
|
#include "core/CircularBuffer.h"
|
||||||
#include "peep/Peep.h"
|
#include "peep/Peep.h"
|
||||||
|
#include "peep/Staff.h"
|
||||||
#include "ride/Vehicle.h"
|
#include "ride/Vehicle.h"
|
||||||
#include "world/Balloon.h"
|
#include "world/Balloon.h"
|
||||||
#include "world/Duck.h"
|
#include "world/Duck.h"
|
||||||
|
@ -296,7 +297,6 @@ struct GameStateSnapshots final : public IGameStateSnapshots
|
||||||
COMPARE_FIELD(Staff, AssignedStaffType);
|
COMPARE_FIELD(Staff, AssignedStaffType);
|
||||||
COMPARE_FIELD(Staff, MechanicTimeSinceCall);
|
COMPARE_FIELD(Staff, MechanicTimeSinceCall);
|
||||||
COMPARE_FIELD(Staff, HireDate);
|
COMPARE_FIELD(Staff, HireDate);
|
||||||
COMPARE_FIELD(Staff, StaffId);
|
|
||||||
COMPARE_FIELD(Staff, StaffOrders);
|
COMPARE_FIELD(Staff, StaffOrders);
|
||||||
COMPARE_FIELD(Staff, StaffMowingTimeout);
|
COMPARE_FIELD(Staff, StaffMowingTimeout);
|
||||||
COMPARE_FIELD(Staff, StaffRidesFixed);
|
COMPARE_FIELD(Staff, StaffRidesFixed);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "../localisation/Localisation.h"
|
#include "../localisation/Localisation.h"
|
||||||
#include "../localisation/StringIds.h"
|
#include "../localisation/StringIds.h"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
|
#include "../peep/Staff.h"
|
||||||
#include "../ride/Ride.h"
|
#include "../ride/Ride.h"
|
||||||
#include "../ride/Vehicle.h"
|
#include "../ride/Vehicle.h"
|
||||||
#include "../scenario/Scenario.h"
|
#include "../scenario/Scenario.h"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "StaffFireAction.h"
|
#include "StaffFireAction.h"
|
||||||
|
|
||||||
#include "../interface/Window.h"
|
#include "../interface/Window.h"
|
||||||
#include "../peep/Peep.h"
|
#include "../peep/Staff.h"
|
||||||
#include "../world/Entity.h"
|
#include "../world/Entity.h"
|
||||||
|
|
||||||
StaffFireAction::StaffFireAction(uint16_t spriteId)
|
StaffFireAction::StaffFireAction(uint16_t spriteId)
|
||||||
|
|
|
@ -111,15 +111,8 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for a free slot in the staff modes.
|
auto numStaff = GetEntityListCount(EntityType::Staff);
|
||||||
int32_t staffIndex;
|
if (numStaff == STAFF_MAX_COUNT)
|
||||||
for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex)
|
|
||||||
{
|
|
||||||
if (gStaffModes[staffIndex] == StaffMode::None)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (staffIndex == STAFF_MAX_COUNT)
|
|
||||||
{
|
{
|
||||||
// Too many staff members exist already.
|
// Too many staff members exist already.
|
||||||
return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_HIRE_NEW_STAFF, STR_TOO_MANY_STAFF_IN_GAME);
|
return MakeResult(GameActions::Status::NoFreeElements, STR_CANT_HIRE_NEW_STAFF, STR_TOO_MANY_STAFF_IN_GAME);
|
||||||
|
@ -222,14 +215,7 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const
|
||||||
newPeep->EnergyTarget = 0x60;
|
newPeep->EnergyTarget = 0x60;
|
||||||
newPeep->StaffMowingTimeout = 0;
|
newPeep->StaffMowingTimeout = 0;
|
||||||
|
|
||||||
newPeep->StaffId = staffIndex;
|
newPeep->PatrolInfo = nullptr;
|
||||||
|
|
||||||
gStaffModes[staffIndex] = StaffMode::Walk;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
|
||||||
{
|
|
||||||
gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
res->SetData(StaffHireNewActionResult{ newPeep->sprite_index });
|
res->SetData(StaffHireNewActionResult{ newPeep->sprite_index });
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,29 +55,6 @@ GameActions::Result::Ptr StaffSetPatrolAreaAction::Query() const
|
||||||
return MakeResult();
|
return MakeResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateStaffMode(const Staff& staff)
|
|
||||||
{
|
|
||||||
bool isPatrolling = false;
|
|
||||||
const auto peepOffset = staff.StaffId * STAFF_PATROL_AREA_SIZE;
|
|
||||||
for (size_t i = peepOffset; i < peepOffset + STAFF_PATROL_AREA_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (gStaffPatrolAreas[i] != 0)
|
|
||||||
{
|
|
||||||
isPatrolling = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPatrolling)
|
|
||||||
{
|
|
||||||
gStaffModes[staff.StaffId] = StaffMode::Patrol;
|
|
||||||
}
|
|
||||||
else if (gStaffModes[staff.StaffId] == StaffMode::Patrol)
|
|
||||||
{
|
|
||||||
gStaffModes[staff.StaffId] = StaffMode::Walk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InvalidatePatrolTile(const CoordsXY& loc)
|
static void InvalidatePatrolTile(const CoordsXY& loc)
|
||||||
{
|
{
|
||||||
// Align the location to the top left of the patrol square
|
// Align the location to the top left of the patrol square
|
||||||
|
@ -104,12 +81,14 @@ GameActions::Result::Ptr StaffSetPatrolAreaAction::Execute() const
|
||||||
{
|
{
|
||||||
case StaffSetPatrolAreaMode::Set:
|
case StaffSetPatrolAreaMode::Set:
|
||||||
staff->SetPatrolArea(_loc, true);
|
staff->SetPatrolArea(_loc, true);
|
||||||
UpdateStaffMode(*staff);
|
|
||||||
InvalidatePatrolTile(_loc);
|
InvalidatePatrolTile(_loc);
|
||||||
break;
|
break;
|
||||||
case StaffSetPatrolAreaMode::Unset:
|
case StaffSetPatrolAreaMode::Unset:
|
||||||
staff->SetPatrolArea(_loc, false);
|
staff->SetPatrolArea(_loc, false);
|
||||||
UpdateStaffMode(*staff);
|
if (!staff->HasPatrolArea())
|
||||||
|
{
|
||||||
|
staff->ClearPatrolArea();
|
||||||
|
}
|
||||||
InvalidatePatrolTile(_loc);
|
InvalidatePatrolTile(_loc);
|
||||||
break;
|
break;
|
||||||
case StaffSetPatrolAreaMode::ClearAll:
|
case StaffSetPatrolAreaMode::ClearAll:
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
// This string specifies which version of network stream current build uses.
|
// This string specifies which version of network stream current build uses.
|
||||||
// It is used for making sure only compatible builds get connected, even within
|
// It is used for making sure only compatible builds get connected, even within
|
||||||
// single OpenRCT2 version.
|
// single OpenRCT2 version.
|
||||||
#define NETWORK_STREAM_VERSION "15"
|
#define NETWORK_STREAM_VERSION "16"
|
||||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||||
|
|
||||||
static Peep* _pickup_peep = nullptr;
|
static Peep* _pickup_peep = nullptr;
|
||||||
|
|
|
@ -655,7 +655,6 @@ void peep_sprite_remove(Peep* peep)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
staff->ClearPatrolArea();
|
staff->ClearPatrolArea();
|
||||||
gStaffModes[staff->StaffId] = StaffMode::None;
|
|
||||||
staff_update_greyed_patrol_areas();
|
staff_update_greyed_patrol_areas();
|
||||||
|
|
||||||
News::DisableNewsItems(News::ItemType::Peep, staff->sprite_index);
|
News::DisableNewsItems(News::ItemType::Peep, staff->sprite_index);
|
||||||
|
|
|
@ -838,104 +838,7 @@ private:
|
||||||
void GoToRideEntrance(Ride* ride);
|
void GoToRideEntrance(Ride* ride);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Staff : Peep
|
|
||||||
{
|
|
||||||
static constexpr auto cEntityType = EntityType::Staff;
|
|
||||||
|
|
||||||
public:
|
|
||||||
StaffType AssignedStaffType;
|
|
||||||
uint16_t MechanicTimeSinceCall; // time getting to ride to fix
|
|
||||||
int32_t HireDate;
|
|
||||||
uint8_t StaffId;
|
|
||||||
uint8_t StaffOrders;
|
|
||||||
uint8_t StaffMowingTimeout;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint16_t StaffLawnsMown;
|
|
||||||
uint16_t StaffRidesFixed;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint16_t StaffGardensWatered;
|
|
||||||
uint16_t StaffRidesInspected;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint16_t StaffLitterSwept;
|
|
||||||
uint16_t StaffVandalsStopped;
|
|
||||||
};
|
|
||||||
uint16_t StaffBinsEmptied;
|
|
||||||
|
|
||||||
void UpdateStaff(uint32_t stepsToTake);
|
|
||||||
void Tick128UpdateStaff();
|
|
||||||
bool IsMechanic() const;
|
|
||||||
bool IsPatrolAreaSet(const CoordsXY& coords) const;
|
|
||||||
bool IsLocationInPatrol(const CoordsXY& loc) const;
|
|
||||||
bool IsLocationOnPatrolEdge(const CoordsXY& loc) const;
|
|
||||||
bool DoPathFinding();
|
|
||||||
uint8_t GetCostume() const;
|
|
||||||
void SetCostume(uint8_t value);
|
|
||||||
void SetHireDate(int32_t hireDate);
|
|
||||||
int32_t GetHireDate() const;
|
|
||||||
|
|
||||||
bool CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) const;
|
|
||||||
|
|
||||||
static void ResetStats();
|
|
||||||
void Serialise(DataSerialiser& stream);
|
|
||||||
|
|
||||||
void ClearPatrolArea();
|
|
||||||
void TogglePatrolArea(const CoordsXY& coords);
|
|
||||||
void SetPatrolArea(const CoordsXY& coords, bool value);
|
|
||||||
bool HasPatrolArea() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void UpdatePatrolling();
|
|
||||||
void UpdateMowing();
|
|
||||||
void UpdateSweeping();
|
|
||||||
void UpdateEmptyingBin();
|
|
||||||
void UpdateWatering();
|
|
||||||
void UpdateAnswering();
|
|
||||||
void UpdateFixing(int32_t steps);
|
|
||||||
bool UpdateFixingEnterStation(Ride* ride) const;
|
|
||||||
bool UpdateFixingMoveToBrokenDownVehicle(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFixVehicle(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFixVehicleMalfunction(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingMoveToStationEnd(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFixStationEnd(bool firstRun);
|
|
||||||
bool UpdateFixingMoveToStationStart(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFixStationStart(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFixStationBrakes(bool firstRun, Ride* ride);
|
|
||||||
bool UpdateFixingMoveToStationExit(bool firstRun, const Ride* ride);
|
|
||||||
bool UpdateFixingFinishFixOrInspect(bool firstRun, int32_t steps, Ride* ride);
|
|
||||||
bool UpdateFixingLeaveByEntranceExit(bool firstRun, const Ride* ride);
|
|
||||||
void UpdateRideInspected(ride_id_t rideIndex);
|
|
||||||
void UpdateHeadingToInspect();
|
|
||||||
|
|
||||||
bool DoHandymanPathFinding();
|
|
||||||
bool DoMechanicPathFinding();
|
|
||||||
bool DoEntertainerPathFinding();
|
|
||||||
bool DoMiscPathFinding();
|
|
||||||
|
|
||||||
Direction HandymanDirectionRandSurface(uint8_t validDirections) const;
|
|
||||||
|
|
||||||
void EntertainerUpdateNearbyPeeps() const;
|
|
||||||
|
|
||||||
uint8_t GetValidPatrolDirections(const CoordsXY& loc) const;
|
|
||||||
Direction HandymanDirectionToNearestLitter() const;
|
|
||||||
uint8_t HandymanDirectionToUncutGrass(uint8_t valid_directions) const;
|
|
||||||
Direction DirectionSurface(Direction initialDirection) const;
|
|
||||||
Direction DirectionPath(uint8_t validDirections, PathElement* pathElement) const;
|
|
||||||
Direction MechanicDirectionSurface() const;
|
|
||||||
Direction MechanicDirectionPathRand(uint8_t pathDirections) const;
|
|
||||||
Direction MechanicDirectionPath(uint8_t validDirections, PathElement* pathElement);
|
|
||||||
bool UpdatePatrollingFindWatering();
|
|
||||||
bool UpdatePatrollingFindBin();
|
|
||||||
bool UpdatePatrollingFindSweeping();
|
|
||||||
bool UpdatePatrollingFindGrass();
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(Guest) <= 512);
|
static_assert(sizeof(Guest) <= 512);
|
||||||
static_assert(sizeof(Staff) <= 512);
|
|
||||||
|
|
||||||
struct rct_sprite_bounds
|
struct rct_sprite_bounds
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,15 +61,18 @@ const rct_string_id StaffCostumeNames[] = {
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Every staff member has STAFF_PATROL_AREA_SIZE elements assigned to in this array, indexed by their StaffId
|
|
||||||
// Additionally there is a patrol area for each staff type, which is the union of the patrols of all staff members of that type
|
|
||||||
uint32_t gStaffPatrolAreas[(STAFF_MAX_COUNT + static_cast<uint8_t>(StaffType::Count)) * STAFF_PATROL_AREA_SIZE];
|
|
||||||
StaffMode gStaffModes[STAFF_MAX_COUNT + static_cast<uint8_t>(StaffType::Count)];
|
|
||||||
uint16_t gStaffDrawPatrolAreas;
|
uint16_t gStaffDrawPatrolAreas;
|
||||||
colour_t gStaffHandymanColour;
|
colour_t gStaffHandymanColour;
|
||||||
colour_t gStaffMechanicColour;
|
colour_t gStaffMechanicColour;
|
||||||
colour_t gStaffSecurityColour;
|
colour_t gStaffSecurityColour;
|
||||||
|
|
||||||
|
static PatrolArea _mergedPatrolAreas[EnumValue(StaffType::Count)];
|
||||||
|
|
||||||
|
const PatrolArea& GetMergedPatrolArea(const StaffType type)
|
||||||
|
{
|
||||||
|
return _mergedPatrolAreas[EnumValue(type)];
|
||||||
|
}
|
||||||
|
|
||||||
// Maximum manhattan distance that litter can be for a handyman to seek to it
|
// Maximum manhattan distance that litter can be for a handyman to seek to it
|
||||||
const uint16_t MAX_LITTER_DISTANCE = 3 * COORDS_XY_STEP;
|
const uint16_t MAX_LITTER_DISTANCE = 3 * COORDS_XY_STEP;
|
||||||
|
|
||||||
|
@ -84,12 +87,6 @@ template<> bool EntityBase::Is<Staff>() const
|
||||||
*/
|
*/
|
||||||
void staff_reset_modes()
|
void staff_reset_modes()
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < STAFF_MAX_COUNT; i++)
|
|
||||||
gStaffModes[i] = StaffMode::None;
|
|
||||||
|
|
||||||
for (int32_t i = STAFF_MAX_COUNT; i < (STAFF_MAX_COUNT + static_cast<uint8_t>(StaffType::Count)); i++)
|
|
||||||
gStaffModes[i] = StaffMode::Walk;
|
|
||||||
|
|
||||||
staff_update_greyed_patrol_areas();
|
staff_update_greyed_patrol_areas();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,27 +139,27 @@ bool staff_hire_new_member(StaffType staffType, EntertainerCostume entertainerTy
|
||||||
*/
|
*/
|
||||||
void staff_update_greyed_patrol_areas()
|
void staff_update_greyed_patrol_areas()
|
||||||
{
|
{
|
||||||
for (int32_t staff_type = 0; staff_type < static_cast<uint8_t>(StaffType::Count); ++staff_type)
|
for (int32_t staffType = 0; staffType < EnumValue(StaffType::Count); ++staffType)
|
||||||
{
|
{
|
||||||
const size_t staffPatrolOffset = (staff_type + STAFF_MAX_COUNT) * STAFF_PATROL_AREA_SIZE;
|
// Reset all of the merged data for the type.
|
||||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
auto& mergedData = _mergedPatrolAreas[staffType].Data;
|
||||||
{
|
std::fill(std::begin(mergedData), std::end(mergedData), 0);
|
||||||
gStaffPatrolAreas[staffPatrolOffset + i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto peep : EntityList<Staff>())
|
for (auto staff : EntityList<Staff>())
|
||||||
{
|
{
|
||||||
if (!peep->HasPatrolArea())
|
if (EnumValue(staff->AssignedStaffType) != staffType)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (static_cast<uint8_t>(peep->AssignedStaffType) == staff_type)
|
if (!staff->HasPatrolArea())
|
||||||
{
|
{
|
||||||
const size_t peepPatrolOffset = peep->StaffId * STAFF_PATROL_AREA_SIZE;
|
continue;
|
||||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
}
|
||||||
{
|
|
||||||
gStaffPatrolAreas[staffPatrolOffset + i] |= gStaffPatrolAreas[peepPatrolOffset + i];
|
auto staffData = staff->PatrolInfo->Data;
|
||||||
}
|
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
||||||
|
{
|
||||||
|
mergedData[i] |= staffData[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,7 +366,6 @@ void Staff::ResetStats()
|
||||||
|
|
||||||
static std::pair<int32_t, int32_t> getPatrolAreaOffsetIndex(const CoordsXY& coords)
|
static std::pair<int32_t, int32_t> getPatrolAreaOffsetIndex(const CoordsXY& coords)
|
||||||
{
|
{
|
||||||
// Patrol areas are 4 * 4 tiles (32 * 4) = 128 = 2^^7
|
|
||||||
auto tilePos = TileCoordsXY(coords);
|
auto tilePos = TileCoordsXY(coords);
|
||||||
auto x = tilePos.x / 4;
|
auto x = tilePos.x / 4;
|
||||||
auto y = tilePos.y / 4;
|
auto y = tilePos.y / 4;
|
||||||
|
@ -379,34 +375,37 @@ static std::pair<int32_t, int32_t> getPatrolAreaOffsetIndex(const CoordsXY& coor
|
||||||
return { byteIndex, byteBitIndex };
|
return { byteIndex, byteBitIndex };
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool staff_is_patrol_area_set(int32_t staffIndex, const CoordsXY& coords)
|
|
||||||
{
|
|
||||||
// Patrol quads are stored in a bit map (8 patrol quads per byte).
|
|
||||||
// Each patrol quad is 4x4.
|
|
||||||
// Therefore there are in total 64 x 64 patrol quads in the 256 x 256 map.
|
|
||||||
// At the end of the array (after the slots for individual staff members),
|
|
||||||
// there are slots that save the combined patrol area for every staff type.
|
|
||||||
|
|
||||||
int32_t peepOffset = staffIndex * STAFF_PATROL_AREA_SIZE;
|
|
||||||
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
|
||||||
return gStaffPatrolAreas[peepOffset + offset] & (1UL << bitIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Staff::IsPatrolAreaSet(const CoordsXY& coords) const
|
bool Staff::IsPatrolAreaSet(const CoordsXY& coords) const
|
||||||
{
|
{
|
||||||
return staff_is_patrol_area_set(StaffId, coords);
|
if (PatrolInfo != nullptr)
|
||||||
|
{
|
||||||
|
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
||||||
|
return PatrolInfo->Data[offset] & (1UL << bitIndex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool staff_is_patrol_area_set_for_type(StaffType type, const CoordsXY& coords)
|
bool staff_is_patrol_area_set_for_type(StaffType type, const CoordsXY& coords)
|
||||||
{
|
{
|
||||||
return staff_is_patrol_area_set(STAFF_MAX_COUNT + static_cast<uint8_t>(type), coords);
|
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
||||||
|
return _mergedPatrolAreas[EnumValue(type)].Data[offset] & (1UL << bitIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Staff::SetPatrolArea(const CoordsXY& coords, bool value)
|
void Staff::SetPatrolArea(const CoordsXY& coords, bool value)
|
||||||
{
|
{
|
||||||
int32_t peepOffset = StaffId * STAFF_PATROL_AREA_SIZE;
|
if (PatrolInfo == nullptr)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
PatrolInfo = new PatrolArea();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
||||||
uint32_t* addr = &gStaffPatrolAreas[peepOffset + offset];
|
auto* addr = &PatrolInfo->Data[offset];
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
*addr |= (1 << bitIndex);
|
*addr |= (1 << bitIndex);
|
||||||
|
@ -419,21 +418,17 @@ void Staff::SetPatrolArea(const CoordsXY& coords, bool value)
|
||||||
|
|
||||||
void Staff::ClearPatrolArea()
|
void Staff::ClearPatrolArea()
|
||||||
{
|
{
|
||||||
const auto peepOffset = StaffId * STAFF_PATROL_AREA_SIZE;
|
delete PatrolInfo;
|
||||||
std::fill_n(&gStaffPatrolAreas[peepOffset], STAFF_PATROL_AREA_SIZE, 0);
|
PatrolInfo = nullptr;
|
||||||
gStaffModes[StaffId] = StaffMode::Walk;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Staff::TogglePatrolArea(const CoordsXY& coords)
|
|
||||||
{
|
|
||||||
int32_t peepOffset = StaffId * STAFF_PATROL_AREA_SIZE;
|
|
||||||
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
|
||||||
gStaffPatrolAreas[peepOffset + offset] ^= (1 << bitIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Staff::HasPatrolArea() const
|
bool Staff::HasPatrolArea() const
|
||||||
{
|
{
|
||||||
return gStaffModes[StaffId] == StaffMode::Patrol;
|
if (PatrolInfo == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
constexpr auto hasData = [](const auto& datapoint) { return datapoint != 0; };
|
||||||
|
return std::any_of(std::begin(PatrolInfo->Data), std::end(PatrolInfo->Data), hasData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,13 +18,107 @@
|
||||||
constexpr size_t STAFF_PATROL_AREA_BLOCKS_PER_LINE = MAXIMUM_MAP_SIZE_TECHNICAL / 4;
|
constexpr size_t STAFF_PATROL_AREA_BLOCKS_PER_LINE = MAXIMUM_MAP_SIZE_TECHNICAL / 4;
|
||||||
constexpr size_t STAFF_PATROL_AREA_SIZE = (STAFF_PATROL_AREA_BLOCKS_PER_LINE * STAFF_PATROL_AREA_BLOCKS_PER_LINE) / 32;
|
constexpr size_t STAFF_PATROL_AREA_SIZE = (STAFF_PATROL_AREA_BLOCKS_PER_LINE * STAFF_PATROL_AREA_BLOCKS_PER_LINE) / 32;
|
||||||
|
|
||||||
enum class StaffMode : uint8_t
|
struct PatrolArea
|
||||||
{
|
{
|
||||||
None,
|
uint32_t Data[STAFF_PATROL_AREA_SIZE];
|
||||||
Walk,
|
|
||||||
Patrol = 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Staff : Peep
|
||||||
|
{
|
||||||
|
static constexpr auto cEntityType = EntityType::Staff;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PatrolArea* PatrolInfo;
|
||||||
|
StaffType AssignedStaffType;
|
||||||
|
uint16_t MechanicTimeSinceCall; // time getting to ride to fix
|
||||||
|
int32_t HireDate;
|
||||||
|
uint8_t StaffOrders;
|
||||||
|
uint8_t StaffMowingTimeout;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t StaffLawnsMown;
|
||||||
|
uint16_t StaffRidesFixed;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t StaffGardensWatered;
|
||||||
|
uint16_t StaffRidesInspected;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t StaffLitterSwept;
|
||||||
|
uint16_t StaffVandalsStopped;
|
||||||
|
};
|
||||||
|
uint16_t StaffBinsEmptied;
|
||||||
|
|
||||||
|
void UpdateStaff(uint32_t stepsToTake);
|
||||||
|
void Tick128UpdateStaff();
|
||||||
|
bool IsMechanic() const;
|
||||||
|
bool IsPatrolAreaSet(const CoordsXY& coords) const;
|
||||||
|
bool IsLocationInPatrol(const CoordsXY& loc) const;
|
||||||
|
bool IsLocationOnPatrolEdge(const CoordsXY& loc) const;
|
||||||
|
bool DoPathFinding();
|
||||||
|
uint8_t GetCostume() const;
|
||||||
|
void SetCostume(uint8_t value);
|
||||||
|
void SetHireDate(int32_t hireDate);
|
||||||
|
int32_t GetHireDate() const;
|
||||||
|
|
||||||
|
bool CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) const;
|
||||||
|
|
||||||
|
static void ResetStats();
|
||||||
|
void Serialise(DataSerialiser& stream);
|
||||||
|
|
||||||
|
void ClearPatrolArea();
|
||||||
|
void SetPatrolArea(const CoordsXY& coords, bool value);
|
||||||
|
bool HasPatrolArea() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdatePatrolling();
|
||||||
|
void UpdateMowing();
|
||||||
|
void UpdateSweeping();
|
||||||
|
void UpdateEmptyingBin();
|
||||||
|
void UpdateWatering();
|
||||||
|
void UpdateAnswering();
|
||||||
|
void UpdateFixing(int32_t steps);
|
||||||
|
bool UpdateFixingEnterStation(Ride* ride) const;
|
||||||
|
bool UpdateFixingMoveToBrokenDownVehicle(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFixVehicle(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFixVehicleMalfunction(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingMoveToStationEnd(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFixStationEnd(bool firstRun);
|
||||||
|
bool UpdateFixingMoveToStationStart(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFixStationStart(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFixStationBrakes(bool firstRun, Ride* ride);
|
||||||
|
bool UpdateFixingMoveToStationExit(bool firstRun, const Ride* ride);
|
||||||
|
bool UpdateFixingFinishFixOrInspect(bool firstRun, int32_t steps, Ride* ride);
|
||||||
|
bool UpdateFixingLeaveByEntranceExit(bool firstRun, const Ride* ride);
|
||||||
|
void UpdateRideInspected(ride_id_t rideIndex);
|
||||||
|
void UpdateHeadingToInspect();
|
||||||
|
|
||||||
|
bool DoHandymanPathFinding();
|
||||||
|
bool DoMechanicPathFinding();
|
||||||
|
bool DoEntertainerPathFinding();
|
||||||
|
bool DoMiscPathFinding();
|
||||||
|
|
||||||
|
Direction HandymanDirectionRandSurface(uint8_t validDirections) const;
|
||||||
|
|
||||||
|
void EntertainerUpdateNearbyPeeps() const;
|
||||||
|
|
||||||
|
uint8_t GetValidPatrolDirections(const CoordsXY& loc) const;
|
||||||
|
Direction HandymanDirectionToNearestLitter() const;
|
||||||
|
uint8_t HandymanDirectionToUncutGrass(uint8_t valid_directions) const;
|
||||||
|
Direction DirectionSurface(Direction initialDirection) const;
|
||||||
|
Direction DirectionPath(uint8_t validDirections, PathElement* pathElement) const;
|
||||||
|
Direction MechanicDirectionSurface() const;
|
||||||
|
Direction MechanicDirectionPathRand(uint8_t pathDirections) const;
|
||||||
|
Direction MechanicDirectionPath(uint8_t validDirections, PathElement* pathElement);
|
||||||
|
bool UpdatePatrollingFindWatering();
|
||||||
|
bool UpdatePatrollingFindBin();
|
||||||
|
bool UpdatePatrollingFindSweeping();
|
||||||
|
bool UpdatePatrollingFindGrass();
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Staff) <= 512);
|
||||||
|
|
||||||
enum STAFF_ORDERS
|
enum STAFF_ORDERS
|
||||||
{
|
{
|
||||||
STAFF_ORDERS_SWEEPING = (1 << 0),
|
STAFF_ORDERS_SWEEPING = (1 << 0),
|
||||||
|
@ -54,8 +148,6 @@ enum class EntertainerCostume : uint8_t
|
||||||
|
|
||||||
extern const rct_string_id StaffCostumeNames[static_cast<uint8_t>(EntertainerCostume::Count)];
|
extern const rct_string_id StaffCostumeNames[static_cast<uint8_t>(EntertainerCostume::Count)];
|
||||||
|
|
||||||
extern uint32_t gStaffPatrolAreas[(STAFF_MAX_COUNT + static_cast<uint8_t>(StaffType::Count)) * STAFF_PATROL_AREA_SIZE];
|
|
||||||
extern StaffMode gStaffModes[STAFF_MAX_COUNT + static_cast<uint8_t>(StaffType::Count)];
|
|
||||||
extern uint16_t gStaffDrawPatrolAreas;
|
extern uint16_t gStaffDrawPatrolAreas;
|
||||||
extern colour_t gStaffHandymanColour;
|
extern colour_t gStaffHandymanColour;
|
||||||
extern colour_t gStaffMechanicColour;
|
extern colour_t gStaffMechanicColour;
|
||||||
|
@ -73,3 +165,5 @@ int32_t staff_get_available_entertainer_costume_list(EntertainerCostume* costume
|
||||||
|
|
||||||
money32 GetStaffWage(StaffType type);
|
money32 GetStaffWage(StaffType type);
|
||||||
PeepSpriteType EntertainerCostumeToSprite(EntertainerCostume entertainerType);
|
PeepSpriteType EntertainerCostumeToSprite(EntertainerCostume entertainerType);
|
||||||
|
|
||||||
|
const PatrolArea& GetMergedPatrolArea(const StaffType type);
|
||||||
|
|
|
@ -1183,19 +1183,6 @@ namespace RCT1
|
||||||
|
|
||||||
void FixImportStaff()
|
void FixImportStaff()
|
||||||
{
|
{
|
||||||
// The RCT2/OpenRCT2 structures are bigger than in RCT1, so initialise them to zero
|
|
||||||
std::fill(std::begin(gStaffModes), std::end(gStaffModes), StaffMode::None);
|
|
||||||
std::fill(std::begin(gStaffPatrolAreas), std::end(gStaffPatrolAreas), 0);
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < RCT1_MAX_STAFF; i++)
|
|
||||||
{
|
|
||||||
gStaffModes[i] = static_cast<StaffMode>(_s4.staff_modes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto peep : EntityList<Staff>())
|
|
||||||
{
|
|
||||||
ImportStaffPatrolArea(peep);
|
|
||||||
}
|
|
||||||
// Only the individual patrol areas have been converted, so generate the combined patrol areas of each staff type
|
// Only the individual patrol areas have been converted, so generate the combined patrol areas of each staff type
|
||||||
staff_update_greyed_patrol_areas();
|
staff_update_greyed_patrol_areas();
|
||||||
}
|
}
|
||||||
|
@ -1258,8 +1245,11 @@ namespace RCT1
|
||||||
dst->PathfindGoal.direction = INVALID_DIRECTION;
|
dst->PathfindGoal.direction = INVALID_DIRECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportStaffPatrolArea(Staff* staffmember)
|
void ImportStaffPatrolArea(Staff* staffmember, uint8_t staffId)
|
||||||
{
|
{
|
||||||
|
// TODO: It is likely that S4 files should have a staffmode check before setting
|
||||||
|
// patrol areas. See S6 importer.
|
||||||
|
|
||||||
// The patrol areas in RCT1 are encoded as follows, for coordinates x and y, separately for every staff member:
|
// The patrol areas in RCT1 are encoded as follows, for coordinates x and y, separately for every staff member:
|
||||||
// - Chop off the 7 lowest bits of the x and y coordinates, which leaves 5 bits per coordinate.
|
// - Chop off the 7 lowest bits of the x and y coordinates, which leaves 5 bits per coordinate.
|
||||||
// This step also "produces" the 4x4 patrol squares.
|
// This step also "produces" the 4x4 patrol squares.
|
||||||
|
@ -1270,7 +1260,7 @@ namespace RCT1
|
||||||
// index in the array ----^ ^--- bit position in the 8-bit value
|
// index in the array ----^ ^--- bit position in the 8-bit value
|
||||||
// We do the opposite in this function to recover the x and y values.
|
// We do the opposite in this function to recover the x and y values.
|
||||||
|
|
||||||
int32_t peepOffset = staffmember->StaffId * RCT12_PATROL_AREA_SIZE;
|
int32_t peepOffset = staffId * RCT12_PATROL_AREA_SIZE;
|
||||||
for (int32_t i = 0; i < RCT12_PATROL_AREA_SIZE; i++)
|
for (int32_t i = 0; i < RCT12_PATROL_AREA_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (_s4.patrol_areas[peepOffset + i] == 0)
|
if (_s4.patrol_areas[peepOffset + i] == 0)
|
||||||
|
@ -2886,13 +2876,14 @@ namespace RCT1
|
||||||
dst->AssignedStaffType = StaffType(src->staff_type);
|
dst->AssignedStaffType = StaffType(src->staff_type);
|
||||||
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
|
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
|
||||||
dst->HireDate = src->park_entry_time;
|
dst->HireDate = src->park_entry_time;
|
||||||
dst->StaffId = src->staff_id;
|
|
||||||
dst->StaffOrders = src->staff_orders;
|
dst->StaffOrders = src->staff_orders;
|
||||||
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
||||||
dst->StaffLawnsMown = src->paid_to_enter;
|
dst->StaffLawnsMown = src->paid_to_enter;
|
||||||
dst->StaffGardensWatered = src->paid_on_rides;
|
dst->StaffGardensWatered = src->paid_on_rides;
|
||||||
dst->StaffLitterSwept = src->paid_on_food;
|
dst->StaffLitterSwept = src->paid_on_food;
|
||||||
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
||||||
|
|
||||||
|
ImportStaffPatrolArea(dst, src->staff_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void S4Importer::ImportEntity<Litter>(const RCT12SpriteBase& srcBase)
|
template<> void S4Importer::ImportEntity<Litter>(const RCT12SpriteBase& srcBase)
|
||||||
|
|
|
@ -747,6 +747,13 @@ struct RCT2SpritePeep : RCT12SpriteBase
|
||||||
};
|
};
|
||||||
assert_struct_size(RCT2SpritePeep, 0x100);
|
assert_struct_size(RCT2SpritePeep, 0x100);
|
||||||
|
|
||||||
|
enum class RCT2StaffMode : uint8_t
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Walk,
|
||||||
|
Patrol = 3
|
||||||
|
};
|
||||||
|
|
||||||
union RCT2Sprite
|
union RCT2Sprite
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -1025,7 +1032,7 @@ struct rct_s6_data
|
||||||
uint32_t next_guest_index;
|
uint32_t next_guest_index;
|
||||||
uint16_t grass_and_scenery_tilepos;
|
uint16_t grass_and_scenery_tilepos;
|
||||||
uint32_t patrol_areas[(RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT) * RCT12_PATROL_AREA_SIZE];
|
uint32_t patrol_areas[(RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT) * RCT12_PATROL_AREA_SIZE];
|
||||||
uint8_t staff_modes[RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT];
|
RCT2StaffMode staff_modes[RCT2_MAX_STAFF + RCT12_STAFF_TYPE_COUNT];
|
||||||
uint8_t pad_13CA73E;
|
uint8_t pad_13CA73E;
|
||||||
uint8_t pad_13CA73F;
|
uint8_t pad_13CA73F;
|
||||||
uint8_t byte_13CA740;
|
uint8_t byte_13CA740;
|
||||||
|
|
|
@ -523,8 +523,7 @@ void S6Exporter::Export()
|
||||||
ExportRideMeasurements();
|
ExportRideMeasurements();
|
||||||
_s6.next_guest_index = gNextGuestNumber;
|
_s6.next_guest_index = gNextGuestNumber;
|
||||||
_s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition;
|
_s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition;
|
||||||
std::memcpy(_s6.patrol_areas, gStaffPatrolAreas, sizeof(_s6.patrol_areas));
|
ExportStaffPatrolAreas();
|
||||||
std::memcpy(_s6.staff_modes, gStaffModes, sizeof(_s6.staff_modes));
|
|
||||||
// unk_13CA73E
|
// unk_13CA73E
|
||||||
// pad_13CA73F
|
// pad_13CA73F
|
||||||
// unk_13CA740
|
// unk_13CA740
|
||||||
|
@ -1107,6 +1106,48 @@ void S6Exporter::RebuildEntitySpatialLocation(const TileCoordsXY& loc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void S6Exporter::ExportStaffPatrolAreas()
|
||||||
|
{
|
||||||
|
std::fill(std::begin(_s6.staff_modes), std::end(_s6.staff_modes), RCT2StaffMode::None);
|
||||||
|
std::fill(std::begin(_s6.patrol_areas), std::end(_s6.patrol_areas), 0);
|
||||||
|
|
||||||
|
auto staffId = 0;
|
||||||
|
for (auto* staff : EntityList<Staff>())
|
||||||
|
{
|
||||||
|
if (staff->HasPatrolArea())
|
||||||
|
{
|
||||||
|
const size_t staffPatrolOffset = staffId * STAFF_PATROL_AREA_SIZE;
|
||||||
|
std::copy(
|
||||||
|
std::begin(staff->PatrolInfo->Data), std::end(staff->PatrolInfo->Data), &_s6.patrol_areas[staffPatrolOffset]);
|
||||||
|
_s6.staff_modes[staffId] = RCT2StaffMode::Patrol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_s6.staff_modes[staffId] = RCT2StaffMode::Walk;
|
||||||
|
}
|
||||||
|
|
||||||
|
_s6.sprites[staff->sprite_index].peep.staff_id = staffId;
|
||||||
|
|
||||||
|
staffId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto hasData = [](const auto& datapoint) { return datapoint != 0; };
|
||||||
|
for (const auto type : { StaffType::Handyman, StaffType::Mechanic, StaffType::Security, StaffType::Entertainer })
|
||||||
|
{
|
||||||
|
const size_t staffPatrolOffset = (EnumValue(type) + STAFF_MAX_COUNT) * STAFF_PATROL_AREA_SIZE;
|
||||||
|
const auto& area = GetMergedPatrolArea(type);
|
||||||
|
std::copy(std::begin(area.Data), std::end(area.Data), &_s6.patrol_areas[staffPatrolOffset]);
|
||||||
|
if (std::any_of(std::begin(area.Data), std::end(area.Data), hasData))
|
||||||
|
{
|
||||||
|
_s6.staff_modes[EnumValue(type) + STAFF_MAX_COUNT] = RCT2StaffMode::Patrol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_s6.staff_modes[EnumValue(type) + STAFF_MAX_COUNT] = RCT2StaffMode::Walk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void S6Exporter::RebuildEntityLinks()
|
void S6Exporter::RebuildEntityLinks()
|
||||||
{
|
{
|
||||||
// Rebuild next/previous linked list entity indexs
|
// Rebuild next/previous linked list entity indexs
|
||||||
|
@ -1422,7 +1463,6 @@ template<> void S6Exporter::ExportEntity(RCT2SpritePeep* dst, const Staff* src)
|
||||||
dst->staff_type = static_cast<uint8_t>(src->AssignedStaffType);
|
dst->staff_type = static_cast<uint8_t>(src->AssignedStaffType);
|
||||||
dst->mechanic_time_since_call = src->MechanicTimeSinceCall;
|
dst->mechanic_time_since_call = src->MechanicTimeSinceCall;
|
||||||
dst->park_entry_time = src->HireDate;
|
dst->park_entry_time = src->HireDate;
|
||||||
dst->staff_id = src->StaffId;
|
|
||||||
dst->staff_orders = src->StaffOrders;
|
dst->staff_orders = src->StaffOrders;
|
||||||
dst->staff_mowing_timeout = src->StaffMowingTimeout;
|
dst->staff_mowing_timeout = src->StaffMowingTimeout;
|
||||||
dst->paid_to_enter = src->StaffLawnsMown;
|
dst->paid_to_enter = src->StaffLawnsMown;
|
||||||
|
|
|
@ -80,4 +80,5 @@ private:
|
||||||
void ExportUserStrings();
|
void ExportUserStrings();
|
||||||
void RebuildEntityLinks();
|
void RebuildEntityLinks();
|
||||||
void RebuildEntitySpatialLocation(const TileCoordsXY& loc);
|
void RebuildEntitySpatialLocation(const TileCoordsXY& loc);
|
||||||
|
void ExportStaffPatrolAreas();
|
||||||
};
|
};
|
||||||
|
|
|
@ -421,8 +421,6 @@ public:
|
||||||
ImportRideMeasurements();
|
ImportRideMeasurements();
|
||||||
gNextGuestNumber = _s6.next_guest_index;
|
gNextGuestNumber = _s6.next_guest_index;
|
||||||
gGrassSceneryTileLoopPosition = _s6.grass_and_scenery_tilepos;
|
gGrassSceneryTileLoopPosition = _s6.grass_and_scenery_tilepos;
|
||||||
std::memcpy(gStaffPatrolAreas, _s6.patrol_areas, sizeof(_s6.patrol_areas));
|
|
||||||
std::memcpy(gStaffModes, _s6.staff_modes, sizeof(_s6.staff_modes));
|
|
||||||
// unk_13CA73E
|
// unk_13CA73E
|
||||||
// pad_13CA73F
|
// pad_13CA73F
|
||||||
// unk_13CA740
|
// unk_13CA740
|
||||||
|
@ -485,6 +483,7 @@ public:
|
||||||
FixLandOwnership();
|
FixLandOwnership();
|
||||||
|
|
||||||
research_determine_first_of_type();
|
research_determine_first_of_type();
|
||||||
|
staff_update_greyed_patrol_areas();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixLandOwnership() const
|
void FixLandOwnership() const
|
||||||
|
@ -1444,6 +1443,43 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImportStaffPatrolArea(Staff* staffmember, uint8_t staffId)
|
||||||
|
{
|
||||||
|
// First check staff mode as vanilla did not clean up patrol areas when switching from patrol to walk
|
||||||
|
// without doing this we could accidentally add a patrol when it didn't exist.
|
||||||
|
if (_s6.staff_modes[staffId] != RCT2StaffMode::Patrol)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32_t peepOffset = staffId * RCT12_PATROL_AREA_SIZE;
|
||||||
|
for (int32_t i = 0; i < RCT12_PATROL_AREA_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (_s6.patrol_areas[peepOffset + i] == 0)
|
||||||
|
{
|
||||||
|
// No patrol for this area
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over the bits of the uint32_t
|
||||||
|
for (int32_t j = 0; j < 32; j++)
|
||||||
|
{
|
||||||
|
int8_t bit = (_s6.patrol_areas[peepOffset + i] >> j) & 1;
|
||||||
|
if (bit == 0)
|
||||||
|
{
|
||||||
|
// No patrol for this area
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// val contains the 6 highest bits of both the x and y coordinates
|
||||||
|
int32_t val = j | (i << 5);
|
||||||
|
int32_t x = val & 0x03F;
|
||||||
|
x <<= 7;
|
||||||
|
int32_t y = val & 0xFC0;
|
||||||
|
y <<= 1;
|
||||||
|
staffmember->SetPatrolArea({ x, y }, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImportEntities()
|
void ImportEntities()
|
||||||
{
|
{
|
||||||
for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++)
|
for (int32_t i = 0; i < RCT2_MAX_SPRITES; i++)
|
||||||
|
@ -1866,13 +1902,14 @@ template<> void S6Importer::ImportEntity<Staff>(const RCT12SpriteBase& baseSrc)
|
||||||
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
|
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
|
||||||
|
|
||||||
dst->HireDate = src->park_entry_time;
|
dst->HireDate = src->park_entry_time;
|
||||||
dst->StaffId = src->staff_id;
|
|
||||||
dst->StaffOrders = src->staff_orders;
|
dst->StaffOrders = src->staff_orders;
|
||||||
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
||||||
dst->StaffLawnsMown = src->paid_to_enter;
|
dst->StaffLawnsMown = src->paid_to_enter;
|
||||||
dst->StaffGardensWatered = src->paid_on_rides;
|
dst->StaffGardensWatered = src->paid_on_rides;
|
||||||
dst->StaffLitterSwept = src->paid_on_food;
|
dst->StaffLitterSwept = src->paid_on_food;
|
||||||
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
||||||
|
|
||||||
|
ImportStaffPatrolArea(dst, src->staff_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void S6Importer::ImportEntity<SteamParticle>(const RCT12SpriteBase& baseSrc)
|
template<> void S6Importer::ImportEntity<SteamParticle>(const RCT12SpriteBase& baseSrc)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../localisation/Localisation.h"
|
#include "../localisation/Localisation.h"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
#include "../paint/VirtualFloor.h"
|
#include "../paint/VirtualFloor.h"
|
||||||
|
#include "../peep/Staff.h"
|
||||||
#include "../ui/UiContext.h"
|
#include "../ui/UiContext.h"
|
||||||
#include "../ui/WindowManager.h"
|
#include "../ui/WindowManager.h"
|
||||||
#include "../util/Util.h"
|
#include "../util/Util.h"
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
# include "ScStaff.hpp"
|
# include "ScStaff.hpp"
|
||||||
|
|
||||||
|
# include "../../../peep/Staff.h"
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
ScStaff::ScStaff(uint16_t Id)
|
ScStaff::ScStaff(uint16_t Id)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
# include "ScMap.hpp"
|
# include "ScMap.hpp"
|
||||||
|
|
||||||
# include "../../../common.h"
|
# include "../../../common.h"
|
||||||
|
# include "../../../peep/Staff.h"
|
||||||
# include "../../../ride/Ride.h"
|
# include "../../../ride/Ride.h"
|
||||||
# include "../../../ride/TrainManager.h"
|
# include "../../../ride/TrainManager.h"
|
||||||
# include "../../../world/Balloon.h"
|
# include "../../../world/Balloon.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "../core/DataSerialiser.h"
|
#include "../core/DataSerialiser.h"
|
||||||
#include "../peep/Peep.h"
|
#include "../peep/Peep.h"
|
||||||
|
#include "../peep/Staff.h"
|
||||||
#include "../ride/Vehicle.h"
|
#include "../ride/Vehicle.h"
|
||||||
#include "Balloon.h"
|
#include "Balloon.h"
|
||||||
#include "Duck.h"
|
#include "Duck.h"
|
||||||
|
@ -223,7 +224,6 @@ void Staff::Serialise(DataSerialiser& stream)
|
||||||
stream << AssignedStaffType;
|
stream << AssignedStaffType;
|
||||||
stream << MechanicTimeSinceCall;
|
stream << MechanicTimeSinceCall;
|
||||||
stream << HireDate;
|
stream << HireDate;
|
||||||
stream << StaffId;
|
|
||||||
stream << StaffOrders;
|
stream << StaffOrders;
|
||||||
stream << StaffMowingTimeout;
|
stream << StaffMowingTimeout;
|
||||||
stream << StaffLawnsMown;
|
stream << StaffLawnsMown;
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
#include "EntityTweener.h"
|
#include "EntityTweener.h"
|
||||||
|
|
||||||
#include "../peep/Peep.h"
|
#include "../peep/Peep.h"
|
||||||
|
#include "../peep/Staff.h"
|
||||||
#include "../ride/Vehicle.h"
|
#include "../ride/Vehicle.h"
|
||||||
#include "EntityList.h"
|
#include "EntityList.h"
|
||||||
#include "Sprite.h"
|
#include "Sprite.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
void EntityTweener::PopulateEntities()
|
void EntityTweener::PopulateEntities()
|
||||||
{
|
{
|
||||||
for (auto ent : EntityList<Guest>())
|
for (auto ent : EntityList<Guest>())
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "../interface/Viewport.h"
|
#include "../interface/Viewport.h"
|
||||||
#include "../peep/Peep.h"
|
#include "../peep/Peep.h"
|
||||||
#include "../peep/RideUseSystem.h"
|
#include "../peep/RideUseSystem.h"
|
||||||
|
#include "../peep/Staff.h"
|
||||||
#include "../ride/Vehicle.h"
|
#include "../ride/Vehicle.h"
|
||||||
#include "../scenario/Scenario.h"
|
#include "../scenario/Scenario.h"
|
||||||
#include "Balloon.h"
|
#include "Balloon.h"
|
||||||
|
@ -555,6 +556,7 @@ static void FreeEntity(EntityBase& entity)
|
||||||
if (staff != nullptr)
|
if (staff != nullptr)
|
||||||
{
|
{
|
||||||
staff->SetName({});
|
staff->SetName({});
|
||||||
|
staff->ClearPatrolArea();
|
||||||
}
|
}
|
||||||
else if (guest != nullptr)
|
else if (guest != nullptr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue