2021-02-04 17:21:17 +01:00
|
|
|
/*****************************************************************************
|
2024-01-01 12:52:28 +01:00
|
|
|
* Copyright (c) 2014-2024 OpenRCT2 developers
|
2014-04-09 04:09:30 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2014-04-09 04:09:30 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2014-04-09 04:09:30 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2021-08-21 12:55:28 +02:00
|
|
|
#pragma once
|
2014-04-09 04:09:30 +02:00
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
#include "../common.h"
|
2018-03-07 19:10:50 +01:00
|
|
|
#include "Location.hpp"
|
2018-05-01 17:47:00 +02:00
|
|
|
#include "TileElement.h"
|
2017-06-03 12:52:34 +02:00
|
|
|
|
2018-06-22 23:17:03 +02:00
|
|
|
#include <initializer_list>
|
2018-12-15 19:23:40 +01:00
|
|
|
#include <vector>
|
2018-06-22 23:17:03 +02:00
|
|
|
|
2024-03-01 21:23:29 +01:00
|
|
|
constexpr uint8_t kMinimumLandHeight = 2;
|
|
|
|
constexpr uint8_t kMaximumLandHeight = 254;
|
|
|
|
constexpr uint8_t kMinimumWaterHeight = 2;
|
|
|
|
constexpr uint8_t kMaximumWaterHeight = 254;
|
2024-02-20 11:49:02 +01:00
|
|
|
/**
|
|
|
|
* The land height that counts as 0 metres/feet for the land height labels and altitude graphs.
|
|
|
|
*/
|
|
|
|
constexpr uint8_t kMapBaseZ = 7;
|
2017-07-13 17:31:37 +02:00
|
|
|
|
2024-03-25 16:56:04 +01:00
|
|
|
constexpr uint8_t kMinimumMapSizeTechnical = 5;
|
|
|
|
constexpr uint16_t kMaximumMapSizeTechnical = 1001;
|
2024-04-01 12:00:32 +02:00
|
|
|
constexpr int16_t kMinimumMapSizePractical = (kMinimumMapSizeTechnical - 2);
|
|
|
|
constexpr int16_t kMaximumMapSizePractical = (kMaximumMapSizeTechnical - 2);
|
2024-03-17 14:41:36 +01:00
|
|
|
constexpr const int32_t MAXIMUM_MAP_SIZE_BIG = COORDS_XY_STEP * kMaximumMapSizeTechnical;
|
2023-06-24 11:45:26 +02:00
|
|
|
constexpr int32_t MAXIMUM_TILE_START_XY = MAXIMUM_MAP_SIZE_BIG - COORDS_XY_STEP;
|
2019-12-30 16:03:51 +01:00
|
|
|
constexpr const int32_t LAND_HEIGHT_STEP = 2 * COORDS_Z_STEP;
|
2022-07-01 00:09:27 +02:00
|
|
|
constexpr const int32_t WATER_HEIGHT_STEP = 2 * COORDS_Z_STEP;
|
2024-03-01 21:23:29 +01:00
|
|
|
constexpr const int32_t kMinimumLandZ = kMinimumLandHeight * COORDS_Z_STEP;
|
2023-06-24 11:45:26 +02:00
|
|
|
constexpr TileCoordsXY DEFAULT_MAP_SIZE = { 150, 150 };
|
2022-07-27 23:31:08 +02:00
|
|
|
// How high construction has to be off the ground when the player owns construction rights, in tile coords.
|
2023-06-24 11:45:26 +02:00
|
|
|
constexpr uint8_t ConstructionRightsClearanceSmall = 3;
|
2022-07-27 23:31:08 +02:00
|
|
|
// Same as previous, but in big coords.
|
|
|
|
constexpr const uint8_t ConstructionRightsClearanceBig = 3 * COORDS_Z_STEP;
|
2017-06-03 12:52:34 +02:00
|
|
|
|
2024-04-01 12:00:32 +02:00
|
|
|
constexpr int16_t kMapMinimumXY = (-kMaximumMapSizeTechnical);
|
2014-08-24 13:33:37 +02:00
|
|
|
|
2023-06-24 11:45:26 +02:00
|
|
|
constexpr uint32_t MAX_TILE_ELEMENTS_WITH_SPARE_ROOM = 0x1000000;
|
|
|
|
constexpr uint32_t MAX_TILE_ELEMENTS = MAX_TILE_ELEMENTS_WITH_SPARE_ROOM - 512;
|
2014-04-09 04:09:30 +02:00
|
|
|
|
2020-02-17 11:43:47 +01:00
|
|
|
using PeepSpawn = CoordsXYZD;
|
2014-05-25 14:59:31 +02:00
|
|
|
|
2020-01-04 11:44:36 +01:00
|
|
|
struct CoordsXYE : public CoordsXY
|
2018-02-14 11:31:49 +01:00
|
|
|
{
|
2020-01-04 11:44:36 +01:00
|
|
|
CoordsXYE() = default;
|
|
|
|
constexpr CoordsXYE(int32_t _x, int32_t _y, TileElement* _e)
|
|
|
|
: CoordsXY(_x, _y)
|
|
|
|
, element(_e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-29 05:09:06 +01:00
|
|
|
constexpr CoordsXYE(const CoordsXY& c, TileElement* _e)
|
2020-01-04 11:44:36 +01:00
|
|
|
: CoordsXY(c)
|
|
|
|
, element(_e)
|
|
|
|
{
|
|
|
|
}
|
2021-01-06 22:29:40 +01:00
|
|
|
TileElement* element = nullptr;
|
2018-02-14 11:31:49 +01:00
|
|
|
};
|
|
|
|
|
2018-06-22 23:17:03 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
MAP_SELECT_FLAG_ENABLE = 1 << 0,
|
|
|
|
MAP_SELECT_FLAG_ENABLE_CONSTRUCT = 1 << 1,
|
|
|
|
MAP_SELECT_FLAG_ENABLE_ARROW = 1 << 2,
|
|
|
|
MAP_SELECT_FLAG_GREEN = 1 << 3,
|
2016-05-14 01:54:13 +02:00
|
|
|
};
|
|
|
|
|
2018-06-22 23:17:03 +02:00
|
|
|
enum
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
MAP_SELECT_TYPE_CORNER_0,
|
|
|
|
MAP_SELECT_TYPE_CORNER_1,
|
|
|
|
MAP_SELECT_TYPE_CORNER_2,
|
|
|
|
MAP_SELECT_TYPE_CORNER_3,
|
|
|
|
MAP_SELECT_TYPE_FULL,
|
|
|
|
MAP_SELECT_TYPE_FULL_WATER,
|
2024-01-12 08:14:11 +01:00
|
|
|
MAP_SELECT_TYPE_FULL_LAND_RIGHTS,
|
2017-06-06 23:24:18 +02:00
|
|
|
MAP_SELECT_TYPE_QUARTER_0,
|
|
|
|
MAP_SELECT_TYPE_QUARTER_1,
|
|
|
|
MAP_SELECT_TYPE_QUARTER_2,
|
|
|
|
MAP_SELECT_TYPE_QUARTER_3,
|
|
|
|
MAP_SELECT_TYPE_EDGE_0,
|
|
|
|
MAP_SELECT_TYPE_EDGE_1,
|
|
|
|
MAP_SELECT_TYPE_EDGE_2,
|
|
|
|
MAP_SELECT_TYPE_EDGE_3,
|
2016-05-14 01:54:13 +02:00
|
|
|
};
|
|
|
|
|
2021-06-13 10:13:13 +02:00
|
|
|
// Used when calling MapCanConstructWithClearAt();
|
2017-12-20 18:20:31 +01:00
|
|
|
// This assumes that the caller has already done the check on the element it wants to place,
|
|
|
|
// as this function can only check the element the player wants to build through.
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
CREATE_CROSSING_MODE_NONE,
|
|
|
|
CREATE_CROSSING_MODE_TRACK_OVER_PATH,
|
|
|
|
CREATE_CROSSING_MODE_PATH_OVER_TRACK,
|
|
|
|
};
|
|
|
|
|
2020-01-14 02:22:04 +01:00
|
|
|
extern const std::array<CoordsXY, 8> CoordsDirectionDelta;
|
2018-04-18 20:34:34 +02:00
|
|
|
extern const TileCoordsXY TileDirectionDelta[];
|
2015-07-14 00:49:39 +02:00
|
|
|
|
2024-02-12 22:32:08 +01:00
|
|
|
CoordsXY GetMapSizeUnits();
|
|
|
|
CoordsXY GetMapSizeMinus2();
|
|
|
|
CoordsXY GetMapSizeMaxXY();
|
2016-04-24 15:00:26 +02:00
|
|
|
|
2018-06-22 23:17:03 +02:00
|
|
|
extern uint16_t gMapSelectFlags;
|
|
|
|
extern uint16_t gMapSelectType;
|
2019-12-12 12:04:40 +01:00
|
|
|
extern CoordsXY gMapSelectPositionA;
|
|
|
|
extern CoordsXY gMapSelectPositionB;
|
2019-12-30 17:51:35 +01:00
|
|
|
extern CoordsXYZ gMapSelectArrowPosition;
|
2018-06-22 23:17:03 +02:00
|
|
|
extern uint8_t gMapSelectArrowDirection;
|
2016-05-14 01:54:13 +02:00
|
|
|
|
2019-03-28 19:29:51 +01:00
|
|
|
extern std::vector<CoordsXY> gMapSelectionTiles;
|
2016-04-24 15:30:21 +02:00
|
|
|
|
2015-10-11 13:26:33 +02:00
|
|
|
// Used in the land tool window to enable mountain tool / land smoothing
|
|
|
|
extern bool gLandMountainMode;
|
2015-05-12 17:37:16 +02:00
|
|
|
// Used in the land tool window to allow dragging and changing land styles
|
2015-10-11 13:26:33 +02:00
|
|
|
extern bool gLandPaintMode;
|
2015-06-05 18:38:52 +02:00
|
|
|
// Used in the clear scenery tool
|
|
|
|
extern bool gClearSmallScenery;
|
|
|
|
extern bool gClearLargeScenery;
|
|
|
|
extern bool gClearFootpath;
|
2014-05-25 14:59:31 +02:00
|
|
|
|
2021-08-16 21:51:16 +02:00
|
|
|
extern uint32_t gLandRemainingOwnershipSales;
|
|
|
|
extern uint32_t gLandRemainingConstructionSales;
|
2016-10-31 20:21:10 +01:00
|
|
|
|
2017-06-08 22:28:39 +02:00
|
|
|
extern bool gMapLandRightsUpdateSuccess;
|
2016-09-10 18:46:34 +02:00
|
|
|
|
2021-04-09 03:09:08 +02:00
|
|
|
void ReorganiseTileElements();
|
|
|
|
const std::vector<TileElement>& GetTileElements();
|
|
|
|
void SetTileElements(std::vector<TileElement>&& tileElements);
|
|
|
|
void StashMap();
|
|
|
|
void UnstashMap();
|
2021-11-14 21:58:33 +01:00
|
|
|
std::vector<TileElement> GetReorganisedTileElementsWithoutGhosts();
|
2021-04-09 03:09:08 +02:00
|
|
|
|
2022-10-11 20:39:24 +02:00
|
|
|
void MapInit(const TileCoordsXY& size);
|
2019-03-04 17:57:01 +01:00
|
|
|
|
2022-10-11 20:39:24 +02:00
|
|
|
void MapCountRemainingLandRights();
|
|
|
|
void MapStripGhostFlagFromElements();
|
|
|
|
TileElement* MapGetFirstElementAt(const CoordsXY& tilePos);
|
|
|
|
TileElement* MapGetFirstElementAt(const TileCoordsXY& tilePos);
|
|
|
|
TileElement* MapGetNthElementAt(const CoordsXY& coords, int32_t n);
|
2022-09-30 20:00:59 +02:00
|
|
|
TileElement* MapGetFirstTileElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc, TileElementType type);
|
2022-10-11 20:39:24 +02:00
|
|
|
void MapSetTileElement(const TileCoordsXY& tilePos, TileElement* elements);
|
|
|
|
int32_t MapHeightFromSlope(const CoordsXY& coords, int32_t slopeDirection, bool isSloped);
|
|
|
|
BannerElement* MapGetBannerElementAt(const CoordsXYZ& bannerPos, uint8_t direction);
|
2023-04-05 22:13:47 +02:00
|
|
|
SurfaceElement* MapGetSurfaceElementAt(const TileCoordsXY& coords);
|
2022-10-11 20:39:24 +02:00
|
|
|
SurfaceElement* MapGetSurfaceElementAt(const CoordsXY& coords);
|
2022-10-12 07:35:20 +02:00
|
|
|
PathElement* MapGetPathElementAt(const TileCoordsXYZ& loc);
|
|
|
|
WallElement* MapGetWallElementAt(const CoordsXYZD& wallCoords);
|
|
|
|
WallElement* MapGetWallElementAt(const CoordsXYRangedZ& coords);
|
|
|
|
SmallSceneryElement* MapGetSmallSceneryElementAt(const CoordsXYZ& sceneryCoords, int32_t type, uint8_t quadrant);
|
|
|
|
EntranceElement* MapGetParkEntranceElementAt(const CoordsXYZ& entranceCoords, bool ghost);
|
|
|
|
EntranceElement* MapGetRideEntranceElementAt(const CoordsXYZ& entranceCoords, bool ghost);
|
|
|
|
EntranceElement* MapGetRideExitElementAt(const CoordsXYZ& exitCoords, bool ghost);
|
|
|
|
uint8_t MapGetHighestLandHeight(const MapRange& range);
|
|
|
|
uint8_t MapGetLowestLandHeight(const MapRange& range);
|
|
|
|
bool MapCoordIsConnected(const TileCoordsXYZ& loc, uint8_t faceDirection);
|
|
|
|
void MapRemoveProvisionalElements();
|
|
|
|
void MapRestoreProvisionalElements();
|
|
|
|
void MapUpdatePathWideFlags();
|
|
|
|
bool MapIsLocationValid(const CoordsXY& coords);
|
|
|
|
bool MapIsEdge(const CoordsXY& coords);
|
|
|
|
bool MapCanBuildAt(const CoordsXYZ& loc);
|
|
|
|
bool MapIsLocationOwned(const CoordsXYZ& loc);
|
|
|
|
bool MapIsLocationInPark(const CoordsXY& coords);
|
|
|
|
bool MapIsLocationOwnedOrHasRights(const CoordsXY& loc);
|
|
|
|
bool MapSurfaceIsBlocked(const CoordsXY& mapCoords);
|
|
|
|
void MapRemoveAllRides();
|
|
|
|
void MapInvalidateMapSelectionTiles();
|
|
|
|
void MapInvalidateSelectionRect();
|
2021-06-06 09:28:07 +02:00
|
|
|
bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements = 1);
|
2022-10-12 07:35:20 +02:00
|
|
|
int16_t TileElementHeight(const CoordsXY& loc);
|
2024-01-12 08:14:11 +01:00
|
|
|
int16_t TileElementHeight(const CoordsXYZ& loc, uint8_t slope);
|
2022-10-12 07:35:20 +02:00
|
|
|
int16_t TileElementWaterHeight(const CoordsXY& loc);
|
|
|
|
void TileElementRemove(TileElement* tileElement);
|
|
|
|
TileElement* TileElementInsert(const CoordsXYZ& loc, int32_t occupiedQuadrants, TileElementType type);
|
2018-06-20 17:28:51 +02:00
|
|
|
|
2022-09-30 20:00:59 +02:00
|
|
|
template<typename T = TileElement> T* MapGetFirstTileElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc)
|
|
|
|
{
|
|
|
|
auto* element = MapGetFirstTileElementWithBaseHeightBetween(loc, T::ElementType);
|
|
|
|
return element != nullptr ? element->template as<T>() : nullptr;
|
|
|
|
}
|
|
|
|
|
2021-02-04 17:21:17 +01:00
|
|
|
template<typename T> T* TileElementInsert(const CoordsXYZ& loc, int32_t occupiedQuadrants)
|
|
|
|
{
|
2022-10-12 07:35:20 +02:00
|
|
|
auto* element = TileElementInsert(loc, occupiedQuadrants, T::ElementType);
|
2021-03-18 23:28:43 +01:00
|
|
|
return (element != nullptr) ? element->template as<T>() : nullptr;
|
2021-02-04 17:21:17 +01:00
|
|
|
}
|
|
|
|
|
2023-01-19 16:13:23 +01:00
|
|
|
struct TileElementIterator
|
2018-06-22 23:17:03 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t x;
|
|
|
|
int32_t y;
|
2018-11-01 13:53:50 +01:00
|
|
|
TileElement* element;
|
2018-02-14 09:42:26 +01:00
|
|
|
};
|
2016-06-03 00:18:20 +02:00
|
|
|
#ifdef PLATFORM_32BIT
|
2023-01-19 16:13:23 +01:00
|
|
|
assert_struct_size(TileElementIterator, 12);
|
2016-06-03 00:18:20 +02:00
|
|
|
#endif
|
2015-01-22 01:19:05 +01:00
|
|
|
|
2023-01-19 16:13:23 +01:00
|
|
|
void TileElementIteratorBegin(TileElementIterator* it);
|
|
|
|
int32_t TileElementIteratorNext(TileElementIterator* it);
|
|
|
|
void TileElementIteratorRestartForTile(TileElementIterator* it);
|
2015-01-22 01:19:05 +01:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
void MapUpdateTiles();
|
|
|
|
int32_t MapGetHighestZ(const CoordsXY& loc);
|
2015-02-13 21:55:49 +01:00
|
|
|
|
2022-10-04 08:51:27 +02:00
|
|
|
bool TileElementWantsPathConnectionTowards(const TileCoordsXYZD& coords, const TileElement* const elementToBeRemoved);
|
2015-06-28 18:45:19 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
void MapRemoveOutOfRangeElements();
|
|
|
|
void MapExtendBoundarySurfaceX();
|
|
|
|
void MapExtendBoundarySurfaceY();
|
2015-07-02 01:37:55 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
bool MapLargeScenerySignSetColour(const CoordsXYZD& signPos, int32_t sequence, uint8_t mainColour, uint8_t textColour);
|
2022-10-11 20:39:24 +02:00
|
|
|
void WallRemoveAt(const CoordsXYRangedZ& wallPos);
|
|
|
|
void WallRemoveAtZ(const CoordsXYZ& wallPos);
|
|
|
|
void WallRemoveIntersectingWalls(const CoordsXYRangedZ& wallPos, Direction direction);
|
2015-07-06 18:59:37 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
void MapInvalidateTile(const CoordsXYRangedZ& tilePos);
|
|
|
|
void MapInvalidateTileZoom1(const CoordsXYRangedZ& tilePos);
|
|
|
|
void MapInvalidateTileZoom0(const CoordsXYRangedZ& tilePos);
|
|
|
|
void MapInvalidateTileFull(const CoordsXY& tilePos);
|
|
|
|
void MapInvalidateElement(const CoordsXY& elementPos, TileElement* tileElement);
|
|
|
|
void MapInvalidateRegion(const CoordsXY& mins, const CoordsXY& maxs);
|
2015-07-06 19:57:36 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
int32_t MapGetTileSide(const CoordsXY& mapPos);
|
|
|
|
int32_t MapGetTileQuadrant(const CoordsXY& mapPos);
|
|
|
|
int32_t MapGetCornerHeight(int32_t z, int32_t slope, int32_t direction);
|
|
|
|
int32_t TileElementGetCornerHeight(const SurfaceElement* surfaceElement, int32_t direction);
|
2015-07-11 19:23:59 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
void MapClearAllElements();
|
2015-08-31 12:42:46 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
LargeSceneryElement* MapGetLargeScenerySegment(const CoordsXYZD& sceneryPos, int32_t sequence);
|
|
|
|
std::optional<CoordsXYZ> MapLargeSceneryGetOrigin(
|
2019-12-23 14:07:20 +01:00
|
|
|
const CoordsXYZD& sceneryPos, int32_t sequence, LargeSceneryElement** outElement);
|
2018-06-22 23:17:03 +02:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
TrackElement* MapGetTrackElementAt(const CoordsXYZ& trackPos);
|
|
|
|
TileElement* MapGetTrackElementAtOfType(const CoordsXYZ& trackPos, track_type_t trackType);
|
|
|
|
TileElement* MapGetTrackElementAtOfTypeSeq(const CoordsXYZ& trackPos, track_type_t trackType, int32_t sequence);
|
|
|
|
TrackElement* MapGetTrackElementAtOfType(const CoordsXYZD& location, track_type_t trackType);
|
|
|
|
TrackElement* MapGetTrackElementAtOfTypeSeq(const CoordsXYZD& location, track_type_t trackType, int32_t sequence);
|
|
|
|
TileElement* MapGetTrackElementAtOfTypeFromRide(const CoordsXYZ& trackPos, track_type_t trackType, RideId rideIndex);
|
|
|
|
TileElement* MapGetTrackElementAtFromRide(const CoordsXYZ& trackPos, RideId rideIndex);
|
|
|
|
TileElement* MapGetTrackElementAtWithDirectionFromRide(const CoordsXYZD& trackPos, RideId rideIndex);
|
2015-10-25 17:00:21 +01:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
bool MapIsLocationAtEdge(const CoordsXY& loc);
|
2017-02-18 09:26:33 +01:00
|
|
|
|
2022-10-12 14:14:45 +02:00
|
|
|
uint16_t CheckMaxAllowableLandRightsForTile(const CoordsXYZ& tileMapPos);
|
2017-03-02 23:02:54 +01:00
|
|
|
|
2018-02-15 17:42:53 +01:00
|
|
|
void FixLandOwnershipTiles(std::initializer_list<TileCoordsXY> tiles);
|
2021-08-01 17:26:43 +02:00
|
|
|
void FixLandOwnershipTilesWithOwnership(
|
|
|
|
std::initializer_list<TileCoordsXY> tiles, uint8_t ownership, bool doNotDowngrade = false);
|
2021-12-17 19:25:46 +01:00
|
|
|
MapRange ClampRangeWithinMap(const MapRange& range);
|