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>
611 lines
17 KiB
C++
611 lines
17 KiB
C++
#include "stdafx.h"
|
|
#include "ModifyCharacter.h"
|
|
|
|
#include <Network/Dispatch/Dispatch.h>
|
|
#include <Network/Protocol/Ryl_AdminMgrProtocol.h>
|
|
#include <Network/Packet/PacketStruct/CharStatusPacket.h>
|
|
#include <Network/Packet/PacketStruct/CharQuestPacket.h>
|
|
#include <Skill/SkillMgr.h>
|
|
#include <Item/ItemStructure.h>
|
|
#include <Log/ServerLog.h>
|
|
#include <Quest/QuestMgr.h>
|
|
#include <Creature/Character/CharacterClass.h>
|
|
#include <Creature/CreatureStructure.h>
|
|
|
|
CModifyCharacter::CModifyCharacter()
|
|
: CCharacter(0, 0)
|
|
, m_dwServerGroup(0)
|
|
, m_byChangedInfo(0)
|
|
, m_bScheduleClose(false)
|
|
, m_bSave(false)
|
|
, m_bIsOwnCopyItem(false)
|
|
|
|
{
|
|
Initialize(NULL);
|
|
ZeroMemory(&m_ExtraData, sizeof(CHAR_EXTRA_DATA));
|
|
|
|
m_ModifyCharItemSerialInfo.clear();
|
|
m_OverlapSerialInfo.clear();
|
|
|
|
m_cOldServerGroupID = UnifiedConst::Part2Selectable;
|
|
}
|
|
|
|
// 이녀석은 사용하지 말자 Initialize <- 이녀석 캐릭터 생성후 딱~~ 1번만 사용하자
|
|
// 그렇지 않으면 메모리 샌다 ㅡ.ㅡ;
|
|
void CModifyCharacter::Reset()
|
|
{
|
|
SetUID(0);
|
|
SetCID(0);
|
|
|
|
m_dwServerGroup = 0;
|
|
m_byChangedInfo = 0;
|
|
m_bScheduleClose = false;
|
|
|
|
ZeroMemory(&m_DBData, sizeof(CharacterDBData));
|
|
Initialize(NULL);
|
|
}
|
|
|
|
unsigned short CModifyCharacter::GetMaxSkillPoint()
|
|
{
|
|
// CalculateStatusData가 선행되어야 함.
|
|
return m_CreatureStatus.m_StatusInfo.m_wSkillPoint;
|
|
}
|
|
|
|
// 스킬 추가 및 스킬 레벨 변경 (이미 습득한 스킬을 추가 요청한다면 레벨 수정으로 인식)
|
|
unsigned char CModifyCharacter::AppendSkill(unsigned short wSkillID, char cLevel, char cLockCount)
|
|
{
|
|
m_DBData.m_Skill.wSkillNum = m_DBData.m_Skill.GetSkillNum(); // 현재 스킬수 재 계산
|
|
|
|
const Skill::ProtoType* lpSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(wSkillID);
|
|
|
|
short sSlotIndex = GetSkillSlotIndex(wSkillID);
|
|
|
|
bool bIsNewSkill = false; // 새 스킬 습득 여부
|
|
if(-1 == sSlotIndex) bIsNewSkill = true;
|
|
|
|
if(NULL == lpSkillProtoType)
|
|
{
|
|
ERRLOG1(g_Log, "스킬 프로토 타입 얻기 실패. 스킬ID: 0x%04x", wSkillID);
|
|
return PktAdminMgr::PktSkillEdit::FAILED_TO_GET_SKILLPROTOTYPE;
|
|
}
|
|
|
|
if(CSkillMgr::MAX_SKILL_LOCKCOUNT <= cLockCount)
|
|
{
|
|
ERRLOG1(g_Log, "최대 스킬 락 카운트를 초과하였습니다. 락 카운트: %c", cLockCount);
|
|
return PktAdminMgr::PktSkillEdit::OVERED_MAX_LOCKCOUNT;
|
|
}
|
|
|
|
if(CSkillMgr::MAX_SKILL_LEVEL < cLevel)
|
|
{
|
|
ERRLOG1(g_Log, "최대 스킬 레벨을 초과하였습니다. 스킬 레벨: %c", cLevel);
|
|
return PktAdminMgr::PktSkillEdit::OVERED_MAX_SKILL_LEVEL;
|
|
}
|
|
|
|
if(lpSkillProtoType[0].m_usSkill_ID != lpSkillProtoType[cLockCount].m_usSkill_ID)
|
|
{
|
|
ERRLOG2(g_Log, "스킬 ID가 다릅니다. 0x%04x : 0x%04x", lpSkillProtoType[0].m_usSkill_ID,
|
|
lpSkillProtoType[cLockCount].m_usSkill_ID);
|
|
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
}
|
|
|
|
// 최대 스킬 레벨을 추가할 경우 (다음 단계로 넘어가는 경우)
|
|
if(cLevel == CSkillMgr::MAX_SKILL_LEVEL)
|
|
{
|
|
// 최종 단계 스킬이 아닌경우 다음 단계 0레벨 스킬로 습득
|
|
if(cLockCount < CSkillMgr::MAX_SKILL_LOCKCOUNT - 1) // 아직 0~3 단계까지만 사용중
|
|
{
|
|
cLevel = 0;
|
|
++cLockCount;
|
|
}
|
|
}
|
|
|
|
// 새로운 스킬 습득
|
|
if(bIsNewSkill && (m_DBData.m_Skill.wSlotNum < SKILL::MAX_SLOT_NUM))
|
|
{
|
|
sSlotIndex = m_DBData.m_Skill.wSlotNum; // 새 슬롯 얻기
|
|
}
|
|
else if(m_DBData.m_Skill.wSlotNum == SKILL::MAX_SLOT_NUM)
|
|
{
|
|
ERRLOG0(g_Log, "이미 사용할 수 있는 최대 슬롯을 사용중입니다.");
|
|
return PktAdminMgr::PktSkillEdit::NOT_ENOUGH_SKILLSLOT;
|
|
}
|
|
|
|
SKILLSLOT TempSkillSlot;
|
|
TempSkillSlot.SKILLINFO.wSkill = wSkillID;
|
|
TempSkillSlot.SKILLINFO.cSkillLevel = cLevel;
|
|
TempSkillSlot.SKILLINFO.cLockCount = cLockCount;
|
|
|
|
unsigned short cResult = ReadSkill(TempSkillSlot, wSkillID, cLockCount);
|
|
|
|
if(PktBase::NO_SERVER_ERR == cResult) // 사용 가능한 스킬임
|
|
{
|
|
SKILL& Skill = m_DBData.m_Skill;
|
|
SKILLSLOT& SkillSlot = Skill.SSlot[sSlotIndex];
|
|
|
|
ChkEmptySlot(Skill); // 빈 슬롯을 가지고 있는지 체크
|
|
|
|
unsigned short BeforePoint =
|
|
(SkillSlot.SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LOCKCOUNT) + SkillSlot.SKILLINFO.cSkillLevel;
|
|
|
|
unsigned short AfterPoint =
|
|
(cLockCount * CSkillMgr::MAX_SKILL_LOCKCOUNT) + cLevel;
|
|
|
|
// 기존 스킬 레벨 변경
|
|
if((!bIsNewSkill) && (GetMaxSkillPoint() >= ((GetSkillPoint() - BeforePoint) + AfterPoint)))
|
|
{
|
|
SkillSlot.SKILLINFO.wSkill = wSkillID;
|
|
SkillSlot.SKILLINFO.cSkillLevel = cLevel;
|
|
SkillSlot.SKILLINFO.cLockCount = cLockCount;
|
|
}
|
|
// 새로운 스킬 추가
|
|
else if(bIsNewSkill && (GetMaxSkillPoint() >= (GetSkillPoint() + AfterPoint)))
|
|
{
|
|
SkillSlot.SKILLINFO.wSkill = wSkillID;
|
|
SkillSlot.SKILLINFO.cSkillLevel = cLevel;
|
|
SkillSlot.SKILLINFO.cLockCount = cLockCount;
|
|
|
|
++m_DBData.m_Skill.wSlotNum; // 사용중인 슬롯수 + 1
|
|
}
|
|
|
|
UpdateQuickSlotSkill(SkillSlot);
|
|
m_DBData.m_Skill.wSkillNum = m_DBData.m_Skill.GetSkillNum();
|
|
}
|
|
else
|
|
{
|
|
switch(cResult)
|
|
{
|
|
case PktSk::FAIL_NOT_CURRENT_CLASS:
|
|
return PktAdminMgr::PktSkillEdit::NOT_CURRENT_CLASS;
|
|
case PktSk::FAIL_NOT_ENOUGH_STATUS:
|
|
return PktAdminMgr::PktSkillEdit::NOT_ENOUGH_STAT;
|
|
case PktSk::FAIL_MAX_LEVEL:
|
|
return PktAdminMgr::PktSkillEdit::OVERED_MAX_SKILL_LEVEL;
|
|
case PktSk::FAIL_NOT_CURRENT_LOCK_COUNT:
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
default:
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
}
|
|
}
|
|
|
|
return PktAdminMgr::PktSkillEdit::SUCCESS;
|
|
}
|
|
|
|
// 스킬 삭제 (스킬 포인트 조정 및 해당 스킬 슬롯 정보 초기화)
|
|
unsigned char CModifyCharacter::DeleteSkill(unsigned short wSkillID, char cLevel, char cLockCount)
|
|
{
|
|
m_DBData.m_Skill.wSkillNum = m_DBData.m_Skill.GetSkillNum(); // 현재 스킬수 재 계산
|
|
|
|
short sDelSlotIndex = GetSkillSlotIndex(wSkillID);
|
|
|
|
if(-1 != sDelSlotIndex)
|
|
{
|
|
SKILL& Skill = m_DBData.m_Skill;
|
|
SKILLSLOT& DelSlot = Skill.SSlot[sDelSlotIndex];
|
|
|
|
ChkEmptySlot(Skill); // 빈 슬롯을 가지고 있는지 체크
|
|
|
|
const Skill::ProtoType* lpSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(wSkillID);
|
|
if(NULL == lpSkillProtoType)
|
|
{
|
|
ERRLOG1(g_Log, "스킬 프로토 타입 얻기 실패. 스킬ID: 0x%04x", wSkillID);
|
|
return PktAdminMgr::PktSkillEdit::FAILED_TO_GET_SKILLPROTOTYPE;
|
|
}
|
|
|
|
if(DelSlot.SKILLINFO.wSkill != wSkillID)
|
|
{
|
|
ERRLOG3(g_Log, "삭제 요청 받은 스킬과 삭제 할 슬롯의 스킬이 일치하지 않습니다."
|
|
"슬롯번호: %d , 삭제할 슬롯의 스킬ID: 0x%04x, 삭제 요청 한 스킬ID: 0x%04x",
|
|
sDelSlotIndex, DelSlot.SKILLINFO.wSkill, wSkillID);
|
|
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
}
|
|
|
|
if(true == lpSkillProtoType->m_bIsClassSkill)
|
|
{
|
|
ERRLOG0(g_Log, "삭제하려는 스킬이 클래스 스킬입니다.");
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
}
|
|
|
|
// 스킬 슬롯 중간이 비면 한칸씩 앞으로 당겨옴 (중간에 비는 슬롯이 없도록!)
|
|
unsigned short sLastSlotIndex = Skill.wSlotNum - 1;
|
|
|
|
for(unsigned short sSlotIndex = sDelSlotIndex; sSlotIndex < sLastSlotIndex; ++sSlotIndex)
|
|
{
|
|
Skill.SSlot[sSlotIndex] = Skill.SSlot[sSlotIndex + 1];
|
|
}
|
|
|
|
Skill.SSlot[sLastSlotIndex].SKILLINFO.wSkill = 0;
|
|
Skill.SSlot[sLastSlotIndex].SKILLINFO.cSkillLevel = 0;
|
|
Skill.SSlot[sLastSlotIndex].SKILLINFO.cLockCount = 0;
|
|
|
|
Skill.wSkillNum -=
|
|
(DelSlot.SKILLINFO.cLockCount * CSkillMgr::MAX_SKILL_LEVEL) + DelSlot.SKILLINFO.cSkillLevel;
|
|
|
|
Skill.wSlotNum -= 1;
|
|
|
|
UpdateQuickSlotSkill(DelSlot);
|
|
|
|
return PktAdminMgr::PktSkillEdit::SUCCESS;
|
|
}
|
|
|
|
return PktAdminMgr::PktSkillEdit::FAILED;
|
|
}
|
|
|
|
bool CModifyCharacter::ChkEmptySlot(SKILL Skill)
|
|
{
|
|
CString strEmptySlotIndex;
|
|
|
|
for(unsigned short sSlotIndex = 0; sSlotIndex < Skill.wSlotNum; ++sSlotIndex)
|
|
{
|
|
if(0 == Skill.SSlot[sSlotIndex].SKILLINFO.wSkill)
|
|
{
|
|
strEmptySlotIndex.AppendFormat("%d ", sSlotIndex);
|
|
}
|
|
}
|
|
|
|
if(!strEmptySlotIndex.IsEmpty())
|
|
{
|
|
ERRLOG3(g_Log, "스킬 슬롯에 빈슬롯이 있습니다. CID: %u, 슬롯수: %d, 빈슬롯: %s",
|
|
GetCID(), Skill.wSlotNum, strEmptySlotIndex);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// 걍 날림 스킬레벨가져오기..
|
|
// Return :
|
|
// 존재하는 스킬이면 현재 내레벨.. 같은계열의 하위스킬일경우 MaxSkillLevel을...
|
|
// 같은 계열스킬중 상위계열이면 0을 리턴..
|
|
short CModifyCharacter::GetSkillLevelEX(unsigned short usSkillType, char cLockCount)
|
|
{
|
|
const Skill::ProtoType* lpSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(usSkillType);
|
|
|
|
if(NULL != lpSkillProtoType)
|
|
{
|
|
int nMaxSlotNum = m_DBData.m_Skill.wSlotNum;
|
|
|
|
if(SKILL::MAX_SLOT_NUM >= nMaxSlotNum)
|
|
{
|
|
for( int nSlot = 0; nSlot < nMaxSlotNum; ++ nSlot )
|
|
{
|
|
const SKILLSLOT& SkillSlot = m_DBData.m_Skill.SSlot[ nSlot ];
|
|
if( SkillSlot.SKILLINFO.wSkill == usSkillType )
|
|
{
|
|
if( SkillSlot.SKILLINFO.cLockCount == cLockCount )
|
|
{
|
|
return SkillSlot.SKILLINFO.cSkillLevel;
|
|
}
|
|
else if( SkillSlot.SKILLINFO.cLockCount > cLockCount )
|
|
{
|
|
return SKILL::MAX_SKILL_LEVEL;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool CModifyCharacter::SetGold(unsigned long dwGold)
|
|
{
|
|
if(dwGold > ULONG_MAX)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_DBData.m_Info.Gold = dwGold;
|
|
|
|
return true;
|
|
}
|
|
|
|
// 캐릭터를 잡고 있는 관리자의 Session을 리턴~~
|
|
CSession* CModifyCharacter::GetCheckSession( unsigned long dwUID )
|
|
{
|
|
if( m_dwUID == dwUID )
|
|
{
|
|
if( NULL != m_lpPacketDispatch )
|
|
{
|
|
CSession& lpSession = m_lpPacketDispatch->GetSession( );
|
|
//if( NULL != lpSession ) return lpSession;
|
|
return &lpSession;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// 캐릭터 정보가 변경됬음을 기억해놓자..
|
|
void CModifyCharacter::OnChangedInfo( int iMask )
|
|
{
|
|
m_byChangedInfo |= iMask;
|
|
}
|
|
|
|
// 캐릭터 변경정보를 지운다..
|
|
void CModifyCharacter::OffChangedInfo( int iMask )
|
|
{
|
|
m_byChangedInfo &= iMask;
|
|
}
|
|
|
|
// 캐릭터의 Status
|
|
void CModifyCharacter::GetModifyCharStatus(PktAdminMgr::CHAR_STATUS_ST& StatusST)
|
|
{
|
|
StatusST.m_cFace = m_DBData.m_Info.Face;
|
|
StatusST.m_cHair = m_DBData.m_Info.Hair;
|
|
StatusST.m_cLevel = m_DBData.m_Info.Level;
|
|
StatusST.m_cRace = m_DBData.m_Info.Race;
|
|
StatusST.m_cSex = m_DBData.m_Info.Sex;
|
|
StatusST.m_dwExp = m_DBData.m_Info.Exp;
|
|
StatusST.m_dwFame = m_DBData.m_Info.Fame;
|
|
StatusST.m_dwMileage = m_DBData.m_Info.Mileage;
|
|
StatusST.m_nClass = m_DBData.m_Info.Class;
|
|
StatusST.m_nCON = m_DBData.m_Info.CON;
|
|
StatusST.m_nDEX = m_DBData.m_Info.DEX;
|
|
StatusST.m_nINT = m_DBData.m_Info.INT;
|
|
StatusST.m_nIP = m_DBData.m_Info.IP;
|
|
StatusST.m_nSTR = m_DBData.m_Info.STR;
|
|
StatusST.m_nWIS = m_DBData.m_Info.WIS;
|
|
StatusST.m_cChance = m_DBData.m_Info.Chance;
|
|
}
|
|
|
|
// 캐릭터 Status변경..
|
|
bool CModifyCharacter::UpdataStatus(PktAdminMgr::CHAR_STATUS_ST& StatusST)
|
|
{
|
|
CHAR_INFOST OrgCharInfo;
|
|
|
|
CopyMemory(&OrgCharInfo, &m_DBData.m_Info, sizeof(CHAR_INFOST));
|
|
|
|
m_DBData.m_Info.Sex = StatusST.m_cSex;
|
|
m_DBData.m_Info.Hair = StatusST.m_cHair;
|
|
m_DBData.m_Info.Face = StatusST.m_cFace;
|
|
m_DBData.m_Info.Race = StatusST.m_cRace;
|
|
m_DBData.m_Info.Class = StatusST.m_nClass;
|
|
|
|
m_DBData.m_Info.Fame = StatusST.m_dwFame;
|
|
m_DBData.m_Info.Mileage = StatusST.m_dwMileage;
|
|
|
|
m_DBData.m_Info.Level = StatusST.m_cLevel;
|
|
m_DBData.m_Info.Exp = StatusST.m_dwExp;
|
|
|
|
m_DBData.m_Info.IP = StatusST.m_nIP;
|
|
|
|
m_DBData.m_Info.STR = StatusST.m_nSTR;
|
|
m_DBData.m_Info.CON = StatusST.m_nCON;
|
|
m_DBData.m_Info.DEX = StatusST.m_nDEX;
|
|
m_DBData.m_Info.INT = StatusST.m_nINT;
|
|
m_DBData.m_Info.WIS = StatusST.m_nWIS;
|
|
m_DBData.m_Info.Chance = StatusST.m_cChance;
|
|
|
|
m_CreatureStatus.m_nExp = StatusST.m_dwExp;
|
|
m_CreatureStatus.m_nLevel = StatusST.m_cLevel;
|
|
|
|
// Status 계산식을 넣자
|
|
if(!CalculateStatusData(false))
|
|
{
|
|
// 잘못된 Status값
|
|
CopyMemory(&m_DBData.m_Info, &OrgCharInfo, sizeof(CHAR_INFOST));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// 캐릭터가 소지하고 있는 아이템을 UID로 검색하여 리턴한다..
|
|
// 해당 아이템이 없으면 NULL
|
|
Item::CItem* CModifyCharacter::UIDbyItem(unsigned __int64 ItemUID, unsigned char cTakeType)
|
|
{
|
|
Item::CItemContainer::iterator Itr;
|
|
|
|
if(cTakeType == TakeType::TS_INVEN) // 인벤토리 아이템
|
|
{
|
|
Item::CArrayContainer& ArrayContainer = GetInventory();
|
|
Itr = ArrayContainer.begin();
|
|
|
|
for(;Itr != ArrayContainer.end(); ++Itr)
|
|
{
|
|
if(NULL != (*Itr))
|
|
{
|
|
if((*Itr)->GetUID() == ItemUID) return (*Itr);
|
|
}
|
|
}
|
|
}
|
|
else if( cTakeType == TakeType::TS_EQUIP ) // 장비창 아이템
|
|
{
|
|
Item::CEquipmentsContainer& EquipContainer = GetEquipments( );
|
|
Itr = EquipContainer.begin( );
|
|
|
|
for(;Itr != EquipContainer.end(); ++Itr )
|
|
{
|
|
if(NULL != (*Itr))
|
|
{
|
|
if((*Itr)->GetUID() == ItemUID) return (*Itr);
|
|
}
|
|
}
|
|
}
|
|
else if(cTakeType == TakeType::TS_DEPOSIT) // 창고 아이템
|
|
{
|
|
Item::CDepositContainer& DepositContainer = GetDeposit();
|
|
|
|
for (unsigned char cTab = 0; cTab < DepositContainer.GetMaxTabNum(); ++cTab)
|
|
{
|
|
Item::CItemContainer* DepositTabContainer = DepositContainer.GetTab(cTab);
|
|
Itr = DepositTabContainer->begin();
|
|
for(; Itr != DepositTabContainer->end( ); ++Itr )
|
|
{
|
|
if( NULL != ( *Itr ) )
|
|
{
|
|
if( ( *Itr )->GetUID( ) == ItemUID ) return ( *Itr );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CModifyCharacter::ChangeName(char* szName)
|
|
{
|
|
strncpy(m_DBData.m_Info.Name, szName, CHAR_INFOST::MAX_NAME_LEN);
|
|
}
|
|
|
|
// 캐릭터를 편집중인 관리자 계정을 저장한다.
|
|
void CModifyCharacter::SetModifyAdmin(char* Account, int Length)
|
|
{
|
|
strncpy(m_szModifyAdmin, Account, Length);
|
|
}
|
|
|
|
void CModifyCharacter::ParseQuestData()
|
|
{
|
|
Quest::ExecutingQuest* aryExecutingQuest = GetExecutingQuest();
|
|
unsigned short* aryHistoryQuest = GetHistoryQuest();
|
|
|
|
// 수행중인 퀘스트 목록
|
|
int nIndex = 0;
|
|
|
|
PktQuestDB::ExecutingQuest* lpExecuteQuestPos =
|
|
reinterpret_cast<PktQuestDB::ExecutingQuest*>(m_ExtraData.m_Quest.Data);
|
|
|
|
PktQuestDB::ExecutingQuest* lpExecuteQuestEnd =
|
|
reinterpret_cast<PktQuestDB::ExecutingQuest*>(m_ExtraData.m_Quest.Data) +
|
|
(m_ExtraData.m_Quest.dwSize / sizeof(PktQuestDB::ExecutingQuest));
|
|
|
|
for(; lpExecuteQuestPos != lpExecuteQuestEnd; ++lpExecuteQuestPos)
|
|
{
|
|
Quest::QuestNode* lpQuest = CQuestMgr::GetInstance().GetQuestNode(lpExecuteQuestPos->m_wQuestID);
|
|
|
|
if (0 != lpQuest && false == lpQuest->CheckNationDependent(GetUserNation()))
|
|
{
|
|
aryExecutingQuest[nIndex] = Quest::ExecutingQuest(lpExecuteQuestPos->m_wQuestID,
|
|
lpExecuteQuestPos->m_cPhase, lpExecuteQuestPos->m_cTriggerCount);
|
|
|
|
++nIndex;
|
|
}
|
|
}
|
|
|
|
nIndex = 0;
|
|
|
|
// 완료 퀘스트 목록
|
|
unsigned short* lpHistoryQuestPos =
|
|
reinterpret_cast<unsigned short*>(m_ExtraData.m_History.Data);
|
|
|
|
unsigned short* lpHistoryQuestEnd =
|
|
reinterpret_cast<unsigned short*>(m_ExtraData.m_History.Data) +
|
|
(m_ExtraData.m_History.dwSize / sizeof(unsigned short));
|
|
|
|
for (; lpHistoryQuestPos != lpHistoryQuestEnd; ++lpHistoryQuestPos)
|
|
{
|
|
Quest::QuestNode* lpQuest = CQuestMgr::GetInstance().GetQuestNode(*lpHistoryQuestPos);
|
|
|
|
if (0 != lpQuest && false == lpQuest->CheckNationDependent(GetUserNation()))
|
|
{
|
|
aryHistoryQuest[nIndex] = *lpHistoryQuestPos;
|
|
++nIndex;
|
|
}
|
|
}
|
|
|
|
// 퀘스트에 의해 받는 영향을 계산
|
|
CalculateStatusData(false);
|
|
}
|
|
|
|
void CModifyCharacter::SetQuestData()
|
|
{
|
|
const int MAX_BUFFER =
|
|
sizeof(PktQuestDB) + PktQuestDB::MAX_EXECUTING_QUEST * sizeof(PktQuestDB::ExecutingQuest) +
|
|
PktQuestDB::MAX_HISTORY_QUEST * sizeof(unsigned short);
|
|
|
|
char szBuffer[MAX_BUFFER];
|
|
|
|
PktQuestDB* lpPktQuestDB = reinterpret_cast<PktQuestDB*>(szBuffer);
|
|
|
|
lpPktQuestDB->m_dwUID = GetUID();
|
|
lpPktQuestDB->m_dwCID = GetCID();
|
|
lpPktQuestDB->m_wExecuteQuestSize = 0;
|
|
lpPktQuestDB->m_wHistoryQuestSize = 0;
|
|
|
|
Quest::ExecutingQuest* ExecutingQuest = GetExecutingQuest();
|
|
unsigned short *wHistoryQuest = GetHistoryQuest();
|
|
|
|
int nIndex = 0;
|
|
for (nIndex = 0; nIndex < PktQuestDB::MAX_EXECUTING_QUEST; ++nIndex)
|
|
{
|
|
if (NULL == ExecutingQuest[nIndex].m_QuestNode)
|
|
{
|
|
break;
|
|
}
|
|
|
|
PktQuestDB::ExecutingQuest* ExecuteQuest =
|
|
reinterpret_cast<PktQuestDB::ExecutingQuest*>
|
|
(szBuffer + sizeof(PktQuestDB) + lpPktQuestDB->m_wExecuteQuestSize);
|
|
|
|
ExecuteQuest->m_wQuestID = ExecutingQuest[nIndex].m_QuestNode->m_wQuestID;
|
|
ExecuteQuest->m_cPhase = ExecutingQuest[nIndex].m_cPhase;
|
|
memcpy(ExecuteQuest->m_cTriggerCount, ExecutingQuest[nIndex].m_cTriggerCount,
|
|
sizeof(unsigned char) * PktQuestDB::MAX_TRIGGER);
|
|
|
|
lpPktQuestDB->m_wExecuteQuestSize += sizeof(PktQuestDB::ExecutingQuest);;
|
|
}
|
|
|
|
for (nIndex = 0; nIndex < PktQuestDB::MAX_HISTORY_QUEST; nIndex++)
|
|
{
|
|
if (0 == wHistoryQuest[nIndex])
|
|
{
|
|
break;
|
|
}
|
|
|
|
unsigned short* wHistoryQuestForPkt =
|
|
reinterpret_cast<unsigned short *>(szBuffer + sizeof(PktQuestDB) +
|
|
lpPktQuestDB->m_wExecuteQuestSize + lpPktQuestDB->m_wHistoryQuestSize);
|
|
|
|
*wHistoryQuestForPkt = wHistoryQuest[nIndex];
|
|
|
|
lpPktQuestDB->m_wHistoryQuestSize += sizeof(unsigned short);
|
|
}
|
|
|
|
memset(&m_ExtraData.m_Quest, 0, sizeof(QUEST));
|
|
m_ExtraData.m_Quest.dwSize = lpPktQuestDB->m_wExecuteQuestSize;
|
|
memcpy(m_ExtraData.m_Quest.Data, lpPktQuestDB + 1, lpPktQuestDB->m_wExecuteQuestSize);
|
|
|
|
memset(&m_ExtraData.m_History, 0, sizeof(HISTORY));
|
|
m_ExtraData.m_History.dwSize = lpPktQuestDB->m_wHistoryQuestSize;
|
|
memcpy(m_ExtraData.m_History.Data, reinterpret_cast<char*>(lpPktQuestDB + 1) + lpPktQuestDB->m_wExecuteQuestSize,
|
|
lpPktQuestDB->m_wHistoryQuestSize);
|
|
}
|
|
|
|
void CModifyCharacter::RevisionQuestNation()
|
|
{
|
|
using namespace Creature;
|
|
|
|
// 양국체제에선 무조건 휴먼은 카르테란트, 아칸은 메르카디아! (퀘스트 파싱할때 필요)
|
|
switch(GetRace())
|
|
{
|
|
case CClass::RaceType::HUMAN:
|
|
m_cQuestNation = Creature::KARTERANT;
|
|
break;
|
|
case CClass::RaceType::AKHAN:
|
|
m_cQuestNation = Creature::MERKADIA;
|
|
break;
|
|
default:
|
|
m_cQuestNation = Creature::MAX_NATION;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// class CModifyItem Down_Cast ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void CModifyItem::SetUID(unsigned __int64 UID)
|
|
{
|
|
m_ItemData.m_dwUID = UID;
|
|
}
|
|
|
|
void CModifyItem::SetPrototoypID(unsigned short PrototypeID)
|
|
{
|
|
m_ItemData.m_usProtoTypeID = PrototypeID;
|
|
}
|