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)
|
||||
------------------------------------------------------------------------
|
||||
- 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)
|
||||
------------------------------------------------------------------------
|
||||
|
|
|
@ -2682,6 +2682,34 @@ declare global {
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -2819,6 +2847,31 @@ declare global {
|
|||
* Removes all items from the guest's possession.
|
||||
*/
|
||||
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" |
|
||||
"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.
|
||||
*/
|
||||
|
@ -3146,6 +3219,31 @@ declare global {
|
|||
* Gets the patrol area for the staff member.
|
||||
*/
|
||||
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";
|
||||
|
|
|
@ -344,9 +344,15 @@ void Peep::UpdateCurrentActionSpriteType()
|
|||
return;
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
ActionSpriteType = newActionSpriteType;
|
||||
|
||||
UpdateSpriteBoundingBox();
|
||||
}
|
||||
|
||||
void Peep::UpdateSpriteBoundingBox()
|
||||
{
|
||||
Invalidate();
|
||||
|
||||
const SpriteBounds* spriteBounds = &GetSpriteBounds(SpriteType, ActionSpriteType);
|
||||
SpriteData.Width = spriteBounds->sprite_width;
|
||||
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
|
||||
// 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 bb = BoundBoxXYZ{ { 0, 0, z + 5 }, { 1, 1, 11 } };
|
||||
|
|
|
@ -380,6 +380,7 @@ public: // Peep
|
|||
void SetState(PeepState new_state);
|
||||
void Remove();
|
||||
void UpdateCurrentActionSpriteType();
|
||||
void UpdateSpriteBoundingBox();
|
||||
void SwitchToSpecialSprite(uint8_t special_sprite_id);
|
||||
void StateReset();
|
||||
[[nodiscard]] uint8_t GetNextDirection() const;
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace OpenRCT2
|
|||
|
||||
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.
|
||||
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
# include "../../../entity/Guest.h"
|
||||
# include "../../../localisation/Localisation.h"
|
||||
# include "../../../peep/PeepAnimationData.h"
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
|
@ -144,6 +145,35 @@ namespace OpenRCT2::Scripting
|
|||
{ "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)
|
||||
: 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::thoughts_get, nullptr, "thoughts");
|
||||
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::give_item, "giveItem");
|
||||
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)
|
||||
: _backing(backing)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
# include "../../../entity/Guest.h"
|
||||
# include "ScPeep.hpp"
|
||||
|
||||
enum class PeepActionSpriteType : uint8_t;
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
static const DukEnumMap<ShopItem> ShopItemMap({
|
||||
|
@ -172,6 +174,14 @@ namespace OpenRCT2::Scripting
|
|||
void give_item(const DukValue& item) const;
|
||||
void remove_item(const DukValue& item) 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
|
||||
|
|
|
@ -13,9 +13,51 @@
|
|||
|
||||
# include "../../../entity/PatrolArea.h"
|
||||
# include "../../../entity/Staff.h"
|
||||
# include "../../../peep/PeepAnimationData.h"
|
||||
|
||||
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)
|
||||
: 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::patrolArea_get, nullptr, "patrolArea");
|
||||
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
|
||||
|
@ -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)
|
||||
: _staffId(id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
# include <memory>
|
||||
|
||||
enum class PeepActionSpriteType : uint8_t;
|
||||
enum class StaffType : uint8_t;
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
class ScPatrolArea
|
||||
|
@ -64,6 +67,15 @@ namespace OpenRCT2::Scripting
|
|||
|
||||
uint8_t orders_get() const;
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue