diff --git a/distribution/changelog.txt b/distribution/changelog.txt index b1b898209d..a6fac3a6d7 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -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) ------------------------------------------------------------------------ diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 4cc2078b17..473648a89c 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -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. diff --git a/src/openrct2/core/EnumMap.hpp b/src/openrct2/core/EnumMap.hpp index bcf96ffb2b..f34562c163 100644 --- a/src/openrct2/core/EnumMap.hpp +++ b/src/openrct2/core/EnumMap.hpp @@ -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{}; diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index c1e58ba9f7..1928121cd8 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -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(value); - SpriteType = EntertainerCostumeToSprite(costume); - UpdateAction(); -} - void Staff::SetHireDate(int32_t hireDate) { HireDate = hireDate; diff --git a/src/openrct2/entity/Staff.h b/src/openrct2/entity/Staff.h index e8cc7b4c62..871dafc993 100644 --- a/src/openrct2/entity/Staff.h +++ b/src/openrct2/entity/Staff.h @@ -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; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index e0e64948bd..381044d17d 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -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; diff --git a/src/openrct2/scripting/bindings/entity/ScStaff.cpp b/src/openrct2/scripting/bindings/entity/ScStaff.cpp index 1796decbac..dbc31aa15f 100644 --- a/src/openrct2/scripting/bindings/entity/ScStaff.cpp +++ b/src/openrct2/scripting/bindings/entity/ScStaff.cpp @@ -26,6 +26,7 @@ namespace OpenRCT2::Scripting dukglue_set_base_class(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 availableHandymanCostumes({ + { "handyman", PeepSpriteType::Handyman }, + }); + + static const DukEnumMap availableMechanicCostumes({ + { "mechanic", PeepSpriteType::Mechanic }, + }); + + static const DukEnumMap availableSecurityCostumes({ + { "security1", PeepSpriteType::Security }, + { "security2", PeepSpriteType::SecurityAlt }, + }); + + static const DukEnumMap 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& 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 ScStaff::availableCostumes_get() const { - ThrowIfGameStateNotMutable(); + std::vector 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 ScStaff::patrolArea_get() const diff --git a/src/openrct2/scripting/bindings/entity/ScStaff.hpp b/src/openrct2/scripting/bindings/entity/ScStaff.hpp index 0cd72b7473..a6f79c3523 100644 --- a/src/openrct2/scripting/bindings/entity/ScStaff.hpp +++ b/src/openrct2/scripting/bindings/entity/ScStaff.hpp @@ -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 availableCostumes_get() const; + std::string costume_get() const; + void costume_set(const DukValue& value); std::shared_ptr patrolArea_get() const;