mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-20 21:43:06 +01:00
By default, not all warnings are enabled. This change makes sure that
the project compiles correctly with following options turned on:
-Wall -Wno-unused-but-set-variable -Wno-missing-braces \
-Wno-unknown-pragmas -Wno-unused-function
372 lines
13 KiB
C
372 lines
13 KiB
C
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
|
/*****************************************************************************
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
*
|
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* A full copy of the GNU General Public License can be found in licence.txt
|
|
*****************************************************************************/
|
|
#pragma endregion
|
|
|
|
#include "map_element.h"
|
|
#include "../paint.h"
|
|
#include "../supports.h"
|
|
#include "../../addresses.h"
|
|
#include "../../config.h"
|
|
#include "../../game.h"
|
|
#include "../../interface/viewport.h"
|
|
#include "../../localisation/localisation.h"
|
|
#include "../../world/map.h"
|
|
#include "../../world/scenery.h"
|
|
|
|
// 6B8172:
|
|
void scenery_multiple_paint_supports(uint8 direction, uint16 height, rct_map_element *mapElement, uint32 dword_F4387C, rct_large_scenery_tile *tile)
|
|
{
|
|
if (tile->var_7 & 0x20) {
|
|
return;
|
|
}
|
|
|
|
int ax = 0;
|
|
int supportHeight = height;
|
|
|
|
if (supportHeight & 0xF) {
|
|
supportHeight &= 0xFFFFFFF0;
|
|
ax = 49;
|
|
}
|
|
|
|
int supportImageColourFlags = 0x20000000;
|
|
|
|
if (dword_F4387C) {
|
|
supportImageColourFlags = dword_F4387C;
|
|
}
|
|
|
|
wooden_b_supports_paint_setup((direction & 1), ax, supportHeight, supportImageColourFlags);
|
|
|
|
int clearanceHeight = ceil2(mapElement->clearance_height * 8 + 15, 16);
|
|
|
|
if (tile->var_7 & 0x40) {
|
|
paint_util_set_segment_support_height(SEGMENTS_ALL, clearanceHeight, 0x20);
|
|
} else {
|
|
paint_util_set_segment_support_height(SEGMENTS_ALL, 0xFFFF, 0);
|
|
}
|
|
|
|
paint_util_set_general_support_height(clearanceHeight, 0x20);
|
|
}
|
|
|
|
rct_large_scenery_text_glyph *scenery_multiple_sign_get_glyph(rct_large_scenery_text *text, uint32 codepoint)
|
|
{
|
|
if (codepoint >= countof(text->glyphs)) {
|
|
return &text->glyphs['?'];
|
|
}
|
|
return &text->glyphs[codepoint];
|
|
}
|
|
|
|
int scenery_multiple_sign_text_width(const utf8 *str, rct_large_scenery_text *text)
|
|
{
|
|
int width = 0;
|
|
uint32 codepoint;
|
|
while ((codepoint = utf8_get_next(str, &str)) != 0) {
|
|
width += scenery_multiple_sign_get_glyph(text, codepoint)->width;
|
|
}
|
|
return width;
|
|
}
|
|
|
|
int scenery_multiple_sign_text_height(const utf8 *str, rct_large_scenery_text *text)
|
|
{
|
|
int height = 0;
|
|
uint32 codepoint;
|
|
while ((codepoint = utf8_get_next(str, &str)) != 0) {
|
|
height += scenery_multiple_sign_get_glyph(text, codepoint)->height;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
const utf8 *scenery_multiple_sign_fit_text(const utf8 *str, rct_large_scenery_text *text, bool height)
|
|
{
|
|
static utf8 fitStr[32] = {0};
|
|
utf8 *fitStrEnd = fitStr;
|
|
strncpy(fitStr, str, sizeof(fitStr) - 1);
|
|
int w = 0;
|
|
uint32 codepoint;
|
|
while (w <= text->max_width && (codepoint = utf8_get_next(fitStrEnd, (const utf8**)&fitStrEnd)) != 0) {
|
|
if (height) {
|
|
w += scenery_multiple_sign_get_glyph(text, codepoint)->height;
|
|
} else {
|
|
w += scenery_multiple_sign_get_glyph(text, codepoint)->width;
|
|
}
|
|
}
|
|
*fitStrEnd = 0;
|
|
return fitStr;
|
|
}
|
|
|
|
int div_to_minus_infinity(int a, int b) {
|
|
return (a / b) - (a % b < 0);
|
|
}
|
|
|
|
void scenery_multiple_sign_paint_line(const utf8 *str, rct_large_scenery_text *text, int textImage, int textColour, uint8 direction, int y_offset)
|
|
{
|
|
const utf8 *fitStr = scenery_multiple_sign_fit_text(str, text, false);
|
|
int width = scenery_multiple_sign_text_width(fitStr, text);
|
|
int x_offset = text->offset[(direction & 1)].x;
|
|
int acc = y_offset * (direction & 1 ? -1 : 1);
|
|
if (!(text->var_C & 0x1)) {
|
|
// sign is horizontal, center text:
|
|
x_offset -= (width / 2);
|
|
acc -= (width / 2);
|
|
}
|
|
uint32 codepoint;
|
|
while ((codepoint = utf8_get_next(fitStr, &fitStr)) != 0) {
|
|
int glyph_offset = scenery_multiple_sign_get_glyph(text, codepoint)->image_offset;
|
|
uint8 glyph_type = direction & 1;
|
|
if (text->var_C & 0x1) { // vertical sign
|
|
glyph_offset *= 2;
|
|
} else {
|
|
glyph_offset *= 4;
|
|
// set slightly different glyph on horizontal sign, which was rendered 1/2 pixel lower to deal with aliasing:
|
|
if (direction & 1) {
|
|
if (!(acc & 1)) {
|
|
glyph_type += 2;
|
|
}
|
|
} else {
|
|
if ((acc & 1)) {
|
|
glyph_type += 2;
|
|
}
|
|
}
|
|
}
|
|
int image_id = (textImage + glyph_offset + glyph_type) | textColour;
|
|
if (direction == 3) {
|
|
paint_attach_to_previous_ps(image_id, x_offset, -div_to_minus_infinity(acc, 2));
|
|
} else {
|
|
if (text->var_C & 0x1) {
|
|
paint_attach_to_previous_ps(image_id, x_offset, div_to_minus_infinity(acc, 2));
|
|
} else {
|
|
paint_attach_to_previous_attach(image_id, x_offset, div_to_minus_infinity(acc, 2));
|
|
}
|
|
}
|
|
x_offset += scenery_multiple_sign_get_glyph(text, codepoint)->width;
|
|
acc += scenery_multiple_sign_get_glyph(text, codepoint)->width;
|
|
}
|
|
}
|
|
|
|
typedef struct boundbox {
|
|
rct_xy16 offset;
|
|
rct_xy16 length;
|
|
} boundbox;
|
|
|
|
static const boundbox s98E3C4[] = {
|
|
{ 3, 3, 26, 26 },
|
|
{ 17, 17, 12, 12 },
|
|
{ 17, 3, 12, 12 },
|
|
{ 17, 3, 12, 26 },
|
|
{ 3, 3, 12, 12 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 3, 28, 12 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 17, 12, 12 },
|
|
{ 3, 17, 26, 12 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 3, 12, 28 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 3, 3, 26, 26 },
|
|
{ 1, 1, 30, 30 }
|
|
};
|
|
|
|
/*
|
|
*
|
|
* rct2: 0x006B7F0C
|
|
*/
|
|
void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) {
|
|
//RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)mapElement, 0, 0); return;
|
|
gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY;
|
|
uint32 ebp = mapElement->properties.scenerymultiple.type >> 10;
|
|
rct_scenery_entry *entry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF);
|
|
uint32 image_id = (ebp << 2) + entry->image + 4 + direction;
|
|
rct_large_scenery_tile *tile = &entry->large_scenery.tiles[ebp];
|
|
uint32 dword_F4387C = 0;
|
|
image_id |= ((mapElement->properties.scenerymultiple.colour[0] & 0x1F) << 19) | ((mapElement->properties.scenerymultiple.colour[1] & 0x1F) << 24) | 0xA0000000;
|
|
rct_xyz16 boxlength;
|
|
rct_xyz16 boxoffset;
|
|
if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) {
|
|
if (!track_design_save_contains_map_element(mapElement)) {
|
|
ebp = 0x21700000;
|
|
image_id &= 0x7FFFF;
|
|
dword_F4387C = ebp;
|
|
image_id |= dword_F4387C;
|
|
}
|
|
}
|
|
if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST) {
|
|
gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_NONE;
|
|
ebp = RCT2_ADDRESS(0x993CC4, uint32_t)[gConfigGeneral.construction_marker_colour];
|
|
image_id &= 0x7FFFF;
|
|
dword_F4387C = ebp;
|
|
image_id |= dword_F4387C;
|
|
}
|
|
int ah = tile->z_clearance;
|
|
if (ah > 0x80) {
|
|
ah = 0x80;
|
|
}
|
|
ah -= 3;
|
|
uint16 edi = tile->var_7;
|
|
int esi = 16;
|
|
if (edi & 0xF00) {
|
|
edi &= 0xF000;
|
|
edi = rol16(edi, direction);
|
|
esi = (edi & 0xF) | (edi >> 12);
|
|
}
|
|
boxoffset.x = s98E3C4[esi].offset.x;
|
|
boxoffset.y = s98E3C4[esi].offset.y;
|
|
boxoffset.z = height;
|
|
boxlength.x = s98E3C4[esi].length.x;
|
|
boxlength.y = s98E3C4[esi].length.y;
|
|
boxlength.z = ah;
|
|
sub_98197C(image_id, 0, 0, boxlength.x, boxlength.y, ah, height, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation());
|
|
if (entry->large_scenery.var_11 == 0xFF || direction == 1 || direction == 2) {
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
return;
|
|
}
|
|
if (entry->large_scenery.flags & 0x4) {
|
|
int al;
|
|
if (entry->large_scenery.tiles[1].x_offset != (sint16)0xFFFF) {
|
|
al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3;
|
|
if (al != direction) {
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
return;
|
|
}
|
|
}
|
|
rct_drawpixelinfo* dpi = unk_140E9A8;
|
|
if (dpi->zoom_level > 1) {
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
return;
|
|
}
|
|
// 6B8331:
|
|
// Draw sign text:
|
|
set_format_arg(0, uint32, 0);
|
|
set_format_arg(4, uint32, 0);
|
|
int textColour = mapElement->properties.scenerymultiple.colour[1] & 0x1F;
|
|
if (dword_F4387C) {
|
|
textColour = COLOUR_GREY;
|
|
}
|
|
textColour = (textColour << 19) | 0x20000000;
|
|
uint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5);
|
|
rct_banner *banner = &gBanners[bannerIndex];
|
|
rct_string_id stringId = banner->string_idx;
|
|
if (banner->flags & BANNER_FLAG_2) {
|
|
rct_ride * ride = get_ride(banner->colour);
|
|
stringId = ride->name;
|
|
set_format_arg(0, uint32, ride->name_arguments);
|
|
}
|
|
utf8 signString[MAX_PATH] = {0};
|
|
format_string(signString, stringId, gCommonFormatArgs);
|
|
rct_large_scenery_text *text = entry->large_scenery.text;
|
|
int y_offset = (text->offset[(direction & 1)].y * 2);
|
|
if (text->var_C & 0x1) {
|
|
// Draw vertical sign:
|
|
y_offset += 1;
|
|
utf8 fitStr[32] = {0};
|
|
const utf8 *fitStrPtr = fitStr;
|
|
strncpy(fitStr, scenery_multiple_sign_fit_text(signString, text, true), sizeof(fitStr) - 1);
|
|
int height = scenery_multiple_sign_text_height(fitStr, text);
|
|
uint32 codepoint;
|
|
while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 0) {
|
|
utf8 str[5] = {0};
|
|
utf8_write_codepoint(str, codepoint);
|
|
scenery_multiple_sign_paint_line(str, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset - height);
|
|
y_offset += scenery_multiple_sign_get_glyph(text, codepoint)->height * 2;
|
|
}
|
|
} else {
|
|
y_offset -= (direction & 1);
|
|
if (text->var_C & 0x2) {
|
|
// Draw two-line sign:
|
|
int width = scenery_multiple_sign_text_width(signString, text);
|
|
if (width > text->max_width) {
|
|
y_offset -= scenery_multiple_sign_get_glyph(text, 'A')->height + 1;
|
|
utf8 *src = signString;
|
|
for (int i = 0; i < 2; i++) {
|
|
utf8 str1[64] = {0};
|
|
utf8 *dst = str1;
|
|
utf8 *srcold = src;
|
|
utf8 *spacesrc = 0;
|
|
utf8 *spacedst = 0;
|
|
int w = 0;
|
|
uint32 codepoint = utf8_get_next(src, (const utf8**)&src);
|
|
do {
|
|
w += scenery_multiple_sign_get_glyph(text, codepoint)->width;
|
|
if (codepoint == ' ') {
|
|
spacesrc = src;
|
|
spacedst = dst;
|
|
}
|
|
} while(w <= text->max_width && (dst = utf8_write_codepoint(dst, codepoint)) && (srcold = src) && (codepoint = utf8_get_next(src, (const utf8**)&src)));
|
|
src = srcold;
|
|
if (spacesrc && codepoint) {
|
|
*spacedst = 0;
|
|
src = spacesrc;
|
|
}
|
|
scenery_multiple_sign_paint_line(str1, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset);
|
|
y_offset += (scenery_multiple_sign_get_glyph(text, 'A')->height + 1) * 2;
|
|
}
|
|
} else {
|
|
scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset);
|
|
}
|
|
} else {
|
|
// Draw one-line sign:
|
|
scenery_multiple_sign_paint_line(signString, entry->large_scenery.text, entry->large_scenery.text_image, textColour, direction, y_offset);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
rct_drawpixelinfo* dpi = unk_140E9A8;
|
|
if (dpi->zoom_level > 0) {
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
return;
|
|
}
|
|
uint8 al = ((mapElement->properties.surface.terrain >> 2) - 1) & 3;
|
|
if (al != direction) {
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
return;
|
|
}
|
|
// Draw scrolling text:
|
|
set_format_arg(0, uint32, 0);
|
|
set_format_arg(4, uint32, 0);
|
|
uint8 textColour = mapElement->properties.banner.unused & 0x1F;
|
|
if (dword_F4387C) {
|
|
textColour = COLOUR_GREY;
|
|
}
|
|
if (direction == 3) {
|
|
textColour |= (1 << 7);
|
|
}
|
|
// 6B809A:
|
|
set_format_arg(7, uint8, textColour);
|
|
uint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5);
|
|
uint16 scrollMode = entry->large_scenery.var_11 + ((direction + 1) & 0x3);
|
|
rct_banner *banner = &gBanners[bannerIndex];
|
|
set_format_arg(0, rct_string_id, banner->string_idx);
|
|
if (banner->flags & BANNER_FLAG_2) {
|
|
rct_ride * ride = get_ride(banner->colour);
|
|
set_format_arg(0, rct_string_id, ride->name);
|
|
set_format_arg(2, uint32, ride->name_arguments);
|
|
}
|
|
utf8 signString[MAX_PATH];
|
|
rct_string_id stringId = STR_SCROLLING_SIGN_TEXT;
|
|
if (gConfigGeneral.upper_case_banners) {
|
|
format_string_to_upper(signString, stringId, gCommonFormatArgs);
|
|
} else {
|
|
format_string(signString, stringId, gCommonFormatArgs);
|
|
}
|
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_TINY;
|
|
|
|
uint16 string_width = gfx_get_string_width(signString);
|
|
uint16 scroll = (gCurrentTicks / 2) % string_width;
|
|
sub_98199C(scrolling_text_setup(stringId, scroll, scrollMode), 0, 0, 1, 1, 21, height + 25, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation());
|
|
|
|
scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile);
|
|
}
|