Files
Client/Server/RylServerProject/RylGameLibrary/Network/Dispatch/GameClient/ParseCharUpgradeItem.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

716 lines
22 KiB
C++

#include "stdafx.h"
#include "ParseCharUpgradeItem.h"
#include "SendCharUpgradeItem.h"
#include "GameClientDispatch.h"
#include <Network/Dispatch/ParseUtils.h>
#include <Network/Packet/PacketStruct/CharItemPacket.h>
#include <Log/ItemLog.h>
#include <Log/LogStruct.h>
#include <Item/Item.h>
#include <Item/ItemStructure.h>
#include <Item/ItemFactory.h>
#include <Item/ItemMgr.h>
#include <Creature/Character/Character.h>
#include <Creature/Npc/NPC.h>
#include <Castle/Castle.h>
#include <Castle/CastleConstants.h>
#include <Castle/CastleMgr.h>
// 아이템 인스톨 소켓
bool GameClientParsePacket::ParseCharInstallSocket(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktIS), GameClientDispatch);
PktIS* lpPktIS = static_cast<PktIS *>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
unsigned long dwCharID = lpPktIS->m_dwCharID;
Item::ItemPos EquipPos = lpPktIS->m_equipPos;
Item::ItemPos GemPos = lpPktIS->m_gemPos;
Item::CEquipment* lpEquipment = Item::CEquipment::DowncastToEquipment(lpCharacter->GetItem(EquipPos));
Item::CItem* lpGem = lpCharacter->GetItem(GemPos);
unsigned short wError = PktBase::NO_SERVER_ERR;
if (NULL != lpEquipment)
{
if (NULL != lpGem)
{
wError = lpEquipment->InstallSocket(*lpGem);
}
else
{
wError = Item::CEquipment::E_GET_GEM_FAILED;
}
}
else
{
wError = Item::CEquipment::E_GET_EQUIP_FAILED;
}
GAMELOG::LogInstallSocket(*lpCharacter, TakeType(GemPos, EquipPos, 1),
lpGem, lpEquipment, static_cast<GAMELOG::ERRType>(wError));
// 젬 개수가 0이면 아이템을 삭제합니다.
if (NULL != lpGem)
{
if (0 == lpGem->GetNumOrDurability())
{
if (lpCharacter->RemoveItem(GemPos))
{
DELETE_ITEM(lpGem);
}
else
{
wError = Item::CEquipment::E_REMOVE_GEM_FAILED;
ERRLOG1(g_Log, "CID:0x%08x 설치한 보석을 제거하는 데 실패했습니다", lpCharacter->GetCID());
}
}
}
if (PktBase::NO_SERVER_ERR == wError && TakeType::TS_EQUIP == EquipPos.m_cPos)
{
lpCharacter->CalculateStatusData(false);
}
if (PktBase::NO_SERVER_ERR != wError)
{
lpEquipment = NULL;
}
return GameClientSendPacket::SendCharInstallSocket(GameClientDispatch.GetSendStream(), dwCharID,
EquipPos, GemPos, lpEquipment, wError);
}
// 아이템 합성
bool GameClientParsePacket::ParseCharItemChemical(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktItemChemical), GameClientDispatch);
PktItemChemical* lpPktIC = static_cast<PktItemChemical *>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
unsigned long dwCharID = lpPktIC->m_dwCharID;
Item::ItemPos PickkingPos = lpPktIC->m_pickkingPos;
Item::ItemPos TargetPos = lpPktIC->m_targetPos;
unsigned char cPickkingNum = lpPktIC->m_cPickkingNum;
unsigned short wError = PktBase::NO_SERVER_ERR;
Item::CItem* lpPickkingItem = lpCharacter->GetItem(PickkingPos);
Item::CItem* lpTargetItem = lpCharacter->GetItem(TargetPos);
Item::CItem* lpResultItem = NULL;
Item::ChemicalInfo chemicalInfo;
unsigned short wPickkingItemID = 0;
unsigned char cPickkingItemNum = 0;
if (NULL == lpPickkingItem || NULL == lpTargetItem)
{
ERRLOG5(g_Log, "CID:0x%08x 존재하지 않는 아이템입니다. "
"들고 있는 아이템 위치 : (%d, 0x%04x), 합성 대상 아이템 위치 : (%d, 0x%04x)",
dwCharID, PickkingPos.m_cPos, PickkingPos.m_cIndex, TargetPos.m_cPos, TargetPos.m_cIndex);
lpCharacter->GetInventory().DumpItemInfo();
wError = PktBase::SERVER_ERROR;
}
else
{
// 스플릿 후 바로 합성하려할 경우 임시 공간으로 스플릿해준다.
if (0 < cPickkingNum && cPickkingNum < lpPickkingItem->GetNumOrDurability())
{
Item::ItemPos HoldPos(TakeType::TS_TEMP, Item::ExtraSpacePos::HOLDITEM_POS);
Item::CItem* lpHoldItem = lpCharacter->GetItem(HoldPos);
if (NULL != lpHoldItem)
{
ERRLOG1(g_Log, "CID:0x08x 아이템 합성 실패 : 이미 잡고 있는 아이템이 있는 상태에서 스플릿 아이템 합성을 시도합니다.",
dwCharID);
wError = PktBase::SERVER_ERROR;
goto SEND_PACKET;
}
Item::CItem* lpSplitItem = Item::CItemFactory::GetInstance().CreateItem(lpPickkingItem->GetItemInfo());
if (NULL == lpSplitItem)
{
ERRLOG1(g_Log, "CID:0x08x 아이템 합성 실패 : 아이템을 생성할 수 없습니다.", dwCharID);
wError = PktBase::SERVER_ERROR;
goto SEND_PACKET;
}
lpSplitItem->SetNumOrDurability(cPickkingNum);
if (false == lpCharacter->SetItem(HoldPos, lpSplitItem))
{
ERRLOG1(g_Log, "CID:0x08x 아이템 합성 실패 : 임시 공간에 스플릿한 아이템을 놓을 수 없습니다.", dwCharID);
wError = PktBase::SERVER_ERROR;
DELETE_ITEM(lpSplitItem);
goto SEND_PACKET;
}
lpPickkingItem->SetNumOrDurability(lpPickkingItem->GetNumOrDurability() - cPickkingNum);
// 스플릿한 아이템을 들고 있는 아이템을 대치해서 합성을 진행한다.
lpPickkingItem = lpSplitItem;
PickkingPos = lpPickkingItem->GetPos();
}
chemicalInfo.m_wPickkingItemID = lpPickkingItem->GetPrototypeID();
chemicalInfo.m_cPickkingItemNum = lpPickkingItem->GetNumOrDurability();
chemicalInfo.m_wTargetItemID = lpTargetItem->GetPrototypeID();
chemicalInfo.m_cTargetItemNum = lpTargetItem->GetNumOrDurability();
wError = Item::CItemMgr::GetInstance().GetChemicalResult(chemicalInfo);
// 여기서 완료된 퀘스트, 어빌리티를 검사한다.
if (PktBase::NO_SERVER_ERR == wError && chemicalInfo.m_usQuestID != 0)
{
// 완료 퀘스트 검사
if( !lpCharacter->HasHistoryQuest(chemicalInfo.m_usQuestID) )
wError = Item::Chemical::F_NOT_QUEST;
}
if (PktBase::NO_SERVER_ERR == wError && chemicalInfo.m_usAbilityID != 0)
{
// 어빌리티 검사
short sLockCount = lpCharacter->GetSkillLockCount(chemicalInfo.m_usAbilityID);
if(chemicalInfo.m_cAbilityLevel <= sLockCount)
wError = PktBase::NO_SERVER_ERR;
else
wError = Item::Chemical::F_NOT_ABILITY;
}
if (PktBase::NO_SERVER_ERR == wError)
{
// 들고 있는 아이템 처리
if (0 == chemicalInfo.m_cPickkingItemNum)
{
if (true == lpCharacter->RemoveItem(PickkingPos))
{
DELETE_ITEM(lpPickkingItem);
}
else
{
ERRLOG1(g_Log, "CID:0x%08x 들고 있는 아이템 제거에 실패하였습니다.", dwCharID);
wError = PktBase::SERVER_ERROR;
goto SEND_PACKET;
}
}
else
{
lpPickkingItem->SetNumOrDurability(chemicalInfo.m_cPickkingItemNum);
wPickkingItemID = chemicalInfo.m_wPickkingItemID;
cPickkingItemNum = chemicalInfo.m_cPickkingItemNum;
}
// 합성 대상 아이템 처리
if (0 == chemicalInfo.m_cTargetItemNum)
{
if (true == lpCharacter->RemoveItem(TargetPos))
{
DELETE_ITEM(lpTargetItem);
}
else
{
ERRLOG1(g_Log, "CID:0x%08x 합성 대상 아이템 제거에 실패하였습니다.", dwCharID);
wError = PktBase::SERVER_ERROR;
goto SEND_PACKET;
}
}
else
{
lpTargetItem->SetNumOrDurability(chemicalInfo.m_cTargetItemNum);
lpCharacter->RemoveItem(TargetPos);
lpCharacter->SetItem(PickkingPos, lpTargetItem);
wPickkingItemID = chemicalInfo.m_wTargetItemID;
cPickkingItemNum = chemicalInfo.m_cTargetItemNum;
}
// 합성 결과물 처리
lpResultItem = Item::CItemFactory::GetInstance().CreateItem(chemicalInfo.m_wResultItemID);
lpResultItem->SetNumOrDurability(chemicalInfo.m_cResultItemNum);
lpCharacter->SetItem(TargetPos, lpResultItem);
}
}
SEND_PACKET:
return GameClientSendPacket::SendCharItemChemical(GameClientDispatch.GetSendStream(), dwCharID,
PickkingPos, TargetPos, wPickkingItemID, cPickkingItemNum, lpResultItem, wError);
}
// 아이템 업그레이드
bool GameClientParsePacket::ParseCharUpgradeItem(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktUgI), GameClientDispatch);
PktUgI* lpPktUgl = static_cast<PktUgI *>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
using namespace Item;
unsigned long dwCID = lpCharacter->GetCID();
unsigned long dwNPCID = lpPktUgl->m_dwNPCID;
unsigned short wError = Item::CEquipment::S_SUCCESS;
unsigned long dwUsedGold = 0;
unsigned char cCurrentMineralNum = 0;
unsigned char cValue = 0;
Item::CItem* lpDstItem = lpCharacter->GetItem(ItemPos(TakeType::TS_EXTRA, ExtraSpacePos::UPGRADE_EQUIPMENT_POS));
Item::CItem* lpMineral = lpCharacter->GetItem(ItemPos(TakeType::TS_EXTRA, ExtraSpacePos::UPGRADE_MATERIAL_POS));
Item::CEquipment* lpEquipment = Item::CEquipment::DowncastToEquipment(lpDstItem);
unsigned char cLastUpgradeLevel = 0;
if (NULL == lpDstItem)
{
wError = Item::CEquipment::E_GET_EQUIP_FAILED;
}
else if (NULL == lpMineral)
{
wError = Item::CEquipment::E_GET_MINERAL_FAILED;
}
else if (NULL == lpEquipment || !lpEquipment->IsUpgradable())
{
wError = Item::CEquipment::E_NOT_EQUIP;
}
else
{
if(lpMineral->GetPrototypeID() == Item::EtcItemID::AWAKENCORE)
cLastUpgradeLevel = lpEquipment->GetCoreLevel();
else
cLastUpgradeLevel = lpEquipment->GetUpgradeLevel();
// lpEquipment는 여기서만 사용
wError = lpEquipment->UpgradeItem(*lpMineral, lpCharacter->GetGold(), dwUsedGold, cValue);
// 성에 속한 NPC 라면, 제련 세율 적용
CNPC* lpNPC = CCreatureManager::GetInstance().GetNPC(dwNPCID);
if (NULL != lpNPC && lpNPC->IsBelongToCastle())
{
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastleByNameID(lpNPC->GetCastleNameID());
if (NULL != lpCastle)
{
const unsigned long dwResmeltTax = static_cast<unsigned long>(dwUsedGold * (lpCastle->GetTax(Castle::RESMELT_TAX) / 100.0f));
if (dwResmeltTax > 0)
{
lpCastle->AddTempTaxMoney(Castle::RESMELT_TAX, dwResmeltTax);
dwUsedGold += dwResmeltTax;
}
}
}
if (0 < dwUsedGold)
{
if (dwUsedGold > lpCharacter->GetGold())
{
wError = Item::CEquipment::E_NOT_ENOUGH_MONEY;
}
else
{
// 돈을 제거
lpCharacter->DeductGold(dwUsedGold, false);
}
}
// 광물이 다 떨어졌으면 광물 제거
cCurrentMineralNum = lpMineral->GetNumOrDurability();
if (0 == cCurrentMineralNum)
{
if (false == lpCharacter->RemoveItem(lpMineral->GetPos()))
{
wError = Item::CEquipment::E_REMOVE_GEM_FAILED;
ERRLOG1(g_Log, "CID:0x%08x 업그레이드시 다 사용한 광물 제거에 실패했습니다.", dwCID);
}
else
{
DELETE_ITEM(lpMineral);
}
}
// 업그레이드 실패시에 장비 없애고 고철 넣음
if (wError == Item::CEquipment::S_BROKEN_EQUIP)
{
if (false == lpCharacter->RemoveItem(ItemPos(TakeType::TS_EXTRA,
ExtraSpacePos::UPGRADE_EQUIPMENT_POS)))
{
wError = Item::CEquipment::E_REMOVE_EQUIP_FAILED;
ERRLOG1(g_Log, "CID:0x%08x 업그레이드 실패시 장비 제거에 실패했습니다.", dwCID);
}
else
{
DELETE_ITEM(lpDstItem);
lpDstItem = Item::CItemFactory::GetInstance().CreateItem(EtcItemID::SCRAPS);
if (NULL == lpDstItem)
{
wError = Item::CEquipment::E_CREATE_SCRAP_FAILED;
ERRLOG1(g_Log, "CID:0x%08x 업그레이드 실패시 고철 생성에 실패했습니다.", dwCID);
}
else
{
if (false == lpCharacter->SetItem(ItemPos(TakeType::TS_EXTRA,
ExtraSpacePos::UPGRADE_EQUIPMENT_POS), lpDstItem))
{
wError = Item::CEquipment::E_SET_SCRAP_FAILED;
ERRLOG1(g_Log, "CID:0x%08x 생성한 고철을 업그레이드창에 놓는 데 실패했습니다.", dwCID);
DELETE_ITEM(lpDstItem);
}
}
}
}
}
if (wError == Item::CEquipment::S_BROKEN_EQUIP || wError == Item::CEquipment::S_SUCCESS)
{
wError = Item::CEquipment::S_SUCCESS;
}
else
{
lpDstItem = NULL;
lpMineral = NULL;
}
GAMELOG::LogUpgradeItem(*lpCharacter, lpCharacter->GetGold(), dwUsedGold,
cLastUpgradeLevel, lpDstItem, lpMineral, cValue, wError);
return GameClientSendPacket::SendCharUpgradeItem(GameClientDispatch.GetSendStream(),
dwCID, lpCharacter->GetGold(), lpDstItem, cCurrentMineralNum, cValue, wError);
}
// 아이템 옵션 이식
bool GameClientParsePacket::ParseCharItemOptionGraft(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktItemOptionGraft), GameClientDispatch);
PktItemOptionGraft* lpPktIOG = static_cast<PktItemOptionGraft *>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
unsigned long dwCID = lpPktIOG->m_dwCharID;
unsigned char cAttributeType = lpPktIOG->m_cAttributeType;
unsigned short wError = PktBase::NO_SERVER_ERR;
unsigned long dwUsedGold = 0;
using namespace Item;
Item::CEquipment* lpOriginalItem = Item::CEquipment::DowncastToEquipment(
lpCharacter->GetItem(Item::ItemPos(TakeType::TS_EXTRA, Item::ExtraSpacePos::GRAFT_ORIGINAL_POS)));
Item::CEquipment* lpSacrificeItem = Item::CEquipment::DowncastToEquipment(
lpCharacter->GetItem(Item::ItemPos(TakeType::TS_EXTRA, Item::ExtraSpacePos::GRAFT_SACRIFICE_POS)));
size_t nOldItemSize = 0;
size_t nUseItemSize = 0;
char szOldItemData[Item::MAX_ITEM_SIZE];
char szUseItemData[Item::MAX_ITEM_SIZE];
unsigned long dwOldGold = lpCharacter->GetGold();
if (NULL == lpOriginalItem || NULL == lpSacrificeItem)
{
// 옵션 이식할 장비가 없습니다.
wError = PktBase::SERVER_ERROR;
}
else
{
// edith 아이템 옵션이식 패킷
// 로그 기록을 위해 item serialize를 한다.
nOldItemSize = Item::MAX_ITEM_SIZE;
if(!lpOriginalItem->SerializeOut(szOldItemData, nOldItemSize))
{
nOldItemSize = 0;
}
nUseItemSize = Item::MAX_ITEM_SIZE;
if(!lpSacrificeItem->SerializeOut(szUseItemData, nUseItemSize))
{
nUseItemSize = 0;
}
bool bUpgradeLevelLimit = false;
wError = lpOriginalItem->OptionGraft(lpSacrificeItem, bUpgradeLevelLimit, cAttributeType, lpCharacter->GetGold(), dwUsedGold);
if (PktBase::NO_SERVER_ERR == wError || wError == 5) // 5면 옵션이식 실패로 금액과 제물만 제거.
{
// 사용 금액
lpCharacter->DeductGold(dwUsedGold, false);
// 제물 아이템 제거
if (false == lpCharacter->RemoveItem(lpSacrificeItem->GetPos()))
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 아이템 옵션 이식 실패 : 제물 아이템 제거에 실패하였습니다.", dwCID);
}
else
{
DELETE_ITEM(lpSacrificeItem);
}
// 원본 아이템은 결과 아이템으로 이동
lpCharacter->MoveItem(TakeType(lpOriginalItem->GetPos(),
ItemPos(TakeType::TS_EXTRA, ExtraSpacePos::GRAFT_RESULT_POS), 1));
}
}
// 게임 로그
GAMELOG::LogItemAttachOption(*lpCharacter, dwOldGold, cAttributeType,
szOldItemData, nOldItemSize, szUseItemData, nUseItemSize, lpOriginalItem, wError);
return GameClientSendPacket::SendCharItemOptionGraft(GameClientDispatch.GetSendStream(),
dwCID, lpCharacter->GetGold(), lpOriginalItem, wError);
}
// 아이템 보상 판매
bool GameClientParsePacket::ParseCharItemCompensation(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktItemCompensation), GameClientDispatch);
PktItemCompensation* lpPktPIC = static_cast<PktItemCompensation *>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
unsigned long dwCID = lpPktPIC->m_dwCharID;
unsigned short wError = PktBase::NO_SERVER_ERR;
Item::CItem* lpOriginalItem = lpCharacter->GetItem(Item::ItemPos(TakeType::TS_EXTRA, Item::ExtraSpacePos::COMPENSATION_POS));
unsigned long dwOldGold = lpCharacter->GetGold();
Item::CEquipment* lpOriginalEquip = Item::CEquipment::DowncastToEquipment(lpOriginalItem);
if (NULL == lpOriginalEquip)
{
ERRLOG1(g_Log, "CID:0x%08x 보상 판매 실패 : 보상 판매할 아이템이 없습니다.", lpCharacter->GetCID());
wError = PktBase::SERVER_ERROR;
}
else
{
Item::CEquipment* lpResultItem = NULL;
long lResultGold = 0;
wError = lpOriginalEquip->Compensation(
static_cast<unsigned char>(lpCharacter->GetClass()), static_cast<unsigned char>(lpCharacter->GetLevel()),
lpCharacter->GetCharStatus(), &lpResultItem, lResultGold);
if (NULL == lpResultItem)
{
ERRLOG1(g_Log, "CID:0x%08x 보상 판매 실패 : 보상 판매에 실패하였습니다.", lpCharacter->GetCID());
wError = PktBase::SERVER_ERROR;
}
if (0 > lResultGold && static_cast<unsigned long>(abs(lResultGold)) > lpCharacter->GetGold())
{
ERRLOG1(g_Log, "CID:0x%08x 보상 판매 실패 : 돈이 부족합니다.", lpCharacter->GetCID());
wError = PktBase::SERVER_ERROR;
}
if (PktBase::NO_SERVER_ERR == wError)
{
if (false == lpCharacter->RemoveItem(lpOriginalEquip->GetPos()))
{
ERRLOG1(g_Log, "CID:0x%08x 보상 판매 실패 : 원본 아이템을 제거하는데 실패하였습니다.", lpCharacter->GetCID());
wError = PktBase::SERVER_ERROR;
DELETE_ITEM(lpResultItem);
}
else
{
if (false == lpCharacter->GiveItem(lpResultItem))
{
ERRLOG1(g_Log, "CID:0x%08x 보상 판매 실패 : 보상 아이템을 주는데 실패하였습니다.", lpCharacter->GetCID());
wError = PktBase::SERVER_ERROR;
lpCharacter->SetItem(Item::ItemPos(TakeType::TS_EXTRA,
Item::ExtraSpacePos::COMPENSATION_POS), lpOriginalItem);
DELETE_ITEM(lpResultItem);
}
else
{
if (0 < lResultGold)
{
lpCharacter->AddGold(lResultGold, true);
}
else
{
lpCharacter->DeductGold(abs(lResultGold), true);
}
GAMELOG::LogItemCompensation(*lpCharacter, dwOldGold, lpOriginalItem, lpResultItem, 0);
GameClientSendPacket::SendCharItemCompensation(GameClientDispatch.GetSendStream(), dwCID, 0);
DELETE_ITEM(lpOriginalItem);
// GiveItem 으로 스택된 경우
if (lpResultItem->IsSet(Item::DetailData::STACKABLE) && 0 == lpResultItem->GetNumOrDurability())
{
DELETE_ITEM(lpResultItem);
}
return true;
}
}
}
}
GAMELOG::LogItemCompensation(*lpCharacter, dwOldGold, 0, 0, wError);
return GameClientSendPacket::SendCharItemCompensation(GameClientDispatch.GetSendStream(), dwCID, wError);
}
// 룬 아이템 설치/제거.
bool GameClientParsePacket::ParseCharInstallRuneSocket(CGameClientDispatch& GameClientDispatch, PktBase* lpPktBase)
{
CHECK_FIXED_PACKETSIZE(lpPktBase, sizeof(PktIRS), GameClientDispatch);
PktIRS* lpPktIRS = static_cast<PktIRS*>(lpPktBase);
CCharacter* lpCharacter = GameClientDispatch.GetCharacter();
CHECK_CHARACTER_PTR(lpCharacter, GameClientDispatch, lpPktBase->GetCmd());
unsigned long dwCharID = lpPktIRS->m_dwCharID;
Item::ItemPos EquipPos = lpPktIRS->m_equipPos;
Item::ItemPos RunePos = lpPktIRS->m_runePos;
unsigned char PktType = lpPktIRS->m_cType;
Item::CEquipment* lpEquipment = Item::CEquipment::DowncastToEquipment(lpCharacter->GetItem(EquipPos));
unsigned short wError = PktBase::NO_SERVER_ERR;
// 장착칸에 장착된 아이템인지 검사.
bool bEquip = lpCharacter->GetEquipments().GetItem(EquipPos) == NULL ? false : true;
Item::CItem* lpRune = lpCharacter->GetItem(RunePos);
if(PktType==PktIRS::RUNE_INSTALL)
{
if(lpEquipment && lpRune)
{
Item::CEquipment::EQUIPMENT_ERROR equipError = lpEquipment->InstallRuneSocket(*lpRune, bEquip, lpCharacter->GetLevel());
if(equipError!=Item::CEquipment::R_SUCCESS)
{
wError = PktBase::SERVER_ERROR;
}
else
{
if(lpRune)
{
if(!lpRune->GetNumOrDurability())
{
if(lpCharacter->RemoveItem(RunePos))
{
DELETE_ITEM(lpRune);
}
else
{
ERRLOG1(g_Log, "CID:0x%08x 설치한 룬을 제거하는 데 실패했습니다", lpCharacter->GetCID());
}
}
}
}
}
else
{
if(!lpEquipment)
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 룬을 설치할 장착 아이템이 없습니다", lpCharacter->GetCID());
}
if(!lpRune)
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 장착 아이템에 설치할 룬이 없습니다", lpCharacter->GetCID());
}
}
}
else if(PktType==PktIRS::RUNE_UNINSTALL)
{
if(lpEquipment && lpRune)
{
// 남아있는 스킬 포인트 검사.
SKILL skill = lpCharacter->GetSkill();
short sSkillPoint = lpCharacter->GetStatus().m_StatusInfo.m_wSkillPoint - skill.GetSkillNum();
if(sSkillPoint<0)
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 사용한 스킬포인트가 최대 스킬포인트보다 클 경우", lpCharacter->GetCID());
}
else
{
Item::CEquipment::EQUIPMENT_ERROR equipError = lpEquipment->UnInstallRuneSocket(*lpRune, bEquip, lpCharacter->GetLevel(), sSkillPoint);
if(equipError!=Item::CEquipment::R_SUCCESS)
{
wError = PktBase::SERVER_ERROR;
}
else
{
if(lpRune)
{
if(!lpRune->GetNumOrDurability())
{
if(lpCharacter->RemoveItem(RunePos))
{
DELETE_ITEM(lpRune);
}
else
{
ERRLOG1(g_Log, "CID:0x%08x 소멸 룬을 제거하는 데 실패했습니다", lpCharacter->GetCID());
}
}
}
}
}
}
else
{
if(!lpEquipment)
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 룬을 제거할 장착 아이템이 없습니다", lpCharacter->GetCID());
}
if(!lpRune)
{
wError = PktBase::SERVER_ERROR;
ERRLOG1(g_Log, "CID:0x%08x 소멸 룬이 없습니다", lpCharacter->GetCID());
}
}
}
lpCharacter->CalculateStatusData(false);
return GameClientSendPacket::SendCharRuneInstallSocket(GameClientDispatch.GetSendStream(), dwCharID,
EquipPos, RunePos, lpEquipment, PktType, wError);
}