From cc668f080e6abffd81b705947f95196c2b1977a2 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Thu, 19 Dec 2024 09:26:39 +0100 Subject: [PATCH] Fix rendering balloons/hats/umbrellas held by guests --- src/openrct2-ui/windows/Guest.cpp | 40 ++++++++------- src/openrct2/entity/Peep.cpp | 53 ++++++++++++-------- src/openrct2/object/PeepAnimationsObject.cpp | 12 ++++- src/openrct2/peep/PeepSpriteIds.h | 3 ++ 4 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 8d78da66cd..6630332beb 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -578,27 +578,31 @@ namespace OpenRCT2::Ui::Windows GfxDrawSprite(clipDpi, spriteId, screenCoords); auto* guest = peep->As(); - if (guest != nullptr) + if (guest == nullptr) + return; + + // There are only 6 walking frames available for each item. + auto itemFrame = (_guestAnimationFrame / 4) % 6; + + if (guest->AnimationGroup == PeepAnimationGroup::Hat) { - // If holding a balloon - if (animationFrame >= kPeepSpriteBalloonStateWatchRideId - && animationFrame < kPeepSpriteBalloonStateSittingIdleId + 4) - { - GfxDrawSprite(clipDpi, ImageId(animationFrame + 32, guest->BalloonColour), screenCoords); - } + auto itemOffset = kPeepSpriteHatItemStart + 1; + auto imageId = ImageId(itemOffset + itemFrame * 4, guest->HatColour); + GfxDrawSprite(clipDpi, imageId, screenCoords); + } - // If holding umbrella - if (animationFrame >= kPeepSpriteUmbrellaStateWalkingId - && animationFrame < kPeepSpriteUmbrellaStateSittingIdleId + 4) - { - GfxDrawSprite(clipDpi, ImageId(animationFrame + 32, guest->UmbrellaColour), screenCoords); - } + if (guest->AnimationGroup == PeepAnimationGroup::Balloon) + { + auto itemOffset = kPeepSpriteBalloonItemStart + 1; + auto imageId = ImageId(itemOffset + itemFrame * 4, guest->BalloonColour); + GfxDrawSprite(clipDpi, imageId, screenCoords); + } - // If wearing hat - if (animationFrame >= kPeepSpriteHatStateWatchRideId && animationFrame < kPeepSpriteHatStateSittingIdleId + 4) - { - GfxDrawSprite(clipDpi, ImageId(animationFrame + 32, guest->HatColour), screenCoords); - } + if (guest->AnimationGroup == PeepAnimationGroup::Umbrella) + { + auto itemOffset = kPeepSpriteUmbrellaItemStart + 1; + auto imageId = ImageId(itemOffset + itemFrame * 4, guest->UmbrellaColour); + GfxDrawSprite(clipDpi, imageId, screenCoords); } } diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index 2c1bae2fe0..76d0c01e0a 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -2909,8 +2909,6 @@ void Peep::Paint(PaintSession& session, int32_t imageDirection) const auto& objManager = GetContext()->GetObjectManager(); auto* animObj = objManager.GetLoadedObject(AnimationObjectIndex); - // 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 = animObj->GetPeepAnimation(AnimationGroup, actionAnimationGroup).base_image; // Offset frame onto the base image, using rotation except for the 'picked up' state @@ -2921,33 +2919,46 @@ void Peep::Paint(PaintSession& session, int32_t imageDirection) const auto imageId = ImageId(baseImageId, TshirtColour, TrousersColour); + // 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 auto bb = BoundBoxXYZ{ { 0, 0, z + 5 }, { 1, 1, 11 } }; auto offset = CoordsXYZ{ 0, 0, z }; PaintAddImageAsParent(session, imageId, { 0, 0, z }, bb); auto* guest = As(); - if (guest != nullptr) + if (guest == nullptr) + return; + + // There are only 6 walking frames available for each item, + // as well as 1 sprite for sitting and 1 for standing still. + auto itemFrame = imageOffset % 6; + if (actionAnimationGroup == PeepAnimationType::WatchRide) + itemFrame = 6; + else if (actionAnimationGroup == PeepAnimationType::SittingIdle) + itemFrame = 7; + + if (AnimationGroup == PeepAnimationGroup::Hat) { - if (baseImageId >= kPeepSpriteHatStateWatchRideId && baseImageId < (kPeepSpriteHatStateSittingIdleId + 4)) - { - imageId = ImageId(baseImageId + 32, guest->HatColour); - PaintAddImageAsChild(session, imageId, offset, bb); - return; - } + auto itemOffset = kPeepSpriteHatItemStart; + imageId = ImageId(itemOffset + (imageDirection >> 3) + itemFrame * 4, guest->HatColour); + PaintAddImageAsChild(session, imageId, offset, bb); + return; + } - if (baseImageId >= kPeepSpriteBalloonStateWatchRideId && baseImageId < (kPeepSpriteBalloonStateSittingIdleId + 4)) - { - imageId = ImageId(baseImageId + 32, guest->BalloonColour); - PaintAddImageAsChild(session, imageId, offset, bb); - return; - } + if (AnimationGroup == PeepAnimationGroup::Balloon) + { + auto itemOffset = kPeepSpriteBalloonItemStart; + imageId = ImageId(itemOffset + (imageDirection >> 3) + itemFrame * 4, guest->BalloonColour); + PaintAddImageAsChild(session, imageId, offset, bb); + return; + } - if (baseImageId >= kPeepSpriteUmbrellaStateWalkingId && baseImageId < (kPeepSpriteUmbrellaStateSittingIdleId + 4)) - { - imageId = ImageId(baseImageId + 32, guest->UmbrellaColour); - PaintAddImageAsChild(session, imageId, offset, bb); - return; - } + if (AnimationGroup == PeepAnimationGroup::Umbrella) + { + auto itemOffset = kPeepSpriteUmbrellaItemStart; + imageId = ImageId(itemOffset + (imageDirection >> 3) + itemFrame * 4, guest->UmbrellaColour); + PaintAddImageAsChild(session, imageId, offset, bb); + return; } } diff --git a/src/openrct2/object/PeepAnimationsObject.cpp b/src/openrct2/object/PeepAnimationsObject.cpp index f58c7a8833..be157a2664 100644 --- a/src/openrct2/object/PeepAnimationsObject.cpp +++ b/src/openrct2/object/PeepAnimationsObject.cpp @@ -37,13 +37,23 @@ void PeepAnimationsObject::Load() _imageOffsetId = LoadImages(); // Set loaded image offsets for all animations - for (auto& group : _animationGroups) + for (auto groupKey = 0u; groupKey < _animationGroups.size(); groupKey++) { + auto& group = _animationGroups[groupKey]; auto& requiredAnimationMap = getAnimationsByPeepType(_peepType); for (auto& [typeStr, typeEnum] : requiredAnimationMap) { group[typeEnum].base_image = _imageOffsetId + group[typeEnum].imageTableOffset; group[typeEnum].bounds = inferMaxAnimationDimensions(group[typeEnum]); + + // Balloons, hats and umbrellas are painted separately, so the inference + // algorithm doesn't account for those. We manually compensate for these here. + // Between 8-12 pixels are needed, depending on rotation, so we're generalising. + auto pag = PeepAnimationGroup(groupKey); + if (pag == PeepAnimationGroup::Balloon || pag == PeepAnimationGroup::Hat || pag == PeepAnimationGroup::Umbrella) + { + group[typeEnum].bounds.sprite_height_negative += 12; + } } } } diff --git a/src/openrct2/peep/PeepSpriteIds.h b/src/openrct2/peep/PeepSpriteIds.h index f27c3ec6a0..6022b9e472 100644 --- a/src/openrct2/peep/PeepSpriteIds.h +++ b/src/openrct2/peep/PeepSpriteIds.h @@ -158,6 +158,7 @@ namespace OpenRCT2 kPeepSpriteBalloonStateWalkingId = 10785, kPeepSpriteBalloonStateWatchRideId = 10781, kPeepSpriteBalloonStateSittingIdleId = 10809, + kPeepSpriteBalloonItemStart = 10813, kPeepSpriteCandyflossStateWalkingId = 10849, kPeepSpriteCandyflossStateWatchRideId = 10845, @@ -168,6 +169,7 @@ namespace OpenRCT2 kPeepSpriteUmbrellaStateWalkingId = 11197, kPeepSpriteUmbrellaStateWatchRideId = 11221, kPeepSpriteUmbrellaStateSittingIdleId = 11225, + kPeepSpriteUmbrellaItemStart = 11229, kPeepSpritePizzaStateWalkingId = 7785, kPeepSpritePizzaStateWatchRideId = 7781, @@ -197,6 +199,7 @@ namespace OpenRCT2 kPeepSpriteHatStateWalkingId = 10721, kPeepSpriteHatStateWatchRideId = 10717, kPeepSpriteHatStateSittingIdleId = 10745, + kPeepSpriteHatItemStart = 10749, kPeepSpriteHotDogStateWalkingId = 7889, kPeepSpriteHotDogStateWatchRideId = 7885,