diff --git a/Source/UI/UIRefiningWnd.cpp b/Source/UI/UIRefiningWnd.cpp index f7a7f0c7..248e0083 100644 --- a/Source/UI/UIRefiningWnd.cpp +++ b/Source/UI/UIRefiningWnd.cpp @@ -4,13 +4,19 @@ #include "Client/Mode/CMode.h" #include "Client/Mode/ModeDragState.h" #include "Client/Mode/ModeMgr.h" +#include "Client/Session.h" +#include "Contents/Sound/SoundMgr.h" #include "Contents/Items/ItemDescription.h" #include "Contents/MessageTable.h" #include "UI/Window/UIWindowMgr.h" +#include "Utility/Text/FormatString.h" #include #include +#include +#include + // OFFSET: 0x007F5270 // FUNCTION: fn_09902 void UIRefiningWnd::Slot10(int x, int y, std::intptr_t value) { @@ -22,6 +28,39 @@ void UIRefiningWnd::Slot10(int x, int y, std::intptr_t value) { } // OFFSET: 0x007F52D0 +// FUNCTION: fn_09903 +__declspec(noinline) void UIRefiningWnd::Reset() { + this->unknown_01F0 = 0; + this->item = ITEM_INFO(0); + this->selectedMaterial = -1; + this->materials.clear(); + this->catalystEnabled = 0; + this->catalystCount = 0; + this->notice->SetNotice("", 0, 0); + + this->refiningButton->cost = 0; + this->refiningButton->Invalidate(); + this->refiningButton->SetDisabled(1); + this->refiningButton->Invalidate(); + + this->state = 0; + this->result = 7; + this->stateTick = timeGetTime(); + this->frame = 0; + if (this->unknown_00C0) { + this->unknown_00C0->SetDisabled(0); + this->unknown_00C0->Invalidate(); + } + + this->result = 7; + this->refiningButton->Enable(1); + this->refiningButton->SetDisabled(1); + this->refiningButton->Invalidate(); + this->returnButton->Enable(0); + this->againButton->Enable(0); + this->Invalidate(); + this->Invalidate(); +} // OFFSET: 0x007F54B0 // FUNCTION: fn_09904 @@ -47,6 +86,143 @@ int UIRefiningWnd::SlotAt(int x, int y) { return index; } +// OFFSET: 0x007F55A0 +// FUNCTION: fn_09906 +void UIRefiningWnd::ApplyResult() { + this->notice->SetNotice("", 0, 0); + this->item = this->nextItem; + this->refiningButton->Enable(0); + this->returnButton->Enable(1); + this->againButton->Enable(1); + + switch (this->result) { + case 3: + this->returnButton->highlighted = 1; + this->returnButton->UpdateBitmaps(); + this->againButton->success = 1; + this->againButton->UpdateBitmaps(); + break; + case 4: + this->returnButton->highlighted = 0; + this->returnButton->UpdateBitmaps(); + this->againButton->success = 0; + this->againButton->UpdateBitmaps(); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + break; + case 5: + case 6: + this->returnButton->highlighted = 0; + this->returnButton->UpdateBitmaps(); + this->againButton->success = 0; + this->againButton->UpdateBitmaps(); + break; + } + + int nextIndex = 0; + for (auto it = this->nextMaterials.begin(); it != this->nextMaterials.end(); ++it) { + if (this->materials[this->selectedMaterial].itemId == it->itemId) { + break; + } + ++nextIndex; + } + + if (g_session.m_zeny < static_cast(this->SelectedMaterialValue())) { + this->notice->SetNotice(LookupMessage(3244), 5000, 1); + this->againButton->SetDisabled(1); + } else { + this->againButton->cost = this->SelectedMaterialValue(); + } + this->againButton->Invalidate(); + + this->catalystCount = this->nextCatalystCount; + if (this->catalystEnabled == 1) { + if (this->nextCatalystCount == 0) { + this->catalystEnabled = 0; + this->notice->SetNotice(LookupMessage(3242), 5000, 1); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + } else { + this->notice->SetNotice(LookupMessage(2967), 0, 0); + const int owned = LookupClientItem(g_session.m_inventoryItems, this->catalystItemId, 0).quantity; + if (this->catalystCount > owned) { + this->catalystEnabled = 0; + this->notice->SetNotice(LookupMessage(3245), 5000, 1); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + } + } + } + + const std::size_t count = this->nextMaterials.size(); + if (count == 0) { + this->materials.clear(); + this->selectedMaterial = -1; + this->notice->SetNotice(LookupMessage(2970), 5000, 1); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + } else { + bool same = true; + if (this->materials.size() == count) { + for (auto it = this->materials.begin(); it != this->materials.end(); ++it) { + auto found = this->nextMaterials.begin(); + for (; found != this->nextMaterials.end(); ++found) { + if (it->itemId == found->itemId) { + break; + } + } + if (found == this->nextMaterials.end()) { + same = false; + break; + } + } + } else { + same = false; + } + + this->materials.assign(this->nextMaterials.begin(), this->nextMaterials.end()); + + unsigned char level = 0; + if (this->item.unknown_0000[1] != 0 && !this->materials.empty() && this->selectedMaterial >= 0 && + static_cast(this->selectedMaterial) < this->materials.size()) { + level = this->materials[this->selectedMaterial].unknown_0004; + } + this->againButton->unknown_0125 = level; + this->againButton->Invalidate(); + + if (same) { + if (this->selectedMaterial >= 0 && static_cast(this->selectedMaterial) < this->materials.size()) { + this->selectedMaterial = nextIndex; + const std::uint32_t itemId = this->materials[nextIndex].itemId; + + ITEM_INFO info; + char name[260]; + std::memset(name, 0, sizeof(name)); + info.SetItemId(itemId); + int capacity = 260; + ItemDescriptions descriptions{g_itemDescriptions}; + descriptions.Name(info, name, capacity, 0); + this->againButton->SetTooltip(name); + + const ITEM_INFO owned = LookupClientItem(g_session.m_inventoryItems, itemId, 0); + if (owned.quantity == 0) { + this->notice->SetNotice(LookupMessage(3243), 5000, 1); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + } + } + } else { + this->selectedMaterial = -1; + this->notice->SetNotice(LookupMessage(3242), 5000, 1); + this->againButton->SetDisabled(1); + this->againButton->Invalidate(); + } + } + + this->unknown_01F0 = 0; + this->Invalidate(); +} + // OFFSET: 0x007F7030 // FUNCTION: fn_09911 void UIRefining_BtnReturn::Paint() { @@ -82,6 +258,161 @@ void UIRefiningWnd::Slot25(int x, int y) { } } +// OFFSET: 0x007F7340 +// FUNCTION: fn_09915 +void UIRefiningWnd::Slot31(int x, int y) { + if (y < 17) { + UIFrameWnd::Slot31(x, y); + return; + } + + if (this->state != 1) { + return; + } + + const int slot = this->SlotAt(x, y); + if (slot < 0) { + return; + } + + if (static_cast(slot) < this->materials.size()) { + const int owned = LookupClientItem(g_session.m_inventoryItems, this->materials[slot].itemId, 0).quantity; + if (owned < 1) { + return; + } + + this->selectedMaterial = slot; + this->refiningButton->cost = this->SelectedMaterialValue(); + this->refiningButton->Invalidate(); + + if (this->materials[slot].unknown_0004 <= 99 && this->catalystEnabled == 0) { + int message; + switch (this->materials[slot].itemId) { + case 6223: + case 6224: + message = 2990; + break; + case 6225: + case 6226: + case 6240: + case 6241: + case 6327: + case 6906: + case 6910: + case 6911: + case 1000331: + case 1000332: + case 1000333: + case 1000334: + message = 2989; + break; + case 984: + case 985: + case 1010: + case 1011: + case 7619: + case 7620: + case 1000335: + case 1000336: + case 1000368: + case 1000369: + case 1000370: + case 1000371: + message = 2988; + break; + default: + this->Invalidate(); + return; + } + this->notice->SetNotice(LookupMessage(message), 0, 0); + } + } else { + if (slot != 4 || this->catalystCount < 1) { + return; + } + + const int owned = LookupClientItem(g_session.m_inventoryItems, this->catalystItemId, 0).quantity; + if (owned < this->catalystCount) { + this->notice->SetNotice(LookupMessage(2969), 3000, 1); + } else if (this->catalystEnabled == 1) { + this->catalystEnabled = 0; + this->notice->SetNotice("", 0, 0); + } else { + this->catalystEnabled = 1; + this->notice->SetNotice(LookupMessage(2967), 0, 0); + } + } + + this->Invalidate(); +} + +// OFFSET: 0x007F7AA0 +// FUNCTION: fn_09917 +void UIRefiningWnd::Slot19() { + if (this->notice) { + this->notice->Slot19(); + } + + if (this->state == 1 && this->refiningButton->Disabled() == 1 && this->item.unknown_0000[1] != 0 && this->selectedMaterial >= 0 && + static_cast(this->selectedMaterial) < this->materials.size()) { + this->refiningButton->SetDisabled(0); + this->refiningButton->Invalidate(); + this->refiningButton->cost = this->SelectedMaterialValue(); + this->refiningButton->Invalidate(); + this->Invalidate(); + } + + const int frameCounts[7] = {4, 3, 14, 17, 20, 20, 20}; + if (this->frame >= frameCounts[this->state]) { + return; + } + if (timeGetTime() <= this->stateTick + this->frameInterval) { + return; + } + + ++this->frame; + if (this->state == 2) { + if (this->frame == 7) { + g_soundMgr->PlayWave("effect\\refine\\bs_refine_1.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); + } + if (this->frame == 12) { + g_soundMgr->PlayWave("effect\\refine\\bs_refine_2.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); + } + } + + if (this->frame >= frameCounts[this->state]) { + switch (this->state) { + case 0: + this->frame = 0; + break; + case 3: + this->frame = 13; + break; + case 4: + case 5: + case 6: + this->frame = 18; + break; + default: + this->frame = frameCounts[this->state] - 1; + if (this->state == 2) { + if (this->result == 3) { + g_soundMgr->PlayWave("effect\\refine\\bs_refine_success.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); + } else if (this->result == 4 || this->result == 5 || this->result == 6) { + g_soundMgr->PlayWave("effect\\refine\\bs_refine_failed.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); + } + this->ApplyResult(); + this->SetState(this->result, 7); + return; + } + break; + } + } + + this->stateTick = timeGetTime(); + this->Invalidate(); +} + // OFFSET: 0x007F7D80 // FUNCTION: fn_09918 void UIRefining_Notice::Slot19() { @@ -105,6 +436,38 @@ void UIRefining_Notice::Slot19() { void UIRefiningWnd::Slot32(int x, int y) { } +// OFFSET: 0x007F80C0 +// FUNCTION: fn_09921 +void UIRefining_BtnAgain::UpdateBitmaps() { + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_again_%s_normal.bmp", this->success == 1 ? "success" : "fail").c_str(), 0, 0 + ); + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_again_%s_normal.bmp", this->success == 1 ? "success" : "fail").c_str(), 1, 0 + ); + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_again_%s_press.bmp", this->success == 1 ? "success" : "fail").c_str(), 2, 0 + ); + this->Resize(this->m_bitmapWidth, this->m_bitmapHeight); + this->Invalidate(); +} + +// OFFSET: 0x007F8210 +// FUNCTION: fn_09922 +void UIRefining_BtnReturn::UpdateBitmaps() { + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_return_%s_normal.bmp", this->highlighted == 1 ? "success" : "fail").c_str(), 0, 0 + ); + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_return_%s_normal.bmp", this->highlighted == 1 ? "success" : "fail").c_str(), 1, 0 + ); + this->SetBitmap( + FormatOwnedString("유저인터페이스\\refining_renewal\\bt_refining_return_%s_press.bmp", this->highlighted == 1 ? "success" : "fail").c_str(), 2, 0 + ); + this->Resize(this->m_bitmapWidth, this->m_bitmapHeight); + this->Invalidate(); +} + // OFFSET: 0x007F8C40 // FUNCTION: fn_09925 void UIRefining_BtnAgain::Enable(unsigned char value) { @@ -129,6 +492,55 @@ void UIRefining_BtnRefining::Enable(unsigned char value) { this->geometry.visible = value; } +// OFFSET: 0x007F8CC0 +// FUNCTION: fn_09927 +void UIRefiningWnd::SetState(int state, int result) { + this->state = state; + this->result = result; + this->stateTick = timeGetTime(); + this->frame = 0; + if (this->unknown_00C0) { + this->unknown_00C0->SetDisabled(0); + this->unknown_00C0->Invalidate(); + } + + switch (state) { + case 0: + case 1: + this->result = 7; + this->refiningButton->Enable(1); + this->refiningButton->SetDisabled(1); + this->refiningButton->Invalidate(); + this->returnButton->Enable(0); + this->againButton->Enable(0); + this->Invalidate(); + return; + case 2: + this->refiningButton->Enable(1); + this->refiningButton->SetDisabled(1); + this->refiningButton->Invalidate(); + this->returnButton->Enable(0); + this->againButton->Enable(0); + if (this->unknown_00C0) { + this->unknown_00C0->SetDisabled(1); + this->unknown_00C0->Invalidate(); + } + break; + case 3: + g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(498)), 0xFFFF00, 0, 0, 0); + break; + case 4: + case 6: + g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(499)), 0xFFFF00, 0, 0, 0); + break; + case 5: + g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1537)), 0xFFFF00, 0, 0, 0); + break; + } + + this->Invalidate(); +} + // OFFSET: 0x007F8EA0 // FUNCTION: fn_09928 void UIRefining_Notice::SetNotice(const char* value, int duration, unsigned char highlight) { diff --git a/Source/UI/UIRefiningWnd.h b/Source/UI/UIRefiningWnd.h index a74d9ada..d6b44a33 100644 --- a/Source/UI/UIRefiningWnd.h +++ b/Source/UI/UIRefiningWnd.h @@ -12,8 +12,8 @@ #pragma pack(push, 1) struct RefiningMaterial { - /* 0000 */ unsigned char unknown_0000; - /* 0001 */ std::uint32_t unknown_0001; + /* 0000 */ std::uint32_t itemId; + /* 0004 */ unsigned char unknown_0004; /* 0005 */ std::uint32_t unknown_0005; }; #pragma pack(pop) @@ -25,9 +25,10 @@ static_assert(sizeof(RefiningMaterial) == 9); class UIRefining_BtnAgain : public UIBitmapButton { public: void Enable(unsigned char value) override; + void UpdateBitmaps(); - /* 0120 */ int unknown_0120; - /* 0124 */ unsigned char unknown_0124; + /* 0120 */ int cost; + /* 0124 */ unsigned char success; /* 0125 */ unsigned char unknown_0125; }; @@ -41,6 +42,7 @@ public: class UIRefining_BtnReturn : public UIBitmapButton { public: void Paint() override; + void UpdateBitmaps(); /* 0120 */ unsigned char highlighted; }; @@ -60,33 +62,37 @@ public: class UIRefiningWnd : public UIFrameWnd { public: void Slot10(int x, int y, std::intptr_t value) override; + void Slot19() override; void Slot25(int x, int y) override; void Slot26(int x, int y) override; + void Slot31(int x, int y) override; void Slot32(int x, int y) override; int SlotAt(int x, int y); void Reset(); std::uint32_t SelectedMaterialValue(); + void ApplyResult(); + void SetState(int state, int result); - /* 00B4 */ UIRefining_BtnAgain* againButton; - /* 00B8 */ UIRefining_BtnRefining* refiningButton; - /* 00BC */ UIRefining_BtnReturn* returnButton; + /* 00B4 */ UIRefining_BtnRefining* refiningButton; + /* 00B8 */ UIRefining_BtnReturn* returnButton; + /* 00BC */ UIRefining_BtnAgain* againButton; /* 00C0 */ UIButton* unknown_00C0; /* 00C4 */ UIRefining_Notice* notice; /* 00C8 */ int state; - /* 00CC */ int unknown_00CC; - /* 00D0 */ int unknown_00D0; + /* 00CC */ int result; + /* 00D0 */ int frameInterval; /* 00D4 */ std::uint32_t stateTick; - /* 00D8 */ int unknown_00D8; + /* 00D8 */ int frame; /* 00DC */ int selectedMaterial; /* 00E0 */ std::vector materials; - /* 00EC */ unsigned char unknown_00EC; - /* 00F0 */ int unknown_00F0; - /* 00F4 */ int unknown_00F4; + /* 00EC */ unsigned char catalystEnabled; + /* 00F0 */ int catalystItemId; + /* 00F4 */ int catalystCount; /* 00F8 */ ITEM_INFO item; /* 01F0 */ unsigned char unknown_01F0; - /* 01F4 */ std::vector unknown_01F4; - /* 0200 */ int unknown_0200; - /* 0208 */ ITEM_INFO unknown_0208; + /* 01F4 */ std::vector nextMaterials; + /* 0200 */ int nextCatalystCount; + /* 0208 */ ITEM_INFO nextItem; }; #endif