Files
Client/Server/ToolProject/SkillConvert/SkillConvert.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

922 lines
25 KiB
C++

// SkillConvert.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <string>
#include <Log/ServerLog.h>
#include <DB/DBComponent.h>
#include <DB/GameDBComponent.h>
#include <Skill/SkillMgr.h>
#include <Utility/Math/Math.h>
#include <list>
using namespace std;
const int nHammerID = 0x8406;
const int nFirstAidID = 0x8405;
class CSkillConvert
{
public:
CSkillConvert() : m_fSrc(NULL), m_fConverted(NULL) { }
~CSkillConvert()
{
if(NULL != m_fSrc) { fclose(m_fSrc); m_fSrc = NULL; }
if(NULL != m_fConverted) { fclose(m_fConverted); m_fConverted = NULL; }
}
bool Initialize(char* szDBServerName, char* szDBName, char* szDBAccount, char* szDBPass);
bool Process();
void Test(const char* szFileName);
private:
bool ProcessSkill();
bool ProcessSkillBook();
bool ProcessSkillLevel();
// return : 업데이트 여부 - 업데이트시 True, 아니면 False
static bool ProcessEraseHammerOfLight(unsigned long dwCID, SKILL& Skill);
static int ProcessEraseHammerOfLightQuickSlot(unsigned long dwCID, QUICK& Quick);
// return : 업데이트한 아이템 갯수.
static int ProcessSkillBookConvert(unsigned long dwUID, unsigned long dwCID, const char* lpBuffer, int nSize);
static bool RecalculateSkill(unsigned long dwCID, SKILL& Skill);
static void EraseSkill(SKILL& Skill, unsigned short usErasePos);
// return : 업데이트 여부
bool AdjustSkillLevel(SKILL& skill);
bool AdjustQSlotSkillLevel(QUICK& quick);
CDBComponent m_ReadDB;
CDBComponent m_WriteDB;
FILE* m_fSrc;
FILE* m_fConverted;
};
void PrintUsage()
{
cout << "다음과 같이 입력하세요 : SkillConvert DB서버주소 DB이름 DB계정 DB패스워드" << endl
<< " 또는 : SkillConvert test testFileName" << endl << endl
<< " 테스트 파일의 포맷은 다음과 같은 포맷입니다. 엑셀로 작성한 후 cvs포맷으로 뽑으십시오" << endl
<< " CID,SkillNum,SlotNum,Skill_1,Skill_1_LockCount,Skill_1_Level,Skill_2,Skill_2_LockCount,Skill_2_Level,..." << endl;
}
void LogSkillToFile(FILE* fWriteFile, unsigned long dwCID, SKILL& Skill)
{
fprintf(fWriteFile, "%d,%d,%d,", dwCID, Skill.wSkillNum, Skill.wSlotNum);
for(int nSlot = 0; nSlot < SKILL::MAX_SLOT_NUM; ++nSlot)
{
if(0 != Skill.SSlot[nSlot].SKILLINFO.wSkill)
{
fprintf(fWriteFile, "0x%04x,%d,%d,", Skill.SSlot[nSlot].SKILLINFO.wSkill,
Skill.SSlot[nSlot].SKILLINFO.cLockCount,
Skill.SSlot[nSlot].SKILLINFO.cSkillLevel);
}
}
fprintf(fWriteFile, "\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
CSkillConvert Convert;
if(argc == 5)
{
if(!Convert.Initialize(argv[1], argv[2], argv[3], argv[4]))
{
cout << "[DB연결 실패]" << endl;
return -1;
}
}
else if(argc == 3)
{
if(0 == strcmp("test", argv[1]))
{
Convert.Test(argv[2]);
}
else
{
PrintUsage();
}
return 0;
}
else
{
PrintUsage();
return 0;
}
cout << "[DB 연결 성공]" << endl;
time_t CurrentTime = time(NULL);
DETLOG1(g_Log, "현재시간 : %s", ctime(&CurrentTime));
Convert.Process();
CurrentTime = time(NULL);
DETLOG1(g_Log, "종료시간 : %s", ctime(&CurrentTime));
cout << "Press Enter Key" << endl;
string temp;
getline(cin, temp);
return 0;
}
bool CSkillConvert::Initialize(char* szDBServerName, char* szDBName, char* szDBAccount, char* szDBPass)
{
// DB 연결
if(!m_ReadDB.Connect(szDBServerName, szDBName, szDBAccount, szDBPass))
{
cout << "[ReadDB 연결 실패]" << endl;
return false;
}
if(!m_WriteDB.Connect(szDBServerName, szDBName, szDBAccount, szDBPass))
{
cout << "[WriteDB 연결 실패]" << endl;
return false;
}
m_fSrc = fopen("SrcSkillLog.txt", "wt");
if(NULL == m_fSrc)
{
return false;
}
m_fConverted = fopen("ConvertedSkillLog.txt", "wt");
if(NULL == m_fConverted)
{
return false;
}
return true;
}
bool CSkillConvert::Process()
{
//ProcessSkill();
//ProcessSkillBook();
ProcessSkillLevel();
return true;
}
bool CSkillConvert::ProcessSkill()
{
char* szQuery = "select UID, Skill from CharSkill";
#pragma pack(1)
struct SkillData
{
unsigned long m_dwCID;
SKILL m_Skill;
};
#pragma pack()
if(!m_ReadDB.ExecuteQuery(szQuery))
{
cout << "[Skill 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
return false;
}
const int MAX_ROWS = 10240;
int nGetRows = 0;
SkillData* skillData = new SkillData[MAX_ROWS];
memset(skillData, 0, sizeof(SkillData) * MAX_ROWS);
while(m_ReadDB.GetData((void**)skillData, sizeof(SkillData), MAX_ROWS, &nGetRows))
{
if(0 == nGetRows)
{
break;
}
for(SkillData* lpSkillData = skillData;
0 < nGetRows; --nGetRows, ++lpSkillData)
{
const unsigned long dwCID = lpSkillData->m_dwCID;
SKILL& skill = lpSkillData->m_Skill;
SKILL oldSkill = lpSkillData->m_Skill;
bool bChanged = false;
if(ProcessEraseHammerOfLight(dwCID, skill))
{
bChanged = true;
}
// 마지막에 해 줄 것
if(RecalculateSkill(dwCID, skill))
{
bChanged = true;
}
if(bChanged)
{
LogSkillToFile(m_fSrc, dwCID, oldSkill);
LogSkillToFile(m_fConverted, dwCID, skill);
DBComponent::GameDB::UpdateCharSkill(m_WriteDB, dwCID, &skill);
}
}
}
delete [] skillData;
return true;
}
bool CSkillConvert::ProcessEraseHammerOfLight(unsigned long dwCID, SKILL& Skill)
{
/*
리턴값. 고치는 데 성공하면, true.
2. SKILL이, 해머 오브 라이트가 있는지 본다.
해머 오브 라이트가 있는 경우.. 퍼스트 에이드가 있는지 확인한다
퍼스트 에이드가 있으면,
해머 오브 라이트보다 레벨이 높거나 같다 - 해머 오브 라이트를 지운다.
해머 오브 라이트보다 레벨이 낮다 - 퍼스트에이드를 지우고, 해머오브라이트를 퍼스트에이드로 바꾼다.
퍼스트 에이드가 없으면, 해머 오브 라이트를 퍼스트 에이드로 바꾼다.
*/
if(20 < Skill.wSlotNum)
{
ERRLOG2(g_Log, "CID:%10d : 스킬 슬롯 개수가 이상합니다. %d개입니다.", dwCID, Skill.wSlotNum);
Skill.wSlotNum = 20;
}
for(int nHammerPos = 0; nHammerPos < Skill.wSlotNum; ++nHammerPos)
{
// 해머오브라이트가 있는지 확인
if(nHammerID == Skill.SSlot[nHammerPos].SKILLINFO.wSkill)
{
// 퍼스트에이드가 있는지 확인
for(int nFirstAidPos = 0; nFirstAidPos < Skill.wSlotNum; ++nFirstAidPos)
{
if(nFirstAidID == Skill.SSlot[nFirstAidPos].SKILLINFO.wSkill)
{
const int nHammerLevel = Skill.SSlot[nHammerPos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + Skill.SSlot[nHammerPos].SKILLINFO.cSkillLevel;
const int nFirstAidLevel = Skill.SSlot[nFirstAidPos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + Skill.SSlot[nFirstAidPos].SKILLINFO.cSkillLevel;
if(nHammerLevel <= nFirstAidLevel)
{
// 퍼스트에이드가 해머오브라이트보다 레벨이 높거나 같다. - 해머오브라이트를 지운다
EraseSkill(Skill, nHammerPos);
}
else
{
// 퍼스트에이드가 해머오브라이트보다 레벨이 낮다 -
// 퍼스트에이드를 지우고, 해머오브라이트를 퍼스트에이드로 바꾼다.
Skill.SSlot[nHammerPos].SKILLINFO.wSkill = nFirstAidID;
EraseSkill(Skill, nFirstAidPos);
}
return true;
}
}
// 퍼스트에이드가 없다.. -> 해머 오브 라이트를 퍼스트에이드로 바꾼다.
Skill.SSlot[nHammerPos].SKILLINFO.wSkill = nFirstAidID;
return true;
}
}
return false;
}
void CSkillConvert::EraseSkill(SKILL& Skill, unsigned short usErasePos)
{
if(usErasePos < Skill.wSlotNum)
{
const int nEraseSkillLevel =
Skill.SSlot[usErasePos].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL +
Skill.SSlot[usErasePos].SKILLINFO.cSkillLevel;
int nEraseCount = usErasePos;
for (; nEraseCount < Skill.wSlotNum - 1; ++nEraseCount)
{
Skill.SSlot[nEraseCount] = Skill.SSlot[nEraseCount + 1];
}
Skill.SSlot[nEraseCount].SKILLINFO.wSkill = 0;
Skill.SSlot[nEraseCount].SKILLINFO.cLockCount = 0;
Skill.SSlot[nEraseCount].SKILLINFO.cSkillLevel = 0;
Skill.wSkillNum -= nEraseSkillLevel;
--Skill.wSlotNum;
}
}
bool CSkillConvert::RecalculateSkill(unsigned long dwCID, SKILL& Skill)
{
unsigned short usOldSkillNum = Skill.wSkillNum;
unsigned short usOldSlotNum = Skill.wSlotNum;
unsigned short usNewSkillNum = 0;
unsigned short usNewSlotNum = 0;
for(int nCount = 0; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
{
if(0 == Skill.SSlot[nCount].SKILLINFO.wSkill)
{
for(; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
{
Skill.SSlot[nCount].SKILLINFO.wSkill = 0;
Skill.SSlot[nCount].SKILLINFO.cLockCount = 0;
Skill.SSlot[nCount].SKILLINFO.cSkillLevel = 0;
}
break;
}
else
{
usNewSkillNum += Skill.SSlot[nCount].SKILLINFO.cLockCount * (CSkillMgr::MAX_SKILL_LEVEL - 1) +
Skill.SSlot[nCount].SKILLINFO.cSkillLevel;
++usNewSlotNum;
}
}
if(usNewSkillNum != usOldSkillNum || usNewSlotNum != usOldSlotNum)
{
Skill.wSkillNum = usNewSkillNum;
Skill.wSlotNum = usNewSlotNum;
return true;
}
return false;
}
bool CSkillConvert::ProcessSkillBook()
{
char Query[MAX_PATH] = "";
int Rows = 0;
STORE Store1 = {0,};
STORE Store2 = {0,};
EQUIP EquipData = {0,};
INVEN InvenData = {0,};
EXTRA ExtraData = {0,};
EXCHANGE Exchange = {0,};
typedef std::list<DWORD> UIDList;
UIDList m_UIDList;
DWORD UIDs[CDBSingleObject::MaxRowNum];
sprintf(Query, "select UID from UserInfo");
for(int StartRows = 0;; StartRows += Rows)
{
memset(UIDs, 0, sizeof(DWORD) * CDBSingleObject::MaxRowNum);
if(!m_ReadDB.Select(Query, (void**)&UIDs, sizeof(DWORD), StartRows, CDBSingleObject::MaxRowNum, &Rows))
{
ERRLOG0(g_Log, "UID 얻기 실패");
return false;
}
for(int Count = 0; Count < Rows; ++Count)
{
m_UIDList.push_back(UIDs[Count]);
}
if(Rows != CDBSingleObject::MaxRowNum)
break;
}
DETLOG1(g_Log, "리스트 유저 숫자 : %d", m_UIDList.size());
DWORD UserID = 0;
USER_INFO UserInfo = {0,};
DWORD CharID[3] = {0,};
SKILL Skill;
SKILL oldSkill;
QUICK Quick;
int nCurrentCount = 0;
int nTotalCount = m_UIDList.size();
for(UIDList::iterator itr = m_UIDList.begin(); itr != m_UIDList.end(); ++itr)
{
UserID = *itr;
memset(&UserInfo, 0, sizeof(USER_INFO));
memset(&CharID, 0, sizeof(DWORD) * 3);
if(!DBComponent::GameDB::GetUserInfo(m_ReadDB, UserID, &UserInfo))
continue;
CharID[0] = UserInfo.Char1;
CharID[1] = UserInfo.Char2;
CharID[2] = UserInfo.Char3;
memset(&Store1, 0, sizeof(STORE));
memset(&Store2, 0, sizeof(STORE));
for(int Count = 0; Count < 3; ++Count)
{
if(0 == CharID[Count])
continue;
memset(&EquipData, 0, sizeof(EQUIP));
memset(&InvenData, 0, sizeof(INVEN));
memset(&ExtraData, 0, sizeof(EXTRA));
memset(&Exchange, 0, sizeof(EXCHANGE));
// 장비
if(!DBComponent::GameDB::GetEquip(m_ReadDB, CharID[Count], &EquipData))
{
ERRLOG2(g_Log, "장비 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], EquipData.Data, EquipData.dwSize))
{
if(!DBComponent::GameDB::UpdateEquip(m_WriteDB, CharID[Count], &EquipData))
{
ERRLOG2(g_Log, "장비 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
}
// 인벤
if(!DBComponent::GameDB::GetInven(m_ReadDB, CharID[Count], &InvenData))
{
ERRLOG2(g_Log, "인벤 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], InvenData.Data, InvenData.dwSize))
{
if(!DBComponent::GameDB::UpdateInven(m_WriteDB, CharID[Count], &InvenData))
{
ERRLOG2(g_Log, "인벤 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
}
// 여분
if(!DBComponent::GameDB::GetExtra(m_ReadDB, CharID[Count], &ExtraData))
{
ERRLOG2(g_Log, "여분 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], ExtraData.Data, ExtraData.dwSize))
{
if(!DBComponent::GameDB::UpdateExtra(m_WriteDB, CharID[Count], &ExtraData))
{
ERRLOG2(g_Log, "여분 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
}
// 교환
if(!DBComponent::GameDB::GetExchange(m_ReadDB, CharID[Count], &Exchange))
{
ERRLOG2(g_Log, "교환 읽기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
else if(0 < ProcessSkillBookConvert(UserID, CharID[Count], Exchange.Data, Exchange.dwSize))
{
if(!DBComponent::GameDB::UpdateExchange(m_WriteDB, CharID[Count], &Exchange))
{
ERRLOG2(g_Log, "교환 쓰기 실패 UID: %d CID: %d", UserID, CharID[Count]);
}
}
// 퀵슬롯
if(!DBComponent::GameDB::GetQuick(m_ReadDB, CharID[Count], &Quick))
{
ERRLOG2(g_Log, "퀵슬롯 읽기 실패 UID:%d, CID:%d", CharID[Count], UserID);
}
else
{
if(0 < ProcessEraseHammerOfLightQuickSlot(CharID[Count], Quick))
{
if(!DBComponent::GameDB::UpdateQuick(m_WriteDB, CharID[Count], &Quick))
{
ERRLOG2(g_Log, "퀵슬롯 쓰기 실패 UID:%d, CID:%d", CharID[Count], UserID);
}
}
}
// 스킬
if(!DBComponent::GameDB::GetCharSkill(m_ReadDB, CharID[Count], &Skill))
{
ERRLOG2(g_Log, "스킬 읽기 실패 UID:%d, CID:%d", CharID[Count], UserID);
}
else
{
oldSkill = Skill;
bool bChanged = false;
if(ProcessEraseHammerOfLight(CharID[Count], Skill))
{
bChanged = true;
}
// 마지막에 해 줄 것
if(RecalculateSkill(CharID[Count], Skill))
{
bChanged = true;
}
if(bChanged)
{
LogSkillToFile(m_fSrc, CharID[Count], oldSkill);
LogSkillToFile(m_fConverted, CharID[Count], Skill);
if(!DBComponent::GameDB::UpdateCharSkill(m_WriteDB, CharID[Count], &Skill))
{
ERRLOG2(g_Log, "스킬 쓰기 실패 UID:%d, CID:%d", CharID[Count], UserID);
}
}
}
}
// 창고1
if(!DBComponent::GameDB::GetItemStore1(m_ReadDB, UserID, &Store1))
{
ERRLOG1(g_Log, "창고1 읽기 실패 UID: %d", UserID);
}
else if(0 < ProcessSkillBookConvert(UserID, 0, Store1.Data, Store1.dwSize))
{
if(!DBComponent::GameDB::UpdateItemStore1(m_WriteDB, UserID, &Store1))
{
ERRLOG1(g_Log, "창고1 쓰기 실패 UID: %d", UserID);
}
}
// 창고 2
if(!DBComponent::GameDB::GetItemStore2(m_ReadDB, UserID, &Store2))
{
ERRLOG1(g_Log, "창고2 읽기 실패 UID: %d", UserID);
}
else if(0 < ProcessSkillBookConvert(UserID, 0, Store2.Data, Store2.dwSize))
{
if(!DBComponent::GameDB::UpdateItemStore2(m_WriteDB, UserID, &Store2))
{
ERRLOG1(g_Log, "창고2 쓰기 실패 UID: %d", UserID);
}
}
cout << ".";
if(0 != (nCurrentCount % 10000))
{
cout << endl << nCurrentCount << "/" << nTotalCount << endl;
}
}
return true;
}
int CSkillConvert::ProcessSkillBookConvert(unsigned long dwUID, unsigned long dwCID, const char* lpBuffer, int nSize)
{
const char* lpItemBuff = lpBuffer;
int nItemSize = nSize;
int nConvertNum = 0;
int nLoopCount = 0;
while(nItemSize > 0)
{
Item::ItemData* lpItem = (Item::ItemData*)lpItemBuff;
// ---------------------------------------------------------------------------------------
// 해머오브라이트 계열 스킬북을 퍼스트에이드 계열 스킬북으로 바꿉니다.
switch(lpItem->m_usProtoTypeID)
{
case 3558: lpItem->m_usProtoTypeID = 3553; ++nConvertNum; break;
case 3559: lpItem->m_usProtoTypeID = 3554; ++nConvertNum; break;
case 3560: lpItem->m_usProtoTypeID = 3555; ++nConvertNum; break;
case 3561: lpItem->m_usProtoTypeID = 3556; ++nConvertNum; break;
case 3562: lpItem->m_usProtoTypeID = 3557; ++nConvertNum; break;
}
// ---------------------------------------------------------------------------------------
// 다음 아이템을 진행합니다.
lpItemBuff += lpItem->m_cItemSize;
nItemSize -= lpItem->m_cItemSize;
++nLoopCount;
if(10000 < ++nLoopCount)
{
// 뭔가 이상하다. break한다.
SERLOG2(g_Log, "UID:%u/CID:%u/ 이상한 아이템을 지니고 있습니다. 확인해 주세요", dwUID, dwCID);
return -1;
}
}
return nConvertNum;
}
int CSkillConvert::ProcessEraseHammerOfLightQuickSlot(unsigned long dwCID, QUICK& Quick)
{
int nErased = 0;
for(int nCount = 0; nCount < QUICK::MAX_QUICK_NUM; ++nCount)
{
if(Quick.Slots[nCount].nType == QUICKSLOT::SKILL &&
(Quick.Slots[nCount].wID == nHammerID || Quick.Slots[nCount].wID == nFirstAidID))
{
Quick.Slots[nCount].wID = 0;
Quick.Slots[nCount].nType = QUICKSLOT::NONE;
Quick.Slots[nCount].nSkillLevel = 0;
Quick.Slots[nCount].nSkillLockCount = 0;
++nErased;
}
}
return nErased;
}
void CSkillConvert::Test(const char* szFileName)
{
const char* szDelimit = ",";
unsigned long dwCID = 0;
SKILL Skill;
FILE* fReadFile = fopen(szFileName, "rt");
if(NULL != fReadFile)
{
char szWriteFile[MAX_PATH];
_snprintf(szWriteFile, MAX_PATH, "Result%s", szFileName);
szWriteFile[MAX_PATH - 1] = 0;
FILE* fWriteFile = fopen(szWriteFile, "wt");
if(NULL != fWriteFile)
{
const int MAX_DATA_LEN = 4096;
char szData[MAX_DATA_LEN];
while(fgets(szData, MAX_DATA_LEN, fReadFile))
{
memset(&Skill, 0, sizeof(SKILL));
char* szBuffer = strtok(szData, szDelimit);
if(NULL == szBuffer)
{
break;
}
dwCID = atoi(szBuffer);
szBuffer = strtok(NULL, szDelimit);
if(NULL == szBuffer)
{
break;
}
Skill.wSkillNum = atoi(szBuffer);
szBuffer = strtok(NULL, szDelimit);
if(NULL == szBuffer)
{
break;
}
Skill.wSlotNum = atoi(szBuffer);
szBuffer = strtok(NULL, szDelimit);
int nSlot = 0;
while(NULL != szBuffer && nSlot < SKILL::MAX_SLOT_NUM)
{
Skill.SSlot[nSlot].SKILLINFO.wSkill = Math::Convert::Atos(szBuffer); // 스킬 ID
szBuffer = strtok(NULL, szDelimit);
if(NULL == szBuffer)
{
break;
}
Skill.SSlot[nSlot].SKILLINFO.cLockCount = Math::Convert::Atoc(szBuffer);
szBuffer = strtok(NULL, szDelimit);
if(NULL == szBuffer)
{
break;
}
Skill.SSlot[nSlot].SKILLINFO.cSkillLevel = Math::Convert::Atoc(szBuffer);
++nSlot;
szBuffer = strtok(NULL, szDelimit);
}
ProcessEraseHammerOfLight(dwCID, Skill);
RecalculateSkill(dwCID, Skill);
LogSkillToFile(fWriteFile, dwCID, Skill);
}
fclose(fWriteFile);
}
fclose(fReadFile);
}
}
bool CSkillConvert::ProcessSkillLevel()
{
char* szQuery = "select UID, Skill from CharSkill";
#pragma pack(1)
struct SkillData
{
unsigned long m_dwCID;
SKILL m_Skill;
};
#pragma pack()
if(!m_ReadDB.ExecuteQuery(szQuery))
{
cout << "[Skill 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
return false;
}
const int MAX_ROWS = 10240;
int nGetRows = 0;
SkillData* skillData = new SkillData[MAX_ROWS];
memset(skillData, 0, sizeof(SkillData) * MAX_ROWS);
while(m_ReadDB.GetData((void**)skillData, sizeof(SkillData), MAX_ROWS, &nGetRows))
{
if(0 == nGetRows)
{
break;
}
for(SkillData* lpSkillData = skillData;
0 < nGetRows; --nGetRows, ++lpSkillData)
{
const unsigned long dwCID = lpSkillData->m_dwCID;
SKILL& skill = lpSkillData->m_Skill;
SKILL oldSkill = lpSkillData->m_Skill;
bool bChanged = false;
if(AdjustSkillLevel(skill))
{
bChanged = true;
}
// 스킬 레벨을 조정한다.
if(bChanged)
{
LogSkillToFile(m_fSrc, dwCID, oldSkill);
LogSkillToFile(m_fConverted, dwCID, skill);
DBComponent::GameDB::UpdateCharSkill(m_WriteDB, dwCID, &skill);
}
}
}
delete [] skillData;
szQuery = "select UID, Quick from CharItem";
#pragma pack(1)
struct QSlotData
{
unsigned long m_dwCID;
QUICK m_Quick;
};
#pragma pack()
if(!m_ReadDB.ExecuteQuery(szQuery))
{
cout << "[Quick 쿼리 실패] : " << m_ReadDB.GetErrorString() << endl;
return false;
}
nGetRows = 0;
QSlotData* qslotdata = new QSlotData[MAX_ROWS];
memset(qslotdata, 0, sizeof(QSlotData) * MAX_ROWS);
while(m_ReadDB.GetData((void**)qslotdata, sizeof(QSlotData), MAX_ROWS, &nGetRows))
{
if(0 == nGetRows)
{
break;
}
for(QSlotData* lpQSlotData = qslotdata;
0 < nGetRows; --nGetRows, ++lpQSlotData)
{
const unsigned long dwCID = lpQSlotData->m_dwCID;
QUICK& quick = lpQSlotData->m_Quick;
QUICK oldquick = lpQSlotData->m_Quick;
bool bChanged = false;
if(AdjustQSlotSkillLevel(quick))
{
bChanged = true;
}
// 스킬 레벨을 조정한다.
if(bChanged)
{
DBComponent::GameDB::UpdateQuick(m_WriteDB, dwCID, &quick);
}
}
}
delete [] qslotdata;
return true;
}
bool CSkillConvert::AdjustSkillLevel(SKILL& skill)
{
int nChangedCount = 0;
for(int nCount = 0; nCount < SKILL::MAX_SLOT_NUM; ++nCount)
{
if(6 == skill.SSlot[nCount].SKILLINFO.cSkillLevel)
{
if(skill.SSlot[nCount].SKILLINFO.cLockCount < 3)
{
++skill.SSlot[nCount].SKILLINFO.cLockCount;
skill.SSlot[nCount].SKILLINFO.cSkillLevel = 0;
++nChangedCount;
}
else
{
skill.SSlot[nCount].SKILLINFO.cLockCount = 3;
skill.SSlot[nCount].SKILLINFO.cSkillLevel = 6;
++nChangedCount;
}
}
}
return (0 < nChangedCount);
}
bool CSkillConvert::AdjustQSlotSkillLevel(QUICK& quick)
{
int nChangedCount = 0;
for(int nCount = 0; nCount < QUICK::MAX_QUICK_NUM; ++nCount)
{
if(QUICKSLOT::SKILL == quick.Slots[nCount].nType &&
6 == quick.Slots[nCount].nSkillLevel)
{
if(quick.Slots[nCount].nSkillLockCount < 3)
{
++quick.Slots[nCount].nSkillLockCount;
quick.Slots[nCount].nSkillLevel = 0;
++nChangedCount;
}
else
{
quick.Slots[nCount].nSkillLockCount = 3;
quick.Slots[nCount].nSkillLevel = 6;
++nChangedCount;
}
}
}
return (0 < nChangedCount);
}