Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create or delete banners when tile elements are changed by plugins #21627

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions distribution/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
- Fix: [#21434] Number of guests overflows in objective text.
- Fix: [#21522] Supports for 3×3 turns and 45 degree turns on the Hybrid Coaster and Wooden Roller Coaster not drawn correctly.
- Fix: [#21543] Crash with creating a TrackIterator with invalid arguments.
- Fix: [#21627] [Plugin] Banners are properly created or deleted when tile elements are changed by plugins.
- Fix: [#21635] Tile inspector hotkey can set wall slope for non-slopeable objects.
- Fix: [#21641] Crash when creating track iterator from an invalid tile element.
- Fix: [#21652] Dialog window to confirm overwriting files does not apply the theme colours correctly.
Expand Down
2 changes: 1 addition & 1 deletion src/openrct2/network/NetworkBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ using namespace OpenRCT2;
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.

constexpr uint8_t kNetworkStreamVersion = 0;
constexpr uint8_t kNetworkStreamVersion = 1;

const std::string kNetworkStreamID = std::string(OPENRCT2_VERSION) + "-" + std::to_string(kNetworkStreamVersion);

Expand Down
2 changes: 1 addition & 1 deletion src/openrct2/scripting/ScriptEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace OpenRCT2

namespace OpenRCT2::Scripting
{
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 87;
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 88;

// Versions marking breaking changes.
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
Expand Down
8 changes: 8 additions & 0 deletions src/openrct2/scripting/bindings/world/ScTile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# include "../../../common.h"
# include "../../../core/Guard.hpp"
# include "../../../entity/EntityRegistry.h"
# include "../../../object/LargeSceneryEntry.h"
# include "../../../ride/Track.h"
# include "../../../world/Footpath.h"
# include "../../../world/Scenery.h"
Expand Down Expand Up @@ -195,6 +196,13 @@ namespace OpenRCT2::Scripting
auto first = GetFirstElement();
if (index < GetNumElements(first))
{
auto element = &first[index];
if (element->GetType() != TileElementType::LargeScenery
|| element->AsLargeScenery()->GetEntry()->scrolling_mode == SCROLLING_MODE_NONE
|| ScTileElement::GetOtherLargeSceneryElement(_coords, element->AsLargeScenery()) == nullptr)
{
element->RemoveBannerEntry();
}
TileElementRemove(&first[index]);
MapInvalidateTileFull(_coords);
}
Expand Down
134 changes: 133 additions & 1 deletion src/openrct2/scripting/bindings/world/ScTileElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# include "../../../common.h"
# include "../../../core/Guard.hpp"
# include "../../../entity/EntityRegistry.h"
# include "../../../object/LargeSceneryEntry.h"
# include "../../../object/WallSceneryEntry.h"
# include "../../../ride/Ride.h"
# include "../../../ride/RideData.h"
# include "../../../ride/Track.h"
Expand Down Expand Up @@ -63,6 +65,7 @@ namespace OpenRCT2::Scripting

void ScTileElement::type_set(std::string value)
{
RemoveBannerEntryIfNeeded();
if (value == "surface")
_element->SetType(TileElementType::Surface);
else if (value == "footpath")
Expand All @@ -85,7 +88,7 @@ namespace OpenRCT2::Scripting
scriptEngine.LogPluginInfo("Element type not recognised!");
return;
}

CreateBannerEntryIfNeeded();
Invalidate();
}

Expand Down Expand Up @@ -537,8 +540,10 @@ namespace OpenRCT2::Scripting
{
case TileElementType::LargeScenery:
{
RemoveBannerEntryIfNeeded();
auto* el = _element->AsLargeScenery();
el->SetSequenceIndex(value.as_uint());
CreateBannerEntryIfNeeded();
Invalidate();
break;
}
Expand Down Expand Up @@ -1194,15 +1199,19 @@ namespace OpenRCT2::Scripting
}
case TileElementType::LargeScenery:
{
RemoveBannerEntryIfNeeded();
auto* el = _element->AsLargeScenery();
el->SetEntryIndex(index);
CreateBannerEntryIfNeeded();
Invalidate();
break;
}
case TileElementType::Wall:
{
RemoveBannerEntryIfNeeded();
auto* el = _element->AsWall();
el->SetEntryIndex(index);
CreateBannerEntryIfNeeded();
Invalidate();
break;
}
Expand Down Expand Up @@ -2140,6 +2149,129 @@ namespace OpenRCT2::Scripting
MapInvalidateTileFull(_coords);
}

const LargeSceneryElement* ScTileElement::GetOtherLargeSceneryElement(
const CoordsXY& loc, const LargeSceneryElement* const largeScenery)
{
const auto* const largeEntry = largeScenery->GetEntry();
const auto direction = largeScenery->GetDirection();
const auto sequenceIndex = largeScenery->GetSequenceIndex();
const auto* tiles = largeEntry->tiles;
const auto& tile = tiles[sequenceIndex];
const auto rotatedFirstTile = CoordsXYZ{
CoordsXY{ tile.x_offset, tile.y_offset }.Rotate(direction),
tile.z_offset,
};

const auto firstTile = CoordsXYZ{ loc, largeScenery->GetBaseZ() } - rotatedFirstTile;
for (int32_t i = 0; tiles[i].x_offset != -1; i++)
{
const auto rotatedCurrentTile = CoordsXYZ{ CoordsXY{ tiles[i].x_offset, tiles[i].y_offset }.Rotate(direction),
tiles[i].z_offset };

const auto currentTile = firstTile + rotatedCurrentTile;

const TileElement* tileElement = MapGetFirstElementAt(currentTile);
if (tileElement != nullptr)
{
do
{
if (tileElement->GetType() != TileElementType::LargeScenery)
continue;
if (tileElement->GetDirection() != direction)
continue;
if (tileElement->GetBaseZ() != currentTile.z)
continue;

if (tileElement->AsLargeScenery() == largeScenery)
continue;
if (tileElement->AsLargeScenery()->GetEntryIndex() != largeScenery->GetEntryIndex())
continue;
if (tileElement->AsLargeScenery()->GetSequenceIndex() != i)
continue;

return tileElement->AsLargeScenery();
} while (!(tileElement++)->IsLastForTile());
}
}
return nullptr;
}

void ScTileElement::RemoveBannerEntryIfNeeded()
{
// check if other element still uses the banner entry
if (_element->GetType() == TileElementType::LargeScenery
&& _element->AsLargeScenery()->GetEntry()->scrolling_mode != SCROLLING_MODE_NONE
&& GetOtherLargeSceneryElement(_coords, _element->AsLargeScenery()) != nullptr)
return;
// remove banner entry (if one exists)
_element->RemoveBannerEntry();
}

void ScTileElement::CreateBannerEntryIfNeeded()
{
// check if creation is needed
switch (_element->GetType())
{
case TileElementType::Banner:
break;
case TileElementType::Wall:
{
auto wallEntry = _element->AsWall()->GetEntry();
if (wallEntry->scrolling_mode == SCROLLING_MODE_NONE)
return;
break;
}
case TileElementType::LargeScenery:
{
auto largeScenery = _element->AsLargeScenery();
auto largeSceneryEntry = largeScenery->GetEntry();
if (largeSceneryEntry == nullptr || largeSceneryEntry->scrolling_mode == SCROLLING_MODE_NONE)
return;

auto otherElement = GetOtherLargeSceneryElement(_coords, largeScenery);
if (otherElement != nullptr)
{
largeScenery->SetBannerIndex(otherElement->GetBannerIndex());
return;
}

break;
}
default:
return;
}

// create banner entry and initialise it
auto* banner = CreateBanner();
if (banner == nullptr)
GetContext()->GetScriptEngine().LogPluginInfo("No free banners available.");
else
{
banner->text = {};
banner->colour = 0;
banner->text_colour = 0;
banner->flags = 0;
if (_element->GetType() == TileElementType::Wall)
banner->flags = BANNER_FLAG_IS_WALL;
if (_element->GetType() == TileElementType::LargeScenery)
banner->flags = BANNER_FLAG_IS_LARGE_SCENERY;
banner->type = 0;
banner->position = TileCoordsXY(_coords);

if (_element->GetType() == TileElementType::Wall || _element->GetType() == TileElementType::LargeScenery)
{
RideId rideIndex = BannerGetClosestRideIndex({ _coords, _element->BaseHeight });
if (!rideIndex.IsNull())
{
banner->ride_index = rideIndex;
banner->flags |= BANNER_FLAG_LINKED_TO_RIDE;
}
}

_element->SetBannerIndex(banner->id);
}
}

void ScTileElement::Register(duk_context* ctx)
{
// All
Expand Down
5 changes: 5 additions & 0 deletions src/openrct2/scripting/bindings/world/ScTileElement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ namespace OpenRCT2::Scripting

void Invalidate();

void RemoveBannerEntryIfNeeded();
void CreateBannerEntryIfNeeded();

public:
static const LargeSceneryElement* GetOtherLargeSceneryElement(
const CoordsXY& loc, const LargeSceneryElement* const largeScenery);
static void Register(duk_context* ctx);
};

Expand Down
Loading