// This method is the same as gfx_draw_string_left_wrapped. // But this adjusts the initial Y coordinate depending of the number of lines. int32_t chat_history_draw_string(rct_drawpixelinfo* dpi, void* args, int32_t x, int32_t y, int32_t width) { int32_t fontSpriteBase, lineHeight, lineY, numLines; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_draw_string(dpi, (char*)"", TEXT_COLOUR_255, dpi->x, dpi->y); char* buffer = gCommonStringFormatBuffer; format_string(buffer, 256, STR_STRING, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); lineHeight = font_get_line_height(fontSpriteBase); gCurrentFontFlags = 0; int32_t expectedY = y - (numLines * lineHeight); if (expectedY < 50) { return (numLines * lineHeight); // Skip drawing, return total height. } lineY = y; for (int32_t line = 0; line <= numLines; ++line) { gfx_draw_string(dpi, buffer, TEXT_COLOUR_254, x, lineY - (numLines * lineHeight)); buffer = get_string_end(buffer) + 1; lineY += lineHeight; } return lineY - y; }
void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, utf8string existing_text, int maxLength) { _maxInputLength = maxLength; window_close_by_class(WC_TEXTINPUT); // Clear the text input buffer memset(text_input, 0, maxLength); // Enter in the the text input buffer any existing // text. if (existing_text != NULL) safe_strcpy(text_input, existing_text, maxLength); // In order to prevent strings that exceed the maxLength // from crashing the game. text_input[maxLength - 1] = '\0'; // This is the text displayed above the input box input_text_description = description; // Work out the existing size of the window char wrapped_string[512]; safe_strcpy(wrapped_string, text_input, 512); int no_lines = 0, font_height = 0; // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); int height = no_lines * 10 + WH; // Window will be in the center of the screen rct_window* w = window_create_centred( WW, height, &window_text_input_events, WC_TEXTINPUT, WF_STICK_TO_FRONT ); w->widgets = window_text_input_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_CANCEL) | (1 << WIDX_OKAY); window_text_input_widgets[WIDX_TITLE].image = title; // Save calling window details so that the information // can be passed back to the correct window & widget calling_class = call_w->classification; calling_number = call_w->number; calling_widget = call_widget; platform_start_text_input(text_input, maxLength); window_init_scroll_widgets(w); w->colours[0] = call_w->colours[0]; w->colours[1] = call_w->colours[1]; w->colours[2] = call_w->colours[2]; }
static void window_text_input_invalidate(rct_window *w) { // Work out the existing size of the window char wrapped_string[512]; safe_strcpy(wrapped_string, text_input, 512); int no_lines = 0, font_height = 0; // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); int height = no_lines * 10 + WH; // Change window size if required. if (height != w->height) { window_invalidate(w); window_set_resize(w, WW, height, WW, height); } window_text_input_widgets[WIDX_OKAY].top = height - 21; window_text_input_widgets[WIDX_OKAY].bottom = height - 10; window_text_input_widgets[WIDX_CANCEL].top = height - 21; window_text_input_widgets[WIDX_CANCEL].bottom = height - 10; window_text_input_widgets[WIDX_BACKGROUND].bottom = height - 1; }
void window_tooltip_show(rct_string_id id, int x, int y) { rct_window *w; int width, height; w = window_find_by_class(WC_ERROR); if (w != NULL) return; RCT2_GLOBAL(0x0142006C, sint32) = -1; char* buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, id, (void*)0x013CE952); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; int tooltip_text_width; tooltip_text_width = gfx_get_string_width_new_lined(buffer); buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); tooltip_text_width = min(tooltip_text_width, 196); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; int numLines, fontSpriteBase; tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &numLines, &fontSpriteBase); RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, sint16) = numLines; width = tooltip_text_width + 3; height = ((numLines + 1) * font_get_line_height(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16))) + 4; window_tooltip_widgets[WIDX_BACKGROUND].right = width; window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; memcpy(gTooltip_text_buffer, buffer, 512); x = clamp(0, x - (width / 2), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); int max_y = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height; y += 26; // Normally, we'd display the tooltip 26 lower if (y > max_y) // If y is too large, the tooltip could be forced below the cursor if we'd just clamped y, // so we'll subtract a bit more y -= height + 40; y = clamp(22, y, max_y); w = window_create( x, y, width, height, &window_tooltip_events, WC_TOOLTIP, WF_TRANSPARENT | WF_STICK_TO_FRONT ); w->widgets = window_tooltip_widgets; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; }
void window_tooltip_show(rct_string_id id, int32_t x, int32_t y) { rct_window* w; int32_t width, height; w = window_find_by_class(WC_ERROR); if (w != nullptr) return; char* buffer = gCommonStringFormatBuffer; format_string(buffer, sizeof(gCommonStringFormatBuffer), id, gCommonFormatArgs); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; int32_t tooltip_text_width; tooltip_text_width = gfx_get_string_width_new_lined(buffer); buffer = gCommonStringFormatBuffer; tooltip_text_width = std::min(tooltip_text_width, 196); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; int32_t numLines, fontSpriteBase; tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &numLines, &fontSpriteBase); _tooltipNumLines = numLines; width = tooltip_text_width + 3; height = ((numLines + 1) * font_get_line_height(gCurrentFontSpriteBase)) + 4; window_tooltip_widgets[WIDX_BACKGROUND].right = width; window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; std::memcpy(_tooltipText, buffer, sizeof(_tooltipText)); int32_t screenWidth = context_get_width(); int32_t screenHeight = context_get_height(); x = std::clamp(x - (width / 2), 0, screenWidth - width); // TODO The cursor size will be relative to the window DPI. // The amount to offset the y should be adjusted. int32_t max_y = screenHeight - height; y += 26; // Normally, we'd display the tooltip 26 lower if (y > max_y) // If y is too large, the tooltip could be forced below the cursor if we'd just clamped y, // so we'll subtract a bit more y -= height + 40; y = std::clamp(y, 22, max_y); w = window_create(x, y, width, height, &window_tooltip_events, WC_TOOLTIP, WF_TRANSPARENT | WF_STICK_TO_FRONT); w->widgets = window_tooltip_widgets; reset_tooltip_not_shown(); }
static rct_xy16 window_multiplayer_information_get_size() { if (!_windowInformationSizeDirty) { return _windowInformationSize; } sint32 width = 450; sint32 height = 110; sint32 numLines, fontSpriteBase; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; utf8 * buffer = _strdup(network_get_server_description()); gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); free(buffer); sint32 lineHeight = font_get_line_height(fontSpriteBase); height += (numLines + 1) * lineHeight; _windowInformationSizeDirty = false; _windowInformationSize = (rct_xy16){ width, height }; return _windowInformationSize; }
// Wrap string without drawing, useful to get the height of a wrapped string. // Almost the same as gfx_draw_string_left_wrapped sint32 chat_string_wrapped_get_height(void *args, sint32 width) { sint32 fontSpriteBase, lineHeight, lineY, numLines; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; char *buffer = gCommonStringFormatBuffer; format_string(buffer, 256, STR_STRING, args); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); lineHeight = font_get_line_height(fontSpriteBase); gCurrentFontFlags = 0; lineY = 0; for (sint32 line = 0; line <= numLines; ++line) { buffer = get_string_end(buffer) + 1; lineY += lineHeight; } return lineY; }
static LocationXY16 window_multiplayer_information_get_size() { if (!_windowInformationSizeDirty) { return _windowInformationSize; } sint32 width = 450; sint32 height = 60; sint32 minNumLines = 5; sint32 descNumLines, fontSpriteBase; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; utf8 * buffer = _strdup(network_get_server_description()); gfx_wrap_string(buffer, width, &descNumLines, &fontSpriteBase); free(buffer); sint32 lineHeight = font_get_line_height(fontSpriteBase); height += (minNumLines + descNumLines) * lineHeight; _windowInformationSizeDirty = false; _windowInformationSize = { (sint16)width, (sint16)height }; return _windowInformationSize; }
static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi) { window_draw_widgets(w, dpi); int y = w->y + 25; int no_lines = 0; int font_height = 0; gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], &TextInputDescriptionArgs); y += 25; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; char wrapped_string[512]; safe_strcpy(wrapped_string, text_input, 512); // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 10 * (no_lines + 1) + 3, w->colours[1], 0x60); y += 1; char* wrap_pointer = wrapped_string; int char_count = 0; uint8 cur_drawn = 0; int cursorX, cursorY; for (int line = 0; line <= no_lines; line++) { gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); int string_length = get_string_size(wrap_pointer) - 1; if (!cur_drawn && (gTextInput.selection_offset <= (size_t)(char_count + string_length))) { // Make a copy of the string for measuring the width. char temp_string[512] = { 0 }; memcpy(temp_string, wrap_pointer, gTextInput.selection_offset - char_count); cursorX = w->x + 13 + gfx_get_string_width(temp_string); cursorY = y; int width = 6; if ((uint32)gTextInput.selection_offset < strlen(text_input)){ // Make a new 1 character wide string for measuring the width // of the character that the cursor is under. temp_string[1] = '\0'; temp_string[0] = text_input[gTextInput.selection_offset]; width = max(gfx_get_string_width(temp_string) - 2, 4); } if (w->frame_no > 15){ uint8 colour = ColourMapA[w->colours[1]].mid_light; gfx_fill_rect(dpi, cursorX, y + 9, cursorX + width, y + 9, colour + 5); } cur_drawn++; } wrap_pointer += string_length + 1; if (text_input[char_count + string_length] == ' ')char_count++; char_count += string_length; y += 10; } if (!cur_drawn) { cursorX = gLastDrawStringX; cursorY = y - 10; } // IME composition if (gTextInputCompositionActive) { int compositionWidth = gfx_get_string_width(gTextInputComposition); int x = cursorX - (compositionWidth / 2); int y = cursorY + 13; int w = compositionWidth; int h = 10; gfx_fill_rect(dpi, x - 1, y - 1, x + w + 1, y + h + 1, 12); gfx_fill_rect(dpi, x, y, x + w, y + h, 0); gfx_draw_string(dpi, gTextInputComposition, 12, x, y); } }
static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi) { window_draw_widgets(w, dpi); sint32 y = w->y + 25; sint32 no_lines = 0; sint32 font_height = 0; gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], &TextInputDescriptionArgs); y += 25; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gCurrentFontFlags = 0; char wrapped_string[512]; safe_strcpy(wrapped_string, text_input, 512); // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 10 * (no_lines + 1) + 3, w->colours[1], INSET_RECT_F_60); y += 1; char* wrap_pointer = wrapped_string; size_t char_count = 0; uint8 cur_drawn = 0; sint32 cursorX = 0, cursorY = 0; for (sint32 line = 0; line <= no_lines; line++) { gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); size_t string_length = get_string_size(wrap_pointer) - 1; if (!cur_drawn && (gTextInput.selection_offset <= char_count + string_length)) { // Make a copy of the string for measuring the width. char temp_string[512] = { 0 }; memcpy(temp_string, wrap_pointer, gTextInput.selection_offset - char_count); cursorX = w->x + 13 + gfx_get_string_width(temp_string); cursorY = y; sint32 width = 6; if (gTextInput.selection_offset < strlen(text_input)){ // Make a 1 utf8-character wide string for measuring the width // of the currently selected character. utf8 tmp[5] = { 0 }; // This is easier than setting temp_string[0..5] uint32 codepoint = utf8_get_next(text_input + gTextInput.selection_offset, NULL); utf8_write_codepoint(tmp, codepoint); width = max(gfx_get_string_width(tmp) - 2, 4); } if (w->frame_no > 15){ uint8 colour = ColourMapA[w->colours[1]].mid_light; gfx_fill_rect(dpi, cursorX, y + 9, cursorX + width, y + 9, colour + 5); } cur_drawn++; } wrap_pointer += string_length + 1; if (text_input[char_count + string_length] == ' ')char_count++; char_count += string_length; y += 10; } if (!cur_drawn) { cursorX = gLastDrawStringX; cursorY = y - 10; } // IME composition if (gTextInputCompositionActive) { draw_ime_composition(dpi, cursorX, cursorY); } }
/** * * rct2: 0x0066792F * * bx: title * dx: message */ void window_error_open(rct_string_id title, rct_string_id message) { utf8 *dst; char *args; int numLines, fontHeight, x, y, width, height, maxY; rct_window *w; window_close_by_class(WC_ERROR); dst = _window_error_text; args = (char*)0x0013CE952; // Format the title dst = utf8_write_codepoint(dst, FORMAT_BLACK); if (title != (rct_string_id)STR_NONE) { format_string(dst, title, args); dst = get_string_end(dst); } // Format the message if (message != (rct_string_id)STR_NONE) { dst = utf8_write_codepoint(dst, FORMAT_NEWLINE); format_string(dst, message, args); dst = get_string_end(dst); } log_verbose("show error, %s", _window_error_text + 1); // Check if there is any text to display if (dst == _window_error_text + 1) return; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; width = gfx_get_string_width_new_lined(_window_error_text); width = min(196, width); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; gfx_wrap_string(_window_error_text, width + 1, &numLines, &fontHeight); _window_error_num_lines = numLines; width = width + 3; height = (numLines + 1) * 10 + 4; window_error_widgets[WIDX_BACKGROUND].right = width; window_error_widgets[WIDX_BACKGROUND].bottom = height; x = RCT2_GLOBAL(0x0142406C, sint32) - (width / 2); x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); y = RCT2_GLOBAL(0x01424070, sint32) + 26; y = max(22, y); maxY = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height; if (y > maxY) { y = y - height - 40; y = min(y, maxY); } w = window_create(x, y, width, height, &window_error_events, WC_ERROR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); w->widgets = window_error_widgets; w->error.var_480 = 0; if (!(RCT2_GLOBAL(0x009A8C29, uint8) & 1)) sound_play_panned(SOUND_ERROR, 0, w->x + (w->width / 2), 0, 0); }
static void window_text_input_paint(){ rct_window *w; rct_drawpixelinfo *dpi; window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); int y = w->y + 25; int no_lines = 0; int font_height = 0; gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], &TextInputDescriptionArgs); y += 25; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; char wrapped_string[512]; strcpy(wrapped_string, text_input); // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 10 * (no_lines + 1) + 3, w->colours[1], 0x60); y += 1; char* wrap_pointer = wrapped_string; int char_count = 0; uint8 cur_drawn = 0; for (int line = 0; line <= no_lines; ++line){ gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); int string_length = get_string_length(wrap_pointer); if (!cur_drawn && (gTextInputCursorPosition <= char_count + string_length)){ // Make a copy of the string for measuring the width. char temp_string[512] = { 0 }; memcpy(temp_string, wrap_pointer, gTextInputCursorPosition - char_count); int cur_x = w->x + 13 + gfx_get_string_width(temp_string); int width = 6; if ((uint32)gTextInputCursorPosition < strlen(text_input)){ // Make a new 1 character wide string for measuring the width // of the character that the cursor is under. temp_string[1] = '\0'; temp_string[0] = text_input[gTextInputCursorPosition]; width = max(gfx_get_string_width(temp_string) - 2, 4); } if (w->frame_no > 15){ uint8 colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; gfx_fill_rect(dpi, cur_x, y + 9, cur_x + width, y + 9, colour + 5); } cur_drawn++; } wrap_pointer += string_length + 1; if (text_input[char_count + string_length] == ' ')char_count++; char_count += string_length; y += 10; } }
static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, rct_widgetindex widgetIndex) { sint32 no_lines = 0; sint32 font_height = 0; char wrapped_string[TEXT_INPUT_SIZE]; // Get the widget rct_widget *widget = &w->widgets[widgetIndex]; // Resolve the absolute ltrb sint32 l = w->x + widget->left; sint32 t = w->y + widget->top; sint32 r = w->x + widget->right; sint32 b = w->y + widget->bottom; // Get the colour uint8 colour = w->colours[widget->colour]; bool active = w->classification == gCurrentTextBox.window.classification && w->number == gCurrentTextBox.window.number && widgetIndex == gCurrentTextBox.widget_index; //gfx_fill_rect_inset(dpi, l, t, r, b, colour, 0x20 | (!active ? 0x40 : 0x00)); gfx_fill_rect_inset(dpi, l, t, r, b, colour, INSET_RECT_F_60); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gCurrentFontFlags = 0; if (!active || gTextInput == NULL) { if (w->widgets[widgetIndex].text != 0) { safe_strcpy(wrapped_string, w->widgets[widgetIndex].string, 512); gfx_wrap_string(wrapped_string, r - l - 5, &no_lines, &font_height); gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); } return; } safe_strcpy(wrapped_string, gTextBoxInput, TEXT_INPUT_SIZE); // String length needs to add 12 either side of box // +13 for cursor when max length. gfx_wrap_string(wrapped_string, r - l - 5 - 6, &no_lines, &font_height); gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); size_t string_length = get_string_size(wrapped_string) - 1; // Make a copy of the string for measuring the width. char temp_string[TEXT_INPUT_SIZE] = { 0 }; memcpy(temp_string, wrapped_string, min(string_length, gTextInput->SelectionStart)); sint32 cur_x = l + gfx_get_string_width(temp_string) + 3; sint32 width = 6; if ((uint32)gTextInput->SelectionStart < strlen(gTextBoxInput)){ // Make a new 1 character wide string for measuring the width // of the character that the cursor is under. temp_string[1] = '\0'; temp_string[0] = gTextBoxInput[gTextInput->SelectionStart]; width = max(gfx_get_string_width(temp_string) - 2, 4); } if (gTextBoxFrameNo <= 15){ colour = ColourMapA[w->colours[1]].mid_light; gfx_fill_rect(dpi, cur_x, t + 9, cur_x + width, t + 9, colour + 5); } }
/** * * rct2: 0x0066792F * * bx: title * dx: message */ void window_error_open(rct_string_id title, rct_string_id message) { utf8 *dst; sint32 numLines, fontHeight, x, y, width, height, maxY; rct_window *w; window_close_by_class(WC_ERROR); dst = _window_error_text; // Format the title dst = utf8_write_codepoint(dst, FORMAT_BLACK); if (title != STR_NONE) { format_string(dst, 512 - (dst - _window_error_text), title, gCommonFormatArgs); dst = get_string_end(dst); } // Format the message if (message != STR_NONE) { dst = utf8_write_codepoint(dst, FORMAT_NEWLINE); format_string(dst, 512 - (dst - _window_error_text), message, gCommonFormatArgs); dst = get_string_end(dst); } log_verbose("show error, %s", _window_error_text + 1); // Check if there is any text to display if (dst == _window_error_text + 1) return; gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; width = gfx_get_string_width_new_lined(_window_error_text); width = min(196, width); gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM; gfx_wrap_string(_window_error_text, width + 1, &numLines, &fontHeight); _window_error_num_lines = numLines; width = width + 3; height = (numLines + 1) * 10 + 4; window_error_widgets[WIDX_BACKGROUND].right = width; window_error_widgets[WIDX_BACKGROUND].bottom = height; x = gCursorState.x - (width / 2); x = clamp(0, x, gScreenWidth); y = gCursorState.y + 26; y = max(22, y); maxY = gScreenHeight - height; if (y > maxY) { y = y - height - 40; y = min(y, maxY); } w = window_create(x, y, width, height, &window_error_events, WC_ERROR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); w->widgets = window_error_widgets; w->error.var_480 = 0; if (!gDisableErrorWindowSound) { audio_play_sound_panned(SOUND_ERROR, 0, w->x + (w->width / 2), 0, 0); } }