mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-22 23:33:04 +01:00
* Fix #20486: Placing track designs with scenery disabled desyncs * Remove pointless error logging, too much log spam * Don't entirely disable all scenery when one element is obstructed * Update changelog.txt * Bump up network version * clang-format
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
0.4.28 (in development)
|
||||
------------------------------------------------------------------------
|
||||
- Change: [#25089] Peep actions and animations that cause them to stop moving no longer trigger when they are on a level crossing.
|
||||
- Change: [#25337] Placing track designs with scenery that is obstructed no longer disables all of the scenery.
|
||||
- Fix: [#20486] Multiplayer desync when placing track designs without any scenery.
|
||||
- Fix: [#22779, #25330] Incorrect queue paths in Nevermore Park and Six Flags Holland scenarios (bug in the original scenarios).
|
||||
- Fix: [#25190] Inserting a block brake while a coaster is simulating will cause the simulation to behave strangely.
|
||||
- Fix: [#25272] Text colour dropdown in the Banner window is too narrow, resulting in truncated labels.
|
||||
|
||||
@@ -356,7 +356,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
private:
|
||||
void UpdatePreview()
|
||||
{
|
||||
TrackDesignDrawPreview(*_trackDesign, _trackDesignPreviewPixels.data());
|
||||
TrackDesignDrawPreview(*_trackDesign, _trackDesignPreviewPixels.data(), !gTrackDesignSceneryToggle);
|
||||
}
|
||||
|
||||
void InstallTrackDesign()
|
||||
|
||||
@@ -203,7 +203,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
if (trackLoc == _placementLoc)
|
||||
{
|
||||
TrackDesignPreviewDrawOutlines(
|
||||
tds, *_trackDesign, RideGetTemporaryForPreview(), { mapCoords, 0, _currentTrackPieceDirection });
|
||||
tds, *_trackDesign, RideGetTemporaryForPreview(), { mapCoords, 0, _currentTrackPieceDirection },
|
||||
!gTrackDesignSceneryToggle);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,7 +217,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
if (res.Error == GameActions::Status::Ok)
|
||||
{
|
||||
// Valid location found. Place the ghost at the location.
|
||||
auto tdAction = GameActions::TrackDesignAction(trackLoc, *_trackDesign);
|
||||
auto tdAction = GameActions::TrackDesignAction(trackLoc, *_trackDesign, !gTrackDesignSceneryToggle);
|
||||
tdAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
|
||||
tdAction.SetCallback([&](const GameActions::GameAction*, const GameActions::Result* result) {
|
||||
if (result->Error == GameActions::Status::Ok)
|
||||
@@ -240,7 +241,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
invalidateWidget(WIDX_PRICE);
|
||||
}
|
||||
|
||||
TrackDesignPreviewDrawOutlines(tds, *_trackDesign, RideGetTemporaryForPreview(), trackLoc);
|
||||
TrackDesignPreviewDrawOutlines(
|
||||
tds, *_trackDesign, RideGetTemporaryForPreview(), trackLoc, !gTrackDesignSceneryToggle);
|
||||
}
|
||||
|
||||
void onToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
|
||||
@@ -285,7 +287,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
return;
|
||||
}
|
||||
|
||||
auto tdAction = GameActions::TrackDesignAction({ trackLoc, _currentTrackPieceDirection }, *_trackDesign);
|
||||
auto tdAction = GameActions::TrackDesignAction(
|
||||
{ trackLoc, _currentTrackPieceDirection }, *_trackDesign, !gTrackDesignSceneryToggle);
|
||||
tdAction.SetCallback([&](const GameActions::GameAction*, const GameActions::Result* result) {
|
||||
if (result->Error != GameActions::Status::Ok)
|
||||
{
|
||||
@@ -381,7 +384,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
if (_hasPlacementGhost)
|
||||
{
|
||||
auto tdAction = GameActions::TrackDesignAction({ _placementGhostLoc }, *_trackDesign);
|
||||
auto tdAction = GameActions::TrackDesignAction(
|
||||
{ _placementGhostLoc }, *_trackDesign, !gTrackDesignSceneryToggle);
|
||||
tdAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
|
||||
auto res = GameActions::Execute(&tdAction, getGameState());
|
||||
if (res.Error != GameActions::Status::Ok)
|
||||
@@ -728,7 +732,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
for (int32_t i = 0; i < 7; i++, loc.z += kCoordsZStep)
|
||||
{
|
||||
auto tdAction = GameActions::TrackDesignAction(
|
||||
CoordsXYZD{ loc.x, loc.y, loc.z, _currentTrackPieceDirection }, *_trackDesign);
|
||||
CoordsXYZD{ loc.x, loc.y, loc.z, _currentTrackPieceDirection }, *_trackDesign, !gTrackDesignSceneryToggle);
|
||||
tdAction.SetFlags(newFlags);
|
||||
res = GameActions::Query(&tdAction, getGameState());
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
_loadedTrackDesign = TrackDesignImport(path.c_str());
|
||||
if (_loadedTrackDesign != nullptr)
|
||||
{
|
||||
TrackDesignDrawPreview(*_loadedTrackDesign, _trackDesignPreviewPixels.data());
|
||||
TrackDesignDrawPreview(*_loadedTrackDesign, _trackDesignPreviewPixels.data(), !gTrackDesignSceneryToggle);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -67,7 +67,6 @@ namespace OpenRCT2::GameActions
|
||||
auto* entry = OpenRCT2::ObjectManager::GetObjectEntry<SmallSceneryEntry>(_sceneryType);
|
||||
if (entry == nullptr)
|
||||
{
|
||||
LOG_ERROR("Invalid small scenery type %u", _sceneryType);
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);
|
||||
}
|
||||
|
||||
@@ -103,7 +102,6 @@ namespace OpenRCT2::GameActions
|
||||
TileElement* tileElement = FindSceneryElement();
|
||||
if (tileElement == nullptr)
|
||||
{
|
||||
LOG_ERROR("Small scenery of type %u not found at x = %d, y = %d, z = &d", _sceneryType, _loc.x, _loc.y, _loc.z);
|
||||
return Result(Status::InvalidParameters, STR_CANT_REMOVE_THIS, STR_INVALID_SELECTION_OF_OBJECTS);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,10 @@
|
||||
|
||||
namespace OpenRCT2::GameActions
|
||||
{
|
||||
TrackDesignAction::TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td)
|
||||
TrackDesignAction::TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td, bool placeScenery)
|
||||
: _loc(location)
|
||||
, _td(td)
|
||||
, _placeScenery(placeScenery)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ namespace OpenRCT2::GameActions
|
||||
|
||||
stream << DS_TAG(_loc);
|
||||
_td.Serialise(stream);
|
||||
stream << DS_TAG(_placeScenery);
|
||||
}
|
||||
|
||||
Result TrackDesignAction::Query(GameState_t& gameState) const
|
||||
@@ -94,7 +96,7 @@ namespace OpenRCT2::GameActions
|
||||
return Result(Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE, STR_ERR_RIDE_NOT_FOUND);
|
||||
}
|
||||
|
||||
bool placeScenery = true;
|
||||
bool placeScenery = _placeScenery;
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (GetFlags() & GAME_COMMAND_FLAG_GHOST)
|
||||
@@ -169,7 +171,7 @@ namespace OpenRCT2::GameActions
|
||||
// Query first, this is required again to determine if scenery is available.
|
||||
uint32_t flags = GetFlags() & ~GAME_COMMAND_FLAG_APPLY;
|
||||
|
||||
bool placeScenery = true;
|
||||
bool placeScenery = _placeScenery;
|
||||
|
||||
auto queryRes = TrackDesignPlace(_td, flags, placeScenery, *ride, _loc);
|
||||
if (_trackDesignPlaceStateSceneryUnavailable)
|
||||
|
||||
@@ -19,10 +19,11 @@ namespace OpenRCT2::GameActions
|
||||
private:
|
||||
CoordsXYZD _loc;
|
||||
TrackDesign _td;
|
||||
bool _placeScenery{ false };
|
||||
|
||||
public:
|
||||
TrackDesignAction() = default;
|
||||
TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td);
|
||||
TrackDesignAction(const CoordsXYZD& location, const TrackDesign& td, bool placeScenery);
|
||||
|
||||
void AcceptParameters(GameActionParameterVisitor&) final;
|
||||
|
||||
|
||||
@@ -340,7 +340,8 @@ ResultWithMessage TrackDesign::CreateTrackDesignTrack(TrackDesignState& tds, con
|
||||
}
|
||||
}
|
||||
|
||||
TrackDesignPreviewDrawOutlines(tds, *this, RideGetTemporaryForPreview(), { 4096, 4096, 0, _currentTrackPieceDirection });
|
||||
TrackDesignPreviewDrawOutlines(
|
||||
tds, *this, RideGetTemporaryForPreview(), { 4096, 4096, 0, _currentTrackPieceDirection }, false);
|
||||
|
||||
// Resave global vars for scenery reasons.
|
||||
tds.origin = startPos;
|
||||
@@ -454,7 +455,8 @@ ResultWithMessage TrackDesign::CreateTrackDesignMaze(TrackDesignState& tds, cons
|
||||
|
||||
// Save global vars as they are still used by scenery????
|
||||
int32_t startZ = tds.origin.z;
|
||||
TrackDesignPreviewDrawOutlines(tds, *this, RideGetTemporaryForPreview(), { 4096, 4096, 0, _currentTrackPieceDirection });
|
||||
TrackDesignPreviewDrawOutlines(
|
||||
tds, *this, RideGetTemporaryForPreview(), { 4096, 4096, 0, _currentTrackPieceDirection }, false);
|
||||
tds.origin = { startLoc.x, startLoc.y, startZ };
|
||||
|
||||
gMapSelectFlags.unset(MapSelectFlag::enableConstruct);
|
||||
@@ -1299,11 +1301,17 @@ static GameActions::Result TrackDesignPlaceAllScenery(
|
||||
auto placementRes = TrackDesignPlaceSceneryElement(tds, mapCoord, mode, scenery, rotation, origin.z);
|
||||
if (placementRes.Error != GameActions::Status::Ok)
|
||||
{
|
||||
// Allow operation to fail when its removing ghosts.
|
||||
if (tds.placeOperation != TrackPlaceOperation::removeGhost)
|
||||
{
|
||||
// Allow operation to fail when its removing ghosts.
|
||||
return placementRes;
|
||||
}
|
||||
|
||||
if (placementRes.Error == GameActions::Status::NoClearance)
|
||||
{
|
||||
// Some scenery might be obstructed, don't abort the entire operation.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cost += placementRes.Cost;
|
||||
}
|
||||
@@ -1768,11 +1776,6 @@ static GameActions::Result TrackDesignPlaceVirtual(
|
||||
tds.previewMax = coords;
|
||||
tds.placeSceneryZ = 0;
|
||||
|
||||
if (gTrackDesignSceneryToggle)
|
||||
{
|
||||
tds.placeScenery = false;
|
||||
}
|
||||
|
||||
// NOTE: We need to save this, in networked games this would affect all clients otherwise.
|
||||
auto savedRideId = _currentRideIndex;
|
||||
auto savedTrackPieceDirection = _currentTrackPieceDirection;
|
||||
@@ -1840,9 +1843,10 @@ void TrackDesignPreviewRemoveGhosts(const TrackDesign& td, Ride& ride, const Coo
|
||||
TrackDesignPlaceVirtual(tds, td, TrackPlaceOperation::removeGhost, true, ride, coords);
|
||||
}
|
||||
|
||||
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, const TrackDesign& td, Ride& ride, const CoordsXYZD& coords)
|
||||
void TrackDesignPreviewDrawOutlines(
|
||||
TrackDesignState& tds, const TrackDesign& td, Ride& ride, const CoordsXYZD& coords, bool placeScenery)
|
||||
{
|
||||
TrackDesignPlaceVirtual(tds, td, TrackPlaceOperation::drawOutlines, true, ride, coords);
|
||||
TrackDesignPlaceVirtual(tds, td, TrackPlaceOperation::drawOutlines, placeScenery, ride, coords);
|
||||
}
|
||||
|
||||
static int32_t TrackDesignGetZPlacement(TrackDesignState& tds, const TrackDesign& td, Ride& ride, const CoordsXYZD& coords)
|
||||
@@ -1888,7 +1892,7 @@ static money64 TrackDesignCreateRide(int32_t type, int32_t subType, int32_t flag
|
||||
* cost = edi
|
||||
*/
|
||||
static bool TrackDesignPlacePreview(
|
||||
TrackDesignState& tds, const TrackDesign& td, Ride** outRide, TrackDesignGameStateData& gameStateData)
|
||||
TrackDesignState& tds, const TrackDesign& td, Ride** outRide, TrackDesignGameStateData& gameStateData, bool placeScenery)
|
||||
{
|
||||
*outRide = nullptr;
|
||||
gameStateData.flags = 0;
|
||||
@@ -1948,7 +1952,6 @@ static bool TrackDesignPlacePreview(
|
||||
|
||||
z += 16 - tds.placeSceneryZ;
|
||||
|
||||
bool placeScenery = true;
|
||||
if (_trackDesignPlaceStateSceneryUnavailable)
|
||||
{
|
||||
placeScenery = false;
|
||||
@@ -2073,7 +2076,7 @@ bool TrackDesignSceneryElement::operator!=(const TrackDesignSceneryElement& rhs)
|
||||
*
|
||||
* rct2: 0x006D1EF0
|
||||
*/
|
||||
void TrackDesignDrawPreview(TrackDesign& td, uint8_t* pixels)
|
||||
void TrackDesignDrawPreview(TrackDesign& td, uint8_t* pixels, bool placeScenery)
|
||||
{
|
||||
StashMap();
|
||||
TrackDesignPreviewClearMap();
|
||||
@@ -2087,7 +2090,7 @@ void TrackDesignDrawPreview(TrackDesign& td, uint8_t* pixels)
|
||||
|
||||
Ride* ride;
|
||||
TrackDesignGameStateData updatedGameStateData = td.gameStateData;
|
||||
if (!TrackDesignPlacePreview(tds, td, &ride, updatedGameStateData))
|
||||
if (!TrackDesignPlacePreview(tds, td, &ride, updatedGameStateData, !gTrackDesignSceneryToggle))
|
||||
{
|
||||
std::fill_n(pixels, kTrackPreviewImageSize * 4, 0x00);
|
||||
UnstashMap();
|
||||
|
||||
@@ -240,13 +240,14 @@ void TrackDesignMirror(TrackDesign& td);
|
||||
OpenRCT2::GameActions::Result TrackDesignPlace(
|
||||
const TrackDesign& td, uint32_t flags, bool placeScenery, Ride& ride, const CoordsXYZD& coords);
|
||||
void TrackDesignPreviewRemoveGhosts(const TrackDesign& td, Ride& ride, const CoordsXYZD& coords);
|
||||
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, const TrackDesign& td, Ride& ride, const CoordsXYZD& coords);
|
||||
void TrackDesignPreviewDrawOutlines(
|
||||
TrackDesignState& tds, const TrackDesign& td, Ride& ride, const CoordsXYZD& coords, bool placeScenery);
|
||||
int32_t TrackDesignGetZPlacement(const TrackDesign& td, Ride& ride, const CoordsXYZD& coords);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Track design preview
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void TrackDesignDrawPreview(TrackDesign& td, uint8_t* pixels);
|
||||
void TrackDesignDrawPreview(TrackDesign& td, uint8_t* pixels, bool placeScenery);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Track design saving
|
||||
|
||||
Reference in New Issue
Block a user