1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-25 15:54:31 +01:00
Files
OpenRCT2/src/openrct2/world/Surface.cpp

249 lines
6.7 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2018 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "Surface.h"
#include "../Context.h"
#include "../object/ObjectManager.h"
#include "../object/TerrainSurfaceObject.h"
#include "../scenario/Scenario.h"
#include "Location.hpp"
#include "Map.h"
uint32_t SurfaceElement::GetSurfaceStyle() const
{
uint32_t retVal = (terrain >> 5) & 7;
if (type & 1)
retVal |= (1 << 3);
return retVal;
}
uint32_t SurfaceElement::GetEdgeStyle() const
{
uint32_t terrain_edge = (slope >> 5) & 7;
if (type & 128)
terrain_edge |= (1 << 3);
return terrain_edge;
}
void SurfaceElement::SetSurfaceStyle(uint32_t newStyle)
{
// Bit 3 for terrain is stored in element.type bit 0
if (newStyle & 8)
type |= 1;
else
type &= ~1;
// Bits 0, 1, 2 for terrain are stored in element.terrain bit 5, 6, 7
terrain &= ~0xE0;
terrain |= (newStyle & 7) << 5;
}
void SurfaceElement::SetEdgeStyle(uint32_t newStyle)
{
// Bit 3 for terrain is stored in element.type bit 7
if (newStyle & 8)
type |= 128;
else
type &= ~128;
// Bits 0, 1, 2 for terrain are stored in element.slope bit 5, 6, 7
slope &= ~TILE_ELEMENT_SURFACE_EDGE_STYLE_MASK;
slope |= (newStyle & 7) << 5;
}
uint32_t SurfaceElement::GetWaterHeight() const
{
return terrain & TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK;
}
void SurfaceElement::SetWaterHeight(uint32_t newWaterHeight)
{
newWaterHeight &= 0x1F;
terrain &= ~TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK;
terrain |= newWaterHeight;
}
bool SurfaceElement::CanGrassGrow() const
{
auto surfaceStyle = GetSurfaceStyle();
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objMgr.GetLoadedObject(OBJECT_TYPE_TERRAIN_SURFACE, surfaceStyle);
if (obj != nullptr)
{
auto surfaceObject = static_cast<TerrainSurfaceObject*>(obj);
if (surfaceObject->Flags & TERRAIN_SURFACE_FLAGS::CAN_GROW)
{
return true;
}
}
return false;
}
uint8_t SurfaceElement::GetGrassLength() const
{
return grass_length;
}
void SurfaceElement::SetGrassLength(uint8_t newLength)
{
grass_length = newLength;
}
void SurfaceElement::SetGrassLengthAndInvalidate(uint8_t length, CoordsXY coords)
{
uint8_t oldLength = grass_length & 0x7;
uint8_t newLength = length & 0x7;
grass_length = length;
if (newLength == oldLength)
{
return;
}
// If the new grass length won't result in an actual visual change
// then skip invalidating the tile, no point
if (((oldLength > 0 && oldLength < 4) && (newLength > 0 && newLength < 4))
|| ((oldLength > 3 && oldLength < 7) && (newLength > 3 && newLength < 7)))
{
return;
}
int32_t z = base_height * 8;
map_invalidate_tile(coords.x, coords.y, z, z + 16);
}
/**
*
* rct2: 0x006647A1
*/
void SurfaceElement::UpdateGrassLength(CoordsXY coords)
{
// Check if tile is grass
if (!CanGrassGrow())
return;
uint8_t grassLengthTmp = grass_length & 7;
// Check if grass is underwater or outside park
uint32_t waterHeight = GetWaterHeight() * 2;
if (waterHeight > base_height || !map_is_location_in_park(coords))
{
if (grassLengthTmp != GRASS_LENGTH_CLEAR_0)
SetGrassLengthAndInvalidate(GRASS_LENGTH_CLEAR_0, coords);
return;
}
// Grass can't grow any further than CLUMPS_2 but this code also cuts grass
// if there is an object placed on top of it.
int32_t z0 = base_height;
int32_t z1 = base_height + 2;
if (slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT)
z1 += 2;
// Check objects above grass
TileElement* tileElementAbove = (TileElement*)this;
for (;;)
{
if (tileElementAbove->flags & TILE_ELEMENT_FLAG_LAST_TILE)
{
// Grow grass
// Check interim grass lengths
uint8_t lengthNibble = (GetGrassLength() & 0xF0) >> 4;
if (lengthNibble < 0xF)
{
grass_length += 0x10;
}
else
{
// Zeros the length nibble
grass_length += 0x10;
grass_length ^= 8;
if (grass_length & 8)
{
// Random growth rate (length nibble)
grass_length |= scenario_rand() & 0x70;
}
else
{
// Increase length if not at max length
if (grassLengthTmp != GRASS_LENGTH_CLUMPS_2)
SetGrassLengthAndInvalidate(grassLengthTmp + 1, coords);
}
}
}
else
{
tileElementAbove++;
if (tileElementAbove->GetType() == TILE_ELEMENT_TYPE_WALL)
continue;
// Grass should not be affected by ghost elements.
if (tileElementAbove->IsGhost())
continue;
if (z0 >= tileElementAbove->clearance_height)
continue;
if (z1 < tileElementAbove->base_height)
continue;
if (grassLengthTmp != GRASS_LENGTH_CLEAR_0)
SetGrassLengthAndInvalidate(GRASS_LENGTH_CLEAR_0, coords);
}
break;
}
}
uint8_t SurfaceElement::GetOwnership() const
{
return (ownership & TILE_ELEMENT_SURFACE_OWNERSHIP_MASK);
}
void SurfaceElement::SetOwnership(uint8_t newOwnership)
{
ownership &= ~TILE_ELEMENT_SURFACE_OWNERSHIP_MASK;
ownership |= (newOwnership & TILE_ELEMENT_SURFACE_OWNERSHIP_MASK);
}
uint8_t SurfaceElement::GetParkFences() const
{
return (ownership & TILE_ELEMENT_SURFACE_PARK_FENCE_MASK);
}
void SurfaceElement::SetParkFences(uint8_t newParkFences)
{
ownership &= ~TILE_ELEMENT_SURFACE_PARK_FENCE_MASK;
ownership |= (newParkFences & TILE_ELEMENT_SURFACE_PARK_FENCE_MASK);
}
uint8_t SurfaceElement::GetSlope() const
{
return (slope & TILE_ELEMENT_SURFACE_SLOPE_MASK);
}
void SurfaceElement::SetSlope(uint8_t newSlope)
{
slope &= ~TILE_ELEMENT_SURFACE_SLOPE_MASK;
slope |= (newSlope & TILE_ELEMENT_SURFACE_SLOPE_MASK);
}
bool SurfaceElement::HasTrackThatNeedsWater() const
{
return (type & SURFACE_ELEMENT_HAS_TRACK_THAT_NEEDS_WATER) != 0;
}
void SurfaceElement::SetHasTrackThatNeedsWater(bool on)
{
type &= ~SURFACE_ELEMENT_HAS_TRACK_THAT_NEEDS_WATER;
if (on)
type |= SURFACE_ELEMENT_HAS_TRACK_THAT_NEEDS_WATER;
}