rodecomp/Source/UI/Window/UIMessageBox.cpp
ragnarok-clanker 04807a93d6 Decompile fn_11769 (UIMessageBoxAutoreturn::Paint)
Batch #5158 by Yommy: 0 byte-identical, 1 confirmed by peer review.

- fn_11769 UIMessageBoxAutoreturn::Paint: logic confirmed by peer review

Peer-reviewed-by: willerthal, youko, sherollyner, Snow, Qwenkler3.8
Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes).
2026-10-30 10:46:06 +00:00

1388 lines
49 KiB
C++

#include "Client/ReplayPacketRecorder.h"
#include "Resource/Bitmap/BitmapResource.h"
#include "Resource/ResourceMgr.h"
#include "Resource/TextureNames.h"
#include "Resource/SkinPalette.h"
#include "UI/Window/UICntWnd.h"
#include "UI/Window/UIChatRoomWnd.h"
#include "UI/Window/UIBank_NewWnd.h"
#include "UI/Edit/UIEditCtrl.h"
#include "Client/Session.h"
#include "Utility/Text/GroupedInteger.h"
#include "UI/Buttons/UIBitmapButton.h"
#include "UI/Window/UILoginWnd.h"
#include "UI/Window/UIMessageBox.h"
#include "UI/Window/UINoticeWnd.h"
#include "UI/Window/UISelectReplayDataWnd.h"
#include "UI/Window/UISelectServerWnd.h"
#include "UI/UIStaticBitmap.h"
#include "UI/Buttons/UITextButton.h"
#include "UI/Text/UITextViewer.h"
#include "UI/Window/WindowBorder.h"
#include "UI/Window/UIWindowMgr.h"
#include "UI/Window/UIMerInfoWnd.h"
#include "UI/Window/UIMessageBoxAutoreturn.h"
#include "UI/Window/UIMonsterInfoWnd.h"
#include "UI/Window/UITalkboxTrapInputWnd.h"
#include "UI/Window/UIHomunInfoWnd.h"
#include "UI/Window/UIPetInfoWnd.h"
#include "UI/Window/UIReplayRECControlWnd.h"
#include "Client/Mode/ModeMgr.h"
#include "Client/Registry.h"
#include "Utility/Cipher/XorBytes.h"
#include "UI/Window/UILoginOTPWnd.h"
#include "UI/Window/InputFocus.h"
#include "UI/Buttons/UIButton.h"
#include "Render/Text/TextContext.h"
#include "Contents/MessageTable.h"
#include "UI/Text/ColoredText.h"
#include "Client/Mode/CMode.h"
#include "UI/Window/UIPayConfirmWnd.h"
#include "UI/Window/UIReplayControlWnd.h"
#include "UI/Window/UIMakeCharWnd.h"
#include "Client/Mode/CLoginMode.h"
#include "Client/Replay.h"
#include "Client/Application/Launcher.h"
#include "UI/Lists/UIChatHisBox.h"
#include "Client/Application/ApplicationWindow.h"
#include "UI/Text/UIStaticText.h"
#include "UI/UIBarGraph.h"
#include "Utility/Text/FormatString.h"
#include "Resource/Sprites/ActionResource.h"
#include "Resource/Sprites/SpriteResource.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#include <timeapi.h>
#include <shellapi.h>
#include <imm.h>
#include <direct.h>
#include <io.h>
namespace {
constexpr char prefix[] = "유저인터페이스\\";
template <std::size_t Length, std::uint64_t Key>
class EncryptedName {
public:
explicit EncryptedName(const std::uint8_t (&source)[Length]) : m_encrypted(true) {
for (std::uint64_t index = 0; index < Length; ++index) {
this->m_text[index] = source[index];
}
}
~EncryptedName() {
for (std::uint64_t index = 0; index < Length; ++index) {
this->m_text[index] = 0;
}
}
const char* Text() {
if (this->m_encrypted) {
utility::XorBytes(this->m_text, Length, Key);
this->m_encrypted = false;
}
return reinterpret_cast<const char*>(this->m_text);
}
private:
std::uint8_t m_text[Length];
bool m_encrypted;
};
// INLINED
std::uint32_t Palette(ResourceMgr& resources, int x, int y) {
const auto* resource = static_cast<CBitmapRes*>(resources.Load((std::string(prefix) + "colorchip.bmp").c_str()));
const auto& image = resource->image;
const std::uint32_t pixel = x >= 0 && y >= 0 && x < image.width && y < image.height ? image.pixels[y * image.width + x] : 0x00FF0000u;
return ((pixel & 255) << 16) | (pixel & 0xFF00) | ((pixel >> 16) & 255);
}
// INLINED
void DrawTextRight(UIWindow& window, FontCache& fonts, const TextLocale& locale, int x, int y, const char* text, int bytes,
int family, int height, std::uint32_t color, unsigned char bold) {
if (!bytes) {
bytes = static_cast<int>(std::strlen(text));
}
TextContext context(*window.geometry.surface);
context.SetFont(family, height, bold, 0);
const int width = context.Measure(text, static_cast<int>(std::strlen(text))).cx;
context.SetColor(color);
context.Draw(x - width, y, text, bytes);
}
}
// OFFSET: 0x008A3FC0
// FUNCTION: fn_11663
UIMessageBox::UIMessageBox(UIWindowContext& windows, UIFrameContext& frames, UIMessageBoxContext& dialog)
: UIFrameWnd(windows, frames, 0), counting(0), protectedMessage(0), m_dialog(&dialog) {
}
// OFFSET: 0x008A5220
// OFFSET: 0x008A64E0
// FUNCTION: fn_11680
UIMessageBox::~UIMessageBox() = default;
// OFFSET: 0x008B8E60
// FUNCTION: fn_11768
void UIMessageBox::Paint() {
auto& controls = this->m_dialog->text.buttons;
const auto load = [&](const char* name) { return static_cast<CBitmapRes*>(controls.resources.Load((std::string(prefix) + name).c_str())); };
int leftWidth = 0;
int rightWidth = 0;
int titleHeight = 0;
const int width = this->geometry.width;
const int height = this->geometry.height;
if (const auto* left = load("basic_interface\\titlebar_left.bmp")) {
this->DrawBitmap(0, 0, &left->image, false);
leftWidth = left->image.width;
}
if (const auto* right = load("basic_interface\\titlebar_right.bmp")) {
rightWidth = right->image.width;
this->DrawBitmap(width - rightWidth, 0, &right->image, false);
}
if (const auto* middle = load("basic_interface\\titlebar_mid.bmp")) {
titleHeight = middle->image.height;
const int tileWidth = middle->image.width;
const int extent = width - rightWidth - leftWidth;
const int tiles = extent / tileWidth + (extent % tileWidth != 0);
for (int index = 0; index < tiles; ++index) {
this->DrawBitmap(leftWidth, 0, &middle->image, false);
leftWidth += tileWidth;
}
}
this->DrawTextAt(controls.fonts, controls.locale, 19, titleHeight - 13, this->caption.c_str(), 0, 0, 12, 0xFFFFFF, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 18, titleHeight - 14, this->caption.c_str(), 0, 0, 12, 0, 0, 0);
const auto* base = load("basic_interface\\sys_base_off.bmp");
this->DrawBitmap(3, 3, base ? &base->image : nullptr, true);
const auto border = Palette(controls.resources, 14, 6);
DrawRoundedBorder(*this, 0, 17, width, height - 17, border);
this->FillRegion(0, 17, width, 5, border);
const auto background = Palette(controls.resources, 2, 2);
this->FillRegion(1, 17, width - 2, height - 19, background);
this->FillRegion(2, height - 2, width - 4, 1, background);
}
// OFFSET: 0x008AC410
// FUNCTION: fn_11729
bool UIBank_NewWnd::Slot03() {
return true;
}
// OFFSET: 0x008AC420
// FUNCTION: fn_11730
bool UIReplayControlWnd::Slot03() {
return true;
}
// OFFSET: 0x008AC430
// FUNCTION: fn_11731
bool UIReplayRECControlWnd::Slot03() {
return true;
}
// OFFSET: 0x008B7A90
// FUNCTION: fn_11756
void UIMessageBox::Slot18() {
}
// OFFSET: 0x008B7AA0
// FUNCTION: fn_11757
void UINoticeWnd::Slot18() {
}
// OFFSET: 0x008B7AB0
// FUNCTION: fn_11758
void UISelectReplayDataWnd::Slot18() {
}
// OFFSET: 0x008B7AC0
// FUNCTION: fn_11759
void UISelectServerWnd::Slot18() {
}
// OFFSET: 0x008B8610
// FUNCTION: fn_11765
void UILoginWnd::Paint() {
this->ClearSurface(0xFFFF00FF);
}
// OFFSET: 0x008B88F0
// FUNCTION: fn_11767
void UIMerInfoWnd::Paint() {
auto& controls = *this->m_controls;
const auto* background = static_cast<CBitmapRes*>(ResourceMgr::Instance().Load(Resolve("유저인터페이스\\basic_interface\\homuninfo_bg.bmp")));
this->DrawBitmap(0, 0, &background->image, false);
char title[50] = {};
const unsigned kind = g_session.m_mercenaryClass;
const int titleId = kind - 6017 <= 9 ? 1181 : kind - 6037 <= 9 ? 1182 : kind - 6027 <= 9 ? 1183 : 1367;
std::sprintf(title, controls.services.MessageText(titleId));
this->DrawTextAt(controls.fonts, controls.locale, 5, 2, title, 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 100, 24, controls.services.MessageText(407), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 100, 47, controls.services.MessageText(408), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 100, 111, controls.services.MessageText(1184), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 100, 135, controls.services.MessageText(1185), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 100, 159, controls.services.MessageText(1186), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 230, 133, controls.services.MessageText(1187), 0, 0, 12, 0, 0, 0);
char number[24] = {};
for (int i = 0; i < 8; ++i) {
const int value = i == 7 ? (2000 - g_session.m_mercenaryStats[i]) / 10 : g_session.m_mercenaryStats[i];
const int bytes = std::sprintf(number, "%d", value);
DrawTextRight(*this, controls.fonts, controls.locale, 79, 24 + 18 * i, number, bytes, 1, 14, 0, 0);
}
this->DrawTextAt(controls.fonts, controls.locale, 136, 24, g_session.m_mercenaryName, 0, 0, 12, 0x646464, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 135, 24, g_session.m_mercenaryName, 0, 0, 12, 0, 0, 0);
char level[12] = {};
_itoa(g_session.m_mercenaryLevel, level, 10);
this->DrawTextAt(controls.fonts, controls.locale, 135, 47, level, 0, 0, 12, 0, 0, 0);
if (g_session.m_mercenaryClass != -1) {
char text[128] = {};
int bytes = std::sprintf(text, "%d / %d", g_session.m_mercenaryHp, g_session.m_mercenaryMaxHp);
this->DrawTextAt(controls.fonts, controls.locale, 218, 70, text, bytes, 1, 14, 0, 0, 0);
bytes = std::sprintf(text, "%d / %d", g_session.m_mercenarySp, g_session.m_mercenaryMaxSp);
this->DrawTextAt(controls.fonts, controls.locale, 218, 85, text, bytes, 1, 14, 0, 0, 0);
std::strftime(text, 128, controls.services.MessageText(1260), _localtime32(&g_session.m_mercenaryExpiration));
this->DrawTextAt(controls.fonts, controls.locale, 155, 111, text, static_cast<int>(std::strlen(text)), 0, 12, 255, 0, 0);
bytes = std::sprintf(text, "%d", g_session.m_mercenaryLoyalty);
this->DrawTextAt(controls.fonts, controls.locale, 170, 133, text, bytes, 1, 14, 0, 0, 0);
bytes = std::sprintf(text, "%d", g_session.m_mercenarySummons);
this->DrawTextAt(controls.fonts, controls.locale, 170, 157, text, bytes, 1, 14, 0, 0, 0);
bytes = std::sprintf(text, "%d", g_session.m_mercenaryKills);
this->DrawTextAt(controls.fonts, controls.locale, 245, 157, text, bytes, 1, 14, 0, 0, 0);
}
}
// OFFSET: 0x008A6E20
// FUNCTION: fn_11712
long long UIBank_NewWnd::TransactionAmount(unsigned char deposit) {
auto& services = this->m_controls->services;
std::string text = this->m_amountEdit->Text();
this->m_amountEdit->SetText("");
const auto fail = [&](int notice, int status) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(services.MessageText(notice)), 255, 0, 0, 0);
this->m_status = services.MessageText(status);
return 0LL;
};
if (text == std::string(services.MessageText(2778))) {
const long long cash = g_session.m_zeny;
const long long balance = g_session.m_bankBalance;
const long long excess = cash + balance > 0x7FFFFFFF ? cash + balance - 0x7FFFFFFF : 0;
if (deposit) {
if (balance >= 0x7FFFFFFF) {
return fail(2787, 2783);
}
if (g_session.m_zeny == 0) {
return fail(2770, 2780);
}
const long long amount = cash - excess;
if (amount < 0) {
return fail(2465, 2780);
}
return amount;
}
if (balance == 0) {
return fail(2770, 2780);
}
const long long amount = balance - excess;
return cash + amount > 0x7FFFFFFF ? static_cast<long long>(0x7FFFFFFF - g_session.m_zeny) : amount;
}
if (text.empty()) {
return fail(2779, 2781);
}
if (!this->IsNumeric(text)) {
return fail(2488, 2782);
}
const long long amount = _atoi64(text.c_str());
if (amount > 0x7FFFFFFF) {
return fail(2768, 2783);
}
if (amount < 1) {
return fail(2769, 2784);
}
return amount;
}
// OFFSET: 0x008A6C20
// FUNCTION: fn_11710
long long UIBank_NewWnd::AdjustAmount(int amount) {
std::string text = this->m_amountEdit->Text();
this->m_amountEdit->SetText("");
long long result = amount;
if (!text.empty() && this->IsNumeric(text)) {
result += _atoi64(text.c_str());
}
if (result > 0x7FFFFFFF) {
result = 0x7FFFFFFF;
} else if (result < 0) {
result = 0;
}
return result;
}
// OFFSET: 0x008C4B00
// FUNCTION: fn_11888
bool UIBank_NewWnd::IsNumeric(std::string text) {
if (text.size() == 0) {
return false;
}
for (auto it = text.begin(); it != text.end(); ++it) {
if (static_cast<unsigned char>(*it - '0') > 9) {
return false;
}
}
return true;
}
// OFFSET: 0x008B7AD0
// FUNCTION: fn_11760
void UIBank_NewWnd::Paint() {
auto& controls = *this->m_controls;
const auto* background = static_cast<CBitmapRes*>(ResourceMgr::Instance().Load(Resolve("유저인터페이스\\bank\\bg_bank.bmp")));
const int titleHeight = this->DrawTitleBar(controls.fonts, controls.locale, true, controls.services.MessageText(2771), 0);
this->DrawBitmap(0, titleHeight, &background->image, false);
char number[260] = {};
char text[260] = {};
this->DrawTextAt(controls.fonts, controls.locale, 30, 29, controls.services.MessageText(2772), 0, 0, 12, 0, 0, 0);
const int x = this->TextWidth(controls.fonts, controls.locale, controls.services.MessageText(2772), 0, 0, 12, 0, 0) + 43;
FormatGroupedInteger(g_session.m_bankBalance, number, 260);
std::sprintf(text, "%s z", number);
this->DrawTextAt(controls.fonts, controls.locale, x, 29, text, 0, 0, 11, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 30, 46, controls.services.MessageText(2773), 0, 0, 12, 0, 0, 0);
FormatGroupedInteger(g_session.m_zeny, number, 260);
std::sprintf(text, "%s z", number);
this->DrawTextAt(controls.fonts, controls.locale, x, 46, text, 0, 0, 11, 0, 0, 0);
if (!this->m_status.empty()) {
const int textWidth = this->TextWidth(controls.fonts, controls.locale, this->m_status.c_str(), 0, 0, 12, 0, 0);
const int statusX = static_cast<int>(this->geometry.width * 0.5f - textWidth * 0.5f);
this->DrawTextAt(controls.fonts, controls.locale, statusX, 112, this->m_status.c_str(), 0, 0, 11, 255, 0, 0);
}
}
// OFFSET: 0x008B7CF0
// FUNCTION: fn_11761
void UIChatRoomWnd::Paint() {
auto& controls = *this->m_controls;
const int titleHeight = this->DrawTitleBar(controls.fonts, controls.locale, false, "", 0);
this->DrawPanelBackground(titleHeight, 0, "");
unsigned red, green, blue;
SkinPaletteChannels(ResourceMgr::Instance(), 20, 6, red, green, blue);
const int width = this->geometry.width;
this->FillRegion(width - width * 56 / 280 - 2, 17, 1, this->geometry.height - 38, RGB(red, green, blue));
this->DrawButtonBar(0, 0, 1);
}
// OFFSET: 0x008B7DA0
// FUNCTION: fn_11762
void UICntWnd::Paint() {
this->DrawBorder(0, 0, 0, 0);
}
// OFFSET: 0x008A91E0
// FUNCTION: fn_11721
void UIFrameWnd::DrawBorder(int x, int y, int width, int height) {
if (width == 0) {
width = this->geometry.width;
}
if (height == 0) {
height = this->geometry.height;
}
const auto load = [&](const char* name) {
return static_cast<CBitmapRes*>(ResourceMgr::Instance().Load(Resolve(name)));
};
const int innerWidth = width - 28;
const int columns = innerWidth / 14 + (innerWidth % 14 != 0);
for (int i = 0; i < columns; ++i) {
const auto* bitmap = load("유저인터페이스\\sysbox_mu.bmp");
this->DrawBitmap(x + 14 + i * 14, y, &bitmap->image, false);
}
const auto* bitmap = load("유저인터페이스\\sysbox_lu.bmp");
this->DrawBitmap(x, y, &bitmap->image, false);
bitmap = load("유저인터페이스\\sysbox_ru.bmp");
this->DrawBitmap(x + width - bitmap->image.width, y, &bitmap->image, false);
const int innerHeight = height - 28;
const int rows = innerHeight / 14 + (innerHeight % 14 != 0);
for (int i = 0; i < rows; ++i) {
bitmap = load("유저인터페이스\\sysbox_lm.bmp");
this->DrawBitmap(x, y + 14 + i * 14, &bitmap->image, false);
}
for (int i = 0; i < rows; ++i) {
bitmap = load("유저인터페이스\\sysbox_rm.bmp");
this->DrawBitmap(x + width - bitmap->image.width, y + 14 + i * 14, &bitmap->image, false);
}
for (int i = 0; i < columns; ++i) {
bitmap = load("유저인터페이스\\sysbox_md.bmp");
this->DrawBitmap(x + 14 + i * 14, y + height - bitmap->image.height, &bitmap->image, false);
}
bitmap = load("유저인터페이스\\sysbox_ld.bmp");
this->DrawBitmap(x, y + height - bitmap->image.height, &bitmap->image, false);
bitmap = load("유저인터페이스\\sysbox_rd.bmp");
this->DrawBitmap(x + width - bitmap->image.width, y + height - bitmap->image.height, &bitmap->image, false);
unsigned red, green, blue;
SkinPaletteChannels(ResourceMgr::Instance(), 2, 2, red, green, blue);
this->FillRegion(x + 14, y + 14, innerWidth, innerHeight, RGB(red, green, blue));
}
// INLINED
void UIMessageBox::FormatCountdown() {
char text[512];
std::sprintf(text, this->format.c_str(), this->remaining);
this->messageText = text;
}
// INLINED
void UIMessageBox::AddButton(const char* name, int id, int x, int y) {
auto& controls = this->m_dialog->text.buttons;
auto* button = new UIBitmapButton(*this->m_context, controls);
const char* suffixes[] = {"", "_a", "_b"};
for (int state = 0; state < 3; ++state) {
const std::string path = std::string(prefix) + name + suffixes[state] + ".bmp";
button->SetBitmap(path.c_str(), state, 0);
}
button->SetSize(button->BitmapWidth(), button->BitmapHeight());
button->Move(x, y);
button->SetId(id);
this->AddChild(button);
}
// OFFSET: 0x008A7350
// FUNCTION: fn_11713
void UIMessageBox::Configure(
const char* text, int type, bool defaultAccept, int timeout, const char* title, int width, int height, int modalValue, const char* icon
) {
this->caption = title;
this->messageText = text;
this->format = text;
this->started = timeGetTime();
this->deadline = timeGetTime() + static_cast<unsigned>(timeout);
const unsigned interval = this->deadline - this->started;
this->remaining = interval / 1000 + (interval % 1000 != 0);
this->counting = timeout != 0;
if (this->counting != 0) {
this->FormatCountdown();
}
this->modal = modalValue;
this->SetSize(width, height);
this->Slot15(width, height);
this->Slot22(width, height);
this->Move((this->m_dialog->screenWidth - 640) / 2 + 185, (this->m_dialog->screenHeight - 480) / 2 + 180);
int inset = 0;
if (icon) {
auto* image = new UIStaticBitmap(*this->m_context, this->m_dialog->text.buttons);
image->SetBitmap(icon);
image->SetSize(image->geometry.width, image->geometry.height);
image->Move(10, 22);
this->AddChild(image);
inset = image->geometry.width + image->geometry.x;
}
this->viewer = new UITextViewer(*this->m_context, this->m_dialog->text);
this->viewer->Configure(inset + 10, 22, width - inset - 20, height - 55, 0);
this->viewer->backgroundColor = Palette(this->m_dialog->text.buttons.resources, 2, 2) | 0xFF000000u;
this->viewer->Invalidate();
this->AddChild(this->viewer);
this->viewer->SendMsg(nullptr, 29, reinterpret_cast<std::intptr_t>(this->messageText.data()), static_cast<int>(static_cast<double>(width) / 7.5), 0, 0);
this->m_message0 = type == 2 ? 188 : 185;
switch (type) {
case 0:
this->AddButton("btn_ok", 184, width - 46, height - 24);
this->m_message0 = 184;
break;
case 2:
this->AddButton("btn_ok", 187, width - 91, height - 24);
this->AddButton("btn_cancel", 188, width - 46, height - 24);
this->m_message0 = defaultAccept ? 187 : 188;
this->m_message1 = 188;
break;
case 4:
this->AddButton("btn_cancel", 185, width - 46, height - 24);
this->m_message0 = 185;
break;
case 5: {
this->AddButton("btn_ok", 184, width - 46, height - 24);
this->m_message0 = 184;
auto& controls = this->m_dialog->text.buttons;
auto* button = new UITextButton(*this->m_context, controls);
button->Configure(controls.services.MessageText(3445), 0x00F4934A, 0, 12, 0, 0);
button->m_hoverColor = 0x00FF7864;
button->Move(14, 70);
button->SetId(426);
button->SetDisabled(0);
button->Invalidate();
this->AddChild(button);
break;
}
default:
break;
}
}
// OFFSET: 0x008BADC0
// FUNCTION: fn_11791
void UIMessageBox::Slot19() {
if (this->counting == 0) {
return;
}
if (timeGetTime() > this->deadline) {
this->m_dialog->response = 187;
this->counting = 0;
return;
}
const unsigned previous = this->remaining;
const bool fraction = (this->deadline - timeGetTime()) % 1000 != 0;
this->remaining = (this->deadline - timeGetTime()) / 1000 + fraction;
if (previous != this->remaining) {
this->FormatCountdown();
this->viewer->Clear();
this->viewer->SendMsg(nullptr, 29, reinterpret_cast<std::intptr_t>(this->messageText.data()), 38, 0, 0);
}
}
// OFFSET: 0x008BF950
// FUNCTION: fn_11808
int UIMessageBox::SendMsg(UIWindow* sender, int message, std::intptr_t a, std::intptr_t b, std::intptr_t c, std::intptr_t d) {
switch (message) {
case 6:
this->m_dialog->recorder.Record(this->geometry.id, static_cast<int>(a), b, c, d);
if (this->modal != 0) {
this->m_dialog->response = static_cast<int>(a);
} else if (a == 184 || a == 187 || a == 188) {
this->m_dialog->retirement.Schedule(this);
}
return 0;
case 57:
this->viewer->Clear();
this->viewer->SendMsg(nullptr, 29, a, 38, 0, 0);
return 0;
case 67:
this->format = reinterpret_cast<const char*>(a);
return 0;
case 98:
if (a == 426) {
auto& controls = this->m_dialog->text.buttons;
ShellExecuteA(this->m_dialog->text.applicationWindow, "open", controls.services.MessageText(3445), nullptr, nullptr, SW_SHOWNORMAL);
}
return 0;
case 156:
this->modal = static_cast<int>(a);
return 0;
case 157:
this->protectedMessage = a > 0;
return 0;
case 158:
return this->protectedMessage == 1;
default:
return UIFrameWnd::SendMsg(sender, message, a, b, c, d);
}
}
// OFFSET: 0x008BFB70
// FUNCTION: fn_11809
int UIMessageBoxAutoreturn::SendMsg(UIWindow* sender, int message, std::intptr_t a, std::intptr_t b, std::intptr_t c, std::intptr_t d) {
if (message == 6) {
g_windowMgr.unknown_0474 = static_cast<int>(a);
return 0;
}
return UIFrameWnd::SendMsg(sender, message, a, b, c, d);
}
// OFFSET: 0x008BFBA0
// FUNCTION: fn_11810
int UIMonsterInfoWnd::SendMsg(UIWindow* sender, int message, std::intptr_t a, std::intptr_t b, std::intptr_t c, std::intptr_t d) {
switch (message) {
case 6:
if (a == 184) {
g_windowMgr.Schedule(this);
}
return 0;
case 79:
if (a) {
this->info = *reinterpret_cast<const MonsterInfo*>(a);
}
this->Invalidate();
return 0;
default:
return UIFrameWnd::SendMsg(sender, message, a, b, c, d);
}
}
// OFFSET: 0x008C1DB0
// FUNCTION: fn_11817
int UITalkboxTrapInputWnd::SendMsg(UIWindow* sender, int message, std::intptr_t a, std::intptr_t b, std::intptr_t c, std::intptr_t d) {
if (message == 6) {
if (a == 184) {
TalkboxTrapRequest request;
request.target = this->target;
request.text = this->edit->Text();
g_modeMgr.GetGameMode()->SendMsg(131, reinterpret_cast<int>(&request), 0, 0, 0);
} else if (a != 185) {
return 0;
}
g_windowMgr.Schedule(this);
return 0;
}
if (message == 68) {
this->target = *reinterpret_cast<const TalkboxTrapTarget*>(a);
return 0;
}
return UIFrameWnd::SendMsg(sender, message, a, b, c, d);
}
// OFFSET: 0x008C1ED0
// FUNCTION: fn_11818
void UIWindowMgr::SetUnknown04DC(const char* text) {
this->unknown_04DC = text;
}
// OFFSET: 0x008C35A0
// FUNCTION: fn_11824
void UIChatRoomWnd::Slot11() {
if (this->saved) {
this->saved->width = this->geometry.width;
this->saved->height = this->geometry.height;
this->saved->x = this->geometry.x;
this->saved->y = this->geometry.y;
}
}
// OFFSET: 0x008C35E0
// FUNCTION: fn_11825
void UIHomunInfoWnd::Slot11() {
if (this->saved) {
this->saved->x = this->geometry.x;
this->saved->y = this->geometry.y;
this->saved->width = this->geometry.width;
this->saved->height = this->geometry.height;
}
}
// OFFSET: 0x008C3630
// FUNCTION: fn_11827
void UIMerInfoWnd::Slot11() {
if (this->saved) {
this->saved->x = this->geometry.x;
this->saved->y = this->geometry.y;
this->saved->width = this->geometry.width;
this->saved->height = this->geometry.height;
}
}
// OFFSET: 0x008C3670
// FUNCTION: fn_11828
void UIPetInfoWnd::Slot11() {
if (this->saved) {
this->saved->x = this->geometry.x;
this->saved->y = this->geometry.y;
this->saved->width = this->geometry.width;
this->saved->height = this->geometry.height;
}
}
// OFFSET: 0x008C36B0
// FUNCTION: fn_11829
void UIReplayRECControlWnd::Slot11() {
if (this->saved) {
this->saved->width = this->geometry.width;
this->saved->height = this->geometry.height;
this->saved->x = this->geometry.x;
this->saved->y = this->geometry.y;
}
}
// OFFSET: 0x008A6DC0
// FUNCTION: fn_11711
void UIBank_NewWnd::AnimateLoading() {
for (int index = 0; index < 4; ++index) {
this->m_loading[index]->Move(-100, -100);
}
this->m_loading[static_cast<int>(timeGetTime() % 1000) / 250]->Move(6, 5);
}
// OFFSET: 0x008B84B0
// FUNCTION: fn_11764
void UILoginOTPWnd::Paint() {
auto& controls = *this->m_controls;
auto& resources = ResourceMgr::Instance();
const std::uint8_t source[] = {0x11, 0xF4, 0x57, 0x1F, 0xF9, 0x49, 0x2E, 0xE2, 0x17, 0xBF, 0x57, 0x29, 0x84, 0x3D, 0xB7, 0x43,
0xBE, 0x3C, 0xFE, 0x8B, 0x66, 0xEE, 0x85, 0x5B, 0xB4, 0x29, 0xF1, 0x84, 0x5A, 0xE2, 0xB7, 0x4D,
0xB6, 0x04, 0xF9, 0x80, 0x4E, 0xE8, 0x9F, 0x5F, 0xE0, 0x75, 0xF5, 0x88, 0x49, 0x87};
thread_local EncryptedName<sizeof(source), 0x2FEB8739E5975BD1ULL> name(source);
const auto* background = static_cast<CBitmapRes*>(resources.Load(Resolve(name.Text())));
this->DrawBitmap(0, 0, &background->image, false);
this->DrawTitleBar(controls.fonts, controls.locale, true, controls.services.MessageText(3254), 280);
}
// OFFSET: 0x008C3620
// FUNCTION: fn_11826
void UILoginWnd::Slot11() {
this->SaveLogin();
}
// OFFSET: 0x008C39E0
// FUNCTION: fn_11831
void UILoginWnd::SaveLogin() {
HKEY key;
DWORD disposition = 0;
if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, g_subKey, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, &disposition) != ERROR_SUCCESS) {
return;
}
char id[52];
int saveId;
if (this->saveId != 0) {
std::strcpy(id, this->idEdit->Text());
saveId = this->saveId != 0;
id[50] = 0;
} else {
std::memset(id, 0, sizeof(id));
saveId = 0;
}
const std::uint8_t idSource[] = {0x24, 0xFF, 0x95};
thread_local EncryptedName<sizeof(idSource), 0xC517FB932D95BB6DULL> idName(idSource);
RegSetValueExA(key, idName.Text(), 0, REG_SZ, reinterpret_cast<const BYTE*>(id), 51);
const std::uint8_t checkSource[] = {0xE6, 0xD5, 0x28, 0xBA, 0x28, 0x74, 0x36, 0x55, 0xE0, 0x9D};
thread_local EncryptedName<sizeof(checkSource), 0x03772763F96D9DA5ULL> checkName(checkSource);
RegSetValueExA(key, checkName.Text(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&saveId), 4);
int bitwise = 1;
const std::uint8_t bitwiseSource[] = {0xC5, 0x5A, 0x3F, 0x28, 0x70, 0x5A, 0x34, 0x0B};
thread_local EncryptedName<sizeof(bitwiseSource), 0x0B7109397F6B1387ULL> bitwiseName(bitwiseSource);
RegSetValueExA(key, bitwiseName.Text(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&bitwise), 4);
RegCloseKey(key);
}
// OFFSET: 0x008C1F00
// FUNCTION: fn_11819
void UIReplayRECControlWnd::ApplyMode() {
this->Resize(194, 34);
if (this->mode == 0) {
this->window_00C0->Move(-100, -100);
for (int index = 0; index < 5; ++index) {
this->tabs[index]->Move(-100, -100);
}
this->window_00C4->Move(-100, -100);
this->window_0134->Move(-100, -100);
this->button_00D0->Move(-100, -100);
this->window_00EC->Move(-100, -100);
for (int index = 0; index < 10; ++index) {
this->options[index]->Move(-100, -100);
}
this->window_0128->Move(-100, -100);
this->window_012C->Move(-100, -100);
this->window_0134->Move(-100, -100);
this->window_00BC->Move(110, 5);
this->button_00C8->Move(136, 5);
this->button_00C8->SetDisabled(0);
this->button_00C8->Invalidate();
this->button_00D0->Move(162, 5);
this->button_00D0->SetDisabled(0);
this->button_00D0->Invalidate();
this->window_00E8->Move(32, 12);
this->tabs[0]->Move(6, 5);
} else if (this->mode == 1) {
this->recordStart = timeGetTime();
this->window_00BC->Move(-100, -100);
for (int index = 0; index < 4; ++index) {
this->tabs[index]->Move(-100, -100);
}
this->tabs[4]->Move(-100, -100);
this->window_00CC->Move(-100, -100);
this->options[7]->Move(-100, -100);
for (int index = 0; index < 10; ++index) {
this->options[index]->Move(-100, -100);
}
this->window_0128->Move(-100, -100);
this->window_012C->Move(-100, -100);
this->window_00C4->Move(-100, -100);
this->window_0134->Move(-100, -100);
this->window_00C0->Move(110, 5);
this->button_00C8->Move(136, 5);
this->button_00C8->SetDisabled(1);
this->button_00C8->Invalidate();
this->button_00D0->Move(162, 5);
this->button_00D0->SetDisabled(1);
this->button_00D0->Invalidate();
this->window_00E8->Move(32, 12);
this->tabs[0]->Move(6, 5);
} else if (this->mode == 2) {
this->Resize(194, 200);
this->window_00BC->Move(-100, -100);
this->window_00C0->Move(-100, -100);
this->button_00C8->Move(-100, -100);
this->button_00D0->Move(-100, -100);
this->window_00E8->Move(-100, -100);
for (int index = 0; index < 4; ++index) {
this->tabs[index]->Move(-100, -100);
}
this->window_00C4->Move(-100, -100);
this->window_0134->Move(-100, -100);
this->tabs[4]->Move(6, 5);
this->window_00CC->Move(162, 5);
this->window_00EC->Move(42, 12);
this->options[0]->Move(17, 63);
this->options[1]->Move(17, 81);
this->options[2]->Move(17, 99);
this->options[3]->Move(17, 117);
this->options[4]->Move(-100, -100);
this->options[5]->Move(104, 81);
this->options[6]->Move(104, 99);
this->options[7]->Move(104, 117);
this->options[9]->Move(104, 63);
this->window_0128->Move(17, 160);
this->window_012C->Move(17, 178);
} else if (this->mode == 3) {
this->window_00BC->Move(-100, -100);
this->window_00C0->Move(-100, -100);
this->button_00C8->Move(-100, -100);
this->button_00D0->Move(-100, -100);
this->window_00E8->Move(-100, -100);
for (int index = 0; index < 4; ++index) {
this->tabs[index]->Move(-100, -100);
}
this->tabs[4]->Move(-100, -100);
this->window_00CC->Move(-100, -100);
this->options[7]->Move(-100, -100);
for (int index = 0; index < 10; ++index) {
this->options[index]->Move(-100, -100);
}
this->window_0128->Move(-100, -100);
this->window_012C->Move(-100, -100);
this->window_00C4->Move(162, 5);
this->window_0134->Move(7, 8);
this->m_focus->Set(this->window_0134);
}
this->SendMsg(nullptr, 60, 0, 0, 0, 0);
}
// OFFSET: 0x008B9790
// OFFSET: 0x008BB070
// FUNCTION: fn_11793
void UINoticeWnd::Slot35(int delta) {
if (delta < 0) {
this->SendMsg(this->m_scrollBar, 7, 6, 0, 0, 0);
} else {
this->SendMsg(this->m_scrollBar, 7, -6, 0, 0, 0);
}
}
// OFFSET: 0x008B9940
// FUNCTION: fn_11772
void UIPayConfirmWnd::Paint() {
auto& controls = *this->m_controls;
this->DrawTitleBar(controls.fonts, controls.locale, true, this->m_title.c_str(), 0);
this->DrawPanelBackground(17, 0, "");
this->DrawButtonBar(2, 0, 1);
if (this->m_image) {
this->DrawBitmapScaled(158, 27, 56, 75, this->m_image, 0);
}
}
// OFFSET: 0x008B9E90
// FUNCTION: fn_11774
void UIReplayControlWnd::Paint() {
const auto* background = static_cast<CBitmapRes*>(ResourceMgr::Instance().Load(Resolve("유저인터페이스\\replay_interface\\replay_base.bmp")));
this->DrawBitmap(0, 0, &background->image, false);
}
// OFFSET: 0x008B9ED0
// FUNCTION: fn_11775
void UIReplayRECControlWnd::Paint() {
this->ClearSurface(0xFFFF00FF);
DrawFilledRoundedBorder(*this, 0, 0, this->geometry.width, 34, 0xF5B899);
DrawRoundedBorder(*this, 0, 0, this->geometry.width, 34, 0x945A63);
DrawRoundedBorder(*this, 1, 1, this->geometry.width - 2, 32, 0xF7C6AD);
DrawRoundedBorder(*this, 2, 2, this->geometry.width - 4, 30, 0xFFFFFF);
DrawRoundedBorder(*this, 3, 3, this->geometry.width - 6, 28, 0xAD7B84);
if (this->mode == 2) {
DrawFilledRoundedBorder(*this, 0, 34, this->geometry.width, this->geometry.height - 34, 0xDEDEDE);
DrawFilledRoundedBorder(*this, 4, 38, this->geometry.width - 8, 95, 0xFFFFFF);
DrawFilledRoundedBorder(*this, 4, 138, this->geometry.width - 8, 57, 0xFFFFFF);
DrawOutlinedText(*this, 10, 42, LookupMessage(1973), 0, 0x7F3C00, 0xFFFFFF, 0, 12, 1, 0);
DrawOutlinedText(*this, 10, 142, LookupMessage(1974), 0, 0x7F3C00, 0xFFFFFF, 0, 12, 1, 0);
}
}
// OFFSET: 0x008BA010
// FUNCTION: fn_11776
void UISelectReplayDataWnd::Paint() {
auto& controls = *this->m_controls;
this->DrawTitleBar(controls.fonts, controls.locale, true, LookupMessage(2084), 0);
this->DrawPanelBackground(17, 0, "");
this->DrawButtonBar(2, 0, 1);
this->FillRegion(6, 32, 268, 77, 0xFFE7E7E7);
this->DrawTextAt(controls.fonts, controls.locale, 6, 19, LookupMessage(2085), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 6, 112, LookupMessage(2086), 0, 0, 12, 0, 0, 0);
}
// OFFSET: 0x008BA0B0
// FUNCTION: fn_11777
void UISelectServerWnd::Paint() {
auto& controls = *this->m_controls;
const char* title = LookupMessage(2082);
if (g_modeMgr.GetLoginMode()->cursorType == 30) {
title = LookupMessage(2083);
}
this->DrawTitleBar(controls.fonts, controls.locale, true, title, 0);
this->DrawPanelBackground(17, 0, "");
this->DrawButtonBar(2, 0, 1);
}
// OFFSET: 0x008BA110
// FUNCTION: fn_11778
void UITalkboxTrapInputWnd::Paint() {
auto& controls = *this->m_controls;
const int titleHeight = this->DrawTitleBar(controls.fonts, controls.locale, false, "", 0);
this->DrawPanelBackground(titleHeight, 0, "");
this->DrawButtonBar(2, 0, 1);
this->DrawTextAt(controls.fonts, controls.locale, 17, 3, LookupMessage(435), 0, 0, 12, 0xFFFFFF, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 16, 2, LookupMessage(435), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 17, 23, LookupMessage(436), 0, 0, 12, 0xFFFFFF, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 16, 22, LookupMessage(436), 0, 0, 12, 0, 0, 0);
}
// OFFSET: 0x008BA660
// FUNCTION: fn_11787
void UILoginWnd::Slot27(int, int) {
}
// OFFSET: 0x008BADB0
// FUNCTION: fn_11790
void UIMakeCharWnd::Slot19() {
}
// OFFSET: 0x008AD130
// FUNCTION: fn_11734
void UIChatRoomWnd::Move(int x, int y) {
this->geometry.Move(x, y);
this->Slot36();
}
// OFFSET: 0x008B7A60
// FUNCTION: fn_11753
void UILoginOTPWnd::Slot18() {
}
// OFFSET: 0x008B7A70
// FUNCTION: fn_11754
void UILoginWnd::Slot18() {
}
// OFFSET: 0x008B7A80
// FUNCTION: fn_11755
void UIMakeCharWnd::Slot18() {
}
// OFFSET: 0x008B8E90
// FUNCTION: fn_11769
void UIMessageBoxAutoreturn::Paint() {
const auto* background = static_cast<CBitmapRes*>(ResourceMgr::Instance().Load(Resolve("유저인터페이스\\win_msgbox.bmp")));
this->DrawBitmap(0, 0, &background->image, false);
}
// OFFSET: 0x008BA670
// FUNCTION: fn_11788
void UILoginOTPWnd::Slot19() {
auto* login = static_cast<CLoginMode*>(g_modeMgr.GetLoginMode());
if (login == nullptr) {
return;
}
const unsigned remaining = static_cast<unsigned>(60.0 - (timeGetTime() - login->otpStarted) * 0.001);
const std::uint8_t source[] = {0x6A, 0x91, 0xFD, 0x51, 0x43, 0xED, 0x61, 0x5C, 0x7F, 0x93, 0xAB, 0x35};
thread_local EncryptedName<sizeof(source), 0x7941D76335CFA14FULL> format(source);
this->timerText->SetText(FormatOwnedString(format.Text(), remaining / 60, remaining % 60).c_str(), 0);
this->Invalidate();
}
// OFFSET: 0x008BAEF0
// FUNCTION: fn_11792
void UIMessageBoxAutoreturn::Slot19() {
if (this->counting == 0) {
return;
}
if (timeGetTime() > this->deadline) {
g_windowMgr.unknown_0474 = 187;
this->counting = 0;
return;
}
const unsigned previous = this->remaining;
const bool fraction = (this->deadline - timeGetTime()) % 1000 != 0;
this->remaining = (this->deadline - timeGetTime()) / 1000 + fraction;
if (previous != this->remaining) {
char text[512];
std::sprintf(text, this->format.c_str(), this->remaining);
this->messageText = text;
this->viewer->Clear();
this->viewer->SendMsg(nullptr, 29, reinterpret_cast<std::intptr_t>(this->messageText.data()), 38, 0, 0);
}
const unsigned duration = this->seconds * 1000;
const unsigned progress = (timeGetTime() + (duration - this->deadline)) * 100 / duration;
this->gauge->SetValue(static_cast<float>(progress));
}
// OFFSET: 0x008AAA10
// FUNCTION: fn_11724
void UIMonsterInfoWnd::DrawResistance(int x, int y, const char* label, int value, std::uint32_t border, std::uint32_t fill) {
auto& controls = *this->m_controls;
char text[64];
wsprintfA(text, "%s:%d", label, value);
unsigned red;
unsigned green;
unsigned blue;
SkinPaletteChannels(ResourceMgr::Instance(), 22, 2, red, green, blue);
this->FillRegion(x, y, 70, 16, border);
this->FillRegion(x + 1, y + 1, 68, 14, fill);
const int width = this->TextWidth(controls.fonts, controls.locale, text, 0, 0, 12, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, (70 - width) / 2 + x, y + 2, text, 0, 0, 12, RGB(red, blue, green), 0, 0);
}
// OFFSET: 0x008B8ED0
// FUNCTION: fn_11770
void UIMonsterInfoWnd::Paint() {
auto& controls = *this->m_controls;
unsigned red;
unsigned green;
unsigned blue;
SkinPaletteChannels(ResourceMgr::Instance(), 2, 2, red, green, blue);
const std::uint32_t fill = RGB(red, green, blue);
this->ClearSurface(fill);
this->DrawPanelBackground(this->DrawTitleBar(controls.fonts, controls.locale, false, "", 0), 0, "");
this->DrawButtonBar(2, 0, 1);
SkinPaletteChannels(ResourceMgr::Instance(), 22, 2, red, green, blue);
const std::uint32_t border = RGB(red, green, blue);
this->DrawTextAt(controls.fonts, controls.locale, 17, 3, LookupMessage(406), 0, 0, 12, 0xFFFFFF, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 16, 2, LookupMessage(406), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 120, 30, LookupMessage(407), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 160, 30, this->name.c_str(), 0, 0, 12, 0, 0, 0);
char text[256];
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "%d", this->info.level);
this->DrawTextAt(controls.fonts, controls.locale, 120, 50, LookupMessage(408), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 160, 50, text, 0, 0, 12, 0, 0, 0);
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "%d", this->info.hp);
this->DrawTextAt(controls.fonts, controls.locale, 120, 70, LookupMessage(409), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 160, 70, text, 0, 0, 12, 0, 0, 0);
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "%d", this->info.defense);
this->DrawTextAt(controls.fonts, controls.locale, 120, 90, LookupMessage(3910), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 160, 90, text, 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 260, 30, LookupMessage(410), 0, 0, 12, 0, 0, 0);
int message;
switch (this->info.size) {
case 0:
message = 3907;
break;
case 1:
message = 3908;
break;
case 2:
message = 3909;
break;
default:
message = 0;
break;
}
if (message != 0) {
this->DrawTextAt(controls.fonts, controls.locale, 300, 30, LookupMessage(message), 0, 0, 12, 0, 0, 0);
}
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "%d", this->info.race);
this->DrawTextAt(controls.fonts, controls.locale, 260, 50, LookupMessage(411), 0, 0, 12, 0, 0, 0);
if (static_cast<unsigned short>(this->info.race) <= 9) {
this->DrawTextAt(controls.fonts, controls.locale, 300, 50, LookupMessage(3887 + static_cast<unsigned short>(this->info.race)), 0, 0, 12, 0, 0, 0);
}
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "%d", this->info.magicDefense);
this->DrawTextAt(controls.fonts, controls.locale, 260, 90, LookupMessage(412), 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 300, 90, text, 0, 0, 12, 0, 0, 0);
this->DrawTextAt(controls.fonts, controls.locale, 260, 70, LookupMessage(413), 0, 0, 12, 0, 0, 0);
const int element = this->info.element % 20;
if (element >= 0 && element <= 9) {
this->DrawTextAt(controls.fonts, controls.locale, 300, 70, LookupMessage(3897 + element), 0, 0, 12, 0, 0, 0);
}
this->DrawResistance(120, 110, LookupMessage(3898), this->info.resistances[0], border, fill);
this->DrawResistance(120, 128, LookupMessage(3899), this->info.resistances[1], border, fill);
this->DrawResistance(120, 146, LookupMessage(3900), this->info.resistances[2], border, fill);
this->DrawResistance(200, 110, LookupMessage(3901), this->info.resistances[3], border, fill);
this->DrawResistance(200, 128, LookupMessage(3902), this->info.resistances[4], border, fill);
this->DrawResistance(200, 146, LookupMessage(3903), this->info.resistances[5], border, fill);
this->DrawResistance(280, 110, LookupMessage(3904), this->info.resistances[6], border, fill);
this->DrawResistance(280, 128, LookupMessage(3905), this->info.resistances[7], border, fill);
this->DrawResistance(280, 146, LookupMessage(3906), this->info.resistances[8], border, fill);
char spriteName[128];
StringFormat(spriteName, sizeof(spriteName), static_cast<std::size_t>(-1), "몬스터\\%s.spr", g_session.GetJobName(this->info.job, -1));
char actionName[128];
StringFormat(actionName, sizeof(actionName), static_cast<std::size_t>(-1), "몬스터\\%s.act", g_session.GetJobName(this->info.job, -1));
if (ResourceMgr::Instance().Exists(actionName) && ResourceMgr::Instance().Exists(spriteName)) {
auto* action = static_cast<CActRes*>(ResourceMgr::Instance().Load(actionName));
auto* sprite = static_cast<CSprRes*>(ResourceMgr::Instance().Load(spriteName));
this->DrawActionSprite(sprite, action, 2, 19, 116, 152, 0, true, nullptr);
}
}
// OFFSET: 0x008C3440
// FUNCTION: fn_11823
void UIReplayRECControlWnd::UpdateRecordTime() {
for (int index = 0; index < 4; ++index) {
this->tabs[index]->Move(-100, -100);
}
this->tabs[timeGetTime() % 1000 / 250]->Move(6, 5);
if (timeGetTime() - this->recordStart <= 200) {
return;
}
const int seconds = static_cast<int>(timeGetTime() - Replay::Instance().started) / 1000;
const int minutes = seconds / 60;
const int hours = minutes / 60;
if (hours == 100) {
this->window_00E8->Move(124, 47);
} else if (hours == 1000) {
this->window_00E8->Move(116, 47);
}
char text[100] = {};
std::sprintf(text, "%03d:%02d:%02d", hours, minutes % 60, seconds % 60);
this->window_00E8->SetTextFitted(text);
this->Invalidate();
this->InvalidateChildren();
this->recordStart = timeGetTime();
}
// OFFSET: 0x008BA820
// FUNCTION: fn_11789
void UILoginWnd::Slot19() {
if (g_windowMgr.GetHoverWindow() == this->idEdit) {
this->idEdit->TextColor(RGB(0, 0, 0), 0xFFFFFFFF);
if (this->idPlaceholder == true) {
const std::uint8_t source[] = {0xA4, 0x31, 0x61};
thread_local EncryptedName<sizeof(source), 0x2D51E3B7236175EDULL> placeholder(source);
if (std::strcmp(placeholder.Text(), this->idEdit->Text()) == 0) {
this->idEdit->SetText("");
goto password;
}
}
this->idPlaceholder = false;
} else {
if (std::strcmp("", this->idEdit->Text()) == 0) {
this->idEdit->TextColor(RGB(156, 156, 156), 0xFFFFFFFF);
this->idPlaceholder = true;
const std::uint8_t source[] = {0x5E, 0x5F, 0x2D};
thread_local EncryptedName<sizeof(source), 0x0F41EBBDA32D1B17ULL> placeholder(source);
this->idEdit->SetText(placeholder.Text());
}
if (this->idPlaceholder == false) {
this->idEdit->TextColor(RGB(0, 0, 0), 0xFFFFFFFF);
}
}
password:
if (g_windowMgr.GetHoverWindow() == this->passwordEdit) {
HIMC context = ImmGetContext(hWnd);
DWORD conversion;
DWORD sentence;
ImmGetConversionStatus(context, &conversion, &sentence);
conversion &= ~(IME_CMODE_NATIVE | IME_CMODE_KATAKANA);
ImmSetConversionStatus(context, IME_CMODE_ALPHANUMERIC, sentence);
ImmReleaseContext(hWnd, context);
this->passwordEdit->TextColor(RGB(0, 0, 0), 0xFFFFFFFF);
if (this->passwordPlaceholder == true) {
const std::uint8_t source[] = {0x99, 0x52, 0xAA, 0x20, 0xAE, 0x96, 0x47, 0x35, 0xC9};
thread_local EncryptedName<sizeof(source), 0x7115D9F973F913C9ULL> placeholder(source);
if (std::strcmp(placeholder.Text(), this->passwordEdit->Text()) == 0) {
this->passwordEdit->SetText("");
this->passwordEdit->mask = 0;
return;
}
}
this->passwordPlaceholder = false;
} else {
if (std::strcmp("", this->passwordEdit->Text()) == 0) {
this->passwordPlaceholder = true;
this->passwordEdit->TextColor(RGB(156, 156, 156), 0xFFFFFFFF);
const std::uint8_t source[] = {0x33, 0xB4, 0xB2, 0x2C, 0x6C, 0x6A, 0x4F, 0x8F, 0x63};
thread_local EncryptedName<sizeof(source), 0xCB1D253B7FE1F563ULL> placeholder(source);
this->passwordEdit->SetText(placeholder.Text());
this->passwordEdit->mask = 0;
}
if (this->passwordPlaceholder != false) {
return;
}
this->passwordEdit->TextColor(RGB(0, 0, 0), 0xFFFFFFFF);
}
this->passwordEdit->mask = '*';
}
// OFFSET: 0x008C36F0
// FUNCTION: fn_11830
void UIChatRoomWnd::SaveChatLog() {
int index = 0;
char path[2048];
std::sprintf(path, "%s\\Chat", g_applicationDirectory);
if (_access(path, 0) != 0 && _mkdir(path) != 0) {
return;
}
std::string name = this->title;
for (unsigned position = 0; position < name.size(); ++position) {
const char character = name[position];
if (character == '\\' || character == '/' || character == ':' || character == '*' || character == '?' || character == '"' || character == '<' ||
character == '>' || character == '|') {
name[position] = '_';
}
}
std::sprintf(path, "%s\\Chat\\%s.txt", g_applicationDirectory, name.c_str());
while (_access(path, 0) == 0) {
++index;
std::sprintf(path, "%s\\Chat\\%s%03d.txt", g_applicationDirectory, name.c_str(), index);
}
if (this->history->SaveChatLog(path)) {
std::string message = path;
message.append(" is Saved.", 10);
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message.c_str()), 0xFF00, 0, 0, 0);
}
}
// OFFSET: 0x008ABDB0
// FUNCTION: fn_11728
void UILoginWnd::LoadLogin() {
HKEY probe;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, g_subKey, 0, KEY_QUERY_VALUE, &probe) != ERROR_SUCCESS) {
this->idEdit->SetText("");
this->passwordEdit->SetText("");
return;
}
RegCloseKey(probe);
HKEY key;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, g_subKey, 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
return;
}
DWORD type = REG_DWORD;
DWORD size = 4;
int saveId;
const std::uint8_t checkSource[] = {0xB2, 0x8F, 0x7C, 0x4A, 0x5C, 0x2A, 0x0E, 0xA7, 0xB4, 0xC7};
thread_local EncryptedName<sizeof(checkSource), 0xF14F79170939C7F1ULL> checkName(checkSource);
RegQueryValueExA(key, checkName.Text(), nullptr, &type, reinterpret_cast<BYTE*>(&saveId), &size);
saveId = saveId == 1;
int bitwise;
const std::uint8_t bitwiseSource[] = {0xDD, 0x8C, 0x39, 0xFC, 0x9E, 0x7A, 0xB8, 0xA5};
thread_local EncryptedName<sizeof(bitwiseSource), 0xA5FD29D7AB6DC59FULL> bitwiseName(bitwiseSource);
RegQueryValueExA(key, bitwiseName.Text(), nullptr, &type, reinterpret_cast<BYTE*>(&bitwise), &size);
char id[52];
std::memset(id, 0, sizeof(id));
char password[26] = {};
type = REG_SZ;
size = 25;
const std::uint8_t passwordSource[] = {0xB1, 0x3A, 0xAA, 0x84, 0x82, 0x5C, 0x6B, 0x99, 0xE1};
thread_local EncryptedName<sizeof(passwordSource), 0xDD3913D5D7F97BE1ULL> passwordName(passwordSource);
RegQueryValueExA(key, passwordName.Text(), nullptr, &type, reinterpret_cast<BYTE*>(password), &size);
password[24] = 0;
type = REG_SZ;
size = 51;
const std::uint8_t idSource[] = {0xD2, 0x13, 0x03};
thread_local EncryptedName<sizeof(idSource), 0x050505679903579BULL> idName(idSource);
RegQueryValueExA(key, idName.Text(), nullptr, &type, reinterpret_cast<BYTE*>(id), &size);
id[50] = 0;
password[24] = 0;
this->saveId = saveId;
if (saveId != 0) {
unsigned char shade;
bool placeholder = std::strcmp("", id) == 0;
if (!placeholder) {
const std::uint8_t compareSource[] = {0xF4, 0xF9, 0xED};
thread_local EncryptedName<sizeof(compareSource), 0x83EFBFBB37EDBDBDULL> compareName(compareSource);
placeholder = std::strcmp(compareName.Text(), id) == 0;
}
if (placeholder) {
this->idPlaceholder = true;
const std::uint8_t textSource[] = {0xEE, 0xB1, 0x7F};
thread_local EncryptedName<sizeof(textSource), 0xBF2B4B31397FF5A7ULL> textName(textSource);
this->idEdit->SetText(textName.Text());
shade = 156;
} else {
shade = 0;
this->idPlaceholder = false;
}
this->idEdit->TextColor(RGB(shade, shade, shade), 0xFFFFFFFF);
this->idEdit->SetText(id);
this->passwordEdit->SetText("");
}
RegCloseKey(key);
}