mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-18 04:23:20 +01:00
Co-authored-by: pfroud <pfroud@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
3023784bbf
commit
0e5c82e2d4
@@ -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 City’s scenario description incorrectly states there are height restrictions.
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user