diff --git a/src/drawing/scrolling_text.c b/src/drawing/scrolling_text.c index 4ba9537cd7..aae6b4c5f7 100644 --- a/src/drawing/scrolling_text.c +++ b/src/drawing/scrolling_text.c @@ -109,7 +109,7 @@ static int scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16 static uint8 scrolling_text_get_colour(uint32 character) { int colour = character & 0x7F; - if (colour & (1 << 7)) { + if (character & (1 << 7)) { return ColourMapA[colour].light; } else { return ColourMapA[colour].mid_dark; diff --git a/src/object.c b/src/object.c index 05c1b6084f..479db16da8 100644 --- a/src/object.c +++ b/src/object.c @@ -974,7 +974,7 @@ static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex) extendedEntryData += sizeof(rct_object_entry); if (sceneryEntry->large_scenery.flags & (1 << 2)) { - sceneryEntry->large_scenery.var_12 = (uint32)extendedEntryData; + sceneryEntry->large_scenery.text = (rct_large_scenery_text*)extendedEntryData; extendedEntryData += 1038; } @@ -989,9 +989,9 @@ static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex) int imageId = object_chunk_load_image_directory(&extendedEntryData); if (sceneryEntry->large_scenery.flags & (1 << 2)){ - sceneryEntry->large_scenery.var_16 = imageId; + sceneryEntry->large_scenery.text_image = imageId; - uint8* edx = (uint8*)sceneryEntry->large_scenery.var_12; + uint8* edx = (uint8*)sceneryEntry->large_scenery.text; if (!(edx[0xC] & 1)) { imageId += edx[0xD] * 4; } else{ @@ -1013,8 +1013,8 @@ static void object_type_large_scenery_unload(void *objectEntry) sceneryEntry->image = 0; sceneryEntry->large_scenery.tiles = 0; sceneryEntry->large_scenery.scenery_tab_id = 0; - sceneryEntry->large_scenery.var_12 = 0; - sceneryEntry->large_scenery.var_16 = 0; + sceneryEntry->large_scenery.text = 0; + sceneryEntry->large_scenery.text_image = 0; } static bool object_type_large_scenery_test(void *objectEntry) diff --git a/src/paint/map_element/scenery.c b/src/paint/map_element/scenery.c index d0fde736fe..87519f5ec0 100644 --- a/src/paint/map_element/scenery.c +++ b/src/paint/map_element/scenery.c @@ -39,7 +39,7 @@ void scenery_paint(uint8 direction, int height, rct_map_element* mapElement) { boxoffset.z = height; int baseImageid = 0; if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) { - if (track_design_save_contains_map_element(mapElement)) { + if (!track_design_save_contains_map_element(mapElement)) { baseImageid = 0x21700000; } } diff --git a/src/paint/map_element/scenery_multiple.c b/src/paint/map_element/scenery_multiple.c index 45653506d3..a622a0f959 100644 --- a/src/paint/map_element/scenery_multiple.c +++ b/src/paint/map_element/scenery_multiple.c @@ -15,9 +15,334 @@ #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" -void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { - RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)mapElement, 0, 0); +// 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, &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; + } +} + +/* +* +* 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 = (edi << direction) | (edi >> (16 - direction)); // rol + esi = (edi & 0xF) | (edi >> 12); + } + boxoffset.x = RCT2_ADDRESS(0x0098E3C4, uint16)[esi * 4]; + boxoffset.y = RCT2_ADDRESS(0x0098E3C6, uint16)[esi * 4]; + boxoffset.z = height; + boxlength.x = RCT2_ADDRESS(0x0098E3C8, uint16)[esi * 4]; + boxlength.y = RCT2_ADDRESS(0x0098E3CA, uint16)[esi * 4]; + 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 = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + 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 dword_F4388A = textColour; + 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); + utf8 str[5] = {0}; + uint32 codepoint; + while ((codepoint = utf8_get_next(fitStrPtr, &fitStrPtr)) != 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; + const utf8 *dstend = dst + sizeof(str1); + utf8 *srcold = src; + utf8 *spacesrc = 0; + utf8 *spacedst = 0; + int w = 0; + uint32 codepoint = utf8_get_next(src, &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, &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 = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + 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); } diff --git a/src/world/scenery.h b/src/world/scenery.h index 121b0e9961..0cdc474b25 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -73,6 +73,21 @@ typedef struct rct_large_scenery_tile { uint16 var_7; } rct_large_scenery_tile; +typedef struct rct_large_scenery_text_glyph { + uint8 image_offset; + uint8 width; + uint8 height; + uint8 var_3; +} rct_large_scenery_text_glyph; + +typedef struct rct_large_scenery_text { + rct_xy16 offset[2]; // 0x0 + uint16 max_width; // 0x8 + uint16 var_A; // 0xA + uint16 var_C; // 0xC + rct_large_scenery_text_glyph glyphs[256]; // 0xE +} rct_large_scenery_text; + typedef struct rct_large_scenery_entry { uint8 tool_id; // 0x06 uint8 flags; // 0x07 @@ -81,8 +96,8 @@ typedef struct rct_large_scenery_entry { rct_large_scenery_tile* tiles; // 0x0C uint8 scenery_tab_id; // 0x10 uint8 var_11; - uint32 var_12; - uint32 var_16; + rct_large_scenery_text* text; // 0x12 + uint32 text_image; // 0x16 } rct_large_scenery_entry;