1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-30 02:05:13 +01:00
Files
OpenRCT2/src/openrct2/paint/tile_element/Paint.SmallScenery.cpp

417 lines
16 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2020 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 "../../Game.h"
#include "../../config/Config.h"
#include "../../interface/Viewport.h"
#include "../../localisation/Date.h"
#include "../../ride/TrackDesign.h"
#include "../../util/Util.h"
#include "../../world/Map.h"
#include "../../world/Scenery.h"
#include "../../world/SmallScenery.h"
#include "../../world/TileInspector.h"
#include "../Paint.h"
#include "../Supports.h"
#include "Paint.TileElement.h"
static constexpr const CoordsXY lengths[] = {
{ 12, 26 },
{ 26, 12 },
{ 12, 26 },
{ 26, 12 },
};
/**
*
* rct2: 0x006DFF47
*/
void scenery_paint(paint_session* session, uint8_t direction, int32_t height, const TileElement* tileElement)
{
if (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES)
{
return;
}
const SmallSceneryElement* sceneryElement = tileElement->AsSmallScenery();
session->InteractionType = ViewportInteractionItem::Scenery;
CoordsXYZ boxlength;
CoordsXYZ boxoffset;
boxoffset.x = 0;
boxoffset.y = 0;
boxoffset.z = height;
uint32_t marker = 0;
const int32_t rotation = session->CurrentRotation;
if (gTrackDesignSaveMode)
{
if (!track_design_save_contains_tile_element(tileElement))
{
marker = SPRITE_ID_PALETTE_COLOUR_1(EnumValue(FilterPaletteID::Palette46));
}
}
if (tileElement->IsGhost())
{
session->InteractionType = ViewportInteractionItem::None;
marker = CONSTRUCTION_MARKER;
}
else if (OpenRCT2::TileInspector::IsElementSelected(tileElement))
{
marker = CONSTRUCTION_MARKER;
}
auto* sceneryEntry = tileElement->AsSmallScenery()->GetEntry();
if (sceneryEntry == nullptr)
{
return;
}
int32_t baseImageid = sceneryEntry->image + direction;
boxlength.x = 2;
boxlength.y = 2;
int8_t x_offset = 0;
int8_t y_offset = 0;
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE))
{
// 6DFFE3:
static constexpr const CoordsXY scenery_half_tile_offsets[] = {
{ 3, 3 },
{ 3, 17 },
{ 17, 3 },
{ 3, 3 },
};
boxoffset.x = scenery_half_tile_offsets[direction].x;
boxoffset.y = scenery_half_tile_offsets[direction].y;
boxlength.x = lengths[direction].x;
boxlength.y = lengths[direction].y;
x_offset = 3;
y_offset = 3;
}
else
{
x_offset = 15;
y_offset = 15;
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
x_offset = 3;
y_offset = 3;
boxlength.x = 26;
boxlength.y = 26;
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_WALLS))
{
x_offset = 1;
y_offset = 1;
boxlength.x = 30;
boxlength.y = 30;
}
}
boxoffset.x = x_offset;
boxoffset.y = y_offset;
}
}
else
{
// 6DFFC2:
uint8_t quadrant = (tileElement->AsSmallScenery()->GetSceneryQuadrant() + rotation) & 3;
x_offset = SceneryQuadrantOffsets[quadrant].x;
y_offset = SceneryQuadrantOffsets[quadrant].y;
boxoffset.x = x_offset;
boxoffset.y = y_offset;
}
// 6E007F:
boxlength.z = sceneryEntry->height - 4;
if (boxlength.z > 128 || boxlength.z < 0)
{
boxlength.z = 128;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_CAN_WITHER))
{
if (tileElement->AsSmallScenery()->GetAge() >= SCENERY_WITHER_AGE_THRESHOLD_1)
{
baseImageid += 4;
}
if (tileElement->AsSmallScenery()->GetAge() >= SCENERY_WITHER_AGE_THRESHOLD_2)
{
baseImageid += 4;
}
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR))
{
baseImageid |= SPRITE_ID_PALETTE_COLOUR_2(sceneryElement->GetPrimaryColour(), sceneryElement->GetSecondaryColour());
}
else
{
baseImageid |= SPRITE_ID_PALETTE_COLOUR_1(sceneryElement->GetPrimaryColour());
}
}
if (marker != 0)
{
baseImageid = (baseImageid & 0x7FFFF) | marker;
}
if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED)))
{
PaintAddImageAsParent(
session, baseImageid, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_GLASS))
{
if (marker == 0)
{
// Draw translucent overlay:
// TODO: Name palette entries
int32_t image_id = (baseImageid & 0x7FFFF) + (EnumValue(GlassPaletteIds[sceneryElement->GetPrimaryColour()]) << 19)
+ 0x40000004;
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ANIMATED))
{
rct_drawpixelinfo* dpi = &session->DPI;
if ((scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED)) || (dpi->zoom_level <= 1))
{
// 6E01A9:
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1))
{
// 6E0512:
int32_t image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 4;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
else if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4))
{
// 6E043B:
int32_t image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 8;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
image_id = direction + sceneryEntry->image + 4;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
image_id = ((gCurrentTicks / 2) & 0xF) + sceneryEntry->image + 24;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
else if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_CLOCK))
{
// 6E035C:
int32_t minuteImageOffset = ((gRealTimeOfDay.minute + 6) * 17) / 256;
int32_t timeImageBase = gRealTimeOfDay.hour;
while (timeImageBase >= 12)
{
timeImageBase -= 12;
}
timeImageBase = (timeImageBase * 4) + minuteImageOffset;
if (timeImageBase >= 48)
{
timeImageBase -= 48;
}
int32_t image_id = timeImageBase + (direction * 12);
if (image_id >= 48)
{
image_id -= 48;
}
image_id = image_id + sceneryEntry->image + 68;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
image_id = gRealTimeOfDay.minute + (direction * 15);
if (image_id >= 60)
{
image_id -= 60;
}
image_id = image_id + sceneryEntry->image + 8;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
else if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_SWAMP_GOO))
{
// 6E02F6:
int32_t image_id = gCurrentTicks;
image_id += session->SpritePosition.x / 4;
image_id += session->SpritePosition.y / 4;
image_id = (image_id / 4) & 15;
image_id += sceneryEntry->image;
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
else if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS))
{
int32_t frame = gCurrentTicks;
if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_COG)))
{
// 6E01F8:
frame += ((session->SpritePosition.x / 4) + (session->SpritePosition.y / 4));
frame += tileElement->AsSmallScenery()->GetSceneryQuadrant() << 2;
}
// 6E0222:
uint16_t delay = sceneryEntry->animation_delay & 0xFF;
frame >>= delay;
frame &= sceneryEntry->animation_mask;
int32_t image_id = 0;
if (frame < sceneryEntry->num_frames)
{
image_id = sceneryEntry->frame_offsets[frame];
}
image_id = (image_id * 4) + direction + sceneryEntry->image;
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED | SMALL_SCENERY_FLAG17))
{
image_id += 4;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR))
{
image_id |= SPRITE_ID_PALETTE_COLOUR_2(
sceneryElement->GetPrimaryColour(), sceneryElement->GetSecondaryColour());
}
else
{
image_id |= SPRITE_ID_PALETTE_COLOUR_1(sceneryElement->GetPrimaryColour());
}
}
if (marker != 0)
{
image_id = (image_id & 0x7FFFF) | marker;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED))
{
PaintAddImageAsParent(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
else
{
PaintAddImageAsChild(
session, image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x,
boxoffset.y, boxoffset.z);
}
}
}
}
// 6E0556: Draw supports:
if (sceneryElement->NeedsSupports())
{
if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_NO_SUPPORTS)))
{
int32_t ax = 0;
int32_t supportHeight = height;
if (supportHeight & 0xF)
{
supportHeight &= 0xFFFFFFF0;
ax = 49;
}
uint32_t supportImageColourFlags = IMAGE_TYPE_REMAP;
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_PAINT_SUPPORTS))
{
supportImageColourFlags = SPRITE_ID_PALETTE_COLOUR_1(sceneryElement->GetPrimaryColour());
}
if (marker != 0)
{
supportImageColourFlags = marker;
}
if (direction & 1)
{
wooden_b_supports_paint_setup(session, 1, ax, supportHeight, supportImageColourFlags, nullptr);
}
else
{
wooden_b_supports_paint_setup(session, 0, ax, supportHeight, supportImageColourFlags, nullptr);
}
}
}
// 6E05D1:
height += sceneryEntry->height;
paint_util_set_general_support_height(session, ceil2(height, 8), 0x20);
// 6E05FF:
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))
{
// 6E0825:
paint_util_set_segment_support_height(session, SEGMENT_C4, height, 0x20);
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, height, 0x20);
}
return;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
// 6E075C:
direction = (tileElement->AsSmallScenery()->GetSceneryQuadrant() + rotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), height, 0x20);
return;
}
return;
}
if (scenery_small_entry_has_flag(sceneryEntry, (SMALL_SCENERY_FLAG27 | SMALL_SCENERY_FLAG_FULL_TILE)))
{
paint_util_set_segment_support_height(session, SEGMENT_C4, 0xFFFF, 0);
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
paint_util_set_segment_support_height(session, SEGMENTS_ALL & ~SEGMENT_C4, 0xFFFF, 0);
}
return;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
direction = (tileElement->AsSmallScenery()->GetSceneryQuadrant() + rotation) % 4;
paint_util_set_segment_support_height(
session, paint_util_rotate_segments(SEGMENT_B4 | SEGMENT_C8 | SEGMENT_CC, direction), 0xFFFF, 0);
return;
}
}