mirror of https://github.com/OpenRCT2/OpenRCT2.git
Scripting: allow precise and safe control of peep animations
This commit is contained in:
parent
bf74dfba7b
commit
893392d987
|
@ -1,6 +1,7 @@
|
||||||
0.4.12 (in development)
|
0.4.12 (in development)
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
- Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type.
|
- Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type.
|
||||||
|
- Feature: [#21913] [Plugin] Allow precise and safe control of peep animations.
|
||||||
|
|
||||||
0.4.11 (2024-05-05)
|
0.4.11 (2024-05-05)
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
|
@ -2682,6 +2682,34 @@ declare global {
|
||||||
*/
|
*/
|
||||||
type PeepType = "guest" | "staff";
|
type PeepType = "guest" | "staff";
|
||||||
|
|
||||||
|
type GuestAnimation =
|
||||||
|
"walking" |
|
||||||
|
"checkTime" |
|
||||||
|
"watchRide" |
|
||||||
|
"eatFood" |
|
||||||
|
"shakeHead" |
|
||||||
|
"emptyPockets" |
|
||||||
|
"holdMat" |
|
||||||
|
"sittingIdle" |
|
||||||
|
"sittingEatFood" |
|
||||||
|
"sittingLookAroundLeft" |
|
||||||
|
"sittingLookAroundRight" |
|
||||||
|
"hanging" |
|
||||||
|
"wow" |
|
||||||
|
"throwUp" |
|
||||||
|
"jump" |
|
||||||
|
"drowning" |
|
||||||
|
"joy" |
|
||||||
|
"readMap" |
|
||||||
|
"wave" |
|
||||||
|
"wave2" |
|
||||||
|
"takePhoto" |
|
||||||
|
"clap" |
|
||||||
|
"disgust" |
|
||||||
|
"drawPicture" |
|
||||||
|
"beingWatched" |
|
||||||
|
"withdrawMoney";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a guest.
|
* Represents a guest.
|
||||||
*/
|
*/
|
||||||
|
@ -2819,6 +2847,31 @@ declare global {
|
||||||
* Removes all items from the guest's possession.
|
* Removes all items from the guest's possession.
|
||||||
*/
|
*/
|
||||||
removeAllItems(): void;
|
removeAllItems(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animations available to this guest.
|
||||||
|
*/
|
||||||
|
readonly availableAnimations: GuestAnimation[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an array of sprite ids representing a particular guest animation.
|
||||||
|
*/
|
||||||
|
getAnimationSpriteIds(animation: GuestAnimation, rotation: number): number[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animation the guest is currently exhibiting.
|
||||||
|
*/
|
||||||
|
animation: GuestAnimation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The frame offset in the current animation.
|
||||||
|
*/
|
||||||
|
animationOffset: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total number of frames in the current animation.
|
||||||
|
*/
|
||||||
|
readonly animationLength: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3113,6 +3166,26 @@ declare global {
|
||||||
"sheriff" |
|
"sheriff" |
|
||||||
"pirate";
|
"pirate";
|
||||||
|
|
||||||
|
type StaffAnimation =
|
||||||
|
"walking" |
|
||||||
|
"watchRide" |
|
||||||
|
"wave" |
|
||||||
|
"hanging" |
|
||||||
|
"staffMower" |
|
||||||
|
"staffSweep" |
|
||||||
|
"drowning" |
|
||||||
|
"staffAnswerCall" |
|
||||||
|
"staffAnswerCall2" |
|
||||||
|
"staffCheckBoard" |
|
||||||
|
"staffFix" |
|
||||||
|
"staffFix2" |
|
||||||
|
"staffFixGround" |
|
||||||
|
"staffFix3" |
|
||||||
|
"staffWatering" |
|
||||||
|
"joy" |
|
||||||
|
"staffEmptyBin" |
|
||||||
|
"wave2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a staff member.
|
* Represents a staff member.
|
||||||
*/
|
*/
|
||||||
|
@ -3146,6 +3219,31 @@ declare global {
|
||||||
* Gets the patrol area for the staff member.
|
* Gets the patrol area for the staff member.
|
||||||
*/
|
*/
|
||||||
readonly patrolArea: PatrolArea;
|
readonly patrolArea: PatrolArea;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animations available to this staff member.
|
||||||
|
*/
|
||||||
|
readonly availableAnimations: StaffAnimation[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an array of sprite ids representing a particular staff animation.
|
||||||
|
*/
|
||||||
|
getAnimationSpriteIds(animation: StaffAnimation, rotation: number): number[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animation the staff member is currently exhibiting.
|
||||||
|
*/
|
||||||
|
animation: StaffAnimation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The frame offset in the current animation.
|
||||||
|
*/
|
||||||
|
animationOffset: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total number of frames in the current animation.
|
||||||
|
*/
|
||||||
|
readonly animationLength: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaffType = "handyman" | "mechanic" | "security" | "entertainer";
|
type StaffType = "handyman" | "mechanic" | "security" | "entertainer";
|
||||||
|
|
|
@ -344,9 +344,15 @@ void Peep::UpdateCurrentActionSpriteType()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Invalidate();
|
|
||||||
ActionSpriteType = newActionSpriteType;
|
ActionSpriteType = newActionSpriteType;
|
||||||
|
|
||||||
|
UpdateSpriteBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peep::UpdateSpriteBoundingBox()
|
||||||
|
{
|
||||||
|
Invalidate();
|
||||||
|
|
||||||
const SpriteBounds* spriteBounds = &GetSpriteBounds(SpriteType, ActionSpriteType);
|
const SpriteBounds* spriteBounds = &GetSpriteBounds(SpriteType, ActionSpriteType);
|
||||||
SpriteData.Width = spriteBounds->sprite_width;
|
SpriteData.Width = spriteBounds->sprite_width;
|
||||||
SpriteData.HeightMin = spriteBounds->sprite_height_negative;
|
SpriteData.HeightMin = spriteBounds->sprite_height_negative;
|
||||||
|
@ -2813,7 +2819,14 @@ void Peep::Paint(PaintSession& session, int32_t imageDirection) const
|
||||||
|
|
||||||
// In the following 4 calls to PaintAddImageAsParent/PaintAddImageAsChild, we add 5 (instead of 3) to the
|
// In the following 4 calls to PaintAddImageAsParent/PaintAddImageAsChild, we add 5 (instead of 3) to the
|
||||||
// bound_box_offset_z to make sure peeps are drawn on top of railways
|
// bound_box_offset_z to make sure peeps are drawn on top of railways
|
||||||
uint32_t baseImageId = (imageDirection >> 3) + GetPeepAnimation(SpriteType, actionSpriteType).base_image + imageOffset * 4;
|
uint32_t baseImageId = GetPeepAnimation(SpriteType, actionSpriteType).base_image;
|
||||||
|
|
||||||
|
// Offset frame onto the base image, using rotation except for the 'picked up' state
|
||||||
|
if (actionSpriteType != PeepActionSpriteType::Ui)
|
||||||
|
baseImageId += (imageDirection >> 3) + imageOffset * 4;
|
||||||
|
else
|
||||||
|
baseImageId += imageOffset;
|
||||||
|
|
||||||
auto imageId = ImageId(baseImageId, TshirtColour, TrousersColour);
|
auto imageId = ImageId(baseImageId, TshirtColour, TrousersColour);
|
||||||
|
|
||||||
auto bb = BoundBoxXYZ{ { 0, 0, z + 5 }, { 1, 1, 11 } };
|
auto bb = BoundBoxXYZ{ { 0, 0, z + 5 }, { 1, 1, 11 } };
|
||||||
|
|
|
@ -380,6 +380,7 @@ public: // Peep
|
||||||
void SetState(PeepState new_state);
|
void SetState(PeepState new_state);
|
||||||
void Remove();
|
void Remove();
|
||||||
void UpdateCurrentActionSpriteType();
|
void UpdateCurrentActionSpriteType();
|
||||||
|
void UpdateSpriteBoundingBox();
|
||||||
void SwitchToSpecialSprite(uint8_t special_sprite_id);
|
void SwitchToSpecialSprite(uint8_t special_sprite_id);
|
||||||
void StateReset();
|
void StateReset();
|
||||||
[[nodiscard]] uint8_t GetNextDirection() const;
|
[[nodiscard]] uint8_t GetNextDirection() const;
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace OpenRCT2
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 86;
|
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 87;
|
||||||
|
|
||||||
// Versions marking breaking changes.
|
// Versions marking breaking changes.
|
||||||
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
|
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
# include "../../../entity/Guest.h"
|
# include "../../../entity/Guest.h"
|
||||||
# include "../../../localisation/Localisation.h"
|
# include "../../../localisation/Localisation.h"
|
||||||
|
# include "../../../peep/PeepAnimationData.h"
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
|
@ -144,6 +145,35 @@ namespace OpenRCT2::Scripting
|
||||||
{ "here_we_are", PeepThoughtType::HereWeAre },
|
{ "here_we_are", PeepThoughtType::HereWeAre },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static const DukEnumMap<PeepActionSpriteType> availableGuestAnimations({
|
||||||
|
{ "walking", PeepActionSpriteType::None },
|
||||||
|
{ "checkTime", PeepActionSpriteType::CheckTime },
|
||||||
|
{ "watchRide", PeepActionSpriteType::WatchRide },
|
||||||
|
{ "eatFood", PeepActionSpriteType::EatFood },
|
||||||
|
{ "shakeHead", PeepActionSpriteType::ShakeHead },
|
||||||
|
{ "emptyPockets", PeepActionSpriteType::EmptyPockets },
|
||||||
|
{ "holdMat", PeepActionSpriteType::HoldMat },
|
||||||
|
{ "sittingIdle", PeepActionSpriteType::SittingIdle },
|
||||||
|
{ "sittingEatFood", PeepActionSpriteType::SittingEatFood },
|
||||||
|
{ "sittingLookAroundLeft", PeepActionSpriteType::SittingLookAroundLeft },
|
||||||
|
{ "sittingLookAroundRight", PeepActionSpriteType::SittingLookAroundRight },
|
||||||
|
{ "hanging", PeepActionSpriteType::Ui },
|
||||||
|
{ "wow", PeepActionSpriteType::Wow },
|
||||||
|
{ "throwUp", PeepActionSpriteType::ThrowUp },
|
||||||
|
{ "jump", PeepActionSpriteType::Jump },
|
||||||
|
{ "drowning", PeepActionSpriteType::Drowning },
|
||||||
|
{ "joy", PeepActionSpriteType::Joy },
|
||||||
|
{ "readMap", PeepActionSpriteType::ReadMap },
|
||||||
|
{ "wave", PeepActionSpriteType::Wave },
|
||||||
|
{ "wave2", PeepActionSpriteType::Wave2 },
|
||||||
|
{ "takePhoto", PeepActionSpriteType::TakePhoto },
|
||||||
|
{ "clap", PeepActionSpriteType::Clap },
|
||||||
|
{ "disgust", PeepActionSpriteType::Disgust },
|
||||||
|
{ "drawPicture", PeepActionSpriteType::DrawPicture },
|
||||||
|
{ "beingWatched", PeepActionSpriteType::BeingWatched },
|
||||||
|
{ "withdrawMoney", PeepActionSpriteType::WithdrawMoney },
|
||||||
|
});
|
||||||
|
|
||||||
ScGuest::ScGuest(EntityId id)
|
ScGuest::ScGuest(EntityId id)
|
||||||
: ScPeep(id)
|
: ScPeep(id)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +204,11 @@ namespace OpenRCT2::Scripting
|
||||||
dukglue_register_property(ctx, &ScGuest::lostCountdown_get, &ScGuest::lostCountdown_set, "lostCountdown");
|
dukglue_register_property(ctx, &ScGuest::lostCountdown_get, &ScGuest::lostCountdown_set, "lostCountdown");
|
||||||
dukglue_register_property(ctx, &ScGuest::thoughts_get, nullptr, "thoughts");
|
dukglue_register_property(ctx, &ScGuest::thoughts_get, nullptr, "thoughts");
|
||||||
dukglue_register_property(ctx, &ScGuest::items_get, nullptr, "items");
|
dukglue_register_property(ctx, &ScGuest::items_get, nullptr, "items");
|
||||||
|
dukglue_register_property(ctx, &ScGuest::availableAnimations_get, nullptr, "availableAnimations");
|
||||||
|
dukglue_register_property(ctx, &ScGuest::animation_get, &ScGuest::animation_set, "animation");
|
||||||
|
dukglue_register_property(ctx, &ScGuest::animationOffset_get, &ScGuest::animationOffset_set, "animationOffset");
|
||||||
|
dukglue_register_property(ctx, &ScGuest::animationLength_get, nullptr, "animationLength");
|
||||||
|
dukglue_register_method(ctx, &ScGuest::getAnimationSpriteIds, "getAnimationSpriteIds");
|
||||||
dukglue_register_method(ctx, &ScGuest::has_item, "hasItem");
|
dukglue_register_method(ctx, &ScGuest::has_item, "hasItem");
|
||||||
dukglue_register_method(ctx, &ScGuest::give_item, "giveItem");
|
dukglue_register_method(ctx, &ScGuest::give_item, "giveItem");
|
||||||
dukglue_register_method(ctx, &ScGuest::remove_item, "removeItem");
|
dukglue_register_method(ctx, &ScGuest::remove_item, "removeItem");
|
||||||
|
@ -791,6 +826,131 @@ namespace OpenRCT2::Scripting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ScGuest::availableAnimations_get() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> availableAnimations{};
|
||||||
|
for (auto& animation : availableGuestAnimations)
|
||||||
|
{
|
||||||
|
availableAnimations.push_back(std::string(animation.first));
|
||||||
|
}
|
||||||
|
return availableAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> ScGuest::getAnimationSpriteIds(std::string groupKey, uint8_t rotation) const
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> spriteIds{};
|
||||||
|
|
||||||
|
auto animationType = availableGuestAnimations.TryGet(groupKey);
|
||||||
|
if (animationType == std::nullopt)
|
||||||
|
{
|
||||||
|
return spriteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto peep = GetPeep();
|
||||||
|
if (peep != nullptr)
|
||||||
|
{
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, *animationType);
|
||||||
|
for (auto frameOffset : animationGroup.frame_offsets)
|
||||||
|
{
|
||||||
|
auto imageId = animationGroup.base_image;
|
||||||
|
if (animationType != PeepActionSpriteType::Ui)
|
||||||
|
imageId += rotation + frameOffset * 4;
|
||||||
|
else
|
||||||
|
imageId += frameOffset;
|
||||||
|
|
||||||
|
spriteIds.push_back(imageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spriteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ScGuest::animation_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetGuest();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view action = availableGuestAnimations[peep->ActionSpriteType];
|
||||||
|
|
||||||
|
// Special consideration for sitting peeps
|
||||||
|
// TODO: something funky going on in the state machine
|
||||||
|
if (peep->ActionSpriteType == PeepActionSpriteType::None && peep->State == PeepState::Sitting)
|
||||||
|
action = availableGuestAnimations[PeepActionSpriteType::SittingIdle];
|
||||||
|
|
||||||
|
return std::string(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScGuest::animation_set(std::string groupKey)
|
||||||
|
{
|
||||||
|
ThrowIfGameStateNotMutable();
|
||||||
|
|
||||||
|
auto newType = availableGuestAnimations.TryGet(groupKey);
|
||||||
|
if (newType == std::nullopt)
|
||||||
|
{
|
||||||
|
throw DukException() << "Invalid animation for this guest (" << groupKey << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* peep = GetGuest();
|
||||||
|
peep->ActionSpriteType = peep->NextActionSpriteType = *newType;
|
||||||
|
|
||||||
|
auto offset = 0;
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
peep->WalkingFrameNum = offset;
|
||||||
|
else
|
||||||
|
peep->ActionFrame = offset;
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
peep->ActionSpriteImageOffset = animationGroup.frame_offsets[offset];
|
||||||
|
peep->UpdateSpriteBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ScGuest::animationOffset_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetGuest();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
return peep->WalkingFrameNum;
|
||||||
|
else
|
||||||
|
return peep->ActionFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScGuest::animationOffset_set(uint8_t offset)
|
||||||
|
{
|
||||||
|
ThrowIfGameStateNotMutable();
|
||||||
|
|
||||||
|
auto* peep = GetGuest();
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
auto length = animationGroup.frame_offsets.size();
|
||||||
|
offset %= length;
|
||||||
|
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
peep->WalkingFrameNum = offset;
|
||||||
|
else
|
||||||
|
peep->ActionFrame = offset;
|
||||||
|
|
||||||
|
peep->ActionSpriteImageOffset = animationGroup.frame_offsets[offset];
|
||||||
|
peep->UpdateSpriteBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ScGuest::animationLength_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetGuest();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
return static_cast<uint8_t>(animationGroup.frame_offsets.size());
|
||||||
|
}
|
||||||
|
|
||||||
ScThought::ScThought(PeepThought backing)
|
ScThought::ScThought(PeepThought backing)
|
||||||
: _backing(backing)
|
: _backing(backing)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
# include "../../../entity/Guest.h"
|
# include "../../../entity/Guest.h"
|
||||||
# include "ScPeep.hpp"
|
# include "ScPeep.hpp"
|
||||||
|
|
||||||
|
enum class PeepActionSpriteType : uint8_t;
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
static const DukEnumMap<ShopItem> ShopItemMap({
|
static const DukEnumMap<ShopItem> ShopItemMap({
|
||||||
|
@ -172,6 +174,14 @@ namespace OpenRCT2::Scripting
|
||||||
void give_item(const DukValue& item) const;
|
void give_item(const DukValue& item) const;
|
||||||
void remove_item(const DukValue& item) const;
|
void remove_item(const DukValue& item) const;
|
||||||
void remove_all_items() const;
|
void remove_all_items() const;
|
||||||
|
|
||||||
|
std::vector<std::string> availableAnimations_get() const;
|
||||||
|
std::vector<uint32_t> getAnimationSpriteIds(std::string groupKey, uint8_t rotation) const;
|
||||||
|
std::string animation_get() const;
|
||||||
|
void animation_set(std::string groupKey);
|
||||||
|
uint8_t animationOffset_get() const;
|
||||||
|
void animationOffset_set(uint8_t offset);
|
||||||
|
uint8_t animationLength_get() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenRCT2::Scripting
|
} // namespace OpenRCT2::Scripting
|
||||||
|
|
|
@ -13,9 +13,51 @@
|
||||||
|
|
||||||
# include "../../../entity/PatrolArea.h"
|
# include "../../../entity/PatrolArea.h"
|
||||||
# include "../../../entity/Staff.h"
|
# include "../../../entity/Staff.h"
|
||||||
|
# include "../../../peep/PeepAnimationData.h"
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
|
static const DukEnumMap<PeepActionSpriteType> availableHandymanAnimations({
|
||||||
|
{ "walking", PeepActionSpriteType::None },
|
||||||
|
{ "watchRide", PeepActionSpriteType::WatchRide },
|
||||||
|
{ "hanging", PeepActionSpriteType::Ui },
|
||||||
|
{ "staffMower", PeepActionSpriteType::StaffMower },
|
||||||
|
{ "staffSweep", PeepActionSpriteType::StaffSweep },
|
||||||
|
{ "drowning", PeepActionSpriteType::Drowning },
|
||||||
|
{ "staffWatering", PeepActionSpriteType::StaffWatering },
|
||||||
|
{ "staffEmptyBin", PeepActionSpriteType::StaffEmptyBin },
|
||||||
|
});
|
||||||
|
|
||||||
|
static const DukEnumMap<PeepActionSpriteType> availableMechanicAnimations({
|
||||||
|
{ "walking", PeepActionSpriteType::None },
|
||||||
|
{ "watchRide", PeepActionSpriteType::WatchRide },
|
||||||
|
{ "hanging", PeepActionSpriteType::Ui },
|
||||||
|
{ "staffAnswerCall", PeepActionSpriteType::StaffAnswerCall },
|
||||||
|
{ "staffAnswerCall2", PeepActionSpriteType::StaffAnswerCall2 },
|
||||||
|
{ "staffCheckBoard", PeepActionSpriteType::StaffCheckboard },
|
||||||
|
{ "staffFix", PeepActionSpriteType::StaffFix },
|
||||||
|
{ "staffFix2", PeepActionSpriteType::StaffFix2 },
|
||||||
|
{ "staffFixGround", PeepActionSpriteType::StaffFixGround },
|
||||||
|
{ "staffFix3", PeepActionSpriteType::StaffFix3 },
|
||||||
|
});
|
||||||
|
|
||||||
|
static const DukEnumMap<PeepActionSpriteType> availableSecurityAnimations({
|
||||||
|
{ "walking", PeepActionSpriteType::None },
|
||||||
|
{ "watchRide", PeepActionSpriteType::WatchRide },
|
||||||
|
{ "hanging", PeepActionSpriteType::Ui },
|
||||||
|
{ "drowning", PeepActionSpriteType::Drowning },
|
||||||
|
});
|
||||||
|
|
||||||
|
static const DukEnumMap<PeepActionSpriteType> availableEntertainerAnimations({
|
||||||
|
{ "walking", PeepActionSpriteType::None },
|
||||||
|
{ "watchRide", PeepActionSpriteType::WatchRide },
|
||||||
|
{ "wave", PeepActionSpriteType::EatFood }, // NB: this not a typo
|
||||||
|
{ "hanging", PeepActionSpriteType::Ui },
|
||||||
|
{ "drowning", PeepActionSpriteType::Drowning },
|
||||||
|
{ "joy", PeepActionSpriteType::Joy },
|
||||||
|
{ "wave2", PeepActionSpriteType::Wave2 },
|
||||||
|
});
|
||||||
|
|
||||||
ScStaff::ScStaff(EntityId Id)
|
ScStaff::ScStaff(EntityId Id)
|
||||||
: ScPeep(Id)
|
: ScPeep(Id)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +72,11 @@ namespace OpenRCT2::Scripting
|
||||||
dukglue_register_property(ctx, &ScStaff::costume_get, &ScStaff::costume_set, "costume");
|
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::patrolArea_get, nullptr, "patrolArea");
|
||||||
dukglue_register_property(ctx, &ScStaff::orders_get, &ScStaff::orders_set, "orders");
|
dukglue_register_property(ctx, &ScStaff::orders_get, &ScStaff::orders_set, "orders");
|
||||||
|
dukglue_register_property(ctx, &ScStaff::availableAnimations_get, nullptr, "availableAnimations");
|
||||||
|
dukglue_register_property(ctx, &ScStaff::animation_get, &ScStaff::animation_set, "animation");
|
||||||
|
dukglue_register_property(ctx, &ScStaff::animationOffset_get, &ScStaff::animationOffset_set, "animationOffset");
|
||||||
|
dukglue_register_property(ctx, &ScStaff::animationLength_get, nullptr, "animationLength");
|
||||||
|
dukglue_register_method(ctx, &ScStaff::getAnimationSpriteIds, "getAnimationSpriteIds");
|
||||||
}
|
}
|
||||||
|
|
||||||
Staff* ScStaff::GetStaff() const
|
Staff* ScStaff::GetStaff() const
|
||||||
|
@ -243,6 +290,153 @@ namespace OpenRCT2::Scripting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DukEnumMap<PeepActionSpriteType>& ScStaff::animationsByStaffType(StaffType staffType) const
|
||||||
|
{
|
||||||
|
switch (staffType)
|
||||||
|
{
|
||||||
|
case StaffType::Handyman:
|
||||||
|
return availableHandymanAnimations;
|
||||||
|
case StaffType::Mechanic:
|
||||||
|
return availableMechanicAnimations;
|
||||||
|
case StaffType::Security:
|
||||||
|
return availableSecurityAnimations;
|
||||||
|
case StaffType::Entertainer:
|
||||||
|
default:
|
||||||
|
return availableEntertainerAnimations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ScStaff::availableAnimations_get() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> availableAnimations{};
|
||||||
|
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
if (peep != nullptr)
|
||||||
|
{
|
||||||
|
for (auto& animation : animationsByStaffType(peep->AssignedStaffType))
|
||||||
|
{
|
||||||
|
availableAnimations.push_back(std::string(animation.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> ScStaff::getAnimationSpriteIds(std::string groupKey, uint8_t rotation) const
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> spriteIds{};
|
||||||
|
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return spriteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& animationGroups = animationsByStaffType(peep->AssignedStaffType);
|
||||||
|
auto animationType = animationGroups.TryGet(groupKey);
|
||||||
|
if (animationType == std::nullopt)
|
||||||
|
{
|
||||||
|
return spriteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, *animationType);
|
||||||
|
for (auto frameOffset : animationGroup.frame_offsets)
|
||||||
|
{
|
||||||
|
auto imageId = animationGroup.base_image;
|
||||||
|
if (animationType != PeepActionSpriteType::Ui)
|
||||||
|
imageId += rotation + frameOffset * 4;
|
||||||
|
else
|
||||||
|
imageId += frameOffset;
|
||||||
|
|
||||||
|
spriteIds.push_back(imageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spriteIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ScStaff::animation_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& animationGroups = animationsByStaffType(peep->AssignedStaffType);
|
||||||
|
std::string_view action = animationGroups[peep->ActionSpriteType];
|
||||||
|
return std::string(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStaff::animation_set(std::string groupKey)
|
||||||
|
{
|
||||||
|
ThrowIfGameStateNotMutable();
|
||||||
|
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
auto& animationGroups = animationsByStaffType(peep->AssignedStaffType);
|
||||||
|
auto newType = animationGroups.TryGet(groupKey);
|
||||||
|
if (newType == std::nullopt)
|
||||||
|
{
|
||||||
|
throw DukException() << "Invalid animation for this staff member (" << groupKey << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
peep->ActionSpriteType = peep->NextActionSpriteType = *newType;
|
||||||
|
|
||||||
|
auto offset = 0;
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
peep->WalkingFrameNum = offset;
|
||||||
|
else
|
||||||
|
peep->ActionFrame = offset;
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
peep->ActionSpriteImageOffset = animationGroup.frame_offsets[offset];
|
||||||
|
peep->UpdateSpriteBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ScStaff::animationOffset_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
return peep->WalkingFrameNum;
|
||||||
|
else
|
||||||
|
return peep->ActionFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScStaff::animationOffset_set(uint8_t offset)
|
||||||
|
{
|
||||||
|
ThrowIfGameStateNotMutable();
|
||||||
|
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
auto length = animationGroup.frame_offsets.size();
|
||||||
|
offset %= length;
|
||||||
|
|
||||||
|
if (peep->IsActionWalking())
|
||||||
|
peep->WalkingFrameNum = offset;
|
||||||
|
else
|
||||||
|
peep->ActionFrame = offset;
|
||||||
|
|
||||||
|
peep->ActionSpriteImageOffset = animationGroup.frame_offsets[offset];
|
||||||
|
peep->UpdateSpriteBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ScStaff::animationLength_get() const
|
||||||
|
{
|
||||||
|
auto* peep = GetStaff();
|
||||||
|
if (peep == nullptr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& animationGroup = GetPeepAnimation(peep->SpriteType, peep->ActionSpriteType);
|
||||||
|
return static_cast<uint8_t>(animationGroup.frame_offsets.size());
|
||||||
|
}
|
||||||
|
|
||||||
ScPatrolArea::ScPatrolArea(EntityId id)
|
ScPatrolArea::ScPatrolArea(EntityId id)
|
||||||
: _staffId(id)
|
: _staffId(id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
# include <memory>
|
# include <memory>
|
||||||
|
|
||||||
|
enum class PeepActionSpriteType : uint8_t;
|
||||||
|
enum class StaffType : uint8_t;
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
class ScPatrolArea
|
class ScPatrolArea
|
||||||
|
@ -64,6 +67,15 @@ namespace OpenRCT2::Scripting
|
||||||
|
|
||||||
uint8_t orders_get() const;
|
uint8_t orders_get() const;
|
||||||
void orders_set(uint8_t value);
|
void orders_set(uint8_t value);
|
||||||
|
|
||||||
|
const DukEnumMap<PeepActionSpriteType>& animationsByStaffType(StaffType staffType) const;
|
||||||
|
std::vector<uint32_t> getAnimationSpriteIds(std::string groupKey, uint8_t rotation) const;
|
||||||
|
std::vector<std::string> availableAnimations_get() const;
|
||||||
|
std::string animation_get() const;
|
||||||
|
void animation_set(std::string groupKey);
|
||||||
|
uint8_t animationOffset_get() const;
|
||||||
|
void animationOffset_set(uint8_t offset);
|
||||||
|
uint8_t animationLength_get() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenRCT2::Scripting
|
} // namespace OpenRCT2::Scripting
|
||||||
|
|
Loading…
Reference in New Issue