mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-21 14:02:59 +01:00
453 lines
15 KiB
C++
453 lines
15 KiB
C++
/*****************************************************************************
|
|
* Copyright (c) 2014-2019 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 "../../common.h"
|
|
#include "../../config/Config.h"
|
|
#include "../../drawing/Drawing.h"
|
|
#include "../../interface/Colour.h"
|
|
#include "../../interface/Viewport.h"
|
|
#include "../../localisation/Localisation.h"
|
|
#include "../../ride/Track.h"
|
|
#include "../../ride/TrackDesign.h"
|
|
#include "../../world/Banner.h"
|
|
#include "../../world/Map.h"
|
|
#include "../../world/Scenery.h"
|
|
#include "../../world/Wall.h"
|
|
#include "../Paint.h"
|
|
#include "Paint.TileElement.h"
|
|
|
|
static constexpr const uint8_t byte_9A406C[] = {
|
|
2, 2, 22, 26, 30, 34, 34, 34, 34, 34, 30, 26, 22, 2, 6, 2, 2, 2, 6, 10, 14, 18, 18, 18, 18, 18, 14, 10, 6, 2, 22, 2,
|
|
};
|
|
|
|
static constexpr const uint8_t byte_9A408C[] = {
|
|
0, 0, 4, 8, 12, 16, 16, 16, 16, 16, 12, 8, 4, 0, 20, 0, 0, 0, 20, 24, 28, 32, 32, 32, 32, 32, 28, 24, 20, 0, 4, 0,
|
|
};
|
|
|
|
static constexpr const uint8_t byte_9A40AC[] = {
|
|
2, 2, 6, 10, 14, 18, 18, 18, 18, 18, 14, 10, 6, 2, 22, 2, 2, 2, 22, 26, 30, 34, 34, 34, 34, 34, 30, 26, 22, 2, 6, 2,
|
|
};
|
|
|
|
static constexpr const uint8_t byte_9A40CC[] = {
|
|
0, 0, 20, 24, 28, 32, 32, 32, 32, 32, 28, 24, 20, 0, 4, 0, 0, 0, 4, 8, 12, 16, 16, 16, 16, 16, 12, 8, 4, 0, 20, 0,
|
|
};
|
|
|
|
static void fence_paint_door(
|
|
paint_session* session, uint32_t imageId, rct_scenery_entry* sceneryEntry, uint32_t imageColourFlags,
|
|
uint32_t tertiaryColour, uint32_t dword_141F710, LocationXYZ16 offset, LocationXYZ16 boundsR1, LocationXYZ16 boundsR1_,
|
|
LocationXYZ16 boundsR2, LocationXYZ16 boundsR2_, LocationXYZ16 boundsL1, LocationXYZ16 boundsL1_)
|
|
{
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
|
|
{
|
|
imageId |= imageColourFlags;
|
|
}
|
|
|
|
if (dword_141F710 != 0)
|
|
{
|
|
imageId = (imageId & 0x7FFFF) | dword_141F710;
|
|
}
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_IS_BANNER)
|
|
{
|
|
paint_struct* ps;
|
|
|
|
ps = sub_98197C(
|
|
session, imageId, (int8_t)offset.x, (int8_t)offset.y, boundsR1.x, boundsR1.y, (int8_t)boundsR1.z, offset.z,
|
|
boundsR1_.x, boundsR1_.y, boundsR1_.z);
|
|
if (ps != nullptr)
|
|
{
|
|
ps->tertiary_colour = tertiaryColour;
|
|
}
|
|
|
|
ps = sub_98197C(
|
|
session, imageId + 1, (int8_t)offset.x, (int8_t)offset.y, boundsR2.x, boundsR2.y, (int8_t)boundsR2.z, offset.z,
|
|
boundsR2_.x, boundsR2_.y, boundsR2_.z);
|
|
if (ps != nullptr)
|
|
{
|
|
ps->tertiary_colour = tertiaryColour;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
paint_struct* ps;
|
|
|
|
ps = sub_98197C(
|
|
session, imageId, (int8_t)offset.x, (int8_t)offset.y, boundsL1.x, boundsL1.y, (int8_t)boundsL1.z, offset.z,
|
|
boundsL1_.x, boundsL1_.y, boundsL1_.z);
|
|
if (ps != nullptr)
|
|
{
|
|
ps->tertiary_colour = tertiaryColour;
|
|
}
|
|
|
|
ps = sub_98199C(
|
|
session, imageId + 1, (int8_t)offset.x, (int8_t)offset.y, boundsL1.x, boundsL1.y, (int8_t)boundsL1.z, offset.z,
|
|
boundsL1_.x, boundsL1_.y, boundsL1_.z);
|
|
if (ps != nullptr)
|
|
{
|
|
ps->tertiary_colour = tertiaryColour;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fence_paint_wall(
|
|
paint_session* session, uint32_t frameNum, const rct_scenery_entry* sceneryEntry, uint32_t dword_141F710,
|
|
uint32_t imageColourFlags, uint32_t dword_141F718, uint32_t tertiaryColour, uint32_t imageOffset, LocationXYZ16 offset,
|
|
LocationXYZ16 bounds, LocationXYZ16 boundsOffset)
|
|
{
|
|
uint32_t baseImageId = sceneryEntry->image + imageOffset + frameNum;
|
|
uint32_t imageId = baseImageId;
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_GLASS)
|
|
{
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
|
|
{
|
|
imageId |= imageColourFlags;
|
|
}
|
|
|
|
if (dword_141F710 != 0)
|
|
{
|
|
imageId = (imageId & 0x7FFFF) | dword_141F710;
|
|
}
|
|
|
|
sub_98197C(
|
|
session, imageId, (int8_t)offset.x, (int8_t)offset.y, bounds.x, bounds.y, (int8_t)bounds.z, offset.z,
|
|
boundsOffset.x, boundsOffset.y, boundsOffset.z);
|
|
if (dword_141F710 == 0)
|
|
{
|
|
imageId = baseImageId + dword_141F718;
|
|
sub_98199C(
|
|
session, imageId, (int8_t)offset.x, (int8_t)offset.y, bounds.x, bounds.y, (int8_t)bounds.z, offset.z,
|
|
boundsOffset.x, boundsOffset.y, boundsOffset.z);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)
|
|
{
|
|
imageId |= imageColourFlags;
|
|
}
|
|
|
|
if (dword_141F710 != 0)
|
|
{
|
|
imageId = (imageId & 0x7FFFF) | dword_141F710;
|
|
}
|
|
|
|
paint_struct* paint = sub_98197C(
|
|
session, imageId, (int8_t)offset.x, (int8_t)offset.y, bounds.x, bounds.y, (int8_t)bounds.z, offset.z,
|
|
boundsOffset.x, boundsOffset.y, boundsOffset.z);
|
|
if (paint != nullptr)
|
|
{
|
|
paint->tertiary_colour = tertiaryColour;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* rct2: 0x006E44B0
|
|
* @param direction (cl)
|
|
* @param height (dx)
|
|
* @param tile_element (esi)
|
|
*/
|
|
void fence_paint(paint_session* session, uint8_t direction, int32_t height, const TileElement* tile_element)
|
|
{
|
|
session->InteractionType = VIEWPORT_INTERACTION_ITEM_WALL;
|
|
|
|
rct_scenery_entry* sceneryEntry = tile_element->AsWall()->GetEntry();
|
|
if (sceneryEntry == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
uint32_t frameNum = 0;
|
|
|
|
if (sceneryEntry->wall.flags2 & WALL_SCENERY_2_ANIMATED)
|
|
{
|
|
frameNum = (gCurrentTicks & 7) * 2;
|
|
}
|
|
|
|
int32_t primaryColour = tile_element->AsWall()->GetPrimaryColour();
|
|
uint32_t imageColourFlags = primaryColour << 19 | IMAGE_TYPE_REMAP;
|
|
uint32_t dword_141F718 = imageColourFlags + 0x23800006;
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR)
|
|
{
|
|
uint8_t secondaryColour = tile_element->AsWall()->GetSecondaryColour();
|
|
imageColourFlags |= secondaryColour << 24 | IMAGE_TYPE_REMAP_2_PLUS;
|
|
}
|
|
|
|
uint32_t tertiaryColour = 0;
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR)
|
|
{
|
|
tertiaryColour = tile_element->AsWall()->GetTertiaryColour();
|
|
imageColourFlags &= 0x0DFFFFFFF;
|
|
}
|
|
|
|
paint_util_set_general_support_height(session, 8 * tile_element->clearance_height, 0x20);
|
|
|
|
uint32_t dword_141F710 = 0;
|
|
if (gTrackDesignSaveMode || (session->ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES))
|
|
{
|
|
if (!track_design_save_contains_tile_element(tile_element))
|
|
{
|
|
dword_141F710 = SPRITE_ID_PALETTE_COLOUR_1(PALETTE_46);
|
|
}
|
|
}
|
|
|
|
if (tile_element->IsGhost())
|
|
{
|
|
session->InteractionType = VIEWPORT_INTERACTION_ITEM_NONE;
|
|
dword_141F710 = CONSTRUCTION_MARKER;
|
|
}
|
|
|
|
// Save tile_element
|
|
|
|
uint8_t ah = sceneryEntry->wall.height * 8 - 2;
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_IS_DOOR)
|
|
{
|
|
LocationXYZ16 offset;
|
|
LocationXYZ16 boundsR1, boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_;
|
|
uint8_t animationFrame = tile_element->AsWall()->GetAnimationFrame();
|
|
// Add the direction as well
|
|
if (tile_element->AsWall()->AnimationIsBackwards())
|
|
animationFrame |= (1 << 4);
|
|
uint32_t imageId;
|
|
switch (direction)
|
|
{
|
|
case 0:
|
|
imageId = sceneryEntry->image + byte_9A406C[animationFrame];
|
|
|
|
boundsR1 = { 1, 3, static_cast<int16_t>(ah - 5) };
|
|
boundsR1_ = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
boundsR2 = { 1, 28, 3 };
|
|
boundsR2_ = { 1, 1, static_cast<int16_t>(height + ah - 9) };
|
|
|
|
boundsL1 = { 1, 28, ah };
|
|
boundsL1_ = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
|
|
offset = { 0, 0, static_cast<int16_t>(height) };
|
|
|
|
fence_paint_door(
|
|
session, imageId, sceneryEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1,
|
|
boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_);
|
|
break;
|
|
|
|
case 1:
|
|
imageId = sceneryEntry->image + byte_9A408C[animationFrame];
|
|
|
|
boundsR1 = { 3, 3, static_cast<int16_t>(ah - 5) };
|
|
boundsR1_ = { 1, 30, static_cast<int16_t>(height + 1) };
|
|
boundsR2 = { 29, 3, 2 };
|
|
boundsR2_ = { 1, 30, static_cast<int16_t>(height + ah - 8) };
|
|
|
|
boundsL1 = { 29, 1, ah };
|
|
boundsL1_ = { 2, 30, static_cast<int16_t>(height + 1) };
|
|
|
|
offset = { 1, 31, static_cast<int16_t>(height) };
|
|
|
|
fence_paint_door(
|
|
session, imageId, sceneryEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1,
|
|
boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_);
|
|
break;
|
|
|
|
case 2:
|
|
imageId = sceneryEntry->image + byte_9A40AC[animationFrame];
|
|
|
|
boundsR1 = { 3, 3, static_cast<int16_t>(ah - 5) };
|
|
boundsR1_ = { 30, 1, static_cast<int16_t>(height + 1) };
|
|
boundsR2 = { 3, 29, 2 };
|
|
boundsR2_ = { 30, 1, static_cast<int16_t>(height + ah - 8) };
|
|
|
|
boundsL1 = { 1, 29, ah };
|
|
boundsL1_ = { 30, 2, static_cast<int16_t>(height + 1) };
|
|
|
|
offset = { 31, 0, static_cast<int16_t>(height) };
|
|
|
|
fence_paint_door(
|
|
session, imageId, sceneryEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1,
|
|
boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_);
|
|
break;
|
|
|
|
case 3:
|
|
imageId = sceneryEntry->image + byte_9A40CC[animationFrame];
|
|
|
|
boundsR1 = { 3, 1, static_cast<int16_t>(ah - 5) };
|
|
boundsR1_ = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
boundsR2 = { 28, 1, 3 };
|
|
boundsR2_ = { 1, 1, static_cast<int16_t>(height + ah - 9) };
|
|
|
|
boundsL1 = { 28, 1, ah };
|
|
boundsL1_ = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
|
|
offset = { 2, 1, static_cast<int16_t>(height) };
|
|
|
|
fence_paint_door(
|
|
session, imageId, sceneryEntry, imageColourFlags, tertiaryColour, dword_141F710, offset, boundsR1,
|
|
boundsR1_, boundsR2, boundsR2_, boundsL1, boundsL1_);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
uint32_t imageOffset = 0;
|
|
LocationXYZ16 offset = { 0, 0, 0 }, bounds = { 0, 0, 0 }, boundsOffset = { 0, 0, 0 };
|
|
|
|
switch (direction)
|
|
{
|
|
case 0:
|
|
if (tile_element->AsWall()->GetSlope() == 2)
|
|
{
|
|
imageOffset = 3;
|
|
}
|
|
else if (tile_element->AsWall()->GetSlope() == 1)
|
|
{
|
|
imageOffset = 5;
|
|
}
|
|
else
|
|
{
|
|
imageOffset = 1;
|
|
}
|
|
|
|
offset = { 0, 0, static_cast<int16_t>(height) };
|
|
bounds = { 1, 28, ah };
|
|
boundsOffset = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
break;
|
|
|
|
case 1:
|
|
if (tile_element->AsWall()->GetSlope() == 2)
|
|
{
|
|
imageOffset = 2;
|
|
}
|
|
else if (tile_element->AsWall()->GetSlope() == 1)
|
|
{
|
|
imageOffset = 4;
|
|
}
|
|
else
|
|
{
|
|
imageOffset = 0;
|
|
}
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_GLASS)
|
|
{
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_IS_BANNER)
|
|
{
|
|
imageOffset += 12;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_IS_BANNER)
|
|
{
|
|
imageOffset += 6;
|
|
}
|
|
}
|
|
|
|
offset = { 1, 31, static_cast<int16_t>(height) };
|
|
bounds = { 29, 1, ah };
|
|
boundsOffset = { 2, 30, static_cast<int16_t>(height + 1) };
|
|
break;
|
|
|
|
case 2:
|
|
if (tile_element->AsWall()->GetSlope() == 2)
|
|
{
|
|
imageOffset = 5;
|
|
}
|
|
else if (tile_element->AsWall()->GetSlope() == 1)
|
|
{
|
|
imageOffset = 3;
|
|
}
|
|
else
|
|
{
|
|
imageOffset = 1;
|
|
}
|
|
|
|
if (sceneryEntry->wall.flags & WALL_SCENERY_IS_BANNER)
|
|
{
|
|
imageOffset += 6;
|
|
}
|
|
|
|
offset = { 31, 0, static_cast<int16_t>(height) };
|
|
bounds = { 1, 29, ah };
|
|
boundsOffset = { 30, 2, static_cast<int16_t>(height + 1) };
|
|
break;
|
|
|
|
case 3:
|
|
if (tile_element->AsWall()->GetSlope() == 2)
|
|
{
|
|
imageOffset = 4;
|
|
}
|
|
else if (tile_element->AsWall()->GetSlope() == 1)
|
|
{
|
|
imageOffset = 2;
|
|
}
|
|
else
|
|
{
|
|
imageOffset = 0;
|
|
}
|
|
|
|
offset = { 2, 1, static_cast<int16_t>(height) };
|
|
bounds = { 28, 1, ah };
|
|
boundsOffset = { 1, 1, static_cast<int16_t>(height + 1) };
|
|
break;
|
|
}
|
|
|
|
fence_paint_wall(
|
|
session, frameNum, sceneryEntry, dword_141F710, imageColourFlags, dword_141F718, tertiaryColour, imageOffset, offset,
|
|
bounds, boundsOffset);
|
|
|
|
if (sceneryEntry->wall.scrolling_mode == SCROLLING_MODE_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (direction != 0 && direction != 3)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto secondaryColour = tile_element->AsWall()->GetSecondaryColour();
|
|
if (dword_141F710 != 0)
|
|
{
|
|
secondaryColour = COLOUR_GREY;
|
|
}
|
|
if (direction == 0)
|
|
{
|
|
secondaryColour = ColourMapA[secondaryColour].light;
|
|
}
|
|
else
|
|
{
|
|
secondaryColour = ColourMapA[secondaryColour].mid_dark;
|
|
}
|
|
|
|
uint16_t scrollingMode = sceneryEntry->wall.scrolling_mode + ((direction + 1) & 0x3);
|
|
auto banner = tile_element->AsWall()->GetBanner();
|
|
if (banner != nullptr && !banner->IsNull())
|
|
{
|
|
banner->FormatTextTo(gCommonFormatArgs);
|
|
utf8 signString[256];
|
|
if (gConfigGeneral.upper_case_banners)
|
|
{
|
|
format_string_to_upper(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, gCommonFormatArgs);
|
|
}
|
|
else
|
|
{
|
|
format_string(signString, sizeof(signString), STR_SCROLLING_SIGN_TEXT, gCommonFormatArgs);
|
|
}
|
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY;
|
|
|
|
uint16_t string_width = gfx_get_string_width(signString);
|
|
uint16_t scroll = (gCurrentTicks / 2) % string_width;
|
|
|
|
sub_98199C(
|
|
session, scrolling_text_setup(session, STR_SCROLLING_SIGN_TEXT, scroll, scrollingMode, secondaryColour), 0, 0, 1, 1,
|
|
13, height + 8, boundsOffset.x, boundsOffset.y, boundsOffset.z);
|
|
}
|
|
}
|