1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Scripting: tailor costume assignment to each staff type

In order to transition staff costumes to objects, we must further disentangle staff from regular peeps. This has many advantages, such as making custom entertainers or even handymen costumes. However, this means putting some restrictions on what costumes can be assigned to staff in the mean while.

We are aware of plug-ins allowing staff to be decorated like normal peeps, though, e.g. using @Manticore-007's Peep Editor. Splitting staff from peeps will mean breaking such functionality. We can do our very best to reverting 'invalid' staff to their normal outfits instead of them outright disappearing. However, in the mean time, we should disallow peep costumes from being assigned to staff to prevent further disappointment down the line.

Once we get to actually adding custom staff costumes, I plan to add a new plug-in API to get available costumes for a particular staff type. This would apply to entertainers, but also other staff types. This should make it easier for plug-in authors to tap into custom costumes in the future.
This commit is contained in:
Aaron van Geffen
2024-05-05 22:41:52 +02:00
committed by GitHub
parent 46b356047c
commit 831c7651bb
8 changed files with 134 additions and 29 deletions

View File

@@ -1,5 +1,6 @@
0.4.12 (in development)
------------------------------------------------------------------------
- Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type.
0.4.11 (2024-05-05)
------------------------------------------------------------------------

View File

@@ -3095,6 +3095,24 @@ declare global {
readonly item: GuestItemType;
}
type StaffCostume =
"none" |
"handyman" |
"mechanic" |
"security1" |
"security2" |
"panda" |
"tiger" |
"elephant" |
"roman" |
"gorilla" |
"snowman" |
"knight" |
"astronaut" |
"bandit" |
"sheriff" |
"pirate";
/**
* Represents a staff member.
*/
@@ -3105,14 +3123,19 @@ declare global {
staffType: StaffType;
/**
* Colour of the staff member. Not applicable for entertainers.
* Colour of the staff member. Not applicable to entertainers.
*/
colour: number;
/**
* The entertainer's costume, only applicable for entertainers.
* Array of costumes available to this particular staff member.
*/
costume: number;
readonly availableCostumes: StaffCostume[];
/**
* The staff member's costume.
*/
costume: StaffCostume | string | number;
/**
* The enabled jobs the staff can do, e.g. sweep litter, water plants, inspect rides etc.

View File

@@ -62,7 +62,7 @@ public:
{
std::sort(_map.begin(), _map.end(), [](const auto& a, const auto& b) { return a.second < b.second; });
if constexpr (ValueIndexable())
if (ValueIndexable() && _map.size() > 1)
{
_continiousValueIndex = true;
T cur{};

View File

@@ -947,18 +947,6 @@ bool Staff::DoPathFinding()
}
}
uint8_t Staff::GetCostume() const
{
return EnumValue(SpriteType) - EnumValue(PeepSpriteType::EntertainerPanda);
}
void Staff::SetCostume(uint8_t value)
{
auto costume = static_cast<EntertainerCostume>(value);
SpriteType = EntertainerCostumeToSprite(costume);
UpdateAction();
}
void Staff::SetHireDate(int32_t hireDate)
{
HireDate = hireDate;

View File

@@ -51,8 +51,6 @@ public:
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;

View File

@@ -47,7 +47,7 @@ namespace OpenRCT2
namespace OpenRCT2::Scripting
{
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 85;
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 86;
// Versions marking breaking changes.
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;

View File

@@ -26,6 +26,7 @@ namespace OpenRCT2::Scripting
dukglue_set_base_class<ScPeep, ScStaff>(ctx);
dukglue_register_property(ctx, &ScStaff::staffType_get, &ScStaff::staffType_set, "staffType");
dukglue_register_property(ctx, &ScStaff::colour_get, &ScStaff::colour_set, "colour");
dukglue_register_property(ctx, &ScStaff::availableCostumes_get, nullptr, "availableCostumes");
dukglue_register_property(ctx, &ScStaff::costume_get, &ScStaff::costume_set, "costume");
dukglue_register_property(ctx, &ScStaff::patrolArea_get, nullptr, "patrolArea");
dukglue_register_property(ctx, &ScStaff::orders_get, &ScStaff::orders_set, "orders");
@@ -108,24 +109,117 @@ namespace OpenRCT2::Scripting
}
}
uint8_t ScStaff::costume_get() const
static const DukEnumMap<PeepSpriteType> availableHandymanCostumes({
{ "handyman", PeepSpriteType::Handyman },
});
static const DukEnumMap<PeepSpriteType> availableMechanicCostumes({
{ "mechanic", PeepSpriteType::Mechanic },
});
static const DukEnumMap<PeepSpriteType> availableSecurityCostumes({
{ "security1", PeepSpriteType::Security },
{ "security2", PeepSpriteType::SecurityAlt },
});
static const DukEnumMap<PeepSpriteType> availableEntertainerCostumes({
{ "none", PeepSpriteType::Normal },
{ "panda", PeepSpriteType::EntertainerPanda },
{ "tiger", PeepSpriteType::EntertainerTiger },
{ "elephant", PeepSpriteType::EntertainerElephant },
{ "roman", PeepSpriteType::EntertainerRoman },
{ "gorilla", PeepSpriteType::EntertainerGorilla },
{ "snowman", PeepSpriteType::EntertainerSnowman },
{ "knight", PeepSpriteType::EntertainerKnight },
{ "astronaut", PeepSpriteType::EntertainerAstronaut },
{ "bandit", PeepSpriteType::EntertainerBandit },
{ "sheriff", PeepSpriteType::EntertainerSheriff },
{ "pirate", PeepSpriteType::EntertainerPirate },
});
static const DukEnumMap<PeepSpriteType>& costumesByStaffType(StaffType staffType)
{
auto peep = GetStaff();
if (peep != nullptr && peep->AssignedStaffType == StaffType::Entertainer)
switch (staffType)
{
return peep->GetCostume();
case StaffType::Handyman:
return availableHandymanCostumes;
case StaffType::Mechanic:
return availableMechanicCostumes;
case StaffType::Security:
return availableSecurityCostumes;
case StaffType::Entertainer:
default:
return availableEntertainerCostumes;
}
return 0;
}
void ScStaff::costume_set(uint8_t value)
std::vector<std::string> ScStaff::availableCostumes_get() const
{
ThrowIfGameStateNotMutable();
std::vector<std::string> availableCostumes{};
auto peep = GetStaff();
if (peep != nullptr)
{
peep->SetCostume(value);
for (auto& costume : costumesByStaffType(peep->AssignedStaffType))
{
availableCostumes.push_back(std::string(costume.first));
}
}
return availableCostumes;
}
std::string ScStaff::costume_get() const
{
auto peep = GetStaff();
if (peep == nullptr)
{
return nullptr;
}
auto& availableCostumes = costumesByStaffType(peep->AssignedStaffType);
auto costume = availableCostumes.find(peep->SpriteType);
if (costume != availableCostumes.end())
{
return std::string(costume->first);
}
else
return nullptr;
}
void ScStaff::costume_set(const DukValue& value)
{
ThrowIfGameStateNotMutable();
auto peep = GetStaff();
if (peep == nullptr)
{
return;
}
auto& availableCostumes = costumesByStaffType(peep->AssignedStaffType);
// Split by type passed so as to not break old plugins
if (value.type() == DukValue::Type::STRING)
{
std::string newCostume = value.as_string();
auto newSpriteType = availableCostumes.TryGet(newCostume);
if (newSpriteType != std::nullopt)
{
peep->SpriteType = *newSpriteType;
return;
}
}
else if (value.type() == DukValue::Type::NUMBER)
{
auto newSpriteType = PeepSpriteType(value.as_uint() + EnumValue(PeepSpriteType::EntertainerPanda));
if (availableCostumes.find(newSpriteType) != availableCostumes.end())
{
peep->SpriteType = newSpriteType;
return;
}
}
throw DukException() << "Invalid costume for this staff member";
}
std::shared_ptr<ScPatrolArea> ScStaff::patrolArea_get() const

View File

@@ -56,8 +56,9 @@ namespace OpenRCT2::Scripting
uint8_t colour_get() const;
void colour_set(uint8_t value);
uint8_t costume_get() const;
void costume_set(uint8_t value);
std::vector<std::string> availableCostumes_get() const;
std::string costume_get() const;
void costume_set(const DukValue& value);
std::shared_ptr<ScPatrolArea> patrolArea_get() const;