diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 5f2561f04c..d87043a963 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -720,20 +720,25 @@ declare global { * Represents a guest or staff member. */ interface Peep extends Entity { + /** + * Whether the peep is a guest or staff member. + */ + peepType: PeepType; + /** * Name of the peep. */ name: string; /** - * Colour of the peep's t-shirt. + * Main flags for peep behaviour. */ - tshirtColour: number; + flags: number; /** - * Colour of the peep's trousers. + * The peep's direct destination. */ - trousersColour: number; + destination: CoordsXY; /** * How tired the guest is between 32 and 128 where lower is more tired. @@ -744,6 +749,38 @@ declare global { * The target energy value. Energy will increase / decrease slowly towards this value. */ energyTarget: number; + } + + type PeepType = "guest" | "staff"; + + /** + * Represents a guest. + */ + interface Guest extends Peep { + /** + * Colour of the guest's t-shirt. + */ + tshirtColour: number; + + /** + * Colour of the guest's trousers. + */ + trousersColour: number; + + /** + * Colour of the guest's balloon. + */ + balloonColour: number; + + /** + * Colour of the guest's hat. + */ + hatColour: number; + + /** + * Colour of the guest's umbrella. + */ + umbrellaColour: number; /** * How happy the guest is between 0 and 255. @@ -806,6 +843,33 @@ declare global { cash: number; } + /** + * Represents a staff member. + */ + interface Staff extends Peep { + /** + * The type of staff member, e.g. handyman, mechanic. + */ + staffType: StaffType; + + /** + * Colour of the staff member. Not applicable for entertainers. + */ + colour: number; + + /** + * The entertainer's costume, only applicable for entertainers. + */ + costume: number; + + /** + * The enabled jobs the staff can do, e.g. sweep litter, water plants, inspect rides etc. + */ + orders: number; + } + + type StaffType = "handyman" | "mechanic" | "security" | "entertainer"; + /** * Network APIs * Use `network.status` to determine whether the current game is a client, server or in single player mode. diff --git a/src/openrct2/peep/Peep.h b/src/openrct2/peep/Peep.h index 6aa33c773d..c7f627d035 100644 --- a/src/openrct2/peep/Peep.h +++ b/src/openrct2/peep/Peep.h @@ -893,6 +893,8 @@ public: bool IsPatrolAreaSet(const CoordsXY& coords) const; bool IsLocationInPatrol(const CoordsXY& loc) const; bool DoPathFinding(); + uint8_t GetCostume() const; + void SetCostume(uint8_t value); private: void UpdatePatrolling(); diff --git a/src/openrct2/peep/Staff.cpp b/src/openrct2/peep/Staff.cpp index 872fda74d8..04367258d0 100644 --- a/src/openrct2/peep/Staff.cpp +++ b/src/openrct2/peep/Staff.cpp @@ -1100,6 +1100,16 @@ bool Staff::DoPathFinding() } } +uint8_t Staff::GetCostume() const +{ + return sprite_type - PEEP_SPRITE_TYPE_ENTERTAINER_PANDA; +} + +void Staff::SetCostume(uint8_t value) +{ + sprite_type = static_cast(value + PEEP_SPRITE_TYPE_ENTERTAINER_PANDA); +} + colour_t staff_get_colour(uint8_t staffType) { switch (staffType) diff --git a/src/openrct2/scripting/ScEntity.hpp b/src/openrct2/scripting/ScEntity.hpp index 4cb3360f9b..9383eeb68e 100644 --- a/src/openrct2/scripting/ScEntity.hpp +++ b/src/openrct2/scripting/ScEntity.hpp @@ -13,6 +13,8 @@ # include "../Context.h" # include "../common.h" +# include "../peep/Peep.h" +# include "../peep/Staff.h" # include "../world/Sprite.h" # include "Duktape.hpp" # include "ScriptEngine.h" @@ -180,7 +182,28 @@ namespace OpenRCT2::Scripting { } + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + dukglue_register_property(ctx, &ScPeep::peepType_get, nullptr, "peepType"); + dukglue_register_property(ctx, &ScPeep::name_get, &ScPeep::name_set, "name"); + dukglue_register_property(ctx, &ScPeep::flags_get, &ScPeep::flags_set, "flags"); + dukglue_register_property(ctx, &ScPeep::destination_get, &ScPeep::destination_set, "destination"); + dukglue_register_property(ctx, &ScPeep::energy_get, &ScPeep::energy_set, "energy"); + dukglue_register_property(ctx, &ScPeep::energyTarget_get, &ScPeep::energyTarget_set, "energyTarget"); + } + private: + std::string peepType_get() const + { + auto peep = GetPeep(); + if (peep != nullptr) + { + return peep->type == PEEP_TYPE_STAFF ? "staff" : "guest"; + } + return ""; + } + std::string name_get() const { auto peep = GetPeep(); @@ -237,31 +260,84 @@ namespace OpenRCT2::Scripting } } - DukValue pathfindGoal_get() const + uint8_t energy_get() const { - auto ctx = GetContext()->GetScriptEngine().GetContext(); auto peep = GetPeep(); - if (peep != nullptr) - { - return ToDuk(ctx, CoordsXY(peep->destination_x, peep->destination_y)); - } - return ToDuk(ctx, nullptr); + return peep != nullptr ? peep->energy : 0; } - - void pathfindGoal_set(const DukValue& value) + void energy_set(uint8_t value) { ThrowIfGameStateNotMutable(); auto peep = GetPeep(); if (peep != nullptr) { - auto pos = FromDuk(value); - peep->pathfind_goal.x = pos.x; - peep->pathfind_goal.y = pos.y; - peep->pathfind_goal.z = pos.z; - peep->Invalidate(); + peep->energy = value; } } + uint8_t energyTarget_get() const + { + auto peep = GetPeep(); + return peep != nullptr ? peep->energy_target : 0; + } + void energyTarget_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetPeep(); + if (peep != nullptr) + { + peep->energy_target = value; + } + } + + protected: + Peep* GetPeep() const + { + return get_sprite(_id)->AsPeep(); + } + }; + + class ScGuest : public ScPeep + { + public: + ScGuest(uint16_t id) + : ScPeep(id) + { + } + + static void Register(duk_context* ctx) + { + dukglue_set_base_class(ctx); + dukglue_register_property(ctx, &ScGuest::tshirtColour_get, &ScGuest::tshirtColour_set, "tshirtColour"); + dukglue_register_property(ctx, &ScGuest::trousersColour_get, &ScGuest::trousersColour_set, "trousersColour"); + dukglue_register_property(ctx, &ScGuest::balloonColour_get, &ScGuest::balloonColour_set, "balloonColour"); + dukglue_register_property(ctx, &ScGuest::hatColour_get, &ScGuest::hatColour_set, "hatColour"); + dukglue_register_property(ctx, &ScGuest::umbrellaColour_get, &ScGuest::umbrellaColour_set, "umbrellaColour"); + dukglue_register_property(ctx, &ScGuest::happiness_get, &ScGuest::happiness_set, "happiness"); + dukglue_register_property(ctx, &ScGuest::happinessTarget_get, &ScGuest::happinessTarget_set, "happinessTarget"); + dukglue_register_property(ctx, &ScGuest::nausea_get, &ScGuest::nausea_set, "nausea"); + dukglue_register_property(ctx, &ScGuest::nauseaTarget_get, &ScGuest::nauseaTarget_set, "nauseaTarget"); + dukglue_register_property(ctx, &ScGuest::hunger_get, &ScGuest::hunger_set, "hunger"); + dukglue_register_property(ctx, &ScGuest::thirst_get, &ScGuest::thirst_set, "thirst"); + dukglue_register_property(ctx, &ScGuest::toilet_get, &ScGuest::toilet_set, "toilet"); + dukglue_register_property(ctx, &ScGuest::mass_get, &ScGuest::mass_set, "mass"); + dukglue_register_property(ctx, &ScGuest::minIntensity_get, &ScGuest::minIntensity_set, "minIntensity"); + dukglue_register_property(ctx, &ScGuest::maxIntensity_get, &ScGuest::maxIntensity_set, "maxIntensity"); + dukglue_register_property(ctx, &ScGuest::nauseaTolerance_get, &ScGuest::nauseaTolerance_set, "nauseaTolerance"); + dukglue_register_property(ctx, &ScGuest::cash_get, &ScGuest::cash_set, "cash"); + } + + private: + Guest* GetGuest() const + { + auto peep = GetPeep(); + if (peep != nullptr) + { + return peep->AsGuest(); + } + return nullptr; + } + uint8_t tshirtColour_get() const { auto peep = GetPeep(); @@ -294,33 +370,51 @@ namespace OpenRCT2::Scripting } } - uint8_t energy_get() const + uint8_t balloonColour_get() const { auto peep = GetPeep(); - return peep != nullptr ? peep->energy : 0; + return peep != nullptr ? peep->BalloonColour : 0; } - void energy_set(uint8_t value) + void balloonColour_set(uint8_t value) { ThrowIfGameStateNotMutable(); auto peep = GetPeep(); if (peep != nullptr) { - peep->energy = value; + peep->BalloonColour = value; + peep->Invalidate(); } } - uint8_t energyTarget_get() const + uint8_t hatColour_get() const { auto peep = GetPeep(); - return peep != nullptr ? peep->energy_target : 0; + return peep != nullptr ? peep->HatColour : 0; } - void energyTarget_set(uint8_t value) + void hatColour_set(uint8_t value) { ThrowIfGameStateNotMutable(); auto peep = GetPeep(); if (peep != nullptr) { - peep->energy_target = value; + peep->HatColour = value; + peep->Invalidate(); + } + } + + uint8_t umbrellaColour_get() const + { + auto peep = GetPeep(); + return peep != nullptr ? peep->UmbrellaColour : 0; + } + void umbrellaColour_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetPeep(); + if (peep != nullptr) + { + peep->UmbrellaColour = value; + peep->Invalidate(); } } @@ -503,35 +597,136 @@ namespace OpenRCT2::Scripting peep->cash_in_pocket = std::max(0, value); } } + }; - Peep* GetPeep() const + class ScStaff : public ScPeep + { + public: + ScStaff(uint16_t id) + : ScPeep(id) { - return get_sprite(_id)->AsPeep(); } - public: static void Register(duk_context* ctx) { - dukglue_set_base_class(ctx); - dukglue_register_property(ctx, &ScPeep::name_get, &ScPeep::name_set, "name"); - dukglue_register_property(ctx, &ScPeep::flags_get, &ScPeep::flags_set, "flags"); - dukglue_register_property(ctx, &ScPeep::destination_get, &ScPeep::destination_set, "destination"); - dukglue_register_property(ctx, &ScPeep::tshirtColour_get, &ScPeep::tshirtColour_set, "tshirtColour"); - dukglue_register_property(ctx, &ScPeep::trousersColour_get, &ScPeep::trousersColour_set, "trousersColour"); - dukglue_register_property(ctx, &ScPeep::energy_get, &ScPeep::energy_set, "energy"); - dukglue_register_property(ctx, &ScPeep::energyTarget_get, &ScPeep::energyTarget_set, "energyTarget"); - dukglue_register_property(ctx, &ScPeep::happiness_get, &ScPeep::happiness_set, "happiness"); - dukglue_register_property(ctx, &ScPeep::happinessTarget_get, &ScPeep::happinessTarget_set, "happinessTarget"); - dukglue_register_property(ctx, &ScPeep::nausea_get, &ScPeep::nausea_set, "nausea"); - dukglue_register_property(ctx, &ScPeep::nauseaTarget_get, &ScPeep::nauseaTarget_set, "nauseaTarget"); - dukglue_register_property(ctx, &ScPeep::hunger_get, &ScPeep::hunger_set, "hunger"); - dukglue_register_property(ctx, &ScPeep::thirst_get, &ScPeep::thirst_set, "thirst"); - dukglue_register_property(ctx, &ScPeep::toilet_get, &ScPeep::toilet_set, "toilet"); - dukglue_register_property(ctx, &ScPeep::mass_get, &ScPeep::mass_set, "mass"); - dukglue_register_property(ctx, &ScPeep::minIntensity_get, &ScPeep::minIntensity_set, "minIntensity"); - dukglue_register_property(ctx, &ScPeep::maxIntensity_get, &ScPeep::maxIntensity_set, "maxIntensity"); - dukglue_register_property(ctx, &ScPeep::nauseaTolerance_get, &ScPeep::nauseaTolerance_set, "nauseaTolerance"); - dukglue_register_property(ctx, &ScPeep::cash_get, &ScPeep::cash_set, "cash"); + 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::costume_get, &ScStaff::costume_set, "costume"); + dukglue_register_property(ctx, &ScStaff::orders_get, &ScStaff::orders_set, "orders"); + } + + private: + Staff* GetStaff() const + { + auto peep = GetPeep(); + if (peep != nullptr) + { + return peep->AsStaff(); + } + return nullptr; + } + + std::string staffType_get() const + { + auto peep = GetStaff(); + if (peep != nullptr) + { + switch (peep->staff_type) + { + case STAFF_TYPE_HANDYMAN: + return "handyman"; + case STAFF_TYPE_MECHANIC: + return "mechanic"; + case STAFF_TYPE_SECURITY: + return "security"; + case STAFF_TYPE_ENTERTAINER: + return "entertainer"; + } + } + return ""; + } + + void staffType_set(const std::string& value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetStaff(); + if (peep != nullptr) + { + if (value == "handyman" && peep->staff_type != STAFF_TYPE_HANDYMAN) + { + peep->staff_type = STAFF_TYPE_HANDYMAN; + peep->sprite_type = PeepSpriteType::PEEP_SPRITE_TYPE_HANDYMAN; + } + else if (value == "mechanic" && peep->staff_type != STAFF_TYPE_MECHANIC) + { + peep->staff_type = STAFF_TYPE_MECHANIC; + peep->sprite_type = PeepSpriteType::PEEP_SPRITE_TYPE_MECHANIC; + } + else if (value == "security" && peep->staff_type != STAFF_TYPE_SECURITY) + { + peep->staff_type = STAFF_TYPE_SECURITY; + peep->sprite_type = PeepSpriteType::PEEP_SPRITE_TYPE_SECURITY; + } + else if (value == "entertainer" && peep->staff_type != STAFF_TYPE_ENTERTAINER) + { + peep->staff_type = STAFF_TYPE_ENTERTAINER; + peep->sprite_type = PeepSpriteType::PEEP_SPRITE_TYPE_ENTERTAINER_PANDA; + } + } + } + + uint8_t colour_get() const + { + auto peep = GetStaff(); + return peep != nullptr ? peep->tshirt_colour : 0; + } + + void colour_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetStaff(); + if (peep != nullptr) + { + peep->tshirt_colour = value; + peep->trousers_colour = value; + } + } + + uint8_t costume_get() const + { + auto peep = GetStaff(); + if (peep != nullptr && peep->staff_type == STAFF_TYPE_ENTERTAINER) + { + return peep->GetCostume(); + } + return 0; + } + + void costume_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetStaff(); + if (peep != nullptr) + { + peep->SetCostume(value); + } + } + + uint8_t orders_get() const + { + auto peep = GetStaff(); + return peep != nullptr ? peep->staff_orders : 0; + } + + void orders_set(uint8_t value) + { + ThrowIfGameStateNotMutable(); + auto peep = GetStaff(); + if (peep != nullptr) + { + peep->staff_orders = value; + } } }; diff --git a/src/openrct2/scripting/ScMap.hpp b/src/openrct2/scripting/ScMap.hpp index bd549b8f8d..3f6088e906 100644 --- a/src/openrct2/scripting/ScMap.hpp +++ b/src/openrct2/scripting/ScMap.hpp @@ -146,7 +146,10 @@ namespace OpenRCT2::Scripting { if (targetList == SPRITE_LIST_PEEP) { - result.push_back(GetObjectAsDukValue(_context, std::make_shared(spriteId))); + if (sprite->peep.type == PEEP_TYPE_STAFF) + result.push_back(GetObjectAsDukValue(_context, std::make_shared(spriteId))); + else + result.push_back(GetObjectAsDukValue(_context, std::make_shared(spriteId))); } else if (targetList == SPRITE_LIST_TRAIN_HEAD) { @@ -195,7 +198,10 @@ namespace OpenRCT2::Scripting switch (sprite->generic.sprite_identifier) { case SPRITE_IDENTIFIER_PEEP: - return GetObjectAsDukValue(_context, std::make_shared(spriteId)); + if (sprite->peep.type == PEEP_TYPE_STAFF) + return GetObjectAsDukValue(_context, std::make_shared(spriteId)); + else + return GetObjectAsDukValue(_context, std::make_shared(spriteId)); default: return GetObjectAsDukValue(_context, std::make_shared(spriteId)); } diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 4232d4adec..876173960b 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -389,6 +389,8 @@ void ScriptEngine::Initialise() ScTileElement::Register(ctx); ScEntity::Register(ctx); ScPeep::Register(ctx); + ScGuest::Register(ctx); + ScStaff::Register(ctx); dukglue_register_global(ctx, std::make_shared(), "cheats"); dukglue_register_global(ctx, std::make_shared(_console), "console");