#include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Character.h" inline unsigned char GetLimitStatus(SKILLSLOT SkillSlot, char LimitValue) { return (SkillSlot.SKILLINFO.cLockCount * 6 + SkillSlot.SKILLINFO.cSkillLevel + 1) * LimitValue; } void LogSkillSlot(const CharacterDBData& DBData) { int nMaxSkill = DBData.m_Skill.wSlotNum < SKILL::MAX_SLOT_NUM ? DBData.m_Skill.wSlotNum : SKILL::MAX_SLOT_NUM; for (int nCount = 0; nCount < nMaxSkill; ++nCount) { ERRLOG5(g_Log, "CID:0x%08x, ij¸¯ÅÍ ½ºÅ³ Á¤º¸¸¦ Ãâ·ÂÇÕ´Ï´Ù. ½½·Ô %2d, ½ºÅ³ Á¾·ù 0x%04x, ¶ô Ä«¿îÆ® %d, ½ºÅ³ ·¹º§ %d", DBData.m_Info.CID, nCount, DBData.m_Skill.SSlot[nCount].SKILLINFO.wSkill, DBData.m_Skill.SSlot[nCount].SKILLINFO.cLockCount, DBData.m_Skill.SSlot[nCount].SKILLINFO.cSkillLevel); } } unsigned short CCharacter::ReadSkill(SKILLSLOT SkillSlot, unsigned short wSkillID, unsigned short wSkillLockCount) { const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(wSkillID); if (NULL == pSkillProtoType) { return PktSk::FAIL_NOT_SKILL; } // By Minbobo // Àӽà ÁÖ¼® ó¸®. ´Ù¸¥ ¹æ½ÄÀ¸·Î Ŭ·¡½º üũ. // ÇÏÀ§ Ŭ·¡½º ½ºÅ³Àº ÇØ´ç Á¾Á·ÀÌ¸é ´©±¸³ª ÀÍÈú ¼ö ÀÖ°í, »óÀ§ Ŭ·¡½º ½ºÅ³ÀÇ °æ¿ì ÇØ´ç Ŭ·¡½º¸¸ÀÌ ±× ½ºÅ³À» ÀÍÈú ¼ö ÀÖ´Ù. /*unsigned char SkillClass = static_cast((((wSkillID - Skill::SKILL_MASK) & 0xFF00) >> 8) & 0x00FF); if (CClass::GetJobLevel(SkillClass) == CClass::JobLevel::DEFAULT_CLASS) { // ÇÏÀ§ Ŭ·¡½º ½ºÅ³ if (GetRace() != CClass::GetRace(SkillClass)) { return PktSk::FAIL_NOT_CURRENT_CLASS; } } else if (CClass::GetJobLevel(SkillClass) == CClass::JobLevel::JOB_CHANGE_1ST) { // »óÀ§ Ŭ·¡½º ½ºÅ³ if (GetClass() != SkillClass) { return PktSk::FAIL_NOT_CURRENT_CLASS; } }*/ if (wSkillLockCount == SkillSlot.SKILLINFO.cLockCount) { if (SkillSlot.SKILLINFO.cSkillLevel < CSkillMgr::MAX_SKILL_LEVEL) { for (int Slot = 0; Slot < Skill::ProtoType::MAX_LIMIT_NUM; ++Slot) { unsigned char cLimitType = pSkillProtoType[wSkillLockCount].m_StatusLimitType[Slot]; unsigned char cLimitValue = pSkillProtoType[wSkillLockCount].m_StatusLimitValue[Slot]; unsigned char cLimitSutatus = (SkillSlot.SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + SkillSlot.SKILLINFO.cSkillLevel) * cLimitValue; switch (cLimitType) { case Skill::StatusLimit::NONE: return PktBase::NO_SERVER_ERR; case Skill::StatusLimit::STR: if (cLimitSutatus > m_CharacterStatus.m_nSTR - 20) { return PktSk::FAIL_NOT_ENOUGH_STATUS; } break; case Skill::StatusLimit::DEX: if (cLimitSutatus > m_CharacterStatus.m_nDEX - 20) { return PktSk::FAIL_NOT_ENOUGH_STATUS; } break; case Skill::StatusLimit::CON: if (cLimitSutatus > m_CharacterStatus.m_nCON - 20) { return PktSk::FAIL_NOT_ENOUGH_STATUS; } break; case Skill::StatusLimit::INT: if (cLimitSutatus > m_CharacterStatus.m_nINT - 20) { return PktSk::FAIL_NOT_ENOUGH_STATUS; } break; case Skill::StatusLimit::WIS: if (cLimitSutatus > m_CharacterStatus.m_nWIS - 20) { return PktSk::FAIL_NOT_ENOUGH_STATUS; } break; } } } else { return PktSk::FAIL_MAX_LEVEL; } } else { return PktSk::FAIL_NOT_CURRENT_LOCK_COUNT; } return PktBase::NO_SERVER_ERR; } bool CCharacter::RedistributionSkill(void) { if (false == CalculateStatusData(false)) { return false; } SKILL &Skill = m_DBData.m_Skill; int nSlotIndex = 0; for (; nSlotIndex < Skill.wSlotNum; ++nSlotIndex) { const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); if (NULL == pSkillProtoType) { ERRLOG2(g_Log, "CID:0x%08x Á¸ÀçÇÏÁö¾Ê´Â ½ºÅ³À» °¡Áö°í ÀÖ½À´Ï´Ù. SkillID:0x%04x", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); return false; } while (true) { bool bLevelDown = false; for (int nTypeIndex = 0; nTypeIndex < Skill::ProtoType::MAX_LIMIT_NUM; nTypeIndex++) { unsigned char cLimitType = pSkillProtoType->m_StatusLimitType[nTypeIndex]; char cLimitValue = pSkillProtoType->m_StatusLimitValue[nTypeIndex]; unsigned char cLimitStatus = (Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL + static_cast(Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel) - 1) * cLimitValue; switch (cLimitType) { case Skill::StatusLimit::STR: if (cLimitStatus > m_CharacterStatus.m_nSTR - 20) { bLevelDown = true; } break; case Skill::StatusLimit::DEX: if (cLimitStatus > m_CharacterStatus.m_nDEX - 20) { bLevelDown = true; } break; case Skill::StatusLimit::CON: if (cLimitStatus > m_CharacterStatus.m_nCON - 20) { bLevelDown = true; } break; case Skill::StatusLimit::INT: if (cLimitStatus > m_CharacterStatus.m_nINT - 20) { bLevelDown = true; } break; case Skill::StatusLimit::WIS: if (cLimitStatus > m_CharacterStatus.m_nWIS - 20) { bLevelDown = true; } break; } } if (true == bLevelDown) { if (0 == Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel) { --Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount; Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL; } --Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel; --Skill.wSkillNum; if (0 == Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel && 0 == Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount) { // ½ºÅ³ ½½·ÔÀ» µµ´Â ·çÇÁ ¾ÈÀ̹ǷΠ½½·Ô ÀÚü¸¦ »èÁ¦ÇÏ´Â °Ç ÀÌÈÄ¿¡ µû·Î ó¸®ÇÑ´Ù. Skill.SSlot[nSlotIndex] = SKILLSLOT::SKILLSLOT(); break; } } else { break; } } } // ½ºÅ³ »èÁ¦·Î ºñ¿öÁø ½½·ÔÀ» »èÁ¦ÇÑ´Ù. for (nSlotIndex = 0; nSlotIndex < Skill.wSlotNum; ) { if (0 == Skill.SSlot[nSlotIndex].dwSkillSlot) { unsigned char Count = nSlotIndex; for (; Count < Skill.wSlotNum - 1; ++Count) { Skill.SSlot[Count] = Skill.SSlot[Count + 1]; } Skill.SSlot[Count] = SKILLSLOT::SKILLSLOT(); --Skill.wSlotNum; continue; } ++nSlotIndex; } return CalculateMaxSkillSlot(); } bool CCharacter::CalculateMaxSkillSlot(void) { SKILL &Skill = m_DBData.m_Skill; // ½ºÅÈÀÌ ¹Ù²¸ ÃÖ´ë ½½·Ô¼ö°¡ ÁÙ¾îµé¸é ±× Â÷¸¸Å­ »èÁ¦ÇÑ´Ù. short wDeleteSkillNum = Skill.GetSkillNum() - m_CreatureStatus.m_StatusInfo.m_wSkillPoint; while (wDeleteSkillNum > 0) { if (1 > Skill.wSlotNum) { ERRLOG1(g_Log, "CID:0x%08x Áö¿ï ½ºÅ³ ½½·ÔÀÌ ¾ø½À´Ï´Ù.", m_dwCID); return false; } int nSlotIndex = Skill.wSlotNum - 1; const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); if (NULL == pSkillProtoType) { ERRLOG2(g_Log, "CID:0x%08x Á¸ÀçÇÏÁö¾Ê´Â ½ºÅ³À» °¡Áö°í ÀÖ½À´Ï´Ù. SkillID:0x%04x", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); return false; } if (0 == Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel) { --Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount; Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL; } --Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel; --Skill.wSkillNum; --wDeleteSkillNum; if (0 == Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel && 0 == Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount) { Skill.SSlot[nSlotIndex] = SKILLSLOT::SKILLSLOT(); --Skill.wSlotNum; } UpdateQuickSlotSkill(Skill.SSlot[nSlotIndex]); } return true; } void CCharacter::UpdateUseAbilityPoint() { m_iUseAbilityPoint = 0; SKILL &Skill = m_DBData.m_Skill; // ¾îºô¸®Æ¼ Æ÷ÀÎÆ®¸¦ °Ë»çÇÑ´Ù. for(int i = 0; i <= Skill.wSlotNum; ++i) { unsigned short SkillID = Skill.SSlot[i].SKILLINFO.wSkill; if(0x1000 <= SkillID && SkillID < 0x2000) { const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(SkillID); if (NULL == lpProtoType) { ERRLOG2(g_Log, "CID:0x%08x ¾îºô¸®Æ¼ ¾ÆÀ̵𰡠ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ¾ÆÀ̵ð:0x%04x", m_dwCID, SkillID); continue; } short SkillLV = Skill.SSlot[i].SKILLINFO.cLockCount; if(SkillLV >= CSkillMgr::MAX_SKILL_LOCKCOUNT) SkillLV = CSkillMgr::MAX_SKILL_LOCKCOUNT-1; for(int j = 0; j <= SkillLV; ++j) m_iUseAbilityPoint += (int)lpProtoType[j].m_fMinRange; } } return; } bool CCharacter::AbilityCreate(Item::CUseItem* lpUseItem) { if(0 == lpUseItem) { ERRLOG1(g_Log, "CID:%10u / ½ºÅ³ »ý¼º ½ÇÆÐ : »ç¿ë ¾ÆÀÌÅÛÀÌ 0ÀÔ´Ï´Ù", m_dwCID); return false; } unsigned short SkillID = lpUseItem->GetItemInfo().m_UseItemInfo.m_usSkill_ID; char SkillLockCount = (char)lpUseItem->GetItemInfo().m_UseItemInfo.m_usSkill_LockCount; unsigned short wError = PktBase::NO_SERVER_ERR; unsigned char Index = 0; bool bLockFlag = false; // ¶ôÀÌ µÉ ¶§´Â SkillCreate ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. SKILL &Skill = m_DBData.m_Skill; if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:%10u / ¾îºô¸®Æ¼ »ý¼º ½ÇÆÐ : ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(SkillID); if (NULL == lpProtoType) { ERRLOG2(g_Log, "CID:0x%08x ¾îºô¸®Æ¼ ¾ÆÀ̵𰡠ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ¾ÆÀ̵ð:0x%04x", m_dwCID, SkillID); return false; } int UsePoint = (int)lpProtoType[SkillLockCount].m_fMinRange; // ¾îºô¸®Æ¼ Æ÷ÀÎÆ®¿¡¼­ °Ë»çÇÑ´Ù. if (GetUseAbilityPoint()+UsePoint > GetAbilityPoint() ) { wError = PktSk::FAIL_NOT_ENOUGH_SKILL_POINT; } else { for (Index = 0; Index < Skill.wSlotNum; ++Index) { if (SkillID == Skill.SSlot[Index].SKILLINFO.wSkill) { if(Skill.SSlot[Index].SKILLINFO.cLockCount < SkillLockCount) { // ÀÌ¹Ì ÀÖ´Â ½ºÅ³ÀÌ¸é ¶ôÀ» È£ÃâÇØ¼­ ·¹º§¾÷À» ÇØÁØ´Ù. bLockFlag = true; Skill.SSlot[Index].SKILLINFO.cLockCount++; Skill.SSlot[Index].SKILLINFO.cSkillLevel = 1; // ÆÐŶ º¸³»±â if (NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillLock, Index, SkillID, wError); } } break; } } // ¾ø´Â ½ºÅ³À̸é. if (Index == Skill.wSlotNum) { if (Skill.wSlotNum == SKILL::MAX_SLOT_NUM) { wError = PktSk::FAIL_NOT_ENOUGH_SLOT; } else { // ¾îºô¸®Æ¼´Â Á¦ÇÑÀÌ ¾ø´Ù. ±×³É ¹è¿ì¸é µÈ´Ù. Skill.SSlot[Index].SKILLINFO.wSkill = SkillID; Skill.SSlot[Index].SKILLINFO.cLockCount = SkillLockCount; Skill.SSlot[Index].SKILLINFO.cSkillLevel = 1; ++Skill.wSlotNum; } } CalculateStatusData(false); // Äü½½·Ô ¾÷µ¥ÀÌÆ® UpdateQuickSlotSkill(Skill.SSlot[Index]); } UpdateUseAbilityPoint(); // ÆÐŶ º¸³»±â if (false == bLockFlag && NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillCreate, Index, SkillID, wError); } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG7(g_Log, "CID:%10u ¾îºô¸®Æ¼ »ý¼º¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. ½ºÅ³¼ö:%d/%d" " Create Ability Index:%d, Level:%d, Int:%d, Error:%d", m_dwCID, Skill.GetSkillNum(), m_CreatureStatus.m_StatusInfo.m_wSkillPoint, Index, m_DBData.m_Info.Level, m_CharacterStatus.m_nINT, wError); LogSkillSlot(m_DBData); return false; } return true; } bool CCharacter::AbilityErase(unsigned char Index_In, Item::ItemPos InvenPos) { SKILL &Skill = m_DBData.m_Skill; unsigned short SkillID = 0; unsigned short wError = 0; bool bUnlockFlag = false; // Unlock µÉ¶§´Â SkillErase ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ¾îºô¸®Æ¼ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } if (Skill.wSlotNum <= Index_In) { ERRLOG3(g_Log, "CID:0x%08x ¾îºô¸®Æ¼ Á¦°Å ¿À·ù : À߸øµÈ À妽ºÀÔ´Ï´Ù. ½ºÅ³ °³¼ö:%d, À妽º:%d", m_dwCID, Skill.wSlotNum, Index_In); return false; } SkillID = Skill.SSlot[Index_In].SKILLINFO.wSkill; const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(SkillID); if (NULL == lpProtoType) { ERRLOG2(g_Log, "CID:0x%08x ¾îºô¸®Æ¼ ¾ÆÀ̵𰡠ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ¾ÆÀ̵ð:0x%04x", m_dwCID, SkillID); return false; } Item::CItem* lpItem = NULL; if(InvenPos.m_cPos != TakeType::TS_ADMIN) { // ¸Á°¢Àǵ¹ È®ÀÎ lpItem = m_Inventory.GetItem(InvenPos); if (NULL == lpItem) { ERRLOG4(g_Log, "CID:0x%08x ¾îºô¸®Æ¼»èÁ¦ ¿À·ù : ¿äûÇÑ À§Ä¡¿¡ ¾ÆÀÌÅÛÀÌ ¾ø½À´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } if (Item::EtcItemID::OBLIVION_STONE != lpItem->GetPrototypeID()) { ERRLOG3(g_Log, "CID:0x%08x ¾îºô¸®Æ¼»èÁ¦ ¿À·ù : »ç¿ëÇÏ·Á´Â ¾ÆÀÌÅÛÀÌ ¸Á°¢ÀÇ µ¹ÀÌ ¾Æ´Õ´Ï´Ù. SkillID:%d, ItemID:%d", m_dwCID, SkillID, lpItem->GetPrototypeID()); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_INVALID_ITEM); return true; } // ¸Á°¢Àǵ¹ °³¼ö°¡ ÀÌ»óÇÑÁö È®ÀÎ if(lpItem->GetNumOrDurability() <= 0) { ERRLOG4(g_Log, "CID:0x%08x ¾îºô¸®Æ¼»èÁ¦ ¿À·ù : ¸Á°¢ÀÇ µ¹ÀÇ °¹¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } } if (Index_In >= Skill.wSlotNum) { wError = PktSk::FAIL_NOT_SKILL; // ÇØ´ç À妽º¿¡ ½ºÅ³ ¾øÀ½ } else { SKILLSLOT SkillSlot = Skill.SSlot[Index_In]; if (SkillSlot.SKILLINFO.cLockCount > 0) { bUnlockFlag = true; Skill.SSlot[Index_In].SKILLINFO.cLockCount--; Skill.SSlot[Index_In].SKILLINFO.cSkillLevel = 1; // ÆÐŶ º¸³»±â if (NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillUnLock, Index_In, SkillID, wError, static_cast(Skill.SSlot[Index_In].SKILLINFO.cSkillLevel), &InvenPos); } } else { unsigned char Count = Index_In; for (; Count < Skill.wSlotNum - 1; ++Count) { Skill.SSlot[Count] = Skill.SSlot[Count + 1]; } Skill.SSlot[Count].SKILLINFO.wSkill = 0; Skill.SSlot[Count].SKILLINFO.cLockCount = 0; Skill.SSlot[Count].SKILLINFO.cSkillLevel = 0; --Skill.wSlotNum; } } UpdateUseAbilityPoint(); CalculateStatusData(false); if (PktBase::NO_SERVER_ERR == wError) { // ¿¡·¯¾øÀÌ ¼º°øÇßÀ¸¸é ¸Á°¢Àǵ¹ °¨¼Ò if(InvenPos.m_cPos != TakeType::TS_ADMIN) { // ¸Á°¢Àǵ¹ °³¼ö 1°³ °¨¼Ò lpItem->SetNumOrDurability(lpItem->GetNumOrDurability() - 1); if (0 == lpItem->GetNumOrDurability()) { if (RemoveItem(InvenPos)) { DELETE_ITEM(lpItem); } else { ERRLOG4(g_Log, "CID:0x%08x ¾îºô¸®Æ¼»èÁ¦ ¿À·ù : ¸Á°¢ÀÇ µ¹À» Á¦°ÅÇÒ ¼ö ¾ø½À´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); m_Inventory.DumpItemInfo(); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } } } // ½ºÅ³¶ô È®ÀÎ UpdateQuickSlotSkill(Skill.SSlot[Index_In]); } // ÆÐŶ º¸³»±â if (false == bUnlockFlag && NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, wError, 0, &InvenPos); } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG5(g_Log, "CID:0x%08x ½ºÅ³ »èÁ¦¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. Erase Skill Index:%d, SkillID:%d, ½ºÅ³ °³¼ö:%d, Error:%d", m_dwCID, Index_In, SkillID, Skill.wSlotNum, wError); LogSkillSlot(m_DBData); } return true; } bool CCharacter::SkillCreate(Item::CUseItem* lpUseItem) { if(0 == lpUseItem) { ERRLOG1(g_Log, "CID:%10u / ½ºÅ³ »ý¼º ½ÇÆÐ : »ç¿ë ¾ÆÀÌÅÛÀÌ 0ÀÔ´Ï´Ù", m_dwCID); return false; } unsigned short SkillID = lpUseItem->GetItemInfo().m_UseItemInfo.m_usSkill_ID; unsigned short SkillLockCount = lpUseItem->GetItemInfo().m_UseItemInfo.m_usSkill_LockCount; unsigned short wError = PktBase::NO_SERVER_ERR; unsigned char Index = 0; bool bLockFlag = false; // ¶ôÀÌ µÉ ¶§´Â SkillCreate ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. SKILL &Skill = m_DBData.m_Skill; if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:%10u / ½ºÅ³ »ý¼º ½ÇÆÐ : ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } if (Skill.GetSkillNum() >= m_CreatureStatus.m_StatusInfo.m_wSkillPoint) { wError = PktSk::FAIL_NOT_ENOUGH_SKILL_POINT; } else { // À妽º ±¸Çϱâ for (Index = 0; Index < Skill.wSlotNum; ++Index) { if (SkillID == Skill.SSlot[Index].SKILLINFO.wSkill) { // ½ºÅ³ Áõ°¡ wError = ReadSkill(Skill.SSlot[Index], SkillID, SkillLockCount); if (PktBase::NO_SERVER_ERR == wError) { ++Skill.SSlot[Index].SKILLINFO.cSkillLevel; ++Skill.wSkillNum; if (Skill.SSlot[Index].SKILLINFO.cLockCount < CSkillMgr::MAX_SKILL_LOCKCOUNT - 2 && Skill.SSlot[Index].SKILLINFO.cSkillLevel == CSkillMgr::MAX_SKILL_LEVEL) { bLockFlag = SkillLock(Index); } } break; } } if (Index == Skill.wSlotNum) { if (Skill.wSlotNum == SKILL::MAX_SLOT_NUM) { wError = PktSk::FAIL_NOT_ENOUGH_SLOT; } else { // ½½·Ô Ãß°¡ wError = ReadSkill(Skill.SSlot[Index], SkillID, SkillLockCount); if (PktBase::NO_SERVER_ERR == wError) { Skill.SSlot[Index].SKILLINFO.wSkill = SkillID; Skill.SSlot[Index].SKILLINFO.cLockCount = 0; Skill.SSlot[Index].SKILLINFO.cSkillLevel = 1; ++Skill.wSkillNum; ++Skill.wSlotNum; } } } CalculateStatusData(false); // Äü½½·Ô ¾÷µ¥ÀÌÆ® UpdateQuickSlotSkill(Skill.SSlot[Index]); } // ÆÐŶ º¸³»±â if (false == bLockFlag && NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillCreate, Index, SkillID, wError); } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG7(g_Log, "CID:%10u ½ºÅ³ »ý¼º¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. ½ºÅ³¼ö:%d/%d" " Create Skill Index:%d, Level:%d, Int:%d, Error:%d", m_dwCID, Skill.GetSkillNum(), m_CreatureStatus.m_StatusInfo.m_wSkillPoint, Index, m_DBData.m_Info.Level, m_CharacterStatus.m_nINT, wError); LogSkillSlot(m_DBData); return false; } return true; } bool CCharacter::SkillErase(unsigned char Index_In, Item::ItemPos InvenPos) { SKILL &Skill = m_DBData.m_Skill; unsigned short SkillID = 0; unsigned short wError = 0; bool bUnlockFlag = false; // Unlock µÉ¶§´Â SkillErase ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } if (Skill.wSlotNum <= Index_In) { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³ Á¦°Å ¿À·ù : À߸øµÈ À妽ºÀÔ´Ï´Ù. ½ºÅ³ °³¼ö:%d, À妽º:%d", m_dwCID, Skill.wSlotNum, Index_In); return false; } SkillID = Skill.SSlot[Index_In].SKILLINFO.wSkill; const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(SkillID); if (NULL == lpProtoType) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ ¾ÆÀ̵𰡠ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ¾ÆÀ̵ð:0x%04x", m_dwCID, SkillID); return false; } if (Skill::Type::CHANT == lpProtoType->m_eSkillType) { AtType attackType; attackType.m_wType = SkillID; attackType.m_cSkillLevel = 0; attackType.m_cSkillLockCount = 0; attackType.m_cAtCount = 0; unsigned char cOffencerJudge = 0, cDefenserJudge = 0; unsigned short wOffencerMPHeal = 0, wDefenserMPHeal = 0; Skill::CProcessTable::GetInstance().UseSkill(attackType, this, this, cOffencerJudge, cDefenserJudge, wOffencerMPHeal, wDefenserMPHeal, wError); } Item::CItem* lpItem = NULL; if(InvenPos.m_cPos != TakeType::TS_ADMIN) { // ¸Á°¢Àǵ¹ È®ÀÎ lpItem = m_Inventory.GetItem(InvenPos); if (NULL == lpItem) { ERRLOG4(g_Log, "CID:0x%08x ½ºÅ³»èÁ¦ ¿À·ù : ¿äûÇÑ À§Ä¡¿¡ ¾ÆÀÌÅÛÀÌ ¾ø½À´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } if (Item::EtcItemID::OBLIVION_STONE != lpItem->GetPrototypeID()) { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³»èÁ¦ ¿À·ù : »ç¿ëÇÏ·Á´Â ¾ÆÀÌÅÛÀÌ ¸Á°¢ÀÇ µ¹ÀÌ ¾Æ´Õ´Ï´Ù. SkillID:%d, ItemID:%d", m_dwCID, SkillID, lpItem->GetPrototypeID()); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_INVALID_ITEM); return true; } // ¸Á°¢Àǵ¹ °³¼ö°¡ ÀÌ»óÇÑÁö È®ÀÎ if(lpItem->GetNumOrDurability() <= 0) { ERRLOG4(g_Log, "CID:0x%08x ½ºÅ³»èÁ¦ ¿À·ù : ¸Á°¢ÀÇ µ¹ÀÇ °¹¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } } if (Index_In >= Skill.wSlotNum) { wError = PktSk::FAIL_NOT_SKILL; // ÇØ´ç À妽º¿¡ ½ºÅ³ ¾øÀ½ } else { SKILLSLOT SkillSlot = Skill.SSlot[Index_In]; if (SkillSlot.SKILLINFO.cLockCount > 0) { if (0 == SkillSlot.SKILLINFO.cSkillLevel) { if (4 <= SkillSlot.SKILLINFO.cLockCount) { wError = PktSk::FAIL_FIFTHSKILL_UNLOCK; } else { // »óÀ§ ´Ü°è 0 ·¹º§ ½ºÅ³À» Áö¿ì´Â °æ¿ì ÇÏÀ§ ´Ü°è 5 ·¹º§·Î ¸¸µé¾î ÁÖ¾î¾ß ÇÑ´Ù. // ¿©±â¼­ Áö¿ìÁö ¸»°í º¯¼ö¸¦ TRUE ÇØ¼­ ¾Æ·¡¿¡¼­ Áö¿öÁÖ°ÔÇÑ´Ù. // SkillUnLock ÇÔ¼ö¾È¿¡¼­bUnlockFlag°¡ trueÀ϶§ ÆÐŶÀ» º¸³»±â ¶§¹®¿¡ // bUnlockFlag°¡ trueÀÌ¸é ¾Æ·¡¿¡¼­ ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. // ÀÌÇÔ¼ö ³»¿¡¼­ ÀÌ¹Ì ÆÐŶÀ» ³¯¸®±â ¶§¹®¿¡.. bUnlockFlag = SkillUnLock(Index_In, &InvenPos); } } else { --Skill.SSlot[Index_In].SKILLINFO.cSkillLevel; --Skill.wSkillNum; } } else { if (0 == SkillSlot.SKILLINFO.cSkillLevel) { wError = PktSk::FAIL_NON_LEVEL; // ½ºÅ³ Áö¿ì±â ½ÇÆÐ } else if (1 == SkillSlot.SKILLINFO.cSkillLevel) { // Ŭ·¡½º ½ºÅ³À» Áö¿ì·Á´ÂÁö üũ if (lpProtoType->m_bIsClassSkill) { wError = PktSk::FAIL_ERASE_CLASS_SKILL; } else { unsigned char Count = Index_In; for (; Count < Skill.wSlotNum - 1; ++Count) { Skill.SSlot[Count] = Skill.SSlot[Count + 1]; } Skill.SSlot[Count].SKILLINFO.wSkill = 0; Skill.SSlot[Count].SKILLINFO.cLockCount = 0; Skill.SSlot[Count].SKILLINFO.cSkillLevel = 0; --Skill.wSkillNum; --Skill.wSlotNum; } } else { --Skill.SSlot[Index_In].SKILLINFO.cSkillLevel; --Skill.wSkillNum; } } } CalculateStatusData(false); if (PktBase::NO_SERVER_ERR == wError) { // ¿¡·¯¾øÀÌ ¼º°øÇßÀ¸¸é ¸Á°¢Àǵ¹ °¨¼Ò if(InvenPos.m_cPos != TakeType::TS_ADMIN) { // ¸Á°¢Àǵ¹ °³¼ö 1°³ °¨¼Ò lpItem->SetNumOrDurability(lpItem->GetNumOrDurability() - 1); if (0 == lpItem->GetNumOrDurability()) { if (RemoveItem(InvenPos)) { DELETE_ITEM(lpItem); } else { ERRLOG4(g_Log, "CID:0x%08x ½ºÅ³»èÁ¦ ¿À·ù : ¸Á°¢ÀÇ µ¹À» Á¦°ÅÇÒ ¼ö ¾ø½À´Ï´Ù. SkillID:%d, Pos:%d, Index:%d", m_dwCID, SkillID, InvenPos.m_cPos, InvenPos.m_cIndex); m_Inventory.DumpItemInfo(); GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, PktSk::FAIL_NO_ITEM); return true; } } } // ½ºÅ³¶ô È®ÀÎ UpdateQuickSlotSkill(Skill.SSlot[Index_In]); } // ÆÐŶ º¸³»±â if (false == bUnlockFlag && NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillErase, Index_In, SkillID, wError, 0, &InvenPos); } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG5(g_Log, "CID:0x%08x ½ºÅ³ »èÁ¦¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. Erase Skill Index:%d, SkillID:%d, ½ºÅ³ °³¼ö:%d, Error:%d", m_dwCID, Index_In, SkillID, Skill.wSlotNum, wError); LogSkillSlot(m_DBData); } return true; } bool CCharacter::SkillLock(unsigned char Index_In) { SKILL &Skill = m_DBData.m_Skill; if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } if (Skill.wSlotNum <= Index_In) { ERRLOG3(g_Log, "CID:0x%08x ¶ô ¿À·ù : À߸øµÈ À妽ºÀÔ´Ï´Ù. ½ºÅ³ °³¼ö:%d, À妽º:%d", m_dwCID, Skill.wSlotNum, Index_In); return false; } unsigned short SkillID = Skill.SSlot[Index_In].SKILLINFO.wSkill; unsigned short wError = 0; if (0 != SkillID) { if (Skill.SSlot[Index_In].SKILLINFO.cSkillLevel == CSkillMgr::MAX_SKILL_LEVEL) { if (Skill.SSlot[Index_In].SKILLINFO.cLockCount != CSkillMgr::MAX_SKILL_LOCKCOUNT - 1) { ++Skill.SSlot[Index_In].SKILLINFO.cLockCount; Skill.SSlot[Index_In].SKILLINFO.cSkillLevel = 0; } else { wError = PktSk::FAIL_FULL_LOCK; // ½ºÅ³´ç ¶ô ¼ö Ãʰú } } else { wError = PktSk::FAIL_NOT_ENOUGH_LEVEL; // ¶ô ÇÒ¼ö ¾ø´Â ½ºÅ³ ·¹º§ } } else { wError = PktSk::FAIL_NOT_SKILL; // ÇØ´ç À妽º¿¡ ½ºÅ³ ¾øÀ½ } if (PktBase::NO_SERVER_ERR == wError) { UpdateQuickSlotSkill(Skill.SSlot[Index_In]); // ½ºÅ³ ½ÃÀüÁßÀ϶§ ´Ü°è¸¦ ¹Ù²Ù¸é ½ºÅ³ÀÌ ³¡³ª¸é¼­ ÄðŸÀÓÀÌ µ¹µµ·Ï º¯°æ switch (SkillID) { case 0x8304: // ¸¶³ª¼¿ (¹ý»ç) GetEnchantInfo().ResetFlag(Skill::SpellID::ManaShell); break; case 0x9204: // Ç÷¢¼­ºô¸®Æ¼ (¿ÀÇÇ) GetEnchantInfo().ResetFlag(Skill::SpellID::Flexibility); break; case 0x8704: // ½ºÅÚ½º (¾î½Ø) case 0x8805: // ij¸ðÇöóÁã (¾ÆÃ³) case 0x9504: // ij¸ðÇöóÁã (°Å³Ê) case 0x9804: // ½ºÅÚ½º (½¦¿É) GetEnchantInfo().ResetFlag(Skill::SpellID::Stealth); break; } } // ÆÐŶ º¸³»±â if (NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillLock, Index_In, SkillID, wError); } if (wError) { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³ ¶ô¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. Lock Skill Index:%d, Error:%d", m_dwCID, Index_In, wError); LogSkillSlot(m_DBData); } return true; } bool CCharacter::SkillUnLock(unsigned char Index_In, Item::ItemPos* InvenPos, bool bSkillFifthUnlock) { SKILL &Skill = m_DBData.m_Skill; if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } if (Skill.wSlotNum <= Index_In) { ERRLOG3(g_Log, "CID:0x%08x ¶ô ÇØÁ¦ ¿À·ù : À߸øµÈ À妽ºÀÔ´Ï´Ù. ½ºÅ³ °³¼ö:%d, À妽º:%d", m_dwCID, Skill.wSlotNum, Index_In); return false; } unsigned short SkillID = Skill.SSlot[Index_In].SKILLINFO.wSkill; unsigned short wError = PktBase::NO_SERVER_ERR; if (0 != SkillID) { if (0 < Skill.SSlot[Index_In].SKILLINFO.cLockCount) { --Skill.SSlot[Index_In].SKILLINFO.cLockCount; --Skill.wSkillNum; if (bSkillFifthUnlock) { Skill.SSlot[Index_In].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL; } else { Skill.SSlot[Index_In].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL - 1; } } else { wError = PktSk::FAIL_NON_LOCK; // Çѹøµµ ¶ôÇÏÁö ¾ÊÀº ½ºÅ³ } } else { wError = PktSk::FAIL_NOT_SKILL; // ÇØ´ç À妽º¿¡ ½ºÅ³ ¾øÀ½ } if (0 == wError) { UpdateQuickSlotSkill(Skill.SSlot[Index_In]); // ½ºÅ³ ½ÃÀüÁßÀ϶§ ´Ü°è¸¦ ¹Ù²Ù¸é ½ºÅ³ÀÌ ³¡³ª¸é¼­ ÄðŸÀÓÀÌ µ¹µµ·Ï º¯°æ switch (SkillID) { case 0x8304: // ¸¶³ª¼¿ (¹ý»ç) GetEnchantInfo().ResetFlag(Skill::SpellID::ManaShell); break; case 0x9204: // Ç÷¢¼­ºô¸®Æ¼ (¿ÀÇÇ) GetEnchantInfo().ResetFlag(Skill::SpellID::Flexibility); break; case 0x8704: // ½ºÅÚ½º (¾î½Ø) case 0x8805: // ij¸ðÇöóÁã (¾ÆÃ³) case 0x9504: // ij¸ðÇöóÁã (°Å³Ê) case 0x9804: // ½ºÅÚ½º (½¦¿É) GetEnchantInfo().ResetFlag(Skill::SpellID::Stealth); break; } } else { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³ ¶ô ÇØÁ¦¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. UnLock Skill Index:%d, Error:%d", m_dwCID, Index_In, wError); LogSkillSlot(m_DBData); } // ÆÐŶ º¸³»±â if (NULL != m_lpGameClientDispatch) { GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, CmdCharSkillUnLock, Index_In, SkillID, wError, static_cast(Skill.SSlot[Index_In].SKILLINFO.cSkillLevel), InvenPos); } return true; } bool CCharacter::SkillFifthLock(unsigned short wSkillID) { unsigned short SkillLockCount = GetSkillLockCount(wSkillID); unsigned short wError = PktBase::NO_SERVER_ERR; unsigned char Index = 0; bool bLockFlag = false; // ¶ôÀÌ µÉ ¶§´Â SkillCreate ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. SKILL &Skill = m_DBData.m_Skill; if (SKILL::MAX_SLOT_NUM < Skill.wSlotNum) { ERRLOG2(g_Log, "CID:%10u / ½ºÅ³ »ý¼º ½ÇÆÐ : ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö:%d", m_dwCID, Skill.wSlotNum); return false; } // À妽º ±¸Çϱâ for (Index = 0; Index < Skill.wSlotNum; ++Index) { if (wSkillID == Skill.SSlot[Index].SKILLINFO.wSkill) { Skill.SSlot[Index].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL - 1; wError = ReadSkill(Skill.SSlot[Index], wSkillID, SkillLockCount); if (PktBase::NO_SERVER_ERR == wError) { Skill.SSlot[Index].SKILLINFO.cSkillLevel = CSkillMgr::MAX_SKILL_LEVEL; bLockFlag = SkillLock(Index); CalculateStatusData(false); // Äü½½·Ô ¾÷µ¥ÀÌÆ® UpdateQuickSlotSkill(Skill.SSlot[Index]); } break; } } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG7(g_Log, "CID:%10u 5´Ü°è ½ºÅ³ ¶ô¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. ½ºÅ³¼ö:%d/%d" " Create Skill Index:%d, Level:%d, Int:%d, Error:%d", m_dwCID, Skill.GetSkillNum(), m_CreatureStatus.m_StatusInfo.m_wSkillPoint, Index, m_DBData.m_Info.Level, m_CharacterStatus.m_nINT, wError); LogSkillSlot(m_DBData); return false; } return true; } bool CCharacter::SkillFifthUnlock(unsigned short wSkillID) { unsigned short SkillLockCount = GetSkillLockCount(wSkillID); unsigned short wError = PktBase::NO_SERVER_ERR; unsigned char Index = 0; bool bUnlockFlag = false; // ¶ôÀÌ µÉ ¶§´Â SkillCreate ÀÇ Ack ÆÐŶÀ» º¸³»Áö ¾Ê´Â´Ù. SKILL &Skill = m_DBData.m_Skill; // À妽º ±¸Çϱâ for (Index = 0; Index < Skill.wSlotNum; ++Index) { if (wSkillID == Skill.SSlot[Index].SKILLINFO.wSkill) { const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(wSkillID); if (NULL == lpProtoType) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ ¾ÆÀ̵𰡠ÀÌ»óÇÕ´Ï´Ù. ½ºÅ³ ¾ÆÀ̵ð:0x%04x", m_dwCID, wSkillID); return false; } if (Skill::Type::CHANT == lpProtoType->m_eSkillType) { AtType attackType; attackType.m_wType = wSkillID; attackType.m_cSkillLevel = 0; attackType.m_cSkillLockCount = 0; attackType.m_cAtCount = 0; unsigned char cOffencerJudge = 0, cDefenserJudge = 0; unsigned short wOffencerMPHeal = 0, wDefenserMPHeal = 0; Skill::CProcessTable::GetInstance().UseSkill(attackType, this, this, cOffencerJudge, cDefenserJudge, wOffencerMPHeal, wDefenserMPHeal, wError); } bUnlockFlag = SkillUnLock(Index, NULL, true); CalculateStatusData(false); if (PktBase::NO_SERVER_ERR == wError) { UpdateQuickSlotSkill(Skill.SSlot[Index]); } //// ÆÐŶ º¸³»±â //if (false == bUnlockFlag && NULL != m_lpGameClientDispatch) //{ // GameClientSendPacket::SendCharSkillCommand(m_lpGameClientDispatch->GetSendStream(), m_dwCID, // CmdCharSkillErase, Index, wSkillID, wError); //} break; } } if (PktBase::NO_SERVER_ERR != wError) { ERRLOG4(g_Log, "CID:0x%08x 5´Ü°è ½ºÅ³ ¶ô ÇØÁ¦¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù. Erase Skill Index:%d, ½ºÅ³ °³¼ö:%d, Error:%d", m_dwCID, Index, Skill.wSlotNum, wError); LogSkillSlot(m_DBData); } return true; } bool CCharacter::HasSkill(unsigned short usSkillType, unsigned char cLockCount, unsigned char cLevel) { const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(usSkillType); if (NULL == pSkillProtoType) { ERRLOG2(g_Log, "CID:0x%08x Á¸ÀçÇÏÁö ¾Ê´Â ½ºÅ³ ¾ÆÀ̵ðÀÔ´Ï´Ù. Skill ID:0x%04x", m_dwCID, usSkillType); return false; } // ÀÚ½Ä ½ºÅ³À» »ç¿ëÇÑ °æ¿ì ºÎ¸ð ½ºÅ³ÀÌ ÀÖ´ÂÁö üũÇÑ´Ù. if (0 != pSkillProtoType->m_usParentSkill) { pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(pSkillProtoType->m_usParentSkill); usSkillType = pSkillProtoType->m_usSkill_ID; } if (Skill::Type::ITEM == pSkillProtoType->m_eSkillType || Skill::Type::SET == pSkillProtoType->m_eSkillType || Skill::Type::ACTION == pSkillProtoType->m_eSkillType) { // ´©±¸³ª »ç¿ëÇÒ ¼ö ÀÖ´Â ½ºÅ³ (Æ÷¼Ç·ù, ÀÎæƮÀÇ Ãß°¡ È¿°ú ½ºÅ³) return true; } if (true == pSkillProtoType->m_bIsClassSkill) { unsigned char cSkillClass = static_cast((((pSkillProtoType->m_usSkill_ID - Skill::SKILL_MASK) & 0xFF00) >> 8) & 0x00FF); if (m_DBData.m_Info.Class != cSkillClass && CClass::GetPreviousJob(static_cast(m_DBData.m_Info.Class)) != cSkillClass) { ERRLOG3(g_Log, "CID:0x%08x ¾Ë¸ÂÁö ¾ÊÀº Ŭ·¡½º ½ºÅ³À» »ç¿ëÇÏ·ÁÇÕ´Ï´Ù. Skill ID:0x%04x, Class:%d", m_dwCID, pSkillProtoType->m_usSkill_ID, m_DBData.m_Info.Class); return false; } return true; } int nMaxSlotNum = m_DBData.m_Skill.wSlotNum; if (SKILL::MAX_SLOT_NUM < nMaxSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö = %d", m_dwCID, m_DBData.m_Skill.wSlotNum); return false; } for (int nSSlot = 0; nSSlot < nMaxSlotNum; ++nSSlot) { const SKILLSLOT& SkillSlot = m_DBData.m_Skill.SSlot[nSSlot]; // ½ºÅ³ ã¾Æ¼­ ÀÖ´Â ½ºÅ³ÀÎÁö, ½ºÅ³ ·¹º§Àº µÇ´ÂÁö È®ÀÎ. if (usSkillType == SkillSlot.SKILLINFO.wSkill) { if ((cLockCount == SkillSlot.SKILLINFO.cLockCount && cLevel <= SkillSlot.SKILLINFO.cSkillLevel) || cLockCount < SkillSlot.SKILLINFO.cLockCount) { return true; } } } return false; } short CCharacter::GetSkillLockCount(unsigned short usSkillType) { const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(usSkillType); if (NULL == lpProtoType) { return -1; } // Ŭ·¡½º ½ºÅ³, SET °è¿­ ½ºÅ³Àº ½ºÅ³À» °¡Áö°í ÀÖÁö ¾Ê¾Æµµ »ç¿ëÇÒ ¼ö ÀÖ´Ù. if (true == lpProtoType->m_bIsClassSkill || Skill::Type::SET == lpProtoType->m_eSkillType || Skill::Type::ACTION == lpProtoType->m_eSkillType) { return 0; } // ºÎ¸ð ½ºÅ³ÀÌ ÀÖ´Â °æ¿ì ºÎ¸ð ½ºÅ³ÀÇ ¶ôÄ«¿îÆ®¸¦ ÀÌ¿ëÇÑ´Ù. if (0 != lpProtoType->m_usParentSkill) { usSkillType = lpProtoType->m_usParentSkill; } int nMaxSlotNum = m_DBData.m_Skill.wSlotNum; if (SKILL::MAX_SLOT_NUM < nMaxSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö = %d", m_dwCID, m_DBData.m_Skill.wSlotNum); return -1; } for (int nSSlot = 0; nSSlot < nMaxSlotNum; ++nSSlot) { const SKILLSLOT& SkillSlot = m_DBData.m_Skill.SSlot[nSSlot]; if (usSkillType == SkillSlot.SKILLINFO.wSkill) { return SkillSlot.SKILLINFO.cLockCount; } } return -1; } short CCharacter::GetSkillLevel(unsigned short usSkillType) { const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(usSkillType); if (NULL == lpProtoType) { return -1; } // ºÎ¸ð ½ºÅ³ÀÌ ÀÖ´Â °æ¿ì ºÎ¸ð ½ºÅ³ÀÇ ¶ôÄ«¿îÆ®¸¦ ÀÌ¿ëÇÑ´Ù. if (0 != lpProtoType->m_usParentSkill) { usSkillType = lpProtoType->m_usParentSkill; } int nMaxSlotNum = m_DBData.m_Skill.wSlotNum; if (SKILL::MAX_SLOT_NUM < nMaxSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö = %d", m_dwCID, m_DBData.m_Skill.wSlotNum); return -1; } for (int nSSlot = 0; nSSlot < nMaxSlotNum; ++nSSlot) { const SKILLSLOT& SkillSlot = m_DBData.m_Skill.SSlot[nSSlot]; if (usSkillType == SkillSlot.SKILLINFO.wSkill) { return SkillSlot.SKILLINFO.cSkillLevel; } } return -1; } short CCharacter::GetSkillSlotIndex(unsigned short usSkillType) { const Skill::ProtoType* lpProtoType = CSkillMgr::GetInstance().GetSkillProtoType(usSkillType); if (NULL == lpProtoType) { return -1; } // ºÎ¸ð ½ºÅ³ÀÌ ÀÖ´Â °æ¿ì ºÎ¸ð ½ºÅ³ÀÇ ¶ôÄ«¿îÆ®¸¦ ÀÌ¿ëÇÑ´Ù. if (0 != lpProtoType->m_usParentSkill) { usSkillType = lpProtoType->m_usParentSkill; } int nMaxSlotNum = m_DBData.m_Skill.wSlotNum; if (SKILL::MAX_SLOT_NUM < nMaxSlotNum) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ °³¼ö°¡ ÀÌ»óÇÕ´Ï´Ù. ½½·Ô ¼ö = %d", m_dwCID, m_DBData.m_Skill.wSlotNum); return -1; } for (int nSSlot = 0; nSSlot < nMaxSlotNum; ++nSSlot) { const SKILLSLOT& SkillSlot = m_DBData.m_Skill.SSlot[nSSlot]; if (usSkillType == SkillSlot.SKILLINFO.wSkill) { return nSSlot; } } return -1; } bool CCharacter::AddWorldWeaponEnchant(CAggresiveCreature* lpWeapon, unsigned char cNation) { if (Creature::KARTERANT != cNation && Creature::MERKADIA != cNation) return false; if (NULL == lpWeapon) return false; switch (cNation) { case Creature::KARTERANT: { if (GetNation() == cNation) { Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(GetGID()); if (lpGuild && lpGuild->IsEnemyGuild(lpWeapon->GetGID())) { // ±¹°¡´Â °°À¸³ª Àû´ë ±æµå¶ó¸é DeBuff Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::KarterantWorldDeBuff, 1, CSpell::INFINITE_DURATION))(this); } else { Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::KarterantWorldBuff, 1, CSpell::INFINITE_DURATION))(this); } } else { Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::KarterantWorldDeBuff, 1, CSpell::INFINITE_DURATION))(this); } } break; case Creature::MERKADIA: { if (GetNation() == cNation) { Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(GetGID()); if (lpGuild && lpGuild->IsEnemyGuild(lpWeapon->GetGID())) { // ±¹°¡´Â °°À¸³ª Àû´ë ±æµå¶ó¸é DeBuff Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::MerkadiaWorldDeBuff, 1, CSpell::INFINITE_DURATION))(this); } else { Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::MerkadiaWorldBuff, 1, CSpell::INFINITE_DURATION))(this); } } else { Skill::CAddSpell(CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, lpWeapon, Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellID::MerkadiaWorldDeBuff, 1, CSpell::INFINITE_DURATION))(this); } } break; } return true; } bool CCharacter::ClearWorldWeaponEnchant(void) { GetSpellMgr().GetAffectedInfo().Disenchant(Skill::SpellType::WORLDWEAPON_SPELL, Skill::SpellTarget::ALL_ENCHANT, Skill::Disenchant::NONE, 1, Skill::Disenchant::INFINITE_NUM); return true; } void CCharacter::CheckSkillVaild(void) { SKILL &Skill = m_DBData.m_Skill; for (int nSlotIndex = 0; nSlotIndex < Skill.wSlotNum; ) { bool bEraseSkill = false; const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); if (NULL == pSkillProtoType) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ ¹«°á¼º °Ë»ç : Á¸ÀçÇÏÁö ¾Ê´Â ½ºÅ³ÀÔ´Ï´Ù. SkillID:0x%04x", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); bEraseSkill = true; } if (Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount < 0 || Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT) { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³ ¹«°á¼º °Ë»ç : ¶ôÄ«¿îÆ®°¡ ºñÁ¤»óÀûÀÔ´Ï´Ù. SkillID:0x%04x, SkillLockCount:%d", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill, Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount); bEraseSkill = true; } if (Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel < 0 || Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel > CSkillMgr::MAX_SKILL_LEVEL) { ERRLOG3(g_Log, "CID:0x%08x ½ºÅ³ ¹«°á¼º °Ë»ç : ·¹º§ÀÌ ºñÁ¤»óÀûÀÔ´Ï´Ù. SkillID:0x%04x, SkillLevel:%d", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill, Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel); bEraseSkill = true; } if (Skill.SSlot[nSlotIndex].SKILLINFO.cLockCount == 0 && Skill.SSlot[nSlotIndex].SKILLINFO.cSkillLevel == 0) { ERRLOG2(g_Log, "CID:0x%08x ½ºÅ³ ¹«°á¼º °Ë»ç : ¶ôÄ«¿îÆ®¿Í ·¹º§ÀÌ ¸ðµÎ 0ÀÔ´Ï´Ù. SkillID:0x%04x", m_dwCID, Skill.SSlot[nSlotIndex].SKILLINFO.wSkill); bEraseSkill = true; } if (true == bEraseSkill) { unsigned char Count = nSlotIndex; for (; Count < Skill.wSlotNum - 1; ++Count) { Skill.SSlot[Count] = Skill.SSlot[Count + 1]; } Skill.SSlot[Count] = SKILLSLOT::SKILLSLOT(); --Skill.wSlotNum; } else { ++nSlotIndex; } } }