1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-04 13:42:55 +01:00

Fix #19822: Banners can now be copy-pasted from the tile inspector

This commit is contained in:
Michael Bernardi
2023-05-30 16:40:04 +02:00
committed by Michael Bernardi
parent 62914a39fb
commit 055a532571
7 changed files with 69 additions and 17 deletions

View File

@@ -8,6 +8,7 @@
- Fix: [#6152] Camera and UI are no longer locked at 40 Hz, providing a smoother experience.
- Fix: [#9534] Screams no longer cut-off on steep diagonal drops.
- Fix: [#19450] The correct element is now auto-suggested when building a Medium Half Loop backwards.
- Fix: [#19822] Tile inspector does not deep copy banners.
- Fix: [#19823] Parkobj: disallow overriding objects of different object types.
- Fix: [#19878] Unresearched scenery can be placed via prebuilt rides.
- Fix: [#20083] Cannot use terrain surfaces with ID > 32 and terrain edges with ID > 16.

View File

@@ -483,6 +483,7 @@ private:
bool _applyToAll = false;
bool _elementCopied = false;
TileElement _copiedElement;
Banner _copiedBanner;
public:
void OnOpen() override
@@ -1835,13 +1836,21 @@ private:
{
// Copy value, in case the element gets moved
_copiedElement = *GetSelectedElement();
_copiedBanner = {};
auto bannerIndex = _copiedElement.GetBannerIndex();
if (bannerIndex != BannerIndex::GetNull())
{
auto banner = GetBanner(bannerIndex);
if (banner != nullptr)
_copiedBanner = *banner;
}
_elementCopied = true;
Invalidate();
}
void PasteElement()
{
auto modifyTile = TileModifyAction(_toolMap, TileModifyType::AnyPaste, 0, 0, _copiedElement);
auto modifyTile = TileModifyAction(_toolMap, TileModifyType::AnyPaste, 0, 0, _copiedElement, _copiedBanner);
GameActions::Execute(&modifyTile);
}

View File

@@ -14,12 +14,13 @@
using namespace OpenRCT2;
TileModifyAction::TileModifyAction(
CoordsXY loc, TileModifyType setting, uint32_t value1, uint32_t value2, TileElement pasteElement)
CoordsXY loc, TileModifyType setting, uint32_t value1, uint32_t value2, TileElement pasteElement, Banner pasteBanner)
: _loc(loc)
, _setting(setting)
, _value1(value1)
, _value2(value2)
, _pasteElement(pasteElement)
, _pasteBanner(pasteBanner)
{
}
@@ -40,7 +41,8 @@ void TileModifyAction::Serialise(DataSerialiser& stream)
{
GameAction::Serialise(stream);
stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement);
stream << DS_TAG(_loc) << DS_TAG(_setting) << DS_TAG(_value1) << DS_TAG(_value2) << DS_TAG(_pasteElement)
<< DS_TAG(_pasteBanner);
}
GameActions::Result TileModifyAction::Query() const
@@ -89,7 +91,7 @@ GameActions::Result TileModifyAction::QueryExecute(bool isExecuting) const
}
case TileModifyType::AnyPaste:
{
res = TileInspector::PasteElementAt(_loc, _pasteElement, isExecuting);
res = TileInspector::PasteElementAt(_loc, _pasteElement, _pasteBanner, isExecuting);
break;
}
case TileModifyType::AnySort:

View File

@@ -49,11 +49,13 @@ private:
uint32_t _value1{};
uint32_t _value2{};
TileElement _pasteElement{};
Banner _pasteBanner{};
public:
TileModifyAction() = default;
TileModifyAction(
CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {});
CoordsXY loc, TileModifyType setting, uint32_t value1 = 0, uint32_t value2 = 0, TileElement pasteElement = {},
Banner _pasteBanner = {});
void AcceptParameters(GameActionParameterVisitor& visitor) override;

View File

@@ -890,3 +890,38 @@ template<typename T, T TNull, typename TTag> struct DataSerializerTraitsT<TIdent
stream->Write(msg, strlen(msg));
}
};
template<> struct DataSerializerTraitsT<Banner>
{
static void encode(OpenRCT2::IStream* stream, const Banner& banner)
{
DataSerializerTraits<BannerIndex>().encode(stream, banner.id);
DataSerializerTraits<ObjectEntryIndex>().encode(stream, banner.type);
stream->WriteValue(banner.flags);
stream->WriteString(banner.text);
stream->WriteValue(banner.colour);
DataSerializerTraits<RideId>().encode(stream, banner.ride_index);
stream->WriteValue(banner.text_colour);
DataSerializerTraits<TileCoordsXY>().encode(stream, banner.position);
}
static void decode(OpenRCT2::IStream* stream, Banner& banner)
{
DataSerializerTraits<BannerIndex>().decode(stream, banner.id);
DataSerializerTraits<ObjectEntryIndex>().decode(stream, banner.type);
stream->Read(&banner.flags);
banner.text = stream->ReadStdString();
stream->Read(&banner.colour);
DataSerializerTraits<RideId>().decode(stream, banner.ride_index);
stream->Read(&banner.text_colour);
DataSerializerTraits<TileCoordsXY>().decode(stream, banner.position);
}
static void log(OpenRCT2::IStream* stream, const Banner& banner)
{
char msg[128] = {};
snprintf(
msg, sizeof(msg), "Banner(x = %d, y = %d, text = %s)", banner.position.x, banner.position.y, banner.text.c_str());
stream->Write(msg, strlen(msg));
}
};

View File

@@ -320,7 +320,7 @@ namespace OpenRCT2::TileInspector
return GameActions::Result();
}
GameActions::Result PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting)
GameActions::Result PasteElementAt(const CoordsXY& loc, TileElement element, Banner banner, bool isExecuting)
{
// Make sure there is enough space for the new element
if (!MapCheckCapacityAndReorganise(loc))
@@ -330,28 +330,31 @@ namespace OpenRCT2::TileInspector
auto tileLoc = TileCoordsXY(loc);
auto bannerIndex = element.GetBannerIndex();
if (bannerIndex != BannerIndex::GetNull() && GetBanner(bannerIndex) == nullptr)
{
return GameActions::Result(GameActions::Status::Unknown, STR_NONE, STR_NONE);
}
if (isExecuting)
{
// Check if the element to be pasted refers to a banner index
if (bannerIndex != BannerIndex::GetNull())
// Check if the element to be pasted has a banner
if (element.GetBannerIndex() != BannerIndex::GetNull())
{
// The element to be pasted refers to a banner index - make a copy of it
// The element to be pasted has a banner - make a copy of it from the banner provided
auto newBanner = CreateBanner();
if (newBanner == nullptr)
{
LOG_ERROR("No free banners available");
return GameActions::Result(GameActions::Status::Unknown, STR_TOO_MANY_BANNERS_IN_GAME, STR_NONE);
}
auto newId = newBanner->id;
// Copy the banners style
*newBanner = *GetBanner(bannerIndex);
*newBanner = banner;
// Reset the location to the paste location
newBanner->position = tileLoc;
newBanner->id = newId;
// If the linked ride has been destroyed since copying, unlink the pasted banner
if (newBanner->flags & BANNER_FLAG_LINKED_TO_RIDE && GetRide(newBanner->ride_index) == nullptr)
{
newBanner->flags &= ~BANNER_FLAG_LINKED_TO_RIDE;
newBanner->ride_index = RideId::GetNull();
}
// Use the new banner index
element.SetBannerIndex(newBanner->id);

View File

@@ -27,7 +27,7 @@ namespace OpenRCT2::TileInspector
GameActions::Result SwapElementsAt(const CoordsXY& loc, int16_t first, int16_t second, bool isExecuting);
GameActions::Result RotateElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting);
GameActions::Result ToggleInvisibilityOfElementAt(const CoordsXY& loc, int32_t elementIndex, bool isExecuting);
GameActions::Result PasteElementAt(const CoordsXY& loc, TileElement element, bool isExecuting);
GameActions::Result PasteElementAt(const CoordsXY& loc, TileElement element, Banner banner, bool isExecuting);
GameActions::Result SortElementsAt(const CoordsXY& loc, bool isExecuting);
GameActions::Result AnyBaseHeightOffset(const CoordsXY& loc, int16_t elementIndex, int8_t heightOffset, bool isExecuting);
GameActions::Result SurfaceShowParkFences(const CoordsXY& loc, bool showFences, bool isExecuting);