#include "UI/Chat/UINewChatWnd.h" #include "Client/Application/ApplicationWindow.h" #include "Client/Mode/CGameMode.h" #include "Client/Mode/ModeMgr.h" #include "Contents/NavigationManager.h" #include "UI/Dialogs/UITipboxWnd.h" #include "UI/Window/UIWindowMgr.h" #include "Contents/Items/ItemInfo.h" #include "UI/Lists/UIScrollBar.h" #include "UI/Buttons/UITextButton.h" #include "UI/Text/UITextViewer.h" #include "UI/Window/WindowManagerWindows.h" #include "Contents/Items/ItemNaming.h" #include "UI/Lists/UIChatHisBox.h" #include "UI/Text/NavigationLink.h" #include "UI/Text/PixelTextWrapping.h" #include "UI/Text/TextMarkup.h" #include "UI/Text/TextWrapping.h" #include "Render/Text/TextContext.h" #include #include #include #include // INLINED __forceinline void UITextViewer::Activate(UITextButton* button, int id) { switch (id) { case 437: if (button) { const std::string& url = button->GetLine(0); if (!url.empty()) { ShellExecuteA(hWnd, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL); } } break; case 438: { if (!button) { break; } const int count = button->GetLinesCount(); if (count == 0) { break; } const std::string& map = button->GetLine(0); const int x = std::atoi(button->GetLine(1).c_str()); const int y = std::atoi(button->GetLine(2).c_str()); if (count > 3) { const int type = std::atoi(button->GetLine(3).c_str()); int policy = std::atoi(button->GetLine(4).c_str()); if (policy == -222) { std::string name = "$$DB "; if (type != 3) { name.clear(); } name += map; g_navigationManager.SearchNavigation(name, type, 0); break; } const int option = std::atoi(button->GetLine(5).c_str()); const int target = std::atoi(button->GetLine(6).c_str()); unsigned char flag = 0; if (policy >= 100) { flag = 1; policy -= 100; } if (policy >= 10) { flag += 2; policy -= 10; } if (policy >= 1) { flag += 4; } g_navigationManager.StartNavigation(map.c_str(), type, flag, option == 0, x, y, target); } else { g_navigationManager.StartNavigation(map.c_str(), 2, 5, false, x, y, 1002); } break; } case 464: { if (!button || button->GetLinesCount() == 0) { break; } int idValue = 0; if (!button->GetLine(1).empty()) { idValue = std::atoi(button->GetLine(1).c_str()); } ITEM_INFO item; item.identified = 1; item.unknown_0000[0] = static_cast(idValue); item.unknown_0060 = 0; item.itemId = button->GetLine(0); if (UIWindow* window = g_windowMgr.EnsureWindow(12)) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 0, 0, 0); } break; } case 517: if (button && button->GetLinesCount() != 0) { const std::string& tip = button->GetLine(0); if (UIWindow* window = g_windowMgr.EnsureWindow(315)) { static_cast(window)->ShowTip(std::atoi(tip.c_str())); } } break; case 539: if (button) { const int value = std::atoi(button->GetLine(0).c_str()); static_cast(g_modeMgr.GetGameMode())->ReceiveServiceRequest(6, value); } break; default: break; } } // INLINED __forceinline void UITextViewer::AppendText(char* text, int width, int carriageReturns, int pixels) { const int lineWidth = width == 0 ? 35 : width; std::vector wrapped; if (width == 138) { WrapPlainText(text, wrapped, 38); for (unsigned index = 0; index < wrapped.size(); ++index) { this->AddLine(wrapped[index].c_str()); } this->unknown_00BC = (this->unknown_00BC & ~255) | 1; return; } if (HasTextLinks(text)) { const std::string expanded = ExpandTextEscapes(text); strcpy_s(text, std::strlen(text) + 1, expanded.c_str()); std::string display = DisplayUrlTextTag(text); display = DisplayNavigationTextTag(display); display = DisplayTipBoxTextTag(display); display = DisplayItemTextTag(display); display = RemoveTextLinkInfo(display); if (g_windowMgr.window_01C8) { display = static_cast(g_windowMgr.window_01C8)->ConvertChat(display); } std::string navigation; DisplayNavigationLink(navigation, display); display = DisplayQuestTextTag(navigation); if (pixels) { const int scrollWidth = carriageReturns ? this->verticalBar->geometry.width + 2 : 0; this->WrapPixelText(display.c_str(), wrapped, this->geometry.width - scrollWidth - 4); } else { WrapRichText(display.c_str(), wrapped, lineWidth, carriageReturns != 0); } for (unsigned index = 0; index < wrapped.size(); ++index) { this->AddLine(wrapped[index].c_str()); } this->AddItemLinks(text, static_cast(wrapped.size())); this->AddUrlLinks(text, static_cast(wrapped.size())); this->AddNaviLinks(text, static_cast(wrapped.size())); this->AddTipLinks(text, static_cast(wrapped.size())); this->AddQuestLinks(text, static_cast(wrapped.size())); } else { if (pixels) { const int scrollWidth = carriageReturns ? this->verticalBar->geometry.width + 2 : 0; this->WrapPixelText(text, wrapped, this->geometry.width - scrollWidth - 4); } else { WrapRichText(text, wrapped, lineWidth, carriageReturns != 0); } for (unsigned index = 0; index < wrapped.size(); ++index) { this->AddLine(wrapped[index].c_str()); } } this->unknown_00BC &= ~255; } // OFFSET: 0x00899E90 // FUNCTION: fn_11562 int UITextViewer::SendMsg(UIWindow* sender, int message, std::intptr_t argument1, std::intptr_t argument2, std::intptr_t argument3, std::intptr_t argument4) { switch (message) { case 7: case 8: case 9: case 10: case 11: case 12: { const int previousX = this->horizontalOffset; UIListBox::SendMsg(sender, message, argument1, argument2, argument3, argument4); for (unsigned index = 0; index < this->links.size(); ++index) { UITextButton* button = this->links[index]; if (!button) { continue; } const int row = button->m_value; if (row >= this->topLine && row < this->geometry.height / this->lineHeight - this->bottomMargin + this->topLine) { button->Enable(1); button->Move(button->geometry.x - this->horizontalOffset + previousX, (row - this->topLine) * this->lineHeight + 3); } else { button->Enable(0); } } return 0; } case 18: if (this->verticalOverflow != 0) { this->SendMsg(this->verticalBar, 7, -1, 0, 0, 0); } return 0; case 19: if (this->verticalOverflow != 0) { this->SendMsg(this->verticalBar, 7, 1, 0, 0, 0); } return 0; case 29: { char* text = reinterpret_cast(argument1); const int width = static_cast(argument2); const bool carriageReturns = argument3 != 0; const bool pixels = argument4 != 0; const int lineWidth = width == 0 ? 35 : width; std::vector wrapped; if (width == 138) { WrapPlainText(text, wrapped, 38); for (const auto& line : wrapped) { this->AddLine(line.c_str()); } this->unknown_00BC = (this->unknown_00BC & ~255) | 1; this->Invalidate(); return 0; } if (HasTextLinks(text)) { const std::string expanded = ExpandTextEscapes(text); strcpy_s(text, std::strlen(text) + 1, expanded.c_str()); std::string display = DisplayUrlTextTag(text); display = DisplayNavigationTextTag(display); display = DisplayTipBoxTextTag(display); display = DisplayItemTextTag(display); display = RemoveTextLinkInfo(display); if (g_windowMgr.window_01C8) { display = static_cast(g_windowMgr.window_01C8)->ConvertChat(display); } std::string navigation; DisplayNavigationLink(navigation, display); display = DisplayQuestTextTag(navigation); if (pixels) { const int scrollWidth = carriageReturns ? this->verticalBar->geometry.width + 2 : 0; this->WrapPixelText(display.c_str(), wrapped, this->geometry.width - scrollWidth - 4); } else { WrapRichText(display.c_str(), wrapped, lineWidth, carriageReturns); } for (const auto& line : wrapped) { this->AddLine(line.c_str()); } this->AddItemLinks(text, static_cast(wrapped.size())); this->AddUrlLinks(text, static_cast(wrapped.size())); this->AddNaviLinks(text, static_cast(wrapped.size())); this->AddTipLinks(text, static_cast(wrapped.size())); this->AddQuestLinks(text, static_cast(wrapped.size())); } else { if (pixels) { const int scrollWidth = carriageReturns ? this->verticalBar->geometry.width + 2 : 0; this->WrapPixelText(text, wrapped, this->geometry.width - scrollWidth - 4); } else { WrapRichText(text, wrapped, lineWidth, carriageReturns); } for (const auto& line : wrapped) { this->AddLine(line.c_str()); } } this->unknown_00BC &= ~255; this->Invalidate(); return 0; } case 98: { auto* button = static_cast(sender); const int id = static_cast(argument1); switch (id) { case 437: if (button && !button->GetLine(0).empty()) { ShellExecuteA(hWnd, "open", button->GetLine(0).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } break; case 438: if (button && button->GetLinesCount() != 0) { const int count = button->GetLinesCount(); const std::string& map = button->GetLine(0); const int x = std::atoi(button->GetLine(1).c_str()); const int y = std::atoi(button->GetLine(2).c_str()); if (count > 3) { const int type = std::atoi(button->GetLine(3).c_str()); int policy = std::atoi(button->GetLine(4).c_str()); if (policy == -222) { std::string name = type == 3 ? "$$DB " : ""; name += map; g_navigationManager.SearchNavigation(name, type, 0); break; } const int option = std::atoi(button->GetLine(5).c_str()); const int target = std::atoi(button->GetLine(6).c_str()); unsigned char flag = 0; if (policy >= 100) { flag = 1; policy -= 100; } if (policy >= 10) { flag += 2; policy -= 10; } if (policy >= 1) { flag += 4; } g_navigationManager.StartNavigation(map.c_str(), type, flag, option == 0, x, y, target); } else { g_navigationManager.StartNavigation(map.c_str(), 2, 5, false, x, y, 1002); } } break; case 464: if (button && button->GetLinesCount() != 0) { int idValue = 0; if (!button->GetLine(1).empty()) { idValue = std::atoi(button->GetLine(1).c_str()); } ITEM_INFO item; item.identified = 1; item.unknown_0000[0] = static_cast(idValue); item.unknown_0060 = 0; item.itemId = button->GetLine(0); if (UIWindow* window = g_windowMgr.EnsureWindow(12)) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 0, 0, 0); } } break; case 517: if (button && button->GetLinesCount() != 0) { const std::string& tip = button->GetLine(0); if (UIWindow* window = g_windowMgr.EnsureWindow(315)) { static_cast(window)->ShowTip(std::atoi(tip.c_str())); } } break; case 539: if (button) { static_cast(g_modeMgr.GetGameMode())->ReceiveServiceRequest(6, std::atoi(button->GetLine(0).c_str())); } break; default: break; } return 0; } default: return UIListBox::SendMsg(sender, message, argument1, argument2, argument3, argument4); } }