1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-18 04:23:20 +01:00

Close #18632: Display land ownership on the water (#21150)

Co-authored-by: pfroud <pfroud@users.noreply.github.com>
This commit is contained in:
Michael Steenbeek
2024-01-12 08:14:11 +01:00
committed by GitHub
parent 3023784bbf
commit 0e5c82e2d4
5 changed files with 123 additions and 48 deletions

View File

@@ -1,5 +1,6 @@
0.4.8 (in development)
------------------------------------------------------------------------
- Improved: [#18632] Land ownership and construction rights are now shown on top of the water.
- Fix: [#21145] [Plugin] setInterval/setTimeout handle conflict.
- Fix: [#21158] [Plugin] Potential crash using setInterval/setTimeout within the callback.
- Fix: [#21178] Inca Lost Citys scenario description incorrectly states there are height restrictions.

View File

@@ -240,9 +240,9 @@ public:
MapInvalidateSelectionRect();
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
auto mapTile = ScreenGetMapXY(screenCoords, nullptr);
if (!mapTile.has_value())
auto info = GetMapCoordinatesFromPos(
screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain, ViewportInteractionItem::Water));
if (info.SpriteType == ViewportInteractionItem::None)
{
if (_landRightsCost != MONEY64_UNDEFINED)
{
@@ -251,6 +251,7 @@ public:
}
return;
}
auto mapTile = info.Loc;
uint8_t state_changed = 0;
@@ -260,9 +261,9 @@ public:
state_changed++;
}
if (gMapSelectType != MAP_SELECT_TYPE_FULL)
if (gMapSelectType != MAP_SELECT_TYPE_FULL_LAND_RIGHTS)
{
gMapSelectType = MAP_SELECT_TYPE_FULL;
gMapSelectType = MAP_SELECT_TYPE_FULL_LAND_RIGHTS;
state_changed++;
}
@@ -273,34 +274,34 @@ public:
int16_t tool_length = (tool_size - 1) * 32;
// Move to tool bottom left
mapTile->x -= (tool_size - 1) * 16;
mapTile->y -= (tool_size - 1) * 16;
mapTile = mapTile->ToTileStart();
mapTile.x -= (tool_size - 1) * 16;
mapTile.y -= (tool_size - 1) * 16;
mapTile = mapTile.ToTileStart();
if (gMapSelectPositionA.x != mapTile->x)
if (gMapSelectPositionA.x != mapTile.x)
{
gMapSelectPositionA.x = mapTile->x;
gMapSelectPositionA.x = mapTile.x;
state_changed++;
}
if (gMapSelectPositionA.y != mapTile->y)
if (gMapSelectPositionA.y != mapTile.y)
{
gMapSelectPositionA.y = mapTile->y;
gMapSelectPositionA.y = mapTile.y;
state_changed++;
}
mapTile->x += tool_length;
mapTile->y += tool_length;
mapTile.x += tool_length;
mapTile.y += tool_length;
if (gMapSelectPositionB.x != mapTile->x)
if (gMapSelectPositionB.x != mapTile.x)
{
gMapSelectPositionB.x = mapTile->x;
gMapSelectPositionB.x = mapTile.x;
state_changed++;
}
if (gMapSelectPositionB.y != mapTile->y)
if (gMapSelectPositionB.y != mapTile.y)
{
gMapSelectPositionB.y = mapTile->y;
gMapSelectPositionB.y = mapTile.y;
state_changed++;
}

View File

@@ -980,6 +980,75 @@ static void PaintPatrolArea(PaintSession& session, const SurfaceElement& element
}
}
static void PaintSurfaceLandOwnership(
PaintSession& session, const SurfaceElement& tileElement, uint16_t height, uint8_t surfaceShape)
{
auto [aboveWaterHeight, aboveWaterSurfaceShape] = SurfaceGetHeightAboveWater(tileElement, height, surfaceShape);
// Loc660E9A:
if (tileElement.GetOwnership() & OWNERSHIP_OWNED)
{
assert(static_cast<size_t>(surfaceShape) < std::size(Byte97B444));
assert(static_cast<size_t>(aboveWaterSurfaceShape) < std::size(Byte97B444));
// Paint outline on top of surface (can be underwater)
PaintAttachToPreviousPS(session, ImageId(SPR_TERRAIN_SELECTION_SQUARE + Byte97B444[surfaceShape]), 0, 0);
const auto tileIsUnderWater = height != aboveWaterHeight || surfaceShape != aboveWaterSurfaceShape;
if (tileIsUnderWater)
{
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(
session, ImageId(SPR_TERRAIN_SELECTION_SQUARE + Byte97B444[aboveWaterSurfaceShape]), { 0, 0, aboveWaterHeight },
{ 32, 32, 1 });
session.LastPS = backup;
}
}
else if (tileElement.GetOwnership() & OWNERSHIP_AVAILABLE)
{
const auto pos = CoordsXYZ(session.MapPosition.x + 16, session.MapPosition.y + 16, aboveWaterHeight);
const auto height2 = TileElementHeight(pos, aboveWaterSurfaceShape);
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(session, ImageId(SPR_LAND_OWNERSHIP_AVAILABLE), { 16, 16, height2 }, { 1, 1, 0 });
session.LastPS = backup;
}
}
static void PaintSurfaceConstructionRights(
PaintSession& session, const SurfaceElement& tileElement, uint16_t height, uint8_t surfaceShape)
{
auto [aboveWaterHeight, aboveWaterSurfaceShape] = SurfaceGetHeightAboveWater(tileElement, height, surfaceShape);
if (tileElement.GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)
{
assert(static_cast<size_t>(surfaceShape) < std::size(Byte97B444));
assert(static_cast<size_t>(aboveWaterSurfaceShape) < std::size(Byte97B444));
// Paint outline on top of surface (can be underwater)
PaintAttachToPreviousPS(session, ImageId(SPR_TERRAIN_SELECTION_DOTTED + Byte97B444[surfaceShape]), 0, 0);
const auto tileIsUnderWater = height != aboveWaterHeight || surfaceShape != aboveWaterSurfaceShape;
if (tileIsUnderWater)
{
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(
session, ImageId(SPR_TERRAIN_SELECTION_DOTTED + Byte97B444[aboveWaterSurfaceShape]), { 0, 0, aboveWaterHeight },
{ 32, 32, 1 });
session.LastPS = backup;
}
}
else if (tileElement.GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE)
{
const auto pos = CoordsXYZ(session.MapPosition.x + 16, session.MapPosition.y + 16, aboveWaterHeight);
const auto height2 = TileElementHeight(pos, aboveWaterSurfaceShape);
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(session, ImageId(SPR_LAND_CONSTRUCTION_RIGHTS_AVAILABLE), { 16, 16, height2 }, { 1, 1, 0 });
session.LastPS = backup;
}
}
/**
* rct2: 0x0066062C
*/
@@ -1134,38 +1203,12 @@ void PaintSurface(PaintSession& session, uint8_t direction, uint16_t height, con
if (session.ViewFlags & VIEWPORT_FLAG_LAND_OWNERSHIP)
{
// Loc660E9A:
if (tileElement.GetOwnership() & OWNERSHIP_OWNED)
{
assert(surfaceShape < std::size(Byte97B444));
PaintAttachToPreviousPS(session, ImageId(SPR_TERRAIN_SELECTION_SQUARE + Byte97B444[surfaceShape]), 0, 0);
}
else if (tileElement.GetOwnership() & OWNERSHIP_AVAILABLE)
{
const CoordsXY& pos = session.MapPosition;
const int32_t height2 = (TileElementHeight({ pos.x + 16, pos.y + 16 })) + 3;
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(session, ImageId(SPR_LAND_OWNERSHIP_AVAILABLE), { 16, 16, height2 }, { 1, 1, 0 });
session.LastPS = backup;
}
PaintSurfaceLandOwnership(session, tileElement, height, surfaceShape);
}
if (session.ViewFlags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS && !(tileElement.GetOwnership() & OWNERSHIP_OWNED))
{
if (tileElement.GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)
{
assert(surfaceShape < std::size(Byte97B444));
PaintAttachToPreviousPS(session, ImageId(SPR_TERRAIN_SELECTION_DOTTED + Byte97B444[surfaceShape]), 0, 0);
}
else if (tileElement.GetOwnership() & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE)
{
const CoordsXY& pos = session.MapPosition;
const int32_t height2 = TileElementHeight({ pos.x + 16, pos.y + 16 });
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(
session, ImageId(SPR_LAND_CONSTRUCTION_RIGHTS_AVAILABLE), { 16, 16, height2 + 3 }, { 1, 1, 0 });
session.LastPS = backup;
}
PaintSurfaceConstructionRights(session, tileElement, height, surfaceShape);
}
// ebx[0] = esi;
@@ -1214,6 +1257,23 @@ void PaintSurface(PaintSession& session, uint8_t direction, uint16_t height, con
const auto image_id = ImageId(SPR_TERRAIN_SELECTION_CORNER + Byte97B444[surfaceShape], fpId);
PaintAttachToPreviousPS(session, image_id, 0, 0);
}
else if (mapSelectionType == MAP_SELECT_TYPE_FULL_LAND_RIGHTS)
{
auto [waterHeight, waterSurfaceShape] = SurfaceGetHeightAboveWater(tileElement, height, surfaceShape);
const auto fpId = FilterPaletteID::PaletteGlassLightPurple;
const auto imageId1 = ImageId(SPR_TERRAIN_SELECTION_CORNER + Byte97B444[surfaceShape], fpId);
PaintAttachToPreviousPS(session, imageId1, 0, 0);
const bool isUnderWater = (surfaceShape != waterSurfaceShape || height != waterHeight);
if (isUnderWater)
{
const auto imageId2 = ImageId(SPR_TERRAIN_SELECTION_CORNER + Byte97B444[waterSurfaceShape], fpId);
PaintStruct* backup = session.LastPS;
PaintAddImageAsParent(session, imageId2, { 0, 0, waterHeight }, { 32, 32, 1 });
session.LastPS = backup;
}
}
else
{
// The water tool should draw its grid _on_ the water, rather than on the surface under water.

View File

@@ -536,9 +536,20 @@ int16_t TileElementHeight(const CoordsXY& loc)
return MINIMUM_LAND_HEIGHT_BIG;
}
uint16_t height = surfaceElement->GetBaseZ();
auto height = surfaceElement->GetBaseZ();
auto slope = surfaceElement->GetSlope();
return TileElementHeight(CoordsXYZ{ loc, height }, slope);
}
int16_t TileElementHeight(const CoordsXYZ& loc, uint8_t slope)
{
// Off the map
if (!MapIsLocationValid(loc))
return MINIMUM_LAND_HEIGHT_BIG;
auto height = loc.z;
uint32_t slope = surfaceElement->GetSlope();
uint8_t extra_height = (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4; // 0x10 is the 5th bit - sets slope to double height
// Remove the extra height bit
slope &= TILE_ELEMENT_SLOPE_ALL_CORNERS_UP;

View File

@@ -79,6 +79,7 @@ enum
MAP_SELECT_TYPE_CORNER_3,
MAP_SELECT_TYPE_FULL,
MAP_SELECT_TYPE_FULL_WATER,
MAP_SELECT_TYPE_FULL_LAND_RIGHTS,
MAP_SELECT_TYPE_QUARTER_0,
MAP_SELECT_TYPE_QUARTER_1,
MAP_SELECT_TYPE_QUARTER_2,
@@ -191,6 +192,7 @@ void MapInvalidateMapSelectionTiles();
void MapInvalidateSelectionRect();
bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements = 1);
int16_t TileElementHeight(const CoordsXY& loc);
int16_t TileElementHeight(const CoordsXYZ& loc, uint8_t slope);
int16_t TileElementWaterHeight(const CoordsXY& loc);
void TileElementRemove(TileElement* tileElement);
TileElement* TileElementInsert(const CoordsXYZ& loc, int32_t occupiedQuadrants, TileElementType type);