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>
1859 lines
83 KiB
C++
1859 lines
83 KiB
C++
// ItemRebalanceConverter.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
|
|
//
|
|
|
|
#define _WIN32_WINNT 0x0500
|
|
|
|
#include "stdafx.h"
|
|
#include "OldItemStructure.h"
|
|
#include <objbase.h>
|
|
|
|
#include <Log/ServerLog.h>
|
|
|
|
#include <atldbcli.h>
|
|
|
|
#define INITGUID
|
|
#define DBINITCONSTANTS
|
|
#include <sqloledb.h>
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <numeric>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <ctime>
|
|
#include <Item/ItemMgr.h>
|
|
#include <Skill/SkillStructure.h>
|
|
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
|
#include <Utility/Setup/ServerSetup.h>
|
|
|
|
#include "OldItemMgr.h"
|
|
|
|
|
|
#define COPY_AND_ADVANCE_DST(dst, src, size) memcpy((dst), (src), (size)); (dst) += (size)
|
|
#define COPY_AND_ADVANCE_SRC(dst, src, size) memcpy((dst), (src), (size)); (src) += (size)
|
|
|
|
|
|
class COMInitialize
|
|
{
|
|
public:
|
|
|
|
static COMInitialize& GetInstance();
|
|
|
|
private:
|
|
|
|
COMInitialize();
|
|
~COMInitialize();
|
|
};
|
|
|
|
COMInitialize& COMInitialize::GetInstance()
|
|
{
|
|
static COMInitialize initialize;
|
|
return initialize;
|
|
}
|
|
|
|
COMInitialize::COMInitialize()
|
|
{
|
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
}
|
|
|
|
COMInitialize::~COMInitialize()
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
class CUserItemDataGet
|
|
{
|
|
public:
|
|
|
|
int m_nCID;
|
|
|
|
BYTE m_Equip[sizeof(EQUIP)];
|
|
BYTE m_Inven[sizeof(INVEN)];
|
|
BYTE m_Extra[sizeof(EXTRA)];
|
|
BYTE m_Exchange[sizeof(EXCHANGE)];
|
|
|
|
DBLENGTH m_EquipLength;
|
|
DBLENGTH m_InvenLength;
|
|
DBLENGTH m_ExtraLength;
|
|
DBLENGTH m_ExchangeLength;
|
|
|
|
void Init()
|
|
{
|
|
m_nCID = 0;
|
|
m_EquipLength = m_InvenLength = m_ExtraLength = m_ExchangeLength = 0;
|
|
|
|
memset(m_Equip, 0, sizeof(EQUIP));
|
|
memset(m_Inven, 0, sizeof(INVEN));
|
|
memset(m_Extra, 0, sizeof(EXTRA));
|
|
memset(m_Exchange, 0, sizeof(EXCHANGE));
|
|
}
|
|
};
|
|
|
|
class CUserItemDataSet
|
|
{
|
|
public:
|
|
|
|
int m_nCID;
|
|
|
|
BYTE m_Equip[sizeof(EQUIP)];
|
|
BYTE m_Inven[sizeof(INVEN)];
|
|
BYTE m_Extra[sizeof(EXTRA)];
|
|
|
|
DBLENGTH m_EquipLength;
|
|
DBLENGTH m_InvenLength;
|
|
DBLENGTH m_ExtraLength;
|
|
|
|
void Init()
|
|
{
|
|
m_nCID = 0;
|
|
m_EquipLength = m_InvenLength = m_ExtraLength = 0;
|
|
|
|
memset(m_Equip, 0, sizeof(EQUIP));
|
|
memset(m_Inven, 0, sizeof(INVEN));
|
|
memset(m_Extra, 0, sizeof(EXTRA));
|
|
}
|
|
};
|
|
|
|
class CUserItemDataSetEx
|
|
|
|
{
|
|
public:
|
|
|
|
int m_nCID;
|
|
BYTE m_Exchange[sizeof(EXCHANGE)];
|
|
|
|
DBLENGTH m_ExchangeLength;
|
|
|
|
void Init()
|
|
{
|
|
m_nCID = 0;
|
|
m_ExchangeLength = 0;
|
|
memset(m_Exchange, 0, sizeof(EXCHANGE));
|
|
}
|
|
};
|
|
|
|
class CStoreItemData
|
|
{
|
|
public:
|
|
|
|
DBLENGTH m_StoreLength;
|
|
int m_nUID;
|
|
BYTE m_Store[sizeof(STORE)];
|
|
|
|
void Init()
|
|
{
|
|
m_StoreLength = 0;
|
|
m_nUID = 0;
|
|
memset(m_Store, 0, sizeof(STORE));
|
|
}
|
|
};
|
|
|
|
class CGetUserItemData : public CUserItemDataGet
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CGetUserItemData >, CRowset, CMultipleResults > Command;
|
|
|
|
BEGIN_COLUMN_MAP(CGetUserItemData)
|
|
COLUMN_ENTRY(1, m_nCID)
|
|
COLUMN_ENTRY_LENGTH(2, m_Equip, m_EquipLength)
|
|
COLUMN_ENTRY_LENGTH(3, m_Inven, m_InvenLength)
|
|
COLUMN_ENTRY_LENGTH(4, m_Extra, m_ExtraLength)
|
|
END_COLUMN_MAP()
|
|
|
|
};
|
|
|
|
class CGetUserItemDataEx : public CUserItemDataGet
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CGetUserItemDataEx >, CRowset, CMultipleResults > Command;
|
|
|
|
BEGIN_COLUMN_MAP(CGetUserItemDataEx)
|
|
COLUMN_ENTRY(1, m_nCID)
|
|
COLUMN_ENTRY_LENGTH(2, m_Exchange, m_ExchangeLength)
|
|
END_COLUMN_MAP()
|
|
};
|
|
|
|
class CSetUserItemData : public CUserItemDataSet
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CSetUserItemData >, CNoRowset> Command;
|
|
|
|
BEGIN_PARAM_MAP(CSetUserItemData)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY_LENGTH(1, m_Equip, m_EquipLength)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY_LENGTH(2, m_Inven, m_InvenLength)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY_LENGTH(3, m_Extra, m_ExtraLength)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY(4, m_nCID)
|
|
|
|
END_PARAM_MAP()
|
|
|
|
};
|
|
|
|
class CSetUserItemDataEx : public CUserItemDataSetEx
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CSetUserItemDataEx >, CNoRowset > Command;
|
|
|
|
BEGIN_PARAM_MAP(CSetUserItemDataEx)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY_LENGTH(1, m_Exchange, m_ExchangeLength);
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY(2, m_nCID)
|
|
|
|
END_PARAM_MAP()
|
|
|
|
};
|
|
|
|
|
|
class CGetStoreItemData : public CStoreItemData
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CGetStoreItemData >, CRowset, CMultipleResults > Command;
|
|
|
|
BEGIN_COLUMN_MAP(CGetStoreItemData)
|
|
COLUMN_ENTRY(1, m_nUID)
|
|
COLUMN_ENTRY_LENGTH(2, m_Store, m_StoreLength)
|
|
END_COLUMN_MAP()
|
|
|
|
};
|
|
|
|
class CSetStoreItemData : public CStoreItemData
|
|
{
|
|
public:
|
|
|
|
typedef CCommand< CAccessor< CSetStoreItemData >, CNoRowset > Command;
|
|
|
|
BEGIN_PARAM_MAP(CSetStoreItemData)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY_LENGTH(1, m_Store, m_StoreLength)
|
|
|
|
SET_PARAM_TYPE(DBPARAMIO_INPUT)
|
|
COLUMN_ENTRY(2, m_nUID)
|
|
|
|
END_PARAM_MAP()
|
|
|
|
};
|
|
|
|
void PrintUsage()
|
|
{
|
|
printf("Usage : ItemRebalanceConverter DBServerAddr DBName DBAccount DBPassword ServerGroupNum convertCharDelHistory(1/0) writeDB(1/0)");
|
|
}
|
|
|
|
int ParseItemData(unsigned long dwUID, unsigned long dwCID,
|
|
char* szItemData, unsigned long dwSize,
|
|
char* szOutData, unsigned long& dwOutDataSize);
|
|
|
|
bool CreateAdjustedItem(unsigned long dwUID,
|
|
unsigned long dwCID,
|
|
OldItem::ItemData* lpItemData,
|
|
OldItem::EquipmentInfo* lpEquipmentInfo,
|
|
unsigned char* lpSocketInfo,
|
|
OldItem::ItemAttribute* lpAttribute,
|
|
char* szOutData,
|
|
unsigned long& dwRemainBufferSize_InOut);
|
|
|
|
|
|
Item::Grade::GradeInfo GetGradeInfo(short* wNewAttribute, const int nMaxAttributeNum,
|
|
const Item::ItemInfo& newItemInfo);
|
|
|
|
const char* GetGradeString(Item::EquipType::Grade grade);
|
|
|
|
#define ERROR_HRESULT_RETURN(ErrorMessage, hr, retVal) \
|
|
if(FAILED(hr)) { printf(ErrorMessage" : hr(0x%08x)", (hr)); return (retVal); }
|
|
|
|
int ProcessCharItem(ATL::CSession& readSession, ATL::CSession& writeSession,
|
|
bool bProcessDelHistory, bool bWriteDB);
|
|
|
|
int ProcessCharItemEx(ATL::CSession& readSession, ATL::CSession& writeSession,
|
|
bool bProcessDelHistory, bool bWriteDB);
|
|
|
|
int ProcessStore(ATL::CSession& readSession, ATL::CSession& writeSession,
|
|
int nStoreNum, bool bWriteDB);
|
|
|
|
bool RewriteItemUID(ATL::CSession& writeSession, int nServerGroupNum);
|
|
|
|
const int SHOW_NUM_PER_PROCESS = 1000;
|
|
int g_GradeNum[Item::EquipType::MAX_GRADE] = { 0, };
|
|
unsigned __int64 g_UID = 0;
|
|
|
|
const int MAX_SERVERZONE = 20;
|
|
unsigned __int64 g_MaxUID[MAX_SERVERZONE] = { 0, };
|
|
|
|
CServerLog g_ItemLog("ItemLog.log");
|
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
{
|
|
COMInitialize::GetInstance();
|
|
|
|
if(argc != 8)
|
|
{
|
|
PrintUsage();
|
|
return -1;
|
|
}
|
|
|
|
// 아이템 스크립트 읽기
|
|
if(!Item::CItemMgr::GetInstance().LoadItemProtoType("./NewItemScript.txt"))
|
|
{
|
|
printf("NewItemScript load failed.");
|
|
return -1;
|
|
}
|
|
|
|
// 아이템 스크립트 읽기
|
|
if(!OldItem::CItemMgr::GetInstance().LoadItemProtoType("./OldItemScript.txt"))
|
|
{
|
|
printf("OldItemScript load failed.");
|
|
return -1;
|
|
}
|
|
|
|
int nServerGroupNum = atoi(argv[5]);
|
|
|
|
bool bWriteDB = (0 == strcmp("1", argv[7]));
|
|
|
|
DETLOG0(g_Log, "DBQuery and convert start!");
|
|
printf("DBQuery and convert start!\n");
|
|
|
|
// DB Property 설정.
|
|
ATL::CDBPropSet dsPropSet[2];
|
|
dsPropSet[0].SetGUID(DBPROPSET_DBINIT);
|
|
dsPropSet[0].AddProperty(DBPROP_INIT_DATASOURCE, argv[1]);
|
|
dsPropSet[0].AddProperty(DBPROP_INIT_CATALOG, argv[2]);
|
|
dsPropSet[0].AddProperty(DBPROP_AUTH_USERID, argv[3]);
|
|
dsPropSet[0].AddProperty(DBPROP_AUTH_PASSWORD, argv[4]);
|
|
|
|
dsPropSet[1].SetGUID(DBPROPSET_ROWSET);
|
|
dsPropSet[1].AddProperty(DBPROP_UPDATABILITY, long(VARIANT_TRUE));
|
|
|
|
// 데이터베이스 오픈
|
|
ATL::CDataSource dataSource;
|
|
HRESULT hr = dataSource.Open(CLSID_SQLOLEDB, dsPropSet, 2);
|
|
ERROR_HRESULT_RETURN("DataSource1 open failed", hr, -1);
|
|
|
|
// 데이터베이스 읽기 세션 열기
|
|
ATL::CSession readSession;
|
|
hr = readSession.Open(dataSource);
|
|
ERROR_HRESULT_RETURN("readSession open failed", hr, -1);
|
|
|
|
// 데이터베이스 쓰기 세션 열기
|
|
ATL::CSession writeSession;
|
|
hr = writeSession.Open(dataSource);
|
|
ERROR_HRESULT_RETURN("writeSession open failed", hr, -1);
|
|
|
|
#define LOG_CONVERT(str) DETLOG0(g_Log, (str)); printf(str "\n");
|
|
#define LOG_CONVERT1(str, arg1) DETLOG1(g_Log, (str), (arg1)); printf(str "\n", (arg1));
|
|
#define LOG_CONVERT2(str, arg1, arg2) DETLOG2(g_Log, (str), (arg1), (arg2)); printf(str "\n", (arg1), (arg2));
|
|
|
|
LOG_CONVERT("Convert CharItem Start.");
|
|
ProcessCharItem(readSession, writeSession, false, bWriteDB);
|
|
|
|
LOG_CONVERT("Convert CharItemEx Start.");
|
|
ProcessCharItemEx(readSession, writeSession, false, bWriteDB);
|
|
|
|
LOG_CONVERT("Convert Store1 Start.");
|
|
ProcessStore(readSession, writeSession, 1, bWriteDB);
|
|
|
|
LOG_CONVERT("Convert Store2 Start.");
|
|
ProcessStore(readSession, writeSession, 2, bWriteDB);
|
|
|
|
if(0 == strcmp("1", argv[6]))
|
|
{
|
|
LOG_CONVERT("Convert CharDelHistory..CharItem Start.");
|
|
ProcessCharItem(readSession, writeSession, true, bWriteDB);
|
|
|
|
LOG_CONVERT("Convert CharDelHistory..CharItemEx Start.");
|
|
ProcessCharItemEx(readSession, writeSession, true, bWriteDB);
|
|
}
|
|
|
|
LOG_CONVERT1("Grade AAA : %10u", g_GradeNum[Item::EquipType::AAA_GRADE]);
|
|
LOG_CONVERT1("Grade AA : %10u", g_GradeNum[Item::EquipType::AA_GRADE]);
|
|
LOG_CONVERT1("Grade A : %10u", g_GradeNum[Item::EquipType::A_GRADE]);
|
|
LOG_CONVERT1("Grade B : %10u", g_GradeNum[Item::EquipType::B_GRADE]);
|
|
LOG_CONVERT1("Grade C : %10u", g_GradeNum[Item::EquipType::C_GRADE]);
|
|
LOG_CONVERT1("Grade D : %10u", g_GradeNum[Item::EquipType::D_GRADE]);
|
|
LOG_CONVERT1("Grade F : %10u", g_GradeNum[Item::EquipType::F_GRADE]);
|
|
|
|
for(int nCount = 0; nCount < MAX_SERVERZONE; ++nCount)
|
|
{
|
|
if(0 != g_MaxUID[nCount])
|
|
{
|
|
LOG_CONVERT2("ServerGroup : %d / Max Old UID : 0x%016I64X", nCount, g_MaxUID[nCount]);
|
|
}
|
|
}
|
|
|
|
RewriteItemUID(writeSession, nServerGroupNum);
|
|
|
|
LOG_CONVERT1("Max New UID : %I64u", g_UID);
|
|
LOG_CONVERT("Convert Complete");
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool RewriteItemUID(ATL::CSession& writeSession, int nServerGroupNum)
|
|
{
|
|
// 아이템 시리얼 전부 지우고, 재기록하기.
|
|
CCommand<> DelCmd;
|
|
HRESULT hr = DelCmd.Open(writeSession, "Delete from ItemUID");
|
|
|
|
ERROR_HRESULT_RETURN("readSession open failed", hr, false);
|
|
|
|
SERVER_ID serverID;
|
|
|
|
serverID.sID.Type = CServerSetup::AuthServer;
|
|
serverID.sID.Group = nServerGroupNum;
|
|
serverID.sID.Channel = 0;
|
|
serverID.sID.ID = 0;
|
|
|
|
const int MAX_QUERY_LEN = 512;
|
|
char szQuery[MAX_QUERY_LEN];
|
|
|
|
_snprintf(szQuery, MAX_QUERY_LEN - 1, "Insert into ItemUID values (0x%08x, 0x%0I64x)",
|
|
serverID.dwID, g_UID);
|
|
|
|
hr = DelCmd.Open(writeSession, szQuery);
|
|
ERROR_HRESULT_RETURN("readSession open failed", hr, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
int ParseItemData(unsigned long dwUID, unsigned long dwCID,
|
|
char* szItemData, unsigned long dwSize,
|
|
char* szOutData, unsigned long& dwOutDataSize)
|
|
{
|
|
char* szItemDataPos = szItemData;
|
|
char* szItemDataEnd = szItemData + dwSize;
|
|
|
|
char* szOutDataPos = szOutData;
|
|
char* szOutDataEnd = szOutData + dwOutDataSize;
|
|
|
|
for(; szItemDataPos < szItemDataEnd && szOutDataPos < szOutDataEnd;
|
|
szItemDataPos += reinterpret_cast<OldItem::ItemData*>(szItemDataPos)->m_cItemSize)
|
|
{
|
|
OldItem::ItemData* lpItemData = reinterpret_cast<OldItem::ItemData*>(szItemDataPos);
|
|
|
|
if(sizeof(OldItem::ItemData) + sizeof(OldItem::EquipmentInfo) <= lpItemData->m_cItemSize)
|
|
{
|
|
// 뒤에 추가 정보가 있으므로 장비다. 옵션을 수정한 후 복사해 준다.
|
|
OldItem::EquipmentInfo* lpEquipmentInfo = reinterpret_cast<OldItem::EquipmentInfo*>(
|
|
szItemDataPos + sizeof(OldItem::ItemData));
|
|
|
|
unsigned char* lpSocketInfo = reinterpret_cast<unsigned char*>(lpEquipmentInfo + 1);
|
|
|
|
OldItem::ItemAttribute* lpAttribute = reinterpret_cast<OldItem::ItemAttribute*>(
|
|
lpSocketInfo + lpEquipmentInfo->m_cSocketNum);
|
|
|
|
unsigned long dwDataSize = static_cast<unsigned long>(szOutDataEnd - szOutDataPos);
|
|
|
|
if(0 == lpEquipmentInfo->m_cReserved)
|
|
{
|
|
if(CreateAdjustedItem(dwUID, dwCID, lpItemData, lpEquipmentInfo,
|
|
lpSocketInfo, lpAttribute, szOutDataPos, dwDataSize))
|
|
{
|
|
szOutDataPos += dwDataSize;
|
|
}
|
|
else
|
|
{
|
|
// 뭔가 길이가 이상한 아이템이다.
|
|
DETLOG5(g_Log, "Item recreation failed.\tUID:%10u\tCID:%10u\tItemUID:0x%016I64X\tPrototypeID:%5u\tItemSize:%3u\t",
|
|
dwUID, dwCID, lpItemData->m_dwUID, lpItemData->m_usProtoTypeID, lpItemData->m_cItemSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 이미 리밸런싱된 아이템이다.
|
|
DETLOG5(g_Log, "이미 리밸런싱된 아이템입니다\tUID:%10u\tCID:%10u\tItemUID:0x%016I64X\tPrototypeID:%5u\tItemSize:%3u\t",
|
|
dwUID, dwCID, lpItemData->m_dwUID, lpItemData->m_usProtoTypeID, lpItemData->m_cItemSize);
|
|
|
|
memcpy(szOutDataPos, lpItemData, lpItemData->m_cItemSize);
|
|
szOutDataPos += lpItemData->m_cItemSize;
|
|
}
|
|
}
|
|
else if(lpItemData->m_cItemSize == sizeof(OldItem::ItemData))
|
|
{
|
|
// 장비가 아닌 잡템이다. 그냥 복사해 준다.
|
|
memcpy(szOutDataPos, lpItemData, lpItemData->m_cItemSize);
|
|
szOutDataPos += lpItemData->m_cItemSize;
|
|
}
|
|
else
|
|
{
|
|
DETLOG5(g_Log, "Item length is invalid. UID:%10u/CID:%10u/ItemUID:0x%016I64X/PrototypeID:%5u/ItemSize:%3u",
|
|
dwUID, dwCID, lpItemData->m_dwUID, lpItemData->m_usProtoTypeID, lpItemData->m_cItemSize);
|
|
}
|
|
}
|
|
|
|
dwOutDataSize = static_cast<unsigned long>(szOutDataPos - szOutData);
|
|
return 0;
|
|
}
|
|
|
|
bool CreateAdjustedItem(unsigned long dwUID,
|
|
unsigned long dwCID,
|
|
OldItem::ItemData* lpItemData,
|
|
OldItem::EquipmentInfo* lpEquipmentInfo,
|
|
unsigned char* lpSocketInfo,
|
|
OldItem::ItemAttribute* lpAttribute,
|
|
char* szOutData,
|
|
unsigned long& dwRemainBufferSize_InOut)
|
|
{
|
|
const int MAX_ATTR_NUM = 7;
|
|
|
|
const OldItem::ItemInfo* lpOldItemInfo =
|
|
OldItem::CItemMgr::GetInstance().GetItemInfo(lpItemData->m_usProtoTypeID);
|
|
|
|
const Item::ItemInfo* lpNewItemInfo =
|
|
Item::CItemMgr::GetInstance().GetItemInfo(lpItemData->m_usProtoTypeID);
|
|
|
|
if(0 == lpNewItemInfo || 0 == lpOldItemInfo)
|
|
{
|
|
DETLOG3(g_Log, "Script has not this item.\tUID:%10u\tCID:%10u\tPrototypeID:%5u\t",
|
|
dwUID, dwCID, lpItemData->m_usProtoTypeID);
|
|
|
|
return false;
|
|
}
|
|
|
|
if(sizeof(OldItem::ItemData) + sizeof(OldItem::EquipmentInfo) +
|
|
sizeof(OldItem::ItemAttribute) * MAX_ATTR_NUM < dwRemainBufferSize_InOut)
|
|
{
|
|
char* szOutDataPos = szOutData;
|
|
unsigned char cItemType = lpOldItemInfo->m_DetailData.m_cItemType;
|
|
unsigned short wDropOption = lpNewItemInfo->m_DetailData.m_wDropOption;
|
|
|
|
unsigned char cMaxDurablility = lpEquipmentInfo->m_cDiffMaxDurability + lpOldItemInfo->m_DetailData.m_cDefaultDurabilityOrStack;
|
|
if(150 < cMaxDurablility)
|
|
{
|
|
const int MAX_BUFFER = 1024;
|
|
char szBuffer[MAX_BUFFER];
|
|
|
|
int nTotalLength = _snprintf(szBuffer, MAX_BUFFER - 1,
|
|
"Item durability is invalid.\tUID:%10u\tCID:%10u\tItemUID:0x%016I64X\tItemSize:%3u\tPrototypeID:%5u\tItemType:%20s\tDurability:%d\t",
|
|
dwUID, dwCID, lpItemData->m_dwUID, lpItemData->m_cItemSize, lpItemData->m_usProtoTypeID,
|
|
OldItem::CItemType::GetInstance().GetItemTypeName()[cItemType].GetTypeName(),
|
|
cMaxDurablility);
|
|
|
|
DETLOG0(g_Log, szBuffer);
|
|
|
|
cMaxDurablility = 150;
|
|
}
|
|
|
|
lpEquipmentInfo->m_cDiffMaxDurability =
|
|
cMaxDurablility - lpOldItemInfo->m_DetailData.m_cDefaultDurabilityOrStack;
|
|
|
|
// 일단 기본 데이터 부분은 그냥 복사한다.
|
|
memcpy(szOutDataPos, lpItemData, sizeof(OldItem::ItemData));
|
|
|
|
unsigned __int64 nNewItemSerial = ++g_UID;
|
|
|
|
INFLOG4(g_ItemLog, "UID:%10u / CID:%10u / OldItemSerial:0x%0I64X / NewItemSerial:0x%0I64X / 아이템 시리얼 변경",
|
|
dwUID, dwCID, reinterpret_cast<Item::ItemData*>(szOutDataPos)->m_dwUID, nNewItemSerial);
|
|
|
|
reinterpret_cast<Item::ItemData*>(szOutDataPos)->m_dwUID = nNewItemSerial;
|
|
szOutDataPos += sizeof(OldItem::ItemData);
|
|
|
|
int nIndex = static_cast<int>(lpItemData->m_dwUID >> 56);
|
|
if(nIndex < MAX_SERVERZONE)
|
|
{
|
|
if(g_MaxUID[nIndex] < lpItemData->m_dwUID)
|
|
{
|
|
g_MaxUID[nIndex] = lpItemData->m_dwUID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRLOG3(g_Log, "Invalid ItemUID : 0x%0I64X / UID:%10d / CID :%10d",
|
|
lpItemData->m_dwUID, dwUID, dwCID);
|
|
}
|
|
|
|
lpEquipmentInfo->m_cReserved = 0;
|
|
COPY_AND_ADVANCE_DST(szOutDataPos, lpEquipmentInfo, sizeof(OldItem::EquipmentInfo));
|
|
|
|
// 이제 소켓 부분을 복사할 차례이다.
|
|
if(0 < lpEquipmentInfo->m_cSocketNum)
|
|
{
|
|
// 소켓이 있으면 소켓을 복사.
|
|
COPY_AND_ADVANCE_DST(szOutDataPos, lpSocketInfo,
|
|
sizeof(unsigned char) * lpEquipmentInfo->m_cSocketNum);
|
|
}
|
|
|
|
// 이제 아이템 속성을 지대로 복사할 차례인데..
|
|
// 1. 아이템 속성값을 배열에 담는다.
|
|
// 2. 업그레이드 속성값을 적용한다.
|
|
// 3. Gem속성값을 적용한다.
|
|
// 4. 아이템 타입별로, 위에서부터 죽 흝으면서 적용할 속성값만 걸러서, 값을 계산한 후 복사한다.
|
|
|
|
short wAttributeValue[OldItem::Attribute::MAX_ATTRIBUTE_NUM];
|
|
short wNewAttributeValue[Item::Attribute::MAX_ATTRIBUTE_NUM];
|
|
|
|
std::fill_n(wAttributeValue, unsigned short(OldItem::Attribute::MAX_ATTRIBUTE_NUM), 0);
|
|
std::fill_n(wNewAttributeValue, unsigned short(Item::Attribute::MAX_ATTRIBUTE_NUM), 0);
|
|
|
|
// 아이템 속성값 배열에 담기.
|
|
OldItem::ItemAttribute* lpAttributePos = lpAttribute;
|
|
OldItem::ItemAttribute* lpAttributeEnd = lpAttribute + lpEquipmentInfo->m_cAttributeNum;
|
|
|
|
for(; lpAttributePos != lpAttributeEnd; ++lpAttributePos)
|
|
{
|
|
if(0 != lpAttributePos->m_cType && lpAttributePos->m_cType < OldItem::Attribute::MAX_ATTRIBUTE_NUM)
|
|
{
|
|
wAttributeValue[lpAttributePos->m_cType] += lpAttributePos->m_usValue;
|
|
}
|
|
}
|
|
|
|
// 업그레이드 속성값 얻어와서 더하기.
|
|
if(0 < lpEquipmentInfo->m_cDiffMaterialType)
|
|
{
|
|
OldItem::ItemAttribute attrUpgrade[OldItem::EquipmentInfo::MAX_UPGRADE_ATTRIBUTE];
|
|
memset(&attrUpgrade, 0, sizeof(OldItem::ItemAttribute) * OldItem::EquipmentInfo::MAX_UPGRADE_ATTRIBUTE);
|
|
|
|
OldItem::CItemType::GetUpgradeItemAttribute(static_cast<OldItem::ItemType::Type>(cItemType),
|
|
attrUpgrade, lpEquipmentInfo->m_cDiffMaterialType, OldItem::EquipmentInfo::MAX_UPGRADE_ATTRIBUTE);
|
|
|
|
lpAttributePos = attrUpgrade;
|
|
lpAttributeEnd = attrUpgrade + OldItem::EquipmentInfo::MAX_UPGRADE_ATTRIBUTE;
|
|
|
|
for(; lpAttributePos != lpAttributeEnd; ++lpAttributePos)
|
|
{
|
|
if(0 != lpAttributePos->m_cType && lpAttributePos->m_cType < OldItem::Attribute::MAX_ATTRIBUTE_NUM)
|
|
{
|
|
wAttributeValue[lpAttributePos->m_cType] += lpAttributePos->m_usValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 소켓 속성값 얻어와서 더하기.
|
|
if(0 < lpEquipmentInfo->m_cSocketNum)
|
|
{
|
|
OldItem::ItemAttribute attrGems[OldItem::EquipmentInfo::MAX_SOCKET_ATTRIBUTE_NUM];
|
|
memset(&attrGems, 0, sizeof(OldItem::ItemAttribute) * OldItem::EquipmentInfo::MAX_SOCKET_ATTRIBUTE_NUM);
|
|
|
|
OldItem::CItemType::GetInstallGemAttribute(lpSocketInfo, attrGems,
|
|
static_cast<OldItem::ItemType::Type>(cItemType), lpEquipmentInfo->m_cSocketNum,
|
|
OldItem::EquipmentInfo::MAX_SOCKET_ATTRIBUTE_NUM);
|
|
|
|
lpAttributePos = attrGems;
|
|
lpAttributeEnd = attrGems + OldItem::EquipmentInfo::MAX_SOCKET_ATTRIBUTE_NUM;
|
|
|
|
for(; lpAttributePos != lpAttributeEnd; ++lpAttributePos)
|
|
{
|
|
if(0 != lpAttributePos->m_cType && lpAttributePos->m_cType < OldItem::Attribute::MAX_ATTRIBUTE_NUM)
|
|
{
|
|
wAttributeValue[lpAttributePos->m_cType] += lpAttributePos->m_usValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define CHECK_ATTR(nOverflowIndex, MaxValue, Value, nIndex) \
|
|
if((MaxValue) < (Value[nIndex])) { (Value[nIndex]) = (MaxValue); (nOverflowIndex) = (nIndex); }
|
|
|
|
bool bInvalidMaxValue = false;
|
|
bool bInvalidUnknownAttr = false;
|
|
|
|
int nOverflowIndex = OldItem::Attribute::MAX_ATTRIBUTE_NUM;
|
|
|
|
short wInvalidAttribute[OldItem::Attribute::MAX_ATTRIBUTE_NUM];
|
|
std::copy(wAttributeValue, wAttributeValue + OldItem::Attribute::MAX_ATTRIBUTE_NUM, wInvalidAttribute);
|
|
|
|
short wOldAttributeValue[OldItem::Attribute::MAX_ATTRIBUTE_NUM];
|
|
std::copy(wAttributeValue, wAttributeValue + OldItem::Attribute::MAX_ATTRIBUTE_NUM, wOldAttributeValue);
|
|
|
|
// 이제, 아이템 타입별로 골라서 복사할 차례가 왔다.
|
|
switch(lpNewItemInfo->m_DetailData.m_cItemType)
|
|
{
|
|
case Item::ItemType::CON_ARMOUR:
|
|
case Item::ItemType::CON_BODY:
|
|
/*
|
|
구항목 신항목 계산식 구항목 최대값.
|
|
|
|
방어력 방어력 구 방어력 * 2.6 72
|
|
방어보정 회피 구 방어보정 * 0.7 58
|
|
HP Max HP Max 구 HP Max * 0.6 54
|
|
MP Max HP 회복 구 MP Max * 1.2 69
|
|
저항력 마법저항 구 저항력 * 0.32 + 구 블록 * 0.32 30
|
|
블록 11
|
|
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 72, wAttributeValue, OldItem::Attribute::DEFENCE);
|
|
CHECK_ATTR(nOverflowIndex, 58, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 54, wAttributeValue, OldItem::Attribute::MAX_HP);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MAX_MP);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 11, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::ARMOR] = static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE] * 2.6f);
|
|
wNewAttributeValue[Item::Attribute::EVADE] = static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE_REVISION] * 0.7f);
|
|
wNewAttributeValue[Item::Attribute::MAX_HP] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_HP] * 0.6f);
|
|
wNewAttributeValue[Item::Attribute::HP_REGEN] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_MP] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::MAGIC_RESIST] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.32f +
|
|
wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 0.32f);
|
|
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_HP] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_MP] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::DEX_ARMOUR:
|
|
case Item::ItemType::DEX_BODY:
|
|
/*
|
|
구항목 신항목 계산식 구항목 최대값.
|
|
|
|
방어력 방어력 구 방어력 * 2.6 72
|
|
방어보정 회피 구 방어보정 * 0.7 58
|
|
HP Max HP Max 구 HP Max * 0.6 54
|
|
MP Max HP 회복 구 MP Max * 1.2 69
|
|
저항력 마법저항 구 저항력 * 0.32 + 구 블록 * 0.32 30
|
|
블록 11
|
|
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 72, wAttributeValue, OldItem::Attribute::DEFENCE);
|
|
CHECK_ATTR(nOverflowIndex, 58, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 54, wAttributeValue, OldItem::Attribute::MAX_HP);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MAX_MP);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 11, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::ARMOR] = static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE] * 2.6f);
|
|
wNewAttributeValue[Item::Attribute::EVADE] = static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE_REVISION] * 0.7f);
|
|
wNewAttributeValue[Item::Attribute::MAX_HP] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_HP] * 0.6f);
|
|
wNewAttributeValue[Item::Attribute::HP_REGEN] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_MP] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::MAGIC_RESIST] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.32f +
|
|
wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 0.32f);
|
|
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_HP] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_MP] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::CON_HELM:
|
|
case Item::ItemType::CON_HEAD:
|
|
case Item::ItemType::DEX_HELM:
|
|
case Item::ItemType::DEX_HEAD:
|
|
|
|
/*
|
|
구항목 신항목 변경규칙 구항목 최대값
|
|
|
|
방어력 DropOption * 0.9 0
|
|
회피 DropOption * 0.225 0
|
|
HP 회복 HP Max 구 HP Max * 0.6 39
|
|
MP 회복 HP 회복 구 MP Max * 1.2 39
|
|
저항력 마법저항 구 저항력 * 0.5 22
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 39, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 39, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 22, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
|
|
wNewAttributeValue[Item::Attribute::ARMOR] = static_cast<short>(wDropOption * 0.9);
|
|
wNewAttributeValue[Item::Attribute::EVADE] = static_cast<short>(wDropOption * 0.225);
|
|
wNewAttributeValue[Item::Attribute::MAX_HP] = static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6);
|
|
wNewAttributeValue[Item::Attribute::HP_REGEN] = static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2);
|
|
wNewAttributeValue[Item::Attribute::MAGIC_RESIST] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.5);
|
|
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::DAGGER:
|
|
case Item::ItemType::OPP_TALON:
|
|
|
|
/*
|
|
구항목 신항목 변경규칙 구항목 최대값
|
|
|
|
mDmg mDmg 구 mDmg * 2.2 43
|
|
MDmg MDmg 구 MDmg * 1.6 64
|
|
공격보정 명중 구 공격보정 * 3.8 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 30
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 30
|
|
블록 블록 구 블록 * 1.2 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 2.2f);
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.6f);
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] = static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 3.8f);
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] = static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f);
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] = static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] = static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::SKILL_A_KNIFE:
|
|
|
|
/*
|
|
구항목 신항목 변경규칙 구항목 최대값
|
|
|
|
mDmg mDmg 구 mDmg * 2.2 43
|
|
MDmg MDmg 구 MDmg * 1.6 64
|
|
공격보정 명중 구 공격보정 * 1.9 + 구 방어보정 * 1.9 43
|
|
방어보정 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 69
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 69
|
|
저항력 블록 구 저항력 * 0.2 + 구 블록 * 1 8
|
|
블록 블록 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 8, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 2.2f);
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.6f);
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 1.9f +
|
|
wAttributeValue[OldItem::Attribute::DEFENCE_REVISION] * 1.9f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] =
|
|
static_cast<short>(
|
|
wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.2f +
|
|
wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.0f);
|
|
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
|
|
case Item::ItemType::ONEHANDED_SWORD:
|
|
case Item::ItemType::ONEHANDED_AXE:
|
|
case Item::ItemType::ONEHANDED_BLUNT:
|
|
case Item::ItemType::COM_BLUNT:
|
|
case Item::ItemType::COM_SWORD:
|
|
case Item::ItemType::OPP_HAMMER:
|
|
case Item::ItemType::OPP_AXE:
|
|
case Item::ItemType::OPP_SLUSHER:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
mDmg mDmg 구 mDmg * 3.2 43
|
|
MDmg MDmg 구 MDmg * 1.8 64
|
|
공격보정 명중 구 공격보정 * 3.8 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 + DropOption * 0.15 30
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 + DropOption * 0.15 30
|
|
블록 블록 구 블록 * 1.2 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 3.2);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 3.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] = static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
|
|
|
|
case Item::ItemType::BOW:
|
|
case Item::ItemType::CROSSBOW:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
mDmg mDmg 구 mDmg * 3.2 43
|
|
MDmg MDmg 구 MDmg * 1.8 64
|
|
공격보정 명중 구 공격보정 * 3.8 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 + DropOption * 0.15 30
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 + DropOption * 0.15 30
|
|
블록 블록 구 블록 * 1.2 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 3.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 3.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] = static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
|
|
break;
|
|
|
|
|
|
case Item::ItemType::SKILL_A_ATTACK:
|
|
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
mDmg mDmg 구 mDmg * 3.2 43
|
|
MDmg MDmg 구 MDmg * 1.8 64
|
|
공격보정 명중 구 공격보정 * 1.9 + 구 방어보정 * 1.9 43
|
|
방어보정 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 69
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 69
|
|
블록 블록 구 저항력 * 0.2 + 구 블록 * 1 10
|
|
저항력 30
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 3.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 1.9f +
|
|
wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 1.9f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] =
|
|
static_cast<short>(
|
|
wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.2f +
|
|
wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1);
|
|
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::SKILL_A_GUN:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
mDmg mDmg 구 mDmg * 3.2 43
|
|
MDmg MDmg 구 MDmg * 1.8 64
|
|
공격보정 명중 구 공격보정 * 1.9 + 구 방어보정 * 1.9 43
|
|
방어보정 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 69
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 69
|
|
블록 블록 구 저항력 * 0.2 + 구 블록 * 1 10
|
|
저항력 30
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 3.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 1.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 1.9f +
|
|
wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 1.9f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] =
|
|
static_cast<short>(
|
|
wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.2f +
|
|
wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1);
|
|
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::TWOHANDED_SWORD:
|
|
case Item::ItemType::TWOHANDED_AXE:
|
|
case Item::ItemType::TWOHANDED_BLUNT:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
mDmg mDmg 구 mDmg * 2.8 43
|
|
MDmg MDmg 구 MDmg * 3.0 64
|
|
공격보정 명중 구 공격보정 * 3.8 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 + DropOption * 0.15 30
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 + DropOption * 0.15 30
|
|
블록 블록 구 블록 * 1.2 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MIN_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 2.8);
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] = static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 3.0);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 3.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f + wDropOption * 0.15f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] = static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
|
|
case Item::ItemType::STAFF:
|
|
case Item::ItemType::OPP_SYTHE:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
mDmg 마법력 구 mDmg * 8 43
|
|
MDmg MDmg 구 MDmg * 3.0 64
|
|
공격보정 명중 구 공격보정 * 3.8 43
|
|
HP 회복 MPMax 구 HP 회복 * 0.6 + DropOption * 0.3 45
|
|
MP 회복 MP회복 구 MP 회복 * 1.2 + DropOption * 0.3 45
|
|
블록 블록 구 블록 * 1.2 10
|
|
크리티컬 크리티컬 구 크리티컬 * 1 20
|
|
*/
|
|
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::MIN_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 64, wAttributeValue, OldItem::Attribute::MAX_DAMAGE);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::OFFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 45, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 45, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 10, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 20, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAGIC_POWER] = wAttributeValue[OldItem::Attribute::MIN_DAMAGE] * 8;
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_DAMAGE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MAX_DAMAGE] * 3.0f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HIT_RATE] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::OFFENCE_REVISION] * 3.8f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.6f + wDropOption * 0.3f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 1.2f + wDropOption * 0.3f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] = static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.2f);
|
|
wNewAttributeValue[Item::Attribute::CRITICAL] = wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 1;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::OFFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
|
|
// 무쉬!
|
|
wInvalidAttribute[OldItem::Attribute::MAX_MP] = 0;
|
|
|
|
break;
|
|
|
|
case Item::ItemType::SHIELD:
|
|
case Item::ItemType::SKILL_A_GUARD:
|
|
|
|
/*
|
|
구항목 신항목 계산식 구항목최대값
|
|
|
|
방어력 HPMax 구 방어력 * 0.1 22
|
|
HP 회복 HP회복 구 HP 회복 * 0.1 69
|
|
방어보정 MPMax 구 방어보정 * 0.1 43
|
|
MP 회복 MP회복 구 MP 회복 * 0.1 69
|
|
블록 블록 구 블록 * 1 + 구 마법 저항 * 0.2 + 구 크리티컬 * 0.2 36
|
|
저항력 30
|
|
크리티컬 15
|
|
|
|
*/
|
|
CHECK_ATTR(nOverflowIndex, 22, wAttributeValue, OldItem::Attribute::DEFENCE);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::HP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 43, wAttributeValue, OldItem::Attribute::DEFENCE_REVISION);
|
|
CHECK_ATTR(nOverflowIndex, 69, wAttributeValue, OldItem::Attribute::MP_REGEN_AMOUNT);
|
|
CHECK_ATTR(nOverflowIndex, 36, wAttributeValue, OldItem::Attribute::BLOCKING_PERCENTAGE);
|
|
CHECK_ATTR(nOverflowIndex, 30, wAttributeValue, OldItem::Attribute::MAGIC_RESISTANCE);
|
|
CHECK_ATTR(nOverflowIndex, 22, wAttributeValue, OldItem::Attribute::CRITICAL_PERCENTAGE);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_HP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE] * 0.1f);
|
|
|
|
wNewAttributeValue[Item::Attribute::HP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::HP_REGEN_AMOUNT] * 0.1f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MAX_MP] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::DEFENCE_REVISION] * 0.1f);
|
|
|
|
wNewAttributeValue[Item::Attribute::MP_REGEN] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::MP_REGEN_AMOUNT] * 0.1f);
|
|
|
|
wNewAttributeValue[Item::Attribute::BLOCK] =
|
|
static_cast<short>(wAttributeValue[OldItem::Attribute::BLOCKING_PERCENTAGE] * 1.0f +
|
|
wAttributeValue[OldItem::Attribute::MAGIC_RESISTANCE] * 0.2f +
|
|
wAttributeValue[OldItem::Attribute::CRITICAL_PERCENTAGE] * 0.2f);
|
|
|
|
// 무쉬!
|
|
wInvalidAttribute[OldItem::Attribute::MIN_DAMAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAX_DAMAGE] = 0;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DEFENCE_REVISION] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::HP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MP_REGEN_AMOUNT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::BLOCKING_PERCENTAGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::MAGIC_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::CRITICAL_PERCENTAGE] = 0;
|
|
break;
|
|
}
|
|
|
|
// wNewAttributeValue를 0이 아닌 항목만 골라서 szOutDataPos에 저장한다.
|
|
short* lpNewAttributeValuePos = wNewAttributeValue;
|
|
short* lpNewAttributeValueEnd = wNewAttributeValue + Item::Attribute::MAX_ATTRIBUTE_NUM;
|
|
|
|
for(int nAttrPos = 0; lpNewAttributeValuePos != lpNewAttributeValueEnd; ++lpNewAttributeValuePos, ++nAttrPos)
|
|
{
|
|
if(*lpNewAttributeValuePos < 0)
|
|
{
|
|
*lpNewAttributeValuePos = 0;
|
|
}
|
|
else if(0 < *lpNewAttributeValuePos)
|
|
{
|
|
Item::ItemAttribute itemAttribute;
|
|
itemAttribute.m_cType = nAttrPos;
|
|
itemAttribute.m_usValue = *lpNewAttributeValuePos;
|
|
|
|
COPY_AND_ADVANCE_DST(szOutDataPos, &itemAttribute, sizeof(Item::ItemAttribute));
|
|
}
|
|
}
|
|
|
|
wInvalidAttribute[OldItem::Attribute::ATTACK_RANGE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::FIRE_ATTACK] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::LIGHTNING_ATTACK] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::COLD_ATTACK] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DRAIN_ATTACK] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::POISON_ATTACK] = 0;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::FIRE_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::LIGHTNING_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::COLD_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::DRAIN_RESISTANCE] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::POISON_RESISTANCE] = 0;
|
|
|
|
wInvalidAttribute[OldItem::Attribute::ADD_STR] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::ADD_DEX] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::ADD_CON] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::ADD_INT] = 0;
|
|
wInvalidAttribute[OldItem::Attribute::ADD_WIS] = 0;
|
|
|
|
if(nOverflowIndex == OldItem::Attribute::MAX_ATTRIBUTE_NUM)
|
|
{
|
|
for(nOverflowIndex = 0; nOverflowIndex < OldItem::Attribute::MAX_ATTRIBUTE_NUM; ++nOverflowIndex)
|
|
{
|
|
if(0 != wInvalidAttribute[nOverflowIndex])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item::Grade::GradeInfo gradeInfo = GetGradeInfo(wNewAttributeValue,
|
|
Item::Attribute::MAX_ATTRIBUTE_NUM, *lpNewItemInfo);
|
|
|
|
++g_GradeNum[gradeInfo.m_eItemGrade];
|
|
|
|
if(gradeInfo.m_eItemGrade <= Item::EquipType::B_GRADE)
|
|
{
|
|
const int MAX_BUFFER = 1024;
|
|
char szBuffer[MAX_BUFFER];
|
|
|
|
int nTotalLength = _snprintf(szBuffer, MAX_BUFFER - 1,
|
|
"ItemGrade is %s.\tUID:%10u\tCID:%10u\tItemUID:0x%016I64X\tItemSize:%3u\tPrototypeID:%5u\t"
|
|
"\tItemName:%20s\t%d\tItemType:%20s\t",
|
|
GetGradeString(gradeInfo.m_eItemGrade), dwUID, dwCID,
|
|
lpItemData->m_dwUID, lpItemData->m_cItemSize, lpItemData->m_usProtoTypeID,
|
|
lpNewItemInfo->m_SpriteData.m_szName,
|
|
lpNewItemInfo->m_UseLimit.m_wLimitValue,
|
|
lpNewItemInfo->m_StringData.m_szTypeName);
|
|
|
|
short* lpAttributeValuePos = wNewAttributeValue;
|
|
short* lpAttributeValueEnd = wNewAttributeValue + Item::Attribute::MAX_ATTRIBUTE_NUM;
|
|
|
|
Item::EquipType::Grade* lpGradePos = gradeInfo.m_aryAttributeGrade;
|
|
Item::EquipType::Grade* lpGradeEnd = gradeInfo.m_aryAttributeGrade +
|
|
Item::Attribute::MAX_ATTRIBUTE_NUM;
|
|
|
|
for(int nCount = 0;
|
|
lpAttributeValuePos != lpAttributeValueEnd; ++lpAttributeValuePos, ++lpGradePos, ++nCount)
|
|
{
|
|
if(*lpGradePos == gradeInfo.m_eItemGrade)
|
|
{
|
|
int nLength = _snprintf(szBuffer + nTotalLength,
|
|
MAX_BUFFER - nTotalLength -1, "%s:%3d(%s)\t",
|
|
Item::Attribute::Attributes[nCount].GetTypeName(),
|
|
(*lpAttributeValuePos), GetGradeString(*lpGradePos));
|
|
|
|
if(0 < nLength)
|
|
{
|
|
nTotalLength += nLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
DETLOG0(g_Log, szBuffer);
|
|
}
|
|
|
|
if(nOverflowIndex != OldItem::Attribute::MAX_ATTRIBUTE_NUM)
|
|
{
|
|
const int MAX_BUFFER = 1024;
|
|
char szBuffer[MAX_BUFFER];
|
|
|
|
int nTotalLength = _snprintf(szBuffer, MAX_BUFFER - 1,
|
|
"Item attribute is invalid.\tUID:%10u\tCID:%10u\tItemUID:0x%016I64X\tItemSize:%3u\tPrototypeID:%5u\tItemType:%20s\tInvalidAttr:%s\t",
|
|
dwUID, dwCID, lpItemData->m_dwUID, lpItemData->m_cItemSize, lpItemData->m_usProtoTypeID,
|
|
OldItem::CItemType::GetInstance().GetItemTypeName()[cItemType].GetTypeName(),
|
|
OldItem::Attribute::Attributes[nOverflowIndex].GetTypeName());
|
|
|
|
short* lpAttributeValuePos = wOldAttributeValue;
|
|
short* lpAttributeValueEnd = wOldAttributeValue + OldItem::Attribute::MAX_ATTRIBUTE_NUM;
|
|
|
|
for(; lpAttributeValuePos != lpAttributeValueEnd; ++lpAttributeValuePos)
|
|
{
|
|
int nLength = _snprintf(szBuffer + nTotalLength, MAX_BUFFER - nTotalLength -1, "%3d\t", *lpAttributeValuePos);
|
|
if(0 < nLength)
|
|
{
|
|
nTotalLength += nLength;
|
|
}
|
|
}
|
|
|
|
DETLOG0(g_Log, szBuffer);
|
|
}
|
|
|
|
dwRemainBufferSize_InOut = static_cast<unsigned long>(szOutDataPos - szOutData);
|
|
reinterpret_cast<OldItem::ItemData*>(szOutData)->m_cItemSize = static_cast<unsigned char>(dwRemainBufferSize_InOut);
|
|
}
|
|
else
|
|
{
|
|
DETLOG3(g_Log, "Not enough datasize : UID:%10u/CID:%10u/current(%u)", dwUID, dwCID, dwRemainBufferSize_InOut);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
int ProcessCharItem(ATL::CSession& readSession, ATL::CSession& writeSession, bool bProcessDelHistory, bool bWriteDB)
|
|
{
|
|
// 데이터베이스 커맨드 생성 - 아이템 읽기. 장비, 인벤토리, 기타, 교환창
|
|
CGetUserItemData::Command getCharItemCommand;
|
|
CSetUserItemData::Command setCharItemCommand;
|
|
|
|
int nCount = 0;
|
|
|
|
HRESULT hr = setCharItemCommand.Create(writeSession, bProcessDelHistory ?
|
|
L"UPDATE CharDelHistory..DelCharItem SET Equip=?, Inventory=?, Extra=? WHERE UID=?" :
|
|
L"UPDATE CharItem SET Equip=?, Inventory=?, Extra=? WHERE UID=?", DBGUID_SQL);
|
|
ERROR_HRESULT_RETURN("Create setCharItemCommand failed.", hr, -1);
|
|
|
|
hr = setCharItemCommand.Prepare();
|
|
ERROR_HRESULT_RETURN("Prepare setCharItemCommand failed.", hr, -1);
|
|
|
|
hr = getCharItemCommand.Open(readSession, bProcessDelHistory ?
|
|
L"Select UID, Equip, Inventory, Extra from CharDelHistory..DelCharItem" :
|
|
L"Select UID, Equip, Inventory, Extra from CharItem");
|
|
ERROR_HRESULT_RETURN("Get Equip, Inventory, Extra failed", hr, -1);
|
|
|
|
getCharItemCommand.Init();
|
|
setCharItemCommand.Init();
|
|
|
|
// 장비, 인벤, Extra, 교환창 컨버팅.
|
|
while (S_OK == getCharItemCommand.MoveNext())
|
|
{
|
|
// 데이터 세팅
|
|
setCharItemCommand.m_nCID = getCharItemCommand.m_nCID;
|
|
setCharItemCommand.m_EquipLength = getCharItemCommand.m_EquipLength;
|
|
setCharItemCommand.m_InvenLength = getCharItemCommand.m_InvenLength;
|
|
setCharItemCommand.m_ExtraLength = getCharItemCommand.m_ExtraLength;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 장비 세팅 및 컨버팅
|
|
EQUIP* lpGetEquip = reinterpret_cast<EQUIP*>(getCharItemCommand.m_Equip);
|
|
EQUIP* lpSetEquip = reinterpret_cast<EQUIP*>(setCharItemCommand.m_Equip);
|
|
|
|
if(sizeof(unsigned long) <= lpGetEquip->dwSize) { lpGetEquip->dwSize -= sizeof(unsigned long); }
|
|
lpSetEquip->dwSize = EQUIP::MAX_EQUIP_SIZE;
|
|
|
|
ParseItemData(0, getCharItemCommand.m_nCID, lpGetEquip->Data, lpGetEquip->dwSize,
|
|
lpSetEquip->Data, lpSetEquip->dwSize);
|
|
|
|
lpSetEquip->dwSize += sizeof(unsigned long);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 인벤토리 세팅 및 컨버팅
|
|
INVEN* lpGetInven = reinterpret_cast<INVEN*>(getCharItemCommand.m_Inven);
|
|
INVEN* lpSetInven = reinterpret_cast<INVEN*>(setCharItemCommand.m_Inven);
|
|
|
|
if(sizeof(unsigned long) <= lpGetInven->dwSize) { lpGetInven->dwSize -= sizeof(unsigned long); }
|
|
lpSetInven->dwSize = INVEN::MAX_INVEN_SIZE;
|
|
|
|
ParseItemData(0, getCharItemCommand.m_nCID, lpGetInven->Data, lpGetInven->dwSize,
|
|
lpSetInven->Data, lpSetInven->dwSize);
|
|
|
|
lpSetInven->dwSize += sizeof(unsigned long);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Extra 세팅 및 컨버팅
|
|
EXTRA* lpGetExtra = reinterpret_cast<EXTRA*>(getCharItemCommand.m_Extra);
|
|
EXTRA* lpSetExtra = reinterpret_cast<EXTRA*>(setCharItemCommand.m_Extra);
|
|
|
|
if(sizeof(unsigned long) <= lpGetExtra->dwSize) { lpGetExtra->dwSize -= sizeof(unsigned long); }
|
|
lpSetExtra->dwSize = EXTRA::MAX_EXTRA_SIZE;
|
|
|
|
ParseItemData(0, getCharItemCommand.m_nCID, lpGetExtra->Data, lpGetExtra->dwSize,
|
|
lpSetExtra->Data, lpSetExtra->dwSize);
|
|
|
|
lpSetExtra->dwSize += sizeof(unsigned long);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 데이터 업데이트 및 데이터 초기화
|
|
|
|
if (0 != memcmp(lpGetEquip, lpSetEquip, sizeof(EQUIP)) ||
|
|
0 != memcmp(lpGetInven, lpSetInven, sizeof(INVEN)) ||
|
|
0 != memcmp(lpGetExtra, lpSetExtra, sizeof(EXTRA)))
|
|
{
|
|
// 업데이트
|
|
if(bWriteDB)
|
|
{
|
|
hr = setCharItemCommand.Open();
|
|
if(FAILED(hr))
|
|
{
|
|
ERRLOG2(g_Log, "CharItem : CID:%10u write failed(hr:0x%08x)", getCharItemCommand.m_nCID, hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 초기화
|
|
getCharItemCommand.Init();
|
|
setCharItemCommand.Init();
|
|
|
|
if(0 == (++nCount % SHOW_NUM_PER_PROCESS))
|
|
{
|
|
printf("%d\n", nCount);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ProcessCharItemEx(ATL::CSession& readSession, ATL::CSession& writeSession, bool bProcessDelHistory, bool bWriteDB)
|
|
{
|
|
CGetUserItemDataEx::Command getCharItemExCommand;
|
|
CSetUserItemDataEx::Command setCharItemExCommand;
|
|
|
|
int nCount = 0;
|
|
|
|
HRESULT hr = setCharItemExCommand.Create(writeSession, bProcessDelHistory ?
|
|
L"UPDATE CharDelHistory..DelCharItemEx SET Exchange=? WHERE UID=?" :
|
|
L"UPDATE CharItemEx SET Exchange=? WHERE UID=?", DBGUID_SQL);
|
|
ERROR_HRESULT_RETURN("Create setCharItemExCommand failed.", hr, -1);
|
|
|
|
hr = setCharItemExCommand.Prepare();
|
|
ERROR_HRESULT_RETURN("Prepare setCharItemCommandEx failed.", hr, -1);
|
|
|
|
hr = getCharItemExCommand.Open(readSession, bProcessDelHistory ?
|
|
L"Select UID, Exchange from CharDelHistory..DelCharItemEx" : L"Select UID, Exchange from CharItemEx");
|
|
ERROR_HRESULT_RETURN("Get Equip, Inventory, Extra failed", hr, -1);
|
|
|
|
getCharItemExCommand.Init();
|
|
setCharItemExCommand.Init();
|
|
|
|
while(S_OK == getCharItemExCommand.MoveNext())
|
|
{
|
|
setCharItemExCommand.m_nCID = getCharItemExCommand.m_nCID;
|
|
setCharItemExCommand.m_ExchangeLength = getCharItemExCommand.m_ExchangeLength;
|
|
// -----------------------------------------------------------------------
|
|
// Exchage 세팅 및 컨버팅
|
|
EXCHANGE* lpGetExchange = reinterpret_cast<EXCHANGE*>(getCharItemExCommand.m_Exchange);
|
|
EXCHANGE* lpSetExchange = reinterpret_cast<EXCHANGE*>(setCharItemExCommand.m_Exchange);
|
|
|
|
if(sizeof(unsigned long) <= lpGetExchange->dwSize) { lpGetExchange->dwSize -= sizeof(unsigned long); }
|
|
lpSetExchange->dwSize = EXCHANGE::MAX_EXCHANGE_SIZE;
|
|
|
|
ParseItemData(0, getCharItemExCommand.m_nCID, lpGetExchange->Data, lpGetExchange->dwSize,
|
|
lpSetExchange->Data, lpSetExchange->dwSize);
|
|
|
|
lpSetExchange->dwSize += sizeof(unsigned long);
|
|
|
|
if(0 != memcmp(lpGetExchange, lpSetExchange, sizeof(EXCHANGE)))
|
|
{
|
|
// 업데이트
|
|
if(bWriteDB)
|
|
{
|
|
hr = setCharItemExCommand.Open();
|
|
if(FAILED(hr))
|
|
{
|
|
ERRLOG2(g_Log, "CharItemEx : CID:%10u write failed(hr:0x%08x)", getCharItemExCommand.m_nCID, hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
getCharItemExCommand.Init();
|
|
setCharItemExCommand.Init();
|
|
|
|
if(0 == (++nCount % SHOW_NUM_PER_PROCESS))
|
|
{
|
|
printf("%d\n", nCount);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ProcessStore(ATL::CSession& readSession, ATL::CSession& writeSession, int nStoreNum, bool bWriteDB)
|
|
{
|
|
CGetStoreItemData::Command getStoreItemData;
|
|
CSetStoreItemData::Command setStoreItemData;
|
|
|
|
// 데이터베이스 커맨드 생성 - 아이템 기록.
|
|
|
|
LPCWSTR szUpdateQuery = 0;
|
|
LPCWSTR szSelectQuery = 0;
|
|
|
|
switch (nStoreNum)
|
|
{
|
|
case 1:
|
|
szUpdateQuery = L"UPDATE ItemStore1 SET Store=? WHERE UID=?";
|
|
szSelectQuery = L"SELECT UID, Store from ItemStore1";
|
|
break;
|
|
|
|
case 2:
|
|
|
|
szUpdateQuery = L"UPDATE ItemStore2 SET Store=? WHERE UID=?";
|
|
szSelectQuery = L"SELECT UID, Store from ItemStore2";
|
|
break;
|
|
}
|
|
|
|
if(0 == szUpdateQuery || 0 == szSelectQuery)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int nCount = 0;
|
|
|
|
HRESULT hr = setStoreItemData.Create(writeSession, szUpdateQuery, DBGUID_SQL);
|
|
ERROR_HRESULT_RETURN("Create setStoreItemData failed.", hr, -1);
|
|
|
|
hr = setStoreItemData.Prepare();
|
|
ERROR_HRESULT_RETURN("Prepare setStoreItemData failed.", hr, -1);
|
|
|
|
// 창고 컨버팅
|
|
hr = getStoreItemData.Open(readSession, szSelectQuery);
|
|
ERROR_HRESULT_RETURN("Get Store1, Store2 failed", hr, -1);
|
|
|
|
getStoreItemData.Init();
|
|
setStoreItemData.Init();
|
|
|
|
while(S_OK == getStoreItemData.MoveNext())
|
|
{
|
|
setStoreItemData.m_nUID = getStoreItemData.m_nUID;
|
|
setStoreItemData.m_StoreLength = getStoreItemData.m_StoreLength;
|
|
|
|
// 창고 컨버팅
|
|
STORE* lpGetStore = reinterpret_cast<STORE*>(getStoreItemData.m_Store);
|
|
STORE* lpSetStore = reinterpret_cast<STORE*>(setStoreItemData.m_Store);
|
|
|
|
if(sizeof(unsigned long) <= lpGetStore->dwSize) { lpGetStore->dwSize -= sizeof(unsigned long); }
|
|
lpSetStore->dwSize = STORE::MAX_STORE_SIZE;
|
|
|
|
ParseItemData(0, getStoreItemData.m_nUID, lpGetStore->Data, lpGetStore->dwSize,
|
|
lpSetStore->Data, lpSetStore->dwSize);
|
|
|
|
lpSetStore->dwSize += sizeof(unsigned long);
|
|
|
|
if(0 != memcmp(lpGetStore, lpSetStore, sizeof(STORE)))
|
|
{
|
|
// 업데이트
|
|
if(bWriteDB)
|
|
{
|
|
hr = setStoreItemData.Open();
|
|
if(FAILED(hr))
|
|
{
|
|
ERRLOG2(g_Log, "Store : UID:%10u write failed(hr:0x%08x)", getStoreItemData.m_nUID, hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
getStoreItemData.Init();
|
|
setStoreItemData.Init();
|
|
|
|
if(0 == (++nCount % SHOW_NUM_PER_PROCESS))
|
|
{
|
|
printf("%d\n", nCount);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
Item::Grade::GradeInfo GetGradeInfo(short* wNewAttribute, const int nMaxAttributeNum,
|
|
const Item::ItemInfo& newItemInfo)
|
|
{
|
|
using namespace Item;
|
|
// -------------------------------------------------------------------------------------------------
|
|
// 가치 그레이드 테이블
|
|
|
|
static const float aryArmorValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 0, 0, 1.8f, 0, 0.45f, 0.9f, 1.8f, 0, 0, 0, 0, 0, 0, 0.18f }, // Grade AAA
|
|
{ 0, 0, 0, 1.5f, 0, 0.375f, 0.75f, 1.5f, 0, 0, 0, 0, 0, 0, 0.15f }, // Grade AA
|
|
{ 0, 0, 0, 1.2f, 0, 0.3f, 0.6f, 1.2f, 0, 0, 0, 0, 0, 0, 0.12f }, // Grade A
|
|
{ 0, 0, 0, 0.9f, 0, 0.225f, 0.45f, 0.9f, 0, 0, 0, 0, 0, 0, 0.09f }, // Grade B
|
|
{ 0, 0, 0, 0.6f, 0, 0.15f, 0.3f, 0.6f, 0, 0, 0, 0, 0, 0, 0.06f }, // Grade C
|
|
{ 0, 0, 0, 0.3f, 0, 0.075f, 0.15f, 0.3f, 0, 0, 0, 0, 0, 0, 0.03f }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryDaggerValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 0.9f, 1.26f, 0, 1.8f, 0, 0, 0, 0.9f, 1.8f, 0.36f, 0.36f, 0, 0, 0 }, // Grade AAA
|
|
{ 0, 0.75f, 1.05f, 0, 1.5f, 0, 0, 0, 0.75f, 1.5f, 0.3f, 0.3f, 0, 0, 0 }, // Grade AA
|
|
{ 0, 0.6f, 0.84f, 0, 1.2f, 0, 0, 0, 0.6f, 1.2f, 0.24f, 0.24f, 0, 0, 0 }, // Grade A
|
|
{ 0, 0.45f, 0.63f, 0, 0.9f, 0, 0, 0, 0.45f, 0.9f, 0.18f, 0.18f, 0, 0, 0 }, // Grade B
|
|
{ 0, 0.3f, 0.42f, 0, 0.6f, 0, 0, 0, 0.3f, 0.6f, 0.12f, 0.12f, 0, 0, 0 }, // Grade C
|
|
{ 0, 0.15f, 0.21f, 0, 0.3f, 0, 0, 0, 0.15f, 0.3f, 0.06f, 0.06f, 0, 0, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryOneHandedWeaponValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 1.08f, 1.44f, 0, 1.8f, 0, 0, 0, 0.9f, 1.8f, 0.36f, 0.36f, 0, 0, 0 }, // Grade AAA
|
|
{ 0, 0.9f, 1.2f, 0, 1.5f, 0, 0, 0, 0.75f, 1.5f, 0.3f, 0.3f, 0, 0, 0 }, // Grade AA
|
|
{ 0, 0.72f, 0.96f, 0, 1.2f, 0, 0, 0, 0.6f, 1.2f, 0.24f, 0.24f, 0, 0, 0 }, // Grade A
|
|
{ 0, 0.54f, 0.72f, 0, 0.9f, 0, 0, 0, 0.45f, 0.9f, 0.18f, 0.18f, 0, 0, 0 }, // Grade B
|
|
{ 0, 0.36f, 0.48f, 0, 0.6f, 0, 0, 0, 0.3f, 0.6f, 0.12f, 0.12f, 0, 0, 0 }, // Grade C
|
|
{ 0, 0.18f, 0.24f, 0, 0.3f, 0, 0, 0, 0.15f, 0.3f, 0.06f, 0.06f, 0, 0, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryLongRangeWeaponValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 1.08f, 1.44f, 0, 1.8f, 0, 0, 0, 0.9f, 1.8f, 0.36f, 0.36f, 0, 0, 0 }, // Grade AAA
|
|
{ 0, 0.9f, 1.2f, 0, 1.5f, 0, 0, 0, 0.75f, 1.5f, 0.3f, 0.3f, 0, 0, 0 }, // Grade AA
|
|
{ 0, 0.72f, 0.96f, 0, 1.2f, 0, 0, 0, 0.6f, 1.2f, 0.24f, 0.24f, 0, 0, 0 }, // Grade A
|
|
{ 0, 0.54f, 0.72f, 0, 0.9f, 0, 0, 0, 0.45f, 0.9f, 0.18f, 0.18f, 0, 0, 0 }, // Grade B
|
|
{ 0, 0.36f, 0.48f, 0, 0.6f, 0, 0, 0, 0.3f, 0.6f, 0.12f, 0.12f, 0, 0, 0 }, // Grade C
|
|
{ 0, 0.18f, 0.24f, 0, 0.3f, 0, 0, 0, 0.15f, 0.3f, 0.06f, 0.06f, 0, 0, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryTwoHandedWeaponValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 1.08f, 1.8f, 0, 1.8f, 0, 0, 0, 0.9f, 1.8f, 0.36f, 0.36f, 0, 0, 0 }, // Grade AAA
|
|
{ 0, 0.9f, 1.5f, 0, 1.5f, 0, 0, 0, 0.75f, 1.5f, 0.3f, 0.3f, 0, 0, 0 }, // Grade AA
|
|
{ 0, 0.72f, 1.2f, 0, 1.2f, 0, 0, 0, 0.6f, 1.2f, 0.24f, 0.24f, 0, 0, 0 }, // Grade A
|
|
{ 0, 0.54f, 0.9f, 0, 0.9f, 0, 0, 0, 0.45f, 0.9f, 0.18f, 0.18f, 0, 0, 0 }, // Grade B
|
|
{ 0, 0.36f, 0.6f, 0, 0.6f, 0, 0, 0, 0.3f, 0.6f, 0.12f, 0.12f, 0, 0, 0 }, // Grade C
|
|
{ 0, 0.18f, 0.3f, 0, 0.3f, 0, 0, 0, 0.15f, 0.3f, 0.06f, 0.06f, 0, 0, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryStaffValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 0, 1.8f, 0, 1.8f, 0, 0, 0, 1.8f, 3.6f, 0.36f, 0.36f, 0, 1.8f, 0 }, // Grade AAA
|
|
{ 0, 0, 1.5f, 0, 1.5f, 0, 0, 0, 1.5f, 3.0f, 0.3f, 0.3f, 0, 1.5f, 0 }, // Grade AA
|
|
{ 0, 0, 1.2f, 0, 1.2f, 0, 0, 0, 1.2f, 2.4f, 0.24f, 0.24f, 0, 1.2f, 0 }, // Grade A
|
|
{ 0, 0, 0.9f, 0, 0.9f, 0, 0, 0, 0.9f, 1.8f, 0.18f, 0.18f, 0, 0.9f, 0 }, // Grade B
|
|
{ 0, 0, 0.6f, 0, 0.6f, 0, 0, 0, 0.6f, 1.2f, 0.12f, 0.12f, 0, 0.6f, 0 }, // Grade C
|
|
{ 0, 0, 0.3f, 0, 0.3f, 0, 0, 0, 0.3f, 0.6f, 0.06f, 0.06f, 0, 0.3f, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
static const float aryShieldValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = {
|
|
// MinDam. MaxDam. Armor HitRate Evade MaxHP HPRegen MaxMP MPRegen Cri. Block Speed M.Power M.Res.
|
|
{ 0, 0, 0, 0, 0, 0, 0.45f, 0.9f, 0.45f, 0.9f, 0, 0.36f, 0, 0, 0 }, // Grade AAA
|
|
{ 0, 0, 0, 0, 0, 0, 0.375f, 0.75f, 0.375f, 0.75f, 0, 0.3f, 0, 0, 0 }, // Grade AA
|
|
{ 0, 0, 0, 0, 0, 0, 0.3f, 0.6f, 0.3f, 0.6f, 0, 0.24f, 0, 0, 0 }, // Grade A
|
|
{ 0, 0, 0, 0, 0, 0, 0.225f, 0.45f, 0.225f, 0.45f, 0, 0.18f, 0, 0, 0 }, // Grade B
|
|
{ 0, 0, 0, 0, 0, 0, 0.15f, 0.3f, 0.15f, 0.3f, 0, 0.12f, 0, 0, 0 }, // Grade C
|
|
{ 0, 0, 0, 0, 0, 0, 0.075f, 0.15f, 0.075f, 0.15f, 0, 0.06f, 0, 0, 0 }, // Grade D
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Grade F
|
|
};
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
|
|
if (0 == newItemInfo.m_DetailData.m_wDropOption)
|
|
{
|
|
return Item::Grade::GradeInfo();
|
|
}
|
|
|
|
float aryUsingValueGradeTable[EquipType::MAX_GRADE][Attribute::MAX_ATTRIBUTE_NUM] = { 0, };
|
|
|
|
switch (newItemInfo.m_DetailData.m_cItemType)
|
|
{
|
|
case ItemType::CON_ARMOUR: case ItemType::DEX_ARMOUR:
|
|
case ItemType::CON_HELM: case ItemType::DEX_HELM:
|
|
case ItemType::CON_BODY: case ItemType::DEX_BODY:
|
|
case ItemType::CON_HEAD: case ItemType::DEX_HEAD:
|
|
memcpy(aryUsingValueGradeTable, aryArmorValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::DAGGER:
|
|
case ItemType::OPP_TALON:
|
|
case ItemType::SKILL_A_KNIFE:
|
|
memcpy(aryUsingValueGradeTable, aryDaggerValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::ONEHANDED_SWORD:
|
|
case ItemType::ONEHANDED_AXE:
|
|
case ItemType::ONEHANDED_BLUNT:
|
|
case ItemType::COM_BLUNT:
|
|
case ItemType::COM_SWORD:
|
|
case ItemType::OPP_HAMMER:
|
|
case ItemType::OPP_SLUSHER:
|
|
case ItemType::SKILL_A_ATTACK:
|
|
memcpy(aryUsingValueGradeTable, aryOneHandedWeaponValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::BOW:
|
|
case ItemType::CROSSBOW:
|
|
case ItemType::SKILL_A_GUN:
|
|
memcpy(aryUsingValueGradeTable, aryLongRangeWeaponValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::TWOHANDED_SWORD:
|
|
case ItemType::TWOHANDED_AXE:
|
|
case ItemType::TWOHANDED_BLUNT:
|
|
memcpy(aryUsingValueGradeTable, aryTwoHandedWeaponValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::STAFF:
|
|
case ItemType::OPP_SYTHE:
|
|
memcpy(aryUsingValueGradeTable, aryStaffValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
case ItemType::SHIELD:
|
|
case ItemType::SKILL_A_GUARD:
|
|
memcpy(aryUsingValueGradeTable, aryShieldValueGradeTable,
|
|
sizeof(float) * EquipType::MAX_GRADE * Attribute::MAX_ATTRIBUTE_NUM);
|
|
break;
|
|
|
|
default:
|
|
return Item::Grade::GradeInfo();
|
|
}
|
|
|
|
// 아이템의 그레이드 정보를 초기화
|
|
Item::Grade::GradeInfo resultGradeInfo = Item::Grade::GradeInfo();
|
|
|
|
for (unsigned char cAttributeIndex = 0; cAttributeIndex < Attribute::MAX_ATTRIBUTE_NUM; ++cAttributeIndex)
|
|
{
|
|
// 속성값이 B 그레이드를 넘으면, B그레이드 값으로 고정한다.
|
|
|
|
short wMaxAttribute = static_cast<short>(
|
|
aryUsingValueGradeTable[EquipType::A_GRADE][cAttributeIndex] *
|
|
static_cast<float>(newItemInfo.m_DetailData.m_wDropOption));
|
|
|
|
if(wMaxAttribute < wNewAttribute[cAttributeIndex])
|
|
{
|
|
wNewAttribute[cAttributeIndex] = wMaxAttribute;
|
|
}
|
|
|
|
const float fGradeFactor = wNewAttribute[cAttributeIndex] /
|
|
static_cast<float>(newItemInfo.m_DetailData.m_wDropOption);
|
|
|
|
// D 그레이드를 초과하면 F 그레이드가 된다.
|
|
for (unsigned char cGradeIndex = 0; cGradeIndex <= EquipType::D_GRADE; ++cGradeIndex)
|
|
{
|
|
if (0 != aryUsingValueGradeTable[cGradeIndex][cAttributeIndex] &&
|
|
fGradeFactor > aryUsingValueGradeTable[cGradeIndex][cAttributeIndex])
|
|
{
|
|
resultGradeInfo.m_aryAttributeGrade[cAttributeIndex] =
|
|
static_cast<EquipType::Grade>(cGradeIndex);
|
|
|
|
if (resultGradeInfo.m_eItemGrade > resultGradeInfo.m_aryAttributeGrade[cAttributeIndex])
|
|
{
|
|
resultGradeInfo.m_eItemGrade = resultGradeInfo.m_aryAttributeGrade[cAttributeIndex];
|
|
resultGradeInfo.m_cPlus = 0;
|
|
}
|
|
else
|
|
{
|
|
if (resultGradeInfo.m_eItemGrade == resultGradeInfo.m_aryAttributeGrade[cAttributeIndex])
|
|
{
|
|
++resultGradeInfo.m_cPlus;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return resultGradeInfo;
|
|
}
|
|
|
|
const char* GetGradeString(Item::EquipType::Grade grade)
|
|
{
|
|
switch(grade)
|
|
{
|
|
case Item::EquipType::AAA_GRADE: return "AAA";
|
|
case Item::EquipType::AA_GRADE: return "AA";
|
|
case Item::EquipType::A_GRADE: return "A";
|
|
case Item::EquipType::B_GRADE: return "B";
|
|
case Item::EquipType::C_GRADE: return "C";
|
|
case Item::EquipType::D_GRADE: return "D";
|
|
case Item::EquipType::F_GRADE: return "F";
|
|
}
|
|
|
|
return "Unknown";
|
|
} |