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_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_SHA1 "C47048B71A95A95428A08035C94AD10E7A020D4D")
|
||||
set(REPLAYS_SHA1 "DF9C3B48755B19FDD4D0EC721007B98CD5B6F420")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
<TitleSequencesSha1>304d13a126c15bf2c86ff13b81a2f2cc1856ac8d</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>c38af45d51a6e440386180feacf76c64720b6ac5</ObjectsSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.56/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>C47048B71A95A95428A08035C94AD10E7A020D4D</ReplaysSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.57/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>DF9C3B48755B19FDD4D0EC721007B98CD5B6F420</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <openrct2/actions/SmallSceneryRemoveAction.h>
|
||||
#include <openrct2/actions/WallRemoveAction.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/peep/Staff.h>
|
||||
#include <openrct2/ride/Ride.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
#include <openrct2/ride/Track.h>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <openrct2/actions/SurfaceSetStyleAction.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/peep/Staff.h>
|
||||
#include <openrct2/ride/RideData.h>
|
||||
#include <openrct2/ride/Track.h>
|
||||
#include <openrct2/ride/TrainManager.h>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/interface/Colour.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/peep/Staff.h>
|
||||
#include <openrct2/world/Entity.h>
|
||||
|
||||
static constexpr const rct_string_id WINDOW_TITLE = STR_SACK_STAFF;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "core/CircularBuffer.h"
|
||||
#include "peep/Peep.h"
|
||||
#include "peep/Staff.h"
|
||||
#include "ride/Vehicle.h"
|
||||
#include "world/Balloon.h"
|
||||
#include "world/Duck.h"
|
||||
|
@ -296,7 +297,6 @@ struct GameStateSnapshots final : public IGameStateSnapshots
|
|||
COMPARE_FIELD(Staff, AssignedStaffType);
|
||||
COMPARE_FIELD(Staff, MechanicTimeSinceCall);
|
||||
COMPARE_FIELD(Staff, HireDate);
|
||||
COMPARE_FIELD(Staff, StaffId);
|
||||
COMPARE_FIELD(Staff, StaffOrders);
|
||||
COMPARE_FIELD(Staff, StaffMowingTimeout);
|
||||
COMPARE_FIELD(Staff, StaffRidesFixed);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../localisation/Localisation.h"
|
||||
#include "../localisation/StringIds.h"
|
||||
#include "../network/network.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../ride/Ride.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
#include "../scenario/Scenario.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "StaffFireAction.h"
|
||||
|
||||
#include "../interface/Window.h"
|
||||
#include "../peep/Peep.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../world/Entity.h"
|
||||
|
||||
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.
|
||||
int32_t staffIndex;
|
||||
for (staffIndex = 0; staffIndex < STAFF_MAX_COUNT; ++staffIndex)
|
||||
{
|
||||
if (gStaffModes[staffIndex] == StaffMode::None)
|
||||
break;
|
||||
}
|
||||
|
||||
if (staffIndex == STAFF_MAX_COUNT)
|
||||
auto numStaff = GetEntityListCount(EntityType::Staff);
|
||||
if (numStaff == STAFF_MAX_COUNT)
|
||||
{
|
||||
// Too many staff members exist already.
|
||||
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->StaffMowingTimeout = 0;
|
||||
|
||||
newPeep->StaffId = staffIndex;
|
||||
|
||||
gStaffModes[staffIndex] = StaffMode::Walk;
|
||||
|
||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
||||
{
|
||||
gStaffPatrolAreas[staffIndex * STAFF_PATROL_AREA_SIZE + i] = 0;
|
||||
}
|
||||
newPeep->PatrolInfo = nullptr;
|
||||
|
||||
res->SetData(StaffHireNewActionResult{ newPeep->sprite_index });
|
||||
}
|
||||
|
|
|
@ -55,29 +55,6 @@ GameActions::Result::Ptr StaffSetPatrolAreaAction::Query() const
|
|||
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)
|
||||
{
|
||||
// Align the location to the top left of the patrol square
|
||||
|
@ -104,12 +81,14 @@ GameActions::Result::Ptr StaffSetPatrolAreaAction::Execute() const
|
|||
{
|
||||
case StaffSetPatrolAreaMode::Set:
|
||||
staff->SetPatrolArea(_loc, true);
|
||||
UpdateStaffMode(*staff);
|
||||
InvalidatePatrolTile(_loc);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::Unset:
|
||||
staff->SetPatrolArea(_loc, false);
|
||||
UpdateStaffMode(*staff);
|
||||
if (!staff->HasPatrolArea())
|
||||
{
|
||||
staff->ClearPatrolArea();
|
||||
}
|
||||
InvalidatePatrolTile(_loc);
|
||||
break;
|
||||
case StaffSetPatrolAreaMode::ClearAll:
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
// This string specifies which version of network stream current build uses.
|
||||
// It is used for making sure only compatible builds get connected, even within
|
||||
// single OpenRCT2 version.
|
||||
#define NETWORK_STREAM_VERSION "15"
|
||||
#define NETWORK_STREAM_VERSION "16"
|
||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||
|
||||
static Peep* _pickup_peep = nullptr;
|
||||
|
|
|
@ -655,7 +655,6 @@ void peep_sprite_remove(Peep* peep)
|
|||
else
|
||||
{
|
||||
staff->ClearPatrolArea();
|
||||
gStaffModes[staff->StaffId] = StaffMode::None;
|
||||
staff_update_greyed_patrol_areas();
|
||||
|
||||
News::DisableNewsItems(News::ItemType::Peep, staff->sprite_index);
|
||||
|
|
|
@ -838,104 +838,7 @@ private:
|
|||
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(Staff) <= 512);
|
||||
|
||||
struct rct_sprite_bounds
|
||||
{
|
||||
|
|
|
@ -61,15 +61,18 @@ const rct_string_id StaffCostumeNames[] = {
|
|||
};
|
||||
// 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;
|
||||
colour_t gStaffHandymanColour;
|
||||
colour_t gStaffMechanicColour;
|
||||
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
|
||||
const uint16_t MAX_LITTER_DISTANCE = 3 * COORDS_XY_STEP;
|
||||
|
||||
|
@ -84,12 +87,6 @@ template<> bool EntityBase::Is<Staff>() const
|
|||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -142,27 +139,27 @@ bool staff_hire_new_member(StaffType staffType, EntertainerCostume entertainerTy
|
|||
*/
|
||||
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;
|
||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
||||
{
|
||||
gStaffPatrolAreas[staffPatrolOffset + i] = 0;
|
||||
}
|
||||
// Reset all of the merged data for the type.
|
||||
auto& mergedData = _mergedPatrolAreas[staffType].Data;
|
||||
std::fill(std::begin(mergedData), std::end(mergedData), 0);
|
||||
|
||||
for (auto peep : EntityList<Staff>())
|
||||
for (auto staff : EntityList<Staff>())
|
||||
{
|
||||
if (!peep->HasPatrolArea())
|
||||
if (EnumValue(staff->AssignedStaffType) != staffType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (static_cast<uint8_t>(peep->AssignedStaffType) == staff_type)
|
||||
if (!staff->HasPatrolArea())
|
||||
{
|
||||
const size_t peepPatrolOffset = peep->StaffId * STAFF_PATROL_AREA_SIZE;
|
||||
for (size_t i = 0; i < STAFF_PATROL_AREA_SIZE; i++)
|
||||
{
|
||||
gStaffPatrolAreas[staffPatrolOffset + i] |= gStaffPatrolAreas[peepPatrolOffset + i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Patrol areas are 4 * 4 tiles (32 * 4) = 128 = 2^^7
|
||||
auto tilePos = TileCoordsXY(coords);
|
||||
auto x = tilePos.x / 4;
|
||||
auto y = tilePos.y / 4;
|
||||
|
@ -379,34 +375,37 @@ static std::pair<int32_t, int32_t> getPatrolAreaOffsetIndex(const CoordsXY& coor
|
|||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int32_t peepOffset = StaffId * STAFF_PATROL_AREA_SIZE;
|
||||
if (PatrolInfo == nullptr)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
PatrolInfo = new PatrolArea();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto [offset, bitIndex] = getPatrolAreaOffsetIndex(coords);
|
||||
uint32_t* addr = &gStaffPatrolAreas[peepOffset + offset];
|
||||
auto* addr = &PatrolInfo->Data[offset];
|
||||
if (value)
|
||||
{
|
||||
*addr |= (1 << bitIndex);
|
||||
|
@ -419,21 +418,17 @@ void Staff::SetPatrolArea(const CoordsXY& coords, bool value)
|
|||
|
||||
void Staff::ClearPatrolArea()
|
||||
{
|
||||
const auto peepOffset = StaffId * STAFF_PATROL_AREA_SIZE;
|
||||
std::fill_n(&gStaffPatrolAreas[peepOffset], STAFF_PATROL_AREA_SIZE, 0);
|
||||
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);
|
||||
delete PatrolInfo;
|
||||
PatrolInfo = nullptr;
|
||||
}
|
||||
|
||||
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_SIZE = (STAFF_PATROL_AREA_BLOCKS_PER_LINE * STAFF_PATROL_AREA_BLOCKS_PER_LINE) / 32;
|
||||
|
||||
enum class StaffMode : uint8_t
|
||||
struct PatrolArea
|
||||
{
|
||||
None,
|
||||
Walk,
|
||||
Patrol = 3
|
||||
uint32_t Data[STAFF_PATROL_AREA_SIZE];
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
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 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 colour_t gStaffHandymanColour;
|
||||
extern colour_t gStaffMechanicColour;
|
||||
|
@ -73,3 +165,5 @@ int32_t staff_get_available_entertainer_costume_list(EntertainerCostume* costume
|
|||
|
||||
money32 GetStaffWage(StaffType type);
|
||||
PeepSpriteType EntertainerCostumeToSprite(EntertainerCostume entertainerType);
|
||||
|
||||
const PatrolArea& GetMergedPatrolArea(const StaffType type);
|
||||
|
|
|
@ -1183,19 +1183,6 @@ namespace RCT1
|
|||
|
||||
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
|
||||
staff_update_greyed_patrol_areas();
|
||||
}
|
||||
|
@ -1258,8 +1245,11 @@ namespace RCT1
|
|||
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:
|
||||
// - 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.
|
||||
|
@ -1270,7 +1260,7 @@ namespace RCT1
|
|||
// 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.
|
||||
|
||||
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++)
|
||||
{
|
||||
if (_s4.patrol_areas[peepOffset + i] == 0)
|
||||
|
@ -2886,13 +2876,14 @@ namespace RCT1
|
|||
dst->AssignedStaffType = StaffType(src->staff_type);
|
||||
dst->MechanicTimeSinceCall = src->mechanic_time_since_call;
|
||||
dst->HireDate = src->park_entry_time;
|
||||
dst->StaffId = src->staff_id;
|
||||
dst->StaffOrders = src->staff_orders;
|
||||
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
||||
dst->StaffLawnsMown = src->paid_to_enter;
|
||||
dst->StaffGardensWatered = src->paid_on_rides;
|
||||
dst->StaffLitterSwept = src->paid_on_food;
|
||||
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
||||
|
||||
ImportStaffPatrolArea(dst, src->staff_id);
|
||||
}
|
||||
|
||||
template<> void S4Importer::ImportEntity<Litter>(const RCT12SpriteBase& srcBase)
|
||||
|
|
|
@ -747,6 +747,13 @@ struct RCT2SpritePeep : RCT12SpriteBase
|
|||
};
|
||||
assert_struct_size(RCT2SpritePeep, 0x100);
|
||||
|
||||
enum class RCT2StaffMode : uint8_t
|
||||
{
|
||||
None,
|
||||
Walk,
|
||||
Patrol = 3
|
||||
};
|
||||
|
||||
union RCT2Sprite
|
||||
{
|
||||
private:
|
||||
|
@ -1025,7 +1032,7 @@ struct rct_s6_data
|
|||
uint32_t next_guest_index;
|
||||
uint16_t grass_and_scenery_tilepos;
|
||||
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_13CA73F;
|
||||
uint8_t byte_13CA740;
|
||||
|
|
|
@ -523,8 +523,7 @@ void S6Exporter::Export()
|
|||
ExportRideMeasurements();
|
||||
_s6.next_guest_index = gNextGuestNumber;
|
||||
_s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition;
|
||||
std::memcpy(_s6.patrol_areas, gStaffPatrolAreas, sizeof(_s6.patrol_areas));
|
||||
std::memcpy(_s6.staff_modes, gStaffModes, sizeof(_s6.staff_modes));
|
||||
ExportStaffPatrolAreas();
|
||||
// unk_13CA73E
|
||||
// pad_13CA73F
|
||||
// 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()
|
||||
{
|
||||
// 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->mechanic_time_since_call = src->MechanicTimeSinceCall;
|
||||
dst->park_entry_time = src->HireDate;
|
||||
dst->staff_id = src->StaffId;
|
||||
dst->staff_orders = src->StaffOrders;
|
||||
dst->staff_mowing_timeout = src->StaffMowingTimeout;
|
||||
dst->paid_to_enter = src->StaffLawnsMown;
|
||||
|
|
|
@ -80,4 +80,5 @@ private:
|
|||
void ExportUserStrings();
|
||||
void RebuildEntityLinks();
|
||||
void RebuildEntitySpatialLocation(const TileCoordsXY& loc);
|
||||
void ExportStaffPatrolAreas();
|
||||
};
|
||||
|
|
|
@ -421,8 +421,6 @@ public:
|
|||
ImportRideMeasurements();
|
||||
gNextGuestNumber = _s6.next_guest_index;
|
||||
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
|
||||
// pad_13CA73F
|
||||
// unk_13CA740
|
||||
|
@ -485,6 +483,7 @@ public:
|
|||
FixLandOwnership();
|
||||
|
||||
research_determine_first_of_type();
|
||||
staff_update_greyed_patrol_areas();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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->HireDate = src->park_entry_time;
|
||||
dst->StaffId = src->staff_id;
|
||||
dst->StaffOrders = src->staff_orders;
|
||||
dst->StaffMowingTimeout = src->staff_mowing_timeout;
|
||||
dst->StaffLawnsMown = src->paid_to_enter;
|
||||
dst->StaffGardensWatered = src->paid_on_rides;
|
||||
dst->StaffLitterSwept = src->paid_on_food;
|
||||
dst->StaffBinsEmptied = src->paid_on_souvenirs;
|
||||
|
||||
ImportStaffPatrolArea(dst, src->staff_id);
|
||||
}
|
||||
|
||||
template<> void S6Importer::ImportEntity<SteamParticle>(const RCT12SpriteBase& baseSrc)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../localisation/Localisation.h"
|
||||
#include "../network/network.h"
|
||||
#include "../paint/VirtualFloor.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../ui/UiContext.h"
|
||||
#include "../ui/WindowManager.h"
|
||||
#include "../util/Util.h"
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
# include "ScStaff.hpp"
|
||||
|
||||
# include "../../../peep/Staff.h"
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
ScStaff::ScStaff(uint16_t Id)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# include "ScMap.hpp"
|
||||
|
||||
# include "../../../common.h"
|
||||
# include "../../../peep/Staff.h"
|
||||
# include "../../../ride/Ride.h"
|
||||
# include "../../../ride/TrainManager.h"
|
||||
# include "../../../world/Balloon.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "../core/DataSerialiser.h"
|
||||
#include "../peep/Peep.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
#include "Balloon.h"
|
||||
#include "Duck.h"
|
||||
|
@ -223,7 +224,6 @@ void Staff::Serialise(DataSerialiser& stream)
|
|||
stream << AssignedStaffType;
|
||||
stream << MechanicTimeSinceCall;
|
||||
stream << HireDate;
|
||||
stream << StaffId;
|
||||
stream << StaffOrders;
|
||||
stream << StaffMowingTimeout;
|
||||
stream << StaffLawnsMown;
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
#include "EntityTweener.h"
|
||||
|
||||
#include "../peep/Peep.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
#include "EntityList.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
void EntityTweener::PopulateEntities()
|
||||
{
|
||||
for (auto ent : EntityList<Guest>())
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../interface/Viewport.h"
|
||||
#include "../peep/Peep.h"
|
||||
#include "../peep/RideUseSystem.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "../ride/Vehicle.h"
|
||||
#include "../scenario/Scenario.h"
|
||||
#include "Balloon.h"
|
||||
|
@ -555,6 +556,7 @@ static void FreeEntity(EntityBase& entity)
|
|||
if (staff != nullptr)
|
||||
{
|
||||
staff->SetName({});
|
||||
staff->ClearPatrolArea();
|
||||
}
|
||||
else if (guest != nullptr)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue