diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 84a066eea8..c5e4a61a92 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.12 (in development) ------------------------------------------------------------------------ - Feature: [#622] Add option to align the top toolbar buttons horizontally centred (off by default). +- Feature: [#20263] Ability to increase the size of the map in the (0, 0) direction. - Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type. - Feature: [#21853] Enlarged UI mode. - Feature: [#21893] On launch, the game now indicates what system is being initialised. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index b764a2faf8..fbf1071cd9 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -939,6 +939,8 @@ declare global { interface MapChangeSizeArgs extends GameActionArgs { targetSizeX: number; targetSizeY: number; + shiftX: number; + shiftY: number; } interface MazePlaceTrackArgs extends GameActionArgs { diff --git a/src/openrct2/actions/MapChangeSizeAction.cpp b/src/openrct2/actions/MapChangeSizeAction.cpp index 04e28ac200..18f4d86c2c 100644 --- a/src/openrct2/actions/MapChangeSizeAction.cpp +++ b/src/openrct2/actions/MapChangeSizeAction.cpp @@ -18,7 +18,13 @@ #include "../world/Park.h" MapChangeSizeAction::MapChangeSizeAction(const TileCoordsXY& targetSize) + : MapChangeSizeAction(targetSize, TileCoordsXY()) +{ +} + +MapChangeSizeAction::MapChangeSizeAction(const TileCoordsXY& targetSize, const TileCoordsXY& shift) : _targetSize(targetSize) + , _shift(shift) { } @@ -31,6 +37,7 @@ void MapChangeSizeAction::Serialise(DataSerialiser& stream) { GameAction::Serialise(stream); stream << DS_TAG(_targetSize); + stream << DS_TAG(_shift); } GameActions::Result MapChangeSizeAction::Query() const @@ -63,6 +70,9 @@ GameActions::Result MapChangeSizeAction::Execute() const MapExtendBoundarySurfaceY(); } + // Shift the map (allows increasing the map at the 0,0 position + ShiftMap(_shift); + // Shrink map if (_targetSize.x < gameState.MapSize.x || _targetSize.y < gameState.MapSize.y) { @@ -84,4 +94,6 @@ void MapChangeSizeAction::AcceptParameters(GameActionParameterVisitor& visitor) { visitor.Visit("targetSizeX", _targetSize.x); visitor.Visit("targetSizeY", _targetSize.y); + visitor.Visit("shiftX", _shift.x); + visitor.Visit("shiftY", _shift.y); } diff --git a/src/openrct2/actions/MapChangeSizeAction.h b/src/openrct2/actions/MapChangeSizeAction.h index 81e8db3e64..e46bae208a 100644 --- a/src/openrct2/actions/MapChangeSizeAction.h +++ b/src/openrct2/actions/MapChangeSizeAction.h @@ -17,6 +17,7 @@ class MapChangeSizeAction final : public GameActionBase(); + for (int32_t y = 0; y < kMaximumMapSizeTechnical; y++) + { + for (int32_t x = 0; x < kMaximumMapSizeTechnical; x++) + { + auto srcX = x - amount.x; + auto srcY = y - amount.y; + if (x > 0 && y > 0 && x < gameState.MapSize.x - 1 && y < gameState.MapSize.y - 1 && srcX > 0 && srcY > 0 + && srcX < gameState.MapSize.x - 1 && srcY < gameState.MapSize.y - 1) + { + auto srcTile = _tileIndex.GetFirstElementAt(TileCoordsXY(srcX, srcY)); + do + { + newElements.push_back(*srcTile); + } while (!(srcTile++)->IsLastForTile()); + } + else if (x == 0 || y == 0 || x == gameState.MapSize.x - 1 || y == gameState.MapSize.y - 1) + { + auto surface = GetDefaultSurfaceElement(); + surface.SetBaseZ(kMinimumLandZ); + surface.SetClearanceZ(kMinimumLandZ); + surface.AsSurface()->SetSlope(0); + surface.AsSurface()->SetWaterHeight(0); + newElements.push_back(surface); + } + else + { + auto copyX = std::clamp(srcX, 1, gameState.MapSize.x - 2); + auto copyY = std::clamp(srcY, 1, gameState.MapSize.y - 2); + auto srcTile = MapGetSurfaceElementAt(TileCoordsXY(copyX, copyY)); + if (srcTile != nullptr) + { + auto tileEl = *srcTile; + tileEl.SetOwner(OWNERSHIP_UNOWNED); + tileEl.SetParkFences(0); + tileEl.SetLastForTile(true); + newElements.push_back(*reinterpret_cast(&tileEl)); + } + else + { + newElements.push_back(GetDefaultSurfaceElement()); + } + } + } + } + SetTileElements(std::move(newElements)); + MapRemoveOutOfRangeElements(); + + for (auto& spawn : gameState.PeepSpawns) + shiftIfNotNull(spawn, amountToMove); + + for (auto& entrance : gameState.Park.Entrances) + shiftIfNotNull(entrance, amountToMove); + + // Entities + auto& entityTweener = EntityTweener::Get(); + for (auto i = 0; i < EnumValue(EntityType::Count); i++) + { + auto entityType = static_cast(i); + auto& list = GetEntityList(entityType); + for (const auto& entityId : list) + { + auto entity = GetEntity(entityId); + + // Do not tween the entity + entityTweener.RemoveEntity(entity); + + auto location = entity->GetLocation(); + shiftIfNotNull(location, amountToMove); + entity->MoveTo(location); + + switch (entityType) + { + case EntityType::Guest: + case EntityType::Staff: + { + auto peep = entity->As(); + if (peep != nullptr) + { + shiftIfNotNull(peep->NextLoc, amountToMove); + peep->DestinationX += amountToMove.x; + peep->DestinationY += amountToMove.y; + shiftIfNotNull(peep->PathfindGoal, amount); + for (auto& h : peep->PathfindHistory) + shiftIfNotNull(h, amount); + } + break; + } + case EntityType::Vehicle: + { + auto vehicle = entity->As(); + if (vehicle != nullptr) + { + shiftIfNotNull(vehicle->TrackLocation, amountToMove); + shiftIfNotNull(vehicle->BoatLocation, amountToMove); + } + break; + } + case EntityType::Duck: + { + auto duck = entity->As(); + if (duck != nullptr) + { + duck->target_x += amountToMove.x; + duck->target_y += amountToMove.y; + } + break; + } + case EntityType::JumpingFountain: + { + auto fountain = entity->As(); + if (fountain != nullptr) + { + fountain->TargetX += amountToMove.x; + fountain->TargetY += amountToMove.y; + } + } + default: + break; + } + if (entityType == EntityType::Staff) + { + auto staff = entity->As(); + if (staff != nullptr) + { + auto patrol = staff->PatrolInfo; + if (patrol != nullptr) + { + auto positions = patrol->ToVector(); + for (auto& p : positions) + shiftIfNotNull(p, amount); + patrol->Clear(); + patrol->Union(positions); + } + } + } + } + } + UpdateConsolidatedPatrolAreas(); + + // Rides + for (auto& ride : GetRideManager()) + { + auto& stations = ride.GetStations(); + for (auto& station : stations) + { + shiftIfNotNull(station.Start, amountToMove); + shiftIfNotNull(station.Entrance, amount); + shiftIfNotNull(station.Exit, amount); + } + + shiftIfNotNull(ride.overall_view, amountToMove); + shiftIfNotNull(ride.boat_hire_return_position, amount); + shiftIfNotNull(ride.CurTestTrackLocation, amount); + shiftIfNotNull(ride.ChairliftBullwheelLocation[0], amount); + shiftIfNotNull(ride.ChairliftBullwheelLocation[1], amount); + shiftIfNotNull(ride.CableLiftLoc, amountToMove); + } + + // Banners + auto numBanners = GetNumBanners(); + auto id = BannerIndex::FromUnderlying(0); + size_t count = 0; + while (count < numBanners) + { + auto* banner = GetBanner(id); + if (banner != nullptr) + { + shiftIfNotNull(banner->position, amount); + count++; + } + id = BannerIndex::FromUnderlying(id.ToUnderlying() + 1); + } + + ShiftAllMapAnimations(amountToMove); +} diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index ab9ac02c85..f1bc156f22 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -246,3 +246,4 @@ void FixLandOwnershipTiles(std::initializer_list tiles); void FixLandOwnershipTilesWithOwnership( std::initializer_list tiles, uint8_t ownership, bool doNotDowngrade = false); MapRange ClampRangeWithinMap(const MapRange& range); +void ShiftMap(const TileCoordsXY& amount); diff --git a/src/openrct2/world/MapAnimation.cpp b/src/openrct2/world/MapAnimation.cpp index 9c1751d48b..690c62f779 100644 --- a/src/openrct2/world/MapAnimation.cpp +++ b/src/openrct2/world/MapAnimation.cpp @@ -709,3 +709,14 @@ void MapAnimationAutoCreateAtTileElement(TileCoordsXY coords, TileElement* el) break; } } + +void ShiftAllMapAnimations(CoordsXY amount) +{ + if (amount.x == 0 && amount.y == 0) + return; + + for (auto& a : _mapAnimations) + { + a.location += amount; + } +} diff --git a/src/openrct2/world/MapAnimation.h b/src/openrct2/world/MapAnimation.h index ddbdabe18e..fff54969c5 100644 --- a/src/openrct2/world/MapAnimation.h +++ b/src/openrct2/world/MapAnimation.h @@ -46,3 +46,4 @@ void MapAnimationInvalidateAll(); const std::vector& GetMapAnimations(); void MapAnimationAutoCreate(); void MapAnimationAutoCreateAtTileElement(TileCoordsXY coords, TileElement* el); +void ShiftAllMapAnimations(CoordsXY amount);