Files
Client/Server/ToolProject/ItemUpgradeSimulator/ItemUpgradeSimulatorDlg.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

475 lines
16 KiB
C++

// ItemUpgradeSimulatorDlg.cpp : 구현 파일
//
#include "stdafx.h"
#include "ItemUpgradeSimulator.h"
#include "ItemUpgradeSimulatorDlg.h"
#include <Item/Item.h>
#include <Item/ItemMgr.h>
#include <Item/ItemFactory.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CItemUpgradeSimulatorDlg 대화 상자
CItemUpgradeSimulatorDlg::CItemUpgradeSimulatorDlg(CWnd* pParent /*=NULL*/)
: CDialog(CItemUpgradeSimulatorDlg::IDD, pParent)
, m_szItemName(_T(""))
, m_nGemType(0)
, m_nMineralType(0)
{
m_simData.m_dwUsedMoney = 0LL;
m_simData.m_dwSacrificeItem = 0L;
m_simData.m_dwUsedMineral = 0L;
memset(m_simData.m_dwSucceededUpgrade, 0, sizeof(m_simData.m_dwSucceededUpgrade));
memset(m_simData.m_dwFailedUpgrade, 0, sizeof(m_simData.m_dwFailedUpgrade));
memset(m_simData.m_dwUsedGems, 0, sizeof(m_simData.m_dwUsedGems));
m_simData.m_usPrototypeID = 0;
m_simData.m_lpMineral = 0;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CItemUpgradeSimulatorDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_ITEM_SACRIFICE, m_simData.m_dwSacrificeItem);
DDX_Text(pDX, IDC_TOTAL_MINERAL, m_simData.m_dwUsedMineral);
DDX_Text(pDX, IDC_TOTAL_USEDMONEY, m_simData.m_dwUsedMoney);
DDX_Text(pDX, IDC_ITEMNAME, m_szItemName);
DDX_Radio(pDX, IDC_MINERAL_SILVIN, m_nMineralType);
DDX_Radio(pDX, IDC_GEM_RUBY, m_nGemType);
DDX_Control(pDX, IDC_CURRENT_ITEM, m_ResultList);
DDX_Control(pDX, IDC_GEM_USED, m_GemUsedList);
DDX_Control(pDX, IDC_UPGRADE_LOG, m_UpgradeResultList);
}
BEGIN_MESSAGE_MAP(CItemUpgradeSimulatorDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_START, OnBnClickedStart)
END_MESSAGE_MAP()
// CItemUpgradeSimulatorDlg 메시지 처리기
BOOL CItemUpgradeSimulatorDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.
// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
// 프레임워크가 이 작업을 자동으로 수행합니다.
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
// TODO: 여기에 추가 초기화 작업을 추가합니다.
m_ResultList.InsertColumn(0, _T(""), LVCFMT_LEFT, 80);
m_ResultList.InsertColumn(1, _T(""), LVCFMT_LEFT, 150);
m_GemUsedList.InsertColumn(0, _T(""), LVCFMT_LEFT, 80);
m_GemUsedList.InsertColumn(1, _T(""), LVCFMT_LEFT, 50);
m_UpgradeResultList.InsertColumn(0, _T(""), LVCFMT_LEFT, 50);
m_UpgradeResultList.InsertColumn(1, _T(""), LVCFMT_LEFT, 120);
return TRUE; // 컨트롤에 대한 포커스를 설정하지 않을 경우 TRUE를 반환합니다.
}
void CItemUpgradeSimulatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CDialog::OnSysCommand(nID, lParam);
}
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
// 프레임워크에서 이 작업을 자동으로 수행합니다.
void CItemUpgradeSimulatorDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 아이콘을 그립니다.
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
// 이 함수를 호출합니다.
HCURSOR CItemUpgradeSimulatorDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
const TCHAR* GradeToString(Item::EquipType::Grade eGrade)
{
const TCHAR* szGradeString = _T("Unknown");
switch(eGrade)
{
case Item::EquipType::AAA_GRADE: szGradeString = _T("AAA"); break;
case Item::EquipType::AA_GRADE: szGradeString = _T("AA"); break;
case Item::EquipType::A_GRADE: szGradeString = _T("A"); break;
case Item::EquipType::B_GRADE: szGradeString = _T("B"); break;
case Item::EquipType::C_GRADE: szGradeString = _T("C"); break;
case Item::EquipType::D_GRADE: szGradeString = _T("D"); break;
case Item::EquipType::F_GRADE: szGradeString = _T("F"); break;
case Item::EquipType::X_GRADE: szGradeString = _T("X"); break;
};
return szGradeString;
}
namespace Item
{
const int MAX_EQUIP_TYPE = 6;
const int MAX_TYPE_NUM = 2;
using namespace Attribute;
Type aryExceptAttr[MAX_EQUIP_TYPE][Item::MAX_GEM_KIND][MAX_TYPE_NUM] =
{
// 루비 에메랄드 사파이어 다이아몬드 블랙문
{ { ARMOR, NONE }, { MAX_HP, NONE }, { HP_REGEN, NONE }, { MAGIC_RESIST, NONE }, { EVADE, NONE } }, // 아머
{ { MIN_DAMAGE, MAX_DAMAGE }, { MAX_MP, NONE }, { MP_REGEN, NONE }, { CRITICAL, NONE }, { HIT_RATE, NONE } }, // 대거
{ { MIN_DAMAGE, MAX_DAMAGE }, { MAX_MP, NONE }, { MP_REGEN, NONE }, { CRITICAL, NONE }, { HIT_RATE, NONE } }, // 한손무기
{ { MIN_DAMAGE, MAX_DAMAGE }, { MAX_MP, NONE }, { MP_REGEN, NONE }, { CRITICAL, NONE }, { HIT_RATE, NONE } }, // 양손무기
{ { MAGIC_POWER, MAX_DAMAGE }, { MAX_MP, NONE }, { MP_REGEN, NONE }, { CRITICAL, NONE }, { HIT_RATE, NONE } }, // 스태프
{ { MAX_HP, NONE}, { MAX_MP, NONE }, { MP_REGEN, NONE }, { BLOCK, NONE }, { HP_REGEN, NONE } }, // 방패
};
}
Item::Attribute::Type GetSacrificePos(Item::CEquipment& item, Item::CEquipment& sacrifice, Item::CItem& gem)
{
short usEquipAttr[Item::Attribute::MAX_ATTRIBUTE_NUM];
short usSacrificeAttr[Item::Attribute::MAX_ATTRIBUTE_NUM];
item.GetAttribute(usEquipAttr, Item::Attribute::MAX_ATTRIBUTE_NUM);
sacrifice.GetAttribute(usSacrificeAttr, Item::Attribute::MAX_ATTRIBUTE_NUM);
int nGemIndex = gem.GetPrototypeID() - 1911;
int nType = 0;
Item::CItemType::ArrayType arrayType = static_cast<Item::CItemType::ArrayType>(
Item::CItemType::GetEquipType(item.GetItemInfo().m_DetailData.m_dwFlags));
switch(arrayType)
{
case Item::CItemType::ARMOUR_TYPE: nType = 0; break;
case Item::CItemType::DAGGER_TYPE: nType = 1; break;
case Item::CItemType::ONEHANDED_TYPE: nType = 2; break;
case Item::CItemType::LONGRANGE_TYPE: nType = 2; break;
case Item::CItemType::TWOHANDED_TYPE: nType = 3; break;
case Item::CItemType::STAFF_TYPE: nType = 4; break;
case Item::CItemType::SHIELD_TYPE: nType = 5; break;
}
int nMinValue = INT_MAX;
int nMinIndex = Item::Attribute::MAX_ATTRIBUTE_NUM;
int nIndex = 0;
for (nIndex = 0; nIndex < Item::Attribute::MAX_ATTRIBUTE_NUM; ++nIndex)
{
// 전략1. 현재 아이템의 속성보다 높은 속성을 골라 합성한다.
if (nIndex != Item::aryExceptAttr[nType][nGemIndex][0] &&
nIndex != Item::aryExceptAttr[nType][nGemIndex][1] &&
item.CanOptionGraft(arrayType, static_cast<Item::Attribute::Type>(nIndex)))
{
if (usEquipAttr[nIndex] <= usSacrificeAttr[nIndex])
{
// 희생물의 옵션이 더 크다.
break;
}
else if (usEquipAttr[nIndex] < nMinValue)
{
nMinValue = usEquipAttr[nIndex];
nMinIndex = nIndex;
}
}
}
if (nIndex == Item::Attribute::MAX_ATTRIBUTE_NUM &&
nMinIndex != Item::Attribute::MAX_ATTRIBUTE_NUM)
{
nIndex = nMinIndex;
}
ASSERT(nIndex != Item::Attribute::MAX_ATTRIBUTE_NUM);
return static_cast<Item::Attribute::Type>(nIndex);
}
Item::CEquipment* CreateResultItem(SimulateData& simData,
Item::EquipType::Grade eGrade, Item::CItem& Gem)
{
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem(simData.m_usPrototypeID);
Item::CEquipment* lpEquipment = Item::CEquipment::DowncastToEquipment(lpItem);
DWORD dwUsedGold = 0;
unsigned char cMaxDurOut = 0;
if (0 != lpEquipment)
{
// C그레이드 아이템으로 뽑는다.
lpEquipment->AddRandomOption(Item::EquipType::C_GRADE, 0);
while(eGrade < lpEquipment->GetItemGrade().m_eItemGrade)
{
// 10제련에 성공할때까지 제련을 한다.
while (lpEquipment->GetUpgradeLevel() < 10)
{
dwUsedGold = 0;
simData.m_lpMineral->SetNumOrDurability(UCHAR_MAX);
unsigned char cUpgradeLevel = lpEquipment->GetUpgradeLevel();
if (Item::CEquipment::S_SUCCESS ==
lpEquipment->UpgradeItem(*simData.m_lpMineral, ULONG_MAX, dwUsedGold, cMaxDurOut))
{
// 성공 로그
if (cUpgradeLevel < lpEquipment->GetUpgradeLevel())
{
++simData.m_dwSucceededUpgrade[lpEquipment->GetUpgradeLevel() - 1];
}
else
{
++simData.m_dwFailedUpgrade[lpEquipment->GetUpgradeLevel()];
}
}
else
{
// 실패 로그
}
simData.m_dwUsedMoney += dwUsedGold;
simData.m_dwUsedMineral += (UCHAR_MAX - simData.m_lpMineral->GetNumOrDurability());
}
// 10제련 완성 후에 보석을 5개 박는다.
for (int nGemInstallCount = 0; nGemInstallCount < 5; ++nGemInstallCount)
{
Gem.SetNumOrDurability(UCHAR_MAX);
if (Item::CEquipment::S_SUCCESS ==
lpEquipment->InstallSocket(Gem))
{
simData.m_dwUsedGems[Gem.GetPrototypeID() - 1911] +=
(UCHAR_MAX - Gem.GetNumOrDurability());
}
else
{
}
}
if (eGrade < lpEquipment->GetItemGrade().m_eItemGrade)
{
// 방어구이면 다이아, 아니면 루비를 사용해, 희생물을 만든다.
unsigned short usSacrificedItemGem =
(lpEquipment->GetItemInfo().m_DetailData.m_dwFlags & Item::DetailData::ARMOR)
? 1914 : 1911;
Item::CItem* lpGem = &Gem;
if (Gem.GetPrototypeID() != usSacrificedItemGem)
{
lpGem = Item::CItemFactory::GetInstance().CreateItem(usSacrificedItemGem);
}
if (0 != lpGem)
{
Item::CEquipment* lpSacrifice =
CreateResultItem(simData, lpEquipment->GetItemGrade().m_eItemGrade, *lpGem);
if (0 != lpSacrifice)
{
dwUsedGold = 0;
if (Item::CEquipment::S_SUCCESS ==
lpEquipment->OptionGraft(lpSacrifice, true,
GetSacrificePos(*lpEquipment, *lpSacrifice, Gem), ULONG_MAX, dwUsedGold))
{
++simData.m_dwSacrificeItem;
simData.m_dwUsedMoney += dwUsedGold;
}
else
{
}
DELETE_ITEM(lpSacrifice);
}
if (lpGem != &Gem)
{
DELETE_ITEM(lpGem);
}
}
}
}
}
else
{
DELETE_ITEM(lpItem);
}
return lpEquipment;
}
void CItemUpgradeSimulatorDlg::OnBnClickedStart()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData(TRUE);
const Item::ItemInfo* lpItemInfo =
Item::CItemMgr::GetInstance().GetItemInfoFromItemName(m_szItemName);
if (0 != lpItemInfo)
{
m_simData.m_dwUsedMoney = 0LL;
m_simData.m_dwSacrificeItem = 0L;
m_simData.m_dwUsedMineral = 0L;
memset(m_simData.m_dwSucceededUpgrade, 0, sizeof(m_simData.m_dwSucceededUpgrade));
memset(m_simData.m_dwFailedUpgrade, 0, sizeof(m_simData.m_dwFailedUpgrade));
memset(m_simData.m_dwUsedGems, 0, sizeof(m_simData.m_dwUsedGems));
m_simData.m_usPrototypeID = lpItemInfo->m_usProtoTypeID;
m_simData.m_lpMineral = Item::CItemFactory::GetInstance().CreateItem(m_nMineralType + 2001);
Item::CItem* lpGem = Item::CItemFactory::GetInstance().CreateItem(m_nGemType + 1911);
if (0 != m_simData.m_lpMineral && 0 != lpGem)
{
Item::CEquipment* lpEquipment =
CreateResultItem(m_simData, Item::EquipType::AAA_GRADE, *lpGem);
if (0 != lpEquipment)
{
// 속성 값을 얻어와서 리스트박스에 추가한다.
CString szText;
int nCount = 0;
Item::Grade::GradeInfo gradeInfo = lpEquipment->GetItemGrade();
szText.SetString(GradeToString(gradeInfo.m_eItemGrade));
for(nCount = 0; nCount < gradeInfo.m_cPlus; ++nCount) { szText.Append(_T("+")); }
m_ResultList.DeleteAllItems();
m_ResultList.InsertItem(0, "Grade");
m_ResultList.SetItemText(0, 1, szText);
short Attributes[Item::Attribute::MAX_ATTRIBUTE_NUM];
lpEquipment->GetAttribute(Attributes, Item::Attribute::MAX_ATTRIBUTE_NUM);
int nInsertIndex = 1;
for(nCount = 0; nCount < Item::Attribute::MAX_ATTRIBUTE_NUM; ++nCount)
{
if (0 != Attributes[nCount])
{
szText.Format("%d (%s)", Attributes[nCount],
GradeToString(gradeInfo.m_aryAttributeGrade[nCount]));
m_ResultList.InsertItem(nInsertIndex,
Item::Attribute::Attributes[nCount].GetTypeName());
m_ResultList.SetItemText(nInsertIndex, 1, szText);
++nInsertIndex;
}
}
m_GemUsedList.DeleteAllItems();
const TCHAR* szGemText[] =
{ _T("루비"), _T("에메랄드"), _T("사파이어"), _T("다이아몬드"), _T("블랙문") };
for(nCount = 0; nCount < Item::MAX_GEM_KIND; ++nCount)
{
m_GemUsedList.InsertItem(nCount, szGemText[nCount]);
szText.Format("%d", m_simData.m_dwUsedGems[nCount]);
m_GemUsedList.SetItemText(nCount, 1, szText);
}
m_UpgradeResultList.DeleteAllItems();
for(nCount = 0; nCount < 10; ++nCount)
{
szText.Format(_T("%d단계"), nCount);
m_UpgradeResultList.InsertItem(nCount, szText);
szText.Format(_T("(%d성공/%d실패)"),
m_simData.m_dwSucceededUpgrade[nCount],
m_simData.m_dwFailedUpgrade[nCount]);
m_UpgradeResultList.SetItemText(nCount, 1, szText);
}
DELETE_ITEM(lpEquipment);
}
}
else
{
DELETE_ITEM(m_simData.m_lpMineral);
DELETE_ITEM(lpGem);
}
}
UpdateData(FALSE);
}